型駆動開発?テストコードを減らせるかもしれない個人的に注目のアイディア
開発していると、○○駆動開発という言葉をよく耳にしますね。
テスト駆動開発、モデル駆動開発やReadme駆動開発などいろいろあります。
今日、紹介するのは「型駆動開発」です。英語でType Driven Development。
型駆動開発って何?
Maciek Próchniak氏によると、型駆動開発とは一言で、テストコードでチェックしている部分をコンパイラで行うという開発スタイルだそうです。
確かにコンパイラでバグが見つけられれば、テストコードを書く手間もないですし、 テストコードはビルドするときに実行し忘れてしまったら問題があっても気づけないですが、 コンパイルは実行前に必ず走るので、チェック漏れも減りそうです。
コンパイラがあれば手軽に始められるのも良さそうですね。
型駆動はバグを防ぐ方法のひとつ
同氏によると、型駆動開発以外でバグを防ぐ方法は
- 防衛的プログラミング
- 契約プログラミング
- そして、度重なるテスト
があるとのことです。
防衛的プログラミングは、入力や状態が正しいかを実行時にチェックする方法で、バグを防ぐには効果的だそうです。
関数の入力をassertなどでチェックしていると、プログラムがおかしな状態で走り続けることがないので、バグを早く発見することに繋がります。
ただ、いたるところでチェックのコードが入ってしまうと、本来のコードの見通しが悪くなるデメリットがあります。
コードもキレイで意味のあるものになる
型駆動設計は、StringやIntをじかに使う代わりに、意味のある型を定義するので、 コードを汚すことなく不変条件をチェックすることができるそうです。
例えば、顧客IDともう一つ別のIDを受け取る関数があった場合、引数の順番が間違っていても実行してみないと問題に気づくことが出来ません。
def loadFriends(cid: String, bid: String): Seq[String] = ???
loadFriends("customer-123", "branch-123")
loadFriends("branch-123", "customer-123") // 順番が間違っている
Stringの代わりにCustomerId
やBranchId
型を定義しておけば、コンパイル時に気づけるわけです。
case class CustomerId(id: String)
case class BranchId(id: String)
def loadFriends(cid: CustomerId, bid: BranchId): Seq[CustomerId] = ???
loadFriends(CustomerId("customer-123"), BranchId("branch-123"))
// 順番が間違っているが、コンパイル時に発見できる。
loadFriends(BranchId("branch-123"), CustomerId("customer-123"))
テストコード減るかも?
型駆動開発では、型を沢山定義することになりそうですが、 テストコードを何行も書く代わりに、型の定義を1,2行書くと考えれば、 型駆動のほうが開発コストも押させられそうですね。
注目の開発スタイルです!
Maciek Próchniak氏による型駆動開発の解説動画(英語)