新聞中心
本章節(jié)我們先講一講在軟件設(shè)計中,模塊化的一些設(shè)計和復(fù)用原則,然后再介紹?GOFrame?框架的模塊化設(shè)計,以便于大家更好地了解?GoFrame?框架模塊化設(shè)計的思想。

創(chuàng)新互聯(lián)2013年開創(chuàng)至今,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目網(wǎng)站設(shè)計制作、做網(wǎng)站網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元寧陜做網(wǎng)站,已為上家服務(wù),為寧陜各地企業(yè)和個人服務(wù),聯(lián)系電話:13518219792
一、什么是模塊
模塊也稱作組件,是軟件系統(tǒng)中可復(fù)用的功能邏輯封裝單位。在不同的軟件架構(gòu)層次,模塊的概念會有些不太一樣。在開發(fā)框架層面,模塊是某一類功能邏輯的最小封裝單位。在Golang代碼層面中,我們也可以將package稱作模塊。
二、模塊化的目標
軟件進行模塊化設(shè)計的目的,是為了使得軟件功能邏輯盡可能的解耦和復(fù)用,終極目標也是為了保證軟件開發(fā)維護的效率和質(zhì)量。
三、模塊復(fù)用原則
- ?
REP復(fù)用/發(fā)布等同原則
復(fù)用/發(fā)布等同原則(?Release/Reuse Equivalency Principle?):軟件復(fù)用的最小粒度應(yīng)等同于其發(fā)布的最小粒度。
直白地說,就是要復(fù)用一段代碼就把它抽成模塊。
- ?
CCP共同閉包原則
共同閉包原則(?Common Closure Principle?):為了相同目的而同時修改的類,應(yīng)該放在同一個模塊中。
對大部分應(yīng)用程序而言,可維護性的重要性遠遠大于可復(fù)用性,由同一個原因引起的代碼修改,最好在同一個模塊中,如果分散在多個模塊中,那么開發(fā)、提交、部署的成本都會上升。
- ?
CRP共同復(fù)用原則
共同復(fù)用原則(?Common Reuse Principle?):不要強迫一個模塊依賴它不需要的東西。
相信你一定有這種經(jīng)歷,集成了模塊A,但模塊A依賴了模塊B、C。即使模塊B、C 你完全用不到,也不得不集成進來。這是因為你只用到了模塊A的部分能力,模塊A中額外的能力帶來了額外的依賴。如果遵循共同復(fù)用原則,你需要把A拆分,只保留你要用的部分。
- 復(fù)用原則競爭關(guān)系
?REP?、?CCP?、?CRP三個原則之間存在彼此競爭的關(guān)系。?REP和 ?CCP是黏合性原則,它們會讓模塊變得更大,而 ?CRP原則是排除性原則,它會讓模塊變小。遵守?REP?、?CCP而忽略 ?CRP,就會依賴了太多沒有用到的模塊和類,而這些模塊或類的變動會導(dǎo)致你自己的模塊進行太多不必要的發(fā)布;遵守 ?REP、?CRP而忽略 ?CCP?,因為模塊拆分的太細了,一個需求變更可能要改n個模塊,帶來的成本也是巨大的。
優(yōu)秀的架構(gòu)師應(yīng)該能在上述三角形張力區(qū)域中定位一個最適合目前研發(fā)團隊狀態(tài)的位置,例如在項目早期,?CCP?比?REP?更重要,隨著項目的發(fā)展,這個最合適的位置也要不停調(diào)整。
四、框架模塊設(shè)計
經(jīng)過前面關(guān)于模塊設(shè)計原則和復(fù)用原則的介紹,我們應(yīng)該對模塊開發(fā)和管理這塊的原則有了大概的了解,那么我們接著介紹框架的模塊化設(shè)計就比較容易理解了。
單倉庫包設(shè)計
根據(jù)?REP?原則我們了解到,一個可復(fù)用的模塊是支持獨立版本管理的,單倉庫包設(shè)計也正是如此。Golang中很多這樣的單倉庫包,一個包就是一個獨立的模塊。單倉庫包根據(jù)?CRP?原則可以再進一步的細化解耦拆分。我們來舉個例子,在開發(fā)復(fù)雜的業(yè)務(wù)項目場景下,常見的包依賴情況,類似于這樣的:
module business
go 1.16
require (
business.com/golang/strings v1.0.0
business.com/golang/config v1.15.0
business.com/golang/container v1.1.0
business.com/golang/encoding v1.2.0
business.com/golang/files v1.2.1
business.com/golang/cache v1.7.3
business.com/framework/utils v1.30.1
github.com/pkg/errors v0.9.0
github.com/goorm/orm v1.2.1
github.com/goredis/redis v1.7.4
github.com/gokafka/kafka v0.1.0
github.com/gometrics/metrics v0.3.5
github.com/gotracing/tracing v0.8.2
github.com/gohttp/http v1.18.1
github.com/google/grpc v1.16.1
github.com/smith/env v1.0.2
github.com/htbj/command v1.1.1
github.com/kmlevel1/pool v1.1.4
github.com/anolog/logging v1.16.2
github.com/bgses123/session v1.5.1
github.com/gomytmp/template v1.3.4
github.com/govalidation/validate v1.19.2
github.com/yetme1/goi18n v0.10.0
github.com/convman/convert v1.20.0
github.com/google/uuid v1.1.2
// ...
)示例中的模塊依賴,都是一些通用模塊,大部分業(yè)務(wù)項目都會涉及到。模塊地址是便于演示而寫的隨意地址,并不一定真實存在。
使用Golang開發(fā)過復(fù)雜一點的業(yè)務(wù)項目的小伙伴們,對于這樣的場景大家一定不會陌生。一個正常的軟件企業(yè),往往至少有數(shù)百個這樣的項目,真實的模塊依賴關(guān)系比這里的例子更加復(fù)雜。在Golang項目開發(fā)中,對于模塊依賴的維護性挑戰(zhàn)是比較大的,我們往往會遇到一些痛點,主要的幾點:
- 實現(xiàn)相同功能邏輯的模塊較多,選擇成本增加
- 項目依賴的模塊過多,項目整體的穩(wěn)定性會受到影響
- 項目依賴的模塊過多,項目無從下手是否應(yīng)當升級這些模塊版本
- 模塊分散設(shè)計,不成體系,難以統(tǒng)一。
現(xiàn)身說法舉例。
本廠的自研模塊有數(shù)十個,這些模塊已經(jīng)被頻繁使用遍布到數(shù)百個業(yè)務(wù)項目中。有一次,我們提交了對幾個模塊的?bug fix?,其中有兩個還是比較重要的?bug?,緊接著,我們要求所有業(yè)務(wù)項目全部升級一下對應(yīng)模塊的版本號,并且這些版本號填寫得務(wù)必小心。當然,這肯定也不是唯一的一次,隨后相同的場景各位同學(xué)可以自行腦補。
我們也可以選擇,不去主動推進所有業(yè)務(wù)項目升級模塊,只要項目還沒有觸發(fā)這些?bug?,那么就等著業(yè)務(wù)項目踩到了坑再由項目組自行去升級。領(lǐng)導(dǎo)如果聽到這種解決方案......各位同學(xué)再自行腦補一下和諧的場景。
其實這種問題主要的原因,還是來源于模塊的不穩(wěn)定,模塊也是需要不停迭代改進的。項目使用到這些模塊,那么就與這些模塊建立了耦合關(guān)系,耦合模塊的變化,必然會影響到依賴的相關(guān)項目。越底層的基礎(chǔ)模塊,頂層模塊則對其依賴的越多,影響面也就越大。那是不是只要模塊穩(wěn)定了,就不會存在這樣的問題了呢?風險依舊是存在的。Golang標準庫大家覺得算穩(wěn)定吧,但是它也是在不斷的迭代改進過程中,也是不斷有bug出現(xiàn),只是大家幸運沒踩上去而已,風險相對較低。
好的軟件設(shè)計,并不是一成不變,而是能夠做到快速響應(yīng)變化,根據(jù)變化快速改進完善。模塊的設(shè)計和管理,亦是如此。尋求能夠快速改進模塊邏輯、有效維護模塊依賴的方案,比編寫更加穩(wěn)定的功能模塊,更加高效和務(wù)實。
模塊聚合設(shè)計
?GoFrame?的模塊化管理思想更偏重于?CCP?原則,看重可維護性比可復(fù)用性更多。由于?GoFrame?是基于開發(fā)框架層面的出發(fā)點考慮,因此整體框架的設(shè)計不是單點設(shè)計的,而是自頂向下設(shè)計的。前面有提到,越底層的基礎(chǔ)模塊,頂層模塊則對其依賴的越多,影響面也就越大。因此,框架將一些通用性的核心模塊進行統(tǒng)一維護,這樣做的目的是使得這些模塊共同形成閉包,保證基礎(chǔ)模塊的穩(wěn)定性,并通過統(tǒng)一的版本管理,提高開發(fā)效率和可維護性,降低接入和維護成本。
站在?GoFrame?框架模塊化設(shè)計的角度,前面例子中的依賴情況應(yīng)當變成以下的樣子:
module business
go 1.16
require (
github.com/gogf/gf v1.16.0
github.com/goorm/orm v1.15.1
github.com/goredis/redis v1.7.4
github.com/gokafka/kafka v0.1.0
github.com/google/grpc v1.16.1
// ...
)?GoFrame?只維護一些通用性的核心模塊,其他非通用核心模塊或者穩(wěn)定性較高的模塊,依舊建議使用單倉庫包的形式進行依賴引入,正如?REP?和?CRP?模塊復(fù)用原則倡導(dǎo)的那樣。在這種設(shè)計模式下:
- 框架核心維護較全面的通用基礎(chǔ)模塊,降低基礎(chǔ)模塊選擇成本
- 我們只需要維護一個統(tǒng)一的框架版本,而不是數(shù)十個模塊版本
- 我們只需要了解一個框架的內(nèi)容變化,而不是數(shù)十個模塊的內(nèi)容變化
- 升級的時候只需要升級一個框架版本,而不是數(shù)十個模塊版本的升級
- 減輕開發(fā)人員的心智負擔,提高模塊可維護性,更容易保證各業(yè)務(wù)項目的模塊版本一致性
五、常見問題解答
雖然每一個模塊都按照低耦合設(shè)計,模塊可以選擇性引入,但在使用時也得全量下載完整框架代碼
文件層面的源文件下載與模塊之間的邏輯耦合沒有直接關(guān)系。需要注意的是,編譯型語言和解釋型語言的模塊管理邏輯不太一樣。
- 編譯型語言:(以靜態(tài)編譯為例)往往以?
main?包為入口,編譯器會自動分析源碼并將所有邏輯依賴模塊中對應(yīng)的資源進行編譯處理,最終生成為靜態(tài)二進制文件進行發(fā)布,自身源文件以及依賴模塊(邏輯依賴)的源文件只在編譯階段使用,源碼文件并不會直接用于發(fā)布,如:C/C++、Golang、Rust等。 - 解釋型語言:往往會將自身源文件(或中間碼)以及依賴模塊的源文件(或中間碼)全部進行打包發(fā)布,例如:PHP、Java、NodeJS、Python等。這個時候,依賴模塊的源碼大小對于項目發(fā)布來說影響會比較大。并且,打包時候的模塊依賴處理并不會檢查"邏輯依賴",只要依賴配置文件中存在指定模塊,那么該模塊都會被共同打包發(fā)布。假如模塊中有10萬個函數(shù),即使其中只有一個函數(shù)被使用到,該模塊所有函數(shù)將被共同打包發(fā)布。因為解釋型語言在代碼發(fā)布前并沒有"編譯-匯編-鏈接"等階段,只能在運行時對源碼及模塊依賴做完整解析處理。特別是PHP/Java轉(zhuǎn)Go的同學(xué),這一塊的思維需要轉(zhuǎn)變適應(yīng)。
框架中任一模塊的版本變更都會引起框架版本的發(fā)布,框架的發(fā)布頻次是否會變高
最主要的一點,框架的模塊設(shè)計也會充分考慮穩(wěn)定性因素,僅會將一些通用性的核心模塊按照?CCP?進行管理,并不會包含特定業(yè)務(wù)的邏輯封裝,因為涉及到特定業(yè)務(wù)的功能邏輯實現(xiàn)將會為框架模塊帶來更多的不穩(wěn)定變化。
在保證一定的穩(wěn)定性前提下,模塊的版本發(fā)布按照框架統(tǒng)一的迭代開發(fā)計劃進行,除了必要的?hot fix?之外,版本發(fā)布設(shè)置有固定的時間窗口,以保證框架核心的穩(wěn)定性。因此,框架通過模塊聚合的方式進行版本管理,不僅沒有增加框架的版本發(fā)布頻次,反而降低了框架的版本發(fā)布頻次,使得框架中的模塊版本更加穩(wěn)定。
框架聚合并維護通用性的核心模塊,通用性的核心模塊定義是什么
首先,它們是基礎(chǔ)模塊,往往位于模塊依賴鏈的最底層,這部分的模塊變化對項目穩(wěn)定性影響最大。
其次,絕大部分項目(二八定律來講為80%以上)都會依賴的通用性基礎(chǔ)模塊,可以稱作核心模塊。
最后,這部分模塊不包含具體業(yè)務(wù)的封裝實現(xiàn)。例如:微信公眾號/小程序、CMS/CRM、區(qū)塊鏈等相關(guān)模塊都是具體業(yè)務(wù)實現(xiàn)封裝。
關(guān)于模塊通用性的評估無法完全準確,框架為保證核心精簡會盡可能持保守態(tài)度,并且會根據(jù)實際情況在未來的迭代中逐步做調(diào)整。
以下為可供參考的模塊分層:
- 業(yè)務(wù)實現(xiàn)模塊:特定業(yè)務(wù)項目邏輯實現(xiàn),這里包含業(yè)務(wù)項目進一步的代碼分層。
- 通用業(yè)務(wù)模塊:可復(fù)用的業(yè)務(wù)邏輯封裝,例如微信公眾號/小程序、CMS/CRM、區(qū)塊鏈等相關(guān)業(yè)務(wù)邏輯封裝模塊。
- 通用基礎(chǔ)模塊:標準庫不提供或者基于標準庫封裝擴展的基礎(chǔ)模塊,例如:配置、校驗、緩存、ORM、I18N等等。
- 標準基礎(chǔ)模塊:Golang標準庫。
分享文章:創(chuàng)新互聯(lián)GoFrame教程:GoFrame框架設(shè)計-模塊化設(shè)計
網(wǎng)站路徑:http://fisionsoft.com.cn/article/dpdccds.html


咨詢
建站咨詢
