Here is a riddle for you: What is very strong and solid so as to be hard to move, yet can move easily at the same time? The answer: a champion sumo wrestler. The other answer: well-thought-out application architecture.
Why are we talking about 400-plus-pound Japanese athletes in the context of agile software development? Let me explain. In order to be successful in the ring, a sumo wrestler needs to maintain a heavy body weight and at the same time be in peak physical condition. Just as these Japanese athletes have to find the right balance through a well thought-out combination of diet and training regimen, software development organizations need a balanced approach to application architecture on agile projects.
System Design: The Winning Technique
Proponents of agile development oppose pursuing a thoroughly worked-out architecture in advance (the so-called “Big Design Up Front,” or BDUF) as a feature of the traditional “waterfall” approach, the paradigm that agile was essentially created to challenge and overturn. In waterfall, the design phase of a software system follows the development of functional specifications and precedes coding. The Agile Manifesto opposes this approach and implies that self-organized teams are responsible for creating the best system design through a series of incremental steps. As the system evolves iteratively, the architecture, in turn, matures gradually throughout the development cycle. Over time, the team members’ knowledge of the business and the technology grows, and they continually review and refactor the architecture. Because in most real-world situations the customers’ idea of what they want from the system will change over time in response to changing market conditions and their own evolved understanding, this process serves the goal of giving customers the software they really want rather than a simply being a masterpiece of elegant, up-front design with insufficient business value.
This approach seems reasonable in that it just doesn’t make much sense to invest too heavily in architecting for system behavior that can change significantly over the life of an application. Moreover, doing so is likely to give developers significant grief as they try to preserve the original design and simultaneously cope with evolving requirements. In fact, it can result in so many complex workarounds that the code may eventually become too convoluted to understand, even for the developers who wrote it.
On the other hand, if absolutely no high-level architectural decisions are made at the start, you run the risk of making the code so complicated that it will be almost impossible to maintain and extend. This would be an acceptable approach if all you want to do is whip up something relatively simple and then throw it away (e.g., a prototype or proof of concept), but attempting to build an actual shippable product this way would be a bad idea.
As an example, consider a client who wants a prototype of a web shop with a simple product database, а homepage, product pages, shopping cart, plus integrations with a payment server and a shipping service. You could implement all of that in, say, a couple of weeks as ASPX code-behind files, without being concerned about such things as presentation logic or data separation and without comprehensive testing (writing tests will be particularly challenging in this case).
After your team finishes all the workarounds and patches, you will have a prototype that can be demoed to the customer, and at this point the temptation to continue to build on top of that codebase instead of discarding the prototype and starting over may be great; after all, you have just spent time and money building the thing, and it seems to work fine! However, that would be a recipe for disaster. As soon as you start adding new features like suggested products, user-defined search filters, product reviews, etc., the numbers of similar database queries will balloon, and you will need to replicate the logic in multiple pages as well as make numerous changes to the code in many places all at once. This will lead to more defects, the entire application will have to be re-tested, and the cost of subsequent changes will continue to go up, thus completely defeating the initial purpose.