コードの書き方

私は良いコードを書いていると思うのが好きです。 まあ、または少なくとも私は悪いよりも良いコードを書くこと。



良いコードの私のお気に入りの機能は退屈です。 予測可能な表現、次々。 驚き、トリック、ユニークな機会はありません。 もちろん、メタプログラミングはありません! 退屈なコードは、デバッグ、読み取り、説明が非常に簡単です。



退屈なコードはグローバルな状態を使用せず、副作用を生成せず、それが存在するプロジェクトとの接続を削減しようとします。 値の割り当ては退屈な方法で行われます。これは、各変数に対して1回だけ発生するため、この状態を誰が、いつ変更したかという興味深い調査の可能性から私たちを救います。 退屈なコードは、必要なことだけを行い、暗黙的に表現された仮定に依存しません。



暗黙の動作を使用するコードは、文書化されていないが既に実装されている機能に基づいている場合があります。 たとえば、多くの間違ったコードが世界中で書かれており、ディレクトリのリストをアルファベット順にソートして返すファイルシステム関数に依存しています。 これは実際にそのように機能することがよくありますが、「理解できない」理由で壊れるまで正確です。 しかし実際、このソートを保証した人はいません。



記述したコードが暗黙的な前提に依存している場合、それらを念頭に置く必要があり、それ自体がそのようなコードのサポートを複雑にします。 書かれた用語を読むこととは別に、頭の中に大きな画像を作成する必要があるため(暗黙の部分を考慮に入れて)、作業に戻りたくないだけです。 これには注意が必要です。 また、外部の要因により暗黙的な仮定が崩れ、コードを新しい世界の図と一致させるという苦痛なプロセスが始まることがあります。



残念ながら、暗黙のコードにも代償が伴います。 これは通常、冗長性です。 いくつかのパターンを繰り返し、同様の状況で同様の方法で処理する必要があります。 暗黙のコードは脆弱であり、長期的にはひどい結果になります。 それとは反対の明示的なコードには、戦略的脅威は少ないですが、ここでは勤勉が必要です。



冗長にやりすぎるのは簡単ですが、 Zen of Pythonにはまだ同意しています。「明示的は暗黙的よりも優れています。」 Javaは冗長になりすぎて、ファイルのすべての行を読み取る必要があるたびに、同じ数行のコードを記述する必要があります。 これに代わるものは、この責任を負う何らかのラッパーですが、ある程度の柔軟性を奪います(そして、すべての行を読む必要がある場合、そして順序が正しくない場合、そして最初からではない場合など)。



APIをレイヤーに分割することで、両方の長所を活用しようとしています。 「最下層」はJavaスタイルで記述されています。小さなコンポーネント、単純な動作ですが、それらから本当に有用なものを組み立てるには少し手間がかかります。 「上位」レイヤーは、人間の可読性と実用性を最前線に置きます。ユーザーは、まさにその構造を備えているため、正しい方法でAPIを簡単に使用できます。



APIの2つの層は、私のお気に入りのPythonライブラリの1つである「リクエスト」で見ることができます。 実際に必要となる可能性のあるほとんどのユースケースをカバーする、非常に表現力豊かで人間が読み取れるAPIを提供します。 ただし、ライブラリ内ではurllib3を使用し、HTTPプロトコルの主な作業が行われます。 はい、そのようなシステムを設計するのは簡単ではなく、リクエストの内部実装にはおそらく冗長性がありますが、これはユーザーにどのような使いやすさをもたらしましたか!



私は自分のコードの仕組みのバックボーンを「モジュール」と呼び、補助タスクを実行するコードの断片を「ライブラリ」と呼びます。 これに加えて、アプリケーションのコードをコンポーネントとフレームワークに分割することも好きです。



コンポーネントは、アプリケーションまたはサービスのビジネスロジックが存在する場所であり、フレームワークは、さまざまなコンポーネントを結び付ける接着剤の薄い層です。 アプリケーションを個別のコンポーネントに正しく分解することは重要なタスクです。エンティティをいくつかの個別のエンティティに分割するだけでなく、これが役立つ理由を明確に理解する必要もあります。



David Parnassusの優れた説明を言い換えると、システムの他のコンポーネントから複雑なソリューションまたは将来変更される可能性が高いソリューションを隠すためにコンポーネントが存在します。



ビジネスロジックは、非常にわかりにくいものであっても、急いでカットする必要があるゴーディアンハブであるとは限りません。 コンポーネントを簡単に交換できない場合は、おそらくそれを個別のコンポーネントに分割することから始めるべきではありません。より重要な問題は、システムの他の部分から十分に隠すことができないからです。



コンポーネントはビジネスロジックを相互に隠し、モジュールは実装を隠し、ライブラリはアルゴリズムを隠し、フレームワークはこれを接続するすべてのスレッドを表示すべきではありません。



実際には、これらのパーツ間の境界は、私が説明したほど正確に耐えることができるとは限りません。 ライブラリはモジュールに影響を与え、ビジネスロジックのごく一部がフレームワークに忍び込み、一部のコンポーネントは内部を十分に隠しません。



読み取りや変更の際に完全に頭に留めておく必要のないコードを書きます。 コードをレイヤーに分割し、ビジネスロジックをコンポーネントに分割することはこれに役立つように思えますが、実際には、時間をかけて混乱させたり、さらに悪いことに私を怖がらせるようなコードを書かないようにしています。



退屈なコードを書きます。



All Articles