டிராப்ஷிப்பிங் (dropshipping) ஸ்டோரைத் தொடங்குபவர்களில் பெரும்பாலானோர் குறுக்கு வழிகளைத் தேடிக்கொண்டிருக்கிறார்கள். அவர்கள் வெற்றிபெறும் தயாரிப்புகளைத் தேடி மன்றங்களில் (forums) தேடுகிறார்கள், மலிவான விர்ச்சுவல் உதவியாளர்களை (virtual assistants) வேலைக்கு அமர்த்துகிறார்கள், மேலும் அல்காரிதம் (algorithm) ஒரே இரவில் பெரும் செல்வத்தைத் தரும் என்று நம்புகிறார்கள். அது எனக்கு ஒருபோதும் ஈர்ப்பாகத் தெரியவில்லை. நான் டிராப்ஷிப்பிங்கை ஒரு பொறியியல் சிக்கலாகப் பார்த்தேன். நான் விரைவான பணத்தைத் தேடி ஓடவில்லை. நான் இன்வென்டரி சிங்க் (inventory syncing) சிக்கலைத் தீர்க்கவும், சந்தையின் உண்மையான மாற்றங்களுக்கு ஏற்ப செயல்படும் விலை நிர்ணய அல்காரிதம்களை உருவாக்கவும், மற்றும் எனது நிதானத்தை இழக்காமல் சப்ளையர் API-களுடன் போராடவும் விரும்பினேன். Node.js மற்றும் PostgreSQL பயன்படுத்தி நான் உருவாக்கிய அமைப்பின் ஒரு பக்கவிளைவாகவே அந்த ஸ்டோர் உருவானது.
ஸ்டோரை ஒரு பேக்எண்ட் சேவையாக (Backend Service) கருதுங்கள்
டிராப்ஷிப்பிங்கை ஒரு மார்க்கெட்டிங் உத்தியாகப் பார்ப்பதை நிறுத்திவிட்டு, அதை ஒரு விநியோகிக்கப்பட்ட அமைப்புகளின் (distributed systems) சவாலாகக் கருதத் தொடங்கும் தருணத்தில், சிக்கல்கள் சுவாரஸ்யமாகின்றன. மூன்று வெவ்வேறு சப்ளையர்கள் உங்கள் இருப்பைக் (stock) கட்டுப்படுத்தும் போது, ஒரு ஸ்டோர்ஃபிரண்ட்டை (storefront) துல்லியமாக வைத்திருப்பது எப்படி? அதே சப்ளையர்கள் உங்களுக்குத் தெரிவிக்காமல் விலையை மாற்றும்போது, நீங்கள் எவ்வாறு போட்டித்தன்மையுடன் விலையை நிர்ணயிப்பது? ஸ்பிரெட்ஷீட்களில் (spreadsheets) மூழ்கிவிடாமல், ஐம்பது SKUs-லிருந்து ஐந்தாயிரம் வரை வளரும் ஒரு கேட்டலாக்கை (catalog) எவ்வாறு கையாள்வது?
இந்தக் கேள்விகளுக்குப் பதிலளிக்க நான் ஒரு பைப்லைனை (pipeline) உருவாக்கினேன். ஒரே நேரத்தில் பல சப்ளையர் இணைப்புகளைக் கையாள எனக்கு non-blocking I/O தேவைப்பட்டதால், Node.js நிகழ்வு சார்ந்த கட்டமைப்பை (event-driven architecture) கையாண்டது. PostgreSQL ஒரு உறுதியான ஆதாரமாக (source of truth) செயல்பட்டது. ஸ்கீமா வடிவமைப்பில் (schema design) நான் மிகுந்த கவனம் செலுத்தினேன், ஏனெனில் ஒரு முறையற்ற இன்வென்டரி அட்டவணை, இல்லாத ஒரு பொருளை நீங்கள் அதிகமாக விற்பனை செய்ய முயற்சிக்கும்போது ஒரு பயங்கரமான சிக்கலாக மாறிவிடும்.
பைப்லைனை உருவாக்குதல்
இதன் முக்கிய வேலை எளிமையானது: சப்ளையர் API-களிலிருந்து தயாரிப்புத் தரவை எடுத்தல். நடைமுறையில், ஒன்றுடன் ஒன்று தொடர்புகொள்ளும் வகையில் வடிவமைக்கப்படாத எண்ட்பாயிண்ட்களில் (endpoints) இருந்து SKUs, விளக்கங்கள், படங்கள், இருப்பு நிலைகள் மற்றும் விலைகளை உள்ளிழுப்பதாகும். சப்ளையர் ஃபீட்களை (feeds) குறிப்பிட்ட இடைவெளிகளில் அணுகும் வகையில் Node.js-இல் போலிங் சேவைகளை (polling services) எழுதினேன். ஒவ்வொரு வரும் தரவும் (payload) எங்களது உள் ஸ்டோர்ஃபிரண்ட் தரவுத்தளத்தைத் தொடுவதற்கு முன் சரிபார்ப்பு மற்றும் மேப்பிங் அடுக்குகளைக் (validation and mapping layers) கடந்து சென்றது.
தயாரிப்புகள், மாறுபாடுகள் (variants), விலை வரலாறு மற்றும் சிங்க் லாக்ஸ் (sync logs) ஆகியவற்றிற்காகத் தனித்தனி அட்டவணைகளுடன் PostgreSQL-ஐ நான் கட்டமைத்தேன். ஒரு சப்ளையர் ஒரு ஃபீல்ட் பெயரை (field name) அமைதியாக மாற்றினாலோ அல்லது ஒரு எண் இருக்க வேண்டிய இடத்தில் 'null' என்று அனுப்பினாலோ, பைப்லைன் அதைத் தடுத்து, ஸ்டோர்ஃபிரண்ட்டைச் சிதைப்பதற்குப் பதிலாக ஒரு தோல்விப் பதிவை (failure record) எழுதியது. ஒரு லாக் வரிசையைப் பார்த்து எந்த எண்ட்பாயிண்ட் உடைந்தது, அது எந்த நேரத்தில் நடந்தது மற்றும் எந்த ஃபீல்டுகள் தவறாக இருந்தன என்பதை என்னால் துல்லியமாக அறிய முடிந்தது. ஒரு சப்ளையர் வார இறுதியில் தங்களது API-ஐ "அப்டேட்" செய்ய முடிவு செய்தபோது, அந்தத் தெளிவு (observability) என்னை ஒன்றுக்கும் மேற்பட்ட முறை காப்பாற்றியது.
சிறப்பாகச் செயல்பட்டவை
ஆட்டோமேஷன் (Automation) பெரும் நேரத்தைச் சேமித்தது. ஆரம்பத்தில், நான் கைமுறை முறையை முயற்சித்தேன்: சப்ளையர் ஸ்பிரெட்ஷீட்களைப் பதிவிறக்குவது, அவற்றை கையால் சுத்தம் செய்வது, படங்களை வடிவமைப்பது மற்றும் ஸ்டோருக்கான CSV-களைப் பதிவேற்றுவது. கேட்டலாக் சில டஜன் பொருட்களைத் தாண்டியவுடன் அது சாத்தியமற்றதாகிவிட்டது. ஆட்டோமேட்டட் பைப்லைன், நான் மீண்டும் ஸ்பிரெட்ஷீட்டைத் தொடாமலேயே புதிய பட்டியல்கள், விலை மாற்றங்கள் மற்றும் இருப்பு மாற்றங்களைக் கையாண்டது.
தயாரிப்பு விளக்கங்களை விரிவுபடுத்துவது டெம்ப்ளேட்கள் (templates) மூலம் நடந்தது. கிட்டத்தட்ட ஒரே மாதிரியான ஐந்நூறு பொருட்களுக்கு தனித்துவமான உரைநடையை எழுதுவது நிலையானதல்ல. அதற்குப் பதிலாக, பொருள் (material), பரிமாணங்கள் (dimensions) அல்லது நிறம் போன்ற சப்ளையர் பண்புகளைப் பெற்று அவற்றை கட்டமைக்கப்பட்ட விளக்கப் பெட்டிகளுக்குள் (description blocks) செலுத்தும் ஒரு டெம்ப்ளேட்டிங் அடுக்கை நான் உருவாக்கினேன். அதன் வெளியீடு மாற்றத்திற்குத் தேவையான அளவு சுத்தமாகவும், ஆயிரம் புதிய SKUs-களைச் சேர்ப்பதற்கு எந்த கைமுறை எழுத்துத் தேவையும் இல்லாத அளவுக்குத் தொடர்ச்சியாகவும் இருந்தது.
விலை கண்காணிப்பும் (Price monitoring) எனது எதிர்பார்ப்புகளைத் தாண்டியது. முக்கிய தயாரிப்புகளின் ஒரு தொகுப்பில் போட்டியாளர்களின் விலையைக் கண்காணிக்கும் ஒரு லேசான கண்காணிப்பு அடுக்கை (lightweight monitoring layer) நான் உருவாக்கினேன். விலையில் மாற்றங்களைக் கண்டறியும்போது, நான் அமைத்த கட்டுப்பாடுகளுக்குள் (guardrails) கணினி எங்களது லாப வரம்புகளை (margins) தானாகவே சரிசெய்தது. ஒரு சப்ளையர் மொத்த விலையைக் குறைத்தால், அந்த மாற்றம் நாட்களுக்குப் பதிலாக நிமிடங்களிலேயே பட்டியலிடப்பட்ட விலையில் பிரதிபலிக்கும். அந்தத் துரிதத் தன்மை, குறைந்த லாப வரம்பு கொண்ட பொருட்களில் குறிப்பிடத்தக்க மாற்றத்தை ஏற்படுத்தியது.
எது உடைந்தது மற்றும் ஏன்
சப்ளையர் API-களில் ஒருமைப்பாடு (consistency) இல்லை. இது ஒரு புகார் அல்ல; இது ஒரு நிதர்சனமான உண்மை. ஒரு கூட்டாளர் கணிக்கக்கூடிய பேஜினேஷனுடன் (pagination) சுத்தமான JSON-ஐ வழங்குகிறார். மற்றொருவர் திங்கட்கிழமை camelCase டேக்குகளுடன் XML-ஐயும், புதன்கிழமை snake_case-ஐயும் வழங்குகிறார். ரேட் லிமிட்கள் (Rate limits) தாராளமானதிலிருந்து தண்டனைக்குரியது வரை மாறுபடுகின்றன. டவுன்டைம் (Downtime) முறையான ஸ்டேட்டஸ் கோடுகளுக்குப் (status codes) பதிலாக HTML பிழைப் பக்கங்கள் மூலம் தெரிவிக்கப்படுகிறது. 2003-இல் வடிவமைக்கப்பட்டது போலச் செயல்படும் எண்ட்பாயிண்ட்களுக்காக, நீங்கள் டிஃபென்சிவ் பார்சர்கள் (defensive parsers) மற்றும் ரீட்ரை லாஜிக்கை (retry logic) எழுத வேண்டியிருக்கும்.
சரக்கு இருப்புத் தொகுப்பில் (Inventory sync) ஏற்பட்ட race conditions காரணமாக நான் தூக்கமில்லாமல் போனேன். இதைக் கற்பனை செய்து பாருங்கள்: இரண்டு வாடிக்கையாளர்கள் சில வினாடிகளுக்குள் கடைசிப் பொருளை ஆர்டர் செய்கிறார்கள், அல்லது ஒரு வாடிக்கையாளர் checkout செய்ய முயலும் அதே நேரத்தில், இருப்பு தீர்ந்துவிட்டதாக ஒரு சப்ளையர் webhook உங்களுக்குத் தெரிவிக்கிறது. எனது ஆரம்பகால 'read-then-update' தர்க்கம் (logic) மிக மோசமாகத் தோல்வியடைந்தது. அதிக விற்பனை கொண்ட SKUs-களுக்காக, atomic PostgreSQL transactions மற்றும் pessimistic locking முறைகளைப் பயன்படுத்தி, நான் அந்தத் தொகுப்பு அடுக்கை (sync layer) மீண்டும் எழுத வேண்டியிருந்தது. நிஜமான பண இழப்பு ஏற்படும் சூழலில், எந்த ஒரு பயிற்சியும் (tutorial) கற்றுத் தர முடியாத ஒரு கடினமான, நடைமுறைப் பாடம் அது.
வாடிக்கையாளர் சேவைத் தானியக்கத்தை (customer support automation) அலட்சியப்படுத்தியதுதான் எனது மிகப்பெரிய தோல்வி. நான் தரவுப் பாதைகளில் (data pipelines) மூழ்கிப் போனேன், அதன் விளைவாக ஏற்படும் மனிதத் தேவைகளை ஒரு இரண்டாம் நிலை விஷயமாகவே கருதினேன். ஆர்டர்கள் தாமதமாக வந்தன. சப்ளையர்கள் தவறான நிறத்தைப் பொருட்களை அனுப்பினர். நான் API timeouts-களைச் சரிசெய்து கொண்டிருக்கும்போது, வாடிக்கையாளர்கள் அனுப்பிய மின்னஞ்சல்கள் பல மணிநேரம் எனது இன்பாக்ஸிலேயே இருந்தன. என்னிடம் ticket routing, தானியங்கி பதில்கள் (automated responses) அல்லது chatbot handoffs எதுவுமே இல்லை. தொழில்நுட்பக் கட்டமைப்பு வலுவாக இருந்தது. ஆனால் மனிதக் கட்டமைப்பு இல்லை, அந்த இடைவெளி ஒரு நிலையற்ற (flaky) webhook-ஐ விட வணிகத்திற்கு அதிகப் பாதிப்பை ஏற்படுத்தியது.
ஒரு பொறியாளரைப் போலப் படங்களைச் சோதனை செய்தல்
தயாரிப்புப் படங்களைப் பற்றி நான் ஒரு பக்கச் சோதனையை (side experiment) மேற்கொண்டேன். session-based bucketing உடன் இணைக்கப்பட்ட எளிய URL parameter routing மூலம் வெவ்வேறு பயனர்களுக்கு வெவ்வேறு hero images-களைக் காண்பித்தேன். ஒரு வகை தயாரிப்பை வெறும் வெள்ளை பின்னணியில் காட்டியது. மற்றொன்று அதை ஒரு மேஜையின் மீது இயல்பான சூழலில் (lifestyle setting) காட்டியது. ஆர்டர் ஓட்டத்துடன் (order flow) நேரடியாக இணைக்கப்பட்ட அடிப்படை event logging மூலம் ஒவ்வொரு தொகுப்பிற்கும் (bucket) மாற்ற விகிதங்களைக் (conversion rates) கண்காணித்தேன்.
சிறிய மாற்றங்கள் ஈடுபாட்டை (engagement) அதிகரித்தன. lifestyle shots எப்போதும் வெற்றி பெறவில்லை, ஆனால் அவை வெற்றி பெற்றபோது, நான் முன்னுரிமை அளிக்கும் முறையை மாற்றியமைக்கும் அளவுக்கு அந்த முன்னேற்றம் (lift) குறிப்பிடத்தக்கதாக இருந்தது.
