- 自己紹介
- テストファーストから始める JavaScript
- リファクタリングから始める JavaScript
- ふりかえりから始める JavaScript
- カキギカツユキ
- おっさんプログラマ
- メインの言語は Ruby と JavaScript あと Java
- マイブームは関数型言語
- オブジェクト指向トッテモトッテモムズカシイね
1 から 100 までの数をプリントするプログラムを書け。
ただし 3 の倍数のときは数の代わりに「Fizz」と、5 の倍数のときは「Buzz」とプリントし、3 と 5 両方の倍数の場合には「FizzBuzz」とプリントすること。
何をテストすべきだろうか --- 着手する前に、必要になりそうなテストをリストに書き出しておこう。
テスト駆動開発
- 1 から 100 まで数をプリントできるようにする。
- 3 の倍数のときは数の代わりに「Fizz」をプリントできるようにする。
- 5 の倍数のときは「Buzz」とプリントできるようにする。
- 3 と 5 両方の倍数の場合には「FizzBuzz」とプリントできるようにする。
いつテストをかくべきだろうか --- それはテスト対象のコードを書く前だ。
テスト駆動開発
const assert = chai.assert;
suite("FizzBuzzTest", () => {
test("こんにちは世界", () => {
assert.equal("hello, world", greeting());
});
});
const assert = chai.assert;
suite("FizzBuzzTest", () => {
test("こんにちは世界", () => {
assert.equal("hello, world", greeting());
});
});
function greeting() {
return "hello, world";
}
アサートファースト
いつアサーションを書くべきだろうか----最初に書こう
テスト駆動開発
test("1から100までをプリントする", () => {
assert.equal(1, print1To100());
});
仮実装を経て本実装へ
失敗するテストを書いてから、最初に行う実装はどのようなものだろうか----ベタ書きの値を返そう。
テスト駆動開発
test("1から100までをプリントする", () => {
assert.equal(1, print1To100());
});
function print1To100() {
return 1;
}
三角測量
テストから最も慎重に一般化を引き出すやり方はどのようなものだろうか----2つ以上の例があるときだけ、一般化を行うようにしよう。
テスト駆動開発
test("1から100までをプリントする", () => {
assert.equal(1, print1To100());
assert.equal(100, print1To100());
});
function print1To100() {
return 1;
}
test("1から100までをプリントする", () => {
let list = print1To100();
assert.equal(1, list[0]);
assert.equal(100, list[99]);
});
function print1To100() {
let list = [];
for (let i = 0; i < 100; i++) {
list[i] = i + 1;
}
return list;
}
1 から 100 まで数をプリントできるようにする。- 3 の倍数のときは数の代わりに「Fizz」をプリントできるようにする。
- 5 の倍数のときは「Buzz」とプリントできるようにする。
- 3 と 5 両方の倍数の場合には「FizzBuzz」とプリントできるようにする。
test("3で割り切れる場合はFizzをプリントする", () => {
assert.equal("Fizz", fizzBuzz(3));
});
test("3で割り切れる場合はFizzをプリントする", () => {
assert.equal("Fizz", fizzBuzz(3));
});
function fizzBuzz(number) {
let result = number;
if (number % 3 === 0) {
result = "Fizz";
}
return result;
}
1 から 100 まで数をプリントできるようにする。3 の倍数のときは数の代わりに「Fizz」をプリントできるようにする。- 5 の倍数のときは「Buzz」とプリントできるようにする。
- 3 と 5 両方の倍数の場合には「FizzBuzz」とプリントできるようにする。
test("5で割り切れる場合はFizzをプリントする", () => {
assert.equal("Buzz", fizzBuzz(5));
});
test("5で割り切れる場合はBuzzをプリントする", () => {
assert.equal("Buzz", fizzBuzz(5));
});
function fizzBuzz(number) {
let result = number;
if (number % 3 === 0) {
result = "Fizz";
} else if (number % 5 === 0) {
result = "Buzz";
}
return result;
}
1 から 100 まで数をプリントできるようにする。3 の倍数のときは数の代わりに「Fizz」をプリントできるようにする。5 の倍数のときは「Buzz」とプリントできるようにする。- 3 と 5 両方の倍数の場合には「FizzBuzz」とプリントできるようにする。
test("15で割り切れる場合はFizzBuzzをプリントする", () => {
assert.equal("FizzBuzz", fizzBuzz(15));
});
test("15で割り切れる場合はFizzBuzzをプリントする", () => {
assert.equal("FizzBuzz", fizzBuzz(15));
});
function fizzBuzz(number) {
let result = number;
if (number % 3 === 0 && number % 5 === 0) {
result = "FizzBuzz";
} else if (number % 3 === 0) {
result = "Fizz";
} else if (number % 5 === 0) {
result = "Buzz";
}
return result;
}
1 から 100 まで数をプリントできるようにする。3 の倍数のときは数の代わりに「Fizz」をプリントできるようにする。5 の倍数のときは「Buzz」とプリントできるようにする。3 と 5 両方の倍数の場合には「FizzBuzz」とプリントできるようにする。
function fizzBuzz(number) {
let result = number;
if (number % 3 === 0 && number % 5 === 0) {
result = "FizzBuzz";
} else if (number % 3 === 0) {
result = "Fizz";
} else if (number % 5 === 0) {
result = "Buzz";
}
return result;
}
function print1To100() {
let list = [];
for (let i = 0; i < 100; i++) {
list[i] = fizzBuzz(i + 1);
}
return list;
}
print1To100();
リファクタリング(名詞):外部から見たときの振る舞いを保ちつつ、理解や修正が簡単になるように、ソフトウェアの内部構造を変化させること。
新装版 リファクタリング―既存のコードを安全に改善する
リファクタリングする(動詞):一連のリファクタリングを適用して、外部から見た振る舞いの変更なしに、ソフトウェアを再構築すること。
新装版 リファクタリング―既存のコードを安全に改善する
へんてこな名前。
function print1To100() {
let list = [];
for (let i = 0; i < 100; i++) {
list[i] = fizzBuzz(i + 1);
}
return list;
}
print1To100();
function generateList() {
let list = [];
for (let i = 0; i < 100; i++) {
list[i] = fizzBuzz(i + 1);
}
return list;
}
generateList();
メソッド内に正常ルートが不明確な条件付き振る舞いがある。
function fizzBuzz(number) {
let result = number;
if (number % 3 === 0 && number % 5 === 0) {
result = "FizzBuzz";
} else if (number % 3 === 0) {
result = "Fizz";
} else if (number % 5 === 0) {
result = "Buzz";
}
return result;
}
function fizzBuzz(number) {
let result = number;
if (number % 3 === 0 && number % 5 === 0) return "FizzBuzz";
if (number % 3 === 0) return "Fizz";
if (number % 5 === 0) return "Buzz";
return result;
}
簡単な式によって一度だけ代入される一時変数があり、それが他のリファクタリングの障害となっている。
function fizzBuzz(number) {
let result = number;
if (number % 3 === 0 && number % 5 === 0) return "FizzBuzz";
if (number % 3 === 0) return "Fizz";
if (number % 5 === 0) return "Buzz";
return result;
}
function fizzBuzz(number) {
if (number % 3 === 0 && number % 5 === 0) return "FizzBuzz";
if (number % 3 === 0) return "Fizz";
if (number % 5 === 0) return "Buzz";
return number;
}
複雑な式がある。
function fizzBuzz(number) {
if (number % 3 === 0 && number % 5 === 0) return "FizzBuzz";
if (number % 3 === 0) return "Fizz";
if (number % 5 === 0) return "Buzz";
return number;
}
function fizzBuzz(number) {
const isFizz = number % 3 === 0;
const isBuzz = number % 5 === 0;
if (isFizz && isBuzz) return "FizzBuzz";
if (isFizz) return "Fizz";
if (isBuzz) return "Buzz";
return number;
}
繰り返しがある。
function generateList() {
let list = [];
for (let i = 0; i < 100; i++) {
list[i] = fizzBuzz(i + 1);
}
return list;
}
function generateList() {
let list = [];
[...Array(100).keys()].forEach(i => {
list.push(fizzBuzz(i + 1));
});
return list;
}
function generateList() {
return [...Array(101).keys()].slice(1).map(i => fizzBuzz(i));
}
function generateList() {
return [...Array(101).keys()].slice(1).map(fizzBuzz);
}
特別な意味を持った数字のリテラルがある。
function generateList() {
return [...Array(101).keys()].slice(1).map(fizzBuzz);
}
const MAX_NUMBER = 100;
function generateList() {
// 配列が0から始まるので1をたさないと99までしか表示されない
return [...Array(MAX_NUMBER + 1).keys()].slice(1).map(fizzBuzz);
}
大切なことなので2回言います
皮肉なことに、TDDはテスト技法ではない(Cunninghamの公案)。TDDは分析技法であり、設計技法であり、実際には開発のすべてのアクティビティを構造化する技法なのだ。
テスト駆動開発
TDDは分析技法であり、設計技法であり、実際には開発のすべてのアクティビティを構造化する技法なのだ。
テスト駆動開発
リファクタリングをするにあたって
リファクタリングに入る前に、しっかりとした一連のテスト群が用意できているかを確認すること。これらのテストには自己診断機能が不可欠である。
新装版 リファクタリング―既存のコードを安全に改善する
テストを完全に自動化して、その結果もテストにチェックさせること。
新装版 リファクタリング―既存のコードを安全に改善する
コンパイラが理解出るコードは誰にでも書ける。すぐれたプログラマは、人間にとってわかりやすいコードを書く。
新装版 リファクタリング―既存のコードを安全に改善する
リファクタリングサイクルを回す
- Compile
- Test
- Commit
テスト駆動開発 = ユニットテスト + リファクタリング
みんなも テスト駆動開発 をキメようぜ!
- テスト駆動開発
- Refactoring: Improving the Design of Existing Code (2nd Edition)
- 新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES)
- リファクタリング:Ruby エディション