GRASP

GRASP(General Responsibility Assignment Software Patterns) 는 Craig Larman 이 제안한 객체지향 설계 원칙으로, 객체와 클래스에 책임을 할당하는 9 가지 핵심 패턴을 제공한다. 이 원칙들은 객체의 역할과 협력을 명확히 하여, 시스템의 유연성, 유지보수성, 확장성을 높이는 데 중점을 둔다. GRASP 는 Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations 등으로 구성되며, 실무에서 객체지향 설계의 기초이자 실질적인 지침으로 널리 활용된다.

핵심 개념

GRASP 의 핵심 개념은 " 책임 할당 (Responsibility Assignment)" 이다. 객체지향 설계에서 가장 중요한 의사결정은 어떤 클래스나 객체가 특정 책임을 담당해야 하는지 결정하는 것이다. 실무에 바로 적용 가능한 구체적이고 명확한 설계 지침이며, SOLID 원칙과 함께 객체지향 설계의 양대 축으로 활용된다.

책임의 두 가지 유형:

배경 및 목적

GRASP 는 Craig Larman 이 1997 년 객체지향 설계의 경험과 모범 사례를 체계화하여 만든 원칙이다. 기존의 좋은 설계 관행들을 정리하고 표준화한 것으로, 새로운 방법론이 아닌 입증된 설계 원칙들의 집합이다.

목적 및 필요성:

GRASP 원칙

객체 설계 시 각 객체가 자신의 데이터와 행위에 대한 책임을 갖도록 하고, 변화에 강한 구조를 위해 결합도를 낮추고 응집도를 높인다.
시스템 이벤트 처리, 객체 생성, 데이터 관리 등에서 각 원칙을 조합하여 적용한다.

원칙설명
Information Expert책임을 수행하는 데 필요한 정보를 가장 많이 가진 클래스에 책임을 할당합니다.
Creator객체 A 를 생성하는 책임을 객체 A 를 포함하거나 사용하는 객체 B 에 할당합니다.
Controller시스템 이벤트를 처리하는 책임을 비 UI 클래스에 할당하여 UI 와 비즈니스 로직을 분리합니다.
Low Coupling클래스 간의 결합도를 낮춰 변경에 대한 영향을 최소화하고 재사용성을 높입니다.
High Cohesion클래스의 책임을 관련 있는 기능으로 묶어 응집도를 높이고 유지보수성을 향상시킵니다.
Polymorphism타입에 따라 변하는 행위를 해당 타입의 클래스에 할당하여 유연성을 확보합니다.
Pure Fabrication도메인 개념과 직접 관련이 없지만 시스템 설계를 개선하기 위해 인위적으로 만든 클래스를 도입합니다.
Indirection두 클래스 간의 직접적인 결합을 피하기 위해 중재자 역할의 클래스를 도입합니다.
Protected Variations변동성이 예상되는 요소를 인터페이스로 감싸고 이를 통해 다른 요소들이 영향을 받지 않도록 보호합니다.

설명:

graph TD
    User-->|Event|Controller
    Controller-->|Delegates|InformationExpert
    InformationExpert-->|Uses|PureFabrication
    Controller-->|Creates|Creator
    Controller-->|Uses|Indirection
    Indirection-->|Protects|ProtectedVariations
    InformationExpert-->|Polymorphism|Polymorphism

Information Expert (정보 전문가)

원칙: 데이터를 가장 많이 가진 클래스에 책임을 할당한다.

예시: Order 객체가 총합 계산 책임을 가짐

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Order:
    def __init__(self):
        self.items = []

    def add_item(self, price, quantity):
        self.items.append({'price': price, 'quantity': quantity})

    def calculate_total(self):
        return sum(item['price'] * item['quantity'] for item in self.items)

# 사용
order = Order()
order.add_item(100, 2)
order.add_item(50, 3)
print(order.calculate_total())  # ➜ 350

Creator (생성자)

원칙: A 객체가 B 객체를 포함하거나 사용하는 경우 A 가 B 를 생성해야 한다.

