refactor: rename examples/ directory to lib/ and update all path references

This commit is contained in:
2026-07-17 19:21:21 +09:00
parent 8f183d597e
commit 8bb11fe205
17 changed files with 49 additions and 49 deletions
+13 -13
View File
@@ -22,7 +22,7 @@ grpccanary/
│ ├── protoapi.pb.go # 메시지 타입 (protoc-gen-go)
│ └── protoapi_grpc.pb.go # 서비스/클라이언트 stub (protoc-gen-go-grpc)
├── obj.json # JSON 예제용 샘플 데이터 파일
├── examples/
├── lib/
│ ├── main.go # 실행 진입점 (현재는 JSON 예제만 호출하도록 설정됨)
│ ├── jsonexample/
│ │ └── json_parser.go # encoding/json 마샬링·언마샬링 예제
@@ -50,16 +50,16 @@ grpccanary/
## 3. 핵심 구성 요소 (학습용 Go 코드)
### 3.1 진입점 — `examples/main.go`
### 3.1 진입점 — `lib/main.go`
- 프로젝트의 유일한 `main()` 함수. `var port = ":8080"`을 정의하고 있으며, 기본 상태에서는 `jsonexample.JsonParsingExample()`만 호출합니다.
- gRPC 예제를 실행하려면 README.md 안내에 따라 `main()` 내부를 수동으로 편집해 `grpcSample()`을 호출하도록 바꿔야 합니다(미사용 import 오류 방지를 위해 `jsonexample` import를 주석 처리해야 함). 즉 **하나의 코드베이스 안에서 학습 단계별로 진입점을 수동 전환하는 방식**으로 설계되어 있습니다.
- `grpcSample()` 함수는 `entity.ServerRun(port)`를 고루틴으로 백그라운드 실행한 뒤 1초 대기 후 `entity.ClientRun(...)`을 호출해, 같은 프로세스 안에서 서버·클라이언트가 통신하는 데모를 구성합니다.
### 3.2 JSON 파싱 예제 — `examples/jsonexample/json_parser.go`
### 3.2 JSON 파싱 예제 — `lib/jsonexample/json_parser.go`
- `encoding/json` 표준 라이브러리를 이용해 (1) `map[string]interface{}` ↔ JSON 문자열 변환, (2) 구조체(`Person`) ↔ JSON 변환의 마샬링/언마샬링을 시연합니다.
- 외부 의존성 없이 표준 라이브러리만 사용하는 가장 단순한 예제로, 커리큘럼의 1단계 역할을 합니다.
### 3.3 HTTP 서버 예제 — `examples/httpentity/`
### 3.3 HTTP 서버 예제 — `lib/httpentity/`
- `server.go``gin-gonic/gin`을 이용한 REST API 서버(정적 파일 서빙 + `/api/randomNumber`, `/api/randomPassword`, `/api/randomDate` 라우트) 초안이 **전체 주석 처리**된 상태로만 존재합니다. 즉 코드는 작성되어 있으나 활성화되지 않은 미완성/보류 상태입니다.
- `client.go``package httpentity` 선언 한 줄만 있는 빈 파일입니다.
- `go.mod`에는 `gin-gonic/gin` 의존성이 여전히 선언되어 있어, 이 파트가 완전히 폐기된 것이 아니라 추후 재개를 염두에 둔 진행 중(work-in-progress) 상태로 보입니다.
@@ -72,21 +72,21 @@ grpccanary/
- `option go_package = "./protoapi/;protoapi"`로 지정되어 있어, `protoc` 컴파일 시 `protoapi/` 디렉토리에 Go 패키지 `protoapi`가 생성됩니다.
- 이미 컴파일된 stub(`protoapi/protoapi.pb.go`, `protoapi/protoapi_grpc.pb.go`)이 저장소에 커밋되어 있어 `protoc` 재설치 없이 바로 빌드/실행이 가능합니다.
### 3.5 gRPC 서버 구현 — `examples/grpcentity/server.go`
### 3.5 gRPC 서버 구현 — `lib/grpcentity/server.go`
- `RandomServer` 구조체가 `protoapi.UnimplementedRandomServer`를 임베딩하여 3개 RPC 메서드(`GetDate`, `GetRandom`, `GetRandomPass`)를 구현합니다.
- `getString(len int64)`은 ASCII 코드 `!`(33)부터 94개 범위 내에서 문자를 뽑아 임의 문자열(비밀번호)을 생성하는 헬퍼입니다.
- `ServerRun(addr string)``grpc.NewServer()`로 서버를 만들고 `reflection.Register(server)`로 gRPC reflection(예: `grpcurl` 같은 외부 CLI 디버깅 도구 지원)을 활성화한 뒤 TCP 포트를 리슨합니다.
- **주의(코드상 특이점)**: `ServerRun`은 인자로 받은 `addr`을 실제로 사용하지 않고 패키지 전역 변수 `port = ":8080"`으로 리슨합니다(`net.Listen("tcp", port)`). 따라서 현재 코드는 항상 `:8080`에서만 동작하며, 호출부에서 다른 포트를 넘겨도 무시됩니다.
- `rand.Seed(r.GetSeed())`(패키지 전역 시드 설정, Go 1.20+에서는 deprecated)와 `rand.NewSource`를 혼용하고 있어 스레드 안전성이나 API 일관성 측면에서 다소 오래된 패턴을 보입니다(학습용 예제이므로 의도된 단순화로 판단됨).
### 3.6 gRPC 클라이언트 구현 — `examples/grpcentity/client.go`
### 3.6 gRPC 클라이언트 구현 — `lib/grpcentity/client.go`
- `grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))`로 평문(TLS 미적용) 채널을 생성합니다(로컬 테스트 목적).
- `AskingDateTime`, `AskPass`, `AskRandom` 세 개의 래퍼 함수가 각각 대응하는 RPC를 호출합니다.
- `ClientRun(addr)`이 실행 엔트리포인트로, 날짜/시간 조회 1회, 비밀번호 생성 1회, 서로 다른 파라미터로 난수 생성 2회를 순차 호출하며 결과를 표준 출력으로 출력합니다.
### 3.7 문서 자료
- **`README.md`(루트)**: 이야기체(스타트업 개발자 '민우'의 사례)로 gRPC 도입 배경(REST/JSON의 한계, Protobuf 계약, HTTP/2)을 설명한 뒤, Go 버전 요구사항(1.25.4+), 의존성 설치, `main.go` 수동 편집 방법, 실행 명령(`go run ./examples`), 기대 출력 예시, 트러블슈팅(포트 충돌, 모듈 로드 오류)까지 안내하는 실행 가이드로 구성되어 있습니다.
- **`examples/grpcentity/README.md`**: `.proto` 파일 문법 요소별 상세 해설, `protoc`/`protoc-gen-go`/`protoc-gen-go-grpc` 설치 및 컴파일 절차, 서버·클라이언트 코드의 구현 단계별 설명을 담은 심화 가이드입니다.
- **`lib/grpcentity/README.md`**: `.proto` 파일 문법 요소별 상세 해설, `protoc`/`protoc-gen-go`/`protoc-gen-go-grpc` 설치 및 컴파일 절차, 서버·클라이언트 코드의 구현 단계별 설명을 담은 심화 가이드입니다.
- **`docs/Working with JSON/`**: JSON 관련 별도 학습 자료(영/한 병기)가 준비되어 있으나, 루트 README와 직접 링크되어 있지는 않습니다.
---
@@ -101,7 +101,7 @@ grpccanary/
- **`.mam/`**: 위 인프라의 런타임 상태 저장소로, `jobs/`(작업 레지스트리 및 브리프 파일), `agent-sessions.yaml`/`.db`(세션 상태), `agent_homes/`(에이전트별 메모리), `delegate_job_logs/`(위임 감사 로그)를 포함합니다. 이번 작업 브리프(`.mam/jobs/702ea1d8/brief.md`) 역시 이 구조를 통해 전달되었습니다.
- **`scripts/generate-env.sh`, `.env.example`**: 이 인프라가 사용하는 MQTT 브로커 접속 정보, 경로 설정 등을 `.env`로 초기화하는 헬퍼입니다. 실제 비밀 값은 `.env`(git-ignored)에만 두고 `.env.example`에는 플레이스홀더만 커밋하도록 설계되어 있습니다.
**참고**: 새로 추가된 `.gitignore``.agents/`, `.mam/`, `.env`, `AGENTS.md` 등을 앞으로 git 추적 대상에서 제외하도록 지정하고 있습니다. 다만 `git log`를 보면 `AGENTS.md`, `examples/grpcentity/README.md` 등은 과거 커밋(`init 251117`, `update 260609`, 이후 docs 커밋들)에서 이미 저장소에 커밋되어 있으므로, 이번 `.gitignore` 추가는 향후 신규/변경 파일이 실수로 다시 커밋되는 것을 막기 위한 조치로 보입니다(기존에 추적 중인 파일을 소급 제외하지는 않음).
**참고**: 새로 추가된 `.gitignore``.agents/`, `.mam/`, `.env`, `AGENTS.md` 등을 앞으로 git 추적 대상에서 제외하도록 지정하고 있습니다. 다만 `git log`를 보면 `AGENTS.md`, `lib/grpcentity/README.md` 등은 과거 커밋(`init 251117`, `update 260609`, 이후 docs 커밋들)에서 이미 저장소에 커밋되어 있으므로, 이번 `.gitignore` 추가는 향후 신규/변경 파일이 실수로 다시 커밋되는 것을 막기 위한 조치로 보입니다(기존에 추적 중인 파일을 소급 제외하지는 않음).
---
@@ -117,16 +117,16 @@ go mod download # 의존성 다운로드
```bash
go run ./examples
```
`examples/main.go`가 기본적으로 `jsonexample.JsonParsingExample()`만 호출하므로, 별도 수정 없이 바로 JSON 마샬링/언마샬링 결과가 콘솔에 출력됩니다.
`lib/main.go`가 기본적으로 `jsonexample.JsonParsingExample()`만 호출하므로, 별도 수정 없이 바로 JSON 마샬링/언마샬링 결과가 콘솔에 출력됩니다.
### 5.3 gRPC 예제 실행 (수동 편집 필요)
1. `examples/main.go`를 열어 `jsonexample` import를 주석 처리하고 `main()` 안에서 `grpcSample()`을 호출하도록 변경.
1. `lib/main.go`를 열어 `jsonexample` import를 주석 처리하고 `main()` 안에서 `grpcSample()`을 호출하도록 변경.
2. 저장 후 실행:
```bash
go run ./examples
```
3. 내부적으로 `:8080` 포트에서 gRPC 서버(고루틴)가 기동되고, 1초 후 클라이언트가 `GetDate`, `GetRandomPass`, `GetRandom`(2회) 순으로 RPC를 호출하며 결과를 출력합니다.
4. 포트 충돌 시(`bind: address already in use`) `examples/grpcentity/server.go`의 `port` 전역 변수를 변경해야 합니다(3.5절에서 언급했듯 `ServerRun`의 `addr` 인자는 무시되므로, 포트 변경은 이 전역 변수 수정으로만 가능).
4. 포트 충돌 시(`bind: address already in use`) `lib/grpcentity/server.go`의 `port` 전역 변수를 변경해야 합니다(3.5절에서 언급했듯 `ServerRun`의 `addr` 인자는 무시되므로, 포트 변경은 이 전역 변수 수정으로만 가능).
### 5.4 HTTP 예제
`httpentity` 패키지는 서버 로직 전체가 주석 처리되어 있고 클라이언트 파일은 비어 있어, 현재 상태로는 실행 가능한 산출물이 없습니다. 향후 주석을 해제하고 `main.go`에 호출부를 추가해야 실습이 가능합니다.
@@ -137,13 +137,13 @@ go run ./examples
protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. \
--go-grpc_opt=paths=source_relative protoapi.proto
```
사전에 `protoc`, `protoc-gen-go`, `protoc-gen-go-grpc`가 설치되어 있어야 합니다(설치 방법은 `examples/grpcentity/README.md` 참고).
사전에 `protoc`, `protoc-gen-go`, `protoc-gen-go-grpc`가 설치되어 있어야 합니다(설치 방법은 `lib/grpcentity/README.md` 참고).
---
## 6. 주요 관찰 사항 및 특이점
1. **단일 진입점, 수동 전환 방식**: `examples/main.go`가 유일한 실행 지점이며, 학습 단계(JSON/HTTP/gRPC)를 전환하려면 코드를 직접 편집해야 합니다. 각 예제를 독립적으로 실행할 수 있는 별도 커맨드나 플래그는 없습니다.
1. **단일 진입점, 수동 전환 방식**: `lib/main.go`가 유일한 실행 지점이며, 학습 단계(JSON/HTTP/gRPC)를 전환하려면 코드를 직접 편집해야 합니다. 각 예제를 독립적으로 실행할 수 있는 별도 커맨드나 플래그는 없습니다.
2. **`ServerRun(addr)`의 `addr` 인자 미사용**: gRPC 서버는 전달받은 인자 대신 패키지 전역 `port` 변수로 리슨하므로, 함수 시그니처와 실제 동작이 일치하지 않는 잠재적 혼동 요소입니다.
3. **HTTP 파트 미완성**: `gin` 의존성은 `go.mod`에 존재하지만 실제 코드는 비활성 상태로, 커리큘럼상 "다음 실습 예정" 단계로 보입니다.
4. **테스트 부재**: 저장소 전체에 자동화된 테스트(`*_test.go`)가 없어, 코드 정상 동작 여부는 수동 실행(`go run`)과 콘솔 출력 확인에 의존합니다. `go build ./...`, `go vet ./...`는 통과합니다.