生まれ変わったJavaScript/ECMAScript

2018年5月16日(水)
佐々木 俊介
【最新JavaScript開発~ES2017対応モダンプログラミング】 株式会社インプレスR&Dより発行された「最新JavaScript開発~ES2017対応モダンプログラミング」の立ち読みコーナー第1回です。

第1章 JavaScript解説

 第1章では言語仕様であるECMAScriptと主な利用用途の過去と現在について触れ、序章で述べた古いイメージからの脱却を図ります。

1.1 ECMAScript

 ECMAScriptはJavaScript1から言語仕様だけを抜き出した規格で、ブラウザのAPIであるDOMと言った余分なものをとりのぞいたものです。一般的にECMAScriptと呼ぶときは言語仕様の話をしたいのだと理解してください。ECMAScriptは、Ecma Internationalという情報通信における世界の標準規格を作ってる団体によって定められているECMA-2622という規格です。(同様にC♯もECMA-3343という規格になっています。)

 さて、2009年に制定されたECMA-262第5版(通称ES5)は長い間使われてきましたが、ES5までのECMAScriptは他の言語にはあまり見かけられない独特な仕様を持っていました。たとえば、オブジェクト指向言語としてのクラスはあるものの、リスト1.1のようにプロトタイプを定義する、といった独特な方法を採ります。他にもJavaScript初学者の大きな壁であるthisや関数スコープなどの特殊な仕様に苦しめられた人が非常に多く、いくつもの黒魔術めいたバッドノウハウ4が当たり前のように使われていました。

 リスト1.1: ES5までのコード

1: // クラスHogeのコンストラクターとなる関数の定義  
2: function Hoge() {  
3:   this.hoge = 'hoge'  
4: }  
5:   
6: // クラスHogeのメソッド定義  
7: Hoge.prototype.fuga = function (){  
8:   console.log(this.hoge)  
9: } 
10:  
11: var hoge = new Hoge() 
12: hoge.fuga() // -> hoge 

 しかし、2015年にECMAScript 2015(ES20155)という仕様が決まってから、現代的で実用に耐える言語になりました。リスト1.2のように素直なクラス定義ができるようになる、変数定義がブロックスコープになる、ラムダ関数のアロー表記が使えるようになる、など数え切れない程の改善が加えられています。

リスト1.2: ES2015以降のコード

1: class Hoge {  
2:   // コンストラクターの定義  
3:   constructor() {  
4:     this.hoge = 'hoge'  
5:   }  
6:   
7:   // メソッドの定義  
8:   fuga() {  
9:     console.log(this.hoge) 
10:   } 
11: } 
12:  
13: const hoge = new Hoge() 
14: hoge.fuga() // -> hoge 

プロトタイピングベースのOOPとは?

 「ECMAScriptはプロトタイピングベースのオブジェクト指向言語である」という主張を耳にします。しかし、ECMAScriptはさまざまな言語から影響をうけたマルチパラダイムな言語であるため、これはあまり意味がありません。ECMAScriptはオブジェクト指向言語だけではなく関数型のエッセンスも混じったものです。ScalaやSwiftなど、最近人気のある新しい言語はこのようなマルチパラダイムのものが主流です。ES5までの古いJavaScriptではプロトタイプベースというのが大きな呪縛になっていましたが、ES2015以降のモダンなJavaScriptで開発を行う際にはプロトタイプということを忘れてもかまいません。前記のような記事は信用ならないものを思っていいでしょう。

 ES2015が登場してからES2016とES2017がリリースされており、毎年6月頃に新しいバージョンが発表されています。ただ、現在のところ大規模な機能追加は行われていません。これはES5からES2015の変化が大きすぎて混乱を巻き起こしたことを省みて、毎年リリースすることで少しずつ改良していこうという方針からくるものです6。これにより、利用者としても新しい仕様に追従するのがとても楽になりました。ブラウザ側で対応していなくてもトランスパイルをするのがセオリーであるため、最新仕様を遠慮無く使えるのです。例えばES2017の目玉機能は、Async/Awaitというもので、非同期プログラミングを非常に楽に整理するためのものです。

 JavaScriptでは動的型が採用されていますが、静的に型を記述することもできます。ECMAScriptにその規定はありませんが、TypeScript7というECMAScriptのスーパーセットを用いるか、ECMAScriptに型定義を追加するFlow8というプロダクトによって、静的型プログラミングが可能になります。Flowは元々段階的に導入しやすさを売りにしていましたし、最近ではTypeScriptに関しても段階的な導入がしやすくなりました。JavaScriptプログラミングだからと言って型の恩恵を受けないというのももったいないので、少しずつでも導入していくといいでしょう。もちろん本格的なプロダクトであれば最初から検討をすべきです。

