後端思想篇:設計好接口的36個錦囊!

後端思想篇:設計好接口的36個錦囊!

作為後端開發,不管是什麼語言,java、go還是c++,其背後的後端思想都是類似的。

最后更新 2022/7/17 下午7:51
捡田螺的小男孩
预计阅读 26 分钟
分类
分享
标签
Java Go 架構設計

前言

大家好,我是捡田螺的小男孩。作为后端开发,不管是什么语言,JavaGo还是C++,其背后的后端思想都是类似的。后面打算出一个后端思想的技术专栏,主要包括后端的一些设计、或者后端规范相关的,希望对大家日常工作有帮助哈。

我們做後端開發工程師,主要工作就是:如何把一個接口設計好。所以,今天就給大家居間,設計好接口的 36 個錦囊。本文就是後端思想專欄的第一篇哈。

1. 接口參數校驗

入參出參校驗是每個程式設計師必備的基本素養。你設計的接口,必須先校驗參數。比如入參是否允許為空,入參長度是否符合你的預期長度。這個要養成習慣哈,日常開發中,很多低級 bug 都是不校驗參數導致的。

比如你的数据库表字段设置为varchar(16),对方传了一个 32 位的字符串过来,如果你不校验参数,插入数据库直接异常了

出参也是,比如你定义的接口报文,参数是不为空的,但是你的接口返回参数,没有做校验,因为程序某些原因,直接返回别人一个null值。。。

2. 修改老接口時,注意接口的兼容性

很多 bug 都是因為修改了對外舊接口,但是卻不做兼容導致的。關鍵這個問題多數是比較嚴重的,可能直接導致系統發版失敗的。新手程式設計師很容易犯這個錯誤哦~

所以,如果你的需求是在原來接口上修改,尤其這個接口是對外提供服務的話,一定要考慮接口兼容。舉個例子吧,比如 dubbo 接口,原本是只接收 a,b 參數,現在你加了一個參數 c,就可以考慮這樣處理:

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

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

3. 設計接口時,充分考慮接口的可擴展性

要根據實際業務場景設計接口,充分考慮接口的可擴展性。

比如你接到一個需求:是用戶添加或者修改員工時,需要刷臉。那你是反手提供一個員工管理的提交刷臉信息接口?還是先思考:提交刷臉是不是通用流程呢?比如轉帳或者一鍵提現需要接入刷臉的話,你是否需要重新實現一個接口呢?還是當前按業務類型劃分模塊,復用這個接口就好,保留接口的可擴展性。

如果按模塊劃分的話,未來如果其他場景比如一鍵提現接入刷臉的話,不用再搞一套新的接口,只需要新增枚舉,然後復用刷臉通過流程接口,實現一鍵提現刷臉的差異化即可。

4.接口考慮是否需要防重處理

如果前端重複請求,你的邏輯如何處理?是不是考慮接口去重處理。

當然,如果是查詢類的請求,其實不用防重。如果是更新修改類的話,尤其金融轉帳類的,就要過濾重複請求了。簡單點,你可以使用 redis 防重複請求,同樣的請求方,一定時間間隔內的相同請求,考慮是否過濾。當然,轉帳類接口,並發不高的話,推薦使用資料庫防重表,以唯一流水號作為主鍵或者唯一索引

5. 重點接口,考慮線程池隔離。

一些登录、转账交易、下单等重要接口,考虑线程池隔离哈。如果你所有业务都共用一个线程池,有些业务出 bug 导致线程池阻塞打满的话,那就杯具了,所有业务都影响了。因此进行线程池隔离,重要业务分配多一点的核心线程,就更好保护重要业务。

6. 調用第三方接口要考慮異常和超時處理

如果你調用第三方接口,或者分布式遠程服務的的話,需要考慮:

  • 異常處理

比如,你調別人的接口,如果異常了,怎麼處理,是重試還是當做失敗還是告警處理。

  • 接口超時

沒法預估對方接口一般多久返回,一般設置個超時斷開時間,以保護你的接口。之前見過一個生產問題,就是 http 調用不設置超時時間,最後響應方進程假死,請求一直占著線程不釋放,拖垮線程池。

  • 重試次數

你的接口調失敗,需不需要重試?重試幾次?需要站在業務上角度思考這個問題

7. 接口實現考慮熔斷和降級

當前網際網路系統一般都是分布式部署的。而分布式系統中經常會出現某個基礎服務不可用,最終導致整個系統不可用的情況, 這種現象被稱為服務雪崩效應

