SDP로 순환 의존성 방지하기

순환 의존성은 소리 없는 살인자입니다. 빌드 오류를 일으키지도 않고, 임포트 시 런타임 예외를 발생시키지도 않습니다. 대신, 몇 주 뒤 프로덕션 환경에서 나타나는 미묘한 undefined 값을 유발합니다.

모듈 A가 B를 임포트하고, B가 다시 A를 임포트할 때 사이클이 발생합니다.

JavaScript는 이러한 임포트를 조용히 해결합니다. 모듈 B가 모듈 A를 요청할 때 모듈 A가 아직 로딩 중이라면, JavaScript는 빈 객체를 반환합니다. 코드는 나중에 실패하며, 스택 트레이스는 잘못된 곳을 가리키게 됩니다.

dependency-cruiser를 사용하면 이를 해결할 수 있습니다. 이 도구는 파일을 스캔하고 의존성 그래프를 매핑합니다. TypeScript 및 모노레포와 함께 사용할 수 있습니다.

설정 방법:

  • 개발 의존성에 추가: yarn add -D dependency-cruiser
  • package.json에 스크립트 추가: "depcruise": "depcruise packages --config .dependency-cruiser.js"
  • 사이클을 감지하기 위한 .dependency-cruiser.js 파일 생성

하지만 사이클을 찾는 것은 문제의 절반에 불과합니다. 사이클이 형성되지 않도록 막아야 합니다.

안정적 의존성 원칙(Stable Dependencies Principle, SDP)을 사용하세요. 이 규칙은 반드시 안정적인 방향으로 의존해야 함을 의미합니다.

안정성은 구조적 속성입니다. 많은 다른 모듈이 특정 모듈에 의존할 때 그 모듈은 안정적입니다. 안정적인 모듈을 변경하면 많은 사람에게 영향을 미칩니다. 이러한 비용이 해당 모듈을 안정적으로 만듭니다.

불안정성(Instability) 공식을 사용하세요: I = Fan-Out / (Fan-In + Fan-Out)

• I = 0은 모듈이 최대한 안정적임을 의미합니다. 모든 것이 이 모듈에 의존하며, 이 모듈은 아무것에도 의존하지 않습니다. • I = 1은 모듈이 최대한 불안정함을 의미합니다. 이 모듈은 많은 것에 의존하지만, 아무것도 이 모듈에 의존하지 않습니다.

규칙: 모듈의 불안정성 점수는 해당 모듈이 임포트하는 모든 모듈의 점수보다 높아야 합니다. 의존성 방향(화살표)은 반드시 불안정성이 더 낮은 쪽을 향해야 합니다.

저수준 유틸리티(low-level utils, I ≈ 0)는 고수준 페이지(high-level pages, I ≈ 1)를 절대 임포트해서는 안 됩니다.

이 원칙을 dependency-cruiser를 통해 자동화된 규칙으로 바꿀 수 있습니다. 단순히 사이클을 확인하는 대신, 방향성을 확인하세요:

  • 유틸리티(utils)가 피처(features)를 임포트하는 것을 방지합니다.
  • 피처(features)가 페이지(pages)를 임포트하는 것을 방지합니다.

이를 통해 사이클을 생성하는 구조적 조건을 차단할 수 있습니다. 버그에 사후 대응하는 대신, 버그를 예방하기 시작하세요.

Source: https://dev.to/wojciech_kot_b82f5d7cbfc6/stop-circular-dependencies-before-they-stop-you-dependency-cruiser-the-stable-dependencies-34ho