PayU가 MVVM 아키텍처로 코드 테스트 가능성을 개선하는 방법: www.deekpay.com
이 글에서는 PayU가 코드 테스트 가능성, 확장성 및 가독성을 향상시키기 위해 애플리케이션과 SDK를 MVVM 아키텍처로 마이그레이션한 방법을 설명합니다. 지난 몇 년 동안 핵심 비즈니스 로직은 거의 변경되지 않은 채(새로운 기능 제외) 여러 차례 반복적인 사용자 인터페이스(UI) 업데이트를 수행했습니다. 하지만 기존 아키텍처로는 비즈니스 성장에 필요한 업데이트 속도를 따라잡기 어려웠습니다. 따라서 MVVM 아키텍처를 채택하여 코드의 가독성, 확장성, 테스트 가능성을 높이기 위해 기본 아키텍처를 재설계하는 데 중점을 두었습니다.
전에는 어떻게 했나요?
그 전까지는 MVC 패턴을 따랐습니다. 이론적으로는 이 패턴이 잘 작동하는 것처럼 보였지만 코드베이스가 커지고 UI 반복이 증가하면서 두 가지 이유로 코드베이스를 관리할 수 없게 되었다는 것을 깨달았습니다:
UI를 반복할 때마다 UI 코드뿐만 아니라 비즈니스 로직도 변경됩니다. 이는 UI가 비즈니스 로직과 완전히 분리되어 있지 않다는 직접적인 증거입니다.
코드 기반이 확장됨에 따라 단위 테스트 코드의 양이 줄어들어 엔드투엔드 테스트에 점점 더 많이 의존하고 있습니다. 이는 테스트 피라미드가 거꾸로 뒤집힌다는 점에서 그 자체로 나쁜 신호입니다.
잘못된 방향(왼쪽에서 오른쪽)으로 이동하고 있습니다.
문제를 이해하려고 하면 뷰와 컨트롤러가 모두 모델에 의존한다는 사실을 알게 됩니다. 또한 활동과 프래그먼트에는 UI 로직과 컨트롤러 로직이 모두 포함되어 있습니다. 결과적으로 단위 테스트의 코드 양이 줄어들고 코드가 관리하기 어려워집니다.
MVC 아키텍처
MVVM 아키텍처 사용
더 나은 아키텍처를 찾기 시작했고, 그때 MVVM이 우리의 구원이 되었습니다. 심지어 구글도 MVVM을 선호했습니다.
MVVM은 모델-보기-보기 모델의 약자입니다:
모델: 애플리케이션의 데이터 계층을 나타냅니다.
보기: 애플리케이션의 UI 로직을 나타냅니다.
ViewModel: 뷰의 모델입니다. 뷰와 모델 사이의 다리 역할을 하며 뷰를 직접 참조하지는 않습니다.
MVVM 아키텍처는 컴포넌트 간의 긴밀한 결합을 제거합니다. 자식 컴포넌트는 부모 컴포넌트를 직접 참조하지 않고 관찰 가능한 속성을 통해서만 참조합니다. 각 컴포넌트는 다음 레벨의 컴포넌트에만 의존한다는 점에 유의하세요. 이러한 설계는 일관되고 즐거운 사용자 경험을 만들어냅니다.
위 다이어그램에서 또 다른 중요한 구성 요소는 리포지토리 모듈입니다. 이 모듈은 데이터 조작을 처리합니다. 애플리케이션의 다른 부분에서 데이터를 쉽게 검색할 수 있도록 명확한 API를 제공합니다. 데이터를 어디에서 가져와야 하는지, 데이터가 업데이트될 때 어떤 API 호출을 수행해야 하는지 알고 있습니다. 리포지토리는 지속성 모델, 웹 서비스, 캐시 등 서로 다른 데이터 소스 사이의 매개체라고 생각할 수 있습니다.
LiveData는 관찰 가능한 데이터 홀더입니다. 애플리케이션의 다른 구성 요소는 이 홀더를 사용하여 명시적이고 고정된 종속성 경로를 만들지 않고도 객체의 변경 사항을 모니터링할 수 있으며, LiveData 구성 요소는 활동, 조각 및 서비스와 같은 애플리케이션 구성 요소의 수명 주기 상태를 존중하고 객체 유출 및 과도한 메모리 소비를 방지하기 위한 정리 로직을 포함합니다.
vantage
관심사 분리: 모든 코드를 액티비티나 프래그먼트에 작성하는 것은 일반적인 실수입니다. UI 클래스에는 UI와 운영 체제 간의 상호 작용을 처리하는 로직만 포함되어야 합니다. 이러한 클래스를 최대한 단순하게 유지하면 라이프사이클과 관련된 많은 문제를 피할 수 있습니다.MVVM을 사용하면 각 유형의 클래스가 하나의 작업만 담당하도록 할 수 있습니다.
테스트 가능성: 사용자 인터페이스 및 상호 작용은 테스트 케이스(Espresso 라이브러리)를 계측하여 테스트할 수 있습니다. ViewModel(뷰모델)과 저장소(리포지토리)는 JUnit 을 사용하여 테스트할 수 있습니다.
확장성: UI 업데이트를 쉽게 도입할 수 있습니다. 기존 코드 베이스의 많은 부분을 리팩토링하거나 변경하지 않고도 새로운 기능을 추가할 수 있습니다. 컴포넌트를 더 쉽게 삽입하고 가져올 수 있습니다.
관리 용이성: 모든 UI 로직은 한 곳에, 비즈니스 로직과 데이터 로직은 다른 곳에 보관하는 등 코드 기반이 더욱 관리하기 쉬워집니다.
단점
MVVM을 시작하고 새로운 기능을 추가하려면 약간의 패턴 경험이 필요할 수 있습니다. 학습 곡선은 비교적 가파릅니다.
MVVM 패턴을 따르면 더 많은 Java 클래스가 생성될 수 있습니다.
결론
모든 애플리케이션을 구축할 때는 올바른 아키텍처 모델을 선택하는 것이 중요하며, 만능 모델은 존재하지 않습니다.
저희의 경우 반복적인 UI 업데이트가 빈번한 UI가 풍부한 제품을 보유하고 있어 제품의 테스트 가능성에 집중하고 싶었고, 나머지 코드에 영향을 주지 않고 코드 베이스의 관련 구성 요소만 변경할 수 있도록 문제를 분리하고자 했기 때문에 MVVM이 유용한 패턴임을 알 수 있었습니다.
