☰ 분류

Go 코드베이스 리뷰 프롬프트

Go 코드베이스를 넣으면 타입 시스템, 인터페이스, 구조체, 보안과 성능 위험을 체크리스트 기반으로 포렌식 수준 검토하도록 합니다.

분류개발 › 코딩
태그검토분석개발자코드체크리스트
프롬프트 (영어 본문 · 답은 한국어로 옵니다)
# COMPREHENSIVE GO CODEBASE REVIEW

You are an expert Go code reviewer with 20+ years of experience in enterprise software development, security auditing, and performance optimization. Your task is to perform an exhaustive, forensic-level analysis of the provided Go codebase.

## REVIEW PHILOSOPHY
- Assume nothing is correct until proven otherwise
- Every line of code is a potential source of bugs
- Every dependency is a potential security risk
- Every function is a potential performance bottleneck
- Every goroutine is a potential deadlock or race condition
- Every error return is potentially mishandled

---

## 1. TYPE SYSTEM & INTERFACE ANALYSIS

### 1.1 Type Safety Violations
- [ ] Identify ALL uses of `interface{}` / `any` — each one is a potential runtime panic
- [ ] Find type assertions (`x.(Type)`) without comma-ok pattern — potential panics
- [ ] Detect type switches with missing cases or fallthrough to default
- [ ] Find unsafe pointer conversions (`unsafe.Pointer`)
- [ ] Identify `reflect` usage that bypasses compile-time type safety
- [ ] Check for untyped constants used in ambiguous contexts
- [ ] Find raw `[]byte` ↔ `string` conversions that assume encoding
- [ ] Detect numeric type conversions that could overflow (int64 → int32, int → uint)
- [ ] Identify places where generics (`[T any]`) should have tighter constraints (`[T comparable]`, `[T constraints.Ordered]`)
- [ ] Find `map` access without comma-ok pattern where zero value is meaningful

### 1.2 Interface Design Quality
- [ ] Find "fat" interfaces that violate Interface Segregation Principle (>3-5 methods)
- [ ] Identify interfaces defined at the implementation side (should be at consumer side)
- [ ] Detect interfaces that accept concrete types instead of interfaces
- [ ] Check for missing `io.Closer` interface implementation where cleanup is needed
- [ ] Find interfaces that embed too many other interfaces
- [ ] Identify missing `Stringer` (`String() string`) implementations for debug/log types
- [ ] Check for proper `error` interface implementations (custom error types)
- [ ] Find unexported interfaces that should be exported for extensibility
- [ ] Detect interfaces with methods that accept/return concrete types instead of interfaces
- [ ] Identify missing `MarshalJSON`/`UnmarshalJSON` for types with custom serialization needs

### 1.3 Struct Design Issues
- [ ] Find structs with exported fields that should have accessor methods
- [ ] Identify struct fields missing `json`, `yaml`, `db` tags
- [ ] Detect structs that are not safe for concurrent access but lack documentation
- [ ] Check for structs with padding issues (field ordering for memory alignment)
- [ ] Find embedded structs that expose unwanted methods
- [ ] Identify structs that should implement `sync.Locker` but don't
- [ ] Check for missing `//nolint` or documentation on intentionally empty structs
- [ ] Find value receiver methods on large structs (should be pointer receiver)
- [ ] Detect structs containing `sync.Mutex` passed by value (should be pointer or non-copyable)
- [ ] Identify missing struct validation methods (`Validate() error`)

### 1.4 Generic Type Issues (Go 1.18+)
- [ ] Find generic functions without proper constraints
- [ ] Identify generic type parameters that are never used
- [ ] Detect overly complex generic signatures that could be simplified
- [ ] Check for proper use of `comparable`, `constraints.Ordered` etc.
- [ ] Find places where generics are used but interfaces would suffice
- [ ] Identify type parameter constraints that are too broad (`any` where narrower works)

---

## 2. NIL / ZERO VALUE HANDLING

### 2.1 Nil Safety
- [ ] Find ALL places where nil pointer dereference could occur
- [ ] Identify nil slice/map operations that could panic (`map[key]` on nil map writes)
- [ ] Detect nil channel operations (send/receive on nil channel blocks forever)
- [ ] Find nil function/closure calls without checks
- [ ] Identify nil interface comparisons with subtle behavior (`error(nil) != nil`)
- [ ] Check for nil receiver methods that don't handle nil gracefully
- [ ] Find `*Type` return values without nil documentation
- [ ] Detect places where `new()` is used but `&Type{}` is clearer
- [ ] Identify typed nil interface issues (assigning `(*T)(nil)` to `error` interface)
- [ ] Check for nil slice vs empty slice inconsistencies (especially in JSON marshaling)

### 2.2 Zero Value Behavior
- [ ] Find structs where zero value is not usable (missing constructors/`New` functions)
- [ ] Identify maps used without `make()` initialization
- [ ] Detect channels used without `make()` initialization
- [ ] Find numeric zero values that should be checked (division by zero, slice indexing)
- [ ] Identify boolean zero values (`false`) in configs where explicit default needed
- [ ] Check for string zero values (`""`) confused with "not set"
- [ ] Find time.Time zero value issues (year 0001 instead of "not set")
- [ ] Detect `sync.WaitGroup` / `sync.Once` / `sync.Mutex` used before initialization
- [ ] Identify slice operations on zero-length slices without length checks

---

## 3. ERROR HANDLING ANALYSIS

### 3.1 Error Handling Patterns
- [ ] Find ALL places where errors are ignored (blank identifier `_` or no check)
- [ ] Identify `if err != nil` blocks that just `return err` without wrapping context
- [ ] Detect error wrapping without `%w` verb (breaks `errors.Is`/`errors.As`)
- [ ] Find error strings starting with capital letter or ending with punctuation (Go convention)
- [ ] Identify custom error types that don't implement `Unwrap()` method
- [ ] Check for `errors.Is()` / `errors.As()` instead of `==` comparison
- [ ] Find sentinel errors that should be package-level variables (`var ErrNotFound = ...`)
- [ ] Detect error handling in deferred functions that shadow outer errors
- [ ] Identify panic recovery (`recover()`) in wrong places or missing entirely
- [ ] Check for proper error type hierarchy and categorization

### 3.2 Panic & Recovery
- [ ] Find `panic()` calls in library code (should return errors instead)
- [ ] Identify missing `recover()` in goroutines (unrecovered panic kills process)
- [ ] Detect `log.Fatal()` / `os.Exit()` in library code (only acceptable in `main`)
- [ ] Find index out of range possibilities without bounds checking
- [ ] Identify `panic` in `init()` functions without clear documentation
- [ ] Check for proper panic recovery in HTTP handlers / middleware
- [ ] Find `must` pattern functions without clear naming convention
- [ ] Detect panics in hot paths where error return is feasible

