Overview of Modular Architecture
How to implement modular architecture – and why it’s worth it.
On our latest Mobile Meetup, TRIARE’s Mobile Architect Olexandr Krugliak has shared some insights about modular architecture.
We’ve comprised key takeaways: how it differs from monoliths, pros & cons, and how modules are created.
What is modular software architecture?
Modular architecture is a set of functions that do not directly depend on each other. They can communicate and interact, but each of them remains easily replaceable.
The notion of modularity is easiest to explain in this example. Imagine that you have to move a bulky painting. Would you agree it’s easier if the painting was a take-apart? When assembling the piece, you could even replace or remake some sections. That’s the difference between the monolithic (bulky painting) and modular (puzzle) approach.
Monolithic architectures are hard to maintain. You will have to change an inter dependable code every time the client asks for updates. Dividing work gets complicated, while functional testing affects many dependencies.
In addition, the choice of architecture will highly depend on the qualification of a team. If the project is large and/or evolving, you will probably need Viper, but Juniors will hardly grasp it.
If you want more details on monoliths, here’s an overview of frequently used architectures in custom app development. We compare monolithic MVC, MVVM, and MVP and a modular Viper with recommendations on when to use each.
Now, let’s talk about modular design and why we put it among the best mobile app development practices.
What is the benefit of modular design?
We have taken on projects built on various architectures. Also, developers make rotations between them every so often. On monoliths, areas of responsibility are not explicit. Legacy projects are bursting at the seams.
These factors led us to modules, code standardization, and the habit of writing and reading code correctly. The seams were taken out in separate modules, and problems with functional tasks were solved in isolation.
We have reduced the amount of extraneous code and delineated areas of responsibility. A unified approach to writing code and docs reduced stress and helped a lot with onboarding.
However, different modules can be developed with completely different approaches. No different architecture or third-party libraries will break the main project. This contributes a lot to a speed of development and a sense of freedom. As well as safety: a mistake inside one module will not affect the rest of the project.
Modules help iterations. Each new project has a ready-made foundation. We create a project on the outlines of the interaction between modules and then accumulate the code inside each individual module. Not only does it increase the speed of development, but it also helps with vector changes (especially in large projects). Adjusting business value becomes as easy as replacing a module.
What are the disadvantages of modular programming?
- Patience needed to cultivate a habit of describing code; no docs means a dead project;
- You will have to learn to divide functionality in modules correctly and develop a great vision of dependencies;
- Since each module is a separate framework, you’ll have to update them both in the main project and the module repository.
How to work with modules?
- Choose the “Framework” template for a new project. The structure of a modular project will look like a root project that hosts the dependencies of other projects/frameworks.
- Deploy the repository where the project will be located.
- Arrange access levels. The developer of the module must own the repository. Developers who reuse the module in their projects can only create their own branches and work with the module separately from the master. Merge to master only after code review.
- Develop the module. We’ll give examples below.
- For testing, create a test project and add your framework.
- Describe the module in the read.me file. Include sections like Structure or How to use.
- Add a module to a “living” project. Use Carthage and CocoaPods for public code, Manual Framework and Swift Package Manager for internal code. Note that SPM does not work with @IBDesignable, @IBInspectable objects.
How to develop a module?
Each project may require a different set of modules and their variations. Here are the examples of modules we use in every project:
- NavigationModule allows access to any stack and flow.
- CoreModule stores all the styles and sets of views for a project.
- ServerApiModule is for working with Rest API.
The structure is as follows: Navigation Router with a Navigation Module inside, which includes Navigation Controller, and Navigation Module View Controller. Navigation Module can branch into additional Navigation Modules.
All of these parts communicate via NavigationModel. It consists of the initiating View Controller and functions as a builder of Navigation Controller.
Launch of the NavigationModule:
We created this simple module to speed up the process by configuring the general style of an app, visualizing xib files, and using ready-made UI sets.
The module includes colour styles, font styles, app styles, UI elements. One simple example is ButtonStyleProperties, which includes all the changeable things. (Hack: if you get a single Figma file with all the styles and properties, it is easily transferable into the project and can be visualized through xib files).
This module was created to reuse the existing code and try testing DI in our modules.
Making a call:
Remember that the internal implementation of a module can be whether simple or complex, but the external use should always remain simple.
Our experience in modular programming
After creating six modular applications and 10+ modules, we can acknowledge the pros of a modular approach to app development:
- The speed of development has increased by 35%.
- Knowledge transmission is much easier due to the description of the module code and documentation.
- Therefore, switching is easier, and the bus factor is reduced.
- We admire our new navigation module that covers the Router’s needs and weaknesses.
- Implementation of TDD implementation and test integration are easier.
- Module reuse keeps code up-to-date and saves days on updating temporarily abandoned projects.
- It’s easier for developers to switch between projects and tasks, the bus factor is reduced.