はぶあぶれーく

IT技術の勉強に関して記録していく備忘録的なものです。

H2の接続モードについて調べてみた

ずっと後回しにしていたH2DBについていろいろ調べてみた。

きっかけは、Springbootで起動したH2にDbSetupからアクセスできなかったことから、H2のことをもっと知ろうと思った。

ぼんやりとした知識

  • なんかインメモリで動く組み込みのデータベース
  • インメモリだけじゃなくてファイルでデータを扱うこともできるよ
  • インメモリではアプリ(Springboot)を落とすとデータが消えるので開発時には便利

ぐらいの感じでした。

調べてみた

公式ドキュメントを読んでみました。

QuickstartやTutorialを読んでみましたが、使い方は書いてあるものの、知りたいことはやっぱりわからず。

自分の知りたいことってなんだろう?考えてたんだけど、なかなか言語化できず、検索できなかったんですよね。

「仕組み」とはちょっと違うし、「中身」でもないし、何知りたいんだっけ?みたいな。

公式ドキュメントを読み進めていくとドンピシャのがありました。

Features

あ、機能を知りたかったんだ。と。

接続モードが3つある

  • 組み込みモード
  • サーバーモード
  • ミックスドモード
組み込みモードについて

SpringBootでデフォルトで接続されるのがこのモード。

ローカル接続

jdbc:h2:~/test や jdbc:h2:file:~/test のようなURLで接続した場合はローカルのファイルを使ってデータを保存するモード(ローカル接続)になります。

インメモリ接続

jdbc:h2:mem:db1 のようにh2:のあとに mem を付けるとインメモリでの接続となります。

また、名前なしのURL(jdbc:h2:mem:)で起動した場合は非公開(private)のデータベースを開くことになります。

この場合、同じURLで開いた場合は2つの異なるデータベースが開かれるので、同じデータベースにはアクセスできないということです。

同じインメモリに複数接続したい場合は、名前ありのURL(jdbc:h2:mem:db1など)で起動します。

この場合は、同じ仮想マシンとクラスローダー内に限り、同じ名前で開くと同じデータベースに接続可能です。

さらに、別のプロセスからアクセスしたい場合は、インメモリデータベースが作成されたのと同じプロセスでTCPサーバーを起動すれば、jdbc:h2:tcp://localhost/mem:db1などのデータベースURLを使用してアクセス可能です。

SpringBoot の場合はデフォルトがインメモリで、TCPサーバーが起動されていないので、TCPサーバーを起動すれば、冒頭の私の悩みである「DbSetupで接続したい」が叶うわけです。

SpringBootでH2のTCPサーバーを起動する方法は下記記事を参考にしました。

Querying the embedded H2 database of a Spring Boot application - techdev Solutions GmbH

サーバーモードについて

JDBCまたはODBC APIを使用してデータベースをリモートで開きます。

同じまたは別の仮想マシン内または別のコンピュータ上でサーバーを起動する必要があります。

このサーバーに接続することにより、同じデータベースに同時に接続できます。 内部的には、サーバープロセスは組み込みモードでデータベースを開きます。

すべてのモードと同様に、永続メモリとインメモリの両方のデータベースがサポートされています。

ドキュメントにはこんな感じで書かれてます。

同じデータベースに同時に接続するためには、このモードで立ち上げる必要があります。

jdbc:h2:tcp://localhost/~/test のようにh2:のあとにtcpを付けるとサーバーモードで立ち上がります。

インメモリ接続のところにも書きましたが、起動したあとは jdbc:h2:tcp://localhost/~/test で接続します。

ミックスドモードについて

混合モードは、組み込みモードとサーバーモードの組み合わせです。

データベースに接続する最初のアプリケーションは組み込みモードで動作しますが、別のアプリケーション(異なるプロセスまたは仮想マシンで実行中)が同じデータに同時にアクセスできるようにサーバーを起動します。

ローカル接続は、データベースが組み込みモードでのみ使用される場合と同じくらい速く、リモート接続は少し遅くなります。

サーバーは、サーバーAPIを使用してアプリケーション内から開始したり停止したり、自動的に(自動混合モード)開始することができます。 自動混合モードを使用する場合、データベースに接続するすべてのクライアント(ローカル接続またはリモート接続のいずれであっても)は、まったく同じデータベースURLを使用して行うことができます。

