VibeKoding / Ensiklopedia Β· Fondasi KuatEnsiklopedia Β· Fondasi Kuat / Principles of Backend Layered ArchitecturePrinciples of Backend Layered Architecture
VK

Principles of Backend Layered ArchitecturePrinciples of Backend Layered Architecture

πŸ“š Ensiklopedia Β· Fondasi KuatEnsiklopedia Β· Fondasi Kuat 🌏 Dual Bahasa (ID / EN) ⚑ VibeKoding Native

Ensiklopedia VibeKoding: Principles of Backend Layered Architecture.Ensiklopedia VibeKoding: Principles of Backend Layered Architecture.

> Core Question: As code grows more chaotic, how should you organize it to stay clear and understandable?> Core Question: As code grows more chaotic, how should you organize it to stay clear and understandable?

When a project expands from dozens of lines to tens of thousands, from solo development to team collaboration, and from simple CRUD to complex business logic, the way code is organized directly determines the project's survival. Layered architecture is not about showing off or following dogma β€” it exists to resolve a fundamental contradiction in software engineering: the clash between the natural growth of business complexity and the limited capacity of human cognition.When a project expands from dozens of lines to tens of thousands, from solo development to team collaboration, and from simple CRUD to complex business logic, the way code is organized directly determines the project's survival. Layered architecture is not about showing off or following dogma β€” it exists to resolve a fundamental contradiction in software engineering: the clash between the natural growth of business complexity and the limited capacity of human cognition.

------

1. Motivation for Layersing1. Motivation for Layersing

1.1 The Root of the Problem1.1 The Root of the Problem

Early version (100 lines of code):Early version (100 lines of code):

