2022年6月26日

コーディングスタイル

私たちのコードは、できる限りクリーンで読みやすいものである必要があります。

それこそがプログラミングの技術です。複雑なタスクを取り上げ、正確で人間が読めるような方法でコーディングすることです。良いコーディングスタイルは、それを大きく助けます。

構文

以下に、推奨されるルールをまとめたチートシートを示します (詳細については下記を参照)。

それでは、詳細にルールとその理由を議論しましょう。

「~しなければならない」というルールはありません

ここでは何も絶対的なものはありません。これらはスタイルの好みであり、宗教的なドグマではありません。

波括弧

ほとんどの JavaScript プロジェクトでは、波括弧は「エジプト風」スタイルで記述され、対応するキーワードと同じ行に開始括弧が記述され、新しい行には記述されません。また、開始括弧の前には、次のようにスペースが必要です。

if (condition) {
  // do this
  // ...and that
  // ...and that
}

if (condition) doSomething() のような単一行の構造は、重要なエッジケースです。そもそも波括弧を使うべきでしょうか?

ご自身で可読性を判断できるように、注釈付きのバリアントを次に示します。

  1. 😠 初心者は時々これをしてしまいます。ダメ!波括弧は不要です。
    if (n < 0) {alert(`Power ${n} is not supported`);}
  2. 😠 波括弧なしで別の行に分割。決してしないでください。新しい行を追加するときにエラーが発生しやすくなります。
    if (n < 0)
      alert(`Power ${n} is not supported`);
  3. 😏 波括弧なしの一行 – 短い場合は許容範囲。
    if (n < 0) alert(`Power ${n} is not supported`);
  4. 😃 最適なバリアント
    if (n < 0) {
      alert(`Power ${n} is not supported`);
    }

非常に短いコードの場合、if (cond) return null のように一行が許可されています。しかし、コードブロック (最後のバリアント) の方が通常は読みやすいです。

行の長さ

長い水平なコード行を読みたい人はいません。分割するのが最善の方法です。

例えば

// backtick quotes ` allow to split the string into multiple lines
let str = `
  ECMA International's TC39 is a group of JavaScript developers,
  implementers, academics, and more, collaborating with the community
  to maintain and evolve the definition of JavaScript.
`;

そして、if ステートメントの場合

if (
  id === 123 &&
  moonPhase === 'Waning Gibbous' &&
  zodiacSign === 'Libra'
) {
  letTheSorceryBegin();
}

最大行の長さはチームレベルで合意する必要があります。通常は 80 文字または 120 文字です。

インデント

インデントには 2 種類あります。

  • 水平インデント: 2 または 4 つのスペース。

    水平インデントは、2 つまたは 4 つのスペース、または水平タブ記号 (Tab キー) を使用して作成されます。どれを選ぶかは、昔からある聖戦です。最近では、スペースがより一般的になっています。

    タブよりもスペースの利点の 1 つは、スペースを使用すると、タブ記号よりも柔軟にインデントを設定できることです。

    たとえば、次のように、パラメータを開き括弧に合わせることができます。

    show(parameters,
         aligned, // 5 spaces padding at the left
         one,
         after,
         another
      ) {
      // ...
    }
  • 垂直インデント: コードを論理ブロックに分割するための空行。

    単一の関数でさえ、多くの場合、論理ブロックに分割できます。下の例では、変数の初期化、メインループ、結果の返却が垂直に分割されています。

    function pow(x, n) {
      let result = 1;
      //              <--
      for (let i = 0; i < n; i++) {
        result *= x;
      }
      //              <--
      return result;
    }

    コードを読みやすくするために役立つ場所に、追加の改行を挿入します。垂直インデントなしで 9 行を超えるコードは存在すべきではありません。

セミコロン

セミコロンは、省略できる場合でも、各ステートメントの後に存在する必要があります。

セミコロンが本当にオプションで、ほとんど使用されない言語もあります。ただし、JavaScript では、改行がセミコロンとして解釈されず、コードがエラーの影響を受けやすい場合があります。詳細については、コード構造 の章を参照してください。

