I'm happy to present today a guest post from Alexander Eisenhuth. Alexander will write about his passion: good software architecture.
How can you recognise a good software architecture?
That was the question at the end of my webinar on "Agile Software Architecture", but before that, the participant told this story:
"We are getting to the point with our embedded software that we can't expand it anymore. The software has supported our device families for over ten years. After changes for one product, unexpected behaviour occurs in other products."
Have you ever heard of a similar story? This software is also called "historically grown" or "big ball of mud".
Architectural characteristics are the answer.
The question of good software architecture is easily answered: A good software architecture can be recognised because it implements the required architectural characteristics. In the case of the story above, the required architectural characteristic is maintainability. In principle, the "historically grown" software is maintainable, but bringing it back to the desired, technically correct state is expensive. The result is unsatisfactory in any case: high costs and the necessary extensions to the functionality are estimated to be spread over many places in the software.
Quality characteristics are described in detail in quality models such as ISO 25010. It is recognised that quality characteristics affect different phases of the software life cycle.
Table 1: Effect of architectural characteristics
There is an important aspect to the priority of architectural characteristics. They can be divided into important, critical, or irrelevant architectural characteristics.
The critical architectural characteristics must be ensured, as without them, the operation and sale of the software or system is not permitted. Compliance with these architectural characteristics must be ensured.
Important architectural characteristics must also be considered in software architectural work, but they do not have an immediate criticality.
Maintainability is usually an important quality feature. The impact of poor maintainability becomes noticeable over the years, as our example from the beginning shows.
Architectural characteristics Maintainability
Maintainability is understood as the quality with which amount of time maintenance activities can be carried out on software.
Maintenance activities are:
- Extend functionality: Implementing new functional requirements
- Perform analyses: Perform or interpret error analysis or static code analysis.
- Eliminate programming errors
- Carry out verifications: Exclude errors due to changes
How do I get maintainable software?
For a team to efficiently carry out the activities listed above, the source code must have a basic structure. It must be clear to the team where functionalities are located in the source code and how software is developed so that the software remains easily maintainable. This is, roughly speaking, the result of the software architectural work:
- Architectural decisions
- Design work
- Conceptual work
Technical concepts refer to the basic solution to a requirement that affects several software building blocks (component, module, class). Their mode of action is referred to as cross-cutting. They influence maintainability because there is precisely one technical solution for a requirement. Technical concepts describe the concrete implementation in the technology of the platform or programming language used.
Concepts that support maintainability
The following table lists typical technical concepts to achieve software maintainability:
Table 2: Typical concepts for maintainability
Architectural Style and Architectural Pattern of a Medical Thermometer
Designing the software start with the basic organisation of the software. An architectural style describes this basic structure of a software. Architectural patterns are the technically concrete solution of the architecture style.
To illustrate the aspects considered when choosing an architectural style and pattern, I would like to do this using a medical thermometer.
Figure 1: Medical Thermometer
A medical thermometer is an embedded system organised in the architectural style of a hierarchical system. On the upper level is the software that uses the hardware below. The software itself is also hierarchical. This results from the fact that the lowest layer of the software contains the hardware abstraction that is used to control the hardware.
The selection of the architectural pattern is an architectural decision. Architecture decisions are made from the background of a development project in a company, which creates the borders for the decision with its technical and organisational constraints.
I will present two architectural patterns and describe aspects that lead to maintainability. I have shown the structure of the two architectural patterns in a simplified form using blocks without showing dependencies.
The layered architecture
Structuring software into layers has been around for many years. The basic concept is to create abstraction layers to organize functions. With the layers, the upper layers may only access the layers below them. This eliminates the possibility of cyclic dependencies. Layers could be replaced, and the overall functionality is preserved. This is a common architectural pattern for embedded systems.
The software of the thermometer is divided into three layers when I look at it:
- Application: Contains the use cases of the system. In this case, the fever measurement and the behaviour when the battery runs low.
- Service: Provides access to technical abstractions with which applications can be implemented. Here, the possibility of measuring temperatures, displaying them, and emitting a sound for signaling. It is important here that the abstraction level is maintained and that no knowledge about the type of hardware access is necessary for the application.
- Hardware Abstraction Layer: Provides an interface to control the hardware.
Figure 2: Layered architecture of a medical thermometer
- ADC: Measurement of voltages
- LCD: Control of the display
- HAL: Hardware Abstraction Layer
The component architecture
Reusability is the driving force in building software with components. Components provide functionality specific to the system via offered interfaces. For their function, components require further functionality, which they receive via required interfaces.
Components can be developed independently if the required and provided interfaces are declared. In addition, components require technical functionalities such as runtime libraries of the programming language. In embedded systems without an operating system, components are realised as static libraries.
Figure 3: Component architecture of a medical thermometer
The component architecture shown here is also a hierarchical architectural style. The application layer is the top layer and uses the components shown. The components have a service layer and the HAL.
Comparison of maintainability layered architecture and component architecture
The most striking difference is that the software of the component architecture is divided into six blocks on the first level, and the layered architecture into three blocks. So you have a finer division of the software.
Another difference is that the component architecture forms functional blocks with cohesion. Cohesion denotes togetherness. The function of the component establishes this cohesion.
In the component architecture, the block ADC occurs several times.
Comparison of the maintainability of the software of a medical thermometer
Figure 4: Comparison of component architecture and layered architecture
Assessment of the differences
The potential advantages of component architecture come at the cost of increased effort in implementing the component interface. The quality feature of maintainability is not the only decisive factor in selecting the architectural pattern. As already mentioned, it depends on the background of a development project.
Dividing the software into components for a simple system like the thermometer will not be worthwhile. But for systems with higher complexity or when it comes to variants in the products or devices, a component architecture can make sense even for simple systems.
In any case, software architectural work is an important part of any development project. Implementing architectural characteristics into software later on is more expensive than considering them initially.
- Maintainability is an architectural characteristic of software
- The more maintainable software is, the less time is required for maintenance tasks.
- Maintainability is achieved through the following:
- A suitable architectural style for the software
- Good technical concepts for maintainability
- Design work appropriate to the problem
- The choice of the architectural style is an important architectural decision with significant implications
About Alexander Eisenhuth
Alexander Eisenhuth has been working independently in software engineering since 1996. For more than ten years, he has supported development teams in their software architectural work of embedded systems as a software architect.
In my next posts, I dive into the architectural pattern Layers, Pipes-and-Filters, Broker, Model View Controller, and Reactor.
The one thing missing in your analysis is comments. Since over 70% of lifetime costs in any application are maintenance, the ability of a competent programmer to pick up code and understand it is crucial. GitHub is full of apps that have thousands of lines of code without a single comment. Comment lines should be at least 10% of the total line count.
Code should be as expressive as possible and ideally should be readable without any comments. As comments come with an additional maintainability cost and tend to diverge over time, nowadays bet practise is to write expressive readable code and keep comments at a minimum.
Running fast and breaking things isn't a good look. Foundations, form, and yes, architecture do matter for well engineered products.
(and you wouldn't accept my valid gTLD email address, backup used ;-)