すべてのプログラマーが知っておくべき9つのアンチパターン

プログラミングにおいて、自己批判とは、設計、コード、プロセス、および動作における非生産的な決定を認識する能力です。 有害な決定テンプレートについて知ることは、プログラマーにとって有益です。 この記事では、私の個人的な経験でときどき経験したアンチパターンについて説明します。



それらのいくつかは人間の意識の認知的歪みに直接または間接的に関連しています-これらの場合、対応するwiki記事へのリンクを提供します。 興味深いのは、既知の認知バイアスのリストです。



1時期尚早の最適化



97%のケースでは、プログラムの小さな部分の有効性を忘れなければなりません。早すぎる最適化はすべての悪の根源です。 ただし、3%のケースでは、最適化を忘れてはなりません。

ドナルドホイップ


多くの場合、今よりも良くなることはありませんが

Pythonの禅、ティムピーターズ




これは何ですか


最適化。どこでどのように実施するかについて、十分な情報に基づいた決定を下すために必要なすべての情報を入手する前に実行されます。



なぜ悪い


実際には、ボトルネックが発生する場所を予測することは困難です。 経験的な結果を得るために最適化しようとすると、より複雑なコードとエラーが発生しますが、メリットはありません。



避ける方法


まず、よく知られた実績のあるアルゴリズムとツールを使用して、クリーンで読みやすい、実用的なコードを記述します。 必要に応じて、プロファイリングツールを使用してボトルネックを見つけます。 推測や推測ではなく、測定値に依存します。



例とサイン


プロファイリング前のキャッシュ。 数学的に正しいアルゴリズムの代わりに、複雑で実績のないヒューリスティックルールを使用する。 負荷がかかった状態でうまく動作しない、テストされていない新しいフレームワークの選択。



難しさは何ですか


最適化が時期尚早になる時期を知ることは困難です。 事前に成長の余地を残すことが重要です。 最適化と成長を容易にするソリューションとプラットフォームを選択する必要があります。 不良コードの言い訳として、時期尚早な最適化を使用することもできます。 たとえば、O(n 2 )アルゴリズムを使用するのは、単にO(n)アルゴリズムがより複雑だからです。



長すぎて読めない


最初のプロファイリング、次に最適化。 経験的に得られたデータがそれを主張するまで、単純さを効率に変えないでください。



2 Bikeshedding



約transl。-アングロサクソン語は動詞を思い付くのが好きです。この用語は「自明のパーキンソンの法則」とも呼ばれ、このパーキンソンが、人々があらゆる種類のナンセンスで会議に時間を費やすことを好むことに気付いた後に登場しました具体的には、原子力発電所の設計者は、自転車シェルターにどの材料を入れるべきかについて非常に長い間議論していました(bike-shed )。

定期的に会話を中断して、活版印刷とページの色について話し合いました。 各議論の後、私たちは投票しました。 前回の会議で選んだ同じ色に投票するのが最も効果的だと思いましたが、私は常に少数派でした。 最後に、赤を選択しました(ただし、最終的には青になりました)。

リチャード・ファインマン、「なぜ他の人があなたのことを考えているのかわからないのですか?」




画像



これは何ですか


些細で主観的なことを議論する時間を無駄にする傾向。



なぜ悪いの


時間の無駄。 このテーマに関するPaul-Khening Campからの詳細な手紙



避ける方法


他のチームメンバーにこの傾向を思い出させてください。これらの場合、主なことは意思決定を迅速に行うことです(コインを投げる、投票するなど)。 ユーザーインターフェイスなどの場合は、チームで議論するのではなく、A / Bテストを参照してください。



例とサイン


背景色やインターフェースのボタンの位置について議論したり、コードでスペースの代わりにタブを使用したりするのに何時間も何日も費やされます。



難しさは何ですか


Bikesheddingは、時期尚早の最適化よりも見つけやすく、予防しやすいです。 決定を下し、タスクの複雑さと比較するのにかかる時間に注意してください。



