
전통적인 흐름 제어가 실행 시점(Runtime)의 데이터 값에 의존했다면, 현대적 설계는 이를 구조(Type)의 영역으로 격상시킵니다.
| 구분 | 값 기반 분기 (런타임) | 타입 기반 분기 (컴파일 타임) |
|---|---|---|
| 핵심 기제 | if-else, switch, 상태 코드, 플래그 | 합타입(Sum Type), match/when, 대수타입 |
| 흐름의 성격 | 코드 곳곳에 흩어진 파편화된 경로 | 타입 정의에 의해 닫힌 경로 공간 |
| 강제성 | 누락 시 런타임 오류 혹은 논리적 미아 발생 | 누락 시 컴파일 오류 (Exhaustive Check) |
| 추적성 | 실행 경로 예측을 위한 조건문 전수 조사 | 타입 정의 자체가 흐름의 지도 역할 |
match/when은 단순한 분기문이 아니라, 분기 결과를 다음 단계의 값으로 변환하여 전달하는 "전이 장치"입니다.match에서 처리될 수밖에 없는 구조로 타입을 먼저 구성합니다.소프트웨어의 복잡성은 '시간'에 따라 변하는 것과 변하지 않는 것을 구분하지 못할 때 발생합니다.
3, "Hello"와 같이 시공간을 초월하여 변하지 않는 데이터.Entity<ID, VO>: ID는 변하지 않으며, VO는 전이에 의해 교체됩니다.
| 전략 | 상태 전이 | 값 사상 |
|---|---|---|
| 메커니즘 | 식별자 내부의 값을 교체 | 주어진 값을 변환하여 새 값을 반환 |
| 비정상 처리 | 값 교체 거부 혹은 예외 발생 | 특수한 타입(Option, Either) 반환 |
| 철학 | 객체 간의 메시지 협력 | 함수 간의 합성 및 사상 |
사상이 성공하려면 모든 입력에 대해 반드시 결과가 보장되어야 합니다.
부수효과가 발생하는 순간 함수는 전함수가 아니게 되며, 합성이 불가능해집니다.
Either, Option, Result).map, flatMap 등을 통해 일관된 시그니처로 관리합니다.// 예시: Either를 이용한 대수적 부수효과 처리
sealed interface Either<out L, out R> {
data class Left<out L>(val error: L) : Either<L, Nothing>
data class Right<out R>(val result: R) : Either<Nothing, R>
// 사상을 유지하며 안전하게 흐름을 이어감 (전함수성 유지)
fun <T> map(block: (R) -> T): Either<L, T> = when (this) {
is Left -> this
is Right -> Right(block(result))
}
}
가장 이상적인 설계는 "논리는 순수한 함수에 두고, 그 함수들이 연결되는 흐름은 타입 시스템이 강제하는 구조"입니다.
match로 강제합니다.이러한 접근을 통해 개발자는 "발견되는 흐름"을 뒤쫓는 것이 아니라, "보장된 흐름" 위에서 안전하게 로직을 전개할 수 있습니다.