Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

「New Relic実践入門」感想、あるいはなぜ監視SaaS使うんだっけという話

New Relic アニキこと清水さんから共著書「New Relic実践入門」をいただきました。ありがとうございます。清水さんにはかつてRDBMSの性能調査をいかに効率的かつ実践的にするかご教示いただいた恩があるのですが、今もその道を追求し活躍されていると知れて嬉しく思います。

破壊的イノベーションを現場の「あたりまえ」にする本書

さて本書は「Part 1. New Relicを知る」「Part 2. New Relicを始める」「Part 3. New Relicを活用する」の3部で構成されていますが、特に「Part 1. New Relicを知る」が割り切った構成になっています。「監視とは何か?」「既存手法にはどのような限界があったか?」「近年の技術革新による新たな課題は?」といった背景をすべてすっとばし、いきなり「オブザーバビリティとは何か?」の説明から入っているのです。まるでTypeScript入門書でJavaScriptの説明を省略するような思い切りの良さです。

結果的にはこの思い切りが、幅広い読者にオブザーバビリティという概念を先入観なく伝えるための仕組みとして作用したように感じました。オブザーバビリティが従来の概念に積み上げる持続的イノベーションではなくDevOpsのような破壊的イノベーションである*1ことを踏まえると、複雑な現状を取っ払ってあるべき姿をまず描くこのアプローチは合理的です。

またNew Relicの利用者は開発者からマネージャまで多様な役割を想定しているようなので、運用技術的土地勘があまり無い読者にも読みやすいというのは狙ったところなのかなと思います。若手からシニアまでまぜた読書会とかもやりやすそうです。これはマネジメントやテックリードとしては「チームに共通理解と合意をもたらす手段」として活用できるというということで、けっこう重要だと思います。

なおPart 2. 以降で既存手法の課題についても都度整理されますし、Part 3. でもケーススタディがこれでもかと出てきます。ので運用経験者も改善手法を学ぶ技術書として興味を持って読めると思いますし、若手とのコミュニケーション手段にもできるかもしれません。

実際にわかりやすく実践入門できるのかという話

入門書を名乗るからにはちゃんとNew Relicに入門できるのかというのは気になるところです。筆者の場合は本書を読んで1日ほどで、手元のspring-boot webfluxアプリにAPM, Infrastructure, Synthetics, Browserを導入してダッシュボードでパフォーマンスを確認するところまで持っていけました。スクリーンショットや表が多くわかりやすく構成されているのと製品のUIが統一されているのとで、さほど迷わなかったと感じます。

f:id:eller:20211019205034p:plain
最終的に得られた解析結果

残念ながらJava agentの最新リリースである7.3.0はJava 17に対応しておらず、ランタイムをJava 16にダウングレードする必要がありました。これは次の7.4.0リリースで対応されるようです。

github.com

なぜ私達ソフトウェアエンジニアはSaaSを監視に使うのか

O'Reillyの「入門 監視」§2.3では、監視ツールはまず「作るのではなく買う」のが大切だと述べています。そのほうが安く良いものを得て、プロダクトにフォーカスできるからです。

本書も§4.1.2において、「運用のための運用」問題を解決する手段としてNew Relicが有効であると主張しています。そもそも監視ツールはIaaSやPaaS、CDNなどのビルディングブロックが不調に陥っても正常に稼働することが求められるため、可用性や対障害性能といった要求が非常に高いのが特徴です。最悪、開発したいプロダクト以上に運用に力を入れるなんてことにもなりかねません。ので監視ツールを「作るのではなく買う」のは多くの場合、合理的な選択になるでしょう。

これに加えて本書§2.1.4では以下に引用するようにノウハウ、すなわち試行錯誤や積み重ねの結果をすべてのエンジニアに提供することを目指していると述べています(強調は筆者による)。オブザーバビリティの重要性を理解して多くの事例を見て支えてきたであろうSaaSベンダーのノウハウを使える、巨人の肩に乗れるというのも、監視にSaaSを使う大きな理由になるでしょう:

次に重要なステップが、収集したテレメトリーデータを意味のある情報として分析、可視化することです。つまり、ありとあらゆるデータを収集できていたとしても、その情報を活用できるかどうかがオブザーバビリティの真価を発揮できるかどうかの分かれ目となります。 従来、この作業は熟練したエンジニアのスキルと経験が必要とされるものでした。New Relic Oneではそのスキルと経験に代わるノウハウを、すべてのエンジニアに提供するということを目指しています

