對(duì)話?cǎi)R丁·福勒(Martin Fowler)——第三部分:進(jìn)化型設(shè)計(jì)
第一部分:重構(gòu)
第二部分:設(shè)計(jì)原則與代碼所有權(quán)
第三部分:進(jìn)化型設(shè)計(jì)
第四部分:靈活性與復(fù)雜性
第五部分:測(cè)試驅(qū)動(dòng)開(kāi)發(fā)
第六部分:性能與過(guò)程調(diào)優(yōu)
第三部分:進(jìn)化型設(shè)計(jì)
在連載的第三部分,福勒討論了計(jì)劃型設(shè)計(jì)和進(jìn)化型設(shè)計(jì)的區(qū)別,揭示了著眼于解決表象問(wèn)題可以使開(kāi)發(fā)者發(fā)現(xiàn)本質(zhì)問(wèn)題,并主張好的設(shè)計(jì)工作不會(huì)降低工作效率。
計(jì)劃型設(shè)計(jì)和進(jìn)化型設(shè)計(jì)
比爾:在你的論文《設(shè)計(jì)是否已死》(Is Design Dead)一文中,談到了計(jì)劃型設(shè)計(jì)。那么什么是計(jì)劃型設(shè)計(jì)?
馬?。?/strong>我將設(shè)計(jì)區(qū)分為計(jì)劃型設(shè)計(jì)和進(jìn)化型設(shè)計(jì)。當(dāng)開(kāi)發(fā)者著手實(shí)施一個(gè)軟件時(shí),他首先需要做設(shè)計(jì),然后再按照這個(gè)設(shè)計(jì)進(jìn)行編 碼實(shí)現(xiàn)軟件,這就是我所說(shuō)的計(jì)劃型設(shè)計(jì)。計(jì)劃型設(shè)計(jì)可能借助 UML;或者把整個(gè)系統(tǒng)分為若干子系統(tǒng),定義這些子系統(tǒng)間的接口。在計(jì)劃型設(shè)計(jì)中,在設(shè)計(jì)和代碼實(shí)現(xiàn)這二者之間存在明確的切換。而這二者又往往由不同的人 來(lái)完成。架構(gòu)師構(gòu)思設(shè)計(jì),開(kāi)發(fā)者編碼實(shí)現(xiàn)。做好的設(shè)計(jì)并不是說(shuō)一點(diǎn)都不能改變,但基本上是固定的。你可能會(huì)說(shuō),設(shè)計(jì)做得越好,在編碼的時(shí)候,就會(huì)越少對(duì)設(shè) 計(jì)做出改動(dòng)。
而在進(jìn)化型設(shè)計(jì)中,開(kāi)發(fā)者在編程實(shí)踐的過(guò)程中逐漸完善設(shè)計(jì)。剛開(kāi)始的時(shí)候并沒(méi)有設(shè)計(jì),而是先實(shí)現(xiàn)一些小的功能。隨著實(shí)現(xiàn)的功能越來(lái)越多,設(shè)計(jì)才逐漸成型。
我在《設(shè)計(jì)是否已死》一文中想要強(qiáng)調(diào)的是,很多人在嘗試進(jìn)化型設(shè)計(jì)時(shí),往往是在一種無(wú)約束無(wú)原則的環(huán)境里,最終的設(shè)計(jì)必然很蹩腳。這是人們之所以傾向于計(jì)劃型設(shè)計(jì)的原因之一。
但是,在我看來(lái),極限編程實(shí)踐中,通過(guò)持續(xù)不斷的集成、測(cè)試和重構(gòu),進(jìn)化型設(shè)計(jì)能夠做到比計(jì)劃型設(shè)計(jì)更有效。計(jì)劃型設(shè)計(jì)的弱點(diǎn)就是,要想做出一個(gè)好的設(shè)計(jì)非常難。
比爾:為什么?
馬丁:我解釋不清楚。這就跟解釋不清楚為什么譜一曲交響樂(lè)會(huì)如此困難一樣。世界上能把這些工作做好的人可以說(shuō)是鳳毛麟角。我想,我認(rèn)為預(yù)先設(shè)計(jì)(upfront design)就屬于這類工作。要做好這類工作實(shí)在是太難了。
有趣的是,很多進(jìn)化型設(shè)計(jì)的倡導(dǎo)者,比如肯特·貝克和沃德·坎寧安,都是非常出色的設(shè)計(jì)師。但正是他們,最后認(rèn)識(shí)到自己所做的預(yù)先設(shè)計(jì)往 往不夠好。他們?nèi)菀装岩恍┦虑檫^(guò)于工程化,在不需要靈活性的地方設(shè)計(jì)靈活性,而在需要靈活性的地方又未予以考慮。因此,他們最終采用了進(jìn)化型設(shè)計(jì),并通過(guò) 運(yùn)用一套規(guī)則,保證了設(shè)計(jì)效果。其結(jié)果是,不但最終的設(shè)計(jì)更加出色,并且速度也加快了。拿我自己來(lái)說(shuō),80%左右的時(shí)間里,進(jìn)化型設(shè)計(jì)會(huì)得到不錯(cuò)的結(jié)果。 而不客氣地說(shuō)一句,我認(rèn)為我的設(shè)計(jì)水平要比一般人高。因此,我認(rèn)為進(jìn)化型設(shè)計(jì)應(yīng)該可以適用于更廣泛的人群。
重構(gòu)與預(yù)先設(shè)計(jì)
比爾:重構(gòu)如何改變了預(yù)先設(shè)計(jì)的地位?
馬?。?/strong>人們之所以采用計(jì)劃型設(shè)計(jì),是因?yàn)樗麄冋J(rèn)為改動(dòng)代碼是件很麻煩的事情。因?yàn)楫?dāng)你改變代碼時(shí),有可能破壞了一些東西并造成許多漏洞??墒?,如果你既有單元測(cè)試,又有在測(cè)試基礎(chǔ)上建立起來(lái)的有條理的重構(gòu)技術(shù),那么你就能十分快速有效地改動(dòng)代碼,并且不太會(huì)引起什么問(wèn)題。
比爾:預(yù)先設(shè)計(jì)在重構(gòu)和其他可行的實(shí)踐中有什么作用?你現(xiàn)在還會(huì)做一些預(yù)先設(shè)計(jì)嗎?
馬?。?/strong>我認(rèn)為一些地方還是可以用到預(yù)先設(shè)計(jì)的,不過(guò)不會(huì)很多。一些人——像肯特·貝克和羅恩·杰弗里斯——認(rèn)為預(yù)先設(shè)計(jì)已 經(jīng)消亡了。從某種意義上來(lái)說(shuō),他們是對(duì)的,因?yàn)槟憧梢越柚M(jìn)化型設(shè)計(jì)搭建更復(fù)雜的系統(tǒng)。但在某些情況下,預(yù)先設(shè)計(jì)可能讓你的進(jìn)度加快一些。比如說(shuō),我不贊 同在架設(shè)數(shù)據(jù)庫(kù)之前就討論數(shù)據(jù)庫(kù)的進(jìn)化問(wèn)題。我可能會(huì)對(duì)數(shù)據(jù)庫(kù)的存在有一個(gè)初步的判斷,然后以此作為起點(diǎn)。當(dāng)然,我仍會(huì)用進(jìn)化的方式完成大部分設(shè)計(jì)。
比爾:構(gòu)造良好的(well-factored)程序和設(shè)計(jì)良好的(well-designed)程序之間有區(qū)別嗎?
馬丁:它們?cè)诒举|(zhì)上并沒(méi)有什么區(qū)別,但側(cè)重點(diǎn)有所不同。設(shè)計(jì)強(qiáng)調(diào)的是構(gòu)造——將程序劃分為若干分割清晰的部分。對(duì)我來(lái)說(shuō),“構(gòu)造良好的”一詞表達(dá)了更多對(duì)于設(shè)計(jì)的感覺(jué),也即當(dāng)你審視或使用這個(gè)設(shè)計(jì)時(shí)的感覺(jué)。代碼中的“壞味道”
比爾:在你的《重構(gòu)》一書中,關(guān)于何時(shí)應(yīng)用重構(gòu),你是這樣闡述的:“與其去追求一些很模棱兩可的編程美學(xué)原則(坦率地說(shuō),這是我們咨詢師們最喜歡做的事情),還不如來(lái)點(diǎn)兒更實(shí)際的。”
我很好奇,你是怎么看待美學(xué)的?我的經(jīng)歷中有很多次都是跟已有的代碼打交道。這些代碼的設(shè)計(jì)很爛,因此處理起來(lái)非常痛苦。如果這些設(shè)計(jì)能做得好些,讓我不那么痛苦的話,我會(huì)非常感激。所以,對(duì)我來(lái)說(shuō),美學(xué)至少還是有些意義的,它可以使我的工作輕松些。
馬丁:嗯,在討論何時(shí)應(yīng)用重構(gòu)時(shí),我的確是這樣談?wù)撁缹W(xué)的。從某種意義上說(shuō),我在重構(gòu)準(zhǔn)則中所給的那些條條框框也是一種模 棱兩可的美學(xué)原則。不過(guò),我試著給出更多的說(shuō)明,而不是僅僅說(shuō)“當(dāng)你的代碼看上去很丑陋的時(shí)候就需要做重構(gòu)。”比如說(shuō),重復(fù)的代碼是一種“壞味道”,再比如 說(shuō),很長(zhǎng)的方法是一種“壞味道”,或者很臃腫的類也是一種“壞味道”。
很多“壞味道”是很容易嗅出來(lái)的。令人驚奇的是,當(dāng)你審視你的程序時(shí),往往一些很明顯的現(xiàn)象,像是某個(gè)方法長(zhǎng)達(dá)100行,就能引導(dǎo)你改進(jìn)你的設(shè)計(jì)。
在重構(gòu)這個(gè)長(zhǎng)達(dá)100行的方法時(shí),你可能會(huì)發(fā)現(xiàn)一些諸如責(zé)任分配(responsibility allocation)不合理這樣的設(shè)計(jì)問(wèn)題。像這樣的問(wèn)題,你是不可能光憑掃一眼代碼就發(fā)現(xiàn)的;但是,一個(gè)長(zhǎng)達(dá)100行的方法,卻是一眼就能看出來(lái)的。 所以說(shuō),很表象的問(wèn)題能夠把你帶向更深層的問(wèn)題。
比爾:我參與過(guò)的一個(gè)項(xiàng)目竟然有一個(gè)長(zhǎng)達(dá)11頁(yè)的 while 循環(huán)。
馬?。?/strong>這太不可思議了。
比爾:我們苦干了六個(gè)月試圖讓這個(gè)軟件穩(wěn)定運(yùn)行,可是我們不敢動(dòng)這個(gè)11頁(yè)的循環(huán)。
馬丁:這恰恰從另一個(gè)側(cè)面說(shuō)明了這個(gè)長(zhǎng)達(dá)11頁(yè)的循環(huán)是個(gè)糟糕的設(shè)計(jì)。如果你對(duì)改動(dòng)某處代碼心存顧慮的話,那它顯然是一個(gè)蹩腳的設(shè)計(jì)。
良好的設(shè)計(jì)與效率
比爾:我想,人們不注重設(shè)計(jì)的一個(gè)原因是由于工作的流動(dòng)性。那個(gè)最初編寫11頁(yè) while 循環(huán)的程序員在我們接手項(xiàng)目的時(shí)候已經(jīng)離開(kāi)了公司。我認(rèn)為,程序員因?yàn)樽约旱脑愀庠O(shè)計(jì)而自食其果的情況很少發(fā)生,因此他們沒(méi)有足夠的動(dòng)因去注重設(shè)計(jì)。此 外,即便他們注重,但設(shè)計(jì)畢竟是一項(xiàng)費(fèi)力不討好的工作,好的設(shè)計(jì)需要時(shí)間,而開(kāi)發(fā)中的時(shí)間壓力往往很大。
馬?。?/strong>我不同意“好的設(shè)計(jì)需要更長(zhǎng)的時(shí)間”這樣的說(shuō)法。
比爾:為什么?
馬丁:這是很有意思的一件事。在軟件業(yè),我們似乎普遍認(rèn)為,慢工出細(xì)活。但當(dāng)我回顧我自己的經(jīng)歷時(shí),卻發(fā)現(xiàn)保持代碼的良好構(gòu)造以及編寫測(cè)試反而使我的工作加快了。
我想,人們把改進(jìn)設(shè)計(jì)所花的時(shí)間看作是“失去”的時(shí)間,但卻沒(méi)有看到將來(lái)對(duì)代碼的改動(dòng)會(huì)容易得多,往往只需要幾分鐘的時(shí)間,否則可能要花上兩三個(gè)小時(shí)。
人們往往還低估了在調(diào)試上所花的時(shí)間,低估了他們用來(lái)追蹤一個(gè)“潛伏”很久的漏洞所花的時(shí)間。我在寫代碼的時(shí)候可以立即察覺(jué)產(chǎn)生的漏洞,這使得我能在它潛伏下來(lái)之前就解決它。沒(méi)有幾件事比調(diào)試更花時(shí)間和更令人沮喪的了。假如我們一開(kāi)始就能避免產(chǎn)生漏洞,那效率豈不是要提高很多?
posted on 2012-05-25 09:46 順其自然EVO 閱讀(192) 評(píng)論(0) 編輯 收藏 所屬分類: 測(cè)試學(xué)習(xí)專欄