プロジェクトのサイズが十分に大きいので、すべての側面を頭の中で維持することができなくなりました。その中でいくつかのクラスと関数を扱っており、データをやり取りしています。
時間の経過とともにエラーが発生し続けることに気づきました。別の関数にデータを渡すときにデータの正確な形式を忘れてしまったためです(、たとえば、1つの関数が文字列の配列を受け入れて出力します。別の関数は後で作成しましたが、ディクショナリなどに保持されている文字列を受け入れます。そのため、処理中の文字列を配列に含めてから、ディクショナリに含めるように変換する必要があります)。
どこがどこでどこが壊れているのかを常に理解する必要がないように、私は各関数とクラスを「分離されたエンティティ」として扱い始めました。これは、正しい入力を与える外部コードに依存できず、入力チェック自体を実行する必要があるという意味で(または、場合によっては、データが間違った形式で提供されている場合は、データを再キャストします。
これにより、渡すデータがすべての関数に「適合」することを確認するために費やす時間が大幅に短縮されました。クラスと関数自体が、入力に問題がある場合は警告を発し(場合によってはそれを修正する場合もあり)、警告を出さないためです。デバッガーを使用してコード全体を処理し、問題が発生した場所を特定する必要があります。
一方、これによりコード全体も増加しました。
私の問題は、このコードスタイルがこの問題の解決に適切かどうかです
もちろん、最善の解決策は、プロジェクトを完全にリファクタリングし、データがすべての機能に対して均一な構造を持っていることを確認することです-しかし、このプロジェクトは絶えず成長しているので、私はより多くの費用をかけ、実際に新しいものを追加するよりもクリーンなコードを心配しています。
(参考:私はまだ初心者なので、この質問が素朴だった場合は失礼します。私のプロジェクトはPythonで行われています。)
より良い解決策は、Python言語機能とツールを利用することです。
たとえば、関数1では、予期される入力は文字列の配列です。最初の文字列は何かのタイトルを示し、2番目の文字列は書誌参照です。関数2では、予想される入力は文字列の配列のままですが、文字列の役割が逆になっています。
この問題は namedtuple
で軽減されます。それは軽量で、配列のメンバーに簡単な意味上の意味を与えます。
言語を切り替えることなく、いくつかの自動型チェックの利点を活用するには、 type hinting を利用できます。良いIDEはこれを使用して、何かばかげたことを知らせることができます。
また、要件が変更されたときに機能が古くなるのではないかと心配しているようです。これは 自動テスト で捕捉できます。
手動でチェックすることが適切であるとは決して言えませんが、使用可能な言語機能をより適切に使用することで、この問題をより保守可能な方法で解決できます。
OK、実際の問題はこの回答の下のコメントに記載されています:
たとえば、関数1では、予期される入力は文字列の配列です。最初の文字列は何かのタイトルを示し、2番目の文字列は書誌参照です。関数2では、予想される入力は文字列の配列のままですが、文字列の役割が逆になります
ここでの問題は、順序が意味を表す文字列のリストの使用です。これは本当にエラーが発生しやすいアプローチです。代わりに、title
およびbibliographical_reference
という名前の2つのフィールドを持つカスタムクラスを作成する必要があります。そうすれば、それらを混同することはなく、将来この問題を回避できます。もちろん、すでに多くの場所で文字列のリストを使用している場合、これにはいくつかのリファクタリングが必要ですが、私を信じて、長期的には安くなるでしょう。
動的型付け言語での一般的なアプローチは「ダックタイピング」です。つまり、渡されたオブジェクトの「型」は本当に気にせず、呼び出すメソッドをサポートするかどうかだけを気にします。あなたのケースでは、必要なときにbibliographical_reference
というフィールドを読み取るだけです。渡されたオブジェクトにこのフィールドが存在しない場合、エラーが発生し、関数に間違った型が渡されたことを示します。これはどんなタイプチェックでも良いです。
まず第一に、あなたが今経験しているのは code smell -あなたがその匂いを意識するようになった原因を思い出し、あなたを磨くようにしてください「精神的」な鼻。コードのにおいが気になるほど早く早く、簡単に、根本的な問題を修正できます。
どこがどこでどこが壊れているのかを常に理解する必要がないように、外部のコードに依存して正しい入力を与えることに頼ることができず、入力チェック自体を実行する必要があるという意味で、各関数とクラスを「分離されたエンティティ」として扱い始めました。
防御的プログラミングは、この手法と呼ばれているように、有効でよく使用されるツールです。ただし、すべてのことと同様に、適切な量を使用することが重要です。チェックが少なすぎると、問題がキャッチされず、多すぎてコードが肥大化します。
(または、データが誤った形式で指定されている場合は、データを再キャストします)。
それはあまり良い考えではないかもしれません。プログラムの一部が誤ってフォーマットされたデータを使用して関数を呼び出していることに気付いた場合は、FIX THAT PART、呼び出された関数を変更して不良をダイジェストできないようにするとにかくデータ。
これにより、渡すデータがすべての関数に「適合」することを確認するために費やす時間が大幅に短縮されました。クラスと関数自体が、入力に問題がある場合は警告を発し(場合によってはそれを修正する場合もあり)、警告を出さないためです。デバッガーを使用してコード全体を処理し、問題が発生した場所を特定する必要があります。
コードの品質と保守性を改善することは、長期的には時間の節約になります(その意味で、一部の関数に組み込まれた自己修正機能に対して再度警告する必要があります。これらはバグの潜伏する原因となる可能性があります。プログラムはクラッシュせず、書き込みも正しく機能するわけではありません...)
最後にあなたの質問に答えます:はい、防御的プログラミング(つまり、提供されたパラメーターの有効性を検証すること)は-健全な程度で-良い戦略です。 それは言った、あなたが言ったように、あなたのコードは矛盾していて、私は強く臭いがする部分をリファクタリングするためにある程度の時間を費やすことをお勧めします-あなたはいつもクリーンなコードについて心配する必要はなく、「クリーンアップ」により多くの時間を費やしたいと述べました"新機能よりも...コードをクリーンに維持しないと、バグをつぶすためにクリーンなコードを維持しないことで「節約」に2倍の時間を費やす可能性があり、新機能の実装に苦労します- 技術的負債 はあなたを粉砕することができます。
大丈夫。私はFoxProでコードを作成していましたが、ほとんどすべての大きな関数にTRY..CATCHブロックがありました。今、私はJavaScript/LiveScriptでコーディングし、「内部」または「プライベート」関数のパラメーターをほとんどチェックしません。
「どれだけチェックするか」は、コードのスキルに依存するよりも、選択したプロジェクト/言語に依存します。