長すぎて読めない


単純な解決策に多くの時間を費やさないでください。



3分析的麻痺



何かを予測したいという欲求、それが単純で効果的であるときに行動することを嫌がる、思考の明快さの欠如...

ウィンストン・チャーチル、議会での議論


今ではないより良い

Pythonの禅、ティムピーターズ




これは何ですか


進行と行動が停止するほどの過剰な分析があります。



なぜ悪い


分析が多すぎると、進行が遅くなったり停止したりすることがあります。 深刻な場合、分析結果は準備が整うまでに不要になるか、プロジェクトでさえ分析フェーズを終了しません。 情報が多いほど、難しい決定を下すのに役立つようです。 有益な歪み許容度錯覚を参照してください。



避ける方法


反復と改善に注意してください。 各反復は、より意味のある分析に使用できるフィードバックと情報を提供します。 この情報がなければ、分析は推測に過ぎません。



例とサイン


プロジェクト、データベースインターフェイス、または構造の要件の分析に費やした月と年。



難しさは何ですか


計画、要件の分析、設計から実装とテストに移行する時期を理解することは困難です。



長すぎて読めない


過剰に分析して推測する代わりに、インクリメンタル開発を使用します。



神の4つのクラス



単純なものは複雑なものよりも優れている

Pythonの禅、ティムピーターズ


これは何ですか


他の多くのクラスを制御するクラスには、多くの依存関係と多くの責任があります。



なぜ悪い


神のクラスは、サポートの悪夢になるまで成長します。 それらは1つの責任の原則に違反します。ユニットテスト、デバッグ、文書化を行うのは困難です。



避ける方法


明確に定義され、単体テストされ、文書化された単一の責任で、責任を小さなクラスに分割します。



例とサイン


「manager」、「controller」、「driver」、「system」、または「engine」という名前のクラスを探します。 他のクラスをインポートしたり、他のクラスに依存したり、他の多くのクラスを制御したり、メインアクティビティに関係のないものを処理する多くのメソッドを持つクラスを疑って見てください。



難しさは何ですか


プロジェクト、リクエスト、およびプログラマーの数が増えており、小さな専門クラスが徐々に神のクラスに変わりつつあります。 そのようなクラスのリファクタリングは、その後多くの時間がかかります。



長すぎて読めない


責任と依存関係が多すぎる大規模なクラスを避ける



5クラス追加の恐怖



疎は密よりも優れている

Pythonの禅、ティムピーターズ


これは何ですか


クラスの数を増やすと設計が複雑になるという信念は、新しいクラスを追加したり、大きなクラスを小さなクラスに分割したりすることを恐れます。



なぜ悪いの


クラスを追加すると、複雑さが軽減されます。 糸のいくつかの小さなボールを解くのは、1つの大きなボールより簡単です。 保守と文書化が容易なクラスの中には、多くの依存関係を持つ1つの大きく複雑なクラス(神のクラス)よりも望ましいものがあります。



画像



避ける方法


クラスを追加すると、設計が簡素化され、コードの一部間の不要な接続が切断される場所に注意してください。



例とサイン


class Shape: def __init__(self, shape_type, *args): self.shape_type = shape_type self.args = args def draw(self): if self.shape_type == "": center = self.args[0] radius = self.args[1] # Draw a circle... elif self.shape_type == "": pos = self.args[0] width = self.args[1] height = self.args[2] # Draw rectangle...
      
      







次に、以下と比較します。



 class Shape: def draw(self): raise NotImplemented(" Shape    'draw'.") class Circle(Shape): def __init__(self, center, radius): self.center = center self.radius = radius def draw(self): #  ... class Rectangle(Shape): def __init__(self, pos, width, height): self.pos = pos self.width = width self.height = height def draw(self): #  ...
      
      







