持續、小步前進纔是敏捷!——>開發輕鬆、快速;
編程思想和代碼結構
持續反饋+報告
先穩定再改良
每個迭代結束後,回顧:哪裏做的好,哪裏需要改進。
以身作則
小而可達到的目標會讓人全速前進。
在團隊中,修改東西必須很謹慎,要時刻警惕風險。
保證系統穩定。
先構建系統最初的、小的和有用的部分。挑選一系列小的功能,完成第一次交付。——客戶承擔的風險更低
做一個大致的評估,給出誤差範圍,解釋如何才能達到這個目標
將精力集中於一點
挑戰陌生的領域
基礎的重要性
好書讓你係統的學習技術
抓緊時間
優秀的程序是不斷重構的過程。
通過與人交流來鍛鍊自己的思維
學習是保證你以後路越走越寬的最佳手段。
依賴於單元測試。但價值不大的方法,不值得花費時間進行測試。單元測試只有在達到一定測試覆蓋率時才能真正發揮作用。
若不是真正需要它時,就不應該實現這個功能!
消除還沒有編寫的類,會簡化代碼;
任何一個設計都可以被改進。
實現特定功能的最低成本。
不同環境,就會有不同問題。
硬件比開發人員的時間便宜。要在多個平臺上測試,只要爲每個平臺設置持續集成系統就行了。
軟件在不同平臺上出現bug很可能是因爲棧佈局的差異、機器字大小端的不同所致。
現在對你顯而易見的事,對別人可能並非如此。註釋要說明爲什麼會這樣寫代碼。
細心選擇有意義的命名。
性能、成本、上市時間等,再軟件開發過程中都是至關重要的因素。若對任何單個因素獨斷強調,而不考慮其他因素,必然導致災難。
沒有適合所有狀況的最佳解決方案。必須對問題進行評估,選出最合適的解決方案。每個設計都是針對特定問題的。
粒度如果太細,也會失去實用價值。
面向對象的代碼讓別的對象去做事情。不要搶別的對象或組件的工作。告訴它做什麼
針對is-a關係使用繼承;針對has-a或uses-a關係使用組合。
通過替換代碼來擴展系統。通過替換遵循接口契約的類,來添加並改進功能特性。
不要試圖馬上了解系統的所有細節。若能隔離出發生問題的模塊,就更容易修復發生問題的代碼。
識別複雜問題的第一步,是將它們分離出來。只與最小數量的相關代碼發生關係,就可以更快發現問題的根源所在。
讓代碼可以測試!——>這樣代碼自然職責單一,耦合性低,可維護性高。
在解決問題時,要將問題域與其周邊隔離開。
以二分查找的方式來定位問題。將問題空間分爲兩半,看看哪一半包含問題。再將包含問題的一半進行二分,並不斷重複這個過程。
寫代碼時,要估計到會發生的問題。
處理或是向上傳播所有的異常。
記錄運行時調試日誌,當捕獲或是拋出異常時,都要記錄日誌信息。這樣做對以後的跟蹤工作很有幫助。
在調用方法時,一定要注意此方法是否有拋出異常。
代碼剛開發完,是尋找問題的最佳時機。放任不管,它不會變得更好。
代碼review,要尋找程序的bug,效果是任何已知形式測試的兩倍,而且是移除80%bug的唯一已知方法。
先寫大的框架(即先定格局),然後再寫細節。在很短的編輯——構建——測試循環中編寫代碼。
編寫代碼時,每天付出一點小的努力,避免代碼腐爛,保證應用程序不會變得難以理解和維護。
先做好設計,想清楚問題,再開始編碼。 設計及其代碼實現會不停地發展和變化。設計滿足實現即可,不必過於詳細。
在理解一個問題時,需要漸次的問5個以上的“爲什麼”。
不停問爲什麼。不能只滿足於別人告訴你的表面現象。要不停提問到你明白問題的根源。
我不知道是一個好的起點。應由此進行更進一步的調查。
在問“爲什麼”前,想好你提問的理由,這會有助於你問出恰當的問題。
若你自己都不清楚所談論的東西,就根本不可能精確描述它。
原則:
a、不管路走了多遠,錯了就要重新返回;
b、態度+習慣+平衡;
c、起步才能變得很出色
d、設定最終期限——沒有最好的方案,只有更合適的方案。
e、結果最重要
f、設計充滿了妥協
g、不僅要發現問題,更重要的是去解決它
h、只有一個人會爲你負責——你自己。能否跟上變化,完全取決於你自己。
i、唯有變化是永恆的
j、當必須要把工作切換到一種新的技術領域,你能做到!
k、不可能精通每一項技術。只要你在某些方面成爲專家,就能使用同樣的方法,很容易成爲新領域的專家。
l、要明白爲什麼需要這項新技術——它解決了什麼樣的問題?它可以被用在什麼地方?
m、總是要成爲你所在的那個對中最差的。若你是最好的,就需要重新選擇隊了。
n、爲了解決問題,需要很好的瞭解系統的全局。需要查看所有你認爲和問題相關的部分——即便其他人覺得這並不相關。
o、計劃是沒有價值的,但計劃的過程是必不可少的。
p、若目標很遙遠,就很難讓自己專注它。
q、最終期限會迫使你做艱難地決定。
r、一步行動,勝過千萬專家的意見
s、平衡以得到最佳的決策:
t、要經常提醒自己是否有方法寫出更易於理解的代碼。
u、代碼要清晰表達意圖——>可讀
v、讓團隊其他人讀自己一年前寫的代碼,是否可以讀一遍就知道它的運行機制。
w、真正的高性能系統,從一開始設計就在向這個方向努力。
x、開發的代碼必須即時反饋
y、保持系統靈活性的關鍵方式,是當新代碼取代原有代碼之後,其他已有的代碼不會意識到任何差別
z、單元測試強迫對代碼分層。因爲要保證代碼的可測試,就必須把它從周邊的代碼中解脫出來。
每個類按照下面的術語描述:
類名:
職責:它應該做什麼?
協作者:要完成工作它要與其他什麼對象一起工作?
高效程序員:
第一:激情,就是對你的工作感興趣.
第二:有很強的分析能力.
第三:高質量的編碼.
第四:快速的解決程序的問題.
第五:發散思維.
第六:團隊默契合作.
第七:相信總可以解決任何問題.
快速而可靠交付高質量軟件
短迭代開發,得到反饋(迭代一般是兩週的時間)、分解任務、站立會議、用戶參與、測試驅動、持續集成、自動部署(一鍵安裝)、定期回顧(持續改進)、持續學習
迭代:在小且重複的週期裏,完成各種開發任務:分析、設計、實現、測試和獲得反饋
通過反饋進行自我調整和完善。
白板、草圖等都是非常好的設計工具。複雜的建模工具只會讓你分散精力,而不是啓發你的工作。
1、In Action
(1)態度:專業的態度;
項目需要什麼你就做什麼;
反饋是敏捷的基礎;
出了問題,最高優先級應該是解決問題;
若你沒有犯過任何錯誤,就說明你可能沒有努力工作。
探究問題的根源,想明白會產生什麼其他影響。
讓團隊成員花些時間閱讀其他同事寫的代碼,能確保代碼是可讀和可理解的。
單元測試能幫助你自然地把代碼分層,分層很多可管理的小塊,這樣就會得到設計更好、更清晰的代碼。單元測試就是一份文檔,讓你理解代碼。
也許不知道每塊代碼的每個細節,或者每個算法的每個步驟,但要對整體的相關知識有很好的瞭解,理解它是如何工作的。
深入瞭解你正在開發的代碼外,還需要從更高的層面瞭解大部分代碼的功能,這樣就可以理解系統各個功能塊之間是如何交互的。
權衡觀點本身的利弊,表達自己的觀點。
融合各種不同的想法和觀點,遠遠勝於單個想法爲項目帶來的價值。
評判那些場景發生的可能性有多大。
用合適的詞和理由去解釋爲什麼你不贊同這個方案,並提出明確的問題。
解釋清楚自己的理由
業務領域的底層數據模型
代碼令人費解,唯一的解決方法是重構代碼
(2)學習
許多新技術都是基於現有的技術和思想。但會加入一些新的東西,這些新東西是逐步加入的。——要跟蹤技術變化。
有很多方法和工具可以幫助我們繼續充電:
a、迭代和增量式的學習
每天計劃用一段時間來學習新技術,要經常進行。
記下你想學習的東西——聽到一些不熟悉的術語或短語時,記下來,在計劃的時間中去研究。
b、瞭解最新行情
閱讀社區討論,瞭解他人遇到的問題以及一些好的解決方案。
選擇好的技術博客,去讀讀。(pragmaticprogrammer.com)
c、閱讀
關於軟件開發和非技術主題的好書。
不需要精通所有技術,但要清楚知道行業的動向,從而規劃你的項目和職業生涯。
要正確把握自己投入的精力。許多新想法並沒有成爲有用的技術。
不要因爲想學習而將應用切換到新的技術、框架或開發語言。必須先評估新技術的優勢。開發一個小的原型系統。
學習新的技術和新的開發方法。舉一反三,靈活應用。
現在開發者的時間纔是最昂貴的資源。
學習一門新的語言,應該使用推薦的集成開發環境。對於所使用的語言,要總結熟悉的語言特性。
對團隊投資:給大家介紹一些概念,演示工具等,提供應用程序示例。
整個團隊都要了解新技術,並如何使用它。討論與應用相關的一般主題。
爲了解決問題,你需要知道許多可能的影響因素。
如何有效提問?
(3)編碼——易於理解、擴展和維護。讓代碼簡單。——>代碼整潔、擴展性好
代碼要有表達力——>做了什麼;要經常提醒自己是否有方法寫出更易於理解的代碼。
增量式編程;
註釋是爲了幫寫得不好的代碼補漏。
把握開發節奏:首先解決困難的問題,把簡單的問題留到最後;防止所有事情同時發生。
軟件項目需要不停地前進,同時要清楚自己的真實進度。
確保每個迭代週期的時間相同。
在每天結束時,測試代碼,提交代碼。
以固定、有規律的長度進行迭代。
當與其他團隊合作時,需要減慢開發節奏。
對代碼進行檢查,防止它們變成龐然怪物。
良好的面向對象設計原則建議:
編寫內聚的代碼,保持邏輯清晰。通過設計能夠根據契約進行替換,以保持代碼的靈活性。
若沒人理解一段代碼的工作方式,這段代碼沒用!
代碼清晰程度的優先級比執行效率高!因爲閱讀代碼的次數要遠遠超過編寫的次數。
首先理解代碼做了什麼,如何做的?然後,搞清楚將要改變哪些部分,最後開始修改並測試。
通過指定一個外部對象來進行同步操作;
編寫代碼,要使用語言特性來提升表達力。使用方法名傳達意圖,參數的命名要幫助讀者理解背後的想法。
異常傳達的信息是哪些可能會出問題,如何進行防禦式編程,要正確使用和命名異常。好的編碼規範可以讓代碼變得易於理解。
變量名清楚、邏輯分離清晰、表達式簡潔
方法要說明下列信息:
a、目的:做什麼的;
b、前置條件:需要什麼樣的輸入;
c、後置條件:有哪些返回值;
d、異常:會發生什麼樣的問題?會拋出什麼異常?
性能、成本、便利性、上市時間等,再軟件開發過程中都是至關重要的因素。若對任何單個因素獨斷強調,而不考慮其他因素,必然導致災難。
降低開發成本和縮短上市時間,二者一樣重要。
有的關注界面展示,有的關注性能,應諮詢相關人員,讓他們決定應將重點放在哪裏。
沒有適合所有狀況的最佳解決方案。必須對問題進行評估,選出最合適的解決方案。每個設計都是針對特定問題的。
要確認投入是否有回報。
增量式開發——所開發的代碼基於即時的反饋。關鍵在於持續做一些細小而有用的事情,而不是做一段長時間的編程或重構。
在很短的編輯——構建——測試循環中編寫代碼。在代碼沒有得到即時反饋時,不會再繼續編寫代碼。
要經常重構測試。
保持簡單:
開發人員應爲自己能夠創建出一個簡單且可用的設計而驕傲。
在用設計模式前,先問問自己,是不是特定的問題需要你使用這個解決方案。不要讓自己進行過分設計。
簡單不是業餘、能力不足。
優雅的代碼,一眼看上去就知道它的用處,而且很簡潔。
一個好的設計會讓人覺得很舒服。若覺得什麼地方不對,就好好想想是哪裏出了問題。
開發可以工作的、最簡單的解決方案——必須滿足功能需求。
編寫的代碼沒有一行多餘的。
代碼總是可以得到進一步精煉,但到了某個點後,再做改進就不會帶來任何實質性的好處了。
內聚性用來評估一個組件(包、模塊)中成員的功能相關性。內聚程度高,表示各個成員共同完成了一個功能特性或一組功能特性。
類也要遵循內聚性。
職責單一——>內聚性一定高
粒度如果太細,也會失去實用價值。
告知,不要詢問——命令與查詢相分離的模式,即將方法分爲命令和查詢兩類。命令可能會改變對象的狀態,有可能返回值。查詢僅僅提供對象的狀態,不會修改。
面向對象的代碼讓別的對象去做事情。不要搶別的對象或組件的工作。告訴它做什麼,然後盯着你自己的職責就好了。
要保證查詢沒有副作用。
根據契約進行替換:
保持系統靈活性的關鍵方式,是當新代碼取代原有代碼之後,其他已有的代碼不會意識到任何差別。
Liskov替換原則:任何繼承後得到的派生類對象,必須可以替換任何被使用的基類對象,而且使用者不必知道任何差異。即某段代碼如果使用了基類中的方法,就必須能使用派生類的對象,並且自己不必進行任何修改。
當使用繼承時,想想派生類是否可以替換基類。若不能,就要問問自己爲什麼要使用繼承。
如何讓代碼易於理解?——明白告訴閱讀代碼的人,代碼做了什麼。
(4) 敏捷協作
準備好後再共享代碼:提交的文件應該與一個特定的任務或一個bug解決相關。絕不要提交尚未完成的代碼。應該頻繁提交代碼。
讓團隊中的成員一起朝着正確方向努力。
定期安排會面時間。面對面的會議是最有效的溝通方式。
實行代碼集體所有制,以保證任何團隊成員的缺席不會對項目造成影響。
團隊中每個人都要提供技能,推進各自的職業發展。
允許大家自己想辦法
和團隊成員一起做代碼review
及時通報進展與問題,讓大家瞭解彼此的進度和遇到的問題。不要等着別人來問項目狀態如何。
站立會議——保證會議快速進行;一般在大家到公司之後的半個小時到一個小時之內舉行。最長不超過30分鐘。
每個人回答三個問題:
a、昨天有什麼收穫?
b、今天計劃要做哪些工作?
c、面臨哪些障礙?
把要解決的問題記下來。
通過促進代碼和思路的共享,來提升開發速度。
在會議中要給出具體的進度。
一個設計要解決的是眼前面臨的特定問題。隨着設計的實現,對問題的理解也會發生改變。
在開始實現之前,就做出一個很有效的詳細設計非常困難。因爲沒有足夠的上下文,能得到的反饋非常少。
作爲設計人員,若不能理解系統的具體細節,就不可能做出有效的設計。
新系統的設計者必須要親自投入到實現中。
架構師應指導開發團隊,提升他們的水平,以解決更爲複雜的問題。
程序員在拒絕設計的同時,也就放棄了思考。不要進行單獨設計。
增強可逆性是注重實效的軟件實現方式的關鍵構成部分。
在團隊中實現任務輪換制,讓每個成員都可以接觸到不同部分的代碼,可以提升團隊整體的知識和專業技能。
在試圖理解代碼時,要問些有用的問題,對問題領域深入理解。
共享知識,讓團隊的人變得更好。
好的想法不會因爲被許多人瞭解而削弱。
當別人提出問題時,可以發現不同的角度。
遇到無法回答的問題,說明這個領域的知識不夠完善,需要在這一方面進一步增強。
分享自己的知識、經驗和體會。
指導別人,也是提升自己。
若一直在就同一個主題向不同的人反覆闡述,不如就此主題寫一篇文章或一本書。
告訴團隊成員解決問題的方法,也要知道如何解決問題的思路。
用問題來回答問題。
代碼剛開發完,是尋找問題的最佳時機。放任不管,它不會變得更好。
代碼review,要尋找程序的bug,效果是任何已知形式測試的兩倍,而且是移除80%bug的唯一已知方法。
在簽入代碼之前,有另一名開發人員對代碼進行徹底的複查。
code review要檢查的最基本的問題列表:
a、代碼是否能被讀懂和理解?
b、是否有明顯的錯誤?
c、代碼是否會對應用的其他部分產生不良影響;
d、是否存在重複的代碼
e、是否存在可以改進或重構的部分?
複查所有的代碼。要讓不同的開發人員在每個任務完成後複查代碼。
code review要積極評估代碼的設計和清晰程度。
可以讓某段代碼明確變得更好
跟進給出的建議
有問題要趁早提出來,給機會讓人找出解決方案;
及時
(5)反饋
如何獲得反饋?如何更好控制團隊進程和性能?
時間也是一個非常重要的反饋。——爲任務設定一個最終期限。
通過演示獲得頻繁反饋。增量發佈來發布新功能。——要讓客戶感覺到在一定程度上控制項目的方向。
給客戶演示所完成功能的時間與得到客戶需求的時間間隔越長,你就會離最初需求越來越遠!
對得到的反饋,如建議、bug修復、功能增強、變更要求等信息,要有一個跟蹤系統記錄這些信息。
人的本性——當開始使用新系統的部分功能時,才意識到它的影響和可能發生的問題。
維護項目術語表——幫助你和用戶進行溝通。在項目開發中,從術語表中爲類、方法、變量選擇合適的名字。
確保代碼不會變壞
設計良好的API
編寫能產生反饋的代碼——>單元測試,單元測試能確保你不破壞任何功能;單元測試有用的設計工具;單元測試是可靠的文檔;
語言都有對應的單元測試框架
確保測試可重複;
測試邊界條件;
不要放過任何一個失敗的測試;
先使用再實現:
先寫測試,你就會站在用戶的角度來思考——>可以設計一個更好的接口,並能幫助你改進設計;
好的設計不表示需要更多的類。
添加無用代碼總是不好的想法。
專注於設計接口
實現特定功能的最低成本
關鍵業務邏輯要獨立測試。
判斷工作進度最好是看實際花費的時間而不是估計的時間。
在你最後真正完成一項任務時,要清楚知道完成這個任務真正花費的時間。 這樣爲下次評估作參考。
讓下一步工作可見——待辦事項。確定優先級。
評估那些需要完成的待辦事項。
關注功能,而不是日程表;
以一週作爲時間單元,粒度太粗了。
傾聽用戶的聲音:沒有愚蠢的用戶。
系統要有詳細的錯誤提示信息。
要和真實用戶進行交談,耐心傾聽。
每一個抱怨的背後都隱藏了一個事實。找出背後真正的問題,解決問題。
若代碼問題解決不了,可以考慮通過修改文檔或培訓來彌補。
(6)調試
如何提高調試效率,節省開發時間?
要想有效重用你的知識,記錄問題解決日誌。
應報告所有的異常。
在出錯時,要考慮用戶的感受,必須提供有用的錯誤信息。 ——提供更易於查找錯誤細節的方式。但不要讓用戶陷入其中。
編譯警告就是錯誤。簽入構建工具中的代碼不應該產生任何警告信息。
在eclipse中,windows-preferences-java-compile-errors/warnings,修改警告的報告級別。
移除被棄用的方法。
必須要處理所有的異常。若可以,從失敗中恢復最好,若不能處理,就要把異常傳播給方法的調用者。
編程時,要想想出現問題時——即事情沒有按計劃進行時,會發生什麼。
不是所有的問題都應該拋出異常。
決定由誰來負責處理異常是設計工作的一部分。
拋出的異常應該在代碼的上下文中有實際意義。
記錄運行時調試日誌,當捕獲或是拋出異常時,都要記錄日誌信息。這樣做對以後的跟蹤工作很有幫助。
沒有人願意調用拋出31種不同檢查異常的方法。
程序使用時,仍然會發生很多的問題,如與數據庫服務器之間的連接可能丟失等。
當發生問題時,讓應用詳細記錄錯誤的相關數據。
錯誤提示信息要易於理解,要有助於定位錯誤。
當應用進入生產系統,就不能把一些底層錯誤信息(幫助開發人員錯誤定位的信息)直接暴露給用戶了。
錯誤報告、調試信息非常重要,不要輕易將其丟棄。因爲有助於解決問題,當問題發生時,可以詳細研究問題的細節描述和發生上下文。
沒有必要等待拋出異常來發現問題。在代碼關鍵點使用斷言來保證一切正常。當斷言失敗時,要提供與異常報告同樣詳細的信息。
(7)交付用戶想要的軟件
創建符合用戶需求的系統。
最大的敵人是變化。
設計是軟件開發的基礎。
確保在項目中引入合適的技術。——在考慮引入新技術或框架之前,先要把你需要解決的問題找出來。
然後問自己:
這個技術框架能解決這個問題嗎?——先做一個小的原型;
維護成本是多少?
不要開發你能下載到的東西,將更多精力放到具體應用的開發中。
根據需要選擇技術。對任何要使用的技術,多問一些挑剔的問題,並如實回答。
每一門技術都會有優點和缺點。
保持項目隨時可以發佈——讓項目一直處於可運行的穩定狀態。
提交代碼前,先本地測試,然後check out,最後check in。
代碼集成是主要的風險。爲了降低集成新代碼帶來的破壞性變化,需要提早集成、頻繁集成。
持續集成系統就是在後臺不停檢出、構建和測試代碼的應用。
提早實現自動化部署。——要測試安裝過程。
在設計方面,開發者做決定。但不要給業務上的關鍵問題做決定。
開發者及項目經理能做的一個最重要的決定就是:判斷哪些是自己決定不了的,應該讓用戶決定。
遇到一個問題,會影響到系統的行爲或者如何使用系統,把這個問題告訴業務負責人。
和客戶討論問題,要從業務的角度,介紹每種方案的優缺點,以及潛在的成本和利益。
記錄客戶做出的決定,並註明原因。
對於業務人員,若問題對業務沒有影響,就是沒有價值的。
實現代碼時要考慮可能出現的變化。
設計能幫助你理解系統的細節,理解部件和子系統之間的關係,並且指導你的實現。用UML畫關鍵工作圖必不可少,要使用類及其交互關係來描繪系統是如何組織的。
在做設計時,需要花時間去思考各種不同選擇的缺陷和益處,以及如何做權衡。
好的設計?——若需求有了小的變化,它仍然容易去實現,那麼就是好的設計。若小的需求變化就帶來一大批基礎代碼的破壞,那麼設計就需要改進。
好的設計應該是正確的,而不是精確的。它描述的一切必須是正確的,不應該涉及不確定或可能會發生變化的細節。
短迭代開發,增量發佈:
迭代:在小且重複的週期裏,完成各種開發任務:分析、設計、實現、測試和獲得反饋。
統一過程和敏捷方法都使用迭代和增量開發。
大部分用戶都是希望現在就有一個夠用的軟件。確定產品可用的核心功能,越早交到用戶越好!不要爲所有可能需要的華麗功能而分心,不要沉迷於你的想象,做一些華而不實的用戶界面。
迭代不必緊挨着下一個迭代!
大系統分解爲一塊塊有用的小系統。
若發佈的功能背離了用戶的需要,多半是因爲迭代的週期太長了!
業務應用
(8)
2、TIPS
(1)編碼沒有結束。
重構:在功能不變的情況下,重新設計部分代碼,改善代碼質量。
(2)
3、PS
(1)敏捷工具箱
wiki:實現知識共享;
版本控制:項目開發中所有的產物——源代碼、文檔、構建腳步等都需要放入版本控制系統中;
單元測試:是開發者獲得反饋的主要來源。
自動構建:又稱爲持續集成。構建是全自動化並可重複的。
(2)