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
반응형