小步慢走通過將一大步轉(zhuǎn)化為一系列的小步慎冤,一步一個(gè)腳印。每次只關(guān)注當(dāng)前這一步沧卢,使得每一步變得容易簡(jiǎn)單蚁堤,易于控制,降低出錯(cuò)概率但狭; 另一方面即使出錯(cuò)披诗,問題也不大,容易回退立磁。 這樣步子小呈队,出錯(cuò)少,返工少唱歧,反而效率更高宪摧,所謂慢就是快粒竖。
小步是一個(gè)相對(duì)概念,對(duì)每一個(gè)人理解都不一樣几于,也難于統(tǒng)一蕊苗,在軟件開發(fā)過程更是這樣子。為了更好的理解什么是小步沿彭,那么我們先看看什么是大步朽砰? 下面的例子,是否似曾相識(shí)
1. 編譯長(zhǎng)時(shí)間沒有通過喉刘。
2. 單元測(cè)試紅燈一直亮著瞧柔。
3. 發(fā)現(xiàn)思路錯(cuò)了,想回退饱搏,不知道從哪里開始非剃。 如果直接revert 太可惜。
4. 修改代碼推沸,測(cè)試失敗备绽,想不錯(cuò)所以然來。
5.? 常常需要IDE里面單步調(diào)試來定位錯(cuò)誤鬓催。這個(gè)說明代碼已經(jīng)超出你的大腦容量肺素,問題已經(jīng)接近失控,需要借助工具來幫助宇驾。
6.. 出現(xiàn)regression倍靡, 推測(cè)不出來是哪里修改導(dǎo)致的, 或者剛改的哪一行代碼课舍。
這些都是步子太大的的問題塌西。反之,如果將步子放小筝尾,每次改一點(diǎn)捡需,甚至是幾行代碼,驗(yàn)證筹淫,再修改再驗(yàn)證站辉,上面問題基本就可以解決掉。對(duì)自己而言這就是小步损姜。大家可以自行感受一下饰剥。
如果要步子小,關(guān)鍵是如何將大步分解為小步摧阅。 常規(guī)軟件里面的分解技術(shù)汰蓉,比如水平層分解,垂直流程分解逸尖,內(nèi)核加插件擴(kuò)展分解古沥,以及按照自治原則分解瘸右,如微服務(wù)。 這些的確可以將一個(gè)大問題岩齿,分解為一組模塊太颤;但是問題是模塊還是太大,對(duì)于日常開發(fā)在類盹沈,接口龄章,方法這個(gè)層面來說還是不夠小。
下面介紹幾種方法乞封,更好的指導(dǎo)在代碼級(jí)別分解:
1. 接口不變逐步生長(zhǎng)
軟件開發(fā)的很多時(shí)候是接口先定下來做裙,然后再逐步完善功能。典型的是算法問題肃晚,輸入輸出很清晰锚贱,接口確定下來而且基本不會(huì)變。 比如N-皇后問題关串,輸入是一個(gè)整數(shù)代表矩陣大小拧廊,輸出是代表有多少種布局。接口很容易定下來而且是不變的晋修。然后隨著test case增加吧碾,有簡(jiǎn)單變的復(fù)雜,功能也一點(diǎn)點(diǎn)的增強(qiáng)墓卦。
比如8N后問題,可以這樣分解:
基于這個(gè)分解的一個(gè)實(shí)現(xiàn)在落剪,這里睁本。如果想看實(shí)現(xiàn)過程,可以在這里回放 ?忠怖。 這個(gè)是用TDD實(shí)現(xiàn)添履,借助cyber-dojo這個(gè)工具可以回放修改代碼的從過程。
另外一個(gè)例子脑又,可以判斷一個(gè)字符串是不是一個(gè)數(shù)字? 比如 1.2e5. 那么也可以分解為: 自然數(shù)锐借,整數(shù)问麸,浮點(diǎn)數(shù),帶有指數(shù)的浮點(diǎn)數(shù)钞翔。一個(gè)實(shí)現(xiàn)在這里严卖。?
其實(shí)這個(gè)軟件功能完善過程,如同軟件有一個(gè)內(nèi)核逐步長(zhǎng)大布轿,類似生長(zhǎng)過程哮笆。也就是我們軟件開發(fā)中的接口不變的增量開發(fā)来颤。但是現(xiàn)實(shí)往往不是這么簡(jiǎn)單,接口在成長(zhǎng)的過程也會(huì)發(fā)生變化稠肘。于是就有下面這個(gè)方法福铅。
2. 先適應(yīng)接口再增加新功能。
有些時(shí)候项阴,隨著test case的增加滑黔,會(huì)發(fā)現(xiàn)已有的接口不是那么合適。 這個(gè)時(shí)候需要修改接口环揽,才能再增加新功能略荡。 這個(gè)和我們經(jīng)常看到的增量開發(fā)演示圖有點(diǎn)不一樣歉胶。
增量開發(fā)汛兜,我們常常用下圖表示。
? 但實(shí)際情況卻是下面這樣子的通今。為增加新功能而需要修改已有代碼和接口粥谬。
這條規(guī)則是指,添加新功能時(shí)如果接口不匹配衡创,那么先修改接口使得接口匹配帝嗡,然后再加入新功能。將一大步分為兩步走璃氢,先是修改接口使得適應(yīng)新功能哟玷,然后再增加新功能代碼。
? 3. 測(cè)試代碼和生產(chǎn)代碼不同時(shí)修改
TDD標(biāo)準(zhǔn)開發(fā)流程中每次迭代是先添加新測(cè)試用例一也,這時(shí)代碼或編譯不通過或者測(cè)試不通過巢寡;再添新加代碼,使得編譯通過椰苟,測(cè)試通過抑月; 然后重構(gòu);完成一次迭代反饋舆蝴,然后進(jìn)行下一次循環(huán)谦絮;這里面其實(shí)隱藏著一條規(guī)則,就是修改測(cè)試代碼的時(shí)候洁仗,不修改生產(chǎn)代碼层皱;修改生產(chǎn)代碼,不修改測(cè)試代碼赠潦。如下圖:
如果同時(shí)修改叫胖,那么到底是代碼的錯(cuò)還是測(cè)試的錯(cuò)呢?每次只修改測(cè)試代碼或者生產(chǎn)代碼她奥,如果出錯(cuò)瓮增,那么肯定是剛修改的代碼導(dǎo)致的怎棱,很容易找打問題。步子小好定位绷跑。
? ? ? ? 規(guī)則2 和規(guī)則3經(jīng)常在一起使用的拳恋。 如果已有的代碼是A,對(duì)應(yīng)測(cè)試集合是TA你踩。 現(xiàn)在要增加新功能使得軟件功能變?yōu)?B,TB), 也就是軟件從一個(gè)狀態(tài)變到另一個(gè)狀態(tài)诅岩,即(A, TA) ----> ( B , TB)带膜。 那么應(yīng)該怎么做吩谦?
(A , TA) 初始狀態(tài)
? (A1膝藕, TA) 修改接口A為A1式廷,為添加B功能做準(zhǔn)備. 測(cè)試集TA沒有變化保證新接口以及修改的代碼不會(huì)對(duì)已有功能產(chǎn)生副作用。
(A1, TA1)修改測(cè)試代碼芭挽,使得調(diào)用新接口滑废;
? ? ? ? ? ? ? ? ? ? 這個(gè)時(shí)候代碼A1,同時(shí)保留接口和新接口
? (B, TA1)刪除舊的接口袜爪, 這是代碼應(yīng)該已經(jīng)完全轉(zhuǎn)換到新接口蠕趁,即接口由A轉(zhuǎn)到B
(B, TB)為新功能B辛馆,添加新的測(cè)試用例TB
(B1俺陋, TB)添加代碼,通過新測(cè)試昙篙。此時(shí)狀態(tài)轉(zhuǎn)換完畢腊状。
4. TDD 黃金法則:
Uncle Bob 提出來TDD的開發(fā)原則:
You are not allowed to write any production code unless it is to make a failing unit test pass.
1、除非為了使一個(gè)失敗的unit test通過苔可,否則不允許編寫任何產(chǎn)品代碼
You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
2.在一個(gè)單元測(cè)試中只允許編寫剛好能夠?qū)е率〉膬?nèi)容(編譯錯(cuò)誤也算失斀赏凇)
You are not allowed to write any more production code than is sufficient to pass the one failing unit test.
3、只允許編寫剛好能夠使一個(gè)失敗的unit test通過的產(chǎn)品代碼
這個(gè)所謂小步慢走的極限目標(biāo)焚辅,也就是增量實(shí)現(xiàn)的終極方式映屋。 但是實(shí)際中卻很難做到,很難做到如此精細(xì)分解的粒度同蜻,而且也難于衡量(什么是剛好)秧荆,也沒有考慮到重構(gòu)。 應(yīng)該根據(jù)自己的實(shí)際情況埃仪,步子盡可能小,理想狀態(tài)是一切都在掌握之中的感覺陕赃,才是恰到好處小步卵蛉。而不是刻意追求這個(gè)過程颁股,為了小步而小步而導(dǎo)致忘記初心。
下面兩個(gè)工具傻丝,可以幫你刻意練習(xí)甘有。?
1. cyber dojo。 這是一個(gè)TDD在線練習(xí)的工具葡缰。每次運(yùn)行代碼的時(shí)候才保存代碼亏掀。? 當(dāng)完成時(shí),可以回放自己的代碼修改過程泛释。 用交通燈顯示每次修改后代碼的狀態(tài)滤愕; 用黃色燈代表編譯沒通過,紅色代表測(cè)試失敗怜校,灰色代表測(cè)試運(yùn)行超時(shí)间影,綠色代表測(cè)試通過;記錄下來后茄茁,就可以用來可視化回放構(gòu)建過程魂贬。 如果一直黃燈,步子太大裙顽,編譯沒通過付燥;一直紅色,測(cè)試不通過愈犹,測(cè)試粒度太大键科; 同樣還記錄下來每次提交的時(shí)間,黃紅綠之間的切換甘萧,可以看到自己的編碼節(jié)奏萝嘁。 這樣可以直觀發(fā)現(xiàn)一些問題? 哪些步子邁的太大扬卷,可以再一次分解牙言,哪些做的好的。通過再次審視怪得,回顧咱枉,分析,總結(jié)徒恋;工具簡(jiǎn)單但是刻意練習(xí)的利器蚕断。
2.git-timer, 就是一個(gè)刻意練習(xí)的工具。 工作原理簡(jiǎn)單入挣,git-timer 監(jiān)控git repository亿乳,在一定的時(shí)間間隔檢測(cè)代碼(比如5分鐘), 如果編譯測(cè)試沒有通過,強(qiáng)制revert 代碼葛假; 如果編譯測(cè)試通過障陶,強(qiáng)制提交代碼;然后重新計(jì)時(shí)聊训。 如果代碼被revert掉 抱究,說明你的步子太大,將剛才的步驟細(xì)化带斑,再來一次鼓寺。 這樣的機(jī)制強(qiáng)制你小步慢走,同時(shí)按照一定的頻率慢走勋磕;
下一篇預(yù)告: 分解的原則 不重不漏妈候;