본문으로 건너뛰기
마탑6F 도서관
풍경

도메인 경계와 영향 범위 CI: 작은 변경을 작게 검증하기

업무 단위로 도메인을 나누고, 바뀐 곳과 그에 의존하는 부분만 골라 테스트하며, 경로 필터로 건너뛴 테스트가 병합을 막는 함정을 피하는 검증 방법을 살펴본다.

시드 개정 2판원문 대조 2026-09-29기록 2026-09-29T12:51:24Z

고친 내용: 독자에게 보이는 문장과 용어를 다듬고 기존 근거 연결을 유지했다.

변경 규모에 맞게 테스트를 줄이려면

저장소가 커지면 모든 테스트를 매번 돌리기가 버거워진다. 다시 테스트하고, 다시 빌드하고, 린트를 다시 실행하는 일이 쌓여 병합 대기 시간이 길어진다. 기다림이 길어지면 작은 수정도 미루게 되고, 미룬 수정이 쌓여 병합은 더 무거워진다.

변경된 부분만 테스트하도록 범위를 나눌 수 있다. 폴더마다 테스트를 연결하고 바뀌지 않은 곳은 건너뛰는 방식이다. 다만 설정이 허술하면 건너뛴 검사가 병합을 막을 수 있다. 로컬 테스트를 통과해도 CI와 보호 브랜치의 병합 조건은 충족하지 못하는 경우다. 테스트 범위를 나누는 기준과 함께 이런 설정 문제도 살펴봐야 한다.

업무와 도메인 모델을 기준으로 경계 정하기

마이크로서비스 안내는 비즈니스 기능을 중심으로 설계하라고 설명한다. 데이터 접근이나 메시징 같은 기술 계층보다 장바구니·결제·배송처럼 업무가 수행하는 기능을 기준으로 나눈다. 각 서비스의 결합도는 낮추고 내부 응집도는 높인다. 한 서비스를 수정할 때 다른 서비스를 함께 수정할 필요가 적을수록 결합도가 낮다.

도메인 주도 설계에서는 하나의 도메인 모델이 적용되는 범위를 바운디드 컨텍스트라고 부른다. 같은 용어도 컨텍스트마다 뜻이 달라질 수 있으므로, 각 범위에서 유비쿼터스 언어(공유 언어)를 정하고 컨텍스트 사이의 관계를 컨텍스트 맵에 기록한다. 폴더를 나누는 것만으로 이런 경계가 정해지지는 않는다. 각 폴더가 어떤 업무와 모델을 담당하는지 먼저 합의해야 한다.

이 절의 근거 S27

변경이 영향을 주는 범위를 그린 개념도개념 편집 일러스트 · 실제 화면·공식 구조도 아님마탑 편집부가 만든 개념 일러스트다. 한 모듈의 변경이 이에 의존하는 다른 모듈에도 영향을 준다는 개념을 마을 모형과 빛줄기로 표현했다. 두 마을은 빛줄기로 연결돼 있고 다른 한 마을에는 빛이 닿지 않는다. 실제 CI 제품 화면이나 공식 구조도가 아니다.마탑 편집부 생성 개념도 · 편집부 일러스트(실제 화면 아님)근거 S27 · S28
마탑 편집부가 만든 개념 일러스트다. 책상 위 지도에 마을 모형 세 개가 놓여 있다. 왼쪽 성과 오른쪽 마을은 빛줄기로 이어져 밝게 빛나고, 앞쪽 수도원과 풍차가 있는 마을에는 빛줄기가 연결되지 않아 어둡다. 주변에는 나침반과 도장, 확대경, 책이 보인다. 실제 제품 화면이나 공식 구조도가 아니다.

프로젝트 그래프와 커밋으로 영향 범위 계산하기

영향 범위를 계산하려면 변경된 파일을 확인할 수 있는 버전 기록과 프로젝트 그래프가 필요하다. 그래프에는 파일이 속한 프로젝트와 프로젝트 사이의 의존 관계가 담긴다. 변경된 프로젝트와 이에 의존하는 프로젝트를 찾아 빌드·테스트·린트 대상을 정한다. 대상이 적으면 계산량을 줄일 수 있지만, 거의 모든 프로젝트가 영향을 받는다면 전체 테스트를 실행하는 편이 낫다.

Nx의 affected 명령은 비교할 기준 커밋(base)과 대상 커밋(head)을 받는다. 로컬의 기본 base는 main 브랜치다. CI에서는 두 값을 직접 정해야 하며, 문서는 main 브랜치에서 CI가 마지막으로 성공한 커밋을 base로 권한다. 그 이후의 변경을 빠짐없이 포함하기 위해서다. 기준 커밋을 찾을 수 있도록 전체 Git 이력을 받아야 한다. GitHub에서는 마지막 성공 실행을 찾는 도구를 사용할 수 있고, 다른 CI에서도 해당 커밋을 변수로 전달할 수 있다.

