ユーザー視点凝集をめぐる冒険 (2) – 継続的なリリースという罠

前回は「どのようにシステムを切るか?」ということについて考えた。

ところで、何故システムを「切る」必要があるのだろうか? それはシステムを作る際に、切り分けたシステムを別々の開発者に割り当てて分業したり、スケジュールに割り当てて完成までのロードマップを作るためである。そしてこのとき、切り分けられたパーツが「ユーザー視点凝集」を満たしていれば、パーツ単体でユーザーの反応を確かめる事が出来る。

タスクを、それぞれ何らかのユーザー価値を生み出す「スモールバッチ(small batch)」に分ける事によって、ウォーターフォール開発のようないわゆる「ラージバッチ(large batch)」なアプローチよりも遥かに早い段階から継続的なフィードバックを得る、というのがアジャイル開発の勘所だった。

インクリメンタル開発(漸増型)とイテレーティブ開発(反復型)

ユーザー視点凝集ごとにシステムを区切る事を「vertical slice(縦方向の分割)」と呼ぶ、というのが前回の話だったが、vertical slice ごとにシステムを作り上げて行く手法は「インクリメンタル(incremental)開発」と呼ばれている。

これはアジャイル以前に開発プロセスの標準的な存在だった RUP(Rational Unified Process)や UP(Unified Process)に含まれていた手法である。これらのプロセスモデルが提唱された90年代後半は、ウォーターフォールを捨ててアジャイルを生み出すまでのちょうど過渡期に当たり、ソフトウェア開発に一発勝負のウォーターフォールは馴染まないという反省から、RUP や UP と言った「繰り返し型」開発プロセスが提唱されるようになった。

インクリメンタル開発は、新規の増分(開発部分)を積み上げていく方法です。この方法は、繰り返しの単位となるN回目、N+1回目で対象となるソフトウェア構造がまったく異なるものや、依存関係のないものに適しており、繰り返しの単位の独立性が保てるので非常に分かりやすいというメリットがあります。もし、N回目、N+1回目の中に、共通するソフトウェア構造が含まれていた場合は、共通部分を別々に開発してしまうことになり、ソフトウェアの保守性に問題が出ます。

この記事の中で紹介されているように、インクリメンタル開発は繰り返し型開発の中の一手法に過ぎない。繰り返し型開発で重要なもう一つの手法は「イテレーティブ(iterative)開発」である。

イテレーティブ開発は、ソフトウェアの全体、あるいは部分について、最初は薄く作り、少しずつ肉付けしていく方法です。この方法は、非常に重要かつ複雑なソフトウェアの個所について、徐々に確認しながら肉付けし、中身を濃くしていけるというメリットがあります。

つまり、イテレーティブ開発は、システムを区切るのではなく、同じユーザー視点凝集(のセット)の完成度を段階的に高めて行く手法だ。

RUP や UP には「ユースケース・ドリブン」と「アーキテクチャ・セントリック」という二大ポリシーがあり、それぞれのポリシーがインクリメンタル開発とイテレーティブ開発に対応している。ユースケース・ドリブンでは、ユースケースという vertical slice ごとに開発を進め、アーキテクチャ・セントリックでは、段階を踏んで全体のアーキテクチャを洗練して行く。この二つのポリシーを組み合わせて、インクリメンタルとイテレーティブのバランスを巧く取りながら開発を進めて行くというのが RUP や UP の要諦である。

考え方としては、今改めて検討しても合理的に思える部分も多いが、CI(Continuous Integration)がまだ一般的でなかった当時、繰り返しのたびにテストをやり直さなければならないという問題や、その他自動化が十分でないためにかかるオーバーヘッドなどを考えると、まだ現実的と言える手法ではなかったのではないかと想像出来る。さらに最も重大だと思われるのは、vertical slice ごとのリリースという考え方がないためにアジャイルのようなフィードバックループを得られず、ユーザー(顧客)視点からはウォーターフォールと何ら変わりのない手法に見えることだ。

「イテレーティブ」の再発見

一つ一つの vertical slice を順番にリリースして、早い段階から「本番」を経験させるのがアジャイルの勘所であると説明したが、このような繰り返しをアジャイルでは「イテレーション」と呼ぶ事が多い。しかし、実際にこの繰り返しが意図するところは「インクリメンタル」な開発である。

アジャイルがインクリメンタル開発にフォーカスしていることを典型的に示すのが、スクラム手法で頻繁に参照される「雪だるまモデル(Snowman model)」だ。

scrum-snowman-model

このように、一つのイテレーション(スクラムでは「スプリント」と呼ぶ)が終わる度に「出荷可能(shippable)」な vertical slice が積み上がって行くイメージである。ユーザーは早い段階で製品に触れて開発者にフィードバックを送る事が可能になり、管理者にとっては、開発のペースが安定して進捗も可視化されるなど、良いこと尽くめのように思える。

