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

コピー&ペーストはパッケージングの敵です
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コンポーネントの開発詳細

推薦する

Mac Docker x509証明書の問題を解決する

質問最近、プライベートミラーセンターにログインする必要がありましたが、ログイン時にエラーメッセージが...

MySQL で日付時刻データを取得し、その後に .0 を追加する方法

MySQL のデータ型は datetime です。データベースに保存されているデータは 2015-0...

React 関数コンポーネントのパフォーマンス最適化のアイデアの詳細な説明

最適化のアイデア最適化には主に 2 つの方向があります。再レンダリングの回数を減らします。 Reac...

WeChatアプレットタブの左右スライドスイッチ機能実装コード

効果画像: 1. はじめに独自のアプレットでこのような機能を実装する必要がある1. 核となる考え方ス...

MySQL CHARとVARCHARの保存と読み取りの違い

導入保存時と読み取り時に CHAR 型と VARCHAR 型の違いを本当にご存知ですか?まずいくつか...

Win10 64 ビットで圧縮パッケージを使用して最新の MySQL 8.0.18 をインストールするチュートリアル (画像とテキスト付き)

WIN10 64ビットに最新のMySQL8.0.18をインストールダウンロード公式サイトから最新バ...

JavaScript でプロトタイプ パターンを実装する方法

概要プロトタイプ パターンは、プロトタイプ インスタンスによって作成されるオブジェクトの型を指し、こ...

Hadoop を使用せずに Linux 環境に Spark のスタンドアロン バージョンをインストールする方法

ビッグデータはますます注目を集めており、ビッグデータのいくつかの構成要素に精通していないと、自慢でき...

WeChatミニプログラムページで値を返す4つの解決策のまとめ

目次使用シナリオ解決1. globalDataを使用して実装する2. ローカルキャッシュストレージを...

CSS リスト モデルでのマーカー タグの使用

この記事では主に、 list-itemの下にある::master疑似要素、 list-style-i...

JavaScript における継承の 3 つの方法

継承する1. 継承とは何か継承: まず、継承とは関係、つまりクラス間の関係です。JS にはクラスはあ...

表には表示したい境界コードが表示されます

テーブルの共通プロパティ基本的な属性は、width (幅)、height (高さ)、border (...

WangEditor リッチ テキスト コンポーネントを Angular でカプセル化する方法

リッチ テキスト コンポーネントは、Web プログラムで、特にブログやフォーラムなどの Web サイ...

CSS3 テキストシャドウ text-shadow プロパティの詳細な説明

テキストシャドウ text-shadow プロパティの効果: 1. 右下隅の影、左下隅の影、左上隅の...

Ubuntu 18.04 のログインループ/ブートインターフェイスで停止/グラフィカルインターフェイスに入ることができない問題を解決する方法

原因: NVIDIA グラフィック カード ドライバーが破損している解決:コマンドラインモードで再起...