Skip to content
This repository has been archived by the owner on Apr 12, 2023. It is now read-only.

Add feature migrations mechanism #165

Merged
merged 33 commits into from
Aug 30, 2021
Merged

Conversation

keiji
Copy link
Collaborator

@keiji keiji commented May 13, 2021

Issue 番号 / Issue ID

目的 / Purpose

アップデート時のメンテナンスコストを低減するため、バージョンアップ(アップデート)時に、特定のバージョンから最新バージョンまでの移行処理を一元的に行う仕組みを用意する。

破壊的変更をもたらしますか / Does this introduce a breaking change?

[x] Yes
[ ] No

Pull Request の種類 / Pull Request type

[ ] Bugfix
[x] Feature
[ ] Code style update (formatting, local variables)
[ ] Refactoring (no functional changes, no api changes)
[ ] Documentation content changes
[ ] Other... Please describe:

検証方法 / How to test

コードの入手 / Get the code

git clone [repo-address]
cd [repo-name]
git checkout [branch-name]
dotnet restore

コードの検証 / Test the code


確認事項 / What to check

  • バージョン1.2.2未満 -> 1.2.2のアップデート
  • バージョン1.2.2 -> 1.2.3のアップデート

その他 / Other information

検証用の実証。

マイグレーション

マイグレーション関係の処理は各プロジェクトのServices/Migration内に集約している。

Covid19Radar/Services/Migration/MigrationService.cs マイグレーションを統括するMigrationServiceが定義されている。
IMigrationProcessServiceには、マイグレーションが必要となるバージョンについてメソッドとして規定する(マイグレーションが発生しないバージョンは加えなくて良い)。
IMigrationProcessServiceは、IoCを通じてプラットフォーム固有のマイグレーション処理をMigrationServiceに提供する。

マイグレーションの実行は、MigrationServiceのメソッドMigrateAsync(Version? fromVersion)で行う。
現在のバージョン(fromVersion)に対してどのバージョンのマイグレーションが必要かを判断して実行する。

マイグレーションは、2つの要素からなる。
一つは共通プロジェクト側のデータのマイグレーション(たとえばApplicationPropertyServiceからPreferenceへの移行)。
もう一つはプラットフォーム固有のマイグレーション(たとえばWorkManagerのキャンセル処理)。

プラットフォーム固有のマイグレーションは、各プラットフォームプロジェクトが、IoCを通じてIMigrationProcessServiceの実装として提供する。

マイグレーションの実行タイミング

Android

マイグレーションは2つのタイミングで実行される。

一つ目は、アプリがアップデートしたタイミング。これはアプリがアップデートしたタイミングでシステムが呼び出すIntent( android.intent.action.MY_PACKAGE_REPLACED )を受け取るAppVersionUpgradeReceiverを通じて実行される。
二つ目は、バックグラウンドでの診断キーの取得と接触確認を行うバックグルアンド処理内。

iOS

マイグレーションは2つのタイミングで実行される。

一つ目は、アプリが起動したタイミング。
二つ目は、バックグラウンドでの診断キーの取得と接触確認を行うバックグラウンド処理内。

@keiji keiji force-pushed the version_migration branch from a8e3819 to 15c0571 Compare May 13, 2021 05:30
@keiji keiji self-assigned this May 13, 2021
@keiji keiji force-pushed the version_migration branch from cf0c96e to b938439 Compare May 15, 2021 03:34
@keiji keiji changed the title Implement migration Add feature migrations mechanism May 15, 2021
@keiji
Copy link
Collaborator Author

keiji commented May 17, 2021

二日寝かせたらもっといい方法らしきものを思いついたのでやってみる。

@keiji
Copy link
Collaborator Author

keiji commented May 17, 2021

もっといい方法というのは、バージョンごとのMigratorをリストに積んで順次実行するものだったのだけど、実際にやろうとしたらうまくいかなかった。
共通処理だけであれば問題ないけど、Platform固有のMigratorを呼ぶとなると処理が複雑になりすぎるので、このままの方が良いという結論に。

