我々は何のためにソフトウェアを開発するのか?

達人プログラマー』の著者であり、アジャイルソフトウェア開発宣言の発起人の一人でもある Dave Thomas氏によって書かれたブログ記事「Agile Is Dead (Long Live Agility)」が、アジャイル界隈に少なからぬ波紋を投げかけたのは記憶に新しい。

その記事で彼は、アジャイルという言葉が、その人気ゆえに、マーケティングの道具にされて有名無実なものになっていることを嘆いていた。

同じくアジャイルソフトウェア開発宣言の発起人である Ron Jeffries氏が年初に出した「The Nature of Software Development」という本は、もしかしたらこの流れに何らかの影響を受けているのかもしれない。

この本でJeffries氏は、いわゆるアジャイルと呼ばれるものの本質について、アジャイルという語やその周辺の専門用語を極力使わずに、おそらく技術者でなくても理解出来るような平易な言葉で解説をしている。150ページほどのコンパクトな内容にたくさんの手書きイラストと専門用語を排した説明。2015年の今、アジャイルの(再)入門として読むには最適な書籍だ。

Dave Thomas氏の記事もそうだが、アジャイルが生まれてから十年以上が経過した今、アジャイルってそもそも何だ? というところに一度立ち返ろうという流れが出てきているように見える。

本来、アジャイルというものは、自分が置かれた状況に合わせてどのように行動したら良いか、ということを考える上での原則を与えるものであって、複雑な手順やツールを利用したり、専門用語に精通したり、ましてやスクラムの資格などとは本質的に関係のないもののはずである。

Jeffries氏は、我々は何のためにソフトウェアを開発するのか? それは「価値」を提供するためである、という当たり前(だけど忘れがちな)事実からスタートして、その効率を最大化するための基礎となる要素「Guiding」「Organizing」「Building」「Slicing」「Quarity」について説明する。

この本の中で個人的に面白いと思ったのは、「価値とは何か」という問いに踏み込んでいるところである。

これまでのアジャイルでは、価値の決定は顧客、あるいはそれに準ずる利害関係者に託されていた。開発の透明性を高めて判断材料を増やし、イテレーション開発で判断機会を頻繁に設けることで、より高い価値を目指す。

アジャイルの考え方を起業に応用したリーンスタートアップでは、さらに踏み込んで、計測可能な価値というものを考える。価値仮説を立てて、実験と計測を繰り返す事で価値の最大化を目指す。

そして、「The Nature of Software Development」では、基本的に価値は計測可能なものではなく「Value is what you want(価値とはあなたが欲しいもの)」だと定義する。一見、何も説明していないようにも読めるが、Jeffries氏は価値というものの多様性を説く。我々は色んなものに価値を認める。例えば「情報」だったり「人命」「資本」「スピード」「幸福」「創造性」などなど、あらゆるものに。

つまり、「価値とはあなたが欲しいもの」の意味は、価値、あるいは何が役に立つかという事は、その価値を受ける人とその人が置かれた状況・文脈に依存するのであって、その状況ごとに自分の頭で考える他はない、ということになる。

DevOpsの起源とOpsを巡る対立

たまチームとして技術ブログを書くようになって、ある日ふと気付いたのだが、そのメインのトピックの一つであるDevOpsという言葉の起源については深く追求しないまま今日に至ってしまっていた。開発と運用が一緒になるとか、あるいはインフラの自動化ぐらいのぼんやりとしたイメージはあったのだが、その運動を起こした人たちとその意図、歴史などについては無頓着なままであった。そこで今回はこの辺の事情について調査を行い、今の知識と照らし合わせながら現状の考えをまとめておきたい。

DevOpsの起源

まず、DevOpsの起源と歴史については以下のサイトに簡単にまとまっている。

Agile 2008 conference

これらの記事によれば、DevOpsという言葉が生まれる一年ほど前、2008年にカナダのトロントで開催された Agile 2008 conference にて、ベルギーのITコンサルタントであるPatrick Debois氏が「Agile Infrastructure & OperationsPDFのプレゼン資料)」というプレゼンテーションを行い、これが後のDevOpsムーブメントの萌芽となったらしい。

このプレゼンテーションで提示されている文脈としては、まず「開発と運用の分離」がある。「What is DevOps?」という資料にも歴史的経緯が解説されているが、元々は分かれていなかった開発(Development)と運用(Operations)という役割が、コンピュータの進歩と共に、次第にそれらを担う別々の専門家が生まれて、最終的には職能として、組織の中では別々の部門に配属される事が多くなったという流れである。

