Posted at

Domaの開発で大切にしている10のこと

More than 3 years have passed since last update.


自己紹介



Domaとは?



Domaの歴史


  • 2009/05: 開発開始

  • 2009/02: v1.0.0リリース

  • 2014/07: v2.0.0リリース (Java 8対応)

  • 2016/06: v2.11.0リリース(最新版)



1. 動かさないとわからないを減らす



  • コンパイル時にできるだけチェック



  • Javaコードに対して


    • 例:アノテーションの存在チェック





  • SQLファイルに対して


    • 例:パラメータの存在チェック



select * from EMP where ID = /*identity*/100



  • SQL内の式コメントに対して


    • 例: 型チェック



select * from EMP where ID = /*id.hoge*/100


  • コンパイル時に idInteger 型だとわかる



    • hoge への参照はコンパイルエラー





2. コードの信頼性を高める


  • SQLテンプレートでSQLインジェクションを防ぐ

select * from emp whrere name = /* name */'taro'


  • PreparedStatementへ変換して実行するので安全

select * from emp whrere name = ?



  • リソース(Connectionとか)を自動で解放する

// トランザクション内で検索と更新をするコード

tm.required(() -> {
Employee employee = dao.selectById(1);
employee.setName("hoge");
employee.setJobType(JobType.PRESIDENT);
dao.update(employee);
});



3. シンプルさを重視する


  • 例えばCriteria APIは提供しない

  • Criteria APIはシンプルさを損なう



EntityManager em = ...;

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> allPets = q.getResultList();



  • 利点


    • 型安全で組み立てられる


      • 文字列のタイポが発生しない





  • 欠点


    • 学習コストが高い

    • いつCriteria APIを使うべきかで迷う


      • 迷う ≒ シンプルさの欠如







4. SQLの発行場所とタイミングを明確にする


  • SQLの発行はDAOインタフェースの呼び出しで


    • 遅延ロードはサポートしない



// ここでSQLを発行するならOK

Dept dept = dao.selectById(1);

// ここでSQLを発行するのはNG!
List<Employee> employees = dept.getEmployees();



  • キャッシュはしない


    • いつも必ずSQLを発行

    • 必要ならアプリレイヤで



// SQL発行

Dept dept = dao.selectById(1);
// SQL発行
Dept dept = dao.selectById(1);



5. SQLの完全性を重視する


  • SQLの断片化を促進させる機能は持たない

-- こんな機能はありません!

select /*%include common_select_list.sql*/
from employee
where /*%include common_search_condition.sql*/


  • 過剰な共通化は見通しを悪くする



6. JDBCでできることを制限しない


  • 例えばストアドプロシージャーの呼び出し

@Procedure

void execute(@In Integer id, @InOut Reference<BigDecimal> salary);



  • 結果セットを複数個返すようなストアドプロシージャー

@Procedure

void execute(
@ResultSet List<Employee> employees,
@ResultSet List<Department> departments,
@In Integer employee_id,
@In Integer department_id);



7. 逃げ道を用意する


  • いざという時にJDBCを自由に使えるのが重要


    • かつ呼び出し元に影響を与えないものポイント



@Dao

public interface EmpDao {
default Emp select() {
Config config = Config.get(this);
DataSource ds = config.getDataSource();
... // 自由にJDBCの機能が使える
}
}



  • Domaを捨てる場合にも使える


    • 他のDBアクセスライブラリへの移行する場合



  • Javaのインタフェースを使っていることの利点



8. 様々な環境で長期的に使えるようにする


  • JDK/JRE以外には依存しない


    • 依存ライブラリがJavaのバージョンに追随しないリスクを避ける

    • 依存ライブラリが他のライブラリと競合するリスクを避ける





  • 実行環境に依存しがちなところはインタフェースで実装を差し替えられるように


    • 例えば、クラスローディング周り


      • Play Framework v1

      • Spring Boot DevTools







  • バイトコードをハックしない


    • 同じ注釈処理をするライブラリでもLombokとは違うところ

    • Domaは将来のJavaでもほぼそのまま動作するはず





9. 変化(トレンド)に追随する


  • Java 8対応


    • Stream

    • Optional

    • JSR310 Date & Time API





  • Kotlin対応(実験的)

@Entity(immutable = true)

data class Person(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int? = null,
val name: String,
val age: Int,
@Version
val version: Int = -1)



10. 利用者の声を聞く


  • 自分が考えた機能は2010年時点でほぼ実装完了


    • それ以降の機能追加は利用者の意見が中心





  • 利用者の声は宝の山


    • そんな使い方があったとは!という良い意味での発見が多い

    • 7年も続けられている理由の1つ





Twitterのつぶやき



Twitterでメンション



Gitterへの書き込み



もちろんPull Requestも



疑問や要望はいつでもWelcome


  • できるだけ応えたい

  • 面白いアイデアに発展するかも?



ぜひ使ってみてください



Domaの開発で大切にしている10のこと


  1. 動かさないとわからないを減らす

  2. コードの信頼性を高める

  3. シンプルさを重視する

  4. SQLの発行場所とタイミングを明確にする

  5. SQLの完全性を重視する

  6. JDBCでできることを制限しない

  7. 逃げ道を用意する

  8. 様々な環境で長期的に使えるようにする

  9. 変化(トレンド)に追随する

  10. 利用者の声を聞く