初回起動時のユーザードキュメント書き込みを最適化#1768
Conversation
- FetchOrCreateUser.call()の返り値を(User, {bool isNewlyCreated})に変更
- _create()に起動情報(stats, timezone, packageInfo等)を追加
- UserSetupで新規作成時はsaveUserLaunchInfoをスキップ
これにより初回起動時のFirestore書き込みが2回から1回に削減される
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @bannzai, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! このプルリクエストは、アプリケーションの初回起動時におけるユーザーデータのFirestoreへの書き込みプロセスを最適化することを目的としています。既存の2段階の書き込み処理を1段階に集約することで、初回起動時のユーザーエクスペリエンスを向上させ、ネットワークラウンドトリップとFirestoreの書き込みコストを削減します。この変更は、ユーザーの初期セットアップフローの効率性を高めることに貢献します。 Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
初回起動時のFirestoreへの書き込みを2回から1回に削減する最適化、素晴らしいです。FetchOrCreateUserの返り値を変更し、UserSetupで新規ユーザー作成時のsaveUserLaunchInfoの呼び出しをスキップする対応は、目的を達成するための的確なアプローチだと感じました。
1点、lib/provider/user.dart内の_createメソッドと_saveStatsメソッドでコードの重複が見られます。詳細はコメントをご確認ください。
| debugPrint('#create $uid'); | ||
| final sharedPreferences = await SharedPreferences.getInstance(); | ||
| final anonymousUserID = sharedPreferences.getString(StringKey.lastSignInAnonymousUID); | ||
|
|
||
| // Stats | ||
| final lastLoginVersion = await PackageInfo.fromPlatform().then((value) => value.version); | ||
| String? beginVersion = sharedPreferences.getString(StringKey.beginVersion); | ||
| if (beginVersion == null) { | ||
| await sharedPreferences.setString(StringKey.beginVersion, lastLoginVersion); | ||
| beginVersion = lastLoginVersion; | ||
| } | ||
|
|
||
| // Timezone | ||
| final now = DateTime.now().toLocal(); | ||
| final timeZoneName = now.timeZoneName; | ||
| final timeZoneOffset = now.timeZoneOffset; | ||
| final timeZoneDatabaseName = await FlutterTimezone.getLocalTimezone(); | ||
|
|
||
| // Package | ||
| final packageInfo = await PackageInfo.fromPlatform(); | ||
| final os = Platform.operatingSystem; | ||
| final package = Package(latestOS: os, appName: packageInfo.appName, buildNumber: packageInfo.buildNumber, appVersion: packageInfo.version); | ||
|
|
||
| // UserIDs(初回なので初期値) | ||
| final userDocumentIDSets = [uid]; | ||
| final anonymousUserIDSets = anonymousUserID != null ? [anonymousUserID] : <String>[]; | ||
| final firebaseCurrentUserID = firebase_auth.FirebaseAuth.instance.currentUser?.uid; | ||
| final firebaseCurrentUserIDSets = firebaseCurrentUserID != null ? [firebaseCurrentUserID] : <String>[]; | ||
|
|
||
| return databaseConnection.userRawReference().set( | ||
| { | ||
| // 既存フィールド | ||
| if (anonymousUserID != null) UserFirestoreFieldKeys.anonymousUserID: anonymousUserID, | ||
| UserFirestoreFieldKeys.userIDWhenCreateUser: uid, | ||
| // 起動情報 | ||
| 'lastLoginAt': now, | ||
| 'stats': { | ||
| 'lastLoginAt': now, | ||
| 'beginVersion': beginVersion, | ||
| 'lastLoginVersion': lastLoginVersion, | ||
| }, | ||
| 'timezone': { | ||
| 'name': timeZoneName, | ||
| 'databaseName': timeZoneDatabaseName, | ||
| 'offsetInHours': timeZoneOffset.inHours, | ||
| 'offsetIsNegative': timeZoneOffset.isNegative, | ||
| }, | ||
| UserFirestoreFieldKeys.packageInfo: package.toJson(), | ||
| UserFirestoreFieldKeys.userDocumentIDSets: userDocumentIDSets, | ||
| UserFirestoreFieldKeys.firebaseCurrentUserIDSets: firebaseCurrentUserIDSets, | ||
| UserFirestoreFieldKeys.anonymousUserIDSets: anonymousUserIDSets, | ||
| UserFirestoreFieldKeys.isTrial: false, | ||
| }, | ||
| SetOptions(merge: true), | ||
| ); |
There was a problem hiding this comment.
_createメソッドと_saveStatsメソッドで、起動情報を構築するロジックがほぼ重複しています。
今後のメンテナンス性を考慮すると、この共通ロジックを別のプライベートメソッドとして抽出し、両方のメソッドから呼び出すようにリファクタリングすることをお勧めします。
例えば、以下のような共通メソッドを作成することが考えられます。
Future<Map<String, dynamic>> _buildLaunchInfoData({User? user, String? newUserID}) async {
// ...共通のロジック...
}これにより、コードの重複が解消され、将来の仕様変更にも対応しやすくなります。
概要
初回起動時のFirestoreへのユーザードキュメント書き込みを2回から1回に削減します。
現状の問題
初回起動時(2回書き込み)
FetchOrCreateUser._create()→ 書き込み1:{anonymousUserID, userIDWhenCreateUser}SaveUserLaunchInfo._saveStats()→ 書き込み2:{lastLoginAt, stats, timezone, packageInfo, ...}通常起動時(1回書き込み)
SaveUserLaunchInfo._saveStats()→ 書き込み1のみ解決方法
_create()で起動情報も一緒に保存し、UserSetupで新規作成時はsaveUserLaunchInfoをスキップするようにしました。変更内容
1.
lib/provider/user.dartFetchOrCreateUser.call()の返り値を(User, {bool isNewlyCreated})に変更(user, isNewlyCreated: false)(user, isNewlyCreated: true)_create()に起動情報を追加:lastLoginAt,stats,timezone,packageInfouserDocumentIDSets,firebaseCurrentUserIDSets,anonymousUserIDSetsisTrial: false2.
lib/features/root/resolver/user_setup.dartisNewlyCreatedの状態を追加saveUserLaunchInfoをスキップ(_create()で既に保存済みのため)3. テスト
build_runnerでモックを再生成(返り値の型変更に対応)効果
テスト結果
全テスト(1299件)がパス