출처: https://zenn.dev/keitakn/articles/go-naming-rules

package 이름

이용해도 좋은 문자열

Effective Go 는 간결하고 명확한 이름이 바람직하다고 한다.

문자만을 이용하여 한 단어(단수)로 구성하는 것이 바람직하다.

  • 좋은 예
  • time
  • http
  • 나쁜 예
  • computeServiceClient (카멜 케이스는 사용하지 않는다)
  • priority_queue (스네이크 케이스는 사용하지 않는다)

그러나 한 가지 예외가 있다.

그것은 _test 접미사를 붙이는 패턴이다.

Go는 같은 디렉토리 아래에 여러 package 이름을 허용하지 않지만 _test을 넣으면 이것을 할 수 있다.

다른 패키지이므로 비공개 메소드 등은 볼 수 없다.

그러나 이를 이용함으로써 순환 참조 문제를 해결 할 수있는 등의 장점이 있다.

이것은 표준 package에도 이용되고 있는 기술이다.

// (예) heap package의 테스트이므로 heap_test 가 된다
package heap_test

피해야 할 단어

또한 아래와 같은 이름은 사용하지 않도록 하는 것이 좋다.

  • base
  • util
  • common
  • lib
  • misc

이들 이름은 "간단한 이름"이며, "명확한 이름'이 아니기 때문입니다.

이름이 고민되면 Go 표준 package 이름을 참고하면 좋을 것이다.

파일 이름

Go 공식 정보에서 "파일 이름을 어떻게 해야 하는가?"라는 설명은 찾을 수가 없었다.

kubernetes 과 terraform 등 유명 OSS 또는 표준 package에서 스네이크 케이스의 이름이 사용되고 있기 때문에 이것에 따르는 것이 무난 할것 같다.

(예)

  • addressed_types_test.go
  • addressed_types.go

디렉토리 이름

파일 이름과 같이 "Go 공식 정보에 어떻게해야 하는가?"라는 설명은 찾을 수가 없다.

여기에 관해서는, package 이름과 같이 간결하고 명확한 한 단어에서 이름을 붙이는 것이 좋다.

그래서 소문자만을 사용한다는 것이 올바른 것이다.

kubernetes 과 terraform 등 유명 OSS에서 케밥 케이스(단어 경계에 - 를 사용)를 사용하는 패턴을 발견했다.

아무래도 단어 구분을 원한다면 케밥 케이스를 사용하는 것도 좋을지도.

(예)

https://github.com/kubernetes/kubernetes/tree/master/cluster/log-dump 

나는 케밥 케이스를 채용하지 않고, 모두 소문자로 통일하도록 하고 있다.

참고로 package 이름과 디렉토리 이름이 다른 경우에도 문제는 아니지만 맞추는 편이 좋다.

함수, type, 구조체

카멜 케이스로 명명한다.

외부에 공개하는 함수나 구조체의 경우 첫 글자를 대문자로 하는 언어 사양이 있으므로 그에 따라 어퍼 카멜 케이스(선두 대문자로 시작) 또는 로어 카멜 케이스(선두 소문자로 시작)를 결정한다.

// package 밖에 공개하는 경우
func Contents(filename string) (string, error) {}

// package 내에서만 이용하는 경우
func contents(filename string) (string, error) {}

리시버 이름

영어 1 문자 또는 2 문자로 가능한한 짧게 명명한다.

타입이 Client 였다면 c, cl 등이다.

리시버 이름은 반드시 통일해야한다(장소에 따라 c 혹은 cl을 사용하고 있다면 NG)

또한 수식어를 사용하지 않는 점이 중요하다.

예를 들면 httpClient 라면 리시버 이름은 c로 되고, DBCreator라면 c로 된다.

변수 · 인수 이름

이쪽도 짧은 변수 이름을 권장한다.

인수에 관해서는 리시버 이름과 같은 문자를 사용하는 것이 좋다.

변수 이름을 가능한 한 짧은 이름이 이상적이라고  되어 있지만 범위에 주의한다.

범위가 큰 함수에서 짧은 변수를 사용하면 가독성이 크게 저하 될 수 있다.

또한 약자에 대해서도 주의가 필요하다.

아래와 같이 프로그래머 사이에서 인기를 끌고있는 약어를 사용하는 것은 문제가 없지만, 억지로 줄여서 버려, 의미를 모르는 변수 이름이 되면 가독성이 떨어진다.

  • Config → conf
  • String → str

개인적인 의견이지만, 만약 좋은 약어가 떠오르지 않는다면, 일반적으로 영어 단어를 사용한 변수 이름이 무난하다.