比如分布式调用链路A->B->C....,下图所示:

如果服務 c 出現問題,比如是因為慢 sql 導致調用緩慢,那將導致 b 也會延遲,從而 a 也會延遲。堵住的 a 請求會消耗占用系統的線程、io 等資源。當請求 a 的服務越來越多,占用計算機的資源也越來越多,最終會導致系統瓶頸出現,造成其他的請求同樣不可用,最後導致業務系統崩潰。

为了应对服务雪崩, 常见的做法是熔断和降级。最简单是加开关控制,当下游系统出问题时,开关降级,不再调用下游系统。还可以选用开源组件Hystrix

8. 日誌列印好,接口的關鍵代碼,要有日誌保駕護航。

關鍵業務代碼無論身處何地,都應該有足夠的日誌保駕護航。比如:你實現轉帳業務,轉個幾百萬,然後轉失敗了,接著客戶投訴,然後你還沒有列印到日誌,想想那種水深火熱的困境下,你卻毫無辦法。。。

那麼,你的轉帳業務都需要哪些日誌信息呢?至少,方法調用前,入參需要列印吧,接口調用後,需要捕獲一下異常吧,同時列印異常相關日誌吧,如下:

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 个建议

9. 接口的功能定義要具備單一性

单一性是指接口做的事情比较单一、专一。比如一个登录接口,它做的事情就只是校验账户名密码,然后返回登录成功以及userId即可。但是如果你为了减少接口交互,把一些注册、一些配置查询等全放到登录接口,就不太妥。

其實這也是微服務一些思想,接口的功能單一、明確。比如訂單服務、積分、商品信息相關的接口都是劃分開的。將來拆分微服務的話,是不是就比較簡便啦。

10.接口有些場景,使用異步更合理

舉個簡單的例子,比如你實現一個用戶註冊的接口。用戶註冊成功時,發個郵件或者短信去通知用戶。這個郵件或者發短信,就更適合異步處理。因為總不能一個通知類的失敗,導致註冊失敗吧。

至於做異步的方式,簡單的就是用線程池。還可以使用消息隊列,就是用戶註冊成功後,生產者產生一個註冊成功的消息,消費者拉到註冊成功的消息,就發送通知。

不是所有的接口都適合設計為同步接口。比如你要做一個轉帳的功能,如果你是單筆的轉帳,你是可以把接口設計同步。用戶發起轉帳時,客戶端在靜靜等待轉帳結果就好。如果你是批量轉帳,一個批次一千筆,甚至一萬筆的,你則可以把接口設計為異步。就是用戶發起批量轉帳時,持久化成功就先返回受理成功。然後用戶隔十分鐘或者十五分鐘等再來查轉帳結果就好。又或者,批量轉帳成功後,再回調上游系統。

11. 優化接口耗時,遠程串行考慮改並行調用

假設我們設計一個 app 首頁的接口,它需要查用戶信息、需要查 banner 信息、需要查彈窗信息等等。那你是一個一個接口串行調,還是並行調用呢?

如果是串行一个一个查,比如查用户信息 200ms,查 banner 信息 100ms、查弹窗信息 50ms,那一共就耗时350ms了,如果还查其他信息,那耗时就更大了。这种场景是可以改为并行调用的。也就是说查用户信息、查 banner 信息、查弹窗信息,可以同时发起。

在 Java 中有个异步编程利器:CompletableFuture,就可以很好实现这个功能。有兴趣的小伙伴可以看我之前这个文章哈:CompletableFuture 详解

12. 接口合併或者說考慮批量處理思想

資料庫操作或或者是遠程調用時,能批量操作就不要 for 循環調用。

一個簡單例子,我們平時一個列表明細數據插入資料庫時,不要在 for 循環一條一條插入,建議一個批次幾百條,進行批量插入。同理遠程調用也類似想法,比如你查詢營銷標籤是否命中,可以一個標籤一個標籤去查,也可以批量標籤去查,那批量進行,效率就更高嘛。

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

//正例
remoteBatchQuery(param);

小伙伴们是否了解过kafka为什么这么快呢?其实其中一点原因,就是kafka 使用批量消息提升服务端处理能力。

13. 接口實現過程中,恰當使用緩存

哪些場景適合使用緩存?讀多寫少且數據時效要求越低的場景

緩存用得好,可以承載更多的請求,提升查詢效率,減少資料庫的壓力。