예시: OrderOrderItem 을 생성

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class OrderItem:
    def __init__(self, product, quantity):
        self.product = product
        self.quantity = quantity

class Order:
    def __init__(self):
        self.items = []

    def add_item(self, product, quantity):
        item = OrderItem(product, quantity)
        self.items.append(item)

Controller

원칙: 시스템 이벤트를 처리하는 객체는 UI 외부에 존재해야 한다.

예시: OrderController 가 요청을 처리

1
2
3
4
5
6
class OrderController:
    def create_order(self, data):
        order = Order()
        for item in data['items']:
            order.add_item(item['product'], item['quantity'])
        return order

Low Coupling (낮은 결합도)

원칙: 의존성을 줄여 유지보수성을 높인다.

예시: 인터페이스 추상화

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class PaymentService:
    def pay(self, amount):
        raise NotImplementedError

class PaypalService(PaymentService):
    def pay(self, amount):
        print(f"Paying ${amount} via PayPal")

class Order:
    def __init__(self, payment_service: PaymentService):
        self.payment_service = payment_service

    def checkout(self, amount):
        self.payment_service.pay(amount)

High Cohesion (높은 응집도)

원칙: 관련 기능을 한 클래스에 집중

예시: Order 는 주문 관련 기능만 포함

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Order:
    def __init__(self):
        self.items = []

    def add_item(self, item):
        self.items.append(item)

    def total_items(self):
        return len(self.items)

    def calculate_total(self):
        return sum(item.price for item in self.items)

Polymorphism (다형성)

원칙: 다양한 구현을 동일한 인터페이스로 처리

예시: 다양한 결제 방식

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class PaymentMethod:
    def pay(self, amount):
        raise NotImplementedError

class CreditCardPayment(PaymentMethod):
    def pay(self, amount):
        print(f"Paid ${amount} with Credit Card")

class PayPalPayment(PaymentMethod):
    def pay(self, amount):
        print(f"Paid ${amount} with PayPal")

def process_payment(method: PaymentMethod, amount):
    method.pay(amount)

Pure Fabrication (순수 창작)

원칙: 설계 품질을 높이기 위한 비도메인 클래스

예시: EmailService 는 도메인과 무관하지만 필요

1
2
3
class EmailService:
    def send_receipt(self, order):
        print(f"Sending receipt for order with {len(order.items)} items.")

Indirection (간접화)

원칙: 두 객체 사이의 직접 의존을 줄이기 위한 중개자 사용

예시: PaymentProcessor 가 중개자 역할

1
2
3
4
5
6
class PaymentProcessor:
    def __init__(self, strategy: PaymentMethod):
        self.strategy = strategy

    def execute_payment(self, amount):
        self.strategy.pay(amount)

Protected Variations (변경 보호)

원칙: 변경 가능성이 높은 부분을 인터페이스로 감싸 보호

예시: 인터페이스로 다양한 결제 방식을 보호

1
# 이미 위 Polymorphism 예시가 해당됨

장점과 단점

구분항목설명
✅ 장점명확한 설계 가이드라인객체 책임 할당에 대한 체계적 접근법 제공
높은 유지보수성낮은 결합도와 높은 응집도로 변경 용이
재사용성 향상모듈화된 설계로 컴포넌트 재사용 증대
확장성다형성과 보호된 변형으로 시스템 확장 용이
⚠ 단점초기 복잡성설계 초기에 많은 고민과 분석 필요
과도한 추상화 위험잘못 적용시 불필요한 복잡성 증가
성능 오버헤드간접 참조와 다형성으로 인한 성능 저하 가능
학습 곡선개발자의 충분한 이해와 경험 필요

분류에 따른 종류

분류 기준종류설명
책임 유형행동 책임 원칙Creator, Controller, Polymorphism
구조 책임 원칙Information Expert, Low Coupling, High Cohesion
보호 책임 원칙Protected Variations, Indirection, Pure Fabrication
적용 범위클래스 수준Information Expert, Creator, High Cohesion
객체 수준Controller, Polymorphism
시스템 수준Low Coupling, Protected Variations, Indirection

