개요
golang 은 쉽게 패키지를 가져오고 내보낼 수 있는 언어이다. 이 번 장에서는 go 모듈을 만드는 과정을 써내려가려한다. 저자는 nb-logger 라는 non-bloking logger 를 만드려고 하기 때문에 nb-logger 와 관련된 부분은 독자가 원하는 패키지 명으로 변경해서 작성하면 된다.
먼저 모듈 소스 코드를 작성할 디렉토리를 만들고 이동한다.
$ mkdir nb-logger
$ cd nb-logger
또한 라이브러리 형태의 go 모듈을 만들기 위해서는 패키지를 가져오고 내보낼 repository 가 필요하다(repo 없이하려면 매우 귀찮다). github를 이용해서 repository 를 만들고, go 모듈을 초기화할 때 사용한다. go mod init {repository path} 이렇게 하면 go 모듈이 생성 되고, go.mod 파일이 생성된다.
$ go mod init github.com/banaconda/nb-logger
go: creating new go.mod: module github.com/banaconda/nb-logger.
$ ls
README.md go.mod
$ cat go.mod
module github.com/banaconda/nb-logger
go 1.18
아래와 같이 logger.go 파일에 테스트 코드를 작성하고 repo 로 push 한다
package nblogger
import "fmt"
func Hello(name string) string {
message := fmt.Sprintf("Hi, %v. Wellcome!", name)
return message
}
그리고 다른 go 모듈을 만든다. 아까와 다르게 repo 경로가 아닌 hello 만 넣어서 로컬 모듈로만 사용한다.
$ cd
$ go mod init hello
hello.go 파일을 수정하기 전에 아까 만들었던 모듈을 가져오자. go get {repository path} 명령을 수행하면. 아래와 같이 모듈을 다운받고, go.mod 파일에 require 로 nb-logger 가 추가된 것을 확인 할 수 있다.
$ go get github.com/banaconda/nb-logger
go: downloading github.com/banaconda/nb-logger v0.0.0-20220702111429-9594bb378c3c
go: added github.com/banaconda/nb-logger v0.0.0-20220702111429-9594bb378c3c
$ cat go.mod
module hello
go 1.18
require github.com/banaconda/nb-logger v0.0.0-20220702111429-9594bb378c3c // indirect
이제 hello.go 파일을 작성해보자. 간단하게 nblogger 의 Hello 함수를 호출해서 출력하는 프로그램이다.
package main
import (
"fmt"
nblogger "github.com/banaconda/nb-logger"
)
func main() {
message := nblogger.Hello("test")
fmt.Println(message)
}
이제 실행해보자. go run {filename} 로 실행하면 정상적으로 nb-logger 모듈에 있는 Hello 함수를 실행했다는 것을 알 수 있다.
$ go run hello.go
Hi, test. Wellcome!
에러 처리
에러 처리는 견고한 모듈을 만들기 위한 필수적인 사항이다. 적절한 에러처리를 통해 유효성 체크를 하지 않으면 모듈 내부에서 패닉이 나거나 더 심한 경우 패닉도 없는 상태로 이상한 방향으로 프로그램이 흘러갈 수 있다. 그렇기 때문에 모듈 작성자는 최대한 예상가능한 유효성 체크를 통해서 모듈 사용자에게 적절한 응답을 할 수 있게 해야된다.
코드를 통해서 알아보자 아까 만들었던 logger.go 를 수정해보자.
Hello 함수를 수정하여 string 과 error 를 같이 리턴하게 변경했다. 그리고 name 파라메터에 비어있는 스트링이 왔을 경우, 빈 스트링과 error 를 리턴하고, 그렇지 않으면 기본적인 동작과 error 를 nil 로 리턴한다.
리턴시 ({type}, error) 구조는 golang 전반적으로 많이 쓰이는 구조이니 알아두면 좋다.
package nblogger
import (
"errors"
"fmt"
)
func Hello(name string) (string, error) {
if name == "" {
return "", errors.New("empty name")
}
message := fmt.Sprintf("Hi, %v. Wellcome!", name)
return message, nil
}
모듈을 고쳤으니 repo 에 올려야되는데 아까와 다른 버전으로 올려야지 hello 프로젝트에서 변경된 모듈을 가져갈 수 있다.그래서 아까와는 다르게 tag를 붙이고 해당 태그를 통해 퍼블리시 하면된다. ($ git push origin --tags 는 추천하지 않음)
$ git tag v0.0.1
$ git push origin
$ git push origin v0.0.1
hello 프로젝트로 가서 새로 변경된 nblogger를 받아보자. 기존 repository path 에 @{version} 을 붙이면 해당 버전을 가져올 수 있다. 아래 보면 기존 버전이 v0.0.1 로 바뀐 것을 볼 수 있다.
$ go get github.com/banaconda/nb-logger@v0.0.1
go: downloading github.com/banaconda/nb-logger v0.0.1
go: upgraded github.com/banaconda/nb-logger v0.0.0-20220702111429-9594bb378c3c => v0.0.1
$ cat go.mod
module hello
go 1.18
require github.com/banaconda/nb-logger v0.0.1 // indirect
이제 다시 코드를 보면 아래 처럼 Hello 함수에 에러가 나고 있는 것을 볼 수 있다. 기존에는 Hello 함수가 string 만 리턴했는데 이젠 error 도 같이 리턴하기 때문에 코드를 수정해주어야 한다.

