상세 컨텐츠

본문 제목

[Medium/번역] Swift 로 Money Type 만들기

Swift

by Mr.Garlic 2022. 10. 6. 16:57

본문

Swift로 Money 타입 만들기

핀테크 도메인이 인기를 얻으면서 개발 관련해서도 많은 논의가 이루어지고 있습니다. 그래서 이번에는 스위프트를 사용해 돈을 저장하는 방법에 대해서 이야기 해보려고 합니다. 이게 애초에 왜 문제가 되는지부터 이야기 해보도록 하죠. 

Decimal vs Binary 숫자 시스템 비교 - 문제의 궁극적인 원인

인간은 10진수를 사용해 숫자를 세죠, 컴퓨터는 2진수를 편하게 생각합니다. 정수같은 경우는 10진수에서 2진수로 문제없이 변환이 될 수 있지만, 문제는 소수일 때 입니다. 10진 소수가 정확하게 2진 소수로 변환이 되지 않기 때문인데요. 10진법 소수의 분모가 2진법 정수의 거듭제곱일때만 정확하게 2진법 소수로 변환이 가능하죠. 

 

아래의 예시를 보시면, 0.001(Float 타입)을 100번 더하도록 만들어 둔 코드가 있습니다. 우리 상식으로 생각하면 총 합이 1이 되어야겠죠? 그런데 결과를 보면 그렇지가 않습니다. Float(이진타입)의 경우 0.01의 값을 정확히 표시하지 못하기 때문입니다. 

 

Rounding Errors using base 2 Floats

그럼 이 문제를 어떻게 해결하면 좋을까요? 이때 우리는 NSDecimalNumber를 사용하면 됩니다. 소수점을 사용해서 정확한 연산이 필요할때면 언제든 NSDecimalNumber를 사용하시면 돼요.

NSDecimalNumber는 NSNumber의 불가변의 서브클래스로, 객체 지향적인 wrapper를 사용해 10진법 산수를 하도록 도와줍니다. 이 인스턴스를 사용하면 가수부(1.xxxx 형태로 정규화를 한 뒤 가장 왼쪽에 있는 1을 제거하고 소수점 이하의 자리 값만 표현)에 10 거듭제곱을 사용해 숫자를 나타내주며, 가수부의 경우 38자리까지, 거듭제곱은 정수로 -128부터 127까지 사용이 가능합니다. 

 

아래 예시를 보시면 NSDecimalNumber을 Float로 검증하는 예시를 보실 수 있습니다. 

Float vs NSDecimalNumber

이해하시는데 도움이 되셨으면 좋겠습니다. 나머지 포스팅에서는 NSDecimalNumber를 사용한 Money 타입을 만들어보고, 간단한 통화 변환기를 만들어보도록 하겠습니다.

Money 타입 정의하기

우리가 오늘 만들려고 하는 이 Money 타입은 불가변한 객체이면서 돈의 양과 화폐 타입을 가지고 있어야합니다. 저는 Struct를 사용해서 Money 타입을 생성하고 화폐를 계산하는 기능이 있게 만들기로 했는데요. 돈의 양과 화폐의 연결성을 강조하기 위해, 그 값을 튜플로 Struct안에 저장하도록 해 두었습니다. 그 밖에는 여러분이 생각하시는 바와 같이 구현을 했는데요. Property getter로 value를 반환하도록 하고, Money를 다양한 방식으로 생성할 수 있는 initializer들을 만들어 두었습니다. 그리고 수학적 연산이 가능한 helper function도 만들었습니다. 플레이그라운드 파일은 여기에서 다운로드가 가능합니다. 

Money 스트럭트

Money를 다듬어 나가는 과정에서, 화폐끼리의 계산과 환율에 대한 열거형(Enum)을 만들어 두었습니다. 환율에 대한 부분은 차차 설명드리도록 하고요, 지금은 NSDecimalNumber라는 객체를 사용함에 있어서의 생소함을 어떻게 해결해야하는지에 먼저 집중해보도록 하겠습니다. 