しかし、2007年にロンドンで行われた XPDay において、「インクリメンタル開発へのこだわりには大きな落とし穴がある」そう指摘したのが Jeff Patton 氏だった。

Patton氏はインクリメンタルにモナ・リザを描くとしたらどうなるかという例を挙げて、仮にインクリメンタルだけで開発を進めようとすれば、結局は最初の段階で全体像を決めておかなければならず、また全てのパーツを完成させない限り全体像の実物を検証する事も出来ないため、結果的にはウォーターフォールと同じ事になると警告した。

Jeff Patton氏のサイトより
Jeff Patton氏のサイトより

インクリメンタルなプロセスとは対照的に、普通に絵を描く時は以下のようなイテレーティブなプロセスを辿る。

Jeff Patton氏のサイトより
Jeff Patton氏のサイトより

全体像をぼんやりと決めてから徐々に細部を詰めて行く。細部を詰めて行く過程で全体像を調整して行くので、最初に完璧な構想を立てる必要はない。

アジャイル時代になって、インクリメンタル開発がイテレーションと呼ばれるようになり、それまでイテレーションと呼ばれていたコンセプトが抜け落ちてしまったというのが Patton氏の指摘だ。

出荷可能(shippable)とは何か?

インクリメンタル開発の落とし穴は、先ほどの雪だるまモデルで登場した「出荷可能(shippable)」という考え方である。

仮にシステムを vertical slice に分けて開発し、イテレーションの度にリリース出来たとして、それらのパーツの集積が本当に出荷可能だと言えるだろうか?

ほとんどの場合、答えは「ノー」である。

出荷可能の本当の意味は、顧客にとって意味のあるプロダクトである、という当たり前の事実だ。そのプロダクトを使って実際の業務を遂行出来る、あるいはサービスや売り物として成立するなど。そのように考えると、多くのケースで vertical slice はこの水準に相当しないだろう。筆者も何度か経験しているが、 vertical slice に分けて開発したとしても、ある程度全体像が完成してこない限り、顧客、あるいはそれに準ずる役割の人たちは、作りかけの製品には興味を示さなかった。

何故このようなズレが生じるのかと言えば、それはおそらく vertical slice の粒度が開発者視点で決定されているからではないだろうか。顧客に決めてもらうとは言っても、そのフレームワークはそもそも開発者側が考えたものだ。つまり、このときの vertical slice はユーザー視点凝集ではない、ということになる。

元々、開発者視点でシステムを区切る「horizontal slice(横方向の分割)」は好ましくないということで、ユーザー視点であるはずの「vertical slice(縦方向の分割)」を持ち込んだ訳だが、そこでも開発者視点を払拭する事は出来なかったということになる。

インクリメンタルとイテレーティブをミックスする

インクリメンタル開発の落とし穴を避けるためには、アジャイル以前の RUP や UP で提案されていたのと同じように、インクリメンタルとイテレーティブを巧く組み合わせようという話になる(実際には意識せずともそうならざるを得ないが)。そのための手法として、ユーザーストーリーをフィーチャーごとに書くだけでなく、一つのフィーチャーをイテレーティブに発展させるためにストーリーを三枚のカードに分けて書くという方法が提案されている。

この方法によって、一度の開発でフィーチャーを完璧(出荷可能)に仕上げなければならないという、インクリメンタル開発のプレッシャーから解放される。

ユーザー視点凝集をそれぞれ同じ完成度で比較すると粒度がまちまちになってしまい、アジャイルが目指す、ペースを維持した開発を実現することが難しくなってしまう。そこで、ユーザー視点凝集の抽象度(曖昧さ)を調節して、一回のイテレーションに収まるサイズに縮めるというのが、イテレーティブ手法が果たす役割である。

スコープ

アジャイルにおけるインクリメンタル開発の落とし穴と、それを回避するためのインクリメンタル/イテレーティブの組み合わせ、なかなかに説得力のある話ではあるが、一つ重大な点が見過ごされているような気もしなくはない。それはスコープと呼ばれる、全体像の問題である。

イテレーティブの導入によって、詳細な全体像を用意する必要は無くなったかもしれないが、それでも依然として全体像は必要になる。アジャイルやリーンの考え方として出来るだけ多くの意思決定を先送りにするとしても、全体像はある程度決定しておかなければならない。しかし、この全体像がちょっと油断するとチームをウォーターフォールへと引きずり込むアリ地獄のような存在になってしまう。

果たしてこの全体像というのは、どのように決定すれば良いのだろうか?

(続く)

ユーザー視点凝集をめぐる冒険 (1) – どのようにシステムを切るか?

凝集性というのは、どのような尺度でプログラムを分けるかという問題だ。凝集度は高い方が良いと言っても、この高い・低いという判断は一筋縄で行くものではない。というのは、どのような尺度を利用するかによって、ある視点からは凝集度が高くなるように見えても、別の視点からは凝集度が低く見えてしまうからである。

