アジャイル開発を支えるためのCI/CD


アジャイル開発での何度も行われるプロダクトリリース

アジャイル開発は早いサイクルが回っているチームでは1週間のうちに何度もリリースを行います。

リリースを何度も行うメリットは

  • 開発中も常に動く状態のアプリケーションが確認できること
  • 壊れたときにすぐに気がつけること
  • 変更箇所を他の人もすぐ取り込むことが出来ること
  • マネージャや顧客に対して常に進捗をデモという形で見せれること
  • 他にも色々

このようなものがあります。

そもそもビッグバンリリースはテストも大変ですし、問題が起こったときに、どの箇所に問題があるかを調査する範囲を調べることが大変です。
バグの修正に掛かる時間の大半を占めるのがバグの調査時間になります。
半日以上かかって調査ししたバグが、1行のコード修正で終わってしまうこともよくあります。

細かくリリースをすることで、壊れた場合にそのコミットの変更の中におかしなところがあったと気がつくことが出来ます。
1つのコミットはその機能や修正の変更に限定されたものなので、調べる範囲はその範囲で済むことになります。

また、バグは埋まっていないことが前提なのに、そのリスクをざっくり見積もったテスト期間はそれが正しいものか分かりません。
細かくリリースすることで、アプリケーション内のバグを最小限に抑え、最終リリース前の全体テストでのバグ発見リスクを最小化することでスケジュール進捗などもより現実的なものが見えるようにもなります。

でも、この何度も行うリリースが毎回全部の動作を画面で動かし、検証し、確認していたら1週間に何度もリリースを行うことなど到底出来ません。
1ヶ月に1度のリリースでもなかなか大変です。

アジャイル開発は1週間に何度もリリースを行いますがテストをしないと言うことではありません。
品質を犠牲にすること無く、
極限まで開発スピードを上げること、
業務変更に対する仕様修正にできるだけ対応すること
を目指しています。

リリース作業の時間に対する観点

リリース作業が多くて、リリース作業に時間を取られて開発が進まなくては本末転倒です。
そこでアジャイル開発ではリリース作業を出来るだけ自動化しつつ、アプリケーション品質を高めるチェックも自動化をすることが前提になります。

この前提技術を無視して、リリース回数のみをアジャイルとして取り込もうとしても到底うまくいかない、アジャイル失敗プロジェクトになることでしょう。

では具体的にどのような技術を使っていけば良いのか。

本題: アジャイル開発のこのリリースを支える技術

CI (Continuous Integration) 継続的インテグレーションと CD (Continuous Delivery) 継続的デリバリーの考えがメインになる
これらを実現するための技術として以下の様なものを使うことができます。

(当方Javaが一番得意なので、コードに関する記述はJavaを使う前提に書いています。ただ、極力言語によらない文にしているつもりです)

1. 自動テスト

最初はメインのアプリケーションの実装以外のコードを書くなんて時間の無駄に感じられるかもしれません。
しかし、テストコードは品質を高めるだけでなく、開発サイクルも向上させることが出来、開発スピードを結果的に上げることが出来ます。

また、1度作ってしまえば、ノーコストで何度でも走らせることが出来るため、あなたが居なくなっても、その部分の品質を保証し続ける事ができます。

Unitテスト

バグを埋め込まないためにはテストコードを書いて、クラスの関心範囲のみを検証するようにします。
これらは何度でも自動で動き、Git等へのマージコミットした時に自動で走ります。
変更した際にロジックが何かしら意図しない結果を返すようになったときにすぐに気がつくことが出来ます。

ほとんどの場合、実装したほうが良いでしょう。

E2Eテスト (end to end test) 自動化

前項が1つの関心のみのテストであれば、これは全体テストの自動化です。
これは作るのは非常に大変ですが、長期にメンテナンスや機能追加、仕様変更などがあるプロジェクトでは非常に力を与えてくれます。
新しい仕様変更に対して、安心して開発を進めることが出来ます。

長期にメンテナンスする場合には、少なくとも正常処理と主要な例外部分について作りたいです。
アプリケーションの納品がゴールの場合には、実装コストの方が労力を超えてしまうケースがあるかもしれませんので、各チームで判断して導入して下さい。

