隨著專案的不斷迭代,複雜的業務模組及專案自身的基礎技術元件迅速擴張,以往基於單個模組的專案往往顯得過於臃腫。程式碼目錄結構,包名混亂,程式碼模組職責不清晰,耦合度高,不便維護。基礎公共元件沒有抽取並剝離乾淨,新人上手較難,專案整體編譯慢,等等。於是,近幾年來,基於Gradle
構建的模組化方案得到迅速應用,甚至在劃分模組的同時,也可以將基礎公共元件抽取獨立的專案,並以單獨的Git
庫進行管理和維護。
模組化的方案,整體上能夠很好的將各個模組按照自身的職責進行獨立劃分,無論是基於業務的,還是基於技術的角度,得以能夠達到“高內聚,低耦合”的效果。
但現實中,往往還存在一種“居中”的情況。
1,基於業務或者技術角度劃分的模組,在職責界定時往往是有粒度的,這種粒度,有可能很大,也可以很小,如果以過大的粒度劃分模組,模組內的程式碼耦合和隔離等情況依然存在問題,如果以過小的粒度分化模組,使得整個專案最終形成的模組往往過多,也不太利於整體理解和維護管理。
2,最終形成的專案模組,應該是粒度適中的,如基於業務維護的劃分(從產品或使用者視角下的產品功能),基於基於技術視角的基於職責的基礎技術庫的模組剝離。
3,最終形成的專案模組,尤其是基於業務維護的劃分,最終模組內依然會存在多個子級粒度的業務,此時,在不宜進一步繼續直接模組化的基礎上,應該有一套類似模組化本身思維的技術方案,以實現模組內的模組劃分,或稱之為程式碼隔離。
子級粒度的業務,往往不僅包含既有的java
程式碼,還包括了可能的jar
包或so
檔案引入,可能圖片資源,字串型別資源,以及常見的佈局檔案等,此時,如果僅僅是傳統方案下的java
原始碼級別的按照目錄形式的劃分,往往是不夠徹底的。
於是,微信最早對外發布的文章,微信Android架構歷史,其中詳細介紹了其模組內的程式碼隔離方案,pins。
後來,美團外賣中也是參照同樣的思路實現了模組內的程式碼隔離。具體參見:美團外賣Android平臺化架構演進實踐
在思維模式上,pins
其實與專案模組化本身,具有異曲同工之妙。並且也是在充分利用了Android Gradle
構建工具基礎上,通過修改指定的源集邏輯,顯示隔離後的程式碼及資原始檔的重新組合。
在技術原理上,pins
自身並沒有太多的技術本身,更多的充分利用了Android Gradle
構建工具,比較巧妙的實現了模組內的再次隔離。
1,將模組內按照子級業務再次抽取,最終形成與src/main
同樣級別的目錄劃分(與上圖中的微信pins目錄結構有所不同),抽取的子級模組以p_子級模組名
命名,其中,p_
開頭是為了後續修改源集邏輯時候的區分標識;
2,對應剝離具體的子級業務,包含java
程式碼,其他資原始檔等;
3,修改對應模組的Android Gradle
構建時的源集邏輯,主要通過如:java.srcDir
、res.srcDir
等方法將p_子級模組名
對應新增上去。
對應修改源集邏輯主體部分如下:
android {
sourceSets {
main {
def src_dir = new File(projectDir, 'src')
def dirs = src_dir
.listFiles()
.toList()
.stream()
.filter(new Predicate<File>() {
@Override
boolean test(File file) {
return file.getName().startsWith("p_")
}
})
.map {
return it.getName()
}
.collect(Collectors.toList())
println("pins-module: " + dirs)
dirs.each { dir ->
java.srcDir("src/$dir/java")
res.srcDir("src/$dir/res")
}
}
}
}
複製程式碼
專案整體,依託模組化進行整體大的業務和技術模組劃分,模組內,依據業務粒度,子級別的參照pins
思路實現模組內的進一步程式碼及資源隔離,基礎的公共技術元件,抽取成單獨的Git
專案庫管理,以形成專案整體上的模組化實踐方案。