सामान्य CRUD आपके प्रोजेक्ट को क्यों बर्बाद करता है, और DDD इसे कैसे ठीक कर सकता है
\n\nहर डेवलपर कम से कम एक बार ऐसी स्थिति का सामना करता है जहाँ एक साधारण प्रोजेक्ट सर्विसेज, कंट्रोलर्स और पूरे कोड में फैली बिज़नेस लॉजिक की 'दलदल' में बदल जाता है। आप UserService लिखना शुरू करते हैं, फिर OrderService, और छह महीने बाद OrderService में ईमेल भेजने, छूट की गणना करने और उपयोगकर्ता का बैलेंस जाँचने की लॉजिक होती है। परिचित लग रहा है?
समस्या यह है कि हम डेटाबेस, फ्रेमवर्क और REST API के बारे में बहुत जल्दी सोचते हैं। हम सबसे महत्वपूर्ण चीज़ — डोमेन (विषय क्षेत्र) को भूल जाते हैं। Domain-Driven Design (DDD) एक पूरी तरह से अलग दृष्टिकोण प्रस्तुत करता है: पहले विशेषज्ञों की भाषा में बिज़नेस प्रक्रियाओं को मॉडल करें, फिर कोड लिखें।
\n\nइस लेख में, हम वास्तविक उदाहरणों के साथ TypeScript में Domain-Driven Design लागू करना सीखेंगे। आप देखेंगे कि कैसे एक स्वच्छ आर्किटेक्चर बनाया जाए जहाँ बिज़नेस नियम इन्फ्रास्ट्रक्चर से अलग रहते हैं, और कोड को आसानी से टेस्ट और बदला जा सकता है।
\n\nDDD की मूल बातें: भाषा, संदर्भ और मॉडल
\n\nUbiquitous Language (सार्वभौमिक भाषा)
\nDDD का पहला सिद्धांत एक साझा भाषा है जो डेवलपर्स और बिज़नेस विशेषज्ञों दोनों को समझ में आती है। अगर मैनेजर कहता है 'ग्राहक ने सब्सक्रिप्शन सक्रिय किया', तो कोड में activateSubscription() मेथड होना चाहिए, न कि setStatus(1)। TypeScript अपनी सख्त टाइपिंग के साथ इसके लिए आदर्श है — क्लास, मेथड और वेरिएबल के नाम ही दस्तावेज़ बन जाते हैं।
Bounded Context (सीमित संदर्भ)
\nबड़े सिस्टम को स्वतंत्र संदर्भों में विभाजित किया जाता है: 'भुगतान', 'उपयोगकर्ता प्रबंधन', 'डिलीवरी'। प्रत्येक संदर्भ का अपना मॉडल और भाषा होती है। TypeScript मॉड्यूल और strict-टाइप्स इन संदर्भों को इम्पोर्ट स्तर पर सख्ती से अलग करने में मदद करते हैं।
\n\nTypeScript में डोमेन मॉडल बनाना
\n\nValue Object (मूल्य-वस्तु)
\nयह एक अपरिवर्तनीय इकाई है जो अपने गुणों से परिभाषित होती है, न कि पहचानकर्ता से। उदाहरण: Email, Money, Coordinates।
\n\n// value-objects/Email.ts\nexport class Email {\n private readonly value: string;\n\n constructor(email: string) {\n if (!this.isValid(email)) {\n throw new Error('अमान्य ईमेल पता');\n }\n this.value = email;\n }\n\n private isValid(email: string): boolean {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n }\n\n public getValue(): string {\n return this.value;\n }\n\n public equals(other: Email): boolean {\n return this.value === other.value;\n }\n}\n\n\nध्यान दें: Email स्वयं अपनी वैधता की जाँच करता है। किसी भी सर्विस को यह नहीं जानना चाहिए कि सही ईमेल कैसा दिखता है। यह शुद्ध TypeScript में Domain-Driven Design है — बिज़नेस नियम ऑब्जेक्ट के अंदर रहता है।
Entity (इकाई)
\nValue Object के विपरीत, इकाई का एक पहचानकर्ता (ID) होता है और यह समय के साथ बदल सकती है। उदाहरण: User, Order।
\n\n// entities/User.ts\nimport { Email } from '../value-objects/Email';\nimport { UserId } from '../value-objects/UserId';\n\nexport class User {\n private readonly id: UserId;\n private email: Email;\n private isActive: boolean;\n\n constructor(id: UserId, email: Email) {\n this.id = id;\n this.email = email;\n this.isActive = true;\n }\n\n public getId(): UserId {\n return this.id;\n }\n\n public changeEmail(newEmail: Email): void {\n if (!this.isActive) {\n throw new Error('निष्क्रिय उपयोगकर्ता के लिए ईमेल नहीं बदला जा सकता');\n }\n this.email = newEmail;\n }\n\n public deactivate(): void {\n this.isActive = false;\n }\n}\n\n\nAggregate (समूह)
\nAggregate, Entities और Value Objects का एक समूह है जिसे एक इकाई के रूप में संसाधित किया जाता है। इसका एक मूल (Aggregate Root) होता है जिसके माध्यम से आंतरिक ऑब्जेक्ट्स तक पहुँचा जाता है।
\n\nउदाहरण: ऑर्डर (Order)