トランスパイル

 今のJavaScript開発が強力な要因がこのトランスパイルという考え方です。トランスパイルとは、ES2017やFlow、TypeScriptなどで書かれたコードをウェブブラウザ上で問題なく動くコードに変換(いってみればダウングレード)してくれる仕組みです。スピードのロスもほとんど無く実用的です。

 現代ではいろいろなプロダクトにJavaScriptが組み込まれていますが、これらのJavaScriptが必ずしも最新のECMAScriptに対応しているとは限りません。そのような場合でもトランスパイルをすることで、最新の手法を使いつつ古い処理系でも問題なくコードが動く、いわばいいところ取りができます。

 最新の仕様で楽にコードを書いて、あとはトランスパイルに任せてしまいましょう。互換性は勝手に吸収してくれます。また、トランスパイルは元となる言語がJavaScriptやAltJSと呼ばれるJavaScriptの亜種である必要はありません。たとえばCSSやテキストファイルやバイナリデータなどさまざまなデータ・アセットを、JSで扱える形に変換して取り込むことが可能です。

1.2 Node.js

 かつてJavaScriptは初期のブラウザである「Netscape Navigator」に搭載されたウェブ向けの組み込みスクリプト言語だったため、どうしてもウェブとの結びつきが強い面があります。それが打破されたのは、これから説明するNode.js9というソフトです。Node.jsによるサーバーサイドJavaScriptといわれる技術は広く用いられるようになっています。Google社がChrome10とそのオープンソースバージョンであるChromium11に使っているJavaScriptエンジンをV812としてオープンソースで公開して以来、V8を組み込む事例が増えました。その中で最も有名なのがNode.jsという処理系です。

 Node.jsの特徴は、GoogleのV8と非同期処理に関する設計のおかげでとても高速な処理系であるということです。また、世界的にユーザーがとても多く、エコシステムがしっかり育っていることや、ウェブ開発の技術がNode.jsに集約しつつあることも見逃せません。

 Rubyがrubyコマンドでスクリプトの実行をするように、Node.jsではnodeコマンドでJavaScriptを実行します。

$ node -e "console.log('Hello, World.')" 
Hello, World. 

 リスト1.3は、Node.jsで動くコードのサンプルです。コマンドライン引数に指定されたファイル名のファイルを読み出して画面に表示するというものです。

リスト1.3: Node.jsサンプル

1: #! /usr/bin/env node  
2:  
3: const fs = require('fs') 
4: const process = require('process') 
5:  
6: const filename = process.argv[2] 
7: console.log(fs.readFileSync(filename).toString()) 

 一行目はハッシュバングというUNIX系OS(Mac, Linux)で使われる呪文のようなものです。このスクリプトをどのコマンドに読み込ませればいいのかを示します。

 const fs = require('fs')というコードは、他のファイルやモジュールを読み込み、fsという変数に入れるものです。

 process.argv[2]は、コマンドライン引数のひとつ目を取るものです。なぜ2なのかというと、process.argv[0]にはnode.js自体のパスが入っていて、process.argv[1]には実行されるスクリプトが入っています。というわけでprocess.argv[2]から引数が始まるのです。

 console.log()は、引数に指定された文字を画面に出力するもので、fs.readFileSync()は引数に指定されたファイルを読み込んで、toString()で文字列化します。

 あなたがRubyやPython, あるいはPHPのような言語に触れているならば、細かい差違はともかく馴染みのある表記ではないでしょうか。

 このNode.jsが登場するまでのJavascriptのエコシステムは、基本的にはウェブブラウザ上で完結していました。信じがたいことにユニットテストすらウェブブラウザ上で動かすのが当たり前だったのです。Node.jsによってUNIXやWindowsのCLIとして動くようになってから、JavaScriptの本格的な進化が始まりました。この流れをいったん頭に入れておいてから、次節ではこれまでのJavaScriptのウェブアプリケーションでの実際の使われ方を見ながら、ウェブアプリケーションがどうあるべきなのかについて説明していきたいと思います。

