
這個枚舉只有一個值我差點刪了——然后所有代發訂單都取不了號技術重構系列 · 第2篇抖音代發共享店鋪Token設計 地址策略解耦本系列基于老系統真實改造復盤文中客戶名、地址、編碼值均已化名/脫敏處理坑的類型、解題思路、踩坑過程為一線實錄。系列背景與為什么重構見首篇。上篇聊了奇門對接順豐的三個暗坑這篇進入抖音代發。抖音代發是一個特殊的業務模式店鋪接到訂單但由另一個倉庫實際發貨。倉庫用自己的抖音賬號調API取號但訂單信息來自店鋪。這種模式帶來三個技術挑戰——Token從哪來、地址用哪個、路由怎么走。三個問題看似簡單實則暗藏前任硬編碼的坑。文檔里一筆帶過代碼里卻藏著業務規則的全部秘密。這篇還多送一個故事一個沉睡了半年的Token是怎么在最不該炸的時候炸出一串空指針的。一、共享店鋪Token你差點手賤刪掉的枚舉1.1 問題背景代發模式下倉庫為多個店鋪代發。每個店鋪有自己的抖音授權Token但某些共享店鋪共享倉庫的Token。系統需要判斷當前訂單的店鋪是不是共享店鋪如果是用倉庫的Token如果不是用店鋪自己的Token。原代碼的實現方式是在一個Java枚舉里硬編碼共享店鋪列表訂單進來時先查枚舉命中了就走共享邏輯。1.2 你差點犯的錯如果你不知道這個業務背景看到這個枚舉只有一個值可能會覺得“這個枚舉是不是可以刪掉只有一個值直接查數據庫不行嗎”但不能刪。這個枚舉是業務配置不是代碼冗余。刪除它會導致共享店鋪的Token獲取邏輯失效所有共享店鋪的訂單都會報未獲取到有效的AccessToken。這種看起來沒用但不能刪的代碼在遺留系統里特別多。刪之前先搞清楚它為什么在那里。1.3 新架構的優化在新架構中Token獲取邏輯被提取為獨立方法增加了空值校驗和友好的錯誤信息含店鋪名稱。不再是3個方法里重復3遍而是一處定義、全局復用。為什么要特意強調空值校驗因為我們真的被空Token炸過一次。往下看。二、一個沉睡半年的Token炸出5處防呆2.1 事故鏈代發業務有明顯的淡旺季可能連續幾個月一張代發訂單都沒有。于是發生了這樣一條事故鏈長期沒有代發訂單 → 沒人觸發Token刷新授權靜默過期 → 某天突然來了一張代發單 → 系統取Token拿到 null → 拼接請求參數時對 null 做URL編碼 → 空指針異常NPE用戶看到的報錯是什么一串和業務毫無關系的堆棧信息。沒有Token過期沒有請重新授權只有一個冷冰冰的空指針。2.2 排查從NPE堆棧往回推編碼的入參是Token → Token從組織配置里取的 → 配置里的Token字段是空的 → 為什么是空的→ 授權早就過期了只是一直沒有訂單來發現它。低頻鏈路的憑證過期不會報警只會在最需要它的時候爆炸。2.3 修復5處防呆修復分兩步數據修復重新走授權流程把新Token更新到組織配置。代碼防呆在5個位置增加Token空值校驗——統一取號入口、兩個請求構建器、兩個HTTP處理器。Token為空時不再往下走直接拋出人話版異常“未獲取到有效的抖音代發AccessToken請檢查平臺配置店鋪XXX”為什么要5處而不是1處因為取號有多個入口任何一個入口漏了校驗NPE還是會從那個口炸出來。防呆的原則是在每一個消費Token的地方守門而不是假設上游一定給了合法值。2.4 這個坑的通用教訓防呆校驗的價值不是防止出錯——Token過期這種事防不住。它的價值是讓錯誤一眼能看懂從一串空指針堆棧排查兩小時變成一行帶店鋪名的提示一分鐘定位。你的系統里有沒有這種半年才走一次的低頻鏈路它的憑證、配置、外部依賴過期了有人知道嗎三、地址策略硬編碼背后的三條規則3.1 表象發件人地址的選擇邏輯代碼里寫了一堆if/else中通用一個地址郵政和順豐用另一個地址其他情況用商家配置的地址看起來就是不同快遞用不同地址沒什么復雜的。3.2 背后的業務規則但仔細看規則比if/else復雜得多規則條件地址規則1中通地址A規則2郵政或順豐且不是書局A的訂單地址B規則3其他商家自己配置的地址為什么中通用地址A因為中通在地址A有網點取件方便。為什么郵政/順豐非書局A要用地址B因為書局A在地址A有自己的收件點但其他商家沒有需要用地址B的公共收件點。為什么只有非重復訂單才執行規則2因為代發自身的業務邏輯差異——重復訂單不重新取號不需要重新判斷地址。順帶提醒一句不同平臺的網點綁定規則可能完全不同。同一家快遞在代發鏈路綁定的是這套地址換到另一個電商平臺可能又是另一套。對照多平臺代碼或文檔時看到地址規則不一樣先別急著當成矛盾——大概率是平臺側網點綁定本來就不同。3.3 這個坑和渠道編碼的坑如出一轍回想上篇的渠道編碼坑文檔說根據訂單類型設置代碼里卻硬編碼了三種值分別對應三種渠道。不知道含義就改改完就出事。地址策略也一樣文檔說不同快遞使用不同地址代碼里硬編碼了兩個地址和三條規則。不知道規則就改改完中通測試通過因為中通規則最簡單但郵政/順豐切換時就報錯。這些坑的共同特點文檔一筆帶過前任把業務規則硬編碼在方法里新人看到代碼覺得不就是個地址選擇嗎殊不知背后藏著三條業務規則。3.4 未來優化方向當前地址選擇邏輯保留在代碼中使用常量引用消除魔法字符串。后續可以下沉到數據庫配置實現新增快遞只需改配置不改代碼。但這個改動需要業務確認暫不動。四、DYXD路由數據庫有值代碼沒注冊4.1 問題抖音平臺有5種變體——普通、供銷、分銷端、代發等。每種變體調API時用的請求格式不同字段名不同、參數結構不同。系統需要根據變體類型選擇正確的翻譯官來組裝請求。測試時發現某個變體的訂單報錯參數缺失。打個比方你要寄國際快遞系統應該找英語翻譯官對應國際格式但找不到fallback 找了個中文翻譯官對應國內格式。翻譯官用中文格式寫了一張國際快遞單對方看不懂直接退回來了。4.2 根因數據庫中記錄了5種變體但代碼里只注冊了1種的翻譯官。其他4種找不到對應的翻譯官就用了默認的——但默認的格式和實際需要的格式不匹配。我犯的錯沒有先查原代碼的路由邏輯憑聽起來像代發的直覺直接注冊為代發處理器。用戶糾正“只有代發走代發其他所有變體走普通。”查了原代碼確認原代碼中那個變體編碼出現0次——根本沒有特殊處理走的就是其他所有變體的默認分支。4.3 修復后的路由表變體編碼走哪個翻譯官普通/默認普通格式供銷普通格式分銷端普通格式代發代發格式只有代發用代發格式其他所有變體用普通格式。這個坑的完整排查過程和憑直覺的反思下篇講抖音普通訂單時還會從另一個角度收個尾。五、抖音平臺的快遞限制回歸測試中發現一個重要限制抖音平臺不支持京東快遞。當用戶切換到京東快遞時系統直接攔截“暫不支持的渠道”。這是原代碼的硬編碼邏輯——京東快遞的電子面單系統與抖音平臺沒有對接。如果你不知道這個限制可能會在測試時跳過京東快遞上線后用戶切換時才發現報錯排查半天才發現是平臺限制不是代碼bug。各平臺快遞支持對比平臺不支持的快遞抖音京東拼多多京東無模板奇門京東無映射微信視頻號京東未配置六、回歸測試抖音代發共完成7次測試3次成功快遞/場景結果說明順豐特快/電商標快成功全鏈路通過產品編碼正確下發郵政成功全鏈路通過中通失敗面單賬戶余額不足——業務問題非代碼問題順豐服務類型切換被拒平臺冪等限制已取號訂單不允許變更服務類型失敗的每一次都定位到了明確原因且都不是新代碼引入的問題。測試的目的不是證明都能通過而是把哪些不能通過、為什么提前摸清楚。七、教訓這篇文章的核心信息代碼里的每一個硬編碼背后都可能藏著一條業務規則每一條低頻鏈路背后都可能藏著一個過期的憑證。改代碼之前先搞清楚規則上線之前先想想最久沒人走的那條路。四個坑的根源都指向同一件事——知識沒有沉淀。共享店鋪枚舉沒注釋、地址規則沒文檔、路由規則只在前任腦子里、Token過期沒人知道。硬編碼不是罪但要留下注釋。前任把地址和快遞限制硬編碼在方法里這在當時的業務環境下是合理的。但問題是沒有留下業務規則的注釋導致后來的開發者不知道這些硬編碼背后的邏輯。新架構中我們用常量替換了魔法字符串并在代碼注釋中記錄了業務規則。這是對歷史的尊重也是對未來的負責。下篇預告下一篇進入抖音普通訂單《取號為什么越來越慢100次數據庫查詢其實只需要1次》。代發搭好的分層架構普通訂單直接復用——但復用不等于照搬四個差異點一個都不能漏。另外還有一個讓所有平臺受益的性能優化。討論話題你們的系統里有沒有那種看起來沒用但不能刪的代碼或者半年才走一次、一走就炸的低頻鏈路評論區聊聊。