Rethinking Layered Architecture: Lessons from Evolving the Coco System
The article chronicles the evolution of Coco's layered architecture, detailing the shift from a monolithic Clean‑Architecture‑inspired design to a modular, plugin‑driven structure, and discusses the trade‑offs of infrastructure layering, code reuse, and future adaptability.
When optimizing Coco's layered architecture, the author faced many decision dilemmas and chose to delay choices to better understand the current system, effectively walking on the edge of risk to maximize benefit.
Design Foundations
Architecture decisions are guided by three factors: past experience, present requirements, and future direction. Because these factors constantly evolve, a design that satisfies every historical period is impossible; the present becomes the past, and the future becomes the present.
Original Monolithic Structure
Initially, Coco adopted a Clean‑Architecture‑like layering (without a Cargo module) consisting of four top‑level directories:
app – the use‑case layer.
bin – the controller layer that builds an executable in Rust.
infrastructure – services such as Git interaction and file‑system access.
domain – business entities and domain models.
Within domain, the project further split into sub‑domains like cloc, git, framework, architecture, etc.
Although the design resembled Clean Architecture, key principles such as dependency inversion were not fully applied, leading to added complexity and limited promotion potential in open‑source contexts.
Monolith Evaluation
The structure adds architectural complexity and requires continuous knowledge transfer.
Refactoring can later convert the monolith into a cleaner architecture; the author treats the current work as a learning exercise.
For a single‑application monolith, the design is acceptable because:
It is not overly complex and helps developers locate code.
It can evolve into a full Clean Architecture.
Modules can be further split by business domain.
Modularization for Code Reuse
To share code across multiple systems, independent modules such as framework and psa were extracted. These modules can be used locally without versioning concerns, and later published remotely when ready.
Typical modularization places each module as a sibling directory to the source code:
├── framework
├── psa
├── src
│ ├── app
│ ├── bin
│ ├── domain
│ ├── infrastructure
│ └── lib.rsIf a module’s dependencies are fully decoupled, it can be released as an independent application.
Copy‑over Reuse
When a module is tiny, copying the code instead of reusing it can simplify dependency management.
Plugin‑Based Architecture Evolution
To flexibly extend functionality and reduce binary size, a plugins directory was introduced, containing modules like coco_xxxx. A plugin_manager was created to load these plugins, although later it was deemed unnecessary as a separate module.
├── framework
├── plugin_manager
├── plugins
│ ├── coco_container
│ ├── coco_pipeline
│ ├── coco_struct
│ └── coco_swagger
├── psa
├── src
│ ├── app
│ ├── bin
│ ├── domain
│ ├── infrastructure
│ └── lib.rsThe design remains usable and does not introduce major issues.
Future Directions
Recognizing missing considerations, the author proposes extracting a dedicated core module to expose essential code to plugins and applications, leading to a core_model implementation that avoids bundling non‑core logic.
For shared infrastructure, two options were evaluated:
Extract the existing infrastructure into a top‑level module.
Introduce a double‑layered infrastructure where only common code is extracted as an independent module.
The author favors the double‑layer approach to prevent code duplication and binary bloat, citing examples of overly nested common packages.
Conclusion
Even small projects undergo continuous architectural evolution; uncontrolled growth can lead to unwieldy systems. The author hints at developing a "layered architecture fitness function" to rate the suitability of a system's layering based on dependency analysis.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
phodal
A prolific open-source contributor who constantly starts new projects. Passionate about sharing software development insights to help developers improve their KPIs. Currently active in IDEs, graphics engines, and compiler technologies.
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.
