自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

優(yōu)秀后端都應(yīng)該具備的開發(fā)好習(xí)慣,你學(xué)會了嗎?

開發(fā) 后端
遠程操作或者數(shù)據(jù)庫操作都是比較耗網(wǎng)絡(luò)、IO資源的,所以盡量不在循環(huán)里遠程調(diào)用、不在循環(huán)里操作數(shù)據(jù)庫,能批量一次性查回來盡量不要循環(huán)多次去查。

?前言

大家好,我是撿田螺的小男孩。

畢業(yè)五年多,一共待過3家公司,碰到各種各樣的同事,見識過各種各樣的代碼,有優(yōu)雅的,賞心悅目的,也有垃圾的,屎山一樣的。因此,寫這篇文章,來記錄一下一個優(yōu)秀的后端開發(fā)程序員,應(yīng)該有哪些好的開發(fā)習(xí)慣。

1.注釋盡可能全面,寫有意義的注釋

接口方法、類、復(fù)雜的業(yè)務(wù)邏輯,都應(yīng)該添加有意義的注釋

  • 對于接口方法的注釋,應(yīng)該包含詳細的入?yún)⒑徒Y(jié)果說明,有異常拋出的情況也要詳細敘述
  • 類的注釋應(yīng)該包含類的功能說明、作者和修改者。
  • 如果是業(yè)務(wù)邏輯很復(fù)雜的代碼,真的非常有必要寫清楚注釋。

清楚的注釋,更有利于后面的維護。

2.項目拆分合理的目錄結(jié)構(gòu)

記得讀大學(xué)那會,剛學(xué)做各種各樣的管理系統(tǒng),都是用MVC?模式,也就是controller、service、mapper、entity?。如果未來業(yè)務(wù)擴展,你沒有拆分業(yè)務(wù)結(jié)構(gòu)的話,很可能就會發(fā)現(xiàn),一個service包下,有上百個服務(wù)。。。

正確的做法,如果服務(wù)過多,應(yīng)該根據(jù)不同的業(yè)務(wù)進行劃分,比如訂單、登陸、積分等等

圖片

當(dāng)然,你也可以根據(jù)不同的業(yè)務(wù)劃分模塊,比如建一個moudles?包,然后按訂單、登陸等業(yè)務(wù)劃分,每個業(yè)務(wù)都有自己的controller、service、mapper、entity。

我們拆分的目的,就是讓項目結(jié)構(gòu)更清晰,可讀性更強,更容易維護而已。

3. 不在循環(huán)里遠程調(diào)用、或者數(shù)據(jù)庫操作,優(yōu)先考慮批量進行。

遠程操作或者數(shù)據(jù)庫操作都是比較耗網(wǎng)絡(luò)、IO資源的,所以盡量不在循環(huán)里遠程調(diào)用、不在循環(huán)里操作數(shù)據(jù)庫,能批量一次性查回來盡量不要循環(huán)多次去查。(但是呢,如果是操作數(shù)據(jù)庫,也不要一次性查太多數(shù)據(jù)哈,可以分批500一次醬紫)。

正例:

remoteBatchQuery(param);

反例:

for(int i=0;i<n;i++){
remoteSingleQuery(param)
}

4. 封裝方法形參

如果你的方法參數(shù)過多,要封裝一個對象出來。反例如下:

public void getUserInfo(String name,String age,String sex,String mobile,String idNo){
// do something ...
}

如果參數(shù)很多,做新老接口兼容處理也比較麻煩。建議寫個對象出來,如下:

public void getUserInfo(UserInfoParamDTO userInfoParamDTO){
// do something ...
}

class UserInfoParamDTO{
private String name;
private String age;
private String sex;
private String mobile;
private String idNo;
}

5. 封裝通用模板

一個優(yōu)秀的后端開發(fā),應(yīng)該具備封裝通用模板的編碼能力。

我們來看一個業(yè)務(wù)需求:假設(shè)我們有這么一個業(yè)務(wù)場景:內(nèi)部系統(tǒng)不同商戶,調(diào)用我們系統(tǒng)接口,去跟外部第三方系統(tǒng)交互(http方式)。走類似這么一個流程,如下:

圖片

一個請求都會經(jīng)歷這幾個流程:

  • 查詢商戶信息
  • 對請求報文加簽
  • 發(fā)送http請求出去
  • 對返回的報文驗簽

