며칠 전에 아래와 같은 글을 썼었다
그래서 스프린트2 회고 시간에 모듈 분리의 필요성에 관해 말씀드리게 되었다. 마침 같이 클라이언트 사이드를 맡은 팀원 분도 공감을 해주셔서 높은 우선 순위까지 부여받은 상태로!! 일을 추진할 수 있게 되었다. 이런 업무를 담당할 수 있어서 굉장히 기쁘다.
기존 코드를 파악해보니 test 코드와 test 코드가 대체하고 있는 production 코드 부분의 로직이 달라서 2가지 로직을 모두 만족하는 코드 위치를 찾기 위해 고군분투해야했고, 결론적으로 production 코드와 로직이 다르니 적절한 테스트가 이뤄진다고 볼 수도 없는 상태였다.
그래서 모듈을 분리하고 동일한 로직을 대체할 수 있도록 test 코드를 분리하기로 했다.
그러기 위해 멘토님께 배운 PlantUML로 시퀀스 다이어그램도 그려보고, Expert님께 배운 ADR도 드디어 용도에 딱맞게!(참작의 여지가 있긴 하지만 아무튼 방법론 선택할 때 써버렸다) 써보았다.
아래 작성한 ADR이 많은 이야기를 담고 있어서 우선 ADR부터 첨부해본다.
제안됨, 수락됨, 거부됨, 더 이상 사용되지 않음, 대체됨 등과 같은 상태는 무엇입니까?
07.19 제안됨
07.19 수락됨
우리가 보고 있는 이 결정이나 변경의 동기가 되는 문제는 무엇입니까?
현재 객체들 간 의존 관계가 깊고, 복잡하여 기능별 동작 테스트를 시행하기에 불편함을 겪고있습니다. 저희가 겪는 불편함은 아래와 같습니다.
위와 같은 문제를 방지하고, 최종적으로 단 한 줄의 주석 처리 만으로 테스트용 코드 또는 production용 코드를 시행하고자 모듈을 분리하고 새로운 상태 관리 패키지를 도입할 것을 제안드립니다.
현재 production 코드 구조는 크게 타이머를 조작하는 Timer와 속도를 측정하는 Speed로 구분되어 있습니다.
테스트용 코드는 testWithChangingSpeedData라는 하나의 함수로 작동되고 있습니다.
initState 함수에서 호출된 testWithChangingSpeedData 함수 내부
본래의 코드와 가장 다른 점은 타이머를 조작하는 Timer 부분과 매번 새로운 속도값이 생성되는 Speed 부분이 분리되지 않았다는 점입니다.
코드가 이렇게 작성된 이유는 일정한 간격을 주지 않으면 테스트 데이터 list를 for문이 너무 빠르게 시행되었기 때문입니다. 또한 이후에도 함수를 쉽게 분리할 수 없었던 이유는 여러 state 값을 받아오고 또 변경해야하는 데에 어려움이 있었기 때문입니다.
이로 인해 production 코드 test 코드의 로직이 달라지면서 의미있는 테스트 시행이 어려워졌습니다.
저희가 관리해야하는 상태 데이터는 2가지로 분류할 수 있습니다.
공식 문서에 따르면 Ephemeral state는 setState만으로 충분히 관리할 수 있습니다. 하지만 저는 앞으로의 확장성을 고려하여, 분리된 모듈의 state 값을 편리하게 관리할 수 있는 패키지 도입을 제안드립니다.
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를 선언하게 되는 딜레마가 발생할 수 있습니다.
상태관리 뿐만 아니라 네비게이션(라우팅) 기능까지 함께 지원하는 패키지입니다. 화면을 이동하며 데이터를 주고받는 경우가 많을 시 유용한 특성입니다.
Provider와 달리 context에 신경쓸 필요 없이 자유롭게 state를 주고받으며 관리할 수 있습니다. 코드도 더욱 간결해진다고 합니다.
하지만 지원하는 기능이 많은 만큼 해당 패키지 사용법을 파악하는 데에 어려움을 겪을 수 있습니다. obs라는 반응형 개념을 새롭게 파악하고 어떤 메소드를 사용할지에 관해 서로 합의하는 과정이 추후에 필요해질 수 있습니다.
우리가 제안 및/또는 하고 있는 변경 사항은 무엇입니까?
timer_screen.dart의 로직을 그린 시퀀스 다이어그램
위와 같이 Timer, Speed, Feedback, Audio로 모듈을 분리하고 호출하여 사용할 것을 제안드립니다.
GetX 사용을 제안드립니다.
이 변경으로 인해 무엇을 하는 것이 더 쉬워지거나 더 어려워지는가?
Speed 모듈과 Test 모듈이 동일한 로직과 의존성을 갖게 되어 새로운 테스트 코드 작성이 쉬워질 것으로 예상됩니다.
코드 작성 시 Ephemeral state와 App State를 구분해야합니다.
상태 관리 패키지를 새롭게 학습하고 사용하는 데에 어려움이 있을 수 있습니다.
팀원분께 상세한 설명으로 칭찬들었다! v^^V
현재의 문제 상황과 개선 방향을 비교와 대조를 통해 명확하게 드러내려고 공을 들였다. 또한 state 관리에 관한 기본적인 개념은 따로 자료를 찾아볼 필요 없이 내가 알게된 내용을 작성하여 추가적인 검색 과정을 없애드리려고 했다.
아쉬웠던 점은...첨부한 사진에도 나오지만 글씨를 좀 더 알아보게 쓰면 더 좋았을 것이라는 거... ㅋㅋ 그치만 아무튼 내용은 좋았다
현재는 위의 결정사항을 가지고 모듈을 분리하고 있다. 할당 포인트가 부족할 것 같아서 데이터 흐름도를 따로 그리진 않았지만 시퀀스 다이어그램을 써두니까 코드를 분리할 때 훨씬 편리하다... private과 static 문제로 조작이 곤란한 함수는 getX를 통해 해결하면 될 것 같다. 주어진 포인트 내에 꼭 해결할 수 있으면 좋겠다.