2.2

अंग्रेज़ी में देखें

2.2 सॉफ़्टवेयर डिज़ाइन सिद्धांत

अवलोकन और प्रेरणा

सॉफ़्टवेयर डिज़ाइन सिद्धांत कोड को व्यवस्थित करने के लिए हेयुरिस्टिक हैं ताकि आप उसे समय के साथ समझ, बदल, और विस्तारित कर सकें। इनमें नामित संक्षिप्त शब्द (SOLID पांच object-oriented डिज़ाइन सिद्धांतों के लिए, DRY don’t-repeat-yourself के लिए, KISS keep-it-simple के लिए, YAGNI you-aren’t-gonna-need-it के लिए), संरचनात्मक अवधारणाएं (coupling, cohesion, separation of concerns), सूचीबद्ध design patterns, Domain-Driven Design जैसे उच्च-स्तरीय मॉडलिंग दृष्टिकोण (व्यवसाय डोमेन की भाषा में सॉफ़्टवेयर को मॉडल करना), और object-oriented, functional, और data-oriented शैलियों के बीच का चुनाव शामिल है। इनमें से कोई भी कानून नहीं हैं। ये संघनित अनुभव हैं, और आपको इन्हें निर्णय-क्षमता के साथ लागू करना होता है।

बड़ी टीमों के लिए, साझा सिद्धांतों का मूल्य समन्वय है। जब सैकड़ों इंजीनियर एक ही सिस्टम पर काम करते हैं, तो उन्हें डिज़ाइन चर्चाओं के लिए एक सामान्य शब्दावली और डिफ़ॉल्ट का एक सामान्य सेट चाहिए ताकि स्वतंत्र रूप से लिखे गए मॉड्यूल एक साथ फ़िट हो सकें। अच्छा डिज़ाइन वही है जो कई लोगों को लगातार टकराव के बिना समानांतर में एक सिस्टम बदलने देता है। यह वह भी है जो एक दशक बाद भी एक सिस्टम को बदलने योग्य बनाए रखता है, जो एंटरप्राइज़ और सरकारी सिस्टम का सामान्य जीवनकाल है, उनके मूल लेखकों के कार्यकाल से बहुत आगे।

महत्वपूर्ण कौशल सिद्धांतों को याद रखना नहीं है। यह जानना है कि हर एक आपको कब गुमराह करता है। हर सिद्धांत की एक विफलता स्थिति होती है: DRY गलत सार (abstraction) उत्पन्न कर सकता है, SOLID अनावश्यक अप्रत्यक्षता (indirection) उत्पन्न कर सकता है, YAGNI उस विस्तार-क्षमता को भूखा रख सकता है जिसकी आपको वास्तव में ज़रूरत है। यह अध्याय सिद्धांतों को प्रयोज्यता के एक डोमेन वाले टूल के रूप में मानता है, और यह coupling और cohesion पर ज़ोर देता है क्योंकि ये वे गहरे गुण हैं जिनकी सेवा करने की कोशिश ये संक्षिप्त शब्द करते हैं।

मुख्य सिद्धांत

  • पहले coupling और cohesion का प्रबंधन करें; अधिकांश नामित सिद्धांत इन दो गुणों को सुधारने के अप्रत्यक्ष तरीके हैं।
  • बदलाव के लिए अनुकूलित करें: अच्छा डिज़ाइन उन बदलावों की लागत को न्यूनतम करता है जिन्हें आपको वास्तव में करने की ज़रूरत होगी।
  • अभी काम करने वाले सबसे सरल डिज़ाइन को प्राथमिकता दें, लेकिन जहां बदलाव की संभावना हो वहां सीमाएं बनाए रखें।
  • डुप्लिकेशन गलत सार से सस्ता है; तब तक प्रतीक्षा करें जब तक पैटर्न स्पष्ट न हो।
  • डिपेंडेंसीज़ को स्पष्ट बनाएं और उन्हें स्थिर चीज़ों की ओर इंगित करें।
  • डोमेन को डोमेन की भाषा में मॉडल करें; सॉफ़्टवेयर सीमाओं को व्यावसायिक सीमाओं के साथ संरेखित करें।
  • विचारधारा नहीं, समस्या के अनुरूप पैराडाइम चुनें; अधिकांश बड़े सिस्टम व्यावहारिक रूप से मिश्रित होते हैं।

सिफारिशें

SOLID को एक चेकलिस्ट नहीं, एक लेंस के रूप में उपयोग करें

