Ang modularidad ay ang prinsipyo kung saan ang aplikasyon ay binuo mula sa mga independiyenteng modyul, bawat isa ay responsable para sa isang functionality. Ayon sa Android Developers, ang paghahati sa mga modyul ay nagpapabilis ng build sa pamamagitan ng parallel compilation at nagpapahintulot sa mga team na magtrabaho sa iba't ibang bahagi ng aplikasyon nang nakapag-iisa. Ang modular na arkitektura ay naging pamantayan para sa malalaking mobile project na may sampu-sampung developer.
Mga Pangunahing Punto
Modularidad ay isang paraan ng pag-oorganisa ng code kung saan ang aplikasyon ay binubuo ng maluwag na konektadong mga modyul, bawat isa ay nagbibigay ng mahigpit na tinukoy na functionality sa pamamagitan ng pampublikong interface. Hindi tulad ng monolitik na arkitektura, kung saan ang lahat ng klase ay nasa isang proyekto, ang modular na approach ay naghahati ng code sa pisikal na independiyenteng mga yunit ng compilation.
Ang pangunahing layunin ng modularidad ay pamamahala ng komplikasyon. Maaaring mag-focus ang developer sa isang modyul nang hindi iniisip ang buong codebase. Ang bawat modyul ay may sariling sona ng responsibilidad at maaaring paunlarin, subukan, at i-deploy nang independiyente sa iba. Ito ay lalong mahalaga sa mga proyektong may 10+ developer, kung saan ang parallel na trabaho sa monolit ay humahantong sa madalas na conflict sa pagsasama.
Mahalagang makilala ang modularidad mula sa layered na arkitektura. Ang mga layer (Presentation, Domain, Data) ay naghahati ng code ayon sa teknikal na pamantayan, habang ang mga modyul — ayon sa functional na pamantayan. Ang modyul na “Profile ng Gumagamit” ay maaaring maglaman ng sarili nitong mga layer sa loob. Sa praktika, ang modular approach at layered na arkitektura ay pinagsama: bawat modyul ay may sariling tatlong-layer na istraktura.
Mga modyul ng Feature — pinakasikat na uri ng modyul. Ang bawat screen o grupo ng magkakaugnay na screen ay nakahiwalay sa isang hiwalay na modyul: Onboarding, Profile, Settings, Feed. Ang modyul ng Feature ay naglalaman ng lahat ng kailangan para sa pagpapatakbo ng function: UI, lohika ng negosyo, layer ng data. Ang mga hangganan ng modyul ay protektado — ang ibang mga function ay hindi maaaring ma-access ang mga panloob na klase nito.
Mga modyul ng Core ay naglalaman ng karaniwang imprastraktura: trabaho sa network, database, analytics, sistema ng disenyo. Hindi sila umaasa sa mga modyul ng Feature, ngunit ang mga modyul ng Feature ay umaasa sa kanila. Tinitiyak ng paghahating ito na ang pagbabago ng analytics SDK ay hindi makakaapekto sa network layer at vice versa. Ang mga modyul ng Core ay ginagamit muli sa pagitan ng mga function nang walang pagdoble ng code.
Mga shared na modyul ay naglalaman ng code na ginagamit ng maraming function: mga modelo ng data, utilidad, constant, custom na View. Ang pangunahing problema ng shared na modyul ay ang panganib na maging tambakan (“misc module”), kung saan naipon ang iba't ibang code sa paglipas ng panahon. Patakaran: ang shared na modyul ay dapat may malinaw na tema, halimbawa “shared-ui” o “shared-models”.
Sa Android, ang mga shared na modyul ay madalas na hinihiwalay sa mga library na may prefix na lib: lib-network, lib-database, lib-ui-components. Sa iOS, ang parehong mga function ay ginagampanan ng panloob na Swift Packages sa loob ng Workspace. Sa praktika, nililimitahan ng mga team ang bilang ng shared na modyul sa 3–5 upang hindi lumikha ng labis na network ng dependencies na nagpapakumplikado sa build.
Hiwalay na mga modyul ng pagsubok ay nagpapahintulot na magpatakbo ng mga pagsubok lamang para sa binagong modyul, nang hindi pinapatakbo ang buong base ng pagsubok. Ito ay nagbabawas ng oras ng CI/CD pipeline mula sa oras hanggang minuto. Tinitiyak ng mga modyul ang paghihiwalay sa antas ng build: ang modyul ng network layer ay hindi maaaring aksidenteng mag-import ng mga UI library sa mga pagsubok.
Ang bawat modyul ay dapat may malinaw na tinukoy na pampublikong API. Sa Android, ito ay nakakamit sa pamamagitan ng mga access modifier at api vs implementation sa Gradle. Sa iOS — sa pamamagitan ng public/internal na mga access modifier at pinamamahalaang dependencies sa pamamagitan ng Package.swift. Ang pagbabawas ng visibility sa pinakamababang kinakailangan ay isang pangunahing kasanayan ng modular na disenyo.
Gradle ay sumusuporta sa modular na arkitektura nang native: bawat modyul ay isang hiwalay na yunit ng compilation na may sariling build.gradle file. Ang mga proyekto sa Android ay gumagamit ng kombinasyon ng application modyul (app) at ilang library modyul. Ang mga modyul ng library ay hindi maaaring patakbuhin bilang aplikasyon, ngunit maaaring i-publish bilang AAR sa repository.
Ang pangunahing tampok ng Gradle ay parallel build ng mga independiyenteng modyul. Kung ang mga modyul na A, B at C ay hindi umaasa sa isa't isa, compile sila ng Gradle nang sabay-sabay, gamit ang lahat ng core ng processor. Sa mga proyektong may 20+ modyul, ito ay nagbabawas ng buong build mula 15 hanggang 3–5 minuto. Ang incremental build ng binagong modyul ay tumatagal ng mga segundo.
Ang Gradle ay nagbibigay ng dalawang uri ng dependencies sa pagitan ng mga modyul: api (transitibo) at implementation (hindi transitibo). Ang pagkakaiba ay kritikal para sa modularidad: ang implementation ay nagtatago ng mga transitibong dependencies mula sa mga consumer ng modyul. Kung ang modyul na :profile ay gumagamit ng :networking sa pamamagitan ng implementation, ang mga consumer ng :profile ay hindi alam ang tungkol sa :networking at hindi maaaring sumangguni dito.
// settings.gradle — deklarasyon ng mga modyul
include ':app'
include ':feature:profile'
include ':feature:settings'
include ':core:network'
include ':core:database'
// build.gradle feature/profile — dependencies ng modyul
dependencies {
implementation project(':core:network')
implementation project(':core:database')
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0'
}
Ang code ay nagpapakita ng istraktura ng isang modular na proyekto sa Android. Settings.gradle ay naglilista ng lahat ng modyul, at ang build.gradle ng bawat modyul ng Feature ay tumutukoy lamang sa mga modyul ng Core na kailangan nito. Ang sistema ng build ay awtomatikong nilulutas ang mga transitibong dependencies at compile ang mga modyul sa tamang pagkakasunod-sunod.
Swift Package Manager (SPM) — pamantayang kasangkapan para sa modularidad sa iOS mula noong 2019. Ang SPM ay nagpapahintulot na hatiin ang aplikasyon sa Swift Packages, bawat isa ay maaaring library o executable. Ang Package ay tumutukoy ng mga modyul (targets) at kanilang mga dependencies sa pamamagitan ng Package.swift. Ang SPM ay integrated sa Xcode at hindi nangangailangan ng karagdagang kasangkapan.
CocoaPods ay nananatiling pangunahing tagapamahala ng dependency para sa mga third-party na library. Ang Podfile at Podspec ay tumutukoy ng modular na istraktura, at ang CocoaPods ay gumagawa ng workspace na may hiwalay na pod project. Para sa sariling modularidad ng proyekto, ang mga team ay lalong pumipili ng SPM, dahil ito ay naka-embed sa Xcode at hindi nangangailangan ng pag-install.
Sa modularidad ng iOS, ang kontrol ng access ay may mahalagang papel: public, package, internal, fileprivate at private. Ang modyul ay naglalathala lamang ng mga uri na dapat ma-access ng ibang mga modyul. Ang panloob na detalye ng implementasyon ay nakatago sa likod ng internal at private na mga modifier. Ito ay pumipigil sa paglitaw ng mga nakatagong dependencies sa pagitan ng mga modyul.
// Package.swift — modular na istraktura ng iOS project
let package = Package(
name: "MyApp",
platforms: [.iOS(SupportedPlatform.iOSVersion.v17)],
products: [
.library(name: "ProfileFeature", targets: ["ProfileFeature"]),
.library(name: "NetworkCore", targets: ["NetworkCore"]),
],
dependencies: [
.package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.9.0")
],
targets: [
.target(name: "ProfileFeature", dependencies: ["NetworkCore"]),
.target(name: "NetworkCore", dependencies: ["Alamofire"]),
]
)
Package.swift ay nagdedeklara ng dalawang produkto ng library: ProfileFeature at NetworkCore. Ang ProfileFeature ay umaasa sa NetworkCore, ngunit hindi alam ang tungkol sa pagkakaroon ng Alamofire — ito ay nakatago sa loob ng NetworkCore. Ang ganitong pagbubukod ay direktang aplikasyon ng paghihiwalay sa antas ng modyul: ang mga pagbabago sa HTTP client ay hindi nangangailangan ng muling pag-compile ng ProfileFeature.
Ang pangunahing bentaha ng modularidad ay bilis ng pag-unlad. Ang mga team ay nagtatrabaho nang parallel sa iba't ibang modyul nang walang conflict sa code. Ang CI/CD pipeline ay bumubuo lamang ng mga binagong modyul at nagpapatakbo lamang ng kanilang mga pagsubok. Ang oras ng feedback ay nababawasan, at ang dalas ng release ay tumataas. Ang Spotify, Uber at Airbnb ay naglathala ng mga kaso ng migrasyon sa modular na arkitektura na may pagpapabuti ng metrik ng 2–3 beses.
Ang pangalawang bentaha — pagbubukod ng error. Ang bug sa modyul ng Profile ay hindi nakakaapekto sa modyul ng Payments, kung walang direktang dependencies sa pagitan nila. Ito ay lalong mahalaga sa mga aplikasyon na may high-risk na function (pagbabayad, medikal na data), kung saan ang error sa hindi kaugnay na screen ay hindi dapat humarang sa release ng kritikal na functionality.
Ang pangunahing hamon — pamamahala ng dependencies. Sa maling disenyo, lumilitaw ang isang graph ng mga modyul kung saan ang pagbabago ng isang modyul ay cascade na nag-rebuild ng sampu-sampung iba pa. Solusyon — sundin ang patakaran ng acyclicity: ang graph ng dependencies ng modyul ay dapat na directed acyclic graph (DAG). Ang mga kasangkapan tulad ng Gradle Module Graph Assert ay tumutulong na matukoy ang mga cycle sa yugto ng build.
Ang pangalawang hamon — pagtaas ng oras ng paunang pagsasaayos. Ang paglikha ng modular na arkitektura ay nangangailangan ng mas maraming oras sa yugto ng pagsisimula ng proyekto. Ang maliliit na proyekto na may 1–3 developer ay maaaring hindi makinabang mula sa modularidad, gumugugol ng oras sa pagpapanatili ng mga hangganan ng modyul nang walang tunay na pangangailangan para sa parallelization. Solusyon — magsimula sa monolit at mag-extract ng mga modyul habang lumalaki ang team.
Feature-first na approach ay naggrupo ng mga modyul ayon sa functionality: bawat screen o grupo ng mga screen ay nagiging hiwalay na modyul. Ang Layer-first na approach ay naghahati ng code ayon sa teknikal na pamantayan: hiwalay na modyul para sa UI, lohika ng negosyo at data. Sa praktika, karamihan sa mga team ay pumipili ng feature-first na may mga modyul ng Core — ito ay nagbibigay ng mas mahusay na pagbubukod at malinaw na nabigasyon sa proyekto.
Ang pagpili sa pagitan ng mga approach ay depende sa laki ng team at pagiging mahulaan ng functionality. Kung alam mo nang eksakto kung anong mga screen ang nasa proyekto, ang feature-first ay nagpapahintulot sa bawat developer na maging responsable para sa kanilang sariling modyul. Kung ang functionality ay madalas na nagbabago at nag-o-overlap sa pagitan ng mga screen, ang layer-first ay nagbibigay ng higit na kakayahang umangkop sa muling paggamit ng code sa pagitan ng iba't ibang function.
Mga Madalas Itanong
Ang optimal na bilang ay depende sa laki ng proyekto at team. Para sa team na 5 tao, sapat na ang 6–10 modyul. Para sa 20+ developer — 20–40 modyul. Patakaran: ang modyul ay dapat sapat na maliit upang maunawaan ito ng isang developer nang buo, at sapat na malaki upang hindi lumikha ng labis na network ng dependencies.
Ang tamang modularidad ay nagpapabilis ng build sa pamamagitan ng parallel compilation at caching. Ngunit ang labis na bilang ng mga modyul na may siksik na dependencies ay nagpapabagal ng build — ang Gradle at Xcode ay gumugugol ng oras sa paglutas ng graph. Ang susi sa mabilis na build — bawasan ang mga transitibong dependencies at sundin ang acyclicity.
Oo, ngunit iteratively. Magsimula sa pag-extract ng mga modyul ng Core (network, database), pagkatapos ay i-extract ang mga function isa-isa. Gumamit ng feature flags upang paganahin ang bagong modular code na kahanay ng lumang monolitikong code. Ang buong migrasyon ng isang malaking aplikasyon ay tumatagal ng 3 hanggang 12 buwan.
Ang mga modyul ay mga yunit ng compilation sa loob ng isang aplikasyon. Ang microservices ay magkahiwalay na proseso na tumatakbo sa iba't ibang server. Ang mga modyul ay naghahati ng code, ang microservices ay naghahati ng runtime. Sa mobile development, ang terminong “microapps” ay madalas gamitin bilang hybrid: mga modyul ng Feature na maaaring patakbuhin bilang mga standalone na aplikasyon.
Ang bawat modyul ay may sariling unit test, na pinapatakbo nang nakapag-iisa. Sinusuri ng integration test ang interaksyon sa pagitan ng mga modyul. Sinasaklaw ng UI test ang mga modyul ng Feature na may mock data. Pinapasimple ng modular na arkitektura ang pagsubok: ang pag-mock ng dependency ng ibang modyul ay mas madali kaysa sa pag-mock ng bahagi ng monolit.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din