摘要:綜合以上問(wèn)題得出以下結(jié)論業(yè)務(wù)處理失敗消息要以的方式向上傳遞給調(diào)用者業(yè)務(wù)處理失敗消息以參數(shù)的方式傳遞不是很適合,并且不能以的方式返回再次思考,最終從里面想到了一點(diǎn)思路幸好是出身。
場(chǎng)景:創(chuàng)建訂單 實(shí)際流程:我需要拍磚 和 看見(jiàn)你們的意見(jiàn),為團(tuán)隊(duì)少挖坑
業(yè)務(wù)處理類(lèi)動(dòng)作:終端調(diào)用(PC端、移動(dòng)端APP、微信端、Web端)-->控制器 或 接口-->實(shí)際的業(yè)務(wù)處理-->控制器 或 接口-->終端做出相應(yīng)處理(控制器可能是渲染對(duì)應(yīng)頁(yè)面; 接口返回 JSON數(shù)據(jù))
檢查用戶是否登陸
驗(yàn)證商品 ID、購(gòu)買(mǎi)數(shù)量等參數(shù)
檢查該商品是否處于上架中
檢查該商品是否可以購(gòu)買(mǎi)
各種檢查...
創(chuàng)建訂單
記錄 Log
返回訂單創(chuàng)建結(jié)果給調(diào)用者
創(chuàng)建失敗:...
創(chuàng)建成功:[return true|return Order info]
游戲規(guī)則前后端數(shù)據(jù)格式約定為 JSON格式如下:
{ code: "00000", // 狀態(tài)碼 msg: "操作成功!", // 提示信息 data: {} // 數(shù)據(jù) }
導(dǎo)火線注:"00000":業(yè)務(wù)成功狀態(tài)碼;非"00000"都為業(yè)務(wù)失敗。
為了防止服務(wù)器端狀態(tài)碼泛濫成災(zāi),code可以為"",這時(shí) msg 里面則是相應(yīng)的錯(cuò)誤信息,只為給用戶提示。
項(xiàng)目開(kāi)發(fā)完畢,測(cè)試人員去測(cè)試,提如下Bug:
如果用戶未登錄,進(jìn)個(gè)人中心,提示用戶未登錄,然后會(huì)去登陸view;而在下單頁(yè),提示用戶未登錄,卻沒(méi)有去登陸view。
然后前端童鞋開(kāi)始去修復(fù)該問(wèn)題,查出如下問(wèn)題:
個(gè)人中心服務(wù)器接口返回的數(shù)據(jù)格式:
{ code: "00008", msg: "用戶未登錄,請(qǐng)登錄", data: [ ] }
下單頁(yè)服務(wù)器接口返回的數(shù)據(jù)格式:
{ code: "", msg: "用戶未登錄,請(qǐng)登錄!", data: [ ] }
然后前端童鞋對(duì)服務(wù)器端童鞋講,這里你應(yīng)該返回給我code: "00008",我這邊一看 code便知是用戶未登錄,就可以做出相應(yīng)的操作,這里你只返回提示信息,我這邊不好做更加細(xì)膩的操作。
然后,后端童鞋開(kāi)始嘗試給該地方添加上 code。
開(kāi)始著手修改代碼:
首先找到接口方法里面發(fā)現(xiàn)如下 demo:
php$order = kernel::single("sysapi_ecoupon_order")->create($params, $msg); if (!$order) { return array("code" => "", "data" => array(), "msg" => $msg); } return array("code" => "00000", "data" => $order);
改方法返回array(); 在外部統(tǒng)一入口、出口處再返回 JSON出去。
sysapi_ecoupon_order
phppublic function createNew($params, & $msg) { // 獲取用戶信息 $member_info = app::get("b2c")->model("members")->get_current_member(); if (empty($member_info)) { $msg = app::get("ecoupon")->_("用戶未登錄,請(qǐng)登錄!"); return false; } // 繼續(xù)下面的業(yè)務(wù)處理 }
接口調(diào)用的kernel::single("sysapi_ecoupon_order")->create($params, $msg);這里面做實(shí)際的業(yè)務(wù)處理,錯(cuò)誤信息是通過(guò) $msg 向上傳遞出去,外部沒(méi)辦法通過(guò) $msg 獲知對(duì)應(yīng)的 code。然后給前端童鞋講這種情況沒(méi)辦法返回 code給你。
前端就只能通過(guò)判斷 msg的方式來(lái)修復(fù)該問(wèn)題
然后寫(xiě)了如下 demo:
javascriptif("用戶未登錄,請(qǐng)登錄!" == data.msg) { // 用戶未登錄,去登錄 // ... }
然后提交,測(cè)試,通過(guò),上線,N天后
有人跑過(guò)來(lái)講:下單頁(yè) 與 個(gè)人中心的提示有點(diǎn)不同,貌似多了個(gè) "!"。(舉例而已,更多的可能是提示不友好、錯(cuò)別字等情況)
然后后端同學(xué)修改為 $msg = app::get("ecoupon")->_("用戶未登錄,請(qǐng)登錄"); 提交,測(cè)試不通過(guò),前端同學(xué)再修改為if("用戶未登錄,請(qǐng)登錄" == data.msg),提交,測(cè)試通過(guò)
// 如此反反復(fù)復(fù)
終究有一天:產(chǎn)品、測(cè)試,前端、后端混戰(zhàn)了一場(chǎng)。N人,卒.....
重新正視問(wèn)題最終前后端得出結(jié)論:要想對(duì)用戶實(shí)現(xiàn)更加友好的體驗(yàn),前后端數(shù)據(jù)必須有個(gè)標(biāo)識(shí)具有唯一性,不變性。而現(xiàn)在用的 msg卻不具備,還是得用 code。并且這里前后端極度耦合msg。
后端童鞋回來(lái)繼續(xù)修改代碼,開(kāi)始著手給這里添加上相應(yīng)的 code。
開(kāi)始思考該怎么添加 code,現(xiàn)在的問(wèn)題是 create( ) 方法可能是其他童鞋開(kāi)發(fā),內(nèi)部返回的提示信息,我這邊是調(diào)用者,不能確定方法內(nèi)部到底會(huì)返回什么提示信息,無(wú)解。
忽然,有一天想到,我在調(diào)用該方法之前檢查下用戶有沒(méi)有登錄就OK了,然后開(kāi)始寫(xiě)如下實(shí)現(xiàn):
public function create($params) { $member = app::get("b2c")->model("members")->get_current_member(); // 登錄驗(yàn)證 if (empty($member)) { return array("code" => "00008"); } $msg = ""; $order = kernel::single("sysapi_ecoupon_order")->create($params, $msg); if (!$order) { return array("code" => "", "data" => array(), "msg" => $msg); } return array("code" => "00000", "data" => $order); }
呵呵,好機(jī)智的少年。
然后告訴前端,這里可以返回 code了,前端愉快的刪掉原來(lái)那坨判斷 msg的代碼,而在 ajax請(qǐng)求的地方統(tǒng)一判斷 code就能預(yù)知用戶未登錄,做出相應(yīng)的操作。
經(jīng)測(cè)試,上線。一切又回到了美好時(shí)光。
隨著時(shí)光的流逝,業(yè)務(wù)的增加,后端童靴發(fā)現(xiàn)Order類(lèi)里面如下 demo:
phppublic function create($params) { $member = app::get("b2c")->model("members")->get_current_member(); // 登錄驗(yàn)證 if (empty($member)) { return array("code" => "00008"); } // 實(shí)際業(yè)務(wù)處理.... } public function getOrderList($params) { $member = app::get("b2c")->model("members")->get_current_member(); // 登錄驗(yàn)證 if (empty($member)) { return array("code" => "00008"); } // 實(shí)際業(yè)務(wù)處理.... } public function getOrderDetail($params) { $member = app::get("b2c")->model("members")->get_current_member(); // 登錄驗(yàn)證 if (empty($member)) { return array("code" => "00008"); } // 實(shí)際業(yè)務(wù)處理.... } // ...
這都是什么玩意............ 然后開(kāi)始封裝,稍微好了點(diǎn)
又過(guò)了一段時(shí)間,有人過(guò)來(lái)說(shuō)創(chuàng)建訂單還需要優(yōu)化體驗(yàn),
點(diǎn)擊創(chuàng)建訂單提示如下:
超過(guò)最大購(gòu)買(mǎi)量——給出提示,繼續(xù)留在創(chuàng)建訂單頁(yè)
該商品已賣(mài)光或已下架——引導(dǎo)用戶去商品列表頁(yè)
這時(shí),前端童鞋告訴后端童鞋,商品下架的時(shí)候,你也應(yīng)該返回一個(gè)狀態(tài)碼。
后端童鞋開(kāi)始打算添加 code,發(fā)現(xiàn)如下 demo
phpkernel::single("sysapi_ecoupon_order")->create($params, $msg);
這里的提示信息是 $msg 返回的,用戶登錄外部可以提前檢測(cè),這里的商品能否購(gòu)買(mǎi)要實(shí)現(xiàn)添加 code也需要提前檢測(cè),將來(lái)要是需要添加類(lèi)是功能豈不是...... 每需要一個(gè)精確的 code返回出去,這里就需要添加檢測(cè),這里代碼將會(huì)變得無(wú)法直視。
況且這里本該在業(yè)務(wù)里面檢測(cè),一切不那么友好起來(lái)了。
再次思考,代碼寫(xiě)的不爽了,一定是哪里不對(duì)
問(wèn)題所在開(kāi)始懷疑 public function create($params, & $msg) { } 這里不應(yīng)該是通過(guò) & $msg 來(lái)作為 調(diào)用者與 被調(diào)用者之間的 錯(cuò)誤信息通信約定,一切的問(wèn)題都出在了這里。錯(cuò)誤消息向上傳播的約定不合適
如果這里約定的是 code作為錯(cuò)誤向上傳播一切的問(wèn)題即將不復(fù)存在。在調(diào)用業(yè)務(wù)方法之前的檢測(cè)代碼就都可以去掉了,代碼簡(jiǎn)約,一切又美好起來(lái)。
接下來(lái)繼續(xù)思考,使用 code作為業(yè)務(wù)處理失敗消息傳遞問(wèn)題又來(lái)了
現(xiàn)在已有的業(yè)務(wù)代碼都是如此定義public function create($params, & $msg),怎樣更加友好的替換成 code
如果使用 code,code只能服務(wù)器端 與 前端約定的一個(gè)具有唯一性的標(biāo)識(shí)(code 比 msg 對(duì)國(guó)際化的實(shí)現(xiàn)更加容易)但是并不能直接展示給用戶,那么就需要定義每個(gè) code 的代表的意義 與 對(duì)應(yīng)的提示信息。那么問(wèn)題來(lái)了,code 應(yīng)該已怎樣規(guī)范來(lái)定義所代表的含義
再來(lái)看如下常用的兩種方法定義:
public function create($params, & $msg)
public function create($goodsId, $num, & $msg)
第一種方式,參數(shù)通過(guò)一個(gè) $params數(shù)組傳遞過(guò)來(lái),方法內(nèi)部在把錯(cuò)誤提示放到 $msg中。
好處:$params是個(gè)數(shù)組,里面參數(shù)可以任意添加
缺點(diǎn):該方法調(diào)用者在外部不能知道該方法需要什么參數(shù),必須來(lái)看該方法內(nèi)部實(shí)現(xiàn),做出對(duì)應(yīng)的數(shù)組 key的轉(zhuǎn)換(如: user_id 轉(zhuǎn) userId)。方法調(diào)用者 與 方法實(shí)現(xiàn) 極度耦合。維護(hù)成本大、出Bug系數(shù)高
第二種方式,按基本類(lèi)型分別傳遞單個(gè)參數(shù)
好處:方法調(diào)用者根據(jù)方法定義就能夠知道方法具體需要的參數(shù),調(diào)用方法時(shí)不需要作 key轉(zhuǎn)換,只需要傳遞對(duì)應(yīng)的參數(shù)即可
缺點(diǎn):參數(shù)數(shù)目過(guò)多時(shí),慘不忍睹
這里有如下問(wèn)題:
這里如何已一種更加容易維護(hù),擴(kuò)展的方式來(lái)處理(Java里面方法參數(shù)已對(duì)象的方式傳遞可以借鑒)
這里的& $msg 真的合適嗎,如果是第二種方式定義的方法,以后擴(kuò)展個(gè) $phone 該如何處理?public function create($goodsId, $num, & $msg, $phone="")這樣么?怎么看怎么蛋疼
再來(lái)看不通過(guò) & $msg傳遞錯(cuò)誤信息之后的代碼
phppublic function create($goodsId, $num) { if ( ? ) { // 返回狀態(tài)碼 return "0001"; } if ( ? ) { // 返回狀態(tài)碼 return "0002"; } // 創(chuàng)建訂單 // ... // 返回訂單信息 return $order; }
看似實(shí)現(xiàn)了,但是方法調(diào)用者,怎么調(diào)用怎么蛋疼,一會(huì)返回狀態(tài)碼,一會(huì)返回訂單信息,完全兩種類(lèi)型。
綜合以上問(wèn)題:得出以下結(jié)論:
業(yè)務(wù)處理失敗消息要以 code 的方式向上傳遞給調(diào)用者
業(yè)務(wù)處理失敗消息以參數(shù)的方式傳遞不是很適合,并且不能以 return的方式返回
再次思考,最終從 Java里面想到了一點(diǎn)思路(幸好是 Java出身。疑問(wèn):為何面試的時(shí)候 Java的工作經(jīng)驗(yàn)都不算在 PHP工作經(jīng)驗(yàn)里呢,并沒(méi)有因此而加分)
解決方案:自定義一個(gè)異常類(lèi),包括 codo屬性 和 msg 屬性
凡是遇到業(yè)務(wù)不能正常處理的時(shí)候就創(chuàng)建一個(gè)異常對(duì)象,設(shè)置對(duì)應(yīng)的 code 或者 msg屬性(為了減少 code泛濫,這里的 code 與 msg 可以2選一,如果前端需要做精準(zhǔn)的處理,就設(shè)置 code,如果只是為了給用戶提示,就只返回 msg,則可以減少一個(gè) code),然后拋出異常
方法調(diào)用者在外部統(tǒng)一捕捉該異常,如 接口的統(tǒng)一入口出口的方法內(nèi)部處理
因個(gè)人工作時(shí)間、項(xiàng)目經(jīng)歷不多、歸根結(jié)底經(jīng)驗(yàn)不足?,F(xiàn)在將該方案寫(xiě)下來(lái),還望有經(jīng)驗(yàn)的大神拍磚,以免給團(tuán)隊(duì)挖坑,以上 $msg 就是 N久以前埋下的坑。
該文章發(fā)布在自己站點(diǎn)地址:http://www.webdevs.cn/article/91.html
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/20921.html
摘要:是騰訊云內(nèi)部自研基于的高可靠強(qiáng)一致可擴(kuò)展分布式消息隊(duì)列,在騰訊內(nèi)部包括微信手機(jī)業(yè)務(wù)紅包騰訊話費(fèi)充值廣告訂單等都有廣泛使用。目前已上線騰訊云對(duì)外開(kāi)放,本文對(duì)核心技術(shù)原理進(jìn)行分享介紹。 ? 極牛技術(shù)實(shí)踐分享活動(dòng) 極牛技術(shù)實(shí)踐分享系列活動(dòng)是極牛聯(lián)合頂級(jí)VC、技術(shù)專家,為企業(yè)、技術(shù)人提供的一種系統(tǒng)的線上技術(shù)分享活動(dòng)。 每期不同的技術(shù)主題,和行業(yè)專家深度探討,專注解決技術(shù)實(shí)踐難點(diǎn),推動(dòng)技術(shù)創(chuàng)新,...
摘要:為了幫助用戶更好地完成消費(fèi)決策閉環(huán),馬蜂窩上線了大交通業(yè)務(wù)?,F(xiàn)在,用戶在馬蜂窩也可以完成購(gòu)買(mǎi)機(jī)票火車(chē)票等操作。第二階段架構(gòu)轉(zhuǎn)變及服務(wù)化初探從年開(kāi)始,整個(gè)大交通業(yè)務(wù)開(kāi)始從架構(gòu)向服務(wù)化演變。 交通方式是用戶旅行前要考慮的核心要素之一。為了幫助用戶更好地完成消費(fèi)決策閉環(huán),馬蜂窩上線了大交通業(yè)務(wù)?,F(xiàn)在,用戶在馬蜂窩也可以完成購(gòu)買(mǎi)機(jī)票、火車(chē)票等操作。 與大多數(shù)業(yè)務(wù)系統(tǒng)相同,我們一樣經(jīng)歷著從無(wú)到有...
閱讀 623·2021-11-25 09:44
閱讀 2790·2021-11-24 09:39
閱讀 2413·2021-11-22 15:29
閱讀 3654·2021-11-15 11:37
閱讀 3515·2021-09-24 10:36
閱讀 2626·2021-09-04 16:41
閱讀 1132·2021-09-03 10:28
閱讀 2037·2019-08-30 15:55