GRASP 패턴 (Ch 16, 22)
GRASP(General Responsibility Assignment Software Patterns)은 "이 책임을 어떤 객체에 줄 것인가"라는 질문에 답하는 9개의 원칙이다. 디자인 패턴이라기보다는 객체 설계의 기본 알파벳에 가깝다. GoF 패턴을 포함한 거의 모든 설계 패턴은 GRASP의 조합으로 분석할 수 있다.
왜 중요한가
Larman이 이 책에서 가장 강조하는 단일 스킬은 **책임 할당(responsibility assignment)**이다. 코드를 짜든 다이어그램을 그리든, 결국 "이 일을 누가 할 것인가"를 결정해야 한다. GRASP는 그 결정을 설명 가능하고 반복 가능하게 만들어준다.
책임 할당이 일어나는 주된 장소는 08-interaction-diagram|Interaction Diagram을 그릴 때다. 메시지를 어떤 객체에 보낼지 결정하는 그 순간이 곧 책임을 할당하는 행위다.
기본 5패턴 (Iteration 1)
Information Expert
문제: 어떤 책임을 어디에 줄까? 해법: 그 책임을 수행하는 데 필요한 정보를 가진 클래스에 준다.
예시 — "Sale의 총액은 누가 계산하나?"
- 총액 = 모든 SalesLineItem의 소계 합산
- Sale이 SalesLineItem 컬렉션을 알고 있으므로 →
Sale.getTotal() - 각 소계 = 수량 × 가격. SalesLineItem이 수량과 ProductSpecification을 알므로 →
SalesLineItem.getSubtotal() - 가격은 ProductSpecification이 알므로 →
ProductSpecification.getPrice()
정보가 분산되어 있으면 Expert를 연쇄적으로 적용해서 메시지 체인을 만든다.
Creator
문제: 누가 객체 A를 생성해야 하나? 해법: 다음 중 하나에 해당하는 B에게 A 생성을 맡긴다:
- B가 A를 포함(contain/aggregate)한다
- B가 A를 기록(record)한다
- B가 A의 초기화 데이터를 갖고 있다
- B가 A를 밀접하게 사용한다
예시 — Sale이 SalesLineItem을 포함하므로, Sale이 SalesLineItem을 생성한다.
Controller
문제: 시스템 이벤트를 누가 최초로 받아 처리하나? 해법: 두 가지 선택지:
- Facade Controller — 전체 시스템/디바이스를 대표하는 클래스 (예:
Register) - Use-Case Controller — 특정 유스케이스 시나리오를 대표하는 클래스 (예:
ProcessSaleHandler)
시스템 이벤트가 적으면 Facade, 많으면 Use-Case Controller. 03-system-sequence-diagram|SSD에서 도출된 시스템 이벤트가 Controller의 메서드가 된다.
Low Coupling (평가적)
문제: 의존성을 어떻게 낮출까? 해법: 불필요한 결합이 낮게 유지되도록 책임을 할당한다.
이건 독립적인 설계 결정이 아니라, 다른 패턴 적용 시 대안을 평가하는 기준이다. 예를 들어 Payment를 Register가 만들지 Sale이 만들지 고민할 때, Sale이 만들면 Register-Payment 간 결합이 줄어든다.
High Cohesion (평가적)
문제: 복잡성을 어떻게 관리할까? 해법: 응집도가 높게 유지되도록 책임을 할당한다.
Low Coupling과 마찬가지로 평가 기준. Controller에 너무 많은 책임이 몰리면 응집도가 떨어지니, 그때 Use-Case Controller로 분리하는 식.
확장 4패턴 (Iteration 2)
Polymorphism
타입에 따라 행동이 달라질 때, 조건문(if/switch) 대신 다형성을 쓴다. 외부 세금 계산기가 여러 종류일 때 ITaxCalculatorAdapter 인터페이스를 두고 각 구현체가 다르게 동작하는 것이 전형적인 예.
Pure Fabrication
도메인 모델에 없지만 Low Coupling과 High Cohesion을 위해 인위적으로 만든 클래스. PersistentStorage, ServicesFactory 같은 것. 거의 모든 GoF 패턴(Adapter, Strategy 등)은 Pure Fabrication이다.
Indirection
두 컴포넌트 사이에 중간 객체를 넣어 직접 결합을 피한다. Adapter, Facade, Observer 등 대부분의 GoF 패턴은 Indirection의 특수한 형태.
Protected Variations
변화나 불안정 지점을 식별하고, 그 주위에 안정적인 인터페이스를 만들어 보호한다. 사실상 모든 좋은 설계의 근본 원리. 데이터 캡슐화, 인터페이스, 다형성, 표준 — 전부 PV를 달성하기 위한 메커니즘이다.
바이브 코딩에서의 활용
GRASP 패턴 이름을 LLM에게 직접 사용하면 설계 의도를 정밀하게 전달할 수 있다.
프롬프트 예시:
"다음 설계 원칙을 따라서 클래스를 설계해줘:
1. Controller: OrderController가 시스템 이벤트(createOrder, addItem, checkout)를 받는다
2. Creator: Order가 OrderLineItem을 생성한다 (Order가 OrderLineItem을 포함하므로)
3. Expert: Order.getTotal()이 총액을 계산한다 (Order가 모든 LineItem을 알고 있으므로)
4. Low Coupling: OrderController는 Payment 직접 생성하지 않고 Order에 위임한다
5. Protected Variations: 외부 결제 서비스는 IPaymentAdapter 인터페이스 뒤에 숨긴다"
패턴 이름 + 이유(~하므로)를 함께 쓰면 LLM이 구조를 정확하게 잡는다.