AI로 업무 시스템을 만들 때, 사람이 운용·유지보수할 수 있는 상태를 어떻게 지킬까
목차
Claude Code와 Codex를 써서 업무 시스템을 개발한 적이 있다.
이 글에서는 "돌아가긴 하는데 아무도 내용을 설명 못 하는" 상태를 피하고, 사람이 시스템을 이해할 수 있는 상태를 어떻게 지켰는지를 소개하려고 한다.
역할 분담
우선 사람과 AI의 역할을 나눴다.
- 사람: 무엇을 만들지, 어떻게 설계할지, 성과물이 타당한지를 정한다
- AI: 구현, 반복 작업, 테스트 작성을 맡는다
AI는 주어진 태스크를 빨리 끝내는 방향으로 움직여요.
그래서 그때그때 땜질식 구현을 하거나, 의도하지 않은 범위까지 바꾸려 들 때가 있어요.
그래서 AI가 매번 같은 전제로 작업할 수 있도록, 규칙과 절차를 먼저 문서화했어요.
진행 방식: 우선 돌리고 나서, 발판을 갖춘다
처음부터 모든 장치를 마련한 건 아니에요.
우선 최소한의 기능을 만들고, 도중부터 규칙, 스킬, CI, 테스트를 추가했어요.
- 처음에는 기능을 만든다. 테스트와 CI는 아직 마련하지 않는다
- 한 매듭이 지어지면 규칙, 스킬, 품질 체크, CI를 한꺼번에 갖춘다
- 장치의 보호를 받으며 기능을 늘린다
- 종반에는 기능 추가를 억누르고, 수정과 문서 정비에 집중한다
한번 돌아가는 것이 있으면, 위험한 곳과 반복하고 있는 작업이 보이기 시작해요.
그 덕에 정말 필요한 장치만 추가할 수 있었어요.
다만, 규칙과 최소한의 금지 사항은 일찍 넣었어야 했어요.
아무것도 없는 상태로 나아가면, 초기 코드가 금방 어질러져요.
처음에는 이 부근에서 몇 번이고 반복 개선을 하면서 많은 시간을 썼어요.
실행 방안 1: 규칙을 CLAUDE.md에 집약한다
Claude Code는 세션 시작 시 CLAUDE.md를 읽어요.
여기에 AI가 지켜 줬으면 하는 규칙을 적었어요.
- 설계 방침: 어느 층에 업무 로직을 둘지 등
- 금지 사항: 프로덕션을 건드리지 않는다, 비밀 정보를 커밋하지 않는다, 공유 브랜치에 직접 push하지 않는다 등
규칙은 한 장에 몰아넣지 않고, 역할별로 나누고 있어요.
CLAUDE.md … 전체 규칙 (Git·품질·금지 사항)
├─ <영역A>/CLAUDE.md … 영역A의 설계 규약
└─ <영역B>/CLAUDE.md … 영역B의 설계 규약
실제로는 리포지터리 바로 아래의 CLAUDE.md에 Git 운용, 품질 기준, 금지 사항을 두고 있어요. 개별 영역의 설계 규칙은 각 영역에 있는 CLAUDE.md에 두고요.
예를 들어 전체 규칙에는 "공유 브랜치에 직접 push하지 않는다", "비밀 정보의 내용을 표시하지 않는다"라고 적어요. 개별 영역의 규칙에는 "표시 부품에서 데이터 가져오기를 하지 않는다" 같은, 구현 시의 판단 기준을 적고 있어요.
Codex용으로는 AGENTS.md를 마련해 뒀지만, 내용을 복제하지 않고 CLAUDE.md를 정본으로 삼아 참조시키고 있어요.
작업 중인 디렉터리에 있는 CLAUDE.md도 함께 참조돼요.
영역별로 나누면 필요한 규칙만 읽을 수 있어요. 루트 규칙도 짧게 유지할 수 있어서, 결과적으로 잘 지켜지게 됐어요.
실행 방안 2: 설계 자료와 절차를 Markdown으로 남긴다
지시만으로 구현을 맡기면, AI가 데이터 항목이나 연계 사양을 추측해서 존재하지 않는 것을 전제로 한 코드를 쓸 때가 있어요.
그래서 설계 자료를 Markdown으로 정리하고, CLAUDE.md에서 "올바른 정보는 여기를 참조한다"고 안내했어요.
- 데이터 설계, 화면·연계 사양, 도표 등을 Markdown으로 관리하고, 정본을 정한다
- 코드와 자료가 어긋나면, 정본인 자료를 갱신한다
이 프로젝트에서는 설계 자료는 docs/, 셋업과 품질 체크는 CONTRIBUTING.md에 두고 있어요. 각 영역의 CLAUDE.md에서 필요한 자료를 참조하게 하고 있어요.
예를 들어 새 항목을 추가할 때는, 먼저 설계 자료에서 항목명, 타입, 이용 목적을 확인해요. 자료에 없는 항목을 AI가 추측으로 늘리지 않게 하기 위해서예요.
기동, 디버그, 셋업 절차도 Markdown으로 만들었어요.
절차가 텍스트면 사람에게도 AI에게도 그대로 건넬 수 있어요. 새로 합류한 사람이 같은 절차로 돌릴 수 있는 상태를 먼저 만들기 위해서예요.
도표나 PDF에만 기대지 않고, 내용을 텍스트로 남겨 두는 것이 중요했어요.
실행 방안 3: 프로그램을 레이어로 나누고, 역할을 고정한다
규칙이 없으면 입구 처리, 업무 로직, 데이터 갱신, 화면 표시가 파일 하나에 뒤섞이기 쉬워요.
돌아가도, 나중에 따라가기 어려워져요.
그래서 각 층의 역할을 고정했어요.
- 입구 처리는 입력을 받고 결과를 돌려주는 것에만 집중한다
- 업무 로직, 데이터 조작, 인가, 화면 표시를 나눈다
- 표시 부품은 표시에 집중하고, 데이터 가져오기와 복잡한 판단은 다른 층에 둔다
이 규칙은 각 영역의 CLAUDE.md에 있는 "디렉터리 책무"와 "구현 규약"에 적혀 있어요. 구현 위치도 역할별로 고정해서, 놓인 자리만 봐도 책무를 알 수 있게 하고 있어요.
예를 들어 버튼을 눌렀을 때의 표시 전환은 표시 부품에 둬요. 한편 입력값 검증, 권한 확인, 데이터 갱신 순서를 정하는 처리는 업무 로직 쪽에 둬요.
역할이 이름과 놓인 자리로 드러나니까, 수정할 때 따라갈 범위를 좁힐 수 있어요.
AI에게도 "이 층을 고쳐 줘"라고 지시하기 쉬워졌어요.
실행 방안 4: 반복하는 작업은 스킬로 만든다
기능 추가나 데이터 정의 변경처럼 몇 번이고 하는 작업은 스킬(절차서)로 만들었어요.
목적은 시간 단축만이 아니에요. 정해진 구조로 구현되게 하는 것이에요.
- 새 처리는 정한 절차와 구성으로 만든다
- 표시 부품과 로직을 별도 절차로 나눠서, 레이어가 섞이지 않게 한다
- 데이터 정의 변경에서는 관련된 정의, 타입, 상수, 문서를 한꺼번에 갱신한다
절차는 .claude/skills/에 두고 있어요. 처리 추가, 표시 부품 추가, 화면 로직 추가, 데이터 정의 변경 등 작업 종류별로 나누고 있어요.
예를 들어 "항목을 하나 늘리는" 작업이라도, 정의만 바꾸고 끝내지 않아요. 표시명, 입력 체크, 저장하는 값, 설계 자료까지 확인하는 절차로 해 놨어요.
데이터 정의를 변경하는 절차에는, 관련된 정의, 샘플 데이터, 앱 쪽의 타입, 상수, 설계 자료를 동시에 갱신할 것을 명기해 놨어요.
놓는 자리와 만드는 방식이 갖춰지니까, 어디를 봐도 같은 방식으로 읽히는 상태를 지킬 수 있어요.
실행 방안 5: 구현하는 AI와 리뷰하는 AI를 나눈다
구현한 AI에게 그대로 리뷰를 시키면, 놓친 것이 남기 쉬워요.
그래서 리뷰 전용 에이전트를 나눴어요.
- 읽기 전용으로 하고, 편집·commit·push는 못 하게 한다
- 버그, 회귀, 인가, 비밀 정보, 테스트 부족, 유지보수성을 확인한다
- 지적만 돌려주고, 고칠지 말지는 사람이 정한다
리뷰 관점과 읽기 전용 규칙은 리뷰용 에이전트의 정의 파일에 두고 있어요. Codex에서도 같은 방침을 쓸 수 있도록, 설정의 정본은 하나로 했어요.
리뷰에서는 "이 변경으로 기존 조작이 안 되게 되지 않나", "권한이 없는 사람도 조작할 수 있게 되지 않나", "실패했을 때 알 수 있는 테스트가 있나"를 봐요. 겉모습 취향보다, 나중에 곤란해질 변경을 잡는 것을 우선하고 있어요.
리뷰를 불러내는 절차도 전용 스킬로 정리해 놨어요.
구현 직후에 다른 시점을 넣으면, 앞으로의 변경에서 곤란해질 만한 코드를 일찍 찾아낼 수 있어요.
실행 방안 6: 부서지면 멈추는 장치를 단계적으로 둔다
규칙만으로는 실수를 다 막을 수 없어요.
문제가 있으면 앞으로 못 나아가는 장치도 마련했어요.
- 편집 직후: 코드 변경 시 타입 체크를 실행한다
- 실행 전: force push와 공유 브랜치로의 직접 push를 설정으로 금지한다
- 머지 전: PR에서 lint, 타입 체크, 테스트를 실행하고, 실패한 PR은 원칙적으로 머지하지 않는다
편집 직후의 타입 체크는 AI 설정 파일에 있는 편집 후 훅으로 설정하고 있어요. 편집 후에 체크용 스크립트를 실행해서 타입 에러를 일찍 찾아요.
PR 시 체크는 CI의 워크플로 정의로 설정하고 있어요. 포매팅, 정적 분석, 타입 체크, 테스트를 자동 실행해요. 실행할 명령은 각 애플리케이션의 설정 파일로 관리하고 있어요.
참고로 현시점에서는 CI 통과를 기술적인 머지 조건으로 걸지는 않았어요. CI가 실패한 PR을 머지하지 않는 것은 CLAUDE.md의 Git 운용 규칙으로 정해 뒀어요.
사람의 주의력에 기대는 게 아니라, 실패를 이른 단계에서 찾아내게 했어요.
실행 방안 7: 보안과 비밀 정보를 지킨다
프로덕션 환경과 비밀 정보의 취급은 특히 엄격하게 했어요.
.env, 접속 설정, 키 같은 비밀 정보는 커밋도 표시도 못 하게 한다- 프로덕션 데이터를 테스트 환경이나 로컬에 복사하지 않는다
- 인가는 "누가, 어떤 상태에서, 어느 범위를 조작할 수 있는가"로 정하고, 전용 절차로 빠짐없이 추가한다
비밀 정보의 취급과 프로덕션 조작 금지는 루트의 CLAUDE.md에 명기해 놨어요. 인가의 설계 규칙은 영역별 CLAUDE.md, 구현 절차는 전용 스킬에 두고 있어요.
위험한 조작은 AI에게 조심해 달라고 하는 것만으로는 부족해요. 애초에 실행할 수 없는 설정으로 했어요.
Claude Code / Codex에는 실행 가능 여부를 제어하는 설정 파일이 있어요. 위험한 명령은 deny(금지), 사람의 판단이 필요한 조작은 ask(실행 전 확인)로 지정해 놨어요.
설정은 예를 들어 이렇게 쓸 수 있어요.
"permissions": {
"deny": [
"Bash(git push --force:*)",
"Bash(git push origin main:*)"
],
"ask": [
"Bash(<프로덕션_환경을_갱신하는_명령>:*)"
]
}
프로덕션의 갱신·삭제, 권한 변경, 키 관리 등 되돌릴 수 없는 조작을 미리 제한해 놨어요.
처음부터 못 건드리는 상태로 만드는 것이 제일 효과적이었어요.
실행 방안 8: 테스트는 중요한 로직부터 붙인다
AI는 테스트도 쓸 수 있지만, 전부를 망라하려 들면 의미가 옅은 테스트만 늘어나요.
무엇을 테스트할지는 사람이 정했어요.
- 틀리면 업무에 직결되는 로직부터 테스트한다. 예를 들어 권한 판단, 금액·수량 계산, 승인 플로의 상태 전이
- 순수한 로직과 외부 접속을 포함한 처리를 나눈다. 화면 조작은 통합 테스트로 확인한다
- 테스트를 사양의 기록으로도 쓴다
테스트 코드는 대상 영역별 tests/ 디렉터리에 두고 있어요. 실행 절차는 테스트용 스킬로 정리하고, 실행 명령은 각 애플리케이션의 설정 파일로 정의하고 있어요.
예를 들어 권한이 없는 사용자가 갱신할 수 없는 것, 같은 번호가 중복 발행되지 않는 것, 승인 완료된 데이터를 편집할 수 없는 것을 테스트해요. 실패했을 때 업무에 영향을 주는 부분부터 우선해요.
"무엇을 테스트할까"는 사람, "테스트를 쓰는 작업"은 AI, 라는 분담이에요.
AI에게 수정 작업을 맡겨도, 부서졌을 때 알아차릴 수 있어요.
실행 방안 9: 질서를 지키기 위한 운용 규칙
수수하지만, 코드를 어지럽히지 않는 데 효과가 있었어요.
- Git은 프로덕션용과 테스트용 2개 브랜치로 운용하고, 브랜치를 따서 PR 경유로 머지한다
- 커밋 메시지 형식을 맞춰서 이력을 따라가기 쉽게 한다
- 하나의 PR은 하나의 목적으로 좁힌다
- 포매터, 린터, 타입 체크는 변경 부분만이 아니라 전체에 실행한다
- PR 작성까지는 AI에게 맡겨도, 머지 전 최종 판단은 사람이 한다
이 운용은 루트 CLAUDE.md에 있는 "Git 운용 정책"과 "팀 개발 진행 방식"으로 정해 놨어요. PR에 적을 내용은 .github/PULL_REQUEST_TEMPLATE.md, 일상 절차는 CONTRIBUTING.md에 두고 있어요.
예를 들어 PR에는 "무엇을 바꿨나", "어떻게 확인했나", "영향이 있을 법한 범위"를 적어요. 리뷰하는 사람이 diff를 읽기 전에, 판단에 필요한 정보를 갖춰 두기 위해서예요.
Claude Code와 Codex를 병용하는 요령
여러 AI를 쓰면 규칙이 이중 관리가 되어 내용이 어긋날 때가 있어요.
그래서 다음처럼 정리했어요.
- 정본은
CLAUDE.md에 하나만 둔다 - Codex용 파일에는 내용을 복제하지 않고,
CLAUDE.md를 읽으라고 안내한다 - 스킬도 실체는 하나로 하고, 참조만 늘린다
갱신할 곳이 하나라서, 한쪽만 낡은 규칙을 읽는 문제를 피할 수 있어요.
걸려 넘어진 점
- AI는 지시가 없는 범위까지 바꾸려 들 때가 있다. 금지 사항의 명문화는 필요했다
- 리뷰의 최종 책임은 사람에게 남는다. 업무 로직의 옳음은 마지막에 스스로 확인한다
- 처음에 시간을 조금 들여 발판을 만드는 편이 낫다. 곧바로 구현을 진행하면 구조가 무너지기 쉽다
- 스킬은 앞질러서 너무 많이 만들지 않는다. 같은 작업을 몇 번 해 보고 나서 틀로 만드는 정도가 딱 좋았다
정리
AI에게 구현을 맡기는 것과 유지보수 가능한 상태를 지키는 것은, 의식해서 양립시켜야 해요.
아무것도 안 하면, 돌아가긴 하는데 읽을 수 없는 코드가 늘어 가요.
제가 한 것은 규칙과 설계 자료를 문서화하는 것, 프로그램을 층으로 나누는 것, 반복 작업을 스킬로 만드는 것이에요.
거기에 구현과 리뷰를 나누고, 품질 체크와 안전 대책을 마련하고, 중요한 로직부터 테스트하고, 운용 규칙을 정했어요.
이것들을 처음부터 완벽하게 갖출 필요는 없어요. 최소한을 돌리면서 필요한 장치를 조금씩 더해 가면 충분하다.
이 글이 도움이 됐다면 추천해 주세요