이 절의 근거 S28

변경이 영향을 주는 프로젝트(가상 상점 예시)화살표는 변경의 영향이 전달되는 방향을 나타낸다. 금액 계산 모듈을 수정하면 이 모듈에 의존하는 결제와 검색이 모두 테스트 대상이 된다. 결제 화면의 문구만 수정한 경우에는 결제만 대상에 포함된다. 두 변경 사례를 함께 표시한 설명용 그림이며 Nx 공식 문서의 사례가 아니다.근거 S28
금액 계산 변경에서 결제 도메인과 검색 도메인으로 향하는 화살표는 변경의 영향 방향이다. 이 경우 테스트 대상 프로젝트에는 결제와 검색이 모두 포함된다. 별도 사례인 화면 문구 변경에서는 결제 도메인으로만 영향이 전달되므로 결제만 테스트 대상이 된다. affected 명령은 base·head 커밋을 비교해 대상을 계산한다. 가상 상점 예시다.변경의 영향변경의 영향결제에만 영향대상에 포함대상에 포함대상 선택금액 계산 변경공유 모듈 수정결제 도메인금액 계산 모듈 사용검색 도메인금액 계산 모듈 사용화면 문구 변경가상 상점의 결제 화면테스트 대상 프로젝트수정한 내용에 따라 선택affected 명령base·head 커밋 비교
그림을 글로 읽기

금액 계산 변경에서 결제 도메인과 검색 도메인으로 향하는 화살표는 변경의 영향 방향이다. 이 경우 테스트 대상 프로젝트에는 결제와 검색이 모두 포함된다. 별도 사례인 화면 문구 변경에서는 결제 도메인으로만 영향이 전달되므로 결제만 테스트 대상이 된다. affected 명령은 base·head 커밋을 비교해 대상을 계산한다. 가상 상점 예시다.

경로 필터로 건너뛴 검사가 병합을 막는 경우

GitHub Actions의 경로 필터는 테스트 나누기의 또 다른 수단이다. push와 pull_request 이벤트에 paths나 paths-ignore를 걸어 바뀐 경로에 따라 워크플로의 실행 여부를 결정한다. 브랜치 필터와 함께 쓰면 두 조건을 모두 만족할 때만 워크플로가 실행된다.

브랜치 필터나 경로 필터, 커밋 메시지 때문에 워크플로를 건너뛰면 해당 상태 검사가 Pending으로 남을 수 있다고 GitHub 문서는 설명한다. 그 검사가 보호 브랜치의 필수 조건이면 결과가 보고되지 않아 병합이 막힌다. 테스트 범위를 줄이려던 설정이 병합을 중단시킬 수 있는 것이다. 이를 어떻게 피할지는 팀의 CI 구성에 맞춰 결정해야 한다.

이 절의 근거 S29

경로 필터와 영향 범위 계산의 차이경로 필터는 변경된 경로에 따라 워크플로 실행 여부를 정한다. 영향 범위 계산은 프로젝트 그래프와 두 커밋으로 테스트 대상을 고른다. 검사를 건너뛰더라도 보호 브랜치가 요구하는 결과는 보고돼야 하므로, 팀의 CI 구성에 맞춰 필수 조건을 확인한다.근거 S29 · S28
방법선택 기준확인할 사항
경로 필터변경된 경로와 브랜치가 설정한 조건을 모두 충족하는지건너뛴 검사가 Pending으로 남아 병합을 막는지
영향 범위 계산프로젝트 그래프와 base·head 커밋대부분의 프로젝트가 포함되면 전체 테스트를 검토
건너뛴 검사필수 검사 결과가 보고되지 않으면 병합 불가경로 필터와 필수 검사 설정을 함께 점검
표를 글로 읽기

경로 필터는 변경 경로와 브랜치 조건을 사용하고, 영향 범위 계산은 프로젝트 그래프와 base·head 커밋을 사용한다. 세 번째 행은 건너뛴 필수 검사가 Pending 상태로 남아 병합을 막는지 확인하도록 설명한다.

의존성 캐시와 빌드 산출물

GitHub가 제공하는 러너(GitHub-hosted runners)는 매번 초기화된 환경에서 시작하므로 의존성을 매번 다시 받는다. 의존성 캐시는 자주 쓰는 파일을 GitHub에 저장해 다시 만드는 시간을 아끼는 수단이다. 산출물과는 쓰임이 다르다. 캐시는 실행 사이에 다시 쓰는 재료용이고, 산출물은 실행이 끝난 뒤에 보거나 다음 일에 넘기는 결과물용이다.

