“Sufficient Architecture? What does that mean?!”, I hear you say!! Bear with me.
Over a beer this week I had a good conversation with a colleague about the principles of architecture and design, and as a result I feel compelled to recount something that I have tried to adhere to for a long time. I know some people will disagree with what I’m saying, so if that’s you, shout up and let me know your thoughts.
When designing a new system I always have two principles in mind (and I’ll probably use the term “design” to refer to both Architecture and Design throughout this post, as it applies to both);
1. Design and Build only what you need today.
2. Design knowing that you’ll need something else tomorrow.
Let me elaborate a little.
Design and Build only what you need today
What I mean by this is that you should not try and anticipate the future. You shouldn’t add methods to classes “because in the future I might need to X”, and you shouldn’t complicate your architecture if there’s no need.
A good example that I discussed with a colleague is adding a Service Layer to an application; perhaps putting all business logic behind web services, and calling those from ASP.NET. I firmly believe you should add a Service Layer if you have good reasons for having one. If you need to scale out components separately, or perform asynchronous processing, or there are hosting prerequisites, or you have other applications that need to communicate with your application, etc – go ahead and add one.
However, if at this point you don’t have any good reason – don’t add one!! If you think an application might need to communicate with yours in the future, remember it is only that – “might”. You cannot anticipate accurately what it might need – you’d get contracts and message exchange patterns wrong, you’d be increasing the attackable surface area of your application, and you’d be complicating your development, maintenance, and deployment.
You should always build to meet the requirements.
What I don’t mean is that you should make your application rubbish – for example, having an application with a good User Experience should always be a requirement. But having one that enables the user to change the layout of your pages – that might or might not be a requirement. If it isn’t a requirement, don’t spend extra time designing and building it.
If you’re convinced that something should be done but it isn’t a requirement, you need to revisit your requirements (a great example of this is instrumentation – so often missed from non-functional requirements!). If you don’t revisit the requirements, you (the techie) are making up your own requirements, and that becomes very dangerous territory.
Design knowing that you’ll need something else tomorrow
The problem with only building what you need today is that we all know systems change and evolve, need maintaining, upgrading, or fixing. Building only what you need today compliments this though – as I’m sure regular readers know I firmly believe simplicity is something you should strive for in all your systems. It keeps learning curves shallow, and therefore helps keep maintenance and enhancement costs down. Building only what you need helps keep your application simple.
But we must also acknowledge that we know your system is probably going to change. This means you need to consider good architectural and design practices, use well known successful patterns (for example a UI pattern like MVP or MVC), write automated tests to validate your code (both now and when you’re enhancing it later, as they then become great regression tests), use clear naming conventions, ensure you can monitor your system, appropriately componentise the code, and so on.
When you design the API for your application, ask yourself something – “if in 5 years time someone comes to change this, will they understand what my code is doing?”.
Designing your application well means that if we need to add a Service Layer in the future (or perhaps just expose a small part of your logic for another application) the task of estimating, designing, and building these changes is not as complex as it could have been, and it is entirely appropriate that the effort is expended on doing this once you know you need to.
The argument against
What I am also not saying is “build applications as quickly as possible”, or “just databind a data grid directly to your database”. Please don’t just build a bad application, say “it meets requirements”, and blame me! J The term Rapid Application Development scares the life out of me – and I’m certainly not aiming at that! This is why the second principle exists. Your non-functional requirements should describe the need for the system to be maintainable, scalable, supportable, etc – and we as developers and architects know this means following good practices.
So what do you think?
The small print: Do remember that the examples in this post are primarily targeted at a single system, living in a fairly isolated world. In particular, my comments about Service Layers could be misinterpreted if you’re building an application that is part of an Enterprise’s Service Oriented Architecture – but of course you should have requirements that dictate how it should participate in the SOA, and what systems must integrate with your new application, so the principles hold true.