관리 메뉴

너와 나의 스토리

[Kotlin] 안전하게 프로그래밍 하기 본문

Programming Language/Kotlin

[Kotlin] 안전하게 프로그래밍 하기

노는게제일좋아! 2021. 8. 23. 00:59
반응형

1. 부수 효과 없애자

  • 값을 반환하는 메서드나 함수가 외부 상태를 변경하는 경우 이를 부수 효과(side effect)라고 한다.
  • 부수 효과를 사용하는 프로그램은 잘못된 것이다.
  • 이런 부수 효과는 단일 책임 원칙(single responsibility principle)을 위배하는 좋지 못한 기법이다.
  • 안전한 대안:
    • 계산 때문에 일어나는 상태 변이와 프로그램의 나머지 부분을 분리하거나 계산하는 부분을 최대한 추상화하기

 

2. 참조 투명성

  • 프로그램을 충분히 안전하고 결정적으로 만들려면 외부 세계로부터 영향을 받아서도 안 된다.
  • 즉, 프로그램의 출력은 오직 그 인자에 의해서만 영향을 받아야 한다.
  • 외부 세계의 상태를 변경하지도 않고 외부 상태에 의존하지도 않는 코드를 일컬어 참조 투명(referentially transparent)하다고 한다.
  • 참조 투명한 코드는
    • 자기 완결적이다.
      • 어떤 문맥에서나 그 코드를 사용할 수 있다.
    • 결정적이다.
      • 인자가 같으면 항상 결과도 같다.
    • 절대 예외를 던지지 않는다.
      • 예외를 던지면 프로그램 흐름이 어디서 시작하는지 알 수 있지만, 어디로 흘러가는지 제대로 따라갈 수 없게 될 수도 있다(spaghetti code).
      • * 다만 out of memory error나 stack overflow error는 발생 가능 -> 프로그램 버그
    • 예기치 않게 다른 코드가 실패하는 상황을 만들지 않는다.
      • 참조 투명한 코드는 인자를 변경하거나 다른 외부 데이터를 변경하지 않으며, 그에 따라 코드를 호출하는 쪽의 데이터가 오염되거나 동시 접근으로 인해 오류가 발생하는 경우가 없다.
    • 자신이 제대로 작동하기 위해 외부 장치에 의존하지 않는다.
      • 참조 투명한 코드는 외부 장치(예: DB, file system, network)를 사용할 수 없다. 

 

 

예제: 부수 효과가 있는 프로그램을 안전하게 바꿔보자.

  • 신용 카드로 도넛을 구매하는 예제를 살표보자.
fun buyDonut(creditCard: CreditCard): Donut {
    val donut = Donut()
    creditCard.charge(Donut.price)
    return donut
}
  • 위의 코드는 부수 효과로 신용 카드를 청구한다.
  • 이런 코드는 테스트하기 어렵다.
    • 테스트하려면 신용카드를 mock으로 만들어야 하고, charge() 함수 호출하는 과정도 mock 처리해야 한다.
  • mock을 사용하지 않고 테스트하기 위해 부수 효과를 없애보자.
    • buyDonut()에서 연산(신용카드 청구)을 하는 게 하는게 아니라, 연산을 나타내는 표현을 반환 값에 덧붙이자.
class Payment(val creditCard: CreditCard, val amount: Int)

class Purchase(val donut: Donut, val payment: Payment)

fun buyDonut(creditCard: CreditCard): Purchase {
    val donut = Donut()
    val payment = Payment(creditCard, Donut.price)
    return Purchase(donut, payment)
}
  • 다음과 같이 수정하게 되면, 지급을 즉시 처리할 수도 있고, 나중에 처리하기 위해 일단 저장해 둘 수도 있다.
    • 심지어는 같은 카드를 사용하는 여러 지급을 저장했다가 한꺼번에 한 연산으로 처리할 수도 있다. 
  • 한꺼번에 처리해주는 combine 함수를 구현해보자.

 

3. 클로저 구현하기

  • 클로저(Closure): 상위 함수의 영역의 변수에 접근할 수 있는 함수
val taxRate = 0.09
fun addTax(price: Double) = price + price * taxRate
  • 위의 예제 코드를 보면, addTax 함수는 taxRate라는 변수에 대해 닫혀 있다.
    • 인자가 같아도 결과가 달라질 수 있기 때문이다.
  • addTax 함수의 매개변수를 (price, taxRate) 튜플로 지정하면 순수 함수가 될 수 있다.
val taxRate = 0.09
fun addTax(taxRate: Double, price: Double) = price + price * taxRate

 

 

 

 

출처

- [코틀린을 다루는 기술]

반응형
Comments