
사람의 의지와 문서 컨벤션을 뛰어넘어 시스템과 타입 제약으로 강제하는 완벽한 리팩터링의 기술
무조건 테스트를 통과시키는 가짜 안전감에서 벗어나, 실수하고 싶어도 실수할 수 없는 강력한 시스템적 제약을 설계해 나가는 과정을 조명합니다. 서비스를 잘게 쪼갠 UseCase 격리부터 포트와 어댑터 구조 설계, 그리고 TypeScript 컴파일 타임 검증을 통한 빈틈없는 인터페이스 동기화 기법까지 실제 아임웹 백엔드 팀의 집요한 개선 여정을 공유합니다. 말뿐인 문서보다 컴파일 에러가 아키텍처 규격을 더 확실히 지켜낸다는 실무적인 지혜를 만나보세요.
프로젝트 규모가 커짐에 따라 Mock 테스트 유지보수에 고통받고 있거나, AI 코딩 에이전트 도입 후 아키텍처 규격이 점점 무너지는 것을 경험하고 있는 개발팀에게 적극 추천합니다. 컴파일러와 린트를 가장 든든한 코드 감시자로 임명하는 구조적 가이드라인을 확보해 보세요.
기존 백엔드 시스템은 비대한 서비스 레이어와 가상 객체(Mock)의 무분별한 남용으로 인해 테스트 신뢰도가 낮았고, TypeORM의 BaseRepository 상속 구조 한계로 안전한 대역 사용이 어려워 'as never' 강제 캐스팅에 의존했습니다.
컨트롤러와 UseCase를 분리해 단일 책임 원칙을 적용하고 인라인 쿼리를 리포지토리 내부로 캡슐화했습니다. 또한, AsyncLocalStorage를 통한 트랜잭션 컨텍스트 전파 기법과 포트 및 어댑터 아키텍처를 도입하고, 커스텀 ESLint 및 TypeScript 양방향 타입 일치 검사로 Mock 사용과 인터페이스 왜곡을 제한했습니다.
기존 약 2,199개에 달하던 Mock 호출 횟수를 검증 성격상 필수적인 HTTP 레이어 4개로 대폭 축소했으며, 통합 테스트 적용 파일을 기존 0개에서 143개로 확장하여 검증력이 높은 견고한 테스트 안전망을 구축했습니다.
Trade-off
사용하지 않는 인터페이스 메서드에 대해 명시적 예외(notUsed)를 던지도록 설계하면서 개발 과정에서 인메모리 어댑터를 수동으로 보완하거나 테스트의 성격에 따라 통합 테스트 영역으로 재배치하는 추가 작업 리소스가 지속해서 발생합니다.
비즈니스 도메인의 핵심 로직(Port)을 외부 DB, 라이브러리, 전송 계층 등의 상세 구현 기술(Adapter)과 완전히 격리하여 시스템 유연성과 테스트 용이성을 극대화하는 소프트웨어 설계 패턴입니다.
Node.js에서 비동기 작업 흐름 전반에 걸쳐 고유한 상태 및 실행 컨텍스트 정보를 공유하고 추적할 수 있도록 제공하는 스레드 로컬 유사 메커니즘입니다.
매개변수 가변성을 허용하는 TypeScript 타입 체커의 특성을 우회하여, 인터페이스와 구현체 간 파라미터 튜플 및 반환 타입을 양방향으로 완벽 대조하는 고급 타입 추론 기술입니다.