AI

태스크 계약에는 금지가 아니라 값을 쓴다

사람이 낸 결함 다섯이 전부 계약에서 났고, 그 계약을 어느 검문도 보지 않았다

한 줄로

루프가 낸 결함을 거슬러 올라가 보니, 사람이 낸 결함 다섯이 전부 계약에서 났다. 그리고 그 계약을 어느 검문도 보지 않고 있었다. 루프는 계약을 충실히 따랐고, 계약이 비어 있는 곳에서는 스스로 기본값을 골랐다. 교훈은 한 줄이다 — "X 하지 않는다" 가 아니라 "Y = 값" 으로 쓴다.

필수 항목이 비어 있으면 루프가 고른다

계약에 “백엔드 언어”가 없었다. 루프는 다른 언어로 백엔드를 만들었고 6시간 넘게 썼다.

루프 쪽에서는 틀린 것이 없다. 물어볼 사람이 없었을 뿐이다. 1편에서 “품질의 상한은 계약”이라고 쓴 것이 이 뜻이다.

처방은 계약이 반드시 값을 가져야 하는 항목 목록을 두고 기계로 검사하는 것이다. 언어, 빌드 도구, DB, 스키마 변경 방식 같은 것들이다.

목록은 처음부터 완성하지 못한다. 사고가 날 때마다 항목을 더한다.

금지만 적었더니 프레임워크 기본값이 이겼다

계약이 “스키마 자동 생성을 쓰지 않는다”로만 적었다. 의도는 “마이그레이션으로만 바꾸고 앱은 스키마를 검증만 한다(validate)” 였다.

루프는 프레임워크 기본값을 골랐고, 그 값은 “아무것도 안 함(none)” 이었다. 검증이 꺼진 채로 갔다.

앞의 결함들은 아무 값도 없었는데, 이것은 값이 있었는데 계약이 “하지 마라”로만 옮긴 경우다.

“쓰지 않는다”는 금지의 반대편에 값이 여럿 있다. 루프는 그중 하나를 고르는데, 그게 내가 원한 값일 이유가 없다.

값을 제대로 넣고 돌리자, 다섯 태스크가 서로 안 보고 각자 짠 엔티티와 마이그레이션이 실제로 맞는다는 것을 확인할 수 있었다. 검증이 꺼져 있었다면 잴 수 없었던 사실이다.

공유 파일에는 주인이 있어야 한다

lock 파일, 빌드 스크립트, .gitignore 를 어느 태스크도 소유하지 않았다.

  • 의존성을 선언해야 하는 태스크는 그 파일을 고칠 수 없어 막혔다
  • .gitignore 에 빌드 산출물이 빠져 있어 작업 트리는 늘 “미커밋 변경 있음”이었다 → 2편의 게이트 1 이 이걸 거부한다

처방은 둘 중 하나다. 계획 첫머리의 “골격” 태스크가 공유 파일을 소유하거나, 여러 태스크에 명시적으로 공동 소유시킨다.

자유 문장이 YAML 을 깼다

태스크 목록을 틀에 문장을 끼워 만들었는데, 제목 자리에 들어간 범위 문장 안의 : (쌍점 + 공백)가 YAML 을 깼다.

첫 사이클에서 파싱이 실패해 이어 돌던 실행이 통째로 멈췄다.

자유 문장은 블록 스칼라(>-, 여러 줄 문자열 표기) 안에만 두고, 시작 전에 계획 검사를 돌린다.

계약을 쓸 때의 체크리스트

  • 값을 적었는가. 금지만 있는 항목은 없는가
  • 공유 파일에 주인이 있는가
  • 테스트가 처음에 실패하는가. 처음부터 통과하는 테스트는 아무것도 증명하지 못한다
  • 테스트 명령이 실제로 도는가. 명령 오타는 “실패”로 보여서 위 검사를 통과한다
  • 테스트가 옳은 이유로 실패하는가. 기계는 “실패하는가”만 잰다 — 이것은 사람이 한 번 읽는다

red 가 거짓말할 때

“처음에 실패하는가”만 재면 엉뚱한 실패도 통과한다. 세 가지를 겪었다.

  • 테스트 명령에 절대경로를 박았더니, 루프의 작업 트리가 아니라 구현이 없는 다른 브랜치를 테스트했다 → 테스트 명령은 작업 트리 안에서 상대경로로 돈다
  • 필요한 라이브러리가 없는 인터프리터로 돌려 테스트가 import 단계에서 죽었는데, 이것도 “실패하는 테스트”로 읽혔다
  • 테스트 러너가 사용법 오류로 0 이 아닌 코드를 내도 실패로 읽힌다

명령 없음·테스트 0개를 걸러도 이 틈은 남는다. 그래서 첫 red 는 사람이 실패 메시지를 한 번 읽는다.

남는 교훈

루프는 계약에 없는 것을 묻지 않는다. 고른다.

  • “X 하지 않는다”로 적으면 루프가 X 아닌 값 중 하나를 고른다. 그게 내가 원한 값일 이유가 없다. “Y = 값”으로 쓴다
  • 계약 필수 항목 검사는 처음부터 완성할 수 없다. 사고가 날 때마다 항목을 더한다
  • 기계는 “테스트가 실패하는가”만 잰다. “옳은 이유로 실패하는가”는 기계가 판정하지 못한다 — 그래서 첫 red 의 실패 메시지는 사람이 한 번 읽는다

지금은 계약을 쓸 때 금지 문장을 발견하면 그 반대편 값이 무엇인지 적어 넣는 것으로 시작한다.

남겨둔 것 — 필수 항목 목록은 지금도 사고가 날 때마다 늘고 있다. 목록을 완성하는 방법은 모른다. 다음 편은 계약이 맞아도 뚫리는 자리 이야기다 — 무인 루프의 게이트가 못 잡는 것들.