SoftwareEngineering

16. ソフトウェア工学

16.1. 概要

ソフトウェア障害は常に発生します.時にその不具合の規模が大きくてプログラムを使いづらくさせてしまうこともあります.また,1つのエラーがコンピュータ全体をクラッシュさせてしまうことも.その中には,他より途方もない規模になるものもあります.

1996年,欧州宇宙機関のARIANE 5ロケットは,その最初のテスト飛行として打ち上げられました.カウントダウン,点火,炎と煙,急上昇するロケット,そして・・・ドカン! バラバラになった大量のロケットの破片が,南アメリカの熱帯雨林全体にまき散らされたのです.調査員が調べ上げた結果,ついにつきとめた原因は,ごく小さな,取るに足らないバグだったのです.ロケットに積まれていたソフトウェアの一部,必要ですらなかったそのプログラムがエラーを報告したことで,自爆処理を作動させてしまったのです.
幸いロケットには誰も乗っていませんでしたが,この失敗により米ドルで3億7000万という損害を被ることになりました.

SE-Ariane-5-150.png

  1. "エラー!"「まあ,いいか.どうせこのコードが使われることはないだろうしね.」
  2.  
  3. "爆発!" 「...えっ」

極端な場合,ソフトウェアのバグが生命を脅かすこともあります.例えば1980年代,ある放射線治療装置が想定の100倍の量の放射線を照射して,3人の患者が死亡するということが起こっています.1979年には,アメリカ陸軍のコンピュータが,ソビエト連邦がミサイルを発射するというシミュレーションを現実と誤って解釈し,あわや核戦争を起こしかけたということもあります.(その他のソフトウェア障害に興味がある人は,CS4FNにさらに衝撃的な事例がリストアップされていますよ!)

今日の我々の社会は,それなしの生活がもはや想像できないほどソフトウェアに依存しています.いろんな方法で,ソフトウェアは我々の生活を楽にしてきました.電子メールを書く,友達とFacebookでチャットする,コンピュータゲームで遊ぶ,Googleで情報を検索する・・・.たくさんのソフトウェアは舞台裏に隠れているため,我々はそれらを,例えば車,信号,テレビ,洗濯機,日本のトイレ,補聴器などの中で使っているということにすら気づけません.我々はソフトウェアを所持するということに慣れきってしまって,それらが常に動くことを期待してしまいます.

ではなぜそうではないのか?そもそもなぜバグができるのか?結局のところ,ソフトウェアを作ることは非常に難しいということです.ソフトウェアは物理的な製品ではないので,単に目視で正しいかどうかを見ることができません.おまけに,普段使われるほとんどのソフトウェアは,巨大で,とてつもなく複雑です.Windows Vistaは約5000万行のソースコードで作られているという噂があります.MacOSXは8600万行とも.もしVistaを紙にプリントすると,高さ88mもの層になってしまいます! これは22階建てのビル,ニューヨークの自由の女神と同じくらいの高さ! もしVistaに目を通してその動作原理を理解しようとしたら,1時間に約120行理解できるとしたら,417,000時間,つまり47年半かかることになります! (しかも単に書くわけではなく,読むだけで)

SE-stacks-of-code-150.png

  1. よし,このソースコードが理解でき始めたぞ・・・
  2. いいね!じゃその後で,このデータベースドライバに取りかかってくれるかな.
  3. 2,3分したら,最初のトラックに積まれてる残りのやつも持ってくるよ.

ソフトウェア工学とは,どうやってソフトウェアをその巨大なサイズや複雑さに関わらず作り上げ,最終的にちゃんと動く製品にできるかに関すること,になります.ソフトウェア工学はコンピュータサイエンスのトピックとして初めて導入されたのは,1960年代のいわゆる「ソフトウェア危機」でした.その時人々が,ハードウェアの性能が信じられないスピードで向上するのに対して,人間のソフトウェア開発能力はほとんど変わらないことに気がついたのです.

ソフトウェア工学はその名前からわかるように,他の工学分野(building bridgesやコンピュータハードウェアなど)からアイデアや手法を取り入れ,ソフトウェアに適用しています.ソフトウェア開発のための構造化されたプロセスを整えることは,ソフトウェア開発の規模や複雑度を管理できるようになるため,とてつもなく重要となるのです.ソフトウェア工学の進歩により,大規模で複雑なソフトウェア製品がうまく動作し,ほとんどバグも混入しないという成功例を多数生み出しています.例えばGoogle.いくつも巨大なプロジェクト(Google検索にGmail...)を抱え,何千もの技術者が働いているにもかかわらず,それでもどういうわけか期待通り動作するソフトウェアを開発できているのです.

1960年代から,ソフトウェア工学はコンピュータサイエンスの非常に重要な要素となっており,そのため今日のプログラマーはそのまま「プログラマー」と呼ばれる事はほとんど無く,「ソフトウェアエンジニア」と呼ばれます.ソフトウェア開発は単にプログラミングするだけではなく,遙かに多くの要素を含むからです.ソフトウェアエンジニアには非常に多くの仕事があり,熟練エンジニアへの要求は上がり続けています.ソフトウェアエンジニアであることのすばらしさは,大規模チームで組んで製品を生み出し,それが何百万という人々の生活に影響を及ぼすということ!ソフトウェアエンジニアは非常に賢く,かつ少しマニア(ギーク)な人でなければならないと思うかもしれませんが,実はコミュニケーションとチームワークの能力がより重要なのです.ソフトウェアエンジニアは,チームで働き,チームメートとコミュニケーションを取ることができなければなりません.人間とうまく仕事が出来る能力は,コンピュータと仕事をするのと少なくとも同じ程度に重要なのです.

もっと知ろう: ムーアの法則

1965年,ゴードン・ムーアは,集積回路(IC)内のトランジスタの数がおよそ2年ごとに2倍になっているということに気がつきました.つまり,コンピュータの処理能力が大体2年単位で2倍になるということになります(トランジスタ数とスピード増加の組み合わせによって,"18ヶ月"と引用されていることもあります).ムーアは当時,この傾向が少なくとも10年は続くと予測しました.

信じるか否かに関わらず,ムーアの法則は10年では終わらず,50年後の現在にもまだ真実であり続けています(今後数年のうちに鈍化すると予測されていますが).これはつまり,今日のコンピュータが1965年当時と比べて1億倍速くなっているということになります!(本文章の作成時点で1965年から47年経過しており,これは処理能力が24回倍増したということ.2^{24} =16,777,216 なので,1965年にコンピュータがある処理を1秒で実行できたとすると,47年後の今はその処理を16,777,216回(1秒で)実行できるわけです!)またこの事実は,もし今コンピュータを買っても,2年後には新しいコンピュータが2倍の速度で動くことにがっかり,という可能性も意味します.ムーアの法則は,携帯電話の処理能力やデジタルカメラのピクセル数など,他のものにも適用されます.

上記の正確な数値は対象物に依りますが,重要な点は,コンピュータの処理能力は指数関数的に増加しているということです・・・"指数関数的増加"とはつまり,単に"すごく高速"ではなく,"信じられないくらい高速",それこそ人類の歴史上存在しなかったレベルで,ということ!逆に言えば,今スマートフォンであるアプリを開くのにかかる時間は0.5秒くらいですが,1965年のスマートフォンであれば同じアプリを開くのに1年以上かかる(しかもそのスマホはサッカーフィールドくらいのサイズになりうる)ことになります.1960年代にスマホが流行らなかったのも無理はない.

ソフトウェア工学は過去数十年の間に大きな発展を遂げましたが,ソフトウェア開発は未だ大変です.利用者としては完成されたプログラムだけ目にし,失敗作を見ることはありません.2009年は,全ソフトウェアプロジェクトの3分の1だけが"成功"し,4分の1が完全な失敗に終わるか,ソフトウェアが納品される前に中止されてしまいました.残りのプロジェクトは,納品が遅れたか,予算オーバーしたか,機能不足かということです.最近の有名な失敗プロジェクトは,デンバーの新空港での手荷物管理システムのソフトウェアです.このシステムは,エンジニアが想定したよりも複雑になっていき,最終的には空港全体の運用準備が整っているにもかかわらず,荷物システムのソフトウェアが動かないがために,オープンまでに16ヶ月も待たなければならなくなりました.その16ヶ月の間,空港は毎日100万ドルの損失となってしまったそうです.