そして、発表が行われたカンファレンスのテーマである「アジャイル開発」も重要な文脈である。このプレゼンテーションのために実施されたアンケートでは、(科学的なサーベイではないと断り書きがあるものの)開発者はアジャイルという方法論に慣れ親しんでいるが、それ以外の部署、運用やインフラ、営業などになると、いわゆるアジリティーはかなり低くなるという結果が出ている。

そして、発表者のPatrick Debois氏は、開発と運用の両方で豊富な経験を持ち、両者の問題をよく理解している、いわば開発と運用のブリッジとなるような人である。その彼がプレゼンテーションで紹介しているのが、データセンターの移行というインフラの仕事をどうやってアジャイル(スクラム)でやるかという事例で、アプリケーションや運用チームがProduct Ownerになるという大変に興味深いものだ。

Velocity 2009 – O’Reilly Conferences

Patrick Debois氏の発表から約一年後、カリフォルニア州サンノゼで開催されたVelocity 2009というイベントで、Flickrのエンジニア(John Allspaw, Paul Hammond)によって発表された「10+ Deploys per Day: Dev and Ops Cooperation at Flickr」というプレゼンテーションがDevOpsという言葉を生み出すきっかけとなった。

このO’Reilly主催のVelocityというカンファレンスのことは知らなかったのだが、インフラ・運用(Web Performance & Operations)がテーマになっていて、参加者もどちらかと言えば開発者より運用系の人が多いようである。このカンファレンスの存在自体が「開発と運用の分離」という事情を象徴するようであるが、そこからDevOpsという言葉が生まれたというのはなかなか興味深い事実である。

さて、件のプレゼンテーションの内容はと言えば、開発者と運用担当者が共通の目的に向かって手を携える事で、一日に10回以上デプロイするような高速な開発を実現できるというものである。まさに Wikipedia などに書かれているようなDevOpsの定義につながる。そして、そこで指摘されていたのは、職能によって分けられてしまった開発者と運用担当者の利害が衝突するようになり、いわゆるセクショナリズムが生じて、いつまでも対立を続けるようになった結果、組織全体が目指すべき本来の目的を見失っているということであった。

この問題は、開発・運用だけにかぎらず、例えば、営業・開発の関係でも、職能で部署が分けられている場合は不可避的に生じる問題である。何か問題が発生した場合に、セクショナリズムが存在すると、その問題を「我々の問題」として認識出来なくなる。そして責任転嫁(finger-pointing)や責任を回避するような保守的な言動が横行するようになる。これは普通の会社の中で働いているたまチーム自身もまさに経験していることでもある。

そして、このプレゼンテーションをベルギーからストリーミングで視聴していたPatrick Debois氏が、「Devopsdays」というイベントを開く事を思い立ち、それが本格的なDevOpsムーブメントの始まりとなった。

devops

NoOps炎上事件

さて、以上の流れでDevOpsというムーブメントが生まれるまでの経緯は大体把握する事が出来たが、その後の2011年から2012年にかけて「NoOps炎上事件」とでも呼ぶべき興味深い事件が起こっているのでここで紹介しておきたい。

事の発端となったのは、2011年にマサチューセッツ州ケンブリッジに本拠地を置くフォレスター・リサーチという調査会社の出した「Augment DevOps With NoOps」というレポートである。

このレポートの主張は、クラウド環境の進歩により自動化が促進されて、将来的に DevOps は NoOps となる、つまり運用というものは必要なくなるというものである。開発者の立場で考えると、昨今のPaaSの隆盛などを見るに、普通に納得出来そうな将来予測ではある。しかしながら、この NoOps という言葉が、運用だけでなく、運用を担ってきた人間さえも否定するように響き、DevOpsという言葉を生み出すきっかけを作ったコミュニティに少なからぬ波紋を引き起こす事となった。

象徴的なのが、DevOpsでは頻繁にその名前が言及される Netflix という会社に当時勤めていたAdrian Cockcroft氏の NoOps に関する記事「Ops, DevOps and PaaS (NoOps) at Netflix」と、それに対するJohn Allspaw氏の反論である。

John Allspaw氏の反論を全部読み通すのはなかなかに骨が折れるが、その長さからして運用のコミュニティを代表する彼の怒りが伝わってくるようだった。しかし、そもそもここで問題にされている事は何なのか?

それは「運用」とは一体何なのか? ということである。Allspaw氏によれば、Cockcroft氏が言うところの「運用」とは、90年代に存在した古い存在であり、相互不理解が原因で開発者にとっての障害かつフラストレーションの原因となっていたが、その反省によってまさに DevOps が生み出されたのだと、そして現代の我々運用コミュニティの人間はとっくにそちらにシフトしているのだと、今更お前は何を言っているんだと、Opsを無くして悦に浸っているようだけど、「運用」という専門領域あるいは責任は変わらずそこにあるし、全然 NoOps になってないじゃないかと、そのような言葉の誤解を指摘している訳である。

