ソフトウェアエンジニアリングとプログラミング言語理論において、抽象化の原則(または抽象化の原理)は、プログラミング言語やソフトウェアライブラリが提供する抽象化を利用することで、可能な限りプログラム内の情報重複(通常はコードの重複)を減らすことを目的とした基本的な原則です。[ 1 ]この原則は、プログラマへの推奨事項として述べられることもあれば、抽象化を使用することが望ましい理由が自明であると仮定して、プログラミング言語の要件として述べられることもあります。この原則の起源は不明であり、わずかな変更を加えながら、異なる名前で何度も再発明されてきました。
プログラマーへの推奨事項として解釈すると、抽象化の原則は「繰り返しを避ける」(DRY)原則として一般化でき、これは一般的に情報の重複を避けること、そしてソフトウェア開発プロセスにおける人的労力の重複を避けることを推奨するものです。
プログラマーへの推奨事項として、ベンジャミン・C・ピアースが『型とプログラミング言語』 (2002年)で定式化した抽象化の原則は、次のように述べられています(原文の強調):[ 2 ]
プログラムにおける重要な機能は、ソースコード内の1箇所のみに実装されるべきである。類似の機能が複数のコードによって実行されている場合は、それぞれの部分を抽象化して1つのコードに統合することが一般的に有益である。
プログラミング言語の要件として、David A. Schmidt がThe structure of typed programming languages (1994) で定式化した抽象化の原則は次のとおりである。[ 3 ]
意味的に意味のある構文クラスに属する句は、すべて命名することができる。
抽象化の原理は、いくつかの書籍で言及されています。以下に、それらの書籍の一部と、簡潔な定式化があればそれらも併せて示します。
この原則はオブジェクト指向プログラミングにおけるデザインパターンにおいて中心的な役割を果たしますが、このトピックに関するほとんどの文献ではこの原則に名前が付けられていません。Gang of Fourによる『デザインパターン』という本には、「ここでの焦点は、多くのデザインパターンのテーマである、変化する概念をカプセル化することです」と書かれています。この記述は、他の著者によって「変化するものを見つけてカプセル化する」と言い換えられています。[ 7 ]
今世紀、この原則はエクストリームプログラミングにおいて「一度きり」というスローガンのもとで再発明されました。この原則の定義は、最初に登場したときは「重複コードなし」と非常に簡潔でした。[ 8 ]その後、ソフトウェア開発における他の問題にも適用できるものとして詳細化されました。「自動化する価値のあるプロセスはすべて自動化する。タスクを何度も実行している場合は、スクリプト化する。」[ 9 ]
抽象化の原則は、抽象化を容易にするための何らかのメカニズムの文脈で述べられることが多い。制御抽象化の基本的なメカニズムは、関数またはサブルーチンである。データ抽象化には、さまざまな形式の型多相性が含まれる。データ抽象化と制御抽象化を組み合わせるより高度なメカニズムには、クラス、多型性などを含む抽象データ型がある。複雑なシナリオで重複を減らすことができる、より豊かな抽象化の追求は、プログラミング言語の研究と設計における原動力の一つである。
経験の浅いプログラマーは、プログラムに過剰な抽象化を導入したくなる誘惑に駆られるかもしれません。そうした抽象化は、一度しか使われないにもかかわらずです。 この問題を強調する補完的な原則として、「必要ない」という原則、そしてより一般的には「KISSの原則」があります。
コードは通常改訂される可能性があるため、抽象化の原則に従うにはコードのリファクタリングが必要になる場合があります。コードの一部を書き直す労力は、抽象化によって将来得られるであろうメリットと比較して償却する必要があります。このための経験則はマーティン・ファウラーによって考案され、 「3の法則」として広く知られるようになりました。この法則によれば、コードの一部が2回以上コピーされる場合、つまり最終的に3つ以上のコピーが存在することになる場合は、そのコードを抽象化する必要があります。
「Don't Repeat Yourself」(DRY原則)は、多層アーキテクチャの文脈で発展した一般化です。多層アーキテクチャでは、関連するコードが必然的に複数の階層で、通常は異なる言語で、ある程度重複して記述されます。実際には、コードジェネレータやデータ変換などの自動化ツールを活用して、重複を避けることが推奨されます。
コードの最適化に加えて、プログラミングにおける抽象化レベルの階層的/再帰的な意味は、ハードウェア通信層間のインターフェースも指し、これらは「抽象化レベル」や「抽象化レイヤー」とも呼ばれます。この場合、抽象化レベルはインターフェースと同義であることが多いです。たとえば、シェルコードと高レベル言語と低レベル言語間のインターフェースを調べると、抽象化レベルはオペレーティングシステムコマンド(たとえばC言語)からレジスタおよび回路レベルの呼び出しとコマンド(たとえばアセンブリ言語とバイナリ言語)に変化します。この例の場合、抽象化レベル間の境界またはインターフェースはスタックです。[ 10 ]