あるSF小説に次のようなフレーズがありました。
ロケットの燃焼効率は...
効率とは至る所で使われている言葉です。例えば私の車は月に一度リッターあたりの走行距離をスマホに通知してきます。燃料効率を定期的に教えてくれるのです。他にも「仕事の効率がいい」だとか「工場の稼働効率」など、多くの場面で使用されます。効率とは一定の”なにか”に対して、生み出される”なにか”の割合のことみたいです(wikipedia)。
効率
私は昔あるプロジェクトの立ち上げにチームメンバー(エンジニア)として参加したことがあります。ビジネスサイドの人からプロジェクトの目的、提供したい価値、想定されるおおよその期間などの大枠を確認し、チームメンバーと一緒に目的を達成するためにはどのようなストーリーが必要かを考え、次のようなストーリーと計画を作りました。(当然ですが当時のストーリーや計画をそのまま見せるわけにはいかないので内容を変えています)

サービスが大きく3つのコンポーネントに分かれていたので、それぞれのコンポーネントごとに必要なストーリーをマッピングしたのです(色はコンポーネントを、数字は順序を表しています)。ストーリーは小さく、内容についてもメンバー間で認識齟齬がない状態にできました。一見良さそうに見えるストーリーですが、私は強い違和感を感じ始めていました。過去の経験からもっと良いストーリーと計画があるはずだと感じていたのです。
Source Lines Of Code
SLOC(Source Lines Of Code)はソフトウェアの規模を表す指標の一つです。コードの行数が多ければ大規模であり、少なければ小規模である、という非常にシンプルな指標です。このSLOCを用いると、ソフトウェア開発における効率を一つの側面から数値化できそうです。つまり、単位時間あたりのSLOCです。1時間あたりに書けるコード行数が多ければ多いほどコードの生産量が高く効率が良いと判断できそうです。
先程のストーリーは、暗黙的にもまさに単位時間あたりに書かれるコードの行数を最大化することを念頭に置いています。フロントエンドからデータベースまで、頭から順番にコードを書いていけば時間を有効に活用できるからです。コンポーネント間の行き来(フロントエンドからバックエンド、バックエンドからデータベース)も3回で済むため、作業のスイッチコストも低いはずです。単位時間あたりのコード行数が増えれば、効率は高まり、プロジェクトはうまくいくはず。そのように考えるかもしれません。
しかし私の経験では、これは大抵うまくいきません。
いくつか理由がありますが、その一つが「開発過程での経験による学習」を無視してしまっていることだと思います。「頭から順番にコードを書いていけば無駄がなく時間を有効に活用できる」ということは暗黙的な前提として「始める前から正しい設計やコードを考えきれている」ということになります。しかし現実のプロジェクトでは私の経験上事前に正しい設計やコードを全て洗い出すことはほぼ不可能です。2~3時間(時には数日)かけて設計を念入りに行ったとしても書き始めてみたらすぐに思っていたのと違うと気が付きます。想像していたよりも処理が複雑だったとか、レイヤーはこんなに必要ではなかった、外部サービスの呼び出しが一定確率で失敗することが分かった、レガシーな部分が一部残っていてそれが作成している機能に影響を与えていることが分かった、などなど。行動が結果を生み、想定と現実の乖離に気が付き始めます。
SLOCに対する効率を最大化することを前提としたストーリーとその計画はたちまち多くの「新しい発見」の波にさらされます。後から分かったことを念頭に再度ストーリーを洗い直し、バックエンドまで進んだけれどフロントエンドに戻ったり、「完了」したストーリーが実は不完全だったことに気が付きます。今度こそはと新しいストーリーとその計画で走り始めようとしますが、また発見の波に飲まれることになります。これがプロジェクトの期間中続きます。予定していたリリースはどんどんと変更されていき、今計画のどのあたりにいるのという問いに自信を持って答えられなくなっていきます。
それではどうしたら良いのでしょうか?なにか良い方法、良い考え方はないでしょうか?
反復
そもそも、「始める前からどうしたらうまくいくか分からない」という問題はソフトウェアの世界だけなのでしょうか?そのような問題が我々の日常で起こっているとしたら。
私は数年前に人生で初めて車を購入しました。子どもが生まれることを想定して、ファミリーカータイプを選びました。一般的な乗用車の大きさですが、軽自動車と比べると車幅は広く、久々の運転に緊張したことを覚えています。納車がちょうど引っ越しのタイミングと重なり、その車を始めての駐車場に停めようとしていました。駐車場を確認していたところ、あることに気が付きました。そこは近隣の家の関係で前向きで駐車する決まりになっていたのです。さらに駐車スペースも広いとは言えず、ファミリーカータイプの車を駐車するには明らかに難しそうでした。