1.3 JavaScriptの使われ方とその問題

 これまでのJavaScriptの多くはウェブアプリの一部として書かれてきました。たとえばウェブアプリを作るための人気のフレームワークにRuby on Rails(以後Rails)があります。RailsはRubyでコードを記述し、テンプレートによってHTMLをレンダリング(この場合はHTMLを作成)してウェブブラウザに渡します。JavaScriptやCSSは静的なファイルとして配信され13HTMLから読み込まれます。言ってみればメインがRubyで書かれて、そこにJavaScriptが混在するような形になります。

 複数のプログラミング言語が入り交じっているわけですが、JavaScriptが単純な用途にしか使われていないような頃はそれでも良かったのです。ちょっとした動きを与える程度なら、その複雑さは問題になりませんでした。しかしGoogleのGmailのようにウェブブラウザ上でJavaScriptを本格的に活用するようになってくると、簡易言語として扱うには複雑すぎるものになってしまいました。

 Gmailのようにページ遷移をしないウェブアプリケーションはSPA(Single Page Application)と呼ばれます。SPAを記述するためにはそれまでのJavaScriptでは力不足だったため、Google社のAngularJSやFacebook社のReactなどのフレームワークが生まれました。またReactなどで特徴的ですが、記述したJavaScriptはそのまま配信されるのではなくトランスパイルなどの加工をされて配信されるようになりました。CSSも同様に複雑化していったためにCSSをそのまま扱うのが現実的ではなくなりました14

 高度化・複雑化したJavaScriptは急激に成長しましたが、ここで問題になるのが、Ruby側で記述したコードとJavaScript側で記述したコードの食い違いです。これまではRubyの経験を積んだRailsエンジニアが片手間でJavaScriptを触ることも多かったのですが、片手間でやるには複雑になりすぎました。RubyとJavaScriptのコードが入り交じったりドメイン知識15が重複したり、不自然な場所で分断されるようになったためです。

 RailsではDRY原則というものが重視されます。これは簡単にいうと重複を防ぐという考え方です。たとえば税率計算のロジックがあるとしてそれを複数の箇所に書くとメンテナンスがとても大変になります16。RubyとJavaScriptが入り交じっている場合、両方に同じロジックが出てくることも多々あり得ます。

 さて複雑さや重複を解決する方法はどのような物でしょうか。次の節ではうまく分離を行うことで解決する方法を提案してみたいと思います。

DRY原則

 DRYはDon't Repeat Yourselfの略で「あなたの手で繰り返してはならない」という意味です。以下は「達人プログラマー」という本に書かれている言葉ですが、この原則を守ることで生産性が劇的に向上するといわれています。

 

 すべての知識はシステム内において、単一、かつ明確な、そして信頼できる表現になっていなければならない。


 ドメイン知識はわかりやすい例です。たとえばある複雑な税率計算をするプロダクトがあったとして、その計算が各所に散らばっていると、税率計算のルールが変わったときに多くの場所を書き換えなければならなくなります。これが一箇所に集約してあればそこを書き換えるだけで変更することができるのです。オブジェクト指向におけるデザインパターンにはこういった重複をとり除くためのテクニックが色々とあります。

 「あなたの手で」と強調されているのは、人間にとっての重複が無ければ良い、つまり機械にとっては重複しているけど人間にとって重複していない状況なら良いという意味です。むしろ、重複したものを機械的に生成するというアプローチが推奨されているのです。生産性の劇的な向上はここにあります。

 生成するものはたとえばSQLです。SQLの手書きはプログラム本体と過度の重複を生じやすい例です。O/Rマッパーなどのミドルウェアを使えば、SQLを手書きせずともデータ構造を元に自動生成されます。昔であれば、マシンの性能面からSQLを手書きでチューンする重要性は高かったのですが、昨今のソフトウェア技術及びハードウェアの進歩や性質の変化によって、RDBの状況とは大きく様変わりしました。O/Rマッパーを使いつつ、いざという時だけ一部のSQLを手書きするということもよくある話です。

 他にもドキュメントの生成やJSON Schemeによる生成なども生産性を向上させるテクニックです。プログラミング開発においては人間がボトルネックです。人間が極力作業をしなくていいようにすることがもっとも生産性を向上させる手段となります。

1.3.1 APIサーバーとJSの分離による解決

 APIサーバーというのは人間相手にHTML(や他のファイル)を返すサーバーではなく、クライアントのプログラムがアクセスしてやりとりするためのサーバーです。よく使われるのは、HTTP/HTTPSなどでREST APIと呼ばれるパターンにしたがってリソース(主にJSON)をやりとりされるものです。JSONはJavaScriptから派生したデータ形式で、非常にシンプルなためあらゆる言語・環境で使われています。

リスト1.4: JSONの事例

