시리즈

[flutter] 1년 반 동안 써보고 느낀 riverpod 의 단점

20230217
dart
flutter
getx
riverpod
state
state management

모던 플러터 개발에서는 riverpod 이 대세다.

riverpod 0점대 버전부터 2.2가 나온 지금까지 riverpod 을 쓰면서 느낀 단점들을 써보려고 한다.

참고로 나의 호감도 순서는 이렇다.

getx(불호) <<< riverpod <= bloc < provider < get_it (가장 호)

50%의 재미를 위한 약간의 riverpod ‘억까’ 가 있을 수 있다는 점에 주의하자.

riverpod이 나오기 이전으로 돌아가보면,

플러터 개발진, 플러터 GDE 들, 공식 디스코드, 레딧을 포함한 공식 플러터 커뮤니티들에서는 Provider를 많이 지지했었다.

대중적인 점유율에서 get 에게는 밀리고 있었지만, provider 에 의존성을 가지는 bloc 까지 포함해서 provider 진영이라고 합친다면 get에 크게 밀리는 것 까진 아니었다.

Provider 진영에서는 getx 를 많이 싫어한다.

이건 많이 알고 있는 사실이다. 어느 정도까지 싫어하는 지는 잘 모를 수 있는데.

디스코드에서 그냥 getx 만 검색해보면 나오는게 이런 것들이다.

다음 채팅이 채널 분위기를 요약해주는 것 같다. https://discord.com/channels/420324994703163402/421444918276390912/1075828148131864618

뒤에 달린 답변을 보면, 한국식으로 하면 소위 ‘병먹금’ 이다. 근데 최초에 어그로를 끈 Robo 도 애플 리뷰시간 어쩌구 하는 걸 보면 일부러 저러는 건지 알 수 없다.

이젠 getx는 까이고 까이다 못해 거의 웃음벨 급의 밈이 되버린 것 같다.

놀라운 건 이런 것들이 내가 getx 까들을 찾으려고 노력한게 아니라, 그냥 글을 쓰는 지금 이 순간에 get 검색하면 나오는 검색 결과에서 맨 위 3개를 가져온 것이라는 거다. 나머지도 저런 느낌이다. Robo처럼 어그로를 끌지 못하는 단순한 getx 질문들은 가볍게 무시당하고 있다.

?statemgmt 라고 명령어를 치면 추천하는 상태관리 패키지들이 쭉 나온다. 요즘은 그 중에서 riverpod 을 추천해준다. riverpod은 괜찮나?

아이러니: riverpod 은 getx 를 따라가고 있다.

사람들은 getx 를 왜 비판했는가? getx에 대한 비판은 riverpod 에게도 적용해볼 수 있다.

  1. 플러터를 배우는 게 아니라 getx를 배우게 만든다. 웹에서 wordpress 같은 존재가 플러터에서 getx 이다. (= getx 만의 생태계를 배워야 한다.)

riverpod 또한 마찬가지다. riverpod을 제대로 쓰려면 기존 flutter 프레임워크에 없는 hook을 배워야 하고, StateNotifier 같은 새로운 개념들, 많은 Provider들을 배워야 한다. 그리고 ConsumerWidget 같은 새로운 위젯들까지 익혀야 한다.

2. 좋은 도큐먼트의 부재.

riverpod 또한 2.0 에 관한 문서가 부족하다.

3. BuildContext 같은 플러터의 핵심적인 부분을 배우지 못하게 만든다.

riverpod 또한 ref를 통해서 context 에서 자유로워 진다.

4. 패키지에 의존적으로 만들어서 나중에 대체하기 어렵게 만든다.

riverpod 또한 마찬가지다. 나중에 riverpod 에서 provider로 바꾼다고 생각해보자. 모든 consumerwidget, ref, providercontainer 등등 거의 대부분의 코드가 빨간 줄이 그어질 것이다.

물론 이런 점들이 getx 와 비교하면 상대적으로 덜하지만 그래도 단점을 공유하고 있다.

어쩌면 getx 보다 안 좋은 점

