그래서 테스트 모듈을 분리하게 되었습니다

서연주·2022년 7월 19일
0

SWMaestro

목록 보기
4/6

며칠 전에 아래와 같은 글을 썼었다

테스트 써본 적 없다...더미 데이터를 만들어서 테스트를 하고 있긴한데 분리가 안돼있으니까 할 때마다 이래저래 주석처리를 해야하고...경우에 따라 적절한 테스트 코드 위치를 찾다보니까
테스트 데이터에서는 안되던 게 본래 데이터로는 되고...그것도 모르고 삽질하고 아주 난리났다ㅋㅋㅜ 아 모듈화 하고싶어요 너무!!!!

그래서 스프린트2 회고 시간에 모듈 분리의 필요성에 관해 말씀드리게 되었다. 마침 같이 클라이언트 사이드를 맡은 팀원 분도 공감을 해주셔서 높은 우선 순위까지 부여받은 상태로!! 일을 추진할 수 있게 되었다. 이런 업무를 담당할 수 있어서 굉장히 기쁘다.

기존 코드를 파악해보니 test 코드와 test 코드가 대체하고 있는 production 코드 부분의 로직이 달라서 2가지 로직을 모두 만족하는 코드 위치를 찾기 위해 고군분투해야했고, 결론적으로 production 코드와 로직이 다르니 적절한 테스트가 이뤄진다고 볼 수도 없는 상태였다.

그래서 모듈을 분리하고 동일한 로직을 대체할 수 있도록 test 코드를 분리하기로 했다.
그러기 위해 멘토님께 배운 PlantUML로 시퀀스 다이어그램도 그려보고, Expert님께 배운 ADR도 드디어 용도에 딱맞게!(참작의 여지가 있긴 하지만 아무튼 방법론 선택할 때 써버렸다) 써보았다.

아래 작성한 ADR이 많은 이야기를 담고 있어서 우선 ADR부터 첨부해본다.


테스트 코드 모듈화를 위한 ADR

상태

제안됨, 수락됨, 거부됨, 더 이상 사용되지 않음, 대체됨 등과 같은 상태는 무엇입니까?

07.19 제안됨
07.19 수락됨

문맥

우리가 보고 있는 이 결정이나 변경의 동기가 되는 문제는 무엇입니까?

문제 상황

현재 객체들 간 의존 관계가 깊고, 복잡하여 기능별 동작 테스트를 시행하기에 불편함을 겪고있습니다. 저희가 겪는 불편함은 아래와 같습니다.

  1. 테스트용 코드 위치가 산재되어 있어 테스트를 시행할 때마다 대치되는 production 코드를 모두 찾아 주석처리하고 해당 코드의 주석처리를 해제해야 하는 번거로움이 있습니다.
  2. 테스트용 코드가 production 코드와 혼재되어 주석 처리 누락으로 인한 버그 발생 우려가 있습니다.
  3. 새로운 테스트용 코드를 작성할 위치를 명확히 파악하기가 어렵습니다.
  4. production 코드에서는 나지 않는 오류가 테스트용 코드에서 발생합니다.
  5. 위 문제를 감당하기 위해 테스트를 시행할 때마다 시간적인 리소스가 크게 들고있습니다.

위와 같은 문제를 방지하고, 최종적으로 단 한 줄의 주석 처리 만으로 테스트용 코드 또는 production용 코드를 시행하고자 모듈을 분리하고 새로운 상태 관리 패키지를 도입할 것을 제안드립니다.

현재 코드 구조

0719 모듈 분석 보완.pdf

현재 production 코드 구조는 크게 타이머를 조작하는 Timer와 속도를 측정하는 Speed로 구분되어 있습니다.

  • Timer 내부에서는 시간을 체크하여 현재 인터벌 걷기의 타입을 결정하고 그에 따라 Timer의 시간을 결정하고 있습니다.
  • Speed 내부에서는 권한을 확인하고 그에 따라 GPS 세팅을 한 뒤 현재 속도를 감지합니다. 그리고 변경된 속도값을 파라미터로 하여 피드백을 출력하도록 하고 있습니다.

테스트용 코드는 testWithChangingSpeedData라는 하나의 함수로 작동되고 있습니다.

initState 함수에서 호출된 testWithChangingSpeedData 함수 내부

본래의 코드와 가장 다른 점은 타이머를 조작하는 Timer 부분과 매번 새로운 속도값이 생성되는 Speed 부분이 분리되지 않았다는 점입니다.

코드가 이렇게 작성된 이유는 일정한 간격을 주지 않으면 테스트 데이터 list를 for문이 너무 빠르게 시행되었기 때문입니다. 또한 이후에도 함수를 쉽게 분리할 수 없었던 이유는 여러 state 값을 받아오고 또 변경해야하는 데에 어려움이 있었기 때문입니다.

이로 인해 production 코드 test 코드의 로직이 달라지면서 의미있는 테스트 시행이 어려워졌습니다.