通過HTTP發(fā)請求出去時,有的商戶可能是走代理的,有的是走直連。假設(shè)當(dāng)前有A,B商戶接入,不少伙伴可能這么實現(xiàn),偽代碼如下:


// 商戶A處理句柄
CompanyAHandler implements RequestHandler {
Resp hander(req){
//查詢商戶信息
queryMerchantInfo();
//加簽
signature();
//http請求(A商戶假設(shè)走的是代理)
httpRequestbyProxy()
//驗簽
verify();
}
}
// 商戶B處理句柄
CompanyBHandler implements RequestHandler {
Resp hander(Rreq){
//查詢商戶信息
queryMerchantInfo();
//加簽
signature();
// http請求(B商戶不走代理,直連)
httpRequestbyDirect();
// 驗簽
verify();
}
}

假設(shè)新加一個C商戶接入,你需要再實現(xiàn)一套這樣的代碼。顯然,這樣代碼就重復(fù)了。這時候我們可以封裝一個通用模板!我們就可以定義一個抽象類,包含請求流程的幾個方法,偽代碼如下:


abstract class AbstractMerchantService {

//模板方法流程
Resp handlerTempPlate(req){
//查詢商戶信息
queryMerchantInfo();
//加簽
signature();
//http 請求
httpRequest();
// 驗簽
verifySinature();
}
// Http是否走代理(提供給子類實現(xiàn))
abstract boolean isRequestByProxy();
}

然后所有商戶接入,都做這個流程。如果這個通用模板是你抽取的,別的小伙伴接到開發(fā)任務(wù),都是接入你的模板,是不是會有點自豪呀,哈哈~

封裝通用模板,就是抽個模板模式嘛?其實不僅僅是,而是自己對需求、代碼的思考與總結(jié),一種編程思想的升華。

6. 封裝復(fù)雜的邏輯判斷條件

我們來看下這段代碼:

    public void test(UserStatus userStatus){
if (userStatus != UserStatus.BANNED && userStatus != UserStatus.DELETED && userStatus != UserStatus.FROZEN) {
//doSomeThing
return
}
}

這段代碼有什么問題呢?是的,邏輯判斷條件太復(fù)雜啦,我們可以封裝一下它。如下:

    public void test(UserStatus userStatus){
if (isUserActive(userStatus)) {
//doSomeThing
}
}

private boolean isUserActive(UserStatus userStatus) {
return userStatus != UserStatus.BANNED && userStatus != UserStatus.DELETED && userStatus != UserStatus.FROZEN;
}

7. 保持優(yōu)化性能的嗅覺

優(yōu)秀的后端開發(fā),應(yīng)該保持優(yōu)化性能的嗅覺。比如避免創(chuàng)建比必要的對象、異步處理、使用緩沖流,減少IO操作等等。

比如,我們設(shè)計一個APP?首頁的接口,它需要查用戶信息、需要查banner信息、需要查彈窗信息等等。假設(shè)耗時如下:

圖片

查用戶信息200?ms,查banner信息100?ms、查彈窗信息50?ms,那一共就耗時350?ms了。如果還查其他信息,那耗時就更大了。如何優(yōu)化它呢?可以并行發(fā)起,耗時可以降為200ms。如下:

圖片

之前我寫過一篇后端思維的文章,手把手教大家如何抽并行調(diào)用框架,大家可以看下:后端思維篇:手把手教你寫一個并行調(diào)用模板

8. 可變參數(shù)的配置化處理

日常開發(fā)中,我們經(jīng)常會遇到一些可變參數(shù),比如用戶多少天沒登錄注銷、運營活動,不同節(jié)日紅包皮膚切換、訂單多久沒付款就刪除?等等。對于這些可變的參數(shù),不用該直接寫死在代碼。優(yōu)秀的后端,要做配置化處理,你可以把這些可變參數(shù),放到數(shù)據(jù)庫一個配置表里面,也可以放到項目的配置文件或者apollo上。

比如產(chǎn)品經(jīng)理提了個紅包需求,圣誕節(jié)的時候,紅包皮膚為圣誕節(jié)相關(guān)的,春節(jié)的時候,為春節(jié)紅包皮膚等。如果在代碼寫死控制,可有類似以下代碼:

if(duringChristmas){
img = redPacketChristmasSkin;
}else if(duringSpringFestival){
img = redSpringFestivalSkin;
}