比如一些平時變動很小或者說幾乎不會變的商品信息,可以放到緩存,請求過來時,先查詢緩存,如果沒有再查資料庫,並且把資料庫的數據更新到緩存。但是,使用緩存增加了需要考慮這些點:緩存和資料庫一致性如何保證、集群、緩存擊穿、緩存雪崩、緩存穿透等問題。

  • 保證資料庫和緩存一致性:緩存延時雙刪、刪除緩存重試機制、讀取 biglog 異步刪除緩存
  • 緩存擊穿:設置數據永不過期
  • 緩存雪崩:redis 集群高可用、均勻設置過期時間
  • 緩存穿透:接口層校驗、查詢為空設置個默認空值標記、布隆過濾器。

一般用Redis分布式缓存,当然有些时候也可以考虑使用本地缓存,如Guava Cache、Caffeine等。使用本地缓存有些缺点,就是无法进行大数据存储,并且应用进程的重启,缓存会失效。

14. 接口考慮熱點數據隔離性

瞬時間的高並發,可能會打垮你的系統。可以做一些熱點數據的隔離。比如業務隔離、系統隔離、用戶隔離、數據隔離等。

  • 業務隔離性,比如 12306 的分時段售票,將熱點數據分散處理,降低系統負載壓力。
  • 系統隔離:比如把系統分成了用戶、商品、社區三個板塊。這三個塊分別使用不同的域名、伺服器和資料庫,做到從接入層到應用層再到數據層三層完全隔離。
  • 用戶隔離:重點用戶請求到配置更好的機器。
  • 數據隔離:使用單獨的緩存集群或者資料庫服務熱點數據。

15. 可變參數配置化,比如紅包皮膚切換等

假如產品經理提了個紅包需求,聖誕節的時候,紅包皮膚為聖誕節相關的,春節的時候,為春節紅包皮膚等。

如果在代碼寫死控制,可有類似以下代碼:

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

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

從一開始接口設計時,可以實現一張紅包皮膚的配置表,將紅包皮膚做成配置化呢?更換紅包皮膚,只需修改一下表數據就好了。

當然,還有一些場景適合一些配置化的參數:一個分頁多少數量控制、某個搶紅包多久時間過期這些,都可以搞到參數配置化表裡面。這也是擴展性思想的一種體現

16.接口考慮冪等性

接口是需要考虑幂等性的,尤其抢红包、转账这些重要接口。最直观的业务场景,就是用户连着点击两次,你的接口有没有hold住。或者消息队列出现重复消费的情况,你的业务逻辑怎么控制?

回憶下,什麼是冪等?

計算機科學中,冪等表示一次和多次請求某一個資源應該具有同樣的副作用,或者說,多次請求所產生的影響與一次請求執行的影響效果相同。

大家別搞混哈,防重和冪等設計其實是有區別的。防重主要為了避免產生重複數據,把重複請求攔截下來即可。而冪等設計除了攔截已經處理的請求,還要求每次相同的請求都返回一樣的效果。不過呢,很多時候,它們的處理流程、方案是類似的哈。

接口冪等實現方案主要有 8 種:

  • select+insert+主鍵/唯一索引衝突
  • 直接 insert + 主鍵/唯一索引衝突
  • 狀態機冪等
  • 抽取防重表
  • token 令牌
  • 悲觀鎖
  • 樂觀鎖
  • 分布式鎖

大家可以看我这篇文章哈:聊聊幂等设计

17. 讀寫分離,優先考慮讀從庫,注意主從延遲問題

我們的資料庫都是集群部署的,有主庫也有從庫,當前一般都是讀寫分離的。比如你寫入數據,肯定是寫入主庫,但是對於讀取實時性要求不高的數據,則優先考慮讀從庫,因為可以分擔主庫的壓力。

如果讀取從庫的話,需要考慮主從延遲的問題。

18.接口注意返回的數據量,如果數據量大需要分頁

一個接口返回報文,不應該包含過多的數據量。過多的數據量不僅處理複雜,並且數據量傳輸的壓力也非常大。因此數量實在是比較大,可以分頁返回,如果是功能不相關的報文,那應該考慮接口拆分。

19. 好的接口實現,離不開 sql 優化

我們做後端的,寫好一個接口,離不開 sql 優化。

