pile·
백엔드·channel-talk채널톡·

AI가 규칙을 "알잘딱" 지키는 백엔드 레포 만들기

채널톡 Go 백엔드에서 AI 코딩 도구가 아키텍처 규칙을 지키지 않는 문제를, CLAUDE.md에 규칙을 더 적는 대신 DDD 리팩터링과 커스텀 아키텍처 테스트로 푼 기록이다. "이 모듈은 저 모듈을 import하면 안 된다"고 문서에 적어도 AI는 종종 무시했고, 결국 사람이 리뷰에서 잡아야 하니 AI를 쓰는 의미가 반감됐다. 결론은 CLAUDE.md는 부탁이고 아키텍처 테스트는 강제라는 것이다.

핵심 포인트
  • 컨텍스트 파일을 열심히 써도 성능은 거의 개선되지 않고 비용만 오르며, 의미 있는 개선을 보인 유일한 경우는 문서화가 전혀 없는 레포뿐이라는 연구를 인용한다.
  • 자연어 규칙이 실패하는 이유는 강제성이 모호하고("지양해주세요"가 절대 금지인지 권장인지 판단 불가), 읽는 것과 따르는 것이 다르며, 규칙이 많아지면 서로 모순되기 때문이다.
  • God Object가 모든 것을 import할 수 있는 구조에서 "import하지 마세요"라고 적는 것은 컴파일러가 허용하는 것을 자연어로 금지하겠다는 뜻이다.
  • 리팩터링 자체가 목적이 아니라 아키텍처 테스트를 걸 수 있는 구조를 만드는 것이 목적이었다.
  • 좋은 아키텍처 테스트가 있으면 AI가 스스로 검증할 수 있고, 검증할 수 있는 AI는 사람 없이도 일할 수 있다.
상세 정리
  • 리팩터링 전 상태: 한 패키지가 app, command, widget, exposure, role 등 거의 모든 모듈을 의존하는 전형적인 God Object였고, 200개 이상의 파일이 internal import로 얽혀 하나의 변경이 어디까지 영향을 미칠지 추적이 불가능했다.
  • 이 구조가 AI에 불리한 이유는 영향 범위를 추적할 수 없다는 점이다. 하나를 바꾸면 200개 이상 파일에 영향이 갈 수 있다.
  • 결정론적 제어 넷: Go AST로 프로젝트 고유 규칙을 강제하는 커스텀 아키텍처 테스트, interface와 private impl 패턴으로 잘못된 의존을 컴파일 에러로 전환, 그리고 pre-commit에서 pre-push, CI로 이어지는 가장 빠른 단계 검출이다.
  • 구조 원칙: "하나를 알면 전부를 안다"를 구조로 만드는 것으로, repo·svc·handler·infra·saga가 전부 같은 패턴이라 AI가 하나의 예시만 보면 나머지를 예측할 수 있다.
  • 디렉터리 레이아웃: 도메인마다 core(다른 서브도메인에 의존하지 않는 핵심)와 선택적 서브도메인들이 있고, 외부에서 접근하는 유일한 창구인 Public Service와 유일한 진입점인 alias.go를 둔다.
  • alias.go 패턴: Go의 type alias를 활용해 도메인 외부에서는 여기 정의된 타입만 import할 수 있게 해, 도메인 내부 구현을 완벽히 캡슐화한다. Saga나 다른 도메인이 서브도메인 internal을 직접 import하는 것이 사실상 불가능해진다.
  • 핸들러를 도메인 안에 두면 도메인을 통째로 추출할 때 핸들러도 함께 따라간다.
  • Saga 패턴: 여러 도메인에 걸친 작업을 조율하며, 앱 설치처럼 세 도메인에 걸친 작업이면 각 도메인의 Public Service를 순서대로 호출하고 하나가 실패하면 이전 단계를 롤백한다. Saga는 Public Service만 의존하고 internal에 절대 접근하지 않는다.
  • Package Stutter 금지: 패키지명이 이미 컨텍스트를 주므로 exported 이름에서 반복하지 않는다. stutter가 없으면 인터페이스 이름에 정답이 하나뿐이라 AI의 예측 정확도가 올라간다.
  • 실행 순서: 1차에서 God Object를 해체하고 Saga를 신규 도입하며 Public Service와 alias.go 패턴, domain 구조를 만들었고, 2차에서 규칙을 강제했다.
  • 1차 과정에서 팀 피드백 10건을 받아 서브도메인 간 호출 전략, Saga의 실패 시 롤백 복구, Context timeout 처리를 구체적으로 논의했다.
  • 확장 방식: 하나의 도메인에 v2 컨벤션을 시험 적용해 검증한 뒤, 단순한 도메인부터 서브도메인이 10개인 가장 복잡한 도메인까지 점진적으로 7개 도메인과 9개 Saga 전체로 넓혔다. 핸들러 35개도 의존성을 분석해 재배치했다.
  • 이 리팩터링을 다른 피처 개발과 병행하면서 Claude Code에게 맡길 수 있었던 이유가 바로 아키텍처 테스트다. "파일을 옮겨라"는 간단하지만 "옮긴 후 의존성 방향이 맞는지" 판단하려면 규칙이 코드로 존재해야 한다.
  • 도구 선택: 기존 아키텍처 테스트 도구들을 검토했지만 프로젝트의 세부 규칙을 표현하기 어려웠고, Go AST 패키지로 소스를 직접 파싱해 컨벤션에 100% 맞는 규칙을 구현했다.
  • 규모: 총 약 105K 라인의 커스텀 분석 코드로, 적지 않은 양이지만 자연어로 규칙을 나열하는 것보다 확실한 투자라고 본다.
  • 테스트 카테고리: 가장 중요한 것은 도메인 간과 서브도메인 간 의존성 방향 강제이고, 위반 시 어느 서브도메인이 어느 것을 직접 import했는지 에러 메시지로 즉시 드러난다.
  • 그 외에 모든 계층에 exported interface와 unexported impl, constructor를 강제하는 카테고리, package stutter와 impl 네이밍·파일 네이밍·handler 프로토콜 임베딩 같은 네이밍 규칙 카테고리가 있다.
  • 점진 전환: 처음부터 전체를 ERROR로 두면 기존 코드가 모두 실패하므로 WARNING에서 ERROR로 단계적으로 옮겼고, 지금은 7개 도메인과 9개 Saga가 모두 enforced 상태다.
  • 시나리오 비교 1 새 기능 추가: 이전에는 AI가 어디에 만들지 몰라 결과가 불확실했지만, 이제는 기존 도메인 구조를 보고 동일하게 생성하고 테스트가 패턴 위반을 즉시 감지한다.
  • 시나리오 비교 2: Saga가 도메인 internal을 직접 import하면 이전에는 AI가 무시하고 코드 리뷰에서 발견해 수동 수정했지만, 이제는 테스트가 실패하며 남기는 메시지를 보고 AI가 자동 수정한다.
  • 교훈 셋: DDD의 명확한 경계와 일관된 패턴, 모듈의 자체 완결성은 AI에게도 그대로 적용되며 예측 가능한 구조가 코드 생성 정확도에 직접 영향을 준다. God Object가 있으면 아키텍처 테스트를 걸 수 없어 리팩터링이 먼저다. 한 번에 모든 것을 바꾸려 하면 실패한다.
  • 다음 계획: 도메인 구조가 정리돼 서비스 간 영향도를 자동 파악하는 지식 시스템 구축이 쉬워졌고, 자체 완결적 모듈이 에이전트 단위 작업 위임의 기반이 된다고 밝힌다.