如果到了元宵節(jié)的時候,運營小姐姐突然又有想法,紅包皮膚換成燈籠相關(guān)的,這時候,是不是要去修改代碼了,重新發(fā)布了?

從一開始接口設(shè)計時,可以實現(xiàn)一張紅包皮膚的配置表,將紅包皮膚做成配置化呢?更換紅包皮膚,只需修改一下表數(shù)據(jù)就好了。當(dāng)然,還有一些場景適合一些配置化的參數(shù):一個分頁多少數(shù)量控制、某個搶紅包多久時間過期這些,都可以搞到參數(shù)配置化表里面。這也是擴展性思想的一種體現(xiàn)。

9. 會總結(jié)并使用工具類。

很多小伙伴,判斷一個list是否為空,會這么寫:

if (list == null || list.size() == 0) {
return null;
}

這樣寫呢,邏輯是沒什么問題的。但是更建議用工具類,比如:

if (CollectionUtils.isEmpty(list)) {
return null;
}

日常開發(fā)中,我們既要會用工具類,更要學(xué)會自己去總結(jié)工具類。比如去文件處理工具類、日期處理工具類等等。這些都是優(yōu)秀后端開發(fā)的一些好習(xí)慣。

10. 控制方法函數(shù)復(fù)雜度

你的方法不要寫得太復(fù)雜,邏輯不要混亂,也不要太長。一個函數(shù)不能超過80行。寫代碼不僅僅是能跑就行,而是為了以后更好的維護。

反例如下:

public class Test {
private String name;
private Vector<Order> orders = new Vector<Order>();

public void printOwing() {
//print banner
System.out.println("****************");
System.out.println("*****customer Owes *****");
System.out.println("****************");

//calculate totalAmount
Enumeration env = orders.elements();
double totalAmount = 0.0;
while (env.hasMoreElements()) {
Order order = (Order) env.nextElement();
totalAmount += order.getAmout();
}

//print details
System.out.println("name:" + name);
System.out.println("amount:" + totalAmount);
......
}
}

其實可以使用Extract Method,抽取功能單一的代碼段,組成命名清晰的小函數(shù),去解決長函數(shù)問題,正例如下:

public class Test {
private String name;
private Vector<Order> orders = new Vector<Order>();

public void printOwing() {

//print banner
printBanner();
//calculate totalAmount
double totalAmount = getTotalAmount();
//print details
printDetail(totalAmount);
}

void printBanner(){
System.out.println("****************");
System.out.println("*****customer Owes *****");
System.out.println("****************");
}

double getTotalAmount(){
Enumeration env = orders.elements();
double totalAmount = 0.0;
while (env.hasMoreElements()) {
Order order = (Order) env.nextElement();
totalAmount += order.getAmout();
}
return totalAmount;
}

void printDetail(double totalAmount){
System.out.println("name:" + name);
System.out.println("amount:" + totalAmount);
}
}

11. 在finally塊中對資源進行釋放

應(yīng)該大家都有過這樣的經(jīng)歷,windows?系統(tǒng)桌面如果打開太多文件或者系統(tǒng)軟件,就會覺得電腦很卡。當(dāng)然,我們linux?服務(wù)器也一樣,平時操作文件,或者數(shù)據(jù)庫連接,IO?資源流如果沒關(guān)閉,那么這個IO資源就會被它占著,這樣別人就沒有辦法用了,這就造成資源浪費。

我們操作完文件資源,需要在在finally塊中對資源進行釋放。

FileInputStream fdIn = null;
try {
fdIn = new FileInputStream(new File("/公眾號_撿田螺的小男孩.txt"));
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}finally {
try {
if (fdIn != null) {
fdIn.close();
}
} catch (IOException e) {
log.error(e);
}
}

12.把日志打印好

日常開發(fā)中,一定需要把日志打印好。比如:你實現(xiàn)轉(zhuǎn)賬業(yè)務(wù),轉(zhuǎn)個幾百萬,然后轉(zhuǎn)失敗了,接著客戶投訴,然后你還沒有打印到日志,想想那種水深火熱的困境下,你卻毫無辦法。。。

一般情況,方法入?yún)?、出參需要打印日志,異常的時候,也要打印日志等等,如下:

