検索

The Wisdom of Avoiding Conditional Statements

循環的複雑度は、コードの複雑さともつれ具合を測定する指標です。

循環的複雑性が高いことは良いことではなく、むしろその逆です。

簡単に言えば、循環的複雑さはプログラム内で可能な実行パスの数に正比例します。言い換えれば、循環的複雑さと条件文 (特にその入れ子) の総数は密接に関係しています。

今日は、条件文について話しましょう。

アンチイフ

2007 年、フランチェスコ・シリロは、アンチイフと呼ばれる運動を開始しました。

フランチェスコ・シリロは、ポモドーロ・テクニックを考案した男です。私は今このブログ記事を「ポモドーロの下」で書いています。

皆さんはその名前から、このキャンペーンが何を意味するのかすぐに理解できたと思います。興味深いことに、この運動の信奉者にはかなりの数のコンピューター科学者が含まれています。

彼らの議論は盤石であり、if ステートメントは邪悪であり、プログラムの実行パスの急激な増加につながります。

一言で言えば、それは循環的複雑さです。値が高くなるほど、コードを読んで理解するだけでなく、テストでカバーすることも難しくなります。

確かに、ある種の「逆」の指標があります。それは、コードのどの程度がテストでカバーされているかを示すコード カバレッジです。しかし、この指標と、カバレッジをチェックするためのプログラミング言語の豊富なツールは、循環的複雑性を無視し、「本能」だけに基づいて if ステートメントを散りばめることを正当化するのでしょうか?

私はそうではないと思います。


ある if を別の if の中に入れ子にしようとしていることに気づくたびに、私は自分が、別の方法で書き換えられる可能性のある本当に愚かなことをしていることに気づきます。それは、if を入れ子にしない、または if をまったく使わないのいずれかです。

「ほぼ」という言葉に気づきましたよね?

私はこれにすぐには気づきませんでした。私の GitHub を見ると、循環的な複雑さが高いだけでなく、まさに循環的な狂気を伴う古いコードの例が複数見つかります。

この問題をより認識するようになったのは何でしたか?おそらく、約 1 年前に私が学んだ経験と、いくつかの賢明な事柄を学び、取り入れたものだと思います。それが今日皆さんと共有したいことです。


if ステートメントを破壊するための 2 つの神聖なテクニック

  1. パダワン、未知の値の各条件チェックを、その値がすでにわかっている場所に移動してください。
  2. パダワン、エンコードされたロジックのメンタル モデルを変更して、条件チェックを必要としないようにしてください。

1. 未知を既知にする

まだ「知らない」ときに何かを確認することは、おそらく「本能」に基づいて条件文を使用する最も一般的な原因です。

たとえば、ユーザーの年齢に基づいて何かをする必要があり、その年齢が有効である (妥当な範囲内である) ことを確認する必要があるとします。次のようなコードになる可能性があります:

from typing import Optional

def process_age(age: Optional[int]) -> None:
    if age is None:
        raise ValueError("Age cannot be null")
    if age  150:
        raise ValueError("Age must be between 0 and 150")

私たちは皆、同様のコードを何百回も見てきましたし、おそらく同じようなコードを書いたことがあるでしょう。

議論されているメタ原則に従って、これらの条件チェックをどのように削除しますか?

年齢に関する具体的なケースでは、私のお気に入りのアプローチを適用できます。つまり、原始的なこだわりから離れ、カスタム データ型の使用に移行します。

class Age:
    def __init__(self, value: int) -> None:
        if value  150:
            raise ValueError("Age must be between 0 and 150")
        self.value = value

    def get_value(self) -> int:
        return self.value

def process_age(age: Age) -> None:
    # Age is guaranteed to be valid, process it directly

万歳、1 つ減りました!年齢の検証と検証は常に「年齢がわかっている場合」、つまり別のクラスの責任と範囲内で行われるようになりました。

Age クラスの if を削除したい場合は、おそらくバリデーターを備えた Pydantic モデルを使用するか、if を Assert に置き換えることによって、さらに別の方法を実行できます。それは今は問題ではありません。


同じメタアイデア内で条件チェックを取り除くのに役立つ他のテクニックやメカニズムには、条件をポリモーフィズム (または匿名ラムダ関数) で置き換えたり、卑劣なブール フラグを持つ関数を分解したりするようなアプローチが含まれます。