本書の魅力として最後に忘れてはいけないのは、New Relic日本法人に強力な技術メンバーが揃っていることの証明になっている点です。この本は日本法人による書き下ろしで、翻訳本ではないそうです。そして執筆陣10名のうち3名を個人的に存じ上げているのですが、いずれも魅力ある優れたエンジニアです。彼らのような専門家が日本の商習慣や組織を理解して顧客を支えてくれるサービスが日本にある、というのが本書が一番言いたいことなのかなと思いました。職場楽しそう。

オブザーバビリティの入門としておすすめの一冊

ということで単にオブザーバビリティを学ぶ入門書としても、New Relicというサービスを活用し実践する参考書としても、現場にある課題に立ち向かうヒントを得るための事例集としても活用できる興味深い一冊だと思います。運用の現場に関わっている方はもちろんそうでない方も「今技術をフル活用すると、どこまでサービスの実態から洞察を得られるのか?」を考えるきっかけを得ることができるはずです。New Relicを使うにしても使わないにしても、読んでみて損はないと思います。

*1:これは本書の主張ではなく筆者の意見

個人サービスやOSS開発の保守運用から何を学んだか

というようなことを私はよく主に採用の文脈で口走るのですが、ちゃんと内容をまとめておこうと思ったのでメモ。特に保守運用を経験しているというのが強いと思っているので、そこに注力して書いてみます。

障害対応の経験が積める

10年ほど前にTwistoire (ついすとわーる)というサービスを運営した際に、利用想定の甘さから半日程度のサービス停止を招いたことがありました。

blog.kengo-toda.jp

個人が無償で提供していたサービスとはいえ、使ってくれているユーザに対してそれなりの責任を感じた記憶があります。またひとりで使っていたころには発生しなかった障害なので、単純に課題の分析と解決が面白そうに映るのも事実です。こうした体験から一次対応の必要性や根本解決ないしポストモーテムのあり方について実体験を持って考えられるようになります。

これ、言葉で「実体験を持って考えられる」と書くと軽いんですが、本人としては結構深刻に落ち込んでいて当時のツイート↓を見てもかなり悔しかったのだと思われます。

業務でメンテしていたシステムでも近い経験はできたので、ホビープログラマ固有の特徴かというとそんなことはないと思います。 ただ最近読んだシステム障害対応の教科書でも指摘されていましたが、障害対応は暗黙知と習熟とが必要になりがちです。そのため、むしろすべて自分でコントロールできる=SECIモデルのプロセスを自分の中で完結できる趣味開発というのは、学習効率の面からも悪くないと思います。

「運用しやすさ」という見えない品質に気づける

「いいログを書くためには何を勉強すればいいですか?」という質問をシニアなプログラマに聞くと、だいたいは「運用経験を積む」という回答が返ってきます(n=10くらい)。逆に言うと、運用を経験していないと悪いログを書きがちということです。思いつく「悪いログ」の例はこんな感じです:

  • 単純に量が多い。ログローテーションや保存、実行時性能に悪影響を及ぼす。
  • ひとつの情報が複数行に渡って表示する、パースしにくい書式を使うなど、機械による利用を想定していない。grepやログ解析サービスで追いにくい。
  • 何が起こったかだけ表示し、何が問題で何をすべきかを教えてくれない。次のアクションに必要な情報が入っていない。
  • 情報が足りず、ソースコードと照らし合わせることで初めて意味が理解できる。
  • 出力してはいけない情報が出力されている。

こういう問題は世に出ているガイドラインなどを参照すれば回避可能ですし、アーキテクトやテックリードがちゃんと統制しろという話もあるんですが、やはりプログラマ個々人が運用を意識してコードを書けた方が良いです。経験は最悪を回避するだけでなく、よりよいログを見出すのにも役立ってくれます。思いつく「良いログ」の例はこんな感じです:

  • 発生しやすい問題や運用時の関心事を考慮したもの
    • TRACEログにバッチ処理の進捗度を出力するとか(処理が進んでいないのか遅いだけなのかの切り分け、完了時間の見積の役に立てる)
    • 処理失敗の原因になりやすい「外部から受け取ったパラメータ」を残してくれるとか
    • ガイドライン化しにくい気がしている
  • 読み手が取るべきアクションがわかるもの
    • 「予期せぬのエラーが発生しました」の真逆
    • エラーコード、参照すべきURL、検索を助けるキーワードなど
    • ガイドラインによってエラーレベル(FATAL, ERROR, WARNINGなど)の使い分け方針を定めておくだけでもだいぶ違うが、最終的には想定力がモノを言う印象

