적용 전략

적용 전략

무엇을 강제할지만큼 중요한 것은, 어디서부터 시작하느냐다. 잘못된 순서로 적용하면 강제가 개발을 막는 장벽이 된다.


왜 순서가 중요한가

강제를 한 번에 다 적용하려 하면 실패한다. lint, 런타임 가드, 구조 변경, 테스트 수정을 동시에 진행하면 충돌이 생기고, 개발이 멈추고, 규칙을 비활성화하기 시작한다.

반대로 너무 조심스럽게 접근하면 강제가 영구히 미뤄진다.

경험상 효과적인 순서는 하나였다. 가장 영향이 크고 비용이 낮은 것부터, 점진적으로 강도를 높인다.


5단계 적용 순서

1단계 — 열린 경로를 먼저 닫는다

가장 먼저 할 일은 가장 자주 사용되는 우회 경로를 제거하는 것이다.

  • global singleton 제거
  • direct import 차단
  • raw context 접근 차단
  • executor 직접 호출 제거

이 경로들이 열려 있는 한 다음 강제는 의미 없다. AI도, 사람도 이 경로를 계속 사용하기 때문이다.

막기 전에 합법 경로를 먼저 만든다. renderWithAppProviders, dispatch, useTypedHook 같은 대안이 없으면 강제만 있고 경로가 없는 상황이 된다.

2단계 — 흐름을 고정한다

경로를 닫은 뒤에는 실행 순서와 상태 전이를 고정한다.

  • 전이 통제: 허용된 상태 전이만 가능하게
  • Planner 통제: AI 실행이 planner를 통해서만 시작되게

이 단계는 “무엇을 막는가"보다 “어떤 순서로만 가능한가"를 정의한다.

3단계 — 빌드 타임에서 자동화한다

흐름이 고정된 뒤에는 빌드 타임 강제를 적용한다.

  • Atlas: Roslyn Analyzer 규칙 설정, severity를 error로
  • Glif: ESLint 규칙 활성화, CI에서 lint 실패 시 빌드 중단

이 단계부터 사람이 개입 없이 위반이 자동으로 차단된다.

중요: 규칙을 warning이 아니라 error로 설정한다. warning은 무시된다.

4단계 — 런타임 방어선을 추가한다

빌드 타임에서 잡지 못한 동적 우회를 런타임에서 차단한다.

  • Guard를 진입점에 배치
  • assertion으로 전제 조건 강제
  • silent fallback 금지

런타임 강제는 빌드 타임의 보완이다. 빌드 타임에서 최대한 줄이고, 런타임은 나머지를 막는다.

5단계 — 테스트를 정렬한다

마지막으로 테스트 환경이 실제 구조와 같은 경계를 갖게 만든다.

  • renderWithAppProviders 강제
  • 테스트에서도 direct state mutation 금지
  • planner 통과 없는 실행 금지

테스트가 마지막인 이유는 코드 수정 범위가 가장 넓고, 저항이 가장 크기 때문이다. 하지만 테스트를 정렬하지 않으면 테스트 코드가 우회 패턴의 정본이 된다.


순서를 바꾸면 일어나는 일

runtime guard를 먼저 추가하면: 빌드 타임 차단 없이 런타임 실패만 있으면 AI가 실패를 돌아가는 경로를 만든다.

테스트를 먼저 수정하면: 테스트가 깨지고 개발이 멈춘다.

한 레이어만 강화하면: 다른 레이어로 우회가 이동한다.


점진적 강화

처음부터 완벽하게 할 필요 없다. 핵심 경로부터 시작해서 점진적으로 커버리지를 넓힌다.

첫 번째 목표는 “가장 자주 발생하는 우회 3개를 막는 것"이다.


실무 체크리스트

강제가 제대로 작동하는지 확인한다.

  • 합법 경로가 우회보다 짧고 쉬운가?
  • 가장 자주 발생하는 우회 경로가 차단됐는가?
  • 빌드 타임 규칙이 warning이 아닌 error인가?
  • CI에서 빌드 실패가 merge를 막는가?
  • 런타임 guard가 진입점 앞에 위치하는가?
  • 테스트가 동일한 경계를 갖는가?
  • disable 주석이 허용되지 않는가?