मॉड्यूल को cohesive रखने के लिए single-responsibility लागू करें, जहां एक सीमा वास्तव में मौजूद हो वहां डिपेंडेंसीज़ को सार (abstractions) की ओर इंगित करने के लिए dependency-inversion, और जहां विस्तार बिंदु वास्तविक हों वहां open-closed लागू करें। जब केवल एक ही इम्प्लीमेंटेशन हो और दूसरे का कोई नामोनिशान न हो, तब केवल संक्षिप्त शब्द को संतुष्ट करने के लिए इंटरफ़ेस, फ़ैक्टरी, और परतें न बनाएं। अप्रत्यक्षता की एक लागत होती है, और आप इसे हर बार पढ़ने पर चुकाते हैं।

DRY को ज्ञान पर लागू करें, टेक्स्ट पर नहीं

DRY ज्ञान के एक ही आधिकारिक टुकड़े को डुप्लिकेट न करने के बारे में है। यह केवल एक जैसी दिखने वाली पंक्तियों को हटाने के बारे में नहीं है। कोड के दो टुकड़े जो एक जैसे दिखते हैं लेकिन अलग-अलग कारणों से बदलते हैं, उन्हें अलग रहना चाहिए। असंबद्ध चीज़ों को जोड़ने वाले एक समय-पूर्व साझा सार की तुलना में थोड़ी सी डुप्लिकेशन को प्राथमिकता दें। एक बार जब वास्तविक पैटर्न दो या तीन बार सामने आ चुका हो तब सार निकालें।

KISS और YAGNI को अटकलों का विरोध करने दें

जो आवश्यकताएं आपके पास हैं उनके लिए बनाएं, जिनकी आप कल्पना करते हैं उनके लिए नहीं। सट्टा सामान्यीकरण (speculative generality) से बचें, जैसे कॉन्फ़िगर करने योग्य फ्रेमवर्क, प्लगइन सिस्टम, और ऐसे विस्तार बिंदु जिनकी किसी ने मांग नहीं की। संतुलन यह है कि कुछ लचीलापन वास्तव में जल्दी बनाना सस्ता होता है, जैसे एक स्थिर इंटरफ़ेस या एक स्वच्छ सीम। YAGNI सट्टा कार्यान्वयन (implementation) के खिलाफ तर्क करता है, सोच-समझकर बनाई गई सीमाओं के खिलाफ नहीं।

कम coupling और उच्च cohesion के लिए स्पष्ट रूप से डिज़ाइन करें

हर मॉड्यूल को एक अच्छी तरह परिभाषित काम करने दें (cohesion), और संकीर्ण इंटरफ़ेस के ज़रिए यथासंभव कम अन्य मॉड्यूल पर निर्भर रहें (कम coupling)। जब आप एक डिज़ाइन की समीक्षा करते हैं, पूछें कि कौन से बदलाव मॉड्यूल सीमाओं के पार लहरें भेजते हैं। वे लहरें ही coupling का असली माप हैं। Separation of concerns परतों और क्रॉस-कटिंग चिंताओं पर लागू वही विचार है।

डिज़ाइन पैटर्न को शब्दावली के रूप में उपयोग करें, एंटी-पैटर्न को चेतावनी के रूप में लागू करें

पैटर्न बार-बार आने वाले समाधानों के लिए उपयोगी साझा नाम हैं। जब समस्या वास्तव में इससे मेल खाए तब किसी एक के लिए पहुंचें। परिष्कृत दिखने के लिए पैटर्न न थोपें, क्योंकि पैटर्न-भारी कोड अक्सर अति-इंजीनियरिंग का संकेत होता है। सामान्य anti-patterns (god objects, जहां अनुपयुक्त हों वहां anaemic models, बड़ी गंदगी के गोले, distributed monoliths) को निदान लेबल के रूप में सीखें।

जहां डोमेन जटिल हो वहां Domain-Driven Design अपनाएं

समृद्ध व्यावसायिक नियमों वाले सिस्टम के लिए, DDD के सामरिक और रणनीतिक टूल का उपयोग करें: डोमेन विशेषज्ञों के साथ साझा एक सर्वव्यापी भाषा (ubiquitous language), सिस्टम को स्वतंत्र रूप से मॉडल किए गए हिस्सों में तराशने वाले bounded contexts, और यह वर्णन करने वाले context maps कि वे हिस्से कैसे संबंधित हैं। Bounded contexts एंटरप्राइज़ पैमाने पर विशेष रूप से मूल्यवान हैं, क्योंकि वे टीम स्वामित्व को मॉडल सीमाओं के साथ संरेखित करते हैं। सरल CRUD (बनाना, पढ़ना, अपडेट करना, हटाना) सिस्टम के लिए DDD अति-उपयोग है।

फ़िट के अनुसार पैराडाइम चुनें