getx보다 호불호가 더 갈리는 부분은 전역(top-level) 에 provider 를 선언해버리는 다는 점인데, 이는 다트의 전역 변수는 lazy-loading 된다는 점을 이용하기 위한 것이다.(https://github.com/rrousselGit/riverpod/issues/202#issuecomment-719520723)

이유가 어떻든 클래스 안에 들어있지 않은 코드들이 import 만으로 다른 파일에서 사용된다는 것은 관리를 어렵게 만든다. 특히 한 파일에 provider 가 여러 개 들어있는 경우라면, 특정 provider 가 어느 위젯에서 쓰이고 있는지 파악하는 것은 매우 어렵다.

그럼 대체 뭐 어쩌라고요?

그렇다. riverpod 이 가까운 미래에 플러터 프레임워크에 공식적으로 흡수되는게 아니라면, 플러터로 개발하는 우리는 큰일난 것 일수도 있다.

위에서 이런 패키지들을 언급했는데

getx(불호) <<< riverpod <= bloc < provider < get_it (가장 호)

이미 단점을 말한 getx, riverpod 을 빼고도, 상황이 좋지 않다.

bloc, provider : 지원 중단. Provider 에 의존하는데, provider 는 Remi가 곧 deprecated 될 수 있다고 선언했음. (참고 : https://pub.dev/packages/riverpod)

get_it : 관리 안됨. 7.3 버전이 github에는 나왔지만 pub에는 7.2 로 방치된 채 1년 반이 흐름.

최대한 플러그인 의존도를 줄여야 한다.

전역 상태관리가 필요한 부분에서만 사용하고 지역 상태관리에는 setState() 를 적극적으로 활용해야 한다. FutureBuilder, StreamBuilder, ValueNotifier, InheritedWidget 같은 바닐라 방식을 적극 활용해야 한다.

하지만 쉽지 않을 것이다. 우린 이미 riverpod 의 맛을 보았고, riverpod 중독자가 되었다.

다음에 기회가 된다면 (get_it 또는 provider) + valuenotifier 를 이용한 상태관리에 대해서 글을 써보려고 한다.

결론

riverpod은 getx 보다는 조금 낫지만 문제가 많다. 최대한 바닐라 코드를 이용해 보려고 애쓰자.

.

piano (press key Q)

Categories

flutter ( 82 ) dart ( 34 ) android ( 32 ) kotlin ( 11 ) plugin ( 8 ) provider ( 8 ) vim ( 7 ) bloc ( 6 ) iOS ( 6 ) state management ( 6 ) 플러터 ( 6 ) PS ( 5 ) algorithm ( 5 ) architecture ( 5 ) async ( 5 ) getx ( 5 ) java ( 5 ) API ( 4 ) BOJ ( 4 ) class ( 4 ) daily ( 4 ) git ( 4 ) golang ( 4 ) memo ( 4 ) riverpod ( 4 ) state ( 4 ) stream ( 4 ) test ( 4 ) web ( 4 ) widget ( 4 ) windows ( 4 ) HTTP ( 3 ) androidX ( 3 ) app state ( 3 ) context ( 3 ) crash ( 3 ) db ( 3 ) editor ( 3 ) error ( 3 ) extension ( 3 ) github ( 3 ) hive ( 3 ) ide ( 3 ) package ( 3 ) pubspec ( 3 ) python ( 3 ) syntax ( 3 ) vscode ( 3 ) app icon ( 2 ) await ( 2 ) chocolatey ( 2 ) consumer ( 2 ) cp949 ( 2 ) deployment ( 2 ) dev ( 2 ) flavor ( 2 ) gesture ( 2 ) globalkey ( 2 ) go ( 2 ) google ( 2 ) hack ( 2 ) js ( 2 ) json ( 2 ) key ( 2 ) keystore ( 2 ) list ( 2 ) listview ( 2 ) lock ( 2 ) mac ( 2 ) map ( 2 ) navigation ( 2 ) nosql ( 2 ) project ( 2 ) pub ( 2 ) recyclerview ( 2 ) rxdart ( 2 ) sdk ( 2 ) selector ( 2 ) setting ( 2 ) size ( 2 ) soc ( 2 ) synchronized ( 2 ) tdd ( 2 ) tip ( 2 ) version ( 2 ) viewmodel ( 2 ) vundle ( 2 ) webview ( 2 ) xcode ( 2 ) yaml ( 2 ) ( 2 ) 플러터 단점 ( 2 ) 16.0 ( 1 ) 2.0 ( 1 ) 2023 ( 1 ) AATP2 ( 1 ) ChangeNotifierProvider ( 1 ) Example ( 1 ) Guava ( 1 ) ImageReader ( 1 ) Mo's algorithm ( 1 ) OAuth2 ( 1 ) OpenGL ( 1 ) Oreo ( 1 ) ProgressBar ( 1 ) REST API ( 1 ) Trie ( 1 ) activity ( 1 ) adaptive ( 1 ) android P ( 1 ) android context ( 1 ) android11 ( 1 ) apktool2 ( 1 ) app exit ( 1 ) append ( 1 ) appicon ( 1 ) arkit ( 1 ) array ( 1 ) asciidoc ( 1 ) async * ( 1 ) async* ( 1 ) audio ( 1 ) authorization ( 1 ) await for ( 1 ) behaviorsubject ( 1 ) beta ( 1 ) binary ( 1 ) binarysearch ( 1 ) blender ( 1 ) book ( 1 ) bottomsheet ( 1 ) break ( 1 ) broadcast ( 1 ) browser ( 1 ) bubbles ( 1 ) bug ( 1 ) build ( 1 ) buildcontext ( 1 ) buildnumber ( 1 ) bundle ( 1 ) button ( 1 ) bytecode ( 1 ) cache ( 1 ) camera2 ( 1 ) cameramanager ( 1 ) cd ( 1 ) chrome ( 1 ) ci ( 1 ) circle ( 1 ) clean ( 1 ) clean architecture ( 1 ) cli ( 1 ) clip ( 1 ) clipboard ( 1 ) cloud ide ( 1 ) cmdlet ( 1 ) code ( 1 ) coding test ( 1 ) command ( 1 ) comparator ( 1 ) complexity ( 1 ) concurrency ( 1 ) conditional ( 1 ) const ( 1 ) constraint ( 1 ) constraintlayout ( 1 ) controlc ( 1 ) controlv ( 1 ) converter ( 1 ) copy ( 1 ) copy project ( 1 ) coupling ( 1 ) coverage ( 1 ) cp ( 1 ) css ( 1 ) cupertino ( 1 ) cursor ( 1 ) cv ( 1 ) data class ( 1 ) data structure ( 1 ) dataBinding ( 1 ) database ( 1 ) debounce ( 1 ) decompile ( 1 ) delegate ( 1 ) deno ( 1 ) design pattern ( 1 ) development ( 1 ) device ( 1 ) di ( 1 ) dialog ( 1 ) dio ( 1 ) drawable ( 1 ) drug ( 1 ) emmet ( 1 ) encoding ( 1 ) english ( 1 ) entries ( 1 ) environment ( 1 ) equality ( 1 ) equatable ( 1 ) euc-kr ( 1 ) euckr ( 1 ) exit ( 1 ) expand ( 1 ) expanded ( 1 ) export ( 1 ) extension method ( 1 ) facade ( 1 ) fake ( 1 ) field ( 1 ) figma ( 1 ) final ( 1 ) fixed ( 1 ) flutter pub ( 1 ) flutter web ( 1 ) flutter_inappwebview ( 1 ) flutter_test ( 1 ) flutterflow ( 1 ) fold ( 1 ) fonts ( 1 ) form ( 1 ) frame ( 1 ) future ( 1 ) gestureDetector ( 1 ) gestureRecognizer ( 1 ) gesturearena ( 1 ) get-command ( 1 ) get_cli ( 1 ) getbuilder ( 1 ) getx단점 ( 1 ) gitignore ( 1 ) glut ( 1 ) google fonts ( 1 ) gopath ( 1 ) goto ( 1 ) gradient ( 1 ) graphics ( 1 ) gvim ( 1 ) hackaton ( 1 ) hash ( 1 ) hashmap ( 1 ) hot reload ( 1 ) how to ( 1 ) html ( 1 ) i18n ( 1 ) icon ( 1 ) id ( 1 ) impeller ( 1 ) implementation ( 1 ) import ( 1 ) indicator ( 1 ) inkwell ( 1 ) interrupt ( 1 ) intl ( 1 ) introduction ( 1 ) io ( 1 ) isar ( 1 ) iterable ( 1 ) iteration ( 1 ) javascript ( 1 ) julia ( 1 ) juno ( 1 ) jupyter ( 1 ) kakaomap ( 1 ) keytool ( 1 ) korean ( 1 ) kotlin syntax ( 1 ) l10n ( 1 ) lambda ( 1 ) language ( 1 ) layer ( 1 ) layout ( 1 ) lineageOS ( 1 ) localkey ( 1 ) localtoglobal ( 1 ) long list ( 1 ) ls ( 1 ) mac osx ( 1 ) markdown ( 1 ) markup ( 1 ) material ( 1 ) method ( 1 ) microtask ( 1 ) migrate ( 1 ) mintlify ( 1 ) mock ( 1 ) module ( 1 ) monitor ( 1 ) moor ( 1 ) mouse ( 1 ) mouseregion ( 1 ) multiplatform ( 1 ) multiset ( 1 ) multithread ( 1 ) mutable ( 1 ) mvvm ( 1 ) new ( 1 ) node ( 1 ) nodejs ( 1 ) nosuchmethod ( 1 ) null-safety ( 1 ) numberformat ( 1 ) nvim ( 1 ) object ( 1 ) objectbox ( 1 ) objectkey ( 1 ) obx ( 1 ) online ide ( 1 ) operator ( 1 ) orientation ( 1 ) parabeac ( 1 ) parse ( 1 ) paste ( 1 ) path ( 1 ) pattern ( 1 ) pitfall ( 1 ) play store ( 1 ) pod ( 1 ) podfile ( 1 ) pointer ( 1 ) pointers ( 1 ) powershell ( 1 ) private ( 1 ) programming ( 1 ) pull to refresh ( 1 ) puzzle ( 1 ) pycharm ( 1 ) realitykit ( 1 ) recursion ( 1 ) reduce ( 1 ) reference ( 1 ) regex ( 1 ) regular expression ( 1 ) release note ( 1 ) renderbox ( 1 ) renderobject ( 1 ) repl ( 1 ) repository ( 1 ) response ( 1 ) rm ( 1 ) rotue ( 1 ) round ( 1 ) run ( 1 ) scope ( 1 ) scroll ( 1 ) search ( 1 ) server ( 1 ) serverless ( 1 ) service ( 1 ) sharp ( 1 ) singlerepo ( 1 ) singleton ( 1 ) sketch ( 1 ) sliver ( 1 ) sliverlist ( 1 ) snippets ( 1 ) sogae ( 1 ) sorting ( 1 ) source ( 1 ) sparse ( 1 ) sparse array ( 1 ) spec ( 1 ) split ( 1 ) sqflite ( 1 ) sqlite ( 1 ) sqrt decomposition ( 1 ) stateful ( 1 ) statefulwidget ( 1 ) step ( 1 ) stepper ( 1 ) string ( 1 ) stringbuffer ( 1 ) stringbuilder ( 1 ) studio ( 1 ) study ( 1 ) sub-directory ( 1 ) svn ( 1 ) swiftui ( 1 ) swipe to refresh ( 1 ) system_alert_window ( 1 ) system_cache ( 1 ) systemnavigator ( 1 ) tail recursion ( 1 ) tailrec ( 1 ) tap test ( 1 ) text ( 1 ) texteditingcontroller ( 1 ) textfield ( 1 ) texttheme ( 1 ) themedata ( 1 ) then ( 1 ) thread ( 1 ) throttle ( 1 ) time ( 1 ) tool ( 1 ) tools ( 1 ) tooltip ( 1 ) ts ( 1 ) tutorial ( 1 ) typescript ( 1 ) ui ( 1 ) unittest ( 1 ) update ( 1 ) usb ( 1 ) utf8 ( 1 ) ux ( 1 ) valuekey ( 1 ) variable ( 1 ) vector ( 1 ) versioncode ( 1 ) very_good ( 1 ) view ( 1 ) vim plugin ( 1 ) vimrc ( 1 ) virtualenv ( 1 ) wasm ( 1 ) web app ( 1 ) webview_flutter ( 1 ) while ( 1 ) widget tree ( 1 ) window ( 1 ) wsl ( 1 ) yield ( 1 ) 강의 ( 1 ) 개발 ( 1 ) 개발 공부 ( 1 ) 공부법 ( 1 ) 그래픽스 ( 1 ) 꼬리재귀 ( 1 ) 꿀팁 ( 1 ) 데노 ( 1 ) 두줄 ( 1 ) 디노 ( 1 ) 번역 ( 1 ) 블록 ( 1 ) 상태관리 ( 1 ) 실험 ( 1 ) 안드로이드 ( 1 ) 안드로이드프로젝트 ( 1 ) 안드로이드프로젝트복사 ( 1 ) 어이없는 ( 1 ) 조건부 임포트 ( 1 ) 주절주절분노조절실패의식으흐름 ( 1 ) 패키지 ( 1 ) 프로젝트복사 ( 1 ) 플러그인 ( 1 )