짧은 변수 이름이 권장되고 있다고해서 명명 규칙을 경시한다는 이야기는 아니기 때문에 이 부분은 주의가  필요하다.

error 변수 이름

error를 변수로 선언하는 경우 Err 라는 prefix를 붙여 선언한다.

명확하게 이렇게 하자고 기재 되어있는 것은 아니지만, Go 공식 블로그 Working with Errors in Go 1.13 에서 이 같은 변수 이름을 사용하는 예를 확인할 수 있다.

또한 Effective Go 에도 아래와 같은 내용이 있다.

// Error codes returned by failures to parse an expression.
var (
   ErrInternal      = errors.New(
"regexp: internal error")
   ErrUnmatchedLpar = errors.New(
"regexp: unmatched '('")
   ErrUnmatchedRpar = errors.New(
"regexp: unmatched ')'")
   ...
)

덧붙여서 Go의 오류 처리는 err를 확인하고 오류가 nil인지 여부를 확인하여 오류가 발생했는지 확인한다.

그러므로 아래와 같은 코드가 많이 나온다.

    data, err := ioutil.ReadFile(src)
   
if err != nil {
       
return nil, err
   }

이 때 err 이라는 변수 이름으로 받는 것이 관례이다.

Err prefix는 어디 까지나 error를 변수로 선언하는 경우 규칙이므로 위와 같은 오류 처리에 이용하지 않는다.

다음 문서에도 쓰여져 있지만, err의 범위를 if 문에 갇혀하거나 := 를 사용한 쓰는 법을 이용하면 대부분의 케이스는 err만으로 그냥 넘어갈 수 있다.

덧붙여서 kubernetes 과 terraform 등 유명 OSS는 Err  prefix를 사용하는 방법은 채택되지 않았다.

이 부분을 어떻게 해야할지 명확한 결정은 없는 것 같아서, 프로젝트마다 맞추는 것이 좋다고 생각된다.

map 등의 존재 확인

아래와 같이 특정 키가 존재하는지 여부를 체크 할 때 ok 라는 변수 이름을 사용하는 것이 관례 같다.

id, ok := users[userID]

이것은 어딘가에 명기 되어있는 것은 아니지만, 표준 package에서이 패턴을 많이 사용하고 있다.

이니셜이나 머리 글자를 딴 이름의 단어 이름 지정에 대해

아래에 기재 되어 있는 내용이다.

https://github.com/golang/go/wiki/CodeReviewComments#initialisms 

Go의 이름은 기본적으로 카멜 케이스이지만, 원래 약어로 침투하고 있는 단어는 일관된 대소 문자를 사용한다.

url대신 URL를 사용하거나, http 대신 HTTP을 사용한다는 내용이다.

개인 의견이지만,이 규칙을 이해하는 것이 어려웠다.

예를 들어, GitHub 라든지 Twitter 등의 단어도 github 라든지 twitter을 사용하면 안되는 것인지 등 여러가지 혼란스러웠다.

golangci-lint 라는 도구에서 이 표기를 확인하고 있는 부분이 있는데 커버되는 단어는 아래와 같다.

(해당란 아래 발췌).

https://github.com/morix1500/lint/blob/master/lint.go#L743 

var commonInitialisms = map[string]bool{
        
"ACL":   true,
        
"API":   true,
        
"ASCII": true,
        
"CPU":   true,
        
"CSS":   true,
        
"DNS":   true,
        
"EOF":   true,
        
"GUID":  true,
        
"HTML":  true,
        
"HTTP":  true,
        
"HTTPS": true,
        
"ID":    true,
        
"IP":    true,
        
"JSON":  true,
        
"LHS":   true,
        
"QPS":   true,
        
"RAM":   true,
        
"RHS":   true,
        
"RPC":   true,
        
"SLA":   true,
        
"SMTP":  true,
        
"SQL":   true,
        
"SSH":   true,
        
"TCP":   true,
        
"TLS":   true,
        
"TTL":   true,
        
"UDP":   true,
        
"UI":    true,
        
"UID":   true,
        
"UUID":  true,
        
"URI":   true,
        
"URL":   true,
        
"UTF8":  true,
        
"VM":    true,
        
"XML":   true,
        
"XMPP":  true,
        
"XSRF":  true,
        
"XSS":   true,
}

이러한 규칙은 golangci-lint 에서 기계적으로 체크하고 싶은데 요즘 자주 나오는 gRPC 및  GraphQL 등의 단어는 체크되지 않는 것 같다.

또한 자동으로 Go 코드를 생성하는 도구의 일부도 이 규칙을 무시한 코드를 생성 할 수 있다.

나는 golangci-lint의 이 규칙을 OFF로 하고, 보통 카멜 케이스로 명명하도록 통일하고 있다.