SRE連載が始まります!

あけましておめでとうございます。SREチーム(新卒)の市川恭佑です。

カヤック技術ブログでは本記事が2023年初エントリですが、Happy Lunar New Year!の方が違和感のない時期になってしまいました。

本年、新たにカヤックSRE連載と題した企画を始めるので、概要についてご報告します。

連載企画を始める経緯

カヤックの技術ブログといえば毎年恒例のアドベントカレンダー企画が人気ですが、これは12月限定のため、それ以外の時期にブログの更新が激減する傾向がありました。

ブログ過疎化の対策として、カヤックでは去年からSREチームで毎月1本のペースでブログ記事を出していました。 実のところ、内部的にはこれを「SRE連載」と読んでいました。

「とりあえずやってみよう」というノリで始まった連載でしたが、結果的には「12月を除くすべての期間において記事を出す」という実績を作れたので、本年は正式に企画化します。

去年の連載記事

2022年に水面下で実施されていたSRE連載の記事を、以下に紹介します。

こうしてみると結構充実していますね。みんなで頑張りました。

時期 タイトル 担当
1月 カヤックのSREチームについて 長田
2月 既存リソースをTerraformでimportする作業を楽にする
3月 SREチームでポストモーテムを1年半運用してみた 藤原
4月 アジャイル的ドキュメンテーションのこころ 橋本
5月 ステージング環境における検証用データベースの立ち上げを自動化する取り組み 市川
6月 SLOの運用のために OSS shimesabaの導入 池田
7月 SLI/SLO運用の実践 shimesabaによる指標モニタリング 池田
8月 ecrm - Amazon ECRから不要イメージを安全に削除するOSSを作った 藤原
9月 EKSからECSに移行して開発運用コストの削減を図る 長田
10月 Terraform管理されたステージング環境・本番環境の差異を検出したくて頑張っている話 橋本
11月 運用中のサービスに負荷試験を導入した事例の紹介 市川

今年の連載記事

本題となる、今年の連載記事の紹介です。タイトルや担当は随時追記・更新します。

時期 タイトル 担当
1月 【実践編】CircleCIからOIDCを用いて安全にGoogle Cloudにアクセスする 市川
2月 【解説編】CircleCIからOIDCを用いて安全にGoogle Cloudにアクセスする 市川
3月 Amazon ECSのタスクを常に新鮮に保つ仕組みをStep Functionsで 藤原
4月 RedshiftのMERGE SQL commandがGAになりましたね。 池田
5月 mirage-ecsで各メンバー専用開発サーバーを実現!まちのコインの運用事例を紹介します 長田
6月 MackerelとGrafana OnCallを連携しました 藤原
7月 カスタマイズで広がるAWS Copilotの実践力 橋本
8月 CloudWatch Logs Insights クエリを定期的に実行して結果をS3に置く(EventBridge Scheduler, Step Functions, Lambda)
9月 OSS 『Prepalert』 の紹介 池田
10月 タスクランナーとしてのmakeを使う際の工夫と注意点 長田
11月 AWS Lambda のアクセス許可を紐解く 橋本
12月 GitHub ActionsでEnvironmentsを使わずにManual approvalを実装する

今年もノリの良いエントリが沢山放出される予定です。お楽しみに!

カヤックではブログ執筆が大好きなエンジニアも募集しています

hubspot.kayac.com

「まちのコイン」で使っているFlutterのバージョンを3系にアップデートした話

こんにちは。ちいき資本主義事業部でFlutterエンジニアをやっている植田です。
この記事ではFlutterで開発している「まちのコイン」というアプリをFlutter2系からFlutter3系にバージョンアップした事例について紹介します。

まちのコインとは?

「まちのコイン」はその地域に関わるユーザーがイベントやお店を通じて地域の人たちと会話をするきっかけを提供するプラットフォームです。

coin.machino.co

例えばQR読み取り機能やマップ機能といったものがあります。
QR読み取り機能ではQRを読み込んで地域限定のイベントに参加したり、スポットにチェックインしてコインを貯めたりすることができます。 マップ機能では利用できるスポットを確認できたり、スタンプラリーのコースを確認しながらまちを散策したりすることもできます。 また、利用するにはユーザー登録が必須となるので登録・ログイン、退会の機能も備えています。

