테스트는 공짜가 아니다.
— Anti-patterns — 4 min read
어플리케이션 사이즈가 커질수록 Testable한 아키텍처를 위해 많은 노력이 들어간다.
하지만, 자동화된 테스트 역시 장점만 있는 것은 아니다. 경우에 따라 안티패턴이 팀 전체의 속도를 매우 느리게 만들 수도 있다.
배럴 파일 패턴이라고 불리는 것이 문제가 된다. 링크에서 자세히 설명하지만 간단하게 살펴보자.
// demo/foo.tsexport class Foo {}
// demo/bar.tsexport class Bar {}
// demo/baz.tsexport class Baz {}위처럼 작성된 세 개의 모듈이 존재한다면 각 모듈을 소비하는 모습은 아래처럼 된다.
import { Foo } from '../demo/foo'import { Bar } from '../demo/bar'import { Baz } from '../demo/baz'뭔가 좀 아쉽다. 세 개의 모듈이 개발자가 정의한 demo라는 범주에 포함된다는 걸 좀 더 명시적으로 드러내고 싶다.
그럴 때 배럴 파일 패턴을 활용하게 된다.
export * from './foo' // re-export all of its exportsexport * from './bar' // re-export all of its exportsexport * from './baz' // re-export all of its exports이제 아래처럼 깔끔하게 소비할 수 있다. 모든 게 좋아보인다.
import { Foo, Bar, Baz } from '../demo' // demo/index.ts is implied문제는 이게 특히 CI/CD에서 테스트 완료 시간/테스트 케이스의 기울기를 급격하게 가파르게 만든다는 거다. jest 이슈로도 레이징되었다.
test runner가 프로젝트 번들을 실행하는 게 아니다보니, 테스트를 시작하기 전에 배럴 파일에 포함된 모듈을 모두 불러오려고 한다.
앱의 엔트리포인트처럼 모듈 의존 그래프에서 루트에 가까운 모듈을 import하면, 그 모듈 내에 배럴 파일 참조 import가 존재하는 경우 거기에 포함된 모든 모듈을 불러오고, 거기에 또다른 배럴 파일 참조 import가 있다면...
매 테스트마다 앱의 거의 전체 소스코드를 불러오려고 할 거다. 그리고 이건 파일시스템을 이용하기에 오버헤드가 크다.
위의 jest 이슈에서 보인 @mui/icons-material같은 경우 배럴 파일이 외부 의존성에 존재하고 디렉토 리가 일관성 있게 구조화되어 babel-plugin-direct-import를 통해 해결해볼 수도 있겠지만, 내부 의존성이라면 해결하는 데 상당한 엔지니어링 리소스가 들어갈 수도 있다.
+
배럴 파일 패턴이 순환 참조를 유발하고, 의도치 않은 모듈까지 불러오면서 런타임에서 예상치 못한 사이드 이펙트까지 유발할 수도 있다.
이정도면 그냥 안 쓰는게 맞는듯...