抽象化

問題を解決するには、まず問題を把握しなくてはなりません。 しかし一歩ずつ進めるうえでの最初の一歩から悩むこともあります。 たくさんの要素を同時に考えないといけなかったり、多くの事柄が複雑に関連していて、小さな部分に切り出すのが難しいことがあります。 分割統治するための分割が、難しいわけです。 いちどに把握して検討できるものの数には限度があって、それ以上になるとまとめて考えることができなくなり、見落としや考慮漏れが発生します。

例として、週末にパーティーを開くために買い物をすることになったと考えてみましょう。 ほしいものを考えながら買い物リストを作っていたら、ものすごく長くなってしまいました。 全部で100個はありそうです。 近所のスーパーで買えるものもあれば、駅前の商店街で買いたいもの、デパートまで行かないといけないものもあります。 これを整理しないで買い物に出かけたら、スーパーと商店街を何回も往復したり、せっかくデパートまで行っても買い忘れをしたりしそうです。

そこで、買い物リストを分割することにします。 どこで買うかによって、リストを3つに分けます。 これで、スーパーの買い物リスト、商店街の買い物リスト、デパートの買い物リストの3つのリストができました。 これで買い物を無駄なく、忘れ物もなくできそうです。

いまの例では、100個以上の項目がある「買い物リスト」を、「どこで買うか」という観点で整理して3つの買い物リストにしました。 整理する前の問題は「リストを見ながらどこで買うか考えながら買い物をして回る」というもので、移動と買い物を同時に考える必要がありました。 100個以上も頭の中だけで整理していたら、移動の無駄が起きたり、買い忘れが起きてしまいます。 整理して3つの買い物リストに分けたおかげで、今度は問題も分割できました。 まず「買い物する場所に行く」という問題、そして「その場所で買い物をする」という問題の2つです。

「買い物リスト」を「どこで買うか」という観点で見直す、これが抽象化の一例です。 大きく複雑なひとかたまりの問題を、観点によって整理し、簡単に解けるいくつかの問題に分割するのです。 細かい点を見ないようにしたり、差異を無視して同じものと扱ったり、似た点があるものをグループ化したりするのが、抽象化です。

「抽象的」は「具体的」の反対の意味です。 抽象化とは、具体的の反対にすることなので、必ず情報が失われます。 このことから「抽象」は「捨象」とも言います。 情報を捨てるという意味です。 いま着目したい、重要視したいところだけを取り出し、それ以外の情報は無視して考える。 それが抽象化です。

例題:
  • 最寄り駅から家までの地図を書いてください。書き終わったら地図を観察して、どんな情報が載っているか、どんな情報は捨てたのか書き出してください。なぜその情報を選んだのか、考えてみてください。
  • 会社で泊まりがけの合宿をすることになり、宿泊場所の候補を探してほしいと頼まれてしまいました。いくつかの宿泊施設を選んで、それぞれの特徴や情報を整理して一覧表にしないといけません。どういう情報を載せますか?
    • 家族や仲間との遊びの旅行だったら、載せる情報は変わりますか?それはなぜですか?
  • ブラウザで適当なWebページを開いてください。そのページの構成や内容について、抽象化して説明してください。

抽象化のレベル

整理した3つのリストを、3枚のメモ用紙に分けて書いて、机の上に置いてみましょう。 ここからちょっと離れてみてください。 2メートルくらい離れると(すごく目のいい人なら5メートルくらい)、もうリストになにが書いてあるかはわからなくなるはずです。 それでもリストが3つあることはわかります。 左がスーパー、真ん中が商店街、右がデパートで買うもののリストです。 これくらい離れると、買うもの個々のことは気にせず、どこに買い物に行くかだけ考えられます。 デパート→商店街→スーパーの順に回るか? 商店街とスーパーは仕事帰りに寄って、デパートは土曜日にするか?

行く場所が決まったら、また机のところに戻りましょう。 そしてこれから最初に行く場所のメモを1枚取って、目の前に持ってきてください。 何を買うのかよく見えるようになったので、買い物の内容をチェックできます。 飲み物は3本で足りるか?料理の材料に忘れ物はないか?花を飾ろうか、いらないだろうか? このとき、他のリストは見えなくなっています。 一箇所の買い物だけに集中できて、その後どこへ行くのか気にしなくてすみます。

