DDD उबाऊ आरेखों के बारे में नहीं, बल्कि जीवंत आर्किटेक्चर के बारे में क्यों है
\nजब C++ में कोई प्रोजेक्ट "खिलौना" एप्लिकेशन के आकार से आगे बढ़ जाता है, तो डेवलपर्स अक्सर अराजकता का सामना करते हैं: व्यावसायिक तर्क नियंत्रकों में बिखरा हुआ होता है, डेटाबेस क्लास संरचना निर्धारित करता है, और नए लोग लीगेसी कोड को छूने से डरते हैं। Domain-Driven Design (DDD) अमूर्त नियमों का एक सेट नहीं है, बल्कि एक व्यावहारिक उपकरण है जो जटिलता को नियंत्रित करने में मदद करता है। इस लेख में, हम विशिष्ट कोड उदाहरणों का उपयोग करके C++ में DDD को लागू करने का तरीका समझेंगे, और यह आपके प्रोजेक्ट को "गंदगी के बड़े ढेर" से क्यों बचाएगा।
\n\nDDD क्या है और C++ डेवलपर को इसकी आवश्यकता क्यों है?
\nDomain-Driven Design (डोमेन-ओरिएंटेड डिज़ाइन) एक दृष्टिकोण है जहाँ मुख्य ध्यान तकनीकी विवरणों के बजाय डोमेन मॉडल पर दिया जाता है। C++ में यह विशेष रूप से प्रासंगिक है: भाषा शक्तिशाली उपकरण (टेम्पलेट, RAII, स्मार्ट पॉइंटर्स) प्रदान करती है, लेकिन सही आर्किटेक्चर के बिना, प्रोजेक्ट एक मोनोलिथ में बदल जाता है जहाँ एक फीचर में बदलाव सब कुछ तोड़ देता है।
\nDDD दो स्तर प्रदान करता है:
\n- \n
- रणनीतिक मॉडलिंग: सिस्टम को संदर्भों (Bounded Contexts) में विभाजित करना और उनकी बातचीत को कॉन्फ़िगर करना। \n
- सामरिक मॉडलिंग: बिल्डिंग ब्लॉक्स — Entity, Value Object, Aggregate, Repository, Domain Service। \n
हम सामरिक मॉडलिंग पर ध्यान केंद्रित करेंगे, क्योंकि यह C++ कोड के लिए विशिष्ट पैटर्न प्रदान करता है।
\n\nस्तरित आर्किटेक्चर: C++ में DDD की नींव
\nDDD स्तरों में स्पष्ट विभाजन मानता है। C++ प्रोजेक्ट के लिए विशिष्ट संरचना इस प्रकार है:
\n- \n
- Domain Layer (कोर): संस्थाएँ, value object, एग्रीगेट, डोमेन सेवाएँ। फ्रेमवर्क या बाहरी लाइब्रेरी पर कोई निर्भरता नहीं। \n
- Application Layer: उपयोग के मामले (use cases), ऑर्केस्ट्रेशन। केवल Domain पर निर्भर करता है। \n
- Infrastructure Layer: रिपॉजिटरी का कार्यान्वयन (SQL, Redis, फ़ाइलें), बाहरी API के साथ काम करना। Domain से इंटरफ़ेस लागू करता है। \n
- Presentation Layer: उपयोगकर्ता इंटरफ़ेस (कंसोल, REST API, GUI)। \n
यह कोई कठोर नियम नहीं है, बल्कि एक सिफारिश है। मुख्य बात यह है कि निर्भरताएँ अंदर की ओर निर्देशित होती हैं: बाहरी स्तर आंतरिक स्तरों पर निर्भर हो सकते हैं, लेकिन इसके विपरीत नहीं।
\n\nउदाहरण: कैसे न करें
\n// ❌ बुरा: व्यावसायिक तर्क SQL के साथ मिश्रित है\nclass UserController {\n void createUser(const std::string& name) {\n // SQL क्वेरी यहीं\n db.execute("INSERT INTO users (name) VALUES (?)", name);\n // जाँच का तर्क भी यहीं\n if (name.empty()) throw std::runtime_error("Name required");\n }\n};\n\n\nउदाहरण: DDD शैली
\n// ✅ अच्छा: स्पष्ट विभाजन\nclass User : public Entity<User, int> {\n std::string name_;\npublic:\n explicit User(int id, std::string name) : Entity(id), name_(std::move(name)) {\n if (name_.empty()) throw std::invalid_argument("User name cannot be empty");\n }\n const std::string& name() const { return name_; }\n};\n\n// रिपॉजिटरी इंटरफ़ेस (Domain)\nclass IUserRepository {\npublic:\n virtual ~IUserRepository() = default;\n virtual void save(const User& user) = 0;\n};\n\n// कार्यान्वयन (Infrastructure)\nclass SqlUserRepository : public IUserRepository {\n void save(const User& user) override {\n // केवल SQL, कोई व्यावसायिक तर्क नहीं\n }\n};\n\n\nC++ पर DDD के बिल्डिंग ब्लॉक्स
\n\nEntity (संस्था)
\nयह एक अद्वितीय पहचानकर्ता वाली वस्तु है जो समय के साथ बनी रहती है। C++ में एक बेस टेम्पलेट क्लास बनाना सुविधाजनक है:
\ntemplate<typename T, typename IdType>\nclass Entity {\n IdType id_;\npublic:\n explicit Entity(IdType id) : id_(std::move(id)) {}\n IdType id() const { return id_; }\n bool operator==(const Entity& other) const { return id_ == other.id_; }\n