1: {  
2:   "name": "Kuraudo",  
3:   "class": "Knight",  
4:   "level": 12,  
5:   "HP": 40,  
6:   "MP": 25,  
7:   "items": ["sword", "armor", "shield"]  
8: } 

 それではクライアントはどういうものになるのでしょうか。一番よく使われるのはiOSやAndroidなどのモバイルアプリかもしれません。ゲームやツールなどさまざまなモバイルアプリでは、APIサーバーと通信することでネットワークを利用することができます。別のサーバーがサーバー同士でやりとりをするためにAPIが使われることもあります。そしてウェブブラウザの場合は、モバイルアプリ同様にウェブブラウザ上で動くJavaScriptからAPIサーバーにアクセスしてリソースを取得し、DOM操作でレンダリング(この場合はウェブブラウザの画面に表示)を行います。

 ウェブブラウザではHTML/CSS/JavaScriptで構成されたSPAがよく使われます。CSSやJavaScriptの加工は事前に行われるため静的に配信できます。以前はこの加工にRubyなど他の言語で書かれたツールを使うしか無かったのですが、今はNode.jsによるエコシステムがあるため、JavaScriptで書かれたツールをNode.jsで動かすのが一般的です。

コラム 静的配信と動的配信の違い

 静的・動的とは何をさすのでしょうか?ウェブブラウザがアクセスした時にいつも同じ結果を返すのが静的で、状況に合わせていろいろ変化するものを返すのが動的といえます。仕組みとしては昔なつかしのCGIのようにウェブサーバー上で何らかのプログラムが走ってそれによって結果が変わるものです。

 静的ファイルの利点はサーバーの負荷が少ない・静的ファイルの配信専門のサービスを利用できるなどがあります。大規模アクセスのあるウェブサイトでは、CDN(Contents Delivery Network)と呼ばれる、自分の代わりにコンテンツを配信してくれるサービスを活用することが多くなりましたし、Amazon S3のように静的ファイルを安価で配信できるサービスもあります。

 APIサーバー(リソース管理)とウェブクライアント(ユーザーインターフェース)が分離したことで、開発言語が入り交じることがなくなり複雑さが減ります。たとえばAPIサーバーとJavaScript側をそれぞれ分業17で開発することも可能ですし、実際にこの開発スタイルは最近よく採用されています。しかし、まだドメイン知識の分散、つまり重複は残っています。

 もう一歩踏み込んでみましょう。Node.jsが登場するまではAPIサーバーは他の言語で書かざるを得なかったのですが、今はNode.jsでAPIサーバーを構築できます。この場合クライアントとサーバーでそれぞれJavaScriptが動くので、ライブラリを共有するというスタイルでドメイン知識の「DRY」を保てるようになります。ライブラリ共有というスタイルにはドメイン知識のDRYを保つ以外にも利点があって、ライブラリという形に切り出すことにより、自然とユニットテストがしやすい形にすることができます。次の節ではサーバーをJavaScriptで構築する方法についても触れてみます。

サーバーサイドレンダリング

 APIサーバーとクライアントの分離では、ウェブブラウザ上でJavaScriptを動かすことが必須です。これには二つの問題があります。一つ目はユーザーがウェブブラウザ上でJavaScriptの実行を切ると動かなくなることと、二つ目はSEOで不利になる可能性があることです。そこでSSR(Server Side Rendering)という技術を使います。

 SPAライブラリ・フレームワークの多くはSSRに対応しているため、ちょっとしたコードの追加だけでサーバー側でJSを処理してくれます。SSRに対応していないフレームワーク・ライブラリの場合でも簡単なコードの追加で対応する為のテクニックがあるため、さほど手間はかかりません。

 SSRはクライアント側の処理を肩代わりしているだけなので、クライアントとサーバーの分離は保たれます。

1.4 JavaScriptの応用例

 JavaScriptはウェブアプリケーションを作成するためだけの言語ではありません。さまざまなところでJavaScriptは使われています。ここではJavaScriptの応用例について見ていきましょう。

1.4.1 サーバーアプリケーション

 先ほどの説明にもあったように、サーバーをJavaScriptで構築するのは良い選択肢です。アクセスの大きな人気スマートフォンのゲームサーバーにもNode.jsが使われるなど、サーバーアプリケーションの第一線でもJavaScriptは活躍しています。元々Node.jsは同時接続数が多くなると生じる、いわゆるC10K18問題を解決できる仕組みをもっています。