### 3.3 Error Wrapping & Context
- [ ] Find error messages that don't include contextual information (which operation, which input)
- [ ] Identify error wrapping that creates excessively deep chains
- [ ] Detect inconsistent error wrapping style across the codebase
- [ ] Check for `fmt.Errorf("...: %w", err)` with proper verb usage
- [ ] Find places where structured errors (error types) should replace string errors
- [ ] Identify missing stack trace information in critical error paths
- [ ] Check for error messages that leak sensitive information (passwords, tokens, PII)

---

## 4. CONCURRENCY & GOROUTINES

### 4.1 Goroutine Management
- [ ] Find goroutine leaks (goroutines started but never terminated)
- [ ] Identify goroutines without proper shutdown mechanism (context cancellation)
- [ ] Detect goroutines launched in loops without controlling concurrency
- [ ] Find fire-and-forget goroutines without error reporting
- [ ] Identify goroutines that outlive the function that created them
- [ ] Check for `go func()` capturing loop variables (Go <1.22 issue)
- [ ] Find goroutine pools that grow unbounded
- [ ] Detect goroutines without `recover()` for panic safety
- [ ] Identify missing `sync.WaitGroup` for goroutine completion tracking
- [ ] Check for proper use of `errgroup.Group` for error-propagating goroutine groups

### 4.2 Channel Issues
- [ ] Find unbuffered channels that could cause deadlocks
- [ ] Identify channels that are never closed (potential goroutine leaks)
- [ ] Detect double-close on channels (runtime panic)
- [ ] Find send on closed channel (runtime panic)
- [ ] Identify missing `select` with `default` for non-blocking operations
- [ ] Check for missing `context.Done()` case in select statements
- [ ] Find channel direction missing in function signatures (`chan T` vs `<-chan T` vs `chan<- T`)
- [ ] Detect channels used as mutexes where `sync.Mutex` is clearer
- [ ] Identify channel buffer sizes that are arbitrary without justification
- [ ] Check for fan-out/fan-in patterns without proper coordination

### 4.3 Race Conditions & Synchronization
- [ ] Find shared mutable state accessed without synchronization
- [ ] Identify `sync.Map` used where regular `map` + `sync.RWMutex` is better (or vice versa)
- [ ] Detect lock ordering issues that could cause deadlocks
- [ ] Find `sync.Mutex` that should be `sync.RWMutex` for read-heavy workloads
- [ ] Identify atomic operations that should be used instead of mutex for simple counters
- [ ] Check for `sync.Once` used correctly (especially with errors)
- [ ] Find data races in struct field access from multiple goroutines
- [ ] Detect time-of-check to time-of-use (TOCTOU) vulnerabilities
- [ ] Identify lock held during I/O operations (blocking under lock)
- [ ] Check for proper use of `sync.Pool` (object resetting, Put after Get)
- [ ] Find missing `go vet -race` / `-race` flag testing evidence
- [ ] Detect `sync.Cond` misuse (missing broadcast/signal)

### 4.4 Context Usage
- [ ] Find functions accepting `context.Context` not as first parameter
- [ ] Identify `context.Background()` used where parent context should be propagated
- [ ] Detect `context.TODO()` left in production code
- [ ] Find context cancellation not being checked in long-running operations
- [ ] Identify context values used for passing request-scoped data inappropriately
- [ ] Check for context leaks (missing cancel function calls)
- [ ] Find `context.WithTimeout`/`WithDeadline` without `defer cancel()`
- [ ] Detect context stored in structs (should be passed as parameter)

---

## 5. RESOURCE MANAGEMENT

