Mastering COLA: Clean Object‑Oriented Layered Architecture for Scalable Backend Systems
This article explains the COLA (Clean Object‑Oriented and Layered Architecture) framework, its layered structure, component breakdown, and practical implementation details with SpringBoot, including code examples, module organization, and design principles for building maintainable backend systems.
The article begins by questioning the characteristics of business code, especially in fast‑moving internet projects, and lists common problems: rapid iteration leading to messy code without comments, frequent personnel changes, inconsistent coding habits among developers, and a lack of time for refactoring, which together cause growing technical debt.
It proposes solutions such as regular team refactoring, designing a robust application architecture, and keeping designs simple so that developers at any level can quickly understand and work with the code.
COLA, the main focus of the article, is introduced as a practical business code structure standard aimed at slowing code decay and improving development efficiency.
What is COLA
COLA stands for Clean Object‑Oriented and Layered Architecture . It was proposed by Alibaba’s Zhang Jianfei and is included as an optional component in Alibaba Cloud’s scaffolding code generator, indicating its influence.
COLA 4.0 splits the framework into two parts: the COLA architecture (Archetype) and COLA components, which can be used independently.
COLA Overall Architecture
The article cites the official COLA blog, noting that most business systems need to receive requests, process business logic, and interact with external systems such as databases, micro‑services, or search engines. This commonality leads to generic architectural ideas like layered, hexagonal, onion, clean, and DDD architectures.
Although many architectural patterns exist, COLA provides concrete, actionable practices rather than just theory, making it a rare open‑source solution at the application architecture level.
COLA offers a ready‑to‑use code architecture that incorporates many design concepts, including domain‑driven design (DDD).
COLA Layered Architecture
Two official diagrams illustrate the overall structure (images omitted for brevity).
The example project follows a Maven parent‑child structure, with the parent pom.xml declaring the following modules:
<code><modules>
<module>demo-web-client</module>
<module>demo-web-adapter</module>
<module>demo-web-app</module>
<module>demo-web-domain</module>
<module>demo-web-infrastructure</module>
<module>start</module>
</modules></code>Start Layer
The start module is the bootstrapping SpringBoot application that holds global configuration and launch logic, providing a clear entry point for newcomers.
Adapter Layer
The adapter layer corresponds to the traditional controller layer in MVC, handling web, wireless, and WAP requests. It adapts incoming requests to the internal service calls.
With the rise of mobile, most applications now need to support Web, Mobile, and WAP front‑ends, so the adapter layer extends beyond classic MVC controllers.
Client Layer
The client layer defines service interfaces (
api) and data transfer objects (
dto) that other modules consume. It does not contain implementation logic; instead, the adapter layer calls these interfaces.
Example client package structure:
api folder – service interface definitions
dto folder – transfer entities
In the adapter layer, a controller injects the client interface:
<code>@RestController
public class CustomerController {
@Autowired
private CustomerServiceI customerService;
@GetMapping(value = "/customer")
public MultiResponse<CustomerDTO> listCustomerByName(@RequestParam(required = false) String name) {
CustomerListByNameQry qry = new CustomerListByNameQry();
qry.setName(name);
return customerService.listByName(qry);
}
}</code>The actual implementation resides in the app layer:
<code>@Service
@CatchAndLog
public class CustomerServiceImpl implements CustomerServiceI {
@Resource
private CustomerListByNameQryExe customerListByNameQryExe;
@Override
public MultiResponse<CustomerDTO> listByName(CustomerListByNameQry qry) {
return customerListByNameQryExe.execute(qry);
}
}</code>App Layer
The app layer implements business logic, organized first by domain (e.g., customer , order ) and then by function (executors, consumers, schedulers). This separation keeps related code together while isolating cross‑domain concerns.
Typical app sub‑layers include:
executor – handles commands and queries
consumer – processes external messages
scheduler – runs scheduled tasks
Domain Layer
The domain layer encapsulates core business logic through entities, domain services, and gateways. Entities may be rich (e.g.,
Customerwith behavior methods), domain services expose business capabilities, and gateways define SPI interfaces for infrastructure implementations.
<code>@Data
@Entity
public class Customer {
private String customerId;
private String memberId;
private String globalId;
private long registeredCapital;
private String companyName;
private SourceType sourceType;
private CompanyType companyType;
public boolean isBigCompany() {
return registeredCapital > 10000000;
}
public boolean isSME() {
return registeredCapital > 10000 && registeredCapital < 1000000;
}
public void checkConfilict() {
if ("ConflictCompanyName".equals(this.companyName)) {
throw new BizException(this.companyName + " has already existed, you can not add it");
}
}
}</code> <code>public interface CustomerGateway {
public Customer getByById(String customerId);
}</code> <code>@Component
public class CustomerGatewayImpl implements CustomerGateway {
@Autowired
private CustomerMapper customerMapper;
@Override
public Customer getByById(String customerId) {
CustomerDO customerDO = customerMapper.getById(customerId);
// Convert to Customer entity
return null; // conversion omitted for brevity
}
}</code>Infrastructure Layer
The infrastructure layer provides technical details such as MyBatis mappers, configuration files, and gateway implementations, handling database CRUD, external service calls, and other low‑level concerns.
Features of COLA
Domain‑and‑Function Packaging Strategy
Packages are first divided by domain and then by function, preventing code decay from spreading across unrelated modules. For example, customer and order domains each have their own DTOs and utilities, avoiding conflicts.
Decoupling Business Domain from External Dependencies
The dependency inversion between domain and infrastructure layers allows a domain entity (e.g., Item ) to obtain data from various sources—MySQL, Redis, or external APIs—through gateway interfaces, keeping the domain logic independent of concrete data sources.
COLA Is Not Perfect
Although COLA provides a clear structure, it can lead to an explosion of DTOs because each interface often defines its own request and response objects, which may become redundant.
Overall, COLA offers a design philosophy rather than a strict enforcement, allowing teams to adopt the parts that fit their needs while discarding unnecessary complexity.
Conclusion
COLA’s architecture is straightforward and has matured through successive refinements, now being an optional component in Alibaba Cloud’s code generator, demonstrating its stability and adoption.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.