실무 적용 예시

상황적용 원칙구현 방법효과
전자상거래 주문 시스템Information ExpertOrder 클래스가 총액 계산데이터와 로직의 응집도 향상
결제 시스템PolymorphismPaymentProcessor 인터페이스다양한 결제 방법 지원
웹 애플리케이션ControllerOrderController 로 요청 처리UI 와 비즈니스 로직 분리
알림 시스템Pure FabricationNotificationService 생성도메인 모델의 순수성 유지

활용 사례

사례 1: 온라인 쇼핑몰 시스템

시나리오: 사용자가 온라인 쇼핑몰에서 상품을 주문하고 결제하는 시스템
시스템 구성도:

graph TB
    subgraph "Presentation Layer"
        A[Web UI] --> B[OrderController]
    end
    
    subgraph "Application Layer"
        B --> C[OrderService]
        C --> D[PaymentService]
    end
    
    subgraph "Domain Layer"
        E[Order] --> F[OrderItem]
        E --> G[Customer]
        H[Payment] --> I[PaymentProcessor]
    end
    
    subgraph "Infrastructure Layer"
        J[OrderRepository]
        K[PaymentGateway]
    end
    
    C --> E
    D --> H
    E --> J
    I --> K

GRASP 원칙 적용:

Workflow:

  1. 사용자 주문 요청 → OrderController
  2. Controller → OrderService 로 처리 위임
  3. OrderService → Order 객체 생성 (Creator)
  4. Order → 총액 계산 (Information Expert)
  5. PaymentService → 결제 처리 (Pure Fabrication)
  6. PaymentProcessor → 결제 방법별 처리 (Polymorphism)

실무에서 효과적으로 적용하기 위한 고려사항 및 주의할 점

구분고려사항설명권장사항
원칙 적용상황에 맞는 원칙 선택모든 GRASP 원칙을 무조건 적용하지 말고 문제 상황에 적절히 적용사용 목적에 따라 선택적으로 적용하고 적용 이유를 문서화
책임 정의명확한 책임 분리클래스의 책임이 중복되지 않도록 설계클래스 다이어그램과 책임 목록을 작성하여 시각화
책임 할당단일 책임 원칙 (SRP) 준수하나의 클래스가 하나의 명확한 책임만 갖도록 유지각 클래스의 책임을 도출하고 불필요한 책임을 제거
결합도 관리의존성 최소화변경이 발생해도 영향이 최소화되도록 클래스 간 의존도를 줄임인터페이스 도입 및 의존성 주입 (DI) 을 통한 결합도 완화
응집도 관리응집도 최대화유사한 기능을 그룹화하여 유지보수성을 높임연관된 속성과 메서드를 한 클래스로 묶고 기능 단위별 책임 구분
유연성 확보설계 변경에 대한 대응성요구사항 변경 시 구조적으로 쉽게 반영되도록 설계전략 패턴, 팩토리 패턴 등 유연한 디자인 패턴을 적극 활용
설계 복잡도과도한 분리 지양책임 분리를 지나치게 하면 오히려 설계가 복잡해질 수 있음단순하고 명확한 구조 유지, 최소 단위 책임으로 압축하여 설계
설계 초기도메인 모델링 선행책임 할당 전 도메인과 비즈니스 로직을 충분히 파악초기 모델 설계 시 시나리오 기반의 분석 및 도메인 전문가 협업
팀 협업표준화 및 리뷰 문화팀원 간 책임 기준이 다를 경우 설계 방향 불일치 가능코드 리뷰, 설계 문서화, 책임 기준 합의 등 표준화된 협업 문화 유지
리팩토링점진적 구조 개선GRASP 원칙에 맞지 않는 기존 코드를 점진적으로 개선주기적인 리팩토링 주기 설정 및 책임 재검토

최적화를 위한 고려사항

