SpringFoxを使ってみる

最近仕事でSpringBootを使う機会ができたのでSpringFoxを使ってみました。   REST APIを作ったとき殆どの場合でそのAPIのドキュメントを用意する必要があると思います。大体の場合はSwaggerを使うと思うのですが(Railsのときはそうでした)これを手書きするのはかなり手間です。
特にエンジニアにとってドキュメントを書く作業は退屈なはずなので自動で作って欲しいですよね。Railsでは難しかったのですが、偶然にもJavaは静的型付けの言語なので(最高ですね)型からいい感じにドキュメントを作れそうです。

SpringFoxを使ってみる

build.gradleで以下の依存関係を追加しましょう。残念ながらstarterはないようです。

implementation('io.springfox:springfox-swagger2:+')
implementation('io.springfox:springfox-swagger-ui:+')

あとはちょっと設定を追加すれば出来上がりです。

@SpringBootApplication
@EnableSwagger2 // <- これと
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

    // このBean
    @Bean
    public Docket document() {
        return new Docket(DocumentationType.SWAGGER_2).select().paths(PathSelectors.any()).build();
    }
}

/swagger-ui.htmlにアクセスすればSwaggerの画面が見れるはずです。このパスを変更する方法は調べましたが、提供されてなさそうです。

情報を増やす

APIのパラメータとレスポンスについては自動的に作ってくれますが、APIの説明がないので付け加えたいですね。
handler methodにアノテーションを書くことで説明を追加することができます。

@ApiOperation("ここにAPIの説明")
@ApiResponses({
        @ApiResponse(code = 400, response = ErrorDetails.class, message = "エラー時のレスポンス")
})
@GetMapping("/hoge")
public HogeResponse hoge(@RequestParam(value = "page", defaultValue = "1") int page) {
...
}

手軽に使えるのでAPIを作る場合はとりあえず入れておけば良いと思いました。

Doma2環境の中間テーブルを考える

Doma2環境でレコードを削除するときに中間テーブルをどう扱うか悩んだのでそのメモ。

悩んだ状況

f:id:orekyuu:20180929201610p:plain 上のようなテーブルで、repositoriesのレコードを削除するときのことを考える。
repositoriesにはlanguages、frameworksの間に中間テーブルが存在していて、一緒に削除しないと外部キー制約に引っかかってエラーになる。 repositoriesを削除する前にこの中間テーブルを削除しなければならないが、Doma2ではsqlファイルに複数のSQL文を書くことができないので何かしらの方法を考える必要がある。

考えられる選択肢

カスケードを使う

中間テーブルの外部キーにON DELETE CASCADEをつけてrepositoriesのレコードを削除したときに一緒に削除できるようにする。
DB側で頑張るのでアプリケーションコードがすっきりする。ただし、テーブルA -> B -> C -> Dのように伝播が広がりすぎると手がつけられなくなる可能性がある。ちょっとこの辺は経験不足なのでどうなるかわからない。

アプリケーションコードで頑張る

中間テーブルのDaoを作ってアプリケーションコードで削除するようにする。アプリケーションコードがつらくなる。面倒。
メリットとしてはDBのマイグレーションよりはアプリケーションコードのほうが変更が容易であること。

JOINして削除する[ボツ]

これは試してボツになった案。調べてみて知ったが、joinして複数のテーブルをまとめて削除できるらしい。
DocumentMulti-Table Deletes 参照
以下のようなSQL1発で解決できると思ったが外部キー制約に引っかかってダメだったのでボツ。

delete repositories, rf, rl from repositories
  join repository_frameworks rf on repositories.id = rf.repository_id
  join repository_languages rl on repositories.id = rl.repository_id
where repositories.id = /*repo.id*/2

カスケードを使うことにした

アプリケーションコードがシンプルになる・カスケードに関してはテストである程度担保できるという理由で選択。
カスケードの伝播が広がりすぎて手がつけられなくなりそうになったら撤退する予定。

最近の悩み

最近エンジニアとしての生き方にもやっと悩んだりしているので文章にして整理してみようと思った。

