人々が言語、フレームワーク、構造などを「明示的」であると称賛するのをよく耳にします。私はこの論理を理解しようとしています。言語やフレームワークなどの目的は、複雑さを隠すことです。あらゆる種類の詳細を明示的に指定する場合、複雑さを隠しているわけではなく、移動しているだけです。明示性の何がそんなに優れているのか、複雑さを隠すという目的を果たしながら、言語/フレームワーク/API をどのように「明示的」にしますか?
13 に答える
明示的か暗黙的かは、状況によって異なります。多くの場合、複雑さを隠そうとするという点であなたは正しいです。また、自動的に裏で行われている特定のことは良いことです。カプセル化など
フレームワークやコンストラクトは、本来隠してはならないことを隠してしまうことがあります。時には特定の情報や設定が隠されているため、何が起こっているのかわかりません。私たちが理解しておらず、判断できないという仮定がなされています。私たちが予測できない行動が起こります。
カプセル化:良好。隠蔽:悪い。適切な電話をかけるには経験が必要です。ロジックが属する場合は、明示的である必要があります。
例: 一連のダースのコードビハインド ページから約 90 行のコードを削除したことがあります。そこに属していないデータアクセスコード、ビジネスロジックなど。それらを基本ページと主要なビジネス オブジェクトに移動しました。これは良かったです (カプセル化、関心の分離、コード編成、デカップリングなど)。
その後、これらのページの多くからコードの最後の行を削除して、ベース ページに移動できることに興奮しました。url からパラメータを取得し、それをビジネス オブジェクトに渡す行でした。いいですよね?いやいや、これはまずい(隠れていた)。このロジックは、すべてのページでほぼ同じ行でしたが、ここに属していました。UI の意図とビジネス オブジェクトを関連付けました。明示的である必要があります。そうでなければ、私はカプセル化ではなく、隠れていました。その行があれば、そのページを見ている人は、そのページが何をしたのか、そしてその理由を知ることができます。それがなければ、何が起こっているのかを判断するのは困難です。
明示的とは、それを使用するときにそれが何をしているのかを正確に知ることを指すと私は信じています。それは、複雑な部分である、それがどのように行われるかを正確に知ることとは異なります.
明示的が良いというより (確かに密接に関連する冗長は悪い) というよりは、暗黙的がうまくいかない場合に、WTF が進行中であることを伝えるのが非常に難しいということです。
C++ を 10 年か 20 年ハックすれば、私の言いたいことが正確に理解できるでしょう。
意思表示についてです。デフォルトが誤って残されているのか、それとも意図的に残されているのか、読者にはわかりません。明確にすることで、その疑いが取り除かれます。
コードは書くよりも読むほうが難しい。重要なアプリケーションでは、コードの特定の部分は、書かれるよりも頻繁に読み取られます。したがって、できるだけ読み手にわかりやすいようにコードを書く必要があります。明らかでない多くのことを行うコードは、読みにくい (というか、読んでも理解しにくい) ものです。したがって、明示性は良いことと見なされます。
デフォルトの動作に依存すると、言語やフレームワークなどに詳しくない人々から重要な詳細が隠されます。
Perl を知らない人にとって、略記に大きく依存する Perl コードを理解するのがいかに難しいかを考えてみてください。
明示的か暗黙的かということは、何を隠し、何を見せるかがすべてです。
理想的には、ユーザーが気にかけている、または気にかけなければならない (気にかけたいかどうかにかかわらず) 概念を公開します。
明示的であることの利点は、特に失敗した場合に、何が起こっているのかを追跡して見つけるのが簡単になることです。たとえば、ログを記録したい場合、ログ用のディレクトリで明示的な初期化を必要とする API を使用できます。または、デフォルトを使用できます。
明示的なディレクトリを指定して失敗した場合、その理由がわかります。暗黙的なパスを使用して失敗した場合、何が問題なのか、その理由は何か、どこを参照すれば修正できるのかわかりません。
暗黙的な動作は、ほとんどの場合、消費者から情報を隠した結果です。たとえば、自分の環境に "答え" が 1 つしかないことがわかっている場合などです。ただし、情報を非表示にするタイミングとその理由を把握し、消費者が本質的に複雑なアイテムを非表示にせずに、消費者の意図のレベルに近づけるようにすることをお勧めします。
多くの場合、暗黙的な動作は、環境を見て正しい動作を推測しようとする「自己構成」オブジェクトの結果です。私は一般的にこのパターンを避けます。
私がおそらく全体的に従うであろう 1 つの規則は、特定の API に対して、すべての操作は明示的または暗黙的のいずれかであるべきであり、決して組み合わせてはならないということです。操作をユーザーがしなければならないものにするか、ユーザーが考える必要のないものにします。最大の問題に遭遇するのは、これら2つを混在させるときです。
フレームワークなどは、実行するジョブに適切な抽象化を提供することで、明示的かつ複雑さを隠すことができます。
明示的であることにより、他の開発者は元の開発者が何を意味するのかを調べて理解することができます。
複雑さを隠すことは、暗黙的であることと同じではありません。この場合、内部で何が行われているのかを理解しようとすることは、リバース エンジニアリングに似ているため、暗黙的であると、それを書いた人だけが理解できるコードになります。
明示的なコードには、正しいことが証明される理論的な可能性があります。この点で、暗黙的なコードは決してチャンスではありません。
明示的なコードは保守可能ですが、暗黙的なコードはそうではありません。これは、正しいコメントを提供し、慎重に識別子を選択することにつながります。
「明示的な」言語を使用すると、コンピューターは、あまり明示的でない言語では見つけられないソフトウェアのバグを見つけることができます。
たとえば、C++ には、const
値が変更されてはならない変数のキーワードがあります。プログラムがこれらの変数を変更しようとすると、コンパイラはコードが間違っている可能性が高いと判断できます。
コードの読者に意図したことを明確にするという文脈では、明示的であることが望ましいです。
多くの例がありますが、それはあなたの意図に疑いを残さないことです.
たとえば、これらはあまり明示的ではありません。
while (condition);
int MyFunction()
bool isActive; // In C# we know this is initialised to 0 (false)
a = b??c;
double a = 5;
double angle = 1.57;
しかし、これらは次のとおりです。
while (condition)
/* this loop does nothing but wait */ ;
private int MyFunction()
int isActive = false; // Now you know I really meant this to default to false
if (b != null) a = b; else a = c;
double a = 5.0;
double angleDegrees = 1.57;
後者の場合、誤解の余地はありません。前者は、誰かがそれらを注意深く読まなかったり、何かを行うための読みにくい構文を明確に理解していなかったり、整数型と浮動小数点型を混同したりすると、バグにつながる可能性があります。
優れた抽象化は複雑さを隠しません。コンパイラーに任せるのが最善の決定を下します。
ガベージ コレクションを検討してください。リソースを解放する複雑さは、(おそらく) プログラマーであるあなたよりも決定を下す資格のあるガベージ コレクターに委任されます。それはあなたの手から決定を下すだけでなく、あなたが自分で持っているよりも良い決定を下します.
明示性は (場合によっては) 良いことです。なぜなら、場合によってはプログラマーに任せた方がよい特定の決定が、資格の低いエージェントによって自動的に行われないようにするからです。良い例は、C 型言語で浮動小数点データ型を宣言し、整数に初期化する場合です。
double i = 5.0;
代わりに、次のように宣言する場合
var i = 5;
コンパイラは、int が必要であると当然想定し、後で操作が切り捨てられます。
場合によっては、その反対が「魔法」です。 「その後、奇跡が起こる」などです。
開発者が何が起こっているのかを理解したりデバッグしたりしようとしてコードを読むとき、明示性は美徳になり得ます。
フレームワークが物事を移動させる目的は、コードの重複を取り除き、全体を壊すことなくチャンクを簡単に編集できるようにすることです。SUM(x,y); のように、何かを行う方法が 1 つしかない場合。私たちはこれが何をするのかを正確に知っており、書き直す必要がある理由はありません。その反対は、非常に複雑な関数を提供する .NET のようなプログラミング言語です。明らかな単純な例以外のことを行う場合、しばしば書き直す必要があります。