Fundamentals 11 min read

Understanding Layered Architecture and Hexagonal Design in Software Systems

This article explains the purpose and benefits of layered software architecture, compares traditional three‑tier designs with hexagonal architecture, discusses system splitting and micro‑service considerations, and provides C# code examples illustrating domain, application, and adapter layers.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Understanding Layered Architecture and Hexagonal Design in Software Systems

Starting with Layers

The article begins by stating that system architects, technical managers, and developers all have their own ideas about how to divide system responsibilities, but the common goal is to build high‑performance, highly available, scalable, and secure systems. Stability is paramount for end users.

It traces the evolution from procedural programming to object‑oriented design and micro‑service solutions, emphasizing that layering—whether at the class level or the distributed deployment level—drives architectural elegance.

Layering is presented as a fundamental software‑engineering technique that splits a system into logical layers, each with clear responsibilities, allowing coordinated functionality.

UI layer – handles user interface responsibilities.

Business layer – handles business‑logic responsibilities.

Data‑persistence layer – handles data storage and persistence.

The article also references the OSI model and a four‑layer network model as analogous examples of layered design.

Benefits of Layered Design

Clear responsibilities and dependencies for each layer.

Reusability reduces code duplication.

Independent modification and extension without affecting other layers.

It argues that while some technical leaders dismiss three‑tier architecture, it remains a practical choice for many medium‑size projects, and that DDD is not a silver bullet.

System Splitting

As business complexity grows, systems inevitably split into more subsystems, creating deployment and operational challenges that drive the adoption of automation tools like Kubernetes.

Splitting is usually driven by business boundaries, leading to physical isolation of code and databases to achieve high cohesion and low coupling.

Architectural Design

When each service can scale horizontally or vertically, micro‑service advantages become evident, yet designing a good monolith still requires patterns, data structures, algorithms, and abstraction—three‑tier architecture being one option.

Business‑driven design is essential; recognizing change points (e.g., sending welcome messages) guides abstraction.

For large systems, DDD aligns better with real‑world abstractions, and the hexagonal architecture offers a useful alternative.

Hexagonal Architecture Design

Hexagonal (or ports‑and‑adapters) architecture is a layered approach where the domain model sits at the core, surrounded by an application layer, and external systems interact through ports and adapters.

Ports expose protocols (often APIs) and adapters translate between the core and external systems, enabling consistent driving of the application and isolation for testing.

Domain layer – core business concepts, state, rules, and behavior.

Application layer – coordinates domain objects to fulfill use cases and manages transactions.

Input ports – receive external requests (e.g., APIs).

Output ports – provide services such as persistence, messaging, or external APIs.

The article demonstrates a user‑registration use case with C# code illustrating the domain object, application service, and adapters.

//用户领域对象
public class UserDomain
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    //注册新用户行为
    public int UpdateName(string name)
    {
        IUserDomainRepositoryAdpater resAdapter = /* ioc获取实例 */;
        return resAdapter.UpdateUserName(this.UserId, name);
    }
}

Application layer that uses the domain and sends a welcome message:

public class UserApplication
{
    public int UpdateUserName(int userId, string name)
    {
        UserDomain user = new UserDomain { UserId = userId, UserName = name };
        user.UpdateName("新用户名");
        ISendMessageAdpater sendMessage = /* ioc获取实例 */;
        sendMessage.SendMessage(userId.ToString(), "新用户注册");
    }
}
public interface ISendMessageAdpater
{
    void SendMessage(string user, string content);
}

Adapter implementations for persistence and messaging:

//外部的adapter实现
public class UserDomainRepositoryAdpater : IUserDomainRepositoryAdpater
{
    public int UpdateUserName(int userId, string name)
    {
        //具体的SQL执行过程
    }
}

public class SendEmailAdpater : ISendMessageAdpater
{
    public void SendMessage(string user, string content)
    {
        //发送邮件实现
    }
}

public class SendPhoneCodeAdpater : ISendMessageAdpater
{
    public void SendMessage(string user, string content)
    {
        //发送短信实现
    }
}

These examples show how hexagonal architecture separates core business logic from external concerns, allowing adapters to be swapped without affecting the domain model.

Software ArchitecturemicroservicesDomain-Driven DesignChexagonal architecturelayered design
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

login 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.