How software architecture can support agility
Software architecture and design has a major impact on success or failure of software projects. How can a good architecture be classified? Which are the architectural key features that decide if a project succeeds or fails? How can architecture support an agile development process such as Scrum?
This post explores attributes of software designs that are required by agile development processes. Furthermore it discusses the differences between classical big up-front designs and the agile way of doing it.
What is software architecture?
The architecture is the sum of all critical design decisions. This includes business (e.g. cost of change), technical (e.g. infrastructure) , software architecture and so on. Complex designs are likely to reduce the ability to evaluate those design decisions. It is important for the team as well as stakeholders that they understand the importance of design decisions. For example building a web application is a different matter than building a smart client or classical client server application. There are certain implications which come with this initial design decision:
- it effects further design decisions
- it effects the team structure
- it effects the GUI
- it reflects the general system design (e.g. platform limitations)
A good architecture reduces the amount of critical design decisions that must be made throughout the day-to-day development work. This means the locality of decisions is higher and people are less afraid to take decisions with small impacts. It is important that design decisions that have the biggest effect on the system under design are taken up-front.
What makes development agile?
The agile manifesto describes the aspects of agility. What does this mean for the development process?
- Sustainability of process and code
- Feedback at different levels of scale
- Awareness of what is being built and how
- The engagement of people in the process
What implications on the software design can be derived from that?
- Extensibility (refers to sustainability of process and code)
- Maintainability (refers to sustainability of process and code)
- Testability (refers to sustainability of process and code)
- The design should improve communication within the team and with business users (refers to feedback)
- Comprehensive to everyone (refers to the what and how)
- Include team in the evolution of the architecture (refers to engagement)
Big Up-Front Design vs No Up-Front Design vs Rough Up-Front Design
The Big Up-Front Design is common for classical approaches such as Waterfall. The problem here is that the planning phase very often exceeds the foreseen time because the extend of detail is too high. It also comes with a lack of flexibility, extensibility and adaptability. Change means re-planning. So the question rises why should a plan be in detail when it will become out of date when the first change occurs.
A common prejudice about agile development methods is that there is no up-front design. There are cases where no up-front design is possible. If all members have a deep inside in the domain and already a sound knowledge of it as well as the technical expertise then it is possible to do it. An example would be that a team rebuilds an existing system from the scratch and since they have already build the first version they won't fall for the same traps etc.
In general it makes sense to have an iteration/sprint before starting the project to do rough (short) up-front design. There fundamental design decision can be taken, such as:
- Platform
- GUI concepts
- Which data storage is to be used?
- etc.
This should short but not too short. Try to document the outcome in an agile way. This means the outcome should not be a massive document, instead it should be code in the form of proof of concepts and such. This also makes it easier for the team and also the stakeholders to visualize the ideas. It is also important to involve business experts and existing knowledge in this process. Delaying design decisions, does not mean ignoring existing knowledge that can help to foresee problems.
Evolutionary Design
During each iteration the software architecture is communicated to the stakeholders and the team is constantly working on it. If design flaws are discovered the design is updated to reflect thew newly discovered needs.
How could an architecture that supports the agile development process look like?
Most softwares now-a-days are using a n-tier architecture (a layered architecture). Instead of building layer by layer, in an agile process vertical slices of the whole application is built in each iteration. In order to be able to do that the architecture needs to support it.
To implement such a process it makes sense to combine ideas from different approaches such as Domain-Driven-Design and Component-Orientated Designs:
- Communication: DDD helps us to initiate a creative collaboration between developers and business experts while it encapsulates business logic into a model. DDD tries to abstract the model from any persistence technology and improves communication by developing an ubiquitous language (UL).
- Maintainability: Can be achieved through encapsulation and loosely coupling. The domain model could be defined in a bounded context of a components. Using Inversion of Control and Dependency Injection.
- Reusability: Creating generic components and modules.
- Composition: Different components and modules can be composed to create other components or features.
- Modularity: Try to created different logical and physical modules which can be developed independent from each other
- Testability: Can be achieved through encapsulation and loosely coupling. Use Test-Driven Design, Behavior-Driven Design, Version Control and Continuous integration to span a safety-net for refactoring which needs to be done when changing the model.
- Loose Coupling: makes it easier to apply changes and helps to improve the quality of tests. Single implementations of different components can be exchanged easily.