C10K問題とその解決

 クライアント1万台問題ともいわれ、同時接続数が増えるとサーバーが耐えきれなくなるという問題です。負荷に問題が無いように見えても発生する事例があり、マルチプロセス・マルチスレッドによる同時接続をさばく仕組みのときによく生じます。

 複数の接続を捌くとき、シングルスレッドでなんの工夫しないと同時に1つの処理しか捌くことができません。これは主に処理が同期的なためにブロッキングしてしまうからです。接続1つに対してプロセスを1つ作る仕組みにすればブロッキングされていてもひとまず複数の接続を捌くことができますが、プロセスというのはかなり重いものです。そこで負荷軽減のためにマルチスレッドが活用されるようになりました。しかし、このマルチスレッドでも大量の接続を捌くために大量のスレッドを作ると、スレッドを管理する仕組みがパンクするようになってしまったのです。

 実はシングルスレッドでも工夫すれば大量の接続を捌けます。昔ながらのselectや、より新しく高性能なkqueueやepollといった、通信などのイベントを検知して通知をしてくれるシステムコール(kernelのAPI)を使ったイベントループと非同期処理を駆使すれば、ノンブロッキングで同時接続を捌けるのでシングルスレッドでも大丈夫なのです。

 元々ウェブサーバーはCPUの演算よりもI/O待ち時間の方が大きくなります。ネットワークやディスクアクセスなどの待ち時間の大半で、CPUは暇なのです。このためマルチスレッドは、1つのスレッド(1つの接続)の大半の時間がアイドル状態になってしまうため、言ってみれば過剰な仕組みです。ノンブロッキングでイベントループを回すだけの方が軽くてちょうどいいのです。

 Node.jsの特徴はこの仕組みを使ったシングルスレッドの動作モデルです。元々JavaScript自体イベントドリブンの性質が強く非同期処理との相性の良い言語です。シングルスレッドのため、ユーザーはマルチスレッドにありがちな競合を気にしなくてもいいという利点もあります。そのままではCPUの複数のコアを使い切るのは難しいですが、clusterという複数プロセスで動かすための標準の仕組みでマルチコアを使い切れます。

 JavaScriptでサーバーを動かす場合、Node.js上でExpress19を使うのが主流です。これはとても軽量で使い勝手のいいウェブサーバーで、WebSocketなどにも対応しています。リスト1.5はExpressを使ったNode.jsのコードのサンプルです。起動するとローカルの3000版ポートで待ち受けるので、ウェブブラウザでhttp://localhost:3000/にアクセスするとHello, world.という文字列が帰ってきます。

リスト1.5: Expressのサンプル

1:   const express = require('express')  
2:   const app = express()  
3:   
4:   app.get('/', (req, res) => {  
5:     res.send('Hello, world.')  
6:   })  
7:   
8:   app.listen(3000) 

1.4.2 デスクトップアプリを作る為のElectron

 Electron20は最近エンジニアの間で人気21が高まっているAtom22というオープンソースなテキストエディタを作るために生まれたGitHub社製のフレームワークです。このElectronおよびAtomはJavaScriptで書かれています。Atom以外にもMicrosoft社のVisual Studio Code23(VSCode)という軽量なIDEがElectronで作られています。もしあなたがVimやEmacsに強いこだわりをもつ人でなければ、AtomやVSCodeの導入を検討してみる価値はあるでしょう。

 ElectronはGoogle社のChromiumというウェブブラウザ24を内蔵していてHTML/CSS/JavaScriptでウェブページとほぼ同じやり方でUIを開発できるため、OS/GUIのAPIを新しく覚える必要はありません。しかもElectronではChromiumを使うとわかっているため、ブラウザの互換性25を気にする必要が無いので、新しい機能をカジュアルに試せます。また、WindowsやMacやLinuxといった違いも、ほとんどElectronが吸収してくれます26

 最近はCSSでネイティブアプリケーションに近いGUIパーツを簡単に作成することができますし、スピードの鬼であるGoogle社による技術がベースにあるため、ネイティブアプリに比べて不利な点はあまりありません。

 またNode.jsも内蔵しており、サーバーアプリケーションのコードも動かすことができるため、よほど特殊なものでなければそれなりのアプリケーションを開発することができます。これにより開発コストを大幅に下げることが可能です。