この議論は果たして有益だろうか? Allspaw氏の反論は、Opsの誤用を諭しているようで、その実は、彼の所属するコミュニティが信奉しているOpsの定義を主張しているだけのようにも見える。つまり、彼はOpsコミュニティの利害を代表して抗議する事によって、DevOpsが避けようとしていた落とし穴に再び陥っているかもしれないのである。

専門用語の定義問題というのは、その専門性によって縄張り意識を生み出し、セクショナリズムにつながる危険性を孕んでいる。

物理から仮想へ

この言葉を巡る炎上問題から学べる事は何だろうか? それはおそらくDevとOpsという区別自体がナンセンスな時代になったということではないだろうか。その区別が引き起こしていた障害を解消するために DevOps が発明された訳だが、依然として言葉上では区別していたために「NoOps炎上事件」のような対立が起きた。

DevOpsの背景にあった重大な変化は、あらゆるものがソフトウェア化しているということである。分かりやすい例で言えば、仮想化技術によって実現されたクラウドやVPSのような、物理リソースから論理リソースへの移行である。その他、元々はOpsの領域だった、OSのインストールやコンフィグレーション、アプリケーションのデプロイなどの操作もコード化されるようになった。それぞれ、Infrastructure as Code, Operations as Code と呼ばれるものである。

そのようなソフトウェア化した世界にとって、Infrastructure や Operations の区別というのはそれほど重要ではなくなる。あるいは別のレイヤーの話になる。例えば、Microservices概念の出現によって、一つのサーバー(Service)と、プログラム上の一つのモジュールとの概念的な違いが無くなっていくように。

物理から仮想へと言っても、物理的なハードウェアが無くなる事はあり得ない。もしOpsという言葉が有効に機能する領域があるとすれば、それは物理的装置に関連する領域ではないだろうか。言葉というのは視点の問題である。Infrastructure も Operations も、コード化してソフトウェアとして扱えるようなれば、ソフトウェア開発の技術がそこに応用出来る。そこで重要なのはDevとOpsの区別ではなくて、物理なのか仮想なのかという問題である。

Microservices時代のプロジェクト管理を考える (2) – サービス開発者の責任 / 優先順位

水平型から垂直型への移行」によって、今までアプリケーションのビルドまで面倒を見ればよかったアプリケーション開発者は、(マイクロ)サービス開発者となって、サーバーの構築 (Provisioning) から運用の一部まで面倒を見ることになった。一つ一つのサービスの独立性が高くなり、開発者あるいは開発チームの自律性は高まるが、やることが増えた分、外部に対する責任をより明確にしておかないと運用やメンテナンスの局面で様々な問題に直面することが予想される。

前回も少し触れたが、開発者やチームの責任を考えるときは、ソフトウェアのモジュール、あるいはオブジェクト指向でいうところの「責務 (responsibility)」の考え方が参考になる。まずシステムが果たすべき役割を検討して、そこから個々のサービスの責務を割り出し、その責務を実現することを第一優先とする。責任を明確にする理由の第一は、優先度に沿ってリソースを効率よく分配することである。「そもそも我々は何のためにこのシステムを作っているのか」という組織やチームのゴールが共有されてないとバランスの悪いリソース配分をしてしまう危険性が高くなる。

よくある問題の一例として、技術者が技術者の責任を考えると、この優先度の考え方が欠落して必要以上に内部の問題に耽溺してしまうということがある。例えば、技術者の間でよく行われる成果物のチェック方法としてコードレビューがある。スケーラビリティやセキュリティといった比較的目的が明確で判定しやすい指標はよいのだが、可読性や保守性といった、人によって判断が分かれることが多い指標は、無駄に議論が長引いたり、最悪なケースだと技術者同士の衝突に発展してしまうケースもある。

お前さえいなければあああああ!!!
お前さえいなければあああああ!!!

プログラムデザインの良し悪しを判断する時に厄介なのは、重要性が高いものほど多くの人間の同意を取るのが難しくなることである。関数やメソッドレベルの設計はまだ良くても、クラス・パッケージレベルやフレームワーク、アーキテクチャレベルになると、必要になる前提知識も増え、考え方のスペクトラムも大きくなるため、宗教論争的になって同意に至るのは容易ではない。結果的に、声が大きい人の意見が採用されるか、衝突を避けるために同意しづらい事項についてはスルーして、反論されづらい些末な指摘ばかりを繰り返すことになる。

