Modular programming has been around since the 60s and is a foundation of any good software architecture. Across many industries that were once hardware-dominated, software architecture is surfacing as a critical bottleneck for delivering the best products to the market first. Simultaneously, the share of R&D spending on software development is increasing rapidly.
The main issue is that software has grown organically within these products. If the perspective hasn't been raised and a unified modular software architecture has been set up, there is an evident risk that you end up with many different monolithic software platforms, each designed for a narrow subset of your products. This issue makes your development slow and costly, with poor output.
One could argue that lack of strategic software modularity is the main reason traditional hardware-first companies have difficulty competing with new, focused competitors that don't have the burden of an existing portfolio.
In this blog post, we will explain what software modularity is, why it matters to your business, and what you can do to improve your software.
What is Software Modularity?
Software modularity is measured by how well software is decomposed into smaller pieces with standardized interfaces. It is analogous to modularity for hardware. We want to create products by combining reusable chunks of code, so you only implement a feature or functionality once and then maximize reuse.
A software module exposes its interface to other modules, both internally within the module system but also externally towards other systems. Externally exposed interfaces belong to the module system's external Application Program Interface (API). They should be carefully designed since changes in APIs will impact other applications. There are plenty of APIs freely available today for cloud services, for example, SkyScanner API (to build your own travel app) or Open Weather API (to build your own weather app). If any of these services suddenly change their API, many apps across the globe will be broken, generating a lot of frustration and extra work. To have a stable modular software system, careful design and governance of interfaces must also be implemented for interfaces between modules for internal use.
The intent of software modularity is different depending on the strategic targets of the software owner. Here are some examples of strategy and intent:
- When software and hardware are combined, software portability might be a key target of modularity. Software portability is defined as software that is independent of the hardware it runs on. This autonomy can be achieved with carefully designed interfaces that abstract the hardware level from the application level.
- Automated testing is typically a major concern for software that is changed often. By being able to test faster and spot issues earlier, less time and resources can be spent on integrating the changes. Automated testing is something that can be achieved better with smart software modularity. By isolating changing parts with interfaces, we can test smaller chunks which is faster both in testing and in finding bugs.
- For software where updates and features are implemented on an installed base, Over-the-Air (OTA) update capability is the tale of the century. To push software updates in a controlled and efficient matter, it is essential to separate frequently updated modules from fundamental critical modules where changes are high risk. Updating small chunks of the software is also faster and less resource consuming.
What is a Software Module?
In software, the term Module has a wide range of different definitions, much like the term Component. Even though it is a term with many different definitions, there are commonalities in the descriptions. Let's have a look at some of these descriptions.
A module is a piece of code that can be independently created and maintained to be (re)used in different systems.
and Wikipedia describes modular programming as:
"Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules …"
Which are the commonalities?
A Software Module is Independent
A software module is independent of other modules in the sense that it is possible to develop and maintain a module with minimal to no impact on other modules. It does not mean that a module has no dependencies on other modules when running the program.
This autonomy is an important aspect of a software module because it helps to increase productivity. Independent modules enable engineering teams to be independent of each other when creating, maintaining, and testing the code.
A Software Module is Reusable and Interchangeable
A module can be reused in different systems, and it is also interchangeable (replaceable) within a system. Reusing modules in different systems or products without modification is very beneficial and will help shorten the time to market.
Interchangeable means you can replace a module without impacting the rest of the system. This flexibility is essential when upgrading a system because of new features or bug corrections. If you can limit changes to one or a few modules, less time is needed to test and implement changes. More frequent and smaller releases, in terms of impacted parts of the system, enable agility. Smaller releases also mean that you take less risk when releasing new features.
A Software Module is a Piece of Code and a Function
A module is a part of a module system. The first description above defines the decomposition in terms of code and the second in terms of functionality. Is that a similarity or a difference?
- We would say both. It is about decomposing the system into smaller parts, but:
Decomposition in terms of code is about organizing the code where a module is a structural unit. Different programming languages support the software modularization concept but not in precisely the same way. For example, a Python module is a file, but a Java module is much more. A Java module consists of one or many packages (another structural unit) and a descriptor that defines the packages that are exported from the module and the other modules that it requires to work. It is only the exported packages that are accessible for other modules to use.
Separating functionality is about organizing logical functions into logical software modules. This organization is beneficial when specifying and documenting the architecture of a system. A logical module may be realized by a code module or another structural unit, like a package. In UML (Unified Modelling Language), a modular system can be described with a UML Component diagram.
How Can a Software Module be Independent, Reusable, and Interchangeable?
There are some important properties of a software module that make it possible for teams to work independently, making the software module reusable in many systems and interchangeable.
encapsulates functionality and data. Encapsulation is about hiding the implementation details of a module. The less a module knows about other modules, the less dependent it will be on changes in other modules. Other modules can only access functionality and data via the provided interface. Generally, it is good to encapsulate as much as possible.
provides an interface to other modules for accessing its functionality and data. The software module interface should be as abstracted and as small as possible. Fewer details mean looser coupling between software modules and make them more independent, reusable, and interchangeable.
requires interfaces provided by other software modules. To realize the functionality of a software module, it must sometimes use the provided interfaces of other modules. A software module that uses another module through its interface has a dependency on that other module. The fewer dependencies, the better. Since non-backward compatible interface changes may occur in a software module's lifecycle, an update to a module can be forced without any benefit to customers, such as better performance, functionality, or quality. Forced software updates that do not improve customer benefit should be considered a cost of complexity in software development.
Figure 1. A software module provides and requires interfaces
Module B1 provides Interface B to Module A and requires Interfaces C and D. Assume we have a new Module B2 with improved performance. If Module B2 provides the same interface and requires the same interfaces as B1, then it is interchangeable with B1.
Figure 2. Two software modules that provide and require the same interfaces are interchangeable
A module that defines provided and required interfaces become reusable in other systems, e.g., Module B1, can be reused in another system as long as the required interfaces are provided.
Figure 3. UML component diagrams can be used to document modules with provided and required interfaces.
What is a Strategic Software Module?
An often-overlooked aspect of forming software modules is company strategy. When creating a module with the properties described above, we typically have a specific intent in mind. This purpose should be explicitly decided and documented. The intent is expressed by answering strategic questions, such as:
- Is the module formed to collect aspects of the system that will frequently change?
- Is the module formed to allow for sourcing the code from a strategic partner?
- Is the module formed because it requires a specific skill set to develop that only very few people have?
As software architecture can easily be circumvented or misunderstood by the coders, it is vital to repeatedly look back at why certain functions were grouped into modules. For this reason, we believe it is crucial to state and document the strategic intent of a module. In fact, a defined module strategy should be considered a criterion to call something a module. A software module with a defined module strategy is a strategic software module.
Our colleague's blog post "What is a good modular system" explains that a modular system must be flexible for a large scope and live for a long time. Creating strategic software modules increases the chance of a longer lifetime, and robustness becomes less person-dependent.
How to Document a Strategic Software Module
Documenting a strategic software module is different from traditional software documentation. The strategic software module should encapsulate function, define interfaces, and be driven by strategy. This information needs to be documented to easily communicate, discuss, and explain. One way of doing it is to create a one-page strategic software module specification stored in your document management system. Another flexible way to document these aspects is a wiki.
Figure 4. Example of a Strategic Software Module Specification in a one-page slide
Strategic Software Modules Deliver Increased Value Over Time
To enable efficiency, flexibility, and agility, large and complex systems must be decomposed into smaller parts or modules. Independent modules make the development teams more autonomous, resulting in improved efficiency and shorter time to market. A module is also reusable in different products. Companies with a modularized product portfolio build their products from a mix of common reusable modules.
By defining the strategic intent of a software module, you create a strategic software module. These modules will be more resilient to change since the reasons why the modules were formed are documented.
It is fascinating that a module with only three simple attributes - encapsulation, interfaces, and strategy – can deliver so much value.
If you want to read more about how to create a modular architecture using a proven method called the Modular Function Deployment you can download our 5 step guide here below:
Software Modularity is a passion of ours and we are happy to continue the conversation with you. Contact us directly via email or on Linkedin if you'd like to discuss the topic covered or be your sounding board in general around Modularity and Strategic Product Architectures.
Senior Specialist Software Architecture