1. 명명 규칙 이해
명명 규칙은 소프트웨어 개발에서 매우 중요합니다. 변수, 함수 및 기타 식별자에 일관되고 설명적인 방식으로 이름을 지정하는 프레임워크 역할을 하기 때문입니다. Go(Golang으로도 불림)에서는 이미 정의된 명명 규칙을 따르면 코드를 읽고 유지보수하는 것이 더 쉬워지며, 누군가(또는 미래의 본인)가 더 적은 어려움으로 코드베이스를 이해하고 협업할 수 있습니다.
1.1. 명명의 중요성
어떤 프로그래밍 언어에서든지 식별자의 명명 방식은 코드의 이해도와 유지보수에 큰 영향을 미칩니다. 특히 간결함과 명확함을 강조하는 Go에서는 적절한 명명이 더욱 중요합니다. 변수나 함수의 목적을 명확하게 전달하는 이름은 추가적인 주석이 필요 없도록 만들어주고 코드 자체가 문서화되도록 합니다. 이는 코드베이스를 오랜 기간 유지하고 원할한 팀 협업을 위해 중요합니다.
1.2. 명명을 위한 일반 규칙
Go의 명명 규칙은 간단하면서도 강력합니다:
-
짧고 간결한 이름 사용: 작은 범위의 변수에 대해 Go는 짧은 이름을 권장합니다. 예를 들어 루프 카운터에는
i
를 사용할 수 있지만, 더 명확성이 필요하다면index
나counter
를 사용할 수 있습니다. -
다중 단어 이름에는 CamelCase 사용: 이름이 여러 단어로 이루어진 경우 CamelCase 표기법을 사용합니다. 외부에서 접근 가능해야 하는 이름(패키지 외부에서 접근 가능해야 하는 것)은 대문자로 시작해야 하며, 내부적인 이름은 소문자로 시작해야 합니다.
-
의미 있는 이름 사용: 이름은 지나치게 장황하지 않고도 목적이나 용도를 전달할 수 있을 정도로 설명적이어야 합니다. 예를 들어
CalculateNetIncome
는CNI
보다 좋은 선택입니다. -
언더스코어 피하기: Go의 규약에 따르면 언더스코어 대신
recordCount
처럼 사용합니다. -
약어는 일관성 있게 사용: 이름에 약어를 사용할 때는 일관된 표기법을 유지해야 합니다. 외부에서 접근 가능한 이름에는 모두 대문자(예:
HTTPServer
)를 사용하고, 내부적인 이름에는 모두 소문자(예:httpServer
)를 사용하는 것이 표준 관행입니다. -
패키지 이름은 간단하게: Go에서의 패키지 이름은 간단하고 소문자로만 이루어져야 하며, 언더스코어나 혼합된 대소문자를 사용해서는 안됩니다. 패키지의 목적을 명확하게 나타내는 단어 하나로 이루어져야 합니다(
net
,os
,json
). -
타입에 기반한 변수 명명: 구조체의 인스턴스를 나타내는 변수에는 일반적으로 구조체의 이름을 소문자로 사용합니다(
var user User
).
아래는 명명 선택에 대한 주석이 포함된 Go 코드의 예시입니다:
package main
import "fmt"
type User struct {
FirstName string
LastName string
Age int
}
func main() {
var currentUser User // 변수 이름으로 소문자로된 구조체 이름 사용.
currentUser.FirstName = "John"
currentUser.LastName = "Doe"
currentUser.Age = 30
fmt.Println(formatUserDetails(currentUser))
}
// formatUserDetails는 User 구조체를 입력으로 받고 포맷팅된 문자열을 반환합니다.
// 이 함수는 외부로 노출되지 않으므로 소문자로 시작하는 이름을 사용합니다.
func formatUserDetails(u User) string {
return fmt.Sprintf("Name: %s %s, Age: %d", u.FirstName, u.LastName, u.Age)
}
이러한 명명 규칙을 준수하면 Go 코드의 가독성과 유지보수성이 크게 향상됩니다.
2. Go에서의 식별자
Go를 시작하면서 식별자의 역할을 이해하는 것이 중요합니다. 식별자는 변수, 함수 및 상수와 같은 코드의 다양한 요소에 할당하는 이름입니다. 의미 있는 이름과 일관된 사용은 코드의 가독성과 유지보수성을 향상시킵니다.
2.1. 변수 명명 규칙
Go에서 변수 이름은 문자나 밑줄로 시작해야 하며, 이후에는 문자, 숫자, 밑줄을 자유롭게 조합하여 사용할 수 있습니다. 그러나 특별한 용도에 사용되는 경우를 제외하고는 밑줄로 시작하는 것은 권장되지 않습니다.
최선의 방법:
- 간결하고 설명적인 이름 사용
- 패키지 수준 스코프에는 소문자로 시작
- 다중 단어 이름에는 CamelCase 사용(예:
totalAmount
) - 외부로 노출되는 변수(패키지 외부에서 접근 가능한 변수)는 대문자로 시작
예시:
var userName string // 외부로 노출되지 않는 변수
var UserAge int // 외부로 노출되는 변수
코드의 주석을 통해 외부 노출 및 비노출 변수의 구별을 명확히 할 수 있습니다.
2.2. 함수 명명 규칙
Go 언어의 함수는 변수와 유사한 규칙을 따라 명명됩니다. 함수명은 함수의 목적을 반영해야 하며, 범위에 따라 첫 글자의 대소문자가 결정됩니다.
최적 사례:
- 함수의 목적을 반영하는 서술적인 이름을 사용합니다.
- 내부 함수에는 소문자로 시작합니다.
- 노출된 함수에는 PascalCase(대문자로 시작)를 사용합니다.
- 함수 이름을 간결하면서도 의미 있게 유지합니다.
예시:
func calculateTotal(price int, quantity int) int { // 내부 함수
return price * quantity
}
func CalculateDiscount(totalPrice int) float64 { // 노출된 함수
return totalPrice * 0.1
}
주석은 함수의 접근성을 첫 글자의 소문자 또는 대문자로 설명하며, 간단한 통찰을 제공합니다.
2.3. 상수 명명 규칙
상수는 정의된 후 변경할 수 없는 불변의 값으로, Go 언어에서는 const
키워드를 사용하여 선언하며 문자, 문자열, 부울, 또는 숫자 값일 수 있습니다.
최적 사례:
- 밑줄로 구분된 모두 대문자를 사용합니다 (예:
MAX_LIMIT
). - 열거형 상수의 경우
iota
열거자를 사용합니다. - 노출된 상수는 대문자로 시작해야 합니다.
예시:
const MAX_RETRY_COUNT int = 3 // 노출된 상수
type ByteSize float64
const (
_ = iota // 빈 식별자에 값을 할당하여 첫 번째 값은 무시합니다.
KB ByteSize = 1 << (10 * iota)
MB
GB
TB
)
이 예시는 iota
를 사용하여 간단한 상수와 관련된 상수 집합을 정의하는 방법을 보여줍니다.
3. 타입 명명 규약
이 장에서는 구조체와 인터페이스와 같은 다른 타입에 대한 명명 표준에 중점을 둡니다.
3.1. 구조체 명명 지침
개요: Go 언어의 구조체는 변수들을 그룹화한 복합 데이터 타입을 나타냅니다. 구조체의 이름은 첫 글자가 대문자로 시작하는 PascalCase를 사용하여 서술적인 이름을 사용합니다.
- 좋은 사례: 명사나 명사구를 사용하여 그들이 나타내는 내용을 명확하게 설명하는 구조체에 이름을 지정합니다. 예를 들어:
// 좋은 예
type Employee struct {
ID int
FirstName string
LastName string
Position string
}
- 피해야 할 점: 구조체의 목적을 전달하지 못하는 모호하거나 일반적인 이름을 사용하는 것을 피합니다.
// 피해야 할 점
type Data struct {
ID int
FirstName string
LastName string
Position string
}
3.2. 인터페이스 명명 지침
개요: Go 언어의 인터페이스는 메서드 집합을 지정하며, 'er' 접미사가 의미가 있다면 설명적인 이름을 사용하여 명명됩니다.
- 좋은 사례: 인터페이스가 추상화하는 행동을 나타내도록 인터페이스에 이름을 지정합니다. 일반적으로, 인터페이스가 하나의 메서드만 포함하는 경우, 이름은 해당 메서드의 동작을 반영하고 '-er' 접미사가 붙습니다.
// 좋은 예
type Reader interface {
Read(p []byte) (n int, err error)
}
- 행동 모음 명명: 인터페이스가 행동의 모음을 나타내는 경우, 'er' 접미사 없이 목적을 정확하게 반영하는 이름을 선택합니다.
// 행동 모음 예시
type Filesystem interface {
ReadFile(path string) ([]byte, error)
WriteFile(path string, data []byte) error
}
4. 대소문자 구분 및 노출된 식별자
4.1. 노출된 vs 비노출된 이름
Go 언어에서 식별자의 가시성은 첫 글자의 대소문자에 의해 결정됩니다. 대문자로 시작하는 식별자는 '노출된(exported)'로, 다른 패키지에서 접근할 수 있습니다. 이는 다른 프로그래밍 언어의 공용 범위와 유사합니다. 반면, 소문자로 시작하는 식별자는 '비노출된(unexported)' 또는 비공개이며, 해당 패키지 내에서만 접근할 수 있습니다.
예시:
package geometry
// 노출된 식별자
type Rectangle struct {
Length, Width float64
}
// 비노출된 식별자
type point struct {
x, y float64
}
이 예시에서 Rectangle
은 대문자로 시작하기 때문에 노출된 타입이며, geometry
패키지를 가져온 다른 패키지에서 사용할 수 있습니다. 반면, point
타입은 비노출된 타입이며, geometry
패키지 내에서만 사용할 수 있습니다.
4.2. 내보낸 식별자의 모범 사례
식별자를 이름 짓는 경우, 다른 사람들에 의해 읽기 쉽고 이해하기 쉽도록 코드를 보호하기 위해 몇 가지 모범 사례를 따르는 것이 중요합니다.
-
간결함보다 명확함: 간결하고 암호적인 이름보다 명확하고 설명적인 이름을 선택하십시오. 예를 들어
CalcA
보다는CalculateArea
를 선호합니다. - 일관성: 코드베이스 전체에서 명명 규칙을 일관되게 유지하십시오. 비슷한 항목을 특정한 패턴으로 명명하기 시작하면 그에 고수하십시오.
-
중복 피하기: 식별자 이름에서 패키지 이름을 반복하지 마십시오. 예를 들어
geometry.GeometryRectangle
대신geometry.Rectangle
을 사용하십시오. - 문맥 고려: 식별자 이름은 사용된 문맥에서 의미를 가지도록하여야 합니다. 혼란스럽거나 모호한 이름을 피하십시오.
- 문서화 주석: 내보낸 식별자를 설명하는 주석을 사용하여 그들이 하는 일과 사용 방법을 설명하십시오.
예시:
package geometry
// CalculateArea는 직사각형의 면적을 반환합니다.
func (r Rectangle) CalculateArea() float64 {
return r.Length * r.Width
}
이 예에서 CalculateArea
는 명확하고 설명적인 이름을 가진 내보낸 함수로, 그 목적을 설명하는 문서화 주석이 포함되어 있습니다.
5. 실무에서의 명명 규칙
이 장에서는 Go의 명명 규칙을 실제 시나리오에 적용하는 방법에 대해 살펴볼 것입니다. 이러한 규칙을 이해하고 준수하는 것은 코드가 관용적이고 읽기 쉽고 유지 관리하기 쉽도록 보장하는 데 중요합니다.
5.1. 흔한 실수와 그것을 피하는 방법
변수, 함수 및 다른 식별자의 명명은 종종 중요성이 과소평가됩니다. 흔한 실수로는 다음이 포함됩니다:
-
일반적인 이름 사용:
data
나info
와 같은 이름은 설명적이지 않고 혼란을 일으킬 수 있습니다. - 지나치게 긴 이름: 설명적인 이름은 좋지만 지나치게 장황한 이름은 번거로울 수 있습니다. 적당한 밸런스를 유지하십시오.
- 다중 단어 식별자에 밑줄 사용: Go는 변수 이름에는 camelCase를, 내보낸 함수 및 타입에는 PascalCase를 선호합니다.
- 일관되지 않은 명명 방식: 명명 규칙의 일관성은 코드 구조를 빠르게 이해하는 데 도움이 됩니다.
이러한 실수를 피하는 팁:
- 간결하지만 설명적인 이름을 사용하십시오. 예를 들어,
data
대신에 사용자 정보를 나타내는 경우userData
를 사용하십시오. - Go의 약어 관례를 따르세요. 예를 들어
HttpServer
대신HTTPServer
와 같이 약어는 대문자로 유지하십시오. - 내보내지 않은 패키지 레벨 변수 및 상수의 경우 범위가 제한되어 있기 때문에 이름을 짧게 유지하십시오.
5.2. 더 나은 이름으로 리팩터링
식별자 이름을 개선하기 위해 코드를 리팩터링하면 코드의 가독성을 크게 향상시킬 수 있습니다. 안전하게 이를 수행할 수 있는 방법은 다음과 같습니다:
-
설명적인 이름 사용: 이름을 리팩터링하여 그들이 무엇을 나타내는지 명확하게 명시하십시오. 예를 들어, 특정 작업을 하는 함수의 이름을
Process
에서ProcessUserInput
으로 변경하십시오. -
도구 활용:
gorename
과 같은 도구를 사용하여 Go 코드를 텍스트적으로 분석하는 것이 아니라 의미론적으로 안전하게 이름을 변경할 수 있습니다. - 동료 검토: 때로는 여러분에게는 명확하게 보이지만 다른 사람들에게는 명확하지 않을 수도 있습니다. 동료 검토를 통해 모호한 이름을 식별하는 데 도움을 받을 수 있습니다.
- 피드백 반복: 변경 사항을 수행한 후에 코드베이스의 사용자로부터 피드백을 수집하고 필요에 따라 명명을 반복하십시오.
이러한 기술을 따르면 Go 코드베이스가 깨끗하고 이해하기 쉽고 유지 관리할 수 있음을 보장할 수 있습니다.