One of the most common questions in teaching and coaching agile processes to groups is:
“How do we design our software while delivering iterations of potentially shippable product increments?”
Scrum, an agile process that I teach about and coach organizations on implementation of, asks that each Sprint, analogous to an iteration, delivers a potentially shippable product increment. There is emphasis on potentially shippable since it is quite common to have releases that involve running multiple Sprints until there is enough value for your users. I usually describe potentially shippable product increment is that the software is of a quality that a releasable version would include. This means that each Product Backlog item that is implemented during the Sprint is tested, coded, integrated, documented, and verified. Scrum teams gain a better understanding of what deliverables are necessary to make this happen by creating a Definition of Done.
When I ask what design decisions are difficult in the Scrum process to deliver it usually revolves around high level architecture decisions or data modeling. There are other specific design areas that get brought up but lets focus on these for now. In order to help a Scrum team understand from a conceptual point of view how incremental design works across a release of their software product I use a diagram that I believe Mike Cohn created. Here is my interpretation of the diagram:
This diagram attempts to describe how in new software product development efforts more emphasis in early Sprints is put into implementation of architecture elements. As the architecture is more fully defined and implemented in later Sprints emphasis is increasingly put into feature development. In the final Sprint of a release there may be little to no architecture implementation left to do. This diagram demonstrates the expectations of early release deliverables in terms of technical architecture implementation to support feature delivery. It also shows that each Sprint in the release should deliver features that a user can review.
In a software product team that delivers more than one release may have less architecture emphasis in early Sprints of following releases. This is shown in a modified version of the diagram below:
After describing the above diagrams to a developer named David Wright he approached me to validate his understanding. Within 10 minutes of my description of incremental architecture he had developed a new diagram perspective which I thought was brilliant. His diagram involved two axis with the x-axis representing the surface visible to users and the y-axis representing depth of the architecture. In Sprint 1 of a multiple Sprint release a portion of both the surface and architecture depth are realized. The figure below is a visual representation of the portions implemented of a fully releasable product version. The dark blue areas of the grid show implementation of the surface and depth in Sprint 1 while the empty grid elements represent what has not been implemented yet.
As a release progresses the amount of surface visible features and architectural depth implemented is incrementally built upon towards a fully releasable product version. The following diagram shows the incremental architecture progress later in the release cycle.
The adoption of an incremental architecture approach comes with a couple of potential issues:
- Less up front design of the overall release architecture is known at the beginning and while the depth of the architecture is still being implemented
- New knowledge may impact existing implementation of architecture elements
In order to manage these types of issues we must implement disciplined practices to allow our architecture to accept change as we gain more knowledge. This is why the Extreme Programming practices such as Test-Driven Design (TDD), Continuous Integration (CI), Pair Programming (or continuous code review), and Refactoring have become so common on Scrum teams. TDD gives our design an executable way to prove we have not broken existing functionality at the component and functional level. This does not negate the need for exploratory testing by a person but it will keep manual testing to a manageable level. CI automatically runs builds, automated tests, and deployment of our application then provides feedback to the team about the current state of the integrated system. Pair Programming increases knowledge transfer across the team and provides coherent communication of the products domain into the tests, code, and support artifacts. And finally, refactoring is defined by the guy who wrote the book on it, Martin Fowler, as:
“a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior”
Refactoring is best support by a high automated test coverage that allows a team to know when the external behavior has not been changed in response to changes deep in the architecture. Here is a visual representation of architectural elements, in red, which could be refactored in response to a new feature.
Each of the refactorings may be small changes but lead to larger positive impact over the span of a release. Effective use of refactoring keeps our architecture flexible and therefore able to meet evolving business needs.
I have used David Wright’s model to describe incremental architecture to other clients in conjunction with the original diagram from Mike Cohn. It has helped provide a clearer picture of incremental design and how to incorporate it into their real world projects. With David’s permission I named it the “Wright Model” and will continue to use it in the future. Thank you, David.
Big design up front (BDUF) is based on the thought that we can lock down business requirements and design our software right the first time. The problem is that business needs change almost as soon as the requirement has been developed. Not only do they change but the functionality requested is better understood once a user touches the feature and provides their feedback. Incremental design of a system throughout a release allows us to incorporate this feedback and change our architecture to satisfy the user’s needs.