hello.go 파일을 수정해주자. error 처리를 해주고, 빈 string 도 넣어보면서 테스트 해보자
package main
import (
"fmt"
nblogger "github.com/banaconda/nb-logger"
)
func main() {
message, err := nblogger.Hello("test")
if err != nil {
fmt.Printf("%v", err)
panic(err)
}
fmt.Println(message)
message, err = nblogger.Hello("")
if err != nil {
fmt.Printf("%v", err)
panic(err)
}
fmt.Println(message)
}
실행하면 아래 와 같이 첫 문장만 잘 출력하고, 두 번 째는 panic 이 생긴 것을 알 수 있다.
$ go run hello.go
Hi, test. Wellcome!
empty namepanic: empty name
goroutine 1 [running]:
main.main()
/home/nem/project/hello/hello.go:20 +0x150
exit status 2
테스팅
에러 처리와 함께 테스트 코드는 모듈을 더욱 견고하게 만들어준다. 추후 변경 사항에 대해서 자동으로 테스트 할 수 있고, 사용법에 대한 예제가 될 수도 있기 때문이다. 그래서 모듈의 안정성을 올릴 수 있다.
테스트 파일은 {package_name}_test.go 규칙으로 만들고 go test 명령으로 테스트 할 수 있다.
먼저 logger_test.go 파일을 만들어보자
package nblogger
import (
"regexp"
"testing"
)
func TestHello(t *testing.T) {
name := "Test"
want := regexp.MustCompile(`\b` + name + `\b`)
msg, err := Hello("Test")
if !want.MatchString(msg) || err != nil {
t.Fatalf(`Hello("Test") = %q, %v, want match for %#q, nil`, msg, err, want)
}
}
func TestEmpty(t *testing.T) {
msg, err := Hello("")
if msg != "" || err == nil {
t.Fatalf(`Hello("") = %q, %v, want "", error`, msg, err)
}
}
이제 테스트를 수행해보면 테스트가 정상적으로 성공한 것으로 보인다.
$ go test -v
=== RUN TestHello
--- PASS: TestHello (0.00s)
=== RUN TestEmpty
--- PASS: TestEmpty (0.00s)
PASS
ok github.com/banaconda/nb-logger 0.002s
결론
정리하면 모듈을 만들고 관리하기 위해서는 go 모듈을 위해서는 아래 항목들을 고려해야된다.
- 모듈을 배포할 github 같은 repository
- 버전 관리
- 에러 처리
- 테스트 코드
참고
https://go.dev/doc/tutorial/create-module
'Programming > Golang' 카테고리의 다른 글
| Go(Golang)으로 Asynchronous Non-Blocking Logger 만들기 3편 (0) | 2022.07.11 |
|---|---|
| Go(Golang)으로 Asynchronous Non-Blocking Logger 만들기 2편 (0) | 2022.07.08 |
| Go(Golang)으로 Asynchronous Non-Blocking Logger 만들기 1편 (0) | 2022.07.07 |
| Go(Golang)로 로거 만들기: Logging in Golang (0) | 2022.07.04 |