長いifを書かない

条件には非常に多くのエラーがあります。 たとえば、 PVS-studioブログからの投稿を取ることができます。それぞれの投稿には、条件の不注意な処理に関連するエラーがあります。 実際、コードが次のように見える場合、条件のエラーを見分けるのは簡単ではありません( この投稿の例)。



static int ParseNumber(const char* tx) { .... else if (strlen(tx) >= 4 && (strncmp(tx, "%eps", 4) == 0 || strncmp(tx, "+%pi", 4) == 0 || strncmp(tx, "-%pi", 4) == 0 || strncmp(tx, "+Inf", 4) == 0 || strncmp(tx, "-Inf", 4) == 0 || strncmp(tx, "+Nan", 4) == 0 || strncmp(tx, "-Nan", 4) == 0 || strncmp(tx, "%nan", 4) == 0 || strncmp(tx, "%inf", 4) == 0 )) { return 4; } else if (strlen(tx) >= 3 && (strncmp(tx, "+%e", 3) == 0 || strncmp(tx, "-%e", 3) == 0 || strncmp(tx, "%pi", 3) == 0 // <= || strncmp(tx, "Nan", 3) == 0 || strncmp(tx, "Inf", 3) == 0 || strncmp(tx, "%pi", 3) == 0)) // <= { return 3; } .... }
      
      





そのような条件はいたるところにあり、私が扱ったすべてのプロジェクトでそれらに出くわしました。 habrのこの投稿は、プログラミングの世界でif-elseの条件を「どのように」書くことができるかを開発した動物園完全に示しています。各アプローチは合理的でクールで、一般的なスペースのルールでは、タブが吸うなどです。 面白いことは、「通常の形式の条件付きステートメントは比較的まれな問題の原因」という言葉で始まるということです。反対の確認のために、PVS-studioブログとあなた自身の苦い経験を​​再度参照します。



最近、if-elseブロックを書くときに、どこでもこのアプローチを使用し始めたことに気付きました。 一般に、これは前述の投稿の最初の解説で説明されたものと一致しますが、より過激で明確なアイデアがあります。 一般に、この手法は、複雑であろうと単純であろうと、すべての条件で使用します。



最も一般的な形式では、ルールは次のとおりです。 条件に複数の論理演算子がある場合、リファクタリングを検討する必要があります。 変数に名前を付けるときは、コードから明らかな正式なチェックではなく、ビジネスロジックに一致する名前を選択します



事実、2番目はさらに重要です。 明示的に記述されていることに加えて、条件について何か言うことがある場合は、変数の名前で表現できるかどうかを考える必要があります。 2つの擬似コードを比較します。



 if (model.user && model.user.id) { doSomethingWithUserId(model.user.id); ... }
      
      





そして



 let userExistsAndValid = model.user && model.user.id; if (userExistsAndValid) { doSomethingWithUser(model.user); ... }
      
      





最初のケースでは、純粋に形式的な値のチェックがあり、user.idが必要で、そこにあるかどうかをチェックします。すべてをそのままにしておくことができます。 2番目のケースでは、すでに有効なモデルが必要であり、ビジネスロジックの用語を通じて変数名でこれを説明します。



このアプローチには、リファクタリング中に利点があります:メソッドでさらに検証が必要な場合、および/または有効条件が拡張された場合(ユーザーが電子メールアドレスを持っている必要があります)-変更は最小限になります。



ユーザーについても例を挙げてみましょうが、より複雑ですが、数日前に出会ってこのスタイルにリファクタリングしました。 それは:



 if (this.profile.firstName && this.profile.lastName && (this.password || !!_.find(this.serviceAccounts, a => a.provider === 'slack' && a.accountId)) { .... }
      
      





次のようになりました:



 const hasSlack = !!_.find(this.serviceAccounts, a => a.provider === 'slack' && a.accountId); const hasSomeLoginCredentials = this.password || hasSlack; const hasPersonalData = this.profile.firstName && this.profile.lastName; if (hasPersonalData && hasSomeLoginCredentials) { .... }
      
      





もちろん、前の要素が成功した場合や他の例外があった場合にのみ条件の一部の要素を満たす必要がある場合もありますが、それでも条件に複数の論理演算子がある場合は、リファクタリングを検討する必要があります 。 ちなみに、これらのポイントのほとんどは、三項式またはローカル関数で解決できますが、これらのツールが長い場合よりもはるかに読みやすいと、誰もが自分で決定します。



私にとって、例外のリストにはショートカットも含まれています。



 if (err || !result || !result.length === 0) return callback(err);
      
      





変数を導入しても意味がありません。



All Articles