錯(cuò)誤碼如何設(shè)計(jì)才合理?
對(duì)于錯(cuò)誤碼的設(shè)計(jì),不同的開(kāi)發(fā)團(tuán)隊(duì)有不同的風(fēng)格習(xí)慣。本文分享阿里文娛技術(shù)專家長(zhǎng)統(tǒng)對(duì)于錯(cuò)誤碼的看法,希望從錯(cuò)誤碼使用的不同場(chǎng)景討論得到一個(gè)合理的錯(cuò)誤碼規(guī)約,得到一個(gè)面向日志錯(cuò)誤碼標(biāo)準(zhǔn)和一個(gè)面向外部傳遞的錯(cuò)誤碼標(biāo)準(zhǔn)。
一 前言
在工作中,接觸過(guò)不少外部接口,其中包括:支付寶,微信支付,微博開(kāi)發(fā)平臺(tái),阿里云等等。每家公司錯(cuò)誤碼風(fēng)格都不盡相同,有使用純數(shù)字的,有使用純英文的,也有使用字母和數(shù)字組合的。也接觸過(guò)很多內(nèi)部系統(tǒng),錯(cuò)誤碼設(shè)計(jì)也不盡相同。
錯(cuò)誤碼的輸出路徑
面向日志輸出
- 服務(wù)內(nèi)傳遞,最終是輸出到日志。
- 域內(nèi)服務(wù)間,比如同時(shí)大麥電商之間的系統(tǒng),最終目的是輸出到日志。
面向外部傳遞
- 域內(nèi)向域外
- 服務(wù)端傳遞到前端
- OpenAPI 錯(cuò)誤碼
- 內(nèi)部不同域之間
錯(cuò)誤碼使用場(chǎng)景
- 通過(guò)錯(cuò)誤碼配置監(jiān)控大盤。
- 通過(guò)日志進(jìn)行問(wèn)題排查,快速定位問(wèn)題。
- 后端服務(wù)之間錯(cuò)誤碼傳遞。
- 前端展示的錯(cuò)誤提示/OpenAPI。
本文希望從錯(cuò)誤碼使用的不同場(chǎng)景討論得到一個(gè)合理的錯(cuò)誤碼規(guī)約,得到一個(gè)面向日志錯(cuò)誤碼標(biāo)準(zhǔn)和一個(gè)面向外部傳遞的錯(cuò)誤碼標(biāo)準(zhǔn)。
PS:本文引用全部引自阿里巴巴《Java 開(kāi)發(fā)手冊(cè)》,下稱《手冊(cè)》。
二 什么是錯(cuò)誤碼
錯(cuò)誤碼要回答的最根本的問(wèn)題是,誰(shuí)的錯(cuò)?錯(cuò)在哪?
那么一個(gè)錯(cuò)誤能表示出誰(shuí)的錯(cuò)和錯(cuò)在哪里就是一個(gè)好的錯(cuò)誤碼嗎?答案顯然是否定的,這個(gè)標(biāo)準(zhǔn)太基礎(chǔ)了。
- 好的錯(cuò)誤碼必須能夠快速知曉錯(cuò)誤來(lái)源。
- 好的錯(cuò)誤碼必須易于記憶和對(duì)比。
- 好的錯(cuò)誤碼必須能夠脫離文檔和系統(tǒng)平臺(tái)達(dá)到線下輕量溝通的目的(這個(gè)要求比較高)。
引自《手冊(cè)》- 異常日志-錯(cuò)誤碼
錯(cuò)誤碼的制定原則:快速溯源、簡(jiǎn)單易記、溝通標(biāo)準(zhǔn)化。
說(shuō)明:錯(cuò)誤碼想得過(guò)于完美和復(fù)雜,就像康熙字典中的生僻字一樣,用詞似乎精準(zhǔn),但是字典不容易隨身攜帶并且簡(jiǎn)單易懂。
正例:錯(cuò)誤碼回答的問(wèn)題是誰(shuí)的錯(cuò)?錯(cuò)在哪?
1)錯(cuò)誤碼必須能夠快速知曉錯(cuò)誤來(lái)源,可快速判斷是誰(shuí)的問(wèn)題。
2)錯(cuò)誤碼易于記憶和比對(duì)(代碼中容易 equals)。
3)錯(cuò)誤碼能夠脫離文檔和系統(tǒng)平臺(tái)達(dá)到線下輕量化地自由溝通的目的。
這個(gè)原則寫在異常日志-錯(cuò)誤碼這個(gè)章節(jié),我認(rèn)為同樣適用在面向用戶的錯(cuò)誤碼。
?? 
三 錯(cuò)誤碼規(guī)范
錯(cuò)誤碼定義要有字母也要有數(shù)字
純數(shù)字錯(cuò)誤碼
錯(cuò)誤碼即人性,感性認(rèn)知+口口相傳,使用純數(shù)字來(lái)進(jìn)行錯(cuò)誤碼編排不利于感性記憶和分類。
說(shuō)明:數(shù)字是一個(gè)整體,每位數(shù)字的地位和含義是相同的。
反例:一個(gè)五位數(shù)字 12345,第1位是錯(cuò)誤等級(jí),第 2 位是錯(cuò)誤來(lái)源,345 是編號(hào),人的大腦不會(huì)主動(dòng)地分辨每位數(shù)字的不同含義。
《手冊(cè)》說(shuō)明了純數(shù)字錯(cuò)誤碼存在的問(wèn)題。
純字母錯(cuò)誤碼
那么純字母錯(cuò)誤碼不香嗎?有兩個(gè)問(wèn)題:
- 對(duì)于使用漢語(yǔ)的我們用英語(yǔ)去準(zhǔn)確描述一個(gè)錯(cuò)誤有時(shí)是比較困難的。
- 純英文字母的錯(cuò)誤碼不利于排序。
錯(cuò)誤碼盡量有利于不同文化背景的開(kāi)發(fā)者進(jìn)行交流與代碼協(xié)作。
說(shuō)明:英文單詞形式的錯(cuò)誤碼不利于非英語(yǔ)母語(yǔ)國(guó)家(如阿拉伯語(yǔ)、希伯來(lái)語(yǔ)、俄羅斯語(yǔ)等)之間的開(kāi)發(fā)者互相協(xié)作。
快速溯源 | 簡(jiǎn)單易記 | 溝通標(biāo)準(zhǔn)化
什么是快速溯源?就是一眼看上去就知道哪里出了什么問(wèn)題。
李雷負(fù)責(zé) A 服務(wù),韓梅梅負(fù)責(zé) B 服務(wù)。韓梅梅發(fā)現(xiàn)服務(wù) B 出現(xiàn)了一個(gè)錯(cuò)誤碼,韓梅梅能夠快速定位這是服務(wù) A 的內(nèi)部業(yè)務(wù)異常造成的問(wèn)題,這個(gè)時(shí)候韓梅梅就可以拿著錯(cuò)誤碼找到李雷說(shuō),"hi,Li Lei,How old are you。(李雷,怎么老是你)"。李雷拿過(guò)來(lái)錯(cuò)誤碼一看,內(nèi)心萬(wàn)馬奔騰,一下就能知道這是上游 Polly 負(fù)責(zé)的應(yīng)用阿爾法出了錯(cuò)。
怎么能達(dá)到這個(gè)效果呢?
- 首先要有一套標(biāo)準(zhǔn)并且在域內(nèi)各個(gè)業(yè)務(wù)都在用同樣的標(biāo)準(zhǔn)。
- 其次要求錯(cuò)誤碼有自我解釋的能力是有信息含量的有意義。
- 最后在域內(nèi)要傳遞錯(cuò)誤碼。
錯(cuò)誤碼標(biāo)準(zhǔn)的意義
開(kāi)宗明義借用了《手冊(cè)》對(duì)于錯(cuò)誤碼定義的原則作為錯(cuò)誤碼規(guī)范能夠給我們帶來(lái)的收益。我想再次強(qiáng)調(diào)并且試著從反面闡述沒(méi)有錯(cuò)誤碼標(biāo)準(zhǔn)會(huì)帶來(lái)的成本。
錯(cuò)誤碼是用來(lái)做溝通的:系統(tǒng)與系統(tǒng)間的溝通,人與人間的溝通,人與系統(tǒng)間的溝通。
試想下面這個(gè)場(chǎng)景:
韓梅梅看到一個(gè)異常日志其中一個(gè)純數(shù)字的錯(cuò)誤碼。
韓梅梅需要理解這串?dāng)?shù)字代表的是什么,它到底是不是一個(gè)錯(cuò)誤碼,經(jīng)過(guò)幾秒鐘確定下來(lái)這是一個(gè)錯(cuò)誤碼,但她不能確定這是不是本系統(tǒng)中錯(cuò)誤碼,因?yàn)樵谒?fù)責(zé)的系統(tǒng)是由韓梅梅、Lucy 和 Lily 三個(gè)人共同維護(hù)的,每個(gè)人都按照自己的理解定義了一套錯(cuò)誤碼。
韓梅梅去系統(tǒng)源碼中查找這個(gè)錯(cuò)誤碼,但是發(fā)現(xiàn)這個(gè)錯(cuò)誤碼并不是本系統(tǒng)的錯(cuò)誤碼。
然后再前翻兩頁(yè)后翻兩頁(yè)從日志上下文中確定這是李雷負(fù)責(zé)系統(tǒng)的錯(cuò)誤碼,“Li Lie,how old are you?”。
韓梅梅把錯(cuò)誤碼甩到李雷臉上,李雷一臉懵逼,這是我的系統(tǒng)的錯(cuò)誤碼嗎?
李雷也不確定,因?yàn)槔罾棕?fù)責(zé)的系統(tǒng)是由李雷、林濤和 Jim 維護(hù)的,也是三人共同維護(hù)的。
李雷只好打開(kāi)源碼,還真是!
上邊的場(chǎng)景經(jīng)過(guò)了發(fā)現(xiàn)-初判斷-判斷來(lái)源-確定來(lái)源-溝通-二次判斷-二次確認(rèn)七個(gè)步驟。
希望上邊的場(chǎng)景描述能夠說(shuō)明沒(méi)有統(tǒng)一標(biāo)準(zhǔn)的錯(cuò)誤所帶來(lái)的成本。
四 面向日志的錯(cuò)誤碼
輸出到日志的錯(cuò)誤碼有兩個(gè)用途:
- 用來(lái)快速溯源找到問(wèn)題。
- 用來(lái)形成監(jiān)控大盤。
錯(cuò)誤碼設(shè)計(jì)
《手冊(cè)》對(duì)于錯(cuò)誤碼的建議有非常多的可取參考的地方:
錯(cuò)誤碼不體現(xiàn)版本號(hào)和錯(cuò)誤等級(jí)信息。
說(shuō)明:錯(cuò)誤碼以不斷追加的方式進(jìn)行兼容。錯(cuò)誤等級(jí)由日志和錯(cuò)誤碼本身的釋義來(lái)決定。
錯(cuò)誤碼為字符串類型,共 5 位,分成兩個(gè)部分:錯(cuò)誤產(chǎn)生來(lái)源+四位數(shù)字編號(hào)。
錯(cuò)誤碼不能直接輸出給用戶作為提示信息使用。
說(shuō)明:堆棧(stack_trace)、錯(cuò)誤信息(error_message)、錯(cuò)誤碼(error_code)、提示信息(user_tip)是一個(gè)有效關(guān)聯(lián)并互相轉(zhuǎn)義的和諧整體,但是請(qǐng)勿互相越俎代庖。
在獲取第三方服務(wù)錯(cuò)誤碼時(shí),向上拋出允許本系統(tǒng)轉(zhuǎn)義,由 C 轉(zhuǎn)為 B,并且在錯(cuò)誤信息上帶上原有的第三方錯(cuò)誤碼。
結(jié)合錯(cuò)誤碼設(shè)計(jì)原則、錯(cuò)誤碼用途、規(guī)約建議,面向服務(wù)端日志的錯(cuò)誤碼應(yīng)該是如下形式。
錯(cuò)誤碼分為一級(jí)宏觀錯(cuò)誤碼、二級(jí)宏觀錯(cuò)誤碼、三級(jí)宏觀錯(cuò)誤碼。
錯(cuò)誤碼即人性,感性認(rèn)知+口口相傳,使用純數(shù)字來(lái)進(jìn)行錯(cuò)誤碼編排不利于感性記憶和分類。
說(shuō)明:數(shù)字是一個(gè)整體,每位數(shù)字的地位和含義是相同的。
反例:一個(gè)五位數(shù)字 12345,第 1 位是錯(cuò)誤等級(jí),第 2 位是錯(cuò)誤來(lái)源,345 是編號(hào),人的大腦不會(huì)主動(dòng)地分辨每位數(shù)字的不同含義。
按照《手冊(cè)》的建議設(shè)計(jì)出的面向日志的錯(cuò)誤碼定義共十三位(十位有意義,三位連接符),并且應(yīng)該具有如下分類:
- 應(yīng)用標(biāo)識(shí),表示錯(cuò)誤屬于哪個(gè)應(yīng)用,三位數(shù)字。
- 功能域標(biāo)識(shí),表示錯(cuò)誤屬于應(yīng)用中的哪個(gè)功能模塊,三位數(shù)字。
- 錯(cuò)誤類型,表示錯(cuò)誤屬于那種類型,一位字母。
- 錯(cuò)誤編碼,錯(cuò)誤類型下的具體錯(cuò)誤,三位數(shù)字。
?? 
《手冊(cè)》還有一條是規(guī)定錯(cuò)誤碼應(yīng)該如何定義:
錯(cuò)誤碼為字符串類型,共 5 位,分成兩個(gè)部分:錯(cuò)誤產(chǎn)生來(lái)源+四位數(shù)字編號(hào)。
說(shuō)明:錯(cuò)誤產(chǎn)生來(lái)源分為 A/B/C,A 表示錯(cuò)誤來(lái)源于用戶,比如參數(shù)錯(cuò)誤,用戶安裝版本過(guò)低,用戶支付超時(shí)等問(wèn)題;B 表示錯(cuò)誤來(lái)源于當(dāng)前系統(tǒng),往往是業(yè)務(wù)邏輯出錯(cuò),或程序健壯性差等問(wèn)題;C 表示錯(cuò)誤來(lái)源于第三方服務(wù),比如 CDN 服務(wù)出錯(cuò),消息投遞超時(shí)等問(wèn)題;四位數(shù)字編號(hào)從 0001 到 9999,大類之間的步長(zhǎng)間距預(yù)留 100。
五位錯(cuò)誤碼的好處是易記,但是對(duì)于面向日志的錯(cuò)誤碼場(chǎng)景利用錯(cuò)誤碼制作需要分類的業(yè)務(wù)監(jiān)控大盤將變得比較困難,比如統(tǒng)計(jì)應(yīng)用 A 的功能 B 的錯(cuò)誤出現(xiàn)次數(shù)。
同樣在系統(tǒng)間傳遞這個(gè)類型的錯(cuò)誤碼非常有可能發(fā)生錯(cuò)誤碼沖突。
當(dāng)然對(duì)于分為四段的錯(cuò)誤碼同樣尤其不好的一面,應(yīng)用標(biāo)識(shí)和功能域標(biāo)識(shí)需要有專人去管理或者開(kāi)發(fā)一個(gè)錯(cuò)誤碼管理工具,否則時(shí)間一長(zhǎng)很容易產(chǎn)生定義的混亂形成破窗。
《手冊(cè)》對(duì)于錯(cuò)誤碼定義我認(rèn)為非常適合面向外部傳遞的錯(cuò)誤碼。簡(jiǎn)單、易記、是大家熟悉的錯(cuò)誤碼樣式,并且透出的錯(cuò)誤碼數(shù)量是非常有限的。
不用枚舉定義錯(cuò)誤碼
國(guó)際化支持是一個(gè)不使用枚舉定義錯(cuò)誤碼很重要的理由。
我們通過(guò) i18n 的支持可以做到錯(cuò)誤碼、錯(cuò)誤狀態(tài)、錯(cuò)誤描述的管理。
五 面向外部傳遞的錯(cuò)誤碼
面向外部傳遞的錯(cuò)誤碼是為了把域內(nèi)的錯(cuò)誤信息傳遞出去。
可以讓域外系統(tǒng)通過(guò)錯(cuò)誤碼進(jìn)行錯(cuò)誤碼進(jìn)行后續(xù)的動(dòng)作或是中斷操作或是記錄日志繼續(xù)執(zhí)行。
可以讓前端通過(guò)錯(cuò)誤碼給出用戶準(zhǔn)確的錯(cuò)誤提示或者忽略錯(cuò)誤進(jìn)行重試。
錯(cuò)誤碼設(shè)計(jì)
根據(jù)《手冊(cè)》給出的錯(cuò)誤碼定義建議設(shè)計(jì)出的面向外部傳遞的錯(cuò)誤碼共五位,并且有如下分類:
- 錯(cuò)誤類型,表示錯(cuò)誤來(lái)源,一位字母。
- 錯(cuò)誤編碼,表示具體錯(cuò)誤,四位數(shù)字。
?? 
錯(cuò)誤碼的后三位編號(hào)與 HTTP 狀態(tài)碼沒(méi)有任何關(guān)系。
錯(cuò)誤碼即人性,感性認(rèn)知+口口相傳,使用純數(shù)字來(lái)進(jìn)行錯(cuò)誤碼編排不利于感性記憶和分類。
說(shuō)明:數(shù)字是一個(gè)整體,每位數(shù)字的地位和含義是相同的。
反例:一個(gè)五位數(shù)字 12345,第1位是錯(cuò)誤等級(jí),第 2 位是錯(cuò)誤來(lái)源,345 是編號(hào),人的大腦不會(huì)主動(dòng)地分辨每位數(shù)字的不同含義。
下圖是《手冊(cè)》給出的錯(cuò)誤碼示例:
?? 
他山之石
他山之石不一定能攻玉。
谷歌 API 錯(cuò)誤碼定義
谷歌 API 的錯(cuò)誤碼定義與 HTTP 狀態(tài)碼有著非常強(qiáng)的聯(lián)系,并且是一個(gè)全數(shù)字錯(cuò)誤碼定義。
沒(méi)有明顯的錯(cuò)誤分類,快速識(shí)別和自解釋能力比較弱。
?? 
騰訊 OpenAPI(文智)錯(cuò)誤碼定義
這也是一個(gè)全數(shù)字的錯(cuò)誤碼,沒(méi)有明確的分類字段,純數(shù)字的某一位已看不出明顯的分類。
不利于進(jìn)行感性記憶。
?? 
微博 API 錯(cuò)誤碼定義
同樣是全數(shù)字的錯(cuò)誤碼定義:
?? 
其他建議
《手冊(cè)》中有一條建議:
全部正常,但不得不填充錯(cuò)誤碼時(shí)返回五個(gè)零:00000。
這也是在其他家 API 錯(cuò)誤碼中能夠看到的定義。
參考
《阿里巴巴java開(kāi)發(fā)手冊(cè)》《Google API Design Guide 》(https://www.bookstack.cn/books/API-design-guide)《阿里云-文件存儲(chǔ)-錯(cuò)誤碼》(https://help.aliyun.com/document_detail/62603.html)《微博開(kāi)放平臺(tái)-API-錯(cuò)誤碼》(https://open.weibo.com/wiki/Help/error)《騰訊開(kāi)放平臺(tái)-錯(cuò)誤碼》(https://wiki.open.qq.com/wiki/%E9%94%99%E8%AF%AF%E7%A0%81)




























