> ## Content Index
> Fetch the complete content index at: https://www.popit.kr/llms.txt
> Use this file to discover other available public pages before exploring further.

# [좌충우돌 개발기] Golang 에서 enum 자료형 사용후기
- URL: https://www.popit.kr/golang-enum-type-experience/
- Published: 2020-04-12T15:07:32.000Z
- Updated: 2020-04-14T06:43:27.000Z
- Author: devarchi33
- Tags: #소프트웨어, golang, enum

이번 글에서는 Golang **enum** 사용후기와 개선점에 대해서 이야기 하겠습니다.

## 정의

> In [computer programming](https://en.wikipedia.org/wiki/Computer%5Fprogramming?ref=popit.kr), an **enumerated type** (also called **enumeration**, **enum**, or **factor** in the [R programming language](https://en.wikipedia.org/wiki/R%5F%28programming%5Flanguage%29?ref=popit.kr), and a [categorical variable](https://en.wikipedia.org/wiki/Categorical%5Fvariable?ref=popit.kr) in statistics) is a [data type](https://en.wikipedia.org/wiki/Data%5Ftype?ref=popit.kr) consisting of a set of named [values](https://en.wikipedia.org/wiki/Value%5F%28computer%5Fscience%29?ref=popit.kr) called *elements*, *members*, *enumeral*, or *enumerators* of the type. The enumerator names are usually [identifiers](https://en.wikipedia.org/wiki/Identifier?ref=popit.kr) that behave as [constants](https://en.wikipedia.org/wiki/Constant%5F%28programming%29?ref=popit.kr) in the language.

[위키피디아](https://en.wikipedia.org/wiki/Enumerated%5Ftype?ref=popit.kr)에서는 **enum 자료형**을 **식별성**을 갖는 **상수로** 정의하고 있습니다.

## Golang 에서 enum을 사용하기

[Effective Go](https://golang.org/doc/effective%5Fgo.html?ref=popit.kr#constants)에는 **enum**을 **Constants**로 정의 한 후 **iota**라는 **enumerator**를 제공합니다. **iota**를 통해 값을 할당받은 변수들은 행이 바뀔때 **차례로 증가** 하고 **정수**로써 다루어 집니다.  

```go
type ByteSize float64

const (
    _           = iota // ignore first value by assigning to blank identifier
    KB ByteSize = 1 << (10 * iota)
    MB
    GB
    TB
    PB
    EB
    ZB
    YB
)
```

## 문자열로 표현된 enum을 사용하고 싶다!

- 지정된 값만 사용하기
- **의미**를 알 수 있도록 선언하기
- 타입으로 유효성을 검사하기

이러한 이유 때문에 const로 선언된 변수에 **문자열**을 할당하고 싶었습니다.  

```go
type Status string

const(
    Shipment = "Shipment"
    Receipt = "Receipt"
    ...
)
```

하지만 이렇게 하면 **지정되지 않은 값**을 사용해도 에러가 발생하지 않습니다. 왜냐하면 할당된 값이 특정타입을 나타내지 않는 **string**이기 때문입니다. 이러한 문제를 보완하기 위해서 [Type에 값을 할당 ](https://forum.golangbridge.org/t/how-to-declare-enums-in-golang/10727/6?ref=popit.kr)할 수 있습니다.  

```go
type Status string

const (
  Shipment = Status("S")
  Receipt = Status("R")
  ...
)
```

이렇게 하면 지정되지 않은 값을 사용 할 때 IDEA에서 **미리 지정된 상수** 인지 알 수 있습니다.

![Screen Shot 2020-04-11 at 4.42.51 PM](https://www.popit.kr/content/images/wp/2020/04/Screen-Shot-2020-04-11-at-4.42.51-PM-600x62.png)

## 한가지 기능이 더 필요한데..

- [배민의 블로그](https://woowabros.github.io/tools/2017/07/10/java-enum-uses.html?ref=popit.kr)를 보면 **상태와 행위를 함께 관리** 하는 방법이 나옵니다.
- [Aggregate Root에 관한 글](https://medium.com/@SlackBeck/%EC%95%A0%EA%B7%B8%EB%A6%AC%EA%B2%8C%EC%9E%87-%ED%95%98%EB%82%98%EC%97%90-%EB%A6%AC%ED%8C%8C%EC%A7%80%ED%86%A0%EB%A6%AC-%ED%95%98%EB%82%98-f97a69662f63?ref=popit.kr)에 **데이터의 무결성**을 위해 Repository를 Aggregate Root로 제한하는 방법이 나와 있습니다.

이러한 글들을 읽고 **enum**을 적극적으로 활용해 보고 싶었습니다. 이런 관점으로 [지난 글](https://www.popit.kr/how-to-name-api-functions/)의 **수불 시스템**을 살펴보겠습니다.  

```go
type Delivery struct {
    Id                  int64           `json:id`
    WaybillNo           string          `json:waybillNo`
    BoxNo               string          `json:boxNo`
    ShipmentLocationId  int64           `json:shipmentLocationId`
    ReceiptLocationId  int64            `json:receiptLocationId`
    Status              string          `json:status`
    Committed           `xorm:"extends"`
}

type Stock struct {
    Id                  int64           `json:id`
    LocationId          int64           `json:locationId`
    SkuId               int64           `json:skuId`
    Qty                 int64           `jsog:qty`
    Committed           `xorm:"extends"`   
}
```

사용자 행동에 의해 생성된 데이터는 **수불 데이터**이고, 그에 영향을 받은 데이터는 **재고 수량** 입니다. 이 부분에 **enum**을 할용하여 수불의 상태 마다 **재고계산**을 하고 싶었습니다.  

```go
type Status struct {
	Code            string          `json:"code"`
	CalculateStock  func(locationId, skuId, qty int64) error
}

const (
  Shipment = Status{
        Code: "S",
        CalculateStock: func(shipmentLocationId, skuId, qty int64) error {
            ...
        }
  }
  Receipt = Status{
      Code: "R",
      CalculateStock: func(receiptLocationId, skuId, qty int64) error {
            ...
      }
  }
)
```

하지만 이렇게 하면 IDEA 에서 에러가 발생 합니다.

![struct 형으로 const 선언 못함](https://www.popit.kr/content/images/wp/2020/04/struct-%E1%84%92%E1%85%A7%E1%86%BC%E1%84%8B%E1%85%B3%E1%84%85%E1%85%A9-const-%E1%84%89%E1%85%A5%E1%86%AB%E1%84%8B%E1%85%A5%E1%86%AB-%E1%84%86%E1%85%A9%E1%86%BA%E1%84%92%E1%85%A1%E1%86%B7-600x103.png)

![Screen Shot 2020-04-02 at 11.59.55 PM](https://www.popit.kr/content/images/wp/2020/04/Screen-Shot-2020-04-02-at-11.59.55-PM-600x394.png)

동료의 리뷰

Java에서는 enum도 독립된 class이기 때문에 **상태와 행위를 함께** 묶을 수 있습니다. 그런데 Golang을 사용하는 우리 팀은 **상태와 행위를 함께 관리** 하기위해 임시방편으로 **var**를 사용했었고 **코드 리뷰**를 통해 오사용을 방지 하고 있습니다. 그렇지만 **변경될 여지**가 있어서 **2% 부족** 합니다. 이런 한계점을 해결하기 위해서 [Golang 커뮤니티에서도 enum이 필요하다는 제안](https://github.com/golang/go/issues/19814?ref=popit.kr#issue-218638547)이 있었습니다. 빠른 시일내에 반영되었으면 좋겠습니다.