1.4.3 モバイルアプリを作る為のReact Native

 JavaScriptのフレームワークで一番人気であるFacebook社のReact27には、ReactNative28という兄弟プロダクトが存在します。これはiOSやAndroid向けのモバイルアプリを、Reactのコードと多くの部分で共有できるようにしたフレームワークです。FacebookやAirBnB, Instagramなどの名だたるモバイルアプリで実際に使われています。

 モバイルアプリを作成するのはかなり大変です。iOSならSwift(あるいはObjective-C)、AndroidならJavaかKotlinというように言語も異なりますし、それぞれ独自の複雑なコアAPIを駆使する必要もあります。そのためiOSとAndorid両方を開発できる人はとても珍しく、ネイティブ29開発の知見はiOSとAndroidでは別々のものとなってしまい、iOSとAndroidそれぞれのソースコードが完全に分断されるのです。そのため開発工数・人員が二倍(場合によってはそれ以上)になってしまいます。

 ReactNativeではJavaScriptとReactを使ってネイティブアプリケーションを開発できますが、全部をReactNativeで記述しようとした場合にはちょっとしたアプリしか作ることはできません。しかし、ReactNativeにネイティブのコード(SwiftやJava)を混ぜることで、iOSとAndroidでそれなりのコードを共有ができます。APIサーバーとクライアントの分離のところでも書きましたが、コードの共有ができるというのは強い武器になります。FacebookやAirBnB, Instagramといったトップクラスのサービスで使われているのはそのためです。

 つまりReactNativeは、ネイティブアプリに取って代わるものではなく、ネイティブアプリ開発の一部をJavaScriptで肩代わりして、iOSとAndroidのコードを共通化するためのものです。言ってみればiOSとAndroidをつなぐグルー30みたいなものだと考えればよいでしょう。

 ただし現時点ではまだReactNativeは登場してから新しく、枯れているとはいえない状況のため、これからのフレームワークであることは注意しなければなりません。

 React Nativeにはfor Windows31やfor macOS32もあるので、デスクトップアプリをReactNativeで作成することも可能ですが、まだあまり事例もないため実際に開発することは大変かもしれません。

learn once, write anywhere

 大昔にSunは "write once, run anywhere" 、つまり一度書いたJavaはどこでも動くと言っていました。実際には一度書いたものを使い回し続けるのは弊害の方が多くこの言葉も死語となってしまいました。

 React/ReactNativeには "learn once, write anywhere" といううたい文句があります。コードの使い回しではなく、学習コストが下がるということです。Reactというやり方を一度覚えれば、ウェブ・モバイルアプリそれぞれに応用が利くためです。モバイルファーストが叫ばれるようになってからそれなりの時間が経ちましたが、モバイル開発は複雑化し続ける一方です。モバイル向けのウェブサイト、iOSアプリ、Androidアプリと三つに完全に分断されいたところにReact/ReactNativeによって秩序がもたらされるのです。完全な統合まではできませんが、ノウハウの共有やコード・ライブラリの共有ができるというのは計り知れないメリットなのです。

1.4.4 クラウドサービスで使う

 現代のサーバーは、自社やデータセンターにサーバーを置いてネットワークを引いてサーバーを管理する、いわゆるオンプレミスなどは好まれません。多くの場合Amazon社のAWSかGoogle社のGCPなどクラウドサービスが利用されています33

 最近はクラウドの中でもサーバーレスと呼ばれる技術がよく使われます。AWSであればEC2というのが汎用的なコンピューティングの仕組み(サーバー)ですが、サーバーを立てずにコードだけをLambdaにデプロイします。Lambdaではさまざまなトリガーによってコードが走り、結果を別の場所に格納したりAPIとしてリソースを返したりします。言ってみれば、Lambdaはサーバーのもつ「コードを実行する」部分だけを切り売りしているようなもので、管理の手間やコストを減らせます。LambdaではPythonやJava, C♯でもコードを書くことができますが、JavaScriptは初期からサポートされている言語です。

 さて、Lambdaのコードはどのようなものでしょうか?実際のところ、ほとんど普通のNode.jsのコードです。

リスト1.6: AWS Lambda

 1: exports.handler = (event, contect, callback) => {
 2:   if (event.text === 'がおー') {
 3:     awesomeBot.post('#friends', '食べないでくださいー')
 4:   }
 5: 
 6:   callback(null, {statusCode: 200, headers: {}, body: ""})
 7: }

 このような感じのコードになります。AWS Lambdaは何をトリガーにするかによって、eventの内容などが大きく変わります。よくあるパターンの一つはAPI Gatewayというサービスとの併用です。たとえばSlackのチャットボットを作るのであれば、SlackのIncoming Webhooksを利用し、Slack上での発言がAPI Gateway経由でAWS Lambdaに飛ばされ、Lambdaの関数(exports.handler)が実行するパターンが一般的です。ただ、AWSに関して詳しく説明するとページがいくらあっても足りないので、詳しくはAWSの公式などを参照してください。

 またGoogleにもGoogle Cloud FunctionsやGoogle Apps Script(GAS)などがあります。これらもうまく活用すればとても便利です。

