- Plan using Risk and Cost Based Architecture for evolution
- Prepare a continuous integration approach to facilitate evolutionary architecture
- Define architecture fitness functions and map them across the system
- Track execution using monitors and feedback mechanisms to enable team actions
- Several software tools and dashboards exist that can help plan, monitor, and validate your architecture as it evolves
Traditionally, software architecture and design phases have been considered as initial phases. In this approach, the architecture decisions were considered valid for the entire life of the system. With the wisdom of ages and in reaction to industry transformations, we have started to see architecture as evolving. This evolution necessitates a different set of approaches in the direction of continuous planning, facilitating via continuous integration, dashboards, and tools, thus providing guide rails for systems to evolve. This article focuses on these approaches and tools to support the journey.
We are in the midst of a rapidly changing environment. As Rebecca Parsons discussed in a presentation on evolutionary architecture, the changes span across business models, requirements, and customer expectations. The technology landscape also changes quite often. In a broader sense, the changes are happening at an unparalleled rate and impact on our environment.
For example, let’s look at technology—it changes fast and also reaches consumers faster than ever. Automotive design times are shrinking from 60 months a few years back to only 24 months now. Smartphones reached major penetration in the last 10 years. Software, a key ingredient of all these, changes even faster. Sometimes, the software frameworks we use are no longer relevant by the time of release.
I came across a situation when my colleague mentioned videogular, a library available with Angular version 8. While building an application in Angular version 10, I noticed the old library was no longer supported. This meant I needed to use a new library, ngx-videogular. I am sure you will have your own examples.
In this constant flux, as architects and technical leaders, we are posed with the challenge of making architecture decisions and ensuring these principles are followed and the system doesn’t deteriorate over time. Like all things continuous, evolutionary architecture comes to play in this context.
As described in the book Building Evolutionary Architectures, an evolutionary architecture supports guided incremental change across multiple dimensions. Like how Martin Fowler states in the foreword, the vision of architecture as something carved in stone to be defined and followed was challenged by agile methods. In response to agile methods, architecture practices showed signs of change.
As Eoin Woods puts it in IEEE Computer, “a fairly recent evolution is
- Architects acting less as upfront structure designers and more as overseers of a stream of informed, significant decisions made just in time
- Architects deals with more probability than certainty
- Large Systems Policy-Driven Automation
- Architecture is still very much art of possible—financial constraints like cloud pricing in consideration
- Radical intelligence, Dynamic Components, Cloud Platform Deployment, Connection to things in the mainstream”
The response also stems from the realization that software systems can change with time, including changes to the core or foundational elements. By enabling evolution—like in living beings—these systems can have a longer life. The architect is driven by this value which by far outweighs the challenges. Similar changes were observed when agile methods picked up. From the traditional approach of architects coming into the picture during the early stages, instead of arriving later, for integration and acceptance. As experts and leaders, it is inevitable we assist teams to navigate the wave of evolution smoothly. It is a given that we need to spread architecture knowledge and create a culture of action, leading by example. You might notice many companies no longer have designated architects—instead, senior engineers in the team play the role in a more distributed fashion.
Agile as a premise of evolution
Agile approaches follow an interactive approach or shorter sprint lifecycles where each iteration involves phases from requirements, design, construction, integration, and acceptance. Let’s look at a little detail into the iterations.
In a traditional approach, the depth of involvement of architects used to follow the curve in the first graph. In an iterative approach, each iteration squeezes in all phases. This iterative approach is a great facilitator of evolution since it enables big requirements to be broken down into smaller user stories. Moreover, continuous delivery enabled a certain guide rail for evolutionary architecture.
As we delve into the details of this picture, we realize the smaller changes mean a lot of consideration of planning, integration, and acceptance be broken into smaller chunks. In another way, this would mean architecture decisions also need to be broken into smaller chunks. So, it looks like we have let loose the devil by letting evolution happen! But how do we deal with this change? Our primary responsibility is making and guiding technical decisions. Does this change my role as an architect?
It is often mentioned that the best employees redefine their roles. Yes, with a growth mindset, we need to lead the change!
Now let us delve a little deeper. Unlike civil engineering, where you can’t change the foundations later, it is now a known fact that even databases can evolve by refactoring methods like managed migrations. However, software becomes harder to change over time. If we see architecture and design as a navigation guidance system, like a map as described by Simon Brown, we should be able to distribute the guide points on the map. Evolvability, the new ability, has an impact on many other architecture quality attributes.
All systems that sustain and thrive are characterized by certain guidelines. For example, railways are guided by the rails and the signaling system. Similarly, traffic management systems have support for navigation, with direction indicators. By considering all stakeholders, a traffic control dashboard enables wardens to take necessary action.
Similarly, we need to build a support system that enables evolution, with guide rails, indicators, and dashboards. In architecture parlance, this is often termed governance. But unlike earlier, these systems also depict the changing environment, the impacts on the system, and whether governance is effective. Systems like Chaos Monkey for instance goes one step further kicking out the ones who fall behind the benchmarks.
Guidance Systems for Software
Now that we agree that change is inevitable and that we understand the need for guide rails, let us look at the execution details. How do we plan such a change? How do we govern changes? Where should we deploy these? What tools might come in handy?
Software ecosystems consist of tools, frameworks, libraries, best practices, and teams. The programming platforms we use are generally guided by transitions in terms of Application Programming Interfaces (APIs). The new guidance principle, reactive manifesto focuses on responsive, resilient, elastic, and message driven as key directions.
Evolvability requires enabling incremental, guided change across multiple dimensions, with APIs defining the axes. From a governance standpoint, evolutionary architecture suggests fitness functions as a way to provide a continuous guidance system.
What are Fitness Functions?
Fitness functions provide the basis for governance. An evolutionary computing fitness function is a particular type of objective function that is used to summarize how well a design solution fares against its objectives. An architectural fitness function provides an assessment of some architectural characteristic(s). These functions need to be distributed across the system to assess the system characteristics and their evolution. System-wide fitness functions are nothing but a combination of the individual fitness functions which include Architecture Metrics, Integration Tests, Monitors, Process Metrics, Contract/Interface Tests, and Unit Tests. We can spread this across the three aspects of:
Let’s look at Planning. A domain model diagram like Object Process Diagram (OPM) is a good starting point. Such a visualization enables us to bring clarity to the scope and gain insights into external and internal interfaces. This enables us to go forward on some early decisions, like an initial architecture vision and two levels of decomposition.
With a basic decomposition, we can plan a roadmap considering the interfaces and components on a sprint-by-sprint basis. From the decomposition, we could also capture the key elements of a minimum viable solution. This understanding enables us to identify which elements are risky and turn out to be expensive if changed later.
In an agile world, one of the best approaches is to follow the Risk and Cost Based Architecture (RCDA). As per this approach, Risk and Cost are the factors that help us identify the significance of each user story or feature. The approach also facilitates a common language with managers. The user stories need to maintain a balance between architecture user stories in addition to requirement driven ones.
Here is an example of such a roadmap from a bids-and-proposal management solution. As you might notice, we have selected to start with a chain of software elements that are risky and expensive to change later. We have also considered testability.
The performance of calculations plays a key role. From a risk assessment standpoint, calculations being slower than expected reigns high. Therefore this is considered a major milestone. To perform a meaningful calculation, tender details and proposal details are necessary. Hence they are considered enablers. Based on this approach of balancing the features and enablers we have planned the first sprints concluding in the calculation. At the end of sprint 3, we might identify calculations that need improvement. This is the premise of a consolidation sprint, where we try to stabilize and make sure evolution is in control.
Similarly, when we deal with external interface changes, we need to make sure it is supported in the next immediate sprint. Once all consumers have started using the new interface, seamlessly eliminate the old one. This is where APIs play a major role. Likewise, in case we change a database table, refactor carefully without disturbing the working system, and like a balloon, inflate it step by step.
Even though we might not be following a microservice approach, we have found it beneficial to follow the principles of the reactive services, like following no shared data, and use message queues to share data. An example using a hexagon with two different services using .NET and Python Flask approaches is shown here. This also allows us to mix technologies without disturbing growth.
While in integration, it is key to implement checkpoints like integration and test pipelines. These checkpoints, which are a key element of fitness functions are implemented as a combination of unit tests, integration tests, interface, or contract level tests chained together. Breaking one beyond tolerance levels would mean the integration will stop there and flag red alerts in dashboards. These red alerts trigger the team to take immediate action. An example mapping the fitness functions to enable built-in quality is presented.
At execution, we move closer to the production environment. Even though it is good practice to keep development and production environments the same, in many cases, there might be differences. As part of the execution, we create monitors including health checks for diagnostics or logs. Often, telemetry logs are available in different forms. Analyzing them helps us get deep insights into the functioning of the software, for instance, the most used features and the most failure-prone areas. Most services now provide some health checks which could be analyzed using tools including google analytics.
We might require integrating multiple tools, including planning tools like Jira, testing frameworks including Selenium, and Robot framework integration—dashboards coming out of Jenkins and wikis. These are chained together as a pipeline to integrate a certain level of acceptance tests. It is important also to understand the fact that the dashboards aren’t just for visibility but for agile teams to check on a daily basis. A major deviation from the guidelines would mean the team focuses on getting it right by dropping everything else in hand and resolving the issue. More than all the instrumentation to support the evolution, the cultural aspects play a major role. Everyone in the team needs to realize that the impact of ignoring the guidance system would mean a total loss of evolutionary capability.
The ideal approach would include a dashboard and logs that allow us to see the big picture and dig deeper when required. Certain tools like Structure 101 or Sonar allow some aspects of architecture dependency analysis. As architects, we should also have a measurement framework that guides decisions. An example representation involves external interfaces with zero tolerance permitted. In the case of technical decisions, internal interfaces, and frameworks, some tolerance is permitted to enable flexibility.
It is a known fact that testing is one single element that can provide major inputs to the quality. One major observation is that the architects or “leads” play significant roles in testing. They need to guide the test-driven approach and evaluate the fitness functions continuously. Often, managers may not place significant value on integration tests. In such cases, we have found it beneficial to involve interns or new team members participating in building integration tests. This is a method that enables us to facilitate these team members to adopt the culture.
An advanced approach would be to connect test failures into the dashboard. A root cause analysis could be integrated by following a fishbone analysis. With all the infrastructure pieces around, still, the significance of a team with a bias for action can’t be underestimated.
Evolutionary architecture is found as a major element of the continuous software engineering journey. To facilitate evolutionary architecture, we need to place fitness functions across the phases of the journey. An even distribution of all these functions across the different aspects of planning, integration/deployment, and execution is key to governing changes while we evolve. The chain could be guided by Risk and Cost based Architecture (RCDA). A dashboard combining all this and the critical visualization it provides, coupled with a culture based on the bias for action is fundamental.
- Klaus Schwab, The Fourth Industrial Revolution.
- Jan Bosch, Speed, Data, and Ecosystems—Excelling in a Software Driven World.
- Neal Ford, Rebecca Parsons, and Patrick Kua, Building Evolutionary Architectures.
- Eoin Woods, “Software Architecture in a Changing World,” IEEE Software Nov/Dec 2016.
- Eltjo Poort, Hans van Vliet, “RCDA: Architecting as a Risk and Cost Management Discipline,” Journal of Systems and Software, May 2012.
- Nick Rozanski and Eóin Woods, Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives.
- Essential Safe
- Simon Brown, “Coding the Architecture”
About the Author
Abhilash Gopalakrishnan has over 20 years of experience in building software systems and emerging technology initiatives. He loves working at the intersection of research, technology, and business. An ardent futurist, he enjoys the architect elevator while staying hands-on. Learning, applying, and sharing knowledge is his passion. He holds a Masters in Software Systems from Birla Institute of Technology and Science, Pilani, and Architecture and Systems Engineering from MIT. He is a Senior Member of IEEE, a member of ACM, and INCOSE.