このへんは、コーナーケース想定やテストシナリオ設計に通じるところがありますね。サービス運用やアプリリリースの経験があれば、こうした想定の幅が広がり、様々な面からソフトウェア品質の改善に役立てることができます。

品質を落とさないためのリグレッションテストや統合テストを大切にできるようになる

「良いテストを書けるようになるには何を勉強をすればいいですか?」という質問をシニアなプログラマに聞くと、だいたいは「ソフトウェアプロジェクトを継続して運用する」という回答が返ってきます。「テストを書くクセをつけるには?」という質問も同様です。

ここでソフトウェアプロジェクトの運用というのは、コードを書いて成果物を届けるという動きを継続して行うことを指しています。

個人プロダクトを始めた理由は「やりたいことがあるから」のはずです。それはお手玉をしながら綱渡りで火の輪くぐりをするような「あっちこっちを意識しながら壊れないように祈りつつコードを書く」体験とは大きく異なります。しかしながら、テスト設計も自動テストも無いプロジェクトでは容易にこうした体験が醸成されてしまいます。機能ひとつ手を加えるごとに他の機能や非機能要件に対する影響を確認しなければならない状況が生まれ、インクリメンタルに成果を積み上げ「やりたいこと」に近づくことすら難しくなります。

ので品質を落とさないための、というか「新しいことをやっているときに他のことを心配しなくて済むための」リグレッションテストや統合テストを大切にできるようになります。私の場合、同じ理由でシステム監視や運用の自動化、開発環境構築の自動化も関心領域になりました。

大富豪プログラミングに気づける

クラウドが生まれAPIやボタンひとつでデプロイが行えるありがたい時代になりました。私が初めて運用したサービスは有償レンタルサーバー上で動いていましたが、前出のTwistoireはGAE/Jで動いていましたし、最近はHerokuやさくらインターネットのHacobuneのような無償あるいは安価に使えるものも多くなっています。

しかし完全に無料でサービスを続けられるかというとそんなことはなく、ある程度はコストをかけていくことになります。そしてある日、想定していたよりもコストが高くなるという事態が生じます。Twistoireの場合はGAE/Jの料金プラン変更がその契機でしたが、アクセス集中や不具合によって気づくこともあるでしょう:

blog.kengo-toda.jp

趣味開発プログラマはこうした機会をコードが計算機資源を効率よく扱えていないというシグナルとして受け止め、プロジェクトとスキルの改善に繋げることができます。「性能足りなかったらサーバースペック上げればいい」ときもあるかもしれませんが、小型の趣味開発システムだとリスクを取った変更がしやすいということもありコスト効率を追求しやすいはずです。リスクや資源を自分でコントロールできるので、勉強会資料や個人Webサービスシステム構成事典↓のような情報を試しやすいというのもあります:

techbookfest.org

以上、まとめるとホビープログラマは勝手に試行錯誤していろんなことの重要性を理解しているかもしれません。落ち込んでいるときも計画していない出費ができてしまったときもあるでしょうから、元気なさそうだったら話を聞いてあげたら良いんじゃないでしょうか。

SonarQube解析をGitHub Actionsのpull_request_targetイベントで回す

SQ解析が現時点ではあまりpull_request_targetイベントをサポートしておらず、ちょいちょい手間が必要だったのでまとめます。 完全なYAMLのサンプルは↓にあります。

github.com

checkout する場合はrefを指定する

pull_request_target イベントでcheckoutを実行すると標準ではデフォルトブランチをチェックアウトしてしまいます。 よって fetch-depth: 0 に加えて ref の指定も必要です。以下のようにHEADをチェックアウトするか:

      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
          ref: ${{ github.event.pull_request.head.ref || github.ref }}

以下のようにマージコミットをチェックアウトすることで解決できます*1

      - name: Decide the ref to check out
        uses: haya14busa/action-cond@v1
        id: condval
        with:
          cond: ${{ github.event_name == 'pull_request_target' }}
          if_true: refs/pull/${{ github.event.pull_request.number }}/merge
          if_false: ${{ github.ref }}
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
          ref: ${{ steps.condval.outputs.value }}

