程序員的素質

程序員的素質

轉載 白楊 http://baiy.cn

    衆所周知,軟件和硬件工程師個體間存在巨大的生產力差異:經常有一個人一兩天就能做好的事情另一個人花一兩個月也沒能做到同樣好。

    Apple創始人史蒂夫·喬布斯曾在《In the Companyof Giants 》一書中接收採訪時提到:“一個最優秀的人完成工作的能力能抵50100 個一般水平的人”。而軟件工程領域也經常提到最好和最差的程序員之間的生產力差異超過1000 倍,因爲如果一個程序員產出的代碼中包含了很多bug ,需要其它程序員花費大量時間去修正,那麼他的生產力是負值。

    在世界名著《人月神話》中,作者也明確地提出了類似的觀點:“最優秀和一般的軟件工程實踐之間的差距是非常大的,可能比其他工程領域中的差距都要大……”。

    除了團隊組織和項目管理等行政方面的問題;以及語文、數學、邏輯思維和形象思維等個人基礎素質以外,到底是哪些專業素養導致了程序員個體間的巨大生產力差異呢?本文嘗試以由淺到深、由易到難的順序來討論程序員的個體素質。

1. 基本技術素養

    基本素養包含了每個程序員都應當牢固掌握和充分理解的技能和知識。基本素養中又可以分爲前景知識和背景知識兩種。

        前景知識:今天的程序員主要通過使用編程語言書寫代碼來完成軟件開發活動,前景知識則特指程序員對其使用語言的掌握程度。這裏所說的“掌握”並不是僅僅能夠寫出合法的代碼就行了,而是對語言中各種實現細節的深度掌握。

    如果一位程序員未能透徹掌握他正在使用的程序設計語言,那他寫的程序就一定會或早或晚地出現一些至少在他看來有些“莫名其妙”的問題,比如:應用程序時常莫名其妙地崩潰、經常發生資源泄露、或是執行過某些操作時性能差的離譜等等。

 

    以C++ 語言爲例:正如大部分 C 程序員都能毫不費力地將任意C 源碼“肉眼翻譯”成僞彙編碼那樣,一個合格的 C++ 程序員也應當可以做到將任意C++ 源碼“人腦編譯”爲對應的僞彙編碼。但現實的情況是由於 C++ 新增了模板、虛函數、RTTI、虛基類、異常等大量高級特性,以至於能夠真正透徹掌握C++ 語言的程序員很少。

 

    除非完全不使用前文中列出的那些C++ 高級特性,僅把它作爲一個“稍好的C”來使用。否則,對於任何一個職業程序員來說,貿然地使用一種尚不瞭解其底層(編譯器或VM實現細節的語言特性是一件很危險的事。

 

    類似的例子同樣適用於其它語言。不管是編譯型的(如:C/C++ )還是解釋/ 虛擬機型的

如:PHP Java 以及JavaScript)程序設計語言,它們都有一些需要程序員事先透徹理解和掌握的實現細節。

        背景知識:透徹地理解和掌握至少一門編程語言對任何一位職業程序員來講都是很重要的基礎素質,但僅僅做到這點仍然是遠遠不夠的。想要產出具備現實意義的產品,還需要具備足夠的背景知識。以下,我們將背景知識分成“公共背景”和“領域背景”兩類,分別進行討論。

        公共背景:公共背景包括了幾乎每個程序員都需要掌握的知識。從操作系統原理、編譯原理、數據結構、離散數學、計算機組成原理、網絡原理等理論性知識到各種接口和實際環境的運行時API(例如:對C/C++ 來講通常是操作系統API,對JavaScript 來講通常是瀏覽器提供的API)都是作爲程序員必不可少的基礎。

        領域背景:領域背景中包含了與具體問題域相關的背景知識,這些知識並不是每個程序員都需要掌握的,但對於涉及該領域的開發人員來講卻必不可少。

 

    例如:對於要實現音頻編輯器的程序員來說,至少具備起碼的聲學背景;MIDI編曲軟件的作者需要樂理和和聲方面的知識;OCR軟件的作者則要學習模式識別和圖像處理方面的理論等等。

