ഡ്രോപ്പ്ഷിപ്പിംഗ് സ്റ്റോർ തുടങ്ങുന്ന മിക്കവരും എളുപ്പവഴികൾ തേടുന്നവരാണ്. അവർ ഫോറങ്ങളിൽ വിജയകരമായ ഉൽപ്പന്നങ്ങൾക്കായി തിരയുന്നു, കുറഞ്ഞ ചിലവിൽ വെർച്വൽ അസിസ്റ്റന്റുകളെ നിയമിക്കുന്നു, അൽഗോരിതം പെട്ടെന്ന് തന്നെ വലിയ ലാഭം നൽകുമെന്ന് പ്രതീക്ഷിക്കുന്നു. അത് എനിക്ക് ഒരിക്കലും ആകർഷകമായി തോന്നിയിട്ടില്ല. ഞാൻ ഡ്രോപ്പ്ഷിപ്പിംഗിനെ ഒരു എഞ്ചിനീയറിംഗ് പ്രശ്നമായാണ് കണ്ടത്. ഞാൻ പെട്ടെന്നുള്ള പണത്തിന് പിന്നാലെ പോയില്ല. ഇൻവെന്ററി സിങ്കിംഗ് (inventory syncing) പരിഹരിക്കാനും, വിപണിയിലെ മാറ്റങ്ങളോട് പ്രതികരിക്കുന്ന പ്രൈസിംഗ് അൽഗോരിതങ്ങൾ നിർമ്മിക്കാനും, എന്റെ സമാധാനം കളയാതെ സപ്ലയർ API-കളുമായി പൊരുത്തപ്പെടാനും ഞാൻ ആഗ്രഹിച്ചു. Node.js ഉം PostgreSQL ഉം ഉപയോഗിച്ച് ഞാൻ നിർമ്മിച്ച സിസ്റ്റത്തിന്റെ ഒരു ഉപോൽപ്പന്നം മാത്രമായിരുന്നു ആ സ്റ്റോർ.
സ്റ്റോറിനെ ഒരു ബാക്കെൻഡ് സർവീസ് പോലെ കാണുക
ഡ്രോപ്പ്ഷിപ്പിംഗിനെ ഒരു മാർക്കറ്റിംഗ് തന്ത്രമായി കാണുന്നത് നിർത്തി, അതിനെ ഒരു ഡിസ്ട്രിബ്യൂട്ടഡ് സിസ്റ്റം ചലഞ്ച് (distributed systems challenge) ആയി കാണാൻ തുടങ്ങുന്ന നിമിഷം, പ്രശ്നങ്ങൾ രസകരമാകും. മൂന്ന് വ്യത്യസ്ത സപ്ലയർമാർ നിങ്ങളുടെ സ്റ്റോക്ക് നിയന്ത്രിക്കുമ്പോൾ എങ്ങനെ ഒരു സ്റ്റോർഫ്രണ്ട് കൃത്യമായി നിലനിർത്താം? സപ്ലയർമാർ നിങ്ങളെ അറിയിക്കാതെ തന്നെ വില മാറ്റുമ്പോൾ എങ്ങനെ മത്സരബുദ്ധിയോടെ വില നിശ്ചയിക്കാം? സ്പ്രെഡ്ഷീറ്റുകളിൽ മുങ്ങിപ്പോകാതെ അമ്പത് SKU-കളിൽ നിന്ന് അയ്യായിരം SKU-കളിലേക്ക് വളരുന്ന ഒരു കാറ്റലോഗ് എങ്ങനെ കൈകാര്യം ചെയ്യാം?
ഈ ചോദ്യങ്ങൾക്ക് ഉത്തരം നൽകാൻ ഞാൻ ഒരു പൈപ്പ്ലൈൻ നിർമ്മിച്ചു. ഒരേസമയം ഒന്നിലധികം സപ്ലയർ കണക്ഷനുകൾ കൈകാര്യം ചെയ്യാൻ എനിക്ക് non-blocking I/O ആവശ്യമായതിനാൽ Node.js ആണ് event-driven architecture കൈകാര്യം ചെയ്തത്. PostgreSQL ആയിരുന്നു കൃത്യമായ വിവരങ്ങളുടെ ഉറവിടം (source of truth). സ്കീമ ഡിസൈനിനെ (schema design) ഞാൻ വളരെയധികം ശ്രദ്ധിച്ചു, കാരണം ഒരു മോശം ഇൻവെന്ററി ടേബിൾ, നിലവിലില്ലാത്ത ഒരു സാധനം വിൽക്കാൻ ശ്രമിക്കുമ്പോൾ തന്നെ വലിയൊരു ദുരന്തമായി മാറും.
പൈപ്പ്ലൈൻ നിർമ്മിക്കുന്നു
പ്രധാന ജോലി ലളിതമായിരുന്നു: സപ്ലയർ API-കളിൽ നിന്ന് ഉൽപ്പന്ന വിവരങ്ങൾ ശേഖരിക്കുക. പ്രായോഗികമായി പറഞ്ഞാൽ, പരസ്പരം ആശയവിനിമയം നടത്താൻ രൂപകൽപ്പന ചെയ്യാത്ത എൻഡ്പോയിന്റുകളിൽ നിന്ന് SKU-കൾ, വിവരണങ്ങൾ, ചിത്രങ്ങൾ, സ്റ്റോക്ക് നിലവാരം, വില എന്നിവ ശേഖരിക്കുക എന്നതായിരുന്നു അത്. സപ്ലയർ ഫീഡുകൾ കൃത്യമായ ഇടവേളകളിൽ പരിശോധിക്കുന്നതിനായി ഞാൻ Node.js-ൽ polling services എഴുതി. ഓരോ ഇൻകമിംഗ് പേലോഡും (payload) നമ്മുടെ ഇന്റേണൽ സ്റ്റോർഫ്രണ്ട് ഡാറ്റാബേസിൽ എത്തുന്നതിന് മുമ്പ് വാലിഡേഷൻ (validation), മാപ്പിംഗ് (mapping) ലെയറുകളിലൂടെ കടന്നുപോയി.
ഉൽപ്പന്നങ്ങൾ, വേരിയന്റുകൾ, പ്രൈസിംഗ് ഹിസ്റ്ററി, സിങ്ക് ലോഗുകൾ എന്നിവയ്ക്കായി വേറിട്ട ടേബിളുകളോടെയാണ് ഞാൻ PostgreSQL ക്രമീകരിച്ചത്. ഒരു സപ്ലയർ ഒരു ഫീൽഡിന്റെ പേര് മാറ്റുകയോ അല്ലെങ്കിൽ ഒരു സംഖ്യയ്ക്ക് പകരം null നൽകുകയോ ചെയ്താൽ, പൈപ്പ്ലൈൻ അത് കണ്ടെത്തി സ്റ്റോർഫ്രണ്ട് നശിപ്പിക്കുന്നതിന് പകരം ഒരു ഫെയിലർ റെക്കോർഡ് രേഖപ്പെടുത്തി. ഏത് എൻഡ്പോയിന്റ് ആണ് തകരാറിലായതെന്നും അത് ഏത് സമയത്താണ് സംഭവിച്ചതെന്നും ഏത് ഫീൽഡുകളാണ് തെറ്റായതെന്നും ഒരു ലോഗ് റോ (log row) നോക്കിയാൽ എനിക്ക് കൃത്യമായി മനസ്സിലാക്കാൻ കഴിഞ്ഞു. ഒരു സപ്ലയർ വാരാന്ത്യത്തിൽ അവരുടെ API "അപ്ഗ്രേഡ്" ചെയ്യാൻ തീരുമാനിച്ചപ്പോൾ ഈ ഒബ്സർവബിലിറ്റി (observability) എന്നെ പലതവണ രക്ഷിച്ചു.
എന്തൊക്കെ നന്നായി പ്രവർത്തിച്ചു
ഓട്ടോമേഷൻ വലിയൊരു അളവിൽ സമയം ലാഭിച്ചു. തുടക്കത്തിൽ, ഞാൻ മാനുവൽ രീതി പരീക്ഷിച്ചു: സപ്ലയർ സ്പ്രെഡ്ഷീറ്റുകൾ ഡൗൺലോഡ് ചെയ്യുക, അവ കൈകൊണ്ട് വൃത്തിയാക്കുക, ചിത്രങ്ങൾ ഫോർമാറ്റ് ചെയ്യുക, സ്റ്റോറിലേക്ക് CSV-കൾ അപ്ലോഡ് ചെയ്യുക. കാറ്റലോഗ് കുറച്ച് ഐറ്റങ്ങൾ കടന്നുപോയതോടെ അത് അസാധ്യമായി മാറി. ഓട്ടോമേറ്റഡ് പൈപ്പ്ലൈൻ പുതിയ ലിസ്റ്റിംഗുകൾ, വില മാറ്റങ്ങൾ, സ്റ്റോക്ക് ക്രമീകരണങ്ങൾ എന്നിവ ഞാൻ സ്പ്രെഡ്ഷീറ്റിൽ തൊടാതെ തന്നെ കൈകാര്യം ചെയ്തു.
ടെംപ്ലേറ്റുകൾ ഉപയോഗിച്ചാണ് ഉൽപ്പന്ന വിവരണങ്ങൾ (product descriptions) സ്കെയിൽ ചെയ്തത്. അഞ്ഞൂറോളം സമാനമായ ഉൽപ്പന്നങ്ങൾക്ക് ഓരോന്നിനും വ്യത്യസ്തമായ വിവരണങ്ങൾ എഴുതുന്നത് നിലനിൽക്കാൻ പ്രയാസമാണ്. അതിനുപകരം, മെറ്റീരിയൽ, ഡൈമൻഷൻ അല്ലെങ്കിൽ നിറം പോലുള്ള സപ്ലയർ അറ്റ്രിബ്യൂട്ടുകൾ എടുത്ത് അവയെ ഘടനയുള്ള വിവരണ ബ്ലോക്കുകളിലേക്ക് ചേർക്കുന്ന ഒരു ടെംപ്ലേറ്റിംഗ് ലെയർ ഞാൻ നിർമ്മിച്ചു. ഇതിന്റെ ഔട്ട്പുട്ട് വളരെ വൃത്തിയുള്ളതും സ്ഥിരതയുള്ളതുമായിരുന്നു, അതിനാൽ ആയിരം പുതിയ SKU-കൾ ചേർക്കാൻ പോലും മാനുവൽ കോപ്പിറൈറ്റിംഗ് ആവശ്യമില്ലായിരുന്നു.
വില നിരീക്ഷണം (Price monitoring) എന്റെ പ്രതീക്ഷകൾക്കും അപ്പുറമായിരുന്നു. പ്രധാനപ്പെട്ട ചില ഉൽപ്പന്നങ്ങളുടെ വില മത്സരക്കാരെ നിരീക്ഷിക്കുന്നതിനായി ഞാൻ ഒരു ലൈറ്റ്വെയ്റ്റ് മോണിറ്ററിംഗ് ലെയർ നിർമ്മിച്ചു. വിലയിൽ മാറ്റം കണ്ടാൽ, ഞാൻ ക്രമീകരിച്ച ഗാർഡ്റൈലുകൾക്കുള്ളിൽ (guardrails) നിന്നുകൊണ്ട് സിസ്റ്റം സ്വയമേവ നമ്മുടെ മാർജിനുകൾ ക്രമീകരിച്ചു. ഒരു സപ്ലയർ ഹോൾസെയിൽ വില കുറച്ചാൽ, ദിവസങ്ങൾക്കപ്പുറം മിനിറ്റുകൾക്കുള്ളിൽ ആ മാറ്റം ലിസ്റ്റിംഗ് വിലയിൽ പ്രതിഫലിച്ചു. കുറഞ്ഞ ലാഭമുള്ള ഉൽപ്പന്നങ്ങളിൽ ഈ വേഗത വലിയ വ്യത്യാസം ഉണ്ടാക്കി.
എന്താണ് തകരാറിലായത്, എന്തുകൊണ്ട്
സപ്ലയർ API-കളിൽ സ്ഥിരതയില്ല. ഇതൊരു പരാതിയല്ല; ഇതൊരു യാഥാർത്ഥ്യമാണ്. ഒരു പാർട്ണർ കൃത്യമായ പേജിനേഷനോടു കൂടിയ ക്ലീൻ JSON നൽകുന്നു. മറ്റൊരാൾ തിങ്കളാഴ്ച camelCase ടാഗുകളുള്ള XML നൽകുന്നു, ബുധനാഴ്ച snake_case നൽകുന്നു. റേറ്റ് ലിമിറ്റുകൾ (Rate limits) വളരെ കുറഞ്ഞതോ അല്ലെങ്കിൽ കഠിനമായതോ ആകാം. ഡൗൺടൈം (Downtime) ശരിയായ സ്റ്റാറ്റസ് കോഡുകൾക്ക് പകരം HTML എറർ പേജുകളിലൂടെയാണ് അറിയിക്കുന്നത്. 2003-ൽ രൂപകൽപ്പന ചെയ്തതുപോലെ പെരുമാറുന്ന എൻഡ്പോയിന്റുകൾക്കായി നിങ്ങൾ ഡിഫൻസീവ് പാഴ്സറുകളും (defensive parsers) റീട്രൈ ലോജിക്കും (retry logic) എഴുതേണ്ടി വരും.
ഇൻവെന്ററി സിങ്ക് (Inventory sync) ചെയ്യുമ്പോൾ ഉണ്ടായ റേസ് കണ്ടീഷനുകൾ (race conditions) കാരണം എനിക്ക് ഉറക്കം നഷ്ടപ്പെട്ടു. ഒന്ന് സങ്കൽപ്പിക്കുക: രണ്ട് ഉപഭോക്താക്കൾ ഏതാനും സെക്കൻഡുകൾക്കുള്ളിൽ അവസാനത്തെ യൂണിറ്റ് ഓർഡർ ചെയ്യുന്നു, അല്ലെങ്കിൽ ഒരു ബയർ ചെക്ക്ഔട്ട് ക്ലിക്ക് ചെയ്യുന്ന അതേ നിമിഷം സ്റ്റോക്ക് പൂജ്യമായി എന്ന് ഒരു സപ്ലയർ വെബ്ഹുക്ക് (supplier webhook) അറിയിക്കുന്നു. എന്റെ ആദ്യകാല 'read-then-update' ലോജിക് വലിയ തോതിൽ പരാജയപ്പെട്ടു. ഉയർന്ന വേഗതയിൽ വിറ്റഴിയുന്ന SKU-കൾക്കായി (high-velocity SKUs), അറ്റോമിക് PostgreSQL ട്രാൻസാക്ഷനുകളും (atomic PostgreSQL transactions) പെസിമിസ്റ്റിക് ലോക്കിംഗും (pessimistic locking) ഉപയോഗിച്ച് സിങ്ക് ലെയർ (sync layer) എനിക്ക് വീണ്ടും എഴുതേണ്ടി വന്നു. പണം നഷ്ടപ്പെടാൻ സാധ്യതയുള്ള സാഹചര്യത്തിൽ നേരിട്ട ഈ കോൺകറൻസി (concurrency) പാഠം, ഒരു ട്യൂട്ടോറിയലിനും നൽകാൻ കഴിയാത്ത അത്ര കഠിനവും പ്രായോഗികവുമായ ഒന്നായിരുന്നു.
കസ്റ്റമർ സപ്പോർട്ട് ഓട്ടോമേഷൻ (customer support automation) അവഗണിച്ചു എന്നതാണ് എന്റെ ഏറ്റവും വലിയ പരാജയം. ഞാൻ ഡാറ്റാ പൈപ്പ്ലൈനുകളിൽ (data pipelines) മാത്രം ശ്രദ്ധ കേന്ദ്രീകരിക്കുകയും, അതിന്റെ ഫലമായി മനുഷ്യർക്കുണ്ടാകുന്ന ബുദ്ധിമുട്ടുകളെ ഒരു രണ്ടാംകിട കാര്യമായി കാണുകയും ചെയ്തു. ഓർഡറുകൾ വൈകി എത്തി. സപ്ലയർമാർ തെറ്റായ നിറത്തിലുള്ള ഉൽപ്പന്നങ്ങൾ അയച്ചു. ഞാൻ API ടൈമൗട്ടുകൾ (API timeouts) ഡിബഗ് ചെയ്യുന്നതിനിടയിൽ ഉപഭോക്താക്കൾ അയച്ച ഇമെയിലുകൾ മണിക്കൂറുകളോളം എന്റെ ഇൻബോക്സിൽ തന്നെ കിടന്നു. എനിക്ക് ടിക്കറ്റ് റൂട്ടിംഗോ (ticket routing), ഓട്ടോമേറ്റഡ് മറുപടികളോ, ചാറ്റ്ബോട്ട് ഹാൻഡ്ഓഫുകളോ (chatbot handoffs) ഉണ്ടായിരുന്നില്ല. സാങ്കേതിക അടിസ്ഥാന സൗകര്യങ്ങൾ (technical infrastructure) മികച്ചതായിരുന്നു. എന്നാൽ മാനുഷികമായ അടിസ്ഥാന സൗകര്യങ്ങൾ (human infrastructure) ഇല്ലായിരുന്നു, ആ കുറവ് ഒരു വെബ്ഹുക്കിനേക്കാൾ (webhook) എത്രയോ മടങ്ങ് ബിസിനസിനെ ബാധിച്ചു.
ഒരു എഞ്ചിനീയറെപ്പോലെ ചിത്രങ്ങൾ ടെസ്റ്റ് ചെയ്യുമ്പോൾ
ഉൽപ്പന്ന ചിത്രങ്ങളിൽ ഞാൻ ഒരു പരീക്ഷണാടിസ്ഥാനത്തിലുള്ള പരീക്ഷണം നടത്തി. സെഷൻ അടിസ്ഥാനമാക്കിയുള്ള ബക്കറ്റിംഗുമായി (session-based bucketing) ബന്ധിപ്പിച്ച ലളിതമായ URL പാരാമീറ്റർ റൂട്ടിംഗ് ഉപയോഗിച്ച്, ഓരോ ഉപഭോക്താവിനും വ്യത്യസ്തമായ ഹീറോ ഇമേജുകൾ (hero images) ഞാൻ നൽകി. ഒരു വേരിയന്റിൽ ഉൽപ്പന്നം വെളുത്ത പശ്ചാത്തലത്തിൽ കാണിച്ചു. മറ്റൊന്ന് ഒരു ഡെസ്കിൽ ഉപയോഗിക്കുന്ന രീതിയിലുള്ള ലൈഫ്സ്റ്റൈൽ സെറ്റിംഗിൽ (lifestyle setting) കാണിച്ചു. ഓർഡർ ഫ്ലോയുമായി (order flow) നേരിട്ട് ബന്ധിപ്പിച്ച ബേസിക് ഇവന്റ് ലോഗിംഗ് (event logging) ഉപയോഗിച്ച് ഓരോ ബക്കറ്റിലെയും കൺവേർഷൻ നിരക്കുകൾ (conversion rates) ഞാൻ നിരീക്ഷിച്ചു.
ചെറിയ മാറ്റങ്ങൾ എൻഗേജ്മെന്റ് (engagement) വർദ്ധിപ്പിച്ചു. ലൈഫ്സ്റ്റൈൽ ചിത്രങ്ങൾ എപ്പോഴും വിജയിച്ചില്ലെങ്കിലും, അവ വിജയിച്ചപ്പോൾ ലഭിച്ച മുന്നേറ്റം എന്റെ മുൻഗണനകൾ മാറ്റാൻ പാകത്തിലുള്ളതായിരുന്നു.