2021年11月17日更新:前者の方法だとforkからのPRでは動作しないので、後者がおすすめです。

PR解析用のオプションを加える

おそらくScanner側の問題だと思うのですが、Developer Editionの機能のためかコードは見つけられていません。現時点では sonar.pullrequest.keysonar.pullrequest.branch の双方を手動で設定する必要があります*2

        run: |
          mvn org.jacoco:jacoco-maven-plugin:prepare-agent verify sonar:sonar -B -e -V \
            ${PR_NUMBER:+ -Dsonar.pullrequest.key=$PR_NUMBER -Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }} }
        env:
          PR_NUMBER: ${{ github.event.pull_request.number }}

2021年8月30日更新:

上記実装では脆弱性が残ることをazu さんにご指摘いただきました。ありがとうございました! ブランチ名はPR作成者が決定可能なので、一度環境変数で受けてから使用するべきとのことです。

        run: |
          mvn org.jacoco:jacoco-maven-plugin:prepare-agent verify sonar:sonar -B -e -V \
            ${PR_NUMBER:+ -Dsonar.pullrequest.key=$PR_NUMBER -Dsonar.pullrequest.branch=${PR_BRANCH} }
        env:
          PR_NUMBER: ${{ github.event.pull_request.number }}
          PR_BRANCH: ${{ github.event.pull_request.head.ref }}

Sonar Scannerの実行にはJava 11が必要

pull_request_targetと直接関係はありませんが、最近更新が入ったようなので念のため。

Sonar Scannerは実行にJava 11以上が必要なので、Java 8のコードを書いている場合でもJDK 11以上でビルドする必要があります。MavenもGradle*3--release オプションをサポートしているので、それを使うと良いでしょう。Java 8に無いAPIを見つけてコンパイルエラーにしてくれるので、 --target よりも安心です。

勝手を知らないプロジェクトにPull Requestを送るときに気にしていること

初心者向けのPull Request(PR)作成方法はopensource.guideをはじめとして数多く見るのですが、もうちょっと突っ込んだというか中級的な内容の記事を読みたかったので自分で書きます。題材として主に直近で書いた大きめの機能追加用PRを使っています:

github.com

修正や新機能を入れる利点を明確に伝える

何かを提案する場合、その背景には必ず動機となる利点があるはずです。これはとても単純に伝えられることもあれば、テストやグラフを作成しないと伝わりにくいものもあります。

今回の変更では、GitHub Actions workflowの定義ファイル簡素化とパフォーマンス改善が利点でした。定義ファイルが簡素化されることはドキュメントで簡単に伝えられますが、パフォーマンスは測定しなければわかりません。よってパフォーマンス検証用のリポジトリを作成し測定を行うことで、ビルド時間が約28%高速化されることを示しました。

github.com

このリポジトリにあるActionsを実行すると、グラフを描くために必要なCSVが出力されます。それをGoogle Sheetsに突っ込んで以下のようなグラフを作成し、PRページに添付しています。結果として、本当に高速化に繋がるのか?といった疑問や質問は来ず、純粋に実装手法についての議論から入ることができました。

f:id:eller:20210826152424p:plain
パフォーマンスがどの程度具合を説明するためのグラフ

こうして根拠となる事実を自動的に出せるようにしておくと、レビューを受けて実装が変わったときに再確認を行えるという利点もあります。今回の例で言うとキャッシュの解決とJDKのインストールとを並行することでの高速化を意図していたのですが、セキュリティ上の兼ね合いから順次実行するようコードを変更せざるを得ませんでした。このような大きな変更があっても、既に自動化されたパフォーマンス比較手段があったため、パフォーマンス改善が維持できていることを示せました。

考慮すべきことも伝える

変更には利点だけではなく、互換性や運用など考慮しなければならないこともあります。これらをどこまで認識していて、どのような検証を行ったのかを事前に共有することで、多角的な議論の下地とすることができます。

今回の変更では upload-chunk-size が設定できなくなりユーザの自由度が失われること、IvyやGrapeといったより多くのパッケージマネージャをサポートすべきかもしれないことを俎上に載せ、その上でそれらが現時点で問題にならない理由を述べています。

新機能をメンテナンスし続けることのコストを最小化する

新機能追加のためにPRを送る場合、その機能のメンテナンスを行うのが自分ではなく相手だという点を意識する必要があります。言い換えれば、メンテナンスの工数が高いと判断された場合、PRをマージしてもらえない可能性があるということです。

