↓ Ir para o conteúdo principal

← todas as notas

📎 Webclip

Evolving modular monoliths: 1. An architecture for .NET

The article presents a way to structure a .NET application so it stays simple like a monolith but avoids becoming a “big ball of mud.” It combines clean architecture and DDD bounded contexts to separate business features, support testing, and make code easier to find and change.

Reading notes
#

  • The series focuses on building a .NET application with a modular monolith architecture.
  • The goal is to keep monolith simplicity while preserving structure as the application grows.
  • The design uses clean separation between major parts of the application through modular monolith structure and DDD bounded contexts.
  • The article does not compare monoliths with microservices or serverless architectures.
  • The intended audience is .NET developers and software architects who already know C#, projects, and NuGet packages.
  • The author applies encapsulation, separation of concerns, organisation, collaboration, development effort versus reward, and testability as guiding principles.
  • The first level of modularization is an n-layered application with front-end, service layer, infrastructure, business logic, persistence, and domain layers.
  • The author uses a clean architecture style, but with some changes, including a Persistence layer deep inside the rings and interfaces placed with the service that defines them.
  • Front-end code is kept thin, and services are used to handle input and output because they are easier to test than ASP.NET Core pages or APIs.
  • The ServiceLayer acts as an adapter between business classes and user-facing code.
  • A pure n-layered structure keeps separation at the layer level, but not within layers, so layers can become large and hard to navigate.
  • The second level of modularization uses DDD bounded contexts to isolate feature groups such as Books and Orders into separate .NET projects.
  • Each bounded context contains its own layers, namespaces, and projects, with a naming convention that makes the code easier to locate.
  • Bounded contexts can share data without losing isolation, and the article says this is covered later in the series.
  • The third level of modularization breaks code up inside a bounded context so large features can be split into smaller .NET projects.
  • The author places code for specific queries or features into separate projects, especially in the ServiceLayer.
  • The rules are that projects only reference others in the same bounded context, outer layers can reference inner layers, and same-layer sharing is allowed only for projects named “Common.”
  • Unit tests are used to enforce those modularization rules.
  • The approach is presented as a way to reduce spaghetti code and make relationships between parts of the system harder to violate.
  • For large applications, the article considers tooling limits, team collaboration, and whether the approach can be added to an existing monolith.
  • The author suggests moving larger or more complex bounded contexts into separate solutions, packaging them as NuGet packages, and installing them in the main application.
  • This keeps the benefits of quick method and data transfer while giving teams more separation.
  • The article concludes that the author’s experience with this structure made code easier to find and later helped with refactoring for performance tuning and CQRS.