這是我我的總結的一些編程思想,從2014年我接觸人生第一門編程語言(C)開始,它一直指引着我,我也不斷的完善它。其中有些是我本身在實踐中得出的結論,有些是書裏學到的知識。在此分享。從此我也會一直完善它,因此大家能看到,博客標題帶有編號,日後的新內容,我會直接追加在這片博客裏,並更新博客標題。java
add/remove increment/decrement open/close begin/end insert/delete show/hide create/destroy lock/unlock source/target first/last min/max start/stop get/put next/previous up/down get/set old/new locked/unlocked opened/closed visible/invisible source/destination
文件夾mysql
同函數。文件夾不使用複數形式,由於文件夾的特質已包含複數含義。程序員
函數sql
首單詞小寫,後面的單詞首字母大寫數據庫
和獲取數據有關的用get。直接從數據庫查詢的用find。find有從數據庫表裏查詢的含義, 因此在一個須要隱藏數據庫的層面,不該該使用find,應該使用get 數據庫用的是insert/delete,其餘層次咱們使用add/remove 因爲函數的參數列表也是其抽象的一部分,因此某些含義應該以參數的型式展現,而不是描 述進參數名字中,這樣的命名策略可避免出現複雜的參數名稱。例如,從數據庫中查詢某種 信息,findAllByxxx就能夠把Byxxx省略,由於你的參數列表已經代表了這樣的用意
變量編程
一般,首單詞小寫,後面的單詞首字母大寫。能夠酌情使用下劃線,但不要用中劃線。final static常量用全大寫,並用下劃線分割單詞。後端
類安全
全部單詞首字母大寫服務器
注意那些會形成知識逃逸的設計。網絡
程序具備金字塔結構特徵,底層接口具備較寬泛的抽象,越接近頂層,接口越具象(即與業務越擬合)
避免dao層出現針對特定業務設計的接口。
判斷一個接口是否針對特定業務設計,關鍵在於判斷接口內的變化是不是由業務變化直接決定的。
dao層的接口應該是無感情的select,insert,update,delete。一旦你發現某個接口具備業務擬合傾向,好比selectForXXX,該接口就須要從新考量。
異常的區分
防止unchecked異常發生是調用者的責任,調用者開發人員要在編碼階段保證unchecked不會在運行時出現。
從被調用者的角度來講,一個異常應該定義爲unchecked仍是checked,有時不是很好區分,但可從下面幾點來思考:
1,異常是否由參數引發(是=unchecked) 2,異常是否由非代碼緣故引發(代碼每每是對邏輯的準確表達,而非代碼如網絡,硬件等每每具備不許確性,不可靠性)(是=checked) 3,異常的解釋性有多強(強解釋性的異常每每來自很具象的異常類,而弱解釋性異常每每更多經過message來解釋本身)(強=checked)
可遵循《阿里巴巴Java開發手冊》(6.1應用分層,一章)。注意,DAO的組合複用,是在manager層作的。
從dao返回的數據,要麼是基本數據類型,要麼是DO實體。
從service返回的數據,要麼是基本數據類型,要麼是DTO實體。
每一個DAO應該有一個主表,圍繞這個主表產生DO,同時儘可能避免聯表。
《高性能Mysql》中有這樣一段話:
不管如何排序都是一個成本很高的操做,因此從性能角度考慮,應儘量避免排序或者儘量避免對大量數據進行排序。
若是 ORDER BY 子句中的全部列來都來自關聯的第一個表,那麼mysql在關聯處理第一個表的時候就進行文件排序。除此以外的全部狀況,mysql都會先將關聯的結果放到一個臨時表中,而後在全部的關聯都結束後,再進行文件排序。
僅供參考:我認爲思考某段sql應該進入哪一個DAO的時候,你須要思考這段SQL的主表是誰,而上面給出的信息,是思考這個問題的一個很不錯的提示。
mapper的查詢條件若是使用枚舉來映射數據庫表中的字段,不該該在枚舉中添加數據庫沒有的數值,好比用某個數來表示「所有」這個概念(但其實數據庫中並無一個狀態值和它對應)。若是你這麼作,你會發現當你須要使用集合來配合IN查詢的時候,多出來的數值會成爲你的麻煩。
下層爲上層服務,以目標爲導向。上層(業務邏輯層)須要什麼,下層(數據訪問層)就提供什麼。而不是下層(數據訪問層)有什麼,上層(業務邏輯層)使用什麼。
dao層不提供計算屬性,只提供真實存在的屬性。(雖然上層看不出來dao提供的屬性是真實存在的仍是計算出來的,但遵照這一點可讓你的sql與業務邏輯有效隔離。)
dao層有兩個部分,一是承載實際代碼的mapper.xml,一是提供接口的mapper.java。mapper.java要提供清晰明確的參數列表和返回值,禁止使用Map作參數和返回值。
任何NEP問題,都由數據使用者來保證。(你要假設任何基本數據類型外的數據都有可能爲NULL,並對出現NULL的狀況作出處理)
對數據庫的增刪改要聚合到特定的service接口上,數據查詢則不須要。這樣有助於控制數據的修改。
每一個函數,每一個類和每一個模塊都全神貫注於一事
應當把類和函數作得足夠小,消除對成員前戳的須要
函數應該作一件事,作好這件事,只作這一件事
函數要麼作什麼事,要麼回答什麼事,但兩者不可得兼
德墨忒爾律,模塊不該瞭解它所操做對象的內部情形。
咱們喜歡把由某個公共函數調用的私有工具函數緊隨在該公共函數後面,這符合了自頂向下原則,讓程序讀起來就像一篇報紙文章。
命名正是幫助判斷類的長度的一個手段,若是沒法爲某個類命以精確的名稱,這個類大概就太長了。類名越含糊,該類越有可能擁有過多權責。
你是想把工具歸置到有許多抽屜,每一個抽屜中裝有定義和標記良好的組件的工具箱中呢,仍是想要少數幾個能隨便把全部東西扔進去的抽屜
咱們但願將系統打形成在添加或修改特性時儘量少惹麻煩的架子。在理想系統中,咱們經過擴張系統而非修改現有代碼來添加新特性。
你是想把工具歸置到有許多抽屜,每一個抽屜中裝有定義和標記良好的組件的工具箱中呢,仍是想要少數幾個能隨便把全部東西扔進去的抽屜
咱們但願將系統打形成在添加或修改特性時儘量少惹麻煩的架子。在理想系統中,咱們經過擴張系統而非修改現有代碼來添加新特性。
類應該依賴於抽象而不是依賴於具體細節(面向接口編程)
封裝邊界條件。
某幾個函數若是被組合調用,那麼它們應該被封裝成一個總體,以保持它們的完整性。
對象把數據隱藏於抽象以後,暴露操做數據的函數。數據結構暴露其數據,沒有提供有意義的函數。注意,類並不簡單的用取值器和賦值器將其變量推向外界,而是暴露抽象接口,以便用戶無需瞭解數據的實現就能操做數據本體。
在良好的面向對象設計中,每一個對象均可以很好的完成一項任務,可是它並不試圖作更多的事。
將程序開發人員按照角色分爲類建立者(那些建立新數據類型的程序員)和客戶端程序員(那些在其應用中使用數據類型的類消費者)是大有裨益的。
當繼承現有類型時,也就創造了新的類型。這個新的類型不只包括現有類型的全部成員,並且更重要的是它複製了基類的接口,也就是說,全部能夠發送給基類對象的消息同時也能夠發送給導出類對象。因爲經過發送給類的消息的類型可知類的類型,因此這也就意味着導出類於基類具備相同的類型。
把導出類看做是它的基類的過程稱爲向上轉型。
面向對象的程序設計一般簡單的概括爲「向對象發送消息」。
你(客戶端程序員)所看到的只是有關下面兩個部份內容的定義:用來表示問題空間概念的對象,以及發送給這些對象的用來表示在此空間內的行爲的信息。
java:閉包是一個可調用的對象,它記錄了一些信息,這些信息來自於建立他的做用域
js:閉包容許你將一些行爲封裝,將它像一個對象同樣傳來遞去,並且它依然可以訪問到原來第一次聲明時的上下文。
我真的須要向上轉型嗎?(判斷是否使用繼承)
繼承是一種(is-a)關係,而組合是(has-a)關係
好比,防盜門是一種(is-a)門,因此防盜門應該繼承自門
而車有一扇(has-a)門,則應該是組合關係。
在設計一個系統時,目標應該是找到或建立某些類,其中每一個類都有具體的用途,並且既不會太大(包含太多的功能而難以複用),也不會過小(不添加其餘功能就沒法使用)。
將代碼視做是一種有機的,進化着的生命體而去培養。
類太過抽象的一個表現,是過長的參數列表(太多的屬性須要對象建立者定義);一個類的合適抽象要視其所處層級而定。參數過長不必定是太過抽象,有多是它本因在底層使用卻被設計給高層調用(底層的類原本就很抽象,它們對靈活性要求較高)。
類太過具象的一個表現,是過長的類名(說明該類的職責太過細節和具體)。這種狀況你要考慮,它可能應該歸屬於某個抽象,化身爲幾個接口,而不是單獨的一個類。
若是某些類具備一些相同的特性,你該考慮把這些特性提取出來,造成一個它們的父類。
恰當的原則應該是優先選擇類而不是接口。從類開始,若是接口的必要性變得很是明確,那麼就進行重構。(這能避免你在程序的一開始就莫名的構造出不少接口來,並且沒完沒了)
只要一個方法操做的是類而非接口,那麼你就只能使用這個類及其子類。若是你想要將這個方法應用於不在此繼承結構中的某個類,那你就會觸黴頭了。
一個接口表示:「全部實現了該接口的類看起來都像這樣」。所以,任何使用某特定接口的代碼都知道能夠調用該接口的哪些方法,並且僅需知道這些。
咱們能夠在任何現有類之上添加新接口,因此這意味着讓方法接收接口類型,是一種讓任何類均可以對該方法適配的方式。這就是使用接口的強大之處。(可是不要濫用接口)
使用接口的核心緣由:爲了可以向上轉型爲多個基類型(以及由此而帶來的靈活性)。
當人類只發現了蘋果的時候,水果這個抽象概念是沒有存在價值的,只有當橘子和香蕉也被發現時,水果才具備其存在乎義。(在爲程序增長抽象性方面,這句話能夠啓發你)
任何抽象性都應該是應真正的需求而產生的。當必要時,你應該首先考慮重構接口而不是處處添加額外級別的間接性,並由此帶來額外的複雜性,這種額外的複雜性是很是顯著的。(不要盲目添加新接口)
保養代碼,持續的改進代碼,代碼纔會精進。
內部類能夠訪問外圍類的全部屬性,不須要任何特殊條件。使用內部類和使用組合是不同的。
好的程序員花去90%的時間思考,研究和實驗,以找出最優的方案。差的程序員花去90%的時間調試問題程序,盲目的修改程序,指望某種寫法可行。
對同一種事物或同一種動做的不一樣叫法會成爲你的噩夢(別把命名不當回事)。
程序必須是爲了給人看而寫,給機器去執行只是附帶任務。
封裝複雜,接口簡單。——《羅輯思惟》
此條談論的接口是廣義接口,而不是面向對象編程中的那個接口(interface)
接口的神奇之處在於,你須要且只須要知道這樣作會獲得什麼。
接口的簡單之處在於,它明確的告訴你它須要什麼,產出什麼。
詞語概念:接口泛指實體把本身提供給外界的一種抽象化物(能夠爲另外一實體),用以由內部操做分離出外部溝通方法,使其能被修改內部而不影響外界其餘實體與其交互的方式。
在數據和數據使用者之間加上一個層次,這樣作的好處是某些對數據的操做,好比控制精度,強制類型轉換等能夠在這個層次集中處理,而不須要每個數據使用者都處理一遍。(這裏僅討論了數據和數據使用者,並不包括數據和數據提供者的狀況)
類是有層次的,最底層的類要儘量的解耦,它們越獨立就越便於使用。(類的概念越抽象,它就越靈活,我要吃水果和我要吃蘋果,顯然前者的選擇更多)
私有成員明確的告訴你,它和其餘人沒有關係。這能有效的下降複雜度。
軟件的首要技術使命——管理複雜度。封裝幫助你管理複雜度的方法是不讓你看到那些複雜度。抽象的主要好處就在於它使你能忽略無關的細節。
按照信息隱藏的原則來思考,可以激發和促進某些設計決策的造成,反而僅按照對象原則思考卻不會。
「這個類應該隱藏些什麼?」在設計的全部層面上,均可以經過詢問該隱藏些什麼來促成好的設計決策。
數據隱藏的關鍵在於,若是你不這麼作,對數據的操做將會分散在程序各處,一個小小的變化可能須要修改100個地方。
內聚性是用來管理複雜度的有用工具,由於當一個類的代碼越集中在一箇中心目標的時候,你就越容易記住這些代碼的功能所在。
問一個對象該對什麼負責,相似於問這個對象應該隱藏些什麼信息,不過這一問題可以帶來更爲廣闊的答案,從而使這種方法具備特殊的價值。
模塊化的目標是使得每一個子程序或者類看上去像個「黑盒子」:你知道進去什麼,也知道出來什麼,可是你不知道里面發生了什麼。
成爲高效程序員的一個關鍵就在於,當你開發程序任一部分的代碼時,都能安全地忽視程序中儘量多的其他部分,而類就是實現這一目標的重要工具。
咱們對着一列火車說「加上一節車箱」,因而火車就多了一節車箱。(這就是咱們所要的簡單)
關注類的接口所表現出來的抽象。保持類的接口所展示的抽象是一致的。
系統各個組成部分的開發者都會作出一些假設,而這些假設之間的不匹配是大多數致命和難以察覺的bug的主要來源。(從本身作起,不要讓本身開發的接口存在任何假設,好比某個函數必須在另外一個函數以後被調用)
架構應該模塊化,以便在替換爲新用戶界面時不影響業務規則和程序的輸出部分。例如,架構應該使咱們很容易的作到:砍掉交互式界面的類,插入一組命令行的類。(MVC)
精心設計的對象關係使關注點相互分離,從而使你能在每一個時刻只專一於一件事情。
一旦你能理解軟件開發中任何其餘技術目標都不如管理複雜度重要時,衆多設計上的考慮就都變得直接了當了。
當他們畫複雜的對象的時候,好比說一座房屋,他們老是一層層地去畫。首先畫出房屋的輪廓,而後畫窗和門,接下來畫進一步的細節,而不是一塊磚,一片瓦,一根釘的去畫。——Simon(1996)
每當你發現本身是經過查看類的內部實現來得知該如何使用這個類的時候,你就不是在針對接口編程了,而是在透過接口針對內部實現編程了。若是你透過接口來編程的話,封裝就被破壞了,而一旦封裝性開始遭到破壞,抽象能力也就快遭殃了。——《代碼大全》
寫出有品位的代碼。拜託,別讓你的代碼處處都是if,else,大於小於等於,加減乘除。那一點都不優雅。它們是你的內褲,必不可缺,但別人絕對不會願意看到它們。
網絡請求放到類中的矛盾是,類是能夠生成多個對象的,而網絡請求顯然應該只有一個,咱們不該該形成好幾個如出一轍的網絡請求不停的煩擾服務器的狀況,它不會開心的。一旦你決定讓類去發送網絡請求,就會出現當你使用一個或幾個對象的時候,沒法得知你將發送多少個網絡請求。
聲明一個變量以前你須要辨識這個變量的做用域,你應該從它的有效性範圍來看,而不是它實際被調用的範圍。
沒有完全理解問題,就不要去修改代碼。
在沒有理解代碼的時候對它所作的修改越大,你對它能正確工做的信心就越低。
你可能以爲你賦予了一個類操做某個數據表的職責,這就是單一職責了,但實際狀況是,它能夠被分解成「增刪改查」四個類,它們的職責更加「單一」。願上帝賜予你智慧,讓你分辨出合適的粒度。
接口並不能減小重複代碼,但它能規範抽象,下降程序複雜度。
當你設計程序結構時,有時會出現上層和下層行爲一致的狀況,這時你要多想想,只是暫時的巧合呢,仍是多餘了一層。
對一個已投入使用的類的任何修改都不能稱爲擴展,儘管你可能僅僅爲它添加了一個新的接口。添加一個新的接口意味着你得全然的瞭解這個類是如何實現的,這樣來設計擴展,不能讓你的工做輕鬆一分。在開閉原則中所說的對擴展開放,對修改關閉,意思是你能夠經過添加一些類實現新的功能,而不是經過給現有類添加新的接口。這意味着,在設計之初,你得把你的系統設計成可接納新類的架子。
代碼以類爲最小單位,若是你在寫一個類,那麼你對這個類就應該是全然明瞭。當你在寫一個類的時候,這個類裏的全部方法都不可信,由於它還在建設階段。變量應該保持最小做用域,當出現做用域須要擴張的時候,由於你對該類全然明瞭,因此你應該清楚哪些變量處在擴張做名單中。
存放類的文件夾不能承載類的解釋功能,好比system/attachment/下的類不能在命名的時候忽略其attachment(附件)的特性,由於當這些類被提供給客戶使用的時候,他是看不到文件夾的,編程中,他只能看到類名。不過類名能夠用來解釋方法。
開閉原則,說的是,某個類投入使用後,它會在不少你不知道的地方出現,此時你對它進行的修改(對接口的修改),將會同時影響系統的許多部分。解決這種災難的辦法就是實施開閉原則,即,讓系統的底層可接納新類,由此使得對接口的修改轉化爲加入新的類來實現。開閉原則還意味着,任何在可預見的將來會發生修改的類或方法,都是有問題的,你應該從新設計它們,以知足開閉原則。
「人們有時會問我,一個函數多長才算合適?在我看來,長度不是問題,關鍵在於函數名和函數本體之間的語義距離」——《重構》
層次的抽象是類,類的抽象是接口,接口的抽象是輸入輸出。(「是」替換爲「源自」更準確,但「是」更簡潔)因此一個接口乾些什麼關乎到了層次的抽象,換句話說,一個接口的職責是什麼,要視其所在層次,類而定。這裏的接口指的是函數的結構,而不是interface
若是函數或者構造函數接收的參數會因實參不合理致使系統出錯,那麼此函數應該使用異常處理機制控制參數輸入。
接口最重要意義是定義操做規範,因此接口用來表達每個處理單元的邏輯語義是最合適不過的。
在Java語言中,一個接口能夠有多個不一樣的實現類,從而構成一個樹形的實現體系。而每個不一樣的實現分支,實際上表明的是對於相同的邏輯語義的不一樣解讀方式。
寫程序應該寫完一個類,再寫下一個類。
一個類提煉的好很差,看兩個方面,其一,接口是否與抽象一致;其二,對擴展的支持是否充分。這裏所說的擴展,不是指去修改類,而是指類自己經過接收信息的方式而表現出不一樣特性的能力。
可擴展性越好的類,在使用前須要越多的參數來具化。位於不一樣層次的類其可擴展性是不一樣的。底層的類須要高可擴展性來提升其靈活程度,而高層次的類則須要高具化程度下降使用成本。
求同法是研究類比推理的一種方法,在求同的過程當中,觀察的場合越多,得出的結論越可靠。而構建一個類就是一個求同的過程。因此類的可靠性是要經過在考驗中不斷完善來提升的。
在編寫組件時,最好考慮好是否要進行復用。一次性組件間有緊密的耦合不要緊,可是可複用組件應當定義一個清晰的公開接口,同時也不要對其使用的外層數據做出任何假設。
來看看那些優秀的開發者一直都在堅持作的事情。 不停的練習、作實踐 參加開發者大會,那裏可能有一些新鮮的東西 不停地得到更多的項目經驗 學習網上的課程 努力靠近牛人並和他們交流 參與開發一些好玩的,你感興趣的項目 學習開源的框架以及類庫,這也是工做必須的 嘗試寫博客、去分享技術、給企業作培訓
編程時要首先考慮類之間的協做(依賴)關係,其次纔是性能。對於性能,有如下幾點:1,你關注的問題不必定是系統瓶頸;2,過多的盲目優化會下降開發效率,事倍功半。
函數式編程三原則:
1,聲明式編程
2,純函數
3,不可變數據(較流行的immutable實現:immutable-js)
與聲明式編程相反的是指令式編程,指令式編程即告訴計算機每一步如何操做,如for循環,if-else塊等,通常來講都是指令式編程。編程離不開指令式編程,但指令式編程應該位於代碼底層,想想lodash你大概就明白個人意思了。
純函數編程有兩個特色:1,函數的輸出只與輸入有關,相同輸入產生相同輸出(函數不依賴除入參之外的外部條件);2,函數不改變除函數域之外的狀態或變量。
程序中,使用註釋來闡述魔法數值的用途,會致使當魔法數值發生增減時,全部基於它的接口都發生抽象變化,此時你須要修改全部使用了該魔法數值的接口的註釋。這是愚蠢的。你應該使用枚舉來代替魔法數值,這樣接口的抽象就不須要註釋來維護,它由一個統一的枚舉抽象來維護。有時,這個魔法數值不是某種字典,而是某種列表的id號,這種狀況下也許你不該該使用枚舉,望斟酌。
代碼的效率和複雜度成正比。大多數狀況下,優化能夠後作。
每一個Exception必需要打印到日誌中一次,且僅一次(誰處理了Exception,誰打印,要注意,捕獲不必定就處理,還可能將它再次拋出,這種狀況下不打印)。
知識逃逸,某個知識沒有被有效的控制在特定的範圍內,致使全部人都須要掌握該知識。知識逃逸問題是編程中一個重要又廣泛存在的問題。
The most important purpose of creating Repository is not to exclude the persistence platform dependent logic from business logic. The most important purpose is to limit the implementation scope of business logic (Service) to the implementation of business rules. This is done by separating the operations to access business data in Repository. As an outcome of this, persistence platform dependent logic gets implemented in Repository instead of business logic (Service).