왜 읽나AI가 프로젝트 규칙을 자꾸 어긴다는 문제를 프롬프트로 풀려던 팀에게, 구조를 먼저 정리하고 규칙을 테스트로 강제하는 순서와 그 투자 규모를 실제 수치로 보여준다.
channel-talk
채널톡 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 백엔드·twilio-engTwilio Engineering·

    Programmable Messaging에서 Verify API로 마이그레이션하기

    Twilio의 Programmable Messaging API로 자체 OTP 솔루션을 운영하던 서비스가 Verify API로 전환하는 방법을 코드 예시와 함께 설명한다. Verify는 OTP 전송·검증을 위한 전용 API로, 전화번호 구매, 토큰 생성, DB 저장·만료 관리를 내부에서 처리해 개발자가 직접 구현할 코드를 크게 줄인다.

    요약 이어보기
    #authentication#twilio#sms+2
  2. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 2부

    포스타입 백엔드 엔지니어가 벡터 기반 개인화 추천 시스템을 실제 운영하며 맞닥뜨린 성능 장애와 용량 문제를 해결한 과정을 담은 2부다. 수백만 개의 벡터 KNN 검색이 피크 시간대에 전체 Elasticsearch 검색 성능을 흔드는 문제부터 클러스터 OOM 사태까지, 쿼리 최적화와 인프라 분리 두 가지 경로로 근본 해결에 이른다.

    요약 이어보기
    #elasticsearch#vector-search#recommendation-system+2
  3. 백엔드·포스타입포스타입·

    포스타입이 개인화 추천을 하는 방법 1부

    포스타입이 태그 기반 추천의 한계를 극복하고 벡터 임베딩 기반 개인화 추천 시스템을 구축한 과정을 담은 1부다. 유사한 콘텐츠가 다른 용어를 쓰거나 동일한 태그가 전혀 다른 톤의 콘텐츠를 가리키는 문제를 임베딩 벡터로 해결하고, OpenSearch의 HNSW ANN 검색으로 수백만 벡터를 실시간 검색하는 시스템을 구축해 구매율 15% 향상을 달성했다.

    요약 이어보기
    #opensearch#vector-search#recommendation-system+2