2. 思維的條理性和連貫性

    對於一個程序員來說,從產品的設計之初到其中組件的逐一實現完成乃至最後的聯調。整個開發週期從始至終都需要保持清晰的條理和連貫的思維。以下準則有助於幫助程序員在開發過程中始終保持思維的條理性和連貫性。

        3W 準則:我想每個程序員都應該遵循3W 準則,即:每次在開始編寫代碼之前,都應當先搞清楚WhatWhy How 三個問題。其中“What”指我們要做什麼,也就是用戶的需求。“Why ”表示爲什麼我們要做這件事,這是對需求和架構的更深層理解。很多時,只有充分了解了“爲什麼”以後,我們才能更好地完成設計(例如:使用更合適的算法和構架,以及在架構中預留恰當的接口等等)。最後“How ”從設計層面指明瞭應當以何種架構、哪些模式和算法來最終構建出產品。

 

    值得指出的是,3W 準則不但適用與對系統進行整體分析和設計,同樣也應當利用在模塊或組件等粒度更細的層面上——在開始着手編寫一個組件前,應當事先搞清楚這個組件的功能(What);需要在何處使用它、爲什麼需要用到它、它的典型用例和工作上下文(Why );最後是使用何種架構、模式和算法來實現它( How )。

 

    本質上講,需求分析和總體設計的意義就是在系統的層面上回答以上三個問題。總體設計使開發人員能夠對待開發的產品在整體上有一個比較清晰的瞭解,知道當前正在實現的組件處於系統中的什麼位置。

 

    在着手實現一個組件前,如果程序員能先在組件的層面上搞清楚這三個問題,那麼他就可以在一個目標、動機和實現方式都很清晰的狀態下開始工作。進一步說,在開始工作之前,清楚的知道自己要做什麼以及如何完成手上的工作對於任何行業的從業人員來說都是非常重要的。遺憾的是,相當多的程序員好像並不這麼認爲。

        時刻保持清晰的邏輯:3W 準則讓我們在動手前就清楚自己要做什麼以及如何做。但在具體實踐的時候我們還需要隨時清楚自己正在做什麼?之前幾步分別做了哪些事?以及之後幾步還要乾點啥?只有時刻了解自己“剛纔”、“現在”、以及“將來”要做的事情,才能隨時保持思維連貫和條理清晰。

        以恰當的層次進行思考:太高的層次過於抽象,而過低的層次容易讓我們揪住某些細節問題不放。在合適的層次思考才能夠最有效地想出恰當的解決方案。什麼層次纔算“恰當”沒有簡單的定論,這取決於產品的規模和正在解決的問題。但是在碰到棘手問題的時候換個層面來重新考量往往能夠事倍功半。

3. 高效的產品維護

    軟件產品的日常維護主要包含排錯、Workaround 、功能變更、架構重構等活動。對於新手來說,花個幾天時間找“臭蟲”實屬常見(有句順口溜說的好:“鋤禾日當午,不如coding 苦,對C++ ,一調一下午……”)。提高產品維護的效率就在很大程度上提高了程序員的生產力(因爲有更多的時間編寫新代碼)。

    多年的經驗顯示,以下要點對於提高產品維護效率、以及提高產品質量都有着不可忽視的作用:

        編碼規範:編碼規範對於軟件品質的影響怎麼強調都不過分。程序代碼作爲一種文檔,首先是供人類閱讀的。好的編碼規範能夠有效地降低錯誤率、提高可讀性、以及極大地曾強代碼的可維護性。換個角度來看,代碼只寫一次,但卻需要斷地進行閱讀、理解、修改等維護工作。沒人願意接手維護一大堆完全看不懂的代碼,在書寫時始終遵循一套完善的編碼規範則可以在很大程度上緩解這些問題。

 

    編碼規範對程序品質和可維護性方面的影響就像鞋對人類的影響一樣:都屬於效果巨大,但跟沒體會過的人很難描述清楚的事情——真是誰用誰知道。這可能也是爲什麼那麼多公司都在強調它,同時那麼多程序員卻又不重視它的原因所在——光腳的不怕穿鞋的!

        錯誤處理和日誌:優秀的錯誤處理和日誌記錄方式能節省大量排錯時間,同時揭示產品改進的重要線索。在另一本世界名著《Code Complete》中,作者憑藉其多年的軟件行業經驗以及NASA IBM 等各大組織的長期研究報告得出結論:“在絕大多數項目中,最大規模的活動就是調試以及修改那些不能正常工作的代碼……消除軟件缺陷實際上是最昂貴且最耗時的軟件工作”。

 

    這方面牽扯到的技術和技巧太多太雜,以至於沒有辦法給出一個總結性的描述。因此,這裏只能以日常維護場景爲例,舉一個簡單的例子:

 

    試想一下,你有一個可以向系統 syslog 、網絡 syslog server、磁盤文件、Event Log Service等等各種日誌目的實時發送日誌消息的記錄器,它能夠工作在調用線程或獨立的線程/進程中,就算進程崩潰它也能夠捕捉到足夠詳細的錯誤信息,即使整個系統崩潰了也不會丟失重要的日誌消息。

 

    與此同時,你所有組件中的任何操作發生錯誤時,都會準確地將該操作的錯誤信息、操作過程中產生錯誤的模塊信息、該模塊調用的底層平臺 API 以及這個API 返回的錯誤信息等等的各級出錯詳細信息都按照層次結構如實地記錄到日誌中。在這樣的環境中,無論是排錯還是調優是不是都會點單很多呢?

 

    正如前文所述,日誌記錄和錯誤處理是個很大的話題,足以著書立說。這個例子也只是揭示其冰山一角,從一個小小的側面來反映一套優秀的日誌記錄和錯誤處理機制對排錯和性能分析之類的活動有多大幫助。

        環境和工具:熟練掌握開發編輯、分析統計、調試跟蹤等工具。優秀的開發、分析、和調試環境可以節省大量時間。儘量避免在不熟悉或者較“艱苦”的環境下分析和調試程序。

 

    當然,有時也會有一些不可避免的情況出現。比如:程序的最終目標平臺是基於MIPS架構的NetBSD,但開發人員最熟悉,各類工具最齊全的開發環境確實 x86 平臺下的Windows系統。對此,我們的解決方案是:實現一套與跨平臺的應用支撐框架,這個支持框架向上封裝所有平臺相關的功能,爲上應用提供統一的,平臺無關的API。然後使用該支撐框架在Windowsx86 )環境完成應用的開發、分析和調試工作,然後在 NetBSDMIPS)平臺上重新編譯併發布。

        其它因素:產品維護的成本還會受到很多其它因素的影響。比如在設計之初以3W 原則精心衡量過的方案可以避免很多後期不必要的變更;比如重用已經經過驗證的可靠組件不但節省了開發成本,而且也避免了重新實現產生的缺陷;再比如經驗、設計思想和品味對設計產生的影響等等。