この例はかなり明白ですが、条件付きロジックまたは複雑なロジックを持つ大規模なクラスは通常、より単純なクラスに分解する価値があることを示しています。 最終コードにはさらに多くのクラスがありますが、より簡単になります。



難しさは何ですか


クラスの追加は万能薬ではありません。 大規模なクラスを分割して設計を簡素化するには、責任と要件の領域を深く分析する必要があります。



長すぎて読めない


クラスの数が多いということは、デザインが悪いという兆候ではありません



6内部プラットフォームの効果



Unixを理解していない人は、その悪いコピーを再発明する運命にあります

ヘンリー・スペンサー


かなり複雑なCまたはFortranプログラムには、Common Lisp言語の半分の、新しく記述された、不特定の、バグがあり、遅い実装が含まれています。

グリーンスパンの第10規則


これは何ですか


複雑なソフトウェアシステムが動作するプラットフォームの機能またはそれらが記述されている言語を再発明する傾向。



なぜ悪いの


プラットフォームレベルのタスク-タスクプランニング、ディスクバッファーなど 正しく実装するのは簡単ではありません。 悪い決定は、特にシステムの成長とともに、しばしばボトルネックとエラーを引き起こします。 言語の助けを借りて既に可能なものの代替構造を再構築すると、コードがより複雑になり、初心者の学習曲線が長くなります。 また、リファクタリングおよびコード分析ツールの利点も制限されます。



避ける方法


プラットフォームまたはオペレーティングシステムの利用可能な機能とプロパティを使用します。 既存の言語と競合する言語構造を作成しないでください(特に新しい言語に慣れておらず、古い言語を見逃している場合)。



例とサイン


データベースをタスクキューとして使用する。 OS機能を使用する代わりにディスクバッファを再発明します。 PHPでWebサーバーのタスクマネージャーを作成します。 Pythonのような構造をサポートするためにCでマクロを定義します。



難しさは何ですか


ごくまれに、プラットフォームで使用可能な機能(JVM、Firefox、Chromeなど)を再作成する必要がある場合があります。



長すぎて読めない


OSまたはプラットフォームにすでに存在する機能の再発明は避けてください。



7魔法の数字と線



明示的は暗黙的よりも優れています

Pythonの禅、ティムピーターズ


これは何ですか


コードで名前付き定数の代わりに、名前のない数字または文字列定数を使用します。



なぜ悪いの


説明的な名前がなければ、数字や文字列の意味は私たちから隠されています。 これにより、コードの理解が複雑になり、定数を変更する必要があるとエラーが発生する可能性があります。 次のコードを検討してください。



 def create_main_window(): window = Window(600, 600) #  .....
      
      







これらの数字は何ですか? 最初が幅、2番目が高さだとします。 将来、幅を800に変更する必要がある場合、検索して交換することにより、偶然同じ高さをフックすることが可能になります。



名前のない文字列定数を使用するとエラーが発生しにくくなりますが、ローカライズが複雑になり、同じ文字列を異なる意味で使用するためにエラーが発生する可能性があります。 「ドット」という単語は、ピクセル、句読点、または推論の終わりを意味する場合があります-結果として、単語の検索と置換はエラーにつながります。 これは、文字列を外部から文字列を取得するメカニズムに置き換えることで回避できます。



避ける方法


名前付き定数を使用し、外部からリソースを取得することを意味します



例とサイン


上に与えられた。 このアンチパターンは簡単に認識できます。



難しさは何ですか


使用される数字が魔法かどうかを言うのは難しい場合があります。 インデックス付けがゼロから始まる言語では0。 利息を計算する場合は100、パリティを計算する場合は2など



長すぎて読めない


名前や説明のない数字や文字列定数の使用は避けてください。



8量による管理



コードの行数でプログラマの進捗を測定することは、飛行機を組み立てる進捗を重量で測定することと同じです。

ビルゲート


これは何ですか


数値のみに基づいて決定を下します。



なぜ悪いの


