Source profileQuality 72/100Review permissions

affaan-m/ECC/docs/ko-KR/skills/golang-patterns/SKILL.md

golang-patterns

Review golang-patterns's use cases, installation, workflow, and original source instructions.

Source repository stars
234,327
Declared platforms
0
Static risk flags
3
Last source update
2026-07-27
Source checked
2026-07-28

Decision brief

What it does—and where it fits

견고하고 효율적이며 유지보수 가능한 애플리케이션 구축을 위한 관용적 Go 패턴과 모범 사례.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/affaan-m/ECC --skill "docs/ko-KR/skills/golang-patterns"
    Safe inspection promptEditorial

    Inspect the Agent Skill "golang-patterns" from https://github.com/affaan-m/ECC/blob/4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38/docs/ko-KR/skills/golang-patterns/SKILL.md at commit 4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      활성화 시점

      새로운 Go 코드 작성 시

      새로운 Go 코드 작성 시Go 코드 리뷰 시기존 Go 코드 리팩토링 시
    2. 02

      핵심 원칙

      Go는 영리함보다 단순성을 선호합니다. 코드는 명확하고 읽기 쉬워야 합니다.

      Go는 영리함보다 단순성을 선호합니다. 코드는 명확하고 읽기 쉬워야 합니다.제로 값이 초기화 없이 즉시 사용 가능하도록 타입을 설계하세요.함수는 인터페이스 매개변수를 받고 구체적 타입을 반환해야 합니다.
    3. 03

      1. 단순성과 명확성

      Go는 영리함보다 단순성을 선호합니다. 코드는 명확하고 읽기 쉬워야 합니다.

      Go는 영리함보다 단순성을 선호합니다. 코드는 명확하고 읽기 쉬워야 합니다.
    4. 04

      2. 제로 값을 유용하게 만들기

      제로 값이 초기화 없이 즉시 사용 가능하도록 타입을 설계하세요.

      제로 값이 초기화 없이 즉시 사용 가능하도록 타입을 설계하세요.
    5. 05

      3. 인터페이스를 받고 구조체를 반환하기

      함수는 인터페이스 매개변수를 받고 구체적 타입을 반환해야 합니다.

      함수는 인터페이스 매개변수를 받고 구체적 타입을 반환해야 합니다.

    Permission review

    Static risk signals and limitations

    Reads files

    low · line 94

    The documentation asks the agent to read local files, directories, or repositories.

    data, err := os.ReadFile(path)

    Network access

    medium · line 205

    The documentation includes network, browsing, or remote request actions.

    return nil, fmt.Errorf("fetch %s: %w", url, err)

    Network access

    medium · line 269

    The documentation includes network, browsing, or remote request actions.

    data, _ := fetch(url)

    Runs scripts

    medium · line 571

    The documentation asks the agent to run terminal commands or scripts.

    go build ./...

    Runs scripts

    medium · line 572

    The documentation asks the agent to run terminal commands or scripts.

    go run ./cmd/myapp

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score72/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars234,327SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    affaan-m/ECC
    Skill path
    docs/ko-KR/skills/golang-patterns/SKILL.md
    Commit
    4e973d3eaf92d97f8d2e2d8abb39d8bdc8711b38
    License
    MIT
    Collected
    2026-07-28
    Default branch
    main
    View the original SKILL.md

    Go 개발 패턴

    견고하고 효율적이며 유지보수 가능한 애플리케이션 구축을 위한 관용적 Go 패턴과 모범 사례.

    활성화 시점

    • 새로운 Go 코드 작성 시
    • Go 코드 리뷰 시
    • 기존 Go 코드 리팩토링 시
    • Go 패키지/모듈 설계 시

    핵심 원칙

    1. 단순성과 명확성

    Go는 영리함보다 단순성을 선호합니다. 코드는 명확하고 읽기 쉬워야 합니다.

    // Good: Clear and direct
    func GetUser(id string) (*User, error) {
        user, err := db.FindUser(id)
        if err != nil {
            return nil, fmt.Errorf("get user %s: %w", id, err)
        }
        return user, nil
    }
    
    // Bad: Overly clever
    func GetUser(id string) (*User, error) {
        return func() (*User, error) {
            if u, e := db.FindUser(id); e == nil {
                return u, nil
            } else {
                return nil, e
            }
        }()
    }
    

    2. 제로 값을 유용하게 만들기

    제로 값이 초기화 없이 즉시 사용 가능하도록 타입을 설계하세요.

    // Good: Zero value is useful
    type Counter struct {
        mu    sync.Mutex
        count int // zero value is 0, ready to use
    }
    
    func (c *Counter) Inc() {
        c.mu.Lock()
        c.count++
        c.mu.Unlock()
    }
    
    // Good: bytes.Buffer works with zero value
    var buf bytes.Buffer
    buf.WriteString("hello")
    
    // Bad: Requires initialization
    type BadCounter struct {
        counts map[string]int // nil map will panic
    }
    

    3. 인터페이스를 받고 구조체를 반환하기

    함수는 인터페이스 매개변수를 받고 구체적 타입을 반환해야 합니다.

    // Good: Accepts interface, returns concrete type
    func ProcessData(r io.Reader) (*Result, error) {
        data, err := io.ReadAll(r)
        if err != nil {
            return nil, err
        }
        return &Result{Data: data}, nil
    }
    
    // Bad: Returns interface (hides implementation details unnecessarily)
    func ProcessData(r io.Reader) (io.Reader, error) {
        // ...
    }
    

    에러 처리 패턴

    컨텍스트가 있는 에러 래핑

    // Good: Wrap errors with context
    func LoadConfig(path string) (*Config, error) {
        data, err := os.ReadFile(path)
        if err != nil {
            return nil, fmt.Errorf("load config %s: %w", path, err)
        }
    
        var cfg Config
        if err := json.Unmarshal(data, &cfg); err != nil {
            return nil, fmt.Errorf("parse config %s: %w", path, err)
        }
    
        return &cfg, nil
    }
    

    커스텀 에러 타입

    // Define domain-specific errors
    type ValidationError struct {
        Field   string
        Message string
    }
    
    func (e *ValidationError) Error() string {
        return fmt.Sprintf("validation failed on %s: %s", e.Field, e.Message)
    }
    
    // Sentinel errors for common cases
    var (
        ErrNotFound     = errors.New("resource not found")
        ErrUnauthorized = errors.New("unauthorized")
        ErrInvalidInput = errors.New("invalid input")
    )
    

    errors.Is와 errors.As를 사용한 에러 확인

    func HandleError(err error) {
        // Check for specific error
        if errors.Is(err, sql.ErrNoRows) {
            log.Println("No records found")
            return
        }
    
        // Check for error type
        var validationErr *ValidationError
        if errors.As(err, &validationErr) {
            log.Printf("Validation error on field %s: %s",
                validationErr.Field, validationErr.Message)
            return
        }
    
        // Unknown error
        log.Printf("Unexpected error: %v", err)
    }
    

    에러를 절대 무시하지 말 것

    // Bad: Ignoring error with blank identifier
    result, _ := doSomething()
    
    // Good: Handle or explicitly document why it's safe to ignore
    result, err := doSomething()
    if err != nil {
        return err
    }
    
    // Acceptable: When error truly doesn't matter (rare)
    _ = writer.Close() // Best-effort cleanup, error logged elsewhere
    

    동시성 패턴

    워커 풀

    func WorkerPool(jobs <-chan Job, results chan<- Result, numWorkers int) {
        var wg sync.WaitGroup
    
        for i := 0; i < numWorkers; i++ {
            wg.Add(1)
            go func() {
                defer wg.Done()
                for job := range jobs {
                    results <- process(job)
                }
            }()
        }
    
        wg.Wait()
        close(results)
    }
    

    취소 및 타임아웃을 위한 Context

    func FetchWithTimeout(ctx context.Context, url string) ([]byte, error) {
        ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
        defer cancel()
    
        req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
        if err != nil {
            return nil, fmt.Errorf("create request: %w", err)
        }
    
        resp, err := http.DefaultClient.Do(req)
        if err != nil {
            return nil, fmt.Errorf("fetch %s: %w", url, err)
        }
        defer resp.Body.Close()
    
        return io.ReadAll(resp.Body)
    }
    

    우아한 종료

    func GracefulShutdown(server *http.Server) {
        quit := make(chan os.Signal, 1)
        signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    
        <-quit
        log.Println("Shutting down server...")
    
        ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
        defer cancel()
    
        if err := server.Shutdown(ctx); err != nil {
            log.Fatalf("Server forced to shutdown: %v", err)
        }
    
        log.Println("Server exited")
    }
    

    조율된 고루틴을 위한 errgroup

    import "golang.org/x/sync/errgroup"
    
    func FetchAll(ctx context.Context, urls []string) ([][]byte, error) {
        g, ctx := errgroup.WithContext(ctx)
        results := make([][]byte, len(urls))
    
        for i, url := range urls {
            i, url := i, url // Capture loop variables
            g.Go(func() error {
                data, err := FetchWithTimeout(ctx, url)
                if err != nil {
                    return err
                }
                results[i] = data
                return nil
            })
        }
    
        if err := g.Wait(); err != nil {
            return nil, err
        }
        return results, nil
    }
    

    고루틴 누수 방지

    // Bad: Goroutine leak if context is cancelled
    func leakyFetch(ctx context.Context, url string) <-chan []byte {
        ch := make(chan []byte)
        go func() {
            data, _ := fetch(url)
            ch <- data // Blocks forever if no receiver
        }()
        return ch
    }
    
    // Good: Properly handles cancellation
    func safeFetch(ctx context.Context, url string) <-chan []byte {
        ch := make(chan []byte, 1) // Buffered channel
        go func() {
            data, err := fetch(url)
            if err != nil {
                return
            }
            select {
            case ch <- data:
            case <-ctx.Done():
            }
        }()
        return ch
    }
    

    인터페이스 설계

    작고 집중된 인터페이스

    // Good: Single-method interfaces
    type Reader interface {
        Read(p []byte) (n int, err error)
    }
    
    type Writer interface {
        Write(p []byte) (n int, err error)
    }
    
    type Closer interface {
        Close() error
    }
    
    // Compose interfaces as needed
    type ReadWriteCloser interface {
        Reader
        Writer
        Closer
    }
    

    사용되는 곳에서 인터페이스 정의

    // In the consumer package, not the provider
    package service
    
    // UserStore defines what this service needs
    type UserStore interface {
        GetUser(id string) (*User, error)
        SaveUser(user *User) error
    }
    
    type Service struct {
        store UserStore
    }
    
    // Concrete implementation can be in another package
    // It doesn't need to know about this interface
    

    타입 어서션을 통한 선택적 동작

    type Flusher interface {
        Flush() error
    }
    
    func WriteAndFlush(w io.Writer, data []byte) error {
        if _, err := w.Write(data); err != nil {
            return err
        }
    
        // Flush if supported
        if f, ok := w.(Flusher); ok {
            return f.Flush()
        }
        return nil
    }
    

    패키지 구성

    표준 프로젝트 레이아웃

    myproject/
    ├── cmd/
    │   └── myapp/
    │       └── main.go           # Entry point
    ├── internal/
    │   ├── handler/              # HTTP handlers
    │   ├── service/              # Business logic
    │   ├── repository/           # Data access
    │   └── config/               # Configuration
    ├── pkg/
    │   └── client/               # Public API client
    ├── api/
    │   └── v1/                   # API definitions (proto, OpenAPI)
    ├── testdata/                 # Test fixtures
    ├── go.mod
    ├── go.sum
    └── Makefile
    

    패키지 명명

    // Good: Short, lowercase, no underscores
    package http
    package json
    package user
    
    // Bad: Verbose, mixed case, or redundant
    package httpHandler
    package json_parser
    package userService // Redundant 'Service' suffix
    

    패키지 수준 상태 피하기

    // Bad: Global mutable state
    var db *sql.DB
    
    func init() {
        db, _ = sql.Open("postgres", os.Getenv("DATABASE_URL"))
    }
    
    // Good: Dependency injection
    type Server struct {
        db *sql.DB
    }
    
    func NewServer(db *sql.DB) *Server {
        return &Server{db: db}
    }
    

    구조체 설계

    함수형 옵션 패턴

    type Server struct {
        addr    string
        timeout time.Duration
        logger  *log.Logger
    }
    
    type Option func(*Server)
    
    func WithTimeout(d time.Duration) Option {
        return func(s *Server) {
            s.timeout = d
        }
    }
    
    func WithLogger(l *log.Logger) Option {
        return func(s *Server) {
            s.logger = l
        }
    }
    
    func NewServer(addr string, opts ...Option) *Server {
        s := &Server{
            addr:    addr,
            timeout: 30 * time.Second, // default
            logger:  log.Default(),    // default
        }
        for _, opt := range opts {
            opt(s)
        }
        return s
    }
    
    // Usage
    server := NewServer(":8080",
        WithTimeout(60*time.Second),
        WithLogger(customLogger),
    )
    

    합성을 위한 임베딩

    type Logger struct {
        prefix string
    }
    
    func (l *Logger) Log(msg string) {
        fmt.Printf("[%s] %s\n", l.prefix, msg)
    }
    
    type Server struct {
        *Logger // Embedding - Server gets Log method
        addr    string
    }
    
    func NewServer(addr string) *Server {
        return &Server{
            Logger: &Logger{prefix: "SERVER"},
            addr:   addr,
        }
    }
    
    // Usage
    s := NewServer(":8080")
    s.Log("Starting...") // Calls embedded Logger.Log
    

    메모리 및 성능

    크기를 알 때 슬라이스 미리 할당

    // Bad: Grows slice multiple times
    func processItems(items []Item) []Result {
        var results []Result
        for _, item := range items {
            results = append(results, process(item))
        }
        return results
    }
    
    // Good: Single allocation
    func processItems(items []Item) []Result {
        results := make([]Result, 0, len(items))
        for _, item := range items {
            results = append(results, process(item))
        }
        return results
    }
    

    빈번한 할당에 sync.Pool 사용

    var bufferPool = sync.Pool{
        New: func() interface{} {
            return new(bytes.Buffer)
        },
    }
    
    func ProcessRequest(data []byte) []byte {
        buf := bufferPool.Get().(*bytes.Buffer)
        defer func() {
            buf.Reset()
            bufferPool.Put(buf)
        }()
    
        buf.Write(data)
        // Process...
        out := append([]byte(nil), buf.Bytes()...)
        return out
    }
    

    루프에서 문자열 연결 피하기

    // Bad: Creates many string allocations
    func join(parts []string) string {
        var result string
        for _, p := range parts {
            result += p + ","
        }
        return result
    }
    
    // Good: Single allocation with strings.Builder
    func join(parts []string) string {
        var sb strings.Builder
        for i, p := range parts {
            if i > 0 {
                sb.WriteString(",")
            }
            sb.WriteString(p)
        }
        return sb.String()
    }
    
    // Best: Use standard library
    func join(parts []string) string {
        return strings.Join(parts, ",")
    }
    

    Go 도구 통합

    필수 명령어

    # Build and run
    go build ./...
    go run ./cmd/myapp
    
    # Testing
    go test ./...
    go test -race ./...
    go test -cover ./...
    
    # Static analysis
    go vet ./...
    staticcheck ./...
    golangci-lint run
    
    # Module management
    go mod tidy
    go mod verify
    
    # Formatting
    gofmt -w .
    goimports -w .
    

    권장 린터 구성 (.golangci.yml)

    linters:
      enable:
        - errcheck
        - gosimple
        - govet
        - ineffassign
        - staticcheck
        - unused
        - gofmt
        - goimports
        - misspell
        - unconvert
        - unparam
    
    linters-settings:
      errcheck:
        check-type-assertions: true
      govet:
        enable:
          - shadow
    
    issues:
      exclude-use-default: false
    

    빠른 참조: Go 관용구

    관용구설명
    Accept interfaces, return structs함수는 인터페이스 매개변수를 받고 구체적 타입을 반환
    Errors are values에러를 예외가 아닌 일급 값으로 취급
    Don't communicate by sharing memory고루틴 간 조율에 채널 사용
    Make the zero value useful타입이 명시적 초기화 없이 작동해야 함
    A little copying is better than a little dependency불필요한 외부 의존성 피하기
    Clear is better than clever영리함보다 가독성 우선
    gofmt is no one's favorite but everyone's friend항상 gofmt/goimports로 포맷팅
    Return early에러를 먼저 처리하고 정상 경로는 들여쓰기 없이 유지

    피해야 할 안티패턴

    // Bad: Naked returns in long functions
    func process() (result int, err error) {
        // ... 50 lines ...
        return // What is being returned?
    }
    
    // Bad: Using panic for control flow
    func GetUser(id string) *User {
        user, err := db.Find(id)
        if err != nil {
            panic(err) // Don't do this
        }
        return user
    }
    
    // Bad: Passing context in struct
    type Request struct {
        ctx context.Context // Context should be first param
        ID  string
    }
    
    // Good: Context as first parameter
    func ProcessRequest(ctx context.Context, id string) error {
        // ...
    }
    
    // Bad: Mixing value and pointer receivers
    type Counter struct{ n int }
    func (c Counter) Value() int { return c.n }    // Value receiver
    func (c *Counter) Increment() { c.n++ }        // Pointer receiver
    // Pick one style and be consistent
    

    기억하세요: Go 코드는 최고의 의미에서 지루해야 합니다 - 예측 가능하고, 일관적이며, 이해하기 쉽게. 의심스러울 때는 단순하게 유지하세요.

    Alternatives

    Compare before choosing