4. 標準化和重用

    標準化本質上就是爲重用做準備。想要擁有大量標準的可重用組件需要長時間的積累。當然,我們這裏提到的“標準化”並不僅僅是指ISO/IEC 之類的國際標準或者GB之類的國家標準。實際上,小到公司甚至是個人也可以有自己的內部標準(其實編碼規範就屬於這種內部標準之一)。C++ 之父Bjarne Stroustrup曾經說過:產品開發就是重用已有標準組件、實現新的標準組件、然後將它們粘接起來的過程。

    想要自己實現一套完備的標準組件庫當然需要長時間的積累,但如果利用其它人已經實現的現成庫呢?我們知道,當今的開源時代,能夠免費取用的第三方功能庫數不勝數。但是使用第三方庫的成本也不低。具體表現在幾方面:首先,要用好它,你需要閱讀大量代碼和文檔;其次,掌握一個庫不光是會使用即可,一旦把它用到自己的產品裏,那麼當它發生問題時你要修正、當它不滿足要求時你要修改和重構、當它缺少功能時你要添加……也就是說,一旦在自己的產品中使用了一套第三方庫,那麼維護它就是你的義務,而要維護一大堆代碼,前提是你需要先讀懂這些代碼。最後,第三方庫的架構和品質不一定滿足你的要求,而且這個問題可能到最後纔會被髮現。

    例如:由於架構的限制,Windows IOCP機制無法被在Boostasio 組件良好地支持。如果你的產品使用了asio 組件,並且在開發的最後階段才考慮需要提供針對Windows 平臺的支持,那麼你將會面臨艱難選擇。再比如:你需要一套跨平臺C/C++ 框架,但BoostMozilla NSPRApache APRGNU Common C++ 等均無法滿足你的需求(舉個最簡單的例子:他們都支持對線程設置CPU 粘滯屬性)這也使你面臨兩難的選擇:是選擇其中一個庫,大規模的修改它以滿足你的功能需求,並且忍受這個實現從架構到編碼規範中所有你看不順眼的地方,同時還要日復一日地將官方補丁合併到你自己的私人分支。還是索性從頭開始建立自己的庫?

    當然,無論你如何選擇,這些代價都是值得的。因爲我們知道,程序員的生產力基本等同於他在單位時間內產出的有效代碼行數與其中每行代碼平均表達能力的乘積。即:

    生產力=有效代碼行數×每行代碼的表達能力

    大量使用標準組件不光獲得了由於組件被反覆使用因而比較成熟的優點,而且也使得每行代碼的平均表達能力大大提高(比如:標準組件通過成千上萬行代碼封裝好的一個功能,使用一行代碼即可調用),這就使得程序員的生產力能夠以乘積的形式增長。

5. 經驗和設計思想

    經驗和個人品味是永遠也無法被替代的。Stroustrup曾說:任何一個成功的產品中都必然充斥着其作者的味道。這話雖然有一定誇張的成分,但也不可否認,設計者的經驗和品味會極大地影響產品的最終品質。而設計思想其實是來自於經驗的總結和昇華,當然其中也糅合了個人的品味與喜好。因此,設計思想只有成熟和幼稚的區別,而成熟的設計思想之間很難有好壞之分——成熟的思維各有各的老練之處,但所有人幼稚起來則是大同小異的。

6. 人品(態度)

    這標題看起來有點怨天尤人的意思。但我們這裏提到的人品既不是傳統上的“忠孝禮義仁智信”,也不是現代網絡用語中“運氣”的意思。這裏主要是指程序員的責任感和追求完美的態度,還有樂於與人交流的生活方式。竊以爲缺乏這幾樣東西的人無論如何都不可能成爲真正優秀的程序員。

總結

    寫完以後發現此小文中的各小節有一節更比一節短的趨勢。本文開頭說各小節是以由淺到深、由易到難的順序來排列的。寫完後再看又何嘗不是從具體到抽象的排列呢?前面說的都是比較具體的技術技巧和知識,容易說出個 1234。而越到了後面哲學色彩就越濃厚,評判標準也越主觀,自然也就越發難以表達清楚了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章