स्टेटफुल व्यवहार को समाहित करने और डोमेन मॉडल करने के लिए object orientation का उपयोग करें। परिवर्तन, समवर्तीता (concurrency), और immutability के ज़रिए पूर्वानुमेयता के लिए functional शैली का उपयोग करें। जहां प्रदर्शन और कैश व्यवहार हावी हों वहां data-oriented design का उपयोग करें। बड़े सिस्टम तीनों को मिलाते हैं। यह चुनाव प्रति घटक करें, और शैलियों के बीच सीमाओं को स्वच्छ रखें।

समझौते: फ़ायदे और नुकसान

सिद्धांत / दृष्टिकोणअच्छी तरह लागू करने परविफलता स्थिति
SOLIDबदलाव होने पर स्पष्ट सीम; टेस्ट करने योग्य यूनिटइंटरफ़ेस और परत का प्रसार; बिना किसी लाभ के अप्रत्यक्षता
DRYवास्तविक ज्ञान के लिए सत्य का एक ही स्रोतअसंबद्ध कोड को जोड़ने वाला गलत सार
KISS / YAGNIदुबले, समझने योग्य सिस्टमकम-डिज़ाइन की गई सीम; आवश्यक लचीलेपन का महंगा बाद में जोड़ना
डिज़ाइन पैटर्नसाझा शब्दावली; सिद्ध संरचनाएंपैटर्न कार्गो-कल्टिंग; आकस्मिक जटिलता
Domain-Driven Designसंरेखित मॉडल और टीमें; नियंत्रित जटिलतासरल डोमेन पर भारी समारोह; गलत जगह के context सीमाएं
Functional / immutableपूर्वानुमेयता; सुरक्षित समवर्तीतास्वाभाविक रूप से स्टेटफुल समस्याओं के लिए अजीब फ़िट; प्रदर्शन आश्चर्य

बार-बार आने वाला तनाव कम-डिज़ाइन और अति-डिज़ाइन के बीच है। कम-डिज़ाइन किए गए सिस्टम coupling जमा करते हैं और कठोर बन जाते हैं। अति-डिज़ाइन किए गए सिस्टम ऐसे सार में डूब जाते हैं जिसे किसी को समझना और बनाए रखना पड़ता है। जवाब कोई निश्चित बिंदु नहीं है। यह एक अनुशासन है: जब तक आपके पास पर्याप्त जानकारी न हो निर्णयों को टालें, साथ ही उन सीमों को बनाए रखें जो आपको अपना मन बदलने देती हैं।