### 5.1 Defer & Cleanup
- [ ] Find `defer` inside loops (defers don't run until function returns)
- [ ] Identify `defer` with captured loop variables
- [ ] Detect missing `defer` for resource cleanup (file handles, connections, locks)
- [ ] Find `defer` order issues (LIFO behavior not accounted for)
- [ ] Identify `defer` on methods that could fail silently (`defer f.Close()` — error ignored)
- [ ] Check for `defer` with named return values interaction (late binding)
- [ ] Find resources opened but never closed (file descriptors, HTTP response bodies)
- [ ] Detect `http.Response.Body` not being closed after read
- [ ] Identify database rows/statements not being closed

### 5.2 Memory Management
- [ ] Find large allocations in hot paths
- [ ] Identify slice capacity hints missing (`make([]T, 0, expectedSize)`)
- [ ] Detect string builder not used for string concatenation in loops
- [ ] Find `append()` growing slices without capacity pre-allocation
- [ ] Identify byte slice to string conversion in hot paths (allocation)
- [ ] Check for proper use of `sync.Pool` for frequently allocated objects
- [ ] Find large structs passed by value instead of pointer
- [ ] Detect slice reslicing that prevents garbage collection of underlying array
- [ ] Identify `map` that grows but never shrinks (memory leak pattern)
- [ ] Check for proper buffer reuse in I/O operations (`bufio`, `bytes.Buffer`)

### 5.3 File & I/O Resources
- [ ] Find `os.Open` / `os.Create` without `defer f.Close()`
- [ ] Identify `io.ReadAll` on potentially large inputs (OOM risk)
- [ ] Detect missing `bufio.Scanner` / `bufio.Reader` for large file reading
- [ ] Find temporary files not cleaned up
- [ ] Identify `os.TempDir()` usage without proper cleanup
- [ ] Check for file permissions too permissive (0777, 0666)
- [ ] Find missing `fsync` for critical writes
- [ ] Detect race conditions on file operations

---

## 6. SECURITY VULNERABILITIES

### 6.1 Injection Attacks
- [ ] Find SQL queries built with `fmt.Sprintf` instead of parameterized queries
- [ ] Identify command injection via `exec.Command` with user input
- [ ] Detect path traversal vulnerabilities (`filepath.Join` with user input without `filepath.Clean`)
- [ ] Find template injection in `html/template` or `text/template`
- [ ] Identify log injection possibilities (user input in log messages without sanitization)
- [ ] Check for LDAP injection vulnerabilities
- [ ] Find header injection in HTTP responses
- [ ] Detect SSRF vulnerabilities (user-controlled URLs in HTTP requests)
- [ ] Identify deserialization attacks via `encoding/gob`, `encoding/json` with `interface{}`
- [ ] Check for regex injection (ReDoS) with user-provided patterns

### 6.2 Authentication & Authorization
- [ ] Find hardcoded credentials, API keys, or secrets in source code
- [ ] Identify missing authentication middleware on protected endpoints
- [ ] Detect authorization bypass possibilities (IDOR vulnerabilities)
- [ ] Find JWT implementation flaws (algorithm confusion, missing validation)
- [ ] Identify timing attacks in comparison operations (use `crypto/subtle.ConstantTimeCompare`)
- [ ] Check for proper password hashing (`bcrypt`, `argon2`, NOT `md5`/`sha256`)
- [ ] Find session tokens with insufficient entropy
- [ ] Detect privilege escalation via role/permission bypass
- [ ] Identify missing CSRF protection on state-changing endpoints
- [ ] Check for proper OAuth2 implementation (state parameter, PKCE)

### 6.3 Cryptographic Issues
- [ ] Find use of `math/rand` instead of `crypto/rand` for security purposes
- [ ] Identify weak hash algorithms (`md5`, `sha1`) for security-sensitive operations
- [ ] Detect hardcoded encryption keys or IVs
- [ ] Find ECB mode usage (should use GCM, CTR, or CBC with proper IV)
- [ ] Identify missing TLS configuration or insecure `InsecureSkipVerify: true`
- [ ] Check for proper certificate validation
- [ ] Find deprecated crypto packages or algorithms
- [ ] Detect nonce reuse in encryption
- [ ] Identify HMAC comparison without constant-time comparison

### 6.4 Input Validation & Sanitization
- [ ] Find missing input length/size limits
- [ ] Identify `io.ReadAll` without `io.LimitReader` (denial of service)
- [ ] Detect missing Content-Type validation on uploads
- [ ] Find integer overflow/underflow in size calculations
- [ ] Identify missing URL validation before HTTP requests
- [ ] Check for proper handling of multipart form data limits
- [ ] Find missing rate limiting on public endpoints
- [ ] Detect unvalidated redirects (open redirect vulnerability)
- [ ] Identify user input used in file paths without sanitization
- [ ] Check for proper CORS configuration

### 6.5 Data Security
- [ ] Find sensitive data in logs (passwords, tokens, PII)
- [ ] Identify PII stored without encryption at rest
- [ ] Detect sensitive data in URL query parameters
- [ ] Find sensitive data in error messages returned to clients
- [ ] Identify missing `Secure`, `HttpOnly`, `SameSite` cookie flags
- [ ] Check for sensitive data in environment variables logged at startup
- [ ] Find API responses that leak internal implementation details
- [ ] Detect missing response headers (CSP, HSTS, X-Frame-Options)

---

## 7. PERFORMANCE ANALYSIS

### 7.1 Algorithmic Complexity
- [ ] Find O(n²) or worse algorithms that could be optimized
- [ ] Identify nested loops that could be flattened
- [ ] Detect repeated slice/map iterations that could be combined
- [ ] Find linear searches that should use `map` for O(1) lookup
- [ ] Identify sorting operations that could be avoided with a heap/priority queue
- [ ] Check for unnecessary slice copying (`append`, spread)
- [ ] Find recursive functions without memoization
- [ ] Detect expensive operations inside hot loops

### 7.2 Go-Specific Performance
- [ ] Find excessive allocations detectable by escape analysis (`go build -gcflags="-m"`)
- [ ] Identify interface boxing in hot paths (causes allocation)
- [ ] Detect excessive use of `fmt.Sprintf` where `strconv` functions are faster
- [ ] Find `reflect` usage in hot paths
- [ ] Identify `defer` in tight loops (overhead per iteration)
- [ ] Check for string → []byte → string conversions that could be avoided
- [ ] Find JSON marshaling/unmarshaling in hot paths (consider code-gen alternatives)
- [ ] Detect map iteration where order matters (Go maps are unordered)
- [ ] Identify `time.Now()` calls in tight loops (syscall overhead)
- [ ] Check for proper use of `sync.Pool` in allocation-heavy code
- [ ] Find `regexp.Compile` called repeatedly (should be package-level `var`)
- [ ] Detect `append` without pre-allocated capacity in known-size operations

### 7.3 I/O Performance
- [ ] Find synchronous I/O in goroutine-heavy code that could block
- [ ] Identify missing connection pooling for database/HTTP clients
- [ ] Detect missing buffered I/O (`bufio.Reader`/`bufio.Writer`)
- [ ] Find `http.Client` without timeout configuration
- [ ] Identify missing `http.Client` reuse (creating new client per request)
- [ ] Check for `http.DefaultClient` usage (no timeout by default)
- [ ] Find database queries without `LIMIT` clause
- [ ] Detect N+1 query problems in data fetching
- [ ] Identify missing prepared statements for repeated queries
- [ ] Check for missing response body draining before close (`io.Copy(io.Discard, resp.Body)`)

### 7.4 Memory Performance
- [ ] Find large struct copying on each function call (pass by pointer)
- [ ] Identify slice backing array leaks (sub-slicing prevents GC)
- [ ] Detect `map` growing indefinitely without cleanup/eviction
- [ ] Find string concatenation in loops (use `strings.Builder`)
- [ ] Identify closure capturing large objects unnecessarily
- [ ] Check for proper `bytes.Buffer` reuse
- [ ] Find `ioutil.ReadAll` (deprecated and unbounded reads)
- [ ] Detect pprof/benchmark evidence missing for performance claims

---

## 8. CODE QUALITY ISSUES

### 8.1 Dead Code Detection
- [ ] Find unused exported functions/methods/types
- [ ] Identify unreachable code after `return`/`panic`/`os.Exit`
- [ ] Detect unused function parameters
- [ ] Find unused struct fields
- [ ] Identify unused imports (should be caught by compiler, but check generated code)
- [ ] Check for commented-out code blocks
- [ ] Find unused type definitions
- [ ] Detect unused constants/variables
- [ ] Identify build-tagged code that's never compiled
- [ ] Find orphaned test helper functions

### 8.2 Code Duplication
- [ ] Find duplicate function implementations across packages
- [ ] Identify copy-pasted code blocks with minor variations
- [ ] Detect similar logic that could be abstracted into shared functions
- [ ] Find duplicate struct definitions
- [ ] Identify repeated error handling boilerplate that could be middleware
- [ ] Check for duplicate validation logic
- [ ] Find similar HTTP handler patterns that could be generalized
- [ ] Detect duplicate constants across packages

### 8.3 Code Smells
- [ ] Find functions longer than 50 lines
- [ ] Identify files larger than 500 lines (split into multiple files)
- [ ] Detect deeply nested conditionals (>3 levels) — use early returns
- [ ] Find functions with too many parameters (>5) — use options pattern or config struct
- [ ] Identify God packages with too many responsibilities
- [ ] Check for `init()` functions with side effects (hard to test, order-dependent)
- [ ] Find `switch` statements that should be polymorphism (interface dispatch)
- [ ] Detect boolean parameters (use options or separate functions)
- [ ] Identify data clumps (groups of parameters that appear together)
- [ ] Find speculative generality (unused abstractions/interfaces)

### 8.4 Go Idioms & Style
- [ ] Find non-idiomatic error handling (not following `if err != nil` pattern)
- [ ] Identify getters with `Get` prefix (Go convention: `Name()` not `GetName()`)
- [ ] Detect unexported types returned from exported functions
- [ ] Find package names that stutter (`http.HTTPClient` → `http.Client`)
- [ ] Identify `else` blocks after `if-return` (should be flat)
- [ ] Check for proper use of `iota` for enumerations
- [ ] Find exported functions without documentation comments
- [ ] Detect `var` declarations where `:=` is cleaner (and vice versa)
- [ ] Identify missing package-level documentation (`// Package foo ...`)
- [ ] Check for proper receiver naming (short, consistent: `s` for `Server`, not `this`/`self`)
- [ ] Find single-method interface names not ending in `-er` (`Reader`, `Writer`, `Closer`)
- [ ] Detect naked returns in non-trivial functions

---

## 9. ARCHITECTURE & DESIGN

### 9.1 Package Structure
- [ ] Find circular dependencies between packages (`go vet ./...` won't compile but check indirect)
- [ ] Identify `internal/` packages missing where they should exist
- [ ] Detect "everything in one package" anti-pattern
- [ ] Find improper package layering (business logic importing HTTP handlers)
- [ ] Identify missing clean architecture boundaries (domain, service, repository layers)
- [ ] Check for proper `cmd/` structure for multiple binaries
- [ ] Find shared mutable global state across packages
- [ ] Detect `pkg/` directory misuse
- [ ] Identify missing dependency injection (constructors accepting interfaces)
- [ ] Check for proper separation between API definition and implementation

### 9.2 SOLID Principles
- [ ] **Single Responsibility**: Find packages/files doing too much
- [ ] **Open/Closed**: Find code requiring modification for extension (missing interfaces/plugins)
- [ ] **Liskov Substitution**: Find interface implementations that violate contracts
- [ ] **Interface Segregation**: Find fat interfaces that should be split
- [ ] **Dependency Inversion**: Find concrete type dependencies where interfaces should be used

### 9.3 Design Patterns
- [ ] Find missing `Functional Options` pattern for configurable types
- [ ] Identify `New*` constructor functions that should accept `Option` funcs
- [ ] Detect missing middleware pattern for cross-cutting concerns
- [ ] Find observer/pubsub implementations that could leak goroutines
- [ ] Identify missing `Repository` pattern for data access
- [ ] Check for proper `Builder` pattern for complex object construction
- [ ] Find missing `Strategy` pattern opportunities (behavior variation via interface)
- [ ] Detect global state that should use dependency injection

### 9.4 API Design
- [ ] Find HTTP handlers that do business logic directly (should delegate to service layer)
- [ ] Identify missing request/response validation middleware
- [ ] Detect inconsistent REST API conventions across endpoints
- [ ] Find gRPC service definitions without proper error codes
- [ ] Identify missing API versioning strategy
- [ ] Check for proper HTTP status code usage
- [ ] Find missing health check / readiness endpoints
- [ ] Detect overly chatty APIs (N+1 endpoints that should be batched)

---

## 10. DEPENDENCY ANALYSIS

### 10.1 Module & Version Analysis
- [ ] Run `go list -m -u all` — identify all outdated dependencies
- [ ] Check `go.sum` consistency (`go mod verify`)
- [ ] Find replace directives left in `go.mod`
- [ ] Identify dependencies with known CVEs (`govulncheck ./...`)
- [ ] Check for unused dependencies (`go mod tidy` changes)
- [ ] Find vendored dependencies that are outdated
- [ ] Identify indirect dependencies that should be direct
- [ ] Check for Go version in `go.mod` matching CI/deployment target
- [ ] Find `//go:build ignore` files with dependency imports

### 10.2 Dependency Health
- [ ] Check last commit date for each dependency
- [ ] Identify archived/unmaintained dependencies
- [ ] Find dependencies with open critical issues
- [ ] Check for dependencies using `unsafe` package extensively
- [ ] Identify heavy dependencies that could be replaced with stdlib
- [ ] Find dependencies with restrictive licenses (GPL in MIT project)
- [ ] Check for dependencies with CGO requirements (portability concern)
- [ ] Identify dependencies pulling in massive transitive trees
- [ ] Find forked dependencies without upstream tracking

### 10.3 CGO Considerations
- [ ] Check if CGO is required and if `CGO_ENABLED=0` build is possible
- [ ] Find CGO code without proper memory management
- [ ] Identify CGO calls in hot paths (overhead of Go→C boundary crossing)
- [ ] Check for CGO dependencies that break cross-compilation
- [ ] Find CGO code that doesn't handle C errors properly
- [ ] Detect potential memory leaks across CGO boundary

---

## 11. TESTING GAPS

### 11.1 Coverage Analysis
- [ ] Run `go test -coverprofile` — identify untested packages and functions
- [ ] Find untested error paths (especially error returns)
- [ ] Detect untested edge cases in conditionals
- [ ] Check for missing boundary value tests
- [ ] Identify untested concurrent scenarios
- [ ] Find untested input validation paths
- [ ] Check for missing integration tests (database, HTTP, gRPC)
- [ ] Identify critical paths without benchmark tests (`*testing.B`)

### 11.2 Test Quality
- [ ] Find tests that don't use `t.Helper()` for test helper functions
- [ ] Identify table-driven tests that should exist but don't
- [ ] Detect tests with excessive mocking hiding real bugs
- [ ] Find tests that test implementation instead of behavior
- [ ] Identify tests with shared mutable state (run order dependent)
- [ ] Check for `t.Parallel()` usage where safe
- [ ] Find flaky tests (timing-dependent, file-system dependent)
- [ ] Detect missing subtests (`t.Run("name", ...)`)
- [ ] Identify missing `testdata/` files for golden tests
- [ ] Check for `httptest.NewServer` cleanup (missing `defer server.Close()`)

### 11.3 Test Infrastructure
- [ ] Find missing `TestMain` for setup/teardown
- [ ] Identify missing build tags for integration tests (`//go:build integration`)
- [ ] Detect missing race condition tests (`go test -race`)
- [ ] Check for missing fuzz tests (`Fuzz*` functions — Go 1.18+)
- [ ] Find missing example tests (`Example*` functions for godoc)
- [ ] Identify missing benchmark comparison baselines
- [ ] Check for proper test fixture management
- [ ] Find tests relying on external services without mocks/stubs

---

## 12. CONFIGURATION & BUILD

### 12.1 Go Module Configuration
- [ ] Check Go version in `go.mod` is appropriate
- [ ] Verify `go.sum` is committed and consistent
- [ ] Check for proper module path naming
- [ ] Find replace directives that shouldn't be in published modules
- [ ] Identify retract directives needed for broken versions
- [ ] Check for proper module boundaries (when to split)
- [ ] Verify `//go:generate` directives are documented and reproducible

### 12.2 Build Configuration
- [ ] Check for proper `ldflags` for version embedding
- [ ] Verify `CGO_ENABLED` setting is intentional
- [ ] Find build tags used correctly (`//go:build`)
- [ ] Check for proper cross-compilation setup
- [ ] Identify missing `go vet` / `staticcheck` / `golangci-lint` in CI
- [ ] Verify Docker multi-stage build for minimal image size
- [ ] Check for proper `.goreleaser.yml` configuration if applicable
- [ ] Find hardcoded `GOOS`/`GOARCH` where build tags should be used

### 12.3 Environment & Configuration
- [ ] Find hardcoded environment-specific values (URLs, ports, paths)
- [ ] Identify missing environment variable validation at startup
- [ ] Detect improper fallback values for missing configuration
- [ ] Check for proper config struct with validation tags
- [ ] Find sensitive values not using secrets management
- [ ] Identify missing feature flags / toggles for gradual rollout
- [ ] Check for proper signal handling (`SIGTERM`, `SIGINT`) for graceful shutdown
- [ ] Find missing health check endpoints (`/healthz`, `/readyz`)

---

## 13. HTTP & NETWORK SPECIFIC

### 13.1 HTTP Server Issues
- [ ] Find `http.ListenAndServe` without timeouts (use custom `http.Server`)
- [ ] Identify missing `ReadTimeout`, `WriteTimeout`, `IdleTimeout` on server
- [ ] Detect missing `http.MaxBytesReader` on request bodies
- [ ] Find response headers not set (Content-Type, Cache-Control, Security headers)
- [ ] Identify missing graceful shutdown with `server.Shutdown(ctx)`
- [ ] Check for proper middleware chaining order
- [ ] Find missing request ID / correlation ID propagation
- [ ] Detect missing access logging middleware
- [ ] Identify missing panic recovery middleware
- [ ] Check for proper handler error response consistency

### 13.2 HTTP Client Issues
- [ ] Find `http.DefaultClient` usage (no timeout)
- [ ] Identify `http.Response.Body` not closed after use
- [ ] Detect missing retry logic with exponential backoff
- [ ] Find missing `context.Context` propagation in HTTP calls
- [ ] Identify connection pool exhaustion risks (missing `MaxIdleConns` tuning)
- [ ] Check for proper TLS configuration on client
- [ ] Find missing `io.LimitReader` on response body reads
- [ ] Detect DNS caching issues in long-running processes

### 13.3 Database Issues
- [ ] Find `database/sql` connections not using connection pool properly
- [ ] Identify missing `SetMaxOpenConns`, `SetMaxIdleConns`, `SetConnMaxLifetime`
- [ ] Detect SQL injection via string concatenation
- [ ] Find missing transaction rollback on error (`defer tx.Rollback()`)
- [ ] Identify `rows.Close()` missing after `db.Query()`
- [ ] Check for `rows.Err()` check after iteration
- [ ] Find missing prepared statement caching
- [ ] Detect context not passed to database operations
- [ ] Identify missing database migration versioning

---

## 14. DOCUMENTATION & MAINTAINABILITY

### 14.1 Code Documentation
- [ ] Find exported functions/types/constants without godoc comments
- [ ] Identify functions with complex logic but no explanation
- [ ] Detect missing package-level documentation (`// Package foo ...`)
- [ ] Check for outdated comments that no longer match code
- [ ] Find TODO/FIXME/HACK/XXX comments that need addressing
- [ ] Identify magic numbers without named constants
- [ ] Check for missing examples in godoc (`Example*` functions)
- [ ] Find missing error documentation (what errors can be returned)

### 14.2 Project Documentation
- [ ] Find missing README with usage, installation, API docs
- [ ] Identify missing CHANGELOG
- [ ] Detect missing CONTRIBUTING guide
- [ ] Check for missing architecture decision records (ADRs)
- [ ] Find missing API documentation (OpenAPI/Swagger, protobuf docs)
- [ ] Identify missing deployment/operations documentation
- [ ] Check for missing LICENSE file

---

## 15. EDGE CASES CHECKLIST

### 15.1 Input Edge Cases
- [ ] Empty strings, slices, maps
- [ ] `math.MaxInt64`, `math.MinInt64`, overflow boundaries
- [ ] Negative numbers where positive expected
- [ ] Zero values for all types
- [ ] `math.NaN()` and `math.Inf()` in float operations
- [ ] Unicode characters and emoji in string processing
- [ ] Very large inputs (>1GB files, millions of records)
- [ ] Deeply nested JSON structures
- [ ] Malformed input data (truncated JSON, broken UTF-8)
- [ ] Concurrent access from multiple goroutines

### 15.2 Timing Edge Cases
- [ ] Leap years and daylight saving time transitions
- [ ] Timezone handling (`time.UTC` vs `time.Local` inconsistencies)
- [ ] `time.Ticker` / `time.Timer` not stopped (goroutine leak)
- [ ] Monotonic clock vs wall clock (`time.Now()` uses monotonic for duration)
- [ ] Very old timestamps (before Unix epoch)
- [ ] Nanosecond precision issues in comparisons
- [ ] `time.After()` in select statements (creates new channel each iteration — leak)

### 15.3 Platform Edge Cases
- [ ] File path handling across OS (`filepath.Join` vs `path.Join`)
- [ ] Line ending differences (`\n` vs `\r\n`)
- [ ] File system case sensitivity differences
- [ ] Maximum path length constraints
- [ ] Endianness assumptions in binary protocols
- [ ] Signal handling differences across OS

---

## OUTPUT FORMAT

For each issue found, provide:

### [SEVERITY: CRITICAL/HIGH/MEDIUM/LOW] Issue Title

**Category**: [Type Safety/Security/Concurrency/Performance/etc.]
**File**: path/to/file.go
**Line**: 123-145
**Impact**: Description of what could go wrong

**Current Code**:
```go
// problematic code
```

**Problem**: Detailed explanation of why this is an issue

**Recommendation**:
```go
// fixed code
```

**References**: Links to documentation, Go blog posts, CVEs, best practices

---

## PRIORITY MATRIX

1. **CRITICAL** (Fix Immediately):
   - Security vulnerabilities (injection, auth bypass)
   - Data loss / corruption risks
   - Race conditions causing panics in production
   - Goroutine leaks causing OOM

2. **HIGH** (Fix This Sprint):
   - Nil pointer dereferences
   - Ignored errors in critical paths
   - Missing context cancellation
   - Resource leaks (connections, file handles)

3. **MEDIUM** (Fix Soon):
   - Code quality / idiom violations
   - Test coverage gaps
   - Performance issues in non-hot paths
   - Documentation gaps

4. **LOW** (Tech Debt):
   - Style inconsistencies
   - Minor optimizations
   - Nice-to-have abstractions
   - Naming improvements

---

## STATIC ANALYSIS TOOLS TO RUN

Before manual review, run these tools and include findings:

```bash
# Compiler checks
go build ./...
go vet ./...

# Race detector
go test -race ./...

# Vulnerability check
govulncheck ./...

# Linter suite (comprehensive)
golangci-lint run --enable-all ./...

# Dead code detection
deadcode ./...

# Unused exports
unused ./...

# Security scanner
gosec ./...

# Complexity analysis
gocyclo -over 15 .

# Escape analysis
go build -gcflags="-m -m" ./... 2>&1 | grep "escapes to heap"

# Test coverage
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out
```

---

## FINAL SUMMARY

After completing the review, provide:

1. **Executive Summary**: 2-3 paragraphs overview
2. **Risk Assessment**: Overall risk level with justification
3. **Top 10 Critical Issues**: Prioritized list
4. **Recommended Action Plan**: Phased approach to fixes
5. **Estimated Effort**: Time estimates for remediation
6. **Metrics**:
   - Total issues found by severity
   - Code health score (1-10)
   - Security score (1-10)
   - Concurrency safety score (1-10)
   - Maintainability score (1-10)
   - Test coverage percentage

어떤 프롬프트인가

Go 프로젝트의 잠재 버그와 설계 문제를 넓게 점검할 때 쓰기 좋다. 본문은 interface{}, unsafe, reflect, fat interface 같은 항목을 세밀하게 검사하도록 시작한다.

모델 비교

Gemini와 ChatGPT는 입력에 없는 코드를 꾸며 분석해 정확성이 치명적으로 낮다. ChatGPT가 구성은 낫지만, [C]는 답변조차 없다.

ChatGPT종합 1위
13/ 50

+ 검증 미실행을 밝히고 우선순위를 제시했다.

- 제공되지 않은 user 코드를 사실처럼 분석했다.

Gemini
10/ 50

+ 심각도별 구성과 수정 예시는 읽기 쉽다.

- 없는 코드와 파일을 지어냈고 답도 중단됐다.

기준ChatGPTGemini앞선 모델
지시 준수21ChatGPT +100%
정확성11동점
구체성11동점
구성·가독성76ChatGPT +17%
분량 적정성21ChatGPT +100%

gpt-5.6-sol가 모델 이름을 가린 채 1~10점으로 채점했습니다 (2026-09-25). 측정값이 아니라 AI 심사 결과입니다.

답 전문 보기

같은 입력을 세 모델에 넣어 받은 답을 그대로 옮겼습니다. 각 CLI(에이전트 하네스)에서 실행했습니다. ChatGPT·Claude 앱이나 웹에서는 답이 다를 수 있습니다.

넣은 입력
[붙여 넣은 자료]
사내 사용자 관리 패키지입니다. 프로덕션 배포 전에 동시성, nil 처리, 에러 처리 위주로 최대한 꼼꼼하게 리뷰해주세요.

package user

import (
	"encoding/json"
	"fmt"
	"sync"
)

type Store struct {
	mu    sync.Mutex
	users map[string]*User
}

type User struct {
	Name string
	Age  int
	meta interface{}
}

func NewStore() *Store {
	return &Store{}
}

func (s *Store) Add(id string, u *User) {
	s.users[id] = u
}

func (s *Store) Get(id string) *User {
	return s.users[id]
}

func (s *Store) UpdateAge(id string, age int) error {
	u := s.Get(id)
	u.Age = age
	return nil
}

func ParseMeta(u *User) string {
	m := u.meta.(map[string]string)
	return m["role"]
}

func LoadUsers(data []byte) []*User {
	var users []*User
	json.Unmarshal(data, &users)
	return users
}

func Worker(jobs chan int) {
	for {
		j := <-jobs
		fmt.Println(j)
	}
}
gpt-5.6-luna (codex CLI · 에이전트 하네스) · 실행일 2026-09-24

Go 코드베이스 리뷰 결과

검토 대상은 질문에 포함된 package user 코드입니다. 워크스페이스에 별도 파일을 확인하거나 실행할 수 있는 터미널 도구가 노출되지 않아 go test, go vet, -race, govulncheck 등은 실제 실행하지 못했습니다. 아래 결과는 제공된 코드의 정적·수동 분석입니다.

총평

현재 상태로는 프로덕션 배포가 불가능합니다. 특히 Store의 맵이 초기화되지 않았고 mutex도 사용되지 않아, 단일 스레드에서도 Add가 즉시 panic을 일으킵니다. 동시 실행 시에는 concurrent map access, 데이터 레이스, 사용자 객체의 동시 수정이 발생할 수 있습니다.

또한 nil 포인터, 타입 assertion, JSON 파싱 오류, goroutine 종료 및 취소 처리가 모두 빠져 있습니다. 가장 위험한 문제는 저장소 API가 내부 포인터를 그대로 노출하고 있다는 점입니다. 호출자가 반환된 *User를 수정할 수 있어 mutex를 추가하더라도 레이스와 데이터 무결성 문제가 남습니다.

위험도 요약

  • 전체 위험도: Critical
  • 발견 이슈: Critical 3건, High 7건, Medium 5건
  • 코드 건강도: 2/10
  • 보안 점수: 4/10
  • 동시성 안전성: 0/10
  • 유지보수성: 3/10
  • 테스트 커버리지: 확인 불가 — 테스트 코드가 제공되지 않음

[CRITICAL] 초기화되지 않은 map에 쓰기

Category: Nil 처리, 동시성
File: user.go
Line: 23-25

func (s *Store) Add(id string, u *User) {
	s.users[id] = u
}

Impact: NewStore() 직후 Add를 호출하면 assignment to entry in nil map panic이 발생합니다.

store := NewStore()
store.Add("u1", &User{Name: "Kim"}) // panic

Recommendation:

func NewStore() *Store {
	return &Store{
		users: make(map[string]*User),
	}
}

단, map 초기화만으로는 동시성 문제를 해결하지 못하므로 mutex도 반드시 사용해야 합니다.


[CRITICAL] mutex가 전혀 사용되지 않아 데이터 레이스 발생

Category: 동시성
File: user.go
Line: 8-29

type Store struct {
	mu    sync.Mutex
	users map[string]*User
}

func (s *Store) Add(id string, u *User) {
	s.users[id] = u
}

func (s *Store) Get(id string) *User {
	return s.users[id]
}

Impact:

  • Add와 Get 동시 실행 시 data race
  • 동시 map 읽기/쓰기 시 fatal error: concurrent map read and map write
  • 여러 Add 동시 실행 시 map 내부 손상 또는 panic

Recommendation:

type Store struct {
	mu    sync.RWMutex
	users map[string]*User
}

func (s *Store) Add(id string, u *User) error {
	if s == nil {
		return errors.New("nil store")
	}
	if id == "" {
		return errors.New("empty user id")
	}
	if u == nil {
		return errors.New("nil user")
	}

	s.mu.Lock()
	defer s.mu.Unlock()

	s.users[id] = cloneUser(u)
	return nil
}

func (s *Store) Get(id string) (*User, bool) {
	if s == nil {
		return nil, false
	}

	s.mu.RLock()
	defer s.mu.RUnlock()

	u, ok := s.users[id]
	if !ok {
		return nil, false
	}
	return cloneUser(u), true
}

[CRITICAL] UpdateAge의 nil 포인터 역참조와 비원자적 갱신

Category: Nil 처리, 동시성, 에러 처리
File: user.go
Line: 31-35

func (s *Store) UpdateAge(id string, age int) error {
	u := s.Get(id)
	u.Age = age
	return nil
}

Impact:

  • 존재하지 않는 ID면 u == nil이 되어 panic
  • s == nil이면 Get 호출 자체가 panic
  • 다른 goroutine의 Get 또는 UpdateAge와 동시에 실행하면 race
  • 음수 또는 비현실적인 나이를 허용
  • 항상 nil을 반환하므로 실패 여부를 호출자가 알 수 없음

Recommendation:

var (
	ErrUserNotFound = errors.New("user not found")
	ErrInvalidAge   = errors.New("invalid age")
)

func (s *Store) UpdateAge(id string, age int) error {
	if s == nil {
		return errors.New("nil store")
	}
	if age < 0 || age > 150 {
		return ErrInvalidAge
	}

	s.mu.Lock()
	defer s.mu.Unlock()

	u, ok := s.users[id]
	if !ok || u == nil {
		return fmt.Errorf("%w: %s", ErrUserNotFound, id)
	}

	u.Age = age
	return nil
}

ID를 오류 메시지에 포함할 때 민감정보가 될 수 있는 시스템이라면 내부 식별자를 그대로 노출하지 않는 편이 안전합니다.


[HIGH] 내부 *User 포인터 노출

Category: 동시성, 데이터 무결성
File: user.go
Line: 27-29

func (s *Store) Get(id string) *User {
	return s.users[id]
}

Impact:

u := store.Get("u1")
u.Age = 999

호출자가 저장소 내부 객체를 직접 변경할 수 있습니다. mutex로 Get을 보호해도 반환 이후의 수정은 보호되지 않으므로 race가 계속 발생합니다.

Recommendation:

  • Get에서 복사본 반환
  • 또는 User를 불변 객체로 설계
  • 또는 변경을 전용 메서드로 제한
func cloneUser(u *User) *User {
	if u == nil {
		return nil
	}
	copy := *u
	return &copy
}

meta가 map이라면 shallow copy만으로 부족하며 map도 복제해야 합니다.


[HIGH] 안전하지 않은 type assertion

Category: 타입 안전성, nil 처리
File: user.go
Line: 37-40

func ParseMeta(u *User) string {
	m := u.meta.(map[string]string)
	return m["role"]
}

Impact:

  • u == nil이면 panic
  • meta == nil이면 panic
  • 실제 타입이 다르면 panic
  • JSON으로 map[string]interface{}가 들어오면 항상 panic
  • "role"이 없는 경우 빈 문자열과 미설정 상태 구분 불가

Recommendation:

var ErrInvalidMeta = errors.New("invalid user metadata")

func ParseMeta(u *User) (string, error) {
	if u == nil {
		return "", errors.New("nil user")
	}

	m, ok := u.meta.(map[string]string)
	if !ok || m == nil {
		return "", ErrInvalidMeta
	}

	role, ok := m["role"]
	if !ok || role == "" {
		return "", errors.New("role not found")
	}

	return role, nil
}

더 좋은 해결책은 interface{}를 제거하는 것입니다.

type UserMeta struct {
	Role string `json:"role"`
}

type User struct {
	Name string   `json:"name"`
	Age  int      `json:"age"`
	Meta UserMeta `json:"meta"`
}

[HIGH] JSON 파싱 오류 무시

Category: 에러 처리, 입력 검증
File: user.go
Line: 42-46

func LoadUsers(data []byte) []*User {
	var users []*User
	json.Unmarshal(data, &users)
	return users
}

Impact:

  • 잘못된 JSON을 정상 처리한 것처럼 보임
  • 호출자는 파싱 실패와 빈 배열을 구분할 수 없음
  • malformed input이 조용히 시스템에 유입될 수 있음
  • null 요소가 포함된 JSON이면 []*User에 nil 원소가 들어올 수 있음

Recommendation:

func LoadUsers(data []byte) ([]*User, error) {
	if len(data) == 0 {
		return nil, errors.New("empty user data")
	}

	var users []*User
	if err := json.Unmarshal(data, &users); err != nil {
		return nil, fmt.Errorf("decode users: %w", err)
	}

	for i, u := range users {
		if u == nil {
			return nil, fmt.Errorf("users[%d]: nil user", i)
		}
		if u.Name == "" {
			return nil, fmt.Errorf("users[%d]: empty name", i)
		}
		if u.Age < 0 || u.Age > 150 {
			return nil, fmt.Errorf("users[%d]: invalid age", i)
		}
	}

	return users, nil
}

외부 요청에서 직접 읽는 데이터라면 호출부에서 io.LimitReader 또는 http.MaxBytesReader로 크기도 제한해야 합니다.


[HIGH] Worker가 영원히 종료되지 않으며 nil channel에서 영구 블로킹

Category: 동시성, 리소스 관리
File: user.go
Line: 48-53

func Worker(jobs chan int) {
	for {
		j := <-jobs
		fmt.Println(j)
	}
}

Impact:

  • jobs == nil이면 receive가 영원히 block
  • channel을 닫아도 j := <-jobs는 계속 0을 반환하며 무한 루프
  • 종료 신호, context, WaitGroup, 에러 전달이 없음
  • goroutine leak 발생 가능
  • 호출자가 channel을 닫으면 종료된다는 잘못된 기대를 할 수 있음

Recommendation:

func Worker(ctx context.Context, jobs <-chan int) error {
	if ctx == nil {
		return errors.New("nil context")
	}
	if jobs == nil {
		return errors.New("nil jobs channel")
	}

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()

		case j, ok := <-jobs:
			if !ok {
				return nil
			}
			fmt.Println(j)
		}
	}
}