@keiji keiji changed the base branch from master to develop June 7, 2021 07:20
@keiji keiji marked this pull request as ready for review June 11, 2021 02:11
@keiji
Copy link
Collaborator Author

keiji commented Jun 11, 2021

しばらく寝かしたらもっといい方法が思い浮かぶかと思ったけどそうでもなかったのでReady for reviewした。

@keiji keiji requested a review from cocoa-dev June 11, 2021 02:12
@keiji keiji force-pushed the version_migration branch from 43eb2c1 to e48849a Compare July 11, 2021 03:05
@keiji
Copy link
Collaborator Author

keiji commented Jul 11, 2021

rebased

@keiji keiji force-pushed the version_migration branch from e48849a to 2e79bdb Compare July 11, 2021 03:13
@keiji keiji force-pushed the version_migration branch from 2e79bdb to e5a925f Compare July 26, 2021 08:36
@keiji
Copy link
Collaborator Author

keiji commented Jul 30, 2021

ひとまずconflictを解消

@cocoa-dev
Copy link
Contributor

@keiji
簡単でいいのでマイグレーション処理の内容を PR の概要に記載していただくことは可能でしょうか?

@cocoa-dev
Copy link
Contributor

@keiji
PR の概要にマイグレーション処理について記載してくださり、ありがとうございます。

マイグレーション処理の実行タイミングについて 2 点ほど理由を確認させてください。
回答は PR の概要を編集していただく形で構いません。

  1. iOS でアプリの起動時にマイグレーション処理を実行するのは、Android と異なりアプリのバージョンアップをフックできないからでしょうか?
  2. バックグラウンド処理内でマイグレーション処理を実行するのはなぜでしょうか?

return VERSION_1_0_0;
}

private async Task MigrateAsync(Version? fromVersion)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

以下のような警告がMac版のVisualStudioで出ていますが期待通りになっているでしょうか?

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

理由があってnullableにしているので接触的に明示していきたいところですが、#nullable を置かないと警告が表示される。これをどうするかという話ですね。

今のところコード規約がないので、警告の解消を優先すれば最小限の範囲で#nullableを付けるのも良いかなと思いました。
しかしその場合、あとから規約としてクラス全体に#nullableを付ける(プロジェクト設定で一括指定したり?)など齟齬が発生した場合に差分が大きくなりますので、コード規約が定まってから手当てしても遅くはないだろうなと思って現状にした経緯があります。

開発チーム内で現状、 #nullable に関する指針が無ければ、警告は一旦このままにしておいて、将来的に方針が定まり次第解消という方向が良いかなと思いますが、いかがでしょうか。

限定的な指定も含めてどちらでも対応できるので、ご意見をお聞かせください。

Copy link
Contributor

@cocoa-dev cocoa-dev Aug 27, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

開発チーム内で現状、 #nullable に関する指針が無ければ

はい。現在指針はありません。
このコードとして理想的な実装になっていたほうがいいとも思いますが、たしかに指針があるわけではないので一旦このままで良いです。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ずいぶん前にもらってる #35 にもありますね。
いっそプロジェクトファイルでNull許容を有効にしてしまっても良いような気がしますが、このPRでやるのが良いかと言われれば 🤔 です。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

とはいえ色のつく警告を放置は気持ち悪いので、クラスファイルの最初と最後に#nullable enable/disableで対応しました。

_loggerService.Debug($"appVersion entry is not found in Preferences.");
return null;
}
var appVersion = _preferencesService.GetValue<string>(PreferenceKey.AppVersion, FIRST_VERSION);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらもVisuslStudioにより修正候補が出ていますが、<string>部分は省略可です。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 127 to 128
var fromVersion = PreferenceVersion;
fromVersion = fromVersion is null ? GuessVersion() : fromVersion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var fromVersion = PreferenceVersion ?? GuessVersion();としたほうがいいと思います。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
}

var currentVersion = CurrentAppVersion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ローカル変数に入れる必要は無いと思います

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あ、すみません。CurrentAppVersionはプロパティですが都度読み込み処理がされるんですね。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