상태state 관리

저희가 관리해야하는 상태 데이터는 2가지로 분류할 수 있습니다.

  1. 해당 위젯 내부 만을 변경하며, 다른 위젯이 해당 상태값에 접근할 필요도 없고, 앱이 종료되어도 해당 상태값을 기억할 필요가 없는 Ephemeral State입니다. 해당 state는 특별한 상태 관리 없이 Stateful 위젯만으로도 충분히 관리할 수 있습니다.
  2. App State(=Shared State)는 Ephemeral state의 여집합으로, 다른 위젯과 값을 공유 하고, 저장도 해야하는 state입니다. 해당 상태값을 효율적으로 관리하기 위해 필요한 것이 상태 관리 패키지입니다.

공식 문서에 따르면 Ephemeral state는 setState만으로 충분히 관리할 수 있습니다. 하지만 저는 앞으로의 확장성을 고려하여, 분리된 모듈의 state 값을 편리하게 관리할 수 있는 패키지 도입을 제안드립니다.

Provider vs GetX

  • Provider

provider | Flutter Package

Provider는 공식 문서에서 추천하는 상태관리 패키지입니다. 특별한 이유가 없다면 이 패키지를 사용할 것을 추천하고 있습니다.

If you are new to Flutter and you don’t have a strong reason to choose another approach (Redux, Rx, hooks, etc.), this is probably the approach you should start with.
리액트 공식 문서 Simple app state management

Flutter Favorite에 선정되어 품질 보장이 어느정도 된다고 볼 수 있으며, 상태 관리 만을 위해 출시된 패키지 이므로 훨씬 간편하게 익힐 수 있다는 장점이 있습니다. 검색 결과도 더욱 많은 것으로 보입니다.

하지만 상태값을 공유하기 위한 위젯들 간의 context를 고려하여야 한다는 번거로움이 있습니다.
상태값을 공유할 위젯 상단에 context를 선언하고 하위 위젯들끼리는 context를 주고받아야 합니다. 또한 효율적인 rebuild를 위해서라면 context를 가능한 한 말단에 선언해야하나 상태값을 주고받는 로직이 복잡해지면 결국 최상단에 context를 선언하게 되는 딜레마가 발생할 수 있습니다.

  • GetX

get | Flutter Package

상태관리 뿐만 아니라 네비게이션(라우팅) 기능까지 함께 지원하는 패키지입니다. 화면을 이동하며 데이터를 주고받는 경우가 많을 시 유용한 특성입니다.

Provider와 달리 context에 신경쓸 필요 없이 자유롭게 state를 주고받으며 관리할 수 있습니다. 코드도 더욱 간결해진다고 합니다.

하지만 지원하는 기능이 많은 만큼 해당 패키지 사용법을 파악하는 데에 어려움을 겪을 수 있습니다. obs라는 반응형 개념을 새롭게 파악하고 어떤 메소드를 사용할지에 관해 서로 합의하는 과정이 추후에 필요해질 수 있습니다.

결정

우리가 제안 및/또는 하고 있는 변경 사항은 무엇입니까?

분리

timer_screen.dart의 로직을 그린 시퀀스 다이어그램

위와 같이 Timer, Speed, Feedback, Audio로 모듈을 분리하고 호출하여 사용할 것을 제안드립니다.

상태 관리 패키지

GetX 사용을 제안드립니다.

결과

이 변경으로 인해 무엇을 하는 것이 더 쉬워지거나 더 어려워지는가?

Speed 모듈과 Test 모듈이 동일한 로직과 의존성을 갖게 되어 새로운 테스트 코드 작성이 쉬워질 것으로 예상됩니다.

코드 작성 시 Ephemeral state와 App State를 구분해야합니다.

상태 관리 패키지를 새롭게 학습하고 사용하는 데에 어려움이 있을 수 있습니다.


팀원분께 상세한 설명으로 칭찬들었다! v^^V
현재의 문제 상황과 개선 방향을 비교와 대조를 통해 명확하게 드러내려고 공을 들였다. 또한 state 관리에 관한 기본적인 개념은 따로 자료를 찾아볼 필요 없이 내가 알게된 내용을 작성하여 추가적인 검색 과정을 없애드리려고 했다.

아쉬웠던 점은...첨부한 사진에도 나오지만 글씨를 좀 더 알아보게 쓰면 더 좋았을 것이라는 거... ㅋㅋ 그치만 아무튼 내용은 좋았다

현재는 위의 결정사항을 가지고 모듈을 분리하고 있다. 할당 포인트가 부족할 것 같아서 데이터 흐름도를 따로 그리진 않았지만 시퀀스 다이어그램을 써두니까 코드를 분리할 때 훨씬 편리하다... private과 static 문제로 조작이 곤란한 함수는 getX를 통해 해결하면 될 것 같다. 주어진 포인트 내에 꼭 해결할 수 있으면 좋겠다.

profile
pizz@ttang

0개의 댓글