Optional.map 안의 긴 람다로 구독 유효성을 판정하던 코드를 읽기 쉬운 도메인 메서드로 바꾼 작은 리팩토링 사례다. 짝 프로그래밍으로 실제 조건을 먼저 문장으로 풀고, 상대적인 이름을 고친 뒤 null·상태·기간 검사를 작은 메서드로 캡슐화했다. 줄 수를 줄이는 것보다 동료가 조건을 순서대로 이해하고 변경할 수 있게 만드는 것이 목표다.
핵심 포인트- 기존 람다는 null 검사, 기간 타입, 만료일, 사용자 상태를 한 블록에서 처리해 의도를 파악하기 어려웠다.
- isUsedOldSubscription이라는 이름은 실제로 검사하는 유효성을 드러내지 못하고 old라는 상대적 표현까지 포함했다.
- 조건을 hasValidPeriod, hasValidExpireDate, isUsable, isNotExpired, isUserStatusNormal로 나눴다.
- 유효하지 않은 입력은 빠르게 false를 반환하고 마지막에 핵심 비즈니스 조건을 AND로 결합했다.
- After 코드가 더 길어도 도메인 지식이 적은 개발자가 메서드 이름만 따라가며 판단 흐름을 읽을 수 있다.
상세 정리- 원래 목적: 현재는 구매할 수 없는 과거 구독형 서비스를 회원이 여전히 사용할 수 있는지 판단하는 로직이었다.
- 기존 구현: Optional.map의 람다 안에서 별도 null 검증을 호출하고 기간 타입이 N이 아닌지, 만료일이 미래인지, 회원 상태가 NORMAL인지 한 번에 계산했다.
- 악취 진단: 변수와 메서드 이름이 의미를 설명하지 못했고, 하나의 람다가 여러 도메인 규칙을 표현했다. Optional 파이프라인도 자연스럽게 읽히지 않았다.
- 규칙 명시: NORMAL 회원이어야 하고 기간 타입이 N이 아니며 만료일이 현재 이후여야 한다. 관련 필드 중 하나라도 null이면 false다.
- 이름 변경: 레거시 여부가 아니라 유효성을 검사하므로 isUsedOldSubscription을 isValidSubscription으로 바꿨다.
- 상대어 제거: old는 시간과 맥락에 따라 의미가 달라져 메서드 계약을 안정적으로 설명하지 못한다는 점도 변경 근거였다.
- 필드 검증: 기간 타입과 만료일의 null 여부를 각각 hasValidPeriod와 hasValidExpireDate로 감쌌다.
- 상태 메서드: 기간 타입 사용 가능 여부, 만료 여부, 회원 NORMAL 여부도 각각 이름 있는 boolean 메서드로 분리했다.
- 캡슐화 효과: 필드의 유효 기준이 바뀌면 호출부의 전체 조건문이 아니라 해당 검증 메서드만 수정할 수 있다.
- 흐름 재구성: 잘못된 기간과 만료일은 early return으로 끝내고, 남은 사용자 상태·사용 가능·미만료 조건만 마지막 반환식에서 결합했다.
- 대안 형태: 팀 취향에 따라 모든 작은 predicate를 하나의 AND 식으로 연결할 수도 있음을 함께 제시했다.
- 개선 결과: 각 조건을 머릿속에 보관할 필요가 줄고 빠른 반환으로 실패 지점을 순서대로 읽을 수 있게 됐다.
- 교훈: 람다는 일회성 로직이라는 이유만으로 선택할 도구가 아니다. 가독성이 떨어지면 명시적인 메서드와 비교한 뒤 더 이해하기 쉬운 쪽을 골라야 한다.
왜 읽나Optional과 람다를 과도하게 압축한 Java 도메인 로직을 의도가 드러나는 이름과 작은 predicate로 풀어내는 기준을 얻을 수 있다.