モジュール管理

モジュール管理はモジュールローダーライブラリをRequireJSを利用

Presenter Notes

AMD

  • AMD(Asynchronous Module Definition)とは

モジュールの定義方法

1 define(
2     module_id /*optional*/,
3     [dependencies] /*optional*/,
4     definition function /*関数 or オブジェクト*/
5 );

モジュールの利用方法

1 require(['foo', 'bar'], function ( foo, bar ) {
2     // rest of your code here
3     foo.doSomething();
4 });

Presenter Notes

問題点

RequireJSは使えば使うほどファイルが細分化され、しかも非同期読み込みができなくなっていくという問題を抱えている

解決方法

  • RequireJS用のビルドツールr.jsを使う
    • ファイルが一つにまとまる
    • RequireJSの利用を決定した要因

Presenter Notes

r.jsでの結合

  • node.js or Javaでの実行環境がある
    • どのOSでも動かせるはず
  • コンフィグファイルを書いて、r.jsでビルド
    • 依存関係を指定してファイルの結合(include/exclude)
    • Closure Compiler or uglifyJSで最適化
  • build/example.build.js at master from jrburke/r.js - GitHub
    r.js -o path/to/app.config.js

Presenter Notes

テスト

プログラミングミスを発見したら

  • まずはその失敗するテストケースを書く
  • コードを修正する
  • テストがグリーン

https://twitter.com/#!/dekokun/status/140428178211602434

Presenter Notes

e.g)レガシーなモジュール

  • 最初はレガシーな感じのモジュール
  • 後でリファクタリングする予定だった

sampleモジュール

1 define(function () {
2     var module = {};
3     // pos+2番目の文字列を取り出すメソッド
4     module.getCharacterAt = function (str, pos) {
5         return str.substr(pos+1, 1);// 0,1,2...
6     }
7     return module;
8 });

Presenter Notes

e.g)テストコード

パスしていたsampleモジュールテストコード

1 define(["src/sample"], function (module) {
2     test("getCharacterAt", function () {
3         var str = "STRING";
4         equal(module.getCharacterAt(str, 0), "T");
5         equal(module.getCharacterAt("STRING", 2), "I");
6         equal(module.getCharacterAt(str, str.length - 2), "G");
7     });
8 });

Presenter Notes

e.g)実際に呼び出すときにのコード

  • sampleモジュールを使用時のコード
  • 第二引数に文字列で数値を指定していた

この時は偶然にも想定した動作になっていた

1 define(["src/sample"], function (module) {
2     var char = module.getCharacterAt("STRING", "1");
3     console.log(char);// R
4 });

Presenter Notes

e.g)リファクタリングしたモジュール

  • charAtで書き換えた
  • 先ほどのテストコードはパスする

書き換えたモジュール

1 define(function () {
2     var module = {};
3     // pos + 2番目
4     module.getCharacterAt = function (str, pos) {
5         return str.charAt(pos + 1);
6     }
7     return module;
8 });

Presenter Notes

e.g) 実際の実行結果は?

  • おかしな返り値になっていた
  • テストが網羅できてない範囲のバグあった

getCharacterAtの第ニ引数に文字列で値をしてみると…

1 module.getCharacterAt("STRING", "1");
2 // (an empty string) 空文字

Presenter Notes

e.g)原因

文字列 + 数値 => 結合された文字列

1 "STRING".charAt(1);// T
2 "STRING".charAt("1"+1);// empty string
3 // "1"+1 => "11"

対策

  • 引数を数値に変換してから加算する
  • 引数が数値な場合だけ受け入れる

など

Presenter Notes

e.g)コードの修正 の前に テストの修正

  • コード修正の前に、失敗するテストケースを追加する
  • テストを実行 -> レッド になるのが正しい!

テストモジュール

 1 define(["src/sample"], function (module) {
 2     test("getCharacterAt", function () {
 3         var str = "STRING";
 4         equal(module.getCharacterAt(str, 0), "T");
 5         equal(module.getCharacterAt("STRING", 2), "I");
 6         equal(module.getCharacterAt(str, str.length - 2), "G");
 7         // 第2引数が文字列の時は失敗 -> 第2引数は数値のみ受け入れる
 8         notEqual(module.getCharacterAt(str, "0"), "T");
 9     });
10 });

Presenter Notes

e.g)テストを追加->コードを修正

追加したテストに合わせた実装に変更する

 1 define(function () {
 2     var module = {};
 3     module.getCharacterAt = function (str, pos) {
 4         if (!(typeof pos === 'number' && isFinite(pos))) {
 5             return;// 第ニ引数が数値でないなら中止
 6         }
 7         return str.charAt(pos + 1);
 8     }
 9     return module;
10 });

Presenter Notes

まとめ

  • TDDにおけるバグの修正
    • バグを再現するテスト
    • テストがレッドになることを確認
    • コードを修正
    • テストがグリーンになることを確認

Presenter Notes