What architecture do we need?
The architecture of a system has a major impact on development of the system. Depending on the system to develop and conditions, a direction will be chosen usually as a result of trade-off decisions. Unfortunately, many times there is no perfect solution where we can have it all…
Examples of conditions driving architecture direction
- Market predictability, expectations
- Market position/competition/ambitions
- Quantity: Special, series, mass
- Development phase vs market phase
- Solution context (interfaces, tightness)
- Technology constraints
- Technology newness, disruptiveness, need to learn
- Safety risks, compliance
- Integration (cost, frequency)
- Dependency on 3rd party suppliers
Depending on what the trade-off looks like, here are some things architecture can help with:
In an environment where time to market and responsiveness are vital, an architecture should pursuit an architecture that supports this. And, in a world where things change a lot, we can’t do this once but have to regularly revisit and refactor.
What else drives an agile architecture?
Part of it has to do with the way we split up the system and how we define the interactions between those parts. Another part has to do with the process, mindset/culture to deal with changes at different levels of the system.
Conway’s Law says “organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.” Driven by an efficiency mindset, many companies, as they grow, split up into departments and groups based on disciplines and system layers. This in turn drives organizations to architecture and design systems split up by those same disciplines and layers. The organizational split-ups cause dependencies, hand-offs and local optimization which lead to delays, lower quality, higher risks, more variability, disengagement, demotivation, etc. In a similar way, the mimicked architecture, leads to lower performance, lower quality, higher risks. In short, it hinders our ability for speed and responsiveness.
The answer is to collect all needed for a specific function or set of functions, or set of components, and combine them into a module. The system will then be made up of interconnected modules which look more like a network or holacracy and less like a hierarchy. Modules in a system can vary largely, some can be hardware only where others are a mix of hardware/software, etc. As the modules are not all the same, so will the teams building them.
Following Conway’s law, this would apply to both the system to be developed as the organization developing it.
So, when we want to shift towards an agile architecture, the organization will have to change with it. This can be done in small steps (Kaizen), but every now and then something needs to give and more radical steps are needed (Kaikuka). Sometimes however, even this won’t do and transformational or disruptive steps are needed (Kakushin) which follow different rules all together as described by Clayton M. Christensen in his theory on Disruptive Innovation.
Modules can vary in size from large tightly coupled monoliths to tiny integrated components like nanobots, or something in between and a mix of it. It depends on conditions and needs what function or set of functions, or set components should be combined into a module. In short, we need to look at different stakeholder needs like Design for Excellence (DfX) does. Some examples:
- a component that needs to be replaced/upgraded often or move freely
- a component/service that we want to sell separately
- Functions combined to provide high local performance (e.g. graphical card)
- To be able to install a large part (weight, size)
- A module to be reused
Some examples of modular architecture:
The modularity approach has impact on the trade-off aspects, see below.
A warning is in place when using modularity. Whenever we bring structure to something, we need to be aware that we reduce complexity which brings good things but has a price (reduces options for emergence). Also, splitting up into modules (in combination with decentralization) has several risks that have to be guarded: local optimization, unintended overall system behavior, non-functional requirements that cross multiple modules, slowest integration determines system integration.
Without connections between parts, no system, no value. Interfaces are the gateways (information, power, force, etc.), constrain design, and have a major impact on system performance and reliability. To enable fast iterations, we need stable interfaces (loose coupling) so we can limit the impact of changes and need for testing everything and be able to focus. This is even more important when working with multiple teams by having each team working on their own module. Some other important aspects of managing an interface are:
- Definition – Make sure you understand and map all interactions for the interface. Depending on the circumstances, this can be done intentional or emergent.
- Single point of control – Interfaces connect at least 2 parts but often more. It is vital to have a single point of control. One person to own the interface, one location/document where its definition can be found, one revision management.
- Process – Have a mechanism for stabilizing/freezing which can be a delicate process (there’s always something to be added, like closing the door at 5 pm). Have a mechanism for going to a new interface version. Depending on the circumstances you may need different ones like big bang, (temporarily) support both versions, per sub-system, etc.
- NFR – Make sure it is clear who is responsible for important Non-Functional Requirements (NFR’s) like weight, capacity, noise.
- Flexibility – Allow margin for changes and variation (overdesign). obtain loose coupling where possible to limit impact of a change.
Intentional vs Emergent
The traditional ‘big plan upfront’ approach had it drawbacks but certainly also some advantages. The same can be said about the ’emergent’ approach. Circumstances determine how intentional or emergent you should be at a given moment for a given situation. The architect should continuously monitor circumstances and adjust the balance in collaboration with the engineers. Below a list of advantages and disadvantages.
In an agile setting, an architect has certain essential responsibilities:
- Foster collaboration – No single person has the knowledge and ability to oversee all aspects of a complex system. Collaboration is essential to gain different views, gather knowledge and expertise, and share ownership.
- Trade-off – There is no perfect solution. Circumstances determine which way to go, what approach to take, how fast you can go, etc.
- Continuous – All is in constant motion and therefore continuous attention and collaboration is required to adjust.
- Be strong – Often, there’s a tension between building something and getting paid for (let’s start…) and think ahead and prepare. Architects need to understand both needs, but advocate the architecture side (feel ownership).
- Lead – Architects have a leading role in which they can steer and influence. This comes with responsibility and is not limited to getting the architecture itself defined and build, but also the process of getting more agile.