Module — dastur kodini alohida mantiqiy yoki texnik birlikka ajratadigan tuzilma. Module function, class, constant va boshqa symbolarni o‘z ichiga oladi hamda qaysi qismlar tashqariga eksport qilinishini belgilaydi.
Module codebase’ni kichik qismlarga bo‘lib, nomlar to‘qnashuvi, dependency va compilationni boshqarishga yordam beradi.
Module chegarasi
Module ichki va tashqi qismlarni ajratadi.
- Export — boshqa module ishlata oladigan symbol.
- Internal — faqat module ichida ishlatiladigan implementation.
Yaxshi module public API’ni kichik va aniq saqlaydi.
File module
Ko‘p tillarda har source fayl module bo‘lishi mumkin.
Fayldagi private yoki local nomlar boshqa faylga avtomatik ko‘rinmaydi.
Import orqali kerakli symbol olinadi.
Boshqa tillarda bitta module bir nechta fayldan iborat bo‘lishi mumkin.
Import
Module boshqa module’ga dependency yaratadi.
import math
import storage.client
Import jarayoni:
- module topish;
- yuklash;
- compile yoki parse;
- initialization;
- namespacega bog‘lash
bosqichlarini o‘z ichiga olishi mumkin.
Export
Module explicit eksport ro‘yxatini berishi mumkin.
Bu:
- internal helperni yashiradi;
- auto-completionni tozalaydi;
- public contractni hujjatlashtiradi;
- tree shakingni yengillashtiradi;
- refactoring chegarasini saqlaydi.
Barcha nomni avtomatik eksport qilish public APIni tasodifiy kengaytiradi.
Module initialization
Module birinchi importda top-level kodni bajarishi mumkin.
Masalan:
- constant hisoblash;
- registryga yozilish;
- config o‘qish;
- connection yaratish.
Og‘ir yoki side effectli initialization:
- startupni sekinlashtiradi;
- import orderga bog‘liqlik;
- test qiyinligi;
- circular dependency
keltirib chiqaradi.
Import cache
Runtime module’ni bir marta yuklab, cache’da saqlashi mumkin.
Keyingi import bir xil module objectini qaytaradi.
Bu singleton state yaratadi.
Testlar orasida module global state tozalanmasa natija bir-biriga ta’sir qiladi.
Circular dependency
Module A Bni, B esa Ani import qiladi.
Muammo:
- A hali to‘liq initialize bo‘lmagan;
- B Adagi symbolni topolmaydi;
- partial object;
- load order xatosi.
Yechimlar:
- umumiy contractni uchinchi modulega chiqarish;
- dependency inversion;
- importni function ichiga kechiktirish;
- responsibilityni qayta ajratish.
Dependency graph
Modulelar directed graph hosil qiladi.
Acyclic graph build va tushunishni osonlashtiradi.
Layer architecture’da yuqori qatlam pastki qatlamga tayanadi, teskari dependency interface orqali boshqariladi.
Namespace bilan munosabat
Module o‘z namespace’ini yaratishi mumkin.
Ammo namespace va module bir xil tushuncha emas.
Bitta namespace bir nechta module’da kengayishi yoki module bir nechta namespace bilan ishlashi mumkin.
Package bilan munosabat
Package bir nechta module’ni guruhlaydi yoki tarqatadi.
Masalan:
package
├── parser module
├── lexer module
└── formatter module
Package manager package’ni o‘rnatadi, runtime esa module’larni import qiladi.
Compilation unit
Compiled tillarda module alohida compilation unit bo‘lishi mumkin.
Afzalliklari:
- incremental build;
- parallel compilation;
- internal symbol hiding;
- dependency tracking;
- reusable binary interface.
Header-based tizimlarda module qayta parse xarajatini kamaytirishi mumkin.
Module format
JavaScriptda bir nechta module formatlar mavjud bo‘lgan:
- ES Modules;
- CommonJS;
- AMD;
- UMD.
Ularning loading, export va runtime semantikasi farq qiladi.
Bundler formatlar orasida transformatsiya qilishi mumkin.
Static import
Static import source’da oldindan ko‘rinadi.
Vositalar:
- dependency graph;
- tree shaking;
- cycle tahlili;
- preloading
bajarishi mumkin.
Static import odatda module load boshida ishlaydi.
Dynamic import
Module runtime shartiga ko‘ra yuklanadi.
Qo‘llanishlar:
- code splitting;
- plugin;
- optional feature;
- platform-specific code;
- lazy loading.
Dynamic path static analysisni qiyinlashtirishi mumkin.
Code splitting
Katta application bir nechta bundle yoki chunkga bo‘linadi.
Foydalanuvchi kerakli module’ni keyin yuklaydi.
Afzalligi — initial load kichik.
Kamchiligi — runtime network request va version mosligi.
Tree shaking
Statik export/import asosida ishlatilmagan code olib tashlanadi.
Side effectli module tree shakingni cheklaydi.
Package metadata module side effect-free ekanini belgilashi mumkin.
Noto‘g‘ri belgi kerakli initializationni olib tashlaydi.
Plugin module
Application belgilangan interface’ga mos module’ni dynamic yuklashi mumkin.
Plugin:
- discovery;
- version;
- permission;
- lifecycle;
- isolation;
- error handling
contractiga ega.
Ishonchsiz plugin application huquqida code bajarishi mumkin.
Module state
Top-level variable module singleton state’iga aylanishi mumkin.
Bu:
uchun qulay.
Ammo:
muammosi tug‘dirishi mumkin.
Hot reload
Development muhitida o‘zgargan module qayta yuklanadi.
State saqlanishi yoki reset bo‘lishi frameworkga bog‘liq.
Oldingi instance va yangi code birga qolsa moslik muammosi yuz beradi.
Public module dizayni
Yaxshi module:
- bitta aniq mas’uliyat;
- kichik public API;
- dependency kam;
- side effect nazoratli;
- nomlar tushunarli;
- testlanadigan;
- cycle’siz.
Module juda mayda bo‘lsa import va navigation shovqini oshadi.
Diagnostika
Module muammosida:
- import path;
- search path;
- export;
- initialization order;
- circular dependency;
- cache;
- module format;
- runtime version;
- package installation;
- dynamic loading
tekshiriladi.
“Symbol mavjud emas” module yuklanmaganini, eksport qilinmaganini yoki partial initializationni bildirishi mumkin.
Module identity
Runtime module’ni faqat fayl nomi bilan emas, canonical path, package nomi yoki loader identity orqali ajratishi mumkin. Bir fayl ikki xil path bilan yuklansa, ikkita module instance va ikkita global state paydo bo‘lishi ehtimoli bor.
Bog‘liq tushunchalar
Import, Export, Namespace, Package, Dependency graph, Circular dependency, Code splitting, Tree shaking, Plugin, Compilation unit