java
@PostMapping("/register") public Result register(@RequestBody User user) { // 1. Check if username already exists if (userRepository.findByUsername(user.getUsername()) != null) { return Result.error("Username already exists"); } // 2. Encrypt password user.setPassword(encrypt(user.getPassword())); // 3. Save user userRepository.save(user); // 4. Send welcome email emailService.sendWelcome(user.getEmail()); // 5. Log log.info("User registered: {}", user.getUsername()); return Result.success(); }

6 months later (500 lines of code):6 months later (500 lines of code):

Now this method is 500 lines, and every change is nerve-wracking because:Now this method is 500 lines, and every change is nerve-wracking because:

The essence of the problem: code has no "boundaries"; all responsibilities are mixed together.The essence of the problem: code has no "boundaries"; all responsibilities are mixed together.

The compounding effect of technical debt:The compounding effect of technical debt:

1.2 The Core Idea of Layering1.2 The Core Idea of Layering

Layered architecture draws clear boundaries for code:Layered architecture draws clear boundaries for code:

CODE
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Accept requests ← Controller β”‚ Only responsible for "taking orders" β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Business orchestration ← Service β”‚ Only responsible for "cooking" β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Data access ← Repository β”‚ Only responsible for "fetching ingredients" β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Business definition ← Domain β”‚ Only responsible for "recipe standards" β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key principles:Key principles:

Engineering value of layered architecture:Engineering value of layered architecture:

  1. Reduces cognitive load: Developers can focus on the responsibilities of the current layer without understanding every global detailReduces cognitive load: Developers can focus on the responsibilities of the current layer without understanding every global detail
  2. Improves testability: Each layer can be unit-tested independently by mocking dependenciesImproves testability: Each layer can be unit-tested independently by mocking dependencies
  3. Enhances maintainability: When requirements change, the scope of modifications is clear, reducing riskEnhances maintainability: When requirements change, the scope of modifications is clear, reducing risk
  4. Promotes code reuse: Business logic is not tied to HTTP β€” it can be reused in scheduled tasks and message queuesPromotes code reuse: Business logic is not tied to HTTP β€” it can be reused in scheduled tasks and message queues
  5. Supports team collaboration: Different developers can work on different layers in parallel, reducing conflictsSupports team collaboration: Different developers can work on different layers in parallel, reducing conflicts
  6. Extends code lifespan: Clear boundaries make code easier to refactor and evolveExtends code lifespan: Clear boundaries make code easier to refactor and evolve
  7. ------

    2. The Four-Layer Architecture in Detail2. The Four-Layer Architecture in Detail

    2.1 Overall Structure2.1 Overall Structure

    The essence of layered architecture is Separation of Concerns and dependency direction control:The essence of layered architecture is Separation of Concerns and dependency direction control:

    CODE
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Frontend request β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ HTTP Request β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Controller Layer β”‚ β”‚ - Accept requests, validate parameters β”‚ β”‚ - DTO conversion β”‚ β”‚ - Call Service β”‚ β”‚ - Return response β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Business call β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Service Layer β”‚ β”‚ - Business logic orchestration β”‚ β”‚ - Transaction management β”‚ β”‚ - Coordinate multiple Repositories β”‚ β”‚ - Cross-module coordination β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Data access β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Repository Layer β”‚ β”‚ - Database CRUD β”‚ β”‚ - Query encapsulation β”‚ β”‚ - ORM mapping β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ Domain objects β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Domain Layer β”‚ β”‚ - Entity β”‚ β”‚ - Value Object β”‚ β”‚ - Business rules β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    

    Dependency direction: Code dependencies must point toward more stable, more abstract directionsDependency direction: Code dependencies must point toward more stable, more abstract directions

    • Controller depends on Service interface (abstraction)Controller depends on Service interface (abstraction)
    • Service depends on Repository interface (abstraction)Service depends on Repository interface (abstraction)
    • All layers depend on Domain (business core, most stable)All layers depend on Domain (business core, most stable)
    • Reverse dependencies are forbidden (e.g., Repository depending on Service)Reverse dependencies are forbidden (e.g., Repository depending on Service)

    2.2 Controller Layer2.2 Controller Layer

    Responsibility: The "receptionist" for requestsResponsibility: The "receptionist" for requests

    • Accept HTTP requests, parse parametersAccept HTTP requests, parse parameters
    • Validate parameters (format, required fields, etc.)Validate parameters (format, required fields, etc.)
    • DTO conversion (Request β†’ Param)DTO conversion (Request β†’ Param)
    • Call Service to execute business logicCall Service to execute business logic
    • DTO conversion (Result β†’ Response)DTO conversion (Result β†’ Response)
    • Return HTTP responseReturn HTTP response

    What it should NOT do:What it should NOT do:

    • Write business logic directlyWrite business logic directly
    • Access the database directlyAccess the database directly
    • Handle transactionsHandle transactions

    Design philosophy:Design philosophy:

    The Controller is the system's "facade," serving as an adapter β€” translating the external HTTP protocol into internal business calls. It should contain no business decisions, because business decisions embody domain knowledge and should be decoupled from the transport protocol.The Controller is the system's "facade," serving as an adapter β€” translating the external HTTP protocol into internal business calls. It should contain no business decisions, because business decisions embody domain knowledge and should be decoupled from the transport protocol.

    Example:Example:

    java
    @RestController @RequestMapping("/api/users") public class UserController { private final UserService userService; @PostMapping public UserResponse createUser( @RequestBody @Valid UserRequest request) { // 1. Request DTO β†’ Param DTO UserParam param = UserParam.builder() .username(request.getUsername()) .password(encrypt(request.getPassword())) .email(request.getEmail()) .build(); // 2. Call Service User user = userService.createUser(param); // 3. Entity β†’ Response DTO return UserResponse.from(user); } }
    

    Key points:Key points:

    • Use @Valid for automatic parameter validationUse @Valid for automatic parameter validation
    • Use DTOs to isolate frontend and backend data structuresUse DTOs to isolate frontend and backend data structures
    • Only do "translation" and "dispatching" β€” no business logicOnly do "translation" and "dispatching" β€” no business logic

    2.3 Service Layer2.3 Service Layer

    Responsibility: The "chef" of the businessResponsibility: The "chef" of the business

    • Implement core business logicImplement core business logic
    • Orchestrate operations across multiple RepositoriesOrchestrate operations across multiple Repositories
    • Manage transaction boundariesManage transaction boundaries
    • Handle cross-module coordinationHandle cross-module coordination

    What it should NOT do:What it should NOT do:

    • Write SQL directly (leave that to Repository)Write SQL directly (leave that to Repository)
    • Handle HTTP-related concernsHandle HTTP-related concerns
    • Return database entities to ControllerReturn database entities to Controller

    Design philosophy:Design philosophy:

    The Service layer carries business logic and should remain pure. It does not depend on any framework or transport protocol, which enables:The Service layer carries business logic and should remain pure. It does not depend on any framework or transport protocol, which enables:

    • Unit testing independent of the web layerUnit testing independent of the web layer
    • Reuse in scheduled tasks and message queue consumersReuse in scheduled tasks and message queue consumers
    • Protection of business logic from technology stack changesProtection of business logic from technology stack changes

    Example:Example:

    java
    @Service @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; private final EmailService emailService; @Transactional public User createUser(UserParam param) { // 1. Business rule: check if username already exists if (userRepository.existsByUsername(param.getUsername())) { throw new UserAlreadyExistsException(); } // 2. Create user entity User user = new User(); user.setUsername(param.getUsername()); user.setPassword(param.getPassword()); user.setEmail(param.getEmail()); // 3. Save to database userRepository.save(user); // 4. Send welcome email (cross-module coordination) emailService.sendWelcomeEmail(user); return user; } }
    

    Key points:Key points:

    • Use @Transactional to guarantee transaction consistencyUse @Transactional to guarantee transaction consistency
    • Throw business exceptions and let the Controller handle them uniformlyThrow business exceptions and let the Controller handle them uniformly
    • No dependency on HTTP concepts β€” reusableNo dependency on HTTP concepts β€” reusable

    2.4 Repository Layer2.4 Repository Layer

    Responsibility: The "warehouse keeper" of dataResponsibility: The "warehouse keeper" of data

    • Encapsulate all data access logicEncapsulate all data access logic
    • Execute CRUD operationsExecute CRUD operations
    • Handle ORM mappingHandle ORM mapping
    • Encapsulate query conditionsEncapsulate query conditions

    What it should NOT do:What it should NOT do:

    • Write business logicWrite business logic
    • Handle transactions (managed by the Service layer)Handle transactions (managed by the Service layer)
    • Depend on upper-layer modulesDepend on upper-layer modules

    Design philosophy:Design philosophy:

    The Repository is an abstraction layer for data access that hides the details of the underlying database. The value of this abstraction lies in:The Repository is an abstraction layer for data access that hides the details of the underlying database. The value of this abstraction lies in:

    • When switching databases, only the Repository implementation needs to change β€” business logic remains untouchedWhen switching databases, only the Repository implementation needs to change β€” business logic remains untouched
    • Easy mocking for unit testingEasy mocking for unit testing
    • Query logic is centrally managed, avoiding duplicate codeQuery logic is centrally managed, avoiding duplicate code

    Example:Example:

    java
    @Repository public interface UserRepository extends JpaRepository<User, Long> { // Automatically implemented by Spring Data JPA Optional<User> findByUsername(String username); boolean existsByUsername(String username); // Custom complex query @Query("SELECT u FROM User u WHERE u.email = :email AND u.deleted = false") Optional<User> findActiveByEmail(@Param("email") String email); }
    

    Key points:Key points:

    • Repository is an interface β€” contains no business logicRepository is an interface β€” contains no business logic
    • Express query intent through method namesExpress query intent through method names
    • Use @Query for custom complex queriesUse @Query for custom complex queries

    2.5 Domain Layer2.5 Domain Layer

    Responsibility: The "recipe standards" of the businessResponsibility: The "recipe standards" of the business

    • Define business entitiesDefine business entities
    • Define value objectsDefine value objects
    • Encapsulate business rulesEncapsulate business rules
    • Serve as the common dependency for all layersServe as the common dependency for all layers

    Important characteristics:Important characteristics:

    • The Domain layer depends on no other layerThe Domain layer depends on no other layer
    • All layers depend on the Domain layerAll layers depend on the Domain layer
    • It is the foundation of the layered architectureIt is the foundation of the layered architecture

    Design philosophy:Design philosophy:

    The Domain layer is the business core of the entire system, expressing domain knowledge and business rules. Its purity is critical:The Domain layer is the business core of the entire system, expressing domain knowledge and business rules. Its purity is critical:

    • Not depending on frameworks means business logic is not held hostage by the technology stackNot depending on frameworks means business logic is not held hostage by the technology stack
    • All layers depending on it ensures the consistency of business rulesAll layers depending on it ensures the consistency of business rules
    • It supports long-term evolution β€” technology stacks can be replaced, but business rules are relatively stableIt supports long-term evolution β€” technology stacks can be replaced, but business rules are relatively stable

    Example:Example:

    java
    @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(unique = true, nullable = false) private String username; @Column(nullable = false) private String password; // βœ… Business method: encapsulates business rules public boolean isPasswordCorrect(String rawPassword) { return BCrypt.checkpw(rawPassword, this.password); } public void changePassword(String oldPassword, String newPassword) { if (!isPasswordCorrect(oldPassword)) { throw new IncorrectPasswordException(); } this.password = BCrypt.hashpw(newPassword); } }
    

    Key points:Key points:

    • Entities have unique identifiersEntities have unique identifiers
    • Business rules are encapsulated in Domain objectsBusiness rules are encapsulated in Domain objects
    • The Domain layer is pure business logic, not dependent on any frameworkThe Domain layer is pure business logic, not dependent on any framework

    ------

    3. DTO: The "Translator" Between Layers3. DTO: The "Translator" Between Layers

    3.1 Motivation for DTOsing3.1 Motivation for DTOsing

    The problem: If you return database entities directly to the frontend:The problem: If you return database entities directly to the frontend:

    java
    // ❌ Wrong: directly returning Entity @Entity public class User { private Long id; private String username; private String password; // Sensitive information! private Boolean isDeleted; // Internal field! }
    

    The frontend would receive fields that should never be exposed, creating security risks.The frontend would receive fields that should never be exposed, creating security risks.

    The solution: Use DTOs as "translators"The solution: Use DTOs as "translators"

    CODE
    Database Entity β†’ Service Param/Result β†’ Controller Request/Response β†’ Frontend
    

    3.2 Types of DTOs3.2 Types of DTOs

    TypePurposeExample
    Request DTOController receives parametersUserCreateRequest
    Response DTOController returns dataUserResponse
    Param DTOService method parametersUserParam
    Result DTOService returns resultsUserResult
    EntityDatabase mappingUser

    Key principle:Key principle:

    Each layer uses its own DTOs β€” never pass entities directly. DTOs contain only necessary fields, which avoids exposing internal implementation details and preserves the independence of each layer.Each layer uses its own DTOs β€” never pass entities directly. DTOs contain only necessary fields, which avoids exposing internal implementation details and preserves the independence of each layer.

    ------

    4. Dependency Direction: The Iron Rule of Layered Architecture4. Dependency Direction: The Iron Rule of Layered Architecture

    4.1 Dependency Inversion Principle4.1 Dependency Inversion Principle

    Wrong approach:Wrong approach:

    CODE
    Controller β†’ UserServiceImpl β†’ UserDaoImpl β†’ UserEntity
    

    Correct approach:Correct approach:

    CODE
    Controller β†’ UserService (interface) β†’ UserRepository (interface) β†’ UserEntity
    

    Dependency direction:Dependency direction:

    The correct dependency direction has all layers depending on more abstract, more stable layers. Specifically, Controller depends on the Service interface, Service depends on the Repository interface, all layers depend on the Domain layer, and the Domain layer depends on no other layer. This dependency direction ensures the independence and testability of business logic.The correct dependency direction has all layers depending on more abstract, more stable layers. Specifically, Controller depends on the Service interface, Service depends on the Repository interface, all layers depend on the Domain layer, and the Domain layer depends on no other layer. This dependency direction ensures the independence and testability of business logic.

    Wrong practices include Service directly depending on a Repository implementation class, Controller directly accessing the database, or the Domain layer depending on other layers β€” all of which increase coupling and reduce system maintainability.Wrong practices include Service directly depending on a Repository implementation class, Controller directly accessing the database, or the Domain layer depending on other layers β€” all of which increase coupling and reduce system maintainability.

    4.2 Code Example4.2 Code Example

    java
    // βœ… Correct: depends on interfaces @Service public class OrderService { private final OrderRepository orderRepository; // interface private final PaymentService paymentService; // interface } // βœ… Implementation class injected automatically by Spring @Repository public class OrderRepositoryImpl implements OrderRepository { // Implementation details }
    

    ------

    5. Real-World Case Study: E-Commerce Order System5. Real-World Case Study: E-Commerce Order System

    5.1 Requirements5.1 Requirements

    Creating an order:Creating an order:

    1. User selects productsUser selects products
    2. Check inventoryCheck inventory
    3. Calculate total amountCalculate total amount
    4. Create the orderCreate the order
    5. Deduct inventoryDeduct inventory
    6. 5.2 Implementation5.2 Implementation

      Domain Layer:Domain Layer:

      java
      @Entity public class Order { @Id private Long id; private Long userId; private List<OrderItem> items; private Money totalAmount; private OrderStatus status; public void calculateTotal() { Money total = Money.zero(); for (OrderItem item : items) { total = total.add(item.getSubTotal()); } this.totalAmount = total; } public void cancel() { if (this.status != OrderStatus.PENDING_PAYMENT) { throw new IllegalStateException("Only pending-payment orders can be cancelled"); } this.status = OrderStatus.CANCELLED; } }
      

      Repository Layer:Repository Layer:

      java
      @Repository public interface OrderRepository extends JpaRepository<Order, Long> { List<Order> findByUserIdOrderByCreatedAtDesc(Long userId); }
      

      Service Layer:Service Layer:

      java
      @Service @RequiredArgsConstructor public class OrderService { private final OrderRepository orderRepository; private final InventoryService inventoryService; @Transactional public OrderDTO createOrder(OrderParam param) { // 1. Validate products and reserve inventory for (OrderItemParam item : param.getItems()) { inventoryService.reserveStock(item.getProductId(), item.getQuantity()); } // 2. Create order Order order = new Order(); order.setUserId(param.getUserId()); order.calculateTotal(); // 3. Save order orderRepository.save(order); return OrderDTO.from(order); } }
      

      Controller Layer:Controller Layer:

      java
      @RestController @RequestMapping("/api/orders") public class OrderController { private final OrderService orderService; @PostMapping public OrderResponse createOrder(@RequestBody @Valid OrderRequest request) { OrderParam param = OrderParam.builder() .userId(request.getUserId()) .items(request.getItems()) .build(); OrderDTO order = orderService.createOrder(param); return OrderResponse.from(order); } }
      

      ------

      6. Frequently Asked Questions6. Frequently Asked Questions

      6.1 Can the Controller contain business logic6.1 Can the Controller contain business logic

      The Controller should not contain business logic β€” it is only responsible for accepting requests and returning responses. Business logic should be encapsulated in the Service layer. The benefit is that code can be reused: for example, scheduled tasks or message queue consumers can directly call the Service without going through HTTP. Additionally, business logic concentrated in one place is easier to test and maintain, avoiding inconsistencies caused by scattered logic.The Controller should not contain business logic β€” it is only responsible for accepting requests and returning responses. Business logic should be encapsulated in the Service layer. The benefit is that code can be reused: for example, scheduled tasks or message queue consumers can directly call the Service without going through HTTP. Additionally, business logic concentrated in one place is easier to test and maintain, avoiding inconsistencies caused by scattered logic.

      6.2 Overview of the Anemic Domain Model and Rich Domain Model6.2 Overview of the Anemic Domain Model and Rich Domain Model

      The Anemic Domain Model means entity classes contain only properties and their corresponding getter/setter methods, with no business logic β€” all business rules reside in the Service layer. This model is simple in structure, easy to understand, and is the approach adopted by most projects.The Anemic Domain Model means entity classes contain only properties and their corresponding getter/setter methods, with no business logic β€” all business rules reside in the Service layer. This model is simple in structure, easy to understand, and is the approach adopted by most projects.

      The Rich Domain Model means entity classes contain not only properties but also business methods related to the entity, encapsulating business rules within the entity itself. This approach aligns better with object-oriented design principles, keeping data and behavior together and improving code cohesion.The Rich Domain Model means entity classes contain not only properties but also business methods related to the entity, encapsulating business rules within the entity itself. This approach aligns better with object-oriented design principles, keeping data and behavior together and improving code cohesion.

      It is recommended to choose the model based on the team's technical background and project complexity. Whichever you choose, maintain consistency, and the Domain layer should at least include basic behavioral methods rather than being a completely empty shell.It is recommended to choose the model based on the team's technical background and project complexity. Whichever you choose, maintain consistency, and the Domain layer should at least include basic behavioral methods rather than being a completely empty shell.

      6.3 Approach to handling transactions that span multiple Services6.3 Approach to handling transactions that span multiple Services

      When a business operation needs to span multiple Services, use a @Transactional annotation on the upper-level Service method, and within that method, call the lower-level Services in sequence. This ensures all operations execute within the same transaction context β€” either all succeed or all fail, maintaining data consistency. Note that transaction boundaries should be as small as possible, including only necessary operations, to avoid holding database locks for extended periods and affecting concurrency performance.When a business operation needs to span multiple Services, use a @Transactional annotation on the upper-level Service method, and within that method, call the lower-level Services in sequence. This ensures all operations execute within the same transaction context β€” either all succeed or all fail, maintaining data consistency. Note that transaction boundaries should be as small as possible, including only necessary operations, to avoid holding database locks for extended periods and affecting concurrency performance.

      ------

      7. Summary7. Summary

      LayerResponsibilityKeywords
      ControllerAccept requests, validate parameters, call Service, return responseReceptionist
      ServiceBusiness logic orchestration, transaction management, coordinate RepositoryChef
      RepositoryData access, ORM mapping, query encapsulationWarehouse Keeper
      DomainEntity definition, business rules, value objectsRecipe Standards

      Core principles:Core principles:

      1. Each layer does only its own jobEach layer does only its own job
      2. Layers communicate through interfacesLayers communicate through interfaces
      3. Business logic is concentrated in Service and DomainBusiness logic is concentrated in Service and Domain
      4. Data access logic is concentrated in RepositoryData access logic is concentrated in Repository
      5. Use DTOs to isolate data structures between layersUse DTOs to isolate data structures between layers
      6. ------

        8. More Architectural Patterns8. More Architectural Patterns

        This article introduces Layered Architecture, the most common and easiest backend architecture pattern to get started with. But backend architecture goes far beyond this one pattern β€” depending on the business context, there are other architectural patterns worth understanding:This article introduces Layered Architecture, the most common and easiest backend architecture pattern to get started with. But backend architecture goes far beyond this one pattern β€” depending on the business context, there are other architectural patterns worth understanding:

        8.1 Other Common Architectural Patterns8.1 Other Common Architectural Patterns

        PatternUse CaseCharacteristics
        Monolithic ArchitectureSmall projects, MVPAll functionality in a single application, simple deployment
        Microservices ArchitectureLarge, complex systemsSplit into multiple independent services, each independently deployable
        Event-Driven ArchitectureHigh concurrency, async processingProcessing flows triggered by events, highly decoupled
        Clean ArchitectureComplex business systemsBusiness logic at the center, dependencies only point inward, frameworks on the outermost layer
        Hexagonal ArchitectureSystems needing diverse external adaptersIsolates core from external systems through ports and adapters
        Onion ArchitectureDomain-Driven DesignConcentric layers, domain model innermost, infrastructure outermost

        Let's explore each one:Let's explore each one:

        Monolithic ArchitectureMonolithic Architecture

        All functionality packaged in a single application, sharing one database and one process.All functionality packaged in a single application, sharing one database and one process.

        CODE
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Monolithic App β”‚ β”‚ β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β” β”‚ β”‚ β”‚Userβ”‚ β”‚Orderβ”‚ β”‚Pay β”‚ ... β”‚ β”‚ β””β”€β”€β”¬β”€β”˜ β””β”€β”€β”¬β”€β”˜ β””β”€β”€β”¬β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ Shared Database β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        
        • Pros: Simple to develop, easy to deploy, straightforward local debuggingPros: Simple to develop, easy to deploy, straightforward local debugging
        • Cons: High code coupling, hard to scale, one module failure can bring down the entire systemCons: High code coupling, hard to scale, one module failure can bring down the entire system
        • Best for: Early-stage startups, single-team development, rapid prototype validationBest for: Early-stage startups, single-team development, rapid prototype validation

        Microservices ArchitectureMicroservices Architecture

        Splits the system into multiple independent services, each with its own data and business logic, independently deployable and scalable.Splits the system into multiple independent services, each with its own data and business logic, independently deployable and scalable.

        CODE
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚User Svcβ”‚ β”‚Order Svcβ”‚ β”‚Pay Svc β”‚ β”‚ DB-1 β”‚ β”‚ DB-2 β”‚ β”‚ DB-3 β”‚ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ API Gateway
        
        • Pros: Independent deployment and scaling, flexible technology stack, fault isolationPros: Independent deployment and scaling, flexible technology stack, fault isolation
        • Cons: Complex inter-service communication, challenging distributed data consistency, requires mature DevOps capabilitiesCons: Complex inter-service communication, challenging distributed data consistency, requires mature DevOps capabilities
        • Best for: Large complex systems, multi-team collaboration, scenarios requiring independent scalingBest for: Large complex systems, multi-team collaboration, scenarios requiring independent scaling

        Event-Driven ArchitectureEvent-Driven Architecture

        Communication through asynchronous events β€” producers emit events, consumers respond to events, with highly decoupled components.Communication through asynchronous events β€” producers emit events, consumers respond to events, with highly decoupled components.

        CODE
        Producer ──→ [Event Bus / Message Queue] ──→ Consumer A ──→ Consumer B ──→ Consumer C
        
        • Pros: Highly decoupled, naturally supports scaling, ideal for real-time processingPros: Highly decoupled, naturally supports scaling, ideal for real-time processing
        • Cons: Difficult debugging, event ordering and idempotency require extra handlingCons: Difficult debugging, event ordering and idempotency require extra handling
        • Best for: Real-time data analysis, IoT systems, async communication between microservicesBest for: Real-time data analysis, IoT systems, async communication between microservices

        Clean ArchitectureClean Architecture

        Proposed by Robert C. Martin, the system is divided into four concentric layers with dependencies pointing only inward:Proposed by Robert C. Martin, the system is divided into four concentric layers with dependencies pointing only inward:

        CODE
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Frameworks & Drivers β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Interface Adapters β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ Use Cases β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ Entities β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ (Domain) β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Dependency direction: outer β†’ inner
        
        • Core rule: Inner layers know nothing about outer layers; business logic is completely independent of frameworks and databasesCore rule: Inner layers know nothing about outer layers; business logic is completely independent of frameworks and databases
        • Pros: High testability, replaceable technology stack, clear business logicPros: High testability, replaceable technology stack, clear business logic
        • Cons: Higher initial development cost, lots of inter-layer mapping code, risk of over-engineering in small projectsCons: Higher initial development cost, lots of inter-layer mapping code, risk of over-engineering in small projects
        • Best for: Complex business systems, projects requiring long-term maintenanceBest for: Complex business systems, projects requiring long-term maintenance

        Hexagonal Architecture (Ports & Adapters)Hexagonal Architecture (Ports & Adapters)

        Defines input/output interfaces for the core business through "ports," and connects external systems through "adapters":Defines input/output interfaces for the core business through "ports," and connects external systems through "adapters":

        CODE
         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” HTTP ──→ Port β”‚ CLI ──→ (Inbound) β”‚ Core Business β”‚ (Outbound) ──→ Database MQ ──→ β”‚ Logic β”‚ Port ──→ External API β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        
        • Core idea: Business logic does not depend on any external technology; external systems connect through adaptersCore idea: Business logic does not depend on any external technology; external systems connect through adapters
        • Pros: External systems can be freely swapped; testing only requires mock adaptersPros: External systems can be freely swapped; testing only requires mock adapters
        • Best for: Scenarios requiring integration with diverse external systemsBest for: Scenarios requiring integration with diverse external systems

        Onion ArchitectureOnion Architecture

        Similar to Clean Architecture, emphasizes the domain model at the innermost layer and infrastructure at the outermost, with dependencies only pointing inward:Similar to Clean Architecture, emphasizes the domain model at the innermost layer and infrastructure at the outermost, with dependencies only pointing inward:

        CODE
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Infrastructure β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Application Services β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ Domain Services β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚Domain Modelβ”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        
        • Core idea: The domain model is the core of the system; all dependencies point toward itCore idea: The domain model is the core of the system; all dependencies point toward it
        • Difference from Clean Architecture: Onion Architecture emphasizes the domain service layer more; Clean Architecture emphasizes the use case layer moreDifference from Clean Architecture: Onion Architecture emphasizes the domain service layer more; Clean Architecture emphasizes the use case layer more
        • Best for: Projects adopting Domain-Driven Design (DDD)Best for: Projects adopting Domain-Driven Design (DDD)

        8.2 Architecture Evolution Path8.2 Architecture Evolution Path

        These architectures are not mutually exclusive alternatives β€” they represent a gradual evolution:These architectures are not mutually exclusive alternatives β€” they represent a gradual evolution:

        text
        Traditional Layered Architecture (N-Layered) β”‚ Problem: inter-layer coupling, hard to replace external dependencies β–Ό Hexagonal Architecture (Ports & Adapters) β”‚ Improvement: use ports and adapters to isolate external systems β–Ό Onion Architecture β”‚ Improvement: explicit concentric layering, domain model at the center β–Ό Clean Architecture β”‚ Improvement: unified dependency rules, clear four-layer responsibilities β–Ό Choose the right architecture based on business needs
        

        8.3 Architecture Selection Guide8.3 Architecture Selection Guide

        text
        Users < 1k, Code < 5,000 lines ↓ Monolithic + Simple Layering ↓ Users 1k–100k, requires multi-team collaboration ↓ Layered Architecture (this article) ↓ Users > 100k, high business complexity ↓ Microservices / Event-Driven Architecture
        

        More detailed selection dimensions:More detailed selection dimensions:

        FactorSimple LayeringClean/Hexagonal ArchitectureMicroservices
        Team size1–5 people5–20 people20+ people
        Business complexityLowMedium–HighHigh
        Deployment frequencyLowMediumHigh (independent deployment)
        Technology stack diversitySingleSingleCan be diverse
        Operations costLowMediumHigh

        8.4 Recommended Reading8.4 Recommended Reading

        • Monolithic Architecture: See the companion article [backend-project-architecture.md](./backend-project-architecture.md) for the evolution from scripts to monolithsMonolithic Architecture: See the companion article [backend-project-architecture.md](./backend-project-architecture.md) for the evolution from scripts to monoliths
        • Microservices Architecture: See [From Monolith to Microservices](/en/appendix/6-architecture-and-system-design/monolith-to-microservices)Microservices Architecture: See [From Monolith to Microservices](/en/appendix/6-architecture-and-system-design/monolith-to-microservices)
        • Clean Architecture: Robert C. Martin's Clean Architecture β€” the classic that introduced dependency rules and the four-layer concentric modelClean Architecture: Robert C. Martin's Clean Architecture β€” the classic that introduced dependency rules and the four-layer concentric model
        • Enterprise Architecture Patterns: Martin Fowler's Patterns of Enterprise Application Architecture β€” the authoritative reference on layered architecture and domain logic organizationEnterprise Architecture Patterns: Martin Fowler's Patterns of Enterprise Application Architecture β€” the authoritative reference on layered architecture and domain logic organization

        8.5 Approach to choosing8.5 Approach to choosing

        Remember this principle: Architecture serves the business β€” don't do architecture for architecture's sake.Remember this principle: Architecture serves the business β€” don't do architecture for architecture's sake.

        • Small projects: use simple architecture, ship fast to validateSmall projects: use simple architecture, ship fast to validate
        • Large projects: consider complex architecture when needed, avoid over-engineeringLarge projects: consider complex architecture when needed, avoid over-engineering
        • Team familiarity matters too β€” choose solutions everyone can understandTeam familiarity matters too β€” choose solutions everyone can understand

        ------

        9. Summary9. Summary

        LayerResponsibilityKeywords
        ControllerAccept requests, validate parameters, call Service, return responseReceptionist
        ServiceBusiness logic orchestration, transaction management, coordinate RepositoryChef
        RepositoryData access, ORM mapping, query encapsulationWarehouse Keeper
        DomainEntity definition, business rules, value objectsRecipe Standards

        Core principles:Core principles:

        The core of layered architecture lies in clear responsibility division and dependency direction control. Each layer focuses only on its own responsibilities, communicates with adjacent layers through interfaces, concentrates business logic in the Service and Domain layers, concentrates data access logic in the Repository layer, and isolates data structures between layers through DTOs to avoid directly exposing internal implementation. This design makes the system easier to understand, test, and maintain, capable of supporting continuous business evolution.The core of layered architecture lies in clear responsibility division and dependency direction control. Each layer focuses only on its own responsibilities, communicates with adjacent layers through interfaces, concentrates business logic in the Service and Domain layers, concentrates data access logic in the Repository layer, and isolates data structures between layers through DTOs to avoid directly exposing internal implementation. This design makes the system easier to understand, test, and maintain, capable of supporting continuous business evolution.

        ------

        ReferencesReferences

        1. [Catalog of Patterns of Enterprise Application Architecture - Martin Fowler](https://www.martinfowler.com/eaaCatalog/) β€” Martin Fowler's catalog of enterprise application architecture patterns, the classic reference for layered architecture[Catalog of Patterns of Enterprise Application Architecture - Martin Fowler](https://www.martinfowler.com/eaaCatalog/) β€” Martin Fowler's catalog of enterprise application architecture patterns, the classic reference for layered architecture
        2. [Backend Side Architecture Evolution (N-layered, DDD, Hexagon, Onion, Clean Architecture)](https://medium.com/@iamprovidence/backend-side-architecture-evolution-n-layered-ddd-hexagon-onion-clean-architecture-643d72444ce4) β€” The evolution from N-Layered to Clean Architecture, understanding why each pattern emerged[Backend Side Architecture Evolution (N-layered, DDD, Hexagon, Onion, Clean Architecture)](https://medium.com/@iamprovidence/backend-side-architecture-evolution-n-layered-ddd-hexagon-onion-clean-architecture-643d72444ce4) β€” The evolution from N-Layered to Clean Architecture, understanding why each pattern emerged
        3. [Complete Guide to Clean Architecture - GeeksforGeeks](https://www.geeksforgeeks.org/complete-guide-to-clean-architecture/) β€” A complete guide to Clean Architecture, covering layers, dependency rules, and separation of concerns[Complete Guide to Clean Architecture - GeeksforGeeks](https://www.geeksforgeeks.org/complete-guide-to-clean-architecture/) β€” A complete guide to Clean Architecture, covering layers, dependency rules, and separation of concerns
        4. [Understanding Hexagonal, Clean, Onion, and Traditional Layered Architectures: A Deep Dive](https://romanglushach.medium.com/understanding-hexagonal-clean-onion-and-traditional-layered-architectures-a-deep-dive-c0f93b8a1b96) β€” An in-depth comparison of Hexagonal, Clean, Onion, and Traditional Layered Architectures[Understanding Hexagonal, Clean, Onion, and Traditional Layered Architectures: A Deep Dive](https://romanglushach.medium.com/understanding-hexagonal-clean-onion-and-traditional-layered-architectures-a-deep-dive-c0f93b8a1b96) β€” An in-depth comparison of Hexagonal, Clean, Onion, and Traditional Layered Architectures
        5. [Building Clean Architectures in Modern Backend Frameworks](https://leapcell.io/blog/building-clean-architectures-in-modern-backend-frameworks) β€” A practical guide to implementing Clean Architecture in modern backend frameworks[Building Clean Architectures in Modern Backend Frameworks](https://leapcell.io/blog/building-clean-architectures-in-modern-backend-frameworks) β€” A practical guide to implementing Clean Architecture in modern backend frameworks
        6. [Backend Architecture Patterns: From Monoliths to Microservices](https://nerdleveltech.com/backend-architecture-patterns-from-monoliths-to-microservices) β€” A panoramic overview of backend architecture patterns from monoliths to microservices[Backend Architecture Patterns: From Monoliths to Microservices](https://nerdleveltech.com/backend-architecture-patterns-from-monoliths-to-microservices) β€” A panoramic overview of backend architecture patterns from monoliths to microservices
        7. [MVC Three-Layer Architecture Case Study](https://www.cnblogs.com/TheMagicalRainbowSea/p/17409206.html) β€” The relationship between MVC and three-layer architecture with practical examples, suitable for Chinese readers getting started[MVC Three-Layer Architecture Case Study](https://www.cnblogs.com/TheMagicalRainbowSea/p/17409206.html) β€” The relationship between MVC and three-layer architecture with practical examples, suitable for Chinese readers getting started