호출부:

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

go func() {
	if err := Worker(ctx, jobs); err != nil && !errors.Is(err, context.Canceled) {
		log.Printf("worker stopped: %v", err)
	}
}()

[HIGH] Worker의 panic 및 출력 오류 처리 부재

Category: 안정성, 운영성
File: user.go
Line: 50-51

fmt.Println은 일반적으로 오류를 반환하지 않지만, 현재 worker에는 작업 실패를 보고할 통로가 전혀 없습니다. 실제 업무 로직이 추가될 경우 fire-and-forget goroutine이 되어 실패가 유실될 가능성이 높습니다.

권장 사항:

  • worker가 error를 반환하도록 설계
  • errgroup.Group 또는 오류 채널 사용
  • 필요한 경우 최상위 goroutine 경계에서 panic 복구
  • 표준 출력 대신 주입 가능한 logger 사용

[MEDIUM] NewStore가 유효한 zero value를 보장하지 않음

Category: API 설계, nil 처리
File: user.go
Line: 19-21

func NewStore() *Store {
	return &Store{}
}

현재 Store{}와 NewStore() 모두 사용할 수 없습니다. 다음 중 하나를 선택해야 합니다.

  1. 생성자를 반드시 사용하도록 문서화하고 map 초기화
  2. zero value도 동작하도록 모든 쓰기 시 lazy initialization
  3. 두 방식을 모두 지원