この章では,いくつかのソフトウェア工学の基礎を見ていきます.最初に,どのようなソフトウェアを作るのかを知る問題分析についての話から始めます.次にソフトウェアの設計・デザインについて述べ,そしてソフトウェアのバグを取り除く最重要ステップであるテストについても少し話します.以下を見ればわかりますが,分析,デザイン,テストは全てソフトウェア開発の際に重要なステップです.実際のプログラミングに費やす時間は,たいていプロジェクト全体の20%程度でしかありません(そしてこの章では,プログラミングはほとんど扱いません!).最後に,常に次に何をすべきかがわかるよう分析・デザイン・テストを含む活動を体系化するソフトウェア開発プロセスを見ていくことにしましょう.

16.2. 分析: 何を作る?

ソフトウェアの作成を始めるには,実際何を作りたいのかをまず確定しなければなりません.ソフトウェアに何が出来る必要があるか正確に分析することから,ソフトウェアプロジェクトにおけるこの段階を分析と呼びます.大したことはないように思えますが,正しく詳細を把握することは非常に大変です.椅子やトースターのような実物をデザインしてくれと言われたら,完成形がどのようなものになるかいいアイデアを明確に考えることができるでしょう.椅子に何本足を付けることにしようと,人間を重力に逆らって支えるという仕事は変わらず満たしてなければなりません.ソフトウェア設計となると,見慣れたものを作るという利点も,物理法則のような既知の制約もないことがよくあります.さて,もし開発すべきソフトウェアが,作家に空想世界の創作を支援するプログラムだとすると,どこから手を付けますか?何を当然の前提とみなしてよいでしょうか?

分析は非常に重要です.明らかに,もしプロジェクトのこの段階でミスをしていたら,最終的にできるソフトウェアは欲しかったものにはならないでしょう.その他のソフトウェアの設計,実装,テストの部分も,全く意味がないものになってしまいます.

例えば,あなたの友人アンナから,朝学校に行く助けとなるプログラムを書いてとお願いされたという状況を考えてみましょう.あなたは素晴らしいGPS道案内システムを作り,それをアンナに見せましたが,実は彼女は,学校にはバスに乗って行くこと,そのため彼女が本当に欲しかったのは,単に現在のバスの時刻表を表示するソフトウェアだったことが,そこで判明したのです.最初に要求の詳細を正しく把握してなかったがために,あなたの懸命な努力は無に帰してしまったのです!

自分のためだけにソフトウェアを作ることもあります.この場合は,ソフトウェアが何をするかを自分で直接決めることができます.(でも注意:開発を始める時にソフトウェアに何をさせたいか自分で理解していると思っていても,おそらくそのプロジェクトの最後には,ソフトウェアが何をすべきかについて全く異なる見方を持っているでしょう.問題は,ソフトウェアを手にする前には,完成時にそれをどのように利用することになるかしっかり予測することができないということ.例えば,スマートフォンとスマホ用アプリの開発者はおそらく,どれだけ多くの人達がそのスマホを電灯として使おうとするかは予測できなかったでしょう!)

多くの場合,他の人達のためにソフトウェアを開発します.叔母の衣料品店のためにWebサイトを作ったり,友達の数学の宿題をを手助けするソフトウェアを作ったりすることもあるかもしれませんね.ソフトウェア会社は,地方議会やGP(General Practitioner,総合開業医)の実務用としてソフトウェアを作ることもあるでしょう.GoogleやMicrosoftは,世界の何百万という人々に使われるソフトウェアを作成しています.作ろうとするプログラムが友達のためか,あるいは何百万の人々のためか,いずれにせよ,まずはソフトウェアに実際何をさせる必要があるのかを,顧客から引き出さなければなりません.

ソフトウェアに興味を持つ全ての人を,ステークホルダー(stakeholder)と呼びます.プロジェクトにおける分析作業の中でソフトウェアに何をさせる必要があるかを見つけ出すため,話をする必要がある人々になります.

たとえばあなたが、生徒が学校の食堂に食べ物を事前注文できるケータイアプリを作っているとしましょう。朝アプリを使って食べるものを注文し、昼食時にはただ注文したものを持っていくだけ。このアイデアで、きっと配膳処理を効率化に役立ち、食堂の行列を減らすと思われます。このプロジェクトにおける明らかなステークホルダーは、(このアプリを使う)生徒と(アプリから注文を受ける)食堂スタッフです。間接的なステークホルダーには、両親(「ジョニーにこのアプリを購入して使えるようにしないとだめ?」)、学校経営者(「学校にいるときは携帯電話は一切使用禁止!」)、そして、アプリの使い方がわからない生徒に対応しなければならない学校のITサポート担当がいます。異なるステークホルダーは、アプリの期待する挙動についてそれぞれ全く異なる考えを持っています。

ステークホルダーの人達がソフトウエアにどんな挙動をしてほしいか調べるには、インタビューするのが一般的です。彼らに質問を投げかけることで、ソフトウェアの機能的/非機能的要求を把握していく。機能的要求は、ソフトウェアが処理すべきものです。例えば、このアプリが注文したい食べ物を生徒が選べるようにする必要がある、というものです。そしてその注文を送信し、その際にはその食事を取りに来た時に簡単に判別できるよう、注文した生徒の氏名も合わせて送る必要があります。

一方、非機能的要求は、ソフトウェアが何をすべきかは教えてくれませんが、どのようにすべきかを教えてくれます。どのように効率的にする必要があるか?どれくらいの信頼性が必要?どんな種類のコンピュータ(もしくは携帯電話)で動くようにすべきか?どのくらい扱いやすくするべきか?

なので、まずステークホルダーが誰かを明らかにし、そして彼らにインタビューしてソフトウェアの要求事項を明らかにします。聞いた感じ難しくなさそうですよね?残念なことに、顧客とのコミュニケーションはしばしば最も困難なものになりがちです。

第一の問題として、顧客とソフトウェアエンジニアはたいてい同じ言語で会話しません。もちろんこれは「どちらも英語をしゃべれるわけではない」のような意味ではなく、ソフトウェアエンジニアは総じて技術用語を使いがちで、顧客は自分の業務に特化した用語を使いがちという意味です。例えば、医者があなたに理解できない恐ろしい医学用語を多用したりすること、ありますよね。

顧客から、Whacky-Flobというスポーツ(フィクションです)のスコア付けシステムを作ってくれとあなたにお願いしたと想定します。顧客はあなたにこういいます。「すごく単純です。foo-whackの記録は必要だけど、bar-whackはFlobがcirculateしていなければ記録する必要がない、というだけなんです。」こんなことを言われて、あなたは確実に大混乱するでしょう。そもそもWhacky-Flobなるスポーツについて何も知らないし、そこで使われる専門用語もわからないわけですから(一体何なんだよfoo-whackって???)始めに、Whacky-Flobのゲームに何回か参加し、それがどのようなゲームなのか、どのように得点が付くのかを観察するべきでしょう。この方法によって、この課題領域についてある程度の知識を得られるので、顧客と遥かによい会話を行うことができるでしょう。(ちなみに、これはソフトウェアエンジニアであることのすばらしい点の一つです。あらゆる種類の異なる、刺激的な問題領域に顔を出すことができるのです。あるプロジェクトではハイイログマの追跡をして、次のプロジェクトではサイバーテロリストの識別だったり、車の自動運転制御だったりすることだってありうる。)