たとえば、次のコード (ひどいボクシングですね?):

class PaymentProcessor:
    def process_payment(self, payment_type: str, amount: float) -> str:
        if payment_type == "credit_card":
            return self.process_credit_card_payment(amount)
        elif payment_type == "paypal":
            return self.process_paypal_payment(amount)
        elif payment_type == "bank_transfer":
            return self.process_bank_transfer_payment(amount)
        else:
            raise ValueError("Unknown payment type")

    def process_credit_card_payment(self, amount: float) -> str:
        return f"Processed credit card payment of {amount}."

    def process_paypal_payment(self, amount: float) -> str:
        return f"Processed PayPal payment of {amount}."

    def process_bank_transfer_payment(self, amount: float) -> str:
        return f"Processed bank transfer payment of {amount}."

そして、if/elif を match/case に置き換えても問題ありません。それは同じゴミです!

次のように書き直すのは非常に簡単です。

from abc import ABC, abstractmethod

class PaymentProcessor(ABC):
    @abstractmethod
    def process_payment(self, amount: float) -> str:
        pass

class CreditCardPaymentProcessor(PaymentProcessor):
    def process_payment(self, amount: float) -> str:
        return f"Processed credit card payment of {amount}."

class PayPalPaymentProcessor(PaymentProcessor):
    def process_payment(self, amount: float) -> str:
        return f"Processed PayPal payment of {amount}."

class BankTransferPaymentProcessor(PaymentProcessor):
    def process_payment(self, amount: float) -> str:
        return f"Processed bank transfer payment of {amount}."

そうですか?


ブール値フラグを持つ関数を 2 つの別々の関数に分解する例は、非常に古いものですが、非常に見慣れたものですが、(私の正直な意見では) 信じられないほど面倒です。

def process_transaction(transaction_id: int,
                                                amount: float,
                                                is_internal: bool) -> None:
    if is_internal:
        # Process internal transaction
        pass
    else:
        # Process external transaction
        pass

たとえそれらのコードの 2/3 が同一であっても、2 つの関数はどのような場合でもはるかに優れています。これは、DRY とのトレードオフが常識の結果であり、コードが改善されるシナリオの 1 つです。


The big difference here is that mechanically, on autopilot, we are unlikely to use these approaches unless we've internalized and developed the habit of thinking through the lens of this principle.

Otherwise, we'll automatically fall into if: if: elif: if...

2. Free Your Mind, Neo

In fact, the second technique is the only real one, and the earlier "first" technique is just preparatory practices, a shortcut for getting in place :)

Indeed, the only ultimate way, method — call it what you will — to achieve simpler code, reduce cyclomatic complexity, and cut down on conditional checks is making a shift in the mental models we build in our minds to solve specific problems.

I promise, one last silly example for today.

Consider that we're urgently writing a backend for some online store where user can make purchases without registration, or with it.

Of course, the system has a User class/entity, and finishing with something like this is easy:

def process_order(order_id: int,
                                  user: Optional[User]) -> None:
    if user is not None:
        # Process order for a registered user
       pass
    else:
        # Process order for a guest user
           pass

But noticing this nonsense, thanks to the fact that our thinking has already shifted in the right direction (I believe), we'll go back to where the User class is defined and rewrite part of the code in something like this:

class User:
    def __init__(self, name: str) -> None:
        self.name = name

    def process_order(self, order_id: int) -> None:
        pass

class GuestUser(User):
    def __init__(self) -> None:
        super().__init__(name="Guest")

    def process_order(self, order_id: int) -> None:
        pass

So, the essence and beauty of it all is that we don't clutter our minds with various patterns and coding techniques to eliminate conditional statements and so on.

By shifting our focus to the meta-level, to a higher level of abstraction than just the level of reasoning about lines of code, and following the idea we've discussed today, the right way to eliminate conditional checks and, in general, more correct code will naturally emerge.


A lot of conditional checks in our code arise from the cursed None/Null leaking into our code, so it's worth mentioning the quite popular Null Object pattern.

Clinging to Words, Not Meaning

When following Anti-if, you can go down the wrong path by clinging to words rather than meaning and blindly following the idea that "if is bad, if must be removed.”

