사람이 이해하고 빌드가 지키는 레이어 규칙
안정적인 레이어 역할과 선택적 상위 레이어의 조건을 정의하고, 필요할 때만 자동 검증으로 규칙을 강제하는 방법을 다룬다.
출처 및 AI 안내: 이 글은 제미니의 개발실무 유튜브를 기반으로 작성되었습니다.
gpt-5.6-sol모델을 사용해 생성·편집했습니다.
어떤 곳에서는 Controller가 FacadeImpl을 호출하고, 그 구현체가 서비스를 거쳐 다시 다른 서비스를 호출한다. 바로 옆 기능은 비슷한 일을 워크플로나 래퍼로 처리한다. 각각의 지역적인 선택은 합리적으로 보일 수 있다. 그러나 이 선택들이 모이면 새로 합류한 사람은 가장 기본적인 질문에 답하지 못한다. 다음 비즈니스 로직은 어디에 두어야 할까?
레이어의 개수 자체가 문제는 아니다. 개별 서비스를 조합하는 상위 흐름이 실제로 필요한 비즈니스도 있다. 문제는 각 레이어의 역할을 설명하는 공통 규칙 없이 레이어가 생겼다가 사라지는 것이다.
안정적인 표준 경로부터 정한다
팀은 일반적인 작업이 통과할 최소 레이어를 정해야 한다. 이름은 프로젝트마다 달라도 된다. 중요한 것은 일관된 경로와 각 위치에 부여한 의미다. 비즈니스 레이어를 표준으로 정했다면 현재 메서드가 한 줄을 위임할 뿐이라는 이유로 건너뛰지 않고 단순한 요구사항도 그 경로를 따르게 한다.
한 부분만 보면 이 작은 형식이 낭비처럼 보일 수 있다. 프로젝트 전체에서는 예측 가능성을 얻는다. 낯선 기능을 연 개발자도 요청이 어디로 들어오고, 비즈니스 행위가 어디에 있으며, 어떤 의존 방향이 허용되는지 알 수 있다. 패키지마다 새로운 아키텍처를 추론할 필요가 없으므로 컨벤션은 읽기와 수정을 돕는다.
일관성에는 유지보수 목적도 있다. 코드는 이후의 구성원이 계속 확장해야 할 회사의 자산이다. 구두 설명으로만 이해할 수 있는 구조는 아직 신뢰할 만한 팀 규칙이 아니다.
규칙을 문서로 남기면 리뷰도 취향 싸움에서 벗어난다. 어느 이름이 더 멋진지를 다투는 대신 현재 코드가 합의한 역할과 의존 방향을 지키는지 확인할 수 있다.
정해진 조합이 있을 때만 상위 레이어를 추가한다
표준 경로를 정한다고 모든 추가 레이어를 금지하는 것은 아니다. 한 비즈니스 컴포넌트가 회원을, 다른 컴포넌트가 상품을 맡는다고 하자. 회원 규칙과 회원 전용 상품 규칙을 함께 다루는 유스케이스라면 둘을 조정하는 상위 레이어가 필요할 수 있다. 팀은 이를 퍼사드, 워크플로, 래퍼 가운데 하나로 부를 수 있다.
이름보다 중요한 것은 진입 조건이다. 예를 들면 “서로 다른 두 비즈니스 역량을 조합하는 흐름에만 퍼사드를 만든다”라고 정할 수 있다. 하나의 비즈니스 책임만 가진 코드를 퍼사드라고 이름 붙여도 의미 있는 상위 레이어가 생기지는 않는다.
이 규칙은 팀의 실제 도메인에 기반해야 한다. 먼저 큰 비즈니스 개념이 무엇이며 그 사이의 조합이 무엇인지 정리해야 한다. 코드와 도메인을 보지 않은 채 보편적인 레이어 그림으로 답을 확정할 수는 없다. 표준 경로를 정하고, 예외가 허용되는 조건을 정하고, 기능 전반에서 같은 용어를 쓴다는 과정은 일관되게 유지할 수 있다.
선택적인 조합 레이어는 조건이 있는 곳에서만 나타날 수 있다. 그러나 그 아래의 표준 레이어까지 요구사항마다 늘었다 줄어들어서는 안 된다. 어떤 레이어가 정말 가치가 없다고 판단했다면 기능마다 우회하지 말고 프로젝트 전체의 표준에서 명시적으로 제거해야 한다.
구현 질문에 답할 수 있는 규칙을 쓴다
쓸모 있는 컨벤션은 신규 구성원이 다음 질문에 답하게 해 줘야 한다.
- 각 표준 레이어의 책임은 무엇인가?
- 의존성은 어느 방향으로 흐를 수 있는가?
- 조합을 맡는 상위 레이어의 단일 명칭은 무엇인가?
- 어떤 비즈니스 조건에서 그 레이어를 만들 수 있는가?
- 한 줄을 위임할 뿐이어도 표준 레이어는 필수인가?
예시는 경계를 드러내는 데 도움이 된다. 일반적인 기능 하나, 정당한 조합 하나, 팀이 허용하지 않는 구조 하나를 보여 주자. 특히 거부하는 사례가 중요하다. 서비스나 퍼사드처럼 넓은 단어는 서로 충돌하는 해석을 모두 허용하기 때문이다.
문서에는 선택한 구조만 적지 말고 왜 다른 구조를 쓰지 않았는지도 남기는 편이 좋다. 예를 들어 단일 비즈니스 행위에는 퍼사드를 만들지 않고, 서로 다른 역량을 조정할 때만 만든다는 식이다. 그러면 새 구성원이 기존 파일을 복사해 우연히 레이어를 늘리는 대신 현재 요구가 예외 조건에 해당하는지 판단할 수 있다.
규칙은 프로젝트를 위해 존재하므로 팀이 새로운 사실을 배우면 바꿀 수 있다. 다만 의도적으로 개정하기 전까지는 비슷한 코드가 구조적으로 대칭을 이루어야 한다. 그렇지 않으면 문서 속 아키텍처와 실행되는 코드가 서로 다른 시스템을 설명하게 된다.
사람의 확인만으로 부족할 때 자동화한다
소규모 팀이라면 문서와 리뷰만으로 충분할 수 있다. 같은 위반이 반복된다면 컨벤션을 실행 가능한 제약으로 바꿀 수 있다. 마커 어노테이션이나 컴포넌트 타입으로 레이어를 표시하고, 아키텍처 테스트나 린트 규칙, 빌드 분석을 통해 금지된 의존성이나 누락된 표준 컴포넌트를 거부하는 방식이다.
강한 자동 검증에도 비용이 든다. 팀이 이해하고 유지해야 할 도구가 늘어나므로 모든 프로젝트의 기본 답은 아니다. 일관된 구조의 가치가 그 장치를 정당화할 때, 특히 수동 리뷰만으로 코드의 정렬을 유지하기 어려울 때 사용한다.
자동화하기 전에는 어떤 실패를 막으려는지도 분명히 해야 한다. 표준 비즈니스 레이어를 건너뛰는 일이 반복되는지, 금지한 역방향 의존성이 리뷰를 통과하는지, 같은 역할이 기능마다 다른 이름으로 생기는지를 확인한다. 한두 번의 실수 때문에 복잡한 검증 장치를 넣기보다 문서와 예시로 먼저 맞출 수 있다. 반대로 같은 이탈이 계속된다면 사람의 기억에 맡긴 규칙을 빌드가 확인하도록 바꿀 근거가 생긴다.
자동화는 코드 두 덩어리가 서로 다른 비즈니스 역량인지 판단해 주지 못한다. 도메인 의미는 여전히 사람이 정하고, 빌드는 코드로 표현된 규칙만 검사할 수 있다. 이 역할 분담이 적절하다. 팀은 경계가 존재하는 이유를 설명하고, 시스템은 기계적인 이탈이 또 다른 지역 규칙으로 굳기 전에 발견한다.