💻 프로그래밍

Go

Golang

Google이 개발한 시스템 언어. 고루틴으로 동시성 지원. Docker, K8s에 사용.

📖 상세 설명

Go(Golang)는 2009년 Google의 Robert Griesemer, Rob Pike, Ken Thompson이 개발한 정적 타입 컴파일 언어입니다. C++의 복잡성과 긴 컴파일 시간에 대한 불만에서 시작되어, 단순함과 효율성을 핵심 설계 철학으로 삼았습니다. Go는 "적게 하면서 더 많이 이루는" 언어로, 배우기 쉽고 읽기 쉬운 코드를 작성할 수 있습니다.

Go의 가장 강력한 특징은 고루틴(goroutine)과 채널(channel)을 통한 동시성 프로그래밍입니다. 고루틴은 OS 스레드보다 훨씬 가벼워서 수만 개를 동시에 실행할 수 있으며, 채널을 통해 고루틴 간 안전하게 데이터를 주고받습니다. "공유 메모리로 통신하지 말고, 통신으로 메모리를 공유하라"는 Go의 철학이 이를 잘 보여줍니다.

Go는 가비지 컬렉션을 제공하면서도 네이티브 바이너리로 컴파일되어 뛰어난 실행 성능을 제공합니다. 크로스 컴파일이 내장되어 있어 단일 코드베이스에서 Linux, Windows, macOS용 실행 파일을 쉽게 빌드할 수 있습니다. 컴파일 속도가 매우 빨라 대규모 프로젝트도 몇 초 만에 빌드됩니다.

실무에서 Go는 Docker, Kubernetes, Terraform, etcd 등 클라우드 네이티브 생태계의 핵심 도구들에 사용됩니다. 마이크로서비스, API 서버, CLI 도구, DevOps 인프라 개발에 특히 강점이 있으며, Netflix, Uber, Dropbox, Cloudflare 등 대규모 서비스에서 널리 채택하고 있습니다.

💻 코드 예제

package main

import (
    "fmt"
    "net/http"
    "sync"
    "time"
)

// 1. 기본 HTTP 서버
func helloHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "안녕하세요! 현재 시간: %s", time.Now().Format("15:04:05"))
}

// 2. 고루틴과 채널을 활용한 동시성 처리
func fetchURLs(urls []string) map[string]int {
    results := make(map[string]int)
    ch := make(chan struct{ url string; status int })
    var wg sync.WaitGroup

    for _, url := range urls {
        wg.Add(1)
        go func(u string) {
            defer wg.Done()
            resp, err := http.Get(u)
            if err != nil {
                ch <- struct{ url string; status int }{u, 0}
                return
            }
            defer resp.Body.Close()
            ch <- struct{ url string; status int }{u, resp.StatusCode}
        }(url)
    }

    go func() {
        wg.Wait()
        close(ch)
    }()

    for result := range ch {
        results[result.url] = result.status
    }
    return results
}

// 3. 구조체와 메서드
type User struct {
    ID   int
    Name string
}

func (u *User) Greet() string {
    return fmt.Sprintf("안녕하세요, %s님!", u.Name)
}

func main() {
    // HTTP 서버 시작
    http.HandleFunc("/", helloHandler)
    fmt.Println("서버 시작: http://localhost:8080")
    http.ListenAndServe(":8080", nil)
}

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"이 마이크로서비스는 Go로 개발하면 좋겠습니다. 고루틴으로 수천 개의 동시 요청을 효율적으로 처리할 수 있고, 단일 바이너리로 배포가 간편해서 Docker 이미지 크기도 10MB 이하로 줄일 수 있어요."
💬 면접에서
"Go의 동시성 모델에서 고루틴은 M:N 스케줄링을 사용합니다. 여러 고루틴이 OS 스레드 위에 다중화되어 컨텍스트 스위칭 비용이 적습니다. 채널을 통한 통신은 뮤텍스보다 데이터 레이스를 방지하기 쉽고, select 문으로 여러 채널을 동시에 대기할 수 있습니다."
💬 코드 리뷰에서
"이 고루틴에서 생성한 채널을 닫지 않아서 고루틴 리크가 발생할 수 있습니다. defer로 close(ch)를 추가하거나, context를 사용해서 취소 시그널을 전파하는 방식으로 수정해주세요."

⚠️ 흔한 실수 & 주의사항

❌
에러 무시하기

Go는 예외 대신 에러 값을 반환합니다. `result, _ := someFunc()`처럼 에러를 무시하면 런타임에 예상치 못한 문제가 발생합니다. 항상 `if err != nil` 체크를 하세요.

❌
고루틴 리크

채널에서 영원히 대기하거나 종료 조건 없이 실행되는 고루틴은 메모리 누수를 일으킵니다. context.WithCancel이나 context.WithTimeout을 사용해 고루틴의 생명주기를 관리하세요.

✅
Go 모듈과 의존성 관리

go mod init으로 모듈을 초기화하고, go mod tidy로 의존성을 정리하세요. go.sum 파일은 버전 관리에 포함하여 재현 가능한 빌드를 보장합니다.

🔗 관련 용어

📚 더 배우기