基本的には単体テストと統合テストの双方を実装し提供することで対応します。単体テストがあることで実装自体のテスト可能性を担保し、統合テストがあることでリグレッションに気づける状態を作ります。またユーザに対する説明が必要な機能なら、READMEのような書類もあわせて準備します。

また自己流のやり方を持ち込むのではなく、既存のコードベースに溶け込むコードを書くことも重要です。今回は既にある定数クラスを再利用したり、統合テストのための仕組みに乗ったりという工夫をしました。特に統合テストのやり方はリポジトリによって様々なので、既存のビルド設定やコードに目を通す必要があります。

早めに返信するが、相手には求めない

質問や指摘があった場合、24時間以内には必ず何らかのリアクションを返すようにします。どうせタイムゾーンの問題があるので”即レス”は難しいのですが、できるだけ早めに返すことで議論の沈静化を防ぎます。

逆に、向こうから連絡がなくても気長に待ったほうが良いことも多いです。今回は企業の中の人が業務としてレビューしてくれましたが、それでも2週間ほど返信がなかった期間がありました。自分が相手の立場でもそういう事はあるだろうと気長に待つのが得策です。

変更の理由をオーバー気味に説明する

PRを提案する際、依存先の更新やリファクタリングのような、一見不要に見える変更を入れることがあります。例えばこちらのPRでは、ネットワークエラー発生時でもHTTPリクエストのリトライを行うために typed-rest-client のバージョンを上げています。何も説明しないと、依存を上げるのは他のPRでやればいいのでは?という疑問が湧くかもしれません。

github.com

こうした変更を入れる際は、コミットコメントかPR内コメントでその意図を伝えるようにしています。やはりコードでWHYを伝えるのは難しいので、少しオーバーかなと思うくらいの勢いで伝えたほうが良さそうです。

その他、細かいこと

  • README.md はもちろん、 CONTRIBUTING.mdCODE_OF_CONDUCT.md といったドキュメントに目を通しましょう。
  • Pull Requestテンプレートがある場合は利用しましょう。
  • わからないことはわからないと言い、素直に尋ねる方が良いです。相手もこちらを助けやすくなります。
  • 新しいライブラリの導入など相手に判断を求めるケースでも、自分の考えを述べた上で素直に尋ねるようにしましょう。

以上です。どなたかの参考になれば幸いです。 Happy hacking!

GitPodでJavaプロジェクトを開発する

GitHub Codespacesがなかなか個人向けに来ないので、changelog.comで宣伝していたGitPodを試しています。 どうも公式のJava向けの説明が古いようで、既にDeprecatedになっているtheiaを前提としているため、調べたことをメモしておきます。

最新のJavaを使う

普通に gitpod/workspace-full イメージ内でJavaを起動すると、Zuluの11が使われていることがわかります:

$ java --version
openjdk 11.0.12 2021-07-20 LTS
OpenJDK Runtime Environment Zulu11.50+19-CA (build 11.0.12+7-LTS)
OpenJDK 64-Bit Server VM Zulu11.50+19-CA (build 11.0.12+7-LTS, mixed mode)

SDKMANやhomebrewが入っているので好きなバージョンを入れてもいいですが、ワークスペースを立ち上げる度に実行するのは面倒なので、 azul/zulu-openjdk のようなイメージを使ってしまうのが楽でいいと思います。

# .gitpod.yml
image: azul/zulu-openjdk:16

Mavenの依存をダウンロードしておく

Mavenの場合、dependency:go-offlineプラグインや依存をすべてダウンロードできます。 これをイメージ作成時に実行しておくのが良さそうです。

# .gitpod.yml
image: azul/zulu-openjdk:16

tasks:
  - init: ./mvnw -B dependency:go-offline

Gradleの依存をダウンロードしておく

Gradleには標準的な手法がないので、単にビルドを回しておきます。

# .gitpod.yml
image: azul/zulu-openjdk:16

tasks:
  - init: ./gradlew build

Extensionを導入する

Java向けExtensionを3つ入れて様子を見ています。

# .gitpod.yml
vscode:
  extensions:
    - redhat.java
    - vscjava.vscode-java-dependency
    - vscjava.vscode-java-debug

ポートを開けておく

