피드로 돌아가기
뱅크샐러드 Go 코딩 컨벤션
뱅크샐러드 기술블로그뱅크샐러드 기술블로그
Backend

뱅크샐러드 Go 코딩 컨벤션

뱅크샐러드가 4년간의 Go 프로젝트 경험으로 panic 금지, 에러 스택 추적, goroutine 안전성 확보 등 12가지 코딩 컨벤션 정의

2023년 9월 6일15intermediate

Context

조직 규모가 커지고 구성원이 변할수록 여러 코드베이스의 개념적 일관성을 유지하기 어려워진다. 뱅크샐러드는 4년간 Go와 gRPC를 활용하며 다양한 실수와 시행착오를 겪으면서 조직 전체에 적용할 명확한 코딩 컨벤션의 필요성을 느꼈다.

Technical Solution

  • Panic 사용 금지: 프로덕션 런타임 중 panic과 fatal을 발생시키지 않으며, 이들은 초기화 시점에서만 빠른 실패 목적으로 사용
  • Recovery 체인 구성: 서버 인터셉터 또는 미들웨어에 recovery 체인을 추가하여 의도치 않은 panic에 대비
  • Goroutine 안전성: PanicSafeGroup 구조체를 구현해 goroutine 내부의 panic을 감지하고 다중 에러를 수집하는 방식으로 panic safe 보장
  • 에러 스택 추적: pkg/errors 패키지를 사용하여 errors.WithStack(err)으로 스택 트레이스를 가장 안쪽에서 한 번만 추가
  • Sentinel 에러 선언: 다른 곳에서 분기처리되어 특별한 대응이 필요한 경우에만 sentinel 에러를 선언하고, 나머지는 errors.Wrap() 또는 errors.WithStack() 사용
  • 에러 네이밍: "failed to", "cannot" 같은 문구를 제외하고 마침표 없는 소문자로 작성
  • HTTP 클라이언트 설정: 외부 서드파티 API 호출 시 MaxIdleConnsPerHost를 기본값 2에서 조정하고, MaxIdleConns를 100으로 설정하여 keep-alive 커넥션 재사용
  • Named return 금지: 함수 반환 시 named return을 사용하지 않아 반환값이 언제 어느 값으로 설정되는지 추적 가능하게 유지
  • 함수 인자 순서: context.Context를 맨 앞에 배치하고, 이후 의존성(db client, service client) → 무거운 인자(slice, map) → 가벼운 인자(string, time.Time) 순으로 정렬
  • 단수형/복수형 메서드 네이밍: 단일 값은 get, 여러 값은 listXxxs로 네이밍하여 반환 형태를 명확히 구분
  • 모호한 단어 제거: information, details, summary 대신 구체적인 이름(예: user information → user) 사용
  • 패키지 네이밍: core, util, helper, common, infra 같은 모호한 이름을 피하고 parser, timeconv, testutil 같은 구체적인 기능명 사용
  • 프로젝트 구조 최소화: client, cmd, config, server 폴더만 필수적으로 유지하여 shallow한 구조 지향

Key Takeaway

Go 프로젝트에서 golangci-lint 같은 린트 도구와 함께 panic 금지, 에러 스택 추적, goroutine 안전성 같은 명시적 규칙을 정의하고 코드 리뷰로 강제하면 조직 전체의 개념적 일관성을 유지할 수 있다.


프로덕션 서비스를 Go로 운영하는 팀에서 서버 미들웨어에 recovery 체인을 추가하고 PanicSafeGroup 패턴으로 goroutine 내부의 panic을 포착하면 의도치 않은 프로세스 종료를 방지할 수 있다. 또한 pkg/errors 패키지로 에러 스택을 가장 안쪽에서만 한 번 추가하고 에러 로깅 시점을 인터셉터로 통일하면 디버깅 효율을 크게 높일 수 있다.

원문 읽기