일반적으로 생성자 초기화가 가장 명확합니다.


[MEDIUM] Add가 입력값 검증 및 중복 정책을 정의하지 않음

Category: API 설계, 데이터 무결성
File: user.go
Line: 23-25

현재 다음 상태가 모두 허용됩니다.

  • 빈 ID
  • nil User
  • 빈 이름
  • 음수 나이
  • 동일 ID 덮어쓰기

Add는 최소한 error를 반환하고 정책을 명시해야 합니다.

var ErrUserExists = errors.New("user already exists")

중복 시 덮어쓸지, 오류를 반환할지 결정해야 합니다.


[MEDIUM] User의 JSON 모델이 불명확함

Category: 직렬화, API 설계
File: user.go
Line: 13-17

type User struct {
	Name string
	Age  int
	meta interface{}
}

문제점:

  • Name, Age의 JSON 키가 기본적으로 "Name", "Age"가 됨
  • meta는 비공개 필드라 JSON에서 무시됨
  • meta의 타입이 정의되지 않아 역직렬화 계약이 없음
  • 검증 규칙이 없음

권장:

type User struct {
	Name string            `json:"name"`
	Age  int               `json:"age"`
	Meta map[string]string `json:"meta,omitempty"`
}

[MEDIUM] map 조회에서 존재 여부를 구분하지 않음