복원한 캐시도 신뢰할 수 없는 입력으로 다뤄야 한다. 캐시는 브랜치나 태그 단위로 공유되며, 신뢰할 수 없는 이벤트로 시작한 워크플로에서도 민감한 캐시에 접근할 수 있기 때문이다. 시크릿은 캐시에 넣지 않는다. 캐시가 실행 시간을 줄여주더라도 테스트를 대신하지는 못한다.

이 절의 근거 S30

TDD와 통합 테스트의 역할

테스트 주도 개발은 다음에 구현할 기능의 테스트를 먼저 작성하고(레드), 테스트를 통과할 때까지 코드를 구현한 뒤(그린), 새 코드와 기존 코드를 다듬는 과정(리팩터)을 반복한다. 테스트를 먼저 쓰면 코드를 호출하는 쪽의 인터페이스부터 생각하게 되므로 인터페이스와 구현을 분리하는 데 도움이 된다. 단위 테스트는 개별 모듈에 빠른 피드백을 주지만, 도메인 사이에 주고받는 데이터와 호출 방식이 약속대로 동작하는지는 별도로 확인해야 한다.

단위 테스트는 개별 모듈의 동작을 확인하고, 통합 테스트와 계약 테스트는 모듈이나 도메인이 함께 동작할 때의 계약을 확인한다. 컨텍스트 맵은 컨텍스트 사이의 관계를 기록하며, 영향 범위 계산은 변경이 어떤 프로젝트에 영향을 주는지 판단한다. 이는 여러 출처를 종합한 편집자의 구분이다. 로컬 단위 테스트는 수정할 때마다, 영향 범위 테스트는 풀 리퀘스트마다, 전체 통합 테스트는 정해진 주기로 실행하는 구성을 생각할 수 있다. 배치 방법은 팀이 정하되 각 검증 역할을 생략하는 것은 권하지 않는다. 특히 공유 모듈을 수정했다면 로컬 테스트 통과만으로 병합을 결정해서는 안 된다.

이 절의 근거 S39 · S27 · S28

테스트 종류별 역할단위 테스트, 영향 범위 테스트, 통합 테스트는 확인하는 대상이 다르다. 이 표는 각 검증을 언제 실행할지 편집자가 정리한 예시다. Pending 상태의 필수 검사가 병합을 막는지도 별도로 확인한다.근거 S27 · S28 · S29 · S39
검증 종류실행 시점확인할 내용
로컬 단위 테스트코드를 수정할 때마다모듈이 의도대로 동작하는가
영향 범위 테스트풀 리퀘스트마다변경이 영향을 주는 프로젝트가 동작하는가
전체 통합 테스트정해진 주기에모듈을 결합해도 동작하는가
병합 상태 점검주기적으로건너뛴 필수 검사가 병합을 막는가
표를 글로 읽기

로컬 단위 테스트는 코드를 수정할 때마다 개별 모듈의 동작을 확인한다. 영향 범위 테스트는 풀 리퀘스트마다 변경이 영향을 주는 프로젝트를 검사한다. 전체 통합 테스트는 정해진 주기에 모듈을 결합한 상태를 확인하고, 병합 상태 점검은 Pending으로 남은 필수 검사를 확인한다.

가상 예시: 상점 저장소의 변경 범위

아래는 실제로 실행하지 않은 가상 예시다. 상점 저장소에 결제와 검색 도메인이 있고, 둘이 금액 계산 모듈을 함께 사용한다고 가정하자. 금액 계산을 수정하면 결제와 검색 모두 테스트 대상에 포함된다. 결제 화면의 문구만 수정하면 결제만 포함된다. 이 범위는 폴더 이름이 아니라 프로젝트 그래프의 의존 관계를 기준으로 계산한다.

CI에서는 최근 성공 커밋을 base로, 이번 풀 리퀘스트(pull request, PR)의 최신 커밋을 head로 정해 affected 명령에 전달한다. 아래 셸 코드는 발췌본이며 두 변수는 팀의 CI에서 설정해야 한다. 전체 워크플로가 아니므로 이 코드만 붙여 넣어서는 실행되지 않는다. origin/main 같은 브랜치 이름으로 비교를 시작할 수도 있지만, 권장 기준은 main에서 CI가 마지막으로 성공한 커밋이다. 경로 필터를 사용한다면 건너뛴 검사가 보호 브랜치의 필수 조건인지도 확인한다. 이 예시는 시간 단축 측정값을 제시하지 않는다. 실제 효과는 같은 풀 리퀘스트 집합으로 도입 전후의 대기 시간과 계산량을 비교해 확인할 수 있다.

