애플리케이션이 해야 할 일이 많아지고 규모가 커지게 되면 코드를 분리해야 하는 경우가 생깁니다. 우리가 지금까지 만들었던 것처럼 main.go
라는 파일 안에 모든 로직들을 넣을 순 없게 됩니다. 그래서 패키지화라는 과정을 통해 애플리케이션의 로직을 비슷한 역할을 하는 코드들끼리 모아 둡니다. 파이썬에서는 디렉터리를 만들고 __init__. py
라는 파일을 만들어서 패키지화를 할 수 있습니다. 비슷한 방법으로 Go 언어 역시 패키지화를 할 수 있습니다. 하지만 Go 언어에서의 패키지화는 개인적으로는 파이썬 보다 훨씬 편하다고 생각합니다. 그리고 Go 언어가 가지는 여러 가지 특징 중 하나가 손쉬운 패키지화라고도 생각합니다. 이번 글에서는 우리가 앞에서 다뤘던 애플리케이션을 패키지화해서 관리하는 방법에 대해서 살펴보겠습니다.
패키지로 나누기
우리가 지난 시간에 만든 애플리케이션은 /
, /hello
, /bye
를 처리할 수 있도록 구성되어 있습니다. 이 과정에서 /hello
는 DoHello()
함수에서 /bye
는 DoBye()
함수에서 처리하게 해 두었죠. DoHello()
와 DoBye()
함수는 현재 아주 간단한 형태이지만 이 함수들의 규모가 커지게 되면 main.go
파일도 커지게 되고 가독성이 떨어지겠죠. 그래서 이 두 함수를 별도의 패키지로 나눠 보겠습니다. Path 들을 처리할 수 있는 함수들을 한 곳에 모아 보겠습니다. 패키지의 이름은 path
로 해보겠습니다.
패키지로 나누기 전에 현재 구조를 살펴보겠습니다.
❯ tree
.
├── bin
│ └── hello-world
├── go.mod
├── go.sum
├── main.go
├── serverless.yaml
└── vendor
우리가 현재 만든 애플리케이션은 위와 같은 구조입니다. main.go
함수에 모든 로직들이 포함되어 있죠. 이제 path
라는 디렉터리를 만들어 주고 hello.go
와 bye.go
두 개의 파일을 만들어 주겠습니다. 그리고 두 개의 파일은 모두 아래와 같이 내용을 채워 줍니다.
만약 GoLand로 두 개의 파일을 만들었다면 아래 내용이 자동으로 입력될 겁니다.
package path
이제 애플리케이션 구조는 아래와 같이 됩니다.
❯ tree
.
├── bin
│ └── hello-world
├── go.mod
├── go.sum
├── main.go
├── path
│ ├── bye.go
│ └── hello.go
├── serverless.yaml
└── vendor
그리고 hello.go
와 bye.go
파일에 기존에 만들어 두었던 DoHello()
함수와 DoBye()
함수 두 개를 각각 작성해 줍니다.
// hello.go 파일
package path
func DoHello() string {
return "Hello From Path Module"
}
// bye.go 파일
package path
func DoBye() string {
return "Bye From Path Module"
}
DoHello()
함수와 DoBye()
함수는 같은 이름으로 main.go
함수에 있는데 괜찮은 걸까?라는 의문이 생길 텐데요, 결론적으로 말씀드리면 괜찮습니다. main.go
파일에 있는 DoHello()
함수와 hello.go
파일에 있는 DoHello()
함수는 전혀 다른 함수입니다. 왜 그런 걸까요? 이건 패키지의 범위와 관련이 있습니다.
패키지의 범위
기본적으로 Go 언어의 패키지는 아래와 같은 규칙을 가집니다.
- 같은 패키지의 함수들은 하나의 디렉터리에 모여 있어야 합니다. 우리가 위에서 만든 Path라는 패키지를 구성하는 모든 함수와 변수 등은 서로 다른 파일 일지라도 같은 디렉터리 안에 있어야 합니다. 이때 디렉터리의 이름과 패키지의 이름은 달라고 상관없습니다만, 가독성을 위해 동일하게 유지하는 것이 좋습니다.
- 이름을 소문자로 시작하는 함수는 같은 패키지 안에서는 사용할 수 있습니다. 그래서 패키지 내부에서만 사용하는 함수는 이름을 소문자로 시작해야 합니다.
- 이름을 대문자로 시작하는 함수는 패키지 외부에서 사용할 수 있습니다. 패키지의 외부에서 호출해야 하는 함수는 이름을 대문자로 시작해야 합니다.
그래서 main.go
파일 안에 있는 DoHello()
함수는 main
패키지에 속하는 함수이고 hello.go
파일 안에 있는 DoHello()
함수는 path
패키지에 속하는 함수이기 때문에 이름이 같지만 완전 다른 함수라고 생각하면 됩니다. 그럼 이제 main.go
에서 path
패키지에 있는 함수를 호출하도록 해보겠습니다.
패키지 호출하기
이제부터가 중요한데요, 앞에서 정의한 패키지를 어떻게 사용할 수 있을까입니다. 바로 Go 언어의 import
구문을 통해서 사용할 수 있습니다. 그래서 아래와 같은 import
구문을 통해서 path
패키지의 함수와 변수들을 사용할 수 있습니다.
import (
"fmt"
"net/http"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"hello-world-go/path"
)
hello-world-go
는 우리가 첫 번째 글에서 go mod init hellow-world-go
라는 명령을 통해 만들었던 바로 그 모듈의 이름입니다. 그리고 그 안에 path
라는 패키지를 만들었으니 hello-world-go/path
라는 이름으로 새로 만든 path
패키지를 호출할 수 있게 됩니다.
우리가 만든 path
패키지를 가져왔으니 함수를 호출해 보겠습니다.
func handler(event events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error){
var responseBody string
fmt.Println(event)
switch event.Path {
case "/hello":
responseBody = path.DoHello() // DoHello()를 path.DoHello()로 수정
case "/bye":
responseBody = path.DoBye() // DoBye()를 path.DoBye()로 수정
default:
responseBody = "Default"
}
return events.APIGatewayProxyResponse{
StatusCode: http.StatusOK,
Body: responseBody,
}, nil
}
이제 main.go
파일에 만들었던 DoHello()
함수와 DoBye()
함수는 삭제합니다. 그럼 main.go
함수에는 API Gateway로부터 받은 event를 기반으로 각각의 Path에 맞는 함수를 호출하는 기본적인 로직만 남게 되고 나머지 실질적인 처리 로직은 모두 path
패키지에 있는 함수들이 처리하게 됩니다. 이를 통해 파일의 내용을 간소화하고 로직을 분리시켜 가독성을 높일 수 있습니다. 그리고 serverless
로 다시 배포하고 테스트를 해보겠습니다.
❯ curl https://o2slv6y2ac.execute-api.ap-northeast-2.amazonaws.com/dev/bye
Bye From Path Module
❯ curl https://o2slv6y2ac.execute-api.ap-northeast-2.amazonaws.com/dev/hello
Hello From Path Module
우리가 의도했던 대로 변경된 함수에서 처리된 스트링으로 잘 동작하는 것을 볼 수 있습니다.
마치며
이번 글에서는 패키지화를 통해 애플리케이션을 구조화하는 방법에 대해서 살펴봤습니다. 이제 우리는 함수를 만들 수 있고, 각각의 함수를 용도에 맞는 모듈로 나눠서 패키지화 하는 방법까지 살펴 봤습니다. 이를 통해 조금 더 큰 규모의 애플리케이션을 만들 수 있고 코드의 가독성을 높일 수 있습니다. 다음 글에서는 AWS의 각 서비스를 호출해서 실제 업무에 도움이 되는 쓸모 있는 애플리케이션을 만들어 보겠습니다.
'IT > GoLang' 카테고리의 다른 글
Go 언어에서 YAML 파일을 구조체로 표현하기 위한 일곱가지 패턴 (0) | 2022.01.17 |
---|---|
두번째 글 - 함수 사용하기 (0) | 2021.09.25 |
첫번째 글 - Hello World on API Gateway (0) | 2021.09.22 |