Without even noticing, I've passed the 300th post on this blog this week.
As the first post was at 30th Jan 2006, it gives 305 posts over 31 months - that's almost 10 per month. And I started off very slow ...
Things to keep in mind:
Through my life as a software developer, usually my clients did not possess the same technical skills that I did.
They did not take "Systems Analysis and Design" course in collage, and they could make very little sense out of UML diagrams.
Blueprints and such are waaaaay to abstract for them.
And guess what? I also lack their knowledge. At best I had a vague idea about their field, and about the domain of their problem which the project I was working on should have addressed.
we speak different languages.
You too, dear reader. Yup.
See the "How many points" problem to understand the possible mismatches you can have when interpreting abstract models.
So if a developer (or a software company, whatever) provide a client with a thick "project analysis" paper, loaded with, ehm, blueprints, UML diagrams and such, then after wasting a lot of time on arguments, the client will sign on a spec he did not comprehend fully, and does not correlate with his needs and whishes.
At the end of the development phase you'll get a product that do not incorporate the domain knowledge, and give a partial solution to the client's pain. The client's satisfaction will be "arrr, that's O.K." at best. Even it will have super-duper-shiny-ajax-powered-SOA-2.0-3D-effects-with-silverlight/wpf/air/flash-thingy
After the 'cool' effect is over, the client just have to learn to live with the not-perfect solution
The only a possible recipe for dealing with that:
you want your developers to be Cathedral Builders not Stone Cutters
Well one should not only strive to hire Cathedral Builders for his team, but also to be one himself.
So how you turn yourself into a Cathedral Builder?
It's simple. Just be one.
So don't whine on problems with the code/methodologies/technologies/etc. Instead you should come up with proposals and solutions for these problems.
You don't have to be radical (we need a web server running Erlang), and you shouldn't be negative (our methodology is crap. we need to act differently). Small incremental steps, and elegant solutions that integrate well with the current assets of the team, are likely to be accepted and valued by your team leader and managers.
And they say we geeks cannot express our feelings ...
That's how my blog's homepage looks like according to wordle.com:
XML has way too many occurrences ...
(via http://humus101.com/)
Following my post on key-level locked cache, I got the following piece of code from my friend Moran Benisty, implementing the same idea over XmlDocuments which is being loaded over the Internet, and ASP.NET's Cache.
This is a real life code. He's using it on a very large-scale website in production.
As usual - use at your own risk, and be kind enough to share thoughts and improvement ideas here for his use.
public static class XmlService
{
private static Dictionary _locks = new Dictionary();
public static XmlDocument GetXml(string url)
{
return GetXml(url, new TimeSpan(1, 0, 0), false);
}
public static XmlDocument GetXml(string url, TimeSpan timeToHold, bool autoRefresh)
{
if (HttpRuntime.Cache[url] as string == "Failed")
return null;
XmlDocument xml = HttpRuntime.Cache[url] as XmlDocument;
if (xml != null)
return xml;
if (!_locks.ContainsKey(url))
lock (_locks)
if (!_locks.ContainsKey(url))
_locks.Add(url, new object());
if (HttpRuntime.Cache[url] == null)
lock (_locks[url])
if (HttpRuntime.Cache[url] == null)
{
xml = LoadXml(url);
if (xml != null)
HttpRuntime.Cache.Insert(url, xml, null,
DateTime.Now.Add(timeToHold),
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.NotRemovable,
delegate(string dataKey, object value, CacheItemRemovedReason reason)
{
if (autoRefresh)
GetXml(url, timeToHold, autoRefresh);
}
);
else
HttpRuntime.Cache.Insert(url, "Failed", null, DateTime.Now.AddMinutes(5), System.Web.Caching.Cache.NoSlidingExpiration);
}
xml = HttpRuntime.Cache[url] as XmlDocument;
return xml;
}
private static readonly ILog _errorlog = LogManager.GetLogger("ErrorLogger");
private static XmlDocument LoadXml(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Timeout = 3000;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
XmlDocument xml = new XmlDocument();
xml.Load(response.GetResponseStream());
return xml;
}
catch (Exception ex)
{
_errorlog.Error(ex.Message, ex);
return null;
}
}
}
I'd have switched XmlService with KeyLevelCacheService, XmlDocument with T, and LoadXml with Func<T>, then have a separate XmlService use KeyLevelCacheService internally.
A thread looking for an item in the cache to find that it's not there, would issue the http request to fill the cache. A second thread might want to initiate another call if it needs the data before the first thread has updated the cache.
use locks on the cache object.
problem with that: you lock the whole cache, so other threads looking for a different type of data will be blocked, even though it's okay for them to get data from the cache, and even to insert data with a different key into the cache.
Keep a key per requested entry. Now you only lock what needs locking.
You'd keep a dictionary of lockers ( new object() ), then the action of obtaining a locker will cause a full cache lock, however the lock duration will be short (the time it takes to retrieve an object from a Hashtable, or to new an object and put it in the Hashtable), and then the long out-of-process operation of loading the object will be with a lock on the specific key, while the rest of the Cache is accessible for reads and writes by other threads.
Note - this is notepad (or rather WindowsLiveWriter) code. You'd need to fix syntax errors, and inspect the usage. License is MIT - Use at your own risk, and don't forget to attribute it to the writer
class KeyLevelSafeCache
{
IDictionary lockers = new Hashtable();
IDictionary cache = new Hashtable();
object ObtainLockerFor(string key)
{
return thread-safely-get-an-object-from-lockers-hashtable()
}
public T Get<T>(string key, Func<T> load())
{
var locker = ObtainLockerFor(key);
//now retrieve the object from the cache using 'locker'
}
}
The FactorySupportFacility in Windsor is very useful but there's a little something to be aware of when using it.
This facility allows you to tell the container that when a given service is to be resolved, instead of new-ing it, it should call a factory method to obtain an instance.
This is very useful for context objects (like DbContext, HttpContext etc.) , which are usually being supplied by a framework thus you can't have the container instantiate them directly.
So, assuming you want to inject a ISomeContext object into a service, you need to create a factory that can obtain it for you:
public class SomeContextFactory
{
ISomeContext ObtainFromFramework()
{
return SomeFrameworkContext.Current; //or whatever
}
}
then you can setup the container to use that factory when injecting the context
Online examples:
When taking the programmatic road, you must follow this order of doing things:
var facility = new FactorySupportFacility();
container.Kernel.AddFacility("factory.support", facility);
facility.AddFactory<ISomeContext, SomeContextFactory>("some.context", "ObtainFromFramework");If you mix 2 and 3, it would break.
There reason of course is that registering the factory into the facility, mean that the facility needs no know about the current container and kernel. This is being done in step 2 so you simply can't do step 3 before that.
yippee - Steve Yegge has published a new post, which is always a treat to read.
This time, I was delighted enough simply by reading the title: Business requirements are bullshit
And that's after my wife has just returned from work, doing as part of a S.A.P. team, some massive blue-prints work. Ha ha.
Prepare to be surprised ...
http://flickr.com/photos/arikfr/2753627777/in/set-72157606676239795
A dude on the ALT.NET Israel mailing list has given the new Google Insights a few things to chew on.
For example, he's shown that there is much more interest in ASP.NET MVC over MonoRail.
So a wonder came up, whether one should choose a framework or a technology should it be highly searched for.
my take on the matter:
I'd look for this type of people in the tech community.
People that:
No matter how you'd turn the search statistics, based on parameter 3 only, any OSS will be way ahead a closed source solution.
Gustavo Ringel also had a say:
I see a lot of articles about how to do stupid things with typed datasets, and much less about how to do great things with ORM's...should i had go for typed datasets instead of NHibernate or other ORM because i have more help of less skilled people?
I'm a big fan of google maps. A simple and yet very effective tool. I wish they had maps for Israel too ...
Anyway, I noticed today that the maps do not load on my FF. started disabling addons one by one (you'd usually blame FireBug ...) but I found out that it was the skype plugin's fault.
hmm. Im not really using it much anyway, and for the rare cases I do need to phone someone abroad, I guess I'll copy and paste into skype.
I've been tagged by Mike Hadlow (Great blog - subscribe to it now, what are you waiting for?)
Ok, let's go.
My dad is one the IT dinosaurs. He have been doing the Punched card dance from early stages of public sector computing in Israel, and I guess I must have inherited the passion for programming. Before I got six, he bought me a ZX-Spectrum, alongside some BASIC beginners book in Hebrew and threw me into the deep water.
After a few months of getting comfy with the language, I've learned to read English and got my first serious programming book, one the tried to teach things like code reuse using GOTO and GOSUB.
I also had to learn some Assembler as the ZX's BASIC was pretty much limited.
BASIC, as noted above
A simple yet effective word processing application, written in Turbo Pascal 5.5. I was about 16 then.
This word processor was for the sole purpose of aiding my older sister go through Law School. I needed a way to type and printing her seminars and there was no built in WP in MS-DOS but edlin.exe back then, and no Internet to download a WP from.
At 18 I wrote another program in Pascal, aimed at keeping track of membership payments for a local Bnei-Akiva Branch. I learned the hard way that building a DB engine by hand without any theoretical background, and without ever hearing about terms like "SQL", "Relations", "Transaction" and the like, is not a simple thing to do. By the time this application had enough features I have already left to recruit to the IDF, so it never got into production.
Then there was a gap of a few years during which I didn't program until I was 24, and I needed to write my third and forth applications. They were in ACCESS, VBA and VB, written as part of my jobs in the army as a logistics officer. I needed a better inventory manager than the old MAGIC based that my unit had, and a better solution for keeping track of vacations utilisation of the staff.
There you go. Not only the first one, but the first four.
After leaving the army, I taught myself C#, HTML and ASP.NET, registered as self employed and ran a few projects for a few clients. The first of which was a simple VBA based automation for an import/export dealer in the aviation industry. The application was automating the read of RFQ emails, looking up for matched data in their propriety Interbase driven DB, and then exported a report containing highly probable sale items. They liked it so much that they started adding features, and other business-helping apps. They still are a valued customer.
An interesting note here - the last time I have updated or fixed a bug on the first application was almost two years ago. And it's still in daily use, so even though it's coded in a way I'd call blasphemy today, with all the VB-ness scattered around, I still am very proud of this piece of code, as professionally it is rock solid, and not too difficult to maintain, and from business prospective it had a huge benefit for the client.
I would have started even earlier :)
Be open to criticism. If you program alone, then try to share as much code with the community as you can, by participating in open source projects. The best place to learn is from your own mistakes, pointed out by others.
I can certainly testify on myself, that I've learned a lot more when I was part of teams where I was not THE tech leader, be it on paid gigs or on OSS.
During University when I took "Introduction to Algorithms" (learning part I of "Introduction to Algorithms") I had to build a Red-Black tree representation. Back then The only language I know well enough was VB, but I had write it in C++. I did know the basic syntax from my C background, and some vague knowledge of pointers and memory allocations, but that's about it. The project was supposed to be written by a team of three, but I then decided that I had to learn C++ decently and write this alone, so I sat down for a long weekend, got myself a copy of the STL to learn by example, and produces a working generic RB-Tree implementation using Templates to allow generic keys in the tree.
When I sent it over to the other team members, all they had to do was to smoothen up the rough edges.
Again, it wasn't very pretty, but I did prove a point to myself, with that little exercise.
In order to make the propagation of this topic even faster, I decided to tag 9 people (!):
Due to the large volume of participants, we needed a larger venue.
Sela Group has generously agreed to accommodate the conference in their building.
So, see you there this Thursday at 18:30
One of the goals of this blog is for me to be able to get feedback from other people. Usually it means feedback regarding code I write, design decisions I make, and other technical stuff.
However one other goal is to improve my written English skills. Therefore I would be happy to accept any input regarding spelling, vocabulary and grammar mistakes. I won't be offended, that's a promise.