sql 優化從這幾個維度思考:

  • explain 分析 sql 查詢計劃(重點關注 type、extra、filtered 欄位)
  • show profile 分析,了解 sql 執行的線程的狀態以及消耗的時間
  • 索引優化 (覆蓋索引、最左前綴原則、隱式轉換、order by 以及 group by 的優化、join 優化)
  • 大分頁問題優化(延遲關聯、記錄上一頁最大 id)
  • 數據量太大(分庫分表、同步到 es,用 es 查詢)

20.代碼鎖的粒度控制好

什麼是加鎖粒度呢?

其實就是就是你要鎖住的範圍是多大。比如你在家上衛生間,你只要鎖住衛生間就可以了吧,不需要將整個家都鎖起來不讓家人進門吧,衛生間就是你的加鎖粒度。

我們寫代碼時,如果不涉及到共享資源,就沒有必要鎖住的。這就好像你上衛生間,不用把整個家都鎖住,鎖住衛生間門就可以了。

比如,在业务代码中,有一个 ArrayList 因为涉及到多线程操作,所以需要加锁操作,假设刚好又有一段比较耗时的操作(代码中的slowNotShare方法)不涉及线程安全问题,你会如何加锁呢?

反例:

//不涉及共享资源的慢方法
private void slowNotShare() {
    try {
        TimeUnit.MILLISECONDS.sleep(100);
    } catch (InterruptedException e) {
    }
}

//错误的加锁方法
public int wrong() {
    long beginTime = System.currentTimeMillis();
    IntStream.rangeClosed(1, 10000).parallel().forEach(i -> {
        //加锁粒度太粗了,slowNotShare其实不涉及共享资源
        synchronized (this) {
            slowNotShare();
            data.add(i);
        }
    });
    log.info("cosume time:{}", System.currentTimeMillis() - beginTime);
    return data.size();
}

正例:

public int right() {
    long beginTime = System.currentTimeMillis();
    IntStream.rangeClosed(1, 10000).parallel().forEach(i -> {
        slowNotShare();//可以不加锁
        //只对List这部分加锁
        synchronized (data) {
            data.add(i);
        }
    });
    log.info("cosume time:{}", System.currentTimeMillis() - beginTime);
    return data.size();
}

21.接口狀態和錯誤需要統一明確

提供必要的接口調用狀態信息。比如你的一個轉帳接口調用是成功、失敗、處理中還是受理成功等,需要明確告訴客戶端。如果接口失敗,那麼具體失敗的原因是什麼。這些必要的信息都必須要告訴給客戶端,因此需要定義明確的錯誤碼和對應的描述。同時,儘量對報錯信息封裝一下,不要把後端的異常信息完全拋出到客戶端。

22.接口要考慮異常處理

實現一個好的接口,離不開優雅的異常處理。對於異常處理,提十個小建議吧:

  • 尽量不要使用e.printStackTrace(),而是使用log打印。因为e.printStackTrace()语句可能会导致内存占满。
  • catch住异常时,建议打印出具体的exception,利于更好定位问题
  • 不要用一个Exception捕捉所有可能的异常
  • 记得使用finally关闭流资源或者直接使用 try-with-resource
  • 捕獲異常與拋出異常必須是完全匹配,或者捕獲異常是拋異常的父類
  • 捕獲到的異常,不能忽略它,至少打點日誌吧
  • 注意異常對你的代碼層次結構的侵染
  • 自定义封装异常,不要丢弃原始异常的信息Throwable cause
  • 运行时异常RuntimeException ,不应该通过 catch 的方式来处理,而是先预检查,比如:NullPointerException处理
  • 注意異常匹配的順序,優先捕獲具體的異常

小伙伴们有兴趣可以看下我之前写的这篇文章哈:Java 异常处理的十个建议

23. 優化程式邏輯

優化程式邏輯這塊還是挺重要的,也就是說,你實現的業務代碼,如果是比較複雜的話,建議把注釋寫清楚。還有,代碼邏輯儘量清晰,代碼儘量高效。

比如,你要使用用户信息的属性,你根据 session 已经获取到userId了,然后就把用户信息从数据库查询出来,使用完后,后面可能又要用到用户信息的属性,有些小伙伴没想太多,反手就把userId再传进去,再查一次数据库。。。我在项目中,见过这种代码。。。直接把用户对象传下来不好嘛。。

反例偽代碼:

public Response test(Session session){
    UserInfo user = UserDao.queryByUserId(session.getUserId());

    if(user==null){
       reutrn new Response();
    }

    return do(session.getUserId());
}

