JavaScript

JavaScriptにおけるリーダブルコードについて

この記事の目次
  1. リーダブルコードについて
  2. 一般的な原則
  3. 関数について
  4. OOP(オブジェクト指向プログラミング)について
  5. ネスト化されたコードについて
  6. 非同期のコードについて
  7. 命令型プログラミングと宣言的プログラミング
  8. 命令型プログラミング(how to do)
  9. 宣言的プログラミング(what to do)
  10. ファンクショナルプログラミング(Functional programming)
  11. ファンクショナルプログラミングのテクニック
  12. 宣言的な構文について(Declarative syntax)

JavaScriptにおけるリーダブルコードとはいったいどんな点に気をつければいいのかについてまとめました。

リーダブルコードについて

JavaScriptにおけるリーダブルコードとは、次のようなコードのことです。

  • 他人が理解できる
  • 1年後の自分が理解できる
  • 複雑でない
  • 理解するのに時間がかかるような賢すぎるコードではない
  • 名前をみただけで何かわかるような変数名をつけている
  • 名前をみただけで何をするかわかるような関数名をつけている

一般的な原則

一般的な原則としては次のようなことに従っている必要があります。

  • DRY原則(Don’t repeat yourself )(コードをリファクタリングする)
  • グローバル名前空間を汚すのではなくカプセル化する
  • var以外を使う
  • ==や!=ではなく、===や!==といった厳格な型のチェックを使う

関数について

リーダブルな関数については次の点に従います。

  • 一般的に関数はたった一つのことしかしないようにする
  • 3つ以上の引数をとる関数を作らない
  • 可能な限りデフォルトの引数を使う
  • 一般的に受け取ったデータ型と同じデータ型を返すようにする
  • アロー関数で読みやすくなるときはアロー関数を使う

OOP(オブジェクト指向プログラミング)について

リーダブルなオブジェクト指向プログラミングについては次の点に従います。

  • ES6クラスを使う
  • クラスの外から変更されないようにデータをカプセル化する
  • メソッドチェーンを使う
  • 通常のオブジェクトのメソッドではアロー関数以外の関数を使う

ネスト化されたコードについて

リーダブルなネスト化されたコードについては次の点に従います。

  • ガード節(guard clauses)を使う
  • if文の代わりに条件(三項)演算子(ternary conditional operators)や論理演算子(logical operators)を使う
  • if/else-if文の代わりに複数のif文を使う
  • (for-ofなども含む)for文の代わりにmap(),filter(),reduce()といった配列メソッドを使う
  • コールバックベースの非同期APIを使わない

非同期のコードについて

リーダブルな非同期のコードについては次の点に従います。

  • コールバック関数が必要なthen()/catch()の代わりに、async/awaitでpromiseを使う
  • 可能な限りPromise.allなどで並行処理させる
  • Promise rejectionsとエラーを処理すること

Promiseの使い方はこちらを参照してみてください。
JavaScriptのPromiseの使い方・書き方
async/awaitに関しては次の記事を参考にしてみてください。
JavaScriptのasync/awaitの書き方

命令型プログラミングと宣言的プログラミング

コードの書き方(パラダイム)には、大きく2つの異なる方法があります。

命令型プログラミング(imperative code)もしくは宣言的プログラミング(declarative code)です。

モダンなコードの書き方(パラダイム)は、宣言的プログラミングの流れになっています。

命令型プログラミング(how to do)

命令型プログラミングでは、プログラマーは、「どのように処理するか」をコンピュータに説明します。
結果に至るまでのすべてのステップをコンピュータに伝えます。
たとえば、カレーを例にしましょう。
そのカレーの作り方をステップ・バイ・ステップですべて説明します。その結果としてカレーを得ることができます。
コードの例でいうと、次のようなコードは、命令型プログラミングです。

const numbers = [1,2,3,4,5];
const tripled = [];
for (let i = 0; i < numbers.length; i++) 
tripled[i] * 3;

望んでいる結果を得るためのすべてのステップを一行ずつ指示しています。

宣言的プログラミング(what to do)

宣言的プログラミングでは、プログラマーは、コンピュータに「何をすべきか」を伝えます。
コンピュータに達成すべき結果がどのようなものかを描写します。 どのようにその結果にいたるかは無視します。 たとえば、カレーを例にしましょう。
そのカレーの作り方は説明せず、カレーがどいういうものかということを伝えます。その結果、カレーを得ることができます。
コードの例でいうと、次のようなコードは、宣言型プログラミングです。

const numbers = [1,2,3,4,5]; 
const tripled = numbers.map(num => num * 3);

この宣言的プログラミングは、サブパラダイムであるファンクショナルプログラミングを生み出しました。

ファンクショナルプログラミング(Functional programming)

ファンクショナルプログラミングは、宣言的プログラミングから生まれたもので、サイドエフェクトやデータの改変を避けるために多くのピュアな関数(pure functions)を組み合わせてソフトウェアを作る考え方です。
サイドエフェクトとは、関数の外にあるデータの改変(変更)のことです。たとえば、スコープの外から変数を変更したり、コンソールに出力したり、DOMを書き換えたりなどです。

ピュアな関数とは、サイドエフェクトのない関数のことです。外部の変数に依拠しません。同じ入力値を与え、常に同じ出力を返します。

ファンクショナルプログラミングのテクニック

ファンクショナルプログラミングには、具体的には次のテクニックがあります。

  • データの変更を極力避ける(常に必須というわけではない)
  • サイドエフェクトが発生しないビルドインメソッドを使用する
  • データの変換はmap(),filter(),reduce()などを使う
  • 極力自分で書いた関数によるサイドエフェクトが生まれないようにする(常に必須というわけではない)

宣言的な構文について(Declarative syntax)

リーダブルコードにするために、宣言的な構文については次の点に従います。

  • 配列やオブジェクトの分割代入(destructuring)を使う
  • スプレッド構文(spread operator)を使う
  • 条件(三項)演算子を使う
  • テンプレートリテラルを使う