優秀後端都應該具備的開發好習慣
前言
畢業五年多,一共待過3家公司,碰到各種各樣的同事,見識過各種各樣的程式碼,有優雅的,賞心悅目的,也有垃圾的,屎山一樣的。因此,寫這篇文章,來記錄一下一個優秀的後端開發程式設計師,應該有哪些好的開發習慣。
1.註釋儘可能全面,寫有意義的註釋
介面方法、類、複雜的業務邏輯,都應該新增有意義的註釋
對於介面方法的註釋,應該包含詳細的入參和結果說明,有異常丟擲的情況也要詳細敘述 類的註釋應該包含類的功能說明、作者和修改者。 如果是業務邏輯很複雜的程式碼,真的非常有必要寫清楚註釋。
清楚的註釋,更有利於後面的維護。
2.專案拆分合理的目錄結構
記得讀大學那會,剛學做各種各樣的管理系統,都是用MVC
模式,也就是controller、service、mapper、entity
。如果未來業務擴充套件,你沒有拆分業務結構的話,很可能就會發現,一個service
包下,有上百個服務。。。
正確的做法,如果服務過多,應該根據不同的業務進行劃分,比如訂單、登陸、積分等等
當然,你也可以根據不同的業務劃分模組,比如建一個moudles
包,然後按訂單、登陸等業務劃分,每個業務都有自己的controller、service、mapper、entity
。
我們拆分的目的,就是讓專案結構更清晰,可讀性更強,更容易維護而已。
3. 不在迴圈裡遠端呼叫、或者資料庫操作,優先考慮批次進行。
遠端操作或者資料庫操作都是比較耗網路、IO資源的,所以儘量不在迴圈裡遠端呼叫、不在迴圈裡運算元據庫,能批次一次性查回來儘量不要迴圈多次去查。(但是呢,如果是運算元據庫,也不要一次性查太多資料哈,可以分批500一次醬紫)。
正例:
remoteBatchQuery(param);
反例:
for(int i=0;i<n;i++){
remoteSingleQuery(param)
}
4. 封裝方法形參
如果你的方法引數過多,要封裝一個物件出來。反例如下:
public void getUserInfo(String name,String age,String sex,String mobile,String idNo){
// do something ...
}
如果引數很多,做新老介面相容處理也比較麻煩。建議寫個物件出來,如下:
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. 封裝通用模板
一個優秀的後端開發,應該具備封裝通用模板的編碼能力。
我們來看一個業務需求:假設我們有這麼一個業務場景:內部系統不同商戶,呼叫我們系統介面,去跟外部第三方系統互動(http方式)。走類似這麼一個流程,如下:
一個請求都會經歷這幾個流程:
查詢商戶資訊 對請求報文加簽 傳送http請求出去 對返回的報文驗籤
透過HTTP發請求出去時,有的商戶可能是走代理的,有的是走直連。假設當前有A,B商戶接入,不少夥伴可能這麼實現,虛擬碼如下:
// 商戶A處理控制程式碼
CompanyAHandler implements RequestHandler {
Resp hander(req){
//查詢商戶資訊
queryMerchantInfo();
//加簽
signature();
//http請求(A商戶假設走的是代理)
httpRequestbyProxy()
//驗籤
verify();
}
}
// 商戶B處理控制程式碼
CompanyBHandler implements RequestHandler {
Resp hander(Rreq){
//查詢商戶資訊
queryMerchantInfo();
//加簽
signature();
// http請求(B商戶不走代理,直連)
httpRequestbyDirect();
// 驗籤
verify();
}
}
假設新加一個C商戶接入,你需要再實現一套這樣的程式碼。顯然,這樣程式碼就重複了。這時候我們可以封裝一個通用模板!我們就可以定義一個抽象類,包含請求流程的幾個方法,虛擬碼如下:
abstract class AbstractMerchantService {
//模板方法流程
Resp handlerTempPlate(req){
//查詢商戶資訊
queryMerchantInfo();
//加簽
signature();
//http 請求
httpRequest();
// 驗籤
verifySinature();
}
// Http是否走代理(提供給子類實現)
abstract boolean isRequestByProxy();
}
然後所有商戶接入,都做這個流程。如果這個通用模板是你抽取的,別的小夥伴接到開發任務,都是接入你的模板,是不是會有點自豪呀,哈哈~
封裝通用模板,就是抽個模板模式嘛?其實不僅僅是,而是自己對需求、程式碼的思考與總結,一種程式設計思想的昇華。
6. 封裝複雜的邏輯判斷條件
我們來看下這段程式碼:
public void test(UserStatus userStatus){
if (userStatus != UserStatus.BANNED && userStatus != UserStatus.DELETED && userStatus != UserStatus.FROZEN) {
//doSomeThing
return
}
}
這段程式碼有什麼問題呢?是的,邏輯判斷條件太複雜啦,我們可以封裝一下它。如下:
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. 保持最佳化效能的嗅覺
優秀的後端開發,應該保持最佳化效能的嗅覺。比如避免建立比必要的物件、非同步處理、使用緩衝流,減少IO操作
等等。
比如,我們設計一個APP
首頁的介面,它需要查使用者資訊、需要查banner資訊、需要查彈窗資訊
等等。假設耗時如下:
查使用者資訊200
ms,查banner資訊100
ms、查彈窗資訊50
ms,那一共就耗時350
ms了。如果還查其他資訊,那耗時就更大了。如何最佳化它呢?可以並行發起,耗時可以降為200
ms。如下:
之前我寫過一篇後端思維的文章,手把手教大家如何抽並行呼叫框架,大家可以看下:後端思維篇:手把手教你寫一個並行呼叫模板
8. 可變引數的配置化處理
日常開發中,我們經常會遇到一些可變引數,比如使用者多少天沒登入登出
、運營活動,不同節日紅包皮膚切換、訂單多久沒付款就刪除
等等。對於這些可變的引數,不用該直接寫死在程式碼。優秀的後端,要做配置化處理,你可以把這些可變引數,放到資料庫一個配置表裡面,也可以放到專案的配置檔案或者apollo
上。
比如產品經理提了個紅包需求,聖誕節的時候,紅包皮膚為聖誕節相關的,春節的時候,為春節紅包皮膚等。如果在程式碼寫死控制,可有類似以下程式碼:
if(duringChristmas){
img = redPacketChristmasSkin;
}else if(duringSpringFestival){
img = redSpringFestivalSkin;
}
如果到了元宵節的時候,運營小姐姐突然又有想法,紅包皮膚換成燈籠相關的,這時候,是不是要去修改程式碼了,重新發布了?
從一開始介面設計時,可以實現一張紅包皮膚的配置表,將紅包皮膚做成配置化呢?更換紅包皮膚,只需修改一下表資料就好了。當然,還有一些場景適合一些配置化的引數:一個分頁多少數量控制、某個搶紅包多久時間過期這些,都可以搞到引數配置化表裡面。這也是擴充套件性思想的一種體現。
9. 會總結並使用工具類。
很多小夥伴,判斷一個list
是否為空,會這麼寫:
if (list == null || list.size() == 0) {
return null;
}
這樣寫呢,邏輯是沒什麼問題的。但是更建議用工具類,比如:
if (CollectionUtils.isEmpty(list)) {
return null;
}
日常開發中,我們既要會用工具類,更要學會自己去總結工具類。比如去檔案處理工具類、日期處理工具類等等。這些都是優秀後端開發的一些好習慣。
10. 控制方法函式複雜度
你的方法不要寫得太複雜,邏輯不要混亂,也不要太長。一個函式不能超過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
,抽取功能單一的程式碼段,組成命名清晰的小函式,去解決長函式問題,正例如下:
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塊中對資源進行釋放
應該大家都有過這樣的經歷,windows
系統桌面如果開啟太多檔案或者系統軟體,就會覺得電腦很卡。當然,我們linux
伺服器也一樣,平時操作檔案,或者資料庫連線,IO
資源流如果沒關閉,那麼這個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.把日誌列印好
日常開發中,一定需要把日誌列印好。比如:你實現轉賬業務,轉個幾百萬,然後轉失敗了,接著客戶投訴,然後你還沒有列印到日誌,想想那種水深火熱的困境下,你卻毫無辦法。。。
一般情況,方法入參、出參需要列印日誌,異常的時候,也要列印日誌等等,如下:
public void transfer(TransferDTO transferDTO){
log.info("invoke tranfer begin");
//列印入參
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個建議,大家可以看看哈:工作總結!日誌列印的15個建議
13. 考慮異常,處理好異常
優秀的後端開發,應當考慮到異常,並做好異常處理。田螺哥給大家提了10個異常處理的建議:
儘量不要使用 e.printStackTrace()
,而是使用log
列印。因為e.printStackTrace()
語句可能會導致記憶體佔滿。catch
住異常時,建議列印出具體的exception
,利於更好定位問題不要用一個 Exception
捕捉所有可能的異常記得使用 finally
關閉流資源或者直接使用try-with-resource
。捕獲異常與丟擲異常必須是完全匹配,或者捕獲異常是拋異常的父類 捕獲到的異常,不能忽略它,至少打點日誌吧 注意異常對你的程式碼層次結構的侵染 自定義封裝異常,不要丟棄原始異常的資訊 Throwable cause
執行時異常 RuntimeException
,不應該透過catch
的方式來處理,而是先預檢查,比如:NullPointerException
處理注意異常匹配的順序,優先捕獲具體的異常
14. 考慮系統、介面的相容性
優秀的後端開發,會考慮系統、介面的相容性。
如果修改了對外舊介面,但是卻不做相容。這個問題可能比較嚴重,甚至會直接導致系統發版失敗的。新手程式設計師很容易犯這個錯誤哦~
因此,如果你的需求是在原來介面上修改,尤其這個介面是對外提供服務的話,一定要考慮介面相容。舉個例子吧,比如dubbo
介面,原本是隻接收A,B
引數,現在你加了一個引數C
,就可以考慮這樣處理:
//老介面
void oldService(A,B){
//相容新介面,傳個null代替C
newService(A,B,null);
}
//新介面,暫時不能刪掉老介面,需要做相容。
void newService(A,B,C){
...
}
15. 採取措施避免執行時錯誤
優秀的後端開發,應該在編寫程式碼階段,就採取措施,避免執行時錯誤,如陣列邊界溢位,被零整除,空指標等執行時錯誤。類似程式碼比較常見:
String name = list.get(1).getName(); //list可能越界,因為不一定有2個元素哈
所以,應該採取措施,預防一下陣列邊界溢位,正例如下:
if(CollectionsUtil.isNotEmpty(list)&& list.size()>1){
String name = list.get(1).getName();
}
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2924537/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 優秀的測試開發應該具備的六大能力
- 一個優秀的智慧展廳應該具備哪些能力
- 【翻譯】WWDC 2019 :優秀的開發習慣
- 後端開發都應該瞭解的登入漏洞後端
- 優秀網際網路高階測試工程師應該具備的能力工程師
- 優秀的專案管理應具備哪些條件?專案管理
- 後端開發都應該瞭解的資訊洩露風險後端
- 一份優秀的資料分析報告應該具備這些要點!
- 投影沙盤的應用都具備哪些優勢
- 轉行學習web前端開發應該具備的條件,這4點,80%的人都堅持不下!Web前端
- 4-6年經驗左右、優秀的 Java 程式設計師應該具備的技能Java程式設計師
- 數字沙盤的應用都具備哪些優勢
- 全息投影技術的應用都具備哪些優勢?
- 地面互動投影的應用都具備哪些優勢
- 安全教育APP開發應該具備哪些功能APP
- 優秀的Web前端開發工程師需要具備的4個條件!Web前端工程師
- 優秀的ITSM(IT服務管理系統)應具備哪些特徵?特徵
- 「完結」優秀的深度學習從業者都有哪些優秀的習慣深度學習
- 互動投影技術的應用都具備哪些優勢?
- 投影互動遊戲的應用都具備哪些優勢遊戲
- 轉行學習web前端開發程式設計師應該具備的條件Web前端程式設計師
- 後端開發應該掌握的Redis基礎後端Redis
- 企業展廳的製作都具備哪些應用優勢
- 企業展廳設計的應用都具備哪些優勢
- 一款好的智慧機器人應該具備哪些功能?機器人
- 10個程式設計好習慣:優秀程式設計師的經驗分享程式設計師
- 網校平臺開發前的設計:應該具備哪些功能?
- 優質的企業展廳都具備哪些優勢
- 虛擬漫遊技術都具備哪些應用優勢
- 數字展廳建設都具備哪些應用優勢
- 城市規劃沙盤的製作都具備哪些應用優勢
- BugKu之備份是個好習慣
- 優秀的DevOps工程師必須具備的軟技能dev工程師
- 醫療保健ERP管理系統都應該具備哪些核心功能?
- 3-5 年的 PHPer 應該具備PHP
- 全息幻影成像的應用都具備哪些特徵特徵
- 互動投影的應用都具備哪些特性
- 一套優質的MES系統,應該具備哪些特質?