Martin Thompson是Java Champion稱號獲得者,同時也是一名高性能計(jì)算科學(xué)家。他說,為了寫出更好的代碼,程序員需要運(yùn)用基本設(shè)計(jì)原則,閱讀已有代碼。在QCon London 2016大會上,他做了題為“挖掘你的工程師屬性(Engineering You)”的演講。InfoQ在會后采訪了他,內(nèi)容涉及軟件行業(yè)面臨的挑戰(zhàn)及程序員如何應(yīng)對那些挑戰(zhàn)成為更好的軟件工程師。
InfoQ:您在演講中引用了1968年第一屆NATO大會上有關(guān)軟件工程的一些內(nèi)容,它們?nèi)匀怀闪?。軟件行業(yè)為什么還是在苦苦掙扎?
Martin Thompson:1968年的NATO大會有好幾個主題。他們認(rèn)識到,軟件行業(yè)存在交付危機(jī)。他們也看到了一些成功的項(xiàng)目,并且希望弄清楚如何吸取好的經(jīng)驗(yàn),進(jìn)行更廣泛地應(yīng)用。在我看來,其中有幾點(diǎn)比較突出,就是認(rèn)識到軟件開發(fā)是一個迭代過程,注重試驗(yàn)/學(xué)習(xí),需要專門人才領(lǐng)導(dǎo),并且最好是在小型團(tuán)隊(duì)內(nèi)完成。他們在幾十年之前就從許多方面描述了TDD和敏捷這些在當(dāng)時并不常見的做法。
作為一個行業(yè),我們已經(jīng)取得了很大的進(jìn)步,但是我們?nèi)匀挥泻荛L的路要走。軟件開發(fā)是一個非常年輕的學(xué)科,我們?nèi)匀挥泻芏鄸|西要學(xué)。我喜歡Dijkstra對它的描述,“煥然一新(radical novelty)”,而使用一些很不恰當(dāng)?shù)碾[喻和類比,會注定我們的失敗。軟件構(gòu)建是在之前活動基礎(chǔ)上的躍變。這些活動和約束與之前的活動截然不同。有些人有這方面的天賦,有些人需要學(xué)著做,而大多數(shù)人很掙扎。在土木工程學(xué)方面,我們耗費(fèi)了幾個世紀(jì)才具備了現(xiàn)在的能力,因此也就不奇怪軟件行業(yè)當(dāng)前的掙扎。
InfoQ:您為什么認(rèn)為理解基本設(shè)計(jì)原則,如耦合和內(nèi)聚,很重要?
Thompson:軟件開發(fā)面臨的其中一個最大的挑戰(zhàn)就是處理應(yīng)用程序規(guī)模增長帶來的復(fù)雜性。對象、組件、模塊或系統(tǒng)之間的耦合程度越高,我們需要承擔(dān)的后果就越多。這些后果包括但不限于修改困難、故障蔓延、由于爭用而無法擴(kuò)展、由于關(guān)聯(lián)操作而導(dǎo)致的性能問題。時間、空間和實(shí)現(xiàn)上的松耦合對于擴(kuò)展性和彈性而言至關(guān)重要。“共生性(Connascence)”可以很好地描述耦合,一個模塊/組件的變化會導(dǎo)致另一個模塊/組件的變化。
我發(fā)現(xiàn),內(nèi)聚比耦合更微妙。我喜歡將內(nèi)聚理解為統(tǒng)一性。當(dāng)我們考慮在不同的方面使用同一個組件時,就失去了統(tǒng)一性,這會導(dǎo)致不必要的行為和特征。軟件設(shè)計(jì)中的低內(nèi)聚常常是一個很好的需求或團(tuán)隊(duì)狀況指標(biāo)。通常,內(nèi)聚設(shè)計(jì)很容易跟蹤,由于相關(guān)的函數(shù)和特性都進(jìn)行了分組,相互關(guān)聯(lián),所以可發(fā)現(xiàn)性很高。
如果我們希望成為更好的軟件工程師,那么提高我們運(yùn)用基本設(shè)計(jì)原則的技能應(yīng)該成為我們?nèi)粘;顒拥暮诵?。在?xùn)練和實(shí)踐中不斷重復(fù)是讓技能成為第二天性的最好方法。
InfoQ:您能舉幾個例子說明下,如何運(yùn)用分解和抽象幫助開發(fā)人員寫出更好的軟件嗎?
Thompson:我認(rèn)為,抽象是軟件開發(fā)領(lǐng)域被人誤解得最深的話題之一。Dijkstra將抽象描述為一種創(chuàng)建“新的語義層次”的方式,“在這個語義層次中,一個人可以做到絕對精確”。大多數(shù)開發(fā)人員都完全是亂用這個術(shù)語,創(chuàng)建他們所謂的抽象來掩飾他們不懂的東西。Joel Spolsky甚至發(fā)明了“抽象泄露(leaky abstractions)”原則,拙劣地想為這種誤解正名。我們有些很棒的抽象示例,如Linux內(nèi)核或設(shè)備驅(qū)動中的塊設(shè)備,但遺憾的是,大多數(shù)軟件抽象通常是源于某種形式的精神自慰,導(dǎo)致弗蘭肯斯坦怪獸的誕生,讓代碼更難以處理,而不是更嚴(yán)密更容易理解。糟糕的抽象比重復(fù)的成本更高。
我們需要更擅長將業(yè)務(wù)目標(biāo)分解成可衡量的具體成果,然后以高質(zhì)量、低耦合的可組合組件為基礎(chǔ)構(gòu)建軟件。商業(yè)公司希望我們在他們的框架內(nèi)完成構(gòu)建,那樣他們可以鎖住客戶。這些框架是錯誤的示范。它們是商業(yè)壓力催生的產(chǎn)物。商業(yè)壓力與交付高質(zhì)量的可維護(hù)軟件往往是矛盾的。
如果看一下其他工程學(xué)科,我們就會看到,工具的使用是為了支持交付流程,而不是強(qiáng)加一個流程。我們似乎展現(xiàn)了這個時代的一個特征,商業(yè)廣告聚焦于人天價格、per-CPU許可及鎖定維護(hù)合同?,F(xiàn)在,類似Amazon這樣的公司提供了實(shí)用計(jì)算,讓我們可以根據(jù)需要使用。非常有趣的是,云計(jì)算很好地支持了持續(xù)集成和交付模型。這改變了市場格局,推動了更好的行為。我們也可以從工具方面看待這個問題,類似Jetbrains這樣的公司將你鎖定在他們的產(chǎn)品合同上;他們是通過提供可以提高生產(chǎn)力的優(yōu)秀產(chǎn)品把你鎖定的。
InfoQ:您提到,把重讀代碼作為發(fā)現(xiàn)缺陷或改進(jìn)代碼的方式。您能詳細(xì)地闡述下嗎?
Thompson:任何創(chuàng)造性的嘗試都可以從不斷地審視和完善中受益。你曾經(jīng)回過頭來閱讀已經(jīng)寫好的郵件、論文、博客或報(bào)告等等,然后覺得某些部分可以做得更好呢?這是一件很自然的事情。當(dāng)我們回過頭來看時,情況不同了,我們會有新的認(rèn)識。從最簡單的層面來說,我們的寫作初衷已經(jīng)從我們的短期記憶中消失了,我們必須真正的重讀和思考。換句話說,我們有了更多的信息,世界發(fā)展了,我們的知識也豐富了。
我喜歡將代碼視為一個可以捕獲當(dāng)前看法的地方。我們都會犯一些回過頭來看時可以糾正的錯誤,除了糾正這些錯誤外,我們還可以記錄我們更深入的理解。一般而言,應(yīng)用程序是業(yè)務(wù)流程的軟件模擬。如果軟件沒有捕獲當(dāng)前了解的業(yè)務(wù)流程,那么開發(fā)人員就必須做一個心理映射。在任何項(xiàng)目中,心里映射都是一個很大的負(fù)擔(dān)。這是我認(rèn)為領(lǐng)域驅(qū)動設(shè)計(jì)是一個重要的軟件開發(fā)工具的原因之一。
定期閱讀所有的代碼,而且不只是你自己的代碼。閱讀他人的代碼是一種很棒的學(xué)習(xí)方式。正如作家Stephen King所言,“讀其他人的書是讓你成為一個更好的作家的最好方式?!边@同樣適用于代碼,開源是我們這個行業(yè)采取的最好的措施之一。通過公開開發(fā)軟件,我們可以分享理解,獲取反饋,向其他人學(xué)習(xí)。參與開源是讓你成為一名更好的工程師的最佳方式之一。