Kengo's blog

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

MRJAR (Multi-Release JAR)を使っているOSS一覧

参考

SLF4JとLogbackは2021年現在では積極採用しない方が良い

SLF4JとLogbackの中の人はここ数年活発ではないのでLog4j2などを代わりに使いましょう。

SLF4Jの活動は最近活発ではない

SLF4JはVCSとしてGitHubを利用しています。最後の変更が2020年2月最後のリリースが2019年12月となっていることからも、あまり活発ではないことが伺えます。

またBTSとしてJIRAを使っていますが、こちらもメンテナンスされていません。昨夏SLF4J-209が既にクローズ可能な状態であることSLF4J-186が修正可能であることなどをコメントしましたが、1年近く経った今もすべて返信がない状態です。

2020年12月にイシューを閉じていたりするので全く動きがないわけではないのですが、年間で22つ作成されたのに対して2つしか閉じられていないので、充分にメンテされているとは言い難い状況です。

f:id:eller:20210531193941p:plain
2021年5月31日時点での過去360日のイシュー消化状況

2021年6月2日追記:Java9リリース以降期待されていたJigsaw対応が入っている2.0(元々1.8だったもの)の安定版がずっと来ていないことも課題です。初回リリースである 1.8.0-alpha0 が2017年04月だったので、4年は経過しています。最新の 2.0.0-alpha1 は2019年10月のリリースで、未だα版ですが、モジュールを利用する場合は1.7は使えない(複数のモジュールが同一パッケージを提供できない)ため使わざるを得ない状況にあります。

メンテナーを増やすつもりはない?

2020年8月14日に ceki@qos.ch にメールを送り、メンテナーを増やすつもりはあるか、あるなら自分はこういった貢献ができますという意思を伝えたのですが、こちらもまだ返信がありません。

少数のメンバーがリリース権限を握っており、かつプロジェクトリーダーが連絡を取れない状態……と考えると、かつてのFindBugsプロジェクトの最後に非常に近い状況にある気がしています:

blog.kengo-toda.jp

Log4j 2が活発に活動しているのが幸い

ではSLF4JやLogbackに頼れないとして、どういった移行先があるのか。ロギングファサードないしロギングライブラリとしては、以下のような選択肢があります:

個人的にありがたいのはLog4j 2が活発なことです。Logbackを採用する理由として実行性能があったと記憶していますが、Log4j 2はLogbackと比べても高い性能を示しているとされています。lazy loggingflow tracingなども備えています。あと地味にLoggerインスタンス作るのが楽です:

// SLF4J
// http://www.slf4j.org/faq.html#declaration_pattern
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

// Log4j 2
// https://logging.apache.org/log4j/2.x/manual/api.html#Logger_Names
private static final Logger logger = LogManager.getLogger();

ログライブラリはプロジェクトによって要件も異なるでしょうし、必ずしもLog4j2が最適な選択肢とは限りませんが、一度試してみても良いのではないかと思います。

2021年6月2日追記:既にあるプロジェクトのSLF4JやLogback依存を今すぐに切らなければならない状況ではないと考えています。これから始めるプロジェクトでは積極採用するべきではないと思いますが、そうではない場合、特にモジュールを利用する予定がない場合(Java 8利用中など)はそのまま使い続ければいいかと思います。新規プロジェクトでモジュールを利用する場合は、更新頻度の低いα版に依存するリスクを受容できるのかどうか検討する必要があるでしょう。

内製化をすすめる知人へのアドバイス

ソフトウェアエンジニアとしての働き方を探求してきた経験と、駐在員として文化の狭間でうろちょろしてきた経験、OSSエンジニアとして多数の多様な人材と交流してきた経験をもとに、果敢にも内製化に挑戦する知人へのアドバイスを気持ちまとめます。

前提

  • 主な利用技術にはJavaSpring Framework)やTypeScriptを想定
    • FaaSを始めとしたManaged Serviceは(いまのところ)積極採用しない構え
  • Digital Transformationを推し進める一環としての内製化に、エンジニアリングの観点から挑む方を読み手として想定
    • 内製化のターゲットは決まっているか心当たりがある状態
    • 既存の開発チームはほぼ無い想定

