システム部の福原と申します。
(以前書いた記事はこちら)
最近弊社では、Kotlinなど新しめの何かを本格導入しよう!という動きがありまして、この記事ではそのへんのドタバタぶりを書いてみました。
ご笑覧あれー。
はじまり
KotlinでSpring BootでAPI作ってDockerで本番稼働させよとの勅令が下る。
Kotlinのプロジェクトはすでにやったことがあるので雛形はある。これをコンテナ化とかCIとかCDとかやりたいらしい。あと、Kotlin初めての人が大半で分かる人少ないから技術普及もやってねとのこと。
うおー、なんだか色々来た。さあ、どうしよう。
最初の設定
まずプロジェクトはgradleで出来てる。とりあえずツール仕込むか。
依存ライブラリ:Gradle Versions Plugin
Gradle Versions Plugin
https://github.com/ben-manes/gradle-versions-plugin
こいつは依存ライブラリの更新チェックをしてくれる。
今使っている版が古くなっているかどうかチェックするのは最新版を追いかけるための第一歩だ。
コードチェックツール:detekt
Kotlinの学習や成果物の品質確保のためにも静的コードチェックツールは欠かせない。ツールの指摘でKotlinの理解が深まるきっかけになるものだ。
調べたところ Ktlint と detekt ていうのがあるのだな。
https://detekt.github.io/detekt/
とりあえず色々設定できそうだから detekt にしておくか。
内容吟味している暇はないから、開発しながらチェック内容の検討をしよう。
統合開発環境
IDE には IntelliJ IDEAを使うようにしよう。
IDEAにはコード整形の設定とか実行の設定とかいろいろあるな。この設定を統一せねばならぬ。
ところで、こういうGUIの設定みたいなのを手作業でやると大変過ぎて死ぬ。手作業は避けたい。なんとか楽できないかな。。。???
そういえばこういうのがあるらしい。「IDE 設定を共有する」 か。。。
https://pleiades.io/help/idea/sharing-your-ide-settings.html
とりあえず、設定リポジトリ方式でやってみるか。
新しくgithubのリポジトリを作って、こいつを設定して、あと夜食のヤキトリをこうして、、、と。
できたかな?とりあえず同僚氏に確認をしてもらおう。
<数日後>
同僚氏:設定共有できたけど、なんだか共有したくないのも共有されちゃったよ!!
なぬーどういうこと?
聞けば、カラーテーマとか(私はライトモード。彼はダークモードが好き)他のプラグイン設定とかIDEAに登録してあるJDKのフルパスとかも共有されてしまったらしい。
やりすぎだ。これは使えない。解除しよう。
となるとやはり手作業が発生してしまうのか。
だがこれはやむを得ない。コード整形の設定はxmlファイルで出し入れできるらしいから、こいつだけ共有するようにしよう。
そもそも開発環境は開発者の創意工夫が発揮される場所。下手な設定の共有化はみんなのやる気を無くさせるかもしれない。もうちょっとツールの理解を深めれば便利に使えるようになるだろうか。
ドタバタ(1)IntelliJ と detekt の狭間
開発者:ねえねえ、IntelliJでコード整形したらdetektに怒られるんだけど。
(注:ブログ向けにサンプルコードを起こしています。わざとらしさを感じろください。)
これは、、??論理式を &&
つなげて1行が長くなって、それを改行したときのインデントが多いと言っている?
例えばこういうのを、
1 2 3 4 5 6 7 8 |
package com.gmor_sys.formatsample class FormatSample { fun doNantoka(): Boolean { val testNumber = 1 return testNumber == 1 && testNumber == 1 && testNumber == 1 && testNumber == 1 && testNumber == 1 } } |
こうしろと言っている。return
の次の行のインデントを減らせと。
1 2 3 4 5 6 7 8 |
package com.gmor_sys.formatsample class FormatSample { fun doNantoka(): Boolean { val testNumber = 1 return testNumber == 1 && testNumber == 1 && testNumber == 1 && testNumber == 1 && testNumber == 1 // この行のインデント } } |
こういうの、IntelliJ の方がそういうふうにやってくれないかな。detektとIntelliJ が噛み合ってないぞ。
<<しばらく試行錯誤。ドタンバタン。>> =☆
調べてみてわかった。まずKotlinの標準コーディング規約にはこのへんについて決まりがない。
そして、IDEAのJavaの方にはこれを設定する機能がある。
しかしKotlin側にない!ぐぬぬ。これはどうしようもない。
とりあえず、detekt側は該当のファイル先頭に
1 |
@file:Suppress("Indentation") |
を入れて無視するようにしよう。ああ、腸が切れそう。
IDEAとしては、機能要望上げてみるか。。。Java側にある機能をKotlinにも移植してほしいって話だから簡単は簡単だろう。
https://youtrack.jetbrains.com/issue/KTIJ-2414
よし書けた。我ながら本当にヘボイ英文だがやらないよりはましだ。
(注:読者の皆様にはぜひupvoteをお願いしたいのですよ。)
ドタバタ(2)カバレッジの工夫
同僚氏:ねえねえ、Jacocoのカバレッジがどうしても取れないところがあって、これどうしよう?
むむ?
Springで @autowired されるフィールドへのsetter と getterに処理を通せと?
つうか、書いてもないコードのカバレッジ問われるってどういうことだ?
うーむ、どうしたらいいんだこれ?
<<そして試行錯誤。ドッタンバッタン大騒ぎ。>> ==のの
あーわかった、こうすれば良い。
フィールドインジェクションじゃなくて、コンストラクタインジェクションで書けばよいのだ。コンストラクタインジェクションならそもそも setter と getter が作られることもない。ない関数に処理を通す必要もない。
しかもKotlinだからJavaよりも端的に書ける。いいぞ!
いろんなブログとか記事調べて見ても、こっちの方が良いらしい。なるほどね。。。
(注:弊社では単体テストを書くことになっていて、カバレッジ100%にすることがルールとなっています。工数やスケジュールの見積もりもそれが前提です。)
▼弊社ユニットテストのカバレッジに関する記事
ドタバタ(3)SwaggerでAPI仕様書自動生成
swaggerでAPI仕様書作りなさいとの指令が下る。
もうpptとか社内wikiに仕様書作るの嫌になったらしい。
・・・???ところで swaggerってなに?springfoxってなんですか?
<<wind bombの練習みたいに試行錯誤。ドカーン。ドカーン。ドカーン。>>
どうやらこういうものらしい。
まず、OpenAPI Specification というのがあって、これはREST APIの仕様をYAMLやJSONで記述するための仕様らしい。(以下、OASと略します。)
https://spec.openapis.org/oas/v3.1.0
で、springfox てのは Springのアプリに組み込んで使うもので、ソースのアノテーションの内容を読み取って、OASのJSONを作ったり、APIリファレンスを作ってくれるらしい。
APIリファレンスにはAPIをテスト実行するフォームもついてくるらしい。(さすがWebだな。)
springfoxは内部的にswaggerを使っているようだ。
http://springfox.github.io/springfox/
swagger は色々なツールやサービス群であるようだ。OASのJSONからAPIリファレンスを作る機能もあるらしい。デザインはいくつか選べるようだ。
じゃあ触ってみるか。
例えばSpringの @RestController
がついている、何らかのパスに対応している関数に、こんなアノテーションを書く。
すると、こういうAPI仕様書が自動生成される。swaggerが生成したものだ。
Try it out
から操作するとテスト実行もできる!
おおお、マークダウン書いたらそのとおり表示してくれる。これはKotlinのraw string (ヒアドキュメント)と相性いいな。JavaだったらJava13まで待たなくてはならぬ。Kotlinやっててよかった。
ドタバタ(4)Continuous Integration
今までJenkinsやってたけどオンプレ環境維持するの大変だしなんか改善せよと伝令が下る。
どうしよう。
<<ムーンサルトりしながら試行錯誤。神よ、私は美しい。 ドカーン ちゅどーん ピキヒィューーーン ドドドドドドドド>>
よし、Github Actionsの出番だ。GithubがJenkins相当のことをやってくれる。
まず Publish Unit Test Results というアクションを使ってテスト結果をPRにコメントさせる。
https://github.com/EnricoMi/publish-unit-test-result-action
あといろんなレポート成果物はそれ用に設定したS3にアップロードして、そのURLもPRコメントに入れるようにした。
detektの結果はcheckstyle形式で出力してreviewdogに食わせて違反をPRに書かせる。
PR内のコードだけ指摘させているのが味噌だ。
普通の人は他人がやった違反を直すモチベーションはないが、自分が修正したコードで指摘が飛んだら直すモチベーションあるだろう。
内容にも依るが、detektの違反は必ずしも0である必要はない。今までよりも減れば良い。そういう心があればよい。来たときよりも美しく。ボーイスカウトルールだ。
テスト失敗やカバレッジ100%達成してない場合は、check失敗として赤くなるようにした。マージ禁止にする設定にはしないが、怠慢かましてこれを無視するPRレビューアは社内には居ないはず。
Github Actionsはコミットごとに動作するようにした。富豪的だが弊社でやってるGitHub Enterpriseの契約では全然気にせず使えてしまう。とりあえず限界が見えるまでこれで行こう。
ドタバタ(5)JCenterで翻弄の一席
2021年2月3日頃
JCenter終わるんだ。ふーん。
って思ってたらうちでも使ってたやんけ。どうしよう。代わりの設定をしろってことになるかな?
試しに ビルドファイルから JCenter の設定であるところの jcenter()
消してビルドしてみた。こけた。
調べると、detekt
が kotlin-html
を使ってて、こいつの最新版がCentralに無いらしい。
むう。
2021年2月28日頃
と思ったら、JCenter停止延期らしい。ですよねー。しばらく塩漬けしとこう。
2021年5月上旬頃
よし、手が空いてきたぞ。この件もっと調べてみよう。
kotlin-htmlのドキュメントによると、jetbrainsのリポジトリを設定すれば良いらしい。
https://github.com/kotlin/kotlinx.html/wiki/Getting-started#gradle
1 2 3 |
repositories { maven { url "https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven" } } |
おお、動くぞ。じゃあこれで行こう。
その数日後
と思ったら、detekt1.17.0で解消するらしい。じゃあdetektだけ上げればよいか。
https://github.com/detekt/detekt/releases/tag/v1.17.0-RC3
さらに数日後
上げたら違反が増えた。どうやら 1.17.0 から、テストコードもチェックするようになっている!
https://github.com/detekt/detekt/pull/3649
その思想、わからんではない。が、うちの場合現実的に適用するのはちょっと無理だ。
除外設定が要る!どうしよう。もうこれまた塩漬けでいいや。
終わりに
もしかすると私が色々解決したように読めるかもですが、実際のところ問題を解決した同僚氏はたくさんいます。話を単純にするためこんな風になりました。彼らの協力に感謝です。
そういえばDockerの話するの忘れてました。それはまた別の機会に。
弊社ではこんな感じで新しい取り組みをやっています。もっと楽してサクサク進めたいものですね。本記事が誰かの参考になれば幸いです。