NSDecimalNumber는 굉장히 유용하지만, 다루기 쉬운 클래스는 아니예요. 이니셜라이저만 해도 여러개가 있는데요. 수학 연산자를 쓰는 것은 뭔가 장황하고 어려워보이죠. 게다가 NSDecimalNumberHandler를 사용해서 올림, 버림, 넘치는 자릿수나 범위를 넘어가는 음수 등을 어떻게 처리할지 다 정해줘야 하죠.  저는 Money 타입을 사용할 때, NSDecimalNumber의 기저에 깔려있는 소소한 디테일을 몰라도 걱정없이 사용하고 싶은데요. 연산자도 사용하고 싶고, 타입이 섞여있을 때도 더하고, 빼고 등등을 하고 싶어요. 

제가 선택한 방식은 연산자 오버로딩 이었습니다. 

Operator overloading

위의 코드를 보시면, 더하기 연산자를 오버로드해서 NSDecimalNumber를 서로 더할 수 있도록 만들어 보았습니다. 추가적으로 Float와 Money를 더할 수 있게 해서 편리하게 사용하도록 해보았습니다. 다른 연산자들도 몇가지 더 만들어 두었으니 여러분이 편의성을 강화하거나 객체 생성을 더 편하게 하고 싶으시다면 확인해보세요. 

 

우리에게 필요한 또 다른 기능은 두가지의 Money 타입을 비교하는 것입니다. Comparable 프로토콜을 채택하게 되면 사용하실 수가 있는데요. 우리는 Money 객체에 == 연산자와 <연산자만 정의를 해주면 스위프트가 나머지 !=, >, <=, >= 연산자를 알아서 해줄거예요. 

Comparable protocol 적용하기

화폐 변환기 만들기

이제 Money 타입을 만들어줬으니, 화폐 변환기를 만들어주겠습니다. 환율만 가지고 있다면 두 화폐로 변환을 해줄건데요. 저희가 하고 싶은 이 기능을 수행하려면, 환율을 나타낼 방법이 필요합니다. 저는 Hashable 프로토콜을 채택한 환율 스트럭트를 만들어 주었는데요. 특히 이것들을 집합(Set)형태로 관리하고 싶었습니다. 순서가 중요하지도 않고, 중복된 값도 필요가 없어서요. 환율 스트럭트는 3개의 프로퍼티만을 가지는데요. 첫번째 화폐, 두번째 화폐, 그리고 비율입니다. 추가적으로 inverseRate(역비율)라는 연산프로퍼티도 만들어 주었습니다. 역으로 계산해야 할 상황도 고려해서요.

Exchange Rate struct implementing Hashable protocol

 

위에서 만들어본 화폐 변환기는 꽤 단순한데요. Money 타입 내에 static한 집합을 더해줘서 환율정보를 가지고 있도록 해 주었습니다. 변환이 필요할 때는, amountIn(currency: Currency) -> Money 라는 함수를 사용해서 적절한 환율을 해당 집합에서 확인하고 변환해서 새로운 Money 타입으로 반환하도록 만들어 두었어요. 

Currency converter function on the Money struct

아래 코드를 보시면 Money 객체를 어떻게 사용하실 수 있고, 화폐 변환이 어떻게 일어나는지를 보실 수 있어요. 저는 CustomStringConverible 프로토콜을 채택해서 객체가 더 잘 읽히도록 만들어 두었습니다. 

Exercising our Money type with exchange rates

마무리

이렇게 Money 타입을 만들어서 10진법 연산을 더욱 정확하게 할 수 있게하고, 화폐 단위를 알도록 만들어 보았어요. 이렇게 만든 Money 타입은 다른 숫자 타입들처럼 사용할 수 있고, Float와 같은 타입과 섞어서도 사용이 가능해요. 여기서 마무리하면서 여러분이 필요에 따라 더 확장하실 수 있도록 열어두겠습니다. 다시 말씀드리지만 플레이그라운드 파일은 여기에서 다운로드가 가능합니다. 

 

도움이 되셨다면 다른 분들께도 추천 부탁드립니다. 저(원글쓴이)의 더 많은 글은 www.gittielabs.com 에서 보실 수 있구요, 제 피드 구독하셔서 포스팅 놓치지 않으셨으면 좋겠습니다. 읽어주셔서 감사합니다!

 

위 글은 Medium의 https://medium.com/swift-programming/creating-a-money-type-in-swift-3b060fb762ed 를 번역한 글 입니다.

관련글 더보기