Recent Posts
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- pytest
- 달인막창
- JanusGateway
- PytestPluginManager
- table not found
- python
- 깡돼후
- terminal
- 헥사고날아키텍처 #육각형아키텍처 #유스케이스
- 개성국밥
- JanusWebRTC
- 겨울 부산
- JanusWebRTCServer
- k8s #kubernetes #쿠버네티스
- Value too long for column
- 오블완
- taint
- VARCHAR (1)
- vfr video
- 자원부족
- preemption #
- 코루틴 컨텍스트
- 코루틴 빌더
- kotlin
- Spring Batch
- mp4fpsmod
- 티스토리챌린지
- tolerated
- JanusWebRTCGateway
- PersistenceContext
Archives
너와 나의 스토리
[Kotlin] 안전하게 프로그래밍 하기 본문
반응형
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
출처
- [코틀린을 다루는 기술]
반응형
'Programming Language > Kotlin' 카테고리의 다른 글
[Kotlin] 재귀 함수 값(val) 사용하기, 재귀 함수 초기화 문제 해결 by lazy (0) | 2021.09.06 |
---|---|
[Kotlin] 재귀 함수의 꼬리 호출 제거(TCE): tailrec 키워드 (0) | 2021.09.06 |
[Kotlin] 위임 프로퍼티(delegated property) / by lazy()를 사용한 초기화 지연 / lateinit (0) | 2021.06.29 |
[Kotlin] 연산자 오버로딩 (0) | 2021.06.22 |
[Kotlin] 컬렉션과 배열 (0) | 2021.06.18 |
Comments