程序員的素質程序員
轉載 白楊 http://baiy.cn算法
衆所周知,軟件和硬件工程師個體間存在巨大的生產力差別:常常有一我的一兩天就能作好的事情另外一我的花一兩個月也沒能作到一樣好。編程
Apple創始人史蒂夫·喬布斯曾在《In the Companyof Giants 》一書中接收採訪時提到:「一個最優秀的人完成工做的能力能抵50到100 個通常水平的人」。而軟件工程領域也常常提到最好和最差的程序員之間的生產力差別超過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 準則,即:每次在開始編寫代碼以前,都應當先搞清楚What、Why 、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。而後使用該支撐框架在Windows(x86 )環境完成應用的開發、分析和調試工做,而後在 NetBSD(MIPS)平臺上從新編譯併發布。
其它因素:產品維護的成本還會受到不少其它因素的影響。好比在設計之初以3W 原則精心衡量過的方案能夠避免不少後期沒必要要的變動;好比重用已經通過驗證的可靠組件不但節省了開發成本,並且也避免了從新實現產生的缺陷;再好比經驗、設計思想和品味對設計產生的影響等等。
4. 標準化和重用
標準化本質上就是爲重用作準備。想要擁有大量標準的可重用組件須要長時間的積累。固然,咱們這裏提到的「標準化」並不只僅是指ISO/IEC 之類的國際標準或者GB之類的國家標準。實際上,小到公司甚至是我的也能夠有本身的內部標準(其實編碼規範就屬於這種內部標準之一)。C++ 之父Bjarne Stroustrup曾經說過:產品開發就是重用已有標準組件、實現新的標準組件、而後將它們粘接起來的過程。
想要本身實現一套完備的標準組件庫固然須要長時間的積累,但若是利用其它人已經實現的現成庫呢?咱們知道,當今的開源時代,可以免費取用的第三方功能庫數不勝數。可是使用第三方庫的成本也不低。具體表如今幾方面:首先,要用好它,你須要閱讀大量代碼和文檔;其次,掌握一個庫不光是會使用便可,一旦把它用到本身的產品裏,那麼當它發生問題時你要修正、當它不知足要求時你要修改和重構、當它缺乏功能時你要添加……也就是說,一旦在本身的產品中使用了一套第三方庫,那麼維護它就是你的義務,而要維護一大堆代碼,前提是你須要先讀懂這些代碼。最後,第三方庫的架構和品質不必定知足你的要求,並且這個問題可能到最後纔會被髮現。
例如:因爲架構的限制,Windows IOCP機制沒法被在Boost庫asio 組件良好地支持。若是你的產品使用了asio 組件,而且在開發的最後階段才考慮須要提供針對Windows 平臺的支持,那麼你將會面臨艱難選擇。再好比:你須要一套跨平臺C/C++ 框架,但Boost、Mozilla NSPR、Apache APR、GNU Common C++ 等均沒法知足你的需求(舉個最簡單的例子:他們都支持對線程設置CPU 粘滯屬性)這也使你面臨兩難的選擇:是選擇其中一個庫,大規模的修改它以知足你的功能需求,而且忍受這個實現從架構到編碼規範中全部你看不順眼的地方,同時還要日復一日地將官方補丁合併到你本身的私人分支。仍是索性從頭開始創建本身的庫?
固然,不管你如何選擇,這些代價都是值得的。由於咱們知道,程序員的生產力基本等同於他在單位時間內產出的有效代碼行數與其中每行代碼平均表達能力的乘積。即:
生產力=有效代碼行數×每行代碼的表達能力
大量使用標準組件不光得到了因爲組件被反覆使用於是比較成熟的優勢,並且也使得每行代碼的平均表達能力大大提升(好比:標準組件經過成千上萬行代碼封裝好的一個功能,使用一行代碼便可調用),這就使得程序員的生產力可以以乘積的形式增加。
5. 經驗和設計思想
經驗和我的品味是永遠也沒法被替代的。Stroustrup曾說:任何一個成功的產品中都必然充斥着其做者的味道。這話雖然有必定誇張的成分,但也不能否認,設計者的經驗和品味會極大地影響產品的最終品質。而設計思想實際上是來自於經驗的總結和昇華,固然其中也糅合了我的的品味與喜愛。所以,設計思想只有成熟和幼稚的區別,而成熟的設計思想之間很難有好壞之分——成熟的思惟各有各的老練之處,但全部人幼稚起來則是大同小異的。
6. 人品(態度)
這標題看起來有點怨天尤人的意思。但咱們這裏提到的人品既不是傳統上的「忠孝禮義仁智信」,也不是現代網絡用語中「運氣」的意思。這裏主要是指程序員的責任感和追求完美的態度,還有樂於與人交流的生活方式。竊覺得缺少這幾樣東西的人不管如何都不可能成爲真正優秀的程序員。
總結
寫完之後發現此小文中的各小節有一節更比一節短的趨勢。本文開頭說各小節是以由淺到深、由易到難的順序來排列的。寫完後再看又未嘗不是從具體到抽象的排列呢?前面說的都是比較具體的技術技巧和知識,容易說出個 1234。而越到了後面哲學色彩就越濃厚,評判標準也越主觀,天然也就愈加難以表達清楚了。