小重構,大收益!技術重構實踐:如何優雅升級老舊接口

重構格言:"優秀系統不是設計出來的,而是通過持續重構演進而來的。"
—— Martin Fowler《重構:改善既有代碼的設計》

希望本文能為您的重構之旅提供指引,讓老舊系統煥發新生!

一、背景:一個“穩定”接口的隱患

下面WEB控制器方法,是我們歷史悠久的短信服務(SMS)里的短信發送接口。

@RestController
@RequestMapping({"/smsSend", "/sendSms"})
public class SmsSendController {@GetMapping@PreventDuplicateRequest(key = "SmsSendController_smsSend", spEL = "{#phones, T(com.sms.common.utils.MD5Util).getMD5(#content)}", expireSeconds = 5)public String smsSend(@RequestParam("account") String account,@RequestParam("sign") String sign,@RequestParam("mphone") String phones,// 多個用逗號分隔@RequestParam("content") String content) {return sendSms(account, sign, phones, content);//"SUCCESS" + msgIds.substring(0, msgIds.length() - 1);}
}

這個接口是在若干年前開發的,彼時,大家技術能力有限。

該接口響應格式簡單粗暴——成功時返回 SUCCESS 拼接消息ID,失敗時直接返回錯誤原因字符串。例如:

SUCCESS123456,789012  // 成功示例
短信賬戶密碼錯誤        // 失敗示例

這種設計在早期快速迭代階段勉強可用,但隨著系統復雜度提升,其弊端日益凸顯:

  1. 客戶端解析困難:需通過字符串前綴匹配判斷成功與否,易因格式微調引發故障
  2. 可觀測性差:缺乏唯一請求標識,排查問題如大海撈針
  3. 擴展性受限:無法攜帶額外數據(如運營商回執、計費信息)

為此,我決定做一個小小的升級,同時要兼容當前響應值。

我們計劃使用 Result 對象來實現相應結構的標準化,即 code/msg/data 的形式,符合RESTful API的最佳實踐。例如:

// 錯誤響應
{"reqId":"a369331163aba36","message":"短信賬戶錯誤","code":500,"data":null,"timestamp":1745285069433,"success":false}
//成功響應
{"reqId":"a6a0bb2f83844d9","message":"發送成功","code":200,"data":["2504223325367695"],"timestamp":1745285136909,"success":true}

二、重構目標:魚與熊掌兼得

怎么進行這項代碼重構呢?

  1. 為該接口增加版本號參數,不同版本響應值不同。
  2. 改造現有WEB控制器方法的返回值。原先返回 String, 變更這個返回值。
  3. 這個API方法所調用的 sendSms,變更其返回值,以明確方法職責。
@RestController
@RequestMapping({"/smsSend", "/sendSms"})
public class SmsSendController {@GetMapping({"/{version}", ""})@PreventDuplicateRequest(key = "SmsSendController_smsSend", spEL = "{#phones, T(com.sms.common.utils.MD5Util).getMD5(#content)}", expireSeconds = 5)public Object smsSend(@RequestParam("account") String account,@RequestParam("sign") String sign,@RequestParam("mphone") String phones,// 多個用逗號分隔@RequestParam("content") String content, @PathVariable(value = "version", required = false) String version) {Result<List<String>> listResult = sendSms(account, sign, phones, content);if ("v2".equals(version)) {// v2版本返回值listResult.setReqId(MDC.get("traceId"));return listResult;} else {// v1版本返回值if (listResult.isSuccess())return "SUCCESS" + String.join(",", listResult.getResult());elsereturn listResult.getMessage();}}
}

三、重構收益:從能用走向好用

1. 響應結構標準化
  • 可維護性提升:統一使用 Result 結構體,符合 RESTful 設計規范

  • 錯誤處理增強Result 中的 codesuccess 字段使調用方能夠通過統一邏輯處理成功與失敗場景(如 if (result.isSuccess())),避免了舊版中依賴字符串內容(如判斷是否以“SUCCESS”開頭)的脆弱邏輯。同時,精準錯誤碼也可指導用戶處理(如 code=501 提示賬戶余額不足)

  • 顯著降低客戶端使用成本:相比原始的“SUCCESS+ID”或“錯誤字符串”,調用方無需通過字符串解析邏輯(如前綴匹配、異常分支判斷)即可快速識別請求結果

2. 版本兼容性設計

實現方式:

@GetMapping({"/{version}", ""})
public Object smsSend(..., @PathVariable String version) {if ("v2".equals(version)) { /* 新版本邏輯 */ }else { /* 舊版本兼容 */ }
}
  • 平滑升級:通過兼容新舊版本共存,舊客戶端無需立即改造,避免“一刀切”式升級帶來的兼容性風險。

