The modular architecture consists of a set of functions that do not directly depend on each other. They just know how to communicate and interact, but it is quite simple to change each structural unit – like in a puzzle. That’s an advantage it has over monoliths.
Let's replace the concept of a piece of the puzzle with a framework. Each separate implemented functionality will be a collection of code for solving a problem integrated into the project as a framework.
This is going to be a root project that hosts the dependencies of other projects/frameworks.
The number of modules and their content may vary in different projects. The first three modules are needed at the start of any project. Therefore, unlike the Onboarding module, they are always used in our projects.
We’ll examine these modules in detail below. But first – a quick tutorial on how to set up your work.
1/ Create a project with the “Framework” template.
Arrange the correct access levels for your team. The developer of the module must have an "owner/maintainer” access level. Developers who will use this module in their projects should remain “developers”.
Working with modules is very convenient in teams. Each team member can be responsible for his own module or use a ready-made module previously implemented in another project simply by changing its properties. It’s convenient to always have a person who can conduct a code review and knows the value that this code brings.
Merge to master only after pull request & code review.
4/ To evaluate and test the code, create a test project, add your framework, and bring it to the desired level. The folder structure will be as follows (BaseApp V2 is a project where I am testing framework):
The integration of our module into the project can be done via a standard set: Swift Package Manager, Manual .framework, Carthage, CocoaPods. When choosing a provider, it is necessary to consider some factors:
Now that you know how to work with modules let’s explore the stuffing. We’ll show how we coded our NavigationModule, CoreModule, and ServerApiModule.
NavigationModule has a very simple structure: Navigation Router with a Navigation Module inside, Navigation Controller, and Navigation Module View Controller. Navigation Module can branch into additional Navigation Modules.
All of these parts communicate via NavigationModel, which consists of the initiating View Controller, and functions as a builder of Navigation Controller.
We only need three points for a successful launch:
This is a very simple CoreModule we created to:
We take all the changeable things out into it. Our designers provide a single file in Figma with all the styles and properties used, so that we easily transfer it into the project, and then visualize through xib files how everything will look like on the devices.
The idea behind this one was to reuse the existing code and try testing DI in our modules.
Making a call is fast and easy:
One of the advantages of modularity is that inside we can use any architecture, any third-party libraries, and this will not break our main project. When initializing a project, we know which modules will be used and how they will communicate with each other, so the control point is exactly the place where the module is glued and not its interior.
Learn about other advantages of modular architecture in the next part of our Modular Architecture Overview. Pros and cons, and revelations from our experience – find out if it’s worth it!