प्रत्येक डेव्हलपरकडे तो एक फोल्डर असतोच. तो utils किंवा helpers नावाचा असतो जो तुम्ही एका रिपॉझिटरीमधून दुसऱ्या रिपॉझिटरीमध्ये कॉपी करता. तुम्ही तो पेस्ट करता, वीस मिनिटे जुन्या डेटाबेस स्कीमांचे संदर्भ काढून टाकण्यात घालवता, लागू न होणारे ऑथ (auth) चेक्स काढून टाकता आणि व्हेरिएबल्सची नावे बदलता जेणेकरून तुमचा नवीन लिंटर (linter) एरर देणे थांबवेल. मी देखील माझ्या 'Dynamic Theme Kit' नावाच्या थीमिंग सिस्टमसोबत असेच करायचो. त्याची सुरुवात एका ॲप्लिकेशनमधील एक फीचर म्हणून झाली होती आणि कित्येक महिने मी त्याला एका पोर्टेबल टूलप्रमाणे वापरले. मी चुकीचा होतो. कोड कॉपी करणे म्हणजे त्याचा पुनर्वापर (reuse) करणे नव्हे. तो फक्त अतिरिक्त पायऱ्यांसह केलेली डुप्लिकेशन (duplication) आहे.
सिंगल-प्रोजेक्ट माइंडसेटचा सापळा
जेव्हा तुम्ही एखाद्या प्रोजेक्टमध्ये एखादे फीचर तयार करता, तेव्हा तुम्ही शेकडो अदृश्य गृहितके (assumptions) गृहीत धरता. कलर पॅलेट कदाचित एका विशिष्ट CSS-in-JS सेटअपवर अवलंबून असू शकते. स्पेसिंग स्केल तुमच्या कंपनीच्या ब्रँड गाईडमधील एखाद्या डिझाइन टोकनचा संदर्भ घेऊ शकते. लाईट आणि डार्क मोडमधील टॉगल कदाचित त्या ॲपच्या बॅकएंडसाठी खास असलेल्या युजर प्रेफरन्स एंडपॉइंटला कॉल करू शकतो. या डिपेंडन्सीज (dependencies) निरुपद्रवी वाटतात कारण प्रोजेक्टच्या आत त्या निरुपद्रवी असतात. त्या तिथेच असाव्यात असे वाटते.
समस्या तेव्हा सुरू होते जेव्हा तुम्ही तो कोड बाहेर काढण्याचा प्रयत्न करता. तुम्हाला समजते की तो "पुनर्वापर करण्यायोग्य" (reusable) घटक प्रत्यक्षात त्या एका कोडबेसशी जोडलेल्या लपलेल्या स्ट्रिंग्सचे जाळे आहे. मला हे DTK सोबत शिकायला मिळाले. त्याने थीम व्हेरिएबल्स तयार केले, बरोबर. पण त्याने एका विशिष्ट फोल्डर स्ट्रक्चरचीही अपेक्षा केली. त्याने मूळ ॲपच्या टाईप्स डिरेक्टरीमधील कुठल्यातरी खोल भागातून टाईप डेफिनेशन इम्पोर्ट केले होते. त्याने एका ग्लोबल कॉन्फिग ऑब्जेक्टच्या अस्तित्वाची अपेक्षा केली जी फक्त त्याच एका रिपॉझिटरीमध्ये अस्तित्वात होती. मी या गोष्टी कधीच लक्षात काढली नव्हती कारण त्या प्रोजेक्टमध्ये सर्व काही नेहमी उपलब्ध होते.
DTK ला स्टँडअलोन पॅकेजमध्ये रूपांतरित करणे म्हणजे विस्तार करणे नसून, एखाद्या शस्त्रक्रियेसारखे (surgery) होते. मला अधिक फीचर्सची गरज नव्हती. मला कमी कनेक्शन्सची गरज होती.
Dynamic Theme Kit बाहेर काढणे (Extracting)
सर्वात कठीण काम म्हणजे कोडबेससोबत बसून प्रत्येक फंक्शन आणि प्रत्येक एक्सपोर्टला विचारणे: हे थीमिंग लॉजिकसाठी आहे की प्रोजेक्टसाठी? मी स्टायलिंग प्रेसेट्स काढून टाकले. वापरकर्ता (consumer) हा एक React ॲप्लिकेशन असेल, हे गृहितक मी काढून टाकले. मी डिफॉल्ट कलर पॅलेट्स पूर्णपणे काढून टाकले. मूळ प्रोजेक्टमध्ये डिफॉल्ट्समध्ये नेव्ही-अँड-स्लेट कॉर्पोरेट एस्थेटिक (aesthetic) समाविष्ट होते. ते काढून टाकणे आवश्यक होते. एखादे पॅकेज तुमचे ब्रँड कलर्स (brand colors) देऊ शकत नाही.
नवीन किट नेमके एकच काम करेल. ते एक कॉन्फिगरेशन ऑब्जेक्ट घेते—काही कलर व्हॅल्यूज, काही स्पेसिंग नंबर्स, काही टायपोग्राफी स्केल्स—आणि ते CSS कस्टम प्रॉपर्टीज तयार करते. बस एवढेच. ते त्या प्रॉपर्टीज लागू करत नाही. तुमच्या DOM मध्ये त्या कुठे जातील हे ते ठरवत नाही. तुम्ही Tailwind, Styled Components किंवा साधे HTML वापरता की नाही, याने त्याला फरक पडत नाही. ते तुमच्या ॲप्लिकेशनला व्हेरिएबल्स देते, आणि तुमचा प्रोजेक्ट त्यांचा वापर कसा करायचा हे ठरवतो.
ती मर्यादा सुरुवातीला बंधनकारक वाटली, पण नंतर तीच मुक्त करणारी ठरली.
जेव्हा तुम्ही खरोखर पुनर्वापर करण्याचा प्रयत्न करता, तेव्हा काय बिघडते
मी काहीही प्रकाशित करण्यापूर्वी, मला खात्री करून घ्यायची होती की हे ॲब्स्ट्रॅक्शन (abstraction) खरोखर काम करते का. मी माझ्या आर्काइव्हमधून तीन लहान वैयक्तिक प्रोजेक्ट्स बाहेर काढले: एक मार्कडाउन प्रिव्ह्यू टूल, एक हॅबिट ट्रॅकर आणि एका इव्हेंटसाठी लँडिंग पेज. त्यांपैकी कोणाचेही फ्रेमवर्क किंवा फोल्डर स्ट्रक्चर सारखे नव्हते. मी प्रत्येक प्रोजेक्टमध्ये स्थानिक पातळीवर (locally) DTK इंस्टॉल केले आणि त्यांना थीम करण्याचा प्रयत्न केला.
पहिला प्रयत्न लगेच अपयशी ठरला. DTK ने तयार केलेली व्हेरिएबलची नावे खूप विशिष्ट होती. ते --primary-action आणि --background-overlay सारखी टोकन्स आउटपुट करत होते, ज्याचा अर्थ एक विशिष्ट UI लेआउट असा निघत होता. मार्कडाउन प्रिव्ह्यूअरमध्ये त्या नावांचा काहीच अर्थ नव्हता. तिथे कोणतेही 'ॲक्शन बटण' नव्हते आणि कोणतेही 'ओव्हरले' नव्हते. मी जनरेशन लॉजिक बदलले जेणेकरून ते विजेटऐवजी व्हॅल्यूचे वर्णन करणारी न्यूट्रल आणि स्ट्रक्चरल नावे तयार करतील.
मला असेही आढळले की माझ्या डिफॉल्ट व्हॅल्यूज खूप जास्त (aggressive) होत्या. जेव्हा वापरकर्त्याने अपूर्ण कॉन्फिग पास केला, तेव्हा DTK अशा व्हॅल्यूजने रिकाम्या जागा भरत असे ज्या डेंस डॅशबोर्डमध्ये चांगल्या दिसत होत्या, पण स्पार्स लँडिंग पेजवर त्या बिघडत होत्या. मी 'ट्रान्सपरंट डिफॉल्ट्स' वापरण्यास सुरुवात केली, जिथे गहाळ टोकन्स रेंडरच होणार नाहीत, ज्यामुळे वापरणारा प्रोजेक्ट स्वतःचे फॉलबॅक्स (fallbacks) ठरवू शकेल.
त्यानंतर डॉक्युमेंटेशनचा प्रश्न होता. मला जे स्पष्ट वाटत होते—"फक्त एक कॉन्फिग ऑब्जेक्ट पास करा"—ते मध्यरात्री README वाचणाऱ्या व्यक्तीसाठी अस्पष्ट होते. मी ते खऱ्या ऑब्जेक्ट्स, खऱ्या फाईल पाथ्स आणि फंक्शन कॉल केल्यावर काय घडते आणि त्यानंतर तुमच्या ॲप्लिकेशनला काय करण्याची गरज आहे, याच्या स्पष्ट स्पष्टीकरणासह पुन्हा लिहिले.
या लहान वैयक्तिक प्रोजेक्ट्सनी टेस्ट बेड म्हणून काम केले. त्यांची जोखीम कमी होती, पण त्यांनी अशा खऱ्या त्रुटी समोर आणल्या ज्या मी केवळ सोर्स कोडकडे बघून पकडू शकलो नसतो.
खरा टेस्ट: Web Weavers World मधील प्रोडक्शन
वैयक्तिक प्रकल्प हे सँडबॉक्ससारखे असतात. त्यांना डेडलाईन्स, स्टेकहोल्डर्स किंवा तुमच्या पॅकेजच्या आधीपासून असलेले लेगसी CSS नसते. खरी परीक्षा तेव्हा आली जेव्हा मी माझ्या व्यवसायाची साइट असलेल्या Web Weavers World मध्ये DTK समाविष्ट (integrate) केले. ही एक लाईव्ह प्रॉपर्टी होती, ज्यामध्ये आधीपासून असलेले स्टाइल्स, क्लायंटच्या अपेक्षा आणि ॲनालिटिक्सचा विचार करणे आवश्यक होते. जर पॅकेजमुळे काही बिघडले असते, तर मी फक्त रिपो (repo) डिलीट करून पुन्हा सुरुवात करू शकलो नसतो.
मी DTK बिल्ड पाइपलाइनमध्ये जोडले, ते एका नवीन कलर कॉन्फिगरेशनकडे वळवले आणि त्याला CSS व्हेरिएबल्सचा एक नवीन संच तयार करू दिले. हे इंटिग्रेशन पूर्ण व्हायला फक्त एक दुपार लागली, एक आठवडा नाही. तोच खरा संकेत होता. यापूर्वी, नवीन थीम जोडणे म्हणजे नवीन CSS लिहिणे, वीस फाईल्समध्ये हार्डकोड केलेले हेक्स (hex) व्हॅल्यूज शोधणे आणि एखादा 'एज केस' (edge case) सुटला नाही याची खात्री करणे, असा होता. आता मी कॉन्फिगरेशन फाईलमध्ये एक पॅलेट जोडतो, DTK व्हेरिएबल्स तयार करते आणि साइटचा उर्वरित भाग त्यांचा वापर करतो. थीम लॉजिक हे एका नाजूक मॅन्युअल प्रक्रियेकडून अशा गोष्टीकडे बदलले ज्यावर मी इतका विश्वास ठेवू शकतो की ती सहकाऱ्यांकडे सोपवू शकतो.
मी कोडिंग करण्याची पद्धत बदलणारे तीन प्रश्न
या प्रक्रियेतून गेल्यामुळे मला एक मानसिक चेकलिस्ट तयार करण्यास भाग पाडले, जी मी आता काहीही ॲबस्ट्रॅक्ट (abstract) करण्यापूर्वी वापरतो:
- हे व्हेरिएबल खरोखरच जेनेरिक आहे का? जर नाव किंवा लॉजिक मूळ प्रकल्पातील एखाद्या डोमेन संकल्पनेचा संदर्भ देत असेल, तर ते तिथेच राहू द्या.
- हे पॅकेजमध्ये असावे की ॲप्लिकेशनमध्ये? बिझनेस रूल्स, ब्रँड आयडेंटिटी आणि लेआउट गृहितके ॲपमध्ये असतात. स्टँडर्ड आउटपुट तयार करणारे पायाभूत घटक (plumbing) पॅकेजमध्ये असतात.
- मी एखादी पुन्हा वापरण्यायोग्य (reusable) समस्या सोडवत आहे की प्रकल्प-विशिष्ट (project-specific) समस्या? याचे प्रामाणिकपणे उत्तर देणे सर्वात कठीण आहे. आपल्याला वाटते की आपली उपाययोजना सार्वत्रिक (universal) आहे, पण सहसा त्या स्थानिक (local) असतात.
या प्रश्नांची उत्तरे शोधल्यामुळे मला माझे डिझाइन सोपे करण्यास भाग पाडले, जे अनेकदा कोड वाढवण्याऐवजी तो कमी करून साध्य झाले. DTK ने मला शिकवले की 'रीयुज' (reuse) ही स्वतःला दिलेली भेट नाही. ती एक शिस्त आहे जी तुम्ही सोयीला नकार देऊन पाळता.
रिफॅक्टरिंगबद्दल विचार करण्याची एक वेगळी पद्धत
मी पूर्वी रिफॅक्टरिंगचे मोजमाप कोड किती लहान झाला यावरून करायचो. कमी ओळी म्हणजे प्रगती वाटायची. आता मी ते किती नवीन मार्ग खुले करतात यावरून मोजतो. Dynamic Theme Kit हे संक्षिप्त असल्यामुळे मोहक (elegant) नाही, तर ते उपयुक्त आहे कारण ते तीन असंबद्ध वैयक्तिक प्रकल्प आणि एक प्रोडक्शन बिझनेस साइट, या सर्वांमध्ये त्याची अंतर्गत रचना न बदलता टिकून राहिले आहे.
हाच तो निकष आहे जो महत्त्वाचा आहे. जो कोड एकदाच काम करतो तो खर्च आहे. जो कोड वारंवार काम करतो तो एक अॅसेट आहे. आता मी कोणतेही फीचर सुरू करण्यापूर्वी थांबतो. मी स्वतःला विचारतो की मी असे काही बनवत आहे का ज्याची मला पुन्हा गरज पडेल. जर उत्तर 'हो' असेल, तर मी पहिल्या ओळीपासूनच ते वेगळ्या पद्धतीने बनवतो. मी इनपुट्स वेगळे करतो. मी आउटपुट्स परिभाषित करतो. मी गृहितके काढून टाकतो.
सर्वोत्तम रिफॅक्टरिंग तुमचा कोड लहान करत नाही. तर तो अशा ठिकाणी काम करण्यास सक्षम करतो ज्याची तुम्ही अजून कल्पनाही केली नसेल.