1. チームビルディング

1.1. スーツとギークの対立を避ける

我々が若かった頃は"スーツ"と"ギーク"の対立を煽る風潮にありました。Rockstar Engineerという、ひとりで27倍の生産性を持つエンジニアを称賛する動きもありました。Being Geekという本の表紙がまさに象徴的です。

それから時は流れ、ギークとスーツは消えました。チームマネジメントが再評価され、Rockstarよりも多様性が重視され、Stallmanが批判され、Linusが変わりました。我々は生産性27倍のSPOFをありがたがることをやめ、ソフトウェアエンジニアリングを組織に適用し業務効率を高め、サイロを克服しドメインを深く理解することによってビジネスを加速化することが求められるようになりました。組織にとって選択肢でしかなかったソフトウェアエンジニアリングは、Lean Software Developmentの確立や端末の市民への普及によって、すべてのビジネスに溶け込んでいます。

現代においてDDDやプロジェクトマネジメント、品質管理やサブスクリプションに関する本を手に取ると何が書いてあるでしょうか。科学的に仮設を検証し高速に市場を創出するための手法として、いかにビジネスとテクノロジーを融合するかという一点に関心が割かれています:

  • ドメインに注力することでビジネスの専門家とソフトウェアエンジニアリングの専門家が同じ用語で議論できるようになり、またソフトウェアをビジネスに追随させやすい状態を比較的保ちやすいことが知られるようになりました。
  • Project Managerはプロジェクトマネジメント手法としてAgileを学ぶことを求められています。
  • 品質とスピードがトレードオフではないことも広く知られ、スピードのために品質に関心を払うことがQAだけではなくProject Managerや経営層の関心事になりました。
  • 多くの企業がサブスクリプションに移行しているのは、収入の予測可能性が高まることに加え、顧客とのつながりを確保しテクノロジーを通じて多様な顧客を理解するための役割を期待しているところもあるようです。

しかし、Digital Transformationのための開発組織を構築する際は、かつての対立が再現されやすいような気がします。 特に"ギーク"が"エイリアン"として振る舞い"スーツ"がそれを"受容"する……という空気を作ってしまうと容易にハマります。

無用な対立を避ける意味で最も良いのは、「ビジネスとテクノロジーが融合する重要性」という内製化の背景を経営層が理解することです。そのきっかけ作りとして私はソフトウェア・ファーストを経営に読むことを勧めたりしていますが、打率はあまり高くない印象です。たぶん長すぎるんでしょう。

読者(ソフトウェアエンジニアリングの責任者)がビジネスの文脈を理解できている場合は、経営との対話を通じて少しずつ意識を変えていくことも効果的かもしれません。
このとき、相手は内製化の背景をまだ共有できていない、ビジネスのスピードを高める必要性を理解していないということを意識する必要があります。相手の語彙で対話し、相手にその必要性を再発見させなければなりません。でもこういう誘導する話し方って、焦っているときほど難しくなるんですよね。他社事例をストックしたり、スピードが出せていないことによる機会損失を試算したりと、普段から道具を収集しておくと助けになります。また話している文の主語を省略せず、常に明確にしましょう。これだけで誤解を避け、相互理解を進められる場合がけっこうあります。

1.2. 目指すアウトカムについて開発チーム内外で合意し文書化する

経営側の意識を変えにくい場合でも、内製化をする理由・テクノロジーに期待するアウトカムを議論し、文書として共有すると良いです。明確な目的は今後のコミュニケーションに役立つでしょう。

アウトカムを明確にすることは、組織がテクノロジーを融合する重要性を理解する助けとなるだけではなく、ソフトウェアエンジニアがビジネスを理解する助けにも、ソフトウェアエンジニアが目先のノイズに囚われないための助けにもなります。この時点では定量的でなくても良いので、チームを越えた錦の御旗として使うに値する明瞭な目標を持つようにします。

1.3. Agileでなくとも構わないが、学習できる組織を目指す

アウトカムを明確にしたくても、そもそも目標や目的の明文化に抵抗がある組織もあります。その場合、その文化を変えることがDigital Transformationよりも重要な課題だと認識する必要があります。なぜなら、目標と目的の明文化は経験主義に立脚する今日のソフトウェア開発において頻出するからです。たとえば:

ここでのキーワードは「学習」です。Scrumやself-organizing team、組織論について学ぶと必ず出てくる言葉です。組織に人によって教えられる”正解”はなく、試行錯誤が必要です。我々がDigital Transformationを目指すのも、この試行錯誤のサイクルを速めたいからだったはずです。よって個人や組織が学習できる環境を作ることが求められます。

ではどうすればいいのか。中原淳氏の研究(2010年)によれば、職場で人が育つためには「業務支援」「内省支援」「精神支援」が必要だそうです。ソフトウェアエンジニアにとっては「OJTや技術教育」「1-on-1を通じた振り返りの促進」「日々のコミュニケーションで励まし褒める」ことになります。

目的が明確であれば、OJTの内容も、1-on-1で振り返る方向性も、褒めるポイントも明確になります。また失敗をした際に意味のあるPostmortemをすることもやりやすくなるでしょう。目標や目的を明文化し、個人と組織が学習できる組織を作ることを心がけましょう。

1.4. 専門職を設けるべきか

今回の想定事例のような新しいプロジェクトで、ビルドやテスト、運用について専門職を設けるべきでしょうか。個人的には否定的です。 人材の流動性が高く既存資産も多くない状況であれば、全員が開発から運用まですべてのプロセスに関わる方が開発高速化の恩恵を受けられるはずです。

ビルドスクリプトやパイプライン定義、プロビジョニング手順はファイルで定義してGitで管理するようにします。 これにより属人性を下げるだけでなく、変更内容がレビュー可能になり信頼性も向上します。

2. 技術選定

とりあえず↓に目を通すのがおすすめです:

qiita.com

その上でいくつか具体的な話を。

2.1. 目指したい「品質」の合意を作っておく

ビジネスの専門家はもちろん、ソフトウェアエンジニアにとっても「品質」の定義はゆらぎがちです。人によって違う定義を使っていたり、品質保証に幻想を抱いていたりすることもあります:

一応ISO/IEC 25010:2011でモデル化されているのでMECEに考えること自体はやりやすいのですが、全部重要に見えてきて「これローンチなんて何年も先になるのでは?」みたいなことにもなりがちです。もちろんそんなことはできないので、優先度をつけなければいけません。

今回の想定するケースでは、少ない資産で早急にプロダクトを作り検証を通じて学習し成果を出さなければならない状況のはずです。であれば、私としてはMaintainabilityを重視します。コードをどんどん書き、どんどん捨てられることが何よりも重要です。そのためにコードが疎結合であること、テスト可能であること、目が届き把握できることを優先します。

なおMaintainabilityは、今回の想定事例以外でも重要視されている認識を持っています。ビジネスなどの変化が速く、すぐに「最適」が変化するためです:

一方でPerformance EfficiencyやCompatibility、Usabilityは脇に置いても良いと考えます。MVPによって正しい仮説を掴むまでは、これらの判断をしようがないためです。Webアプリケーション開発のようにインストール先が管理下にある場合は、Portabilityも不要かもしれません。さすがにSecurityが低優先とは言いませんが、ある程度のリスクは受容する判断があってもいいでしょう。

2.2. ビルドパイプライン

パイプラインファーストを志向するべきです。ソフトウェアプロジェクトを始める際は、まずパイプラインを構築します。

Gitを使ったPull Request(PR)ベースでの開発をする場合は、デフォルトブランチへの直接pushを禁止し、ビルドを壊す変更が導入されない状態をパイプラインによって保ちます。

CIがあればPRは不要だとする意見もありますが、今回の想定では新設チームであることも鑑み、いきなりデフォルトブランチへのpushを解禁することは危険だと判断します。あと、あんまり直接pushを是とする組織は現状多くないと思うんですよね。長いもの(industry standard)に巻かれておくことは、組織外の資源を有効活用するためのひとつの知恵です。

なおビルドパイプラインがどうあるべきかは、以前ブログに書いてますのでご参考まで。

2.3. まずはテストケースから書く

