CodeComplete/如何譬喻軟體開發

本篇分享閱讀 Code Complete 一書第二章對於隱喻與軟體開發的重要性以及關聯性,以及介紹四種譬喻方式:書寫、培育、生長與建造的心得,還有一些我自己的感想以及對於軟體開發的譬喻:堆積木。

蘇曰
11 min readJun 30, 2018
對於軟體開發你會怎麼比喻它呢?Photo by Markus Spiske on Unsplash

「啊,有臭蟲!」

軟體開發還需要譬喻?

首先我們先來說文解字一下,什麼是譬喻?根據教育部辭典的定義,譬喻指的是,

利用二件事物的相似點,用彼方來說明此方,通常是以易知說明難知,以具體說明抽象。可分為明喻、隱喻、略喻、借喻、假喻五種。

簡單而言呢,譬喻就是用A來說明B,通常是用簡單的東西來說明複雜的東西,用具體的東西來說明抽象的東西。

那什麼時候我們會需要用到這種方法?就是當有一個我們不怎麼瞭解的東西時,就用一種我們比較了解的東西,來說明這個我們不怎麼了解的東西(好饒舌)。

那為什麼我們在軟體開發中會需要了解譬喻?其實呢,譬喻早就充斥在整個軟體開發之中了!

1947年飛入Mark II 電腦的蛾。來源:維基百科

例如本文最開始的臭蟲(Bug),這比喻應該是所有工程師最耳熟能詳的,也是最不想聽到的,因為這表示程式執行過程中,發生了不可預期的事情。而我們將「程式執行時發生不可預料的事情」的情境,用「臭蟲」來描述。

那為什麼會用臭蟲來描述呢?我想大家都應該很熟悉一個故事,在古早以前,還真的是因為一隻蟲,導致電腦莫名不能執行的問題。

在1947年,程式設計師的先驅者 Grace Hopper,他的團隊在使用 Mark II工作時,不知道為何這台電腦就是不能正常工作,後來他們營運商在繼電器中,找到一隻蛾。Hopper還將那隻蛾貼在他的日記中,讓我們這些後人可以一見這隻「始源之蟲」。之後的是,大家應該都知道了,我們就開始將電腦不能正常運作稱為 bug,然後除錯的過程叫做 debug。

其他譬喻例如病毒(virus)、特洛伊木馬(Trojan horse)、蠕蟲(worm)、邏輯炸彈(logic bomb)等等這些。

當我們一聽到這些譬喻時,我們就可以簡略地了解到,現在是在說明什麼事情,以及它的情境大致如何。例如當我們說到木馬病毒時,可以清晰的聯想到是特洛伊戰爭中,希臘人「送給」特洛伊人的那隻木馬,來借喻偽裝成無害程式,讓使用者無心執行,進而取得電腦權限的後門或者病毒程式。

譬喻X思考起點

但譬喻其實還有一個更強而有力的影響力,那就是會影響到我們觀察點,更甚至是哲學觀點。從前面我們提到,一個適切的譬喻,可以讓我們在腦中快速地描繪出情境,從另一種層面來講,就是譬喻會影響我們所思考的情境,也影響到整個思考起點。

托勒密宇宙體系圖。來源:維基百科

這裡比較適切的例子,就是天動說(地心說)與地動說(日心說)。古早人們觀察到,為什麼太陽、月亮和星星位置會不一樣,可是「地」仍是穩穩的在這呢?觀察到太陽、月亮和星星是會移動的,而地是不會移動的。開始認為這個宇宙是以地球為中心的,所以其他星星、月亮都是繞著地球轉。

中世紀教會加入神學觀點,認為地球是神將人安放的所在,所以它本身是具有特別地位的,是宇宙的中心,世界的中心。

但隨著觀察儀器進步,發現許多實測的數據,怎麼和天動說不怎麼相符?例如天體逆行。但那時候還沒有其他可以解釋的模型,所以只好繼續圍繞著天動說,完善既有天動說體系,直到哥白尼提出鼎鼎有名、撼動世界的地動說,才讓當時人們意識到,原來不是天在動,是地在動呀,顛覆整個數百年的宇宙觀。之後的歷史應該就不用提了,要撼動延續百年的宇宙觀非常艱難的。

資料中心是近代才出現的概念。來源 Akela999@Pixabay

