インターフェースは、システムと外部環境との間の一種の契約と考えることができます。 コンピュータプログラムのフレームワーク内で、「システム」は問題の機能またはモジュールであり、「環境」はプロジェクトの残りの部分です。 インターフェイスは、システムと環境の間で転送できるデータを正式に記述します。 また、「実装」は「システムマイナスインターフェイス」として説明できます。 Haskellのような言語では、インターフェイスは非常に限定的です。 また、Pythonのような言語では、対照的に非常に一般的です。 選択するインターフェースのタイプは、作成される技術的負債の規模とプログラマーの生産性に影響を与える可能性があります。 これを計算する方法を以下に説明します。 異なるインターフェイスを評価および比較する方法も提案されます。 これらの比較に基づいて、言語ツールまたはソフトウェアツールの使用方法を自分で観察できます。
ソフトウェア開発で最も重要な概念は、 インターフェイスの概念です。 この記事はJavaのインターフェースについてではなく、ソフトウェア設計のインターフェースについてです。 そして、それほどではありませんが、私たちを取り巻く世界のインターフェースについてです。 もちろん、他の多くの重要な概念がソフトウェア開発で使用されていますが、それらのほとんどは何らかの形でインターフェースの重要性に依存していると思います。
インターフェイスとは何ですか?
私たちのほとんどは、2つの簡単な公式に精通しています。
インターフェイスは、システムと外部環境の間の契約です。
インターフェースは、システムと外部環境とのインターフェースです。
= ∩
共役定義は、システムが物理オブジェクトである場合に最適です。 両方の定義は非常に抽象的なので、次のように入力して見てみましょう。
ここでは、システムはラップトップであり、環境は手です(キーボードに登る猫の足も同様です)。 したがって、インターフェイスは、手とラップトップの間の相互作用の一部である必要があります。これは、一方だけに起因するものではなく、両方にのみ起因するものです。 通常、手とキーボードを別々に考えるため、この場合のインターフェイスの正確な境界は哲学的な議論の問題です。 指とキーが接触したときに、キーボードが全体として機能するか、個々の原子が相互作用するかを決定するのはあなた次第です。
この例がインターフェースのコントラクトとしての定義にどのように関係するか驚くでしょう。 この場合、合意とは、キーの位置を覚えて筋肉の記憶を発達させたときに十分な時間を費やしたという合意を意味します。 多くのニュアンスが契約に関連しています。 たとえば、キーを押したままにすることは、単純な1回押すこととは異なる意味を持ちます。
これはすべて奇妙な哲学的推論ですが、ソフトウェアの作成とどのように関係していますか? まあ、そもそも注意を払わなくても、プログラミングインターフェイスはあらゆる側面からあなたを取り囲んでいます。 たとえば、Javaでプログラムする場合、目的に応じて明示的にインターフェイスに名前を付けます。 また、他の言語では、それらも存在します。
add_numbers
関数
add_numbers
例を見てみましょう。
unsigned int add_numbers(unsigned int, unsigned int); void other_function(void){ add_numbers(3,4); } unsigned int add_numbers(unsigned int a, unsigned int b){ return a + b; } int main(void){ add_numbers(9,99); return 0; }
環境、
add_numbers
システム、およびインターフェイスを記述するために、
ここで説明する「システム」は、
add_numbers
関数で構成されて
add_numbers
ます。 mainメソッド
other_function
別のシステムと見なすことができると言うなら、あなたは正しいでしょう。 ただし、簡単にするために、
add_numbers
関数
add_numbers
分離されたシステムで
add_numbers
と考えています。 また、インターフェイスの一部として
add_numbers
を考慮することをお勧めします。
ご覧のとおり、ここに4番目の概念「実装」が追加されています。 特定の実装を考慮せずにインターフェースのトピックを議論することはかなり困難です。 この用語を定義しましょう:
実装は、システムを除いたインターフェースです。
Implementation = System ∖ Interface
Implementation = System ∖ (System ∩ Environment)
私はそのような実装の定義に出会ったことがなかったことを認めなければなりません。 しかし、これは、一連のインターフェース定義の避けられない拡張であり、いくつかの利点があります。 あなたが貧しい学生で、試験の準備をしている場合、先生はおそらくそのような定義を聞いたことがないでしょう。 オブジェクト指向プログラミングの分類法と矛盾する場合でも、私は驚かないでしょう。 しかし、この場合でも、変更するつもりはありません。 私の定義に従って、OOPファンにメモを書き直させてください。
次に、物理システムのインターフェースについて話すとき、通常、このシステムの「実装」を単一の物理オブジェクトとして想像します。 結局のところ、ボタン、ディスプレイ、またはその他のコンポーネントを考慮せずに「実際の」実装を検討するのは奇妙です。 そして、これはインターフェースを物理的なオブジェクトのセットというよりもむしろ「合意」として考えるように私たちを押し進めます。 つまり、一連の約束、保証、または何かのような形で... システムと環境の間の合意 。
契約としてのインターフェース
add_numbers
関数のインターフェースを
add_numbers
の形で考えると、保証は次のようになります。
-
add_numbers
関数が存在します。 -
add_numbers
は2つのパラメーターのみがあり、各パラメーターは符号なしint
です。 -
add_numbers
は、unsignedint
1つだけ返します。
この関数のインターフェースは何も伝えません:
- 実行の中断について
add_numbers
; - ランタイム
add_numbers
漸近的な複雑さについて。 -
add_numbers
実行に必要な空きメモリの量。 - unsigned
int
特定の実装について。 - 副作用(メモリ割り当て、グローバル変数の変更)について。
上記の
add_numbers
インターフェイスは、
prototype
関数として知られています。 K&R Cの以前のバージョンでは、より弱い形式のインターフェイス記述が使用されていました。
unsigned int add_numbers();
インターフェイスをコントラクトとして定義すると、プログラミングに非常に便利です。 結局のところ、ほとんどのプログラマーのタスクは、公理のセットを定義および照会することにあります。 初期条件と最終条件は、いくつかのプロパティまたは動作を提供します。 両当事者は、互いにビジネス関係を確立する前に、契約を作成します。 最終結果、金額、支払い条件を定式化します。 早期終了、払い戻し、費用の条件も事前に合意されています。 契約に違反した場合、状況は裁判所または仲裁によって解決されます。 しかし、契約で何かを示すのを忘れると、驚きが生じるかもしれません。
コンピュータープログラムでは、すべてが同じです。 モジュールと関数は、必要なものと(場合によっては)返すものを返します。 この契約に違反すると、コンパイルエラー、ランタイムエラー、アプリケーション、システム、コード品質管理ツールの障害、および管理者からの懲戒処分につながります。 コントラクトとしてのインターフェイスの定義は比ical的ではないとさえ言えます。 それほど詳細ではありませんが、商業契約と同じ原則を使用しています。
特許、著作権、インターフェース
法的助言はいたしません。 おそらく私が言ったことのいくつかは、法律と矛盾することさえあります。 以下はすべて、著者の個人的な意見です。
そのため、インターフェイスを文字通り 2つのエンティティ間の「商業契約」と見なす傾向があります。 私は強調します-これを比thisとは考えません。 私は特にこの解釈をコンピューター科学者と著作権擁護者に向けています。
インターフェイスの特許を取得する必要がありますか? システムと環境の間の契約としての定義を考えると、特許の使用は間違いだと思います。 そして、明らかに、既存の判例法は私の立場を支持しています。 しかし、「インターフェイス」という言葉は非常に広く使用されており、上で説明したような意味ではまったく使用されないことが多いことに留意してください。
インターフェイスは著作権で保護されるべきですか? 繰り返しますが、「契約上の」性質を考えると、著作権の対象はインターフェースの「ソースコード」でなければならないと思います。 同時に、著作権は、インターフェースを特別なものにするインターフェースの側面には適用すべきではありません。 ソースコードまたは手書きの画像を保護するのに十分ですが、保証または制限はありません。 インターフェースの保証または制限がそのコードのどの部分とも切り離せない場合、これらの部分は保護の権利を奪われるべきです。
何かを著作権で保護する必要があるかどうかを評価する簡単なテストを提案します。
インターフェイスで何らかの方法で使用される、サードパーティのコンポーネントを含む属性のセットを保護する場合は、いつでも適切な代替を作成できます。 交換品は同じインターフェースを実装し、このソフトウェアを変更することなく、著作権を侵害することなく、サードパーティのソフトウェアで正常に使用されます。 置換が著作権侵害につながる場合、またはサードパーティからのソフトウェアの変更を意味する場合、または機能を損なう場合、属性セットは攻撃的すぎるため、削減する必要があります。
このテストの助けを借りて、特許性もチェックすることをお勧めします。 注:テストの目的は、著作権または特許保護の不適切性を判断することのみです。 何を保護すべきかを決定する助けにはなりません。 さらに、このテストは単なる私の意見であり、規範的な行為や法律ではありません。
また、ある言語のインターフェースの一部と見なされる基準は、別の言語ではそうではないことにも注意してください。 たとえば、Javaでは、関数が宣言される順序はプログラムの実行に影響しません。 また、ファイル内の関数の順序が重要ではないと誤って言った場合、これはPythonのプログラムに関連するエラーになります。
def foo(): print("asdf") def foo(abc): print(abc) foo("lol")
この法律に関するすべての話は、Googleに対するOracleの訴訟を思い出させました 。 提供されているリンクで開発者にとって興味深い詳細を見つけることができるので、分析ではそれらに依存します。 すべての側面を考えると、オラクルを支持する決定に反対する理由はないと思います。 手続きの詳細がそれほど多くないので、無条件に支持するとは言えません。
インターフェースの要素を特許や著作権で保護するための先例が作られるのではないかと多くの人が心配していたと思います。 私のテストに合格しなかった場合にのみ。 地方裁判所は、「APIの構造、一貫性、およびアーキテクチャは著作権によって保護されている可能性があります。」 これは問題ではないと思います。「構造、シーケンス、およびアーキテクチャ」の定義自体が、私のテストに完全に合格するからです。 上記のリンクの記事からの抜粋をいくつか紹介します。
「地裁は、「Javaとやり取りする広告を書く方法は1つしかない」と結論付けました。 その場合、複製広告の使用は著作権保護の対象にはなりません。 Googleは、3つの例外を除いて、Javaにアクセスするための独自のAPIを作成できるという事実に異議を唱えません。 そして最後に、「Googleは文字通り広告をコピーしたことを認めました。」
裁判所は正しい判断を下し、本質的に一意のインターフェイスプロパティは保護すべきではないと結論付けたと思います。 さらに、Googleは「逐語的」コピーを認識しました。 これがコピーアンドペーストを意味し、すべてのスペースとコメントのスペルミスを含む場合、私はこれを権利の侵害と見なします。 インターフェースを保護できない場合でも、個々の創造的な表現の保護を妨げることはありません。
この訴訟についてはオープンネットワークのソースからしか知りませんが、明らかに、Googleはインターフェイスを含むJavaソースコードを完全にコピーしました。 これは、2010年以前にSunとのライセンス契約に関する交渉の主題であったため、Javaの使用をライセンスする必要があると彼ら自身が考えていたようです。 しかし、SunがOracleに買収された後、これらの契約は失敗しました。 それにもかかわらず、グーグルはコードの「逐語的」コピーを使い続けたが、それは明らかに彼女が裁判で利益を得なかった。 私は彼らの弁護士が自分の立場の弱さを知っていたのではないかと思うので、彼らはインターフェースの著作権の不拡散の法的要件に基づいた防衛戦略を選んだ。 彼らは、ソースコードの形でインターフェースを提示し、それをより哲学的な概念と組み合わせることで、このケースで勝つことを望んでいました。
「モジュール」または「抽象化」とは何ですか?
私の頭の中の「モジュール」という言葉には、投稿のタイトル画像があります。 この図は、モジュールの境界の重要性と環境との相互作用を示しています。 キューブインターフェイスは、環境とキューブのコンテンツとの相互作用を厳しく制限します。 インターフェースをバイパスすることはできないため、インターフェースによって課される「ゲームのルール」を遵守する必要があります。 最後に、キューブ内には何もありませんが、重要ではありません。重要なのはコンテンツではなく、インターフェースです。
別の例:細胞膜の構造。 さまざまなコンポーネントにより、必要な場合にのみ、必須物質のみが膜を通過します。
この記事では、「モジュール」と「抽象化」という用語を同義語として使用します。 もちろん、説明辞書は私とは一致しません。また、異なるプログラミング言語であっても、これらの用語の意味は異なります。 しかし、この場合、この記事で理解されているように、これらのエンティティの両方がシステムと見なされるという事実にのみ興味があります。 つまり、抽象化とモジュールは、インターフェイスと実装で構成できます。
単一の関数をCのモジュール、Pythonの「モジュール」、Javaのクラスまたはパッケージと見なすことができます。 外部インターフェースと「隠された」実装を備えている場合のみ。 さらに、「ステルス」は、言語のルールやプログラマーの決定の結果である場合があります。
漏れやすい抽象化
私の知る限り、 漏れやすい抽象化のアイデアはJoel Spolskyによって提唱されました 。 彼のエッセイにはいくつかの良い例がありますが、私は自分の例を挙げたいと思います。 プログラミングでは、「マップ」の概念は非常に一般的です。キーと値のペアで構成されるデータ構造の表現です。 重要な制限:カードは、すべてのキーが一意でなければならないことを保証します。 既存のキーに新しい値を書き込もうとすると、エラーが発生するか、以前の値が上書きされます。 一番下の行は、キーを複製しないことです。 ほとんどの場合、プログラマはこれらすべてのキーをソートする必要があります。 また、カードはキーの並べ替えの特定の順序を保証できないため、繰り返し処理した後はどの順序になるのか疑問に思うことがありますか? これは、カードインターフェイスが並べ替えを保証しないという事実の結果です。 そして、それは問題ではないと信じられていますが、実際にはそれを整理したいです。 これは、たとえば既存のキーの検証を容易にするために、より効率的なデータ編成に必要です。
ソートされたデータを列挙すると、ランダムデータを列挙する場合とはまったく異なる結果が得られます。 リストで最小値を見つける必要があるとしましょう:
min = null; list = map.getMapKeys(); for (item in list){ if ( min == null ){ min = item }else if (item < min){ min = min; /* This line has a bug */ } }
データが昇順でソートされている場合、
else if
ブランチは実行されません。 リスト内のランダムな場所からチェックを開始しても、プログラムはこの行に出くわすことはありません。 そして、これは大きな問題です。なぜなら、カードの実装を変更し、ソートされたキーを返さないと、バグが発生してブランチでコードの実行が突然開始されるからです。 そしてその時までに、あなたはこのコードとその中に隠された爆弾を完全に忘れるでしょう。
抽象リークの独自の定義を提供したいと思います。
抽象化リークは、実装がインターフェイスによって提供されなかった方法で環境に影響を与える可能性がある状況です。
この定義によれば、 ほとんどすべての抽象化は漏れやすいです。 実際、あらゆるタイプの環境影響のインターフェースでの記述は、最も厳密な数学的システムでのみ意味があります。 物理システムについては、 ゲーデルの不完全性定理を思い出してください。
ほとんどの抽象化における漏れの考えは根拠のないものではありません。 ジョエル・スポルスキーはまた、彼の漏れのある抽象化の法則でこれを暗示しています。
「すべての非自明な抽象化は、ある程度漏れやすい。」
すべての抽象化には穴がたくさんあるので、何について話せますか? 問題が発生するのは、環境の一部が、環境上のシステムに影響を与える予期せぬ方法の1つに依存し始めたときだけです。 誰もがそのような漏れについて話している。
これは、通常のバグだけでなく、セキュリティの分野でも、広範囲に及ぶ結果をもたらします。 セキュリティを損なう外部環境へのリークがある物理システムでは、「 サードパーティのチャネルを介した攻撃 」という用語が関連付けられています。 すべての抽象化には漏れがあるという声明と合わせて、これが結論につながります。
暗号システムの各物理実装は、サードパーティのチャネルを介した攻撃に対して脆弱です。
上記のすべてを考慮すると、このアイデアは物理的だけでなく、エミュレートされた実装にも拡張できます。
インターフェイスの評価と比較
上で見たように、戻り値の型や関数に渡すことができるパラメーターの数など、Cインターフェースで設定されます。 Pythonはどうですか? 私は、記事の文脈に従って「インターフェース」という用語を使用します。つまり、Pythonの「インターフェース」に関する本に書かれているものよりも広い意味で使用します。
def add_numbers(a,b): return a + b print(add_numbers(3,1)) print(add_numbers("abc","def"))
この言語では、関数インターフェイスタイプを形式化する必要があります。 これにより、処理する必要のある情報が少なくなるため、関数の定義と呼び出しが簡単になります。 一方、時間の経過とともにエラーを見つけるためにチェックできる制限は少なくなります。
情報転送方法の観点から、インターフェースのさまざまな特性を評価および比較することについて、何か言わなければならないことがあると思います。 特定のインターフェイスと、この言語で実装できるすべてのインターフェイスの全体の両方を評価できます。
add_numbers
例を思い出して、抽象リークを使用してインターフェイスを通過およびバイパスできる情報量を評価してみましょう。
インターフェイス経由 | インターフェースのバイパス | ||
機能の説明 | 可能な状態の数 | 機能の説明 | 可能な状態の数 |
パラメータタイプ1 | 1(符号なし整数) | グローバル変数状態 | (グローバル変数の数)*(グローバル変数の状態の数) |
パラメータタイプ2 | 1(符号なし整数) | ファイルシステム | ファイルシステムの状態の数 |
戻りタイプ | 1(符号なし整数) | CPU使用時間 | 制限なし |
パラメーター1値 | 2 ^(符号なし整数のビット数) | ヒープ状態 | ヒープ状態 |
パラメータ2値 | 2 ^(符号なし整数のビット数) | 他の多くの... | ... |
戻り値 | 2 ^(符号なし整数のビット数) |
また、Pythonインターフェースを介して
add_numbers
通信できるものがいくつかあります。
Pythonインターフェイスを介した情報の受け渡し | Pythonインターフェースをバイパスして情報を渡す | ||
機能の説明 | 可能な状態の数 | - | |
1 | - | ||
2 | |||
- | |||
1 | ... | ||
2 | ... | (- ) * (- ) | |
, Haskell:
add_numbers :: Int > Int -> Int add_numbers 3 4 = 7 main = print (add_numbers 3 4)
,
add_numbers
:
Haskell | Haskell | ||
- | - | ||
1 | 1 (Int) | ||
2 | 1 (Int) | / | |
1 (Int) | ... | ... | |
1 | 1 ( 3) | ||
2 | 1 ( 4) | ||
2^30[ 1 ] |
:
- ;
- .
:
- , ;
- .
, :
GUI | GUI | ||
- | - | ||
1 | - , 1 * - | UI | |
2 | - , 2 * - | - , 2 | |
1 | - , 1 | UI | ... |
2 | - , 2 | ||
- | |||
, GUI | - , GUI |
cd
:
GUI | GUI | ||
- | - | ||
- , |
, . ( ) ( ), , . . , «OK» «Cancel» 1 .
, .
, . :
- , , .
- .
- , , , .
- , .
- , , .
. :
(leaky interface) — , .
(specific interface) — .
— - , .
«» «» , , , — .
, - , , . : . .
, , . «» , - . , .
:
- , - , .
- , (1). , (1), . (N^2). , , , N^2.
, . - , . - , . — , , .
, (N^2), , (N). , : . 20 , , , , . , . , , — .
?
, :
- .
- .
- , .
, , ! . 100 , , GUI. GUI, - , , . … .
, , . , . , . GUI . , . , .
, , GUI — . , . , . , , .
, , Haskell Java. , . .
?
« », , . , , , , « ».
« », , : . — , , . , MVP . , , .
« », . , . , - ( ).
- , Twitter Ruby on Rails, . Twitter Scala. - , Scala. . Twitter' , . , . , , , . – , . Twitter' , . , , , : « , , ». - , , , . , «» , .
Python?
, , . , «» «» , .
, Python , , . Python .
Python . , .
Java/C++?
, . Java ++ , Python Ruby. , , ( Haskell), Java ++ , . , . , , .
- , : , . , ! , , :
- .
- «» Java.
- .
- .
- (.h) C/C++.
- RESTful API.
- URL.
- «» «».
- (DDL).
- その他。
おわりに
ご覧のように、インターフェイスの概念は非常に重要であり、法的保護、生産性、およびシステム構造の他の側面との哲学的つながりの数の分野でプロジェクトの開発に非常に大きな影響を与えます。他のプログラマーにインターフェースについてどう思うか尋ね、あらゆる種類のものを聞いてください。