「まちのコイン」を利用するスポット向けの管理アプリも用意しています。
そちらではユーザー情報のQRをカメラで読み込んで承認したりイベントを作成したりといったことができます。
内部的には2つのアプリをflavorを切り替えることで実現しているため一つのリポジトリで構成されています。

ユーザー管理にはFirebase Auth、クラッシュレポートにはFirebase Crashlyticsなども使っているため firebase_auth, firebase_crashlytics などのパッケージに強く依存した作りになっています。

Flutterをアップデートしていくモチベーション

Flutterには便利なパッケージがたくさんあります。
そして、そのほとんどがFlutterのバージョンアップに追従して新機能が追加したりbugfixを出したりしますが、中には全くアップデートされず陳腐化していくものもあります。

そのため、アプリのFlutterバージョンを随時アップデート対応しておかないと、パッケージの新機能やbugfixを取り込みたくてもFlutterのバージョンが古くて取り込めない、という問題が発生してしまいます。 Flutterのアップデート(特にメジャーアップデートは大変)もして、利用しているパッケージもアップデートして…諸々やると工数は膨れ上がります。 日頃からFlutterを最新バージョンに対応しておくことで、こういった運用工数を分散して割く事ができるようになります。

もちろん運用面での工数が減らせるだけでなくFlutterのアップデートをするだけで嬉しいこともいくつかあります。
Flutter本体のbugfixや言語としての新機能が使えるようになるので安定性の向上や、より柔軟なコードが書けるようになるかもしれません。 画面描画のパフォーマンスがより効率的になったり、メモリの使用率が下がったりといったパフォーマンス改善も入ってくる事が多いのでできるだけ最新のバージョンを追従する意識を持っていた方が良いでしょう。

Flutter3では大きくみると下記のようなパフォーマンス改善も入っていたのでユーザーにとってもよりアプリが快適に使えるのでメリットがあると思います。 2つのアプリを運用しているのでメリットも2倍です。

  • iOSでの120hzリフレッシュレートに対応
  • フレームビルドのパフォーマンスが約20%向上

今回のゴール

Flutterのバージョンアップの対応の中でやりたかったことは以下の2つです。

  • Flutterのバージョンを3.x系にアップデートする
    • 対応当時は2.10.5から3.3.3にアップデート
  • 依存しているパッケージを最新のバージョンまでアップデートする

つまづいたポイント

アップデートしていくにあたって事前に影響範囲の調査をしながら進めていましたが、想定していた以外のところで時間がかかってしまったポイントがあったのでいくつか紹介したいと思います。

docs.flutter.dev

docs.flutter.dev

flutter_facebook_authのセットアップ方法に変更があった

Flutterのアップデート後、iOSアプリが起動後すぐにクラッシュするという挙動が発生するようになりました。 以下のように、アプリ起動後すぐに接続が切れているログしか観測できなくてFlutter側の不具合なのかと思い調査にかなり時間を費やしてしまいました。

[        ] Waiting for observatory port to be available...
[+3339 ms] Observatory URL on device: http://127.0.0.1:58503/5oeggSOiUdw=/
[   +8 ms] Caching compiled dill
[ +139 ms] Connecting to service protocol: http://127.0.0.1:58503/5oeggSOiUdw=/
[ +418 ms] Launching a Dart Developer Service (DDS) instance at http://127.0.0.1:0, connecting to VM service at http://127.0.0.1:58503/5oeggSOiUdw=/.
[ +255 ms] DDS is listening at http://127.0.0.1:58514/ojIHBhq-rfk=/.
[  +46 ms] Fail to connect to service protocol: http://127.0.0.1:58503/5oeggSOiUdw=/: Exception: DDS shut down too early
[        ] Error connecting to the service protocol: failed to connect to http://127.0.0.1:58503/5oeggSOiUdw=/

エラーログの情報が足りないときはXcode側のログを確認してみると何かヒントになるかもしれません。
今回はXcodeに残っていたエラーログを確認すると FBSDKCoreKit が含まれている事がわかったので、 アプリ内でFacebook機能を利用している flutter_facebook_auth に絞って調査することで対応方法が見つかりました。