Spring Framework標準の8080ポートを開けておく場合は ports の設定 で足ります。 が、URLの取得にgpコマンドが必要なので azul/zulu-openjdk ではなく gitpod/workspace-full をベースとしたイメージを用意する必要があります。URLの決定ロジックがいまのところ非常に単純なのでなくてもなんとかなりそうではありますが、一応。

# .gitpod.yml
image:
  file: .gitpod.Dockerfile
ports:
  - port: 8080
# .gitpod.Dockerfile
FROM gitpod/workspace-full
RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && sdk install java 16.0.2-zulu"

バッジを付ける

バッジはDiscourseに落ちています。 README.md とかに貼っておくと、Contributorの敷居が下がって良いんじゃないでしょうか。

community.gitpod.io

The 2021 State of DevOps Reportが出た

ということでスキマ時間に読み進めていたので、感想と面白いと感じた点をまとめときます。網羅性が高く公平なまとめが必要な方は、3〜4ページに掲載のExective Summaryをおすすめします。

テーマは「中間層からの脱出」

6ページ目を見てもらえれば一目瞭然、今回のテーマは生産性が高くできず中間層で留まっているチームに対する処方箋の発見にあるようです。

近年のレポートは「今更それは無いでしょ」って感じのLow levelが5%強、「リアルチートじゃん」って感じのHighが10%強で、ほとんどのチームがMiddleに属していました。ごく少数の上澄みが高いパフォーマンスを出していて、その鍵となるKPIもベストプラクティスもわかっているのに、ほとんどの中間層は現状から脱出できず指を咥えて見ていた……と言ったら言いすぎでしょうか。この8割を占めるMiddle levelをさらに細分化し、中間層を脱するための働き方を見つけようということです。

f:id:eller:20210726175415p:plain
DevOps evolutionary levels (State of DevOps Report 2021 p.6 より引用)

DevOpsのやり方がだいぶ浸透してきて「何を計測し何をやるか」から「どうやるか」に関心がシフトしてきたとも言えます。同じ6ページにはDevOpsについて語ることよりも働き方について語るチームが多いことが述べられています:

In fact, many of the teams that are “doing DevOps” well don’t even talk about DevOps anymore—it’s simply how they work.

面白いと思ったところ

  • トップダウンによりボトムアップ型の改革を可能にする (p.11)
    • 経営の協力は当然必要というか「DevOpsによる生産性の向上=経営の関心事」という大前提がこのレポートには感じられる
    • 生産性が低い組織はリスクを避けるためにリスクを増大する手段を選択する傾向にある(p.31)が、これも部下を信じられない・Continuous Deliveryの適用をためらう経営なのではと思った
    • executive summaryによれば何でも話して疑問を解消し論点を明確にできる組織が高い生産性を持つわけで、マネジメントやリーダーの日々のコミュニケーションの賜物なのだろうと思った
  • DevOpsチームの存在は組織の進化を助けず、その曖昧な責務が組織に混乱をもたらす(p.13)
    • 開発とオペレーションの間に独立したDevOpsチームを配置するのはアンチパターンとして知られる(p.13)
  • 高度に進化した組織にとって文化は障害にはならず、これこそが高度に進化した理由である(p.14)
  • Team Topologiesという概念の導入(p.17)
    • Fast flow(p.16)実現にとっての障害を取り除くことに注力するものである(p.29)
    • 役割が多く、小規模のチームに当てはめるのは難しそうだと感じた
    • これを実現するための教育はどうやるのだろう?各チームの役割について専門家を探すのも難しそうな気がする
  • internal platformsについて
    • 2020でも触れられたが更に掘り下げて説明している(p.36)
    • 社内向けシステムを構築する際に利用できる認証・認可・デプロイ・保守・監視に使えるPlatformという理解をした
    • データレイクにおけるデータカタログとかも入ってくるんだろうなという理解をした
    • 高度に進化した組織はこうした基盤をinternal customerのビジネスを理解してエンジニアに構築提供している(p.30)
    • こうしたplatform teamがあっても生産性が向上するとは限らないが、DevOps transformationを加速できる(p.30)
    • 標準やルールではなくサービスを提供するということ、すなわち人をチームを信じることが肝要なのだと感じた
  • DevOpsの進化とinternal platformsの利用状況には関連がありそう(p.18)
    • 知識やベストプラクティスを他のチームと活発に共有することが生産性と関連しており、(p.19) これこそがMid levelを脱出するためのとっかかりになる(p.29)
    • だからこそ「でも保守(conservatism)も必要だよね」というCTOコメントが面白い(p.31)
    • 他チームがデプロイの課題を解決したことについて話す事例(p.28)があり、チームの壁を超えて課題解決や挑戦について共有する仕組みや文化が必要なのだと感じた、成果発表会のような季節性の仕組みでは動作しなさそう
    • Chat、金曜のメール、月次学習セッションといった共有手法の一例が共有されている(p.29)
  • 文化を嘆くのをやめて手を動かせ(p.28)
    • これ個人的にはとても気に入った、文化は個人の持ち物ではなくmutabilityを確信できないので
    • 表層の変えやすく失われやすい変化ではなく、5 Whyで組織文化の根っこを変えよう (p.32)
    • 日々正しい方向に組織の振る舞いをnudge(誘導?)していこう(p.32)

