Mastering Architecture Design Principles: Layered, Cohesive, and DDD Approaches
This article explains core architecture design principles—including layered, hexagonal, and COLA structures—covers cohesion and coupling types with evaluation criteria, presents practical strategies to reduce coupling, and details domain‑driven design concepts such as bounded contexts, aggregates, and repository patterns, all illustrated with concrete code examples and decision records.
1. Architecture Layering
1.1 Classic Layered Architecture
Traditional three‑layer architecture
┌─────────────────────────────────────────────────┐
│ Presentation Layer │
│ Controller Filter Interceptor │
│ Responsibilities: request handling, validation, view rendering, routing │
│ Business Logic Layer │
│ Service Domain DTO │
│ Responsibilities: business logic, transaction management, permission checks, exception handling │
│ Data Access Layer │
│ Repository DAO Mapper │
│ Responsibilities: persistence, cache, connection pool │
└─────────────────────────────────────────────────┘1.2 Hexagonal Architecture (Ports & Adapters)
Hexagonal architecture diagram
┌─────────────────────────────────────────────────┐
│ Domain Core │
│ Aggregate Entity ValueObject │
│ └───────┬───────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ Input Port │ Output Port │ │
│ │ (REST API) │ (Repository)│ │
│ └───────────────┴───────────────┘ │
└─────────────────────────────────────────────────┘1.3 COLA Architecture (Alibaba)
COLA architecture diagram
┌─────────────────────────────────────────────────┐
│ App Layer (Application) │
│ CommandA CommandB Query Event │
│ Responsibilities: request handling, transaction boundary, business orchestration │
│ Domain Layer (Domain) │
│ Entity ValueObject Service DomainEvent │
│ Responsibilities: core business logic, domain rules, state management │
│ Infrastructure Layer (Infra) │
│ Repo Impl RPC Client Cache MQ Client │
│ Responsibilities: technical implementation, framework integration, external service calls │
└─────────────────────────────────────────────────┘2. High Cohesion and Low Coupling
2.1 Cohesion Types
Accidental cohesion – Level: Worst – No relation between module parts; hard to maintain.
Logical cohesion – Level: Poor – Similar logic grouped together; difficult to understand.
Temporal cohesion – Level: Poor – Functions that run at the same time are grouped; hard to understand.
Procedural cohesion – Level: Medium – Functions executed in a specific order; acceptable.
Communicational cohesion – Level: Medium – Functions that operate on the same data are together; fairly good.
Sequential cohesion – Level: Good – Output of one function is input of the next; good.
Functional cohesion – Level: Best – Single business function completed; best.
2.2 Coupling Types
Content coupling – Level: Worst – Direct access to internal data; prevents independent testing.
Common coupling – Level: Poor – Communication via global variables; hard to trace data flow.
External coupling – Level: Medium – Depends on external environment; acceptable.
Control coupling – Level: Medium – Caller controls callee logic through parameters; logic is caller‑controlled.
Stamp coupling – Level: Good – Only necessary data passed; minimizes dependencies.
Data coupling – Level: Best – Only business data passed; fully independent.
2.3 Strategies to Reduce Coupling
Dependency Injection – Inject dependencies via constructor or setter instead of creating them directly.
Interface Segregation – Clients depend only on the methods they need, not on large monolithic interfaces.
Facade Pattern – Provide a unified entry point that hides internal complexity.
Event‑Driven – Communicate through events rather than direct method calls.
Dependency Inversion – Depend on abstractions rather than concrete implementations.
// Dependency Injection example (Bad)
public class OrderService {
private EmailService emailService = new EmailService(); // strong coupling
}
// Dependency Injection example (Good)
public class OrderService {
private final MessageService messageService; // depends on abstraction
public OrderService(MessageService messageService) {
this.messageService = messageService;
}
}
// Interface Segregation (Bad)
public interface Service {
void sendEmail();
void sendSms();
void sendPush();
}
// Interface Segregation (Good)
public interface EmailService { void sendEmail(); }
public interface SmsService { void sendSms(); }
// Facade example
@Service
public class NotificationFacade {
private final EmailService emailService;
private final SmsService smsService;
private final PushService pushService;
public void notifyUser(User user, String message, NotifyType type) {
switch (type) {
case EMAIL -> emailService.send(user.getEmail(), message);
case SMS -> smsService.send(user.getPhone(), message);
case PUSH -> pushService.push(user.getDeviceToken(), message);
}
}
}
// Event‑Driven example
@Service
public class OrderService {
private final ApplicationEventPublisher eventPublisher;
public void confirmOrder(Long orderId) {
Order order = findOrder(orderId);
order.confirm();
eventPublisher.publishEvent(new OrderConfirmedEvent(order));
}
}
@Component
public class InventoryEventListener {
@EventListener
public void handleOrderConfirmed(OrderConfirmedEvent event) {
inventoryService.reserve(event.getOrder());
}
}3. Domain‑Driven Design
3.1 Core Concepts
DDD strategic design diagram
┌─────────────────────────────────────────────────┐
│ Bounded Contexts (e.g., Order, Inventory) │
│ Order Context: Order aggregate, OrderItem entity, Customer value object │
│ Inventory Context: Inventory aggregate, Warehouse value object, Inventory service │
│ Context mapping connects shared identifiers (CustomerId / OrderId) │
└─────────────────────────────────────────────────┘3.2 Domain Model Examples
public class Order extends AggregateRoot {
private OrderId id;
private CustomerId customerId;
private List<OrderItem> items;
private OrderStatus status;
private Money totalAmount;
public void addItem(Product product, int quantity) {
if (status != OrderStatus.DRAFT) {
throw new DomainException("Only draft orders can add items");
}
OrderItem existing = findItem(product.getId());
if (existing != null) {
existing.increaseQuantity(quantity);
} else {
items.add(new OrderItem(product, quantity));
}
recalculateTotal();
}
public void confirm() {
if (items.isEmpty()) {
throw new DomainException("Order cannot be empty");
}
this.status = OrderStatus.CONFIRMED;
this.confirmedAt = LocalDateTime.now();
registerEvent(new OrderConfirmedEvent(this));
}
}
public class Money {
private final BigDecimal amount;
private final Currency currency;
private Money(BigDecimal amount, Currency currency) { this.amount = amount; this.currency = currency; }
public static Money of(BigDecimal amount, Currency currency) { return new Money(amount, currency); }
public Money add(Money other) {
if (!this.currency.equals(other.currency)) {
throw new DomainException("Currency mismatch");
}
return new Money(this.amount.add(other.amount), this.currency);
}
public Money multiply(int factor) { return new Money(this.amount.multiply(BigDecimal.valueOf(factor)), this.currency); }
}
public class TransferService {
public void transfer(Account from, Account to, Money amount) {
if (from.getBalance().lessThan(amount)) {
throw new DomainException("Insufficient balance");
}
from.debit(amount);
to.credit(amount);
}
}3.3 Repository Pattern
public interface OrderRepository {
void save(Order order);
Optional<Order> findById(OrderId id);
List<Order> findByCustomerId(CustomerId customerId);
List<Order> findByStatus(OrderStatus status);
}
@Repository
public class JpaOrderRepository implements OrderRepository {
@Autowired
private OrderJpaRepository jpaRepository;
@Override
public void save(Order order) {
OrderEntity entity = toEntity(order);
jpaRepository.save(entity);
}
@Override
public Optional<Order> findById(OrderId id) {
return jpaRepository.findById(id.getValue()).map(this::toDomain);
}
private OrderEntity toEntity(Order order) { /* conversion logic */ }
private Order toDomain(OrderEntity entity) { /* conversion logic */ }
}4. Architecture Views
4.1 4+1 View Model
4+1 view model diagram
┌─────────────────────────────────────────────────┐
│ Scenarios (Use Cases) │
│ ──► Logical View ──► Development View ──► Process View │
│ (modules/classes) (code organization) (threads/processes) │
│ ▼ ▼
│ Physical View (deployment, hardware, load‑balancing) │
└─────────────────────────────────────────────────┘4.2 Architecture Decision Record (ADR‑001)
# ADR-001: Adopt Microservice Architecture
## Status
Accepted
## Background
Monolithic application suffers from code bloat, limited deployment frequency, high coordination cost, and stagnant tech stack.
## Decision
Adopt microservices, split system into user‑service, order‑service, payment‑service, notification‑service.
## Consequences
### Positive
- Independent deployment reduces release risk.
- Tech stacks can evolve per service.
- Team autonomy improves efficiency.
- Individual services can be scaled separately.
### Negative
- Added distributed system complexity.
- Inter‑service communication overhead.
- Data consistency challenges.
- Increased operational burden.
## Alternatives
1. Modular monolith – a compromise.
2. Service mesh – future evolution.4.3 Architecture Review Checklist
Architecture review checklist diagram
┌─────────────────────────────────────────────────┐
│ Functional │ • Requirement coverage
│ │ • RESTful API compliance
│ │ • Error handling completeness
│ │ • Logging completeness
│
│ Scalability │ • Horizontal scaling support
│ │ • Stateless design
│ │ • Read/write DB separation
│ │ • Reasonable caching strategy
│
│ Availability│ • Circuit‑breaker & fallback
│ │ • Timeout controls
│ │ • Retry mechanisms
│ │ • Data backup
│
│ Security │ • Authentication & authorization
│ │ • Sensitive data encryption
│ │ • Injection protection
│ │ • Audit logging
│
│ Maintainability│ • Layered architecture adherence
│ • Unified exception handling
│ • Clear dependencies
│ • Unit test coverage
│
│ Performance│ • QPS/TPS meets expectations
│ │ • Response time within acceptable range
│ │ • Reasonable resource utilization
│ │ • Performance test reports available
└─────────────────────────────────────────────────┘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.
Long Ge's Treasure Box
I'm Long Ge, and this is my treasure chest—packed with cutting‑edge tech insights, career‑advancement tips, and a touch of relaxation you crave. Open it daily for a new surprise.
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.