このようなことを避けるため、レビューをするとしても出来るだけ価値の高い外部視点のもの、例えばテストコードをレビューすることを過去の現場では奨めてきたのだが、これも現実にはなかなか難しかった。技術者同士でレビューするとすれば、単体から結合テストレベルのコードになるが、テストの価値が相対的に低いので些末な感じは否めない。受け入れテストなど、もっと上位のテストになれば、ユーザー視点からのレビューも可能になるというのが、Acceptance Test Driven Development (ATDD) などの考え方であるが、以前の記事でFitの失敗を紹介したように、この分野もなかなか前途多難である。

さて話を戻すと、まずサービス開発者の責任を明確にして、責任を果たす限りは自由な裁量に任せるという形にした方が、プロジェクトの参加者全員にゴールへの意識を持たせつつも、無駄なコミュニケーションコストを省くことが出来るし、ゴールと関係ない内部の詳細に耽溺することも無くなる。というわけで、次回以降では、まずサービスの受益者は誰かということを考えて、そこからサービス開発者の果たすべき責任を一つ一つ定義してみたいと思う。

運用中のサービスに与える影響を最小限に抑えつつ、EC2-Classic上のRDSをVPC上に移行する

たまチームで開発しているWebサービスの大半は AWS EC2-Classic 上で動いているのだが、去年から標準でサポートされるようになった VPC (Virtual Private Cloud) に移行しないといろいろと不便なことが多くなってきた。というわけで、移行にあたって一番厄介だと思われる RDS の移行手順を以下にまとめた。

ちなみにこの手順は、EC2-Classic から VPC への移行だけでなく、VPC から VPC の移行にも適用出来るはず。

rds-migration1

大まかな流れとしては、

  1. リードレプリカ経由でClassic側のdumpを取り
  2. それをVPC側で復元
  3. 復元したデータベースをClassic側のslaveとして動かしてデータを同期
  4. 読み込み専用のアプリはここでVPC側に移行して動作確認
  5. VPC側をmasterに昇格した後(ここで一瞬だけ Read Only になる)
  6. 書き込みのあるアプリケーションもVPC側に切り替えて
  7. Classic側を潰せば

めでたく移行は完了する。

1. リードレプリカ経由でClassic側のdumpを取る

rds-migration2

まずはClassic側で移行用のdumpを取得する。リードレプリカを作ってすぐにリプリケーションを停止し、そのときのdumpとバイナリログの位置を取得しておく。リードレプリカ経由なので、この間、サービスの運用には一切影響を与えない。

バイナリログの保持期間を変更する

デフォルトのバイナリログの保持期間が短いので、VPC-slaveを作る間にログが消失してしまわないよう、Classic-masterで以下のように変更しておく。

CALL mysql.rds_set_configuration('binlog retention hours', 24);

現在の設定を確認する:

CALL mysql.rds_show_configuration;

レプリケーション用のユーザーを作る

Classic-masterでレプリケーション用のユーザーを作っておく。

GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'repl_user' IDENTIFIED BY 'some-password';

Classic-masterのリードレプリカを作る

AWS管理コンソールで Classic-master となるRDSインスタンスを選び、”Instance Actions” から “Create Read Replica” を選択する。

レプリケーションをストップする

Classic-slave(今作ったレプリカ)のレプリケーションをストップする。

CALL mysql.rds_stop_replication;

バイナリログの位置を記録する

Classic-slaveで、レプリケーションの状態をメモる(どの位置からレプリケーションを再開すれば良いか)。

show slave statusG
...
    Master_Log_File: mysql-bin-changelog.050354
Read_Master_Log_Pos: 422
...
   Slave_IO_Running: No
  Slave_SQL_Running: No
...

Slave_IO_RunningSlave_SQL_RunningNoになっているので、ちゃんとレプリケーションが止まっていることが分かる。

Classic-slaveのdumpを取る

  • Classic-slaveのエンドポイントを classic-slave.rds.amazonaws.com、管理ユーザーを dbuser とする。
mysqldump -u dbuser -h classic-slave.rds.amazonaws.com --single-transaction --compress --order-by-primary --max_allowed_packet=1G -p --databases database1 databases2  > classic-slave.dump

2. VPCにClassic-masterのレプリカを作る

rds-migration3

VPC内に立てたRDSインスタンスに、Classic-slaveのdumpをインポートしてClassic-masterへのレプリケーションを再開させる(VPC-slave)。

VPC-slaveとなるRDSインスタンスを立ち上げる

AWS管理コンソールでサクッと立ち上げる。

VPC-slaveにClassic-slaveのdumpをインポート

  • VPC-slaveのエンドポイントを vpc.rds.amazonaws.com、管理ユーザーを dbuser とする。
