붕괴 메커니즘

붕괴 메커니즘

시스템은 한 번의 오류로 무너지지 않는다. 작은 우회가 쌓이면서, 이미 되돌릴 수 없는 상태가 된다.


이 문서는 구조적 어긋남을 다룬다. 같은 목적지로 가는 경로가 늘어나고, 중복과 예외가 누적될 때 시스템이 어떻게 무너지는지 본다.


처음에는 괜찮다

초기에는 문제가 없다.

기능이 단순하다. 상태가 흐르는 경로도 많지 않다. 무언가를 바꾸면 결과가 바뀐다. 예측 가능하다.

이 단계에서는 어긋남이 드러나지 않는다. 그래서 구조가 탄탄하다고 느껴진다.


복잡해지기 시작하면

기능이 늘어난다.

새로운 요구사항이 붙고, 기존 코드 위에 새로운 코드가 얹히고, 상태를 읽고 쓰는 위치가 점점 많아진다.

여기서부터 달라진다. 아주 조금씩.

어떤 기능은 service를 거친다. 어떤 기능은 컴포넌트에서 직접 상태를 바꾼다. 어떤 경로는 검증을 통과하고, 어떤 경로는 슬쩍 우회한다.

각각 따로 보면 문제없어 보인다. 모두 동작하니까.


아주 흔한 한 가지 붕괴 장면

예를 들어 문서 편집 화면이 있다고 하자. 처음에는 모든 저장이 DocumentStore -> Action -> Validator 경로를 통과한다. 그래서 autosave, publish, undo가 같은 상태 의미를 공유한다.

그런데 어느 날 빠른 수정 하나를 위해 컴포넌트 안에 local state가 붙는다. 화면은 즉시 반응하고, 임시 저장도 되는 것처럼 보인다. 하지만 이 순간부터 같은 title 값이 두 경로로 갈라진다.

  • 한 경로는 Store를 거치며 검증, 이벤트, undo stack을 남긴다
  • 다른 경로는 local state에서 바로 값을 바꾸고 UI만 갱신한다

처음에는 아무 일도 없어 보인다. 하지만 publish는 Store 값을 보고, UI는 local state를 보고, 테스트는 Store 경로만 가정한 채 통과한다. 그 시점부터 시스템은 같은 값을 서로 다른 의미로 다루기 시작한다.


보이지 않는 어긋남

실행은 정상이다. 기능도 동작한다.

하지만 내부에서는 이미 다른 일이 일어나고 있다.

같은 상태가 경로에 따라 다르게 처리된다. 어떤 수정은 검증을 거치고, 어떤 수정은 거치지 않는다. 어떤 흐름에서는 특정 조건이 적용되고, 어떤 흐름에서는 그냥 통과된다.

이게 테스트에서도 드러나지 않는다. 테스트는 경로를 가정하고 작성되기 때문이다. 가정한 경로가 틀리지 않았다면, 테스트는 통과된다.

그래서 더 늦게 발견된다. 그리고 발견됐을 때는 이미 여러 겹이 쌓여 있다.


반복

한 번 수정한다.

그 지점은 잠깐 안정된다.

그리고 다른 곳에서 같은 현상이 나타난다.

다시 고친다. 또 다른 곳에서 나타난다.

이 패턴은 끝나지 않는다.

수정 → 안정 → 재발 → 수정 → 안정 → 재발.

어느 순간부터는 고칠수록 코드베이스가 더 복잡해지는 것처럼 느껴진다. 그게 맞다. 실제로 그렇게 되고 있다.


문제는 어디에 있는가

보통은 이렇게 본다. 코드가 잘못되었다고.

그래서 다시 고친다. 더 나은 구현으로, 더 명확한 로직으로.

하지만 이건 증상을 다루는 것이다.

문제는 여기 있다.

시스템이 여러 경로를 동시에 허용하고 있다.

같은 상태를 바꾸는 경로가 여러 개 존재하면, 그 경로들은 반드시 제각각으로 사용된다. 일관되게 쓰려는 의도가 있어도, 작업이 이어지고 사람이 바뀌고 컨텍스트가 달라지면서 결국 다른 경로로 흘러가게 된다.


왜 막을 수 없는가

경로가 열려 있는 한, 우회는 필연이다.

나쁜 의도 때문이 아니다. 더 빠른 방법이 눈에 띄기 때문이다. 지금 당장 작동하는 방법이 있기 때문이다. 이전 코드의 패턴을 그냥 따라가기 때문이다.

이건 사람의 집중력 문제가 아니다. 시스템이 허용하고 있기 때문에 일어나는 일이다.

그래서 사람을 더 조심하게 만들거나, 규칙을 더 촘촘하게 만드는 방식으로는 이 문제를 막을 수 없다.

경로 자체를 닫아야 한다.


여기서 방향이 바뀐다

개별 오류를 줄이는 방식으로는 반복을 멈출 수 없다.

고치는 것 자체는 계속 해야 한다. 하지만 고치는 것만으로는 같은 문제가 다시 나타나는 것을 막지 못한다.

그래서 질문을 바꾼다.

어디가 틀렸는가가 아니라,

왜 이 경로가 아직도 열려 있는가.