有問必答
最近有好多讀者私信我,為什么選擇GoFrame做電商項目的開發(fā)?
原因很簡單:
因為我司是用GoFrame做電商業(yè)務(wù)開發(fā)的,而且我司同事基本都是php轉(zhuǎn)Go的。GoFrame可以說是非常適合PHPer轉(zhuǎn)Gopher的開發(fā)框架。
在入職我司之前,我有使用Gin和go-micro框架,目前也正在學(xué)習(xí)go-zero。
不管是開發(fā)語言還是開發(fā)框架,都服務(wù)于我們所做的業(yè)務(wù),拋開業(yè)務(wù)去聊語言或者框架都是沒有意義的。
使用GoFrame做開源項目的另一個原因是:想體驗一下V2版本的新特性,自己的項目怎么做自己能完全說了算,沒有歷史包袱。
前言
讓開發(fā)者更好的做到“模塊內(nèi)部高內(nèi)聚,模塊之間松耦合”,是我認(rèn)為GoFrame V2設(shè)計的精髓。
用GoFrame開發(fā)商業(yè)項目已經(jīng)很長時間,發(fā)現(xiàn)GoFrame的版本更新比較快,社區(qū)也非常的活躍。
因為歷史原因,我之前一直用V1.16版本做商業(yè)項目的開發(fā),雖然個人有比較強的意愿升級到V2。
但是考慮到項目穩(wěn)定性及開發(fā)成本等等原因,商業(yè)項目并未升級。這可能也是很多小伙伴面臨的問題。
受到鼓勵
正好前段時間,分享了自己的開源項目【Go WEB進階實戰(zhàn)】基于GoFrame搭建的電商前后臺API系統(tǒng)受到了大家的關(guān)注和支持,GoFrame的作者也在點贊轉(zhuǎn)發(fā),更受鼓勵。
更重要的是:收到了社區(qū)里很多小伙伴的建議,最多的建議就是建議我使用V2版本,因為提供了很多新特性,可以更好的實現(xiàn)需求,穩(wěn)定且高效。
決定升級
所以,我決定把我開源的項目從V1.16.x版本,升級到最新的V2.2.0版本,踩一下升級的坑,享受一下升級后的快樂。
歡迎小伙伴們加入到我的開源項目中:電商前后臺系統(tǒng)API[1],目前V1版本已經(jīng)收尾,包括電商項目的常用功能,開發(fā)了120多個接口。
一起參與
V2版本在開發(fā)過程中,目前已經(jīng)開發(fā)了30多個接口,計劃這個月內(nèi)開發(fā)完畢,也開源出去。歡迎小伙伴們參與共建,也歡迎閱讀我的源碼,多提寶貴建議:
V2版本GitHub地址
因為內(nèi)容比較長且硬核,所以我決定分兩篇文章分享:
- 這篇文章重點:介紹GoFrame V2的新特性,和V1相比有哪些優(yōu)勢?最大的變化是什么?
- 下一篇文章會分享一下:我從V1升級到V2的踩坑之旅,相信對很多小伙伴都有幫助。
這個經(jīng)歷實屬不易,希望小伙伴們可以點贊、關(guān)注、轉(zhuǎn)發(fā)一波。
適合看的人群
- 掌握Go基礎(chǔ)后,想用成熟框架開發(fā)項目的伙伴,建議讀完我的文章之后,直接使用GoFrame最新的V2版本實戰(zhàn)開發(fā)
- 目前在用V1版本,有意愿但是沒有大量精力學(xué)習(xí)V2新特性的伙伴,擔(dān)心升級問題太高不敢貿(mào)然升級的伙伴們。
- 想提高自己學(xué)習(xí)新知識效率的小伙伴,歡迎復(fù)刻我的這種實踐方式。
站在開發(fā)者的角度
不管你是哪種人群,都建議先花時間仔細(xì)閱讀官方文檔,尤其是 框架介紹[2]這部分。
區(qū)別于官方文檔,這篇文章會結(jié)合我自己的經(jīng)驗,站在框架使用者的角度,幫大家更快更好的理解Goframe V2版的設(shè)計思路,基于V2版本如何更好的進行商業(yè)項目的開發(fā)。
踩的坑
在我升級版本的過程中發(fā)現(xiàn):一定要先了解清楚V2的新特性,然后再從V1升級到V2,否則升級到一半會出現(xiàn)無從下手的問題:
- 因為通過V2版本的CLI工具生成的dao、model,和V1版本是不一致的:廢棄了gmvc模塊等,也引入了新的模塊。
- V2版本支持gf gen service的方式生成service層,統(tǒng)一我們接口邏輯的實現(xiàn)方式,引入了logic層和service層的概念
結(jié)合自己的升級經(jīng)歷,分享給大家學(xué)習(xí)GoFrame V2必知必會的知識點:
必知必會
- 項目工程結(jié)構(gòu)發(fā)生了變化,且需要按照V2的標(biāo)準(zhǔn)來,因為gf工具生成代碼的目錄結(jié)構(gòu)發(fā)生了改變,更重要的:V2官方建議的目錄結(jié)構(gòu)也是我們踐行"高內(nèi)聚低耦合"比較好的工程目錄結(jié)構(gòu)。
- gf gen dao除了會像V1一樣生成dao層和model層,還會另外生成do層和entity層
- V2版本的目錄結(jié)構(gòu)實踐了業(yè)務(wù)模型和數(shù)據(jù)模型解耦的思想(也是我認(rèn)為非常贊的地方)
- V2相比于V1會出現(xiàn)方法或者模塊廢棄的情況,比如廢棄了gmvc耦合模塊,未來不再進一步支持。同時也為我們提供了更好的實現(xiàn)方式。
- V2有點編寫“微服務(wù)”的意思了,需要服務(wù)注冊:controller調(diào)用一個或多個service實現(xiàn)具體的業(yè)務(wù)邏輯;但是復(fù)雜的業(yè)務(wù)邏輯又不是在service中實現(xiàn)的,為了解耦,V2版本引入了logic目錄,用于編寫和復(fù)用復(fù)雜的業(yè)務(wù)邏輯。在logic中注冊服務(wù),在service中通過接口方式規(guī)范logic層要實現(xiàn)的方法。
重中之重
下面再介紹一下我花了很長時間才消化的知識點:
dao代碼生成(很重要)
gf gen dao
在業(yè)務(wù)項目中,官方推薦使用dao/do/entity的方式操作數(shù)據(jù)庫,這些文件都是通過開發(fā)工具自動生成的,由開發(fā)工具統(tǒng)一維護。
區(qū)別于V1版本,V2版本引入了do的概念,為什么這么設(shè)計?
在這里我只說結(jié)論,文章最后會附上官方鏈接:
- dao層用于數(shù)據(jù)訪問,這是一層抽象對象,用于和底層數(shù)據(jù)庫交互,僅包含最基礎(chǔ)的 CURD 方法
- model層是結(jié)構(gòu)模型,是數(shù)據(jù)結(jié)構(gòu)管理模塊,管理數(shù)據(jù)實體對象,以及輸入與輸出數(shù)據(jù)結(jié)構(gòu)定義。2.1 model中的do是領(lǐng)域?qū)ο螅糜赿ao數(shù)據(jù)操作中業(yè)務(wù)模型與實例模型轉(zhuǎn)換,由工具維護,用戶不能修改。2.2 model中的entity是數(shù)據(jù)模型,數(shù)據(jù)模型是模型與數(shù)據(jù)集合的一對一關(guān)系,由工具維護,用戶不能修改。
后面我會帶著大家用實例講解
服務(wù)接口生成(更重要)
gf gen service
服務(wù)接口是非常重要的知識點,也是我認(rèn)為在cli工具支持方面和V1版本最大的區(qū)別:
為了降低業(yè)務(wù)項目內(nèi)部模塊間的耦合,框架將模塊間的依賴抽象為了接口,由internal/service包維護。internal/service可以由開發(fā)者自定義維護接口,也可以通過internal/logic業(yè)務(wù)封裝的代碼按照一定規(guī)則自動生成接口代碼文件。
實踐出真知
看10遍文檔,都不如一次動手實踐。建議大家和我一起操練起來,歡迎復(fù)刻:
我的思路是這樣:
- 下載官方的示例項目,學(xué)習(xí)一下官方是怎么寫的。
- 給自己提需求,參考官方的實現(xiàn)方式,實現(xiàn)自己的業(yè)務(wù)場景。
- 我會帶著大家實現(xiàn)經(jīng)典的電商場景:添加和查詢商品信息。
1. 下載運行官方示例的GitHub
官方示例GitHub[3]
1.1 下載部署好項目之后,啟動:非常順滑的就啟動成功了:
1.2 請求接口,驗證試一下DB是否連接正常。
1.3 查詢數(shù)據(jù)庫,也是有值的。
驗證環(huán)境無誤,下面開始帶著大家參考官方示例實現(xiàn)自己的需求,進而更好的理解V2版本新特性和工程實踐。
2. 基于V2編寫商品管理
我們按照官方建議的工程方式去實踐,看看會不會踩坑:
2.1 創(chuàng)建goods表如下:
2.2 通過gf gen dao生成dao和model
初次嘗試,失敗,原因是沒有修改hack目錄下的config.yaml配置文件。
注意:和V1不同,官方說hack目錄的作用是工具腳本,存放項目開發(fā)工具、腳本等內(nèi)容。例如,CLI工具的配置,各種shell/bat腳本等文件。所以我們就不要像V1一樣把cli工具的配置文件也寫到manifest/config目錄中了。
2.3 搞定,成功生成。
小技巧,如果我們不指定tables,則生成所有表對應(yīng)的數(shù)據(jù)。我是比較喜歡這么操作:因為能避免自己改了多個tables,但是在配置文件中漏寫了某個tables導(dǎo)致意料之外的問題。
下面開始正式擼代碼了:
我會先按照大家容易理解的方式進行編寫,文章最后我會分享實踐經(jīng)驗:按照什么順序編寫各個模塊的代碼是比較科學(xué)的。
2.4 首先我們實現(xiàn)api層,定義請求和響應(yīng)的結(jié)構(gòu)體
2.5 我們在cmd中注冊Goods相關(guān)的路由
2.6 我們發(fā)現(xiàn)注冊路由時,controller.Goods飄紅,原因是我們還沒有編寫這個方法。
我們參考示例代碼去編寫controller層:
我們發(fā)現(xiàn)右側(cè)的示例項目,方法內(nèi)部調(diào)用了service中的方法,但是我們目前還沒有定義service,怎么辦?
我們先點擊示例項目中的user.go,查看一下service中都定義了什么:
經(jīng)過查閱文檔得知:
我們需要通過編寫logic層實現(xiàn)業(yè)務(wù)邏輯,通過配置goland插件,自動生成service代碼。
這要是官方建議我們的最佳實踐:
2.7 導(dǎo)入官方提供的xml文件(只需要配置一次)
xml文件地址[4]
強烈建議大家這么操作,經(jīng)過這個配置在我們編寫logic層代碼的時候,service能自動生成接口定義文件。
當(dāng)然也可以不配置,只是每一次在開發(fā)/更新完成logic業(yè)務(wù)模塊后,都需要手動執(zhí)行一下 gf gen service 命令。太麻煩了!!!
2.8 我們參考右側(cè)的示例 編寫商品goods的logic代碼,處理業(yè)務(wù)邏輯:
2.9 經(jīng)測試我發(fā)現(xiàn):在編寫logic邏輯后,就自動在service層生成了對應(yīng)的goods文件和方法,非常方便。
2.10 我們再繼續(xù)寫添加商品邏輯和查看商品邏輯
我們發(fā)現(xiàn):在logic層編寫完添加商品邏輯后,在右側(cè)的service層自動生成了代碼。
2.11 細(xì)心的同學(xué)可能發(fā)現(xiàn)了service層的RegisterGoods方法,這是干嘛用的呢?
答案是:我們要在service層生成RegisterXX()方法后,在對應(yīng)的業(yè)務(wù)模塊中加上接口的實現(xiàn)注入。
小提示:該方法每個業(yè)務(wù)模塊加一次即可。
建議大家在編寫完第一個logic方法后(或者說service層生成了RegisterXX方法后):
- 就在logic層的init函數(shù)中實現(xiàn)服務(wù)的注冊;
- 然后去查看logic.go文件是否添加了相關(guān)的依賴,沒有的話也可以手動添加一下;
要成良好的編碼習(xí)慣,少出bug。
2.12 我們查看logic目錄下的logic.go文件,發(fā)現(xiàn)已經(jīng)自動添加了我們本次編寫的goods相關(guān)的import:
這個文件的作用是:將接口的具體實現(xiàn),在程序啟動時執(zhí)行注冊。
好了,logic和service到此結(jié)束,我們已經(jīng)完成了業(yè)務(wù)邏輯的編寫。
內(nèi)容不少,大家可以上劃再看一遍這部分內(nèi)容,消化吸收一下。
2.13 咱們回過頭來,繼續(xù)編寫controller層的代碼:
我們參考官方提供的controller/user.go 實現(xiàn)了我們自己的 controller/goods.go的添加商品方法:
2.14 到這里,我們已經(jīng)完成了新需求的編寫,啟動服務(wù)查看一下效果:
很OK,已經(jīng)看到了對應(yīng)的接口。
編碼完畢,測試一下:
我們請求接口,添加數(shù)據(jù)看一下:
在數(shù)據(jù)庫中也查看到數(shù)據(jù):插入成功,流程走通!
反思回顧
按照上面這個流程走下來,雖然整體跑通了。我個人感覺還是比較混亂的。
我又花了比較長的時間消化吸收了官方文檔的工程實踐,結(jié)合我自己的經(jīng)驗。
我們再來梳理一下V2項目的編寫流程,我的建議是這樣的:
整理流程
- 設(shè)計表結(jié)構(gòu)
- 使用gf gen dao生成對應(yīng)的dao/do/model目錄代碼
- 編寫api層:定義「業(yè)務(wù)模塊」的數(shù)據(jù)結(jié)構(gòu),提供對外接口的輸入/輸出數(shù)據(jù)結(jié)構(gòu)
- 編寫model層:定義「數(shù)據(jù)模塊」的數(shù)據(jù)結(jié)構(gòu),提供對內(nèi)的數(shù)據(jù)處理的輸入/輸出數(shù)據(jù)結(jié)構(gòu)
- 編寫logic層,自動生成service層代碼。(通過配置goland File Watcher自動生成,也可以通過gf gen service手動執(zhí)行腳本生成,強烈建議前者)
- 在service層代碼生成RegisterXX()方法后,在對應(yīng)的logic模塊注冊服務(wù)(每個模塊只需要寫一次)
- 編寫controller層,接收/解析用戶輸入的參數(shù),調(diào)用service層的服務(wù)。
- 注冊路由,對外暴露接口,比如這個項目是編寫cmd.go文件。
- 在main.go中 加入一行 _ "project-name/internal/logic" (只需寫一次)
- 在main.go中加入一行 _ "github.com/gogf/gf/contrib/drivers/MySQL/v2" (如果你使用的是mysql;只需寫一次)
關(guān)鍵流程
- 上面的步驟只有3~8是每次開發(fā)新需求都需要的
- 步驟1、2設(shè)計表結(jié)構(gòu)和自動生成代碼很簡單,涉及到新增表或者修改表時才需要
- 步驟9、10在創(chuàng)建項目時編寫一次即可
再次實操
我按照上面這個步驟,編寫了查詢商品邏輯,整體還是非常順滑的:
小伙伴們也動手實踐吧,歡迎star fork我的開源項目:https://github.com/wangzhongyang007/goframe-shop-v2
帶著問題學(xué)習(xí)
我在編寫商品管理需求的時候有些疑惑:
為什么要定義兩遍數(shù)據(jù)結(jié)構(gòu)呢?在api層定義了一遍,在model層又定義了一遍,我寫了兩遍重復(fù)的結(jié)構(gòu)體,意義何在呀?
我靜下心來想想,這個設(shè)計還是值得好好推敲的,我結(jié)合之前的項目經(jīng)歷分享一下我的理解。拋磚引玉,小伙伴們有什么理解歡迎在評論區(qū)留言。
之前遇到的問題
我們之前在在開發(fā)商品中心統(tǒng)一入庫時就遇到了難以維護的問題,原因就是業(yè)務(wù)邏輯和數(shù)據(jù)處理邏輯耦合在一起。
隨著業(yè)務(wù)的復(fù)雜度越來越高,項目維護成本越來越高,甚至達(dá)到了難以維護的程度。
我們是如何解決的呢?
解決辦法和GoFrame的數(shù)據(jù)模型和業(yè)務(wù)模型解耦,底層思想是一樣的:
我們把復(fù)雜的邏輯進行了拆分:定義了業(yè)務(wù)模塊和數(shù)據(jù)處理模塊。
「業(yè)務(wù)模塊」:只處理接收的參數(shù),并不關(guān)心如何入庫和取值,按照「數(shù)據(jù)模塊」的要求,處理好前端傳入的數(shù)據(jù),統(tǒng)一結(jié)構(gòu)體傳遞給「數(shù)據(jù)模塊」即可。
「數(shù)據(jù)模塊」:不需要關(guān)心「業(yè)務(wù)模塊」的具體實現(xiàn),定義了統(tǒng)一的傳參標(biāo)準(zhǔn),要求業(yè)務(wù)模塊按照自己的要求,統(tǒng)一傳入數(shù)據(jù);數(shù)據(jù)模塊考慮的重點是如何高效的批量插入數(shù)據(jù),如何高效的按需取值,并不需要關(guān)心多變的業(yè)務(wù)側(cè)需求。
升華一下
經(jīng)過對冗余模塊的拆解,梳理清楚了「數(shù)據(jù)模塊」和「業(yè)務(wù)模塊」的邊界,我們不僅解決了之前項目難以維護的問題,還提高了靈活對接客戶需求的能力。
結(jié)合自己的項目經(jīng)歷和這次實踐V2版本的經(jīng)歷,所以我開篇說:讓開發(fā)者更好的做到“模塊內(nèi)部高內(nèi)聚,模塊之間松耦合”,是我認(rèn)為GoFrame V2設(shè)計的精髓。
好了,這篇文章就到這里,硬核爆肝5千字,堅持更新實屬不易,歡迎大家點贊、評論、轉(zhuǎn)發(fā)。
參考資料
[1]電商前后臺系統(tǒng)API: http://github.com/wangzhongyang007/GoFrame-shop
[2]框架介紹: https://GoFrame.org/pages/viewpage.action?pageId=3672399
[3]官方示例GitHub: https://github.com/gogf/gf-demo-user
[4]xml文件地址: https://GoFrame.org/pages/viewpage.action?pageId=49770772&preview=/49770772/49770777/watchers.xml
本文轉(zhuǎn)載自微信公眾號「 程序員升級打怪之旅」,作者「王中陽Go」