Jacksonは、完成度の高い多機能なオープンソースプロジェクトで、Indeed でも利用やサポート、コントリビュートを行っています。私の前回の投稿では、Java用のJSONライブラリとしての主力機能を紹介しました。また、Jacksonがサポートするその他のデータフォーマット、データ型、JVM言語についても説明しました。今回は、Jacksonの作成者と主任メンテナーを務める私の視点から、Jacksonの拡大に伴う課題についてお伝えします。また、このような課題にコミュニティとして対処するためのプランについても紹介します。
フラッタリー岬の反対側(撮影:Tatu Saloranta)
成長の痛み
Jacksonプロジェクトには、大規模なコントリビューターのコミュニティのサポートを得て、13年の間に多くの新機能が加わってきました。ユーザーはイシューを報告し、デベロッパーは修正や新機能に加え、新しいモジュールの提供も行っています。たとえば、Java 8の日付と時刻データ型モジュールは、JSR-310で指定されているJava 8の日付と時刻型、java.time.*をサポートするもので、仕様そのものと並行してコミュニティのメンバーが開発しました。
これまでにないほどの機能やユーザー基盤の拡大は、Jacksonに成長の痛みをもたらしており、以下のような支援が必要になっています。
- ドキュメンテーションの改善
- プロジェクトのWebサイトの改良とブランディング
- 大規模な変更や機能の管理と優先順位決め
- 報告されたイシューの詳細の絞り込み
- Jacksonに依存している機能に対するJacksonの新バージョンの互換性テスト
ドキュメンテーションの構造と編成
ドキュメンテーションを十分に提供し、アクセシビリティや内容の新しさを維持することは、広範囲で利用されているライブラリやフレームワークにとっては常に課題となります。Jacksonも例外ではなく、ドキュメンテーションの負担は、同程度のユーザー基盤を持つ他のライブラリよりも大きいかもしれません。
とはいえ、ドキュメンテーションが不足していることそのものが問題の本質ではなく、 Jacksonには、すでに次のような大量のコンテンツが存在します。
サードパーティ提供のチュートリアル | |
Jacksonプロジェクトリポジトリ |
|
StackOverflow |
|
Jacksonには、関係のあるほとんどのクラスを記載したJavadocリファレンスも用意されていますが、巨大なライブラリなので、Javadocリファレンスは膨大すぎて新しいユーザーには使いにくいと感じられるようです。また、Javadocリファレンスには使用例も含まれていません。
私たちの最優先事項は、ライブラリの利用者に、以下に挙げるような最も一般的なユースケースを紹介する実践ガイドを作成することです。
- JSON構造をJavaオブジェクトに対応するように変換する方法。
- XMLなど、他のデータ型のフォーマットを作成する方法。
- Spring/Spring Boot、DropWizard、JAX-RS/Jersey、Lombok、Immutablesなどのフレームワーク内でJacksonを使用する方法。
Javadocリファレンスの改善も必要です。一部のクラスやメソッドには説明がなく、説明があっても不完全な場合があります。自動生成されたJavadocリファレンスの他に、最もよく使われる機能やオブジェクトを詳しく説明するwikiページを私たちが手作業で作成し、公開しています。これらのwikiページを自動更新する方法を見つけたいと考えています。
これらのページの変更を実装するには、以下のドキュメンテーション構造、ツール、プロセスの変更が必要です。
- インラインコンテンツと外部コンテンツへのリンクを追加するための上位構造
- コントリビューターがドキュメンテーションを追加したり訂正したりするためのアクセス許可
- 改良とメンテナンスの作業に集中するために役立つ、ドキュメンテーションのフィードバックメカニズム
- 情報の追加を簡単にするドキュメンテーションテンプレート
プロジェクトのWebサイトとブランディング
このプロジェクトは13年の歴史があり、幅広く利用されていますが、メインプロジェクトのホームページの見た目はいまだに標準的なGitHubプロジェクトのままです。このリポジトリにはJacksonについての役に立つ情報がたくさん入っているにも関わらず、際立ったスタイルやブランド、ロゴがありません。
Hacktoberfest 2020では、Jacksonロゴデザインに関するイシューを作成しました。イメージしているのは、以下のようなロゴです。
- Go言語のGopherマスコット
- Kotlin言語のブランディング
- KubernetesのホイールロゴやDockerのクジラ
大規模な変更の管理
多くのコードのコントリビューションがあることに感謝しています。そのほとんどは報告されたイシューの修正目的ですが、新機能のコードもあります。
これまでの経験から言えば、Jacksonプロジェクトのコントリビューションの中で特に価値があるのは、GitHubイシューとして登録されるユーザーバグレポートでしょう。毎週かなりの数のイシューを受け取り、修正や品質向上を行っています。このようなレポートがなければ、Jacksonがこれほどの品質を維持することはできなかったでしょう。また、新機能のリクエストもよく受け取りますが、これらも改善に役立つ貴重な意見であり、私たちが取り組むべき新規開発の優先順位付けにも役立っています。
大規模な変更や機能の管理については、さらに改善の余地があると考えています。このような取り組みは実行に時間がかかるため、慎重な計画やコラボレーションを通じて改善するのが効果的です。大規模な変更を1つのイシューとして処理することもできますが、扱いが難しくなってしまうこともあります。
Jacksonプロジェクトが助けを必要としているのは、新機能リクエストの優先順位を決めることです。
- どの問題の改善を優先するべきなのか?
- 活発で発言力が大きい少数の参加者に依存するのではなく、コミュニティ全体の総意をくみ取ることができるか?これは、不満の声が大きい問題ばかりが優先される状態になるのを防ぐのに大切なことです。
- APIや実装計画について早めにフィードバックをもらうにはどうするのが最善か?既存のメーリングリスト、イシュートラッカー、チャットのどれを使ったとしても、それぞれに問題があります。
コミュニティからのフィードバックを促進していきたいという課題を解決するために、JSTEP(Jackson Strategic Enhancement Proposals)と名付けた、「小さな仕様」を公開するアイデアを取り入れました。KafkaのKIPと同じく、JSTEPの目的はコラボレーションの活性化です。GitHubのwikiページには、GitHubのイシューやGoogleドキュメントにあるような機能が備わっておらず、このようなツール上の制約から、今のところ一定のレベルの成果しか得られていません。
さらに、個人用と公開用を兼ねて、To DoやWork In Progress(WIP:進行中の作業)を記録したリストJackson WIPをGitHub wikiページで管理することを始めました。メンテナンスに手間をかけずに、自分の短期的なプランを記録し、共有するための仕組みです。
報告されたイシューを絞り込むためのコラボレーション
上で述べたように、これまでで最も役に立つタイプのフィードバックはバグレポートですが、役に立つ一方で、報告されたイシューと新機能リクエストの管理にはかなりの労力が求められます。データフォーマット、データ型、JVM言語、ユーザー基盤が拡大した今となっては、この管理が特に厳しくなってきました。
基本的なイシューのトリアージに時間がかかるようになり、以下のような手順が必要になっています。
- 報告されたイシューを検証する。
- 報告されたイシューが、ドキュメンテーションの不備や不明確な記述によるものかどうか判断する。
- 質問して詳細を確認する。
機能とドキュメンテーションに取り組むための限られた時間から、このトリアージに対応する時間も捻出しなければなりません。また、イシューレポートの回答遅延は、報告者の満足度の低下にもつながります。
そこで希望者をトレーニングして、ボランティアとしてイシューのトリアージをサポートしてもらう方法を模索したいと思っています。以下に挙げたようなサポートで、イシューの素早い絞り込みとユーザーエンゲージメントの改善を実現することができます。
- ラベルを追加する
- 質問して詳細を確認する
- 自分でも調査して発見事項を追加する
- 必要に応じてモジュールや専門分野のエキスパートの協力を得る
jackson-databindのイシューを手始めに、以下のものを作成することによってワークフローを改善し、GitHubイシューの絞り込みを行いました。
- ユーザーによるレポーティングの品質を向上するためのイシューテンプレート
- 新規イシューに対して自動的に設定される「to-evaluate」ラベル
- メーリングリストで頻出したり、同意を意味するサムズアップアイコンがGitHubで多く押されたイシューであることを示す「most-wanted」ラベル
これらの変更が成功すれば、他のプロジェクトリポジトリにも展開していきます。同じようなやり方で、他の変更も段階的に進めることができるでしょう。
依存関係がある機能に対する新バージョンの互換性テスト
Jacksonプロジェクトでは、コードのかなり広い部分でユニットテストを行っており、コアコンポーネントのカバレッジも良好です。さらにjackson-integration-testsリポジトリでは、コンポーネント間の機能テストを拡充する取り組みも始まったばかりです。一方、開発中のJacksonのマイナーバージョンと、Jacksonに依存する機能(たとえば、Spring Bootのようなフレームワーク)との互換性テストは、現在のところかなり後れを取っています。
課題の1つは、Jacksonとライブラリの開発ライフサイクルと、Jacksonを使用するフレームワークの開発ライフサイクルに差があることです。既存のライブラリとフレームワークは、安定したJacksonのマイナーバージョンに依存していて、すべてのテストがそのバージョンのみを対象に行われます。バージョン2.11が現在の安定バージョンです。イシューが見つかれば報告され、修正する場合は、2.11.1などのパッチリリースで行います。
同時に、Jacksonプロジェクトは新しいマイナーバージョン2.12の開発中で、これはバージョン2.12.0としてリリース、公開される予定です。バージョン2.11.1と2.12の作業が同時進行していることは問題ありません。Jacksonの公開APIでは標準のセマンティックバージョニング方式を使用していて、これが新しい問題の発生を防いでくれるはずです。
ところが現実には、標準のセマンティックバージョニングによって実際の問題をすべて防ぐことはできません。セマンティックバージョニングはJacksonの公開APIに使用されていますが、コアコンポーネント間の内部APIは同じレベルの後方互換性を備えていません。Jacksonのメンテナーが考慮するのは公開および文書化されたAPI間の互換性ですが、ユーザーはAPIの本来意図された動作よりも、実際の目に見える動作に頼りがちです。たとえば、メンテナーがバグや予期しない動作であると考えているものについて、ユーザー側では、それが実際の機能であったり正しい動作であるととらえていることがあります。
このような状況でも、開発中のJacksonのSNAPSHOTバージョンを使用してダウンストリームのシステムをテストすれば、新バージョンの開発サイクル中にこうした問題を把握して解決できます。この記事の執筆時点で提供されているSpring Bootの現行バージョンは、Jackson 2.11.2(最新パッチバージョン)に依存していますが、代わりにJackson 2.12.0-SNAPSHOTに依存するSpring Bootのユニットテストと統合テストを作成できます。スナップショットバージョンは定期的に公開され、Jacksonプロジェクトはスナップショットビルドを自動的に提供します。
このようなプロジェクト間の統合テストを行えば、関係するすべてのプロジェクトにとって有益です。リリースの前にリグレッションの一部、あるいは大部分の問題を予防することができ、パッチバージョンを作成する必要性が減ります。また、長い目で見ればJacksonのバージョン間の互換性が大幅に向上し、APIの意図された動作と実際の動作のギャップも埋まるはずです。
参加するには
Jacksonのユーザー基盤の拡大に伴って、ドキュメンテーション、ブランディング、イシューのトリアージ、イシューの優先順位決め、コードのテストなどの課題が生じています。この記事では、これらの課題に対処するために私たちが行ってきた取り組みのいくつかを紹介しました。これらの解決策を実装したり、代替策を提案してくださることが、私たちへの支援になります。Jacksonの将来の成長に向けて、一緒に土台を築き上げませんか?コントリビューションの機会については、Jackson Hacktoberfest 2020をご覧ください。詳しい情報については、Gitterチャットに参加するか、jackson-devメーリングリストに登録してください。
筆者紹介
Tatu Salorantaは、Indeed のスタッフソフトウェアエンジニアで、次世代の継続的デプロイメントシステムを統合するチームを率いています。Indeed の社外では、オープンソース分野での活動で広く知られる存在であり、@cowtowncoderのハンドルで、Jackson、Woodstox、lzf圧縮コーデック、Java ClassMateなど、多くの人気のあるオープンソースJavaライブラリを生み出しています。詳しい一覧についてはFasterXML Orgをご覧ください。