不只靠青春飯的程式人


iThome 網站首載:不只靠青春飯的程式人

許多人說程式設計是吃青春飯,40歲之後的老程式人,比不上精力旺盛、全力追求新技術的年輕程式人。實際上各行各業都一樣,時間可以是最大的敵人,也可以是最強的盟友,差異在於歲月流逝之餘,經驗中是否含有年輕人必須花同等時間追趕的因子。就程式設計領域來說,就是從新技術的拼裝上看不到,而是那些必須在逐步演化過程中才得以積累的知識、思路與專業。

對效率的多角度思考

談到效率(Efficiency),很多人會想到Donald Ervin Knuth談過的「程式設計者對效率的思考或擔憂,多數在程式中非關鍵部份,這類努力在除錯或維護時實際上會有很大的負作用。97%的情況下,過早最佳化是萬惡根源。然而,我們不該放棄那關鍵的3%。」,近來「過早最佳化是萬惡根源」這句話有被濫用的情況,Knuth的話中並沒有告訴我們,撰寫程式不需考慮效率。

對效率的探討是個逐步演進的過程,程式人過程中要懂得如何多角度思考。就算列印三角型這類簡單程式,在觀摩不同實作時也會發現不同的思考深度。學習資料結構與演算法就是在培養思考過程,單是排序就有多種方式,不同資料結構對搜尋也會有不同影響。現在不少程式庫實作了有效率的資料結構與演算法,如果經驗上已知某演算或資料結構可有效率解決某問題,那就應該使用對應實作,這並不會造成除錯或維護的負擔。思考效率也可從數學方向著手,以計算1至N總合為例,不少程式人被程式語法制約採用了迴圈解法,然而數學上可用等差數列公式求得,費式級數也有公式解法。對效率反覆且多角度的思考並非過早最佳化,有時多角度思考效率,也可同時對效率與維護發生助益,像是函數式的思考方向,經常可以清楚地分解問題,也有助於後續的效率檢討。

Knuth提到的還有不要放棄關鍵的3%,這關係到如何實際測試以找出效率瓶頸,以及找到瓶頸後如何改進,這些都需要多角度思考,是該減少IO?重用物件?採用非同步?平行處理?運用叢集?考量可擴充性?面對問題時,從累積的知識中找出最好解決方式,這樣的思考方式,並非朝夕得以形成。

對安全的持續認識與警惕

需求文件中不斷出現「此時應該要...」的字句,在開發程式過程中,我們致力於撰寫出符合功能的程式,然後按照一般使用者會進行的流程進行測試,以確定程式正常運行,然而後續卻發現有使用者特意構造意料外的流程,讓程式在依然遵循原本的設計下,產生了不想要的結果。如同效率,安全也是屬於非功能需求,使用者可以感受到程式運行緩慢,然而安全問題卻不易察覺,直到某天構成傷害為止。

幸運(或者該說不幸)的是,由於過去發生的傷害累積得夠多,留下不少模式與經驗,讓開發者在撰寫程式時,可以避免類似誤用而導致的安全問題,然而就如同無法宣稱程式中沒有臭蟲,即使運用了過去經驗避免了形式上可能的誤用,也無法保證程式中沒有安全問題。如同效率,對安全議題的認識與預防也是個持續演進的過程,隨著時間遞移,相關的模式與經驗越來越多,而瞭解與落實卻需要時間。

確實,作為一個程式人不一定要有安全知識,這也許是現今多數程式設計教學或教育訓練,多著重在如何運用技術實作功能,只有少數著重在使用或銜接技術時必須留意的安全問題,安全知識有賴於程式人的自發學習;然而好的程式人應該要持續認識與警惕安全問題,正如同效率需要多角度思考,安全也需要多角度而且是負面方向的思考;系統的不同層面也會有不同的安全議題,將系統各層面的認識及安全議題相結合,隨著時間累積越久,對相關的安全問題也會越有不可取代的敏感度。

培養撰寫可讀性程式的能力

先前Knuth引言中可以看出,易於除錯或維護是程式的重要考量,而易於除錯或維護牽涉到可讀性,實際上效率、安全與可讀性並不衝突,同樣的演算法,越有經驗的程式人越能寫出有效率且兼具可讀性的程式碼。Robert C. Martin在《Clean Code》書中亦提到「今天你撰寫程式碼的難易度,取決於周遭程式碼閱讀的難易度。」可讀性牽涉到許多層面,從變數、方法與類別的命名,函式職責、物件內聚性與獨立性,仍至於清楚的架構,都是可讀性的探討範圍。

現今程式碼的可讀性不斷地受到重視,寫出正確功能對大多數程式人來說並不困難,然而要寫出可讀性高的程式碼,單是命名就不簡單,如果不能為變數、方法或類別等取個適當名稱,可能表示你不夠瞭解它要的作用與職責,或者是它擔負了過多的工作,你必須知道如何重構它,直到可以為它取個適當名稱為止;除了命名之外,如何撰寫適當註解、編排程式碼、清楚地處理程式錯誤、設計職責適中的函式與類別,都需要時間與經驗的累積。

可惜的是,與安全問題類似,程式碼可讀性雖然不斷受到重視,但程式設計教育上鮮少著重,同樣有賴於程式人的自發學習。可讀性牽涉層面極廣,這也代表它是個逐步演進的過程,在認識與培養時有對應的順序與基礎,不少人從抽象的設計模式與架構探討,忽略了可讀性為前題,因而對模式或架構產生了錯誤的認知。撰寫可讀性程式的能力需要時間與經驗的累積,有時基於可讀性考量,也會推翻自己先前的設計,《Clean Code》中寫到童子軍規則「離開營地前,讓營地比使用者更乾淨。」對程式設計來說似乎很嚴格的規則,實際上不少程式人都有類似經驗,在閱讀舊程式碼時,都能看出自己不成熟的過去,因而想讓它更為乾淨。

深化特定領域的專業能力

回到一開始的主題,程式設計是吃青春飯嗎?先前針對效率、安全或可讀性的論述,無非是在強調,不要只是問「我寫程式贏得過年輕人嗎?」單比寫程式,老程式人也許不一定贏得了,如果程式能力中有必須付出同等時間追趕的因子在裏頭,那就是年輕人就欠缺的而老程式人具備的優勢,多數人常說經驗中無可取代的就是這個部份。除了從程式能力面向來累積這種能力之外,另一個面向就是深化特定領域的專業能力。

技術終究只是程式人的工具,工具是用來打造解決問題的產品。許多程式人除了程式相關技術之外,沒有其他領域的能力,更別說具備其他領域專業了。有時只要結合特定領域知識,就算使用簡單技術也能有出色表現。舉例來說,我曾很快地概覽並教會我太太Excel VBA,讓她撰寫程式來解決手動計算必須兩小時的基金計價表格,Excel VBA對我來說沒什麼,然而若表格中新增基金,我連改都不敢幫她改,因為我不具備該領域的知識,多數人稱「domain know how」才是最重要的,就是指這類情況的延伸。

特定領域的知識可以是在工作中累積,也可以是結合自身的興趣或能力,無論如何,要讓它隨著時間而成為專業並與程式設計結合;實際上效率、安全與可讀性,也正是程式設計這特定領域的專業,強大的功能或者是新技術終究只是一時,能夠累積特定領域專業,程式設計才能像好酒一樣越陳越香。