Fundamentals 14 min read

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.

Long Ge's Treasure Box
Long Ge's Treasure Box
Long Ge's Treasure Box
Mastering Architecture Design Principles: Layered, Cohesive, and DDD Approaches

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
└─────────────────────────────────────────────────┘
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ArchitectureMicroservicesDomain-Driven DesignLayered ArchitectureCouplingCohesionSoftware Design Principles
Long Ge's Treasure Box
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.