また、顧客が、誰でも知ってるはずだろうと思うような技術用語を(JPEGとか、データベースとか、オペレーティングシステムでさえも)十分理解していると仮定してはいけません。「メタクラスのサブクラス層は、それらのインスタンスであるクラスのサブクラス層と同様の制約を受ける」のような表現は、ソフトウェアエンジニアには意味をつかめるかもしれませんが、顧客は混乱しきってあなたを見つめるだけでしょう!この記事の著者の一人はかつて顧客インタビューへ参加したのですが、そこでステークホルダーの人は「ブラウザからシステムを使いたいか」と質問をうけました。不幸なことに、その顧客はブラウザが何かがわかりませんでした。
時に、顧客は相手が何を話してるかわからないことを認めたくなくて、提案されるもの何でも「はい」とだけ言うことがあります。覚えておくべきは、顧客が互いに理解し合い、インタビュー時に顧客から役立つ回答を得ることができるかどうかは、エンジニアであるあなた次第だということです。

SE-design-150.png

  1. 「顧客の詳細情報を記録するシステムが欲しいんだが」「大丈夫ですよ!いくつか簡単な質問だけ・・・」
  2. 「GUIもしくはCLI?」「自動セーブ機能は必要ですか?」「遠隔ブラウザアクセスは?」「セキュリティについては?秘密鍵暗号にします?」「64bitと128bit,どちらに?」
  3. 「とにかく何でもそちらの思う一番いいのを頼む!」
  4. そして... 「...」

なんとかして顧客とコミュニケーションが取れたとしても、顧客は何をそのソフトウェアにさせたいのかを、十分に知らないか、表現することができないことに気づくでしょう。彼らは「ソフトウェアで業務を改善したい」もしくは「業務をより効率的にしたい」とは言うかもしれませんが、あまり具体的ではありません。(すばらしいマンガであるDilbertに,この点を表現したものがあります!) もし開発したソフトウェアを顧客に見せれば、たいていそれが自分たちの望むものか、またそれが気に入るか入らないかを伝えることはできます。そんなわけでシステムを開発するときは、小さなプロトタイプを作って、それを顧客に見せ続けてフィードバックを得ながら行うのがいい案です。

顧客は、自分のところで既に行われている特定の処理があって、ソフトウェアをその流れに適合させたいと考えることもよくあります。我々はかつて図書館向けに大学生が行うプロジェクトに参加したことがありました。図書館のスタッフは、貸出中の物品の情報を紙のフォームに3回書き、それを切り分けてそれぞれ記録として別の所に送るということを行っていました。学生が彼らにインタビューすると、プログラム中のスクリーン上に、同じように情報を3回書き込めるようにという要求を出してきたのです(コンピュータシステムでそんなことをする意味は全くないにもかかわらず)!

顧客は常にその分野の専門家なので、自分達にとって明らかだと考える情報を除外してしまいがちですが、エンジニア側にとっては明らかでないことかもしれません。また、コンピュータに何ができて何ができないかを十分理解しておらず、ある事がコンピュータで実行可能であることに気づかず、それに言及しないこともあります。繰り返しになりますが、彼らから情報を引き出し、こちらが知りたいことを彼らに話させるようにするのは、エンジニアであるあなた次第です。

もし複数のステークホルダーを抱えているなら、相異なる観点が得られることもあります。例えば、食堂スタッフに注文アプリについて話すと、どの生徒も高々10ドル程度の食事くらいしか注文できないようにして欲しいと提案してくるかもしれません。これによって、いたずらの注文を防ぎたいのです。教師と話すと、いじめ行動への心配からその提案に賛同するでしょう。一人の生徒がむりやり他の大勢の生徒の注文をさせられることにはしたくないのです。でも生徒からは、友達の分も注文できるようにしてほしいと話してきます。彼らの視点からすれば、1人の生徒に10ドルというのは足りないのです。

これらの相反する支店についてあなたはどうしますか?このような状況は、その時の状況、ステークホルダー、そして作成するソフトウェアに依存して、取り扱いが困難になりやすいです。このケースで言うと、ソフトウェア稼働のために食堂と教師からの支援は必要ですが、全てのステークホルダーを幸せにするために、注文の上限を少しだけ高い20ドルにする交渉をする余地はあると思います。

最後に、開発プロジェクトの解析段階を完璧に行い、全ステークホルダーと話をし、ソフトウェアの全ての要求事項を洗い出したとしても、要求しようはソフトウェア開発の中で変更される可能性があります。大規模なソフトウェアプロジェクトでは完成まで何年もかかることもあります。技術の世界で、1年間に一体どれだけの変化が起こっているか考えてみてください!プロジェクトに携わっている間も、新しいハードウェア(電話、コンピュータ、タブレット、...)が世に出てきますし、自分たちの開発しているものと非常によく似たソフトウェアを、ライバル会社がリリースするかもしれません。開発中のソフトウェア自身も状況は変わっていくかもしれません。一旦ソフトウェアが公開されると、顧客はそれを使って仕事を行い、そのソフトウェアが本当に自分たちが欲しかったものではないことに気づくかもしれません。そのため、ソフトウェアの要求仕様は固定化するべきではありません。理想的には、プロジェクトの間は顧客と常時やりとりを続け、要求仕様の変更にいつでも対応できるようにすべきです!

16.2.1. プロジェクト課題: 要求事項の発見

このプロジェクト課題では、あなたがソフトウェア開発を行う対象となる誰かを見つける必要があります。あなたの家族や友達がその「誰か」になるでしょう。例えば彼らが、仕事での顧客に関する情報を管理するソフトウェアが欲しいかもしれませんし、所属するスカッシュクラブがトーナメント戦のスケジューリングや練習の時間調整ができるソフトウェアを欲しいかもしれません。(このプロジェクトでは、実際にソフトウェアを作る必要はなく、要求事項について考えましょう。プロジェクトが自分でプログラムできる程度に小規模であれば、おそらくソフトウエア工学の好例としては十分な規模ではないでしょう!)

プロジェクトを見つけたら、そのプロジェクトのステークホルダーを特定し書き出すところから始めましょう。(少なくとも2種類の異なるステークホルダーがいればベストです) そのソフトウェアに間接的な利害関係があるだけの人もいるかもしれないことを意識して、全てのステークホルダーを見つけ出してみましょう。例えば、もし顧客情報を格納するデータベースを作るなら、自らの情報が格納される顧客も、たとえソフトウェアを直接使うことはないにしてもソフトウェアに一定の関係を持つことになります。例えば彼らは、データが盗まれないようにソフトウェアに十分なセキュリティを求めるでしょう。各ステークホルダーについて、出来るだけ詳しくその背景を書き出しましょう。彼らは誰なのか?ソフトウェアにどんな関心/関係を持つのか?技術的な知識をどれだけ持っているか?...

ステークホルダーの一人にインタビューを行い、ソフトウェアに何をしてほしいかを見つけ出しましょう。ソフトウェアの要求仕様を、各仕様について少し詳細も含めて書き出しましょう。機能的要求と非機能的要求に分けましょう。必ずステークホルダーから、自身にとって何が最も重要なのかを聞き出してください。これによって、各要求の優先度を定めることができ(例:高/中/低)、実際にソフトウェアを開発する時に最も重要なところから手をつけることができます。

他のステークホルダーについては、彼らの要求事項がどのようなものかを想像してみましょう。特に、その要求が他のステークホルダーとどのように異なるのかを明らかにしてみてください。2人のステークホルダーが同じ要求を出す可能性もありますが、その場合にそれぞれ異なる優先度をもっているかもしれませんね?ステークホルダー間の潜在的な不一致や競合があるかどうか確かめてみましょう。もしあるなら、解決にあたって何ができるでしょう?

16.3. 設計(Design): どのように作り上げるか?

ソフトウェアで何をできるようにする必要があるか決定したら、実際に作成することができます。でも、単に闇雲にプロムラムを始めても、トラブルに巻き込まれがちです。ほとんどのソフトウェアは巨大で、非常に複雑だということを覚えておきましょう。どうにかしてソフトウェアの複雑度を最小化することが必要です。そうでないと、将来他の開発者がソフトウェアを理解し、維持管理することが不可能になってしまいます。

ソフトウェア設計とは,複雑度を管理し作成するソフトウェアが適切な構造を持つようにすること全体です.何かコードを書く前に,プロジェクトの設計フェーズにおいてソフトウェアの構造をデザインします.ソフトウェアの設計(design)と言うと,多くの人はそのソフトウェアの見た目をデザインすることだと思うでしょう.実際には,ここではソフトウェアの内部構造の設計を見ていくことになります.