過去ログ

2019と2020の感想はTwitterを漁れば出てきます

Gradleのbaseプラグインに書くべきでないconventionとは何か

ひとつ前の記事では「Gradleの設定やコードをどこに書くべきか」のうち、答えが明確な「build.gradleファイルとbuildSrcディレクトリの使い分け」について書きました。この記事ではまだ自分の中でもよくわかっていない「Gradleでbaseプラグインに書くべきでないconventionとは何か」について書きます。

baseプラグインとは

ここで言うbaseプラグインは、plugins { id "base" } で使えるThe base pluginのことではありません。Gradleプラグインの設計手法のひとつとして推奨されている「設定より規約」の文脈で登場するものです。「設定より規約」を実現しつつ、(大部分のケースをカバーするであろう)規約が適用できないケースでもプラグインの機能を使えるようにするため、プラグインの規約(conventions)と基本的な機能(capabilities)とを別のプラグインに定義する設計手法です。

例えば java プラグインjava-base プラグインの場合、 java プラグインが規約を提供し、 java-base プラグインが基本的な機能を提供します。 java プラグインjava-base プラグインに依存することで、java-base プラグインが提供するtaskやextensionを利用します。

なお公式にはbaseプラグイン「ではない」方のプラグインには固有名詞がないのですが、ここでは記載を簡略化するために「規約プラグイン」と呼ぶことにします。

GradleはConventionという用語を多義的に使っている

ではbaseプラグインに書くべきconventionとは何か。この話題に触れるにあたり、GradleがConventionという用語をいつどのように使っているか確認する必要があります。私の知る限り、大きく分けて以下の3つが存在します:

  1. ”設定より規約”の文脈でのconventionのこと。一般的な用法。
  2. プロパティを指定しなかった場合に暗黙的に採用される値。default valueのこと。
  3. プラグイン設定用のconvention
    • 例えばJavaPluginConventionなど。
    • 現時点では非推奨なため、Extensionを利用する必要がある。

こうなるとよくわからないのが「baseプラグインに書くべきでないconventionはどれ?」です。

1のconventionはプラグインが提供する規約そのものでありbaseプラグインに書くべきでないのは明らかですが、JavaBasePluginCargoBasePluginは2と3のconventionを含んでいます。

規約プラグインであるJavaPluginCargoPluginはconventionを持っていることを期待され、実際1や2のconventionを含んでいます。

非推奨となった3のconventionは脇に置くとしても、2の置き場所やそれを決定する判断基準は明瞭に持ちたいところです。

メソッド名に惑わされないのが吉か?

私も2021年7月現在では明瞭な判断基準は持っていないのですが、ポイントはProperty#convention(Provider)というメソッド名に惑わされないことだと思われます。言い換えれば、2のconventionはどこにでも出てくるものだと割り切り、1のconventionを規約プラグインに限定して書くことのみに注力します。そして機能を書く上で必要なプロパティがある場合、baseプラグインでも気にせずにデフォルト値をProperty#convention(Provider)メソッドで設定してしまいましょう。

公式フォーラムに問い合わせてみた

自分的にはわかった気になれましたが、なんかしっくりこないので公式フォーラムに問い合わせてみました。

discuss.gradle.org

返信もらえたらこちらのブログ記事も更新します。

2021年9月29日更新: 公式Slackの方で「JavaBasePluginが異色なだけ、普通は1と2と3は全く同じものでbaseプラグインには出てこないべき」というコメントを貰いました。確かに一番シンプルなまとめ方かもしれません。