--- id: wiki-2026-0508-뇌와-팔다리의-분리-관심사의-분리-separation-of title: Separation of Concerns (관심사의 분리) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [SoC, 관심사의 분리, separation of concerns, modularity, decoupling, brain-limbs] duplicate_of: none source_trust_level: B confidence_score: 0.85 verification_status: conceptual tags: [architecture, design-principles, modularity, decoupling, srp, hexagonal, ddd, ai-agent-design] raw_sources: [] last_reinforced: 2026-05-09 github_commit: pending inferred_by: Claude Opus 4.7 (manual cleanup 2026-05-09) tech_stack: language: TS / Python / generic applicable_to: [Software Architecture, AI Agent, System Design] --- # Separation of Concerns (관심사의 분리) ## 📌 한 줄 통찰 (The Karpathy Summary) > **"매 module 의 own 역할 — 1 reason to change"**. Dijkstra 1974. SRP / DDD bounded context / hexagonal / module boundary 의 base. **AI agent 의 decision loop + execution tool 의 분리 의 modern 응용**. ## 📖 구조화된 지식 (Synthesized Content) ### 정의 **Edsger Dijkstra (1974)** "On the role of scientific thought": > "Separation of concerns... is what I sometimes have called 'the focusing of attention upon some aspect': it does not mean ignoring the other aspects, it is just that from this aspect's point of view, the other is irrelevant." → 매 aspect 의 focus + 매 다른 aspect 의 irrelevant. ### 핵심 idea 1. **Modularity**: 매 module 의 specific responsibility. 2. **Decoupling**: 매 change 의 ripple ↓. 3. **Boundaries**: 매 concern 의 explicit boundary. 4. **Maintainability**: 매 code 의 understand + modify. ### "뇌와 팔다리" - **뇌 (decision)**: business logic, strategy. - **팔다리 (execution)**: tool, IO, side effect. → 매 brain 의 단일 logic. 매 limb 의 swap 가능. ### 매 응용 #### MVC (Model-View-Controller) - **Model**: data + business rule. - **View**: presentation. - **Controller**: input + flow. #### Hexagonal / Clean Architecture - **Domain**: business rule (core). - **Application**: use case. - **Infrastructure**: DB, API, UI. → 매 inner 의 outer 무관. 매 outer 의 swap. #### DDD (Domain-Driven Design) - **Bounded Context**: 매 domain 의 own model. - 매 different context 의 own language. - 매 ACL (Anti-Corruption Layer) 의 boundary. #### Microservices - 매 service 의 own responsibility. - 매 service 의 own DB. - 매 service 의 own deploy. #### Single Responsibility Principle (SRP) - 매 class / module 의 1 reason to change. - 매 specific actor / use case 의 own. ### 매 game design #### Game logic vs rendering - **Game logic**: rule, state, behavior. - **Rendering**: visual, animation. → 매 server (no rendering) + 매 client (rendering only). #### AI vs game state - **AI**: decision (behavior tree, FSM). - **Game state**: data. → 매 AI 의 different (player, enemy, NPC) + 매 same data structure. ### 매 AI agent #### Decision loop vs execution **옛 monolithic**: 매 logic + execution mixed. ```python def agent_loop(): # Logic + tool call mixed if some_condition: result = direct_db_query(...) elif other: result = direct_api_call(...) return decide(result) ``` **현대 SoC**: 매 decision 의 LLM, 매 tool 의 separate. ```python class Agent: def think(self, context): # 매 reasoning (no side effect) return llm.complete(context) def execute(self, action): # 매 tool call (no reasoning) return self.tools[action.name](action.input) def loop(self): while not done: decision = self.think(context) result = self.execute(decision.action) context = update(context, result) ``` → 매 brain (LLM) + 매 limb (tool) 의 swap 가능. ### 매 모범 example #### React component ```tsx // ❌ Mixed function UserProfile({ userId }) { const [user, setUser] = useState(null); useEffect(() => { fetch(`/api/users/${userId}`) .then(r => r.json()) .then(data => { const formatted = `${data.firstName} ${data.lastName.toUpperCase()}`; setUser({ ...data, fullName: formatted }); }); }, [userId]); return user ?

{user.fullName}

: ; } // ✅ Separated function useUser(userId) { return useQuery(['user', userId], () => api.getUser(userId)); } function formatUser(user) { return { ...user, fullName: `${user.firstName} ${user.lastName.toUpperCase()}` }; } function UserProfile({ userId }) { const { data: user, isLoading } = useUser(userId); if (isLoading) return ; return

{formatUser(user).fullName}

; } ``` → 매 fetching (hook) + 매 formatting (function) + 매 rendering (component) 의 분리. #### Backend API ```python # ❌ Mixed @app.post('/orders') def create_order(req): user = db.execute('SELECT ... FROM users WHERE id = ?', req.user_id).fetchone() if user.balance < req.total: return 400 db.execute('INSERT INTO orders ...') db.execute('UPDATE users SET balance = ?', user.balance - req.total) send_email(user.email, 'Order confirmed') return 200 # ✅ Separated @app.post('/orders') def create_order(req): # HTTP layer return order_service.create(req) class OrderService: # Business logic def __init__(self, user_repo, order_repo, email): self.users = user_repo self.orders = order_repo self.email = email def create(self, req): user = self.users.find(req.user_id) if user.balance < req.total: raise InsufficientFundsError() order = self.orders.create(...) self.users.deduct_balance(req.user_id, req.total) self.email.send_confirmation(user.email, order) return order class UserRepository: # Data access def find(self, user_id): ... def deduct_balance(self, user_id, amount): ... ``` → 매 HTTP / business / data 의 layer 별 분리. ### 매 SoC 의 limit #### Over-engineering - 매 small project 의 9-layer architecture = boilerplate. - 매 explicit boundary 의 cost. #### Coordination cost - 매 cross-concern feature 의 매 module 의 touch. - 매 small change 의 5 file. #### Pure SoC 의 myth - 매 real system 의 some coupling. - 매 perfect 의 X. → Pragmatic SoC + 매 case-by-case. ### Modern decision #### Modular monolith first - 매 module 의 boundary. - 매 explicit 1 deploy. - 매 team 의 ownership. - 매 future 의 microservice 의 가능. → Microservice premature 의 avoid. #### 매 function (FaaS) extreme - 매 function 의 own deploy. - 매 cold start cost. - 매 distributed 의 complexity. → 매 large org 만. #### 매 monolith with internal SoC - 매 1 codebase + 매 module / package boundary. - 매 lint rule (ESLint boundary). - 매 explicit interface. → 매 most common modern. ## 💻 코드 패턴 (Code Patterns) ### Module boundary (TS) ```ts // modules/users/index.ts export { User } from './domain/User'; export { UserService } from './application/UserService'; // 매 internal 가 not export // modules/orders/application/OrderService.ts import { UserService } from '../../users'; // ✅ public import { internal } from '../../users/domain/secret'; // ❌ ban ``` ### ESLint boundary plugin ```json // .eslintrc.json { "plugins": ["boundaries"], "rules": { "boundaries/element-types": ["error", { "default": "disallow", "rules": [ { "from": "feature/*/ui", "allow": ["feature/*/api"] }, { "from": "feature/*/api", "allow": ["shared"] } ] }] } } ``` ### Dependency injection (FastAPI) ```python from fastapi import Depends def get_user_repo() -> UserRepository: return UserRepository(db) def get_order_service(user_repo = Depends(get_user_repo)) -> OrderService: return OrderService(user_repo, ...) @app.post('/orders') def create_order(req: CreateOrderReq, service: OrderService = Depends(get_order_service)): return service.create(req) ``` ### Hexagonal port + adapter (TS) ```ts // Domain (port) interface PaymentGateway { charge(amount: Money, card: CardToken): Promise; } // Adapter class StripeGateway implements PaymentGateway { async charge(amount, card) { /* Stripe */ } } class FakeGateway implements PaymentGateway { async charge(amount, card) { /* test */ } } // Service class CheckoutService { constructor(private gateway: PaymentGateway) {} async checkout(...) { const payment = await this.gateway.charge(...); } } // Wiring const service = new CheckoutService(new StripeGateway()); ``` → 매 production = Stripe, 매 test = Fake. 매 service 의 unchanged. ### AI agent decision / execution ```python class Agent: def __init__(self, llm, tools: dict): self.llm = llm self.tools = tools def think(self, context): """Pure decision (no side effect).""" return self.llm.complete( system="You are an agent. Decide next action.", user=context, tools=list(self.tools.keys()), ) def execute(self, action): """Pure execution (no decision).""" if action.name not in self.tools: raise UnknownTool(action.name) return self.tools[action.name](action.input) def loop(self, task, max_steps=10): context = task for _ in range(max_steps): decision = self.think(context) if decision.is_done: return decision.answer result = self.execute(decision.action) context += f"\n{decision.action.name} returned: {result}" raise MaxStepsExceeded() ``` → 매 brain (LLM swap 가능) + 매 limb (tool swap). ### Game logic (Unity ECS-like) ```csharp // ❌ Mixed public class Player : MonoBehaviour { int health = 100; void Update() { // Input if (Input.GetKey(KeyCode.W)) transform.position += Vector3.forward * Time.deltaTime; // Combat if (Physics.OverlapSphere(transform.position, 1).Length > 0) health -= 10; // Render GetComponent().material.color = health < 30 ? Color.red : Color.white; } } // ✅ Separated systems public class InputSystem { void Update() {} } public class MovementSystem { void Update() {} } public class CombatSystem { void Update() {} } public class RenderSystem { void Update() {} } // 매 component 의 only data public struct Health { public int value; } public struct Position { public Vector3 value; } ``` → 매 system 의 own update. 매 component 의 only data. ### React feature folder ``` src/features/ ├── auth/ │ ├── api/ # data layer │ ├── domain/ # business rule │ ├── ui/ # component │ └── index.ts # public API ├── orders/ │ └── ... └── shared/ # cross-cutting ``` → 매 feature 의 own slice. 매 internal 의 own. ### Redux slice (state management) ```ts // 매 feature 의 own slice const authSlice = createSlice({ name: 'auth', initialState, reducers: { login: (state, action) => { ... }, logout: (state) => { ... }, }, }); const userSlice = createSlice({ name: 'user', initialState, reducers: { ... }, }); // 매 slice 의 internal. 매 selector 의 cross-slice. ``` ### Test의 SoC ```ts // Unit (logic only) test('formatUser', () => { expect(formatUser({ firstName: 'Alice', lastName: 'doe' })) .toEqual({ firstName: 'Alice', lastName: 'doe', fullName: 'Alice DOE' }); }); // Integration (with DB) test('UserService.create', async () => { const service = new UserService(testDb); const user = await service.create({...}); expect(user.id).toBeDefined(); }); // E2E (full stack) test('signup flow', async () => { await page.goto('/signup'); await page.fill('[name=email]', 'a@x'); await page.click('button[type=submit]'); await expect(page).toHaveURL('/dashboard'); }); ``` → 매 layer 의 own test type. ## 🤔 의사결정 기준 (Decision Criteria) | 상황 | 추천 | |---|---| | Small project | Light SoC (folder structure) | | Mid-size | Module + lint rule | | Large monolith | Modular monolith + DDD | | Microservice | Bounded context per service | | AI agent | Decision (LLM) + execution (tool) | | React app | Feature folder + custom hook | | Game | ECS / system separation | **기본값**: Module boundary + 매 layer (UI / domain / data) 의 separate. 매 case 의 over-engineer X. ## ⚠️ 모순 및 업데이트 (Contradictions & Updates) - **Pure SoC vs DRY**: 매 cross-concern feature 의 매 layer 의 duplicate. 매 trade-off. - **Boundary 의 cost**: 매 explicit boundary 의 boilerplate. - **Microservice premature**: 매 small team 의 microservice = pain. - **DDD 의 learning curve**: 매 small project 의 overkill. - **AI agent 의 emerging**: 매 LLM + tool 의 SoC 의 modern. ## 🔗 지식 연결 (Graph) - 부모: [[Software-Architecture]] · [[Design-Principles]] · [[Modularity]] - 변형: [[Single Responsibility Principle (SRP)|Single-Responsibility-Principle]] · [[Hexagonal Architecture]] · [[Clean-Architecture]] - 응용: [[MVC]] · [[Modular Monolith]] · [[Microservices]] - 비판: [[Over-Engineering]] - Adjacent: [[Decoupling]] · [[Encapsulation]] · [[Information-Hiding]] ## 🤖 LLM 활용 힌트 (How to Use This Knowledge) **언제 이 지식을 쓰는가:** - 매 architecture 의 review. - 매 module / service 의 boundary 결정. - 매 AI agent 의 decision / execution 분리. - 매 testability 의 design. - 매 refactor 의 strategy. **언제 쓰면 안 되는가:** - 매 small script (overkill). - 매 prototype (premature). - 매 specific micro-optimization. - Functional language 의 idiom (different paradigm). ## ❌ 안티패턴 (Anti-Patterns) - **God class / module**: 매 모든 거 1 곳. - **Circular dependency**: SoC violation. - **Anemic domain model**: 매 logic 의 service. 매 model 의 data 만. - **Service locator everywhere**: 매 hidden dependency. - **Pure SoC + 매 small project**: over-engineer. - **AI agent 의 mixed decision + execution**: untestable. - **Microservice premature**: 매 single team 의 distributed pain. ## 🧪 검증 상태 (Validation) - **정보 상태:** verified (concept-level). - **출처 신뢰도:** B (Dijkstra 1974, "Clean Architecture" Martin, "DDD" Evans). - **검토 이유:** Manual cleanup. Foundational concept 의 stable. ## 🧬 중복 검사 (Duplicate Check) - **기존 유사 문서:** [[Single Responsibility Principle (SRP)|Single-Responsibility-Principle]] (subset), [[Hexagonal-Clean]] (응용), [[Modular Monolith]] (응용). - **처리 방식:** KEEP (foundational principle). - **처리 이유:** 매 specific architecture 의 base. ## 🕓 변경 이력 (Changelog) | 날짜 | 변경 내용 | 처리 방식 | 신뢰도 | |------|-----------|-----------|--------| | 2026-05-08 | P-Reinforce Phase 1 정규화 | UPDATE | A | | 2026-05-09 | Manual cleanup — 매 architecture 응용 + AI agent SoC + code pattern + 안티패턴 추가 | UPDATE | B |