अपनी टीम के साथ चर्चा करने के लिए सवाल

  1. एक साझा सार निकालने के लिए आपकी ठोस सीमा क्या है, और आप DRY को गलत सार उत्पन्न करने से कैसे रोकते हैं? यह अध्याय स्पष्ट रूप से कहता है कि डुप्लिकेशन गलत सार से सस्ता है, और यह कि सार निकालने से पहले आपको तब तक प्रतीक्षा करनी चाहिए जब तक पैटर्न दो या तीन बार सामने न आ जाए। एक बड़ी टीम पर खतरा यह है कि कोई व्यक्ति टीम सीमाओं के पार दो एक जैसे दिखने वाले स्निपेट को एक साझा मॉड्यूल में बदल देता है, फिर एक कॉलर में भविष्य का हर बदलाव दूसरे में लहर भेजता है। लाने लायक संकेत यह है कि क्या डुप्लिकेट एक ही कारण से बदलते हैं या अभी केवल एक जैसे दिखते हैं। तीन का एक नियम तय करें, और मांग करें कि कॉलर को जोड़ने से पहले एक उम्मीदवार सार वास्तव में एक साथ बदला हो। वह अकेला समझौता उस प्रकार के coupling को रोकता है जिसे एक बार कई टीमें उस पर निर्भर हो जाएं तो खोलना महंगा होता है।

  2. आप coupling और cohesion को डिज़ाइन समीक्षा में गट फ़ील पर छोड़ने के बजाय दिखाई कैसे बनाते हैं? मुख्य सिद्धांत coupling और cohesion को हर संक्षिप्त शब्द से ऊपर रखते हैं, और coupling को उन बदलावों के रूप में परिभाषित करते हैं जो मॉड्यूल सीमाओं के पार लहरें भेजते हैं। सहज ज्ञान सैकड़ों इंजीनियरों में स्केल नहीं करता जिनमें से हर एक सिस्टम के केवल अपने कोने को देखता है। ऐसा प्रमाण लाएं जो एक मशीन उत्पन्न कर सके: डिपेंडेंसी ग्राफ़, और co-change डेटा जो दिखाता है कि कौन से मॉड्यूल एक ही कमिट में एक साथ संपादित होते रहते हैं। एक स्पष्ट समीक्षा सवाल जोड़ें जो पूछे कि कोई बदलाव किन मॉड्यूल सीमाओं को पार करने के लिए मजबूर करता है। जब दो मॉड्यूल हमेशा एक साथ बदलते हैं, वह आपके लिए उन्हें मर्ज करने या उनके बीच की सीमा को ठीक करने का संकेत है।

  3. आपके सिस्टम में एक ऐसे डोमेन के बीच रेखा कहां है जो Domain-Driven Design को उचित ठहराने के लिए पर्याप्त समृद्ध है और एक सादे CRUD ऐप के बीच जहां यह अति-उपयोग है? यह अध्याय DDD के bounded contexts की सिफारिश ठीक इसलिए करता है क्योंकि वे टीम स्वामित्व को मॉडल सीमाओं के साथ संरेखित करते हैं, और चेतावनी देता है कि सरल create-read-update-delete सिस्टम के लिए DDD अति-उपयोग है और बिना वास्तविक मॉडलिंग के एक समारोह में बदल जाता है। इसे किसी भी दिशा में गलत करना महंगा है: एक पतले डोमेन पर भारी DDD एक सरल ऐप को समारोह में दफ़न कर देता है, जबकि कई टीमों में फैला एक साझा मॉडल निरंतर क्रॉस-टीम समन्वय को मजबूर करता है। वे संकेत लाएं जो वास्तव में इसे तय करते हैं: व्यावसायिक नियमों का घनत्व, और कितनी टीमों को स्वतंत्र रूप से हिस्सों का स्वामित्व लेने की ज़रूरत है। रणनीतिक मशीनरी को जटिल कोर के लिए सुरक्षित रखें, और सरल किनारों को सरल रहने दें। यह आपको DDD थिएटर और बड़ी गंदगी के गोले दोनों से दूर रखता है।

  4. एक सार, इंटरफ़ेस, या डिज़ाइन पैटर्न कब उस अप्रत्यक्षता के लायक होता है जो यह जोड़ता है, और किसे एक डिज़ाइन को अति-इंजीनियर्ड कहने का अधिकार है? यह अध्याय स्पष्ट है कि अप्रत्यक्षता की एक लागत है जो आप हर बार पढ़ने पर चुकाते हैं, और यह कि SOLID को संतुष्ट करने या परिष्कृत दिखने के लिए इंटरफ़ेस, फ़ैक्टरी, और परतें बनाना एक विफलता स्थिति है। एक बड़ी टीम पर दबाव उल्टी दिशा में चलता है: समीक्षक अतिरिक्त सार को इसलिए पास कर देते हैं क्योंकि यह अनुशासित दिखता है, और कोई भी कम संरचना के लिए बहस करने वाला व्यक्ति नहीं बनना चाहता। प्रतिस्पर्धी विचार वास्तविक है, क्योंकि कुछ सीम वास्तव में अपनी कीमत कमाती हैं और उन्हें बाद में हटाना महंगा होता है। चर्चा में ठोस प्रमाण लाएं: आज वास्तव में एक इंटरफ़ेस के कितने इम्प्लीमेंटेशन हैं, विस्तार बिंदु कितनी बार लचीला हुआ है, और एक पाठक को एक कोड पथ का पालन करने के लिए कितनी फ़ाइलें खोलनी पड़ती हैं। सहमत हों कि बिना दूसरे के नामोनिशान वाला एक अकेला इम्प्लीमेंटेशन इनलाइन करने का एक डिफ़ॉल्ट कारण है, और नाम दें कि कौन बिना अपमान लगे एक डिज़ाइन को अति-इंजीनियर्ड कह सकता है। एंटरप्राइज़ और सरकारी सिस्टम में जो अपने लेखकों से एक दशक आगे जीते हैं, अनावश्यक अप्रत्यक्षता हर भविष्य के अनुरक्षक द्वारा चुकाया जाने वाला कर है, इसलिए “यह सार हमें क्या देता है” को एक व्यक्तिगत चुनौती के बजाय एक स्थायी समीक्षा सवाल मानें।

  5. आप कैसे तय करते हैं कि हर घटक कौन सा पैराडाइम उपयोग करता है, object-oriented, functional, या data-oriented, और आप उनके बीच की सीमाओं को स्वच्छ कैसे रखते हैं? यह अध्याय तर्क देता है कि बड़े सिस्टम व्यावहारिक रूप से मिश्रित होते हैं और आपको फ़िट के अनुसार प्रति घटक चुनना चाहिए, स्टेटफुल डोमेन के लिए object orientation, परिवर्तन और समवर्तीता के लिए functional शैली, और जहां प्रदर्शन और कैश व्यवहार हावी हों वहां data-oriented design का उपयोग करते हुए। अप्रबंधित छोड़ दिए जाने पर, पैराडाइम चुनाव इस बात का मामला बन जाता है कि मॉड्यूल पहले किसने लिखा, और परिवर्तनशील स्थिति उसमें रिस जाती है जो शुद्ध परिवर्तन होना चाहिए, या एक functional शुद्धतावाद एक स्वाभाविक रूप से स्टेटफुल समस्या से लड़ता है। लाने लायक प्रमाण यह है कि आपकी वास्तविक पीड़ा कहां है: कौन से घटक छुपी हुई स्थिति के कारण टेस्ट करना कठिन हैं, कौन से हॉट पाथ कैश-बाउंड हैं, और वर्तमान शैली कहां अजीब वर्कअराउंड मजबूर करती है। हर परत के लिए डिफ़ॉल्ट पैराडाइम को जानबूझकर तय करें और लिख लें कि शैलियों के बीच सीम कहां गिरती हैं, ताकि एक functional कोर और एक अनिवार्य (imperative) किनारा एक-दूसरे में न घुसें। एक विनियमित या सरकारी सिस्टम के लिए जहां एक गणना को किसी दी गई अवधि के लिए ऑडिट करने योग्य और पुनरुत्पादनीय होना चाहिए, एक अपरिवर्तनीय, functional कोर अक्सर एक पसंद के बजाय एक अनुपालन आवश्यकता होती है, और उस बाधा को सीमा का पालन करने के बजाय उसे संचालित करना चाहिए।

  6. आप इन सिद्धांतों को हठधर्मिता में कठोर होने से कैसे रोकते हैं, और आप एक डिज़ाइन निर्णय के पीछे के तर्क को कहां दर्ज करते हैं ताकि भविष्य की एक टीम उसे फिर से देख सके? इस अध्याय के हर सिद्धांत की प्रयोज्यता का एक डोमेन और एक विफलता स्थिति है, और पूरी फ़्रेमिंग इन्हें लागू किए जाने वाले कानूनों के बजाय निर्णय-क्षमता के साथ लागू किए जाने वाले टूल के रूप में मानती है। एक बड़ी टीम पर एक सिद्धांत चुपचाप एक नियम बन जाता है: DRY किसी भी डुप्लिकेशन को मना करता है, SOLID प्रति क्लास एक इंटरफ़ेस अनिवार्य करता है, और व्यावहारिक अपवादों को समीक्षा में उन लोगों द्वारा रोक दिया जाता है जो परिणाम के बजाय संक्षिप्त शब्द का हवाला देते हैं। तनाव यह है कि कुछ स्थिरता वास्तव में सैकड़ों इंजीनियरों को समन्वय करने में मदद करती है, इसलिए आप हर सिद्धांत को केवल वैकल्पिक घोषित नहीं कर सकते। उदाहरण लाएं जहां किसी सिद्धांत को अक्षरशः पालन करने से एक बदतर डिज़ाइन उत्पन्न हुआ, और वे निर्णय रिकॉर्ड लाएं, यदि कोई हों, जो बताते हैं कि एक दी गई सीमा या सार क्यों मौजूद है। सहमत हों कि सिद्धांत डिफ़ॉल्ट हैं जिनसे एक इंजीनियर एक दर्ज कारण के साथ विचलित हो सकता है, और परिणामी डिज़ाइन चुनावों को एक छोटे आर्किटेक्चर निर्णय रिकॉर्ड में कैद करें ताकि अगली टीम केवल कोड ही नहीं बल्कि तर्क भी विरासत में पाए। एंटरप्राइज़ और सार्वजनिक-क्षेत्र के सिस्टम में, जहां मूल लेखक बहुत पहले जा चुके होते हैं और ऑडिट पूछते हैं कि सिस्टम इस तरह क्यों आकार लिया गया, वह लिखित पगडंडी ही अंतर है एक ऐसे डिज़ाइन के बीच जिसे भविष्य की टीमें सुरक्षित रूप से बदल सकती हैं और एक ऐसे के बीच जिसे छूने से वे डरती हैं।

