🌀

ソフトウェア開発における抽象化

2021/12/27に公開

抽象化とは

抽象化とは忘れる技術の一つである。

ソフトウェア設計においては「明確に決めないままにしておく」「決めないことで様々なものに適用できる」という事が大事になることがある。モノや概念に抽象化によって名前を与えてやると、明確になっていない事についても語る事ができるようになる。

例えば、ディレクトリからファイルを名前で検索して操作するようなコードを書いているとする。ディレクトリもファイルもパスがあり内容にアクセスするという部分は共通なので、ディレクトリツリーを横断的に検索するようなロジックを書くときは「ディレクトリかファイルかを区別しない存在」として扱う(例えばポリモーフィックなクラスを用意する)ことで、コードの重複を減らすことができる。

しかし「ディレクトリかファイルかを区別しない存在」を表すのに使える用語で、無定義で使える一般的な名詞はない。日常生活においてはディレクトリとファイルを区別しないことが便利になるシチュエーションはほとんどないので、こういうものの名前が現れる状況は限られている。つまりこのようなプログラムを書いている時の専用の語彙が発生する。これを作るのがソフトウェア開発における抽象化の第一歩である。名前をつけることが抽象化のすべてではないが、概念を抽出して名前を定義する作業によって抽象度を上げた議論が可能になり、その後の議論のベースとなるので命名が重要になる。

上の例は単純すぎるかもしれないが、OSI参照モデルやUNIXのデバイス入出力の抽象化、抽象データ構造、オブジェクト指向設計など、抽象化によって関心を分離するというテクニックはソフトウェアエンジニアリングのあらゆる場面で様々な粒度で使われている。

名前

名前をつけることで抽象度を一段階上げ、不要な詳細をそぎ落とした議論が可能になる。しかしよく言われるように名前を付けるのは計算機科学で最も難しいことの一つである。

先の例でいうと、「ディレクトリかファイルかを区別しない存在」を表す用語は世間一般に普及していないので、万人に納得してもらえる言葉を用意するのは難しい。しかしコードを書くには何らかの方法で命名する必要がある。見るところ、命名法にはいくつかのパターンがあるようだ。

  • 機能の説明的な名前をつける
    例えばディレクトリエントリディレクトリメンバーのように「ディレクトリに存在する何らかのもの」という点に注目し、それを説明するような名前とする。

  • 比喩からおこなう
    ディレクトリの階層をディレクトリとファイルから構成されるツリーとみなす。ツリーの頂点や葉はノード(節という意味)と呼ばれるので、この用語を使用しノードと呼ぶことにする。OSの用語にもinodeという名前がある。

  • 名前や概念の流用
    パスはファイルやディレクトリのプロパティの一つでファイルやディレクトリそのものとは異なる概念だがファイルを操作するようなコードの文脈においては一対一に対応して同一視できるためパスを「ディレクトリかファイルかを区別しない存在」の名前とすることもできる。実際Java 1.7で追加されたjava.nio.fileパッケージではPathクラスはそのような用途で使われている。

  • 名前の拡大解釈
    ディレクトリもファイルの一種である、という立場をとることにすると、一言でファイルという名前で呼ぶこともできる。Javaの標準APIではFileクラスによってファイルもディレクトリも表すことが可能で、File.isDirectory()やFile.isFile()という一見奇妙に見えるメソッドがある。この方法は濫用すると分かりにくさを助長する可能性がある。

  • 抽象化の失敗、あいまいな命名
    あまり深く考えずにdirectory_or_fileのように具体的すぎる名前を付けてしまうことがある。これは抽象化に失敗しており、ディレクトリでもファイルでもないもの、例えばシンボリックリンクが出てきたときにうまく扱えなくなってしまう。逆に一般化を意識しすぎてobjectのようなあいまいな名前をつけてしまうと、名前が本来果たすべき役割が不十分となり読みにくいコードにつながる。

抽象化のスキル

抽象化は身につける事ができるスキルである(と思いたい)。抽象化を意識してコードを書いたり、デザインパターンやオブジェクト指向設計の勉強をしたりするのが有効だが、他にも役に立ちそうな事を列挙する。

  • 要約を作る
    文章を読み書きした際に、ポイントを押さえた要約をつくるようにする。新しい文章を書くのは足し算だが、要約は引き算である。要約は抽象化そのものではないが、引き算である事は共通している。

  • 現実の機能を抽象化して考える
    我々の身の回りには機能があふれている。家、部屋、道路など、日常生活で身近にあるものをピックアップし、それが果たしている機能を抽象化して考える。現実にあるものは複数の解釈が可能なので抽象化は自明でなく、いいトレーニングになる。

  • APIを調べる
    抽象化が機能する例を多く知るのも重要である。既存のコードを読むのもよいが、コードリーディングによって具体と抽象を理解し抽象化がうまく機能している理由を把握するのは時間がかかることも多い。おすすめはライブラリやサービスのAPIをみることである。よいAPIは詳細を隠ぺいするために抽象化をうまく使っている事が多いし、コード以外にもドキュメンテーションが充実していて解説も豊富である。公開前提のものはよく考えられているので、コードをランダムに読むよりもいいアイディアに遭遇する可能性が高い。

Discussion