4年と3カ月開発の続いているシングルページWebアプリケーションの開発環境で変化した点としなかった点

この記事は[ACCESS Advent Calendar 2016](http://qiita.com/advent-calendar/2016/access) 21日目の記事です。

ACCESSで電子書籍のブラウザ向けビューワを開発をしている@aTomoyaKuboです。

この記事では2012年9月から開発が始まったPUBLUS Reader for Browserの開発環境の
開発初期から変化した点としなかった点をその理由を踏まえてまとめたいと思います。

# なぜこの記事を書こうと思ったのか

- 2012年9月から4年3カ月開発を続けている間に世の中のブラウザアプリの開発環境(ライブラリや言語、ツール)は大きく変化しました。  
その中で変化した点としなかった点をまとめて現状を再認識したかった。
- どのような**考え**で変化したのか**しなかったのか**を  
まとめた記事をあまり見かけたことがなかったので実例として共有することにも意味があると考えた。
- まとめることで状況を客観的にみたかった。

# 想定読者

- ブラウザアプリやウェブアプリの開発を行っている方。
- 世の中の変化にどのように対処していくか同じく悩んでいる方。
- そこそこの開発が続いているウェブアプリがどのように変化しているのか興味ある方

# この記事に書かないこと

- 最近の技術トピックのまとめやその詳細の記述
- サーバーサイドに関する事項

# PUBLUS Reader for Browserって？

ブラウザ向けのEPUB用電子書籍ビューワです。
ブラウザ側でUIの動作やコンテンツの取得・復号、表示等を行うシングルページWebアプリケーション(SPA)です。
サポートブラウザは IE9以上, Firefox, Chrome, Safari, Android標準ブラウザ, Mobile Safariです。

**ここからが本編です。**

# 開発初期の環境

## 言語

IE9以上のサポートだったのでHTML5/CSS3を採用しました。
当時はCoffeeScriptも盛んに利用されていましたが、開発要員の確保や言語寿命への不安を考慮に入れ採用しませんでした。
CSS3を採用したのも開発要員の確保が主な理由です。  

| 項目 | 言語 |
|:--|:--|
| マークアップ  |  HTML5 |
| スタイル  | CSS3  |
| スクリプト  | ES5 Strict  |
| 静的型付け  | JSDoc  |

## ツール

ユニットテストやカバレッジ測定、CIなどを開発初期から整備していました。
テストコードがないプロダクトは寿命が短く長期的に見て開発コストが増大すると判断したためです。
また一度動くコードだけを書き始めるとテストコードを考慮していない実装が増え、
後々にテストコードを追加するのは非常に大きなコストになると考え初期段階で整備しました。

| 項目 | ツール |
|:--|:--|
| IDE | Eclipse|
| タスクツール | Grunt|
| ユニットテスト | Qunit 1.9.0|
| ユニットテスト実行環境 | サーバーを立ててブラウザからユニットテストページを開く|
| ユニットテスト集計 | Qunit-tap|
| ユニットテストカバレッジ測定 | JSCoverage|
| CI | Jenkins|
| Linter | JSHint|
| CSS最適化 | CSSmin|
| HTML最適化 | HTMLmin|
| コードの結合と最適化 | Closure-compiler|
| パッケージマネージャ | NPM|

## 利用ライブラリ

長く開発が行われる可能性を考えライブラリの寿命を考慮して当時メジャーでシンプルな構成のライブラリを選択しました。
シンプルな構成のライブラリを選んだのは、新規の利用者も多くなりライブラリの寿命が長いと考えたこと、
別ライブラリに移行が必要になった場合も手間が小さいと考えたためです。

| 項目 | ライブラリ |
|:--|:--|
| MVC | Backborne.js 0.9.2|
| DOM | jQuery-1.8.0|
| UI | jQuery-UI-1.9.0|
| util | underscore.js|

※ライブラリは一部です。

# 現在の開発環境

## 言語

変化しませんでした。

## ツール

| 項目 | 変更前 | 変更後 |
|:--|:--|:--|
| IDE | Eclipse| WebStorm |
| タスクツール | Grunt||
| ユニットテスト | Qunit 1.9.0||
| ユニットテスト実行環境 | サーバーを立ててブラウザからユニットテストページを開く| Karma |
| ユニットテスト集計 | Qunit-tap| Karma |
| ユニットテストカバレッジ測定 | JSCoverage| Karma |
| CI | Jenkins||
| Linter | JSHint| WebStorm組み込みのLinter |
| CSS最適化 | CSSmin||
| HTML最適化 | HTMLmin||
| コードの結合と最適化 | Closure-compiler| uglify |
| パッケージマネージャ | npm||

## 利用ライブラリ

機能追加でライブラリの追加はありますが基幹ライブラリやバージョンは変化していません。

# なぜ変化したのか？

## ツール

変化したのは開発に効率が悪いや実行が面倒などの不都合や、
正常に動作しないことがあるとといった問題の発生が主な理由です。

- IDE : Eclipse => WebStorm   
EclipseはWeb開発環境が十分とは言えずコード補完やIDE上でのLintが非常に重い(メモリも多く消費する)などの多々問題を抱えていました。  
そこでWebStormを評価し、Web開発環境との連携等や親和性が高く、コード補完やLintなどプラグインの追加が不要で利用できることから移行しました。  
WebStormは有料ですが導入した効果は非常に大きいです。
- ユニットテスト実行環境 : サーバーを自前で立ててテストページ読み込み => Karma  
ユニットテストを導入していたものの手元開発環境での実行環境が手動でのテストページ読み込みと非常に面倒でお粗末なものでした。  
Karmaによりテスト実行を簡略化できるため動作に問題ないか評価後、移行しました。
- ユニットテスト集計 : QUnit-Tap => Karma  
テスト実行環境をKarmaに移したのでテスト集計もKarmaに変更しました。
- ユニットテストカバレッジ測定 : JSCoverage => Karma  
CI環境でのカバレッジの測定時間がコードの増加とともに非常に遅くなり(60分かかるようになっていた)CIの実行時間が問題になっていました。  
Karmaを評価していたときに実行時間が3分程度に短縮されレポートも問題なく動作したので手元開発環境の移行とともに即CIも移行しました。
- Linter : JSHint => WebStorm組み込みのLinter  
WebStormのLinterが便利なので利用しています。  
コマンドラインやCIでのLintが形骸化しているのでESLintを導入を検討しています。
- コードの結合と最適化 : Closure-Compiler => uglify  
Closure-Compilerはバグが多く変換に失敗するライブラリが存在したこと、  
実行環境がJavaのため別途ツールとしてインストールが必要だったという理由で  
npmからインストールが可能でJavaScriptベースのuglifyに変更しました。

# なぜ変化していないのか？

## 言語

初期の段階からユニットテストやCI環境を整備していたため、
大きな改修が必要になっていないのも変化していない理由の一つです。

* マークアップ : HTML5  
特に理由も移行先もないため。
* スタイル : CSS3  
Sass、ScssやLESSを検討したことはありました。  
移行にかかる作業量を考慮に入れ現段階では移行に至っていません。  
またCSS自体の進歩に期待もしていました。  
CSSに変数や計算は入りましたので現在はPostCSSの移行を視野に入れ検討中です。
* スクリプト : ES5 Strict   
  * ES2015への移行を検討中です。アローファンクションなど開発効率を向上させる機能も豊富なためです。  
  既存のコードベースの移行をどのようにするか、コストはどの程度かなどを考慮に入れつつ検討中です。  
  * Coffee Scriptを採用しなかったので移行を急ぐ必要もなかったのも変化がない理由の一つです。  
  * 現状の開発環境がビルドせずに動作確認が可能になっておりBabelによる変換にかかる時間が気になっていました。  
  幸いブラウザでのES2015(やasync/await)のサポートが一部ブラウザで行われてるので開発環境においてはビルドフリーにできると考えています。  
* 静的型付け : JSDoc  
JSDocにて型付けを行っているので必要十分ではありました。  
ただnull安全等も考慮してFlowへの移行は検討しています。  
Flowのsuggestを利用することで型指定の導入のコストを下げられそうというのも検討の理由です。  

## ツール

- タスクツール : Grunt  
「一時期開発者がいなくなった」、「パッケージが古いままのものも多い」などが起きていますが実開発をするうえで致命的な問題が起きていない、  
タスクを多く作成しているのでその移行コストが大きい、Gruntと新規ツールの混在はメンテナンス性の低下から避けたい  
といった理由から変更していません。新規プロダクトならGulp(やWebpack)にします。  
- ユニットテスト : QUnit  
テスト項目数が非常に多いため、他テスト環境への移行コストが非常に大きいことことが理由です。
またプロジェクトを健全にするにはユニットテストが書かれていれば必要十分であるとも考えています。
- CI : Jenkins  
本体もプラグインもバージョンアップが続いているので特に変更する理由がないためです。
- パッケージマネージャ : npm  
他に移行先もなく困ってもいないので変更していません。  
Yarnは評価しているところです。

## 利用しているライブラリ

- ライブラリ構成 :   
追加したものはありますが初期のライブラリから変更していません。はやりのReact/Reduxといったライブラリを利用したいですが、  
はやりを追いかけてばかりでは追いかけることばかりに時間を割いてしまうことになります。  
追いかけたくなりますが開発をするうえで問題が起きていないか、本当に必要かといったことも考慮に入れ判断するようにしています。  
まとめていてunderscoreのままなのは理由が思い当たらないのでlodashに変更しようと思います。
- ライブラリのバージョン :   
問題が起きない限りは変更しないようにしています。  
理由はメジャーバージョンの変更により利用箇所のコードの変更が必要であったり、不具合が発生するといった問題のためです。  
バグ修正やパフォーマンス向上など魅力的な変更も多々ありますが、実際にそれが製品の品質向上に直接つながるかは別問題と考えました。

# まとめ

- ツールは大きく進歩しており利便性も格段にいいものが出てきたのでそれらに移行しました。
- その他は問題や移行に見合う大きなメリットがない限り変更しない保守的な運用になっています。  
変化が大きいのでどんどん変更を取り入れていきたい気持ちになりますが、  
そこは冷静に必要性やコストを考慮に入れ判断するようにしています。
- とはいえ、まとめてみると変化していない点が非常に多く気になる点が多々ありました。  
変化しないことが悪いことではありませんが、さまざまな点で進歩があるはずなので今一度、変化しないままでいいのかは検討するべきと思いました。    
特にライブラリのバージョンやツールのバージョンは今一度見直したいです。  
作業コストの兼ね合いで難しいものが多いと思いますが、作業コストに見合うものもあると思います。

明日は @ymtszw です。