mysql -u dbuser -h vpc.rds.amazonaws.com -p --default-character-set=utf8 < classic-slave.dump

Classic-masterのセキュリティグループ設定を変更する

レプリケーションを可能にするために、VPC-slave から Classic-master にアクセス出来るようにセキュリティグループ(DB Security Groups)を設定する。

以下のような感じで VPC-slave のIPを調べて、そのIPからのアクセスを許可する:

$ ping vpc.rds.amazonaws.com

以下を Classic-master のセキュリティグループに追加。

CIDR/IP to Authorize:  xxx.xxx.xxx.xxx/32

レプリケーションをスタートさせる

VPC-slave にログインして、レプリケーションをスタートさせる(さっき作った専用ユーザーがここで活躍)。
パラメータは先ほどメモしたレプリケーションの状態を参考に。

CALL mysql.rds_set_external_master('classic-master.rds.amazonaws.com',3306,'repl_user','some-password','mysql-bin-changelog.050354',422,0);
CALL mysql.rds_start_replication;

レプリケーションの状態を確認:

show slave statusG

以下のような項目があれば、正しくレプリケーションが動作している。

...
 Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...

レプリケーションがうまく行ったら、Classic-slaveは用無しなので削除する。
この段階で読み込み専用のアプリはVPC内に移行出来る。

3. VPC-slaveをmasterに昇格する

rds-migration4

Classic-masterをReadOnlyにする

FLUSH TABLES WITH READ LOCK;

Closes all open tables and locks all tables for all databases with a global read lock. This is a very convenient way to get backups if you have a file system such as Veritas or ZFS that can take snapshots in time. Use UNLOCK TABLES to release the lock.

として、全てのテーブルをロックしてから切り替えたいところなのだが、RDSではこの命令を実行するための権限がないことが判明。

簡単な代替策もないようなので、とりあえず編集を行う可能性があるサービスを全て「メンテナンス中」として操作出来ないようにした。

VPC-slaveのレプリケーションを停止する

CALL mysql.rds_stop_replication;
CALL mysql.rds_reset_external_master;

以後、こちらを master として扱う。

アプリケーションをVPC内に移動する

VPC内にアプリケーションサーバーを立てて、そちらを指すようにDNSの設定を書き換える。

後は古いClassic環境を潰して移行は完了。

ドキュメンテーションを成功させるには

ドキュメンテーションをうまく機能させるのは本当に難しい。

たまチームの開発は、同じフロアにいるマーケティングチームからの要求に従って行われている。ミーティングなどで要件のヒアリングを行い、それを簡単なタスクの箇条書きに落とし込む。PDCAサイクルを一週間(場合によっては二週間)ごとに行うイテレーション開発を採用しているので、全ての要件を一度に明らかにせず、次のイテレーションのタスクが埋まる程度にヒアリングを行う。ミーティングではイテレーションの成果を踏まえて次の要件やタスクを考えるので、想定外の事象が発生しても早い段階で軌道修正を行える(ここに落とし穴があったのだが、これはまた後日)。

いわゆるアジャイル的な開発である。進捗は可視化されていて、軌道修正もしやすく、見当違いなものを作ってしまうリスクも抑えられるので、なかなか効果的な開発方法に思えるが一つ大きな問題があった。それは、きちんとしたドキュメントを残すタイミングがなく、ほとんど全てが現物主義になってしまうことだ。

そもそもアジャイルという手法に現物主義の傾向があるとも言える。動くソフトウェアとクリーンなコードが何よりも現状を雄弁に語るという考え方だ。

しかし、それはある程度小規模な開発であれば当てはまるかもしれないが、一年以上に渡って開発し続ける複雑なシステムではなかなか難しい状況になる。たとえ動くソフトウェアがあったとしても全貌を把握することは難しくなるし、全てのコードをクリーンに保つことも現実的には難しい。

ある日、こういうことがあった。開発がスタートしてから一年半が経過し、システムの機能も大分増えてきた頃だ。

マーケティング担当者「そう言えば、この機能って XXX のような仕様だったと思うんですけど。」

開発者「え、そうでしたっけ。私は YYY と聞いたように記憶してるんですが。」

マーケティング担当者「うーん、それは困るな。お客さんになんと説明すればよいのか。。。」

もの凄くありがちな光景である。イテレーションごとに現物を確認していても、同じ機能を何度も修正している間に、マーケティング担当者の想定と現物がズレてきてしまったのだ。

