programming/golang
Go 언어, 이렇게 쓰면 GOAT 된다 - 실전 꿀팁 12개!
jamie91
2025. 3. 10. 10:04
1. 중첩을 피하고 에러를 먼저 처리하라
✅ 핵심 로직을 깊게 중첩하지 않도록 에러를 먼저 처리
// Bad: 중첩이 깊어지는 코드
func process(value int) error {
if value > 0 {
if value < 100 {
if value%2 == 0 {
return nil
} else {
return errors.New("value must be even")
}
} else {
return errors.New("value must be less than 100")
}
} else {
return errors.New("value must be positive")
}
}
// Good: 에러를 먼저 처리하고 핵심 로직을 단순화
func process(value int) error {
if value <= 0 {
return errors.New("value must be positive")
}
if value >= 100 {
return errors.New("value must be less than 100")
}
if value%2 != 0 {
return errors.New("value must be even")
}
return nil
}
2. 중복을 피하라
✅ 반복되는 코드를 함수로 추출하여 재사용
// Bad: 중복 코드 발생
func printHelloWorld() {
fmt.Println("Hello, World!")
}
func printHelloUser(name string) {
fmt.Println("Hello, " + name + "!")
}
// Good: 공통 로직을 함수로 분리
func printMessage(message string) {
fmt.Println(message)
}
3. 중요한 코드를 먼저 작성하라
✅ 핵심 로직을 먼저 작성하고 보조 코드(로깅, 보완 처리 등)를 뒤에 배치
// Bad: 로그와 부가적인 코드가 먼저 나옴
func processUser(id int) {
log.Println("Processing user:", id)
if id == 0 {
log.Println("Invalid user ID")
return
}
// 핵심 로직
fmt.Println("User processed")
}
// Good: 핵심 로직을 먼저 처리
func processUser(id int) {
if id == 0 {
log.Println("Invalid user ID")
return
}
fmt.Println("User processed") // 중요한 코드
log.Println("Processing user:", id) // 보조 코드
}
4. 문서화를 잘하라
✅ 함수, 패키지, 구조체 등에 적절한 주석을 추가
// AddNumbers는 두 정수를 더한 값을 반환한다.
func AddNumbers(a, b int) int {
return a + b
}
5. 코드 길이는 짧게 유지하라
✅ 가독성을 위해 짧고 간결한 코드 작성
// Bad: 너무 길고 불필요한 코드
func isEven(n int) bool {
if n%2 == 0 {
return true
}
return false
}
// Good: 한 줄로 간결하게
func isEven(n int) bool {
return n%2 == 0
}
6. 패키지를 여러 파일로 나누어 관리하라
✅ 큰 프로젝트에서는 패키지를 여러 파일로 분할하여 관리
/myproject
├── main.go
├── user/
│ ├── user.go
│ ├── user_service.go
│ └── user_repository.go
├── utils/
│ ├── file.go
│ ├── string.go
7. 패키지는 "go get"-able 하게 만들어라
✅ 패키지를 쉽게 가져올 수 있도록 적절한 구조를 유지
- 예: github.com/username/mypackage 형태로 go get 가능하도록 관리
go get github.com/myusername/mypackage
8. 필요한 것만 요청하라
✅ 필요한 정보만 인자로 받아서 의존성을 줄임
// Bad: 불필요한 전체 구조체를 받음
func process(user User) {
fmt.Println(user.Name)
}
// Good: 필요한 값만 받음
func process(name string) {
fmt.Println(name)
}
9. 독립적인 패키지는 독립적으로 유지하라
✅ 불필요한 의존성을 제거하고 패키지를 독립적으로 설계
// Bad: 불필요한 의존성 추가
package auth
import (
"database/sql"
"fmt"
)
func AuthenticateUser(db *sql.DB, username, password string) bool {
// DB 의존성 없이 인증 로직만 구현하는 것이 좋음
}
// Good: DB와 분리
package auth
func AuthenticateUser(username, password string) bool {
// 독립적인 인증 로직
}
10. API에서 동시성을 피하라
✅ API 내부에서는 동시성을 직접 다루지 않음
// Bad: API에서 직접 고루틴 실행
func handleRequest(w http.ResponseWriter, r *http.Request) {
go processRequest(r) // 비효율적
fmt.Fprintln(w, "Processing started")
}
// Good: API는 동시성을 다루지 않도록 함
func handleRequest(w http.ResponseWriter, r *http.Request) {
processRequest(r) // 동기 처리
fmt.Fprintln(w, "Request processed")
}
11. 고루틴을 사용하여 상태를 관리하라
✅ 고루틴과 채널을 활용하여 상태를 안전하게 관리
type Counter struct {
value int
mu sync.Mutex
}
func (c *Counter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.value++
}
func (c *Counter) Get() int {
c.mu.Lock()
defer c.mu.Unlock()
return c.value
}
12. 고루틴 누수를 피하라
✅ 고루틴을 사용한 후 반드시 종료하도록 처리
// Bad: 고루틴이 종료되지 않음
func startWorker() {
go func() {
for {
time.Sleep(time.Second)
fmt.Println("Working...")
}
}()
}
// Good: 종료를 위해 context 사용
func startWorker(ctx context.Context) {
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("Worker stopped")
return
default:
time.Sleep(time.Second)
fmt.Println("Working...")
}
}
}()
}
728x90
반응형