public void transfer(TransferDTO transferDTO){
log.info("invoke tranfer begin");
//打印入?yún)?br> log.info("invoke tranfer,paramters:{}",transferDTO);
try {
res= transferService.transfer(transferDTO);
}catch(Exception e){
log.error("transfer fail,account:{}",
transferDTO.getAccount())
log.error("transfer fail,exception:{}",e);
}
log.info("invoke tranfer end");
}

之前寫過一篇打印日志的15個建議,大家可以看看哈:工作總結(jié)!日志打印的15個建議

13. 考慮異常,處理好異常

優(yōu)秀的后端開發(fā),應(yīng)當(dāng)考慮到異常,并做好異常處理。田螺哥給大家提了10個異常處理的建議:

  • 盡量不要使用e.printStackTrace()?,而是使用log?打印。因為e.printStackTrace()語句可能會導(dǎo)致內(nèi)存占滿。
  • catch?住異常時,建議打印出具體的exception,利于更好定位問題
  • 不要用一個Exception捕捉所有可能的異常
  • 記得使用finally?關(guān)閉流資源或者直接使用try-with-resource。
  • 捕獲異常與拋出異常必須是完全匹配,或者捕獲異常是拋異常的父類
  • 捕獲到的異常,不能忽略它,至少打點日志吧
  • 注意異常對你的代碼層次結(jié)構(gòu)的侵染
  • 自定義封裝異常,不要丟棄原始異常的信息Throwable cause
  • 運行時異常RuntimeException? ,不應(yīng)該通過catch?的方式來處理,而是先預(yù)檢查,比如:NullPointerException處理
  • 注意異常匹配的順序,優(yōu)先捕獲具體的異常

14. 考慮系統(tǒng)、接口的兼容性

優(yōu)秀的后端開發(fā),會考慮系統(tǒng)、接口的兼容性。

如果修改了對外舊接口,但是卻不做兼容。這個問題可能比較嚴(yán)重,甚至?xí)苯訉?dǎo)致系統(tǒng)發(fā)版失敗的。新手程序員很容易犯這個錯誤哦~

因此,如果你的需求是在原來接口上修改,尤其這個接口是對外提供服務(wù)的話,一定要考慮接口兼容。舉個例子吧,比如dubbo?接口,原本是只接收A,B?參數(shù),現(xiàn)在你加了一個參數(shù)C,就可以考慮這樣處理:

//老接口
void oldService(A,B){
//兼容新接口,傳個null代替C
newService(A,B,null);
}

//新接口,暫時不能刪掉老接口,需要做兼容。
void newService(A,B,C){
...
}

15. 采取措施避免運行時錯誤

優(yōu)秀的后端開發(fā),應(yīng)該在編寫代碼階段,就采取措施,避免運行時錯誤,如數(shù)組邊界溢出,被零整除,空指針等運行時錯誤。類似代碼比較常見:

String name = list.get(1).getName(); //list可能越界,因為不一定有2個元素哈

所以,應(yīng)該采取措施,預(yù)防一下數(shù)組邊界溢出,正例如下:

if(CollectionsUtil.isNotEmpty(list)&& list.size()>1){
String name = list.get(1).getName();
}

責(zé)任編輯:武曉燕 來源: 撿田螺的小男孩
相關(guān)推薦

2019-08-21 10:15:41

開發(fā)Redis數(shù)據(jù)

2011-03-24 09:25:54

程序員編程

2022-11-03 08:16:33

MySQL·窗口函數(shù)

2014-10-24 10:13:19

程序員

2022-12-28 09:02:50

WebStorm主題字段

2022-04-29 08:55:43

前端開發(fā)規(guī)范

2009-01-22 10:19:53

2011-06-14 17:50:47

SEO

2024-02-02 11:03:11

React數(shù)據(jù)Ref

2022-07-08 09:27:48

CSSIFC模型

2024-01-02 12:05:26

Java并發(fā)編程

2023-08-01 12:51:18

WebGPT機器學(xué)習(xí)模型

2023-05-30 14:16:00

開源項目Python

2023-01-10 08:43:15

定義DDD架構(gòu)

2024-02-04 00:00:00

Effect數(shù)據(jù)組件

2023-07-26 13:11:21

ChatGPT平臺工具

2024-01-19 08:25:38

死鎖Java通信

2022-04-22 08:10:45

云上數(shù)據(jù)安全

2024-05-29 07:47:30

SpringJava@Resource

2022-12-06 08:37:43

點贊
收藏

51CTO技術(shù)棧公眾號