開発のためのテスト

複雑な計算ロジックやプログラミングする際に素早く動かして確認を行うサイクルのためにテストを書く考えです。
Unitテストではカバレッジなどを気にしますが、こちらの観点はよりはやく実装コードを書くためにテストを利用することです。
毎回Webアプリケーションをコンパイルして、起動して、Webフォームに入力して、ボタンを押して、画面を表示して確認するよりも
本当にプログラムを実装しているかしょの動作のみを素早いサイクルで確認します。

これは必ず実行するべき最低限のテストコードです。
この作業すらない実装コードは、実際に動かす環境にデプロイされるまで1度も動くことなく、バグの発見をもっとも遅らせ、開発サイクルを遅くする原因になるでしょう。

テストファースト開発(TDD)/ ビヘイビア駆動開発(BDD)

テストを最初にかいて、そのメソッドのインプット値と期待されるアウトプット値のパターンを全て書いてから実装を始めます。 (TDD)
BDDはより仕様書に沿ったテストを全て書ききった後に実装コードを書き始める、仕様書ベースのテストファーストのような考えになります。

2. 自動ビルド / 自動デプロイ

自動ビルドは継続的に人の手を介さずに、テストの実行、ビルド、デプロイを行うことが出来ます。
あなたがgitにpushした瞬間それは走り、自動でテストし、問題があれば通知され、問題がなければ、デモ環境に最新のコードがデプロイされます。
1度作ってしまえば、あなたの作業はgitにpushをするだけです。この環境を作らない理由はあるでしょうか?
それとも毎回コンパイルして、サーバにアプリケーションを送信して、再起動する作業がしたいでしょうか?
仕事した気にはなるかもしれません。ですが、それは無駄な作業です。
必ずCIの環境を作って下さい!

Jenkins

昔ながらのビルドツールです。
Jenkins2が出ていますので、これから導入を考えるチームは必ずversion2の方を利用して、
コードベースでビルド設定が管理できるようにしましょう。

CircleCI / Shippable / Wecker など

クラウド管理型のビルド、デプロイツールです。
いくらかのお金を負担して、1度設定するだけで、非常に手軽にCIの環境を整えることが出来ます。
自前でビルドやデプロイ用のサーバを立てて管理するよりもメリットが大きいケースが非常にあるので、ぜひ導入を検討してみて下さい。

AWS CodeDeploy / AWS CodeBuild (本日発表ホヤホヤ)

AWS環境で利用できるビルドツールとデプロイツールです。
非常に便利なのでAWS環境を利用しているのであればぜひ使っていきましょう。

3.開発環境の統一化

アプリケーションを作るときに、動作するバージョン、必要なDB、必要なミドルウェア、OS、など、それらが
あなたの開発環境と隣の人の開発環境と本番環境で違ったらどうなるでしょうか?
あなたの開発環境で動いているコードは本番環境で動くのでしょうか? DBがバージョンアップしたら?
新しい開発で違うミドルウェアを導入したら?
みんなで個々に開発環境を揃えるのでしょうか?
今はそれらの設定をコードベースで自動で揃えるためのツールがあります。
ただし、最初のコストは少々かかります。
プロジェクトが小さいときから導入できるのがベストですが、
チームの環境のずれが問題になったときや開発スピードに支障をきたしていると感じたときに導入を検討しましょう

Chef / Ansible

それぞれ PythonとRuby 環境設定のコードを書くツールです。
installするミドルウェアや設定などをコードベースで書いてあるので、同じ設定の環境を何回でも作ることが出来ます。

Docker

最近は仮想化の環境の中でもコンテナ管理というものがメジャーになってきています。
まだまだオーケストレーションなどがまだまだな部分もありますが、この知識はエンジニアとして身につけておいて損は無さそうです。
本番環境では、さまざまなコントロールする価値のある場合しか、導入メリットは薄いかもしれませんが、開発環境においてはメリットが大きいでしょう。特にOSで影響を受ける言語を開発している場合には特に導入した方が良いと思います。

締め

最大限の品質と開発スピードを得るために、
エンジニアとしての高い技術を駆使しつつ、
ぜひ自動化の箇所を増やしていってもらいたいと思います!