디자인 패턴은 단순한 추상 개념이 아니에요.
개발을 하다 보면 반복적으로 마주치는 문제가 생기는데, 이런 문제를 해결하기 위해 이미 검증된 방식(패턴)을 사용하는 게 바로 디자인 패턴이에요.
디자인 패턴을 몰라도 개발은 가능하지만, 알고 있으면 더 깔끔하고 확장성 있는 구조를 빠르게 만들 수 있어요.
지금 마주한 문제가 이미 다른 개발자들도 겪었던 문제라면, 그 해결책은 이미 패턴으로 정리돼 있을 수도 있기 때문이죠.
분류 | 설명 | 대표 예시 |
---|---|---|
생성 패턴 | 객체를 유연하게 생성하는 방법 | 싱글턴, 팩토리 메서드 |
구조 패턴 | 객체나 클래스를 조합해 더 큰 구조로 만드는 방식 | 어댑터, 데코레이터, 퍼사드 |
행동 패턴 | 객체 간의 책임 분담과 흐름 제어 방식 | 옵서버, 전략, 템플릿 메서드 |
핵심은 반복되는 문제를 일관된 방식으로 풀자는 사고예요.
프론트엔드는 사용자와 직접 맞닿는 영역이라, 백엔드와는 요구 사항이 달라요.
기존 객체지향 기반의 패턴보다 데이터 흐름, UI 구성, 상태 관리에 초점을 맞춘 패턴들이 더 많이 사용돼요.
예를 들어 이런 것들이 있어요 :
많은 패턴들이 있지만, 이중에서 최근 많이 쓰이는 패턴 중심으로, 요즘 프론트엔드 개발이 어떤 흐름을 따르고 있는지 살펴보고자 해요.
컴포넌트 깊이에 상관없이 데이터를 전달하고 싶을 때
<MyContext.Provider value={someValue}>
<Child />
</MyContext.Provider>
Context를 사용하면 props drilling 없이 전역 상태를 공유할 수 있어요.
다만 모든 상태를 Context에 넣으면 오히려 구조가 복잡해질 수 있으니, 꼭 필요한 경우에만 사용하는 게 좋아요.
*전역 상태를 언제 사용하면 좋을지에 대한 생각 정리
상태를 간단하게 관리하고 싶을 때
Redux처럼 단계가 많은 상태 관리 방식은 구조가 무거워질 수 있어요.
Recoil, Jotai, Zustand 같은 라이브러리는 상태를 직접 get/set할 수 있게 설계돼 있어요.
const count = useCounterStore((state) => state.count);
const increment = useCounterStore((state) => state.increment);
보일러플레이트 없이 직관적으로 상태를 다룰 수 있지만, 동기화나 동시성 문제에는 주의가 필요해요.
서버 상태를 자동으로 관리하고 싶을 때
const query = useQuery({
queryKey: ['user', id],
queryFn: () => fetchUser(id),
});
React Query는 서버 상태를 가져오는 과정 전체를 자동화해줘요.
캐싱, 리패칭, 오류 처리까지 모두 포함돼 있어서, 복잡한 상태 관리 코드를 줄일 수 있어요.
필요한 데이터만 선택해서 가져오고 싶을 때
{
user(id: 1) {
name
email
}
}
GraphQL은 REST보다 유연하게 데이터를 다룰 수 있어요.
클라이언트가 필요한 필드만 지정해서 요청하고, 서버는 그에 맞춰 응답해줘요.
프론트엔드 중심의 개발 환경에서 유리한 구조를 만들 수 있어요.
관련된 컴포넌트를 하나처럼 조립해서 사용하고 싶을 때
<Tabs>
<Tabs.List>
<Tabs.Button />
</Tabs.List>
<Tabs.Panel />
</Tabs>
컴파운드 패턴은 여러 컴포넌트를 묶어 하나의 컴포넌트처럼 사용할 수 있게 해줘요.
구성은 자유롭고, 내부 로직은 감출 수 있어서 재사용성과 유연성을 높일 수 있어요.
공통 로직을 여러 컴포넌트에 적용하고 싶을 때
const withAuth = (Component) => (props) => {
return isLoggedIn ? <Component {...props} /> : <LoginPage />;
};
HOC는 컴포넌트 외부에서 기능을 확장할 수 있는 패턴이에요.
요즘은 Hook과 컴포지션이 많이 쓰이지만, 특정 상황에서는 여전히 유용한 패턴이에요.
항상 같은 정답이 있다기 보다는
상황에 따라 알맞은 패턴을 선택해야 해요.
상황 | 패턴 |
---|---|
전역 상태 공유가 많고 구조가 단순할 때 | Context API, Atomic 패턴 |
서버와 통신이 잦고 데이터 중심일 때 | React Query, GraphQL |
상태가 복잡하고 비즈니스 로직이 많은 경우 | Redux Toolkit, Zustand |
UI 컴포넌트를 조립형으로 구성하고 싶을 때 | Compound Components |
공통 로직을 여러 컴포넌트에 재사용해야 할 때 | HOC (Higher-Order Component) |
디자인 패턴은 강제 규칙의 개념보다는, 상황에 맞는 해결책을 찾기 위한 틀이에요.
따라서 어떤 패턴을 쓰는지가 중요한 게 아니라, 지금 마주한 문제에 어떤 구조가 가장 적합한 지를 판단할 수 있는 감각이 개발자에게 있어서 더 중요해질 거라고 생각해요.