Modular software architecture - benefits explained using a text chat server
At the beginning of a new project, the software developer faces the challenge of designing the architecture of the program code to be sustainable. In addition to easy maintenance, low dependency on specific libraries and independent testing options, readability should also be the focus of a successful software architecture. A shorter development time for an extension is only one positive effect of the structuring.
The requirements mentioned can be met by adhering to various concepts. In this context, the term "clean code" with the associated principle "separation of responsibilities" is often used. Below we present one way in which this concept can be applied to a text chat server implementation.
text chat server
One of the tasks of a current customer project was the implementation of a text chat server, where the functionality can be changed quickly. The changing requirements could be effectively met with the help of modularity.
Unlike a monolithic architecture, it is possible with a modular design, e.g. B. to use data management concepts that act independently of one another and do not require any changes to the rest of the source code. The named division into modules is the architectural focus of this text chat server.
Basically, the text chat server has two tasks: accepting events and distributing events. An event can be a message, but also information about joining a chat. Events go through several phases during an active chat: serialization, deserialization, validation, persistence, and distribution to clients, among others. Each phase, in turn, uses different technologies. For example, multiple serialization mechanisms must be supported, otherwise some chat clients would not be compatible.
We implemented the text chat server using the Java programming language and separated the source code into several logical modules. Starting with version 9, Java offers a native way of dividing source code with the "Project Jigsaw". For older Java versions, build tools such as Maven or Gradle can be used for modularization.
The figure visualizes the exemplary structure of the implementation, which is based on the facade design pattern. The central module common contains all overarching components of the system. The special feature, however, is that this module does not implement any specific logic, but mainly contains interfaces that are replaced either statically during design time or dynamically at runtime by technology-dependent modules and thus implemented. So is in common Defines the MessageService interface with the method signatures for get, create, update and delete. The software developer then has the option of realizing the implementation according to the desired technology. We have a separate module for our text chat server persistence-db created, which contains the source code to store events in a database. The module has a dependency on direction common and inherits from the interface MessageService. The corresponding methods are then implemented in relation to persistence in a database.
The requirements for a software component change, especially with an agile way of working: An external service is now supposed to replace the database. The dependency on the database can be resolved quickly thanks to the modularity. Just a new module persistence service with the appropriate implementation of the MessageService interface meets the new requirement. Instead of the previous database connection, calls are now sent to the external service. A further adaptation of the source code is not necessary.
The modules shown in the illustration work according to a similar principle communication-http, communication-mqtt, serialization-json and serialization-proto. The clients that access the text chat server do not necessarily have to support the same protocol and the same form of serialization. As in a modular system, the required technologies can be added to the architecture using modules. In our example, the text chat server would support the HTTP and MQTT protocols, as well as the JSON and Protocol Buffers serialization forms. If the AMQP protocol is now required, the corresponding module can be implemented and added.
The modules described so far together form the basis for the software. The final modules client web and client mobile access this basis and supplement the implementation in the direction of the clients. These modules define and implement the necessary interfaces to communicate with a web browser or with a mobile application. Depending on the requirements, further modules are also possible here. Depending on the application, it makes sense to combine the modules from multiple clients.
The architecture of a software component forms the basic building block for being able to implement subsequent requirements quickly and efficiently. In the example described, we have divided a text chat server into a large number of modules. In compliance with "clean code" principles and various design patterns, we were able to create a clear source code. In addition, the modularity gained promotes the implementation of independent test options.