क्षेत्र लेंस

स्टार्टअप। शिप होने वाले सबसे सरल डिज़ाइन को प्राथमिकता दें और एक अच्छी तरह से बनाए गए मॉड्यूल को तब तक रखें जब तक एक वास्तविक दूसरा उपयोग मामला एक सीम मजबूर न करे। आपका सबसे दुर्लभ संसाधन इंजीनियरिंग ध्यान है, इसलिए समय-पूर्व इंटरफ़ेस, परतें, और सट्टा फ्रेमवर्क शुद्ध लागत हैं। किसी भी साझा सार को निकालने से पहले तीन के नियम का पालन करें, और YAGNI को उन विस्तार बिंदुओं को मार डालने दें जिनकी किसी ने अभी तक मांग नहीं की।

लघु व्यवसाय। बिना किसी समर्पित आर्किटेक्ट और सीमित बजट के, अपने खुद के पैटर्न बनाने के बजाय उन फ्रेमवर्क और लाइब्रेरी में पहले से बने डिज़ाइन पर निर्भर रहें जो आप खरीदते हैं। कस्टम डिज़ाइन प्रयास को उन मुट्ठी भर नियमों के लिए सुरक्षित रखें जो वास्तव में आपका व्यवसाय हैं, और बाकी सब कुछ पारंपरिक रखें ताकि एक ठेकेदार या एक नया कर्मचारी इसे पढ़ सके। थोड़ी सी डुप्लिकेशन जिसे आप समझते हैं वह एक चतुर सार से बेहतर है जिसे केवल उसका लेखक बनाए रख सकता है।