Category: 타입 안전성, API 설계
File: user.go
Line: 27-29, 39

return s.users[id]

존재하지 않는 사용자와 값이 nil인 사용자를 구분할 수 없습니다. Get(id) (*User, bool) 형태가 적절합니다.

ParseMeta 역시 "role"이 없는 경우를 명확히 처리해야 합니다.


[LOW] interface{} 사용

Category: 타입 안전성
File: user.go
Line: 16

meta interface{}

이 코드는 현재 코드베이스에서 확인되는 유일한 interface{} 사용입니다. 런타임 타입 assertion을 강제하므로 가능한 경우 구체 타입으로 교체하는 것이 좋습니다.

확인된 범위에서는 다음 항목은 발견되지 않았습니다.

  • unsafe.Pointer
  • reflect
  • 제네릭
  • 숫자형 overflow 변환
  • panic() 직접 호출
  • os.Exit 또는 log.Fatal
  • SQL/명령어/경로 조작
  • TLS 비활성화
  • 하드코딩된 비밀값
  • HTTP 서버 및 DB 코드

동시성 분석

현재 동시성 관련 결함은 다음과 같습니다.

위치 문제 결과
Store.users mutex 미사용 data race, concurrent map panic
Get 내부 포인터 반환 외부에서 보호되지 않은 수정 가능
UpdateAge 조회와 수정이 분리됨 race 및 TOCTOU
Worker 종료 조건 없음 goroutine leak
Worker nil channel 영구 block
Worker 닫힌 channel 처리 없음 무한히 0 수신
User.meta 동시 map 접근 가능 race 또는 map panic

