docs: 연구 방향(CLAUDE.md)과 구현 가이드(IMPLEMENTATION.md) 분리

연구 방향·정책과 구현 세부사항을 두 문서로 명확히 분리한다.

CLAUDE.md (연구 방향·정책 전용):
- 연구 배경 요약 (BACKGROUND.md 참조)
- 제안 기법 ① gRPC over QUIC 통신 모듈 (AIoT 도메인 실증)
- 제안 기법 ② AI Agent + IoT 통합 엣지 게이트웨이
- 우선순위별 목표(P0/P1/P2)와 의존성·리스크
- 위험 관리(Risk Register) — quic-go 호환성, tc 작동, 어댑터 범위 등
- 평가 시나리오·KPI·네트워크 조건·통계적 유의성 확보 계획
- 코드 작성 정책(계층 분리, 컨텍스트 전파, 에러 처리, 측정 가능성)

IMPLEMENTATION.md (구현 세부사항 전용):
- 프로젝트 디렉터리 구조 (proto/, gen/, internal/, cmd/, benchmarks/)
- 네이밍 규칙 (Proto·Go)
- 개발 워크플로우 (proto 컴파일, 서버 실행, tc 시뮬레이션, 테스트)
- 코드 패턴 (Transport 인터페이스, 컨텍스트, gRPC 에러, 인터셉터)
- Makefile 타겟 목록
- 멀티 에이전트 작업 분담 가이드
- 자주 수행하는 작업 시나리오

원칙: 디렉터리 경로·명령어·코드 샘플 등 구현 세부사항은 모두
IMPLEMENTATION.md에 두고, CLAUDE.md는 연구 방향과 정책에만 집중한다.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-07 01:31:31 +00:00
parent 5f35254d03
commit d2c63e7c19
2 changed files with 719 additions and 0 deletions
+345
View File
@@ -0,0 +1,345 @@
# IMPLEMENTATION.md — 구현 가이드
> 본 문서는 `CLAUDE.md`(연구 방향·정책)에서 분리된 **구현 세부 사항**을 다룬다.
> 디렉터리 구조, 네이밍 규칙, 개발 워크플로우, 코드 패턴, 멀티 에이전트 작업 분담 등이 포함된다.
>
> 연구 동기·목표·평가 지표는 `CLAUDE.md`를 참조한다.
---
## 1. 프로젝트 구조
```
.
├── proto/ # IDL 정의
│ └── aiot/
│ ├── inference/inference.proto # AI 추론 요청/응답
│ ├── device/device.proto # 디바이스 등록·상태 보고
│ └── gateway/gateway.proto # 게이트웨이 데이터 전달 서비스
├── gen/ # protoc 자동 생성 파일 (수동 수정 금지)
│ └── aiot/{inference,device,gateway}/
├── internal/ # 프로젝트 내부 패키지 (외부 import 불가)
│ ├── transport/
│ │ ├── transport.go # Listener/Dialer 인터페이스 정의
│ │ ├── quic_listener.go # QUIC 리스너 (quic-go 래핑)
│ │ ├── quic_dialer.go # QUIC 다이얼러 (클라이언트 연결)
│ │ └── h2_listener.go # HTTP/2 리스너 (비교군)
│ ├── gateway/
│ │ ├── gateway.go # 게이트웨이 코어 (라우팅·변환 엔진)
│ │ ├── protocol_adapter.go # IoT 프로토콜 어댑터 인터페이스
│ │ ├── mqtt_adapter.go # MQTT → Protobuf
│ │ ├── coap_adapter.go # CoAP → Protobuf
│ │ └── route_table.go # 서비스 디스커버리·라우팅 테이블
│ ├── server/
│ │ ├── inference_server.go # InferenceService 구현
│ │ ├── device_server.go # DeviceRegistry 구현
│ │ └── gateway_server.go # GatewayService 구현
│ ├── client/
│ │ ├── inference_client.go # gRPC 클라이언트 (재시도·타임아웃 포함)
│ │ └── rest_client.go # REST 비교군 클라이언트
│ ├── middleware/
│ │ ├── logging.go # 요청/응답 로깅 인터셉터
│ │ └── metrics.go # latency 측정 인터셉터
│ └── router/
│ └── task_router.go # 엣지 라우팅 로직 (ROI 결과 기반)
├── cmd/
│ ├── server/main.go # gRPC 서버 진입점 (--transport=quic|h2 플래그)
│ ├── gateway/main.go # gRPC 게이트웨이 진입점
│ ├── rest-server/main.go # REST 비교군 서버 진입점
│ └── benchmark-runner/main.go # 벤치마크 실행 CLI
├── benchmarks/
│ ├── scenarios/
│ │ ├── unary_test.go # Unary RPC 벤치마크
│ │ ├── streaming_test.go # Streaming RPC 벤치마크
│ │ └── rest_compare_test.go # REST vs gRPC 비교 벤치마크
│ └── results/ # 날짜별 결과 (YYYY-MM-DD/)
│ └── .gitkeep
├── docs/
│ ├── decisions/ # ADR (Architecture Decision Records)
│ │ └── 001-go-grpc-baseline.md
│ └── open-questions.md # 미해결 질문 및 탐색 주제
├── tests/
│ ├── unit/ # 단위 테스트
│ └── integration/ # 통합 테스트 (실제 서버 기동)
├── scripts/
│ ├── proto-gen.sh # protoc 컴파일 스크립트
│ ├── tc-setup.sh # tc 네트워크 지연 설정
│ └── tc-reset.sh # tc 설정 초기화
├── docker/
│ ├── Dockerfile.server
│ ├── Dockerfile.rest-server
│ └── docker-compose.yml # 전체 실험 환경 구성
├── CLAUDE.md # 연구 방향·정책
├── IMPLEMENTATION.md # (본 파일) 구현 세부 사항
├── BACKGROUND.md # 연구 수행 배경
├── go.mod
├── go.sum
└── Makefile
```
---
## 2. 네이밍 규칙
### 2.1. Proto 정의
| 대상 | 규칙 | 예시 |
|------|------|------|
| 패키지 | `aiot.{module}` | `aiot.inference` |
| 서비스 | `{명사}{역할}Service` | `InferenceService`, `DeviceRegistry` |
| RPC 메서드 | `{동사}{명사}` | `PredictFrame`, `RegisterDevice`, `StreamSensorData` |
| 메시지 | `{명사}{동사}Request/Response` | `FramePredictRequest`, `DeviceRegisterResponse` |
| 열거형 | `UPPER_SNAKE_CASE` | `PROCESSING_STATUS_PENDING` |
### 2.2. Go 코드
| 대상 | 규칙 |
|------|------|
| 파일 | `snake_case.go` |
| 패키지 | 단수 소문자 (`server`, `client`, `router`) |
| 인터페이스 | `{명사}` 또는 `{명사}er` (`InferenceService`, `Router`) |
| 구조체 | `PascalCase` |
| 함수/메서드 | `camelCase` (내부), `PascalCase` (공개) |
| 에러 변수 | `Err{명사}` (`ErrConnectionTimeout`) |
| 컨텍스트 | 첫 번째 인수, 변수명 `ctx` |
---
## 3. 개발 워크플로우
### 3.1. 초기 셋업
```bash
# Go 버전 확인 (1.22 이상 권장)
go version
# protoc 및 플러그인 설치 (최초 1회)
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
# 의존성 설치
go mod tidy
```
### 3.2. Proto 컴파일
```bash
make proto
# 또는 직접 실행:
# scripts/proto-gen.sh
```
**`gen/` 디렉터리 파일은 절대 직접 수정하지 않는다.** `.proto` 파일을 수정 후 재생성한다.
### 3.3. 서버/클라이언트 실행
```bash
# gRPC 서버 (전송 계층 선택)
make run-server # 기본
go run ./cmd/server --transport=quic --port=50051
go run ./cmd/server --transport=h2 --port=50052
# REST 비교군 서버
make run-rest-server
# 벤치마크
make benchmark
go run ./cmd/benchmark-runner --scenario unary --requests 10000 --concurrency 10
```
### 3.4. 네트워크 조건 시뮬레이션
```bash
# 지연 50ms
sudo ./scripts/tc-setup.sh --delay 50ms --interface eth0
# 지연 200ms + 패킷 손실 1%
sudo ./scripts/tc-setup.sh --delay 200ms --loss 1% --interface eth0
# 초기화
sudo ./scripts/tc-reset.sh --interface eth0
```
### 3.5. 테스트
```bash
# 단위 테스트
go test ./tests/unit/... -v
# 통합 테스트 (서버 자동 기동)
go test ./tests/integration/... -v -timeout 60s
# 벤치마크 (Go 표준)
go test ./benchmarks/... -bench=. -benchmem -count=5
```
---
## 4. 코드 패턴
### 4.1. Transport 인터페이스 설계
QUIC↔TCP를 동일한 코드 경로에서 교체할 수 있도록, 전송 계층은 인터페이스로 추상화한다.
```go
// internal/transport/transport.go
type Listener interface {
Accept(ctx context.Context) (net.Conn, error)
Addr() net.Addr
Close() error
}
type Dialer interface {
Dial(ctx context.Context, addr string) (net.Conn, error)
Close() error
}
```
- gRPC 서버/클라이언트 생성 시 `Listener`/`Dialer`를 주입받음
- 벤치마크는 동일 코드 경로로 전송 계층만 변경하여 공정 비교
### 4.2. 컨텍스트와 타임아웃
타임아웃은 **클라이언트에서 설정**한다. 서버는 컨텍스트 취소를 존중한다.
```go
func (c *InferenceClient) PredictFrame(ctx context.Context, req *pb.FramePredictRequest) (*pb.FramePredictResponse, error) {
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
return c.stub.PredictFrame(ctx, req)
}
```
### 4.3. gRPC 에러 처리
```go
import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// 서버 측
return nil, status.Errorf(codes.InvalidArgument, "frame data is empty")
// 클라이언트 측
if st, ok := status.FromError(err); ok {
switch st.Code() {
case codes.DeadlineExceeded:
// 타임아웃 처리
case codes.Unavailable:
// 재연결 처리
}
}
```
### 4.4. Latency 측정 인터셉터
`internal/middleware/metrics.go`의 인터셉터를 RPC 등록 시 함께 등록한다. 직접 측정이 필요한 경우 구간을 명시적으로 기록한다.
```go
// 등록 예시
grpc.NewServer(
grpc.UnaryInterceptor(middleware.MetricsUnaryInterceptor),
grpc.StreamInterceptor(middleware.MetricsStreamInterceptor),
)
```
---
## 5. Makefile 타겟
```makefile
make proto # .proto → gen/ Go 코드 생성
make build # 모든 cmd/ 바이너리 빌드
make run-server # gRPC 서버 실행 (기본 포트 :50051)
make run-rest # REST 서버 실행 (기본 포트 :8080)
make test # 단위 + 통합 테스트
make benchmark # 전체 벤치마크 시나리오 실행
make lint # golangci-lint 실행
make docker-up # docker-compose로 전체 환경 기동
make docker-down # 환경 종료
make clean # 빌드 아티팩트 및 gen/ 삭제
```
---
## 6. 멀티 에이전트 작업 분담 가이드
여러 에이전트가 동시에 작업할 경우 아래 경계를 지킨다.
### 6.1. 독립 작업 도메인
| 도메인 | 담당 파일/디렉터리 | 주의사항 |
|--------|------------------|----------|
| **Proto 설계** | `proto/` | 필드 번호 변경은 전체 팀에 공지 후 진행 |
| **QUIC 전송 계층** | `internal/transport/` | 인터페이스(`Listener`/`Dialer`) 확정 후 구현, quic-go 의존 |
| **gRPC 게이트웨이** | `internal/gateway/`, `cmd/gateway/` | transport 인터페이스 의존, 프로토콜 어댑터는 독립 개발 가능 |
| **gRPC 서버 구현** | `internal/server/`, `cmd/server/` | `gen/` + transport 인터페이스 의존 |
| **REST 비교군** | `internal/client/rest_client.go`, `cmd/rest-server/` | gRPC 서버와 동일한 시나리오 구현 필수 |
| **벤치마크 스크립트** | `benchmarks/`, `cmd/benchmark-runner/` | 서버/클라이언트 인터페이스 확정 후 구현 |
| **라우터 로직** | `internal/router/` | 인터페이스만 맞추면 독립 개발 가능 |
| **문서/분석** | `docs/`, `benchmarks/results/` | 코드 변경 없이 병행 가능 |
### 6.2. 의존 순서
```
Proto 정의 완료
└─→ gen/ 코드 생성
Transport 인터페이스 확정 (internal/transport/transport.go)
├─→ QUIC Listener/Dialer 구현 (internal/transport/quic_*.go)
├─→ H2 Listener/Dialer 구현 (internal/transport/h2_*.go)
├─→ gRPC 서버 구현 (transport 주입)
├─→ gRPC 게이트웨이 구현
│ ├─→ 프로토콜 어댑터 (MQTT, CoAP — 독립 병행 가능)
│ └─→ 라우팅 테이블
├─→ gRPC 클라이언트 구현
├─→ REST 비교군 구현
└─→ 벤치마크 구현
└─→ 실험 실행 → 결과 기록
```
### 6.3. 충돌 방지
- `go.mod` / `go.sum` 변경 시 다른 에이전트에 즉시 알린다
- `proto/` 파일에 새 필드 추가 시 **필드 번호를 기존과 겹치지 않게** 유보 번호를 확인한다
- 실험 결과 파일은 날짜/시나리오명으로 고유하게 명명하여 덮어쓰기를 방지한다
---
## 7. 자주 수행하는 작업 시나리오
### 7.1. 새 RPC 추가
1. `proto/aiot/{module}/{service}.proto`에 메시지·서비스 정의
2. `make proto``gen/` 코드 생성
3. `internal/server/`에 핸들러 구현
4. `internal/middleware/metrics.go` 인터셉터로 측정 자동화
5. `tests/unit/`에 단위 테스트 추가
6. `benchmarks/scenarios/`에 벤치마크 시나리오 추가
### 7.2. 새 전송 계층 추가
1. `internal/transport/transport.go``Listener`/`Dialer` 인터페이스 충족 확인
2. `internal/transport/{name}_listener.go`, `{name}_dialer.go` 구현
3. `cmd/server/main.go``--transport` 플래그 분기에 추가
4. 벤치마크 실행 시 `--transport={name}` 옵션으로 비교군 등록
### 7.3. 새 IoT 프로토콜 어댑터 추가 (게이트웨이)
1. `internal/gateway/protocol_adapter.go`의 어댑터 인터페이스 확인
2. `internal/gateway/{protocol}_adapter.go` 구현
3. 게이트웨이 부트스트랩(`cmd/gateway/main.go`)에서 어댑터 등록
4. `tests/integration/`에 end-to-end 테스트 추가