先述の通り、品質としてはMaintainabilityを最優先にします。そのためには、まずテストケースから書き始める文化を醸成します。新機能開発にTDDを適用したり、バグ修正時にバグを単体テストで再現したりといったところから着手します。

このプロセスを不要あるいは非効率と主張された場合は、品質とスピードがトレードオフではないことを根気よく伝えていく必要があります。プロダクトが高速に変化・成長するためには、既存機能が壊れていないことを機械的に検証する手段である自動テストは非常に重要です。またテストケースから書くことには、目的や目標の明確化をチームに促す効果もあります。

なお勘違いしてほしくないのですが、作成したテストケースは削除して構いません。実装や要件が変わり、既存テストが不要と判断された時点で削除しましょう。不要なテストが多く残ることでビルドやデプロイのパイプラインが遅くなっては元も子もありません。もちろんテストの並列実行のような技術的な解決方法はありますが、不要なテストを実行する理由にはなりません。
一応テスティングフレームワークには実行をスキップする機能もありますが、あれを多用すると好ましいスキップと悪しきスキップとを判別するコストが上がるので、VCSを信じてサクッと消すのが吉です。*1

また自動テストケースがあれば手動テストが不要、というのもよくある勘違いです。テスト自動化の8原則にも書いてありますが、手動テストはなくなりません。手動テストすべきところにコストをかける手段として自動テストがある、くらいの理解がちょうどいいかもしれません。

2.4. プロジェクト固有ルールを作らない

コミットコメント、コードレビューのやり方、ラベルの扱い、ビルド用コマンドやリリースノートの書き方など、ソフトウェア開発にはオレオレルール策定のチャンスが多く潜んでいます。これらを早めに潰すことで、新しくプロジェクトに参入する人の参入障壁を減らし、特定プロジェクトでのみ行うべき配慮をなくすことができます。既存資産がなく人材の流動性が高くレベル感もあわせにくい状況では、これは大きな助けになるでしょう。

例えば以下のような、一般化され公開されている知見を流用します:

逆に個人の裁量を認める部分としては、エディタやOSがあります。これらの選択を自由にするための技術として、というか開発環境の差を最小化する技術として、以下のようなものがあります:

なお新しい手法をまず小さく試すために一部プロジェクトに適用する、というのはありです。堅苦しく”管理”することは本意ではありません。必要なのは検証中という状態をずるずると伸ばさないことで、これも前述の学習する組織の構築や目的の明確化によって達成可能です。

2.5. KubernetesとかService MeshとかMicroserviceとか、他にもなんかエッジなやつ

チームが小さいうちは考慮しないでいいです。こまめにデプロイしリリースできることが重要です。 将来的にチームが増え、チーム間の協力体制をどう築くか?が組織の関心事になってからで良いでしょう。

3. 忘れてはいけないこと

実行こそが最重要です。ぐだぐだと基礎や知見、歴史を語ることは必要かもしれませんが、実行だけが世界を変えます。

つーか「明瞭な目標を設定しよう」とか、言うだけならタダなんですよ。それを現実のものとするのに、一体どれだけの傾聴と対話と勉強と失敗と思い切りが必要なのかって話ですよ。頑張ってください。

まとめ

  • ビジネスの専門家とともに目的と目標を設定し、継続的に学習するチームを作る
  • 求めるアウトカムと品質について、チームと議論し共有する
  • パイプラインとテストを最初期に導入する
  • コードを書け、検証しろ、振り返りをしろ、実行がすべてだ

あわせて読みたい

いただいたフィードバック

学習できる組織とはそもそもAgileでは?という疑問に対して、Agileという用語を避けることでビジネスの専門家に受け入れやすくなることを期待していると返答したことに対していただいたフィードバック:

内製化そのものに関してはあんまり触れらてないのでその辺をもっと聞きたい、という意見への私の考え:

*1:この点ではLaunchableにはちょっと期待していまして、スキップすべきテストが自動的に選択される未来が一般化するのかもしれません。

JJUG CCC 2021 Springでバイトコードの話をしました

ということでJava8〜16におけるバイトコード生成の変化について、先日開催されたJJUG CCCで喋ってきました。 動画をYoutubeにて配信していただいているので、よろしければご覧ください:

