# Composable Design Patterns for Composio
Composio에서의 Composable Design Patterns는 작은 단위의 구성 요소(component)들을 조합하여 복잡한 시스템을 유연하고 재사용 가능하게 만드는 원칙들의 모음이다. 이 문서는 각 패턴의 정의, 구성 요소, 사용 시점, 장단점, 실무 적용을 위한 예시를 제공한다. 영어 용어를 병기하되 한국어 설명을 병행하여 이해를 돕는다.
---
## 용어 정리 (Glossary)
- Component: 시스템의 가장 작은 독립적인 재사용 단위. 컴포넌트는 명확한 인터페이스를 통해 다른 요소와 결합된다.
- Pattern: 문제를 해결하기 위한 일반화된 구조나 해결책의 틀.
- Composition: 여러 구성 요소를 조합하여 더 큰 기능을 만들어내는 과정.
- Pipeline: 데이터나 이벤트가 순차적으로 처리 단계를 거치는 연쇄적인 처리 흐름.
- Higher-Order: 함수나 컴포넌트가 다른 함수/컴포넌트를 인수로 받거나 반환하는 형태의 확장 방식.
- Decorator / Enrichment: 기존 구성 요소에 추가 기능을 동적으로 결합하는 방식.
- Context / Dependency Injection: 외부 컨텍스트에서 의존성을 주입해 구성 요소의 재사용성과 테스트 용이성을 높이는 방법.
- State / State Machine: 상태를 명시적으로 모델링하고 전이를 합성적으로 구성하는 방식.
- Event-Driven: 이벤트 기반으로 구성 요소 간의 결합도를 낮추고 반응형 흐름을 만드는 방식.
---
## 설계 원칙 (Design Principles)
- 구성 우선 (Composition over Inheritance): 상속보다는 구성 요소의 조합을 통해 기능을 확장한다.
- 명시적 계약 (Explicit Contracts): 인터페이스/타입이 명확히 정의되어야 재사용이 용이하다.
- 단일 책임 원칙 (Single Responsibility): 구성 요소는 하나의 기능에 집중한다.
- 흐름의 단방향성 (Unidirectional Data Flow): 데이터 흐름과 이벤트 흐름을 한 방향으로 설계한다.
- 재사용 가능성 우선 (Reusability): 작은 컴포넌트의 조합으로 다양한 필요를 만족시킨다.
- 테스트 용이성 (Testability): 의존성 주입과 인터페이스 명확화로 테스트를 쉽게 한다.
---
## 패턴 카탈로그
아래 패턴들은 Composio 환경에서 특히 잘 작동하는 일반적이고 재사용 가능한 구성 기법들이다. 각 패턴은 정의, 언제 사용하면 좋은지, 구성 요소, 장단점, 간단한 예시로 구성된다.
### 1) Component Composition (컴포넌트 합성)
- 정의: 여러 작은 컴포넌트를 조합하여 더 큰 UI나 기능 단위를 구성하는 방식.
- 사용 시점: 동일한 비즈니스 도메인 내에서 다양한 조합이 필요한 UI를 설계할 때.
- 기본 구성 요소:
- BaseComponent: 재사용 가능한 기본 뼈대
- Container: 레이아웃 및 위치 관리
- ChildComponent: 재사용 가능한 기능 모듈
- 장점: 재사용성 증가, 테스트 용이성, 확장성 우수
- 단점: 구성 트리가 복잡해지면 추적이 어려워질 수 있음
- 예시 (의사 코드/간단한 스니펫):
- 예시 목표: 버튼과 아이콘을 조합한 IconButton 컴포넌트
```
define Component Button(label)
define Component Icon(icon, child)
define Component IconButton(label, icon)
render:
Icon(icon)
Button(label)
```
- 구현 팁:
- 명확한 인터페이스로 서로 다른 컴포넌트를 조합하도록 설계한다.
- 프래그먼트/슬라이스 단위로 상태를 관리하고, 상태는 상향식으로 전달한다.
---
### 2) Higher-Order Composition (고차 합성)
- 정의: 함수나 컴포넌트가 다른 컴포넌트/함수를 인수로 받아 확장된 기능을 제공하는 패턴.
- 사용 시점: 공통 기능(로깅, 트랜잭션, 테마 등)을 여러 컴포넌트에 걸쳐 적용할 때.
- 구성 요소:
- withXxx(Hoc): 특정 기능을 주입하는 고차 컴포넌트
- compose(patterns): 여러 패턴을 순차적으로 적용하는 조합자
- 장점: 코드 중복 감소, 교차 기능의 재사용
- 단점: 추적 가능성 저하 가능성, 과도한 래핑으로 읽기 어려움
- 예시:
```
function withTheme(component)
return function ThemedComponent(props) {
theme = useThemeContext()
return component({ ...props, theme })
}
const EnhancedButton = withTheme(Button)
```
- 구현 팁:
- 고차 컴포넌트는 순수 함수로 만들고 사이드 이펙트를 최소화한다.
- compose를 이용해 패턴들을 합성할 때 순서를 명확히 기록한다.
---
### 3) Decorator / Enrichment (데코레이터 및 기능 확장)
- 정의: 기존 컴포넌트에 외부 기능을 동적으로 추가하는 방식.
- 사용 시점: 특정 컴포넌트에 선택적으로 기능(로깅, 접근성 보강, 무효화 처리 등)을 붙이고 싶을 때.
- 구성 요소:
- Decorator: 기능 확장을 수행하는 래퍼
- Target: 기능을 확장받는 원래 컴포넌트
- 장점: 기능의 조합 가능성 증가, 비침투적 확장
- 단점: 여러 데코레이터가 겹치면 복잡도 증가
- 예시:
```
define Decorator withLogging(component)
return function LoggedComponent(props)
log("props:", props)
return component(props)
const ButtonWithLogging = withLogging(Button)
```
- 구현 팁:
- 데코레이터는 가능한 독립적으로 유지하고, 순서를 명시적으로 관리한다.
---
### 4) Pipeline / Data Flow (파이프라인 및 데이터 흐름)
- 정의: 데이터 또는 이벤트를 처리하는 여러 단계(pipeline stage)를 연결하여 흐름을 구성하는 방식.
- 사용 시점: 데이터 변환, 검증, 사전 처리, 최종 렌더링 같은 일련의 처리 단계가 필요할 때.
- 구성 요소:
- Stage: 단일 처리었다를 수행
- Pipeline: Stage들을 연결하는 컨테이너
- 장점: 각 단계의 재사용성 및 독립성 증가
- 단점: 파이프라인이 길어지면 디버깅이 어려워질 수 있음
- 예시:
```
const pipeline = pipe(
fetchData,
validate,
transform,
render
)
pipeline(input)
```
- 구현 팁:
- 각 Stage는 순수 함수로 구성한다.
- 실패 시 예외 처리나 백프레션(backpressure)을 명시적으로 다룬다.
---
### 5) Contextual Composition (컨텍스트 기반 합성)
- 정의: 외부 컨텍스트나 DI(Dependency Injection)로 의존성을 주입해 구성 요소의 재사용성과 테스트를 높이는 방식.
- 사용 시점: 공통 자원(Theme, Config, Logger, Translations)을 여러 컴포넌트에서 공유해야 할 때.
- 구성 요소:
- Context/Provider: 의존성을 공급하는 공급자
- Consumer: 컨텍스트를 소비하는 구성 요소
- 장점: 테스트 용이성, 구성 요소 간 결합도 감소
- 단점: 과다한 컨텍스트 의존은 추적을 어렵게 할 수 있음
- 예시:
```
const ThemeContext = createContext(defaultTheme)
function ThemedButton(props) {
const theme = useContext(ThemeContext)
return Button({ ...props, style: theme.buttonStyle })
}
```
- 구현 팁:
- 공급자와 소비자의 경계선을 명확히 한다.
- 필요 시 커스텀 훅/함수를 통해 의존성 주입을 간결하게 만든다.
---
### 6) Event-Driven Composition (이벤트 기반 합성)
- 정의: 이벤트를 중심으로 컴포넌트 간의 결합을 느슨하게 만들고 반응형 흐름을 구성하는 방식.
- 사용 시점: 비동기 동작, 사용자 상호작용, 시스템 이벤트를 동적으로 연결해야 할 때.
- 구성 요소:
- EventBus / Publisher-Subscriber( PubSub)
- EventHandler: 이벤트 처리 로직
- 장점: 결합도 감소, 비동기 흐름 관리 용이
- 단점: 이벤트 추적이 어려워질 수 있음
- 예시:
```
eventBus.subscribe('user.login', onUserLogin)
eventBus.publish('user.login', userInfo)
```
- 구현 팁:
- 이벤트 이름은 명확하고 일관되게 설계한다.
- 중요 이벤트는 우선순위를 두고 필터링/버퍼링을 적용한다.
---
### 7) State Machines as Composition (상태 기계 기반 합성)
- 정의: 상태 전이를 명확히 모델링하고 이를 구성 요소 간의 동작으로 합성하는 방식.
- 사용 시점: 복잡한 사용자 흐름, 허용 가능한 상태/전이가 많은 경우.
- 구성 요소:
- State: 현재 상태
- Transition: 상태 간의 전이 규칙
- Action: 전이 시 실행될 부수 효과
- 장점: 로직의 가시성, 테스트 용이성, 오류 감소
- 단점: 초기 학습 비용, 간단한 케이스에선 과도할 수 있음
- 예시:
```
stateMachine = createStateMachine({
idle: { click: 'loading' },
loading: { success: 'ready', failure: 'error' },
ready: { click: 'idle' },
error: { retry: 'idle' }
})
```
- 구현 팁:
- 상태는 불변으로 관리하고 전이만으로 상태를 바꾼다.
- 사이드 이펙트는 전이의 결과로만 발생하도록 설계한다.
---
## 구현 팁과 모범 사례
- 패턴 간 조합: 패턴은 독립적으로 설계하되 필요에 따라 적절히 조합한다. 조합 순서가 동작에 영향을 미칠 수 있음에 주의한다.
- 테스트 전략: 컴포지션의 각 모듈에 대한 단위 테스트와 함께 통합 테스트를 구성한다. 모의 객체(mock)와 스포이(spy) 사용을 고려한다.
- 성능 고려: 과도한 컴포지션, 깊은 트리 구조는 렌더링/처리 성능에 영향을 줄 수 있다. 필요 시 memoization이나 샤딩을 적용한다.
- 문서화: 각 컴포넌트/패턴의 의도, 인터페이스, 기대되는 입력/출력, 예시를 문서화한다.
- 도구/환경: Composio의 런타임 지원 패턴(예: pipe, context, event bus 등)을 적극 활용하되, 표준화된 접근법을 팀 간에 합의한다.
---
## 참고 예시: 작은 예제 설계 흐름
- 목표: 사용자 프로필 화면을 Composio에서 컴포지션으로 구성
- 기본 컴포넌트: Avatar, Username, UserStats
- 구성: Card(Avatar, Username, Stats) + 행동 패턴: HoverDecorator, ClickHandler
- 흐름: Contextual Theme + Event-Driven 업데이트 + Pipeline로 데이터 처리
예시 코드 스니펫은 필요 시 프로젝트의 스타일에 맞게 변형하여 사용한다.
---
## 관련 문서
관련 문서: [[Composio UI Design Principles]], [[Functional Composition Patterns]], [[Composable Architecture for UI]], [[Design System for Composio]]