1. 分支開發(fā)流程
- GIT分支開發(fā)規(guī)范未巫,具體請參考:http://www.reibang.com/p/cbd8cf5e232d锅劝。
2. 代碼規(guī)范
- 主要使用Java語言來進行開發(fā),嚴(yán)格遵循Sun公司的Java編碼規(guī)范疯淫。此外還有以下補充宪卿。
2.1 大小寫
- 常量的字母 全部大寫,單詞之間用一個 下劃線字符(_)進行分隔望众。
- 除常量外的命名 采用大小寫混合匪补,提高名字的可讀性。
- 一般采用小寫字母烂翰,但是類和接口的名字的首字母叉袍,以及任何中間單詞的 首字母應(yīng)該大寫。
2.2 編碼格式
- 確保IDE工作環(huán)境使用UTF-8編碼格式刽酱。
- 縮進一律使用空格而非Tab。
- 縮進一律采用4空格瞧捌】美铮可以設(shè)置IDE 1Tab=4空格。
- 對于非第一次創(chuàng)建的代碼文件姐呐,禁止做reformate操作殿怜,這個操作會破壞代碼的修改歷史,造成大概率的push曙砂、merge头谜、pull等操作沖突。
2.3 常量定義
- 對具有特殊意義的數(shù)字或字符要以常量的形式定義鸠澈,并說明常量所表示的意義柱告,避免幻數(shù)的出現(xiàn)。
2.4 統(tǒng)一定義公共常量
- 對于一些公共常量的使用笑陈,應(yīng)該單獨定義相應(yīng)的常量類际度,并統(tǒng)一使用,避免在各業(yè)務(wù)類涵妥、功能類中分別定義乖菱、直接使用。
2.5 命名規(guī)則
Package:
1.1 Package: 每一個包的名稱總是小寫蓬网,暫定將com.keegoo.+(模塊名)作為總前綴窒所,比如com.keegoo.demo.blog.service、com.keegoo.demo.blog.dto帆锋;
1.2 明確不同業(yè)務(wù)建議建立子package吵取,比如有關(guān)User業(yè)務(wù)的:com.keegoo.user.account.service、com.keegoo.user.account.dto窟坐;Class類:類名必須是名詞海渊,且以大寫字母開頭绵疲。類名應(yīng)該簡單清晰。
Interface類:
3.1 Interface命名上臣疑,暫定以XxxService的形式提供盔憨;
3.2 最終提供的接口應(yīng)以Java Interface的形式出現(xiàn);
3.3 每個獨立的業(yè)務(wù)的Interface應(yīng)該有獨立的package包讯沈,一個package下可包含該業(yè)務(wù)模塊下的多個Interface郁岩;
3.4 每個Interface的一個方法對應(yīng)所謂的一個“中間層服務(wù)接口”,需要按照規(guī)范書寫該接口的說明缺狠;緩存命名規(guī)則:對緩存的key要采用命名空間问慎,以避免沖突,同時要考慮緩存的命中率挤茄,不要浪費緩存的空間如叼。
2.6 Controller,Interface類穷劈,接口實現(xiàn)類編寫注意事項
- Controller類里不能出現(xiàn)業(yè)務(wù)邏輯笼恰,只能直接調(diào)用Service類,不能直接調(diào)用Biz類(Biz類是對業(yè)務(wù)邏輯的實現(xiàn)封裝歇终,不依賴dao層社证,可獨立做單元測試),manager類則是作為service评凝、biz追葡、dao三層的粘合劑,來協(xié)調(diào)三者執(zhí)行關(guān)系奕短。
- Interface接口定義類只定義方法宜肉,方法的實現(xiàn)要在實現(xiàn)類里完成,interface接口以xxxService結(jié)尾翎碑,接口實現(xiàn)類以xxxServiceImpl結(jié)尾崖飘。
2.7 注釋
- 方法注釋:每個接口、方法應(yīng)該有一個方法的整體說明杈女,包括方法實現(xiàn)的功能朱浴、參數(shù)的詳細(xì)含義、返回值的取值及其詳細(xì)含義达椰。
- 類注釋:對于工具類或者流程類翰蠢,需要在類的注釋中對于類的功能進行詳細(xì)的說明;對于Model類啰劲,要對其重要的屬性添加注釋梁沧,注明其含義,必要時要重載hashCode和equals蝇裤,toString方法廷支。
3. 設(shè)計規(guī)范
3.1 對功能性模塊的抽象
業(yè)務(wù)模塊的開發(fā)過程中频鉴,應(yīng)該避免過長的方法,進行合理的功能模塊的提取以及抽象恋拍,避免同一段代碼垛孔、類似代碼到處copy的情況。
3.2 單一職責(zé)原則SRP(Single Responsibility Principle)
所謂單一職責(zé)原則施敢,指的就是:一個類應(yīng)該僅有一個引起它變化的原因周荐。
這里變化的原因就是 所說的“職責(zé)”,如果一個類有多個引起它變化的原因僵娃,那么也就意味著這個類有多個職責(zé)概作,再進一步說,就是把多個職責(zé)耦合在一起了
默怨。這會造成職責(zé)的相互影響讯榕,可能一個職責(zé)的變化,會影響到其它職責(zé)的實現(xiàn)匙睹,甚至引起其它職責(zé)跟著變化瘩扼,這種設(shè)計是很脆弱的。
這個原則看起來是最簡單和最好理解的垃僚,但是實際上是很難完全做到的,難點在于如何區(qū)分這個“職責(zé)”
规辱,這是個沒有標(biāo)準(zhǔn)量化的東西谆棺,哪些算職責(zé),到底這個職責(zé)有多大的粒度罕袋,這個職責(zé)如何細(xì)化等等改淑。因此,在實際開發(fā)中浴讯,這個原則也是最容易違反的朵夏。
3.3 開放-關(guān)閉原則OCP(Open-Closed Principle)
所謂開放-關(guān)閉原則,指的就是:一個類應(yīng)該對擴展開放榆纽,對修改關(guān)閉仰猖。一般也被簡稱為開閉原則,開閉原則是設(shè)計中非常核心的一個原則奈籽。
開閉原則要求的是饥侵,類的行為是可以擴展的
,而且是在不修改已有的代碼的情況下進行擴展衣屏,也不必改動已有的源代碼或者二進制代碼躏升。
看起來好像是矛盾的,怎么樣才能實現(xiàn)呢狼忱?
實現(xiàn)開閉原則的關(guān)鍵就在于合理的抽象膨疏,分離出變化與不變化的部分一睁,為變化的部分預(yù)留下可擴展的方式
,比如:鉤子方法佃却、或是動態(tài)組合對象等等者吁。
這個原則看起來也很簡單,但事實上双霍,一個系統(tǒng)要全部做到遵守開閉原則砚偶,幾乎是不可能的
,也沒這個必要洒闸。適度的抽象可以提高系統(tǒng)的靈活性染坯,使其可擴展、可維護丘逸,但是過度的抽象单鹿,會大大增加系統(tǒng)的復(fù)雜程度
。應(yīng)該在需要改變的地方應(yīng)用開閉原則就可以了深纲,而不用到處使用仲锄,從而陷入過度設(shè)計。
3.4 里氏替換原則LSP(Liskov Substitution Principle)
所謂里氏替換原則湃鹊,指的就是:子類型必須能夠替換掉它們的父類型儒喊。這很明顯是一種多態(tài)的使用情況,它可以避免在多態(tài)的應(yīng)用中币呵,出現(xiàn)某些隱蔽的錯誤怀愧。
事實上,當(dāng)一個類繼承了另外一個類余赢,那么子類就擁有了父類中可以繼承下來的屬性和操作芯义,理論上來說,此時使用子類型去替換掉父類型妻柒,應(yīng)該不會引起原來使用父類型的程序出現(xiàn)錯誤扛拨。
但是,很不幸的是举塔,在某些情況下是會出現(xiàn)問題的绑警,比如:如果子類型覆蓋了父類型的某些方法,或者是子類型修改了父類型某些屬性的值央渣,那么原來使用父類型的程序就可能會出現(xiàn)錯誤
待秃,因為在運行期間,從表面上看痹屹,它調(diào)用的是父類型的方法章郁,需要的是父類型方法實現(xiàn)的功能,但是實際運行調(diào)用的確是子類型覆蓋實現(xiàn)的方法,而該方法跟父類型的方法并不一樣暖庄,那就會導(dǎo)致錯誤的產(chǎn)生
聊替。
從另外一個角度來說,里氏替換原則是實現(xiàn)開閉的主要原則之一培廓,開閉原則要求對擴展開放惹悄,擴展的一個實現(xiàn)手段就是使用繼承肩钠,而里氏替換原則是保證子類型能夠正確替換父類型泣港,只有能正確替換,才能實現(xiàn)擴展价匠,否則擴展了也會出現(xiàn)錯誤
当纱。
3.5 依賴倒置原則DIP(Dependence Inversion Principle)
所謂依賴倒置原則,指的就是:
要依賴于抽象踩窖,不要依賴于具體類
坡氯。要做到依賴倒置,典型的應(yīng)該做到:
高層模塊不應(yīng)該依賴于底層模塊
洋腮,二者都應(yīng)該依賴于抽象箫柳;抽象不應(yīng)該依賴于具體實現(xiàn)
,具體實現(xiàn)應(yīng)該依賴于抽象啥供;
很多人覺得悯恍,層次化調(diào)用的時候,應(yīng)該是高層調(diào)用“底層所擁有的接口”伙狐,這是一種典型的誤解涮毫。事實上,一般高層模塊包含對業(yè)務(wù)功能的處理和業(yè)務(wù)策略選擇鳞骤,應(yīng)該被重用,應(yīng)該是高層模塊去影響底層的具體實現(xiàn)黍判。
因此豫尽,這個底層的接口,應(yīng)該是由高層提出的顷帖,然后由底層實現(xiàn)的美旧,也就是說底層的接口的所有權(quán)在高層模塊
,因此是一種所有權(quán)的倒置贬墩。
倒置接口所有權(quán)榴嗅,這就是著名的Hollywood(好萊塢)原則:不要找我們,我們會聯(lián)系你陶舞。
3.6 接口隔離原則ISP(Interface Segregation Principle)
所謂接口隔離原則嗽测,指的就是:
不應(yīng)該強迫客戶依賴于他們不用的方法
。
這個原則用來處理那些比較“龐大”的接口,這種接口通常會有較多的操作聲明唠粥,涉及到很多的職責(zé)疏魏。客戶在使用這樣的接口的時候晤愧,通常會有很多它不需要的方法大莫,這些方法對于客戶來講,就是一種接口污染官份,相當(dāng)于強迫用戶在一大堆“垃圾方法”里面去尋找他需要的方法只厘。
因此,這樣的接口應(yīng)該被分離舅巷,應(yīng)該按照不同的客戶需要來分離成為針對客戶的接口羔味,這樣的接口里面,只包含客戶需要的操作聲明悄谐,這樣既方便了客戶的使用介评,也可以避免因誤用接口而導(dǎo)致的錯誤。
分離接口的方式爬舰,除了直接進行代碼分離之外们陆,還可以使用委托來分離接口,在能夠支持多重繼承的語言里面情屹,還可以采用多重繼承的方式進行分離坪仇。
3.7 最少知識原則(Least Knowledge Principle)
所謂最少知識原則,指的就是:
只和你的朋友談話
垃你。
這個原則用來指導(dǎo)我們在設(shè)計系統(tǒng)的時候椅文,應(yīng)該盡量減少對象之間的交互,對象只和自己的朋友談話惜颇,也就是只和自己的朋友交互皆刺,從而松散類之間的耦合
。通過松散類之間的耦合來降低類之間的相互依賴凌摄,這樣在修改系統(tǒng)的某一個部分時候羡蛾,就不會影響其它的部分,從而使得系統(tǒng)具有更好的可維護性锨亏。
那么究竟哪些對象才能被當(dāng)作朋友呢痴怨?最少知識原則提供了一些指導(dǎo):
當(dāng)前對象本身;
通過方法的參數(shù)傳遞進來的對象器予;
當(dāng)前對象所創(chuàng)建的對象浪藻;
當(dāng)前對象的實例變量所引用的對象;
方法內(nèi)所創(chuàng)建或?qū)嵗膶ο螅?/p>
總之乾翔,最少知識原則要求我們的方法調(diào)用爱葵,必須保持在一定的界限范圍之內(nèi),盡量減少對象的依賴關(guān)系。
3.8 其它原則
除了上面提到的這些原則钧惧,還有一些大家都熟知的原則暇韧,比如:
面向接口編程;
優(yōu)先使用組合/聚合浓瞪,而非繼承懈玻;
當(dāng)然也還有很多不是很熟悉的原則,比如:
一個類需要的數(shù)據(jù)應(yīng)該隱藏在類的內(nèi)部乾颁;
類之間應(yīng)該零耦合涂乌,或者只有傳導(dǎo)耦合,換句話說英岭,類之間要么沒有關(guān)系湾盒,要么只使用另一個類的接口提供的操作;
在水平方向上盡可能統(tǒng)一的分布系統(tǒng)功能诅妹;
4. 日志規(guī)范
根據(jù)日志的嚴(yán)重程度和功能所劃分成以下五種:
FETA:致命的錯誤罚勾,程序不能或不應(yīng)該正常運行。FETAL級別的日志主要用于記錄非常嚴(yán)重而導(dǎo)致程序不能正常運行的錯誤吭狡,比如得不到FileSystem對象尖殃、Job運行失敗、ODFS寫重要的數(shù)據(jù)文件不成功等划煮。
ERROR:嚴(yán)重的錯誤送丰,但不影響程序流程,Tool可以繼續(xù)運行弛秋。ERROR級別的日志主要用于記錄雖然嚴(yán)重但不至于影響程序運行的錯誤器躏,比如Parser解析失敗等。代碼中捕獲異常后輸出的日志一部分會屬于ERROR級別蟹略。
WARN: 警告日志登失,不影響程序流程,Tool可以繼續(xù)運行挖炬。WARN級別的日志與ERROR級別的日志有一些相似揽浙,但通常是不能準(zhǔn)確判斷是否出現(xiàn)問題,需要人來判 斷茅茂,比如某輪待抓取的數(shù)據(jù)為0捏萍;而ERROR級別的日志通常是在程序運行過程中就可以發(fā)現(xiàn)代碼太抓、流程或數(shù)據(jù)等的某一方面或幾方面存在問題空闲。
INFO:信息日志,不影響程序流程走敌,Tool可以繼續(xù)運行碴倾。INFO級別的日志主要用來記錄一些需要統(tǒng)計的信息,比如抓取統(tǒng)計,以及一些必要的諸如程序啟停等信息跌榔。
DEBUG:調(diào)試日志异雁,不影響程序流程,Tool可以繼續(xù)運行僧须。DEBUG級別的日志主要用于記錄調(diào)試所用到的信息纲刀,在線上運行的過程中該級別的日志不會輸出。
設(shè)計這些日志級別是為了方便的對日志進行過濾担平,對于線上系統(tǒng)示绊,一般會將日志級別設(shè)置為WARN
,這是為了讓維護人員能夠根據(jù)日志迅速判斷問題暂论,另一方面不會因為頻繁的寫磁盤也帶來性能問題面褐。而在查找具體問題時,可能要將日志級別調(diào)到DEBUG
取胎,希望通過更多的輸出信息來定位問題展哭。
5. 日志格式
日志格式指的是輸出到日志文件的每一條日志所遵循的格式。為方便起見闻蛀,每一條日志格式都由若干個“key=value”這樣的屬性對組成匪傍,不同的屬性對之間用制表符(即“\t”)分隔。有幾個特殊的屬性稍有區(qū)別循榆,不采用“key=value”這樣的形式:
- 時間:時間是一條日志的第一項析恢。而由于outlog會采用“yyyyMMddHHmmssSS”這樣的格式自動記錄日志的時間,所以無需再增加“key=value”這種格式的時間秧饮。
- 級別:級別是一條日志的第二項映挂。級別采用“[LEVEL]”這種形式,如“[INFO]”盗尸。
- 消息體:消息體是一條日志的最后一項柑船。為更直觀,消息體也不采用“key=value”的格式泼各,而直接輸出鞍时,如“This is a message.”。
除此之外的其他屬性均采用“key=value”的格式扣蜻。這些屬性對位于級別和消息體之間逆巍,以制表符(即“\t”)分隔,無需排序莽使。對于“key=value”中的“key”锐极,有一些常用的值可以定義為常量,如“CLASS(類名)”芳肌、“ERROR(錯誤類型)”等灵再,對于非常見或特殊需求的“key”肋层,可以在記log的時候自己定義,解析的時候注意保持一致即可翎迁。 屬性中還有一個特殊的屬性栋猖,即“ERROR(錯誤類型)”,用于表示錯誤的類型汪榔。ERROR和FETAL級別的日志中需要包含該屬性蒲拉,其他級別的日志中無需包括〕针纾“ERROR”屬性的取值會有一個固定的范圍全陨,包括但不限于以下幾種:
- IOException
- ConnectionRefused