1. 始めに
アジャイル型開発の導入を目指す現場が増えてきた印象はあるが、今までの(ウォーターフォールモデル)との違いはなんだろうか?
色々説明はあると思うが、アジャイルという考え方に焦点をあてて、自分なりに考えてみた。
なお、私的と断りを入れている通り、これはあくまでも思考の過程だ。これが正しいと言っているわけではないことは承知のうえで読んでほしい。
アジャイルは適応だ。変わっていく状況に適応するため、プロジェクトはどうあるべきなのだろうか?
1. システムを成長させよう
例えばあるシステムの機能を難易度や重要度によって分類して、こんな風に円環上に配置できたとする。
すると、こんなふうに中央から外側へ向かってスパイラルに開発を進めていこう。開発中のモノは「未完成」ではない。全ての段階でそれは「システムとして完成」している。
周辺の機能がないとそのシステムは動かないだろうか?そんなことはない。コアさえあればそのシステムは使えるはずだ。それはもしかしたらライブラリという名前かもしれない。それはもしかしたら画面のないAPIかもしれない。だがそれはシステムである。
プロトタイプリリースしよう
システムはすべて完成しないと動かないということはない。途中途中のバージョンをプロトタイプリリースしよう。開発中のモノをどんどん開発チーム外の人に使ってみてもらい、方向性を確認しよう。
PoCリリース
PoCでは、最も難易度が高い中央部のみ作る。PoCは成長のスタート地点だ。
アルファ版
主要機能の開発は終わったら、一度プロトタイプリリースをしよう。これを内部関係者に使ってみてもらい、フィードバックを得よう。
ベータ版
ほぼ終了というあたりで再度プロトタイプリリースしよう。これを一般ユーザーに使ってみてもらい、使い勝手を確認しよう。
必要な時に必要な事だけ
完全な実装、完全なテストを目指さない。
場合によってはその機能は不要になるかもしれないし、大きな修正が必要になるかもしれない。
必要な時に必要なことを最小限やろう。
無駄なことを如何にしないか、が俊敏性ためには重要だ。
絵を描こう
認識を共有するために、絵を描こう。文章は半分も読まれない。
でも絵に書きすぎたらいけない。不要に詳細な絵はなにが重要なのかわからなくする。テーマを決めたら、テーマ以外のものを書いては行けない。外側も内側も。
markdown preview enhancedのようなツール(markdown+plantuml)を使おう。絵に凝る必要はない。スピード重視で。
テストはコスト
テストは必要だと叫ばれるが、テストしすぎない事も重要だと思う。過度なテストはテスト不足より害悪だ。
問題が発覚したときにテストを追加することで、テスト品質を高めていく事に重点を置こう。
テスト量の最適量があったとする。
もし当初から最適量を超えるテストを書いてしまったら最適量に近づく事はない。
もしテストが最適量よりも少ない場合、問題が発覚してその分のテストを追加していけば、テストは漸近的に最適量に近づく。
つまり、テストは足りないくらいが望ましいと思う。
リファクタリングを味方にしよう
コードはリファクタされることを前提に作ろう。関数の疎結合性と、ユニットテストが重要だ。
とはいえリファクタしすぎてもいけない。そのリファクタは本当に必要な時間なのか?個人の趣味ではないか?事前に目的を決めてからリファクタしよう。
- 関数が疎結合であれば、その関数内部だけを修正することができる。
- ユニットテストによって修正後にデグレしていないことを証明しよう。それにより我々は勇気をもってリファクタできる。
確実に将来、破壊的変更が発生するモノは最初に作ってしまおう
例えばロギング、エラー処理、OpenTracing、context処理など、全体に偏在する系の処理は最初に必ず設計しよう。たとえ最初は不要だとしても。
test, lintなどに関する設計も。
これらを後回しにすると、あとあと痛い目に合う。
2. 分業と責任モデルを変えよう
一般的にウォーターフォールでは、全体を基本設計・詳細設計・実装・テストフェーズに分けてそれぞれ別の人間が担当する(縦の分業)。
アジャイルでは、機能ごとに担当者を割り当て、それぞれの担当者が小さな機能を基本設計・詳細設計・実装・テスト・リリースまでおこなう(横の分業)。
なぜその方がアジャイルなのだろうか?
コミュニケーション量を最小化したい
チーム開発によって発生するコストは、コミュニケーション量に比例すると思う。
必要となるコミュニケーション量が多いほど、作成する必要がある資料が増えてコミュニケーションにかかるコストは飛躍的に増大する。そして、コミュニケーションロスの可能性も増えて「間違える」リスクも増える。
ウォーターフォールでは、工程から工程へ渡す情報量は膨大だ。そしてそれを小さくする手段はない。
だから、ウォーターフォール開発では手戻りを本能的に避ける。誰も好き好んでそんなギャップを何度も越えたいとは思わない。
アジャイルでは、システムを何段階も、疎なコンポーネント群に分割してコンポーネントごとに開発する。開発工程は同じ人間が基本的に最初から最後まで担当するから工程から工程へ渡すコストは発生しない。ただし、コンポーネント間のインターフェースに関するコミュニケーションは必要である。むろんコンポーネント間が疎であればあるほどその量を減らす事ができる。
そして、行程を戻るリスクやコストは(スプリント内であれば)ほとんどない。
もちろんこれが可能なのは事前のモジュール分解が疎結合に分解されている場合に限られる。このための技術が「抽象による概念設計」である。概念設計が行われていない場合はモジュール間の境界線が定まらず、横の分業は崩壊するだろう。これが密結合状態。
詳細な設計する前に必ず絵を描き、そのモジュールがどういうものなのか、名前が適切にその責任を表現しているか。別のモジュールと密結合になってはいないか絵を見ながら議論しよう。
コミュニケーション量を最大化したい
いわゆる雑談系コミュニケーションは「社会的安心」「技術的安全」のために必要だ。アジャイルではモジュール間の信頼関係と、モジュール担当者間の信頼関係は同義だ。「社会的安心」「技術的安全」のないチームは「安全で安心な」システムを作ることはできないだろう。
3. システムを小さく分割してイテレーションしよう
システムは小さなシステムの集合であり、部品となる小さなシステムを素早く開発してそれを積み上げていこう。
難しい問題は分割して解決していくべきであることは、古今東西変わらない。
イテレーション間で情報の受け渡しによるギャップが発生しないのかって?
もし受け渡しに失敗したら、実装であればテストに失敗することですぐに判明する。情報による受け渡しと実装の受け渡しは違うのだ。
人もシステムもDesign by Contractで
オブジェクト指向設計の世界には「契約による設計」という考え方がある。callerとcallee(呼ぶ側のコンポーネントと呼ばれる側のコンポーネント)それぞれが果たすべき責任(事前条件、事後条件)を話し合おう。
コンポーネントが果たすべき責任と、チームもしくは個人が果たすべき責任を一致させよう。そして、責任に相当する権利を各チームや各開発者に移譲しよう。
中央集権型チームから脱却しよう。中央集権型システムではなく自律分散協調型システムを作るために、自律分散協調型チームを作ろう。重要なのは適切に責任と権利を分散させることだ。
ヒエラルキカルな組織をフラットな組織へ
WFでは、工程間のギャップがあまりに大きく、工程を戻る事は再度そのギャップを超えるコストが必要という事になる。であればできるだけ工程を戻りたくないと考えるのは当然ではないだろうか。
つまりWFでは工程を戻したくないという意思がプロジェクト全体に生じる。
これがヒエラルキーを生む。
すべてのエンジニアは、一人の開発者として自立的・自律的に動くことを求められる。ヒエラルキーは、プロジェクト内に壁を作り、セクショナリズムを産む。コミュニケーションを阻害するような壁は可能な限りなくしていこう。
4. 最後に
Agileに関する説明は無数に散らばっているし、特に新しい事はないかもしれないが、何かしら新しい発見があればと思い纏めてみた。
まだまだとっちらかっているが、少しずつ整理したい。