JavaScriptのプログラミングスタイルはどうあるべきか? 重鎮Douglas Crockford氏が脳の働きとの関係を語る(後編)。QCon Tokyo 2013
4月23日に都内で開催されたエンジニア向けのイベント「QCon Tokyo 2013」。基調講演に登壇したのは、JavaScriptの重鎮であるDouglas Crockford氏。「プログラミング・スタイルと私たちの脳」という大胆なタイトルで、JavaScriptプログラミングにおいてバグをどう減らしていくのかについて解説しています。
(この記事は「JavaScriptのプログラミングスタイルはどうあるべきか? 重鎮Douglas Crockford氏が脳の働きとの関係を語る(前編)。QCon Tokyo 2013」の続きです)
プログラムが明確に読めなければバグが入り込む
JavaScriptの良い部品(Good Parts)の1つの例として即時関数を挙げましょう。これは関数を定義し、すぐに実行するというものです。
しかしこの書き方ではエラーになります。より整然とした書き方はこうでしょう。読み手のことを考えると、この即時関数全体がカッコで示されている方が分かりやすいのです。
with文について。ここにあるwith文では、真ん中の式は右にある4通りのどれにでも展開可能です。プログラムを読んでいても、これのどれに該当するかは分からないでしょう。
プログラムを読んでいてもどれが正しいのか分からなくなってしまうのですから、私はJavaScriptでwith文を使わないことをおすすめします。with文が便利ではないと言っているのではなく、混乱をもたらすと言いたいのです。
混乱は避けなければなりません。もしもプログラムが明確に読めないとき、そこにバグが入り込む余地があるのです。
つねに===演算子を使おう
JavaScriptには==演算子がありますが、これはしばしば混乱し、分かりにくい結果をもたらします。そこで私は==を使わず、つねに===を使うことをおすすめします。
もしもあるプログラミング言語の機能になにか問題があり、より信頼できる別の機能で置き換えられるのならば、つねに信頼できる機能の方を使うべきです。
JavaScriptは複数行をリテラルに書ける機能があります。私はこれを使うこともおすすめしません。
この2つの例は同じに見えますが、片方は問題なく実行でき、片方は文法エラーになります。というのも、2つ目の例の1行目の最後、ここにスペースが入ってるからです。(笑)
見つけるのは困難でしょう。ありふれたエラーを見つけにくくするような書き方は避けるべきです。
白文字で書かれた例は、よくあるエラーです。赤文字で書かれた例のつもりで書いたのでしょうが、実際には緑文字で書かれたように解釈されてしまいます。
何がしたいのか分かるようにプログラムを書く、というのが大事です。
すべての変数を関数の先頭で宣言しよう
スコープはプログラミング言語の歴史の中でももっとも優れた発明の1つです。変数の有効範囲や寿命を決定します。ほとんどのプログラミング言語がブロックスコープを備え、カッコやファイルの範囲でそれが規定されています。
JavaScriptはブロックスコープを備えておらず、関数スコープのみを備えています。問題は、その文法がブロックスコープのように見えるため、ほかの言語に慣れたプログラマがそこにブロックスコープがあるように誤解してしまうこと。その誤解がバグの元になります。
JavaScriptで変数を定義するvar文には、変数を宣言することと、変数を値によって初期化する2つの役割に分けることができます。
そこで私が推奨するのは、すべての変数を関数の先頭で宣言すること、そしてすべての関数を呼び出す前に定義しておくことです。
また、ここに示したのは多くのプログラマが憤っている例だと思います。ここでvar文によって定義された変数iは、スコープがループの中にあると期待されるが、そうではなく、この関数内です。この誤解がしばしばバグの元になります。
ですからfor文で使う変数であっても、関数の先頭で宣言しておくことをおすすめしたい。
JavaScriptの次のバージョンではlet文が使えるようになります。これはブロックスコープを実現してくれます。
グローバル変数は大文字に
ほとんどのプログラミング言語ではグローバル変数を定義できますが、これは害悪です。セキュリティの面でも信頼性の面でも問題を引き起こすため、使うべきではありませんが、JavaScriptでは残念ながらこれを避けることができません。使うときには、それが明示的にグローバル変数だと分かるように大文字にすることをおすすめします。
JavaScriptにはnew演算子がありますが、もしこれを付け忘れるとコンパイルの警告もなくグローバル変数として宣言され、実行時エラーとなるでしょう。
そこでコンストラクタ関数には命名規則として単語の最初を大文字にする(InitialCaps)ようにし、それ以外にはこの命名規則を使わない、ということをおすすめします。
次もよくある例です。白文字で書かれたコードは赤文字で示されたように実行されると想像されますが、実際には緑文字で書かれたように実行されます。つまり片方がグローバル変数になってしまうのです。これもよくないことです。
私のアドバイスは、意図に対して明確に分かるように書く、ということです。
これもよく見る例ですが、赤文字のように実行されるように見えて、実際には緑文字のように実行されます。これを防ぐには、つねに波カッコを使って範囲を示すことです。
私たちのプロセスはよりアジャイルになっていくなかで、コーディングはより信頼性のあるものでなければなりません。後からやってきた人がコードを見て、それを壊さずに改善できるようなものが望ましいのです。
どんな人が悪いスタイルを選択してしまうのか? 4つに分類してみました。勉強不足な人とはプログラミングをきちんと学んでおらず、ネットで見つけたサンプルを好んでそのまま使ってしまうような人です。古い教育を受けた人とは、別の言語で教育を受け、新しい言語を使うときもその要件を理解しないまま当てはめてしまうような人。スリルを好む人。最悪なのは、自己顕示欲家です。彼らは言語の実装や標準を調べて、極端な書き方をわざと使いたがります。
彼らは「分かっていてわざとやっている」と言うのですが、本当に分かっていればそんな書き方はしないものです。
プログラムには完璧が求められるが、人は完璧ではない
プログラミングは人が行うものの中でもっとも複雑なものです。プログラムは完璧が求められる一方で、人は完璧なものではありません。そのため、プログラミングには多くの努力が必要であり、スタイルを適切に用いることで間違いを減らすことができます。
そしてプログラミングスタイルの設計には規律が必要であり、それは好みや見かけや慣れではなく、間違いを減らすためのものです。これ以外の目的で作られるスタイルは間違っています。
より効果的になろうとすればタイプ数を減らすのではなく、エラーを少なくするようなことをするべきです。
JSLintスタイルは、自動的にエラーを検出するという動機によって作られました。ある人が「このプログラムが動かないんだけど、どこが悪いんだろう?」とほかの人に聞く、ということがよくあります。私がそのプログラムをJSLintにかけると、JSLintがその原因を示す、ということをしてくれます。もちろん、うまく示せないときもあります。
それは、プログラミング言語の機能がエラーを見えにくくしてしまっていることがあります。自動的にセミコロンを追加してしまうとかそういったことに依存した形式では、エラーがマスクされてしまうのです。
そこで、より効果的にエラーを検知するには、そうした機能を使わないようにすることを考えました。JSLintスタイルはつまり、私の意見や考えによってできたものではありません。
これは言語のすべての機能を使うのではなく、その中で信頼できるサブセットだけを使うという考え方です。言語設計者がある機能を追加し、その後にその言語が普及してしまうと、もうその機能を削除することはできなくなります。
しかしあなた方プログラマは、その機能を使わないという選択ができます。それによって間違いを起こしにくくなるという力を得ることができます。
バグはつねに起こり得ます。良いスタイルがバグをなくせるという約束はできませんが、良いスタイルによって直感的にもバグを起こしにくくなるのです。
―本書は、JavaScript言語の「良いパーツ」に注目し、良質なコードを書くためのポイントを示唆する書籍です。 「良いパーツ」を通してJavaScriptを再評価することで、見落とされていたJavaScript言語の本質が見えてきます。
あわせて読みたい
Pinterestはいかにスケーラビリティと格闘してきたのか(前編)。QCon Tokyo 2013
≪前の記事
JavaScriptのプログラミングスタイルはどうあるべきか? 重鎮Douglas Crockford氏が脳の働きとの関係を語る(前編)。QCon Tokyo 2013