1.3.1 Architecture Principles

Koupleless Architecture Principles

Modular Application Architecture

To address these issues, we have performed both horizontal and vertical splits on applications. Firstly, the vertical split involves dividing the application into base and business layers, corresponding to two layers of organizational responsibilities. The base team, like traditional applications, is responsible for machine maintenance, common logic abstraction, business architecture governance, and providing runtime resources and environments for business. By separating concerns, all underlying infrastructure below the business layer is shielded, allowing the focus to remain on the business itself. Secondly, we horizontally partition the business into multiple modules, allowing independent parallel iteration among them without interference. Since modules exclude the base part, their build artifacts are lightweight, and their startup logic only encompasses the business itself, enabling rapid startup and providing sub-second verification capabilities, thus optimizing module development efficiency to the utmost extent.
image.png
Before the split, each developer may have perceived all the code and logic from the framework to middleware to business common parts to business itself. After the split, the collaboration within the team has changed, and developers are divided into two roles: base and module developers. Module developers are not concerned with resources and capacity but enjoy the ability to deploy and verify changes in seconds, focusing solely on business logic.
image.png

Here it’s crucial to understand how we perform these vertical and horizontal splits. The split is for isolation, and isolation is for independent iteration, stripping unnecessary dependencies. However, isolation alone, without sharing, is akin to merely relocating deployment positions, which may not yield desirable results. Thus, besides isolation, we also emphasize sharing capabilities. Therefore, it’s essential to focus on understanding the principles behind modular architecture in terms of isolation and sharing.

Module Definition

Before delving further, let’s clarify what modules are in this context. Modules are derived by subtracting the base part from the original application. This subtraction is achieved by setting the scope of dependencies in the module as provided.
image.png
image.png
A module can be defined by these three points:

  1. A jar package generated by SpringBoot packaging
  2. A module: a SpringContext + a ClassLoader
  3. Hot deployment (no need to restart the process during upgrade)

Isolation and Sharing of Modules

Modules are isolated in terms of configuration and code through ClassLoader and SpringContext. They share configurations and code classes between modules and bases through SOFAArk and between multiple modules through SpringContext Manager.
image.png
Within the JVM, this is achieved through:

  1. Ark Container providing a multi-ClassLoader runtime environment
  2. Arklet managing module lifecycles
  3. Framework Adapter associating SpringBoot lifecycle with module lifecycle
  4. SOFAArk’s default delegation loading mechanism bridging module and base class delegation loading
  5. SpringContext Manager providing bean and service discovery mechanisms
  6. Bases essentially being modules with independent SpringContext and ClassLoader

image.png

However, modularization technologies in the Java domain have developed for 20 years. Why can modularization technologies be scaled within Ant Group? The core reason lies in the multi-module capabilities based on SOFAArk and SpringContext Manager, which provide a low-cost usage approach.

Isolation Aspect

Compared to other modularization technologies, from an isolation perspective, JPMS and Spring Modulith impose limitations through custom rules, with Spring Modulith requiring verification in unit tests. The isolation capabilities are relatively weak and somewhat tricky, with significant retrofitting costs for legacy applications, and even infeasible for legacy applications. Similar to OSGi, SOFAArk employs ClassLoader and SpringContext for configuration and code, as well as bean and service isolation, maintaining consistency with the native application startup mode.

Sharing Aspect

While SOFAArk shares isolation mechanisms with OSGi, OSGi, JPMS, and Spring Modulith all require defining import/export lists or other configurations between source and target modules, resulting in high usage costs for business modules that need to understand and perceive multi-module technologies. SOFAArk defines a default class delegation loading mechanism and cross-module bean and service discovery mechanisms, enabling business usage of multi-module capabilities without modification.
Additionally, why can the modularization technology based on SOFAArk provide these default capabilities at low cost and emphasize low-cost usage? The main reason is that we have differentiated roles for modules, distinguishing between bases and modules. Based on this core reason, we have also attached importance to low-cost usage and made important design considerations and trade-offs. For specific design considerations and trade-offs, refer to the technical implementation article.

Inter-Module Communication

Inter-module communication relies primarily on the bean and service discovery mechanism provided by SpringContext Manager.
image.png

Module Evolution

Looking back at the mentioned major issues, it can be seen that through the isolation and sharing capabilities of modular architecture, problems such as complex infrastructure, collaboration blocking, and high resources and long-term maintenance costs can be solved. However, the issue of inconsistent agility between microservices splitting and business remains unresolved.
image.png
Here, we address this by reducing the cost of microservices splitting. So how do we reduce the cost of microservices splitting? The main approach is to introduce modular architecture between monolithic and microservices architectures.

  1. Modules do not occupy resources, so splitting incurs no resource costs.
  2. Modules do not include business common parts, frameworks, or middleware parts, so modules incur no long-term SDK upgrade and maintenance costs.
  3. Modules themselves are SpringBoot, and we provide tools to assist in the low-cost splitting of monolithic applications into modular applications.
  4. Modules have flexible deployment capabilities; they can be deployed together in one JVM or separately, allowing modules to evolve into microservices or revert to monolithic application modes at low cost.

image.png
The arrows in the diagram are bidirectional. If there are too many microservices currently split, multiple microservices can also be cost-effectively transformed into modules and deployed together in one JVM. So, the essence here is to add a bidirectional transitional modular architecture between monolithic and microservices architectures, reducing the cost of transformation while allowing developers to evolve or roll back according to business needs. This can solve several problems of microservices.

Advantages of Modular Architecture

The main advantages of modular architecture are concentrated in these four points: speed, savings, flexible deployment, and evolvability,
image.png

When compared to traditional applications, the data below show more than a 10x improvement in development, deployment, and runtime stages.
image.png

Platform Architecture

Just having application architecture is not enough. It is necessary to provide complete supporting capabilities from the development stage to the operation and runtime stages to truly realize the advantages of modular application architecture to developers.
image.png
During the development stage, it is necessary to provide capabilities for base access, module creation, and more importantly, local rapid build and debugging capabilities for modules; during the operation stage, provide fast module deployment capabilities, and on top of module deployment, provide A/B testing and second-level scaling capabilities; during the runtime stage, provide reliability capabilities for modules, fine-grained control of observability, traffic, scheduling, and scaling.

image.png
Component View

Within the entire platform, four components are needed:

  1. Development tool Arkctl, providing module creation, rapid debugging testing, and other capabilities.
  2. Runtime components SOFAArk, Arklet, providing module operation, module lifecycle management, and multi-module runtime environment.
  3. Control plane components ModuleController
    1. ModuleDeployment provides module deployment and operation capabilities.
    2. ModuleScheduler provides module scheduling capabilities.
    3. ModuleScaler provides module scaling capabilities.