では,ソフトウェアが非常に複雑で理解不可能なことにならないためには,どのように設計すればよいのでしょう?
ここで,2つの重要なアプローチを紹介します.細分化(subdivision)と抽象化(abstraction)です.ずいぶん怖い言葉ですが,この裏側にある概念はびっくりするほど単純だということが,この後すぐにわかるでしょう.

おそらく既に,細分化がどういう意味かは推測できていると思います.その一つのソフトウェアを,独立に作成できる程度の小さい部分に分けていくことです.それぞれの部分を,さらに細かく分割しつづけることもあります.最初の章で述べた通り,多くのソフトウェアは一人の人間が全体を理解することが困難なほど,大規模かつ複雑です.つまり小さな部分に分割すれば,遙かに扱いやすくなるということです.大規模ソフトウェアは,大規模なチームによって開発されていて,チーム内で異なる人々が異なる部分で,互いに独立に,並行して開発していきます.たとえば食堂プロジェクトの場合,あなたは食堂が売り出すメニューとそれぞれの値段を記録するデータベースを設計している一方で,あなたの友人は生徒が実際に注文する実際のケータイアプリ作成に携わっています.

全ての部分プログラムを構築できたら,あとは互いに連携させるだけです.各部分がきちんと設計できていれば,比較的たやすいことです.
各部分はいわゆるインタフェースを持っていて,他の部分がやりとりを行うのに使用できます.例えば,食堂プロジェクトのあなたの担当部分は,何の食事が提供されていて,それぞれいくらするかを他の部分にわかるようにする方法を提供しなければなりません.これにより,生徒用ケータイアプリの作成を担当する友人は,あなたの開発部分に単に要求メッセージを送って情報を得るだけでよいことになります.その際,友人側のアプリは単に要求メッセージを送るだけで,あなたの開発部分から得られる回答を信用しなければなりません.このようにして,プロジェクトに携わる各メンバーは,ソフトウェアのうち自身の担当部分がどう動くかだけを理解していればよいわけです.

OKそれでは次の概念,抽象化について述べましょう.なぜ人はエンジンの動きを知らなくても車を運転できるのか,これまで考えたことがありますか?あるいは,ハードウェアについて十分知ることなく,どうやってコンピュータを使えているのか?もしかするとプロセッサ(演算装置)やハードディスクドライブが何であるかは知っているかもしれませんが,コンピュータを自力で作成することができますか?あなたの両親は? コンピュータや車が内部でどのように動くか,正確に知る必要なくそれらを使うことができるのも,抽象化のおかげなのです!

より詳細にコンピュータを見ていくと,そこには実際には何層もの抽象化の層があることがわかります.一番下の層にはハードウェア,これにはプロセッサ,RAM,ハードディスク,加えて様々な,複雑な外見の回路基板,ケーブル,プラグなどが含まれます.

コンピュータを起動すると,オペレーティングシステム(基本ソフト)が動きます.オペレーティングシステムはハードウェアとやりとりを(通追う特別なドライバソフトウェアを介して)行う役割を担います.コンピュータの起動が完了すれば,ブラウザなどのプログラムを動かすことができるようになります.ブラウザは,実際にはハードウェアとのやりとりを直接ではなく,常にオペレーティングシステムを介して行います.

最後にシステムの一番上の層,ユーザであるあなた自身です.ユーザはプログラムを使用しますが,(理想的には)ハードウェアはいわずもがな,ドライバソフトウェアのようなオペレーティングシステムのややこしい部分ともやりとりする必要は全くありません.このようにして,ややこしい部分に煩わされる必要なくコンピュータを使用することができるのです.

SE-computer-layers.png

このようなシステムを,階層化システムと呼びます.いくつでも必要なだけ階層を設けることができますが,各階層はその1段階下の階層とのみやりとりを行えます.オペレーティングシステムはハードウェアに直接アクセスできますが,コンピュータ上で動くプログラムはそれができません.ユーザであるあなたはプログラムを使用できますが,幸いにもハードウェアや,ドライバのようなOSのもっと複雑な部分にアクセスする必要は全くありません.各階層が自分の直下の階層についてのみ知っていればよく,他のどの階層も気にする必要がないことで,システムの複雑度を減らすことになります.

システム内の各階層は,その上の階層が自身とやりとりができるようなインタフェースを設ける必要があります.例えば,演算装置はオペレーティングシステムに対し,一連の操作命令セットを提供します.オペレーティングシステムはプログラムに対し,ハードディスクドライブ上でファイルを作成/削除するコマンドを提供します.プログラムはユーザであるあなたに,プログラムと相互にやりとりができるようなボタンとコマンドを提供します.

ある階層は,下の階層の内部動作については何も関知しません.どのようにその階層のインタフェースを扱うかを知る必要があるだけです.このようにして,下の階層の複雑さは完全に隠される,言い換えれば抽象化されるわけです.各階層は高度に抽象化されます.

各階層が複雑性を隠していることで,階層が増えても管理しやすさが維持されます.階層を持つことによるもう一つの利点は,他の階層に影響を与えることなくある階層を入れ替えることができる - もちろんインタフェース部分を変更しない限り - ということです.例えば,ブラウザの内部コードが変化しても,変化前と変わらぬ見た目と動きをしている限りはその事実に気づくことはないでしょう.もちろん,ブラウザが動作を停止したり,突然新しいボタンが現れたりすれば,何か変化が起こったと気づきますが.

同じ"階層化"アプローチを,単一のプログラム内でも使うことができます.例えば,Webサイトはよく,データベース層,論理層,プレゼンテーション層の3つの階層からなる,いわゆる3階層(three-tier)システムでデザインされています.
データベース層は,Webサイトが必要とするデータをもつデータベースで構成されます.たとえばFacebookは,ユーザに関する情報を保持する巨大なデータベースを持っています.各ユーザについて,友達は誰か,ウォールに何をポストしたか,どんな写真を貼り付けたか,などなどの情報を格納しています.
論理層は,データベースから取得したデータを処理します.例えばFacebookの論理層では,ユーザの"Home"フィードにどの投稿を表示するか決定したり,新しい友達として誰を推薦するか,などの処理を行います.
最後に,プレゼンテーション層は論理層から情報を受け取り表示します.プレゼンテーション層は取得した情報にさらに処理を加えることはなく,閲覧するHTMLページを作成するだけです.

SE-facebook-system.png

Curiosity: Reuse - Kangaroos and Helicopters

さらに知ろう: 再利用 - カンガルーとヘリコプター

ソフトウェア作成は非常に難しく時間のかかるものなので,良くある手法は,既存のソフトウェアを再利用するというものです.当然ながら,これをソフトウェア再利用と呼びます.理論的にはいいアイデアなのですが(既にあるものをなぜ再作成するのか?),実際に導入するのは難しいことがわかります.一つの理由は,既存のソフトウェアは巨大で複雑でもあるからです.ソフトウェアを再利用するときは,既存ソフトウェアの全ての機能ではなく,ごく一部だけ使いたいということが常です.