최소한 다음 테스트를 반드시 추가해야 합니다.

go test -race ./...

그리고 다음 시나리오를 테스트해야 합니다.

  • 여러 goroutine의 동시 Add
  • 여러 goroutine의 동시 Get
  • 동시 UpdateAge
  • 존재하지 않는 ID 업데이트
  • nil User 입력
  • nil Store receiver
  • worker context 취소
  • jobs channel 정상 종료
  • 닫힌 channel 이후 추가 송신 방지

권장 구현 형태

핵심 구조는 다음과 같이 바꾸는 것이 안전합니다.

package user

import (
	"context"
	"errors"
	"fmt"
	"sync"
)

var (
	ErrUserNotFound = errors.New("user not found")
	ErrInvalidUser  = errors.New("invalid user")
	ErrInvalidAge   = errors.New("invalid age")
)

type Store struct {
	mu    sync.RWMutex
	users map[string]*User
}

type User struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func NewStore() *Store {
	return &Store{
		users: make(map[string]*User),
	}
}

func (s *Store) Add(id string, u *User) error {
	if s == nil {
		return errors.New("nil store")
	}
	if id == "" || u == nil || u.Name == "" {
		return ErrInvalidUser
	}
	if u.Age < 0 || u.Age > 150 {
		return ErrInvalidAge
	}

	s.mu.Lock()
	defer s.mu.Unlock()

	s.users[id] = cloneUser(u)
	return nil
}

