為什么要談代碼層級與接口設(shè)計
在目前的工作中丽惭,代碼如果按照MVC邏輯劃分,那么只有MC兩層炼彪。作為后端吐根,只對其他各端提供接口,V層是不用實現(xiàn)辐马。在MC的大前提下仍然和各端的工作有著不少的沖突】介伲現(xiàn)行的問題存在以下幾點:
1、根據(jù)前端流行的一種觀念:后端提供什么數(shù)據(jù)喜爷,前端就消費什么數(shù)據(jù)冗疮。在一端的情況下,這樣無可厚非檩帐,但是當(dāng)面臨幾個端的時候术幔,這樣就相當(dāng)于將各端格式化的數(shù)據(jù)工作全部疊加在后端身上。導(dǎo)致后端的工作可能是9倍xN端的疊加湃密。
2诅挑、接口設(shè)計需要具備單一職責(zé)原則。但是在高并發(fā)的情況下泛源,為了減少網(wǎng)絡(luò)請求拔妥,需要將幾個接口進行融合產(chǎn)生新的接口作為提供。隨著這樣的接口不斷增多达箍,同樣會導(dǎo)致后端的工作也可能是9倍xN的疊加没龙。
3、由于目前工作的問題缎玫,接口文檔都是后端編寫的硬纤,這樣后端維護文檔也占用了后端大部分的時間。曾經(jīng)有人向我吐槽過赃磨,后端讓各端都共用一份接口筝家,讓他的工作很難做,因為他對接口做很多邏輯操作來兼容產(chǎn)品提出的設(shè)計邻辉。我當(dāng)時給出的觀點是肛鹏,為各端的不同邏輯給出不一樣的接口和提供不同的接口文檔。現(xiàn)在想想恩沛,我當(dāng)時的做法也是導(dǎo)致后端工作繁重疊加的根源。因為維護接口文檔也是一件很重要而又不想做的工作缕减。
這幾個問題的疊加雷客,特別遇上產(chǎn)品經(jīng)理要改需求的時候,后端的工作簡直不可想象桥狡。為了解決這幾個問題搅裙,還是要回歸到后端的代碼層級和接口設(shè)計皱卓。
代碼層級的誕生
代碼層級就像公司里面的部門一樣產(chǎn)生的。如一家小公司部逮,一個人可能身兼多職娜汁,隨著公司的壯大,會因為職責(zé)劃分明確而產(chǎn)生不同的職能部門兄朋。MVC是我們熟悉的層級掐禁,我們只是知道了大體方向,至于里面如果將代碼層劃分出更細化的功能颅和,沒有那些資料可以給出明確的答案傅事,因為根據(jù)業(yè)務(wù)的不同和架構(gòu)師(程序員)的“信仰”不一樣,具象化的層級也會不一樣的峡扩。而我現(xiàn)在面對的是需要靈活擴展的需求蹭越,所以我的代碼層級劃分上,以犧牲一定性能來獲取更高的可擴展性教届。所以我的代碼目前細致分為:模塊化的純Model層响鹃、Model組合字段層、邏輯業(yè)務(wù)層案训、邏輯格式化層买置、邏輯條件過濾層。
模塊化的純Model層
為什么要“純”萤衰?這一層只負責(zé)從數(shù)據(jù)庫中取出原生的數(shù)據(jù)堕义,數(shù)據(jù)庫中的字段名稱是什么就是什么,不作任何的加工脆栋。要實現(xiàn)這樣的要求倦卖,那么我們的設(shè)計首先就要符合模塊化的設(shè)計,有把重名的字段在查詢的階段就作了沖突處理椿争,所有在查詢的時候不會因為數(shù)據(jù)庫字段名相同而產(chǎn)生沖突怕膛。故此,這一層得到的數(shù)據(jù)可以看作是原子數(shù)據(jù)秦踪。
Model組合字段層
根據(jù)不同的業(yè)務(wù)邏輯褐捻,往往需要對原生的字段進行組合,如:A+B=C這樣的形式椅邓,或者會是更加復(fù)雜的字段組合柠逞。這一層是純Model層的額外附加,不會產(chǎn)生跟數(shù)據(jù)庫原生字段的有命名沖突景馁。所以查詢是會從數(shù)據(jù)庫中查詢出原生字段板壮,然后再根據(jù)業(yè)務(wù)邏輯的需要進行相應(yīng)的組合。
邏輯業(yè)務(wù)層
這一層就是我們熟悉的Controller層合住。根據(jù)業(yè)務(wù)需求將Model層數(shù)據(jù)組合處理進行返回绰精。故此撒璧,不過多闡述。
邏輯格式化層
由于模塊化的純Model層不做格式化的工作笨使,故此誕生這一層的代碼卿樱。如對時間的轉(zhuǎn)換,即數(shù)據(jù)庫中設(shè)計的字段是整形(int)類型硫椰,需要轉(zhuǎn)換為2017-01-08繁调。這一層的誕生,可以讓model層的工作更加專注化最爬,也讓業(yè)務(wù)更加靈活涉馁。因為這一層可以根據(jù)不同端的需求和業(yè)務(wù)的不同,切換不同的格式化工具爱致,但是一般不建議這樣做烤送。
邏輯參數(shù)過濾層
該層將接口傳遞的參數(shù)進行篩選過濾后,經(jīng)過格式化層后糠悯,再傳入Model層帮坚。其實這一層的誕生,是因為每次寫代碼時互艾,獲取幾個參數(shù)是试和,都要寫一次循環(huán)是很麻煩。經(jīng)過對相同操作進行不斷的整合而誕生的這一層纫普。
這些層級是是我目前的代碼層級阅悍。這是經(jīng)過一年多對代碼的不斷重構(gòu)后的成果。邏輯業(yè)務(wù)層通過對其他幾層的不同的組合昨稼,可以滿足因為業(yè)務(wù)的擴展而快速提供接口节视。
接口設(shè)計
在完成代碼層級的設(shè)計后,便開始遇到了以上幾點工作上的難題假栓。盡管那些問題我的代碼層級都可以完全實現(xiàn)寻行。但是這些不得不做的繁重的工作,致使工作量的堆積匾荆,會導(dǎo)致我很難進行新的優(yōu)化拌蜘,這樣會使工作困難重重。(Don't repeat yourself牙丽!是我的代碼信仰)简卧。為了解決以上問題,構(gòu)思了幾點接口上設(shè)計的建議烤芦,這些建議建立在接口設(shè)計的六大原則之上举娩。
后端提供模塊化的所有字段
即模塊的字典表,后端應(yīng)該維護好這份字典表。因為接口的所有參數(shù)(增刪查改)晓铆,都必須是字典表里面的字段。即使是而我上面提出的組合字段層的字段绰播,也會全部出現(xiàn)在字段表中骄噪。一旦在字典表中聲明,特別是在有對應(yīng)的端接上的時候蠢箩,是不可以更改的链蕊。這份字典表幾乎是只可以增量。
參數(shù)帶上模塊的標(biāo)識
因為不同的模塊谬泌,會有相同的字段滔韵。如:產(chǎn)品模塊的name和客戶模塊的name。當(dāng)特別遇到組合接口的時候掌实,需要用product[name]和customer[name]進行區(qū)分陪蜻。而后端可以利用邏輯參數(shù)過濾層后,再將參數(shù)傳入Model層贱鼻。從Model層出來的數(shù)據(jù)宴卖,可以經(jīng)過邏輯格式化層再返回給各端。
盡量提供統(tǒng)一性接口
在提供接口時邻悬,盡量要考慮多端利益症昏,不可單端返回接口,盡量做到做統(tǒng)一的格式化工作父丰。各端需要自己進行格式化后端提供的數(shù)據(jù)肝谭。如:created_at: 1293971786,產(chǎn)品在為不同端設(shè)計時蛾扇,或者在不同場景攘烛,會有不同格式如顯示2011/1/2 20:36:26或者顯示2011/1/2。即是屁桑,沒有特定的情況下医寿,盡量少針對性提供接口。
后端不編寫針對性接口文檔
每端會因為自身語言的特性蘑斧,或者特定的插件靖秩,需要提供針對性的接口。同時為了加快開發(fā)速度竖瘾,需要后端做一些特定的邏輯沟突,來滿足他端的需要。站在目前的角度捕传,我不希望出現(xiàn)這個接口惠拭,因為出現(xiàn)不統(tǒng)一,直接導(dǎo)致更多的coding,自然會導(dǎo)致更多的錯誤职辅,造成后期更難的擴展棒呛,甚至?xí)?dǎo)致項目的失敗。故此域携,這些文檔不應(yīng)該由后端提供簇秒。
其實寫到最后,感覺說服力有點不足秀鞭。首先趋观,因為我沒有見過一些完整的規(guī)范(缺陷長存),而目前我也沒有見到接口相關(guān)的規(guī)范和編寫代碼要如何分層锋边。一切都靠自己的經(jīng)驗去摸索和驗證皱坛!正如,我今天很不滿意我?guī)讉€月前很自豪的代碼一樣豆巨,但是我相信一點剩辟,程序員是一群努力走在“完美”道路上的藝術(shù)家。