dely Tech Blog

クラシル・TRILLを運営するdely株式会社の開発ブログです

クラシルAndroidプロジェクトの開発者体験の向上を頑張ってます!2

f:id:meilcli:20200827161534p:plain

クラシルを開発してるAndroidエンジニアのMeilCliです。前回のクラシルAndroidプロジェクトの開発者体験の向上を頑張ってます!を投稿してから進捗があったので報告します

前回予告した内容は以下の感じでですが、設定した目標通りに行動できないのがエンジニアです。ご了承ください

  • 長年放置し続けてきたlintの対応、不要になったリソースの削除
  • 使用しているOSSなどのライセンス表記のための集計ツールをMeilCli/Librarianに置き換える
  • ライブラリーアップデートの自動検出・通知
  • モジュールのbuild.gradleの共通な宣言部分をbuildSrcへまとめる

長年放置され続けてきたlint問題

不要なリソースの削除

クラシルの開発は多種多様な機能を作っては検証し、価値がなければ消すの繰り返しをしてきました。そのため開発者が消し忘れているリソースがたくさんあり、そのリソースによってビルドに時間がかかっているのではと考え大掃除することにしました

f:id:meilcli:20200806192516p:plain
大掃除の様子

大掃除自体はIntelliJ IDEAやAndroid Studioに搭載されているInspect Code機能(ツールバーのAnalyze=>Inspect Codeで使えます)を使えば機械的に使用していないコードなどをあぶり出してくれるので比較的楽に行うことができます
※Inspect Codeでの機械的なチェックだと検知ミスやリフレクションなどのすり抜けがありえるのでプロジェクトの全文検索などを駆使して人力で消すかどうかの最終確認をすることをお勧めします

結果としてはビルド時間は大して変わりませんでした(残念)
ただ、lintのwarningを結構な数減らすことができたのとダウンロード時のapk容量を2MBほど減らすことができたのでやって正解だったかなと思います

今後の計画

不要なリソースを削除したあとではAndroid lintのみで約400件ほどのWarningがある状態となりました(IntelliJ IDEAのInspect Codeベースだとそれを遥かに超えるWarningが貯まっています)

それらのWarningを今すぐに撲滅するのは現実的ではないため、計画を立てて減らしていき最終的に撲滅するということにしました

f:id:meilcli:20200806193148p:plain
lint戦略

画像はAndroidチームに共有したlint戦略です。概要としては以下の感じです

  • ファーストステップ
    • 2Q終わり(つまり9月末)までを想定
    • ルール調整や重要度の高いものへの対応
    • モニタリング環境整備
    • セカンドステップの準備(PullRequestでのwarningのインラインコメント)
  • セカンドステップ
    • 撲滅作業が苦にならない程度に減るまでを想定
    • Warningを増やさない・気づいたら消す・気が向いても消す
  • ファイナルステップ
    • Warningをひたすら消す

計画は立てたのであとは実行するのみです。モニタリングは週1ペースでWarningの総数や推移が分かればいいかなと考えています

Android lintとDetektに関してはGitHub ActionでWarningの計測と統計・推移画像を生成するMeilCli/android-lint-statisticsMeilCli/detekt-statisticsを作成&導入をし、現在は週1で試験実行しています

他にもIntelliJ IDEAのInspect CodeをCI上で実行したいところなのでJetBrains/inspection-pluginを使っていこうと考えています*1

Librarianの導入

クラシルで使用しているライブラリーのライセンス表記を自動生成するツールとして自作のMeilCli/Librarianを導入しました

今までも自動生成ツールを使用していたのですがいくつかの問題を抱えていました

  • マルチモジュールプロジェクトによる複雑なConfigurationによるライブラリーの誤検知
  • 新たなライブラリーを導入したなどにConfigファイルを手作業による調整
  • Maven Artifactごとにライセンス表記が生成されていたことによって膨大なライセンス表記
  • HTMLを生成していたため2MBにもおよぶファイルをアプリに組み込んでいた

これらの問題が表面化し始めた頃、ちょうどMeilCliが他のライブラリーを作るためにライブラリーのライセンス集計ライブラリーを作っていたためそれを導入する運びになりました*2

実際に導入して数週間経ちましたが検知精度としては期待値通りになっています。すでにLibrarianを導入したものがストア配信されているので気になる方はぜひクラシルをインストールしてマイページの設定からライセンス表記画面を見てください

また、個人ブログでLibrarianの解説記事を書いているので気になる方はぜひ見てください

ライブラリーアップデートの自動検知・通知(+ ついでにbuild.gradle整理)

さて、みなさんdependabotという便利なbotをご存知でしょうか?リポジトリー内のライブラリー依存宣言部分をスキャンしてアップデートがあったらバージョン宣言を置き換えたPullRequestを自動で作ってくれるbotです

(npmやnuget方面の方は)セキュリティー関連の警告やPullRequestが自動で作成されるのを見たことがある人がいるかもしれませんが、dependabotがGitHubに統合された結果、リポジトリーにdependabotの設定ファイルを追加すればセキュリティー関連のPullRequest以外も自動で作成されるようになりました*3

PrivateリポジトリーでもGitHubへのデータ提供を許可していればdependabotを運用することができるのでこれを使わない手はないですよね?ということでクラシルAndroidにもdependabotを導入しました

# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "gradle"
    directory: "/"
    schedule:
      interval: "weekly"
    assignees:
      - "MeilCli"
    labels:
      - "dependencies"
    commit-message:
      prefix: "[improvement] "
    open-pull-requests-limit: 15

今の所、クラシルではこのような設定ファイルで運用していこうと考えていて、運用を始めて数週間経ちましたが毎週何個かアップデートがあるという状態になっています*4。この設定ファイルで毎週画像のようなPullRequestが作成されています

f:id:meilcli:20200811191001p:plain
dependabotが作成してくれたPullRequest

また、Gradleプロジェクトでdependabotを導入するには多少手心加えるとより良いマルチモジュールプロジェクト運用ができるのですが、ここで解説すると長くなるためマルチモジュールプロジェクトで導入したい方は以前に個人ブログで書いたdependabot導入記事を参照ください

あと、ついでに行ったbuild.gradleの整理ですが、具体的に言うとbuild.gradleで記述する内容をbuildSrc配下のGradle Pluginとして記述するようにしました。この記事に書くとコードで埋め尽くされてしまいますので、同様な記述をしているLibrarianを見ていただければと思います。↓コードリンク

Librarian/buildSrc/src/main/kotlin/net/meilcli/librarian/gradle/plugins at master · MeilCli/Librarian · GitHub

その他

今後について

細かい改善はいろいろとありますが、皆さんにご紹介するほどの内容になると

  • Android lintのインラインコメント対応
  • inspection-pluginの続報
  • ライブラリーアップデート時の差分検知

といったところを次回予告としておきます


join-us.dely.jp

新しい採用ページできたらしいです

*1:Gradle v6に対応できていませんでしたがそこはコントリビュートしておきました、最新版を使えばおそらく皆さんのAndroidプロジェクトでも動作するはずです

*2:ライブラリーを作るためにライブラリーを作る、GitHub Actionを作るためにGitHub Actionを作る、それがMeilCliです

*3:個人的にはいつの間に統合されたんだという感じです

*4:dependabot任せにできないPullRequestは手作業でアップデート作業したり、場合によっては何らかの都合によってPendingするといったこともやっています