구분고려사항설명권장사항
객체 생성 최적화불필요한 객체 생성을 줄이기빈번한 객체 생성은 GC(가비지 컬렉션) 부하 및 성능 저하로 이어질 수 있음팩토리 패턴, 싱글톤, 객체 풀링 등 재사용 가능한 생성 기법 활용
다형성 사용 주의성능 민감 구간에서 간접 호출 제한과도한 다형성 (가상 메서드 호출) 은 CPU 캐시 효율 저하를 유발할 수 있음성능 중요 구간에서는 구체 클래스 직접 호출 또는 전략적 캐싱 적용
메모리 관리참조 사이클 및 누수 방지순환 참조나 강한 참조로 인해 메모리 해제가 지연될 수 있음약한 참조 (Weak Reference), 옵저버 패턴, 명시적 자원 해제 적용
캐싱 전략계산 비용 절감정보 전문가 (Information Expert) 에 따라 계산이 집중되면 반복 계산 부담 증가계산 결과나 읽기 빈도 높은 데이터는 로컬 캐싱 또는 전역 캐싱으로 보관
추상화 최소화과도한 간접화 회피불필요한 추상화 계층은 호출 트리 증가 및 디버깅 복잡도 상승Pure Fabrication 최소화, 불필요한 Wrapper 제거
책임 분배 효율화책임 중복 방지과도한 책임 분산은 동일한 데이터/로직 반복 구현 가능성 존재정보 전문가 원칙에 따라 데이터 소유자에게 책임 집중
결합도와 호출 최적화객체 간 호출 비용 관리지나친 객체 분리는 모듈 간 호출 빈도 증가로 오버헤드 발생 가능상호작용이 잦은 객체는 같은 모듈 또는 동일 계층에 배치
계층 구조 최적화성능 불필요한 추상 계층 제거필요 없는 추상 계층이나 간접화는 런타임 성능 저하를 초래성능 분석을 바탕으로 실질적 이점 없는 추상 계층 제거
데이터 접근 최적화접근 경로 단순화모든 데이터 접근을 도메인 객체에 몰아주면 깊은 호출 경로 및 중복 발생DAO, Repository 등 전용 데이터 접근 계층으로 분리하고 로직은 필요한 객체에 위임
객체 수 제어과도한 클래스 분리 방지설계 원칙을 적용하다가 객체 수가 지나치게 증가할 경우 메모리 및 호출 관리 부담 상승단일 책임을 유지하되 연관 책임은 한 클래스로 묶어 최소 단위 구성

하위 주제 학습 내용

카테고리주제설명
GRASP 원칙 및 구현GRASP 9 가지 원칙Creator, Controller, Expert 등 GRASP 각 원칙의 개념 및 적용 전략 학습
객체지향 설계 원칙책임 할당과 단일 책임 원칙 (SRP)클래스에 명확하고 일관된 책임을 부여하고, 책임 분리 기준을 학습함
설계 품질 개선결합도 (Coupling), 응집도 (Cohesion)설계의 유연성, 변경 대응력, 테스트 용이성을 높이기 위한 구조적 품질 요소 학습
구조적 패턴MVC, MVP, MVVMController 원칙이 반영된 UI 아키텍처 패턴 구조와 책임 분배 방식 학습
의존성 제어 및 분리DI(Dependency Injection) 컨테이너Indirection 및 Pure Fabrication 구현을 위한 의존성 주입 기법 학습
변경에 강한 설계 전략Protected Variations 원칙 적용법시스템 변경에 강인한 구조 설계를 위한 추상화 및 인터페이스 활용 전략
반응형 아키텍처옵저버 패턴이벤트 중심의 시스템에서 변화 감지와 처리를 위한 핵심 패턴 학습
함수형 설계 접근법고차 함수 (Higher-Order Function)Polymorphism 원칙을 함수형 프로그래밍 관점에서 구현하는 방법 학습
실무 설계 적용도메인 모델링, 컨트롤러 구조실제 프로젝트에서 책임 분산을 위한 도메인 중심 설계 및 이벤트 처리 방식
비교 학습GRASP vs. SOLID두 설계 원칙 체계의 차이점과 상호 보완 관계를 명확히 이해