その後もシステムはどんどん複雑化することが予想されたので、たまチームとしても何か対策を打たざるを得なくなった。仕様書を書こうということになったのだが、常に変化し続けるシステムの仕様書を維持管理することの難しさは重々承知している。そこで、どのようにドキュメントを管理したよいかを入念に検討して以下の指針を作った。

  • 分かりやすさ: XXXを知らない人でもシステムの目的・機能要件が理解できること
  • 網羅性: 要件が一通りカバーできていること
  • 探しやすさ: 必要な情報をすぐに見つけられること
  • ステータス管理: 要件ごとに「実装待ち」「実装済み」「検証済み」のようなステータスを管理すること
  • 変更容易性: 文書の内容が常にup-to-dateになるように、変更のコストを最小化すること
  • テスト仕様書: この文書を見ながらシステムを操作して要件をテストできること

今回のお題である「Lean Documentation」に書かれている指針と大体同じである。Lean Documentationで紹介されている「良いドキュメンテーションのためのルール」は以下の通り:

  • 素早く書けて更新出来るようにする。現状を反映してない情報は、まったく情報が存在しないことより有害である。
  • 簡単に正しい回答を得られること。必要な情報が見つけづらければ誰もそれを利用しなくなる。
  • ドキュメンテーションが対話を置き換えるわけではない。「プロセスやツールよりも、個人や対話に重きを置くべきである(Manifesto for Agile Software Development より)」。

変更容易性はかなり重要な要件で、これを考えるとWordやExcelなどで仕様書を管理することの問題がよく分かると思う。プロジェクトメンバー全員で情報を共有しつつ、かつ変更も容易に行えるとなると、データベース的な仕組みがどうしても必要になる。

昨今の開発プロジェクトだとWikiで仕様を管理することも多いのではないかと思う。しかしWikiでも、まだ変更容易性に若干の不満があり、ステータス管理やフィードバックなどの扱いに難がある。そこで、たまチームではチケットシステム(具体的には GitHub の Issues)を試してみることにした。

仕様を独立した小さな単位に分割してチケットとして管理すれば、その単位でステータスを管理したり、フィードバックをチケットのコメントとして行えるようになる。変更についても、そのチケット自体を修正したり、破棄したり、また新しく作ったりと、より柔軟に行える。どのような機能が修正されたかも把握しやすい。

全体の構成について、Lean Documentation では「Structure it like Google Earth(グーグルアースのように構造化せよ)」というプラクティスが紹介されている。全体像から詳細に向かって徐々にズームインしていく仕組みがあれば、情報が格段に見つけやすくなるというわけだ。たまチームでは、細かい単位であるチケットだけだと全体像が見えないので、Wikiページに概要とチケットへのインデックスを作った。

「さて、これで完璧なドキュメントが出来上がったぞ(ドヤァ)」

数ヶ月後、苦労して作ったドキュメントは誰にも読まれなくなっていた。読まれないので更新もされない。ドキュメントは徐々に現実からズレていく。

つまり、大失敗である。

原因は一体何だったのだろうか? Lean Documentation にあるように、ドキュメントがマーケティング担当者のニーズに沿った構成や内容になっていなかったのだろうか(「Practice 1 – ドキュメントの利用者とその目的を特定せよ」)?

マーケティング担当者曰く「GitHubを見ることが習慣化していないというのと、同じフロアにいるので、つい直接尋ねてしまう。」

ドキュメンテーションを成功させるために、最も重要でかつ最低限必要なことは「(継続的に)読まれること」である。

このことは文書そのものをどう書くかということよりも遥かに重要である。文書が適切に書かれるから読まれるのではなくて、読まれるから適切な形に変わっていく。読まれなければその文書は死んだも同然である。

ドキュメンテーションというのは固定化されたものではない。コミュニケーションの記録である。口頭の対話は記録されないが、ドキュメンテーションという対話は記録され、かつ構造化される。かなり効率は落ちるが、その記録が残ることの価値はかなり大きい。

ここで重要なのは、「読まれること」は「読ませること」ではないということだ。「GitHubを見ることが習慣化していない」という人に対して「じゃあ、習慣化して下さい」と言うのは間違っている。ドキュメンテーションを行うものは、その文書を読んでもらうためのあらゆる努力をしなければならない。それには、Web上にブログを開設して読者を集めることと同様の難しさがある。

仕様を表現するための一手法である「Specification by Example」も、手法としては素晴らしいと思う。Living document のコンセプトも良いし、Given-When-Then 形式の Acceptance Test Scenario(あるいは、Acceptance Criteria)も分かりやすく書きやすい。実際に、たまチームの一つのプロジェクトでは英語話者と日本語話者が効率的にコミュニケーションするためにこのフォーマットを採用している。しかしこれでも「読まれること」とは、全く別次元の話なのだ。