  • 灰度發布能力:通過 URL 路徑控制新老版本流量比例

3. 請求追蹤集成
  • 日志可追溯:通過 reqId 快速關聯請求全鏈路日志

  • 調試效率提升:快速定位具體請求的服務器處理線程,故障定位時間縮短 70%

4. 底層邏輯與接口解耦
  • 統一內部返回類型:將 sendSms 方法的返回值從原始字符串改為 Result<List<String>>,使底層邏輯專注于業務處理(生成標準化結果),而控制器層僅負責“按版本格式化響應”,減少了控制器中的條件判斷邏輯,符合“單一職責原則”。
  • 隔離版本差異邏輯:版本相關的響應轉換(如舊版字符串拼接、新版 Result 裝配)集中在控制器層,底層服務(如 sendSms)和 Result 模型保持無版本依賴,便于后續擴展更多版本(如 v3、v4)而不影響核心邏輯。

四、總結

小重構,大收益!

本次小重構通過版本化路徑設計響應格式分層兼容,在不破壞現有調用的前提下實現了接口的標準化升級,顯著提升了接口的可維護性、調用方體驗和錯誤處理能力。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/903111.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903111.shtml
英文地址,請注明出處:http://en.pswp.cn/news/903111.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

OSPF中DR/BDR的選舉

OSPF 開放式最短路徑優先協議-CSDN博客 選舉原因&#xff1a;廣播網絡中使路由信息交換更加高速有序&#xff0c;可以降低需要維護的鄰接關系數量 基本概念&#xff1a; DR (Designated Router, 指定路由器)&#xff1a;負責在廣播網絡&#xff08;以太網&#xff09;或NBMA網…

[特殊字符]?[特殊字符]Linux驅動開發入門 | 并發與互斥機制詳解

文章目錄 &#x1f468;?&#x1f4bb;Linux驅動開發入門 | 并發與互斥機制詳解&#x1f4cc;為什么驅動中需要并發和互斥控制&#xff1f;&#x1f4a1;常見的并發控制機制&#x1f510;自旋鎖和信號量通俗理解&#x1f300;自旋鎖&#xff08;Spinlock&#xff09;——“廁所…

Kafka 架構設計和組件介紹

什么是Apache Kafka&#xff1f; Apache Kafka 是一個強大的開源分布式事件流平臺。它最初由 LinkedIn 開發&#xff0c;最初是一個消息隊列&#xff0c;后來發展成為處理各種場景數據流的工具。 Kafka 的分布式系統架構支持水平擴展&#xff0c;使消費者能夠按照自己的節奏檢…

elk中kibana一直處于可用和降級之間且es群集狀態并沒有問題的解決方法

前言 在公司部elk的時候發現kibana的web界面一直很卡&#xff0c;數據量為0也會很卡&#xff0c;es群集狀態正常&#xff0c;資源足夠。 報錯信息 [2025-03-17T09:54:50.19400:00][INFO ][status] Kibana is now available (was degraded) [2025-03-17T09:55:03.28000:00][I…

什么是視頻上墻

視頻聯動上墻是指當監控系統中出現報警或其他特定事件時&#xff0c;相關的視頻畫面能夠自動切換并顯示在指定的監控大屏或顯示設備上&#xff0c;以便監控人員能夠快速、直觀地查看事件現場的情況&#xff0c;及時做出響應和處理。 具體介紹? 系統組成 &#xff1a;一般由前端…

26考研——存儲系統(3)

408答疑 文章目錄 一、存儲器概述二、主存儲器三、主存儲器與 CPU 的連接四、外部存儲器五、高速緩沖存儲器六、虛擬存儲器七、參考資料鮑魚科技課件26王道考研書 八、總結復習提示思考題常見問題和易混淆知識點 一、存儲器概述 文章鏈接: 點擊跳轉 二、主存儲器 文章鏈接: …

.NET 6 + Dapper + User-Defined Table Type

大家都知道&#xff0c;對于SQL Server IN是有限制條件的&#xff0c;如果IN里面的內容過多&#xff0c;在執行的時候會被自動截斷&#xff0c;因而導致查詢到的結果不是實際需要的結果。 select * from Payments where Id in (1,2,3,4,...) 為了解決上面的限制&#xff0c;可以…

MySQL 8(Ubuntu 18.04.6 LTS)安裝筆記

一、前言 其實之前已經寫過一篇筆記【MySQL 8.0.34&#xff08;x64&#xff09;安裝筆記】。機緣巧合&#xff0c;這次遇到的環境是Ubuntu 18.04 LTS&#xff0c;相比Windows平臺的安裝&#xff0c;對mysql的版本以及依賴的選擇&#xff0c;稍微要窄一些。特作筆記。 二、準備…

學習 Apache Kafka

學習 Apache Kafka 是一個很好的選擇&#xff0c;尤其是在實時數據流處理和大數據領域。以下是一個系統化的學習建議&#xff0c;幫助你從入門到進階掌握 Kafka&#xff1a; 1. 先決條件 在開始 Kafka 之前&#xff0c;確保你具備以下基礎&#xff1a; Java 基礎&#xff1a;K…

使用 binlog2sql 閃回 MySQL8 數據

【說明】 MySQL服務器版本 8.0.26 mysql> SELECT version(); ----------- | version() | ----------- | 8.0.26 | -----------Python 版本 Python 3.8.10 [infuq ~]# python -V Python 3.8.10【安裝】 binlog2sql 官方地址 1.安裝 binlog2sql [infuq ~]# git clone …

JavaScript 異步編程與請求取消全指南

JavaScript 異步編程與請求取消全指南 涵蓋&#xff1a;同步/異步、Promise、async/await、AbortController、前后端協作 一、同步與異步 1. 同步&#xff08;Synchronous&#xff09; 定義&#xff1a;代碼按順序執行&#xff0c;前一步完成才能執行下一步。特點&#xff1…

永久緩存 Git 憑證

永久緩存 Git 憑證 打開終端或命令行工具。 執行以下命令&#xff0c;設置 Git 使用 store 憑證幫助程序&#xff1a; bash git config --global credential.helper store第一次執行 git pull 時輸入賬號密碼。之后&#xff0c;所有需要憑證的操作都將自動使用存儲的憑證&…

力扣-48.旋轉圖像

題目描述 給定一個 n n 的二維矩陣 matrix 表示一個圖像。請你將圖像順時針旋轉 90 度。 你必須在 原地 旋轉圖像&#xff0c;這意味著你需要直接修改輸入的二維矩陣。請不要 使用另一個矩陣來旋轉圖像。 class Solution { public:void rotate(vector<vector<int>…

Qt ModbusSlave多線程實踐總結

最近項目中用到了ModbusSlave&#xff0c;也就是Modbus從設備的功能&#xff0c;之前用的基本都是master設備&#xff0c;所以讀取數據啥的用單線程就行了&#xff0c;用 void WaitHelper::WaitImplByEventloop(int msec) {QEventLoop loop;QTimer::singleShot(msec, &loop…

opencv--圖像

像素(像素點) 定義&#xff1a; Pixel 是 Picture Element&#xff08;圖像元素&#xff09;的縮寫&#xff0c;是數字圖像中最小的獨立單位。每個像素代表圖像中的一個點的顏色和亮度信息。 關鍵特性&#xff1a; 顏色&#xff1a;通過不同的色彩模型&#xff08;如RGB、CMYK…

記錄學習匯編語言02+各種寄存器分類

8086cpu是十六位的 然后寄存器能存八位 所以分為高八位低八位 高八位在下面低八位在上面 從下往上讀&#xff08;從地址小的地方開始讀&#xff09; 8086cpu種有兩個和棧相關的寄存器 棧段寄存器ss&#xff08;棧頂的段寄存器&#xff09; 棧頂指針寄存器sp&#xff08;…

OpenCV 圖形API(53)顏色空間轉換-----將 RGB 圖像轉換為灰度圖像函數RGB2Gray()

操作系統&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 將圖像從 RGB 色彩空間轉換為灰度。 R、G 和 B 通道值的常規范圍是 0 到 255。生成的灰度值計算方式如下&#xff1a; dst ( I ) 0.299 ? src…

(51單片機)LCD顯示數據存儲(DS1302時鐘模塊教學)(LCD1602教程)(獨立按鍵教程)(延時函數教程)(I2C總線認識)(AT24C02認識)

目錄 演示視頻&#xff1a; 源代碼 main.c LCD1602.c LCD1602.h AT24C02.c AT24C02.h Key.c Key.h I2C.c I2C.h Delay.c Delay.h 代碼解析與教程&#xff1a; Dealy模塊 LCD1602模塊 Key模塊 I2C總線模塊 AT24C02模塊 /E2PROM模塊 main模塊 演示視頻&#xff1a; E2…

電子病歷高質量語料庫構建方法與架構項目(數據遺忘篇)

引言 在人工智能與醫療健康的深度融合時代,醫療數據的價值與風險并存。跨機構和平臺的醫療數據共享對于推動醫學研究、提高診斷精度和實現個性化治療至關重要,但同時也帶來了前所未有的隱私挑戰。先進的AI技術可以從理論上去標識化的醫療掃描中重新識別個人身份,例如從MRI數…

CentOS創建swap內存

服務器版本為CentOS7 一、檢查現有 swap 空間 sudo swapon --show如果系統中沒有 swap 空間或者現有的 swap 空間不足&#xff0c;可以繼續后續步驟來創建 swap 空間。 二、創建 swap 文件&#xff08;推薦 2GB 作為示例&#xff09; sudo dd if/dev/zero of/swapfile bs1M …