1. 制定該規范的目的: 碼出高效,碼出質量.結合自己的業務場景,整理出適合自己的規范.
2. 當前版本規范主要包含下列內容:
一. 代碼編碼規范
(一) 基本規范
A. 命名規范
通用:以英文為主導的駝峰格式, 不允許出現拼音命名和中文命名,非實際意義的數字不可使用,
【正例】expense,name
【反例】feiyong,name1
(1)【強制】常量以下劃線拼接, 全大寫格式,常量應抽離放在類級別定義或常量類中單獨定義,不能在業務邏輯中直接使用, 因為常量重復在堆疊中創建影響性能,
【正例】EXPENSE_DETAIL = “expense_detail”
【反例】expense_detail = “expense_detail”、expenseDetail = “expense_detail”
(2)【推薦】命名推薦全稱英文,建議不要出現縮寫、業界公認的縮寫名稱可使用,以系統固有使用規則為主,
【正例】conditionDetail、mvc、statistic
【反例】conDetail、stat
(3)【強制】各模式命名以具體的后綴結尾,方便理解和協同開發,
【正例】DefaultException、ExpenseTest.
【反例】DefaultExceptions(例外類)、ExpenseDemo(測驗類)
(4)【強制】包名統一用小寫,不允許出現復數形式包名
【正例】com.bj58.coin.utils、com.bj58.coin.controller
【反例】com.bj58.coin.coinModel
(5)【強制】領域模型物件如DTO/BO/DO/VO/PO,模型類命名應加回應模型后綴,且后綴全為大寫,
【正例】ExpenseDTO、ExpenseVO
【反例】ExpenseDto
(6)【推薦】Dao層命名規約,
l 獲取單個物件方法,用get做方法名前綴,
【正例】getExpense
【反例】selectExpense、searchExpense、findExpense、queryExpense
l 獲取集合物件方法,用list做方法名前綴,
【正例】listExpense
【反例】getExpense、getExpenses、selectExpenseList
l 獲取統計值方法,用count做方法名前綴或后綴
【正例】countExpense
【反例】getExpenseCount、selectCountOfExpense
l 新增物件方法,用insert做方法名前綴,
【正例】addExpense
【反例】insertExpense
l 洗掉方法,用remove做方法名前綴,
【正例】removeExpense
【反例】updateExpense、clearExpense、delExpense、deleteExpense
l 更新方法,用modify做方法名前綴,邏輯洗掉亦然,
【正例】modifyExpense
【反例】changeExpense、updateExpense
B. 代碼格式
(1)【推薦】大括號使用約定,若大括號內為空,簡潔寫成{}即可,否則:除左大括號左邊不需要換行外,左大括號右邊、右大括號左右兩邊均需要換行,
【正例】
if ( a == b) {
// TODO
}
【反例1】
if (a == b){ // TODO }
【反例2】
if (a == b)
{
// TODO
}
【反例3】
if (a == b)
{// TODO }
(2)【推薦】數學運算子左右兩邊均需要空格,例如:
【正例】if (a == b)
【反例】if (a==b)、if (a== b)、if (a ==b)
(3)【推薦】if/for/while/switch/do等保留字與括號之間都必須加空格,
【正例】if (a == b)、while (a == 1)
【反例】if(a==b)、while(a == 1)
(4)【推薦】注釋符號與注釋內容之間有且僅有一個空格,
【正例】// 注釋
【反例】//注釋
(5)【推薦】方法呼叫時,需要多個換行時,在點號或逗號前換行,
【正例】
CoinUtil.toggle(condition_one
, condition_two
, condition_three
, condition_four);
【反例】
CoinUtil.toggle(condition_one,
condition_two,
condition_three,
condition_four);
(6)【推薦】方法引數在定義或呼叫時,多個引數逗號后必須加空格,
【正例】CoinUtil.toggle(one, two, three);
【反例】CoinUtil.toggle(one,two,three);
(7)Object類的equals()方法容易拋空指標例外,使用常量或確定的值來呼叫equals,例如:
【正例】“test”.equals(object)
【反例】
String object = null;
// 空指標例外
object.equals(“test”);
(8)【推薦】所有的領域模型物件中,屬性不允許使用基本型別定義,防止基本型別的默認值給業務使用上帶來不必要的麻煩,分場景??
【正例】Integer a; Boolean deletedFlag;
【反例】int a; boolean isDeleted;
(9)【強制】領域模型物件不允許改造其getter或setter方法,亦不允許初始化屬性值,分場景???網路互動的模型不允許撰寫邏輯(對外提供協議、資料庫互動),
【正例】
public void setPrjId(long prjId) {
this.prjId = prjId;
}
【反例】
public void setPrjId(Long prjId) {
this.prjId = (null == prjId) ? 0L : prjId;
}
(10)【強制】業務邏輯中查詢產生的模型物件或集合物件都需要進行非空判斷來避免空指標例外,若已對空指標例外已做兜底機制則可忽略,
【正例】
List<Expense> expenseList = coinService.listExpense();
if (CollectionUtils.isEmpty(expenseList)) {
// TODO
}
【反例】
List<Expense> expenseList = coinService.listExpense();
// TODO (直接使用expenseList可能產生空指標例外)
(11)【推薦】使用StringBuilder類的append()方法來代替String類的“+”號拼接字串操作,
【正例】StringBuilder date = new StringBuilder(“2020”)
.append( “-”).append( “09”)
.append(“-”).append(“21”);
【反例】String date = a + b + c + “-” + “21”;
(13)【推薦】類中存在相似或相仿的方法時,應緊鄰放在一起,例如getWord()和getWordForSomething()方法,
(14)【推薦】if/else/for/while/do陳述句中必須使用大括號,即使只有一行代碼,
【正例】
if (a == b) {
a++;
}
【反例】
if (a == b) a++;
(15)【推薦】if…else嵌套陳述句不得超過三層,采用取反、短路結束邏輯
【正例】
if (a != c) {
return;
}
if (a == b) {
a++;
}
【反例】
if (a == b) {
if (a == c) {
if ( a == d) {
if (a == e) {
a++;
}
}
}
}
(16)【強制】外部傳入的入參物件不能直接傳入Dao層,應經過model轉換后再傳入底層,
【正例】
public void update(CoinDTO record) {
CoinModel coinModel = new CoinModel();
BeanUtils. copyProperties(record, coinModel);
coinService.update(coinModel);
}
【反例】
public void update(CoinDTO record) {
coinService.update(record);
}
C. 例外規范
(1)【推薦】try…catch保證最小原則,即拒絕將大量已知穩定的業務邏輯放入其中,因為try…catch影響性能,
(2)【強制】非兜底捕獲時,使用具體的例外類,而非用Exception一概而全,
【正例】
【反例】
(4)【強制】禁止捕獲例外后catch塊中處理邏輯為空,
【正例】
【反例】
(6)【強制】try…catch應采用最上層處理原則,拒絕每一個呼叫層內均增加try…catch,底層應選擇將例外拋出給上層處理,
【正例】
【反例】
(二) 注釋規范
(1·)【強制】類、類屬性、類方法的注釋必須使用Javadoc規范,即使用“/** 內容 */”格式,不得使用“/*內容*/” 或“//內容”的格式,
【正例】
【反例】
(2)【推薦】類、介面、檔案都需注明@author屬性和@date屬性,增加當前類描述說明,
【正例】
【反例】
(3)【強制】方法內部單行注釋,在備注陳述句上方另起一行,使用//注釋,方法內部多行注釋使用/* */注釋,注意對齊,方法若多層呼叫且相當復雜,斟酌加上實際邏輯對應的文字說明,
【正例】
【反例】
(4)【強制】所有的列舉欄位、常量欄位均需要注釋說明,說明具體用途,
【正例】
【反例】
(5)【強制】代碼修改后、相應的引數、回傳值、例外、核心邏輯釋義也要做相應修改,
(6)【強制】謹慎注釋掉代碼,做詳細說明、如注釋原因、后續是否會恢復,若永不再用,則直接洗掉,
(7)待后續完成的功能,可使用TODO標注,代碼錯誤無法作業的可使用FIXME標注,
【正例】存在TODO的方法,協作開發使用前會檢查、更謹慎選擇使用,
【反例】
二. 依賴組件操作規范
(一) DB使用規范
A. 建表規范
(1)【強制】主鍵必須為“id”, 不允許自定義主鍵名,建表需有COMMENT屬性,注明每個欄位的含義, 表名必須加備注,說明當前表的用處;
(2)【強制】不允許使用外鍵約束,
(3)【強制】表名中的單詞沒有復數一說,因為表名只表達的是當前表的內容.
【反例】如表名 orders
(4)【推薦】表名一定要包含一定的業務含義,如果表名是關鍵字的時候最好加修飾欄位.不要只使用單個欄位來表示表資訊,
【反例】如表名 order 【正例】pay_order,resource_order
(5)【強制】表名禁用保留欄位: desc ,like,status等,
https://www.cnblogs.com/zhuyeshen/p/11496545.html
(6)【強制】表存盤引擎僅僅支持InnoDB,且必須指明ENGINE=InnoDB.
(7)【推薦】 表必備三欄位:id, created_at, modified_at.,創建人, id表示主鍵, create_time, modified_time建議設為Long型別,兩個欄位分別表示當前記錄的創建時間和更新時間,
(8)【推薦】普通索引名稱必須以idx_開頭,唯一索引必須以uniq_開頭,且索引名越簡潔越好(越長占用磁盤空間越大),主鍵索引不允許自定義索引名,示例:idx_a_id、idx_a_id_b_id,
【正例】給create_at,user_id建聯合索引:idx_create_at_user_id
(9)【推薦】大欄位Text,varchar欄位超過128以上不建議建立索引,varchar欄位長度設定為2^N次方,
說明:索引的長度與區分度是一對矛盾體,一般對字串型別資料,長度為20的索引,區分度會高達90%以上,可以使用count(distinct left(列名, 索引長度))/count(*)的區分度來確定,
索引很長的字符列,會讓索引變得大且慢.部分欄位建索引,可以節約索引空間,從而提高索引效率
(10)【強制】小數型別使用decimal格式,按需要設定小數位,禁止使用float和double格式,
(11)【推薦】使用數字型別(Long,int)等盡量使用unsigned型別來標注,int型別建議統一使用11位長度,這是int的最大長度,
(12)【強制】Long、varchar使用2的倍數設定欄位長度,
(13)【強制】欄位均需設定非空屬性,varchar欄位型別默認值是””(不能設定為Null)
B. 改表規范
(1)【強制】新增欄位時、不能固定化直接放在所有欄位之后,適當運用after/before方法,
(2)【強制】新建欄位時必須指定默認值,且默認值不能為null
(3)【強制】更新表欄位名時、若注釋已改、相應的COMMENT值也要隨之變化,
(4)【強制】資料庫操作規范(DDL):包括增加,修改,洗掉表欄位,增加索引,清理表碎片等操作.所有的DDL操作強制遵循以下原則:
a. 在低峰期操作(高峰期的操作時容易引起主從資料不一致,進而影響交易)
b. 需和DBA溝通清楚,當前操作是否支持批量操作,是否會進行批量操作,當前操作的影響范圍等資訊
mongoDB的關于表的操作:同(4)
C. 資料操作規范
(1)【推薦】修復資料新增時、創建人應注明實際操作人,且時間為當前時間,
(2)【推薦】修復資料更新時、更新人應注明實際操作人,且時間為當前時間,
(3)【強制】洗掉資料時,自己做好資料備份,做好及時回滾的準備,
(4)【推薦】超過三表的聯表查詢需關注執行效率、謹慎使用,
(5)【強制】查詢sql撰寫若非特定需求,禁止介面回傳超過200條資料,需做分頁,
(6)【推薦】查詢SQL排序使用注意索引的順序規則,
(7)【強制】sql條件里邊的集合條件盡量用in選擇確定值.
原始dao介面:
【反例】狀態值直接取范圍區間
【正例】狀態值取確定的范圍
(8) 【推薦】在表查詢中,不要使用 * 作為查詢的欄位串列,需要哪些欄位必須明確注明
說明:(1)增加查詢分析器決議成本,
(2) 無用欄位增加網路消耗,尤其是text型別的欄位
(9)【推薦】統計數量時請使用count(*),count(*)是SQL92定義的標準統計行數的語法,跟資料庫無關. count(*)會統計值為NULL的行,而count(列名)不會統計此列為NULL值的行.
(10)【強制】當某一列的值全是NULL時,count(col)的回傳結果為0,但sum(col)的回傳結果為NULL,因此使用sum()時需注意NPE問題,
【正例】可以使用如下方式來避免sum的NPE問題:
SELECT IFNULL(SUM(column), 0) FROM table;
(11)【推薦】不要寫一個大而全的資料更新介面,傳入為POJO類,不管是不是自己的目標更新欄位,都進行update table set c1=value1,c2=value2,c3=value3; 這是不對的,執行SQL時,不要更新無改動的欄位,一是易出錯;二是效率低;三是增加binlog存盤,推薦使用mayatis的動態sql來設定更新值,
(12) 【推薦】Like查詢時使用<bind name="bindeName" value="https://www.cnblogs.com/'%\'+eName+\'%\'" />僅限于mybatis
(二) 內部RPC使用規范
(1)【強制】序列化目前不支持內部類,
(2)【強制】介面定義不需要加public 等訪問權限控制符,
(3)【強制】序列化不支持map型別key為null,
(5)序列化不支持 File, InputStream, JSON 等沒有加@SCFSerializable的java物件,
(6)序列化SCFV3不支持嵌套的泛型,如List<Map<String, Object>>, 這種型別SCFV4可以支持(SCFV4和SCFV3功能基本一致,升級不需要其他改動,)
(7)不支持JDK11,掃包會出現問題
(8)【推薦】對外和對內的SCF介面應單獨拆分類使用,即使功能相同,
對外提供的介面粒度最小化.
(9)【強制】回傳值使用固定包裝類,拒絕資料裸奔,回應碼,回應訊息等資訊,示例:
【正例】
【反例】
(10)【推薦】回傳結果若為集合時,應回傳空集合,而非null,
【正例】
【反例】
(三) Redis使用規范
(1)【強制】Redis不能隨用隨建,應建立合理的連接池使用,具體連接池引數需根據使用場景評估,
(2)【強制】Redis拒絕使用模糊查詢,查詢易使Redis服務宕機重啟,
(3)【推薦】存盤的Key必須設定過期時間,否則永久占用Redis記憶體,影響性能,權限類資訊
(4)【強制】拒絕存盤大文本(超過500位元組)資料,
(5)【強制】Key命名規則:不同名稱間使用“:”連接,Key名不易過長,固定最長64位,
【正例】
【反例】
(6)【強制】Redis對大集合的操作必須加上limit限制,limit200條,單條命令執行時間不宜過長,超過1ms可認為慢sql,
(7) redis必須做好資料備份,能快速恢復資料,
(四) 大資料平臺使用規范
(1)【推薦】命名規范
? 大資料平臺任務:{業務線}-{具體意義};若為全業務線的任務,則格式為{部門下的組名}-{具體意義}
比如云窗任務名稱:
可以改為: 黃頁線-積分訂單指定時間資料統計
【正例】招聘-積分流水每日全量統計
【正例】積分-積分流水每日全量統計
? DP任務:{自定義前綴}{表名}{自定義后綴};主要是為了方便通過表名立刻定位具體任務,具體的自定義前綴和后綴為非必須值,
? 云窗表名:若為增量表固定格式:{自定義名}_daily_incr;全量表固定格式:{自定義名}_whole
(2)【強制】任務停用時,需在任務描述中注明具體停用原因,對應啟用任務時洗掉相關停用描述,
(3)【強制】DP任務SQL中禁止使用 unix_timestamp()函式做日期轉化操作,因為決議SQL時因使用了SQL的函式,導致Hive無法決議SQL進行優化,導致MySQL負載,
【正例】$bash{date -d\'${dateSuffix}\' +%s%3N}
【反例】unix_timestamp(\'${dateSuffix}\',\'yyyyMMdd\')*1000
(4)【強制】拉取MySQL資料庫當且僅能使用ETL庫,
(5)【推薦】DP拉取已增量拉取為主,若為特殊必要,謹慎使用全量拉取,并且需要設定定期洗掉策略,
三. 服務部署規范
(1) 【推薦】區分正式jar包和快照jar包兩套規則,不能跳包,例如例如正式為包1.0.0,最新快照包為1.0.2-SNAPSHOT,打正式包時應為1.0.1,
(2) 【推薦】使用jdk版本1.8;
(3) 【推薦】Jvm引數設定:
設定metaspace: -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M
設定堆記憶體大小:最大值和最小值一樣 -Xms4g -Xmx4g
設定測驗環境遠程debug埠:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5855
設定出現oom時自動dump記憶體檔案快照:
-XX:+HeapDumpOnOutOfMemoryError
設定dump的檔案目錄 -XX:HeapDumpPath=${目錄}
設定列印GC日志:
-XX:+PrintGC 輸出GC日志
-XX:+PrintGCDetails 輸出GC的詳細日志
-XX:+PrintGCTimeStamps 輸出GC的時間戳(以基準時間的形式)
-XX:+PrintGCDateStamps 輸出GC的時間戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
四. 日志列印規范
(一) 日志規范
(1)【強制】日志需注明呼叫時間,(日志初始化配置應有相關配置)
(2)【推薦】日志進行具體分類,但不應過細,推薦日志分類不超過8個,
(3)【推薦】日志內容應正確使用占位符,而非字串拼接方法,
【正例】
【反例】
(4)【推薦】對于集合類結果的列印需要考慮記憶體的承受,需要防止資料過大將記憶體擊垮,
可以采用列印集合大小或者采用debug級別模式,在需要的時候再列印集合內容的方式
【反例】
(5)【強制】例外捕獲后必須增加日志,且列印例外資訊Exception,捕獲后不處理是埋雷操作,
(6)【推薦】交易類介面需要列印業務的請求引數和回應引數,以方便排查業務呼叫相關的問題,
(7)【強制】日志列印內容需包括完整的類路徑名稱,以及交易的主標識資訊,配置資訊參考如下:
輸出日志格式如下:
Error級別的日志按重要度可以考慮輸出到郵件組,以供及時介入問題,
郵件資訊配置如下:
五.服務架構
(1) 整體工程可以分為對外協議(contract),業務實作(service)
Service層用來進行具體的業務實作,可以劃分為component,communication,dao,biz層等,
component:引數校驗,模型轉換
biz處理真正的業務邏輯
communication負責與第三方系統通信互動,比如操作日志,與攤銷互動;
dao 負責mapper,sql操作底層db或redis
其中biz層還可根據不同的模塊功能進行更細節的劃分,外加其他模塊的業務處理邏輯,共享一個工具類.
(2) 服務依賴中禁止進行直接/間接的回圈依賴,需要讓依賴保證線性的關系
【反例】A服務的pom中依賴B服務的介面,同時B服務中依賴A服務的介面
(3) 線上應用不要依賴SNAPSHOT版本;正式發布的類別庫必須先去中央倉庫進行查證,使RELEASE版本號有延續性,且版本號不允許覆寫升級,
(4) 服務中依賴的外部服務,按場景做好降級
【正例】資源服務呼叫攤銷介面時就做了降級,雖然是異步的呼叫,但是為了保證執行緒的復用和服務佇列的堆積,防止超時帶來的執行緒長時間阻塞而影響主服務;
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/196909.html
標籤:架構設計
下一篇:Hystrix 配置引數全決議