ビジネスパーソンとエンジニアは、そもそも異なる言語で会話をしている。アジャイルコミュニティではドキュメントの限界を理解しつつも、テストプログラムに通じる形式的な文書を、いかにビジネスパーソンに読ませる(書かせる)かということに苦心してきた。しかしこの試みも Fit の失敗 に代表されるように、うまく行っているとは言えないように見える。ビジネスパーソンとエンジニア、両者の想定があまりに違うのである。

書いたものを読んでもらうというのは、人を動かすということである。Stackoverflow の共同創業者で、Joel on Software で有名な Joel Spolsky 氏は、編著「The Best Software Writing I」の中で「ストーリー」の重要性を説いている(「”Show, don’t tell” rule」)。いくら内容が正しくとも、ストーリーなき文章を長々と読めるわけがないというわけだ。

ストーリーなんて仕様書のような形式的な文書とは関係がないと思うだろうか? アジャイル開発で要件の単位となる「ユーザーストーリー」は、形式的表現に慣れているエンジニアからビジネスパーソンに歩み寄った結果として生み出されたものだ。ドキュメンテーションとはコミュニケーションであり、その質にはコミュニケーション能力がそのまま反映される。だからこそプログラミングそのものよりも難しいと言っても過言ではないように思える。

Microservicesアーキテクチャの思想性

Microservices and the Goal of Software Development:
http://www.infoq.com/news/2015/03/microservices-software

  • ソフトウェア開発の目的は business impact を生み出すこと
    • Business impactとは、組織内で観測可能な効果のこと(新規顧客やオペレーションコストの削減など)
    • Lead time(機会の発見からその解答を生み出すまでの時間)を最小限にすること
    • これを持続的に行うのが難しい
  • 三種類のコード
    1. 最近書いて理解しているコード
    2. よくテストされ、文書化されているコード
    3. 誰も知らないコード(不明瞭な依存関係、変更の影響範囲が局所化されない)
  • ソフトウェア開発最大の問題は、大部分のコードが 3 に分類されるということ
  • コードはきちんと運用出来るものだけを維持するようにするべき(3のコードを排除すべき)
  • North氏の提案する二つのパターン
    1. コードの目的(意図)を明確にすること
      • ソフトウェアの半減期は短い(「半減期」とは放射性崩壊の速さを示す物理学用語)
      • なので、それぞれのコードの目的を明確にして安定化に努めるべし
    2. 理解しやすいようにコードを分割統治すること
  • 上の二つのパターンを実現するために有効なのが「置換可能なコンポーネントによるアーキテクチャ (replaceable component architecture) 」
    • APIによって意図が明確にされたコンポーネント
    • コンポーネントは Alan Kay の発明したオブジェクト指向のオブジェクトのごとく、メッセージのやり取りをする小さなコンピュータのようなもの
  • Microservicesは、置換可能なコンポーネントによるアーキテクチャになり得る
    • 置換可能性と一貫性を追求すること
    • コンポーネントの「小ささ」よりも「置換可能性」の方が重要

現場のエンジニアがMicroservicesアーキテクチャを評価するときは、どうしてもその実用性や現実性、例えばプロセス間通信の多用によるオーバーヘッドなどが問題にされがちである。しかし、そのコンセプトをつぶさに見ていくと、これは単にアーキテクチャだけの問題ではなく、ソフトウェア開発はどうあるべきかという、ある種の思想を提示していることに気がつく。

開発の現場には「エンジニアとは外から持ち込まれた問題に解を与える者だ」という強い思い込みがあることが多い。しかし、これはプログラミングに対する誤解を含んでいるだけでなく、一つのシステムを長く育てるというケースにおいては、持続可能なモデルではない。

Martin Fowler氏が「The New Methodology」の中で「ソフトウエア開発は、全てが「デザイン」である」と指摘したのはもう大分昔のことだが、この考え方が開発の現場においてどれだけ浸透しているだろうか。

ソフトウエア開発は、本質的に、問題に対する解法の実装だけでなく、問題自体の検証と再設定を含むサイクルを繰り返す作業で、プログラミングというのはそのための強力な武器である。既に設定された問題を解決するためだけにプログラミングが存在し、そしてその問題設定を開発から切り離せると考えるのは、ソフトウエア開発に対する大きな誤解である。

Microservicesで提案されているのは、一つのサービスだけでなく、それを開発する開発者(あるいはチーム)も、できるだけ完結した存在になることが望ましいということである。中央集権的な開発体制ではなく、いくつものサービスとその開発を担当する cross-functional なチームが自律的に連携して、全体として大きなシステムを実現するという、オブジェクト指向が理想としていたようなモデルである。