추가 학습 주제 및 관련 분야 정리

카테고리주제설명
객체지향 설계인터페이스와 Indirection의존성 역전을 위한 인터페이스 기반 설계 및 결합도 최소화를 위한 중재 구조 학습
소프트웨어 아키텍처레이어드 아키텍처책임 분리, 계층화 구조 및 계층 간 의존 관계 관리 방식 학습
도메인 모델링DDD 의 핵심 개념Aggregates, Entity, Value Object 를 통해 GRASP 의 책임 분배 구현
설계 품질 개선책임 재배치 및 중복 제거리팩토링을 통해 불필요한 책임 분산을 개선하고 응집도 향상
테스트 전략테스트 가능한 설계TDD 기반 책임 단위 테스트 구조와 유닛/통합 테스트 적용 방안
API 및 시스템 인터페이스RESTful API 설계Controller 패턴을 활용한 명확한 엔드포인트와 책임 구분
아키텍처 패턴헥사고날 아키텍처GRASP 원칙 기반 포트/어댑터 구성으로 외부 의존성과 내부 도메인 분리
성능 최적화캐싱 전략과 분리 구현Pure Fabrication 원칙 기반의 캐싱 서비스 계층 분리 및 응답 성능 향상
데이터 영속화ORM 설계 및 정보 전문가 적용엔티티 중심으로 데이터 책임을 위임하는 GRASP 의 Information Expert 구현
설계 원칙 비교 학습SOLID 원칙GRASP 과의 차이 및 보완 관계 이해를 위한 객체지향 설계 핵심 원칙 학습

용어 정리

GRASP 원칙 (General Responsibility Assignment Software Patterns)

용어설명
GRASP객체지향 설계에서 책임 할당을 위한 9 가지 원칙의 집합.
Information Expert데이터를 가장 잘 알고 있는 객체에 책임을 할당하는 원칙.
Creator어떤 객체를 생성할 책임이 있는 객체를 결정하는 원칙.
Controller시스템 외부 이벤트를 처리하는 객체를 정의하는 원칙.
Pure Fabrication도메인 모델에 속하지 않는 기능을 별도 객체로 분리하는 원칙.
Indirection객체 간 결합도를 낮추기 위해 중간 객체를 두는 설계 원칙.
Protected Variations변경 가능성이 높은 요소를 인터페이스로 추상화해 변경으로부터 보호.
Low Coupling객체 간 결합도를 최소화하여 변경에 유연하게 대응하는 원칙.
High Cohesion관련 책임을 한 객체나 모듈에 집중시켜 응집도를 높이는 원칙.
Polymorphism동일한 인터페이스로 서로 다른 구현을 사용하는 다형성 원칙.

객체지향 핵심 개념

용어설명
다형성 (Polymorphism)동일한 메시지로 다양한 동작을 수행할 수 있는 객체지향 특성.
책임 할당 (Responsibility Assignment)클래스나 객체가 수행할 책임을 분배하는 설계 활동.

설계 품질 관련 용어

용어설명
결합도 (Coupling)클래스나 모듈 간의 의존도 수준. 낮을수록 유지보수성과 유연성이 좋음.
응집도 (Cohesion)클래스 내부 구성 요소들 간의 관련성. 높을수록 모듈의 일관성과 명확성이 향상.

설계 전략 및 기법

용어설명
순수 가공 (Pure Fabrication)도메인에 속하지 않지만 기술적 필요로 만들어진 책임 분리용 클래스.
간접 참조 (Indirection)직접적인 의존성을 피하고, 구조의 유연성을 위해 중간 계층을 활용하는 기법.
보호된 변형 (Protected Variations)변화에 강한 구조를 위해 인터페이스나 추상화 계층을 도입하는 전략.

참고 및 출처

📘 공식 문서 / 백서 / 전문 블로그

📚 책 / 저자 중심 자료

📝 국내 블로그 및 커뮤니티 정리