なんとかその日は駐車スペースに車を入れることができましたが、曲がる角度の調整が非常に難しく隣の車に擦ってしまわないか大量の汗を流す羽目になりました。こんな恐怖を毎回抱きながら車を出し入れしたくはありません。車の出入りが少ない夜間にどうやったら駐車がうまくできるか試行錯誤することにしました。上の図の矢印のルート(駐車場の入口から自分の駐車スペースまで)を何度も行き来しているうちにあることに気が付きました。敷地内に入ってきた後、できるだけ右側を走行してから駐車スペースに入っていけば角度の調整がやりやすいことに気がついたのです。これで少しは楽になりましたが、どうしても車体の先頭との距離が掴みづらく、右側の車を傷つけてしまわないかまだ心配が残りました。さらに練習を続けるとまたあることに気が付きます。私の駐車スペースの後方だけ、マンションの階段部分になっており少しスペースが余っていました。このスペースを活用することはできないか?というアイデアを思いつき、試しに以下の図のように車を動かしてみたところ、とても余裕を持って駐車することができたのです。

そのルートはこうです。
- まず自分の駐車スペースを通り過ぎて斜めの状態にする。
- ハンドルを右に切り、バックで階段部分に車の後方を入れる。
- ハンドルを左に切り、正面の駐車スペースに入れる。
妻にもこのルートを教え、家族で安全に車を出し入れできるようになりました。
私は「狭い駐車スペースに前向きで駐車するうまいやり方が分からない」状態からその駐車場の特性を活かして安全に駐車する方法を発見し、問題を解決することができたのです。これと同じように、おそらく皆さんもこれまでの人生で(もしくは日常的に)「はじめからうまくいく方法がわからない」問題に対し、同じ様な方法をとって問題に対処しているのではないでしょうか?難しいゲームで初めてボスと対戦する、初めて音楽のレッスンを受ける、水泳を始める、などなど。どの問題においても、何度も挑戦することで習熟度を高め、乗り越えてきたはずです。
つまり我々は、はじめからうまくやる方法がわからない問題への対処として、意識的か無意識的かにかかわらず、反復を利用することがあります。繰り返すうちに「問題の構造」や「効果的な手段」を発見し学習することで、上手なやり方を身に着けているはずです。
これを先程のストーリーと計画に対して転用してみると、どんなことが考えられるでしょうか。
学習と活用の機会損失
先程のストーリーを見返してみると、反復が存在しないことがわかります。ストーリーは各コンポーネント内に存在しており、コンポーネントを横断していません。フロントエンドの実装を終えてから、バックエンドに移り、最後にデータベースの変更を行い、初めてリリースができるようになります。はじめから終わりまでの往復は存在せず、一度でやりきる計画になっています。
反復の欠如は、次の3つの問題を引き起こします。
一つ目は、開発過程における学習を活かしにくいという問題です。例えばバックエンドの処理を実装しているときにもっと良いアーキテクチャを思いつき、フロントエンドとの通信の方法を変えたくなったとします。でも、フロントエンドの実装は既に終わってしまっているので、今から変更するとなると実装してきたコードを大きく変える必要があるかもしれません。「完了」としたはずのストーリーを再び「TODO」に戻すことへの心理的抵抗も加わります。結果としてより良い方法を発見したとしても、今の実装のまま進むことを選択しがちです。学習を活かしたくても、活かしにくい進め方になっているのです。このような妥協を積み重ねていった先に、どのような結末が訪れるかは言うまでもないでしょう。
二つ目は、システム全体への洞察が計画の後半まで得られないという問題です。一度決めたアーキテクチャで頭から順番に実装をするので、システムの全体像をつかめるのが計画の最後の方になります。データがどのように流れるのか、どの処理がどれほど複雑になっているのか、どこがパフォーマンスのボトルネックになるのか、といったシステムに対する重要な洞察が計画の後半部分に集中します。もしくは全てのストーリーを完了させてからやってくるかもしれません。このタイミングで深い洞察を得られたとしても、改善できる余地は殆ど残っていません。
三つ目は、反復がないとそもそも得られない知見があるという問題です。コードへの理解は初めて書いた時点ではなく、使い続けることで徐々に育っていきます。例えばバックエンドの処理の一部を終わらせ、それを再びフロントエンドから眺めてみて初めて違和感に気がつく場合があります。「このエンドポイントなんか一貫性がないな」「JSONレスポンス大きすぎるな」など書いた時点では気がつけなかったことに、別の視点から気が付ける場合があります。この例ではフロントエンドとバックエンドを例にしましたが、一つのコンポーネント内部(クラス間や関数間)でも同じことが起こります。反復がない場合、Aを書いたら次はBに移ったっきりになるので、Bの実装をAから眺めてみる機会が存在しません。
SLOCベースで考えるならたしかに多くの行数を達成できているでしょう。しかし全てを終えたあと全体を見渡してみると、積み上げてきたコードのいくつかが間違った方向への投資だったと気がつくかもしれません。もしくは計画の最後の方でコンポーネント同士を繋げたら上手く機能しないことが判明するかもしれません。反復を無くし、SLOCへの効率を最大化しようとした結果、本当に必要だった学習とそれを活用する機会が失われてしまいます。
Gregor HohpeはAgile Is the Steering Wheel, Not the Gas Pedalで「アジャイルな手法とは車のステアリングであってアクセルペダルではない」と言っています。(ステアリング:車体の進行方向を変えるための装置の総称)ソフトウェア開発は直線上を走るレースと言うよりも、障害物レースであり、旋回能力が重要であると説いているのです。