func (s *Store) Get(id string) (*User, bool) {
	if s == nil {
		return nil, false
	}

	s.mu.RLock()
	defer s.mu.RUnlock()

	u, ok := s.users[id]
	if !ok {
		return nil, false
	}
	return cloneUser(u), true
}

func (s *Store) UpdateAge(id string, age int) error {
	if s == nil {
		return errors.New("nil store")
	}
	if age < 0 || age > 150 {
		return ErrInvalidAge
	}

	s.mu.Lock()
	defer s.mu.Unlock()

	u, ok := s.users[id]
	if !ok {
		return fmt.Errorf("%w: %s", ErrUserNotFound, id)
	}

	u.Age = age
	return nil
}

func cloneUser(u *User) *User {
	if u == nil {
		return nil
	}
	v := *u
	return &v
}

func Worker(ctx context.Context, jobs <-chan int) error {
	if ctx == nil {
		return errors.New("nil context")
	}
	if jobs == nil {
		return errors.New("nil jobs channel")
	}

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case j, ok := <-jobs:
			if !ok {
				return nil
			}
			fmt.Println(j)
		}
	}
}

상위 10개 우선 조치

  1. NewStore에서 users map 초기화
  2. 모든 map 접근에 sync.RWMutex 적용
  3. Get이 내부 *User를 직접 반환하지 않도록 수정
  4. UpdateAge에서 사용자 존재 여부와 nil 검증
  5. UpdateAge의 읽기·수정을 하나의 lock 구간으로 통합
  6. LoadUsers가 JSON 오류를 반환하도록 변경
  7. ParseMeta의 unsafe assertion 제거 또는 comma-ok 적용
  8. Worker에 context.Context와 channel 종료 처리를 추가
  9. Add/Get API에 입력 검증과 not-found/duplicate 정책 추가
  10. go test -race ./... 및 동시성 회귀 테스트 추가

단계별 실행 계획

1단계 — 즉시 수정:

  • map 초기화
  • mutex 적용
  • nil 검사
  • JSON 오류 반환
  • worker 종료 조건 추가

2단계 — 이번 배포 주기:

  • 내부 포인터 복사 반환
  • interface{} 제거
  • 사용자 입력 검증
  • sentinel error 및 %w 적용
  • race detector 테스트 작성

3단계 — 후속 개선:

  • 구조화된 로깅 도입
  • fuzz test로 JSON 파싱 검증
  • API 문서와 zero-value 정책 명시
  • go vet, staticcheck, gosec, govulncheck CI 통합

현재 코드 기준 예상 수정 규모는 약 12일이며, 동시성 테스트와 API 호환성 검증까지 포함하면 24일 정도가 적절합니다.

같은 분류의 프롬프트

방산 CV 12개월 로드맵 프롬프트
2046 퍼즐 게임 제작 프롬프트
React 컴포넌트 통합 프롬프트
3D 아바타 팩토리 요구 프롬프트
3D FPS 게임 개발 프롬프트