현재 플레이스토어에 출시중인 "내가 만든 월드컵" 앱에서 바텀시트를 열어 항목을 클릭하면 아래의 스샷과 같이 바로 실행 다이얼로그가 뜨고 있다.
.

이 과정을 아래와 스샷과 같이 수정해보았다.
.

바텀시트의 항목을 클릭해서 실행 다이얼로그를 바로 띄우는 기존의 단조로운 연출과 달리, 항목을 클릭하면 바텀시트가 내려가고 페이저의 스크롤이 움직이면서 선택한 항목의 아이템 카드가 보여지는 역동적인 연출을 보여주는게 미적으로 좋아보였기 때문이다.
하지만 막상 구현해보고나니 어떤 사람은 잠깐이라도 시간이 소요되는 애니메이션을 감상하는것 보다 바로 게임을 실행하고 싶어할 수도 있겠다라는 생각이 들었다. 그리고 만약 내 생각이 만 명 중 단 하나이고, 나머지가 모두 후자의 생각을 갖고있다면, 내 플레이스토어 페이지의 평점과 댓글은 엄청난 난리가 날지도 모르게 될것이다.(내 앱이 인기 앱이었다면...!)
만약 해당 기능을 업데이트 후 많은 유저들의 피드백을 받아 수정을하여 다시 업데이트를 해야한다면 업데이트 후 플레이스토어에 게시될 때까지 어느정도 시간이 걸린다... (가끔 게시가 몇시간 만에 바로 반영되는 경우도 있긴 하다!)
이럴 때 파이어베이스의 Remote Config 기능을 사용하면 좋겠다는 생각을 했다. 원격으로 플래그를 조정할 수 있기때문에 A/B 테스트용으로 많이 쓰이는 기능이라고 한다.
내 경우에는 앱을 실행할 때 Remote Config기능으로 플래그 값을 불러와서 새로 업데이트 한 기능을 활성화 할 지 비활성화 할지를 설정해주면 되는 것이다.

파이어베이스에서 Remote Config 메뉴를 선택하고 "구성 만들기"를 클릭한다.

앱에서 사용할 변수명을 그대로 입력하고 데이터 유형은 bool로, 디폴트값은 true로 설정하고 저장하면 된다.

초안이 먼저 올라오고 상단에 "변경사항 게시" 버튼을 눌러주면 된다.
플러터 프로젝트에서는 다음과 같이 코드를 추가해준다.
// main.dart
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
final enableBottomSheetSelectionPagerTransition =
await _loadBottomSheetSelectionPagerTransitionFlag();
Future<bool> _loadBottomSheetSelectionPagerTransitionFlag() async {
try {
final remoteConfig = FirebaseRemoteConfig.instance;
await remoteConfig.setDefaults(const {
_bottomSheetSelectionPagerTransitionKey:
_bottomSheetSelectionPagerTransitionDefault,
});
try {
await remoteConfig.setConfigSettings(
RemoteConfigSettings(
fetchTimeout: const Duration(seconds: 10),
minimumFetchInterval: kDebugMode
? const Duration(minutes: 5)
: const Duration(hours: 12),
),
);
await remoteConfig.fetchAndActivate();
} catch (error, stackTrace) {
log(
'Remote Config를 가져오지 못해 캐시 또는 기본값을 사용합니다.',
error: error,
stackTrace: stackTrace,
name: 'main_remote_config',
);
}
return remoteConfig.getBool(_bottomSheetSelectionPagerTransitionKey);
} catch (error, stackTrace) {
log(
'Remote Config 초기화에 실패해 앱 기본값을 사용합니다.',
error: error,
stackTrace: stackTrace,
name: 'main_remote_config',
);
return _bottomSheetSelectionPagerTransitionDefault;
}
}
// worldcup_list.dart
Future<void> _handleSheetItemTap(WorldCupModel model) async {
if (_isHandlingSheetItemTap) return;
_isHandlingSheetItemTap = true;
try {
if (!widget.enableBottomSheetSelectionPagerTransition) {
await showDialogBeforeGameStart(context, model, refresh);
return;
}
...이제 앱을 설치 후 실행하면 fetch값을 불러올 수 있고, 재실행 하는 경우에는 다음과 같은 흐름이 된다.
앱 재실행
→ fetchAndActivate() 호출
1. 최소 fetch 간격이 지나지 않음
→ 서버 요청 생략
→ 기존 활성화된 캐시값 반환
2. 최소 fetch 간격이 지남
→ 서버 요청
→ 파이어베이스에서 설정한 fetch값 가져옴(업데이트)minimumFetchInterval fetch 간격을 12시간으로 해놓은 이유는 해당 기능이 UX적으로 치명적인 위험이 있는 요소는 아니라 생각했고, 오히려 간격을 짧게 해버리면 트래픽 비용이 그만큼 발생할 수 있기 때문이었다.(12시간이 너무 긴 것 같다면 6시간 정도로 줄여도 상관없을 것 같다.)
만약에 유저의 반응에 따라 빠른 대응이 중요한 기능이었다면 fetch 간격을 더 짧게 줄였을 것이다.
이제 앱 업데이트 후 유저들의 피드백을 받아 필요 시 Remote Config로 플래그를 변경해보자
=====================================================================