今やっている仕事

 今はtoCのサービスをRailsで書いている。Java好きじゃなくなったかというとそういうわけでもなく、toCやりたいなーと思っていたら成り行きでそうなった感じ。学びがなかったかというとそんなことはなくて異文化に触れることでいろいろ学ぶことはあったけど、RubyRailsを学ぶことに対して熱量が持てていないのが現状。実際趣味でRubyRailsを触ってないしね。
 ただ、toCを作ることの面白さみたいなのはあってユーザーが良い反応してくれると嬉しいし新しいものをリリースする楽しさはとてもある。正直学生の時より楽しい。

Javaが好き

 今でも趣味でJavaを書いていて、Java11がリリースされるのもワクワクしていたし楽しみにしてた。趣味でコードを書くときはJavaしか書かないし、仕事でどうでもいい使い捨てのコードを書くときも無駄にJavaで書いたりしている(きっとRubyで書いたほうが早い)。学生のときほどではないけど今でもJavaの情報は追っているつもり。
 仕事で触ってない今JJUG CCCとかJavaの勉強会で登壇するネタが出せない現状がすごくつらい。Rubyの勉強会のネタはあるのにね…やっぱり業務で触ってないと難しいんだと思う。

今の悩み

 多分だけど、いつか転職するときはJavaが書けるところに行くんだろうなと思っているけど実務経験もなくRailsを書いていた人間がJavaの会社に行けるか不安だし、toCかつJavaという選択肢はすごく狭くてどちらか捨てないといけなくなるとも思っている。どっちも好きだし選ぶのって難しいなー…。エンジニアとして成長するなら多分Javaの会社に行くことだと思っていて、得意な言語を伸ばしていきたい。最近Twitterやってると他のエンジニアとどんどん差ができているような気持ちになってるし危機感。
 ちなみに今の仕事に不満があるわけではなくJavaが書けない以外は最高の職場と業務内容です。

ふつうのDoma2の使い方

最近Tuzigiriというリポジトリを作ったりしてる。あまり進んでないけど。
このリポジトリは、GitHubリポジトリシェアのサービスをオープンソースで作りつつ、色んな人にSpringBootのお手本や参考にしてもらえばいいかなというモチベーションで作っている。このへんのお気持ちはまぁおいおい別記事で書こうと思う。
いまはnoko_kと一緒に走り始めた段階だが、とあるプルリクエストでDoma2の使い方について議論になったのでそのへんのことを書こうと思う。

ワイルドカードというアンチパターン

雑にワイルドカードでカラム指定をしているSQLでnokoによってお縄になった。これはSQLアンチパターンのインプリシットカラム(暗黙の列)というものらしい。(最近SQLアンチパターンを買ったのに積んであって申し訳ない…)

積んであったSQLアンチパターンを読んでみると以下のようなデメリットが書かれていた。

  1. 列の追加削除をしたとき、添字でアクセスしていた場合ずれてしまう Doma2の場合は影響なさそう。生JDBCResultSet#getString(columnIndex)のようなケースだと踏んでしまうケースですね。
  2. 余分なカラムをフェッチするのでパフォーマンスに悪影響がある それほど大量のカラム持ってないし気にするほどか?という気持ちもある。ちなみにDoma2では/*%expand*/ と書くことで、マッピングするEntityのカラムを自動的に展開してくれる機能がある。これを使って回避すると良いっぽそう。

さらに、Domaは特別に設定を書かなかった場合デフォルトでマッピングできないカラムがあったときに例外をスローするのでワイルドカードは危ない。
また、SQLアンチパターンになかった指摘としてカラムの型変換をしたときに明示的に書くことでgrepしやすいというものもあった。これはexpandでは満たせない要求なので難しい。

どうするのが良いのか

ワイルドカードを使わずにカラム指定を使ったほうが良いのは確かになったが、expandか明示的にカラムを書くか考える必要がある。 結論としては以下の理由でexpandを使う方針になった。

  • 明示的にカラムを書いていた場合、新しいDBにカラムが追加されたときに複数のsqlファイルを変更する必要があり漏れて例外になる可能性がある。expandの場合マッピングする型の修正のみで済む。
  • expandのほうが楽なのと、Domaに乗っかっている感じがある。

まだ探り探りやっているのでこれが普通かどうかはまだ自信がない。