Inversion of inversion of control

Followup to Sam’s post, Sam’s other post and Liz’s post about Sam’s posts.

The contextual IOC pattern looks to me like a solution to the ‘problem’ of Dependency Injection based IOC, namely that all an object’s dependencies are explicitly named. But wait a minute, IOC was a solution to the problem of having objects whose dependencies weren’t clear in the first place.

Dependency injection bothers me because it encourages an object to have too much control. To shamelessly steal Liz’s example code:

new GameFactory(UserPreference preference, GuiComponentFactory factory, Scorer scorer, RulesEngine rulesEngine, Timer timer)

The reason GameFactory needs all that stuff is because it is presumably going to pass it down to the Game objects it creates. That is fine, and 5 parameters in a constructor isn’t setting off any code-smell alarms for me. I wouldn’t do it that way however. For a start, I question the need for a factory. Presumably somewhere there is a UI showing a list of possible games waiting for the player to choose one. I see no benefit in having an abstract factory when what I want to do in response to a user clicking ‘Tetris’ is a new TetrisGame(). The indirection of the factory is just getting in the way.

I could see how you might want a more configurable list of games, in which case possibly a GameCollection containing a TetrisFactory, a PacmanFactory etc. might work, if the game objects were too heavyweight to simply pre-instantiate at startup.

That’s not really where I want to go with this post though. The thing that really caught my eye was the Timer parameter. I’m being a bit mean picking on this one as its easy target, and design is subjective, but it demonstrates one of my concerns with IOC quite nicely. Clearly a Game object requires some notion of the passage of time, as many games are based on things happening periodically. In the Tetris example, it has to move a block down the screen and check to see if it’s landed on the pile. However, injecting a Timer is not what I would do. What the game object really wants is for something else to tell it when time has passed. Something external. The code might look like this:

public abstract class Game implements TimeDependent {
}

public interface TimeDependent {
void clockTick(long millisSinceLastTick);
// or possibly, for more OO flexibility
void clockTick(TimeInstant aFrozenMomentInTime);
}

This style satisfies all the requirements of testability, with the added simplification of removing one of the dependencies from the constructor.

You could do the same with Scorer. The game could expose a public TetrisScore basicScore() method, that a collaborator can call, and do its own post-processing on before showing it to the user.

UserPreferences is tougher. I’d agree that the game wants to ask a number of questions of the preferences object, so it should probably be given it.

To conclude, we build object-oriented systems. Its ok for an object to need help from collaborating objects, without having to own them all, or even know who is helping it.

The XP definition of 3rd party code

Continuing along the train of thought from my previous post, I came up with this rather extreme definition of 3rd party code:

3rd party code is any code on a different release cycle to the system under development.

This definition covers everything from 3rd party binaries, code developed by other in-house teams, the operating system, and your database schema.

Third party code considered harmful

Most systems are not built from scratch. Most will use third party libraries, either commercial products or open source utilities.

A good example of this in the Java world is log4J – many projects use it for their logging requirements, and its a good tool. However what most projects will do is use it directly, which means that virtually every class in the system will have a dependency on log4J. If a need arises that log4J can’t handle, or a new version is released that changes some behaviour your project depends on, it can be a huge job to go through all your code making changes.

A useful approach is to wrap all access to 3rd party code yourself, thus giving you a single point of contact between your system’s code and the external library. This wrapper is also a useful place to put any extension functionality that your system needs.

Webtrends

Seeing lots of signs that dotcom bubble 2.0 might be on the way. Lots of people putting together ruby on rails based sites that all seem to be dedicated to finding new ways of helping people publicise things we used to write in private diaries.

Me. I’m going straight to the front of the curve, stepping right past ruby on rails, to seaside on smalltalk.

Registry Rant

The Windows Registry.

Lets make a giant file that every application dumps all its data into!
Lets make the operating system use it as well so a misbehaving application can wreck your whole system!
Lets key everything with a GUID so nobody has a damn clue what anything is!
And lets categorize it so that every application has to sprinkle its data into 10 different places!

Windows Registry, I want the last 3 hours of my life back.

Compile Time Outmoded

Much is made of the ability of statically typed languages to catch certain types of mistake at compile time instead of having things fail at runtime. If I try and write a call to a method that doesn’t exist, the compiler will tell me and refuse to compile my code. This is often held up as an advantage over dynamically typed languages such as Ruby or Smalltalk, which will fail at runtime if I mistype the name of a method I want to call.

It turns out that the lack of compile time checking is nowhere near as much of an issue as common sense wants to tell you it is. One of the reasons for this is that dynamically typed languages are usually interpreted (or pseudo-interpreted) in the sense that there is no manual compilation step. What this means is that if while developing I get an unexpected ‘Object doesNotUnderstand: someMethad’ (in Smalltalk), its the work of a moment to go and correct the typo in the calling code.

It gets more interesting when you get errors that aren’t caught by the compiler (eg. calling a method on a null reference). In Java or C# the defect is already ossified in the compiled bytecode, and to fix it I have to change the source and recompile it plus everything that depends on it. On a big project this can be a time consuming process. On the other hand, in Smalltalk the error would be ‘UndefinedObject doesNotUnderstand:someMethod’. And it would be as easy to correct as the mispelled method name from the previous example.

Seems to me that compile time checking is only important when you have the inconvenience of compile time in the first place.

Code Generation

Is code generation a sign that you are missing a layer of abstraction?

This doesn’t feel like a new thought, so I may have read it somewhere, or possibly even blogged it.

It seems to me that code generation is most often seen in statically typed languages such as java, and even then could conceivably be alternatively implemented with an additional layer of abstraction that expressed the intent of the generated code at a higher level.

Crypto Cash

Just completed ‘Crypto’ by Steven Levy. Excellent book, very accessible account of the development of public-key cryptography and all the security stuff we take for granted.

Made me think though, as I filled in my credit card details on yet another e-commerce site: why do I need to hand out my credit card details to every site I want to buy stuff from? The technology for digital cash already exists and is well understood by the crypto community. It is technically feasible for a customer (me) to visit a trusted site (eg. my credit card provider), and request a secure token that represents a sum of money equal or greater to the amount I want to spend, and hand that over to the merchant. The token is digitally signed to verify its authenticity and value. The transaction can then take place with the merchant needing no credit card information, or even personal details (although a delivery address might be useful). Opportunities for fraud would be limited to (a) the amount the token is good for, and (b) a window of time before the merchant has handed it to the credit card company, at which point it is tagged as ‘used’ and worthless. Used tokens could be posted on a website for all the good they would do fraudsters, so high profile cases of hackers downloading a database full of credit card numbers would be a thing of the past.

Of course, there is the one extra step of having to obtain the token first, which is a tiny inconvience, and therefore far less preferable than having your credit card number stolen, which usually involves no effort whatsoever.