基本方法用下劃線隔開的方式程序員
類名用大駝峯web
變量用小寫算法
路徑變量大寫數據庫
1. 一切代碼與註釋都是有實際意義的,沒有冗餘,整潔乾淨
2. 代碼能經過全部測試,運行高效
3. 命名名副其實,區分清晰,意義明瞭,儘可能作到看名字就能知道你的意圖
4. 代碼邏輯儘可能直白,簡單
5. 每一個方法只作一件事,功能明確且單一,方法間井井有條
6. 每一個類職責儘可能單一,高內聚,類與類之間低耦合
7. 測試覆蓋面廣,每一個測試用例基本只測一個點
8. 測試代碼的要求與業務代碼同樣高編程
整潔代碼的一些特徵安全
代碼邏輯應該直接了當,叫缺陷難以隱藏;數據結構
儘可能減小依賴關係,使之便於維護;多線程
依據某種分層戰略完善錯誤處理代碼;架構
性能調至最優,免得引誘別人作沒規矩的優化,搞出一堆混亂來;併發
整潔的代碼只作好一件事;
有單元測試和驗收測試;
有意義的命名;
儘可能「少」;
兩條重要原則:
儘可能讓代碼易讀,開發時減小讀的時間。
童子軍軍規:「讓營地比你來時更乾淨」。
名副其實
避免誤導
1.程序員必須避免留下掩藏代碼本意的錯誤線索,應當避免使用與本意相悖的詞
2.以一樣的方式拼寫出一樣的概念纔是信息,拼寫先後不一致就是誤導
3.要注意使用小寫字母i和大寫字母O做爲變量名,看起來像「壹」和「零」
作有意義的區分
1.不一樣東西意義不同時,必定要在命名上區分,如變量,不要簡單的cat1,cat2這樣區分
命名讀得出來,單詞可搜索
避免使用編碼
1.不要亂用前綴
避免思惟映射
1.明確是王道,不要讓人須要想象或者產生聯想
類名是名詞或名詞短語,方法名是動詞或者動詞短語
別扮可愛
別用雙關語
1.避免將同一單詞用於不一樣目的
2.應盡力寫出易於理解的代碼,把代碼寫得讓別人能一目盡覽而沒必要殫精竭慮地研究
使用解決方案領域名稱,使用源自所涉問題領域的名稱
添加有意義的語境
1.你須要用有良好命名的類、函數或名稱空間來放置名稱,給讀者提供語境
2.若是沒這麼作,給名稱添加前綴就是最後一招了
不要添加沒用的語境
1.只要短名稱足夠清楚,就要比長名稱好
最後的話
1.取好名字最難的地方在於須要良好的描述技巧和共有文化背景
短小,只作一件事
每一個函數一個抽象層級
1.要確保函數只作一件事,函數中的語句都要在同一抽象層級上
2.自頂向下讀代碼:向下規則,讓代碼擁有自頂向下的閱讀順序,讓每一個函數後面都跟着下一抽象層級的函數,這樣一來,在看函數列表時,就能循抽象層級向下閱讀了,我把這叫作向下規則
switch語句
1.儘可能隱藏switch,不要暴露
使用描述性的名稱
1.沃德原則:「若是每一個例程都讓你感到深合已意,那就是整潔代碼」
2.函數越短小,功能越集中,就越便於取個好名字
3.別懼怕長名稱,長而具備描述性的名稱,要比短而使人費解的名稱好
4.命名方式要保持一致。使用與模塊名一脈相承的短語、名詞和動詞給函數命名
函數參數
1.最理想的參數數量是零,有足夠的理由才能用三個以上參數
2.事件:在這種形式中,有輸入參數而無輸出參數,程序將函數看做一個事件,使用該參數修改系統狀態
3.對於轉換,使用輸出參數而非返回值使人迷惑,若是函數要對輸入參數進行轉換操做,轉換結果就該體現爲返回值
4.向函數傳入布爾值會使方法簽名馬上變得複雜起來,大聲宣佈函數不止作一件事
5.若是函數看來須要兩個、三個或三個以上參數,就說明其中一些參數應該封裝爲類了
6.有可變參數的函數多是一元、二元甚至三元,超過這個數量就可能要犯錯了
7.對於一元函數,函數和參數應當造成一種很是良好的動詞/名詞對形式
無反作用
1.函數承諾只作一件事,但仍是會作其餘被藏起來的事,會致使古怪的時序性耦合及順序依賴
2.參數多數會被天然而然地看做是函數的輸入
分隔指令與詢問
1.函數要麼作什麼事,要麼回答什麼事,但兩者不可得兼
使用異步替代返回錯誤碼
1.從指令式函數返回錯誤碼輕微違反了指令與詢問分隔的規則。它鼓勵了在if語句判斷中把指令看成表達式使用
2.try/catch代碼塊把錯誤處理與正常流程混爲一談,最好把try和catch代碼塊的主體部分抽離出來,另外造成函數
3.錯誤處理就是一件事,處理錯誤的函數不應作其餘事
4.依賴磁鐵(dependency magnet):其餘許多類都得導入和使用它,如一些錯誤碼枚舉類
別重複本身
結構化編程
1.函數中的每一個代碼塊都應該只有一個入口和一個出口
2.儘可能少使用break,continue,不能用goto
如何寫出這樣的函數
1.打磨代碼,分解函數、修更名稱、消除重複
2.縮短和從新安置方法、拆散類、保持測試經過
1.若編程語言足夠有表達力,就不須要註釋
2.註釋的恰當用法是彌補咱們在用代碼表達意圖時遭遇的失敗。註釋老是一種失敗
3.程序員應當負責將註釋保持在可維護、有關聯、精確的高度,更應該把力氣用在寫清楚代碼上,直接保證無須編寫註釋
4.不許確的註釋要比沒註釋壞得多
註釋不能美化糟糕的代碼
用代碼來闡述
格式的目的
1.代碼格式關乎溝通,而溝通是專業開發者的頭等大事
垂直格式
1.經過間隔來區分邏輯模塊
橫向格式
1.適當對齊,間隔
團隊規則
1.一組開發者應當認同一種模式風格,每一個成員都應該採用那種風格
2.好的軟件系統是由一系列讀起來不錯的代碼文件組成的,須要擁有一致和順暢的風格
數據、對象的反對稱性
1.過程式代碼難以添加新的數據結構,由於這要修改全部相關函數;面向對象代碼難以添加新函數,由於要修改全部相關類
得墨忒耳律
1.得墨忒耳律(The Law of Demeter):模塊不該瞭解它所操做對象的內部情形,意味着對象不該經過存取器曝露其內部結構,由於這樣更像是曝露而非隱藏其內部結構
2.混合結構,一半是對象,一半是數據結構,應避免這種結構
數據傳送對象
1.最爲精練的數據結構,是一個只有公共變量、沒有函數的類,這種被稱爲數據傳送對象,或DTO(Data Transfer Objects)。在與數據庫通訊、或解析套接字傳遞的消息之類場景中存在。
2.JavaBean或Active Record
3.不要塞進業務規則方法,把Active Record當作數據結構。建立包含業務規則、隱藏內部數據(可能就是Active Record的實體)的獨立對象。
錯誤處理很重要,但若是它搞亂了代碼邏輯,就是錯誤的作法
使用異常而非返回碼
1.遇到錯誤時,最好拋出一個異常。調用代碼很整潔,其邏輯不會被錯誤處理搞亂
先寫Try-Catch-Finally語句
1.異常的妙處之一是,它們在程序中定義了一個範圍。執行try-catch-finally語句中try部分的代碼時,你是在代表可隨時取消執行,並在catch語句中接續
2.在某種意義上,try代碼塊就像是事務,catch代碼塊將程序維持在一種持續狀態
3.在編寫可能拋出異常的代碼時,最好先寫try-catch-finally語句,能幫你定義代碼的用戶應該期待什麼,不管try代碼塊中執行的代碼出什麼錯都同樣
使用不可控異常
1.可控異常,就是指在方法簽名中標註異常。但有時候會產生多層波及,有時候你對較底層的代碼修改,可能會波及不少上層代碼
給出異常發生的環境說明
1.拋出的每一個異常,都應當提供足夠的環境說明,以便判斷錯誤的來源和處所
2.應建立信息充分的錯誤消息,並和異常一塊兒傳遞出去
依調用者須要定義異常類
1.自定義的異常類最重要的考慮是它們如何被捕獲
2.將第三方API打包是個良好的實踐手段,下降了對每一個第三方的依賴,也有助於模擬第三方調用,並將一些複雜的異常捕獲過程封裝
定義常規流程
1.特例模式(SPECIAL CASE PATTERN,[Fowler]),建立一個類或配置一個對象,用來處理特例,異常行爲被封裝到特例對象中
儘可能別返回null值,也別傳遞null值
使用第三方代碼
1.第三方程序包和框架提供者追求普適性,這樣就能在多個環境中工做,吸引普遍的用戶
2.咱們建議不要將Map(或在邊界上的其餘接口)在系統中傳遞,把它保留在類或近親類中,避免從API中返回邊界接口,或將接口做爲參數傳遞給公共API
學習性測試的好處不僅是免費
1.學習性測試毫無成本,編寫測試是得到這些知識(要使用的API)的容易而不會影響其餘工做的途徑
2.學習性測試確保第三方程序包按照咱們想要的方式工做
使用尚不存在的代碼
編寫咱們想獲得的接口,好處之一是它在咱們控制之下,有助於保持客戶代碼更可讀,且集中於它該完成的工做
整潔的邊界
1.邊界上的改動,有良好的軟件設計,無需巨大投入和重寫便可進行修改
2.邊界上的代碼須要清晰的分割和定義了指望的測試。依靠你能控制的東西,好過依靠你控制不了的東西,省得往後受它控制
3.可使用ADAPTER模式將咱們的接口轉換爲第三方提供的接口
TDD三定律
1.在編寫能經過的單元測試前,不可編寫生產代碼(測試先行)
2.只可編寫恰好沒法經過的單元測試,不能編譯也算不經過(測試一旦失敗,開始寫生產代碼)
3.只可編寫恰好足以經過當前失敗測試的生產代碼(老測試一旦經過,返回寫新測試)
測試先行的一大好處:
若是先寫測試,必然得知道輸入是什麼,指望輸出的是什麼。這樣就不斷促進思考該如何獲得這樣的輸出,即把設計代碼也放入了測試前期的準備中。
保持測試整潔
1.髒測試等同於沒測試,測試必須隨生產代碼的演進而修改,測試越髒,就越難修改
2.測試代碼和生產代碼同樣重要,它須要被思考、被設計和被照料,它該像生產代碼通常保持整潔
3.若是測試不能保持整潔,你就會失去它們,沒有了測試,你就會失去保證生產代碼可擴展的一切要素
整潔的測試
1.三個要素:可讀性、可讀性和可讀性,明確、簡潔還有足夠的表達力
2.構造-操做-檢驗(BUILD-OPERATE-CHECK)模式,第一個環節構造測試數據,第二個環節操做測試數據,第三個部分檢驗操做是否獲得指望的結果
3.守規矩的開發者也將他們的測試代碼重構爲更簡潔和具備表達力的形式
每一個測試一個斷言
1.JUnit中每一個測試函數都應該有且只有一個斷言語句
2.最好的說法是單個測試中的斷言數量應該最小化
3.更好一些的規則或許是每一個測試函數中只測試一個概念
4.最佳規則是應該儘量減小每一個概念的斷言數量,每一個測試函數只測試一個概念
F.I.R.S.T
1.快速(Fast)測試應該夠快
2.獨立(Independent)測試應該相互獨立
3.可重複(Repeatable)測試應當可在任何環境中重複經過
4.自足驗證(Self-Validating)測試應該有布爾值輸出,本身就能給出對錯,而不須要經過看日誌,比對結果等方式驗證
5.及時(Timely)測試應及時編寫
類的組織
1.類應該從一級變量列表開始,若是有公共靜態變量,應該先出現,而後是私有靜態變量,以及實體變量,不多會有公共變量
2.公共函數應該跟在變量列表以後
3.保持變量和工具函數的私有性,但並不執着於此
類應該短小
1.職責單一,類的名稱應當描述其權責,若是沒法爲某個類命以精確的名稱,這個類大概就太長了,類名越含混,該類越有可能擁有過多權責;類或模塊應有且只有一條加以修改的理由
2.內聚性強,方法操做的變量越多,就越黏聚到類上,若是一個類的每一個變量都被每一個方法所使用,則該類具備最大的內聚性
3.保持函數和參數列表短小的策略,有時會致使爲一組子集方法所用的實體變量數量增長。出現這種狀況時,每每意味着至少有一個類要從大類中掙扎出來。你應當嘗試將這些變量和方法分拆到兩個或多個類中,讓新的類更爲內聚
4.將大函數拆爲許多小函數,每每也是將類拆分爲多個小類的時機
爲了修改而組織
1.在整潔的系統中,咱們對類加以組織,以下降修改的風險
2.開放-閉合原則(OCP):類應當對擴展開放,對修改封閉
3.在理想系統中,咱們經過擴展系統而非修改現有代碼來添加新特性
4.依賴倒置原則(Dependency Inversion Principle,DIP),類應該依賴於抽象而不是依賴於具體細節
如何建造一個城市
1.每一個城市都有一組人管理不一樣的部分,有人負責全局,其餘人負責細節
2.深化出恰當的抽象等級和模塊,好讓我的和他們所管理的「組件」即使在不瞭解全局時也能有效地運轉
將系統的構造與使用分開
1.構造與使用是很是不同的過程
2.軟件系統應將啓始過程和啓始過程以後的運行時邏輯分離開,在啓始過程當中構建應用對象,也會存在互相纏結的依賴關係
3.將構造與使用分開的方法之一是將所有構造過程搬遷到main或被稱爲main的模塊中,設計系統的其他部分時,假設全部對象都已正確構造和設置
4.可使用抽象工廠模式讓應用自行控制什麼時候建立對象,但構造的細節卻隔離於應用程序代碼以外
5.控制反轉將第二權責從對象中拿出來,轉移到另外一個專一於此的對象中,從而遵循了單一權責原則。在依賴管理情景中,對象不該負責實體化對自身的依賴,反之,它應當將這份權責移交給其餘「有權力」的機制,從而實現控制的反轉
擴容
1.「一開始就作對系統」純屬神話,反之,咱們應該只去實現今天的用戶故事,而後重構,明天再擴展系統、實現新的用戶故事,這就是迭代和增量敏捷的精髓所在。測試驅動開發、重構以及它們打造出的整潔代碼,在代碼層面保證了這個過程的實現
2.軟件系統與物理系統能夠類比。它們的架構均可以遞增式的增加,只要咱們持續將關注面恰當地切分
3.持久化之類關注面傾向於橫貫某個領域的自然對象邊界
Java代理
純Java AOP框架
AspectJ的方面
測試驅動系統架構
1.經過方面式(AOP)的手段切分關注面的威力不可低估。假使你能用POJO編寫應用程序的領域邏輯,在代碼層面與架構關注面分離開,就有可能真正地用測試來驅動架構
2.不必先作大設計(Big Design Up Front,BDUF),BDUF甚至是有害的,它阻礙改進,由於心理上會抵制丟棄即成之事,也由於架構上的方案選擇影響到後續的設計思路
3.咱們能夠從「簡單天然」但切分良好的架構開始作軟件項目,快速交付可工做的用戶故事,隨着規模的增加添加更多基礎架構
4.最佳的系統架構由模塊化的關注面領域組成,每一個關注面均用純Java(或其餘語言)對象實現,不一樣的領域之間用最不具備侵害性的方面或類方面工具整合起來,這種架構能測試驅動,就像代碼同樣
優化決策
1.模塊化和關注面切分,成就了分散化管理和決策
2.延遲決策至最後一刻也是好手段,它讓咱們可以基於最有可能的信息作出選擇
3.擁有模塊化關注面的POJO系統提供的敏捷能力,容許咱們基於最新的知識作出優化的、時機恰好的決策,決策的複雜性也下降了
明智使用添加了可論證價值的標準
1.有了標準,就更易複用想法和組件、僱用擁有相關經驗的人才、封裝好點子,以及將組件鏈接起來。不過,創立標準的過程有時卻漫長到行業等不及的程度,有些標準沒能與它要服務的採用者的真實需求相結合
系統須要領域特定語言
1.領域特定語言(Domain-Specific Language, DSL)是一種單獨的小型腳本語言或以標準語言寫就的API,領域專家能夠用它編寫讀像是組織嚴謹的散文通常的代碼
2.領域特定語言容許全部抽象層級和應用程序中的全部領域,從高級策略到底層細節,使用POJO來表達
經過迭進設計達到整潔目的
簡單規則:
* 經過全部測試
* 不可重複
* 表達了程序員的意圖
* 儘量減小類和方法的數量
* 以上規則按其重要程序排列
簡單設計原則2~4:重構
1.有了測試,就能保持代碼和類的整潔,方法就是遞增式地重構代碼
2.測試消除了對清理代碼就會破壞代碼的恐懼
不可重複
表達力
儘量少的類和方法
爲何要併發
1.併發是一種解耦策略,它幫助咱們把作什麼(目的)和什麼時候(時機)作分解開
2.解耦目的與時機能明顯地改進應用程序的吞吐量和結構
3.單線程程序許多時間花在等待web套接字I/O結束上面,經過採用同時訪問多個站點的多線程算法,就能改進性能
常見的迷思和誤解
* 併發總能改進性能:只在多個線程或處理器之間能分享大量等待時間的時候管用
* 編寫併發程序無需修改設計:可能與單線程系統的設計極不相同
* 在採用web或ejb容器時,理解併發問題並不重要
有關編寫併發軟件的中肯的說法
* 併發會在性能和編寫額外代碼上增長一些開銷
* 正確的併發是複雜的,即便對於簡單的問題也是如此
* 併發缺陷並不是總能重現,因此常被看作偶發事件而忽略,未被當作真的缺陷看待
* 併發經常須要對設計策略的根本性修改
併發防護原則
1.單一權責原則
2.限制數據做用域
3.使用數據副本
4.線程應儘量獨立
瞭解Java庫
* 使用類庫提供的線程安全羣集
* 使用executor框架(executor framework)執行無關任務
* 儘量使用非鎖定解決方案
* 有幾個類並非線程安全的
瞭解執行模型
警戒同步方法之間的依賴
保持同步區域微小
很維編寫正確的關閉代碼
1.平靜關閉很難作到,常見問題與死鎖有關,線程一直等待永遠不會到來的信號
2.建議:儘早考慮關閉問題,儘早令其工做正常
測試線程代碼
1.建議:編寫有潛力曝露問題的測試,在不一樣的編程配置、系統配置和負載條件下頻繁運行。若是測試失敗,跟蹤錯誤。別由於後來測試經過了後來的運行就忽略失敗
2.將僞失敗看做可能的線程問題:線程代碼致使「不可能失敗的」失敗,不要將系統錯誤歸咎於偶發事件
3.先使非線程代碼可工做:不要同時追蹤非線程缺陷和線程缺陷,確保代碼在線程以外可工做
4.編寫可插拔的線程代碼,能在不一樣的配置環境下運行
5.編寫可調整的線程代碼:容許線程依據吞吐量和系統使用率自我調整
6.運行多於處理器數量的線程:任務交換越頻繁,越有可能找到錯過臨界區域致使死鎖的代碼
7.在不一樣平臺上運行:儘早並常常地在全部目標平臺上運行線程代碼
8.裝置試錯代碼:增長對Object.wait()、Object.sleep()、Object.yield()、Object.priority()等方法的調用,改變代碼執行順序,硬編碼或自動化
1.要編寫清潔代碼,必須先寫骯髒代碼,而後再清理它
2.毀壞程序的最好方法之一就是以改進之名大動其結構