ソフトウェア再利用の問題を端的に表す面白い話の一つが,ヘリコプターとカンガルーの再利用です(あいにく完全に正確な喩えというわけではないですが.詳しくはこちら→ http://www.snopes.com/humor/nonsense/kangaroo.asp).オーストラリア空軍は,パイロット訓練用の新しいヘリコプターのシミュレータを開発していました.開発者らはそのシミュレータをできるだけ本物に近づけようとして,そのためたくさんのカンガルーをシミュレータに内蔵することを決定しました.時間の節約のため,歩兵を内蔵する別のシミュレータからコードを再利用し,兵士のアイコンをカンガルーに変える変更だけ施しました.

プログラム完成後,何人かのパイロットにデモを行いました.パイロットの一人が,ヘリコプターをカンガルーの群れに近づけて何が起こるか見てみようとしました.ヘリコプターが近づくと,カンガルーは散り散りに逃げました(ここまではOK)がしかし,パイロットが驚いたことに,次にカンガルーたちは銃やミサイルランチャーを取り出し,ヘリコプターに撃ってきたのです.プログラマーは,元のシミュレータからコードの一部を取り除くことを忘れてしまっていたようです.

16.3.1. 課題プロジェクト: ソフトウェアの設計

先に述べた解析プロジェクトの中で見つけた要求事項に戻りましょう.今回のプロジェクトでは,ソフトウェアの設計方法について注目していきます.

まず最初に,今作成したいソフトウェアがどれだけ小さい部分に分割できるか考えてみましょう.データベースだったり,ユーザインタフェースだったり,あるいはWebサイトだったりするでしょうか? 例えば,あなたはロボットを制御するソフトウェアを作成しているとしましょう.そのロボットはセンサを使って,目標物までの地面の黒い線を辿っていく必要があります.そのロボット用のソフトウェアには,何を「見て」いるかの情報を得るためセンサーとやりとりする部分が必要です.またその情報を,データを解析し次にどこへ動くか決定する部分に渡さなければなりません.最後に,望む方向にロボットを動かすためタイヤとやりとりするソフトウェア部も必要です.

ソフトウェアを,出来るだけ多くの部分に分割してみましょう(思い出してみよう,小さい構成要素にすれば作成も簡単になる!),ただあまりやりすぎないように.各部分が適切な処理を行い,かつシステムの他の部分から比較的独立するようにしましょう.

区別した各部分について,それが何をするものなのか簡単に記述しましょう.それから各部分がどのようにやりとりを行うかを考えましょう.各部分について,他のどの部分と直接やりとりする必要があるか自問してください.図を使うと関係性がイメージしやすくなるかもしれませんね.

16.4. テスト: 正しいものを作ったか/動く? Testing: Did we Build the Right Thing / Does it Work?

これまでソフトウェアが何をすべきか確定し(分析),内部構造のデザインを行い(設計),そのデザインに従ってプログラミングがなされました.では,当然ながら,正しく動くかどうか確認するテストをしなければなりません.

テストはソフトウェアの開発において非常に重要な要素です.たくさんのバグが残ったままソフトウェアを顧客に正式に提供することは不可能です(まあ,できはしますが,顧客はあまり嬉しくは思わないでしょう).ソフトウェアのバグによる影響は非常に小さくも,また非常に大きくもなりうることを覚えておきましょう.深刻でない場合であっても,プログラムが使いにくくなったりコンピュータが固まったりするかもしれません.一方で,何百万ドルというコストがかかったり,人間の生活を危険にさらすことすらあり得ます.もっとテストをしておけば,ARIANE 5の失敗を防ぐことも,3人の患者を死なせてしまうTheracのバグを発見することもできたかもしれません.

残念なことに,ソフトウェアの規模と複雑さが要因となって,テストも非常に難しい作業です.一つのソフトウェアを読んで理解するのに何年も必要としていたら,それを完全にテストするのにどれだけかかるか,想像してみてください!

ソフトウェアをテストするとき,大量の異なる入力を試して,どんな出力もしくは振る舞いをソフトウェアが行うのかという観察をしてみます.もし出力に誤りがあれば,バグを見つけたことになります.

もっと知ろう: バグと「ガ」

SE-harvard-mark-II.jpg

1947年,MarkIIと呼ばれるコンピュータで仕事していた技術者が,コンピュータのエラーを調べていたところ,コンピュータの内部でひっかかっていた蛾によって引き起こされていたことを発見しました.それ以来,「バグ」はコンピュータのエラーを指す言葉として使われています.もちろん今日はこの言葉を,コンピュータ内でひっかかった実際の昆虫というよりは,プログラム内のエラーを指すものとして使っています.

(訳注:実際のところ,このMark IIのエピソードは「'バグ'が実際に発見された初めてのケースだ!」と,当時の技術者がジョークを含めて報告書に記録したものであり,つまり1947年の時点で既にコンピュータのエラーを「バグ」と呼んでいた証拠と言われています.)

テストにおける問題は,テストでわかるのはエラーの存在であって,エラーの非存在ではないということ!もしプログラムから正しくない出力結果が得られれば,バグを発見したことがわかります.でももし正しい出力が得られたら,本当にそのプログラムは正しいと結論づけられるか?そうではありません.この特定の場合は動作しているかもしれませんが,他の状況で動作すると仮定することはできません.たとえ徹底的にプログラムのテストを行ったとしても,これが正しいと100%確証を持つことは,決してできません.例えばGoogleについて,検索ができる全てのものについてテストすると考えてみてください! でもたとえ全てをテストすることはできなくても,可能な限りたくさんの異なるテストケースを試して,少なくともバグの可能性を減少させることは期待できそうです.

テストも設計作業と同様,ソフトウェア全体を一度に扱うのはおそらく難しいので,より小さい部品単位で見ていき,一度に一つずつテストしていくことにします.このアプローチを単体テスト(unit testing)と呼びます.単体テストは通常,作成しているプログラムの上でテスト作業を行う,別個のプログラムによって行われます.こうすることで好きなだけの頻度で - 1日単位とか,プログラムに何か変更がある毎にという頻度でも - テストを実行できます.単体テストプログラムを実際のプログラムより前に作成することも,珍しいことではありません.全体プログラムの代わりに各プログラムに単体テストプログラムを作るのは無駄な作業のように思えますが,システムが変更するたびにいつでも注意深くテストできているということは,最終製品の信頼性を非常に高めることになり,システム全体でのバグを見つけるための多くの時間を節約できます.各単体(unit)が正しく動くことへの一定の保証が得られているわけですから.

一旦全ての単体にわたってテストできれば,システム全体についてテストを行い,全ての異なる部品が同時に正しく動くかどうかをチェックすることができます.これを結合テスト(integration testing)と言います.いくつかのテストは自動化されていますが,一方でソフトウェアエンジニアが手作業で行う必要があるテストもあります.

もしあなたにテストが必要なソフトウェアの一部を渡すとして,どのようにテストを始めますか?どんなテスト入力を使用しますか?どれくらい異なるテストケースが必要になりますか?全てが正しく動くと合理的に革新できるのは,いつですか?

ここで採ることができる基本的な手法として2つ,それぞれブラックボックステスト,ホワイトボックステストと呼ばれる手法があります.ブラックボックステストでは,単純にプログラムをブラックボックスと見立て,どのような構造か,内部でどのように動作するかを知らないと仮定します.テストの入力を行い,出力を得て,プログラムが期待通りの動きをしているかを確認します.

でも,どのように有用なテスト入力を選択しましょう?通常,非常に多くの異なる選択肢が存在します.例えば,整数を受け取ってその次の数,つまりより大きな次の数字(3を与えると4を得る,-10を与えると-9を得る,など)を出力するプログラムを,テストするように言われたとします.全ての数字をプログラムに試すことはできないので,さてどの数字でトライしますか?

あなたはこう評価します.多くの数字は似ているのだから,そのうち1つでプログラムが動けば,他の似た数字でも正しく動くと仮定して大丈夫だろう.たとえば,3という数字を与えてプログラムが期待通り動作すれば,4,5,6やそこらの数字も試すのはおそらく時間の無駄だろう.いずれも3と非常に似た数字なのだから.

これは,等価クラス(equivalence classes)という考え方です.いくつかの入力が似たものであれば,そのうち一つか二つ取り出してそれでソフトウェアが正しく動作するのであれば,他全ての類似した入力に対しても動作すると仮定することができる,というものです.上記のプログラムのケースで言えば,2つの大きな等価クラス,正の数と負の数があります.おそらく0も,正の数でも負の数でもないことから,それ自体が一つの等価クラスと考えられるでしょう.

テストにあたっては,各等価クラスからいくつかの入力を取り出します.等価クラスの境界にある入力が,通常特に興味深い対象となります.ここでは,-1(0を出力するはず),0(1を出力するはず),そして1(2を出力するはず)をテストすべきです.また,たとえば-48や57など,境界上にない他の負の数や正の数も試してみるべきでしょう.最後に,非常に大きな数をいくつか試すのも興味深そうなので,-2,338,678 と 10,462,873 を取り上げるのもよさそうです.ここまでで7つの異なる数しかテストしていませんが,これらの入力でソフトウェアの興味深い振る舞いのほとんどをおそらくカバーできており,大半のバグを取り除くことができるはずです.

もちろん,いくつか不正な入力,たとえば "やあ"(単語),"1,234"(カンマ区切りの数値),"1.234"(小数点込みの数値)について試したいでしょう.しばしば,こういったテストケースは,プログラマーが不正な入力値を与えるかもしれないと考慮してなかったために,プログラムが非常に奇妙な動き方をしたり,停止してしまうことすらありえます.特に人間の利用者は,例えばそのプログラムの使い方を誤解している場合,あらゆるヘンテコな入力を与えることがありうることを覚えておきましょう.不正な入力値の場合,その入力は正しくないとプログラムがユーザに伝えるようにしたいと考えるでしょう.何せプログラムをクラッシュさせたくないですから!

ブラックボックステストは容易に実行できますが,常に十分というわけではありません.もしプログラムの内部構造を知らなければ,異なる等価クラスを見つけるのが難しい場合があるためです.ホワイトボックステストをする時は,テストしようとするコードを閲覧し,出来るだけ多くの異なる行を実行するようテストケースを考えます.少なくとも各行を一回実行すれば,多数のバグを発見できるはずです.このアプローチをコードカバレッジもしくはコード網羅率(code coverage)と呼び,コード内の各行が少なくとも1回実行されるように100%のカバー率を目指します.実際には,100%のコード網羅率でも必ずしも全てのバグを見つけるわけではありません,というのも1行のコードも,入力やプログラム内の変数の値によって異なる動きをする場合があるためです.とはいえ,これは出発点としては非常によいです.

単体テストはバグ発見に大変役立ちます.自分達が想定した通りにプログラムが動くかどうかを見つけ出す助けとなります.テストにおけるもう一つの重要な論点は,ソフトウェアが顧客の求める振る舞いになっているか(正しいものを構築したか)?ということです.ユーザ受け入れテスト(acceptance testing)とは,あなたのプログラムを顧客に見せて,顧客の好むものと好まないもののフィードバックを得ることを意味します.プロジェクトの分析段階で行ったあらゆる失敗は,おそらく受け入れテストの際にも現れてくるでしょう.インタビューの段階で顧客への誤解をしていたら,単体テストはパスする(つまり,自分達がこうあるべきという動きをする)かもしれませんが,幸せでない顧客を抱えることになるかもしれません.

ステークホルダーが異なると,たとえば技術的なスキルの観点で全く異なっており,ソフトウェアに対して相反する要求を出すことすらありえます.そのため,あるステークホルダーから肯定的な反応を得つつ,別のステークホルダーから否定的なフィードバックを得ることもあり得るのです.

16.4.1. 課題プロジェクト:ユーザ受け入れテスト

このプロジェクトでは、Windowsのデスクトップガジェット、Apple(Mac OS X)のDashboardウィジェットのような小さなプログラムを選びましょう(例えば、 http://www.thoosje.com/desktop-gadgets-gallery.html では、Windowsガジェットの豊富なラインナップが揃っています)。特に興味があるものや役立つものを見つけたら、いくつか選んでみましょう。実際に試す前に、プログラムの概要を読んでそれが何をするものなのか確認しましょう。
(訳注:現在、WIndowsガジェットは脆弱性の問題などから廃止されています。

次にこのソフトウェアのステークホルダーを考えましょう.そのソフトウェアを誰が,なぜ使うのか?(解析プロジェクトの時のように)彼らの背景情報と主な要求を簡単に書き出してみましょう.どの要求が彼らにとって最も重要で,それはなぜかに注目しましょう.

さて次に進んで,プログラムをインストールしていじってみます.自分が先ほど挙げたステークホルダーであると想定してみましょう.自身をそのステークホルダーの立場に立って考えてみましょう.このプログラムに対してどのように思うだろうか?自分の要求を満たしているか?どんな重要な機能が足りないのか?何か特定の問題やバグがプログラムにあるかどうか探してみましょう. (ヒント: プログラムに時々想定外の入力,例えば数字を期待する所で文字を与えてみることで,興味深い振る舞いが起きることがあります)

見つけた内容について、簡単な受入テストレポートをまとめましょう。先に記述した要求事項に立ち戻って、どの要求が満たされた(あるいは一部だけ満たされた)か、また満たされなかったかを確認しましょう。全体としてそのステークホルダーはソフトウェアに満足すると思いますか?そのソフトウェアを使いたいだろうと思いますか?ソフトウェア開発者に、次にどんな機能を実装するよう伝えますか?

16.5. ソフトウェアプロセス

本章ではこれまで、ソフトウェア開発の異なるフェーズ(分析、デザイン、テスト)についてそれぞれ学んできました。でもどのようにこれらのフェーズを結合するのでしょうか?プロジェクト中のどんな時に、何の活動をするのでしょう?これが、ソフトウェアプロセスのテーマとなります。

明らかに答えられるのは,まず分析して何を作りたいのか明らかにする,次にソフトウェア構成を設計する,全体を実装する,そして最後にソフトウェアをテストする,というものでしょう.これが一番単純なソフトウェアプロセス,ウォーターフォールプロセスです.

SE-waterfall-diagram.png

ウォーターフォールプロセスは,別業種の工学分野から持ってきたものです.橋を一つ作りたい場合も,分析,設計,実装,テストという同じフェーズを辿ります.具体的には,どんな橋が必要なのか(長さは?幅は?どれだけの荷重を支えられるようにするか?)を決め,橋を設計し,建設を行い,最後に一般に供する前にテストする.少なくとも橋の建設は,何十年もこのような形で行われ,非常にうまくいってきました.

このプロセスをウォーターフォールプロセスと呼ぶ理由は,プロジェクトのあるフェーズから次のフェーズへ一度"ジャンプ"すると,以前の段階へは戻れないことにあります.実際には,以前のフェーズに起因する問題を修正するため少し後戻りすることは許されていますが,そのような後戻りは通常例外扱いです.プロジェクトのテスト段階で突然要求仕様に問題を発見したとしても,そのフェーズに戻って要求仕様を書き換えることは,明らかに許されないでしょう.

SE-waterfall-150.png

  1. 「ボス,次のステージに移行する準備ができたようです」「よし!」
  2. (実装ステージへ)ジャンプ!
  3. [しかし後になって...]「ボス,要求仕様に一つ問題がありました」「心配ない!上のステージまで戻って,それから・・・」
  4. 「おい待て,あのはしごを持ってきてたのは誰だ?」

ウォーターフォールプロセスの利点は,非常に単純で把握しやすいということです.プロジェクトのどのポイントでも,自分が今プロジェクトのどの段階にいるかがとても明確です.これは作業計画の際にも助けになります.もし今テストの段階にいるなら,プロジェクトが相当進んでいて,もうすぐ完了するだろうということがわかります.こういった理由からウォーターフォールプロセスは,プロジェクトが今どこにいるか,どこに進んでいるかを管理下に置きたいと考える管理者に,非常に人気があります.

Curiosity: Hofstadter’s law

もっと知ろう: ホフスタッターの法則

Your manager and customer will probably frequently ask you how much longer the project is going to take and when you will finally have the finished program. Unfortunately, it’s really difficult to know how much longer a project is going to take. According to Hofstadter’s law, “It always takes longer than you expect, even when you take into account Hofstadter’s Law.”

おそらくあなたの管理者と顧客は,プロジェクトがどれだけの期間かかるか,最終的にいつ完成形のプログラムが得られるのか,頻繁に訪ねることと思います.残念なことに,プロジェクトの期間がどれだけかを知ることは非常に難しいのです.ホフスタッターの法則によるとこうあります.

「それは常に想定よりも長くかかるものだ.たとえホフスタッターの法則を考慮に入れたとしても.」

非常に洗練され単純であることから,ウォーターフォールプロセスは未だ多くのソフトウェア工学の教科書に記載され,産業界でも広く使われています.ただ一つ問題点を挙げるとすれば,ウォーターフォールプロセスは,多くのソフトウェア開発プロジェクトにおいてまず機能しないということです.

So why does the waterfall process not work for software when it clearly works very well for other engineering products like bridges (after all, most bridges seem to hold up pretty well...)? First of all, we need to remember that software is very different from bridges. It is far more complex. Understanding the plans for a single bridge and how it works might be possible for one person but the same is not true for software. We cannot easily look at software as a whole (other than the code) to see its structure. It is not physical and thus does not follow the laws of physics. Since software is so different from other engineering products, there really is no reason why the same process should necessarily work for both.

To understand why the waterfall process doesn’t work, think back to our section about analysis and remember how hard it is to find the right requirements for software. Even if you manage to communicate with the customers and resolve conflicts between the stakeholders, the requirements could still change while you’re developing the software. Therefore, it is very unlikely that you will get the complete and correct requirements for the software at the start of your project.

If you make mistakes during the analysis phase, most of them are usually found in the testing stage of the project, particularly when you show the customer your software during acceptance testing. At this point, the waterfall process doesn’t allow you to go back and fix the problems you find. Similarly, you can’t change the requirements halfway through the process. Once the analysis phase of the project is finished, the waterfall process “freezes” the requirements. In the end of your project, you will end up with software that hopefully fulfills those requirements, but it is unlikely that those will be the correct requirements. You end up having to tell the customer that they got what they asked for, not what they needed. If they’ve hired you, they’ll be annoyed; it it’s software that you’re selling (such as a smartphone app), people just won’t bother buying it.

You can also get things wrong at other points in the project. For example, you might realise while you’re writing the code that the design you came up with doesn’t really work. But the waterfall process tells you that you have to stick with it anyway and make it work somehow.

SE-tree-swing-cartoon.png

顧客の表現プロジェクトリーダーの理解アナリストのデザインプログラマーの書いたものビジネスコンサルタントの表現
プロジェクトの記録実装された操作顧客に請求されたものサポートの結果顧客が本当に欲しかったもの

Design by Paragon Innovations and drawn by Project Cartoon

So if the waterfall process doesn’t work, what can we do instead? Most modern software development processes are based on the concept of iteration. We do a bit of analysis, followed by some design, some programming and some testing. (We call this one iteration.) This gives us a rather rough prototype of what the system will look like. We can play around with the prototype, show it to customers and see what works and what doesn’t. Then, we do the whole thing again. We refine our requirements and do some more design, programming and testing to make our prototype better (another iteration). Over time, the prototype grows into the final system, getting closer and closer to what we want.

se-iterative-development.png

The advantage with this approach is that if you make a mistake, you will find it soon (probably when you show the prototype to the customer the next time) and have the opportunity to fix it. The same is true if requirements change suddenly; you are flexible and can respond to changes quickly. You also get a lot of feedback from the customers as they slowly figures out what they need.

There are a number of different software processes that use iteration (we call them iterative processes); a famous one is the spiral model. Although the details of the different processes vary, they all use the same iteration structure and tend to work very well for software.

Apart from the question of what we do at what point of the project, another interesting question addressed by software processes is how much time we should spend on the different project phases. You might think that the biggest part of a software project is programming, but in a typical project, programming usually takes up only about 20% of the total time! 40% is spent on analysis and design and another 40% on testing. This shows that software engineering is so much more than programming.

Once you’ve finished developing your program and given it to the customer, the main part of the software project is over. Still, it’s important that you don’t just stop working on it. The next part of the project, which can often go on for years, is called maintenance. During this phase you fix bugs, provide customer support and maybe add new features that customers need.

Curiosity: Brooks’s law さらに知ろう: ブルックスの法則

Imagine that your project is running late and your customer is getting impatient. Your first instinct might be to ask some of your friends if they can help out so that you have more people working on the project. Brooks’s law, however, suggests that that is exactly the wrong thing to do!

あなたのプロジェクトが遅れていて、顧客がイライラしはじめてる状況を想定しましょう。あなたが最初に思いつくのは、 友達に手伝いをお願いして、プロジェクトに携わる人を増やそうとすることかもしれませんね。でもブルックスの法則は、それがまさに悪い手段であると示唆しています。
>

Brooks’s law states that “adding manpower to a late software project makes it later.” This might seem counterintuitive at first because you would assume that more people would get more work done. However, the overhead of getting new people started on the project (getting them to understand what you are trying to build, your design, the existing code, and so on) and of managing and coordinating the larger development team actually makes things slower rather than faster in the short term.

ブルックスの法則は、「遅れているソフトウェアプロジェクトに人力を追加すると、プロジェクトはより遅れる」。より多くの人がいればより多くの仕事がこなせると想定するのが普通ですから、一見直感にそぐわないように思うかもしれません。しかし、新しい人達にプロジェクトを始めさせ(何を構築しようとしているか、あなたの設計図、現在のコード、などなどを彼らに理解させる)、より大きくなった開発チームを管理調整するというコストは、短期的に作業を早めるのではなく、むしろ実質的に遅くする要因になってしまいます。

16.5.1. Activity: Fun with the Waterfall Process

The waterfall process is simple and commonly used but doesn’t really work in practice. In this activity, you’ll get to see why. First, you will create a design which you then pass on to another group. They have to implement your design exactly and are not allowed to make any changes, even if it doesn’t work!

You need a deck of cards and at least 6 people. Start by dividing up into groups of about 3-4 people. You need to have at least 2 groups. Each group should grab two chairs and put them about 30cm apart. The challenge is to build a bridge between the two chairs using only the deck of cards!

Before you get to build an actual bridge, you need to think about how you are going to make a bridge out of cards. Discuss with you team members how you think this could work and write up a short description of your idea. Include a diagram to make your description understandable for others.

Now exchange your design with another group. Use the deck of cards to try to build your bridge to the exact specification of the other group. You may not alter their design in any way (you are following the waterfall process here!). As frustrating as this can be (especially if you know how to fix the design), if it doesn’t work, it doesn’t work!

If you managed to build the bridge, congratulations to you and the group that managed to write up such a good specification! If you didn’t, you now have a chance to talk to the other group and give them feedback about the design. Tell them about what problems you had and what worked or didn’t work. The other group will tell you about the problems they had with your design!

Now, take your design back and improve it, using what you just learnt about building bridges out of cards and what the other group told you. You can experiment with cards as you go, and keep changing the design as you learn about what works and what doesn’t (this is an agile approach). Keep iterating (developing ideas) until you get something that works.

Which of these two approaches worked best — designing everything first, or doing it in the agile way?

16.5.2. Activity: A Navigation Language

In this activity, you will develop a language for navigating around your school. Imagine that you need to describe to your friend how to get to a particular classroom. This language will help you give a precise description that your friend can easily follow.

First, figure out what your language has to do (i.e. find the requirements). Will your language be for the entire school or only a small part? How exact will the descriptions be? How long will the descriptions be? How easy will they be to follow for someone who does / doesn’t know your language? How easy will it be to learn? …

Now, go ahead and design the language. Come up with different commands (e.g. turn left, go forward 10, …). Make sure you have all the commands you need to describe how to get from one place in your school to any other!

Finally, test the language using another student. Don’t tell them where they’re going, just give them instructions and see if they follow them correctly. Try out different cases until you are sure that your language works and that you have all the commands that you need. If you find any problems, go back and fix them and try again!

Note down how much time each of the different phases of the project take you. When you have finished, discuss how much time you spent on each phase and compare with other students. Which phase was the hardest? Which took the longest? Do you think you had more time for some of the phases? What problems did you encounter? What would you do differently next time around?

16.5.3. Activity: Block Building (Precise Communication)

Communicating clearly with other software engineers and customers is essential for software engineers. In this activity, you get to practice communicating as precisely as possible!

Divide up into pairs, with one creator and one builder in each pair. Each person needs a set of at least 10 coloured building blocks (e.g. lego blocks). Make sure that each pair has a matching set of blocks or this activity won’t work!

The two people in each pair should not be able to see each other but need to be able to hear each other to communicate. Put up a screen between the people in each pair or make them face in opposite directions. Now, the creator builds something with their blocks. The more creative you are the more interesting this activity will be!

When the creator has finished building, it’s the builders turn. His or her aim is to build an exact replica of the creator’s structure (but obviously without knowing what it looks like). The creator should describe exactly what they need to do with the blocks. For example, the creator could say “Put the small red block on the big blue block” or “Stand two long blue blocks up vertically with a one block spacing between them, and then balance a red block on top of them”. But the creator should not describe the building as a whole (“Make a doorframe.”).

When the builder thinks they are done, compare what you built! How precise was your communication? Which parts were difficult to describe for the creator / unclear for the builder? Switch roles so that you get to experience both sides!

16.6. Agile software development

Agile software development has become popular over the last 10 years; the two most famous agile processes are called XP and Scrum. Agile software development is all about being extremely flexible and adaptive to change. Most other software processes try to manage and control changes to requirements during the process; agile processes accept and expect change.

Agile processes work similarly to iterative processes in that they do a number of iterations of analysis, design, implementation and testing. However, these iterations are extremely short, each usually lasting only about 2 weeks.

In many other processes, documentation is important. We document the requirements so that we can look back at them; we document our design so that we can refer back to it when we program the system. Agile software processes expect things to change all the time. Therefore, they do very little planning and documentation because documenting things that will change anyway is a bit of a waste of time.

Agile processes include lots of interesting principles that are quite different from standard software development. We look at the most interesting ones here. If you want to find out more, have a look at Agile Academy on Youtube which has lots of videos about interesting agile practices! There’s also another video here which explains the differences between agile software development and the waterfall process.

Here are some general principles used for agile programming:

Pair-programming

Programming is done in pairs with one person coding while the other person watches and looks for bugs and special cases that the other might have missed. It’s simply about catching small errors before they become bugs. After all, 4 eyes see more than 2.

You might think that pair-programming is not very efficient and that it would be more productive to have programmers working separately; that way, they can write more code more quickly, right? Pair-programming is about reducing errors. Testing, finding and fixing bugs is hard; trying not to create them in the first place is easier. As a result, pair-programming has actually been shown to be more efficient than everyone programming by themselves!

YAGNI

YAGNI stands for “You ain’t gonna need it” and tells developers to keep things simple and only design and implement the things that you know you are really going to need. It can be tempting to think that in the future you might need feature x and so you may as well already create it now. But remember that requirements are likely to change so chances are that you won’t need it after all.

SE-xkcd-the-general-problem.png

  1. 「塩を取ってくれる?」
  2. ・・・
  3. 「だからs」
    「わかってるよ!今あらゆる香辛料を渡せるシステム作ってるから」
    「もう20分も経ってるよ!」
    「長い目で見れば時間の節約になるんだよ!」

You ain’t gonna need it!

Constant testing

Agile processes take testing very seriously. They usually rely on having lots of automated unit tests that are run at least once a day. That way, if a change is made (and this happens often), we can easily check if this change has introduced an unexpected bug.

Refactoring

There are many different ways to design and program a system. YAGNI tells you to start by doing the simplest thing that’s possible. As the project develops, you might have to change the original, simple design. This is called refactoring.

Refactoring means to change your design or implementation without changing the program’s behaviour. After a refactoring, the program will work exactly the same, but will be better structured in some way. Unit tests really come in handy here because you can use them to check that the code works the same way before and after the refactoring.

Refactoring only works on software because it is “soft” and flexible. The same concept does not really work for physical engineering products. Imagine that when building a bridge, for example, you started off by doing the simplest possible thing (putting a plank over the river) and then continually refactored the bridge to get the final product.

Courage

”Courage” might seem like an odd concept in the context of software development. In agile processes, things change all the time and therefore programmers need to have the courage to make changes to the code as needed, fix the problems that need to be fixed, correct the design where needed, throw away code that doesn’t work etc. This might not seem like a big deal, but it can actually be quite scary to change code, particularly if the code is complicated or has been written by a different person. Unit tests really help by giving you courage: you’ll feel more confident to change the code if you have tests that you can run to check your work later.

Test-driven development

In standard software development, we first write some code and then test it. This makes sense: we need the code before we can test it, right? Test-driven development tells you to do the exact opposite!

Before you write a piece of code, you should write a test for the code that you are about to write. This forces you to think about exactly what you’re trying to do and what special cases there are. Of course, if you try to run the test, it will fail (since the functionality it is testing does not yet exist). When you have a failing test, you can then write code to make the test pass.

Programmer welfare

Software developers should not work more than 40 hours per week. If they do overtime one week they should not do more overtime the following week. This helps keep software developers happy and makes sure they don’t get overworked.

Customer involvement

A customer representative should be part of the developing team (ideally spending full-time with the team), on hand to answer questions or give feedback at all times. This is important to be able to quickly change the requirements or direction of the project. If you have to wait 2 weeks until you can get feedback from your customer, you will not be able to adapt to change very quickly!

Although having a customer on the development team is a great idea in theory, it is quite hard to achieve in practice. Most customers simply want to tell you their requirements, pay you and then get the software delivered 5 months later. It’s rare to find a customer who is willing and has the time to be more involved in the project.

Curiosity: Christopher Alexander

So far, we’ve mainly compared software development to engineering and building bridges, but you might have noticed that it’s also pretty similar to architecture. In fact, software development (in particular agile software development) has borrowed a lot of concepts from architecture. An architect called Christopher Alexander, for example, suggested involving customers in the design process. Sound familiar? Several other suggestions from Christopher Alexander were also picked up by the agile development community and as a result his thinking about architecture has shaped how we think about software development. This is despite the fact that Christopher Alexander knew nothing about software. He was apparently very surprised when he found out how well known he is among software developers!

16.6.1. Project: Software processes

This project will provide insight into a real software engineering process, but you’ll need to find a software engineer who is prepared to be interviewed about their work. It will be ideal if the person works in a medium to large size company, and they need to be part of a software engineering team (i.e. not a lone programmer).

The project revolves around interviewing the person about the process they went through for some software development they did recently. They may be reluctant to talk about company processes, in which case it may help to assure them that you will keep their information confidential (your project should only be viewed by you and those involved in supervising and marking it; you should state its confidential nature clearly at the start so that it doesn’t later get used as an exemplar).

You need to do substantial preparation for the interview. Find out about the kind of software that the company makes. Read up about software engineering (in this chapter) so that you know the main terminology and techniques.

Now prepare a list of questions for the interviewee. These should find out what kind of software development processes they use, what aspects your interviewee works on, and what the good and bad points are of the process, asking for examples to illustrate this.

You should take extensive notes during the interview (and record it if the person doesn’t mind).

You then need to write up what you have learned, describing the process, discussing the techniques used, illustrating it with examples, and evaluating how well the process works.

16.7. The whole story!

In this chapter, we’ve tried to give you an introduction to the challenges of creating software and some techniques that software engineers use to overcome them. We’ve really only scratched the surface of software analysis, design, testing and software processes; there are entire books about each of these areas!

It can be difficult to understand the importance of some of the problems and techniques we have described here if you have never worked on a larger software project yourself. Some may seem blindingly obvious to you, others may seem irrelevant. When you work on your first large project, come back to this chapter and hopefully you’ll recognise some of the problems we have described here!

16.8. Further reading

16.8.1. Useful Links

  • Wikipedia - Software engineering
  • CS4FN - Software engineering
  • Teach ICT - Systems Life Cycle
  • Wikipedia - Software crisis
  • IEEE - Why software fails
  • Wikipedia - Software design
  • Wikipedia - Abstraction
  • Wikipedia - Software testing
  • Wikipedia - Software development process
  • Wikipedia - Waterfall model
  • Wikipedia - Iterative and incremental development
  • Wikipedia - Agile software development
  • Wikipedia - Test driven development

Computer Science Field Guide is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.

Produced by Tim Bell, Jack Morgan, and many others based at the University of Canterbury, New Zealand.

powered by Quick Homepage Maker 5.1
based on PukiWiki 1.4.7 License is GPL. QHM

最新の更新 RSS  Valid XHTML 1.0 Transitional