public Response do(String UserId){
  //多查了一次数据库
  UserInfo user = UserDao.queryByUserId(session.getUserId());
  ......
  return new Response();
}

正例:

public Response test(Session session){
    UserInfo user = UserDao.queryByUserId(session.getUserId());

    if(user==null){
       reutrn new Response();
    }

    return do(session.getUserId());
}

//直接传UserInfo对象过来即可,不用再多查一次数据库
public Response do(UserInfo user){
  ......
  return new Response();
}

當然,這只是一些很小的一個例子,還有很多類似的例子,需要大家開發過程中,多點思考的哈。

24. 接口實現過程中,注意大文件、大事務、大對象

  • 读取大文件时,不要Files.readAllBytes直接读取到内存,这样会 OOM 的,建议使用 BufferedReader 一行一行来。
  • 大事務可能導致死鎖、回滾時間長、主從延遲等問題,開發中儘量避免大事務。
  • 注意一些大對象的使用,因為大對象是直接進入老年代的,可能會觸發 fullgc

25. 你的接口,需要考慮限流

如果你的系統每秒扛住的請求是 1000,如果一秒鐘來了十萬請求呢?換個角度就是說,高並發的時候,流量洪峰來了,超過系統的承載能力,怎麼辦呢?

如果不採取措施,所有的請求打過來,系統 cpu、內存、load 負載飈的很高,最後請求處理不過來,所有的請求無法正常響應。

針對這種場景,我們可以採用限流方案。就是為了保護系統,多餘的請求,直接丟棄。

限流定義:

在計算機網絡中,限流就是控制網絡接口發送或接收請求的速率,它可防止 dos 攻擊和限制 web 爬蟲。限流,也稱流量控制。是指系統在面臨高並發,或者大流量請求的情況下,限制新的請求對系統的訪問,從而保證系統的穩定性。

可以使用 Guava 的RateLimiter单机版限流,也可以使用Redis分布式限流,还可以使用阿里开源组件sentinel限流

大家可以看下我之前这篇文章哈:4 种经典限流算法讲解

26.代碼實現時,注意運行時異常(比如空指針、下標越界等)

日常開發中,我們需要採取措施規避數組邊界溢出,被零整除,空指針等運行時錯誤。類似代碼比較常見:

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

應該採取措施,預防一下數組邊界溢出。正例如下:

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

27.保證接口安全性

如果你的 api 接口是對外提供的,需要保證接口的安全性。保證接口的安全性有token 機制和接口簽名

token 機制身份驗證方案還比較簡單的,就是

  1. 客戶端發起請求,申請獲取 token。
  2. 服務端生成全局唯一的 token,保存到 redis 中(一般會設置一個過期時間),然後返回給客戶端。
  3. 客戶端帶著 token,發起請求。
  4. 服務端去 redis 確認 token 是否存在,一般用 redis.del(token)的方式,如果存在會刪除成功,即處理業務邏輯,如果刪除失敗不處理業務邏輯,直接返回結果。

接口簽名的方式,就是把接口請求相關信息(請求報文,包括請求時間戳、版本號、appid 等),客戶端私鑰加簽,然後服務端用公鑰驗簽,驗證通過才認為是合法的、沒有被篡改過的請求。

有关于加签验签的,大家可以看下我这篇文章哈:程序员必备基础:加签验签

除了加簽驗簽和 token 機制,接口報文一般是要加密的。當然,用 https 協議是會對報文加密的。如果是我們服務層的話,如何加解密呢?

可以參考 https 的原理,就是服務端把公鑰給客戶端,然後客戶端生成對稱密鑰,接著客戶端用服務端的公鑰加密對稱密鑰,再發到服務端,服務端用自己的私鑰解密,得到客戶端的對稱密鑰。這時候就可以愉快傳輸報文啦,客戶端用對稱密鑰加密請求報文,服務端用對應的對稱密鑰解密報文

有時候,接口的安全性,還包括手機號、身份證等信息的脫敏。就是說,用戶的隱私數據,不能隨便暴露

28.分布式事務,如何保證

分布式事務:就是指事務的參與者、支持事務的伺服器、資源伺服器以及事務管理器分別位於不同的分布式系統的不同節點之上。簡單來說,分布式事務指的就是分布式系統中的事務,它的存在就是為了保證不同資料庫節點的數據一致性。

