コピー&ペーストはパッケージングの敵です

コピー&ペーストはパッケージングの敵です
OO、デザイン パターン、および多くのオブジェクト指向の原則について話す前に、まず 1 つのことを習得する必要があります。それは、カプセル化です。カプセル化の原理と技術を習得すると、OO 言語を使用していなくても美しいフレームワークを持つプログラムを構築できるようになります。これらの原則をプログラム外に適用すると、驚くべき結果が得られることもあります。 「設計ルール - モジュール化の力」(http://www.douban.com/subject/1737636/) では、カプセル化とモジュール化を重視しており、この位置づけにふさわしいものです。これは、複雑な問題を解決するために使用する最も基本的な方法です(他にはありません)。

プログラムは複雑なシステムです。 「道は一つを生み、一つは二つを生み、二つは三つを生み、三つは(四つ、四つは…)万物を生む。」複雑さの源泉が「道」の変容であると考えられるならば、この「一つ」はカプセル化であるに違いありません。さまざまなプログラミング言語と、これらのプログラミング言語から派生したメソッドは、「2 番目」の位置にあり、たとえば、OO 設計パラダイム、FP (関数型プログラミング) パラダイム、階層化の原則などがあります。リスコフの置換原則や継承よりも優先される合成などのオブジェクト指向設計原則は「3 番目」の位置にあり、特定の設計パターンなどは「3 番目」の後の「4 番目」の位置にあります。

私は愚かなので、リスコフの置換原則とは何か、このモデルやあのモデルをどのように実装するかなど、それらの原則をまだ思い出せません。デザインパターンの中では戦略パターンにのみ興味があり、他のパターンにはあまり興味がありません。本質的には、これらのパターンや原則は、カプセル化をより適切に実装するための方法とツールを提供するだけです。

コピー アンド ペーストはカプセル化の敵であり、醜いコードの最大の悪臭です。 1 回コピーすることは、少なくとも 1 つの変数ポイントを追加することと同じであり、2 回コピーすることは、少なくとも 2 つの変数ポイントを追加することと同じです。なぜ「少なくとも」と言うのでしょうか? モジュール間には関連性があるため、1 か所の変更によって他の複数の場所でも変更が発生します。 S がシステム自体、M がシステム自体の測定値、C がシステム S 内のモジュールのコピーの平均数 (C>1) であると仮定すると、M と C の関係は指数関係になるはずです。つまり、M は C の N 乗 (N>1) に比例します。

指数関数的な関係だけでも十分恐ろしいのですが、さらに恐ろしいのは、システム内のモジュールが変更されたときに、そのモジュールがシステム内に複数のコピーを持っている場合、私たちが怠惰になり、すべてのコピーを変更するのではなく、コピーの 1 つだけを変更する可能性があることです。これにより、モジュールが 1 つのモジュールから複数の類似しているが異なるモジュールに分割され、システムの複雑さが大幅に増加し、最終的にはシステムが腐敗することになります。直感的に言えば、設計が不十分なシステムの複雑さは、モジュールの数の階乗関係、あるいはべき乗関係にほぼ相当し、指数関係よりも恐ろしい関係です。

したがって、コピー&ペーストは非常に邪悪なコーディング方法です。コーディングするときは、コピーと貼り付けを減らす方法を見つける必要があります。これは、リファクタリング フェーズ中に行うものではなく、コーディング中に考慮する必要があるものです。どのような方法、手段、モデルを使用するかは、すべて細かい問題です。

コピー&ペーストをせず、それを貫くと、大きなメリットが得られ、作成するコードは高品質で価値の高いものになります。他の人のシステムを見ると、そのシステムの利点と欠点がすぐにわかります。デザインパターン、インターフェースの直交性、デザイン原則など、これまで意識的に勉強したことがないかもしれませんが、最終的にはすべてが同じ目的地につながることがわかり、海外の専門家とのつながりを感じることができます。私たちは、これらの専門家のアイデアや方法を自発的に組み合わせて改善し、さらには新しい方法や手段を生み出していきます。 3 と 4 を教条的かつ崇拝的な方法で学ぶのではなく、1 から直接始め、1 が 2 を生み、2 が 3 を生み、3 が 4 を生むようにします。おそらく、その時点では、オブジェクトが何であるかを忘れているでしょう。

私が文句を言っている理由は、昨日から今日にかけて、モジュールをリファクタリングしているからです。このモジュール M1 のコア コンポーネントは、RTF からラップされたレイアウト ルール エディターです。このコア コンポーネントを設計した人は、RichTextBox を中心としたコントロール A を設計し、このコントロールのルール ロジックの一部を抽出して、クラス B とクラス C の静的メソッドに配置しました。さらに驚くべきことは、クラス B は別のモジュール M2 にあり、クラス C はモジュール M1 にあることです。このコントロールは、M1 の 3 つの場所 (D、E、F) で使用されます。D、E、F のそれぞれで、このスペース A に対して 7 つまたは 8 つのイベントを登録し、イベント コールバック関数でモジュール M2 のクラス B の静的メソッドとモジュール M1 のクラス C の静的メソッドを呼び出して、何らかのロジックを実装する必要があります。ここで、コントロール G を記述したいのですが、この G にはコントロール A も必要です。この場合、G の A のイベントとコールバック関数を多数登録し、コールバック関数に一連のロジックを配置する必要があります。これには少なくとも 200 行のコードが必要になります。これらのコールバック関数を記述するには、コントロール A とクラス B および C の内部動作メカニズムを理解する必要があります。つまり、豚肉を食べるためには、自分で豚を殺さなければならないのです。もちろん、時間を節約するために、D、E、または F からコードをコピーして変更することもできます。

深刻な問題は、制御 A 自体に論理エラーと不完全な機能があり、修復する必要があることです。あらゆる場所に複製されるため、1 回の動作が全身に影響します。A に手術を行う場合は、B、C、D、E、F にも手術を行う必要があります。 A を整形する際に、コンパイルするために、B、C、D、E、F の A に関係するコードをすべてコメントアウトし、合計で約 1,500 行のコードをコメントアウトしました。実際、この 1500 行のコードのうち、本当に価値のあるコードは 200 行程度しかなく、残りのコードはすべてコピー、貼り付け、変数名の変更によって完成しています。

なぜこの問題が発生するのでしょうか?コピー&ペーストのためです。コピー&ペーストは簡単です。パッケージングについて考える時間を費やすことなく、いくつかの単語をコピーして変更するだけで使用できます。実際の状況は、コントロール A を参照するために、200 行から 300 行のコードを書かなければなりません。複数の場所で参照する場合は、1,000 行以上のコードを書かなければなりません。コピー アンド ペーストは面倒ではありませんが、A にエラーがあることがわかった場合、または拡張する必要がある場合、A を変更するときに、この 1,000 行のコードも移動する必要があります。この 1,000 行のコードには、さらに多くのコードが含まれる可能性があり、最終的にはさらに多くのコードを修正する必要が生じます。これがコードの腐敗です。

実際、この A は非常にうまくカプセル化されています。他のクラスが入力データを入力する必要はありません。他のクラスは、A コントロールから最終的なルール結果であるリストを取得するだけで済みます。カプセル化が適切であれば、A を呼び出して結果を取得することは 2 行または 3 行のコードで実現できます。

カプセル化しない理由は、コピー&ペーストに慣れているから、カプセル化するのが面倒だから、あるいはカプセル化するという考えがまったくないからです。

多くの新人プログラマー、あるいはそれほど新人ではないプログラマー、特に Web 開発プログラマーは、自分の仕事の技術的内容が低いことに常に不満を抱いており、常にもっと学びたいと考えています。本質的に、彼らが行う仕事は非常に技術的であり、それはすべてあなたがそれをどのように見るかによって決まります。

自分の作品を単なるコピー、貼り付け、盗作、コード改変としか捉えていない場合、技術的な内容は当然低くなります。いかにしてコピー&ペーストを排除し、品質と進捗を向上させ、作業において不要なものを排除し、あらゆる無駄を排除するかが仕事だと捉えれば、この仕事の技術的内容は極めて高いと言えます。主人を崇拝してはいけません。そうすると、主人の仕事をしていることになります。新しいテクノロジーを崇拝しないでください。崇拝すると、あなたの仕事が新世代のテクノロジーの萌芽となる可能性があります。あらゆるもの、あらゆる色、あらゆる香り、すべてが私の心の中にあります。緑の竹はすべて法身であり、青々とした黄色い花はすべて般若です。

<<:  複数の Tomcat を展開して起動し、プロジェクトを移行する方法を 1 つの記事で学習します。

>>:  Vue3コンポーネントの開発詳細

推薦する

MySQL の InnoDB ストレージ ファイルの詳細な説明

物理的に言えば、InnoDB テーブルは、共有テーブルスペース ファイル (ibdata1)、排他テ...

MySQL で絵文字表現を挿入できない理由と解決策

失敗のシナリオMySQL データベースに絵文字表現を挿入するために JDBC を呼び出すと、例外ja...

React、Angular、Vueの3つの主要なフロントエンド技術の詳細説明

目次1. 反応する基本的な使い方注目すべき機能クラスコンポーネント仮想DOMライフサイクルメソッドJ...

Dockerfile を使用して nginx イメージを構築する例

Dockerfile の紹介Docker は、Dockerfile の内容を読み取ってイメージを自動...

Vue の element-ui コンポーネントのデフォルトの CSS スタイルを変更する 4 つの方法

目次序文1. グローバル統合オーバーライドを使用する2. .vueファイルを変更する3. コンポーネ...

JS ES6 変数分割代入の詳細な説明

目次1. 脱構築とは何か? 2. 配列の分割3. 配列モードと代入モードの統一4. デフォルト値の構...

MySQLでデータをエクスポートするいくつかの方法の詳細な説明

MySQL データをエクスポートする目的は、データベースのバックアップ、テーブル構造のエクスポート、...

インデックスを使用して数千万のデータを持つ MySQL のクエリ速度を最適化する

1. インデックスの役割一般的に言えば、インデックスは本の目次に相当します。条件に基づいてクエリを実...

Nginx10m+の高並列カーネル最適化に関する簡単な説明

高い同時実行性とは何ですか?デフォルトの Linux カーネル パラメータは、最も一般的なシナリオ向...

Vue-cliフレームワークはタイマーアプリケーションを実装します

技術的背景このアプリケーションは vue-cli フレームワークを使用し、カスタム コンポーネント ...

MySQL ステートメントコメントの紹介

MySQL は次の 3 種類のコメントをサポートしています。 1. 行末の「#」文字から。 2. 「...

LAMP ソースコードを使用したエンタープライズレベルのインストールチュートリアル

目次LAMPアーキテクチャ1.ランプの紹介2. WebサービスワークフローWebサーバーのリソースは...

MySQL で浮動小数点データを文字データに変換するときに起こりうる問題の詳細な説明

序文この記事は主に、MySQL で浮動小数点型を文字型に変換するときに発生する問題を紹介します。これ...

パスワードログインなしのLinux構成スタンドアロンおよびフルディストリビューションの詳細なチュートリアル

目次1: 単一マシンのパスワードフリーログイン構成1. 仮想マシンのホスト名を設定する2. 仮想マシ...

nginx アンチホットリンクおよびアンチクローラー設定の詳細な説明

新しい設定ファイルを作成します (たとえば、nginx インストール ディレクトリの下の conf ...