経験豊富な JavaScript プログラマーであれば、StandardJS のようなセミコロンなしのコードスタイルを選択しても構いません。それ以外の場合は、考えられる落とし穴を避けるために、セミコロンを使用するのが最適です。ほとんどの開発者はセミコロンを記述します。

ネストレベル

コードをあまり深くネストしないようにしてください。

たとえば、ループでは、ネストを避けるために、continue ディレクティブを使用することをお勧めする場合があります。

たとえば、次のようにネストされた if 条件を追加する代わりに

for (let i = 0; i < 10; i++) {
  if (cond) {
    ... // <- one more nesting level
  }
}

次のように記述できます

for (let i = 0; i < 10; i++) {
  if (!cond) continue;
  ...  // <- no extra nesting level
}

同様のことは、if/elsereturn で行うことができます。

たとえば、次の 2 つの構造は同一です。

オプション 1

function pow(x, n) {
  if (n < 0) {
    alert("Negative 'n' not supported");
  } else {
    let result = 1;

    for (let i = 0; i < n; i++) {
      result *= x;
    }

    return result;
  }
}

オプション 2

function pow(x, n) {
  if (n < 0) {
    alert("Negative 'n' not supported");
    return;
  }

  let result = 1;

  for (let i = 0; i < n; i++) {
    result *= x;
  }

  return result;
}

2 番目の方が読みやすいです。なぜなら、n < 0 の「特別なケース」が早期に処理されているからです。チェックが完了したら、追加のネストを必要とせずに「メイン」コードフローに進むことができます。

関数の配置

いくつかの「ヘルパー」関数とそれらを使用するコードを記述する場合、関数を整理する方法は 3 つあります。

  1. 関数を、それを使用するコードのに宣言する

    // function declarations
    function createElement() {
      ...
    }
    
    function setHandler(elem) {
      ...
    }
    
    function walkAround() {
      ...
    }
    
    // the code which uses them
    let elem = createElement();
    setHandler(elem);
    walkAround();
  2. 最初にコード、次に関数

    // the code which uses the functions
    let elem = createElement();
    setHandler(elem);
    walkAround();
    
    // --- helper functions ---
    function createElement() {
      ...
    }
    
    function setHandler(elem) {
      ...
    }
    
    function walkAround() {
      ...
    }
  3. 混合: 関数は最初に使われた場所に宣言する。

ほとんどの場合、2 番目のバリアントが推奨されます。

これは、コードを読んでいるときに、最初に *何をするか* を知りたいからです。コードが最初に来れば、最初から明確になります。次に、特に関数の名前が実際に何をするのかを説明している場合は、関数をまったく読む必要がないかもしれません。

スタイルガイド

スタイルガイドには、「どのように」コードを記述するかについての一般的なルールが含まれています。たとえば、使用する引用符、インデントするスペースの数、最大行の長さなどです。多くの些細なことが含まれます。

チームのすべてのメンバーが同じスタイルガイドを使用すると、チームメンバーの誰が書いたかに関係なく、コードは均一に見えます。

もちろん、チームは常に独自のスタイルガイドを作成できますが、通常は必要ありません。選択できる既存のガイドはたくさんあります。

いくつかの人気のある選択肢

あなたが初心者開発者であれば、この章の冒頭にあるチートシートから始めてください。次に、他のスタイルガイドを参照して、より多くのアイデアを収集し、どれが最適かを決定できます。

自動リンター

リンターは、コードのスタイルを自動的にチェックし、改善提案を行うことができるツールです。

リンターの優れた点は、スタイルチェックによって、変数名や関数名のタイプミスのようなバグも見つけることができることです。この機能により、特定の「コードスタイル」に固執したくない場合でも、リンターを使用することをお勧めします。

有名なリンティングツールを次に示します。

  • JSLint – 最初のリンターの 1 つ。
  • JSHint – JSLint よりも多くの設定があります。
  • ESLint – おそらく最も新しいものです。

