Go 언어 소개

검프·2021년 3월 6일
3

Go 언어 소개 포스팅을 하려고 검색하던 중 우연히 아래 영상을 발견했습니다. 겨울 왕국의 Let It Go를 개사하여 Go 언어의 특징들을 소개하는 "Write in Go"입니다. 본격적으로 Go 언어를 공부하시기 전에 학습 욕구를 높여주는 데 도움이 되는 것 같습니다. Write in Go 한글 가사가 있어서 좌표 남겨놓습니다.



본격적으로 Go 언어에 대해서 알아보겠습니다.

만든이와 업데이트 주기

2007년 구글에서 켄 톰슨, 롭 파이크, 로버트 그리즈머가 함께 일하고 있었습니다. 이들의 업적은 저 같은 평범한 프로그래머들이 더 나은 환경에서 프로그래밍 할 수 있도록 플랫폼을 만들고 발전시켜온 역사 자체라고 해도 무방해 보입니다. 그야말로 프로그래머들의 프로그래머.

  • 켄 톰슨Ken Thompson^{Ken\ Thompson} : B언어, Unix, UTF-8
  • 롭 파이크RobPike^{Rob Pike} : Unix, UTF-8, Newsqeak
  • 로버트 그리즈머Robert Griesemer^{Robert\ Griesemer} : Java HotSpot VM, V8 Javascript engine

이들은 2007년부터 함께 Go 언어를 개발하여 2009년 11월 첫 버전을 출시하였고, 2012년 3월에 버전 1.0을 출시합니다. 2021년 2월 16일에는 최신 버전인 Go 1.16이 출시되었습니다. 자세한 버전 이력은 Release History에서 확인하실 수 있습니다. Go는 6개월 주기로 메이저 업데이트가 이루어지고 있습니다. 각 메이저 버전은 출시 후 2번의 메이저 업데이트가 추가로 이루어질 때까지 유지 보수가 됩니다. 즉, Go 메이저 버전의 LTSLong Term Supoort^{Long\ Term\ Supoort}는 2년이라고 보시면 될 것 같습니다.


왜 만들었나

이들은 C++로 인페르노Inferno^{Inferno}라는 분산 운영체제를 개발하고 있었습니다. 이 과정에서 C++의 느린 빌드 속도, 언어의 복잡성, 안정성 확보 및 동시성 프로그래밍의 어려움 등에 의한 한계를 깨달았고 더 나은 프로그래밍 언어를 개발하기로 합니다. 이들이 공감한 문제점 들은 Go 언어에서 해결하고자 하는 핵심 철학이 됩니다.

  • 빠른 성능
  • 안정성
  • 쉬운 프로그래밍

이런 철학은 go.dev 사이트에 카피에서도 잘 드러납니다.

Build fast, reliable, and efficient software at scale



로고와 이름

위에 이미지는 Go 언어의 마스코트이자 로고인 고퍼Gopher^{Gopher}입니다. 실존하는 동물을 모티브로 하고 있는데요, 개인적으로 프로그래밍 언어 로고 중에 가장 마음에 듭니다. Go 언어 사용자들은 자신들을 고퍼라고 부르기도 합니다. 고퍼 옆에는 Golang이라고 쓰여있는데요, "Go" 언어를 "Golang"이라고 표현하는 경우도 많습니다. 특히 검색 엔진에서는 "Go"만 검색해서는 만족스러운 검색 결과를 만나기가 어렵기도 합니다.

GitHut에서 GitHub에서 사용되는 언어별 인기 트렌드를 확인할 수 있는데요. Go 언어는 통계 지표 대부분에서 상위권에 위치해있습니다. 그만큼 최근 개발자들 사이에서 인기 있는 프로그래밍 언어라고 할 수 있겠습니다.


Go 언어 특징

  • 정적 타입
  • 강 타입
  • 빠른 컴파일 속도
  • 가비지 컬렉션
  • 동시성, 멀티프로세싱
  • 간결한 문법
  • 귀여운 로고

정적 타입 vs 동적 타입

정적 타입Static typing^{Static\ typing}은 컴파일 시점Compile time^{Compile\ time}에 타입이 결정되고 동적 타입Dynamic typing^{Dynamic\ typing}은 실행 시점Run time^{Run\ time}에 타입이 결정되는 것을 말합니다. 이런 특징 때문에 아래와 같은 장/단점이 있을 수 있습니다.

항목정적 타입동적 타입
타입 안정성높음낮음
실행 속도빠름느림
표현의 유연성낮음높음
/* Go */
var name string
name = "Gump"  // string
// name = 123  // Error
/* JavaScript */
let name
name = "Gump"  // String
name = 123     // Number

강 타입 vs 약 타입

강 타입Strongly typed^{Strongly\ typed}은 값의 타입을 바꿀 수 없습니다. 반면 약 타입Weakly typed^{Weakly\ typed}은 값의 타입을 바꿀 수 있습니다. 타입 캐스팅Type casting^{Type\ casting}과 타입 컨버전Type conversion^{Type\ conversion}차이도 이래를 해야 하는데요, 타입 캐스팅은 서로 다른 데이터 타입 간에 명시적으로 타입 변환를 하는 것을 말하며, 타입 컨버전은 서로 다른 타입 간에 자동으로 타입 변환을 하는 것을 말합니다. Go 언어는 타입 캐스팅만을 지원합니다.