ドキュメントにはこんな感じに(ry

前述の、インメモリで接続してTCPサーバーを起動するのがミックスドモードということでしょうか。

「自動混合モード」はどうやったら使用できるのか、とか。ドキュメントのどこ見たら書いてあるんだろ。。。

気が向いたらまた調べときます。

おまけ

よく、「同じURLで接続してるのになんかうまくいってない!」とかあったんですが、たぶんPrivateで開いてたから同じURLでも違うデータベース開いてたんでしょうね。

これ、違うデータベース開いてるのか、ちゃんと接続してるけど何かしらの理由でうまくいってないのかの判別が難しいと思ってたのですが、良いオプションがありました。

String url = "jdbc:h2:/data/sample;IFEXISTS=TRUE";

IFEXISTSをTRUEにしてあげると既存のデータベースを開くことのみを許可することができます。

この場合、データベースが存在しない場合は、接続しようとすると例外がスローされます。

これは便利。トラブルシューティングに使えそうです。

まとめ

H2には接続モードが大きく分けて3つある。最低でも組み込みモードとサーバーモードの違いは知っておかないと使うのは厳しそう。(今までよく使ってたな。。。

ミックスドモードでどう開くのかは謎のまま。

DDDしてみた

2017/6/24のKANJAVA PARTY 2017 !!!で@haljik さんのセッションを見て、挑戦してみました。

普段使いのDDD // Speaker Deck

 

作るもの

お題として、簡単なSNSを作ろうと思います。

誰かが「投稿した記事を、誰でも見れる。」というだけの超簡素なSNSです。

 

人・物・事分析

その業務に登場する、人・物・事を並べたてます。

  • 人=投稿者、閲覧者
  • 物=記事
  • 事=閲覧、投稿、検索、コメント

こんな感じでしょうか。

まず、人としては、投稿者と閲覧者がいます。

物は記事だけかと思います。記事に対して何か事を起こします。

事は、閲覧者が記事の検索、閲覧、コメントをしたいですし、投稿者は投稿したいです。

 

時系列

独立してある人や物をまず並べてそれが起こす主要なイベントを時系列で並べます。

  1. 投稿者と閲覧者がいる
  2. 投稿者が記事を投稿する
  3. 閲覧者が記事を検索する
  4. 閲覧者が記事を閲覧する
  5. 閲覧者が記事にコメントをする
  6. 投稿者が記事にコメントを返す

こんな感じで並べてみました。

 

モデル化

人・物・事分析で出た要素を時系列分析で関連付けし、依存の方向を決めます。

 

f:id:bird_cage313:20170715003416p:plain

 

モデル図はこんな感じで作ってみました。

 作ってみてわかったんですが、矢印が記事に集中してるんですね。つまりこのアプリケーションのコアドメイン記事だという事がわかります。

このアプリケーションは小さいものなのでそんなの最初からわかってるよって思うかも知れませんが、ちゃんと分析でも想定してた結果が出たのがおもしろい。

こうして、ちゃんと分析してコアドメインを把握していくのですね。

 

コードを書く 

これをそのままコードに落とし込んでみます。

投稿者

public class Author {

private String name;

public Author(String name) {
this.name = name;
}

}

記事
public class Article {
private Identifier identifier;
private Author author;
private Title title;
private Contents contents;

public Article(Identifier identifier, Author author, Title title, Contents contents) {
this.identifier = identifier;
this.author = author;
this.title = title;
this.contents = contents;
}
}

検索
public class Search {
private Articles articles;

public Search(Articles articles) {
this.articles = articles;
}
}

これ、ちょっとおもしろいんですが、Searchというクラスがあってその中にArticlesクラスがあるんですよね。
まあモデル図通りに書いてるのでそうっちゃそうなんですが。

僕がこの分析をせずにコードを書くなら、間違いなくArticleクラスかArticleServiceクラスを作ってそこにsearchメソッドを書くと思います。

分析して作ったクラスは逆なんですよね。でもそっちの方が妙にしっくりくるというか、使うときも Search.articles と書くはずなので英語の文としてもかなりしっくりくる。
これはありかもしれない…!


まとめ

コード少ししか書いてないけどかなり気づきが得られた。コードを書く前に業務を分析することは大事です。

「和田卓人の“テスト駆動開発”講座」を読んだ

これです。

gihyo.jp

 

この連載は、WEB+DB PRESSfでテスト駆動開発の特集をしたときにフィードバックに答えるために企画したそうです。

フィードバックの内容として、「もう少し初心者にもわかりやすく」「もっと突っ込んだ内容をもう少し詳しく」「もう少し実践的に」という内容があったようで、連載の前半は初心者にもわかりやすく連載第2回はテスト駆動開発」とは何か?というタイトルで連載が始まっています。

さらにテストとはどういうものなのか、テスト駆動に慣れていくのにはどうすれば良いのか、という内容に触れ、後半では和田さんがTDDに目覚めた話なども入っております。

TDD初心者でも最初から読み進めると一歩ずつ理解できるような構成になっていると感じました。

また、連載の各記事の最初に動画があって、ホワイトボードを使って解説してくれているので、わかりやすいと思いました。(記事はその動画を文字に起こしたという感じ

 

とくに印象に残った

第3回 「テスト」という言葉について ── Developer Testing,Customer Testing,QA Testing

第3回の記事でテストという言葉広義に解釈されるので、まずテスト駆動開発における「テスト」とは何なのか?という説明がされているのですが、ぼくもこの「テスト」という言葉を誤解していて、この回を読んでDeveloper Testという言葉を知ってテストに対する考えがわかりました。

第9回 テスト駆動開発の「サイクル」――次にテストリストでToDoを洗い出し,レッド,グリーンでサイクルを回す

ToDoをテストリストという形にしてやるべきことを明確にする。

開発対象の機能を考えている際には,こういうことをやらなければならない,ああいうこともやらなければならない,という課題・ToDoが次々に浮かんできます。それらのToDoを,まず簡単に箇条書きにしていくんですね。箇条書きにするのは紙でもテキストファイルでも結構です。これをテストリストといいます。

 

さらに、大きい機能をRED-GREEN-リファクタリングのサイクルで回すときはREDの状態が1週間や2週間かかるかも知れない。その状態は好ましくないので、そういう場合は小さい機能にテストリストとして分けてそれをRED-GREEN-リファクタリングのサイクルで回していくんだ。みたいなことが書かれてます。

タスク分割のときの考え方に基づいてるのかなと思いました。大きいタスクは分割しないとね。

ただ、REDの状態が1週間というの極端ですが、実際はREDの状態はどのぐらいを目安にしてるんでしょうねー。というのは気になりました。が第10回はそれが題材でした。笑

第10回 テストの最小単位は不安

ぼくが第9回で感じた疑問「実際はREDの状態はどのぐらいを目安にしてるんでしょうねー。」はREDがどのくらいの時間になるのかで分けるのではなく、不安に感じている最小の部分をテストするということでした。

例えばif文1つでも不安と思うならテストをするってことです。

プログラマとしての私は,if文の条件部分のミスや,配列をループしたりするときにカウンタ値を1個間違えてしまう(フェンスポストエラー)といった,すごい単純ミスが多いんですね。

 これにはすごい共感して、ぼくも単純ミスが多いのでTDDでカバー出来たらと思います。

 

あと学習テストの話。

これからコードを書く際に,自分が使おうと思っている技術,たとえば未経験のライブラリの使い方に対して不安がある場合に,それをテストの形で書いて技術検証することを「学習テスト」と呼びます

 私は何回やっても忘れてしまうことが多いため,暗記できないものに関しては,自分でその場でライブラリの使い方などに対するテストを都度書いていって,その使い方が機能する(テストがグリーンである)ことを自信の根拠にします。

これもすごく共感しました。忘れちゃうんですよね。。。

学習テストという言葉も初めて聞いたのですが、先輩がライブラリの使い方調べてるときに調査用のリポジトリ立ててテスト書いてたのを思いだました。あれが学習テストだったのだと。

これからは意識してやっていこうと思った。

第11回 テストの資産価値

不安をテストにするなら、新人は不安だらけだからすごく小さいテストが多くなる。

そうした場合、リファクタリングとか仕様変更とかでテストが要らなくなるケースがある。

新人はそれに対して「もったいない」と感じる人がいるが、そういう人に対してどう思いますか?という質問からの記事です。

これはぼくも気になっていて、「もったいない」とは思わないんですが、テスト自体消して良いのかな?と思っちゃいます。

今まで必要で書いてきてて、それが要らなくケースとは?そこリファクタリングするときどうするの?って。

その答えは

リファクタリングで小さい粒度のテストが赤くなったときには,もうそのテストは役目をある程度果たしていると考えています注1)⁠

ですから,テストをその時点で捨ててしまうこともあります。ただし,小さいテストを捨てるという判断をするときには,当然それらのテストを包含している大きいテストがあることが前提です。

でした。

なるほど、それらを包含しているテストがあれば確かに要らないか・・・。

ただし、TDDで開発してるんだからその包含しているテストも速くないといけないよね。ってことで良いんですよね?

それらを包含しているE2EのテストをFluentLeniumで作ったから捨てるぜ!ってわけにはいかないですよね?って理解であっているかな。

第20回 テストコードの重複はアリかナシか

ここは連載で意見が割れてたところなんですが、ぼくは重複ナシ派だなーと。

厳密に言えば、なるべく重複なくしたいなーと。仕様が変わった時に重複箇所全部触るのはちょっとなーという感じです。

ただ、テストコードの重複をなくす=テストコードのリファクタリングをするという話は大きくなるそうで。

なぜ大きいトピックかという説明を,少しだけしましょう。リファクタリングをするためには,テストが必要ですというのが,リファクタリングの大原則としてあります。ということは「テストのリファクタリングを行うときには,テストのテストがないといけない」という話にどうしてもなってしまいます。

 確かに!これどうするんだ。。。

⁠達人プログラマー』ですこし言及されてるみたいなので読んでみようかな。

 

まとめ

この連載2007年開始なんですね。。。

この業界は技術の進歩が速いので、ぼくは2年、3年前の記事は割と懐疑的に見るんですが、この連載はまったく色褪せていないと感じました。

まずはTDDでコード書いてみよう!

TDDについてちょろっと調べてみた

なぜ調べる経緯に至ったか

勉強会でサービスを作っていまして、そのプロジェクトでふと、単体テスト書けてなくね?となりました。

あれ?最初は書くようにしてたのにいつ間にか形骸化してるじゃん。どうしよ。ってなって、じゃあTDDでやったらいいかも!と提案したのが始まりです。

じゃあ次からTDDでやろう!と決まったは良いものの、TDDについてはよく知らない。ユニットテストから書いていくことだよね?ぐらいの知識でした。

なので、TDDってどんな問題を解決するものなのか、そもそもテスト書くの忘れるからTDDって訳でもなさそうな気がする。と思って調べてみました。

 

どう調べたか

ググりました。「TDD やり方」「TDD メリット デメリット」「TDD 目的」とかで調べました。

見つけた記事

基本的にQiitaの記事は荒れてる印象でした。TDDについて書くの怖くなった。笑

技評の和田さんの連載が素晴らしくて、まだ第3回までしか読んでないけど、これ無料で読めて良いんだろうかと。

 

なぜTDDでやるのか? 

色んな記事を見る限りは「開発者のため」なのかなーと。

当たり前だろ!と思うかも知れませんが、これ結構誤解されがちなんじゃないかなーと思います。僕も誤解していたかも。

TDDは素早いフィードバックと開発者の安心のためとどこかの記事に書いてました。

そして和田さんの連載では

Developer Testingは,開発者が開発者のために,自分自身のために,もしくはチームメンバーのために行うテストです。

このように書かれてます。

和田さんの連載によると、テスト駆動開発におけるテストとは、品質保証ではなく、Developer Testingという開発者のためのテストであるということでした。

完全に品質保証のテストをやるものだと誤解してました。

Qiitaで盛り上がってる記事もこの辺を誤解しているように見えます。TDDでテストカバレッジを100%に近づけるのは無理だ。的な。

話は逸れますが、テストカバレッジは80%以上になれば100%にしようと大きな効果はないといった記事を見つけたので、その辺りも勉強したいところ。

 

TDDどうするのか

RED-GREEN-リファクタリングのサイクルを回すのだ!これは前の現場で実は教えてもらってて、改めてそうだったなー。と思い出しました。最近できてなかったや。

  1. まずプロダクトコードを書く前にテストコードを書いてテストをこかす。
  2. テストが通るように実装する
  3. テストが通る状態を保ちながらリファクタリングする

簡単に書くとこんな流れ。詳しくは和田さんの連載をみてください。

 

TDDをやるときの心構え

素早いフィードバックを得るためという目的があるので、テストは速い状態を保たないといけない。

あとはわかんない。ちょろっと調べただけだから。

TDDが白熱するところ

雑に書きます。

  • テストしにくいところどうするの?
  • 開発コストでかくなるんじゃね?
  • 遅いテストを書くんじゃねえ
  • 全体的に極端に捉えられがち

なんか議論が白熱してるところはこんなところなのかな。

TDDは死んだとかあまり何が言いたいのかよくわかんなくて。原文読んだらわかるのかな。

Mock化しまくってテストするべきところができねーじゃん。って言いたいのはなんとなくわかった。

開発コストは、デバッグとかも考えるとむしろ最終的にコストが小さくなるんじゃないのかなと思ってます。

 

まとめ

テスト書くの忘れる防止のためとかではなかった。

でもTDDやってみようと思います。安心したいし。

深く調べた訳ではないので、次はもう少し議論白熱してるとこに焦点当てて調べて行きたいです。

BDDとか、テストファーストとかってワードも出てきたのでそちらも合わせてちょっと調べれれば。

TDDやる上での仮説
  • 開発者が安心できるはずだ
  • 素早いフィードバックを得れるはずだ
  • 開発コストは膨らまないはずだ

検証できない仮説ばかりを立ててしまった。。。

 

FluentLeniumで自動テストを用意する「前」に迷った話

E2EのテストにFluentLeniumを使いたいと思っているんですが、どんなふうに導入すれば良いかわからず困りました。

 

テスト対象

 

具体的に何を迷っているかというと

  • テスト対象とは別プロジェクトでFluentLeniumだけを動かすプロジェクトを作る
  • テスト対象と同じプロジェクトで単体テストと同じパッケージに作る

このどっちにすれば良いんだろう。で迷っています。

実は前いた現場では前者で実装しておりました。しかし、どっちが一般的というか、正しいお作法というか、そういうのがわかりません。

 

別プロジェクトで作る場合

想定するパターンがいくつかあって、1つはリポジトリ直下にプロジェクト2つ置いちゃう。

project

     ┣ product

     ┃     ┗ build.gradle

     ┗ e2e-test

              ┗ build.gradle

こんな感じかな。(だれかパッケージ構成をブログで簡単に書ける方法を教えてほしい)

この場合、Gitで落としてきてIDEでプロジェクトimportするときは producte2e-test を両方importしないといけない。(ちょっとめんどくさい)

 

もう1つは、Gradleでマルチプロジェクトにしちゃう。

project

     ┣ product

     ┃     ┗ build.gradle

      e2e-test

          ┗ build.gradle

     ┗ build.gradle

これは project ごとimportしたらsubprojectもimportできるのでいける。と思う。

Gradleでのマルチプロジェクトはまだ勉強中でわからないことが多い。

ただ、productはマルチプロジェクトじゃないのになーとは思う。

同じプロジェクトで作る場合

project

      product

           ┣ main

           ┣ test 

           ┃     ┣ unit

                ┗ e2e ←ここに置く

           ┗ build.gradle

この場合は、TDDで開発する際に、気軽に全テスト実行できないんじゃないかという不安がある。

パッケージさえ分けておけば問題ないのかも知れないけれど。(Ctrl+S押したくなるタイミングでunitの全テストして、コミットしたくなるタイミングでe2e含む全テスト動かすみたいな)

あとは、CIどうしよ。unitだけciでテストできる設定とかあるんだろうか。その辺も詳しくないので要調査。

結論

わからない。

ドキュメントとかSampleとか見てたら後者が多い気がするなーという感。

ただ、前の現場で前者でやってて特に不便は感じなかった。

今回は後者でやってみて知見が得られたらここに書くことにする。

一応、後者でやっていく上での想定を書いておく。

メリット
  • マルチプロジェクトにする必要がない(今ある知識でいけそう、importどうこうも気にしなくて良い)
デメリット
  • うっかり全テスト流してしまって慌てて止めて残念な気持ちになるかもしれない
  • CIどうしよ(今ある知識では無理かもしれない)