Android MonoRepo多倉(cāng)和單倉(cāng)的差別理論
前言
今天不打算展開任何關(guān)于技術(shù)的探討,只是想拋出一些觀點(diǎn),關(guān)于工程結(jié)構(gòu)上的??赡苡行┤速澇梢灿行┤朔磳?duì),但是我覺(jué)得技術(shù)的世界還是需要一些討論和探索的。
并沒(méi)有指明那些就是最優(yōu)解,可能都只是一些個(gè)人觀點(diǎn)而已。
兩種模式其實(shí)我都略微有點(diǎn)接觸,當(dāng)然文章也存粹是個(gè)人觀點(diǎn)。我們先看下下面這幅圖,其實(shí)就是一個(gè)原始工程結(jié)構(gòu),分倉(cāng)結(jié)構(gòu),還有單倉(cāng)結(jié)構(gòu)的工程。

什么是Monorepo
Monorepo的意思是在版本控制系統(tǒng)的單個(gè)代碼庫(kù)里包含了許多項(xiàng)目的代碼。這些項(xiàng)目雖然有可能是相關(guān)的,但通常在邏輯上是獨(dú)立的,并由不同的團(tuán)隊(duì)維護(hù)。
簡(jiǎn)單的說(shuō)當(dāng)我們把所有的代碼全都放在一個(gè)倉(cāng)庫(kù)內(nèi),然后所有同學(xué)都在這個(gè)倉(cāng)庫(kù)上進(jìn)行開發(fā),這種模式就可以稱之為Monorepo。
很多人認(rèn)為這種形式不就回到了一開始并沒(méi)有完成組件化的單Project的模式。然而并不是這樣的,Monorepo內(nèi)還是會(huì)有分層結(jié)構(gòu)設(shè)計(jì),也具有組件化的所有,只是所有的源代碼聚合在一個(gè)倉(cāng)庫(kù)內(nèi),每個(gè)同學(xué)也是在自己負(fù)責(zé)的業(yè)務(wù)模塊中開發(fā)的。
這種有什么好處呢?那么他的缺點(diǎn)是什么呢?接下來(lái)要介紹下他的兄弟,然后可能雙向?qū)Ρ炔拍苷f(shuō)明這到底是個(gè)啥東西。
什么是multi-repo
一個(gè)項(xiàng)目由多個(gè)git倉(cāng)庫(kù)來(lái)構(gòu)成,然后通過(guò)依賴aar的形式將幾個(gè)倉(cāng)庫(kù)組合在一起。
現(xiàn)在市面上大部分公司的解決方案應(yīng)該都是多倉(cāng),然后通過(guò)插件將多個(gè)工程同步aar版本配置的形式完成的multi-repo模式。
基本上每個(gè)業(yè)務(wù)會(huì)獨(dú)立成一個(gè)倉(cāng)庫(kù),然后基礎(chǔ)庫(kù)也會(huì)變成一個(gè)獨(dú)立的倉(cāng)庫(kù),然后通過(guò)依賴aar的方式來(lái)引入其對(duì)其他倉(cāng)庫(kù)的依賴的形式進(jìn)行開發(fā)。我把這種模式叫做multi-repo。
多倉(cāng)模式下因?yàn)楦鱾€(gè)project都是獨(dú)立的,所以配置統(tǒng)一,依賴管理等等一直都是個(gè)老大難的問(wèn)題, 但是也并非無(wú)解,很多公司包括我以前都會(huì)寫一個(gè)依賴版本清洗的插件,然后將依賴的ext放在遠(yuǎn)端,之后基于branc分支的形式提供給到各個(gè)使用的業(yè)務(wù)方。
multi-repo的問(wèn)題
我以前在哈啰的時(shí)候遇到過(guò)一個(gè)場(chǎng)景,我們依賴于業(yè)務(wù)方的代碼,然后業(yè)務(wù)方也依賴與我們的代碼,然后就變成我先發(fā)布個(gè)快照版本給到對(duì)方,然后他們基于我們的快照版本再進(jìn)行代碼開發(fā),之后我再把他們的快照版本更新過(guò)來(lái),進(jìn)行代碼開發(fā)的情況。
一般情況下可能還好,但是如果萬(wàn)一有人不小心更改到api的方法入?yún)⒒蛘咭恍┖瘮?shù)的名字。那么在最后的編譯階段會(huì)出現(xiàn)運(yùn)行是出現(xiàn)方法找不到的問(wèn)題,然后出現(xiàn)崩潰的問(wèn)題,這種問(wèn)題發(fā)生的次數(shù)應(yīng)該是非常的多的。
因?yàn)榇a的隔離情況,所以大家都在自己的分支和倉(cāng)庫(kù)上獨(dú)立開發(fā),對(duì)于別人的代碼處于一個(gè)低感知的狀態(tài),所以自然而然的我認(rèn)為代碼上是一個(gè)不穩(wěn)定的狀態(tài)。
很多公司最后會(huì)在交付階段采用全源代碼進(jìn)行編譯的方式給到最終的apk。原理就是通過(guò)一個(gè)aar切換源代碼的插件,然后把所有工程聚合在一起進(jìn)行打包,避免出現(xiàn)一些非必要的編譯問(wèn)題。
還有就是項(xiàng)目重構(gòu)以及項(xiàng)目持續(xù)升級(jí),多倉(cāng)需要對(duì)每一個(gè)工程都設(shè)置一套ci/cd體系,還有就是分支管理等等問(wèn)題就會(huì)不停的消耗開發(fā)的精力,同時(shí)因?yàn)榇蠹叶际亲约旱囊惶紫到y(tǒng),后面就會(huì)出現(xiàn)不可避免的內(nèi)卷。
我聽(tīng)一個(gè)網(wǎng)友說(shuō)過(guò)一個(gè)案例,因?yàn)槭莂ar的依賴方式,所以他們?cè)谧约旱哪K中直接依賴了對(duì)方的項(xiàng)目,然后對(duì)方的項(xiàng)目也直接依賴了他們的aar產(chǎn)物,在實(shí)際開發(fā)中,這種依賴成環(huán)的現(xiàn)象是一定要避免的,但是在多倉(cāng)中他也不一定會(huì)報(bào)錯(cuò)提示。
另外則是一些統(tǒng)一的升級(jí)操作,比如說(shuō)AGP版本升級(jí),koltin版本升級(jí),gralde 插件版本等等配置信息的升級(jí)。
代碼復(fù)用率方面多倉(cāng)可能會(huì)更低一點(diǎn)。每個(gè)業(yè)務(wù)可能都會(huì)有一些可能更優(yōu)秀的代碼實(shí)現(xiàn),但是如果你想復(fù)用的這個(gè)就會(huì)相對(duì)比較糟糕,可能就會(huì)涉及到大量的代碼cv。一個(gè)穩(wěn)定的功能還好,如果是一個(gè)還在迭代過(guò)程中的代碼,多倉(cāng)反倒更容易出現(xiàn)代碼風(fēng)險(xiǎn)。
multi-repo的優(yōu)點(diǎn)
相對(duì)來(lái)說(shuō)多倉(cāng)的工程結(jié)構(gòu)會(huì)更獨(dú)立,每個(gè)工程都是具有獨(dú)立打開的能力的,這樣對(duì)于業(yè)務(wù)同學(xué)來(lái)說(shuō),他的學(xué)習(xí)成本是相對(duì)最低的,因?yàn)樗旧现灰獙?duì)自己的業(yè)務(wù)模塊負(fù)責(zé)就可以了,更專注與自己當(dāng)前所需要關(guān)心的。
工程同步和編譯的速度會(huì)更快,因?yàn)榇蟛糠謧}(cāng)庫(kù)都已經(jīng)被編譯成aar產(chǎn)物了,所以對(duì)于分倉(cāng)模式來(lái)說(shuō),他們的同步和編譯都只需要對(duì)于當(dāng)前工程負(fù)責(zé)就可以了,不需要編譯與當(dāng)前工程無(wú)關(guān)的東西,所以速度上來(lái)說(shuō)會(huì)更快。
學(xué)習(xí)成本低,因?yàn)橹灰獙?duì)當(dāng)前工程負(fù)責(zé),所以只要搞懂當(dāng)前工程如何能工作就可以了。
安全性相對(duì)來(lái)說(shuō)會(huì)更高,因?yàn)楣こ探Y(jié)構(gòu)相對(duì)獨(dú)立,所以對(duì)于一些相對(duì)涉密的工程來(lái)說(shuō),分倉(cāng)的結(jié)構(gòu)的安全性會(huì)更高,即時(shí)看到代碼也無(wú)權(quán)進(jìn)行任何代碼變動(dòng)。
MonoRepo的缺點(diǎn)
相比較于分倉(cāng)模式,MonoRepo的編譯速度會(huì)更慢,同步的時(shí)間也會(huì)更長(zhǎng)。因?yàn)槊總€(gè)工程都需要重新Configuration策略,將aar依賴方式切換成源代碼依賴。同時(shí)不同于aar依賴的情況,源代碼依賴的情況下每個(gè)工程的build.gradle還有全局配置以及插件等都需要被執(zhí)行到,所以消耗的時(shí)間會(huì)更長(zhǎng)一點(diǎn)點(diǎn)。也就是正常的gradle相關(guān)的生命周期,對(duì)于源碼編譯的工程都是需要執(zhí)行一次的。
工具鏈相對(duì)來(lái)說(shuō)會(huì)比較復(fù)雜,因?yàn)樗性创a都在一起,所以工程內(nèi)可能需要配置更多ndk等等配置環(huán)境,需要更多的工具鏈將這些倉(cāng)庫(kù)進(jìn)行協(xié)調(diào),從而能達(dá)到混編的狀態(tài)下。
安全性相對(duì)來(lái)說(shuō)較差,比如說(shuō)相對(duì)機(jī)密的公司核心源代碼。因?yàn)閱蝹}(cāng)的緣故,所以代碼的權(quán)限就會(huì)對(duì)所有人開放。如果出現(xiàn)源碼泄露的狀況,就相對(duì)來(lái)說(shuō)比較嚴(yán)重了。
同時(shí)工程體量會(huì)變得非常巨大,也會(huì)造成編碼過(guò)程中需要頻繁的rebase主干的代碼,可能每天都會(huì)有巨量的代碼落后的情況。但是這個(gè)個(gè)人覺(jué)得是在可預(yù)期范圍內(nèi)的。
MonoRepo的優(yōu)點(diǎn)
要說(shuō)到MonoRepo的優(yōu)點(diǎn),其實(shí)也都是相對(duì)于分倉(cāng)模式來(lái)說(shuō)的。
首先要提出的第一個(gè)觀點(diǎn)是開發(fā)狀況下你的倉(cāng)庫(kù)狀態(tài)是穩(wěn)定的。工作流程上來(lái)說(shuō),都是切出一個(gè)分支,然后在這個(gè)分支上開發(fā)自己的業(yè)務(wù)需求,之后合并回主干。但是和多倉(cāng)相比,即使是多人協(xié)作開發(fā),因?yàn)榇蠹宜褂玫亩际窃创a,只要拉取了代碼各自的變更都是當(dāng)場(chǎng)可見(jiàn)的。每一個(gè)提交相對(duì)來(lái)說(shuō)都是知道彼此互相做了什么事情的,所以這就是相對(duì)來(lái)說(shuō)的穩(wěn)定切片。就算我們重新rebase了主干之后,這部分代碼也是相當(dāng)穩(wěn)定的一個(gè)狀態(tài),因?yàn)樗麄兌际蔷幾g完測(cè)試完成之后才合入的。即使代碼變更了,因?yàn)橛芯幾g階段的語(yǔ)法校驗(yàn),所以所有的改動(dòng)都是一個(gè)相對(duì)來(lái)說(shuō)的穩(wěn)定狀態(tài)。
這一點(diǎn)我認(rèn)為是非常重要的一點(diǎn)。對(duì)比與多倉(cāng),因?yàn)槊總€(gè)人都在自己的倉(cāng)庫(kù)可以提交代碼,彼此的提交都是互相隔離分立的,所以我們無(wú)法預(yù)知到對(duì)方的改動(dòng)是否會(huì)對(duì)當(dāng)前的我們產(chǎn)生影響,這就導(dǎo)致了存在更多的風(fēng)險(xiǎn)。這個(gè)也就是MonoRepo所說(shuō)的原子提交。
高參與度與代碼的可復(fù)用性,因?yàn)樗写a對(duì)大家都是可見(jiàn)的狀態(tài),所以當(dāng)我們需要一些我們想要的代碼的時(shí)候,并不需要直接去cv他們,而可以直接通過(guò)依賴的形式直接獲取到他們的使用權(quán)。如果碰到我們前面所說(shuō)的不穩(wěn)定狀態(tài)的情況下,因?yàn)榇蠹叶寄軈⑴c到代碼的改動(dòng)中,所以我們可以讓我們的代碼更趨于一個(gè)穩(wěn)定狀態(tài),而不是打補(bǔ)丁的方式這里改一句哪里改一句。
更有效的依賴檢查,前面所說(shuō)的模塊間互相依賴成環(huán)的問(wèn)題,MonoRepo也是不存在的,依托于編譯器的特性,當(dāng)依賴成環(huán)的情況下,編譯自然就會(huì)報(bào)錯(cuò)。這樣就可以避免掉一些錯(cuò)誤的寫法。
更簡(jiǎn)便的代碼升級(jí)操作,之前和大家介紹過(guò)我們當(dāng)前的AGP的版本相對(duì)來(lái)說(shuō)已經(jīng)是比較高的版本了,我們的插件數(shù)量其實(shí)也很多,我們也有插件化等等黑科技。在編譯階段上我們也魔改了不少代碼。但是因?yàn)槲覀兊膯蝹}(cāng)結(jié)構(gòu),我們可以只需要改動(dòng)一個(gè)version版本號(hào)就可以對(duì)所有的倉(cāng)庫(kù)生效??焖俚膶pp進(jìn)行持續(xù)的迭代操作。
單一的檢查工具,這部分就是避免重復(fù)性建設(shè)的工作了,因?yàn)閭}(cāng)庫(kù)單一所以只要對(duì)當(dāng)前倉(cāng)庫(kù)進(jìn)行一份靜態(tài)檢查就行了,避免重復(fù)造輪子的風(fēng)險(xiǎn)。
以上就是Android MonoRepo多倉(cāng)和單倉(cāng)的差別理論的詳細(xì)內(nèi)容,更多關(guān)于Android MonoRepo多倉(cāng)單倉(cāng)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android ViewPager實(shí)現(xiàn)動(dòng)畫切換效果
這篇文章主要為大家詳細(xì)介紹了Android ViewPager實(shí)現(xiàn)動(dòng)畫切換效果的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
Flutter StaggeredGridView實(shí)現(xiàn)瀑布流效果
這篇文章主要為大家詳細(xì)介紹了Flutter StaggeredGridView實(shí)現(xiàn)瀑布流效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
解決VSCode調(diào)試react-native android項(xiàng)目錯(cuò)誤問(wèn)題
這篇文章主要介紹了VSCode調(diào)試react-native android項(xiàng)目錯(cuò)誤解決辦法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Android ProgressDialog使用總結(jié)
ProgressDialog 繼承自AlertDialog,AlertDialog繼承自Dialog,實(shí)現(xiàn)DialogInterface接口,本文給大家介紹Android ProgressDialog使用總結(jié)的相關(guān)知識(shí),需要的朋友通過(guò)此文一起學(xué)習(xí)吧2016-01-01
android 獲取手機(jī)中的所有圖片或某一目錄下的圖片方法
下面小編就為大家分享一篇android 獲取手機(jī)中的所有圖片或某一目錄下的圖片方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
Android編程實(shí)現(xiàn)在一個(gè)程序中啟動(dòng)另一個(gè)程序的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)在一個(gè)程序中啟動(dòng)另一個(gè)程序的方法,結(jié)合實(shí)例形式分析了Android通過(guò)ResolveInfo類來(lái)取得啟動(dòng)Acitivty類名的方法來(lái)啟動(dòng)另一個(gè)程序的方法,需要的朋友可以參考下2017-02-02
Flutter網(wǎng)絡(luò)請(qǐng)求Dio庫(kù)的使用及封裝詳解
本文主要介紹了Flutter網(wǎng)絡(luò)請(qǐng)求Dio庫(kù)的使用及封裝詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
Android 優(yōu)雅的實(shí)現(xiàn)通用格式化編輯
這篇文章主要介紹了Android 優(yōu)雅的實(shí)現(xiàn)通用格式化編輯,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下2021-03-03

