Wednesday, August 20, 2008

Balancing “YAGNI” with “avoiding the cul-de-sac”

This is a tough part of the architect’s job because it involves speculation. It would be easier if we had a crystal ball to peer into, but we don’t. All we have to go on is our instinct based on past experiences.

Let’s look at one end of the spectrum – “Avoiding the cul-de-sac”. You may have been burnt in the past due to significant amount of rework required as requirements changed or new requirements surfaced during the middle of a project. The common knee-jerk reaction is to make everything flexible, configurable and adaptable. However, like most engineering endeavors there are always trade-offs to be made. Be careful, you may have ended up with un-necessary complexity (which drives up the cost of the project).

Let’s look at the other end of the spectrum – You Ain’t Gonna Need It. With this approach, you eschew flexibility, configurability and adaptability until a requirement surfaces that demands it. This approach is a gamble, but the agile folks will tell you that this is ok because of continuous refactoring and unit tests.

So what is the architect to do? Well, it depends. You have to look at the sub-systems of the architecture and run through some what-if scenarios. To prioritize, I would focus on the sub-systems that have external dependencies. Wherever you have external dependencies, you have given up control. Anything could happen to the external dependency and you have no control over it. The vendor or organization that owns it could a) go out of business b) change their licensing model c) raise their prices d) break backwards compatibility e) discontinue support f) fail to meet performance SLAs. The architect is responsible for addressing these risks in such a way that if any of these events would happen, the impact is contained.

The single most effective way of containing impact is to effectively manage the degrees of coupling within the system. A Formula 1 team can change the wheel in under 10s because the wheel component is loosely (yet securely) coupled to the car. How long would it take to switch your system from say Oracle to SQL Server?

Where couplings between components are legitimate, there are several coding techniques and (albeit very similar) design patterns you can use to allow for independent evolution of the components yielding contained impact in the event of change. On the coding side, coupling to an interface rather than implementation is a safe bet – thus allowing for different implementations to be plugged in later. On the design front, the strategy, provider and adaptor patterns all help to introduce flexibility into the architecture. For example, the Java Cryptography Extensions (JCE) is a great example of the provider pattern. Initially, I may use a software based provider that performs cryptographic services – but I may upgrade to a hardware based provider (HSM) for when the time comes when a performance boost is required – all without having to change any code. A more common example is the JDBC architecture, where drivers can be plugged in to connect the application to a different database product for its persistence needs.

A goal of the architecture is therefore to provide flexibility without disruption where it makes sense.

0 comments: