Files
Godopu d2c63e7c19 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>
2026-05-07 01:31:31 +00:00

12 KiB

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. 초기 셋업

# 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 컴파일

make proto
# 또는 직접 실행:
# scripts/proto-gen.sh

gen/ 디렉터리 파일은 절대 직접 수정하지 않는다. .proto 파일을 수정 후 재생성한다.

3.3. 서버/클라이언트 실행

# 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. 네트워크 조건 시뮬레이션

# 지연 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. 테스트

# 단위 테스트
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를 동일한 코드 경로에서 교체할 수 있도록, 전송 계층은 인터페이스로 추상화한다.

// 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. 컨텍스트와 타임아웃

타임아웃은 클라이언트에서 설정한다. 서버는 컨텍스트 취소를 존중한다.

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 에러 처리

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 등록 시 함께 등록한다. 직접 측정이 필요한 경우 구간을 명시적으로 기록한다.

// 등록 예시
grpc.NewServer(
    grpc.UnaryInterceptor(middleware.MetricsUnaryInterceptor),
    grpc.StreamInterceptor(middleware.MetricsStreamInterceptor),
)

5. 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 protogen/ 코드 생성
  3. internal/server/에 핸들러 구현
  4. internal/middleware/metrics.go 인터셉터로 측정 자동화
  5. tests/unit/에 단위 테스트 추가
  6. benchmarks/scenarios/에 벤치마크 시나리오 추가

7.2. 새 전송 계층 추가

  1. internal/transport/transport.goListener/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 테스트 추가