एंटरप्राइज़। साझा सिद्धांतों का लाभ कई टीमों में समन्वय है: डिज़ाइन समीक्षा के लिए एक सामान्य शब्दावली, और bounded contexts जो मॉडल सीमाओं को टीम स्वामित्व के साथ संरेखित करते हैं ताकि समूह स्वतंत्र रूप से विकसित हो सकें। डिपेंडेंसी और co-change डेटा के साथ coupling और cohesion का स्पष्ट रूप से प्रबंधन करें, और परिणामी डिज़ाइन निर्णयों को दर्ज करें ताकि सिस्टम उनके लेखकों के आगे बढ़ने के बहुत बाद भी बदलने योग्य रहें। टीमों को जोड़ने वाले गलत सार और हर पाठक पर कर लगाने वाली अति-इंजीनियरिंग दोनों से समान रूप से रक्षा करें।

सरकार। ऑडिटेबिलिटी और पुनरुत्पादनीयता अक्सर डिज़ाइन तय करती हैं। एक अपरिवर्तनीय, functional कोर आपको किसी दी गई अवधि के लिए एक ऐतिहासिक गणना को बिल्कुल उसी तरह पुनरुत्पादित करने देता है, जिसकी छुपी हुई परिवर्तनशील स्थिति वाला एक उलझा हुआ object ग्राफ़ गारंटी नहीं दे सकता। context सीमाओं पर साझा तालिकाओं के बजाय स्पष्ट प्रकाशित अनुबंधों को प्राथमिकता दें, और डिज़ाइन व उसके निर्णय रिकॉर्ड को ऑडिटर और उस टीम दोनों के लिए स्पष्ट रखें जो एक दशक बाद सिस्टम विरासत में पाती है।

उदाहरण

स्टार्टअप। अपना पहला उत्पाद बना रहा एक तीन-इंजीनियर स्टार्टअप हर फ़ीचर को इंटरफ़ेस और फ़ैक्टरी की परतों में विभाजित करने के आग्रह का विरोध करता है, एक वास्तविक दूसरा उपयोग मामला सामने आने तक एक अच्छी तरह बनाए गए मॉड्यूल को बनाए रखता है। जब साइनअप और बिलिंग प्रवाह में वही लॉजिक तीसरी बार दिखाई देता है, वे एक सट्टा फ्रेमवर्क के बजाय एक छोटा साझा फ़ंक्शन निकालते हैं। यह कोडबेस को इतना छोटा रखता है कि उनमें से कोई भी इसे अपने दिमाग में रख सकता है, और जो कुछ सीम वे खींचते हैं वे वहां गिरती हैं जहां उत्पाद के बदलने की सबसे अधिक संभावना है।

एंटरप्राइज़। एक बड़ा बीमा प्लेटफ़ॉर्म पॉलिसी, दावे, और बिलिंग को अलग-अलग bounded contexts के रूप में मॉडल करता है, हर एक का स्वामित्व अपने खुद के डेटा मॉडल और सेवा सीमा वाली एक समर्पित टीम के पास होता है। जहां contexts मिलते हैं, जैसे जब एक दावा एक पॉलिसी को संदर्भित करता है, वे साझा डेटाबेस तालिकाओं के बजाय स्पष्ट प्रकाशित अनुबंधों के ज़रिए बात करते हैं। यह तीनों टीमों को स्वतंत्र रूप से विकसित होने देता है, और सर्वव्यापी भाषा underwriters और actuaries के साथ बातचीत को सटीक रखती है। पहले के एक संस्करण ने एक ही फैले हुए मॉडल को साझा किया था, और हर बदलाव के लिए क्रॉस-टीम समन्वय की आवश्यकता थी।

