Laravel ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കുന്ന ഡെവലപ്പർമാർ അവരുടെ കൺട്രോളറുകൾക്കുള്ളിലെ new കീവേഡ് ഒഴിവാക്കി Factory Method പാറ്റേണിലേക്ക് മാറാൻ നിർദ്ദേശിക്കപ്പെടുന്നു. ഒബ്ജക്റ്റ് നിർമ്മാണം (object creation) പ്രത്യേക ഫാക്ടറികളിലേക്ക് മാറ്റുന്നതിലൂടെ, കോഡ് എളുപ്പത്തിൽ വികസിപ്പിക്കാനും (extend), ടെസ്റ്റ് ചെയ്യാനും, പരിപാലിക്കാനും (maintain) സാധിക്കുന്നു—പ്രോജക്റ്റുകൾ വലുതാകുമ്പോൾ ഈ ഗുണങ്ങൾ വളരെ പ്രധാനമാണ്.
എന്തുകൊണ്ടാണ് new കീവേഡ് ഒരു മറഞ്ഞിരിക്കുന്ന ബാധ്യതയാകുന്നത്?
ഒരു കൺട്രോളറിൽ താഴെ പറയുന്ന രീതിയിലുള്ള ഒരു വരി ഉണ്ടെങ്കിൽ:
$processor = new StripePaymentProcessor($config);
ആ കൺട്രോളർ StripePaymentProcessor ക്ലാസുമായി ശക്തമായി ബന്ധിക്കപ്പെട്ടിരിക്കുന്നു (tightly coupled). പേയ്മെന്റ് പ്രോസസ്സർ ആവശ്യമുള്ള ഓരോ സ്ഥലത്തും ആ വരി ആവർത്തിക്കുന്നു, ഇത് കോഡ്ബേസ് മുഴുവൻ നിർമ്മാണ ലോജിക് (construction logic) ചിതറിക്കിടക്കാൻ കാരണമാകുന്നു. പ്രോസസ്സറിന് പിന്നീട് ഒരു ലോഗർ (logger), ഒരു കാഷെ മാനേജർ (cache manager), അല്ലെങ്കിൽ മറ്റൊരു കോൺഫിഗറേഷൻ ഫോർമാറ്റ് എന്നിവ ആവശ്യമായി വന്നാൽ, ആ ഓരോ സ്ഥലത്തും മാറ്റങ്ങൾ വരുത്തേണ്ടി വരും. ഇതിന്റെ ഫലമായി മാറ്റങ്ങൾ വരുത്താൻ പ്രയാസമുള്ളതും യൂണിറ്റ് ടെസ്റ്റുകളിൽ (unit tests) മോക്ക് (mock) ചെയ്യാൻ ബുദ്ധിമുട്ടുള്ളതുമായ ഒരു കോഡ് ലഭിക്കുന്നു.
Factory Method പാറ്റേൺ എങ്ങനെ സഹായിക്കുന്നു
നേരിട്ടുള്ള ഇൻസ്റ്റാൻസിയേഷൻ (direct instantiation) എന്നതിന് പകരം, ഒരു ഇൻ്റർഫേസിൻ്റെ (interface) ഇൻസ്റ്റൻസ് തിരികെ നൽകുന്ന ഒരു മെത്തേഡ് ഉപയോഗിച്ച് Factory Method പാറ്റേൺ പ്രവർത്തിക്കുന്നു. കൺട്രോളർ ഇൻ്റർഫേസിനെ ആശ്രയിക്കുമ്പോൾ, ഏത് കോൺക്രീറ്റ് ക്ലാസ് (concrete class) നിർമ്മിക്കണമെന്നും അതിൻ്റെ ഡിപെൻഡൻസികൾ (dependencies) എങ്ങനെ ക്രമീകരിക്കണമെന്നും ഒരു ഫാക്ടറി ക്ലാസ് അറിയുന്നു. എല്ലാ നിർമ്മാണ ലോജിക്കും ഒരിടത്ത് മാത്രം ഇരിക്കുന്നതിനാൽ, പുതിയൊരു ഡിപെൻഡൻസി ചേർക്കുകയോ നിലവിലുള്ളവ മാറ്റുകയോ ചെയ്യുമ്പോൾ ഫാക്ടറിയിൽ മാത്രം മാറ്റം വരുത്തിയാൽ മതിയാകും.
പ്രധാന നേട്ടങ്ങൾ
- Loose coupling – കൺട്രോളറുകൾ കോൺക്രീറ്റ് ക്ലാസുകൾക്ക് പകരം അബ്സ്ട്രാക്ഷനുകളുമായി (abstractions) പ്രവർത്തിക്കുന്നു.
- Centralized construction – നിർമ്മാണ പ്രക്രിയയിൽ മാറ്റം വരുത്താൻ ഒരു ഫയൽ മാത്രം എഡിറ്റ് ചെയ്താൽ മതി.
- Testability – ഫാക്ടറികളെ സ്റ്റബ് (stub) ചെയ്യാനോ മോക്കുകൾ (mocks) ഉപയോഗിച്ച് മാറ്റാനോ സാധിക്കും, ഇത് കൺട്രോളറുകളെ ഒറ്റപ്പെട്ട രീതിയിൽ ടെസ്റ്റ് ചെയ്യാൻ സഹായിക്കുന്നു.
- Open/Closed Principle – നിലവിലുള്ള കൺട്രോളർ കോഡിൽ മാറ്റം വരുത്താതെ തന്നെ പുതിയ ഫീച്ചറുകൾ (ഉദാഹരണത്തിന്, പുതിയൊരു പേയ്മെന്റ് ഗേറ്റ്വേ) ചേർക്കാൻ സാധിക്കുന്നു.
ഒരു കോഫി ഷോപ്പ് ഉദാഹരണം
ഓരോ ഓർഡറിനും ധാരാളം if-else സ്റ്റേറ്റ്മെന്റുകൾ ഉപയോഗിച്ച് കോഫി ബീൻസ് പൊടിക്കുകയും, പാൽ സ്റ്റീം ചെയ്യുകയും, വെള്ളം ഒഴിക്കുകയും ചെയ്യുന്ന ഒരു ബാരിസ്റ്റയെ സങ്കൽപ്പിക്കുക. ലാറ്റെ (latte) റെസിപ്പിയിൽ മാറ്റം വന്നാൽ, എല്ലാ ബാരിസ്റ്റുകളും ആ സ്റ്റെപ്പുകൾ വീണ്ടും പഠിക്കേണ്ടി വരും. എന്നാൽ ഓർഡർ സ്വീകരിക്കുകയും തയ്യാറാക്കൽ പ്രക്രിയ സ്വന്തമായി കൈകാര്യം ചെയ്യുകയും ചെയ്യുന്ന ഒരു കോഫി മെഷീൻ ഈ പ്രശ്നം പരിഹരിക്കുന്നു: ബാരിസ്റ്റ മെഷീനോട് എന്ത് വേണമെന്ന് പറഞ്ഞാൽ മാത്രം മതി, ബാക്കി എല്ലാ കാര്യങ്ങളും മെഷീൻ തന്നെ ചെയ്യുന്നു. ഇനി റെസിപ്പി മാറ്റണമെങ്കിൽ മെഷീനിൽ മാത്രം മാറ്റം വരുത്തിയാൽ മതി, എല്ലാ ബാരിസ്റ്റമാരെയും മാറ്റേണ്ടതില്ല.
Laravel ഇതിനകം തന്നെ ഫാക്ടറികളെ ആശ്രയിക്കുന്നുണ്ട്
Laravel-ന്റെ പ്രധാന ഘടകങ്ങൾ ഈ പാറ്റേൺ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് കാണിച്ചുതരുന്നു:
- Database – MySQL ആണോ അതോ PostgreSQL ആണോ എന്ന്
ConnectionFactoryതീരുമാനിക്കുന്നു. - Queues – Redis, SQS അല്ലെങ്കിൽ മറ്റ് ബാക്ക്-എൻഡുകൾക്കായി
QueueManagerഡ്രൈവറുകൾ നിർമ്മിക്കുന്നു. - Filesystem – ലോക്കൽ അല്ലെങ്കിൽ S3 ഡിസ്ക് ഇൻസ്റ്റൻസുകൾ
FilesystemManagerനൽകുന്നു. - Mail – SMTP, Mailgun അല്ലെങ്കിൽ മറ്റ് മെയിൽ ഡ്രൈവറുകളെ
MailManagerകൈകാര്യം ചെയ്യുന്നു.
ഫ്രെയിംവർക്ക് തന്നെ ഇത്തരം പ്രധാന സേവനങ്ങൾക്ക് ഫാക്ടറികളെ വിശ്വസിക്കുന്നുണ്ടെങ്കിൽ, നമ്മുടെ കോഡും അത് പിന്തുടരേണ്ടതാണ്.
എപ്പോഴാണ് ഒരു ഫാക്ടറി ഉപയോഗിക്കേണ്ടത്?
താഴെ പറയുന്ന സാഹചര്യങ്ങളിൽ ഒരു ഫാക്ടറി ഉപയോഗിക്കുക:
- ഒബ്ജക്റ്റ് നിർമ്മാണത്തിന് ഒന്നിലധികം കോൺഫിഗറേഷൻ സ്റ്റെപ്പുകളോ ബാഹ്യ സേവനങ്ങളോ (external services) ആവശ്യമുണ്ടെങ്കിൽ.
- പരസ്പരം മാറ്റാൻ കഴിയുന്ന ഒന്നിലധികം ഇംപ്ലിമെന്റേഷനുകൾ ഉണ്ടെങ്കിൽ (വ്യത്യസ്ത പേയ്മെന്റ് ഗേറ്റ്വേകൾ, സ്റ്റോറേജ് പ്രൊവൈഡറുകൾ മുതലായവ).
- ഭാവിയിൽ കൂടുതൽ ഇംപ്ലിമെന്റേഷനുകൾ വരാൻ സാധ്യതയുണ്ടെങ്കിൽ.
താഴെ പറയുന്ന സാഹചര്യങ്ങളിൽ ഫാക്ടറി ഒഴിവാക്കുക:
- നിർമ്മാണം എന്നത് അധിക സെറ്റപ്പുകൾ ഇല്ലാത്ത ഒരു ലളിതമായ
newകോൾ മാത്രമാണെങ്കിൽ. - ഒരു ഇംപ്ലിമെന്റേഷൻ മാത്രമേ ഉപയോഗിക്കപ്പെടുന്നുള്ളൂ എങ്കിൽ, അബ്സ്ട്രാക്ഷൻ ഉപയോഗിക്കുന്നത് അനാവശ്യമായ സങ്കീർണ്ണത (overhead) മാത്രമേ ഉണ്ടാക്കൂ.
ഒരു പേയ്മെന്റ് കൺട്രോളർ റീഫാക്ടർ ചെയ്യുന്ന രീതി: ഒരു ലഘുവിവരണം
- ഒരു ഇൻ്റർഫേസ് നിർവചിക്കുക –
process(array $data)എന്ന മെത്തേഡോട് കൂടിയPaymentProcessorInterface. - കോൺക്രീറ്റ് ക്ലാസുകൾ നിർമ്മിക്കുക – ഇൻ്റർഫേസ് പാലിച്ചുകൊണ്ട്
StripePaymentProcessor,PayPalPaymentProcessorഎന്നിവ നിർമ്മിക്കുക. - ഒരു ഫാക്ടറി നിർമ്മിക്കുക –
make(string $driver): PaymentProcessorInterfaceഎന്ന മെത്തേഡോട് കൂടിയPaymentProcessorFactory. ഇതിനുള്ളിൽ, ശരിയായ ക്ലാസ് തിരികെ നൽകാൻ ഒരുswitchഅല്ലെങ്കിൽ മാപ്പ് (map) ഉപയോഗിക്കുക, കൂടാതെ Laravel-ന്റെ സർവീസ് കണ്ടെയ്നറിൽ (service container) നിന്ന് ആവശ്യമായ സേവനങ്ങൾ ഇൻജക്റ്റ് ചെയ്യുക. - ഫാക്ടറി ഇൻജക്റ്റ് ചെയ്യുക – കൺട്രോളറുടെ കൺസ്ട്രക്ടറിൽ (constructor)
PaymentProcessorFactoryടൈപ്പ്-ഹിൻ്റ് (type-hint) ചെയ്യുക. Laravel ഇത് സ്വയം റെസ dàng (resolve) ചെയ്യും. - ഫാക്ടറി ഉപയോഗിക്കുക –
$processor = $this->processorFactory->make('stripe'); $processor->process($request->all());
ഇപ്പോൾ കൺട്രോളറിൽ new എന്നോ ഏതെങ്കിലും കോൺക്രീറ്റ് പ്രോസസ്സറോ പരാമർശിക്കപ്പെടുന്നില്ല. പുതിയൊരു ഗേറ്റ്വേ ചേർക്കാൻ ഒരു ക്ലാസ് നിർമ്മിച്ചാൽ മതി, ഫാക്ടറി മാപ്പിൽ അത് ഉൾപ്പെടുത്തിയാൽ കൺട്രോളറിൽ മാറ്റങ്ങൾ വരുത്തേണ്ടതില്ല.
ഉണ്ടായേക്കാവുന്ന ദോഷങ്ങളും അവ പരിഹരിക്കാനുള്ള വഴികളും
ഫാക്ടറികളോടുള്ള പ്രധാന വിമർശനം അവ നൽകുന്ന അനാവശ്യമായ ഇൻഡയറക്ഷൻ (indirection) ആണ്, ഇത് ലളിതമായ ഒബ്ജക്റ്റുകൾക്ക് അനാവശ്യമായ സങ്കീർണ്ണത (verbose) തോന്നിപ്പിക്കാം. ഒരു ലളിതമായ സർവീസിനെ ഓവർ-എഞ്ചിനീയർ ചെയ്യുന്നത് യഥാർത്ഥ ഗുണമില്ലാതെ കോഡ്ബേസ് (codebase) വലുതാക്കാൻ കാരണമാകും. നിർമ്മാണത്തിന്റെ സങ്കീർണ്ണത വിലയിരുത്തുക എന്നതാണ് പ്രധാനം: ഒരു ഒബ്ജക്റ്റ് മറ്റ് ഡിപെൻഡൻസികൾ ഇല്ലാത്ത ഒരു പ്ലെയിൻ ഡാറ്റാ ഹോൾഡർ ആണെങ്കിൽ, നേരിട്ടുള്ള new ഉപയോഗിക്കുന്നത് സ്വീകാര്യമായേക്കാം. കൂടാതെ, ഫാക്ടറികൾ ബന്ധമില്ലാത്ത ലോജിക്കുകൾ കുത്തിനിറയ്ക്കുന്ന ഇടമായി മാറാനും സാധ്യതയുണ്ട്. ഒബ്ജക്റ്റ് നിർമ്മാണത്തിൽ മാത്രം ശ്രദ്ധ കേന്ദ്രീകരിക്കുകയും കോൺഫിഗറേഷൻ കാര്യങ്ങൾ പ്രത്യേക സർവീസ് പ്രൊവൈഡറുകൾക്ക് (service providers) കൈമാറുകയും ചെയ്യുന്നത് വ്യക്തത നിലനിർത്താൻ സഹായിക്കും.
അടുത്തതായി ശ്രദ്ധിക്കേണ്ട കാര്യങ്ങൾ
- സർവീസ് കണ്ടെയ്നർ ബൈൻഡിംഗുകൾ (Service container bindings) – ഒരു സർവീസ് പ്രൊവൈഡറിൽ ഇന്റർഫേസിനെ ഫാക്ടറി ക്ലാസുമായി ബൈൻഡ് ചെയ്താൽ, Laravel-ന്റെ കണ്ടെയ്നറിന് ഫാക്ടറികളെ സ്വയമേവ റെസൾവ് ചെയ്യാൻ കഴിയും.
- ഓട്ടോ-ഡിസ്കവറി (Auto-discovery) – ചില പാക്കേജുകൾ അവയുടെ സ്വന്തം ഫാക്ടറികൾ പുറത്തുവിടുന്നു; പേരിന്റെ टकरावങ്ങൾ (naming collisions) ശ്രദ്ധിക്കുക.
- ടെസ്റ്റിംഗ് സ്ട്രാറ്റജികൾ (Testing strategies) – കൺട്രോളറുകൾ യൂണിറ്റ് ടെസ്റ്റ് ചെയ്യുമ്പോൾ, ഫാക്ടറിക്ക് പകരം ഒരു സ്റ്റബ്ബ് പ്രോസസറിനെ (stubbed processor) തിരികെ നൽകുന്ന ഒരു മോക്ക് (mock) ഉപയോഗിക്കുക; ഇത് ടെസ്റ്റുകൾ വേഗതയുള്ളതും ഐസൊലേറ്റഡ് (isolated) ആയിരിക്കുന്നതും ഉറപ്പാക്കുന്നു.
ചുരുക്കത്തിൽ
ചിതറിക്കിടക്കുന്ന new കോളുകൾക്ക് പകരം കൃത്യമായ രീതിയിലുള്ള ഒരു ഫാക്ടറി ഉപയോഗിക്കുന്നത് നിർമ്മാണ പ്രക്രിയയെ കേന്ദ്രീകരിക്കാനും, കപ്ലിംഗ് (coupling) കുറയ്ക്കാനും, നിങ്ങളുടെ കോഡിനെ Laravel-ന്റെ ഡിസൈൻ ഫിലോസഫിയുമായി പൊരുത്തപ്പെടുത്താനും സഹായിക്കുന്നു. പുതിയ പേയ്മെന്റ് പ്രൊവൈഡറുകൾ, സ്റ്റോറേജ് ബാക്കെൻഡുകൾ അല്ലെങ്കിൽ പ്ലഗ്-ഇൻ രീതിയിലുള്ള ഏതെങ്കിലും ഘടകങ്ങൾ എന്നിവയിലൂടെ വളർച്ച പ്രതീക്ഷിക്കുന്ന ടീമുകൾക്ക്, Factory Method പാറ്റേൺ എന്നത് ഫ്ലെക്സിബിലിറ്റിയും ആത്മവിശ്വാസവും നൽകുന്ന കുറഞ്ഞ ചിലവിലുള്ള ഒരു നിക്ഷേപമാണ്. നിങ്ങളുടെ ഭാവിയിലെ സ്വയവും, ഈ കോഡ് കൈമാറുന്ന മറ്റാരും നിങ്ങളോട് നന്ദി പറയും.
