4.0.0がリリース&貢献者募集のお知らせSpotBugs.classファイル向け静的解析ツールであるSpotBugsのバージョン4.0.0がリリースされました。FindBugsとの互換性を極力保っていた3.1系と異なり、いくつかのAPIが変わったり機能が削られていたりします。移行ガイドを確認するようお願いします。一応ユーザに使われていない機能を調べて削ったので、一般ユーザに対する影響は限定的なはずです。9以降にはまだ対応していません。コミュニティで議論された4.0でやりたいことには含まれていたのですが、貢献がありませんでした。BCELの更新に追随しているのでコア機能は動作しますが、標準DetectorのうちNullness周りをはじめとしたいくつかのDetectorが動作しないことが知られています。Java9移行のプロジェクトでもSpotBugsの利用が必要な場合は、オプションで利用するDetectorを絞ってください。11なお最近はIDEAプラグインの実装に動きがあるので、SpotBugsを使いたいIDEAユーザはwatchすると良いかもしれません。Gradleプラグインもフルスクラッチで書き直し中で、正式リリースも近いのでGradleユーザは是非試してみてほしいです。SpotBugsは貢献者を求めていますさて本日、サイボウズさんのブログでOSSに貢献する利点や手法が紹介されています:そしてSpotBugsは知名度もあり、本家のFindBugsよりも使われているプロダクトとなりましたが、まだ貢献者が少ない状態です。Pluginに特化した人がいますが、間に落ちている問題もJava9対応に限らず多くあります。直接コードに貢献しなくても、使い方や利用状況をブログやSNSで発信するだけでも他のユーザの参考になります。いう形でも構わないので、ぜひ検討してみてください。コミュニティの言語は英語ですが、日本語のわかる私を貢献の取っ掛かりに利用していただいても構わないです。Twitterやメールで連絡ください。継続的に貢献いただいた方には、Organization参加要請を出していきます。実績としても、2019年には2名をOrganizationに招待しています。お邪魔でなければ受けていただければ幸いです。Teamを通じてコミュニケーションを取っていますので、招待や議論は問題なく行えます。めもを見て良い取り組みだと思ったので書いてみたのですが、100も出てこないのでとりあえず半分でお茶を濁す作戦。プログラミング昨年のに引き続きFOSS活動状況をまとめます。2019年12月30日時点の情報です。contributionsは1,166で、昨年が950だったので約22%増です。21%なので、けっこう手を動かしてコードを書けたと思います。contributionsはゼロなので、すべて趣味開発です。gradle-semantic-release-pluginについては3月に紹介記事も書いています。減っているのは勤務先における異動による影響です。これがなかったら1,500くらい行けたかもしれません。SpotBugs周りの開発2019年もSpotBugsが一番活発な開発でした。pluginは横ばいという感じです。APIに依存していたりAndroid開発へのケアが抜けていたりという課題が多かったので、半年ほどかけて準備をしスクラッチで書き直しています。Pluginポータルにはデプロイしたので、承認されしだい利用可能となるはずです。今年の目玉はSpotBugsのダウンロード数がFindBugsのそれを上回ったことですね。あれから苦節3年弱、継続は力なりを体現した感じです。リリースもそうですがマニュアルサイトの作成と管理も結構関われているので、嬉しく思います。2019その他ひとつプロジェクトに関わらせていただいているのですが、まだ公開できる状態ではなさそうです。積極的に貢献できていないとはいえ意義のあるプロジェクトですので、機が熟したらいろいろと紹介していければと思います。javascript以前のJavaウェブアプリ開発では、JavaScriptをはじめとした静的アセットはsrc/main/webappディレクトリに配置するのが普通だった。そこに置くことでmaven-war-pluginのようなビルドシステムが.warファイルの中に突っ込んでくれる。この挙動は今でも変わらないが、src/main/webappディレクトリに静的アセットを直接置くにはいくつかの問題がある:TypeScriptコンパイラやBabelのような、静的アセットに事前処理を施す手法が普通になった。cleanなどで処理後のリソースが削除されるようにする手間を考えるとtargetディレクトリ直下にあるwebappDirectoryに置くのが無難と思われる。よってsrc/main/webappには事前処理を必要としないアセットのみを置くことになるが、次に挙げる理由からそれも必要なくなってきている。フロントエンド開発が複雑化し、サーバサイドと同一プロジェクト・モジュールで開発することが難しくなった。ここで言うフロントエンドはサーバからのレスポンスを受け取ってユーザ向けにインタフェースを提供する部分。HTML5アプリだったりモバイルアプリだったりする。workflowは必ずしもJavaのそれと一致しない。ブラウザやOSのプレビュー版が出たときにフロントエンドだけテストを回すといったことができればより高速に検証できる。JavaScriptライブラリはJavaライブラリ以上にこまめなバージョンアップが必要となるケースが多い(脆弱性対応とか、OSアップデート追随とか)ため、フロントエンドを独立に更新していけるプロジェクト体制を整えることが必要になる。frontend-maven-pluginを使ってJavaのビルドツールに統合することは可能だが、そもそも開発者が異なるケースではあまり意味がない。OpenAPIやgRPC、GraphQLなどのインタフェース定義をフロントエンドとサーバサイドの間に入れて独立に開発していく体制を組むほうが良い。S3のようなストレージサービスやCDNによって配信することが好ましい場合が多い。Cloudのドキュメントでは、アプリによる静的アセットの配信をstraightforwardだが欠点のある手法として紹介している。この問題を解決するために、大きく分けて3つの手法を紹介する。同一プロジェクト内で2つのビルドツールを併用するサーバサイド開発にはMaven/Gradleを、フロントエンド開発にはnpm/Yarnを利用するが、プロジェクトは分割しない手法。同梱する形が最もやりやすい。Resourcesとして配信可能。懸念されるサーブレットコンテナの負荷低減は、HTTPレスポンスのキャッシュやCDNによって実現することになる。サーバサイドをMaven/Gradleで、フロントエンドをMaven/Gradleで包んだnpm/Yarnで開発するケースサーバサイドとフロントエンドを同一のビルドライフサイクルに乗せるため、frontend-maven-plugin/frontend-gradle-pluginを使って、Maven/Gradleからnpm/Yarnを実行することになる。フロントエンド開発の複雑さがあまりない場合、Java開発者がフロントエンド開発も兼ねる場合に重宝する。src/main/typescriptにTypeScriptを、src/main/sassにSassを置くような体制。プロジェクトルートにpom.xmlやsettings.gradleを置いてフロントエンド用モジュールをMavenのサブモジュール/Gradleのサブプロジェクトとして扱うこともできるが、そこまでやるならば次に挙げる手法2で充分であろう。Repositoryにzipしてデプロイし、他プロジェクトから利用するということを以前試したことがあったのだが、zip/unzipを多用し性能が出ないのでおすすめしない。普通にファイルコピーで済ませるために、利用者(サーバサイド)と同一プロジェクト(Gitリポジトリ)に置くようにしたほうが良い。サーバサイドをYarnで包んだMaven/Gradleで、フロントエンドをYarnで開発するケース逆にYarnを主、Maven/Gradleを従とする手法。サーバサイドが小さいときは使えるかもしれないが、そこまでするなら手法3が素直。サーバサイドとフロントエンドでプロジェクトを分ける各モジュールの開発技法において、自由度を確保することを意識した手法。それぞれ異なる開発者が請け負う場合にはこういった形を取ることが多いのでは。Gitリポジトリを分けるかmonorepoにするかという点も考慮が必要だが、自分の開発経験(小型中心)だと分割の必要性を感じたケースは無いので、ここではmonorepoという前提をおいて考える。フロントエンド=ウェブアプリとし、モバイルアプリ開発については触れない。サーバサイドとフロントエンドのつなぎ目には、OpenAPIなどのAPI定義手法を利用する。サーバサイドとフロントエンドを突合する部分(CD、プロビジョニングなど)が複雑化する可能性はある(例えばspring-boot-vue-exampleではserverとclientのデプロイにスクリプトを使っている)が、多くの場合でさほど問題ないのでは。TerraformとかCloudFormationとか?README.mdこの場合、フロントエンドの成果物はサーバサイドの成果物に含めない。serverを利用できるし、その他のAPI定義手法でも似たものがあるはず。サーバサイドをNode.js化するという選択肢これはタイトルに全く沿わない手法であるが、真面目にありがちな話だと感じている。JavaとJavaScriptという異なる言語を同一プロジェクトで使用することが複雑さを生むならば、その原因を取り除けないだろうか?ということである。そもそもNode.jsが発展しTypeScriptのような型を使った開発も可能な現代において、サーバサイドとフロントエンドで異なる言語を使うモチベーションがどの程度あるだろうか?サーバサイドをNode.jsにすれば、プロジェクトの複雑さを除くことができる。性能に直結する非同期処理もCompletableFutureやRxJava、spring-webfluxで使われるReactorに比べればJavaScriptのasync/awaitの方が簡潔になるし、何よりJavaScriptは言語自身が「メインスレッドをブロックしない」ことを前提に設計されているので、うっかりblocking処理をサーバ内に書くことを避けやすい。Javaの方がやりやすいこともたくさんある。JVMの進展は非常に目覚ましいものがある。運用の知見など積み直しになるものもあるため即置き換えとは行かないし、する必要もない。結局道具は適材適所なので、Javaエンジニアだと自分を狭く定義するのではなくて、JavaもNode.jsもTypeScriptも学んで使いこなせばいいし、KotlinやDartのような新しい言語とそのコミュニティにも目を向けていければ良いのだと思う。まとめ小型のプロジェクトでは手法1.1、専任のフロントエンド開発者がいる場合は手法2を使うことをまず検討すると良いだろう。成果物のデプロイビルドの成果物(artifct)をアップロードすること。アップロードと公開は分けて考えることに注意。Packagesはコンテナも.jarもまとめて置けるが、コミュニティ標準の場所ではないので利用する際にひと手間必要になる。プライベートプロジェクトの場合は積極利用することになりそう。Centralに置くことになる*1。プロジェクトによっては.jarファイルとしてではなくコンテナとしてデプロイすることもあるだろう。リリースノートの作成CHANGELOG.mdやsrc/site以下のファイルを手動でメンテナンスする手法だけではなく、コミットコメントやPRからリリースノートを作成する手法もある。Releasesを使うことで、変更内容の伝達を自動化できる。Dependabotは依存先の更新を提案する際にリリースノートの内容をPRに含めてくれる。Releasesも合わせて使ったほうが良い。2.0を使うことが前提になる。Commitsから生成するものがsemantic-releaseだけでなく様々あるので使ったほうが良い。私はプラグイン機構がしっかりしているのでsemantic-releaseを使っている。gradle.propertiesといったファイルで管理するのが普通だが、最近はGitのTagを見るものもある。Tagを見ることで「ファイルに書いてあるバージョンをインクリメントする」ためのコミットが不要になるのが利点。Releaseを本Releaseに昇格させる(ブランチの最新コミットにタグを打つ)ことで公開処理を回す(tagイベントに紐付いたワークフローを回す)処理がシンプルになる。SNAPSHOT運用と相性が悪いのと、ファイルに書かれたversionの信頼性がなくなるのとで、あまりJavaプロジェクト向きではないと考えている。release:performを実行するだけで必要な処理が完結する。Maven公式の機能で完結し、歴史も長いのでノウハウも蓄積されている。シンプルだが、Tag作成をリリースの起点にできない(Tag打ちがプラグインによって行われる)ために自動化には向かない。ci]を含めたり設定を変更したりといった工夫が必要になる。(maven-deploy-plugin)Mavenでリリースを自動化する場合はmaven-deploy-pluginによるデプロイ手法を採ることになる。maven-versions-pluginのsetゴールと組み合わせることが多いはず。リリースに使用するバージョンをTag名などを経由してnewVersionプロパティに渡してversions:setを実行、deploy:deployでデプロイした後に再度versions:setでSNAPSHOTバージョンに変えてGitにpushする運用。release-drafterが使えるのでリリースノート管理もしやすい。この場合でも、Tagが打たれたrevisionのpom.xmlには実際にリリースされたversionとは異なる値が書いてあるはず。versionの信頼性という点で問題が残る。mismatchが気になる場合は、semantic-releaseの利用を検討する。これはmasterブランチにpushされた変更をすべてリリースするという手法である。バージョンの決定はsemantic-release本体が、リリースノートの作成は@semantic-release/githubや@semantic-release/release-notes-generatorや@semantic-release/changelogが、GitのcommitやTag打ちやpushは@semantic-release/gitが行うことになる。すべてのプロセスが自動化されるので、運用の負担は最も低くなる。versionの信頼性も確保できる。Commits(厳密にはAngularのルール)の利用を全開発者に強制しなければならないこと、Javaプロジェクトなのにpackage.jsonを使わなければならないこと、masterブランチを常にリリース可能にすることが許容できるならばこの手法が最善と思われる。ライブラリはともかくアプリやサービスだとPR毎リリースが受け入れられないことはあると思うが、こちらのFAQに目を通した上でも必要と判断されるなら、リリースを意図的なタイミングでトリガする手法を取り入れることもできる。(gradle-semantic-release-plugin)semantic-releaseはGradleでも使える。詳細は以前の投稿を参照。applicationsと書いてあるように、Javaアプリをコンテナ化するときに使えるツール。Maven/Gradle両対応。デフォルトでもコンテナのレイヤをうまく分けたり、warプロジェクトならJettyを同梱したりしてくれる。Actionsだとデフォルトで付いてくる)のでそこまでの利点という感じではない。ドキュメントにちょいちょいKubernetesとの組み合わせ方について言及されているので、Kubernetes使いにとってはやりやすいところがあるのかも。DockerMavenやGradleを使ってデプロイするのではなく、CIサービスでdockerコマンドを実行する。pushで行う運用になる。classのサポートを受けているので、セットアップは非常に楽。buildもあるので最終成果物も充分に小さくしやすい。やりやすいが、開発作業中にdockerコマンドが実行されない可能性をはらんでいる。これは開発者が触るものがリリースされるものと異なるものになるということで、微妙なリスクになる。開発作業中もmvnw/gradlewではなくdockerコマンドを使うようにする(付随する課題も解決する)か、コンテナにデプロイされたアプリを使うE2Eテストを早期に統合すると良いかもしれない。試してみたいのだが、現状ではalpineで動くOpenJDK(Portolaプロジェクト)が公開されてない?ようで、2018年5月時点で有効だった手法が使えなくなっている。alpineイメージをベースにするためにはDockerfileがけっこう複雑かつ管理の難しい状態になってしまうのが難点。この辺の情報はおそらくこの2018年11月時点のブログ記事が最新。docker-composeコンテナの利用をもう一歩進めて、データストアやHTTPサーバもコンテナ化してアプリとの依存関係やそのバージョンをdocker-compose.ymlで管理する。ここまで行くとより良いデプロイ手段というよりは、より良いプロビジョニングやポータブルな実行環境の方を実現したい段階だと思われる。注意することはDockerを単体で利用する場合と同様だが、アプリのコンテナが依存するコンテナ(データストアなど)をアプリをビルドするたびにビルドするような運用にならないように注意する必要がある。具体的には、ADDするファイルを最小限にすることで、スキーマ定義やマイグレーションスクリプトが変更されたときなど、必要なときだけ依存するコンテナがビルドされるようにする。2019-12-12buildpacks.ioでHerokuで使えるbuildpackを標準化しようとしているらしい。良いチームを作る2019なるほど、最近感じるフラストレーションは、新しい仕事の考え方のフレームワークを欲している線から来てるのはあるかもしれないな。前回まとめた↓のが4.5年前で、当時と変わった視点もあるので考えてみよう。2019ということで形にするために書き下しています。高い利益を上げる製品、キャリアを高める成長機会、より良い待遇と給与、良い顧客。した良いモノすべての源泉が「良いチーム」である。変化の激しい時代、ひとつの固定した「理想のチーム像」を作ることは不可能である。よって現代のチームは「時や状況に応じて学び変化できるチーム」を目指すべきである。この文書では「最高のチーム」「理想的なマネジメント」ではなく「より良いチーム」を作ることを目標とする。頻繁に質の高い学習ができる。頻繁に:組織の目的によるが、少なくとも月イチ程度にretrospectiveを行う。iterationを目指す。突発性インシデントへの対応が規定され共有されているため、ダメージを抑えpostmortemを行い学習し製品にfeedbackできる。質の高い:すべての施策に共有された目標がある。このfactがほしいと思ったときに探し出せる、あるいは新規に測定できる。solvingについてチームが理解している。他社事例や公開された研究結果などを適宜参照する。自分たちの学習したことも可能な限り公開し、ひろくフィードバックを受け付ける。postmortemの文化がある。個人の意識や努力でカバーするのではなく、組織や自動化でカバーする。目指す像が全員に共有されている。commitのための責任の所在(後述)が明確である。個人の個性と意思が尊重され、結果としてモチベーション高くモノづくりができる。多様性を重視する、オープンな議論を行う、役職を発言と紐付けない。認知的不協和を抑えるためにも、個人が謙遜さとオープンさを身につける必要が、組織が心理的安全性を満たす必要がある。マネジメントが「上司」ではなく「支援者」であることを信じてもらう。leadershipを実行する。各個人が学びたいこと、挑戦したいことの把握に努める。得た情報を現状に照らし、勤務の一環として成長機会を作る努力をする。学びたくないこと、目を背けたいこととの折り合いを共に考える。健康状態や家庭の事情に気を配る。可能な限り勤務時間や貢献手法に制限を設けない。場所や時間を縛る働き方を排除する。各自の役割が明確になっている、ボトムアップとトップダウンのバランスが良い。ブレークスルーの源泉は常にチームにある。チームのリソースをどこに割くかを検討し優先度をつけるのがマネジメントの役割。ボトムアップの力を信じてempowermentすることと、組織目標やスコープを明確にすることは両立する。マネジメントはまずチームのMissionとVisionを明確にし、チームのベクトルを合わせる必要がある。チームを信じられない、チームに任せられない理由があるならばまず第一に排除する。言語の壁、文化の壁、情報の不対称性、習慣の違いなどが該当する。我々は(失敗したときに)責任を取れという言い方をすることがあるが、それになんの意味があるのだろうか?まさにそれですね。「責任」というものが出てくるのは仕事、職業が社会身分、ステータスの延長にあるようなメンタルモデルにとどまっているからだと考える次第。2019失敗によるダメージを抑えるためにマネジメントはリスク管理をするべきで、管理が足りていなかったなら反省し学ぶ必要がある。管理できなかったダメージは既に存在するので、再発防止だけでなくケアの方法も考える必要がある。責任の本質は、情報と権限を明確にして状況に応じて速やかに学び行動できる組織づくりではないか。責任を取らせることが必要なのではなく、責任を預けるに足る能力(組織づくりやリスク管理)を持つ人材を責任者に据えることと、能力が足りないと判断したときに上長の判断で外せることが必要なのではないか。Resultsがすべて達成できてるのは逆に良くないという前提が共有されている)ので良いと思う。あとフォームを利用したマネジメントへの匿名FBも有用。コーチングが問題発見の手法になるかもしれない。少なくとも聞き手と話し手の双方に問題発見を促す働きがある。不確実性を早期に発見するために、目標は小さくし、Scrum手法を適用する。ダメージを想定し備えるとともに、失敗したときのコンティンジェンシープランを持っておく。手を動かすことと議論することにチームを集中させる必要がある。ここで言う議論はコンセンサスを作ることではなく知恵を出し合うことである。手を動かす時間を作るために、作業は極力自動化する。バグの再現環境を作ったり、管理用の情報を揃えたり、やるべき作業をリマインドしたり、必要なライブラリやミドルウェアを揃えたり、コードレビューをしたり。CIジョブでできるチェックは極力CIジョブで実施する。理想的には1日あたり4時間以上集中して作業できる状態にする。時間はまとまって確保できるようにし、フローに入れるようにする。議論はあらかじめ目的を明確にして、結論の出し方を決めておく。ファシリテーターを置く。ここでは思考や知見を積み上げることを目的としているため、アウトプットは文書化し検索可能にする必要がある。ベータ版が個人リポジトリの方に来ているので、色々と試しています。使っているテンプレートプロジェクトと実アプリケーションプロジェクトから、いくつか事例を紹介します。各種単語の定義が公式サイトにあるので、いちど目を通すことをおすすめします。runに対して添付することができます。ミソで、これがないとテスト失敗時にupload-artifactが実行されません。always()の説明は公式サイトにあります。複数のjobを並列に実行する場合は、nameを固有かつ直感的な名前にしないと、レポートをダウンロードする際にどれを確認すべきかわからなくなってしまいますので要注意です。wrapperとDockerコンテナどちらを使うべきかGradleを使ったビルドは、大きく分けて2つの方法が採れます。Hubで公開されているgradleのイメージを使う方法です。Gradle用の非公式actionが存在しますが、特にメリットがないため検討していません。Wrapperを叩くケースが最もシンプルと言えます。Wrapperを使うため、開発者が手元で使うGradleとバージョンを合わせることも容易です(Wrapperを使わずGradleをインストールしてPATHに通しても良いが特にメリットがない)。Hubのgradleイメージを使う場合は、with.argsを使って実行するコマンドを指定します。e2eテストのようなコマンドに依存するビルドでは使いにくい面もあると考えられますが、持ち運びの効くコンテナでCIを回せるのは嬉しい点です。YAMLファイルの見通しも比較的良いです。buildなお今のところ、この2つの方法には速度の違いはないようです。Dockerコンテナを使うとsetup-javaがなくなりGradleインストールの時間が短縮される反面、イメージをpullする時間がかかります。Dockerイメージやローカルファイルシステムのキャッシュが導入されたら、このあたりは変わってくるかもしれませんね。Repositoryは何が良いかOrganizationで使う場合はActionsを実行するリージョンが選べるそうです。SettingsのOverviewに表示されているリージョンを使っています。agentが何らかの問題で使えない場合でもペアリージョンの別のagentを使ってるみたいです。Artifacts使えばupstreamからのキャッシュになります。2019が、少なくとも私の個人リポジトリでは選択できない状態です。15s試行回数を重ねないと確かなことは言えませんが、少なくともMavenリポジトリの物理位置がビルド速度に影響出るのは間違いありません。Repositoryを運用している場合は、それを物理的にどこに置くか考える必要がありそうです。package-registryを使っても良いかもしれませんね。sonar.organizationそしてsonar.projectKeyをシステムプロパティで指定するだけです。公式フォーラムで紹介されています。これだけで通常の解析もブランチ解析もPR解析もいけます。オプションを使って指定していますが、build.gradleに直接書いても大丈夫です。GITHUB_TOKENとSONAR_TOKENの設定が必要です。variableにアクセス可能な場合にのみ実行するような工夫が必要なようです。}}READMEにステータスバッジを埋める公式ドキュメントが公開されましたので、それを参照すればOKです。公式ドキュメント来ました。キャッシュしたい!GradleやMavenを使っていると、Mavenリモートリポジトリからダウンロードしたjarファイルをキャッシュしたくなります。残念ながら現時点ではその方法は無いようです。toolkitに入っているtool-cacheを使って~/.gradle/cachesをキャッシュするActionsを書いてみたのですが、キャッシュの保存はできてもキャッシュされたディレクトリをfindできません。Debugログを有効化しても特に情報は得られませんでした。Javaに限らず他の言語のコミュニティにも期待されている機能だと思いますので、今後に期待しています。