Python

레지스트리(Registry) 패턴

효진인데요 2026. 2. 11. 19:51

레지스트리(Registry) 패턴 쉽게 이해하기

개발하다 보면 이런 상황이 자주 생긴다.

  • 기능이 몇 개 없을 땐 if-else로 처리 가능
  • 근데 도메인/툴이 계속 늘어나면?
  • 파일 수정이 계속 발생하고 코드가 점점 더러워짐

이 문제를 깔끔하게 해결하는 패턴이 바로 Registry(레지스트리) 패턴이다.


 

1. 레지스트리 패턴이란?

레지스트리 패턴은 쉽게 말해서

이름(key) → 객체(또는 클래스) 를 매핑해서 저장해두는 구조


즉, 문자열 이름만 알면 해당 기능을 찾아서 실행할 수 있도록 하는 패턴이다.


 

2. 비유로 이해하기: 전화번호부

레지스트리를 전화번호부로 생각하면 쉽다.

 

📒 레지스트리 = 전화번호부

 

예를 들어 전화번호부에는 이런 정보가 들어있다.

  • "김김김" → 010-1234-5678
  • "박땡땡" → 010-9876-5432

이름만 알면 전화번호를 바로 찾을 수 있는 구조.


코드에서는 이렇게 대응된다

  • "member_info" → MemberInfoTool
  • "book_order" → BookOrderTool

즉, 툴 이름만 알면 해당 툴 클래스를 찾아서 실행 가능한 것

 


3. 레지스트리 없을 때: if-else 지옥

레지스트리를 사용하지 않으면 보통 이런 코드가 된다.

 
# tools.py - 새 도메인 추가할 때마다 여기 수정해야 함
def get_tool(name):
    if name == "member_info":
        return MemberInfoTool()
    elif name == "book_order":
        return BookOrderTool()
    elif name == "lecture_order":      # 추가
        return LectureOrderTool()
    elif name == "reimbursement":      # 추가
        return ReimbursementTool()
    # ... 계속 늘어남

문제점

  • 새로운 Tool 추가할 때마다 if-else 계속 추가
  • 코드가 계속 길어지고 유지보수 어려움
  • 도메인이 10개, 20개, 50개 되면 관리 불가능

결국 이 구조는 확장성이 매우 떨어진다.


 

4. 레지스트리 있을 때: 전화번호부에 등록하고 찾기

레지스트리 패턴을 적용하면 구조가 완전히 달라진다.

registry.py (전화번호부 역할)

 
# registry.py
class SnowflakeToolRegistry:
    _registry = {}  # 빈 전화번호부
    
    @classmethod
    def register(cls, tool_class):
        """전화번호부에 등록"""
        name = tool_class._tool_name.tool_name
        cls._registry[name] = tool_class
        return tool_class
    
    @classmethod
    def get(cls, name):
        """전화번호부에서 찾기"""
        tool_class = cls._registry.get(name)
        return tool_class() if tool_class else None

 

이제 registry는 내부적으로 이렇게 저장하게 된다.

 
_registry = {
    "book_order": BookOrderTool,
    "member_info": MemberInfoTool,
}

 

5. 툴 파일에서는 등록만 하면 끝

 
# book_order.py
@SnowflakeToolRegistry.register
class BookOrderTool:
    _tool_name = ToolName.BOOK_ORDER  # "book_order"
 

툴을 추가할 때 @register만 붙이면 자동으로 registry에 들어간다.

즉, 새로운 툴을 추가해도 기존 파일을 수정할 필요가 없다.


 

6. tools.py는 더 이상 수정 필요 X

 
# tools.py
def get_tool(name):
    return SnowflakeToolRegistry.get(name)
 

이제 get_tool 함수는 항상 registry만 바라보면 된다.


 

7. @데코레이터가 실제로 하는 일

많이 헷갈리는 부분이 데코레이터(@register)인데,
실제로는 아래 코드와 완전히 동일하다.

# 데코레이터 코드
@SnowflakeToolRegistry.register
class BookOrderTool:
    ...

# 실제 동작 코드
class BookOrderTool:
    ...

BookOrderTool = SnowflakeToolRegistry.register(BookOrderTool)
 
 

클래스가 정의되는 순간 자동으로 registry에 등록


8. 실제 동작 흐름 (앱 실행 순서)

레지스트리 패턴은 결국 import될 때 동작한다.

 

1) 앱 시작 시 import

from app.tools.snowflake.book_order import BookOrderTool

 

2) import되면서 @register 실행

_registry = {"book_order": BookOrderTool}

 

3) 나중에 LLM이 "book_order" 호출

tool = SnowflakeToolRegistry.get("book_order")

 

4) tool 실행

result = await tool.run_tool(query_type="delivery_status", ...)

9. 레지스트리 패턴의 장점

 

✅ 확장성

  • Tool이 10개든 100개든 registry 구조는 동일

✅ 유지보수성

  • 기존 코드 수정 없이 Tool 파일만 추가하면 됨

✅ 플러그인 구조에 적합

  • LangGraph, LangChain Agent 구조에서 매우 유용

10. 핵심 요약

개념설명
레지스트리 이름 → 클래스 매핑하는 전화번호부
@register 전화번호부에 자동 등록하는 스티커
장점 새로운 도메인 추가해도 기존 코드 수정 불필요

11. 한 줄 정리

"이름표 붙여서 창고에 넣어두고, 나중에 이름으로 꺼내 쓰는 패턴"


결론

레지스트리 패턴 == "Tool 이름으로 실행해야 하는 구조"에서 거의 필수적인 패턴

if-else로 Tool을 관리하는 구조는 확장성에 한계도 있고 코드가 지저분해지지만,
레지스트리 패턴을 적용하면 코드가 훨씬 깔끔해지고 유지보수도 쉬워진다.

728x90