どれも仕事をこなすことができます。著者は ESLint を使用しています。

ほとんどのリンターは、多くの人気のあるエディターと統合されています。エディターでプラグインを有効にして、スタイルを構成するだけです。

たとえば、ESLint の場合は、次の手順を実行する必要があります。

  1. Node.js をインストールします。
  2. npm install -g eslint コマンドで ESLint をインストールします (npm は JavaScript パッケージインストーラーです)。
  3. JavaScript プロジェクトのルート (すべてのファイルが含まれているフォルダー) に、.eslintrc という名前の構成ファイルを作成します。
  4. ESLint と統合するエディターのプラグインをインストール/有効にします。ほとんどのエディターにはプラグインがあります。

.eslintrc ファイルの例を次に示します。

{
  "extends": "eslint:recommended",
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  "rules": {
    "no-console": 0,
    "indent": 2
  }
}

ここで、"extends" ディレクティブは、構成が「eslint:recommended」設定セットに基づいていることを示します。その後、独自の構成を指定します。

Web からスタイルルールセットをダウンロードして、代わりに拡張することもできます。インストールに関する詳細については、https://eslint.org/docs/user-guide/getting-started を参照してください。

また、特定の IDE には、組み込みのリンティング機能がありますが、便利ですが、ESLint ほどカスタマイズ可能ではありません。

まとめ

この章で説明した (および参照したスタイルガイドで) すべての構文ルールは、コードの可読性を高めることを目的としています。それらはすべて議論の余地があります。

「より良い」コードを書くことを考えるとき、自問すべき質問は、「何がコードをより読みやすく、理解しやすくするのか?」と「何がエラーを防ぐのに役立つのか?」です。これらは、コードスタイルを選択して議論する際に留意すべき主な事項です。

人気のスタイルガイドを読むことで、コードスタイルのトレンドとベストプラクティスに関する最新のアイデアを把握できます。

タスク

重要度: 4

次のコードスタイルは何が間違っていますか?

function pow(x,n)
{
  let result=1;
  for(let i=0;i<n;i++) {result*=x;}
  return result;
}

let x=prompt("x?",''), n=prompt("n?",'')
if (n<=0)
{
  alert(`Power ${n} is not supported, please enter an integer number greater than zero`);
}
else
{
  alert(pow(x,n))
}

修正してください。

次のことに注意できます

function pow(x,n)  // <- no space between arguments
{  // <- figure bracket on a separate line
  let result=1;   // <- no spaces before or after =
  for(let i=0;i<n;i++) {result*=x;}   // <- no spaces
  // the contents of { ... } should be on a new line
  return result;
}

let x=prompt("x?",''), n=prompt("n?",'') // <-- technically possible,
// but better make it 2 lines, also there's no spaces and missing ;
if (n<=0)  // <- no spaces inside (n <= 0), and should be extra line above it
{   // <- figure bracket on a separate line
  // below - long lines can be split into multiple lines for improved readability
  alert(`Power ${n} is not supported, please enter an integer number greater than zero`);
}
else // <- could write it on a single line like "} else {"
{
  alert(pow(x,n))  // no spaces and missing ;
}

修正されたバリアント

function pow(x, n) {
  let result = 1;

  for (let i = 0; i < n; i++) {
    result *= x;
  }

  return result;
}

let x = prompt("x?", "");
let n = prompt("n?", "");

if (n <= 0) {
  alert(`Power ${n} is not supported,
    please enter an integer number greater than zero`);
} else {
  alert( pow(x, n) );
}
チュートリアルマップ

コメント

コメントする前にこれを読んでください…
  • 改善のための提案がある場合は、コメントする代わりに GitHub issue を送信するか、プルリクエストを送信してください。
  • 記事の内容が理解できない場合は、詳しく説明してください。
  • コードを数語挿入するには <code> タグを使用し、複数行の場合は <pre> タグで囲み、10 行を超える場合はサンドボックス (plnkrjsbincodepen…) を使用してください。