而在書中提到在電腦史上的例子,就是早期處理電腦資料時,是將資料看待成流經電腦的連續卡片流(stram of cards),一種以電腦中心的思考方式,而在現在則是將資料看成是在一個資料池(pool of data),電腦只是偶爾才涉入其中的資料中心觀點。

從這些例子可以理解的,一個譬喻可以讓人輕易地掌握概念的全貌,同時提示這個概念隱含的事物關聯、性質以及待查證的部分,而譬喻更將概念抽象化以及內化,使得我們可以輕易地站在高點思考問題,而避免掉低層次的錯誤。

如果將譬喻和演算法比較,譬喻比較像是指引,它是告訴你「如何」去得到答案,那是否可以得到答案則是偶然的,也許有、也許沒有;而不像演算法是得到答案的「步驟」,當完成這些步驟後,可以得到解答。

換言之,我認為本書所要提的譬喻,其實是一種將事物概念化,接著發揮觀察力,將這個事物再與其他事物連結的一種心智過程。

從這可以建立起軟體開發與譬喻的連結。在軟體開發過程中,我們很難直接得到開發需求的步驟,通常是需要一步一步地將需求概念化,再將需求轉化成得以用程式開發的步驟,接著才是開始撰寫程式碼。在這過程中,可以巧妙的藉由譬喻,來增進自身的觀察與探索能力,讓自己的開發之路更加明亮。

常見的軟體開發譬喻

前面我們可瞭解到譬喻是什麼,以及譬喻與軟體開發的關聯性,那軟體開發本身的譬喻有哪些呢?在本書中,主要介紹幾種常見的譬喻:書寫、培育、生長以及建造:

  • 書寫觀點:寫程式碼(Writing code)
  • 耕耘觀點:培育系統(Growing a system)
  • 養殖觀點:系統生長(System accretion)
  • 建構觀點:建構軟體(Building software)

不過必須提醒大家一點,各種譬喻間並不是互斥的,並不是說用了書寫就不能再用建構來表示,再者既然他是譬喻,需要思考以及理解他的概念也是理所當然的。並且固守各種譬喻或者錯誤的利用,有可能使你誤解概念,而導引到錯誤的方向,不過經驗使人成長,這些錯誤也將成為個人經驗一環,成為自身思考工具其中之一。

書寫觀點:寫程式碼

「寫」程式是最常見的意象。來源:Free-Photos@Pixabay

寫程式碼,應該是軟體開發最古老也是最廣為人知的譬喻。諭示著軟體開發,就是工程師在某個地方好好的從頭到尾將程式完成,就如同在寫一封信一般(書中的比喻)。

作者認為這種譬喻會導致幾種不適宜的觀點,就是會認為開發是一種小型、個人以及重視原創性的活動,就如同書寫是一個人隨性,並且將書信彌封後就完成的工作,同時也認為在完成前會丟棄一堆草稿,一種不斷嘗試錯誤的過程。而忽略軟體開發重視重複利用而並非原創性,況且在大型專案中是多人協作,還有程式沒有所謂的「完成」一事,而是需要不斷地完善。

對此我部份認同,但我認為作者如果是將長篇寫作來做類比的話,可能更加適宜。在長篇寫作中,需要原創性也需要旁徵博引,同時更重視文章的架構,一個率性寫作長文的作者,在過程中會非常難熬。而且書寫本身並非一次性完成,而是要歷經初稿以及不斷的迭代修正,也可能完全沒有滿意的一天。

耕耘觀點:培育系統

這譬喻是將寫程式比喻成播種與耕耘的結果,每次都完成一部分工作,小步前進,逐步完成工作,將阻礙降到最少。

此觀點在小步快跑是蠻有益處,不過比喻成耕種有先天上的缺陷,就是「看天吃飯」,雖然你播種了、耕耘了,但最後是否能豐收還是要看上天,是否也暗示工程師對於軟體開發的過程以及結果,無法直接控制?

牡蠣觀點:系統生長

牡蠣觀點?就是認為軟體開發,是類似養珠過程,牡蠣將一顆細沙,經年累月後變成了一個珍珠。

