注重实效的程序员
1、關心你的技藝?
Care About Your Craft?
除非你在乎能否漂亮地開發出軟件,否則其它事情都是沒有意義的。
2、思考!你的工作?
Think!About Your Work?
在你做某件事情的時候思考你在做什么。不間斷地思考,實時地批判你的工作。這將占據你的一些寶貴時間,酬勞則是更為活躍地參與你喜愛的工作、感覺到自己在掌握范圍日增的各種主題以及因感受到持續的進步而歡愉。從長遠來說,你在時間上的投入將會隨著你和你的團隊變得更為高效、編寫出更易于維護的代碼以及開會時間的減少而得到回報。?
3、提供各種選擇,不要找蹩腳的借口?
Provide Options,Don't Make Lame Excuses?
不要說事情做不到;要說明能夠做什么來挽回局面。不要害怕提出要求,也不要害怕承認你需要幫助。
4、不要容忍破窗戶?
Don't Live With Broken Windows?
不要留著“破窗戶”(低劣的設計、錯誤的決策、或者糟糕的代碼)不修。發現一個就修一個。如果沒有足夠的時間進行適當的修理,采取某種行動防止進一步的破壞,并說明情勢處在你的控制之下。?
如果你發現你所在團隊和項目的代碼十分漂亮——編寫整潔、設計良好,并且很優雅,你不會想成為第一個弄臟東西的人。
5、做變化的催化劑?
Be a Catalyst for Change?
你不能強迫人們改變。相反,要向他們展示未來可能會怎樣,并幫助他們參與對未來的創造。?
設計出你可以合理要求的東西,好好開發它。一旦完成,就拿給大家看,讓他們大吃一驚。然后說:“要是我們增加...可能就會更好。”假裝那并不重要。坐回椅子上,等著他們開始要你增加你本來就想要的功能。人們發現,參與正在發生的成功要更容易。讓他們瞥見未來,你就能讓他們聚集在你周圍。
6、記住大圖景?
Remember the Big Picture?
如果你抓一只青蛙放進沸水里,它會一下子跳出來。但是,如果你把青蛙放進冷水里,然后慢慢加熱,青蛙不會注意到溫度的緩慢變化,會呆在鍋里,直到被煮熟。?
不要像青蛙一樣。留心大圖景。要持續不斷地觀察周圍發生的事情,而不只是你自己在做的事情。
7、使質量成為需求問題?
Make Quality a Requirements Issue?
你所制作的系統的范圍和質量應該作為系統需求的一部分規定下來。讓你的用戶參與權衡,知道何時止步,提供足夠好的軟件。
8、定期為你的知識資產投資?
Invest Regularly in Your Knowledge Portfolio
- 讓學習成為習慣。
- 持續投入十分重要。一旦你熟悉了某種新語言或新技術,繼續前進,學習另一種。
- 是否在某個項目中使用這些技術,或者是否把它們放入你的簡歷,這并不重要。學習的過程將擴展你的思維,使你向著新的可能性和新的做事方式拓展。思維的“異花授粉”十分重要;設法把你學到的東西應用到你當前的項目中。即使你的項目沒有使用該技術,你或許也能借鑒一些想法。例如,熟悉了面向對象,你就會用不同的方式編寫純C程序。
- 如果你自己找不到答案,就去找出能找到答案的人。不要把問題擱在那里。
?
9、批判地分析你讀到的和聽到的?
Critically Analyze What You Read and Hear?
不要被供應商、媒體炒作、或教條左右。要依照你自己的看法和你的項目的情況去對信息進行分析。10、你說什么和你怎么說同樣重要?
It's Both What You Say and the Way You Say It - 作為開發者,我們必須在許多層面上進行交流。我們的時間有很大部分都花在交流上,所以我們需要把它做好。
- 如果你不能有效地向他人傳達你的了不起的想法,這些想法就毫無用處。
- 知道你想要說什么;了解你的聽眾;選擇時機;選擇風格;讓文檔美觀;讓聽眾參與;做傾聽者;回復他人。
- 交流越有效,你就越有影響力。
?
11、DRY原則——不要重復你自己?
DRY - Don't Repeat Yourself?
系統中的每一項知識都必須具有單一、無歧義、權威的表示。與此不同的做法是在兩個或更多地方表達同一事物。如果你改變其中一處,你必須記得改變其它各處。這不是你能否記住的問題,而是你何時忘記的問題。12、讓復用變得容易?
Make it Easy to Reuse?
你要做的是營造一種環境,在其中要找到并復用已有的東西,比自己編寫更容易。如果復用很容易,人們就會去復用。而如果不復用,你們就會有重復知識的風險。13、消除無關事物之間的影響?
Eliminate Effects Between Unrelated Things?
我們想要設計自足(self-contained)的組件:獨立,具有單一、良好定義的目的。如果組件是相互隔離的,你就知道你能夠改變其中一個,而不用擔心其余組件。只要你不改變組件的外部接口,你就可以放心:你不會造成波及整個系統的問題。?
你得到兩個主要好處:提高生產率與降低風險。14、不存在最終決策?
There Are No Final Decisions?
沒有什么永遠不變——而如果你嚴重依賴某一事實,你幾乎可以確定它將會變化。與我們開發軟件的速度相比,需求、用以及硬件變得更快。通過DRY原則、解耦以及元數據的使用,我們不必做出許多關鍵的、不可逆轉的決策。有許多人會設法保持代碼的靈活性,而你還需要考慮維持架、部署及供應商集成等領域的靈活性。15、用曳光彈找到目標?
Use Tracer Bullets to Find the Target?
曳光彈能通過試驗各種事物并檢查它們離目標有多遠來讓你追蹤目標。?
曳光彈代碼含有任何一段產品代碼都擁有的完整的錯誤檢查、結構、文檔、以及自查。它只不過功能不全而已。但是,一旦你在系統的各組件之間實現了端到端(end-to-end)的連接,你就可以檢查你離目標還有多遠,并在必要的情況下進行調整。一旦你完全瞄準,增加功能將是一件容易的事情。16、為了學習而制作原型?
Prototype to Learn?
任何帶有風險的事物。以前沒有試過的事物,或是對于最終系統極其關鍵的事物。任何未被證明的、試驗性的、或有疑問的事物。任何讓你覺得不舒服的東西。都可以通過制作原型來研究。比如:架構;已有系統中的新功能;外部數據的結構或內容;第三方工具或組件;性能問題;用戶界面設計等等。?
原型制作是一種學習經驗,其價值并不在于所產生的代碼,而在于所學到的經驗教訓。17、靠近問題領域編程?
Program Close to The Problem domain?
計算機語言會影響你思考問題的方式,以及你看待交流的方式。用你的用戶的語言進行設計和編碼。18、估算,以避免發生意外?
Estimate to Avoid Surprises?
在著手之前先進行估算。你將提前發現潛在的問題。?
1)要選擇能反映你想要傳達的精確度的單位;?
2)基本的估算訣竅:去問已經做過這件事情的人;?
3)理解提問內容;?
4)根據對問題的理解,建立粗略、就緒的思維模型骨架;?
5)把模型分解為組件,找出描述這些組件怎樣交互的數學規則,確定每個組件的參數;?
6)給每個參數指定值,找出哪些參數對結果的影響最大,并致力于讓它們大致正確;?
7)進行多次計算,改變關鍵參數的值,然后根據那些參數表達你的答案;?
8)在被要求進行估算時說的話:“我等會回答你”。19、通過代碼對進度表進行迭代?
Iterate the Schedule with the Code?
實行增量開發。追蹤你的估算能力,提煉對迭代次數、以及在每次迭代中可以包含的內容的猜想。提煉會變得一次比一次好,對進度表的信心也將隨之增長。你將給予管理部門你所能給予的最精確的進度估算。20、用純文本保存知識?
Keep Knowledge in Plain Text - 保證不過時;
- 杠桿作用:每一樣工具,都能夠在純文本上進行操作;
- 更易于測試;
- 你需要確保所有各方能夠使用公共標準進行通信。純文本就是那個標準。
?
21、利用命令shell的力量?
Use the Power of Command Shells?
GUI環境通常受限于它們的設計者想要提供的能力。當你想要快速地組合一些命令,以完成一次查詢或某種其他的任務時,命令行要更為適宜。多使用你的命令shell,你會驚訝它能使你的生產率得到怎樣的提高。22、用好一種編輯器?
Use a Single Editor Well?
選一種編輯器,徹底了解它,并將其用于所有的編輯任務。如果你用一種編輯器進行所有的文本編輯活動,你就不必停下來思考怎樣完成文本操縱:必需的鍵擊將成為本能反應。編輯器將成為你雙手的延伸;鍵會在滑過文本和思想時歌唱起來。這就是我們的目標。23、總是使用源碼控制?
Always Use Source Code Control - 總是。即使你的團隊只有你一個人,你的項目只有一周時間;確保每樣東西都處在源碼控制之下。
- 源碼控制是你的工作的時間機器——你能夠回到過去。
- 把整個項目置于源碼控制系統的保護之下具有一項很大的、隱蔽的好處:你可以進行自動的和可重復的產品構建。
?
24、要修正問題,而不是發出指責?
Fix the Problem,Not the Blame?
要接受事實:調試就是解決問題,要據此發起進攻。Bug是你的過錯還是別人的過錯,并不是真的很有關系。它仍然是你的問題。25、不要恐慌?
Don't Panic?
做一次深呼吸,思考什么可能是bug的原因。 - 要總是設法找出問題的根源,而不只是問題的特定表現;
- 搜集所有的相關數據;
- 開始修正bug的最佳途徑是讓其可再現;
- 使你的數據可視化;
- 跟蹤:觀察程序或數據結構隨時間變化的狀態;
- 找到問題的原因的一種非常簡單、卻又特別有用的技術是向別人解釋它。你只是一步步解釋代碼要做什么,常常就能讓問題從屏幕上跳出來,宣布自己的存在。
?
26、“Select”沒有問題?
"Select" Isn't Broken?
Bug有可能存在于OS、編譯器、或是第三方產品中——但這不應該是你的第一想法。有大得多的可能性的是,bug存在于正在開發的應用代碼中。與假定庫本身出了問題相比,假定應用代碼對庫的調用不正確通常更有好處。即使問題確實應歸于第三方,在提交bug報告之前,你也必須先消除你的代碼中的bug。27、不要假定,要證明?
Don't Assume it - Prove It?
不要因為你“知道”它能工作而輕易放過與bug有牽連的例程或代碼。證明它。在實際環境中——使用真正的數據和邊界條件——證明你的假定。28、學習一種文本操作語言?
Learn a Text Manipulation Language?
你用每天的很大一部分時間處理文本,為什么不讓計算機替你完成部分工作呢??
應用示例: - 數據庫schema維護;
- Java、C#屬性(Property)訪問;
- 測試數據生成。
?
29、編寫能編寫代碼的代碼?
Write Code That Writes Code?
代碼生成器能提高你的生產率,并有助于避免重復。30、你不可能寫出完美的軟件?
You Can't Write Perfect Software?
這刺痛了你?不應該。把它視為生活的公理,接受它,擁抱它,慶祝它。因為完美的軟件不存在。在計算機簡短的歷史中,沒有一個人曾經寫出過一個完美的軟件。你也不大可能成為第一個。除非你把這作為事實接受下來,否則你最終會把時間和精力浪費在追逐不可能實現的夢想上。31、通過合約進行設計?
Design with Contracts?
什么是正確的程序?不多不少,做它聲明要做的事情的程序。用文檔記載這樣的聲明,并進行校驗,是按合約設計(簡稱DBC)的核心所在。?
這里,強調的重點是在“懶惰”的代碼上:對在開始之前接受的東西要嚴格,而允諾返回的東西要盡可能少。?
使用DBC的最大好處也許是它迫使需求與保證的問題走到前臺來。在設計時簡單地列舉輸入域的范圍是什么、邊界條件是什么、例程允諾交付什么——或者,更重要的,它不允諾交付什么——是向著編寫更好的軟件的一次飛躍。不對這些事項作出陳述,你就回到了靠巧合編程,那是許多項目開始、結束、失敗的地方。32、早崩潰?
Crash Early?
死程序不說謊。?
當你的代碼發現,某件被認為不可能發生的事情已經發生時,你的程序就不再有存活能力。從此時開始,它所做的任何事情都會變得可疑,所以要盡快終止它。死程序帶來的危害通常比有問題的程序要小得多。33、如果它不可能發生,用斷言確保它不會發生?
If It Can't Happen,Use Assertions to Ensure That It Won't?
斷言驗證你的各種假定。在一個不確定的世界里,用斷言保護你的代碼。?
不要用斷言代替真正的錯誤處理。斷言檢查的是決不應該發生的事情。34、將異常用于異常的問題?
Use Exceptions for Exceptional Problems?
異常表示即使的、非局部的控制轉移——這是一種級聯的(cascading)goto。異常應保留給意外事件。那些把異常用作其正常處理的一部分的程序,將遭受所有可讀性和可維護性問題的折磨。這些程序破壞了封裝:通過異常處理,例程和它們的調用者被更緊密地耦合在一起。35、要有始有終?
Finish What You Start?
只要可能,分配某資源的例程或對象也應該負責解除其分配。36、使模塊之間的耦合減至最少?
Minimize Coupling Between Modules - 編寫“羞怯”的代碼;
- 函數的得墨忒耳(Demeter)法則規定,某個對象的任何方法都應該只調用屬于以下情形的方法:?
1)它自身;?
2)傳入該方法的任何參數;?
3)它創建的任何對象;?
4)任何直接持有的組件對象。 - 物理解耦。
?
37、要配置,不要集成?
Configure,Don't Integrate?
細節會弄亂我們整潔的代碼——特別是如果它們經常變化。把它們趕出代碼。當我們在與它作斗爭時,我們可以讓我們的代碼變得高度可配置和“軟和”——也就是,容易適應變化。?
要用元數據(metadata)描述應用的配置選項:調諧參數、用戶偏好(user preference)、安裝目錄,等等。38、將抽象放進代碼,細節放進元數據?
Put Abstractions in Code,Details in Metadata?
但我們不只是想把元數據用于簡單的偏好。我們想要盡可能多地通過元數據配置和驅動應用。我們的目標是以聲明方式思考(規定要做什么,而不是怎么做),并創建高度靈活和可適應的應用。我們通過采用一條一般準則來做到這一點:為一般情況編寫程序,把具體情況放在別處——在編譯的代碼庫之外。?
也許你在編寫一個具有可怕的工作流需求的系統。動作會根據復雜的(和變化的)商業規則啟動和停止。考慮在某種基于規則的系統(即專家系統)中對它們進行編碼,并嵌入到你的應用中。這樣,你將通過編寫規則、而不是修改代碼來配置它。39、分析工作流,以改善并發性?
Analyze Workflow to Improve Concurrency?
時間是軟件架構的一個常常被忽視的方面。時間有兩個方面對我們很重要:并發(事情在同一時間發生)和次序(事情在時間中的相對位置)。?
我們在編寫程序時,通常并沒有把這兩個方面放在心上。當人們最初坐下來開始設計架構,或是編寫代碼時,事情往往是線性的。那是大多數人的思考方式——總是先做這個,然后再做那個。但這樣思考會帶來時間耦合:方法A必須總是在方法B之前調用;同時只能運行一個報告;在接收到按鈕點擊之前,你必須等待屏幕重畫。“嘀”必須在“嗒”之前發生。?
這樣的方法不那么靈活,也不那么符合實際。?
我們需要容許并發,并考慮解除任何時間或者次序上的依賴。40、用服務進行設計?
Design Using Services?
實際上我們創建的并不是組件,而是服務——位于定義良好的、一致的接口之后的獨立、并發的對象。?
通過把你的系統架構成多個獨立的服務,你可以讓配置成為動態的。41、總是為并發進行設計?
Always Design for Concurrency?
首先,必須對任何全局或靜態變量加以保護,使其免于并發訪問,現在也許是問問你自己、你最初為何需要全局變量的好時候。此外,不管調用的次序是什么,你都需要確保你給出的是一致的狀態信息。?
在被調用時,對象必須總是處在有效的狀態中,而且它們可能會在最尷尬的時候被調用。你必須確保,在任何可能被調用的時刻,對象都處在有效的狀態中。這一問題常常出現在構造器與初始化例程分開定義的類中(構造器沒有使對象進入已初始化狀態)。?
一旦你設計了具有并發要素的架構,你可以靈活地處理應用的部署方式:單機、客戶-服務器、或是n層。42、使視圖與模型分離?
Separate Views from Models?
也就是常說的MVC模式(Model-View-Controller)。 - 模型。表示目標對象的抽象數據模型。模型對任何視圖或控制器都沒有直接的了解。
- 視圖。解釋模型的方式。它訂閱模型中的變化和來自控制器的邏輯事件。
- 控制器。控制視圖、并向模型提供新數據的途徑。?
通過松解模型與視圖/控制器之間的耦合,你用低廉的代價為自己換來了許多靈活性。?
43、用黑板協調工作流?
Use Blackboards to Coordinate Workflow?
用黑板協調完全不同的事實和因素,同時又使各參與方保持獨立和隔離。?
現代的分布式類黑板(blackboard-like)系統,比如JavaSpaces和T Spaces。44、不要靠巧合編程?
Don't Program by Coincidence - 總是意識到你在做什么。
- 不要盲目地編程。試圖構建你不完全理解的應用,或是使用你不熟悉的技術,就是希望自己被巧合誤導。
- 按照計劃行事。
- 依靠可靠的事物。如果你無法說出各種特定情形的區別,就假定是最壞的。
- 為你的假定建立文檔。“按合約編程”有助于澄清你頭腦中的假定,并且有助于把它們傳達給別人。
- 不要只是測試你的代碼,還要測試你的假定。
- 為你的工作劃分優先級。
- 不要做歷史的奴隸。不要讓已有的代碼支配將來的代碼。?
所以下次有什么東西看起來能工作,而你卻不知道為什么,要確定它不是巧合。?
45、估算你的算法的階?
Estimate the Order of Your Algorithms?
在你編寫代碼之前,先大致估算事情需要多長時間。46、測試你的估算?
Test Your Estimates?
對算法的數學分析并不會告訴你每一件事情。在你的代碼的目標環境中測定它的速度。47、早重構,常重構?
Refactor Early,Refactor Often?
在需要時對代碼進行重寫、重做和重新架構。要鏟除問題的根源。不要容忍破窗戶。?
關于重構,詳見Martin Fowler的《重構》一書。48、為測試而設計?
Design to Test?
在你還沒有編寫代碼時就開始思考測試問題。測試驅動開發?49、測試你的軟件,否則你的用戶就得測試?
Test Your Software,or Your Users Will?
測試是技術,但更是文化。一點預先的準備可以大大降低維護費用、減少客戶服務電話。50、不要使用你不理解的向導代碼?
Don't Use Wizard Code You Don't Understand?
向導很了不起。只需要點擊一個按鈕,回答一些簡單的問題,向導就會自動為你生成骨架代碼(skeleton code)。但如果你使用向導,卻不理解它制作出的所有代碼,你就無法控制你自己的應用。你沒有能力維護它,而且在調試時會遇到很大的困難。51、不要搜集需求——挖掘它們?
Don't Gather Requirements - Dig for Them?
需求很少存在于表面上。它們深深地埋藏在層層假定、誤解和政治手段的下面。52、與用戶一同工作,以像用戶一樣思考?
Work with a User to Think Like a User?
要了解系統實際上將如何被使用,這是最好的方法。開采需求的過程也是開始與用戶群建立和諧的關系、了解他們對你正在構建的系統的期許和希望的時候。53、抽象比細節活得更長久?
Abstractions Live Longer than Details?
“投資”于抽象,而不是實現。抽象能在來自不同的實現和新技術的變化的“攻擊”之下存活下去。54、使用項目詞匯表?
Use a Project Glossary?
如果用戶和開發者用不同的名稱指稱同一事物,或是更糟,用同一名稱指稱不同事物,這樣的項目很難取得成功。55、不要在盒子外面思考——要找到盒子?
Don't Think Outside the Box - Find the Box?
在遇到不可能解決的問題時,問問自己以下問題: - 有更容易的方法嗎?
- 你是在設法解決真正的問題,還是被外圍的技術問題轉移了注意力?
- 這件事情為什么是一個問題?
- 是什么使它如此難以解決?
- 它必須以這種方式完成嗎?
- 它真的必須完成嗎??
很多時候,當你設法回答這些問題時,你會有讓自己吃驚的發現。很多時候,對需求的重新詮釋能讓整個問題全部消失。?
你所需要的只是真正的約束、令人誤解的約束、還有區分它們的智慧。?
56、傾聽反復出現的疑慮——等你準備好再開始?
Listen to Nagging Doubts - Start When You're Ready?
你的一生都在積累經驗與智慧。當你面對一件任務時,如果你反復感覺到疑慮,或是體驗到某種勉強,要注意它。你可能無法準確地指出問題所在,但給它時間,你的疑慮很可能就會結晶成某種更堅實的東西,某種你可以處理的東西。軟件開發仍然不是科學。讓你的直覺為你的表演做出貢獻。57、對有些事情“做”勝于“描述”?
Some Things Are Better Done Than Described?
你應該傾向于把需求搜集、設計、以及實現視為同一個過程——交付高質量的系統——的不同方面。不要掉進規范的螺旋,在某個時刻,你需要開始編碼。58、不要做形式方法的奴隸?
Don't Be a Slave to Formal Methods?
如果你沒有把某項技術放進你的開發實踐和能力的語境中,不要盲目地采用它。59、昂貴的工具不一定能制作出更好的設計?
Expensive Tools Do Not Produce Better Designs?
小心供應商的炒作、行業教條、以及價格標簽的誘惑。在考察工具的產出時,試著不要考慮它值多少錢。60、圍繞功能、而不是工作職務進行組織?
Organize Around Functionality,Not Job Functions?
把你的人劃分成小團隊,分別負責最終系統的特定方面的功能。讓團隊按照個人的能力,在內部自行進行組織。?
但是,只有在項目擁有負責的開發者、以及強有力的項目管理時,這種途徑才有效。創立一組自行其是的團隊并放任自流,是一種災難性的處方。?
要記住,團隊是由個體組成的。讓每個成員都能以他們自己的方式閃亮。61、不要使用手工流程?
Don't Use Manual Procedures?
shell腳本或批處理文件會一次次地以同一順序執行同樣的指令。我們可以自動安排備份、夜間構建、網站維護、以及其他任何可以無人照管地完成的事情。讓計算機去做重復、庸常的事情——它會做得比我們更好。我們有更重要、更困難的事情要做。62、早測試,常測試,自動測試。?
Test Early.Test Often.Test Automatically.?
與呆在書架上的測試計劃相比,每次構建時運行的測試要有效得多。63、要等到通過全部測試,編碼才算完成?
Coding Ain't Done 'Til All the Tests Run?
就是這樣。64、通過“蓄意破壞”測試你的測試?
Use Saboteurs to Test Your Testing?
在單獨的軟件副本上故意引人bug,以檢驗測試能夠抓住它們。65、測試狀態覆蓋,而不是代碼覆蓋?
Test State Coverage,Not Code Coverage?
確定并測試重要的程序狀態。只是測試代碼行是不夠的。即時具有良好的代碼覆蓋,你用于測試的數據仍然會有巨大的影響,而且,更為重要的是,你遍歷代碼的次序的影響可能是最大的。66、一個bug只抓一次?
Find Bugs Once?
一旦測試員找到一個bug,這應該是測試員最后一次找到它。此后自動測試應該對其進行檢查。67、把英語當作又一種編程語言?
Treat English as Just Another Programming Language?
像你編寫代碼一樣編寫文檔:遵守DRY原則、使用元數據、MVC、自動生成,等等。68、把文檔建在里面,不要拴在外面?
Build Documentation In,Don't Bolt It On?
與代碼分離的文檔不太可能被修正和更新。使用像JavaDoc和NDoc這樣的工具,我們可以根據源碼生成API級的文檔。?
文檔和代碼是同一底層模型的不同視圖,但視圖是唯一應該不同的東西。69、溫和地超出用戶的期望?
Gently Exceed Your Users' Expectations?
要設法讓你的用戶驚訝。請注意,不是驚嚇他們,而是要讓他們高興。要理解用戶的期望,然后給他們的東西要多那么一點。給系統增加某種面向用戶的特性所需的一點額外努力將一次又一次在商譽上帶來回報。70、在你的作品上簽名?
Sign Your Work?
我們想要看到對所有權的自豪。“這是我編寫的,我對自己的工作負責。”你的簽名應該被視為質量的保證。當人們在一段代碼上看到你的名字時,應該期望它是可靠的、用心編寫的、測試過的和有文檔的,一個真正的專業作品,由真正的專業人員編寫。?
一個注重實效的程序員。
總結
- 上一篇: 『飞秋』Windows7新功能体验(1)
- 下一篇: 『飞秋』在ASP.NET服务器端过程中使