静的JavaScriptパーサーと、それらが学習し直すのに役立つエラー(パート2)

静的アナライザーに関する記事の翻訳を続けます。最後の部分では、著者は==および===演算子の使用などのニュアンスに加え、不定の変数と最新の定義に触れ、さらに、アナライザーが(JSHintの例を使用して)そのようなエラーを検出します。 このパートでは、変数の再宣言と、コードの循環的な複雑さの制御について説明します。





変数の再宣言(使用)

JavaScriptでは、変数を再宣言(使用)できますが、これはほとんどの場合偶然に取得されます。 参照:



function incrementCount(counter) { if (counter.count) { counter.count++; } else { var counter = 1; counter.count = counter; } }
      
      







この関数では、提示されたオブジェクトのcountプロパティをインクリメントしますが、まだ存在しない場合はプロパティを追加する必要があります。 バグがありますか?



この関数は、カウンターを追加またはインクリメントしません。 else式は常に呼び出され、引数をカウンター関数に再定義します。 基本的に、この関数は新しいオブジェクトを作成し、それにプロパティを割り当て、関数が戻るときにオブジェクトを失います。 彼女は提示されたオブジェクトを変更することはありません。



この単純なタイプを使用すると、エラーなしでコードを実行できますが、かなり奇妙な結果になります。



JSHintは次を表示します。



 test.js: line 21, col 21, 'counter' is already defined.
      
      







ブロック、ループ、条件付き構造の中括弧



 if (false) doSomethingElse(); doSomething();
      
      







このコードは何をしますか-doSomethingまたはdoSomethingElse? 一見、doSomethingやdoSomethingElseを実行しないように思われます。 これはPythonでの動作ですが、JavaScriptでは動作しません。 JavaScriptは、そもそも、ブロックの一部としてifステートメントの下の行を実行します。 インデントは重要ではありません。



全体の問題はコードの可読性です。 コードが何をするのかわからない場合は、バグを作成します。

PythonとCoffeeScriptは中括弧をスキップするのが大好きです。 これは、フリースペースの書式設定を使用する言語ではうまく機能しますが、JavaScriptの動作は異なります。 JavaScriptを使用すると、多くの奇妙な構文を作成できますが、中括弧は問題を回避するのに役立ちます。



 if (false) { doSomethingElse(); doSomething(); }
      
      







括弧を追加すると、コードは常に読みやすくなります。 それらをスキップすると、JSHintは以下を表示します。



 test.js: line 27, col 5, Expected '{' and instead saw 'doSomething'.
      
      







一重引用符と二重引用符



 console.log("This is a string. It's OK."); console.log('This string is OK too.'); console.log("This string " + 'is legal, but' + "really not OK.");
      
      







JavaScriptでは、一重引用符と二重引用符を使用して文字列を定義できます。 これは、HTMLの定義などの柔軟性がある場合に適していますが、柔軟性を高めるとコードの一貫性が非常に失われる可能性があります。



Googleには、文字列に常に単一引用符を使用するコードスタイルガイドがあるため、HTMLで二重引用符を削除する必要はありません。 一重引用符は二重引用符よりも優れているとは言えませんが、ここでは一貫性が重要であると主張できます。 コンプライアンスにより、コードが読みやすくなります。



JSHintは、次のような引用符の混在について警告します。



 test.js: line 31, col 27, Mixed double and single quotes.
      
      







引用符のコピーと貼り付けまたは記述の誤りは非常に簡単です。 間違った引用符を入力するとすぐに、特に複数の人がファイルを編集している場合は、残りの引用符も使用し始めます。 静的アナライザーは、引用符の一貫性を保ち、将来の大きなクリーンアップを回避するのに役立ちます。



循環的な複雑さ



循環的複雑度は、特定のコードブロックの複雑度の尺度です。 コードを見て、動作可能なブランチの数を数えます-この数は循環的な複雑さです。

たとえば、このコードの循環的複雑度は1です。



 function main() { return 'Hello, World!'; }
      
      







このコードの実行の1つのブランチのみをトレースできます。

条件付きロジックを追加しましょう:



 function main() { if (true) { return 'Hello, World!'; } else { return 'Hello, unWorld!'; } }
      
      







サイクロマティックの難易度が2に増加しました。



完全なコードは読みやすく、理解しやすいです。 循環的複雑度が高いほど、コードを理解するのが難しくなります。 高いサイクロマティックな複雑さは悪いことに誰もが同意しますが、だれも特定の限界に達することはできません。 5は適切で、100は多すぎます。 そして、真ん中にはあまりにも多くの不確実性があります。



循環的複雑度が事前定義された制限に達すると、JSHintはこれを通知します。



 test.js: line 35, col 24, This function's cyclomatic complexity is too high. (17)
      
      







JSHintは、循環的な複雑さを考慮した3つの検証プログラムのうちの唯一のものです。 また、制限を設定することもできます。 maxcomplexityの数値を超えると、JSHintが警告します。 制限を14に設定するのが好きですが、多くの解析が必要なプロジェクトでは、少し高くすることができます。



実際、複雑さの意味は、コードをいつ再編成するかを指示するため重要です。 長い関数を初めて記述するときは重要です。 しかし、6か月待ってからバグを修正するためにコードに戻ると、読みやすくするために時間をかけたことをうれしく思います。



循環的な複雑さは通常、リストに分類されます。 たとえば、カレンダーを作成し、各国の正しい最初の曜日を設定したかった。 次のような関数がありました。



 function getFirstDay(country) { if (country === 'USA') { return 'Sunday'; } else if (country === 'France') { return 'Monday'; } else if… }
      
      







私は多くの国をカバーする必要があったので、サイクロマティックの複雑さはすぐに50マークを超えました。 私は最終的に機能を分割し、最大以下の複雑さになりました。 この特定のケースでは簡単な作業ではありませんでしたが、一般的にコードをきれいにするための低価格です。



編集したものすべてを複数回確認する



静的アナライザーは、簡単なテストでは発見できなかったバグを見つけます。 彼らはまた、作業中ではなくコンパイルプロセスでバグを見つけます-これらは、1ダースの人が1つのことをするときに忍び込む同じ真夜中のバグです。 コードをチェックせずにこれらすべての微妙なバグを見つけることは、長くて苦しいプロセスです。



この記事は、常にコードアナライザーを使用するというステートメントから始めましたが、1回限りのコードを作成する場合などには、これを行いません。 クイックプロトタイプを使用して、インタラクティブなアイデアを紹介し、チームが何かの仕組みを理解するのを支援します。 このようなプロトタイプは1回限りのコードです。 ここでバグを修正する必要はありません。数週間のうちにこのコードを破棄するからです。 このような1回限りのコードは、短いデモのためだけに存在し、微妙なバグがあるかどうかは私には関係ありません。 そして、私にとって重要なことはすべて分析されます。



プロジェクトの開始時にこれらのタイプのバグを修正するのはかなり簡単です。 リリースの前夜にそれらを見つけることは、あなたを狂わせることができます。 コードアナライザーは何度も私の命を救ってきたので、あなたを救います。



Habré読者向けの便利なPaystoソリューション:
今すぐクレジットカードで支払いを受けましょう。 サイト、IPおよびLLCなし。

オンライン企業からの支払いを受け入れます。 サイト、IPおよびLLCなし。

サイトの会社からの支払いを受け入れます。 ドキュメント管理とオリジナルの交換。

法人との販売およびサービス取引の自動化。 計算の仲介なし。






All Articles