Design And Create Modules on Code Base
Why we need and how to create modules in a code base
Working on a code base where business logic and other functionalities are scattered is at least a frustrating situation for software developers.
Modules are a solution to keep things clean and separated in a code base such as a well-organized warehouse with products.
๐Letโs deep dive into modules
Characteristics of a Module
Modules have clear characteristics that must follow :
- Bounded Context Every module has a clear bounded context that encapsulates all the functionalities. For example a module with User as a bounded context, will encapsulate and expose all the functionalities of the User.
- High Cohesion A module with a well-defined bounded context has all its close related code very close
- Low Coupling A module must have few or zero dependencies
- High Reusability By nature, a module is designed to be reusable
- Information Hiding Modules have to expose only the necessary information and hide all other data that consumers donโt need
- Less effort for refactoring and migrations In cases that we need to refactor or we need to migrate a module is way easier because all the consumers-client depend on the module interface
Interface and Model Consistency
Every module has to expose a bunch of different classes, functions, and data (models).
These functionalities and models are the stable contract that other modules will consume, and interact with.
All the inner logic must be encapsulated and hidden.
The best practice is to expose all module functionalities with an interface and all consumers will interact with it.
This approach is known as the Dependency Inversion Principle (DIP).
With DIP we can create loosely coupling modules
For example, in the above pic case if the Blog module needs to get the info for a User the Blog module doesnโt know where the user data is located and how itโs retrieved. The result is that we have eliminated the data and implementation logic coupling between the 2 modules.
Structuring
We can build a well-structured module in 3 steps :
- Create the main interface that will expose all the module functionality
- Create all the module inner logic behind the interface
- Create the data store (database access, HTTP requests, IO operations, etc), the data store must be independent between the modules
Communication between modules
Synchronous
Synchronous communication between modules is when a module-a
call directly a function on a module-b
Asynchronous
Asynchronous communication between modules is when modules communicate with events and a publish-subscribe system (aka message bus).
The publish-subscribe system can be :
- Built into the code base
- Implemented with an out-of-process system like Redis, Kafka, RabbitMQ, etc
Types Of Modules
We can have 2 types of modules :
- Domain base modules these types of modules offers business logic and support all domain use cases
- Infrastructure modules these types of modules donโt have any business logic and support all the app operations
Benefits of using modules on the code base
โ A more Clean Architecture
โ Higher DX
โ High cohesion at code base level
โ Low coupling at code base level
โ Easier to refactor functionalities
โ Easier to migrate to a microservices architecture
โ Separation of concerns โ Single Responsibility
โ Encapsulation of failures at a module level