這種觀點其實和上述耕耘蠻像的,強調軟體開發的成長性。認為軟體開發是一種從最簡單,逐步開發累積成可運作的工作系統即可。至於一開始他是真是假完全不重要,只要逐步將上線環境的要素逐步替換進去即可,就像是牡蠣一開始也不是真的珍珠,而只是一顆細沙,而在過程中逐漸將它轉化成珍珠。現代的敏捷開發主要就是建立在此種觀點上。

這種觀點好處也是不會過度承諾,最後可能是一顆珍珠,我是說可能。

建構觀點:建構軟體

建築設計藍圖是建築不可或缺的環節。來源:3844328@Pixabay

建構觀點,同時我認為也是作者比較推崇的觀點,認為軟體開發是類似建築的過程,規劃與客製化取決於建物的複雜性與目的,以及發生錯誤時的處理難度。

如果現在只是要需要一間狗屋,那可能可以簡單畫一下狗屋藍圖,需要一個屋頂、四面牆、挖一個洞當門,然後注意門不能比狗狗小,接著就可以開始買材料,可能一個下午新的狗屋就出來了,並且如果門一開始挖的比較小時,還可以直接的將門再挖大一點即可。

但如果是要蓋一棟房子的話,可能就要思考地點、地基、建材、構造、裝潢、管線等等,需要更多精準的規劃,並且修改難度將隨著房屋完成度成正比,例如牆壁,在草稿期可能只要動動筆,就可以改變牆壁位置,可是當牆壁蓋起來才要改變時,就要開始思考他是主力牆還是結構牆,會不會影響房屋結構,接著請人打掉,然後還要打掃等等,提高變動成本。而當是一棟摩天大樓時,難度就更倍加提升,甚至是開始思考對周遭環境的影響。

此外在建造的過程中,會依照需求調整客製化程度,傾向利用現有的物件來完成工作,例如冰箱、電視、沙發,或者頂多是用原物料加工,例如裝潢會雇用木工來達成我們的需求,而只要購買木材。而並非事事都會試圖從無到有建構,比方說現在需要一台冷氣,不會從壓縮機開始拼裝,甚至是馬達繞線圈。

簡言之,在建構觀點下的軟體開發,強調的是軟體架構以及設計彈性。在初期或者小型專案可以用著輕量彈性的方式快速開發;而在大型專案時則要注重設計架構、擴展性、穩定性等,避免災難性的後果;此外,程式邏輯並非皆要手工藝客製化,而可以善用第三方元件,使開發者可以專注在主要需求上等等。

我的觀點 — — 堆樂高、堆積木

“A little boy playing with a lego set in Erlangen” by Markus Spiske on Unsplash

介紹完書中四種觀點,這裡也要講講我的觀點。

我認為軟體開發比較像是堆積木,或者堆樂高,強調的是擴展性以及元件化,注重元件間的介面。積木和樂高,有一個共同觀點,就是它們可以利用簡單的結構與單元,來完成複雜的構造體。只要介面標準一致,客製化自己的樂高,與原本的樂高相容上就完全沒有問題。

因為我從小就是玩樂高長大的,每塊樂高都可以和另一塊樂高結合,所以可以隨意將樂高重組另一個樣貌,以及可以用原本組好的樂高加速完成,或者變出新樣貌,對我而言就是有莫大的吸引力。換言之,樂高本身就具有標準化、一致性、最小單元,來達成重用性。

不過此觀點也有著缺陷所在,如果一開始介面設計不好或者介面變更,將導致災難性的後果,因為所有的介面都需要更改。以及元件化,要注意避免程式過度切割,導致破碎化。此外元件數量增加,必須了解元件是否存在以及利用方法,將增加程式管理成本以及學習成本(不過更多情況可能是在直接寫一個,變成anti-pattern)。最嚴重問題,可能就是底層元件的變動,將牽一髮動全身,著名事例就是NPM的left-pad事件,相關事件可參閱關鍵評論網這篇文章

最後,你的譬喻呢?

感謝你讀到這篇長文最後。

前面我們了解到譬喻的用意以及對於軟體開發的關聯性,以及介紹各種常見譬喻,可以理解到譬喻其實是思考觀點的展現,同時也影響對於軟體開發過程的著重點。

最後,你的譬喻呢?

--

--

蘇曰

一位喜歡寫作、寫code,徜徉於法律、程式與知識天地間的智人。https://www.linkedin.com/in/jing-jhong-su/ email: sujingjhong@gmail.com