物事を抽象化すると、それぞれ異なる抽象化のレベルが見つかります。 この例では「リストを選ぶレベル」と「買い物で使うレベル」の2つできました。 それぞれのレベルでは、それぞれの問題に集中できます。 そしてあるレベルで考えたり判断したことは、他のレベルに影響しません。 いまは「スーパー」「商店街」「デパート」の3つに整理していますが、たとえば商店街のどの店で買うのか、デパートのどのフロアに行くのかを考えたくなるかもしれません そうすればレベルが増えて、商店街を回る順番や、デパートで寄るフロアを考えることもできるようになります。

具体的に近い方を「低レベル」、抽象度の高い方を「高レベル」と呼ぶこともあります。 これは誰かをほめたり、けなしたりしているわけではなく、単に抽象化の度合いを表している言葉です。 高い低いを、空を飛ぶ鳥や飛行機のような高度でイメージしてみてください。 地面に近い、低いところでは、いろいろなものが詳細に、具体的に見えます。 地面から遠く、高い高度まで上がっていくと、広い範囲が見渡せるようになります。 低レベルでは詳細度が上がりますが視野が狭まり、高レベルでは詳細は見えませんが視野が広くなります。 どちらが大事とか、偉いとかいう話ではありません。 それぞれのレベルで見えるものが違い、考えられることも、解決できることも違うという考え方です。

問題のどの部分を、どのレベルから解決していくのか意識すると、問題全体にどうアプローチしていくのか作戦が立てられるようになります。 そうすると抽象レベルを高く上がったり低く下がったり、行ったり来たりしながら問題に取り組むことになります。 自分がいまどのレベルで考えているのか、そこでどういう問題を解こうとしているのか、忘れないようにしましょう。

例題:
  • Googleマップで自宅周辺の地図を表示して、拡大・縮小してみましょう。4つくらいのレベルを決めて、それぞれ比較してください。(スクリーンショットを保存して見比べるとよいです。)
    • それぞれのレベルでは、何が見え、何が見えないですか?どんなことがわかりますか?
    • それぞれのレベルの地図は、どんな使い道に向くと思いますか?
    • 同じことを、衛星写真(Earth)でやったり、交通状況を切り替えたりして、比較してください。
  • ふだん使っているソフトウェアやアプリについて、4つの抽象レベルで、それぞれ100文字程度で説明してください。
    1. 今日(または最後に使ったとき)の具体的なやったこと、使い方
    2. 自分がなんのためにそのソフトウェアを使うのか、その目的
    3. 類似するソフトウェアと比較した特徴
    4. 90歳のおばあちゃん(または3歳の子供)にそのソフトウェアを説明する
    • それぞれの説明の違いはなにか、なぜそのように変えたのか、整理してください
    • 他にどんな抽象レベルがあるか、考えてみてください
      • 例: そのソフトウェアの開発者なら?その会社の社長なら?株式アナリストなら?ライバルなら?

観点が重要

ここまでの例や例題で見てきたように、抽象化はソフトウェア開発に限らず、あらゆる場面で使われています。 もちろんソフトウェア開発やシステム開発でも、問題解決のためさまざまな抽象化がおこなわれています。 システムは一般的に複雑なものなので、抽象化も様々な観点が必要となります。 設計書、仕様書などのドキュメントはほとんどが、なんらかの観点からシステムを抽象化して記述したものです。 (なおドキュメントの呼称や内容は、会社や現場、人によって大きく違うので、知っているのと違うと思うかもしれません。 あくまで一例です。)

  • ワイヤーフレーム
    • 観点は画面の種類や数と、表示する主要な情報、遷移の流れなど
  • フローチャート
    • 一連の処理がどこから始まりどこで終わるか、どう流れていくかという観点
  • 詳細仕様書
    • 対象としている範囲に限った、プログラミングに必要な情報をすべて含む観点
  • システム概要
    • システムに登場するもの最大粒度で表現する観点で、システムの境界を定め、対象と対象外を区別するのに使う

このように観点しだいで抽象化の結果も目的も変わってきます。 どういう観点を選べばいいのか、どういう問題にはどういう観点を使えばいいのか、これは知識と経験が必要になってきます。 また観点の選び方が悪いと、問題解決の役に立たないどころか、かえって事態を混乱させてしまうこともあります。

