178 lines
5.8 KiB
Markdown
178 lines
5.8 KiB
Markdown
---
|
|
id: wiki-2026-0508-관심사의-분리-separation-of-concerns
|
|
title: 관심사의 분리 (Separation of Concerns)
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [SoC, Separation of Concerns, 관심사 분리]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.9
|
|
verification_status: applied
|
|
tags: [soc, modularity, design-principle, architecture]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: agnostic
|
|
framework: agnostic
|
|
---
|
|
|
|
# 관심사의 분리 (Separation of Concerns)
|
|
|
|
## 매 한 줄
|
|
> **"매 system 을 서로 겹치지 않는 concern 단위로 쪼개 각각이 독립 변경 가능하도록 한다"**. Dijkstra (1974) — 매 modularity 의 근본 원리. 매 layer / module / function / file 모든 scale 에 적용. 매 변경의 locality + 매 testability 를 동시에 얻는다.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 SoC 의 본질
|
|
- **Concern**: 매 system 이 처리하는 distinct topic (UI, persistence, billing, auth).
|
|
- **Separation**: 매 concern 별로 코드/모듈/팀/배포 단위 분리.
|
|
- **Independent change**: concern A 의 변경이 B 의 코드 수정 X.
|
|
|
|
### 매 적용 scale
|
|
- **Function**: 매 single responsibility (SRP).
|
|
- **Module**: 매 cohesion 높음 + coupling 낮음.
|
|
- **Layer**: presentation / business / persistence (layered arch).
|
|
- **Service**: bounded context / microservice.
|
|
- **Repository**: monorepo path / multirepo.
|
|
|
|
### 매 응용
|
|
1. MVC / MVP / MVVM.
|
|
2. Clean / Hexagonal Architecture (port-adapter 분리).
|
|
3. Aspect-Oriented Programming (cross-cutting 분리).
|
|
4. Microservice (bounded context 분리).
|
|
5. CSS-in-JS vs separate stylesheet — 매 variant.
|
|
|
|
## 💻 패턴
|
|
|
|
### Function-level: 매 1 함수 = 1 개념
|
|
```typescript
|
|
// ❌ Mixed
|
|
function processOrder(input: any) {
|
|
if (!input.email) throw new Error("invalid"); // validation
|
|
const tax = input.amount * 0.1; // tax calc
|
|
db.execute("INSERT INTO orders ..."); // persistence
|
|
smtp.send(input.email, "Confirmed"); // notification
|
|
}
|
|
|
|
// ✅ Separated
|
|
function validate(input: OrderInput): Order { /* ... */ return order; }
|
|
function computeTax(order: Order): Money { /* ... */ }
|
|
async function persist(order: Order, tax: Money): Promise<OrderId> { /* ... */ }
|
|
async function notify(order: Order): Promise<void> { /* ... */ }
|
|
async function processOrder(input: OrderInput) {
|
|
const order = validate(input);
|
|
const tax = computeTax(order);
|
|
const id = await persist(order, tax);
|
|
await notify(order);
|
|
return id;
|
|
}
|
|
```
|
|
|
|
### Module: 매 dependency direction
|
|
```
|
|
src/
|
|
├── domain/ ← 매 pure logic (no IO)
|
|
├── application/ ← 매 use cases (orchestration)
|
|
├── infrastructure/ ← DB, HTTP, queue
|
|
└── interface/ ← controller, CLI
|
|
```
|
|
|
|
### MVC (web)
|
|
```python
|
|
# model.py
|
|
class User: ...
|
|
|
|
# view.py (template)
|
|
def render_user(user): ...
|
|
|
|
# controller.py
|
|
def get_user(req):
|
|
user = User.find(req.params["id"])
|
|
return render_user(user)
|
|
```
|
|
|
|
### CSS 분리 (concern: layout / theme / interaction)
|
|
```css
|
|
/* layout.css */
|
|
.container { display: grid; grid-template-columns: 240px 1fr; }
|
|
/* theme.css */
|
|
:root { --bg: #fff; --fg: #111; }
|
|
.dark { --bg: #111; --fg: #eee; }
|
|
/* interaction.css */
|
|
.btn:hover { transform: translateY(-1px); }
|
|
```
|
|
|
|
### Hexagonal port-adapter
|
|
```typescript
|
|
// domain port (concern: business)
|
|
export interface OrderRepo {
|
|
save(o: Order): Promise<void>;
|
|
findById(id: OrderId): Promise<Order | null>;
|
|
}
|
|
|
|
// adapter (concern: infra)
|
|
export class PostgresOrderRepo implements OrderRepo { /* SQL */ }
|
|
export class InMemoryOrderRepo implements OrderRepo { /* test */ }
|
|
```
|
|
|
|
### AOP (cross-cutting) — Spring
|
|
```java
|
|
@Aspect @Component
|
|
class TxAspect {
|
|
@Around("@annotation(Transactional)")
|
|
Object inTx(ProceedingJoinPoint pjp) throws Throwable {
|
|
var tx = txManager.begin();
|
|
try { var r = pjp.proceed(); tx.commit(); return r; }
|
|
catch (Throwable t) { tx.rollback(); throw t; }
|
|
}
|
|
}
|
|
// 매 business code 에서 tx 코드 누설 X
|
|
```
|
|
|
|
### Bounded context (microservice 단위)
|
|
```
|
|
billing-service/ ← 매 invoice, charge
|
|
inventory-service/ ← 매 stock
|
|
shipping-service/ ← 매 carrier integration
|
|
# 매 각자 DB, 각자 deploy, 각자 schema
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Approach |
|
|
|---|---|
|
|
| 매 small script | function-level SRP 만 |
|
|
| 매 medium app | layered + module 단위 |
|
|
| 매 complex domain | hexagonal + bounded context |
|
|
| 매 large org | microservice + team boundary |
|
|
| 매 cross-cutting (log, tx, auth) | AOP / middleware / interceptor |
|
|
|
|
**기본값**: 매 layered + DI + interface boundary. 매 over-fragmentation (매 1 함수 1 파일) 의 X.
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[Software Design Principles]]
|
|
- 변형: [[Single Responsibility Principle]] · [[Modularity]] · [[High Cohesion / Low Coupling]]
|
|
- 응용: [[Layered Architecture]] · [[Hexagonal Architecture]] · [[Microservices]]
|
|
- Adjacent: [[SOLID]] · [[Design by Contract]] · [[Aspect-Oriented Programming]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: refactor proposal, code smell detection (mixed concerns), boundary 설정.
|
|
**언제 X**: 매 throwaway script — overhead 만.
|
|
|
|
## ❌ 안티패턴
|
|
- **God Module / God File**: 매 모든 concern 의 mix.
|
|
- **Shotgun Surgery**: 매 1 변경이 매 N 파일 수정 — 매 concern 의 분산 잘못.
|
|
- **Premature decomposition**: 매 unclear boundary 의 microservice 분할 — 매 distributed monolith.
|
|
- **Leaky abstraction**: 매 infra 의 domain 누수 (e.g. ORM annotation 의 domain entity 노출).
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (Dijkstra "On the role of scientific thought" 1974, Parnas "On the Criteria To Be Used in Decomposing Systems into Modules" 1972).
|
|
- 신뢰도 A.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — SoC 본질 + scale + MVC + hexagonal + AOP |
|