항목강 타입약 타입
타입 케스팅가능가능
타입 컨버전불가능가능
/* Go */
var num1 int16 = 5
var num2 int32 = 10
// var sum int32 = num1 + num2      // 컴파일 에러
var sum int32 = int32(num1) + num2  // 정상 동작
/* Java */
short num1 = 5;
int num2 = 10;
int sum = num1 + num2;  // 정상 동작

빠른 컴파일 속도

C, C++는 컴파일할 때 헤더 파일 간의 의존성이 복잡해져 속도가 매우 느리고, 헤더 파일이 수정되면 다시 컴파일해야 하는 문제가 있습니다. 반면에 Go 언어는 헤더 파일이 없고, 패키지 단위로 변경된 부분만 컴파일하므로 컴파일 속도가 빠릅니다. 언어 문법적인 측면에서도 빠른 컴파일 속도를 유지할 수 있도록 복잡한 요소를 최대한 줄여서 설계하였습니다.

몇 해 전에 모던 언어에 대한 갈증이 많던 시절 Scala를 공부하여 업무에 적용하려고 시도했었습니다. 결국 도입하지 못했는데요, 가장 큰 원인은 너무 오래 걸리는 빌드 속도였습니다. 빌드 시간이 짧다는 것은 현업에서는 상당한 경쟁력 차이로 볼 수 있을 것 같습니다. Go 언어는 빌드 시간이 짧아서 굉장히 만족스럽게 사용하고 있습니다.

Go 1.5 버전부터는 Go 컴파일러가 Go 언어로 작성되기 시작했다고합니다. 그 전까지는 C로 개발되어 있었다고 하네요. 컴파일 시 타깃 시스템별로 실행 파일을 만들어 줍니다.

가비지 컬렉션

Go 언어는 가비지 컬렉션Garbage Collection^{Garbage\ Collection}을 지원합니다. C, C++ 언어에서는 메모리를 할당하면 반드시 해제해 주어야 합니다. 이는 작은 실수에도 메모리 누수로 인한 오류 발생 가능성을 높입니다. Java, C#, Python, JavaScript 등의 언어에서도 GC를 지원하는데요, 이들 언어의 경우 VM에서 GC를 지원합니다. 반면, Go 언어의 GC는 실행 파일에 내장되어 있습니다. GC를 지원함에 따라 프로그래머는 메모리 관리보다 도메인에 집중할 수 있게 됩니다.

Go 언어의 GC가 경우에 따라서는 단점으로 꼽는 경우도 있는데요. 특히 임베디드 환경 등에서 실행 파일이 커지고, GC로 인한 오버헤드가 성능 최적화에 도움이 안된다는 주장이 있기도 합니다. 은 총알은 없습니다. 상황에 맞는 적합한 도구를 사용할 수 있는 안목이 필요할 것 같아요.

동시성, 멀티프로세싱

개인적으로 Go 언어의 최대 장점으로 꼽는 것이 뛰어난 동시성 지원입니다. Go 언어는 go라는 키워드를 이용하여 아주 쉬운 방법으로 고루틴Goroutine^{Goroutine}을 이라는 동시성 실행 단위를 생성해냅니다. 심지어 고루틴은 스레드Thread^{Thread}보다 훨씬 효율적인 방법으로 멀티프로세싱 처리를 수행해냅니다.

package main

import "fmt"

func main() {
  go func(){
    fmt.Println("This is Gorouine")
  }()
}

Go의 동시성에 대한 설명은 동시성 소개를 참고 부탁드립니다.

간결한 문법

Go 언어는 C 계열 언어들과 비슷한 문법 구조를 가지고 있습니다. 1.16 버전을 기준으로 제공하는 키워드는 총 25개입니다. C언어 37개, C++ 84개, Java 50개에 비하면 정말 간결하게 유지되고 있습니다. 이런 부분들은 언어를 배우는 입장에서 더 쉽게 배울 수 있도록 해줍니다.

코딩 컨벤션 통일을 위해서 gofmt라는 도구를 제공하는데요, gofmt를 통해서 컴파일 시점에 컨벤션이 맞지 않을 경우 컴파일 오류를 발생시킵니다. 이 때문에 개발자 간에 논쟁도 줄어들고 큰 고민 없이 프로그래밍에 집중할 수 있습니다. 부먹이냐 찍먹이냐.. 이런 논쟁은 그만하고 문제 해결에 집중해 보아요.

귀여운 로고

Google 이미지 검색에서 golang gopher를 검색해보세요. 다양한 고퍼를 만날 수 있습니다. 귀여워서 고퍼 티셔츠도 질렀다능...


Hello Go

Golang 생태계에서 많이 사용되는 웹 프레임워크 중 하나인 Echo 프레임워크를 이용하여 Hello Go 출력하는 간단한 예제를 만들어 보겠습니다. 예제는 macOS BigSur를 기준으로 설명합니다.

