Development method
開発手法
継続的インテグレーション
私たちは、継続的インテグレーション(CI: Continuous Integrationの略)を採用しています。これは、バージョン管理とテスト駆動開発を用いることで、スピード感を維持しながら継続的なソフトウエアの改善を行なっていくことを仕組み化していく手法です。
オープンソースソフトウエアの開発においては、特定の企業やルール、カルチャーなどに所属しない多様なプログラマーたちが開発に参加します。
私たちは、スキルとモチベーションが高いエンジニアを一人でも多く参加させることこそ追求するべき多様性だと考えています。そのための様々なコミュニケーションコストを削減しながら、「スピード感の確保」や「改善される一方であることを保証する」には、継続的インテグレーションはもっとも重視されるべき開発手法です。
テスト駆動開発
私たちは、継続的インテグレーションを実現するために、自動化されたテストコードを実行しながら開発していくことで、不具合の早期発見とコミュニケーションコストの低減を図っています。
私たちは以下の原則に従って開発を進めています:
- 開発者たちはまずテスト用コードを開発してから、実際の開発に進みます(テストファースト)
- 不具合修正も同様に、不具合発見したら失敗しているテストケースを作って、修正の開発を行い、テストケースが通ることを確認します
- テストコードはそれ自体が仕様書として成立するものであり、テストを書くことによって開発者間のコミュニケーションコストの低減を図ることが可能となります
- 既存のテストは、修正されたり削除されたりしないことを原則として想定しており、結果的に「品質が良くなる一方」であることが保証されやすくなります
テストの例:
it('期待通りにジオコーディングされること', async () => {
const lnglat = addressToLngLat('東京都千代田区丸の内1丁目1番1号')
assert.equal([139.767, 35.6811], lnglat);
})
私たちは、このようなテストコードについて以下のように考えています:
- 住所から緯度経度に変換するメソッドを開発する場合、入力が住所であることと、戻り値が緯度経度であることはあらかじめ決まっているので、本体のコードを書く前にテストコードを書くことができます(つまりこのコードは開発前の仕様書としても機能しているということです)
- データが不十分であったなどの事情で、「東京都山田区山本1-1-1」の緯度経度が適切に返されないというフィードバックがユーザーから寄せられた場合、適切な修正を加えた上で「東京都山田区山本1-1-1」用のテストを加えておくことで、「よくなる一方」であることが保証されます
- このようにテストは継続的に追加されていき、著名なオープンソースプロジェクトでは、数千〜数万ケースのテストが自動実行されています
テストの種類
私たちは主に以下の二通りのテストを実施しています。これらのテストは、必要なタイミングで自動実行されなければ意味がないと考えています。
ユニットテスト
私たちは、すべてのソフトウエアを小さな単位の関数の集合体として捉えています。これらの関数に対して個々にテストコードを書き、期待通りに動作していることをテストすることをユニットテストといいます。
ユニットテストは、車で言えば、エンジンに対する単体テストのことであり、シリンダーや点火プラグなど、さらに小さな単位でのユニットテストが行われることも考えられます。
このテストが適切に実行されていれば、不具合の早期発見や、原因究明コストの削減などのメリットがあります。
エンドツーエンド(E2E)テスト
私たちは、エンドツーエンドテストまたは振る舞いテストと呼ばれるテスト手法も採用しています。これは、ユーザーの操作をコードで再現してテストを行うことです。例えば最近ではコマンドラインで操作するためのヘッドレスブラウザ(GUIのないブラウザ)がE2Eテストに用いられるようになりました。
上述の「ユニットテスト」には開発者の「仕様に対する勘違い」をカバーできないという課題があり、E2Eテストは「仕様どおりに動作するか?」を確認するために用いられます。