सरकार। एक राष्ट्रीय कर-प्रोसेसिंग सिस्टम जानबूझकर अपने गणना इंजन के लिए एक data-oriented, functional कोर को प्राथमिकता देता है। कर नियमों को अपरिवर्तनीय इनपुट रिकॉर्ड पर शुद्ध परिवर्तनों के रूप में व्यक्त किया जाता है, जो उन्हें किसी दिए गए कर वर्ष के लिए ऑडिट करने योग्य, टेस्ट करने योग्य, और पुनरुत्पादनीय बनाता है। अनिवार्य (imperative), स्टेटफुल हिस्सों (वर्कफ़्लो, सूचनाएं) को किनारों पर रखा जाता है। ऑडिटर एक विशिष्ट नियम संस्करण की ओर इशारा कर सकते हैं और किसी भी ऐतिहासिक गणना को बिल्कुल पुनरुत्पादित कर सकते हैं, जो एक कानूनी आवश्यकता है जिसकी छुपी हुई परिवर्तनशील स्थिति वाला एक उलझा हुआ object ग्राफ़ गारंटी नहीं दे सकता था।

व्यावसायिक मामला: प्रेरणाएं, ROI, और TCO

डिज़ाइन गुणवत्ता एक सिस्टम की बदलने-योग्यता (changeability) में एक निवेश है, और बदलने-योग्यता कुल स्वामित्व लागत पर हावी रहती है। एक सिस्टम की अधिकांश लागत उसकी पहली रिलीज़ के बाद, संशोधन और विस्तार में आती है। अच्छी तरह डिज़ाइन किए गए सिस्टम समय के साथ बदलाव की लागत को लगभग स्थिर रखते हैं। खराब डिज़ाइन किए गए सिस्टम में हर बदलाव की लागत तब तक बढ़ती है जब तक सिस्टम प्रभावी रूप से संशोधित करने योग्य नहीं रह जाता और उसे फिर से लिखना पड़ता है, जो सबसे महंगा परिणाम है।

अपनाने की लागत मुख्य रूप से कौशल और समीक्षा अनुशासन है: सिद्धांत सिखाना, और पहले से डिज़ाइन समय खर्च करना। इन्हें न अपनाने की लागत है technical debt का धीमा निर्माण, गिरती डिलीवरी वेलोसिटी, बढ़ती दोष दर, और अंततः महंगी पुनर्लेखन। नेतृत्व के सामने मामला रखने के लिए, डिज़ाइन अनुशासन को डिलीवरी पूर्वानुमेयता से और पुनर्लेखन कार्यक्रमों से बचने से जोड़ें, और बदलाव-विफलता दर और समय के साथ तुलनीय फ़ीचर लागू करने में लगने वाले समय जैसे अग्रणी संकेतकों को ट्रैक करें। विपरीत विफलता पर भी नज़र रखें: अनिश्चित भविष्य के लिए डिज़ाइन में अति-निवेश करना भी मूल्य नष्ट करता है। इसलिए तर्क उपयुक्त डिज़ाइन के लिए है, जो भविष्य के बदलाव की संभावना और लागत के अनुसार तय किया गया हो।

एंटी-पैटर्न और नुकसान

  • सट्टा सामान्यीकरण (Speculative generality): ऐसी काल्पनिक आवश्यकताओं के लिए विस्तार-क्षमता बनाना जो कभी नहीं आतीं।
  • गलत सार: DRY को संतुष्ट करने के लिए असंबद्ध कोड को जबरन एक साथ रखना, जो डुप्लिकेशन से बदतर coupling बनाता है।
  • पैटर्न कार्गो-कल्टिंग: केवल उनके अपने लिए डिज़ाइन पैटर्न लागू करना, बिना किसी लाभ के अप्रत्यक्षता जोड़ना।
  • Anaemic या god objects: ऐसे मॉडल जिनमें कोई व्यवहार नहीं, या ऐसे objects जो सब कुछ करते हैं; दोनों गलत जगह रखी गई ज़िम्मेदारियों का संकेत देते हैं।
  • Distributed monolith: सेवाएं भौतिक रूप से विभाजित लेकिन फिर भी कसकर जुड़ी हुई, दोनों दृष्टिकोणों की लागतों को जोड़ते हुए।
  • बड़ी गंदगी का गोला (Big ball of mud): कोई पहचानने योग्य संरचना नहीं; हर बदलाव सब कुछ जोखिम में डालता है।
  • DDD थिएटर: उस डोमेन मॉडलिंग के बिना शब्दावली और फ़ोल्डर संरचना को अपनाना जो इसे मूल्य देती है।