原因は、flutter_facebook_authのバージョンを4系にアップデートしたことで、flutter_facebook_authが内部で使っているFacebook SDKのバージョンも14にアップデートされていることでした。 Facebook SDKのセットアップ手順にもあるように、 FacebookClientToken の設定を追加する必要があり、それによってクラッシュは解消されました。

flare_flutterが非アクティブな状態になっている

「まちのコイン」の一部のアニメーションにはRive(旧Flare)のアニメーションが採用されていました。
こちらは .flr でアニメーションを作ってベクターアニメーションを描画できるという利点がありましたが、 すでにリポジトリが非アクティブとなっていること、新規アニメーションを作るときにRiveコンソールからアニメーション作成できる人がいないという問題がありこのタイミングで脱却することになりました。

Riveアニメーションを使っているところはFlutterの AnimationController を使った実装に置き換えたり、複雑なものはAPNGに置き換えたりして対応する方針としました。

その他FlutterのBreaking Changes

Scrollbar 'isAlwaysShown' is deprecated and shouldn't be used. Use thumbVisibility instead. This feature was deprecated after v2.9.0-1.0.pre..
Try replacing the use of the deprecated member with the replacement.

スクロールバーを常に表示しておく必要がある場合は、 isAlwaysShownthumbVisibility に置き換えるだけで対応が完了します。

WidgetsBinding.instance is non null value

WidgetsBinding.instance?.addPostFrameCallback は非同期処理が完了した時にUIを更新したい場合などに使うケースが多いと思います。 non nullになっただけなので修正は簡単ですが、これを頻繁に使っているアプリは修正箇所が多くて大変かもしれません。

TextInputClient Missing concrete implementations of 'TextInputClient.insertTextPlaceholder', 'TextInputClient.removeTextPlaceholder', and 'TextInputClient.showToolbar'.
Try implementing the missing methods, or make the class abstract.

TextInputの挙動を拡張などしたい場合に利用する TextInputClient にメソッドが追加されていました。 TextInputClientをimplementsしているWidgetがあれば追加されたメソッドを実装する必要がありますが、実装は空のままでも問題ないようです。 メソッドの定義だけ追加しておきましょう。

やって良かったことなど

Flutterのバージョンが古いことで一番困っていたのは不具合の修正を取り込めないということでしたが、Flutterをアップデートすることでパッケージ側の変更も取り込むことができるようになりました。 特にログイン周りで使用しているFirebase Authの不具合修正を取り込めるようになったことが大きかったですね。 描画パフォーマンスの向上や言語機能としての新機能も嬉しい要素で、Enhanced enumsfreezed パッケージで実装している箇所の置き換えもしていけそうです。

  • 依存パッケージのbugfixを取り込めるようになった
  • devtoolsで描画パフォーマンスの向上を確認できた
  • Enhanced enumsが使えるようになった

packageの更新にDependabotを導入した

今回はFlutterをアップデートするのでアプリの全体テストを実施する必要がありました。
そこにパッケージのアップデートも合わせて対応しましたが、大幅にアップデートされているパッケージもあればアップデートが止まってほぼdeprecatedなパッケージもあり、苦戦することが多かったです。 こうした影響範囲の広い改修のタイミングで対応するよりも小さくアップデートを取り込んでいった方がテスト範囲も小さくなりますし、 1つ1つをアップデートする工数も小さくて済みそうです。

「まちのコイン」のアプリは多くのパッケージを利用していますのでbugfixがあれば積極的に取り込んでいきたいです。
現在はbeta版ではありますが、pub用のDependabotを設定してパッケージのアップデートがあれば適宜取り込む運用で開発を進めています。 特にFirebaseなどのパッケージ間で依存関係があるもの、他のFirebaseパッケージが依存している firebase_core を依存解決する必要がある場合に便利で 他のパッケージが更新されたときにまとめてアップデートしてくれます。

slack notification from dependabot

まとめ

  • Flutterを継続的にバージョンアップしていくことでFlutterやパッケージのbugfixを安定して取り込むことができるようになる
  • アプリの描画パフォーマンスがいい感じに上がる
  • パッケージの更新にはDependabotを使うと依存関係含めて常にアップデートし続けることができるので便利

カヤックでは、信頼できる開発環境運用に興味があるエンジニアも募集しています。