Monday, 13 June 2011

Strategy Pattern

I thought I would share in this post my thoughts on a design pattern that has changed the way I write code. The beauty is in the simplicity of this pattern. It's easy to implement and doesn't unnecessarily complicate the problem domain, in fact it simplifies it and leads you gently towards the wonderful world of Test Driven Development(TDD). The pattern is the strategy pattern.

The Strategy Pattern is also known as "Constructor injection" (or just called a "plug-ins" by those that haven't read Design Patterns).

The strategy pattern is taken to the next level by the Dependency Injection Pattern and can be implemented programmatically (or declaratively) using an IoC container. IoC (Inversion of Control) containers are powerful in the sense that all the services in your application that have access to the container have "access" to all the services that have subscribed to the container. These patterns also facilitate ... and make it easier to write tests for the services in your application by relying heavily on Interfaces.

How Dependency Injection is "abused":
The problem is that your code is no longer self documenting. You are never sure just by looking at methods where services are extracted out of the container which service they will receive from the container. This makes your code feel a little like "black magic". Extracting services from a container is also more of a performance hit than "wiring" up your services programmatically.

TDD (Test Driven Development):
This concept is about writing a programmatic test for a method/function call to ensure that the expected result is returned from the provided parameters, be it an exception, or a physical data value. Unit tests also allow for behavioural testing by recording the inner service calls expected using a Mocking Framework such as Rhino Mocks.

This can be extremely useful if you have a deep framework with multiple layers of functionality where a change in one area can have a ripple effect on other areas.

Misconceptions, and mistakes developers make with regards to TDD:
1. Writing/generating unit tests that test every single property of every object in the System. This is a waist of time and causes code bloat.
2. Unit tests are generated/written for the System AFTER the application is has been completed. This is useful, although only from a "white box" testing perspective.

The key ideas to keep in mind are:
1. What are the root or core features of my application that I need to have unit tests for. These services will normally contain the more complex code.
2. Unit tests are more useful if they are written BEFORE the system has been built. This will facilitate the design of your services and give you a deeper insight into their future extensibility requirements.
3. The unit tests serve as "specifications" for future developers that would like to use your libraries. The unit tests also provide insight into the behaviour of the API's your libraries expose.

TDD should be used to drive out the flow and design of the system you are working on.