買い物リストの話で考えてみましょう。 どこで買うかという観点でリストを整理し、3つのリストを作って、「どこに行くか」と「その場所で何を買うか」を分離して考えられるようにしました。 ところで、もし花を買うとしたら、どこで買うといいでしょうか? 花はデパートでも買えるし、商店街にも花屋がありそうですし、スーパーでも売っています。 花を実際に見て値段も確認してから買おうと思ったら、どのリストに入れておくといいでしょうか。 もし3箇所見比べたかったら、「どこに行くか」を考えるとき考慮しないといけなくなります。 こうなると、せっかくリストを整理したのに、「花をどこで買うか」という新たな問題が発生してしまいます。

また別の観点もあるかもしれません。 たとえば、予算が決まっていて、ほしいものは全部買えないかもしれません。 リストが1つだけだったら、リストの中身を必要な順に並べ替えて、予算がなくなるまで上から順に買えばいいでしょう。 しかしリストが3つに分かれていると、どのリストをどこまで買うべきなのかわからなくなってしまいます。 全体の予算があると、「どこで買うか」という観点の抽象化は不適切なわけです。 先に予算の問題を解決しないと、適用できない観点だということになります。

観点と抽象化レベルによって、もともとの大きな問題を分割してそれぞれ個別に解いていけます。 しかし、分離しきれない問題が残ることもあって、これはレベルをまたいで考える必要があります。 観点が間違っていて、問題が複雑化してしまうこともあります。 もともとの問題を全部理解して把握できていれば、あとからこんなことに気づいたりしないですむかもしれません。 しかしそもそも、問題は複雑で理解も把握も難しいから、いろいろ工夫をしているわけです。 「考えればわかること」は「考えたからわかる」ので、最初からわかっていれば苦労しません。

そこで、抽象化がうまく働いているか、問題がきれいに分割できているか、進めながら確かめる必要が出てきます。 高レベルで問題を解決したら、それが低レベルでもちゃんと解決できているか調べます。 また、他のレベルに不要な影響を与えていないかも、要確認です。 こうした確認を通じて、設定した観点と抽象レベルが妥当なものだったかわかってくるのです。 抽象レベルを自由自在に行き来しながら問題を解決し検証するというのは、とても高度なスキルですが、これができるようになるとプログラマとしての問題解決能力が大きく広がります。

コラム: アーキテクトも実装する

ソフトウェア開発ではよく「上流の設計が、下流で矛盾を生む」という事態が起きます。 その理由のひとつが、こうした抽象化の誤りです。(理由は他にもたくさんありますが。) 上流SEや、アーキテクト、プロジェクトリーダーといった立場の人が、高レベルのことだけ考えて低レベルでの確認を怠ると、実装時に設計を考え直さないといけなくなったり、実装できない設計になったりしてしまいます。

『組織パターン』には「アーキテクトも実装する」というパターンがあり、全体の方向性を決定するアーキテクトもプログラマーと一緒にコードを書くことの重要性を説いています。 また『人月の神話』の「第3章 外科手術チーム」では、生産性の非常に高い10名の開発チームには「執刀医」に当たるチーフプログラマーがいて、「自ら機能と性能を定義し、プログラムをデザインし、コーディングし、テストして文書を書く」と述べています。 ソフトウェア開発において実装というのはかなり具体的な活動、低レベルなものですが、ここまで下りてこないと本当には確認できない問題というのがたくさんあるのです。 (ちなみに、さらに低く、OSやメモリ、通信プロトコルや物理マシンといったレベルまで下がっていくこともできます。)

例題:
  • 何人かのグループを男女に分けるという場面をよく目にすると思います。どんな状況があるか、男女に分けることでどんな問題を解決しようとしているのか、いくつか書き出してください。
    • 男女に分けるという問題解決が、どういった観点からもたらされたのか、考えてください。
    • 男女に分けたせいで問題が起きることもあります。どんな観点だと、かえって状況が悪化すると思いますか。
  • いま利用しているプログラミング言語を、他の言語と比較しながら、なぜ自分がいまそちらを使っているのか説明してください。できれば他の言語は2つ以上選んでください。

https://github.com/yattom/text_for_programmer/wiki/%E6%8A%BD%E8%B1%A1%E5%8C%96