Skip to main content

Basics


Installation

export GO_VERSION="1.18.1"
export CURRENT_SYSTEM=`uname -s | awk '{print tolower($0)}'`
wget https://go.dev/dl/go"$GO_VERSION"."$CURRENT_SYSTEM"-amd64.tar.gz
sudo mkdir -p /opt/go/"$GO_VERSION"
pv -ptrb go"$GO_VERSION"."$CURRENT_SYSTEM"-amd64.tar.gz | sudo tar -xzp -C /opt/go/"$GO_VERSION"
export PATH=/opt/go/"$GO_VERSION"/go/bin:$PATH
info

.zshrc 등에 등록해서 사용할 경우에는 PATH에 버전을 명시해 주어야 합니다.

Setup

mkdir <package>
cd <package>
go mod init github.com/<user>/<package>
go mod tidy

모듈의 소스코드와 go.mod 파일을 비교하여 모듈을 추가 또는 제거합니다.

Build

[envs] go build [flags] [-o <output>]
  • [envs]
    • GOOS=<os>
    • GOARCH=<arch>
    • CGO_ENABLED=0|1: cgo 사용 여부
  • [flags]
    • -a: 사용되는 모든 패키지를 강제로 다시 빌드합니다.
    • -ldflags 'flags'
      • flags
        • -s: static linking

Ex) CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -a -ldflags '-s' -o app

info

사용 가능한 GOOSGOARCHgo tool dist list | column -c 75 | column -t 명령어로 알 수 있습니다.

go install

빌드된 바이너리가 GOBIN경로에 설치됩니다.

Project Layout

처음엔 main.go로 시작한 후, 프로젝트가 성장함에 따라 리팩토링을 통해 구조화 해가는 것이 좋습니다.

  • /cmd
    • 메인 애플리케이션
    • /cmd/<command>/...: 디렉터리 명 == 실행파일 명
    • /cmd/<command> 내에서는 코드 작성을 최소화해야 합니다.
  • /internal
    • private 애플리케이션과 라이브러리
    • 다른 사람이 import 하기 원치 않는 코드
    • Go 컴파일러는 internal 이라는 디렉터리를 인식합니다.
  • /pkg
    • public 라이브러리
    • 다른 사람이 사용할 수도 있으므로 주의해서 코드를 추가해야 합니다.
  • /api
    • OpenAPI/Swagger 스펙, JSON schemas, 프로토콜 정의 등
  • /web
    • static assets, server side templates, SPA 등
  • /configs
  • /init
    • 시스템 init (systemd, upstart, sysv) 과 프로세스 매니저/슈퍼바이저 (runit, supervisord) 설정 등
  • /scripts
    • 빌드, 설치, 분석, 기타 작업을 위한 스크립트
    • 루트 디렉터리의 Makefile에서 스크립트를 호출하는 방식을 사용하여 가독성을 높일 수 있습니다.
  • /build
    • 클라우드, 컨테이너, 운영체제 패키지 설정과 스크립트를 /build/package에서 관리
    • CI 설정과 스크립트를 /build/ci에서 관리
  • /deployments
    • 배포 설정과 템플릿
    • /deploy를 사용하기도 합니다.
  • /test
    • 추가적인 외부 테스트 앱과 데이터
  • /docs
  • /tools
  • /examples
  • /third_party
  • /assets
    • 리포지터리와 함께 사용될 수 있는 이미지, 로고 등
  • /website
    • 프로젝트의 웹사이트 데이터

라이브러리의 경우 패키지 코드를 루트 디렉토리에 두는 경우가 있습니다. import path에 리포지터리 구조가 노출되어야 하거나 불필요한 경로가 없도록 해야합니다.

Name Convention

  • 일관성, 간결성, 정확성
  • 카멜케이스
  • private은 소문자로 시작하고, public은 대문자로 시작합니다.
  • 선언 위치와 사용 위치가 멀어질 수록 이름을 길게 하는 것이 좋습니다.
    • index -> i, reader -> r, buffer -> b 등으로 줄여 쓰는 것이 좋습니다.
    • 이름이 길어야지 이해되는 코드가 있다면 리팩토링이 필요할 수 있습니다.
  • 축약어는 모두 대문자로 씁니다.
  • 중복 될 수 있는 이름은 피합니다. server.ServerRun -> server.Run
  • func
    • 파라미터: 타입만으로 추측이 가능하다면 가능한 짧게, 추측이 어렵다면 충분히 설명할 수 있도록 합니다.
    • 리턴: 타입이나 함수명으로 추측이 안되는 경우에만 이름을 씁니다.
    • Receiver: 한 개 또는 두 개의 문자로 이름을 짓고, 한 번 사용한 이름을 일관되게 사용해야 합니다.
    • Must로 시작하는 함수의 경우 실행에 문제가 있을 때, panic을 발생시킵니다.
  • interface
    • 하나의 메서드만 가지는 interface는 일반적으로 er을 마지막에 붙입니다. 말이 안되는 단어가 되더라도 붙입니다.
    • 여러 메서드를 가지는 interface는 목적을 정확하게 설명하는 이름을 붙입니다.
  • 에러 타입은 Error로 끝나고, 에러 변수는 Err로 시작합니다.
  • package
    • 의미 있는 단어를 사용하되 util, common 등의 이름은 피하세요.
    • 복수형을 사용하지 마세요.
    • 대문자를 사용하지 않습니다.
    • path의 마지막 컴포넌트와 package 명은 동일해야 합니다.
    • pakcage 위에 주석을 달아주는 것이 좋습니다.

Reference