一戈毒、代碼的可讀性
1.1艰猬、命名
命名隨處可見,給變量埋市、函數(shù)冠桃、參數(shù)、類和封包命名道宅。應(yīng)遵循規(guī)范文檔的命名規(guī)范食听,并且一旦發(fā)現(xiàn)有更好的名稱,就換掉舊的污茵。這么做樱报,你和讀你代碼的人都會更開心。
1.2泞当、格式
- 大括號與if, else, for, do, while語句一起使用迹蛤,即使只有一條語句(或是空),也應(yīng)該把大括號寫上 襟士;
- 空的塊狀結(jié)構(gòu)可以簡寫為一行盗飒,但如果他是多塊狀結(jié)構(gòu)的一部分,無論如何也要換行陋桂;
//空塊狀結(jié)構(gòu)
void do(){}
if() return ;
//多塊狀結(jié)構(gòu)
if(expression){
}else if(otherExpression){
}else{
}
- 一行代碼超過80個字符需要換行逆趣;
- 一個方法函數(shù)內(nèi)的代碼不超過100行。
1.3章喉、異常
- 異常處理需要對java和spring的異常體系有所了解汗贫,并遵循對已知捕獲身坐、對未知拋出的原則,進(jìn)行項(xiàng)目內(nèi)異常體系的構(gòu)建落包、優(yōu)化部蛇;
- 長代碼塊的異常需要分別處理,不要在一個try catch中進(jìn)行捕獲咐蝇;
- 反例:
public void test(){
try{
do smoething
do smoething
do smoething
}catch(Exception e){
}
}
- 正例:
public void test(){
try{
do smoething
}catch(Exception e){
}
try{
do smoething
}catch(Exception e){
}
try{
do smoething
}catch(Exception e){
}
}
- 循環(huán)體內(nèi)不要使用try catch涯鲁,需要時在循環(huán)外使用;
1.4有序、常量/魔術(shù)值
- 所有常量的修飾符必須含有static final抹腿;
- 常量的使用域需要限制在相應(yīng)模塊中,防止版本更迭后其他模塊發(fā)生錯誤旭寿;
- 代碼中涉及邏輯中斷和條件判斷不要出現(xiàn)不明的警绩、未經(jīng)釋義的值,需要有明確命名魔術(shù)值盅称;
- 反例:
public boolean hasAdminRole(List<Role> roles){
for(Role role : roles){
if(user.getId == 9527){
return true;
}
}
return false;
}
- 正例:
//key角色對應(yīng)的id
private static final Integer KEY_ROLE_ID = 9527;
public boolean hasKeyRole(List<Role> roles){
for(Role role : roles){
if(user.getId == KEY_ROLE_ID){
return true;
}
}
return false;
}
1.5肩祥、函數(shù)
- 每一個方法函數(shù)在邏輯上應(yīng)該包含明確的 輸入(參數(shù))和輸出(返回值);
- 一個方法函數(shù)需要明確的主體邏輯和次要邏輯缩膝,對于復(fù)雜冗長的函數(shù)混狠,盡可能的展現(xiàn)主體邏輯,拆分次要邏輯到其他函數(shù)中疾层,進(jìn)行模塊化編程将饺;
- 反例:
public LoginUser getUserInfo(){
//獲取用戶 token
ServletAttributs requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRquest();
String token = request.getHeader("access_token");
if(StringUtils.isEmpty(token)){
throw new EmptyLoginTokenException("用戶登錄token獲取錯誤");
}
//根據(jù)token 獲取用戶信息
SysUser user = (SysUser)redisUtil.get(token);
//轉(zhuǎn)換loginUser
LoginUser loginUser = new LoginUser();
loginUser.setId(user.getId());
loginUser.setAccount(user.getAccout());
loginUser.setName(user.getName());
...
//補(bǔ)充角色信息
List<SysRole> roles = new ArrayList<>();
roles = roleService.getRolesByUserId(loginUser.getId());
if(CollectionUtils.isNotEmpty(roles)){
Set<SysRole> roleSet = new HashSet(roles);
roles.setRoles(roleSet);
//補(bǔ)充權(quán)限信息
List<SysPermission> permissions = new ArrayList<>();
permissions = permissionService.getPermissionsByRoles(roles);
if(CollectionUtils.isNotEmpty(permissions)){
Set<SysRSysPermissionole> permissionSet = new HashSet(permissions);
roles.setPermissions(permissionSet);
...
}
}
return loginUser;
}
- 正例:
public LoginUser getUserInfo(){
//獲取用戶 token
String token = getToken();
//根據(jù)token 獲取用戶信息
SysUser user = (SysUser)redisUtil.get(token);
if(ObjectUtil.isNEmpty(user)){
return null;
}
//轉(zhuǎn)換loginUser
LoginUser loginUser = convertLoginUser(user);
//補(bǔ)充角色信息
supplyLoginUser(loginUser);
return loginUser;
}
private String getToken(){
ServletAttributs requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRquest();
String token = request.getHeader("access_token");
if(StringUtils.isEmpty(token)){
throw new EmptyLoginTokenException("用戶登錄token獲取錯誤");
}
return token;
}
private LoginUser convertLoginUser(SysUser user){
LoginUser loginUser = new LoginUser();
loginUser.setId(user.getId());
loginUser.setAccount(user.getAccout());
loginUser.setName(user.getName());
...
return loginUser;
}
private void supplyLoginUser(LoginUser loginUser){
List<SysRole> roles = new ArrayList<>();
roles = roleService.getRolesByUserId(loginUser.getId());
if(CollectionUtils.isNotEmpty(roles)){
Set<SysRole> roleSet = new HashSet(roles);
roles.setRoles(roleSet);
//補(bǔ)充權(quán)限信息
List<SysPermission> permissions = new ArrayList<>();
permissions = permissionService.getPermissionsByRoles(roles);
if(CollectionUtils.isNotEmpty(permissions)){
Set<SysRSysPermissionole> permissionSet = new HashSet(permissions);
roles.setPermissions(permissionSet);
...
}
}
}
1.6、嵌套
- 一個方法函數(shù)內(nèi)的嵌套不要超過三層痛黎;
- 反例:
void render(List<User> users){
if(CollectinUtils.isNotEmpty(users)){
for(User user : users){
if(CollectinUtils.isNotEmpty(user.getRoles())){
for(Role role : user.getRoles()){
do something
}
}
}
}
}
- 正例:
void render(List<User> users){
if(CollectinUtils.isEmpty(users)){
return;
}
for(User user : users){
if(CollectinUtils.isEmpty(user.getRoles())){
continue;
}
for(Role role : user.getRoles()){
do something
}
}
}
1.7予弧、條件
- 循環(huán)條件進(jìn)行邏輯上的合并;
- 合并前:
List goodNames = new ArrayList<>();
if(bool){
for (String name: names) {
if (name.contains("bad")) {
continue;
}
goodNames.add(name);
...
}
}
- 合并后:
List goodNames = new ArrayList<>();
for (String name: names) {
if (!name.contains("bad")) {
goodNames.add(name);
...
}
}
- 多條件判斷超過三個需要換行舅逸;
if(menus.contain(MenuEnums.HOME_PAGE)
&& menus.contain(MenuEnums.ERROR_PAGE)
&& menus.contain(MenuEnums.LOGIN_PAGE)){
}
- 賦值條件為2個時盡量使用三目運(yùn)算符號桌肴;
Subject sub = new Subject();
sub.setDataScope(UserContext.hasAdminRole()?"all":user.getDataScope());
1.8皇筛、邊界
項(xiàng)目管理中琉历,項(xiàng)目由進(jìn)度、成本水醋、質(zhì)量和邊界構(gòu)成旗笔,邊界是指研發(fā)過程中應(yīng)完成需求對應(yīng)的功能,避免不必要的過度編碼拄踪,由此引發(fā)的返工問題也會回過頭來影響進(jìn)度蝇恶、成本與代碼質(zhì)量。
1.9惶桐、注釋
- 遵循注釋規(guī)范使用單行注釋與多行注釋撮弧,代碼中不要使用尾注釋潘懊;
- 優(yōu)雅代碼應(yīng)追求即使沒有注釋仍能被看懂的原則,通過規(guī)范的命名和簡介的功能描述減少冗余注釋的編寫贿衍;
二授舟、代碼的可維護(hù)性
- 編寫時可維護(hù)性:是指在程序或系統(tǒng)上線后爆出 BUG,開發(fā)團(tuán)隊(duì)能夠及時撲滅這個 BUG 且不會爆出其他 BUG贸辈。保持方法的原子性释树,提高代碼內(nèi)聚,能使某處修改的影響降到最低擎淤,這樣某處方法出現(xiàn) BUG奢啥,也不太會影響到其他模塊的正常運(yùn)作;
- 運(yùn)行時的可維護(hù)性:是指在系統(tǒng)運(yùn)行過程中(或無需再次編碼發(fā)布嘴拢、只需系統(tǒng)重啟一次)修改系統(tǒng)的某項(xiàng)配置并使其生效桩盲,且不影響現(xiàn)在正在進(jìn)行的業(yè)務(wù)和用戶的操作。這要求軟件工程師不能把代碼寫死席吴。例如配置文件正驻、數(shù)據(jù)庫連接字符串、資源文件抢腐、日志等姑曙。
三、代碼的可變更性
- 提高代碼的復(fù)用:需要對整個系統(tǒng)的整體進(jìn)行分析與合理規(guī)劃迈倍,長期不斷的對系統(tǒng)模型進(jìn)行劃分伤靠,對模型邊界進(jìn)行設(shè)定,保證每個功能被合理地劃分到響應(yīng)的模型的每個類中啼染,這樣可以很好地保證代碼復(fù)用宴合;
- 設(shè)計(jì)模式:是解決特定問題的一系列套路。它不是語法規(guī)定迹鹅,而是一套用來提高代碼可復(fù)用性卦洽、可維護(hù)性、可讀性斜棚、穩(wěn)健性以及安全性的解決方案阀蒂。
四、技術(shù)評審
技術(shù)評審包含編碼前的方案評審和編碼后的代碼review弟蚀,是代碼質(zhì)量管理方式的一種蚤霞,以下列舉代碼評審階段排排查的典型案例:
- 功能錯誤
- 資源泄漏
- 空的異常處理、缺失日志
- 事務(wù)的使用
- 文檔义钉、類昧绣、方法、復(fù)雜算法注釋
- 重復(fù)代碼
- 過長的方法參數(shù)列表
- if/while/for等嵌套3層以上
- 無實(shí)際意義的類捶闸、方法夜畴、變量名稱