本周Code Retreat中,其中一次是Silent Pair,就是在Pair過程中不能說話,由于兩個人都是第一次Pair,所以也不會熟悉對方套路的問題,我覺得這樣在Pair中需要注意幾點,1.步子不能太大,太大了對方可能很難理解。 2.寫測試用例或者生產(chǎn)代碼目的性更強,能讓對方理解起來更容易 3.命名需要更準(zhǔn)確。
總體來講我和Pair雖然全程沒有講話,但基本上還是做到這幾點,看來程序員之間還是比較默契的_,言歸正傳,這里介紹下在Pair中學(xué)到一點小技巧-快速通過用例,考慮到需要突出重點,所以以階段來介紹,就不stepBystep了
題目還是Game Of Life,
思路大概是這樣的
1.以任意一個Cell中心,根據(jù)8個鄰居狀態(tài),判斷該Cell下一個狀態(tài):如果2個活著那么保持狀態(tài)不變,3個鄰居活者也為活,其他情況都是死。
2.邊界判定,在4條邊上的Cell,鄰居就不是8個而是3或者5個,需要判定邊界,但判斷邊界的代碼太不優(yōu)雅,所以在原有“棋盤”上包一圈死的Cell(全是0,計算時就不會影響結(jié)果),如圖:

Paste_Image.png
階段1:
先來看一下test代碼
function test0InitLife(){
//given
var grid = [[0,0,0],[0,0,0],[0,0,0]];
var expected = [[0,0,0],[0,0,0],[0,0,0]];
//when and then
expected(next(grid),expected)
}
function test1InitLife(){
//given
var grid = [[0,0,0],[0,1,0],[0,0,0]];
var expected = [[0,0,0],[0,0,0],[0,0,0]];
//when and then
expected(next(grid),expected)
}
此時的生產(chǎn)代碼代碼如下:
int[][] grid;
function next(grid){
this.grid = grid;
var newGrid = cloneGrid();
//這里也是一樣,判定(1,1)即可滿足上面2個測試用例
newGrid[1][1] = getLiveNeigboursCount(1,1,grid[1][1]);
return newGrid;
}
function getLiveNeigboursCount(int i,int j,int currentStatus){
var liveCount = grid[i-1][j] + grid[i-1][j] + grid[i-1][j+1] +grid[i][j-1]
+grid[i][j+1] +grid[i+1][j-1] +grid[i+1][j] +grid[i+][j+] ;
if( liveCount == 2 ){
return currentStatus;
}else if( liveCount == 2 ){
return currentStatus;
}
return 0;
}
function cloneGrid(){
return this.grid;
}
````
在階段1中,為快速讓測試用例通過,cloneGrid方法以及next的判定是特定的,而不是通用的。
###階段2:
增加一個用例,并且使用輪詢的方式判定每個Cell,此時代碼肯定不能通過了,并且拋出數(shù)組越界異常,因為getLiveNeigboursCount方法中沒有判定邊界。
增加一個測試用例:
```
function test3InitLife(){
//given
var grid = [[0,0,0],[1,1,1],[0,0,0]];
var expected = [[0,0,0],[0,0,0],[0,0,0]];
//when and then
expected(next(grid),expected)
}
````
next方法輪詢判定變成這樣
```
function next(grid){
this.grid = grid;
var newGrid = cloneGrid();
for(var i=0;i<newGrid.length;i++){
for(var j=0;j<newGrid[0].length;i++){
newGrid[i][j] = getLiveNeigboursCount(i,j,grid[i][j]);
}
}
return newGrid;
}
```
###階段3:
根據(jù)設(shè)計,我們需要在原有棋盤上包裝一圈,代碼變成這樣(這一步稍微快了一些,畢竟之前已經(jīng)有過4次Pair^_^):
```
var grid;
function next(grid){
this.grid = grid;
var warpperGrid = wrapperGrid();
var newGrid = cloneGrid();
for(var i=0;i<newGrid.length;i++){
for(var j=0;j<newGrid[0].length;i++){
newGrid[i][j] = getLiveNeigboursCount(i+1,j+1,grid[i][j], warpperGrid);
}
}
return newGrid;
}
function getLiveNeigboursCount(int i,int j,int currentStatus, warpperGrid){
var liveCount = wrapperGrid[i-1][j] + wrapperGrid[i-1][j] + wrapperGrid[i-1][j+1] + wrapperGrid[i][j-1] + wrapperGrid[i][j+1] + wrapperGrid[i+1][j-1] + wrapperGrid[i+1][j] + wrapperGrid[i+][j+] ;
if( liveCount == 2 ){
return currentStatus;
}else if( liveCount == 2 ){
return currentStatus;
}
return 0;
}
function cloneGrid(){
var newGrid = new Array();
for(var i=0;i<newGrid.length;i++){
for(var j=0;j<newGrid[0].length;i++){
newGrid[i][j] = this.grid[i][j];
}
}
}
function wapperGrid(){
//TODO
}
```
到這里,貌似其他步驟的代碼都已經(jīng)完成,但是wapperGrid看起來好像很簡單,但很難下手,為了讓測試快速通過,于是代碼變成這樣:
```
function wapperGrid(){
var wrapperGrid = new Array();
warpperGrid.push([0,0,0,0,0,0]);
warpperGrid.push([0].concat(this.grid[0]).concat([0]));
warpperGrid.push([[0].concat(this.grid[1]).concat([0]));
warpperGrid.push([[0].concat(this.grid[2]).concat([0]));
warpperGrid.push([0,0,0,0,0,0]);
return warpperGrid;
}
```
這樣寫好后,邏輯就已經(jīng)很清楚了^_^
*******
結(jié)尾:
在TDD的方法中有一條就是"寫剛好通過測試用例的實現(xiàn)代碼",雖然本次TDD沒有嚴格按照TDD方法做,但我覺得在階段1中的next方法,以及階段3中的wapperGrid方法,也是一種合理的方式可以運用。