코드베이스의 구조와 결정론적 검증 시스템으로 만드는 AI Native 개발 환경 리팩토링하기
Perry • Software Enginner
안녕하세요, 채널톡 소프트웨어 엔지니어 페리입니다.
채널톡 팀은 Claude Code, Cursor 등 AI 코딩 도구를 적극적으로 활용하고 있습니다. 코드 생성, 리팩토링, 테스트 작성 등 다양한 작업에서 AI의 도움을 받고 있는데요. 그 과정에서 한 가지 뚜렷한 문제를 발견했습니다.
AI가 우리 프로젝트의 아키텍처 규칙을 지키지 않는다는 것입니다. CLAUDE.md에 "이 모듈은 저 모듈을 import하면 안 됩니다"라고 적어도, AI는 종종 무시합니다. 결국 사람이 리뷰에서 잡아야 하는데, 그러면 AI를 쓰는 의미가 반감됩니다.
이 글에서는 채널톡의 Go 백엔드 서비스에서 이 문제를 어떻게 해결했는지를 다룹니다. DDD 기반 리팩토링과 커스텀 아키텍처 테스트 도입을 통해, LLM이 안정적으로 코드를 생성할 수 있는 환경을 만든 과정입니다.
DDD(Domain-Driven Design) 가 익숙하지 않은 분을 위해 간단히 설명하면, 비즈니스 도메인(예: 주문, 결제, 사용자)을 중심으로 코드를 구성하는 설계 방법론입니다. 핵심은 관련된 코드를 하나의 모듈(bounded context)로 묶고, 모듈 간 경계를 명확하게 유지하는 것입니다.
컨텍스트 파일이란? AI 코딩 도구가 프로젝트를 이해할 수 있도록 레포지토리 루트에 두는 설명서입니다.
CLAUDE.md(Claude Code용),.cursorrules(Cursor용) 등이 대표적입니다. 코딩 규칙, 아키텍처 설명, 금지 사항 등을 자연어로 기술합니다.
우리 팀도 처음에는 CLAUDE.md에 기대를 걸었습니다. 의존성 규칙, 네이밍 규칙, 디렉토리 구조 등을 정성껏 적었습니다. 하지만 특히 "하지 마라" 계열의 지침 — 예를 들어 "서브도메인 간 직접 의존은 금지" — 은 무시되는 빈도가 높았습니다.
이건 우리만의 경험이 아니었습니다. 최근 발표된 연구 결과가 이를 뒷받침합니다.
지표 | 결과 |
|---|---|
SWE-bench Lite 성공률 | LLM 생성 컨텍스트 추가 시 0.5% 하락 |
AgentBench 성공률 | 2% 하락 |
추론 비용 | 20~23% 증가 |
정성 들여 직접 작성한 경우 | 최대 4% 향상 |
문서화가 전혀 없는 레포 | 2.7% 긍정 효과 (유일한 양수) |
컨텍스트 파일을 열심히 작성해도 성능은 거의 개선되지 않고, 오히려 비용만 올라갑니다. 의미 있는 개선을 보인 유일한 경우는 문서화가 전혀 없는 레포뿐이었습니다.
직관적으로는 "규칙을 더 많이 알려주면 더 잘 따를 것"이라고 생각합니다. 하지만 실제로는 그렇지 않습니다.
자연어의 모호성: "서브도메인 간 import를 지양해주세요"라는 지침은 "절대 하지 마"인지 "가급적이면"인지 AI가 판단할 수 없습니다
읽었다고 따르지는 않음: AI가 컨텍스트를 "읽었다"는 것과 "따른다"는 것은 전혀 다릅니다. 특히 긴 컨텍스트에서 후반부의 지침은 무시될 확률이 높습니다
규칙 충돌: 규칙이 많아지면 서로 모순되는 경우가 생기고, AI는 어느 쪽을 따를지 임의로 결정합니다
연구의 결론은 명확합니다.
"컨텍스트 파일에 지침을 늘리는 것보다 유닛 테스트와 타입 체크를 강화하는 게 우선이다."
우리 팀에서도 **CLAUDE.md 사용을 최소화하고, 테스트 + 타입 체크 + 린터 + 아키텍처 테스트 같은 결정론적 코드 제어를 강화하는 방향**을 선택했습니다.
AI에게 코딩 규칙을 전달하는 방법은 크게 두 가지입니다.
프롬프트 기반 (CLAUDE.md) | 결정론적 제어 (테스트/린터) | |
|---|---|---|
방식 | "이렇게 짜라" 자연어 지침 | 잘못 짜면 빌드/테스트 실패 |
강제력 | 없음 (무시 가능) | 절대적 (CI에서 차단) |
비용 | 추론 비용 20~23% 증가 | 0 (이미 CI에 포함) |
효과 | -0.5% ~ +4% (연구 수치) | 위반 시 100% 감지 |
유지보수 | 코드 변경 시 문서도 갱신 필요 | 코드 = 규칙 (자동 동기화) |
AI 학습 | 자연어 해석 필요 | 에러 메시지로 즉시 학습 |
우리가 도입한 결정론적 제어는 크게 네 가지입니다. (각각의 상세 내용은 이후 섹션에서 다룹니다.)
커스텀 아키텍처 테스트 — 프로젝트 고유 규칙을 Go AST로 강제 (6장에서 상세 설명)
golangci-lint — Go 표준 규칙을 pre-commit hook에서 즉시 피드백
타입 시스템 활용 — interface + private impl 패턴으로 잘못된 의존을 컴파일 에러로 전환
3단계 enforcement pipeline — pre-commit → pre-push → CI로 가장 빠른 단계에서 잡음
"규칙을 문서로 적지 마라. 코드로 강제하라."
이것이 이 글의 핵심 주장입니다. 이제부터는 이 "강제"를 어떻게 만들었는지를 설명하겠습니다.
결정론적 제어를 도입하려면 먼저 구조가 정리되어야 합니다. 규칙을 정의할 수 없는 구조에서는 규칙을 강제할 수도 없기 때문입니다.
리팩토링 전 우리 서비스의 구조는 다음과 같았습니다.
store/svc에서 모든 모듈로 빨간 화살표가 뻗어나가는 것이 보입니다. hook/svc는 역방향으로 store/svc와 command/svc를 의존하며 순환 의존성 위험까지 안고 있었습니다.
God Object란? 너무 많은 책임을 가진 객체(또는 패키지)를 말합니다. 하나의 패키지가 거의 모든 모듈을 의존하면, 그 패키지를 수정할 때 전체 시스템에 영향이 퍼집니다.
store/svc는 app, command, widget, exposure, role 등 거의 모든 모듈을 의존하는 전형적인 God Object였습니다. 200개 이상의 파일이 internal import를 통해 서로 얽혀 있었고, 하나의 변경이 어디까지 영향을 미칠지 추적이 불가능했습니다.
이 구조가 AI에게 얼마나 불리한지 구체적으로 살펴보면:
"이 파일 어디 있어?" — AI가 핸들러를 찾으려면 api/http/를 뒤지고, 서비스를 찾으려면 internal/을 뒤져야 합니다. 탐색 자체에 토큰을 낭비합니다
"이거 수정해도 돼?" — God Object가 모든 것에 의존하므로, 하나를 바꾸면 200개 이상의 파일에 영향이 갈 수 있습니다. AI가 영향 범위를 추적할 수 없습니다
"어떤 패턴으로 짜야 해?" — 모듈마다 패턴이 달랐습니다. 어떤 곳은 AppQuerySvc, 어떤 곳은 QueryService, 또 어떤 곳은 query. AI가 일관된 코드를 생성하기 어렵습니다
이 상태에서 CLAUDE.md에 규칙을 적어봤자 소용없습니다. God Object가 모든 것을 import할 수 있는 구조에서 "import하지 마세요"라고 적는 건, Go 컴파일러가 허용하는 것을 자연어로 금지하겠다는 뜻입니다.
구조 자체를 바꿔서, 잘못된 의존이 자동으로 감지되게 해야 합니다.
먼저 두 번의 리팩토링을 거쳐 도달한 최종 설계를 보여드리겠습니다. "왜 이렇게 됐는지"(실행 과정)는 5장에서 다룹니다.
우리가 세운 가장 중요한 원칙은 대칭성(symmetry)입니다. "하나를 알면 전부를 안다"를 구조로 만드는 것입니다.
모든 계층이 동일한 패턴을 따릅니다. 예외 없이.
repo, svc, handler, infra, saga — 전부 이 패턴입니다. AI가 하나의 예시만 보면 나머지 모든 코드를 예측할 수 있습니다. CLAUDE.md에 "이 패턴을 따르세요"라고 적을 필요 없이, 코드가 곧 규칙이 됩니다.
internal/domain/{name}/
├── subdomain/ (서브도메인 그룹)
│ ├── core/ {model/, repo/, svc/} ← 핵심 도메인. 다른 서브도메인에 의존하지 않음
│ ├── role/ {model/, repo/, svc/} ← 선택적 서브도메인. core에 의존 가능
│ └── ...
├── svc/ (App Service — 서브도메인 간 조율)
│ └── public.go (Public Service — 외부에서 접근하는 유일한 창구)
├── handler/ (driving adapter — HTTP/gRPC 핸들러)
│ ├── http/
│ └── jsonrpc/
├── infra/ (driven adapter — 외부 서비스 호출)
│ └── {service}/client.go
└── alias.go (외부에서 접근할 수 있는 유일한 진입점)
alias.go란? Go의 type alias를 활용한 패턴입니다. 도메인 외부에서는
alias.go에 정의된 타입만 import할 수 있으므로, 도메인 내부 구현을 완벽하게 캡슐화합니다. 예를 들어type Public = svc.Public으로 정의하면, 외부에서는app.Public만 사용하고app/subdomain/core/svc를 직접 import할 수 없습니다.
이 구조의 핵심은 구조 자체가 규칙을 강제한다는 점입니다.
alias.go를 통해서만 외부 접근이 가능합니다. Saga나 다른 도메인이 서브도메인 internal을 직접 import하는 것은 사실상 불가능합니다
모든 도메인이 동일한 디렉토리 레이아웃을 가집니다. AI가 하나의 도메인 구조를 보면 다른 도메인도 동일한 구조라고 예측할 수 있습니다
핸들러(handler/)가 도메인 안에 위치합니다. 도메인을 통째로 추출하면 핸들러도 함께 따라갑니다
Saga란? 여러 도메인에 걸친 작업을 조율하는 패턴입니다. 예를 들어 "앱 설치"라는 작업이 app, extension, hook 세 도메인에 걸쳐 있다면, Saga가 각 도메인의 Public Service를 순서대로 호출합니다. 하나가 실패하면 이전 단계를 롤백(compensation)합니다.
From ↓ \ To → | Same Sub | Other Sub | App Svc | Public | Other Domain | Saga |
|---|---|---|---|---|---|---|
Subdomain | ||||||
App Service | ||||||
Public Service | (Public만) | |||||
Saga | (Public만) |
이 표의 모든 는 아키텍처 테스트로 강제됩니다. AI가 위반하면 테스트가 실패하고, 에러 메시지로 정확히 어디가 잘못되었는지 알 수 있습니다. (6장에서 상세 설명)
Go 표준 가이드에서 강조하는 원칙 중 하나가 Package Stutter 금지입니다. 패키지명이 이미 컨텍스트를 제공하므로 exported 이름에서 패키지명을 반복하지 않습니다.
이 규칙은 단순한 미학의 문제가 아닙니다. AI가 repo 패키지의 인터페이스 이름을 예측할 때, stutter가 없으면 repo.App이라는 단 하나의 정답이 존재합니다. stutter가 있으면 AppRepo, AppRepository, AppRepoInterface 등 여러 가능성이 생기고, AI의 예측 정확도가 떨어집니다.
여러 도메인에 걸친 작업은 Saga가 담당합니다. Saga는 각 도메인의 Public Service만 의존하며, 서브도메인 internal에는 절대 접근하지 않습니다.
이 설계가 독자적인 것은 아닙니다. handler와 client를 도메인 안으로 가져오는 것은 Go 커뮤니티에서 이미 검증된 패턴입니다(부록 C 참고). 우리는 여기에 Uber FX(Go용 DI 프레임워크)를 활용한 모듈 패턴과 아키텍처 테스트를 결합했습니다.
실행은 두 번의 대규모 리팩토링으로 나뉘었습니다. 1차에서 구조를 잡고, 2차에서 규칙을 강제하는 순서입니다.
1차의 핵심은 Saga 패턴을 처음부터 새로 만드는 것이었습니다. 리팩토링 전에는 Saga가 없었습니다. God Object인 store/svc가 모든 모듈 간 조율을 직접 담당하고 있었습니다.
Before: After:
store/svc (God Object) saga/ (모듈 간 조율 전담)
├── app 의존 ├── lifecycle/ (설치/삭제)
├── command 의존 ├── discovery/ (조회 조합)
├── widget 의존 └── registry/ (등록/해제)
├── exposure 의존
└── role 의존 domain/ (각 모듈 독립)
→ 전부 하나의 패키지에서 조율 ├── app/ {svc/, alias.go}
├── extension/
└── hook/
주요 변경:
변경 | 내용 |
|---|---|
Saga 신규 생성 | Write Saga(트랜잭션 조율)와 Query Saga(조회 조합) 도입 |
Public Service 도입 | 각 도메인의 외부 인터페이스를 |
alias.go 도입 | 도메인 외부에서 접근할 수 있는 유일한 진입점 |
domain/ 구조 | internal/app/ → |
팀에서 10개의 피드백을 받았고, 서브도메인 간 호출 전략, Saga compensation(실패 시 롤백) 복구, Context timeout 처리 등의 구체적인 논의를 거쳤습니다.
1차에서 구조를 잡았다면, 2차의 목적은 그 구조를 코드로 강제할 수 있게 만드는 것이었습니다.
먼저, 하나의 도메인에 v2 컨벤션을 시험 적용했습니다.
Phase | 변경 | 예시 |
|---|---|---|
프로젝트 구조 | lib/ → | Go 표준 레이아웃 적용 |
네이밍 | AppQuerySvc → | Package stutter 제거 |
도메인 구조 | subdomain/ 래퍼 도입, handler/infra를 도메인 안으로 이동 | 자체 완결적 모듈 |
시험 적용으로 검증한 뒤, 7개 도메인과 9개 Saga 전체에 확장했습니다. 단순한 도메인부터 시작해서, 서브도메인이 10개인 가장 복잡한 도메인까지 점진적으로 적용했습니다. 핸들러 35개도 의존성을 분석해서 도메인 또는 saga의 handler/로 재배치했습니다. 최종 상태: 0 errors, 0 warnings.
핵심은 리팩토링 자체가 목적이 아니었다는 것입니다. 아키텍처 테스트를 걸 수 있는 구조를 만드는 것이 진짜 목적이었습니다. 구조가 정리되지 않으면 규칙을 자동화할 수 없기 때문입니다.
흥미로운 점은, 2차 리팩토링의 상당 부분을 Claude Code가 사람의 개입 없이 자율적으로 수행했다는 것입니다. 다른 피처 개발과 병행하면서, 리팩토링 작업은 Claude Code에게 맡길 수 있었습니다.
이것이 가능했던 이유가 바로 아키텍처 테스트입니다.
Claude Code가 파일을 이동하고 import를 수정합니다
go build가 컴파일 에러를 잡고, go test ./test/architecture/...가 구조 위반을 잡습니다
Claude Code가 에러 메시지를 보고 스스로 수정합니다
모든 테스트가 통과할 때까지 이 루프를 반복합니다
아키텍처 테스트가 없었다면 이런 자율 수행은 불가능했을 것입니다. "파일을 옮겨라"는 간단하지만, "옮긴 후 의존성 방향이 맞는지"를 판단하려면 규칙이 코드로 존재해야 합니다. CLAUDE.md에 규칙을 적어두는 것만으로는, AI가 중간에 길을 잃을 수밖에 없습니다.
좋은 아키텍처 테스트가 있으면, AI는 "맞게 했는지"를 스스로 검증할 수 있습니다. 그리고 검증할 수 있는 AI는, 사람 없이도 일할 수 있습니다.
이 섹션이 이 글의 하이라이트입니다. CLAUDE.md 대신 우리가 만든 것을 소개합니다.
go-arch-lint, archunit-go 등 기존 도구를 검토했지만, 우리 프로젝트의 세부 규칙을 표현하기 어려웠습니다. 특히 다음과 같은 규칙들은 기성 도구로 구현이 불가능했습니다.
subdomain/ 래퍼 안의 서브도메인 간 격리
Saga가 alias.go를 통해서만 도메인에 접근하는 규칙
interface + private impl + constructor 3종 세트 강제
파일명과 인터페이스명의 일치 검증
Go의 go/ast 패키지를 사용하면 Go 소스 코드를 직접 파싱할 수 있으므로, 우리 컨벤션에 100% 맞는 규칙을 구현할 수 있었습니다. 무엇보다 별도 도구 설치 없이 go test로 실행되므로 CI에 자연스럽게 통합됩니다.
test/architecture/
├── arch_test.go (4개 테스트 스위트 + 서머리 + 벤치마크)
├── analyzer/
│ ├── parser.go (Go 파일 AST 파싱)
│ └── domain.go (도메인/서브도메인 식별)
├── report/
│ └── violation.go (위반 보고서 생성)
└── ruleset/
├── config.go (severity 설정 — 모든 도메인 ERROR)
├── dependency.go (의존성 규칙 — ~31K lines)
├── naming.go (네이밍 규칙 — ~34K lines)
├── interface.go (인터페이스 패턴 — ~12K lines)
└── structure.go (구조 규칙 — ~28K lines)
총 ~105K lines의 커스텀 분석 코드입니다. 적지 않은 양이지만, CLAUDE.md에 자연어로 규칙을 나열하는 것보다 훨씬 확실한 투자입니다.
가장 중요한 카테고리입니다. 도메인 간, 서브도메인 간 의존성 방향을 강제합니다.
서브도메인에서 다른 서브도메인 직접 import
Saga에서 서브도메인/App Service import (Public만)
핸들러에서 다른 도메인의 서브도메인 직접 import (alias.go 경유)
계층 역방향 의존 (model ← repo ← svc 방향만 허용)
AI가 이 규칙을 위반하면 어떤 일이 일어날까요?
=== FAIL: TestDependencyRules
violation: subdomain "role" imports subdomain "httpfn" directly
file: internal/domain/app/subdomain/role/svc/token.go:15
rule: subdomains must not import other subdomains
fix: use Public Service or move logic to core/
AI가 이 에러 메시지를 보면 어디서 무엇이 잘못되었고, 어떻게 고쳐야 하는지 즉시 알 수 있습니다. CLAUDE.md에 같은 규칙을 자연어로 적으면 AI가 무시할 수 있지만, 테스트 실패는 무시할 수 없습니다.
Package stutter 검출: repo.AppRepo → repo.App
Impl 접미사 금지: appRepoImpl → app (unexported)
파일명-인터페이스 일치: install.go → Install interface
파일명 레이어 접미사 금지: install_svc.go → install.go
모든 계층에 exported interface + unexported impl + constructor 강제
constructor는 interface를 반환해야 함
impl struct는 interface와 같은 파일에 위치해야 함
금지 패키지명: util, common, misc, helper, shared, lib
Import alias 규칙 강제
처음부터 전체를 ERROR로 설정하면 기존 코드가 모두 실패합니다. 그래서 점진적으로 전환했습니다.
모든 도메인/saga를 WARNING으로 시작
도메인별로 위반 사항 수정
수정 완료된 도메인은 ERROR로 전환
최종 상태: 모든 도메인/saga가 ERROR
7개 도메인 + 9개 saga가 모두 enforced 상태. 아키텍처 위반 시 테스트가 실패합니다.
규칙 | CLAUDE.md | 아키텍처 테스트 |
|---|---|---|
"서브도메인 간 import 금지" | AI가 무시할 수 있음 | CheckSubdomainIsolation() — 100% 감지 |
"Saga는 Public만 사용" | 복잡한 설명 필요 | CheckSagaDependency() — 컴파일 수준 강제 |
"interface + impl 패턴" | 예시를 적어도 변형 생성 | CheckInterfacePattern() — 정확한 패턴 매칭 |
"Package stutter 금지" | "repo.AppRepo 대신 repo.App" | CheckPackageStutter() — 자동 검출 |
"금지 패키지명" | 리스트를 적어도 새 이름 만듬 | CheckForbiddenPackageNames() — 즉시 차단 |
CLAUDE.md는 부탁입니다. 아키텍처 테스트는 강제입니다.
항목 | Before | After |
|---|---|---|
모듈 결합도 | 높음 (200+ 파일 cross-import) | 90% 감소 (Public만 의존) |
변경 영향 범위 | 7개 패키지 | 1개 모듈 |
테스트 mock 수 | 과도함 | 70% 감소 (Public만 mock) |
아키텍처 위반 감지 | 불가능 | 100% 자동 감지 |
Enforced 도메인 | 0 | 7/7 domain + 9/9 saga |
구체적인 시나리오로 Before/After를 비교해보겠습니다.
시나리오 1: "새 서브도메인 추가"
Before: AI가 어디에 만들지 모릅니다. CLAUDE.md를 읽어도 기존 코드와 패턴이 달라서 혼란. 결과 불확실.
After: AI가 기존 서브도메인(예: role/)의 구조를 보고 동일하게 생성. 아키텍처 테스트가 패턴 위반을 즉시 감지. 결과 확실.
시나리오 2: "Saga에서 도메인 internal 직접 import"
Before: CLAUDE.md에 "하지 마세요" → AI가 무시 → 코드 리뷰에서 발견 → 수동 수정
After: AI가 import → go test 실패 → 에러 메시지 "Saga must use Public Service via alias.go" → AI가 자동 수정
시나리오 3: "핸들러에서 다른 도메인 서브도메인 직접 import"
Before: 감지 불가. 프로덕션까지 갈 수 있음.
After: pre-push hook에서 차단. push 자체가 안 됨.
"규칙을 문서로 적지 마라. 코드로 강제하라."
우선순위 | 수단 | 효과 |
|---|---|---|
1 | 아키텍처 테스트 + 타입 체크 + 린터 | 위반 시 100% 감지, 추가 비용 0 |
2 | 예측 가능한 코드 구조 (DDD) | AI가 패턴을 보고 학습, 문서 불필요 |
3 (최후수단) | CLAUDE.md / 컨텍스트 파일 | 효과 미미 (-0.5%~+4%), 비용 20~23% 증가 |
DDD는 사람만을 위한 것이 아닙니다. DDD의 이점 — 명확한 경계, 일관된 패턴, 모듈의 자체 완결성 — 은 AI에게도 그대로 적용됩니다. 특히 "예측 가능한 구조"는 AI의 코드 생성 정확도에 직접적인 영향을 줍니다.
구조가 정리되어야 규칙을 자동화할 수 있습니다. God Object가 있는 상태에서는 아키텍처 테스트를 걸 수 없습니다. 먼저 리팩토링 → 그 다음 테스트로 강제 → 이후 AI가 안전하게 코드를 생성하는 순서가 중요합니다.
점진적 적용이 핵심입니다. 하나의 도메인에 시험 적용 → 팀 피드백 → 전체 확장. WARNING → ERROR 점진적 전환. 한 번에 모든 것을 바꾸려 하면 실패합니다.
좋은 테스트가 있으면, AI는 사람 없이도 일할 수 있습니다. 5.3에서 다뤘듯이, 아키텍처 테스트가 검증을 대신해주면 AI의 자율 작업이 가능해집니다.
이번 작업으로 "AI가 안정적으로 코드를 짤 수 있는 환경"의 기반을 만들었습니다. 다음으로는 아래의 태스크를 추가로 진행중에 있습니다.
다른 서비스로 확장: 검증된 패턴을 팀 내 다른 Go 서비스에 적용
지식 그래프 통합: 도메인 구조가 잘 정리되어 있으면 서비스 간 영향도를 자동으로 파악하는 지식 시스템 구축이 쉬워짐
멀티 에이전트 시스템 연동: 도메인 단위 자체 완결적 모듈 → 에이전트 단위 작업 위임의 기반
AI 코딩 도구의 성능은 빠르게 올라가고 있지만, 그 성능을 안정적으로 발휘하게 만드는 건 결국 코드베이스의 구조와 결정론적 검증 시스템입니다. CLAUDE.md에 규칙을 적는 것보다, 잘못된 코드가 애초에 통과하지 못하는 환경을 만드는 것이 더 확실합니다.
여러분의 프로젝트에서도 "AI가 자꾸 규칙을 어긴다"는 문제를 겪고 있다면, 프롬프트를 고치기 전에 구조와 시스템을 먼저 점검해보는 것은 어떨까요?
채널톡에서는 AI가 안정적으로 코드를 생성할 수 있는 환경 구축, 대규모 Go 백엔드 리팩토링, 커스텀 정적 분석 도구 개발 같은 도전적인 문제를 함께 풀어갈 엔지니어를 찾고 있습니다. 이러한 문제 해결 과정에 함께하며 성장하고 싶으신 분들은 언제든지 채널톡의 문을 두드려 주세요!
단계 | 내용 |
|---|---|
1차: 구조 수립 | God Object 해체, Saga 패턴 신규 도입, Public Service + alias.go 패턴, domain/ 구조 생성, 네이밍 v1 |
아키텍처 테스트 도입 | 커스텀 Go AST 기반 분석기 개발 (~105K lines) |
2차: 규칙 강제 | lib/→pkg/, subdomain/ 래퍼, 핸들러 도메인 내 이동, 네이밍 v2, 7개 도메인 + 9개 saga 전체 enforcement, pre-push hook |
카테고리 | 코드량 | 주요 검증 항목 |
|---|---|---|
Dependency | ~31K lines | 서브도메인 격리, 계층 방향, saga import, handler import |
Naming | ~34K lines | Package stutter, impl 네이밍, 파일 네이밍, handler 프로토콜 embedding |
Interface Pattern | ~12K lines | interface + private impl 패턴, constructor 반환 타입, impl 같은 파일 위치 |
Structure | ~28K lines | Import alias 네이밍, 금지 패키지명 (util, common, misc 등) |
Go go/ast 기반 커스텀 분석기 (~105K lines)\
위반 시 CI 실패
레퍼런스 | Stars | 핵심 패턴 |
|---|---|---|
ThreeDotsLabs/wild-workouts | 5.3k | Hexagonal — handler( |
go-kit/kit | 26k | transport/ 서브패키지가 도메인 안에 위치, endpoint 패턴 |
benbjohnson/wtf | 3k | root 패키지에 도메인 타입, |
mehdihadeli/go-food-delivery | 800 | Vertical Slice + FX — 기능별 handler+command+event 한 폴더 |
We Make a Future Classic Product