以前、連載記事『TDD再考』の中で、凝集性の分類として「論理的凝集」と「機能的凝集」というものがあるということを紹介した。論理的凝集は実装上の特徴でまとまりを作り、機能的凝集は(プログラムの利用者から見た)機能の単位でまとまりを作る。つまり、これらの尺度の違いは、それぞれのまとまりの受益者が異なる事に由来する。前者は開発者の視点であり、後者はユーザーの視点だ。

わざわざ「(プログラムの利用者から見た)機能」と前置きのあるところから分かるように、「機能」という概念がそもそも視点を前提としていることに注意して欲しい。機能というのは受益者がいて初めて成り立つ概念である。機能的凝集がユーザーから見た機能に対応する一方、論理的凝集は開発者から見た機能に対応するという意味では、いずれも「機能的凝集」と呼んでも差し支えないはずなのだ。分けるという行為を実際に根拠づけるのは視点であり、そのように考えると、凝集性の分類でより適切なのは視点による分類ではないだろうかと思う。というわけで、ここでは機能的凝集を「ユーザー視点凝集」、論理的凝集を「開発者視点凝集」と呼んでみる事にしたい。

coherence

プログラムデザインの手法としてレイヤーアーキテクチャが人気なのは、レイヤーが開発者視点凝集、つまりプログラマーから見た凝集性を実現しているからだと言っても良いのかもしれない。データアクセスの処理や、ユーザーからのリクエストを各々のロジックに振り分ける処理など、ユーザーにとってはブラックボックスの中身の話であるが、プログラマーにとっては日常である。

『TDD再考』では、Ruby on Rails 開発者の David Heinemeier Hansson 氏が——先ほど導入した言葉を使って説明すれば——開発者視点凝集よりもユーザー視点凝集を重視すべきだという主張を展開していることを紹介した。TDDのような手法を使ってプログラムをデザインすると、ミクロなレベルではどうしても開発者視点に引っ張られて、結果的にユーザー視点凝集よりも開発者視点凝集を優先してしまうというのがDHH氏によるTDD批判の要点である。

21世紀に入ってからユーザー視点凝集はプログラムデザインおいて極めて重要な地位を占めている。ひょっとしたら最も重要な概念だと言っても間違いではないのかもしれない。それはユーザー視点凝集がアジャイル開発を進める際の単位として想定されているからである。

アジャイル界隈では、ユーザー視点凝集を「vertical slice(縦方向の分割)」と呼んでいる。

この vertical slice についての分かりやすい説明が、最近話題の書籍『SOFT SKILLS』の著者、John Sonmez 氏のサイト「Simple Programmer」にあった。

Sonmez氏は vertical slice を「家を建てる」という例で説明している。

普通に家を建てる時の手順を想像してみよう。まず最初に作らなければならないのは土台である。基礎工事で土台を作り、そこに骨組みを乗せる。その後、骨組みに沿って壁を作り、最後に屋根を乗せる。この最後のステップが完了して初めて実際の家の中身を確認する事が出来るようになる。

このように普通の家屋建築で現れる手順は「horizontal slice(横方向の分割)」に基づいて作業が分かれている。

house-horizontal

この horizontal slice に対して、vertical slice で家を建てるというのは、まず一つの部屋を利用出来るような形で完成させ、その次にまた別の部屋を作るという感じで、人間が実際に利用出来る最小単位ごとに建物を作っていくことに相当する。

house-vertical

部屋ごとに家を建てるのは、建築においてはいささか非現実的なアプローチに見えるが、ソフトウェア開発においては重要な考え方になりつつある。

そもそもソフトウェア開発でも、この家屋建築の例と同じように horizontal slice に基づいた開発が主流だった。それは作業を縦に分割するよりも横に分割する方が遥かに簡単だからである。しかし、horizontal slice は一つ一つのスライスがシステム全体に渡るため、最初に全体の設計図を書かなければならない。更には、一つ一つのスライス(レイヤー)を合体して完成品とする最終段階で想定と異なる事実が判明しても、そこから大幅な変更をするためには大きなコストがかかってしまう。変化の速いソフトウェアの世界では horizontal slice による開発ではなく、vertical slice によって、出来るだけ早い段階で機能の検証を行うべきだというのがアジャイル開発の考え方であった。

A vertical slice from the components of a project
A vertical slice from the components of a project

しかし、この「家を建てる」例での説明は、若干ミスリードな部分もあるかもしれないなと思う。というのは、家の場合は例外なくまず先に設計書があって、それに従って現場の大工さんが家を建てる流れになるが、ソフトウェア開発、あるいはプログラミングは、大工さんの作業というよりも、設計書を作る方に相当するのではないかと思うからである。その意味で、家屋やその他の建築物の設計書を作るプロセスはソフトウェア開発と変わりない試行錯誤があるはずである。

ユーザー視点凝集をめぐる冒険 (2) – 継続的なリリースという罠