youtu.be

資料はSpeakerdeckにあります。ハイパーリンクを埋めているところは、PDFを落としてもらえれば追えるはずです:

speakerdeck.com

マイクロベンチマークGitHubに置いてあります。みんなも手元でレッツJMHだ:

github.com

なお最後の方に触れたJEP396については、掘り下げたセッションがあったようです:

youtu.be

運営の皆様、いつも素敵なイベントを開催いただきありがとうございます!

InclusiveなOSS開発体制を作る意味で、GFWの影響をざっくり知ってもらえるとありがたい

TL;DR

2021年5月時点では raw.githubusercontent.comgcr.ioはGFW内からアクセスできません。 開発しているOSSを広いユーザに利用してもらいたい場合は、こうしたドメインへの強い依存は避けることを検討しても良いかもしれません。

中国インターネットから見たOSS開発体制

中国本土でOSS開発をしていると、以下のようにバッジが壊れているGitHubリポジトリによく遭遇します:

f:id:eller:20210520191050p:plain
バッジが表示されないGitHubリポジトリの図

これはバッジが使っているドメイン raw.githubusercontent.com にアクセスできないことから生じます。バッジなら大して影響ないのですが、開発体制構築がこれに依存していると厄介です。 例えばYarn v2のインストール手順は、JSONファイルを raw.githubusercontent.com からダウンロードするためにうまく実行できません。このためGitHub Issuesでユーザ側による回避策の適用が推奨されています:

github.com

GitHubが中国本土からアクセス可能なのは有名な話だと思いますが、それでもこうした一部ドメインへの制限があったり、Web画面にもたまにアクセスできなかったりもします。

同様に gcr.io もアクセスできません。Jibがかつて標準で利用していたベースイメージであるDistrolessのダウンロードが行えません。ただJibが利用するベースイメージはv3からDocker Hubに置いてあるAdoptopenjdkに変わったので、だいぶ使いやすくなりました。

試してませんがStackoverflowの投稿によるとfirestoreも一癖あるっぽいですね。

どのような回避・緩和策があるのか

GFW内からもアクセス可能なドメインを使う

バッジやJSONファイルを配布する場合、2021年5月時点では shields.ioGitHub Pages、Netlifyなどで代用が可能です。 おそらく最も運用が軽い対策になると思います。

2021年5月26日追記:GitHub Releasesに添付されたファイルもダウンロード可能でした。

ミラーサイトを用意する

Mavenやnpmなどのパッケージダウンロードが遅い場合は、中国国内に大手が提供するミラーサイトが利用できます。通信自体は可能なので必須ではありませんが、開発体験を向上できる場合があります。

maven.aliyun.com github.com

このように、ミラーを用意してそちらを使ってもらう手は一応あります。ただ個人的にはXcodeGhostの1件があったので、ミラーの利用をコミュニティとして推奨するのは避けたいなぁとは思っています。少なくとも公式サイトからチェックサムを確認できるようにする必要があるかと。なおGradleはv6から依存のチェックサムを自動的に検証できるようになりました。

hostsを書き換えてもらう

以下のように、中国語ブログでよく紹介されているのがこれです。詳細は割愛。

www.cnblogs.com

まとめ:そんなに気を使わなくても良いかも

こういうことを気にできると確かにInclusiveOSS開発体制の構築には貢献すると思いますが、今見たらant-designも普通に raw.githubusercontent.com を使っていたので、気にしなくても問題ないレベルかもしれません。

JavaのRecordでは配列を使わないほうが良いという話

配列使うとmutableになるから使うべきではない、というのに加えて。生成される hashCode()equals(Object), toString() が配列を考慮しない実装になっているため、JavaのRecordでは配列を使わないほうが良いようです。

検証コード

生成される hashCode()equals(Object) の挙動を検証するコードです。

gist.github.com

なぜこうなるのか

ObjectMethods クラスによって生成されるコードを見ると、 Arrays.hashCode(int[]) ではなくint[].hashCode()が、Arrays.equals(int[], int[]) ではなく int[].equals(Object) が使われているようです。これは考慮漏れというわけではなく、ObjectMethodsクラスのjavadocに明記されている仕様です。core-libs-devメーリスに質問を投げて確認しました