各プロパティはコンストラクタのタイミングのみで読み込むのでは都合悪いでしょうか?
できるならそのほうがわかりやすいかと思います。
都度読み込む必要があるならメソッドにしたほうがわかりやすいかもしれません。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UpdateAppVersionPreferenceで値を書き換える場合があるので、常に最新の値を読み込めるようにしています。
その上で、当該処理ではローカル変数currentVersionに格納してしまっていますし、UpdateAppVersionPreferenceとの対象もわかりづらいので良くないですね。

この部分は考え直します。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CurrentAppVersionはアプリのバージョンなので固定でした。
コンストラクタからEssentialServiceを使うとエラーが起きてスタックすることがわかったので、呼び出しのときに変数を取って使い回すようにしてあります。

UpdateAppVersionPreferenceもわかりにくかったのでSet/Getの組み合わせのメソッドを用意しました。

}
}

private Task<bool> DetectDowngradeAsync()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

非同期で動作するようなものではないので、戻り値boolのメソッドで良いと思います。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ダウングレードなしで行くことになったので、このメソッドは削除になりました。

Comment on lines 175 to 182
if (await DetectDowngradeAsync())
{
_loggerService.Warning("Downgrade is detected. All data will be cleared.");

await ClearAllDataAsync();

_loggerService.Info("All data cleared.");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ダウングレード時のみということは、一般ユーザ向けとしては不要なコードですね。
デバッグ用としても、ダウングレードする際は一旦アンインストールするべきで不要なコードだと思います。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございます。
Androidの場合は常に正式リリースのバージョンは上がるばかりで、下がることはない(ダウングレードはない)という認識です。

一方、ぼくはiOSの事はよくわかっていないのですが、そちらも同様でしょうか。AppStoreからバージョン指定して落とせるみたいな事はなさそうでしょうか。

ないようであれば当該部分は削除します。

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

はい。iOSでも同じくダウングレードはできないと思います。

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ダウングレードはないのでこの周辺の処理は削除します。
念のためログだけ仕込んでおきます。

@keiji
Copy link
Collaborator Author

keiji commented Aug 27, 2021

iOS でアプリの起動時にマイグレーション処理を実行するのは、Android と異なりアプリのバージョンアップをフックできないからでしょうか?

はい。その認識ですが、確認はしておいた方がいいですね。
@kazuhiro4949 iOSでは、アプリのアップグレードのタイミングをフックして処理する方法は提供されていますか?

バックグラウンド処理内でマイグレーション処理を実行するのはなぜでしょうか?

これはExposureWindow modeの際に指摘をもらったのですが「BroadcastReceiverであまり長い時間処理をすると、システムによって強制停止される可能性がある」というAndroid的な事情に対応するためです。

時間としてはだいたい10秒で、今回のマイグレーション処理でこれを越えることはなさそうなのですが、しかし今後どうなるかわからないので安全策としてWorkManagerを使っています。

一方、ご指摘の通り、アプリ起動時に発生するマイグレーションとアップデート時のBroadcastReceiverから起動するマイグレーションが衝突する可能性はありますね。
ありがとうございます。排他機構を入れるなどして、マイグレーションが終わるまではスプラッシュ画面で待ってもらうことを検討します(そうするとスプラッシュ画面に「データ移行中です」のようなステータス表示が欲しくなりますが…)。

@keiji keiji requested a review from cocoa-dev August 29, 2021 13:01
Comment on lines 27 to 29
string[] oldWorkName = {
"exposurenotification",
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちら内容が変わってしまっていますのでご対応をお願いします。

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

そうか……この間のsyncでここ変わったんですね。対応します!

@keiji keiji requested a review from cocoa-dev August 30, 2021 02:08
@keiji keiji requested a review from cocoa-dev August 30, 2021 04:11
@keiji keiji merged commit 55277b0 into cocoa-mhlw:develop Aug 30, 2021
@keiji keiji deleted the version_migration branch August 30, 2021 08:55
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

バージョンアップ時に移行(マイグレーション)する仕組みを作る
2 participants