Since conditional statements are semantic rather than syntactic elements, there are countless ways to remove the if token from your code without changing the underlying logic in our beloved programming languages.

Replacing an elif chain in Python with a match/case isn’t what I’m talking about here.

Logical conditions stem from the mental “model” of the system, and there’s no universal way to "just remove" conditionals entirely.

In other words, cyclomatic complexity and overall code complexity aren’t tied to the physical representation of the code — the letters and symbols written in a file.

The complexity comes from the formal expression, the verbal or textual explanation of why and how specific code works.

So if we change something in the code, and there are fewer if statements or none at all, but the verbal explanation of same code remains the same, all we’ve done is change the representation of the code, and the change itself doesn’t really mean anything or make any improvement.

以上が条件文を避けるための知恵の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Python:ゲーム、GUIなどPython:ゲーム、GUIなどApr 13, 2025 am 12:14 AM

PythonはゲームとGUI開発に優れています。 1)ゲーム開発は、2Dゲームの作成に適した図面、オーディオ、その他の機能を提供し、Pygameを使用します。 2)GUI開発は、TKINTERまたはPYQTを選択できます。 TKINTERはシンプルで使いやすく、PYQTは豊富な機能を備えており、専門能力開発に適しています。

Python vs. C:比較されたアプリケーションとユースケースPython vs. C:比較されたアプリケーションとユースケースApr 12, 2025 am 12:01 AM

Pythonは、データサイエンス、Web開発、自動化タスクに適していますが、Cはシステムプログラミング、ゲーム開発、組み込みシステムに適しています。 Pythonは、そのシンプルさと強力なエコシステムで知られていますが、Cは高性能および基礎となる制御機能で知られています。

2時間のPython計画:現実的なアプローチ2時間のPython計画:現実的なアプローチApr 11, 2025 am 12:04 AM

2時間以内にPythonの基本的なプログラミングの概念とスキルを学ぶことができます。 1.変数とデータ型、2。マスターコントロールフロー(条件付きステートメントとループ)、3。機能の定義と使用を理解する4。

Python:主要なアプリケーションの調査Python:主要なアプリケーションの調査Apr 10, 2025 am 09:41 AM

Pythonは、Web開発、データサイエンス、機械学習、自動化、スクリプトの分野で広く使用されています。 1)Web開発では、DjangoおよびFlask Frameworksが開発プロセスを簡素化します。 2)データサイエンスと機械学習の分野では、Numpy、Pandas、Scikit-Learn、Tensorflowライブラリが強力なサポートを提供します。 3)自動化とスクリプトの観点から、Pythonは自動テストやシステム管理などのタスクに適しています。

2時間でどのくらいのPythonを学ぶことができますか?2時間でどのくらいのPythonを学ぶことができますか?Apr 09, 2025 pm 04:33 PM

2時間以内にPythonの基本を学ぶことができます。 1。変数とデータ型を学習します。2。ステートメントやループの場合などのマスター制御構造、3。関数の定義と使用を理解します。これらは、簡単なPythonプログラムの作成を開始するのに役立ちます。

プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は?プロジェクトの基本と問題駆動型の方法で10時間以内にコンピューター初心者プログラミングの基本を教える方法は?Apr 02, 2025 am 07:18 AM

10時間以内にコンピューター初心者プログラミングの基本を教える方法は?コンピューター初心者にプログラミングの知識を教えるのに10時間しかない場合、何を教えることを選びますか...

中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか?中間の読書にどこでもfiddlerを使用するときにブラウザによって検出されないようにするにはどうすればよいですか?Apr 02, 2025 am 07:15 AM

fiddlereveryversings for the-middleの測定値を使用するときに検出されないようにする方法

Python 3.6にピクルスファイルをロードするときに「__Builtin__」モジュールが見つからない場合はどうすればよいですか?Python 3.6にピクルスファイルをロードするときに「__Builtin__」モジュールが見つからない場合はどうすればよいですか?Apr 02, 2025 am 07:12 AM

Python 3.6のピクルスファイルのロードレポートエラー:modulenotFounderror:nomodulenamed ...

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

WebStorm Mac版

WebStorm Mac版

便利なJavaScript開発ツール