実際の実装はObjectMethodsクラスのコードを読むか、以下の記事を参照ください。

alidg.me

望ましい対策

Recordでは配列の代わりに不変コレクションを利用するのが望ましいと思われます。Java 9からimmutable listを作るfactory methodが導入されています。また不変であることを型として示したいならば、GuavaのImmutableListを使う手もあります。

Recordクラスがmutableになるリスクを受容した上で配列を使う場合は、hashCode()equals(Object), toString() を自動生成に頼るのではなくハードコードすることで、この問題を回避可能です。大抵のIDEにはこれらのコードを自動的に生成する機能が備わっているので、利用すると良いでしょう。

オンラインコミュニティに参加してるまとめ

自分のキャリアを考えたときに、FOSSエンジニアであることの比重が高いわりにプレゼンスないんだよね……ということに課題を感じたので改善策を考えてみた。LTやセッションを増やしたりcontributeするプロジェクトを増やしたりするのも必要だけど、他にも継続的にオンラインの知り合いを増やせる・議論の機会を得る手段がほしいと思い、オンラインコミュニティにいくつか参加し始めているところ。

参加コミュニティ

Codacy Community

OSSの静的解析ツールを複数組み合わせて統一されたUIで解析結果を伝えるSaaS、のコミュニティ。Twitterで見かけてDiscourseに参加。

SonarQubeやLGTMのような自社解析エンジンは持っていないが、CEOが静的解析で修士とった人だったし社員ぽい人もSpotBugsにPR送ってくる。のでマニアが集まるのではと期待してDiscourseに静的解析を学ぶ良い方法について話題を投げたけど反応薄いのが今。

SonarSource Community

前から参加してたDiscourseをより頻繁に見に行くようにした。私はコミュニティ担当の方とどうも反りが合わないようで、PRで話が噛み合わないとか返信を何週間も待たされたりとか、どうも見る気になれないのだけど。

どこにも買収されてない&自社で技術を持っている数少ない企業だと思うので、今後も注目していきたい。

Gradle Community

Slackがあるのに最近気づいて参加。Discourseでもいいけど、Configuration CacheとかWorker APIとかわりと新しめの話題について質問するにはSlackのほうが反応早いかもしれない。

GradleはGitHub Issuesでコミュニティ発のプラグインの機能について俯瞰状況をまとめてたり活発なユーザを称えるFellowship Programを初めていたりと周りを巻き込もうという意気を感じる。のはいいんだけどYoutubeチャンネルのノリがよくわからない。アイスブレイクのつもりなんだろうけどバラエティ番組みたいになっていたりする。

Write the Docs

コミュニティの蓄積がすごい。ツールの話はもちろんテクニカル面についてもまとまってそう。L10nについては特にまとまっていないので、Slackチャネルでおすすめのツールを聞いてみている。ドキュメンテーションツールもそうだが翻訳メモリなどについても話していきたい。

API the Docsというオンラインカンファレンスが近いようなので覗いてみるつもり。

SIGPX

DX: Developer Experience (開発体験)は重要だ - Islands in the byte stream で知り、PXは静的解析ツールとの親和性高いのではと思って第8回勉強会に以下のスライドで参加。静的コード解析そのものについて扱っている方はいらっしゃらなかったが、IDE周りというかMagpieBridgeLSPについて掘り下げて話すと良いかもと感じた。

speakerdeck.com

Java-jp Discord

ゆるゆる参加している。

twitter.com

コミュニティの更新を追う方法

モバイルアプリで追えるようにして、通勤中などのスキマ時間にぱぱっと済ませられるようにしている。

Discourse

公式モバイルアプリがあり、複数サイトを横断的に管理できる。今まではメール通知に頼っていたけどこちらのほうが早い。

Slack

Slackアプリが複数ワークスペース管理をサポートしている。各ワークスペースに同一のメールアドレスでサインインするようにすれば特別な配慮は不要。

Discord

こちらもSlackと同じ。

まとめ

はじめたばかりなのでまとまらない。情報発信は得意な方なはずなので継続していきたい。