コードが臭いのは、編集または改善できる可能性が高いためです。
これらの臭いのほとんどは、何かが間違っている可能性があることを示唆するものにすぎません。したがって、それ自体を修正する必要はありません… (ただし、検討する必要があります。)
以前のすべてのコード匂い (パート I ~ XLV) はここで見つけることができます。
続けましょう...
またしても墜落した宇宙船。別のソフトウェアの問題
TL;DR: ソフトウェアを設計してテストします。ハードウェアよりも安い
ルナ 25 号は2023 年 8 月 19 日に月面に墜落しました。
インドのチャンドラヤーン3号が月の南極に軟着陸する4日前。
フォレンジック分析の結果、命令がバスを共有しており、優先順位が正しく設定されていないことが判明しました。
宇宙船にはソフトウェア障害の長い歴史があります。
class TaskManager: def __init__(self): self.tasks = [] def add_task(self, task, priority): self.tasks.append((task, priority)) def execute_tasks(self): # No sorting for task, _ in self.tasks: task.execute() class Task: def __init__(self, name): self.name = name def execute(self): print(f"Executing task: {self.name}") task_manager = TaskManager() highPriorityTask = Task("Slow down") mediumPriorityTask = Task("Take Photos") reviveKlaatu = Task("Klaatu barada nikto") # unsorted task_manager.add_task(mediumPriorityTask, 2) task_manager.add_task(highPriorityTask, 1) task_manager.add_task(reviveKlaatu, 3) task_manager.execute_tasks()
class TaskManager: def __init__(self): self.tasks = [] def add_task(self, task, priority): self.tasks.append((task, priority)) def execute_tasks(self): # Sort tasks by priority (high to low) self.tasks.sort(key=lambda x: x[1], reverse=True) for task, _ in self.tasks: task.execute() class Task: def __init__(self, name): self.name = name def execute(self): print(f"Executing task: {self.name}") task_manager = TaskManager() highPriorityTask = Task("Slow down") mediumPriorityTask = Task("Take Photos") reviveKlaatu = Task("Klaatu barada nikto") # unsorted task_manager.add_task(mediumPriorityTask, 2) task_manager.add_task(highPriorityTask, 1) task_manager.add_task(reviveKlaatu, 3) task_manager.execute_tasks()
これはデザインの匂いです
ソフトウェアコンポーネントを作成し、実際の条件と非現実の条件をシミュレートします
コードの匂いは私の意見です。
分析エンジンには、何かを生み出すためのふりはありません。それは私たちが知っていることなら何でも実行できます…しかし、それは科学そのものに間接的かつ相互的な影響を与える可能性があります。
エイダ・ラブレス
カウボーイのことはハリウッド映画に任せましょう。
TL;DR: チーム プログラマーとしてコードを作成する
プロフェッショナルなコードを書きます。
暗号化されていない宣言的な名前を使用してください。
カウボーイのプログラマーはベストプラクティスに従いません。
彼らはチームの提案に従いません。
カウボーイ コーディングは、保守が難しくエラーが発生しやすいコードにつながる可能性があるため、一般にソフトウェア開発における専門的ではない危険なアプローチであると考えられています。
カウボーイプログラマーは良い人たちです。ただし、グループで作業することはできません。
# Very simple example # Compute the sum of two numbers without any structure or best practices. num1 = input("Enter the first number: ") num2 = input("Enter the second number: ") # WARNNING!!!! Don't remove the line below !!!!! # (Unpleasant comment) res = num1 + num2 # (No data type checking or error handling) print("The sum is: " + result) # (No validation or formatting) # (No good names, no functions, no error handling, no testing, # no version control, and no structure.)
def add_numbers(): try: firstAddend = float(input("Enter the first number: ")) secondAddend = float(input("Enter the second number: ")) total = firstAddend + secondAddend return total except ValueError: print("Invalid input. Please enter valid numbers.") return None def main(): total = add_numbers() if total is not None: print("The sum is: {:.2f}".format(sum)) if __name__ == "__main__": main()
環境ルールを設定して、このようなコーディング慣行を防止し、チーム構築を強制することができます。
ソフトウェア開発はチームワークです。
https://www.linkedin.com/pulse/software-development-cowboy-coding-hakan-atbaş/
UnsplashのTaylor Brandonによる写真
コンピュータの危険は、コンピュータが最終的には人間と同じくらい賢くなることではなく、その間に私たちが中途半端にコンピュータに会うことに同意してしまうことだ。
バーナード・アビシャイ
複数のクラスは混乱します。
TL;DR: 関心事の分離の原則とファイル構成に従う
ファイルごとに 1 つのクラスを宣言する
名前のスコープを使用する
ファイル システムを使用してクラスを宣言する言語では、ファイルごとに 1 つのクラスを持つことが一般的にベスト プラクティスと考えられています。
このアプローチは、コードの構成と保守性を向上させ、潜在的な問題を軽減するのに役立ちます。
プロジェクト構造内の別のディレクトリに名前空間を整理できます。
こうすることで、単一ファイルで複数のクラスを宣言する問題を回避しながら、論理的で効率的なコードベースを維持できます。
<? namespace MyNamespace; class Class1 { public function sayHello() { echo "Hello from Class1!\n"; } } class Class2 { public function sayHello() { echo "Hello from Class2!\n"; } }
<? namespace MyNamespace; class Class1 { public function sayHello() { echo "Hello from Class1!\n"; } }
<? namespace MyNamespace; class Class2 { public function sayHello() { echo "Hello from Class2!\n"; } }
多くの標準がこのルールを適用しています
コードを整理して、既知の標準に従ってください。
UnsplashのMarjan Blanによる写真
要件や設計がなければ、プログラミングは空のテキスト ファイルにバグを追加する技術です。
ルイス・シグレー
コードが複雑になりすぎます。
TL;DR: 偶発的な複雑さと官僚主義を避ける
コードの「お役所仕事」の匂いは、コードベースの理解や保守を困難にする不必要な複雑さ、官僚主義、または過剰な構成に関連している可能性があります。
class VotingSystem: def __init__(self, config): self.config = config def validate_voter(self, voter_id): if self.config['voter_verification_enabled']: # Code to verify the voter's identity goes here def cast_vote(self, voter_id, candidate): if self.config['voting_enabled']: # Code to record the vote goes here def generate_vote_report(self): if self.config['generate_report']: # Code to generate a voting report goes here def audit_voting_system(self): if self.config['audit_enabled']: # Code to perform an audit of the voting system goes here # ... other voting-related methods ... # Usage config = { 'voter_verification_enabled': True, 'voting_enabled': False, 'generate_report': False, 'audit_enabled': True } voting_system = VotingSystem(config) # Voter validation, voting, report generation, # and auditing are handled based on the configuration.
class VoterVerification: def verify_voter(self, voter_id): # Code to verify the voter's identity goes here class VotingMachine: def cast_vote(self, voter_id, candidate): # Code to record the vote goes here class VoteReporter: def generate_report(self): # Code to generate a voting report goes here class VotingAuditor: def audit_voting_system(self): # Code to perform an audit of the voting system goes here # Usage voter_verification = VoterVerification() voting_machine = VotingMachine() vote_reporter = VoteReporter() voting_auditor = VotingAuditor() # Voter verification, vote casting, report generation, # and auditing are handled separately.
一部のツールは、不必要な責任を負ってオブジェクトが肥大化していると推測できます。
開発者はどの機能がアクティブであるかを判断するために複雑な構成をナビゲートする必要があるため、お役所仕事のコードの匂いは明らかです。
これにより、不必要な複雑さが増すだけでなく、システムの整合性に影響を与える可能性のある構成ミスの可能性も高まります。
コードの匂いは私の意見です。
ソフトウェアの誤謬: ソフトウェアが機能していて、何も変更しなければ、引き続き動作し続けます。
ジェシカ・カー
あなたのコードは死んでいて生きています。
TL;DR: 競合状態を注意深く確認してください
競合状態を回避する
グローバル変数を避ける
適切な同期を使用する
シュレーディンガー コードは、同時に 2 つの異なる状態になれるコードですが、コードの状態は実行されるまで決定されません。
これは、コードに競合状態が含まれている場合、またはコードが他のスレッドまたはプロセスによって変更される可能性のあるグローバル変数の状態に依存している場合に発生する可能性があります。
import threading cats_alive = 0 def thread_1(): cats_alive += 1 def thread_2(): cats_alive -= 1 if cats_alive > 0: feedThem() # The value of cats_alive is indeterminate, # so the code can be in either of the two states: # # 1. cats_alive > 0 and feedThem() is called. # 2. cats_alive <= 0 and feedThem() is not called.
import threading lock = threading.Lock() cats_alive = 0 def thread_1(): with lock: cats_alive += 1 def thread_2(): with lock: cats_alive -= 1 if cats_alive > 0: feedThem() # With the lock, the two threads cannot access # the `cats_alive` variable at the same time. # This means that the value of `cats_alive` is always determined, # and the program will not exhibit Schrödinger code behavior.
同時実行コードのコードレビューを行う
シュレーディンガー コードを回避するには、競合状態を回避し、他のスレッドまたはプロセスによって変更される可能性のあるグローバル変数の状態に依存しないようにします。
コードでグローバル変数を使用する必要がある場合は、それが正しく同期されていることを確認してください。
UnsplashのYerlin Matuによる写真
プログラマにとって最も避けたいことは、内部状態をいじることです。
アラン・ケイ
来週はさらに5つの香りを追加します。