피드로 돌아가기
코드 품질 개선 기법 22편: To equal, or not to equal
LINE Engineering
Backend

코드 품질 개선 기법 22편: To equal, or not to equal

LY Corporation의 Review Committee가 equals 오버라이딩 시 일부 속성만 비교하는 안티패턴을 분석해 StateFlow와 Flow의 distinctUntilChanged 동작 오류 원인 규명

2025년 11월 7일9intermediate

Context

Java/Kotlin에서 equals를 오버라이딩할 때 일부 속성만 비교하면 예상치 못한 버그가 발생한다. StateFlow, Flow(distinctUntilChanged), Observable, LiveData 등의 observable은 equals 메서드를 사용해 이전 인스턴스와 비교하는데, 불완전한 equals 구현으로 인해 일부 속성 변경이 감지되지 않는다.

Technical Solution

  • equals 메서드는 동일성(identity) 또는 등가성(equivalence) 중 정확히 하나를 나타내도록 정의: 동일성은 Object/Any의 기본 equals 사용, 등가성은 모든 속성 비교
  • Kotlin data class 활용해 자동으로 생성자 파라미터의 모든 속성을 비교하는 등가성 구현
  • 일부 속성만 비교해야 하는 경우 별도의 커스텀 메서드 정의(예: hasSameIdWith) 및 observable과 분리
  • 예외적으로 캐시나 메모 같은 부가 속성은 등가성 정의에서 제외 가능하나, 그 동작 차이를 무시할 수 있는 경우에만 적용
  • 등가성 정의 시 모델의 용도(표현 vs 계산)에 따라 비교 기준을 신중하게 결정

Key Takeaway

equals 메서드는 반드시 동일성과 등가성 중 하나의 명확한 의미를 가져야 하며, 일부 속성만 비교하는 구현은 observable과 함께 사용될 때 상태 변경 감지 실패를 초래한다.


StateFlow, Flow, Observable, LiveData 등을 사용하는 Kotlin/Java 프로젝트에서 데이터 모델의 equals를 오버라이딩할 때, 모든 속성을 비교하는 등가성 정의를 기본으로 하고, 특정 속성만 비교해야 한다면 별도의 명명된 메서드로 분리하면 UI 업데이트 누락 버그를 방지할 수 있다.

원문 읽기