Go 언어 설치

❯ brew install go
==> Downloading https://homebrew.bintray.com/bottles/go-1.16.big_sur.bottle.tar.gz
Already downloaded: /Users/saturdaynight/Library/Caches/Homebrew/downloads/1860d1cb8f63bb63c1d0ad2ad7d3ef8674f177c83ad66428c47114cc4abbe60b--go-1.16.big_sur.bottle.tar.gz
==> Pouring go-1.16.big_sur.bottle.tar.gz
🍺  /usr/local/Cellar/go/1.16: 9,967 files, 503.5MB

❯ go version
go version go1.16 darwin/amd64

Go 프로젝트 생성

❯ mkcd hello-go
❯ go mod init hello-go
go: creating new go.mod: module hello-go
❯ mkdir src

Console에 Hello Go!! 출력하기

src/hello-go.go 파일 생성

package main

import "fmt"

func main() {
    fmt.Println("Hello Go!!")
}

hello-go.go 실행하기

❯ go run src/hello-go.go
Hello Go!!

Echo 프레임워크를 이용하여 Hello Go!! 출력하기

Echo 프레임워크 설치하기

❯ go get -v github.com/labstack/echo/v4
go: downloading github.com/labstack/echo/v4 v4.2.0
golang.org/x/sys/internal/unsafeheader
github.com/valyala/bytebufferpool
golang.org/x/text/transform
golang.org/x/sys/unix
golang.org/x/net/http2/hpack
golang.org/x/text/unicode/bidi
github.com/valyala/fasttemplate
golang.org/x/crypto/acme
golang.org/x/text/unicode/norm
golang.org/x/text/secure/bidirule
golang.org/x/net/idna
github.com/mattn/go-isatty
github.com/mattn/go-colorable
github.com/labstack/gommon/color
github.com/labstack/gommon/log
golang.org/x/net/http/httpguts
golang.org/x/crypto/acme/autocert
golang.org/x/net/http2
golang.org/x/net/http2/h2c
github.com/labstack/echo/v4
go get: added github.com/labstack/echo/v4 v4.2.0

❯ cat go.mod
module hello-go

go 1.16

require github.com/labstack/echo/v4 v4.2.0 // indirect

src/hello-go.go 파일 수정하기

package main

import (
  "net/http"
  "github.com/labstack/echo/v4"
  "github.com/labstack/echo/v4/middleware"
)

func main() {
  // Echo instance
  e := echo.New()

  // Middleware
  e.Use(middleware.Logger())
  e.Use(middleware.Recover())

  // Routes
  e.GET("/", helloGo)

  // Start server
  e.Logger.Fatal(e.Start(":7063"))
}

// Handler
func helloGo(c echo.Context) error {
  return c.String(http.StatusOK, "Hello Go!!")
}

hello-go.go 실행하기

❯ go run src/hello-go.go

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v4.2.0
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:7063

http://localhost:7063/ 접속하면 Hello Go!!가 출력됩니다.

Go 언어의 단점

객체 지향 언어가 아님

OOPObject oriented programming^{Object\ oriented\ programming}를 지원하지 않는 것 자체가 문제는 아니지만, 워낙 많은 언어가 OOP 패러다임을 지원하다 보니 OOP에 익숙한 개발자들에게는 오히려 언어를 배우고 잘 사용하기 어렵게 만들 수 있겠다는 생각이 들었습니다.

제네릭 지원 안함 늦었지만 제네릭 지원

Go 언어 1.18 버전부터 제네릭을 지원하기 시작했습니다.

제네릭Generics^{Generics}은 아주 강력한 도구입니다. 컴파일 시 강한 타입 체크를 할 수 있게 도와주고, 불필요한 타입 캐스팅을 제거할 수 있습니다. 그리고 무엇보다 강력한 점은 제네릭스로 타입을 정의하고 인터페이스로 제공하여 서로 다른 타입 간에 공통 인터페이스를 제공하는 높은 수준의 추상화를 제공할 수 있다는 점입니다.

Go 1.16 버전까지는 제네릭을 지원하지 않습니다. 이 때문에 많은 개발자들로부터 제네릭을 구현해달라는 요구를 받아봤는데요, 드디어 1.17 버전부터 지원하는 것으로 결정이 되었습니다. Go 언어와 Go 언어를 사용하는 생태계가 다소 복잡해지는 것이 우려되기는 하지만, 유용한 도구라는 점은 변함이 없습니다. 마치 화약처럼요. 기대됩니다!

기타 다른 단점은 언어를 더 많이 사용해봐야 알 것 같습니다 ㅠ.ㅜ


마치며

이상으로 Go 언어에 대해서 소개해 봤습니다.
스터디에서 간단히 Go 언어를 소개할 목적으로 정리해 봤는데요, 사실 저도 Go 언어를 이제 막 알아가는 고린이라서 정리를 하면서 정말 많은 걸 배우게 됐습니다.
내용에 오류나 개선할 부분이 있다면 댓글로 피드백 부탁드립니다.
다들 Go 언어로 재미지게 코딩하세요!

profile
권구혁

0개의 댓글