最近讀到一篇文章,文章一開始提到一位工作十餘年的程式設計者,發現自己隨著工作經驗愈來愈多,完成程式設計工作的時間愈來愈長,原因是因為過去經驗的累積,使得他還沒有開始動手撰寫程式之前,就已經預料了許多日後可能會發生問題的情境,致使在撰寫程式時,考慮的愈來愈周詳。

也因此,後來他所需要從事的設計,以及需要撰寫的程式碼也愈來愈多,導致完成程式碼的時間也愈來愈長。

這讓我想起剛學寫程式的前幾年,寫起程式碼總是勇猛精進,有時一個晚上不睡,能寫三千行程式,而且愈寫愈興奮。但的確也隨著時間的推移,似乎程式碼產出的步調也不那麼快了。可是仔細想想,軟體完成的速度卻並沒有因此而減慢,反而還是愈來愈快。

這是怎麼一回事呢?因為,如此看起來,似乎有點矛盾。

倉稟實而知禮節,衣食足而知榮辱

為什麼經驗愈多,反而寫起程式碼來的速度,好像變慢了?

因為,隨著程式設計者的經驗漸漸增多,體驗過的實際情況也愈多,另一方面,也隨著技巧愈來愈純熟、設計觀念愈來愈好,使得他們在撰寫程式碼時的重點,慢慢地,就會從怎麼實作出功能,逐漸地進展到怎麼更有效率地完成工作,也會因為知道了更多可能造成異常的情況,而能寫出更穩固的程式碼。同時,也會開始思考怎麼讓程式碼的可讀性更好,更有利於維護,甚至更易擴充、更能因應變化而修改。

如果說,實作出功能,是滿足基本的溫飽,那麼其餘更進階特質的追求,就是滿足溫飽之上、進一步的需求了。

滿足溫飽是最基本的,在這之上的各種需求就複雜多了。

因為這使得需要顧及的面向更多。就像我過去寫過的〈未慮對,先慮錯〉中所提到的心態一樣,程式設計者實作出功能是滿足「晴天情境」,而各種可能引發錯誤的情況則是「雨天情境」。只考慮「晴天情境」的實作當然寫得飛快,但是要先預知各種「雨天情境」,並且知道如何在程式碼中提防,就需要更多的時間了。

新手程式設計者常常只將目光焦點放在「晴天情境」,而且也不管日後是否容易修改、擴充,所以看似完成的時間較短。另一方面,有經驗、考慮周詳的程式設計者,因為需要賦予程式碼更多的作用,無論是效率、穩固性、可讀性、可擴充性、等等,所以,完成表面上看似相同的功能所需的時間就比較長。

程式碼完成得很快,不等於精準達到目標

首先,讓我們從生產力的觀點來看這個比較,是否能得出是新手程式設計者生產力較高,而老手程式設計者因為做起事來「瞻前顧後」,反而生產力下降了?

這或許是一個可能的誤解,但是,生產力的時間基準並不是基於初次產出程式碼所需的時間來計算,而是要一直計算到程式碼通過測試可以上線或發行穩定使用的那一刻為止。

寫出初版的程式碼,不代表這份程式碼是可用的程式碼,因為或許經歷過殘酷的測試之後,能通過的測試案例有限,於是又得花費更多的時間來反覆除錯、修改,再重新測試。大家都應該要意識到,修正錯誤所花費的時間,往往數倍於寫下程式碼的時間。

很快完成一個看似會動的產物,卻埋藏諸多會引爆的地雷,反而延長了這些程式碼成為合格程式碼的過程,增加了實質上所需的時間。

寫得快,不如寫得準。表面上的快,不見得是真正的快,一劍準確的致命,才是真正的快。

現在的軟體開發,現成的程式碼多、需要重新撰寫的程式碼相較於以前是變了。

這是因為,近二十年來軟體開發領域,普遍重視程式碼的重複運用,不論是程式語言、設計觀念,或是各種現成的程式庫及應用程式框架的發展,都逐漸將這個共用的基礎變大。我們所寫下的程式碼,大多不是特定應用的邏輯(application-specific logic),就是用來「黏合」各個獨立的現成程式元件。

所以,如何巧妙地撰寫有品質的程式碼,來操控現成、重複運用得來的程式碼,比起快速寫下大量的程式碼,顯得更加重要。

想太多,不等於想得正確,要避免過度工程化的問題

另一方面,程式設計者撰寫程式碼時想顧及更多層面的心態,固然很好,但也需要小心落入「過度工程化(over engineering)」的陷阱。

什麼是「過度工程化」?這意思是,在軟體開發裡,過度工程化指的就是預想的比實際需求的多,以致於投入更多的資源,卻做出額外、不在真實需求內的東西。以簡單的方式來解釋,其實,過度工程化就是「想太多了」。

當我們「先慮錯」時,有可能考慮到太多類型的錯誤,甚至包括了不會發生的錯誤,或是在開發情境下不需要考慮到的錯誤。例如,考慮到開啟檔案時,可能會開檔失敗,這是常見的情況。但是若是還考慮到系統 API 出錯,導致無法取得檔案長度,或是檔案長度資訊錯誤,有時,這就顯得「想太多了」。

程式碼是需要有一定的彈性沒錯,但是,有些走火入魔的程式設計者,會企圖置入遠超過真實需求的彈性,不只浪費成本、同時也往往增加程式碼的複雜度,最後又沒有帶來任何好處。這也是一種過度工程化。

就像,有些人從來不寫程式註解,有些人卻浪費太多的時間在寫毫無意義的註解,程式碼並沒有因為這些沒有意義的註解,而變得更容易理解。有些時候,增加註解只能增加「些微」的說明力,考量到成本效益比,這樣的註解不見得划算。

所以說,這些活動都是過猶不及。就像並不是一味想要增加程式的穩固性就好,你必須權衡當下的應用情境,包括究竟有多少時間、資源,以及應用本身、運行的條件及環境,來決定你究竟要落在「過」與「不及」中的那個點上平衡。

拿捏原則,權衡過與不及的後果再行動

軟體開發有一些原則,但是這些原則的運用之妙,也都是存乎一心。並不是把一些原則死板板的拿出來用,就一定可以得到很好的功效。就像寫程式要考慮穩固性、擴充性、可讀性、 ……等等,但是,真實的應用情境下,必須仔細的思考需要的究竟是多少?

並不是無限上綱地追尋每個特質的最佳狀態。先別提有些特質彼此之間甚至還相互衝突、干擾,追求最佳往往需要付出極大的代價。但是,需要為了不存在的需求,而付出額外的代價嗎?

這就是我所說的,許多決策終究都要在「過」與「不及」中的某個點上去平衡。你要從真正的現實去考慮,而不是照著原則死做,把它做到極限。軟體開發當然是藝術,而程式碼也時常被比喻為是藝術的產物,但是它的美通常不是表現在極致的雕琢之上,而是表現在滿足實用性的基礎上,所展現出來的諸般美好特質。

在軟體開發裡,如何做取捨本身就是藝術。

專欄作者

熱門新聞

Advertisement