前提、選定基準、優先順位(昇順)
- 開発スピード(必須)
- ビジネスチャンスを逃すような開発はありえない
- とは言えスケールした時ORM原因で一気に開発速度が下がるようなものは避けたい
- 学習コストの低さ(必須)
- システム開発において理解しなければならないことはORMの仕組みだけではない
- SQLの理解はORMに関係なく必須
- 精鋭軍団で開発できる機会は早々無い、人の入れ替わりや若いメンバーの参画は常に想定が必要
- OracleなどのDBではパーサの最適化により正規化されたDBではエンジニアの書いたSQLに関係なくハイパフォーマンスな処理が行われる(ORM側で最適なクエリを発行しなくても大丈夫)
- リードモデルの自動生成(必須)
- SQLレコードとのマッピングクラスは何れにしても必要
- ORMだけでの複雑なオブジェクトへのマッピング機能は柔軟性も高くないしORMそのものを複雑にする
- ジェネレータ、ツールの使い勝手は重要
- 環境構築の容易さや実行時のハマりにくさなど
- SQLレコードとのマッピングクラスは何れにしても必要
- コードの見通しの良さ(重要度高)
- 極力発行されるSQLまで理解しやすくしたい
- 処理があちこちにあったり、断片化すると理解までに時間がかかる
- SQLの柔軟性(重要度高)
- 数百、数千の超大作SQLは作らないとしても、非正規化やある程度柔軟なクエリは書きたい
- ある程度の条件分岐はあったほうがいい
- 単純なStringだけでは流石に冗長
- 変更容易生(重要度高)
- 初期生成はコードジェネレータで生成できるのは一般的だが、それ以降の修正に対して感知できるがは重要
- 早期にバグを発見したい
- 静的に発見できるものが望ましい
- ただし、ユニットテストで発見できる範囲であれば妥協すべき部分もある
- 環境構築(重要度高)
- ORMの大半はジェネレータと併用が必要
- 無くてもいいもの多いがコンパイラの範囲外になるSQLにおいてジェネレータで生成するコードは自分ですべて実装するより精度、信頼性が高くDB変更やリファクタリングのしやすさなどを考えると費用対効果は十分にある
- Annotation processorのサポートは強力だが、開発環境構築の複雑さと壊れやすさを生み出す原因になる場合がある
- ツールチェインが複雑になるとハマるポイントが増えるので、無いか極力初期設定のみでカバーできるほうが望ましい
- ORMの大半はジェネレータと併用が必要
- 冗長性の排除
- 極力シンプルにはしたいが、裏側の仕組みが複雑になれば、ハマった時の深さが大きくなる
- 冗長なコードは10分で書けるし、Grepも容易だが、フレームワークでハマれば、1,2時間ですまないことはよくある
- 信頼性
- 信頼性が高いほうが周りの説得にこまらない
- 自作のORMは落とし穴にハマりやすい
対象外
Spring JDBC
- pros
- 圧倒的学習コストの低さ
- コネクションやトランザクション管理などORMに必要な最低限の機能を網羅
- 最低限のオブジェクトマッピング機能
- cons
- pros以外の機能はほとんどない
- 型安全性もほとんど無い
- 謹製の自動生成は無い(別ツールの自動生成と併用して、NamedJdbcTemplateでReadモデルへのマッピングはできる)
Javaで現実的に候補になるできるORMで最もシンプルだと思う。とはいえ、実運用で使うのであれば、もう少し柔軟なSQL発行機能が無いと、SQL周りのコードが煩雑になりやすい
(パラメータ生成やクエリを分けるための条件分岐やループ、変換などがSQL String周りで多発が懸念される)
Spring Data JPA
- pros
- Spring親和性
- 高機能なAPI、キャッシュ機構
- SQLレス(SQLも使用可)
- 様々なクエリ機構(CrudRepository, @Named, Specification, JPQL, JPA)
- 1:NやN:Nのクエリ生成までCrudRepositoryのみで可能
- 標準仕様
- cons
- 高機能ゆえの圧倒的学習コストの高さ
- 理解度が低いとやりたいことをするまでにかかる時間
- 発行されるSQLが圧倒的に予想しにくい
- ハマった時の時間
- 非正規化が苦手
- 我々はいかにして技術選択を間違えたのか? 2016
非正規化は避け、安定して有識者(1人に依存しない)にすぐに相談できる環境であれば候補になりえる。効率的なSQLが発行できるらしい。
少なくとも若いエンジニアが安定して保守できるORMには思えない(もちろん出来なくはないが、費用対効果が悪すぎる)。
比較表
- | Doma 2 | MyBatis | jOOQ |
---|---|---|---|
Annotation processor | ◯ | × | × |
コードジェネレータ | ◯ | ◯ | ◯ |
コードジェネレータのカスタマイズ | ◯ | ◯ | ? |
環境構築(プロジェクト) | 汎用R Daoの追加 IntelliJ build設定 |
Java 8対応設定 | |
環境構築(個人) | コードジェネレータ設定 Annotation processor設定 IntelliJ plugin追加 |
コードジェネレータ設定 IntelliJ plugin追加 |
コードジェネレータ設定 |
汎用 CRUD | ◯(R自作) | ◯ | ◯ |
学習項目(個人) | 更新系の仕組み SQL内の埋込み式 |
XMLのマッピングの仕組み SQLの埋込み式 |
DSL |
アクセッサーの排除 | ◯ | ◯ | × |
Write Domain modelマッピング | SQLファイル private field |
アノテーションString or XML private field |
× |
Read Domain modelマッピング | × | △(XMLマッピング+ミュータブルクラス) | × |
Read Entityマッピング | ◯ | ◯ | ◯ |
見通しの良さ(Read) | RepositoryImpl Dao I/F SQL |
RepositoryImpl Mapper I/F XML(オプション) |
RepositoryImpl |
見通しの良さ(Write) | Service Dao I/F SQL(オプション) |
Service Mapper I/F XML(オプション) |
Service |
静的チェック力
変更容易性において、静的チェック力は重要な観点の一つ
- | Doma 2 | MyBatis | jOOQ | |
---|---|---|---|---|
SQLシンタックスエラー (Java->File) | × | × | ◯ | jOOQは全てライブラリ内で生成するため安全 それ以外はチェック文字列で記述しているためチェック不可 |
外部ファイルチェック | ◯(apt) | × | ◯ | Domaはaptで実現(マッピングできないSQL(Java<-SQL)も警告してくれる) jOOQは外部ファイルを使用しない(コンパイラ保証) |
パラメータ変数存在チェック | ◯(apt) | × | ◯ | Domaはaptで実現 jOOQは外部ファイルを使用しない(コンパイラ保証) |
スキーマ情報の整合性チェック | × | × | ◯ | jOOQは自動生成した、スキーマ情報をSQLで使用するため静的に保証 |
- apt: annotation processor
vs
Doma vs Spring JDBC
項目 | Doma | Spring JDBC | コメント |
---|---|---|---|
学習コストの低さ | ◯ | ◎ | 単機能なぶん間違いなくSpring JDBCの方がすくない |
SQLの柔軟性 | 2Way-SQL | String | StringでSQLは似たようなSQLが増えた時に相当冗長になる、またその辺りを構造化すると煩雑になり可読性の悪化に繋がる |
変更容易生 | 静的チャック | × | 全体の見通しは悪くないがStringでは静的チャックは変更にはリスクが伴う |
環境構築 | Anotation processerの設定はやはりハマりやすいし、壊れやすい | ◎ | Spring JDBCは他の機能を捨てる代わりに基本dependency以外は不要 |
冗長性の排除 | ◯ | × | 2Way-SQLは必要十分、Stringの冗長性は言うまでもない |
Spring JDBCを別言語と併用するアプローチを考えたい(要調査)
- ヒアドキュメントはやっぱり便利
- RepositoryImplのみGroovy、KotlinやScalaなどのJVM言語を使用するなど
- 学習コスト、ツールチェインの複雑さは発生するが言語サポート機能による型安全性やシンプルな実装になど費用対抗があれば
Doma vs MyBatis
項目 | Doma | MyBatis | コメント |
---|---|---|---|
開発スピード | Annotation processerの設定が手間 | XMLの設定が手間 | XMLは誰か一人でいいがannotation processerは全員行う必要があるので、ビルドツールでIDEも含めた設定が必要 |
学習コストの低さ | ◯ | △ | どちらもそこまで高くない、MyBatisの方が設定や機能が多そうなので若干高いかも |
SQLの柔軟性 | ◯ | ◯ | どちらも十分な表現力を持っている、XMLで構造化出来る分MyBatisの方が自由ではある |
変更容易生 | ◯ | × | MyBatisは静的チャックが行えないので変更に関してはリスクがある |
環境構築 | △ | ◯ | Annotation processerは設定が決して楽とは言い切れない |
SQLテンプレート | SQLファイル クエリビルダ |
アノテーションString XMLファイル クエリビルダ |
XMLによる構造化は一見強力に見えるが見通しが悪くなるのと、MyBatisは静的チャックを行えないので変更容易生も悪化する。あとXMLが好きかどうか。 |
- SQLファイル vs XMLファイル
- SQL(Doma)
- そのまま実行可能な2Way SQL
- 柔軟なSQL埋め込み機能
- シンプルさのために極端な構造化機能を容易していない
- XML(MyBatis)
- xmlによる構造化、再利用が可能
- SQL(Doma)
- アノテーションString vs SQLファイル
- MyBatisは世界的に使用されている実績がある、Domaは性質上国内での十分な実績がある
- MyBatisは実行時エラーが中心なので設定ファイルの作成以外は基本複雑な設定はない、Domaはコンパイルエラーによる検知のためにAnnotation processor設定が必要になる
機能的にも設計思想的にも似ていて競合しやすい。現時点でMyBatisの方が優れていると思うポイントはアノテーションにSQLを直接書けることくらい。構造化できるXMLはむしろ可読性と保守性を考えるとデメリットになりやすい。
逆にDomaの欠点はAnotation processorによる開発環境周りの複雑性と不安定性。プロジェクトの初期設定で出来る限りすませれるようにするのが重要。それができればアノテーションプロセッサーによる静的チェックは非常に強力。
Doma vs jOOQ
項目 | コメント | ||
---|---|---|---|
開発スピード | |||
学習コストの低さ | ◯ | △ | jOOQも学習コストが極端に高いわけではないが、直接SQLを書くのと比べてしまうと高い。ただし、Domaは2Way-SQLの式の理解は必要 |
SQLの柔軟性 | |||
変更容易生 | |||
環境構築 | |||
冗長性の排除 | |||
jOOQの最大の魅力は壊れないSQL。SQLを自分で書かないため、基本的なシンタックスエラーはもとより、カラム名やテーブル名も自動生成されるため、実質的に手書きで書くSQLで起こり得るタイポや存在しないスキーマアクセスなどは起こらない。これはDomaの静的チェックよりも強力。
またスキーマ変更時にもコンパイルエラーで発見できるのも便利。これはタイポ同様完全なSQLを記述するDomaでは検知できない(Javaコード側は出来るがスキーマ側はできない)。
ただし、どこまでコンパイラの保証が必要なスキーマ変更が入るかや、強力な構文チェックが必要かは要検討。シンタックスエラーやある程度のスキーマ変更は条件に関わらず必ずエラーに起こるため、通常の開発時にそこまで保証しなくても、ユニットテストを一つ動かせば十分検証出来るはず。
あと、jOOQのタイプセーフクエリはIDEの補完がどんどん効いて書いてる人だけが分かる気持ちよさを持っている。終端処理周りもList,Optional,Record,Table,Json,CSVなど様々な形式に変換できる機能を持っているのも便利。
とにかく型に保証され安全に書けている気持ちになる。
またSQL発行方法も、Defaultのジェネレータで生成するDSL方式とActiveRecord方式の他に、オプションでDao方式も選べる(ActiveRecordがあればほとんどDaoは不要?)。その他にもDomaと比較するとAnnotation processorもいらないので環境周りの設定、安定性も高い。つまり非常に書きやすく、そこそこ読みやすいという特徴がある。
とは言え、そもそもDSLなので極限までSQLに近づけてるとは言えAPIの理解や学習コストもかかるし(特に複雑なSQL周り)、実際のSQLとは乖離があったり、直接コピペで実行出来なかったり(SQLを出力は出来るが開発環境が動かせないと確認できない)、JavaとSQLの中間層なので実際に発行されるSQLへの脳内変換が必要になったりする。
後は、Javaコード上にクラス内のにアクセッサーが必須になる(DomaやMyBatisは外部ファイルを使用しリフレクションでアクセスするため不要)ためDDDの場合内部データアクセスにアクセスするためのGetterが必要になる。
そして、有償DBには有償ライセンスになるため、職場によってはそもそも選択肢に出来ない可能性もある。
個人的に考えるjOOQが最適な環境は
- 有償DBではない or ORMであっても会社がお金を出してくれる
- DDDなど柔軟で高度な設計パターンより、型保証されたロジカルな処理が書きたい
- annotation processerやSQLなどに頼るより、型の力に守られたい
などのときにはいいと思う。データ処理やバッチなど?
柔軟性の高いDomaと型安全性の高いjOOQという印象(個人的感想)
Java、SQL指向的Domaと関数指向的jOOQという印象(個人的感想)
特にjOOQはメリットとデメリットに大きな特徴がるので、選択時には比較的条件を絞りやすいと思う。
vs
項目 | コメント | ||
---|---|---|---|
開発スピード | |||
学習コストの低さ | |||
SQLの柔軟性 | |||
変更容易生 | |||
環境構築 | |||
冗長性の排除 | |||
まとめ(編集中)
Doma
- prop
- 2Way-SQL
- SQLファイルを利用していてもAnnotation propcessorによる静的チェック(コンパイラサポートに近い機能)
- SQL以外の機能(DSLやXMLのルール)が少ないが必要順分で純粋なJavaとSQLが中心の設計
- cons
- ツールチャインの複雑さ、Annotation processorの設定
- prop/cons
- ドキュメントもエラーも日本語
- 日本人にとっては非常にありがたいが、英語であればもっと世界的にも評価されるはず(主観)
- ドキュメントもエラーも日本語
MyBatis
- prop
- アノテーションString SQLの可読性(JavaコードとSQLが近い)
- getter不要
- cons
- XMLマッピングの複雑性、構造化による可読性の悪化
- String文字列によるルールベースのマッピングを行うため修正が安易にしにくい
jOOQ
- prop
- ツールチェインが他と比べシンプル
- DBアクセスのクラス(Repository/Service)も一つにできる
- スキーマも含めた可能な限りの型安全性
- 書いた人だけが分かるIDEの補完の気持ちよさ
- cons
- 有償DBは有償サポート
- Javaライブラリの中で圧倒的にSQLに近いがDSLには変わりないので、いくらかの学習コスト
- 発行されるSQLが想定と違う系のハマりポイント
- 全てがJavaのためアクセッサーが必須
- デバッグ時にコピペでSQLが使えない
Writeはgetterを割り切るならあり、Readなら問題ない
基本1クラスにDBアクセス処理が集約できる見通しの良さもあるが、DSL->SQLへの脳内変換が必要なのでそこは生SQLよりは見通しが悪くなる一面もある
有償サポート系のDBを使用しいる場合は会社次第では致命的になる
結論(検討中)
Annotation processorの複雑性はあるもののビルドツールとIDEの設定次第である適度カバーでき、全体的に見てもシンプルで高い可読性、必要十分な静的チェック、getter不要などの特徴を踏まえると現時点ではDomaが一番使いやすい。