分布式事務的幾種解決方案:

  • 2pc(二階段提交)方案、3pc
  • TCC(Try、Confirm、Cancel)
  • 本地消息表
  • 最大努力通知
  • seata

大家可以看下这篇文章哈:看一遍就理解:分布式事务详解

29. 事務失效的一些經典場景

我們的接口開發過程中,經常需要使用到事務。所以需要避開事務失效的一些經典場景。

  • 方法的訪問權限必須是 public,其他 private 等權限,事務失效
  • 方法被定義成了 final 的,這樣會導致事務失效。
  • 在同一個類中的方法直接內部調用,會導致事務失效。
  • 一個方法如果沒交給 spring 管理,就不會生成 spring 事務。
  • 多線程調用,兩個方法不在同一個線程中,獲取到的資料庫連接不一樣的。
  • 表的存儲引擎不支持事務
  • 如果自己 try... catch 誤吞了異常,事務失效。
  • 錯誤的傳播特性

推荐大家看下这篇文章:聊聊 spring 事务失效的 12 种场景,太坑了

30. 掌握常用的設計模式

把代碼寫好,還是需要熟練常用的設計模式,比如策略模式、工廠模式、模板方法模式、觀察者模式等等。設計模式,是代碼設計經驗的總結。使用設計模式可以可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性。

我之前写过一篇总结工作中常用设计模式的文章,写得挺不错的,大家可以看下:实战!工作中常用到哪些设计模式

31. 寫代碼時,考慮線性安全問題

高并发情况下,HashMap可能会出现死循环。因为它是非线性安全的,可以考虑使用ConcurrentHashMap。所以这个也尽量养成习惯,不要上来反手就是一个new HashMap();

  • hashmap、arraylist、linkedlist、treemap 等都是線性不安全的;
  • vector、hashtable、concurrenthashmap 等都是線性安全的

32.接口定義清晰易懂,命名規範。

我們寫代碼,不僅僅是為了實現當前的功能,也要有利於後面的維護。說到維護,代碼不僅僅是寫給自己看的,也是給別人看的。所以接口定義要清晰易懂,命名規範。

33. 接口的版本控制

接口要做好版本控制。就是说,请求基础报文,应该包含version接口版本号字段,方便未来做接口兼容。其实这个点也算接口扩展性的一个体现点吧。

比如客户端 APP 某个功能优化了,新老版本会共存,这时候我们的version版本号就派上用场了,对version做升级,做好版本控制。

34. 注意代碼規範問題

注意一些常見的代碼壞味道:

  • 大量重複代碼(抽共用方法,設計模式)
  • 方法參數過多(可封裝成一個 dto 對象)
  • 方法過長(抽小函數)
  • 判斷條件太多(優化 if... else)
  • 不處理沒用的代碼
  • 不注重代碼格式
  • 避免過度設計

代码的坏味道,这里我都写到啦:25 种代码坏味道总结+优化示例

35.保證接口正確性,其實就是保證更少的 bug

保證接口的正確性,換個角度講,就是保證更少的 bug,甚至是沒有 bug。所以接口開發完後,一般需要開發自測一下。然後的話,接口的正確還體現在,多線程並發的時候,保證數據的正確性, 等等。比如你做一筆轉帳交易,扣減餘額的時候,可以通過 cas 樂觀鎖的方式保證餘額扣減正確吧。

如果你是实现秒杀接口,得防止超卖问题吧。你可以使用 Redis 分布式锁防止超卖问题。使用 Redis 分布式锁,有几个注意要点,大家可以看下我之前这篇文章哈:七种方案!探讨 Redis 分布式锁的正确使用姿势

36.學會溝通,跟前端溝通,跟產品溝通

我把這一點放到最後,學會溝通是非常非常重要的。比如你開發定義接口時,一定不能上來就自己埋頭把接口定義完了,需要跟客戶端先對齊接口。遇到一些難點時,跟技術 leader 對齊方案。實現需求的過程中,有什麼問題,及時跟產品溝通。

總之就是,開發接口過程中,一定要溝通好~

最後(求關注,別白嫖我)

如果這篇文章對您有所幫助,或者有所啟發的話,求一鍵三連:點讚、轉發、在看,您的支持是我堅持寫作最大的動力。

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 2022/3/17

工作6年,失業19天

我是一名java程式設計師,在北京工作了6年,此篇文章記錄了我2019年11月,在這個寒冷的冬天被裁員之後,心態變化及重新找工作的心路歷程。

继续阅读