# 팀 CI가 두 변수를 준다. 전체 흐름이 아니라 발췌이다.
: "${NX_BASE:?set NX_BASE to last successful main commit SHA}"
: "${NX_HEAD:?set NX_HEAD to PR head SHA}"
nx affected -t test --base="$NX_BASE" --head="$NX_HEAD"

실패 양상과 한계

프로젝트 그래프에 없는 의존 관계는 영향 범위 계산에서 빠진다. 그래프에 기록되지 않은 동적 import, 수동 배포 스크립트, 문서로만 남은 계약은 변경돼도 테스트 대상으로 선택되지 않을 수 있다. 반대로 공유 모듈을 수정하면 테스트 대상이 많아져 실행 시간을 줄이기 어려울 수 있다. 이때는 전체 테스트를 실행하는 편이 낫다.

기준 커밋을 잘못 정하면 테스트 대상도 달라진다. 필요보다 오래된 커밋을 기준으로 삼으면 이미 확인한 변경까지 포함하고, 너무 최근의 커밋을 선택하면 확인해야 할 변경을 빠뜨린다. 얕은 클론 때문에 기준 커밋을 찾지 못하는 경우도 있다. 로컬 테스트를 통과했더라도 CI의 경로 필터와 보호 브랜치 조건 때문에 병합이 중단될 수 있으므로, 두 환경의 차이를 확인해야 한다.

이 절의 근거 S28 · S29

기준 커밋이 어긋났을 때 바로잡기테스트 대상이 예상과 다르면 기준 커밋을 확인한다. 너무 오래된 기준은 불필요한 변경까지 포함하고, 너무 최근의 기준은 필요한 변경을 빠뜨린다. CI에서는 main의 최근 성공 커밋을 기준으로 삼고 이를 찾을 수 있도록 전체 Git 이력을 받는 구성이 권장된다.근거 S28
  1. 대상이 너무 많으면 기준 시점 확인

    기준 커밋이 너무 오래됐다면 불필요한 변경까지 포함된다. main에서 CI가 마지막으로 성공한 커밋을 기준으로 삼는다.

  2. 변경이 빠지면 비교 범위 확인

    기준 커밋이 너무 최근이면 필요한 변경이 빠진다. 마지막 성공 실행 이후의 변경을 모두 포함하도록 기준을 정한다.

  3. 기준 커밋을 찾지 못하면 이력 확인

    얕은 클론에 기준 커밋이 없을 수 있다. 전체 Git 이력을 받고, GitHub에서는 마지막 성공 실행을 찾는 도구도 활용한다.

단계를 글로 읽기

기준 커밋을 점검하는 세 단계. 대상이 너무 많으면 기준이 오래됐는지, 변경이 빠지면 기준이 너무 최근인지 확인한다. 기준 커밋을 찾지 못하면 얕은 클론 여부를 확인하고 전체 Git 이력을 받는다.

대기 시간과 누락된 오류 확인하기

병합 대기 시간, 실행당 계산량, 건너뛴 검사의 보고 여부를 측정한다. 영향 범위에서 빠진 프로젝트에 오류가 생긴 횟수도 따로 기록한다. 이런 오류가 늘면 프로젝트 그래프에 누락된 의존 관계가 있는지 확인하고 도메인 경계도 다시 살핀다.

필수 검사가 Pending 상태로 남아 병합이 중단되는지도 주기적으로 확인한다. 같은 문제가 반복되면 경로 필터와 보호 브랜치의 필수 검사 설정을 함께 점검한다. 테스트 범위를 줄인 뒤에도 필요한 검사 결과가 보고되는지 확인해야 한다.

테스트 범위를 줄인 뒤에도 확인할 것

업무와 도메인 모델을 기준으로 경계를 정한 뒤, 프로젝트 그래프와 base·head 커밋으로 변경의 영향 범위를 계산한다. 로컬 단위 테스트로 빠르게 피드백을 받되, CI에서 검사를 건너뛸 때는 보호 브랜치의 필수 조건도 함께 확인해야 한다.

도구와 기준 커밋은 팀의 CI 구성에 맞춰 정한다. 병합 조건을 설정하는 방법은 「검토 게이트와 병합」에서, 평가 결과를 해석하는 기준은 「AI 평가」에서 이어서 살펴볼 수 있다.

현재 판 출처 (이 개정의 출처 보관본 아님) 5건

아래는 현재 판의 출처 목록을 고리 풀이용으로 그대로 둔 참조이며, 이 개정의 출처 보관본이 아니다.

  1. Use Domain Analysis to Model Microservices (외부)
    S27
  2. Nx: Run Only Tasks Affected by a PR (외부)
    S28
  3. GitHub Actions: Workflow syntax for GitHub Actions (외부)
    S29
  4. GitHub Actions: Dependency caching (외부)
    S30
  5. Test Driven Development (외부)
    S39
← 고침 기록으로