Go 파헤치기 - 들어가며, Import and Tooling

 

1. 들어가며

 

Go에 대해서 반년 전에 간단하게 문법을 포스팅한 적이 있었는데요. 이번에 사이드 프로젝트로 채팅 서버를 golang으로 구현하기로 했고, 그 김에 Go를 조금 더 깊게, 공부하고자 합니다.

제가 선택한 책은 Go in Action입니다. Kotlin in Action이 읽고 좋았던 기억이 있고, 학교 도서관에서 온라인 도서를 이용할 수 있게 제공해주었기 때문입니다 :) 영어 원서만 있다는 점도 블로그 글로 포스팅하면 다른 분들께 도움이 될 것 같다는 것이 한몫했습니다.Go in Action을 기반으로 궁금했던 점을 더 조사해나가면서 하나씩 정리해보겠습니다.

 

2. Go란?

Go는 2009년 11월에 처음 발표되고 2012년 3월에 정식 발표된 프로그래밍 언어입니다! Java가 1995년 처음 발명되었던 것과 비교하면 비교적 젊지만, 벌써 12년 정도 된 언어라고도 볼 수 있을 것 같습니다. :) 물론 메이저한 프로그래밍 언어에서는 상당히 젊은 언어 축에 속합니다.

 

그렇다면 이 Go를 왜 사용하게 되었을까요?

Go in Action에서는 다음과 같은 장점을 첫 장에서 소개하고 있습니다.

 

  • Go는 스마트 컴파일러와 간소화된 종속성 해결 알고리즘을 사용하여 번개처럼 빠른 컴파일을 제공합니다. Go 프로그램을 빌드할 때 컴파일러는 Java, C, C++와 같이 전체 종속성 체인에 포함된 모든 라이브러리의 종속성을 탐색하는 대신 직접 포함하는 라이브러리만 살펴보면 됩니다. 결과적으로 많은 Go 애플리케이션이 1초 이내에 컴파일됩니다. 전체 Go 소스 트리는 최신 하드웨어에서 20초 이내에 컴파일됩니다.
  • JavaScript와 같은 동적 언어로 대규모 애플리케이션을 작성하다가 hello라는 필드를 수신할 것으로 예상하는 함수를 발견했다고 상상해 보세요 ID. 정수, 문자열 또는 UUID일까요? 알아내는 방법은 소스를 보는 것입니다. 숫자나 문자열로 함수를 실행해 보고 무슨 일이 일어나는지 볼 수 있습니다. Go에서는 컴파일러가 유형 차이를 잡아주기 때문에 궁금해하는 데 시간을 허비하지 않을 것입니다.
  • Go의 동시성 지원은 가장 강력한 기능 중 하나입니다. 고루틴은 스레드와 비슷하지만 훨씬 적은 메모리를 사용하고 사용하는 데 필요한 코드도 적습니다. 채널은 동기화가 내장된 고루틴 간에 입력된 메시지를 보낼 수 있는 데이터 구조입니다. 이를 통해 고루틴 간에 데이터를 보내는 프로그래밍 모델이 용이해지고, 고루틴이 동일한 데이터를 사용하기 위해 싸우지 않아도 됩니다. (고루틴은 추후 장에서 더 자세히 면밀하게 살펴보겠습니다 :))

이러한 장점을 가진 go에 대해서 차근차근 알아보도록 하겠습니다.

 

3. Import and Tooling

 

가장 기초적인, import와 tool을 사용하는 방법에 대해서 명렁어를 하나씩 정리하면서 배워보고자 합니다. build, clean과 같은 명확한 명령어보다는 Go에 있는 독특한 명령어 위주로 정리하도록 하겠습니다 :)

 

Go의 다양한 명령어

 

1) go get

 

Go github과 같은 DVCS를 통해 import가 가능하도록 지원합니다. go get 명령어를 통해 수행될 수 있습다.

 

go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages]

 

-d : 설치는 하지 않고 소스 파일만 다운로드합니다.

-u : 패키지 및 해당 종속성을 업데이트합니다.

-t : 패키지에 대한 테스트를 빌드하는 데 필요한 패키지도 다운로드합니다.

-v : 진행 및 디버그 출력

 

자세한 옵션 설명은 go help get을 통해 확인할 수 있습니다.

 

 

같은 이름을 가진 여러 패키지가 있다면 어떻게 할까요? 이 땐 named import가 필요해집니다.

package main

import (

"fmt"

myfmt "mylib/fmt"

)

func main() {

fmt.Println("Standard Library")

myfmt.Println("mylib/fmt")

}

 

위와 같이 이름을 구분해줘서 import를 해주면 됩니다.

_ 라는 식별자를 통해 할당을 무시할 수 있습니다. 이는 for문 뿐만 아니라 함수 반환, package 이름 등에서도 모두 가능합니다. 식별자로 할당을 무시해야 하는 경우가 package 이름에 왜 필요할까요?

 

Go에서는 런타임에서 패키지가 필요한 작업을 하기 위해서 init 함수가 사용됩니다. 이는 main 함수에 앞서 실행됩니다.

 

예를 들어 위와 같은 코드에서 "github.com/goincation/..." 패키지를 _ 없이 import 하지 않는다면 go는

사용하지 않는 패키지를 가져올 수 없도록 하므로 오류가 발생합니다. 해당 오류가 발생하지 않기 위해서 사용됩니다.

 

2) go vet

go vet: 코드에서 일반적인 오류를 검사합니다.

 

  • Prinf-style의 함수 call에 있는 좋지 않은 paramter
  • 메소드 시그니처 오류
  • 안좋은 구조체 태그들
  • Unkeyed composite literals

 

예를 들면

package main

import "fmt"
func main() {
     fmt.Printf("The quick brown fox jumped over lazy dogs", 3.14)
}

 

위와 같은 코드는 printf에서 3.14를 주입했지만 placeholder가 없습니다. 이와 같은 코드에 대해 go vetno formatting directive in Printf call와 같은 오류를 지적해줍니다.

물론 go vet logic 상의 큰 오류를 잡아줄 것이라 생각하면 안 됩니다. 하지만 일반적인 오류에 대해서는 잘 잡아주므로 commit 전에 실행하는 보조적인 도구로 생각하시면 됩니다!

 

3) go fmt

go fmt: 자동으로 소스 코드를 format에 맞게 바꾸어 준다.

 

4) go doc

go doc: 주석을 포함한 소스코드를 분석하고 간단한 문서를 반환해준다. 전체 API 구조를 파악하기 편하다.

 

와 같은 여러 명령어들을 제공하고 있습니다.