1.4.5 Chrome extensionを書く

 Chromeでは拡張(Extension)をJavaScriptで書けます。最近ではChrome Extensionがウェブブラウザの拡張として標準になり、他のウェブブラウザでも対応する動きが出ているため、Chrome Extenionを覚えておくと損はありません。ものによってはChromeの動作が重くなる可能性もありますが、それなりにお手軽にウェブブラウザを拡張できます。

リスト1.7: Chrome Extension

 1: const merchantInfo = document.getElementById('merchant-info')  
 2: const isAmazon = () => {  
 3:     const s = merchantInfo.innerHTML.replace(/\s+/g , ' ')  
 4:     return s.includes('Amazon.co.jp</a> が販売、発送します。') ||  
 5:     s.includes("Amazon.com Int'l Sales, Inc. が販売")  
 6: }  
 7: const elem = document.createElement('span')  
 8: if (isAmazon()) {  
 9:     elem.style.color = 'blue' 
10:     elem.innerText = 'Amazon公式商品' 
11: } else { 
12:     elem.style.color = 'red' 
13:     elem.innerText = '注意!Amazon以外が発売している商品です' 
14: } 
15:  
16: const productTitle = document.querySelector('#productTitle') 
17: productTitle.parentElement.appendChild(elem) 

1.5 他にも

 JavaScriptを他のソフトウェアに組み込む事例も数多くあります。たとえばMacromediaのFlashにもActionScriptというECMAScriptの亜種が組み込まれていますし、有名なKVSストレージであるMongoDBにもクエリ言語としてJavaScriptが組み込まれています。

 今後もV8を組み込むなど、JavaScriptを内蔵するソフトウェアが増えるのではないでしょうか?

1.6 JavaScriptエンジニアとしてのキャリア

 以前のJavaScript界隈はあまり技術的評価が高いものではありませんでした。見た目に派手さはあるものの、技術的には微妙な扱いをされることも多かったのです。所詮ウェブページにちょっとした動きを付けたりするくらいのもの、いってしまえば他の言語に劣るような片手間でできる程度と見られていました。それが変わり始めたのはNode.jsの登場によるサーバーサイドJavaScriptや、SPAプロダクトといったウェブの複雑化と、そしてES2015の登場でECMAScriptがモダンな言語に生まれ変わったことによるものです。

 ウェブの複雑化のため、他の言語のエンジニアが片手間でやるには厳しい時代になりました。フロントエンド開発に携わるのであればJavaScriptのスキルを身に着けて損はないでしょう。

 現在は、まだサーバーサイドJavaScriptを採用している事例や、ReactNativeを採用しているモバイル開発事例は少ないかもしれません。しかしこれらにある多大なメリットを見逃し続けるのはもったいないことです。特にモバイル開発はReactNativeで大きな変化を遂げる可能性が高いからです。

 現代のプログラミング環境は、様々な条件のそろったとてもバランスのとれた状況だと筆者は考えます。かつてJavaScriptで開発を行っていたプログラマの中には、jQueryやES5といった化石のような技術にとらわれている人も散見されます。しかし、今はそういったものをスキップして、ES2017やモダンなライブラリをいきなり覚えることができるのです。開拓者というほどの苦労は必要ありません。それでいてこれから案件が増えるので先行者利益のある状態です。今ちょうど美味しい技術、それがJavaScriptなのです。

1.7 まとめ

 JavaScriptは言語仕様であるECMAScriptと、Node.jsおよびパッケージシステムのnpmによるエコシステムが強みです。

 ECMAScript2017が現時点での最新版で、オーソドックスなオブジェクト指向言語であり、ウェブだけではなくサーバーやデスクトップ・モバイルなどの開発もできる、全方位の言語です。

 これまでウェブアプリケーションの多くはRailsのような環境で作成されてきましたが、現代の高度化したウェブサービスを提供するためには、すくなくともAPIサーバーとクライアントの分離をすべきです。またよりよいウェブサービスを作る為にはAPIサーバーについてもJavaScriptを採用する大きなメリットがあります。今後は最低でもウェブ開発はJavaScriptに集約するでしょう。

 ウェブ以外のアプリケーション開発にもJavaScriptは大きな力を発揮します。ElectronやReactNativeを使えばアプリケーションとウェブでコードやノウハウの共有ができます。高度化・複雑化する一方のモバイル開発を少しでも和らげることができるJavaScriptという技術は是非とも検討すべきなのです。

(次回へ続く)

1. 「JavaScript」はECMAScriptにDOM(Document Object Model)というウェブページを扱うためのAPIなどを含めた総合的なものを指す用語です。言語仕様だけに言及する際はECMAScriptと呼びます。

