코어를 깨끗하게 지키는 의도적인 오염 경계
피할 수 없는 복잡성을 명시적인 외부 경계에 가두고, 제한된 개발 시간을 시스템의 핵심 개념에 쓰는 방법을 다룬다.
출처 및 AI 안내: 이 글은 제미니의 개발실무 유튜브를 기반으로 작성되었습니다.
gpt-5.6-sol모델을 사용해 생성·편집했습니다.
시간과 인력, 기존 코드의 상태는 언제나 제한되어 있다. 시스템의 모든 부분에 같은 관심을 쓸 수 없다면 어디를 가장 깨끗하게 지키고 어디에서 어느 정도의 지저분함을 감당할지 선택해야 한다.
한 영역을 “쓰레기통”이라고 부르는 것은 그 선택을 드러내는 거친 비유다. 일부러 나쁜 코드를 만들자는 뜻이 아니다. 피할 수 없는 지저분함이 시스템 전체에 퍼지게 두지 말고 눈에 보이는 한곳에 모으자는 뜻이다.
쓰레기통을 없앤다고 쓰레기까지 사라지지는 않는다. 버릴 곳이 없으면 난간이나 길가처럼 원래 목적과 무관한 곳에 흩어진다. 코드도 비슷하다. 외부 형식에 맞춘 분기와 기존 코드의 예외를 둘 곳이 없으면 컨트롤러, 공통 코드, 핵심 모델 가운데 당장 넣기 쉬운 곳으로 번진다. 지정한 경계의 첫 번째 가치는 지저분함의 존재를 인정하는 데 있고, 두 번째 가치는 그 범위를 보이게 하는 데 있다.
따라서 이 비유는 품질 기준을 낮추기 위한 구호가 아니라 자원 배분을 위한 언어다. 일정, 가용 인원, 기존 코드의 오염 정도를 놓고 모든 곳을 같은 수준으로 정리할 수 있는지 먼저 본다. 할 수 없다면 어느 영역의 혼란이 장기적으로 더 큰 비용을 만드는지 선택한다. 선택하지 않는 척하면 우선순위가 사라지는 것이 아니라 가장 급한 변경이 매번 우선순위를 대신 정하게 된다.
비즈니스가 소유한 개념을 지킨다
외부 연동사의 데이터를 수집하고 정제하는 영역과, 비즈니스가 직접 소유한 상품 개념 영역이 함께 있는 시스템을 생각해 보자. 외부 영역은 팀이 통제하지 못하는 이유로 계속 바뀐다. 개념 영역은 팀이 가장 잘 이해하고 지켜야 할 부분이다.
두 영역이 나뉘지 않으면 어디에 더 강한 설계 노력을 써야 하는지 보기 어렵다. 모듈 경계를 그으면 우선순위가 드러난다. 일정이 빠듯할 때는 외부 수집 영역의 거친 부분을 조금 더 허용하더라도 핵심 상품 개념은 분명하게 유지할 수 있다.
분리 전에는 수집과 정제에 필요한 규칙, 연동사별 변형, 상품 자체의 정책이 한 덩어리로 보일 수 있다. 모듈을 나누면 어떤 변화가 외부에서 왔고 어떤 규칙이 회사의 개념인지 비교할 수 있다. 외부 쪽은 우리가 결정하지 않은 형식과 변화 속도를 받아들여야 하지만, 코어 쪽은 비즈니스가 사용하는 언어와 책임을 오래 유지해야 한다. 이 차이가 설계 노력의 우선순위를 만든다.
외부 데이터를 다루는 코드가 다소 거칠 수 있다는 말도 무제한 허용은 아니다. 외부의 모양을 코어에 그대로 전달하지 않고 경계 안에서 처리해야 한다. 연동사마다 다른 조건이 생기더라도 그 조건이 상품 개념의 규칙인 것처럼 중앙으로 이동하지 않게 한다. 그래야 새 연동사가 추가되거나 기존 형식이 바뀔 때 코어 전체를 함께 흔들지 않을 수 있다.
외부 영역이 중요하지 않다는 말은 아니다. 그곳도 맡은 일을 해야 한다. 제한된 설계 시간을 어디에 먼저 쓸지를 정하는 트레이드오프다.
외부 영역 역시 실제 서비스를 운영하는 코드이므로 입력을 처리하고 실패를 찾고 수정할 수 있어야 한다. 다만 불안정한 외부 세계를 완벽하게 우아한 모델로 꾸미는 데 쓰는 시간과, 핵심 개념의 책임을 분명히 하는 데 쓰는 시간을 같게 배분하지 않을 수 있다는 뜻이다. 동작 가능성까지 포기하는 것이 아니라 정제 수준과 추상화에 들이는 우선순위를 다르게 잡는 선택이다.
쓰레기통의 가치는 지저분함을 가두는 데 있다
지정된 장소가 없다고 어색한 코드가 사라지지는 않는다. 누군가 넣을 수 있는 곳마다 흩어지고, 결국 코드베이스 전체가 읽기 어려워진다. 쓰레기통 비유의 장점은 쓰레기통만 더러워진다는 데 있다.
격리는 오염 경계에서 코어로 넘어가는 지점을 분명히 할 때 성립한다. 외부 형식과 예외를 처리한 뒤 코어가 이해하는 개념으로 넘기고, 코어는 특정 연동사의 우연한 필드나 규칙을 알지 않게 한다. 경계 안에서 허용한 임시 방식이 편하다는 이유로 다른 모듈의 새 표준이 되지 않게 하는 것도 필요하다. 그렇지 않으면 이름만 분리된 모듈일 뿐 지저분함은 의존성을 따라 계속 퍼진다.
따라서 경계에는 두 가지 약속이 함께 있어야 한다.
- 자원이 부족할 때 한 영역의 덜 정돈된 상태를 감당한다.
- 그 타협이 핵심 영역으로 퍼지지 않게 한다.
양쪽이 모두 같은 정도로 얽혔다면 이 트레이드오프는 실패한 것이다. 지저분함의 비용은 냈지만 그 대가로 아무것도 보호하지 못했다.
그래서 코어 쪽에는 반대 방향의 약속이 필요하다. 오염 경계에서 타협을 허용한 만큼 핵심 영역에서는 외부 사정을 끌어들이지 않는 기준을 더 엄격히 지킨다. 리뷰할 때 지금 추가하는 조건이 상품 자체의 정책인지, 어느 연동사의 데이터를 맞추기 위한 것인지 묻는다. 후자라면 경계 바깥으로 새기 전에 수집·정제 영역에서 흡수할 방법을 먼저 찾는다.
비유를 무성의의 허가로 바꾸지 않는다
“오염 경계”가 운영하거나 변경할 수 없는 코드를 허용한다는 뜻은 아니다. 그 영역을 영원히 지저분하게 두라는 말도 아니다. 시간과 사람이 생기면 그곳도 개선하면 된다.
지저분함을 감당한다는 말에는 최소한의 선이 있다. 담당자가 동작을 추적할 수 있어야 하고, 바뀐 외부 입력을 수정할 수 있어야 하며, 핵심으로 넘기는 결과가 무엇인지 설명할 수 있어야 한다. 실패를 방치하거나 누구도 고칠 수 없게 만드는 코드는 트레이드오프가 아니라 운영 책임의 포기다. 덜 다듬은 지역적 구현과 통제되지 않는 혼란을 구분해야 한다.
이 비유는 실제로 선택해야 하는 순간에 유용하다. 한 시간만 남았고 외부 연동 영역과 핵심 개념 가운데 한쪽만 정리할 수 있다고 해보자. 이 예시에서는 코어에 먼저 시간을 쓴다. 시간이 더 있으면 둘 다 다듬는다.
한 시간이라는 조건은 정답을 고정하려는 숫자가 아니라 선택을 피할 수 없는 상황을 드러낸다. 시간이 충분하다면 양쪽을 깨끗하게 만드는 편이 좋다. 하지만 지금 하나만 고쳐야 한다면 외부 변화에 다시 흔들릴 코드보다 여러 기능이 의지하는 핵심 개념을 우선할 수 있다. 제한이 사라졌을 때 바깥 영역으로 돌아와 개선할 수 있도록, 받아들인 타협의 위치와 범위는 남겨 두어야 한다.
정확한 우선순위는 소프트웨어마다 다르다. 중요한 것은 선택을 드러내는 일이다. 비즈니스가 가장 지켜야 할 영역을 찾고 경계를 그리자. 피할 수 없는 타협이 모든 곳에 동시에 퍼지는 대신 통제할 수 있는 한곳에 머물게 하자.
외부 연동이 나중에 안정되거나 비즈니스에서 더 중요한 영역이 되면 우선순위는 바뀔 수 있다. 그때 경계 안에 모인 비용을 보고 더 많은 시간을 투입하면 된다. 처음의 판단을 영구 규칙으로 만들 필요는 없다. 다만 타협이 한곳에 모여 있어야 판단을 바꾸었을 때 손볼 대상도 명확하다. 결국 깨끗한 코어와 의도적인 오염 경계는 완벽함의 선언이 아니라, 현재 제약 속에서 무엇을 보호하고 나중에 무엇을 개선할지 합의하는 방식이다.