数字は良いです。 最初の2つのアンチパターン、時期尚早な最適化と自転車脱落は、A / Bテストといくつかの定量的な結果で回避する必要があります。 しかし、数字だけに基づくのは危険です。 たとえば、数字は意味のあるモデルを生き延びたり、モデルが古くなって現実を正しく反映しなくなったりします。 これは、特に自動的に行われる場合(自動化のゆがみ )に、不適切な決定につながります



画像



もう1つの問題は、意思決定に数字を使用することです(単純な通知には使用しません)。測定プロセスを操作して、目的( オブザーバーと期待の効果)を達成できます。 Wireシリーズは、警察署と教育システムが意味のある目標から数字ゲームに移行した様子をカラフルに示しています。 次のグラフは、この問題を示しています。 テストのグレードの分布を示します。テストに合格するための最小グレードは30です。



画像



避ける方法


盲目的にではなく、次元と数字を賢く使いましょう。



例とサイン


行数、コミット数などを使用する プログラマーの有効性を評価する。 オフィスで過ごした時間数で従業員のパフォーマンスを測定します。



難しさは何ですか


会社が大きくなるほど、より多くの意思決定が必要になり、自動化とブラインドナンバーへの信頼が強くなり、そのプロセスに浸透し始めます。



長すぎて読めない


意思決定の基礎としてではなく、数字を使用して通知します



9役に立たない(ポルターガイスト)クラス



どうやら、完璧は、追加するものがないときではなく、奪うものがないときに達成されます。

アントワーヌドサンテグジュペリ


これは何ですか


依存関係のない役に立たないクラスは、別のクラスのメソッドを呼び出したり、単純に不要な抽象化レイヤーを追加するために使用されます。



なぜ悪い


Poltergeistクラスは、複雑さとサポートおよびテスト用のコードを追加し、コードを読みにくくします。 ポルターガイストが何をするか(そしてほとんど何もしない)を決定し、その使用を実際に機能するクラスで精神的に置き換えるように訓練する必要があります。



避ける方法


役に立たないクラスを作成して、可能な限りそれらを削除しないでください。



例とサイン


数年前、私が卒業証書に取り組んでいたとき、私はJavaで新入生のプログラミングを教えました。 ラボの1つでは、スタックとリンクリストの使用に関するトピックが提供されました。 そして、彼らは私に「解決策」を与えました。 これがそのような決定です。ほぼ文字通りです。



 import java.util.EmptyStackException; import java.util.LinkedList; public class LabStack<T> { private LinkedList<T> list; public LabStack() { list = new LinkedList<T>(); } public boolean empty() { return list.isEmpty(); } public T peek() throws EmptyStackException { if (list.isEmpty()) { throw new EmptyStackException(); } return list.peek(); } public T pop() throws EmptyStackException { if (list.isEmpty()) { throw new EmptyStackException(); } return list.pop(); } public void push(T element) { list.push(element); } public int size() { return list.size(); } public void makeEmpty() { list.clear(); } public String toString() { return list.toString(); } }
      
      







読んだときの混乱を想像してください。LabStackクラスが必要な理由と、このような役に立たない演習から学生が理解することを理解しようとしています。 これがまだ明確でない場合、このクラスは何もしません。 LinkedListオブジェクトに呼び出しを渡すだけです。 また、いくつかのメソッドの名前を変更し(clearではなくmakeEmpty)、さらに混乱を招きます。 LinkedListのメソッドは同じことを行うので、エラーチェックロジックは必要ありません(単に別の例外NoSuchElementExceptionを介して)。 今日まで、私はこの資料の著者の頭の中に何があったのか理解できません。



難しさは何ですか


一見すると、このアドバイスは「クラスを追加することへの恐怖」セクションのアドバイスとは反対になります。 クラスが重要な役割を果たし、設計を簡素化する時期と、役に立たない方法で複雑さを増大させる時期を理解することが重要です。



長すぎて読めない


本当の責任のないクラスを避けてください。



All Articles