2. https://www.ecma-international.org/publications/standards/Ecma-262.htm

3. https://www.ecma-international.org/publications/standards/Ecma-334.htm

4. ES5までの書籍やウェブ記事には、この時代の負の遺産があまりにも多く有害で困りものです。

5. ECMAScript 2015は、ECMA-262第6版なのでES6と呼ばれることもありますが規格名としてはECMAScript 2015の方が正式な名称です。ES5までは一律ECMAScriptという規格でしたが、ECMA-262第6版以後は、ECMAScript20xxのように制定された年が規格名に入るようになりました。

6. 最近はOSやアプリも毎年かそれ以上の短いサイクルでのリリースを採用することが多くなりました。これは、大きな変更が加わるとバージョン移行がしづらくなってしまうため、小さい変更を繰り返すという考え方によるものです。利用者にも開発者にとっても負担を減らす優れたやり方です。

7. https://www.typescriptlang.org/

8. https://flowtype.org/

9. https://nodejs.org/

10. https://www.google.co.jp/chrome/browser/desktop/index.html

11. https://www.chromium.org/Home

12. https://developers.google.com/v8/

13. Apacheやnginxで特定のURLで静的ファイルを配信することが多いですね。

14. 生のCSSにはさまざまな弱点があり、それらを克服するためにSCSS/SASSやPostCSSと言ったAltCSSを使うのが通例になっています。

15. ドメイン知識とは、アプリケーションが解決する対象に関する知識です。たとえば銀行アプリケーションであれば銀行の仕組み、たとえば利率計算といった計算の手順、お金をやりとりする手順などを指します。

16. 筆者が実際に見聞きした物としては、RailsでJavaScript側が複雑化して手に負えなくなったSPAプロダクトがありました。そのプロダクトはCSSでも苦労していて、一部を書き換えると予想も付かないところに影響が出ていました。

17. JSON Schemeなどを使ってAPIサーバーの仕様を共有することでさらに開発の安定化も可能です。

18. http://www.kegel.com/c10k.html

19. http://expressjs.com/

20. https://electron.atom.io/

21. 元々似たようなテキストエディタとしてSublime Textというとても有名なシェアウェアがありましたが、最近はAtomが勢力を伸ばしています。実は本書の執筆にもAtomを使っています。

22. https://atom.io/

23. https://code.visualstudio.com/

24. ChromiumはChromeの一部をオープンソースにしたものです。

25. 最近はブラウザの互換性が高いのであまり気にする必要はないのですが、新しい機能をカジュアルに試せるという利点があります。

26. 実際にはそれぞれの環境で動かすには細かい部分で違いがあるため、少しノウハウが必要になります。

27. https://facebook.github.io/react/

28. https://facebook.github.io/react-native/

29. システムで用意されている標準の言語で標準のAPIを叩くスタイルをネイティブ開発といいます。JavaScriptやC♯を使ったマルチプラットフォーム技術はネイティブ開発ではありません。

30. グルー言語というものがあります。異なるものを接着する接着剤・糊のようなものです。

31. https://github.com/Microsoft/react-native-windows

32. https://github.com/ptmt/react-native-macos

33. もちろん厳密にはサーバーはありますがサーバーという区分を占有しません。

高校生のときにパソ通にハマリ、その後紆余曲折を経てテキストエディタやMSXエミュレータその他を開発。技術者として勤務した後、現在はフリーランスエンジニア。技術同人誌や技術ブログやマッハ新書などを書いている。新しい技術に目が無い。アルゴリズム大好き。著書に『最新JavaScript開発~ES2017対応モダンプログラミング』(インプレスR&D)など。

連載バックナンバー

開発言語
第5回

ユニットテストをしよう

2018/6/11
【最新JavaScript開発~ES2017対応モダンプログラミング】 株式会社インプレスR&Dより発行された「最新JavaScript開発~ES2017対応モダンプログラミング」の立ち読みコーナー第5回です。
開発言語書籍・書評
第4回

型の恩恵をうける

2018/6/5
【最新JavaScript開発~ES2017対応モダンプログラミング】 株式会社インプレスR&Dより発行された「最新JavaScript開発~ES2017対応モダンプログラミング」の立ち読みコーナー第4回です。
開発言語書籍・書評
第3回

ECMAScript

2018/5/29
【最新JavaScript開発~ES2017対応モダンプログラミング】 株式会社インプレスR&Dより発行された「最新JavaScript開発~ES2017対応モダンプログラミング」の立ち読みコーナー第3回です。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています