Separation of Concerns across Layers
데이터베이스, 네트워크, 웹 프레임워크, OS — 서로 다른 여러 도메인에서 **"책임을 분리된 계층/컴포넌트에 위임한다"**는 같은 설계 패턴이 반복해서 나타난다. 이 페이지는 그 반복이 우연한 관례가 아니라, 변경 영향 범위를 국소화하고 각 부분을 독립적으로 교체·검증 가능하게 만드는 구조적 강제라는 관점에서 여섯 개 도메인의 사례를 모아 비교한다. 왜 "한 통로가 전체를 다루지 않고 위임"하는 패턴이 이렇게 다른 시스템에서 반복되는지, 그리고 관심사 분리가 단순한 "코드 정리" 이상의 의미를 갖는 이유가 무엇인지가 이 종합이 답하려는 질문이다.
여섯 도메인에서 반복되는 위임 패턴
1. Database — 3-Schema Architecture
3-schema architecture는 데이터베이스를 외부(External, 사용자·프로그램 뷰)/개념(Conceptual, 전체 DB 구조·제약)/내부(Internal, 물리적 저장 구조·인덱스) 세 수준으로 나눈다(수준 사이를 잇는 매핑은 Raw에 없는 이 page의 보충 설명이다). 개념 스키마가 바뀌어도 외부 스키마와 그에 연결된 응용 프로그램은 바뀌지 않는 논리적 데이터 독립성, 내부 스키마가 바뀌어도 개념 스키마는 바뀌지 않는 물리적 데이터 독립성이 이 분리의 목적이다.[1] 이 page의 해석으로는, 이 구조가 없다면 응용 코드가 저장 구조를 직접 알아야 하고 물리적 독립성이 무너진다.
2. Network — IEEE 802 LLC / MAC 하위 계층 분업
LAN Architecture는 OSI 2계층을 LLC(Logical Link Control)와 MAC(Media Access Control)으로 나눈다. LLC는 상위 계층에 공통 인터페이스를 제공하며 흐름 제어·오류 제어를 수행하고, MAC은 매체별 프레임 조립·주소 인식·접근 제어·충돌 관리를 담당한다.[2] 이 page의 해석으로는, Ethernet·무선 LAN이 서로 다른 MAC을 쓰더라도 상위 계층은 동일한 LLC 인터페이스만 보므로 응용·네트워크 계층 코드가 매체 종류에 종속되지 않는다. 같은 해석에서 이 분업이 없다면 LLC 없이 MAC에 상위 인터페이스를 하드코딩하는 셈이 되어, 매체가 바뀔 때마다 상위 계층 코드까지 고쳐야 하는 매체 종속적 응용이 된다.
3. Backend — Spring MVC DispatcherServlet의 위임
Spring MVC Controller에서 DispatcherServlet은 Front Controller로서 모든 요청을 가장 먼저 받지만, 비즈니스 로직을 직접 처리하지 않는다 — 흐름만 잡고 HandlerMapping(URL → Controller 매핑), HandlerAdapter(파라미터 바인딩 + 메서드 호출), ViewResolver(논리 View 이름 → 실제 View), Controller에게 각자의 몫을 위임한다.[3] Controller 자체도 얇게 유지하고 비즈니스 로직은 Service에 위임하는 것이 같은 원칙의 연장이다.[3:1] 이 page의 해석으로는, Controller가 비즈니스 로직을 직접 구현해 버리면 Controller/Service 역할 분리가 무너진다.
4. Backend — Spring AOP 프록시와 Transaction 경계
Spring AOP는 트랜잭션 제어 코드를 비즈니스 로직에 동적으로 주입하는 프록시 패턴이다. 개발자는 @Transactional만 선언하면 되고, 스프링이 만든 프록시 객체가 PlatformTransactionManager로 트랜잭션 경계를 시작·커밋·롤백한다 — 비즈니스 로직(Service 메서드 본문)과 트랜잭션이라는 횡단 관심사(cross-cutting concern)가 이렇게 분리된다.[4] 그런데 이 분리는 프록시를 실제로 경유해야만 성립한다: 클래스 내부에서 this.method()로 같은 클래스의 @Transactional 메서드를 직접 호출하는 Self-Invocation은 프록시를 우회하므로 트랜잭션이 적용되지 않는다. 권장되는 해결책은 트랜잭션이 필요한 비즈니스 단위를 별도 클래스(서비스 빈)로 분리해 항상 프록시를 경유하는 외부 호출 구조로 바꾸는 것이다.[4:1] 이 page의 해석으로는, Self-Invocation은 관심사 분리가 깨지는 구체적인 실패 사례에 해당한다.
5. OS — Multiprogramming과 Memory Protection
OS Memory Management에서 multiprogramming의 요구사항으로 Protection, Fast translation, Fast context switching을 든다. 가상 메모리는 각 프로세스의 주소 공간을 격리해 다른 프로세스의 메모리 침범을 막는다.[5] 각 프로세스는 고유의 가상 주소 공간을 갖고 가상 주소를 물리 주소로 변환하므로,[5:1] 이 분리된 추상화 계층이 바로 이 protection을 만든다고 이 page는 해석한다. 프로세스 간 메모리를 공유해 이 격리를 포기하면 보안·안정성이 그만큼 깨진다는 것도 이 page의 해석이다.
6. Network — IP의 비연결 서비스와 목적지 재조립
IP Internetworking에서 IP는 종단 시스템(End System, ES) 간에 연결 없는 서비스를 제공하며, 그 장점으로 유연성, 견고성, 불필요한 오버헤드가 없다는 점을 든다.[6] 단편화된 데이터그램의 재조립도 목적지에서만 수행된다.[6:1] 다만 원문은 IP 설계 문제의 흐름 제어를 라우터가 데이터 수신 속도를 제한하고 흐름 제어 패킷으로 데이터 흐름 감소를 요청하는 기능으로 설명하므로, 라우터가 패킷 전달만 담당한다고 단정할 수는 없다.[6:2] 재조립 같은 책임을 목적지 쪽에 두는 방식을 관심사 분리로 읽는 것은 이 page의 해석이며, 신뢰성·순서 보장을 ES의 전송 계층이 맡는다는 책임 분담과 라우터 무상태성이 확장성·장애 복구에 주는 효과는 인용 원문에서 확인되지 않는다.
공통 구조
flowchart LR High["상위 관심사
(사용자, 비즈니스, 응용)"] Mid["중간 추상화 계층
(인터페이스·매핑·프록시)"] Low["하위 구현
(저장·매체·OS 자원)"] High -.변경 영향 국소화.-> Mid Mid -.변경 영향 국소화.-> Low Note["각 계층은 자신의 책임만 담당
변경이 인접 계층에 전파되지 않음"] Note -.-> Mid
여섯 사례를 나란히 놓으면 같은 구조가 드러난다. 하나의 통로(Front Controller, DBMS, 가상 메모리 계층, LLC, 라우터)가 외부 요청을 받고, 이를 분류·매핑해 적절한 하위 컴포넌트에 위임하며, 하위 컴포넌트는 자신의 책임만 수행하고 다른 컴포넌트의 결정을 건드리지 않는다. 그리고 변경 영향이 인접하지 않은 계층으로 번지지 않도록 매핑·프록시·격리라는 장치가 그 경계를 지킨다.
| 도메인 | 분리 대상 | 달성 효과 |
|---|---|---|
| Database | 외부/개념/내부 스키마 | 논리/물리 독립성 — 안쪽 변경이 바깥쪽에 영향 안 줌 |
| Network (LAN) | LLC vs MAC | 상위 계층 코드가 매체 종류 무관 |
| Backend (Spring MVC) | DispatcherServlet / Controller / Service | Front Controller는 흐름만, 비즈니스는 Service |
| Backend (Spring AOP) | 비즈니스 / 횡단 관심사 | @Transactional 하나로 선언적 트랜잭션 |
| OS | 프로세스 주소 공간 | Protection (프로세스 간 메모리 침범 차단) |
| Network (IP) | 라우터 / End System | ES 간 비연결 서비스, 재조립은 목적지에서만 수행 |
관심사 분리는 코드 정리 기법이 아니라 변경 영향을 국소화하는 구조적 강제라고 볼 수 있다 — 여기서 얻는 것은 크게 세 가지다.
- 변경 영향 범위 국소화 — 한 계층의 변경이 다른 계층의 코드 수정을 유발하지 않는다.
- 독립 검증 — 각 컴포넌트를 개별적으로 테스트·대체할 수 있다.
- 관심사 경계 명확화 — "이 코드는 어디에 속하는가"라는 질문에 명확한 답이 나온다.
관련
- Abstraction Cost Tradeoff — 관심사 분리가 가져오는 추상화 계층의 비용 측면.
- 3-schema architecture
- LAN Architecture
- Spring MVC Controller
- Spring AOP
- OS Memory Management
- IP Internetworking
테스트 질문
- 관심사 분리가 "코드 정리"가 아니라 "구조적 강제"인 이유는 무엇인가?
- 3-schema, LLC/MAC, Spring MVC DispatcherServlet 모두에 공통으로 나타나는 패턴은 무엇인가?
- Spring AOP Self-Invocation이 "관심사 분리 실패"인 이유는 무엇인가?
- IP 비연결 서비스와 목적지 재조립을 "관심사 분리" 사례로 읽을 수 있는 근거와 한계는 무엇인가?
- 관심사 분리가 가져오는 주요 효과 3가지는 무엇인가?
출처
2장 데이터베이스 시스템 개념과 아키텍처.md — 세 가지 스키마 아키텍처: "외부 스키마: 여러 사용자의 뷰를 설명"(L105), "내부 스키마: 물리적 저장 구조와 액세스 경로(예: 인덱스)를 설명"(L101), 논리적 데이터 독립성("외부 스키마와 관련된 응용 프로그램을 변경하지 않고 개념적 스키마를 변경할 수 있는 능력", L113), 물리적 데이터 독립성("개념적 스키마를 변경하지 않고 내부 스키마를 변경할 수 있는 능력", L116). ↩︎
LAN.md — 논리 링크 제어(LLC) 계층("상위 계층에 인터페이스를 제공", "흐름 제어 및 오류 제어를 수행", L39-41), 매체 접근 제어(MAC) 계층("데이터 프레임을 전송 시 조립하고 수신 시 분해하며, 주소 인식 및 오류 검출을 수행", "LAN 전송 매체에 대한 접근을 제어", "네트워크에 여러 사용자가 동시에 접근 시 충돌 방지 관리", L43-46). ↩︎
Spring MVC.md — "
DispatcherServlet은 Spring MVC의 Front Controller다"(L82), "핵심은DispatcherServlet자체가 직접 비즈니스 로직을 처리하지 않는다는 점이다. 흐름만 잡고 실제 작업은 각 컴포넌트에게 위임한다"(L84),HandlerMapping/HandlerAdapter/ViewResolver역할표, "Controller는 요청을 받고 Service를 호출한 뒤 결과를Model에 담고 어떤 View를 보여줄지 이름으로 반환한다"(L191), "Controller는 얇게 유지하고, 비즈니스 로직은 Service에 위임한다"(L779). ↩︎ ↩︎Transaction.md — "스프링은 실제 객체를 감싸는 프록시 객체(Proxy)를 자동으로 만들어 등록", "클라이언트가 메서드를 호출하면 프록시 객체의 메서드가 대신 먼저 호출되며 ...
PlatformTransactionManager를 통해 DB 트랜잭션을 시작", Self-Invocation 문제("동일 클래스 내의 다른@Transactional메서드를 직접 호출(this 호출)하는 경우, 프록시를 거치지 않고 실제 객체의 레퍼런스를 직접 참조하므로 트랜잭션이 적용되지 않습니다", L97), 해결책("트랜잭션이 필요한 비즈니스 단위를 별도의 클래스(서비스 빈)로 분리하여 외부 호출 구조로 변경"). ↩︎ ↩︎뭔가 나올거같은 개념 정리.md — "프로세스 간의 메모리 격리"(L4), multiprogramming 요구사항 중 Protection(L12-13), "물리적 메모리보다 큰 메모리 공간을 제공하여 메모리 부족 문제를 해결하고, 프로세스 간의 주소 공간을 격리"(L79), "각 프로세스는 고유의 가상 주소 공간을 가집니다"(L83), "가상 주소를 물리 주소로 변환하는 과정"(L87). ↩︎ ↩︎
Data and Computer Communications.md — 종단 시스템(ES)/중간 시스템(IS) 정의(L12-13), "IP는 종단 시스템 간에 연결 없는 서비스를 제공", 장점 "유연성", "견고하게 만들 수 있음", "불필요한 오버헤드를 가하지 않음"(L41-45), "IP는 목적지에서만 재조립을 수행"(L71), "흐름 제어 ... 라우터가 데이터를 수신하는 속도를 제한할 수 있도록 함 ... 흐름 제어 패킷을 전송하여 데이터 흐름 감소 요청"(L87-89). ↩︎ ↩︎ ↩︎