परिपक्वता मॉडल

  • स्तर 1, आरंभ करें: डिज़ाइन तदर्थ और प्रतिक्रियाशील है; coupling बिना जांचे जमा होता है; सिद्धांत अज्ञात हैं या नारों के रूप में लागू किए जाते हैं, और सार व्यक्तिगत आदत से प्रकट या गायब होते हैं।
  • स्तर 2, विकसित करें: टीमें सिद्धांत जानती हैं और उन्हें लागू करती हैं, लेकिन असंगत रूप से और अक्सर हठधर्मिता से; कुछ समूह जानबूझकर coupling और cohesion का प्रबंधन करते हैं जबकि अन्य नहीं करते, और संगठन में कोई साझा शब्दावली नहीं है।
  • स्तर 3, मानकीकृत करें: एक साझा डिज़ाइन शब्दावली, सार निकालने के लिए तीन का नियम, coupling और cohesion विश्लेषण, और टीमों के अनुरूप bounded contexts पूरे संगठन में दस्तावेज़ीकृत और अपेक्षित हैं, व्यक्तिगत पसंद के बजाय डिज़ाइन समीक्षा में लगातार लागू किए जाते हैं।
  • स्तर 4, प्रबंधित करें: डिज़ाइन स्वास्थ्य को बेसलाइन के मुकाबले मापा जाता है: coupling और co-change डेटा, बदलाव-विफलता दर, और तुलनीय फ़ीचर लागू करने में लगने वाला समय समय के साथ ट्रैक किया जाता है, ताकि सार और सीमाएं प्रमाण के आधार पर जोड़ी, रखी, या हटाई जाएं, और अति-इंजीनियरिंग व गलत सार राय के बजाय डेटा द्वारा पकड़े जाएं।
  • स्तर 5, समन्वयित करें: डिज़ाइन अनुशासन पूरे संगठन में डिलीवरी और जोखिम योजना के साथ एकीकृत है; सिद्धांत बारीकी और ज्ञात विफलता स्थितियों के साथ लागू किए जाते हैं; पैराडाइम और सीमा चुनाव जानबूझकर किए जाते हैं और लगातार पुनर्विचारित होते हैं, और संगठन नियमित रूप से डोमेन और प्रमाण बदलने पर सार को रीफ़ैक्टर, पुनः-दायरा, और सेवानिवृत्त करता है।

चर्चा के लिए विचार

  • भविष्य की आवश्यकता होने से पहले आप एक आवश्यक सीम और सट्टा सामान्यीकरण के बीच का अंतर कैसे बताते हैं?
  • DRY ने कब आपकी टीम को गलत सार तक पहुंचाया, और आपने इसे कैसे पहचाना?
  • bounded-context सीमाएं कहां गिरनी चाहिए, और उन्हें org chart को कितनी बारीकी से प्रतिबिंबित करना चाहिए?
  • आपके संदर्भ में कोड से पहले कितना डिज़ाइन होना चाहिए, और आप निर्णयों को कैसे दर्ज करते हैं?
  • आपके सिस्टम के कौन से हिस्से एक अधिक functional या data-oriented शैली से लाभान्वित होंगे?
  • आप डिज़ाइन सिद्धांतों को ऐसी हठधर्मिता में कठोर होने से कैसे रोकते हैं जो व्यावहारिक अपवादों का विरोध करती है?

मुख्य निष्कर्ष

  • Coupling और cohesion वे गुण हैं जो मायने रखते हैं; संक्षिप्त शब्द उन लक्ष्यों तक पहुंचने के साधन हैं।
  • हर सिद्धांत की एक विफलता स्थिति होती है; जानें कि हर एक कब गुमराह करता है।
  • एक समय-पूर्व या गलत सार की तुलना में थोड़ी सी डुप्लिकेशन को प्राथमिकता दें।
  • जटिल डोमेन को टीम स्वामित्व के साथ संरेखित करने के लिए DDD और bounded contexts का उपयोग करें।
  • फ़िट के अनुसार पैराडाइम चुनें; बड़े सिस्टम व्यावहारिक रूप से मिश्रित होते हैं।
  • उन बदलावों के लिए डिज़ाइन करें जिनकी आपको वास्तव में ज़रूरत होगी, कम-डिज़ाइन और अति-डिज़ाइन दोनों से बचते हुए।

संदर्भ और आगे पढ़ने के लिए

  • Robert C. Martin, Clean Architecture and Agile Software Development, Principles, Patterns, and Practices
  • Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software
  • Vaughn Vernon, Implementing Domain-Driven Design
  • Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software
  • Martin Fowler, Refactoring: Improving the Design of Existing Code and Patterns of Enterprise Application Architecture
  • David L. Parnas, On the Criteria to Be Used in Decomposing Systems into Modules
  • Sandi Metz, Practical Object-Oriented Design