あまり理想主義的になり過ぎるのも良くないが、このような考え方のルーツの一つにオブジェクト指向があり、それが考え方としてはデザインパターンやアジャイル開発などにつながり、プロダクトとしてはインターネットやiPhoneなどにつながっていることを考えると、実用性や現実性はともかく、その思想の重要性に注目しておく必要はあるだろう。

Microservices時代のプロジェクト管理を考える (1) – 水平型から垂直型へ

たまチームで管理しているGitHubリポジトリの数もどんどん増えてきて、今ではデプロイ可能なサービスだけでも20個ぐらい、リポジトリの総数は30を超えた。既に書いた通り、これらのサービスに共通するサーバーの構築 (Provisioning) と管理は、これまで一人のインフラ担当者が頑張って面倒を見てきた。しかしこのままサービスの数が増えていくと、インフラ部分がボトルネックになって効率が大きく損なわれることが目に見えている。そこで Deployment や Provisioning の管理方法を変えよう、というのが前回の話であった。

この方針変更をたまチームでは「水平型から垂直型への移行」と呼んでいる。

従来の管理方法だと、アプリケーション開発者はアプリケーションのビルドにだけに注力すればよい一方、インフラ担当者は、すべてのアプリの Deployment、サーバーの Provisioning や Monitoring まで面倒を見なければならなかった。

horizontal

これを垂直型に移行すると以下のようになる。

vertical

アプリケーション開発者はサービス開発者となり、アプリケーションのビルドに加えて、そのアプリケーションが動作する環境の Provisioning も担当し、最終的には Server Image をアウトプットするようにビルドプロセスを変更する。インフラの共通部分は最小限に抑えて、チームメンバー全員で共同管理出来るようにする。

水平型も垂直型も、それぞれ一長一短でありトレードオフがある。インフラの共通部分を厚くすれば、同じような構成のサーバーを一括で変更したり、多くのProvisioningコードを再利用出来る一方、共通部分と各アプリケーション開発者間で生じるコミュニケーションコストは馬鹿にならない。

あるいは、高度に訓練されたチームであれば、メンバーの誰もが共通部分(インフラ)とアプリケーションを行ったり来たりしながら自在に開発出来るのかもしれない。しかし、残念ながら我々たまチームはそこまでのレベルには達していないので、共通管理する部分を出来るだけ薄くして、後はアプリケーション開発者の裁量に任せてみることにした。

この考え方はソフトウェアのモジュール(あるいはオブジェクト)の考え方に似ている。モジュールは外部との責任を明確にする一方、内部構造については隠蔽しておくのが望ましいとされる(責任を果たす限り内部の詳細を問題にしない)。これはモジュール間のコミュニケーションコストを最小限にして、大量のモジュールが柔軟に連携出来るようにするための考え方であり、これをそのままサービス開発に応用するとすれば、アプリケーション開発者は、そのアプリケーションが外部に果たす役割を明確にする限り、他の開発者はその内部のことを(とりあえずは)気にしなくて済む。

サービスの数が増えていくのと同時に、技術の進歩に伴って、サービスの粒度が小さくなってきている。サービスが Microservice化すると、一つのリポジトリを複数の人間が管理するよりも、一人の人間が複数のリポジトリを管理するケースの方が増えてくる。その意味でも、コミュニケーションコストを抑える方法を考えておかなければならない。

個々のサービス開発者に課せられる責任は、オープンソースプロジェクトの開発に要求されることに似ている。そのプロジェクトを誰かに使って欲しければ、それが外部に提供する価値について、そしてその利用方法について、第三者が分かる形で説明する必要がある。ここで何を説明するべきかという最小限のラインを考えることが垂直型の勘所ではないかと思う。

ソフトウェアアーキテクチャと組織の構造

Martin Fowler氏が記事 Microservices の中で言及しているように、コンウェイの法則によれば、ある組織が開発するソフトウェアのアーキテクチャはその組織の構造をそっくりそのまま反映した形になる。今回の話で言えば、水平型のアーキテクチャを生み出す組織は職能で分けられた水平分業組織であり、垂直型の場合は cross-functional な垂直統合チーム型組織になる。

既に述べたように、いずれも一長一短があるため、どちらが良いとは一概には言えない。たまチームではたまチーム独自の事情があって、今回は垂直型への移行を試みることになった。この移行によって開発のやり方やアウトプットがどう変わったかはこのブログで逐一レポートする予定である。

最後に一つだけ垂直型への期待を述べるとすれば、現代は専門領域の境界がめまぐるしく変化する時代である。一つの専門領域に留まっていたら、あっという間に時代遅れになることも珍しく無い。このような時代においては、多様な領域に横断的に関わり、それらの融合をもって競争社会のアドバンテージとするべきであり、そういう意味ではチームだけでなく、個人にも cross-functional な能力が求められるのではないだろうか。