つまり、無闇にSLOCの効率を最大化しようとすることは、旋回に必要な学習の機会を失ったまま猛スピードで走り続けることと同義なのです。気がついたときには壁に激突しているかもしれません。
学習とそれを活用する機会の創出はどうすればいいのでしょうか。この問いに対する私なりの考えは「縦ではなく横」で考えること、です。
縦と横

一つのストーリーをフロントエンド、バックエンド、データベースを横断するような形にします。各コンポーネントを薄くスライスするようなイメージです。それぞれのストーリーでは各コンポーネントの実装が完了しませんが、ユーザが操作できる何らかの機能を完成させるようにします。そのため、受け入れテストやデプロイメントパイプラインの実行、リリースを各ストーリーごとに行うことができます。リリースできたら再度フロントエンドからはじめ、この反復を繰り返していきます。各コンポーネントは概ね10%、20%、30%と段階的に実装されていきます。
反復があることで先程の問題、(1)開発過程における学習の活かしにくさ、(2)洞察が計画の後半に集中すること、(3)得られない知見があること、の3つに対して対処しやすくなります。途中で良いアイデアを思いついたなら、完了したストーリーをTODOに戻すのではなく、次のストーリーで試すという選択が取りやすくなります。各コンポーネントを横断することで、早い段階からシステムの全体像が明確になりやすく、重要な洞察を早期に得られる機会も増えるはずです。さらに、書かれたコードを使ったり読み直すことで、一度書いただけでは得られなかった知見を得られる機会も増えます。
例えば、2つ目のストーリーでフロントエンドの処理を書いているとしましょう。バックエンドに対する呼び出しを行おうとしたところ、1つ目のストーリーで実装したエンドポイントに一貫性がないことに気が付きます。この場合、以降のストーリーでバックエンドに触れる際に修正することができます。ストーリーを進めながら学習した内容を活かす機会が生まれやすくなるのです。
学習した内容を活かす機会の増加は、システムの成長方向を調整する機会の増加へと繋がります。早い段階からすべてのコンポーネントに触れており、リリースしながら進めているため「実はこのデータは利用できない」「本番環境では外部APIとの通信に時間がかかる」というような、重要な洞察に早期に気づける可能性が増えます。壁に激突する直前でこれらのことに気がつくよりも、遠くに壁があるのでこのまま直線で進むとまずい、と早めに察知できるほうが問題に対処しやすくなるでしょう。
「アウトプット」と「アウトカム」で考えてみると、「縦と横」の違いが明確になるかもしれません。縦(コンポーネント内部に閉じる)で開発を行えば横(コンポーネントを横断する)よりもアウトプットの効率は高まります。単位時間あたりにまとめて沢山のコードを書きやすくなるからです。しかし、アジャイルな開発において重視するべきはアウトプットだけではありません。アウトプットによって生じた変化、アウトカムにも同様に(もしくはそれ以上に)着目するべきです。コードを書いたり読んだり、コンポーネント間をつなげたり、リリースしたりすることによって我々の理解は変化するはずです。(おそらくステークホルダーにも変化があるはずです。この話はまた別の機会に)この理解の変化を捉え、次のストーリー、イテレーションに活かしていけば「障害物レース」をうまく突破できるでしょう。反復的な開発はアウトプットだけではなくアウトカムに着目する機会を増やすことでステアリングの能力を得ようとしているのです。
よって、アジャイルな開発における効率とはSLOCではなく、学習と調整の量です。コードをどれだけ大量に生産できるか?ではなく、何を学び進行方向をどの程度頻繁に調整できるか?が問われます。(そしてその先に、価値のあるソフトウェアを提供できているか?という問いが続きます)
不確実性
反復的な開発は、他のエンジニアたちの言葉と自然と重なります。Andrew Hunt, David Thomasは達人プログラマーで閃光弾という比喩を用いて最初から全レイヤーを薄く貫通させる実装をすることを提案しています。言葉は違いますが、これはまさに「縦と横」の概念と一致するものです。さらに、Alistair Cockburn(アジャイルマニフェストの署名者の一人)はWalking Skeletonというアーキテクチャの全レイヤーを貫通する、最小限の実装を行うことを提案しています。こちらも反復や閃光弾と本質的な考えが一致しています。
反復も、閃光弾も、Walking Skeletonも、表現が異なりますが本質は同じです。「不確実なものは着手前ではなく、アウトプットによって生じたアウトカムによって明らかになる」ということです。この記事では主に開発者の理解の側面に焦点を当てましたが、不確実性は他にもあります。ユーザのニーズ、組織や市場の変化など、ソフトウェア開発を取り巻く環境というのは程度の差こそあれ多くの不確実を内包しているはずです。不確実性を否定するのではなく、むしろ不確実性をうまく利用し「障害物レース」を乗り越える手段の一つが、反復や閃光弾、Walking Skeletonだと思います。
計画づくり
「縦ではなく横」というのは少し抽象度の高い理想的な考え方です。現実のプロジェクトでこんな綺麗にストーリーを並べられるのでしょうか?常にスライスできるのでしょうか?どうやって横にすればいいのでしょうか?
これら問いに対する私の考えはまた次の記事で書こうと思います。






