Architecture
The principle I consider important in development is clear separation of concerns. Regardless of the architectural pattern, each layer’s responsibility must be clearly separated.
Layer Structure Example (MVC Pattern)
A typical example of layered architecture is the Controller-Service-Repository 3-layer structure:
┌────────────────────────┐
│ Controller Layer │ ← HTTP request/response only
├────────────────────────┤
│ Service Layer │ ← Business logic only
├────────────────────────┤
│ Repository Layer │ ← Database access only
└────────────────────────┘Core Principles:
- Controller calls Service only: Direct Repository calls forbidden
- Service does not invade Repository layer responsibilities: Direct query writing forbidden (utility classes and external service calls are allowed)
- Each layer has single responsibility: Clear separation of concerns between layers
Controller Layer
Role
Controller handles HTTP request/response only.
- Receive and validate HTTP requests
- Call Service layer
- Generate HTTP responses (including status codes, headers)
- DTO transformation (Request DTO → Service, Domain → Response DTO)
Allowed Operations
| |
Forbidden Operations
| |
Service Layer
Role
Service handles business logic only.
- Implement business rules
- Transaction management
- Domain object manipulation
- External service calls (event publishing, external APIs, etc.)
- Combine multiple Repositories
Allowed Operations
| |
Forbidden Operations
| |
Repository Layer
Role
Repository handles database access only.
- CRUD operations
- Query execution
- Data persistence management
Allowed Operations
| |
Forbidden Operations
| |
Data Flow Between Layers
Request Flow (Request → Domain)
| |
Response Flow (Domain → Response)
| |
Service Dependencies
No Same-Layer Calls
| |
Solution 1: Direct Repository Call
| |
Solution 2: Event-Based Communication
| |
Layer-Specific Test Strategy
Controller Test
| |
Service Test
| |
Repository Test
| |
DTO vs Entity Separation (Required)
Never Expose Entity Directly
| |
DTO Conversion Location
Principle: Convert DTO only in Controller
| |
Preventing Circular References
| |
Security
No Logging of Sensitive Information
| |
No Sensitive Information in Exception Messages
| |
SQL Injection Prevention
| |
Performance
Solving N+1 Query Problem
| |
Utilizing @Transactional(readOnly = true)
| |
Pagination Handling
| |
Transaction
Minimize Transaction Scope
| |
Understanding Propagation Options
| |
Concurrency Handling
Optimistic Locking
| |
Pessimistic Locking
| |
Large Data Processing
Batch Processing
| |
EntityManager flush/clear Pattern
| |
Checklist
When writing Controller:
- Depends only on Service? (No Repository dependency)
- Handles only HTTP request/response?
- Contains no business logic?
- Only performs DTO transformation?
- Not returning Entity directly?
When writing Service:
- Depends only on Repository? (No other Service dependency)
- Contains only business logic?
- No HTTP related code? (ResponseEntity, HttpStatus, etc.)
- Manages transactions appropriately?
- Applied @Transactional(readOnly = true) to query methods?
- Solved N+1 problem?
- Not logging sensitive information?
When writing Repository:
- Performs only database access?
- Contains no business logic?
- No event publishing?
- No transaction management? (Managed by Service)
Security:
- Using Prepared Statement to prevent SQL Injection?
- Not logging sensitive information (passwords, tokens)?
- Not including sensitive information in exception messages?
Performance:
- Solved N+1 problem with Fetch Join or @EntityGraph?
- Applied pagination?
- Applied batch processing for large data?
Concurrency:
- Applied Optimistic or Pessimistic Locking for concurrency issues?
- Considered optimistic locking with @Version?