सभी सॉफ्टवेयर एप्लिकेशन समय के साथ बदलते हैं। सॉफ़्टवेयर में किए गए परिवर्तन अनपेक्षित कैस्केडिंग समस्याओं का कारण बन सकते हैं। हालाँकि, परिवर्तन अपरिहार्य है, क्योंकि हम ऐसे सॉफ़्टवेयर का निर्माण नहीं कर सकते हैं जो नहीं बदलता है। जैसे-जैसे सॉफ्टवेयर बढ़ता है, सॉफ्टवेयर की आवश्यकताएं बदलती रहती हैं। हम क्या कर सकते हैं डिजाइन सॉफ्टवेयर इस तरह से कि यह बदलने के लिए लचीला है। सॉफ्टवेयर को ठीक से डिजाइन करने में शुरुआत में समय और मेहनत लग सकती है, लेकिन लंबी अवधि में, यह समय और प्रयास को बचाता है। कसकर युग्मित सॉफ़्टवेयर नाजुक होता है, और हम यह अनुमान नहीं लगा सकते कि परिवर्तन के साथ क्या होता है। यहाँ खराब डिज़ाइन किए गए सॉफ़्टवेयर के कुछ प्रभाव दिए गए हैं:
- यह गतिहीनता का कारण बनता है।
- कोड बदलना महंगा है।
- सॉफ़्टवेयर को सरल बनाने की तुलना में अधिक जटिलता जोड़ना आसान है।
- कोड अप्रबंधनीय है।
- डेवलपर को यह पता लगाने में बहुत समय लगता है कि इसकी कार्यक्षमता कैसे काम करती है।
- सॉफ़्टवेयर के एक हिस्से को बदलने से आमतौर पर दूसरा भाग टूट जाता है, और हम यह अनुमान नहीं लगा सकते कि कोई परिवर्तन किन समस्याओं को ला सकता है।
पेपर डिज़ाइन सिद्धांत और डिज़ाइन पैटर्न, सड़ने वाले सॉफ़्टवेयर के निम्नलिखित लक्षणों को सूचीबद्ध करता है:
- कठोरता:समस्या पैदा किए बिना कोड बदलना बहुत मुश्किल है, क्योंकि एक भाग में परिवर्तन करने से कोड के अन्य भागों में परिवर्तन करने की आवश्यकता होती है।
- नाजुकता:कोड बदलने से आमतौर पर सॉफ़्टवेयर का व्यवहार टूट जाता है। यह उन हिस्सों को भी तोड़ सकता है जो सीधे परिवर्तन से संबंधित नहीं हैं।
- स्थिरता:हालांकि सॉफ़्टवेयर एप्लिकेशन के कुछ हिस्सों में समान व्यवहार हो सकता है, हम कोड का पुन:उपयोग करने में असमर्थ हैं और उन्हें डुप्लिकेट करना होगा।
- चिपचिपापन:जब सॉफ़्टवेयर को बदलना मुश्किल होता है, तो हम सॉफ़्टवेयर को बेहतर बनाने के बजाय उसमें जटिलता जोड़ते रहते हैं।
सॉफ़्टवेयर को इस तरह डिज़ाइन करना आवश्यक है कि परिवर्तनों को नियंत्रित और अनुमानित किया जा सके।
सॉलिड डिजाइन सिद्धांत सॉफ्टवेयर प्रोग्राम को अलग करके इन मुद्दों को हल करने में मदद करते हैं। रॉबर्ट सी. मार्टिन ने इन अवधारणाओं को अपने पेपर में डिज़ाइन प्रिंसिपल्स एंड डिज़ाइन पैटर्न्स शीर्षक से पेश किया, और माइकल फेदर्स ने बाद में परिवर्णी शब्द का आविष्कार किया।
सॉलिड डिजाइन सिद्धांत में ये पांच सिद्धांत शामिल हैं:
- एस जिम्मेदारी का सिद्धांत
- ओ कलम/बंद सिद्धांत
- एल iskov प्रतिस्थापन सिद्धांत
- मैं इंटरफ़ेस अलगाव सिद्धांत
- डी एपेंडेंसी उलटा सिद्धांत
हम उनमें से प्रत्येक को यह समझने के लिए खोजेंगे कि ये सिद्धांत रूबी में अच्छी तरह से डिज़ाइन किए गए सॉफ़्टवेयर के निर्माण में कैसे मदद कर सकते हैं।
एकल उत्तरदायित्व सिद्धांत - SRP
मान लें कि मानव संसाधन प्रबंधन सॉफ्टवेयर के लिए, हमें उपयोगकर्ता बनाने, एक कर्मचारी का वेतन जोड़ने और एक कर्मचारी की वेतन पर्ची बनाने के लिए कार्यक्षमता की आवश्यकता है। इसे बनाते समय, हम इन कार्यात्मकताओं को एक वर्ग में जोड़ सकते हैं, लेकिन यह दृष्टिकोण इन कार्यात्मकताओं के बीच अवांछित निर्भरता का कारण बनता है। जब हम शुरू करते हैं तो यह आसान होता है, लेकिन जब चीजें बदलती हैं और नई आवश्यकताएं उत्पन्न होती हैं, तो हम यह अनुमान लगाने में असमर्थ होंगे कि कौन सी कार्यक्षमता परिवर्तन को तोड़ देगी।
<ब्लॉकक्वॉट>एक वर्ग के पास बदलने का एक और केवल एक कारण होना चाहिए - रॉबर्ट सी मार्टिन
यहां एक नमूना कोड है जहां सभी कार्यक्षमता एक ही वर्ग में है:
class User
def initialize(employee, month)
@employee = employee
@month = month
end
def generate_payslip
# Code to read from database,
# generate payslip
# and write it to a file
self.send_email
end
def send_email
# code to send email
employee.email
month
end
end
एक पेस्लिप जेनरेट करने और उसे यूजर को भेजने के लिए, हम क्लास को इनिशियलाइज़ कर सकते हैं और जनरेट पेस्लिप मेथड को कॉल कर सकते हैं:
month = 11
user = User.new(employee, month)
user.generate_payslip
अब, एक नई आवश्यकता है। हम पेस्लिप जनरेट करना चाहते हैं लेकिन ईमेल नहीं भेजना चाहते हैं। हमें मौजूदा कार्यक्षमता को यथावत रखने की जरूरत है और आंतरिक रिपोर्टिंग के लिए एक नया पेस्लिप जनरेटर जोड़ने की जरूरत है, बिना ईमेल भेजे, क्योंकि यह आंतरिक प्रस्ताव के लिए है। इस चरण के दौरान, हम यह सुनिश्चित करना चाहते हैं कि कर्मचारियों को भेजी जाने वाली मौजूदा वेतन पर्ची चालू रहे।
इस आवश्यकता के लिए, हम मौजूदा कोड का पुन:उपयोग नहीं कर सकते। हमें या तो यह कहते हुए Generate_payslip मेथड में फ़्लैग जोड़ने की ज़रूरत है कि अगर सही ईमेल भेजें तो नहीं। यह किया जा सकता है, लेकिन चूंकि यह मौजूदा कोड को बदल देता है, यह बाहर निकलने की कार्यक्षमता को तोड़ सकता है।
यह सुनिश्चित करने के लिए कि हम चीजों को न तोड़ें, हमें इन तर्कों को अलग-अलग वर्गों में विभाजित करने की आवश्यकता है:
class PayslipGenerator
def initialize(employee, month)
@employee = employee
@month = month
end
def generate_payslip
# Code to read from database,
# generate payslip
# and write it to a file
end
end
class PayslipMailer
def initialize(employee)
@employee = employee
end
def send_mail
# code to send email
employee.email
month
end
end
इसके बाद, हम इन दो वर्गों को इनिशियलाइज़ कर सकते हैं और उनके तरीकों को कॉल कर सकते हैं:
month = 11
# General Payslip
generator = PayslipGenerator.new(employee, month)
generator.generate_payslip
# Send Email
mailer = PayslipMailer.new(employee, month)
mailer.send_mail
यह दृष्टिकोण जिम्मेदारियों को अलग करने में मदद करता है और एक पूर्वानुमेय परिवर्तन सुनिश्चित करता है। अगर हमें केवल मेलर कार्यक्षमता को बदलने की आवश्यकता है, तो हम रिपोर्ट पीढ़ी को बदले बिना ऐसा कर सकते हैं। यह कार्यक्षमता में किसी भी बदलाव की भविष्यवाणी करने में भी मदद करता है।
मान लीजिए हमें ईमेल में महीने के फ़ील्ड के प्रारूप को Nov
. में बदलने की आवश्यकता है 11
. के बजाय . इस मामले में, हम PayslipMailer वर्ग को संशोधित करेंगे, और यह सुनिश्चित करेगा कि PayslipGenerator कार्यक्षमता में कुछ भी नहीं बदलेगा या टूटेगा नहीं।
हर बार जब आप कोड का एक टुकड़ा लिखते हैं, तो बाद में एक प्रश्न पूछें। इस वर्ग की क्या जिम्मेदारी है? यदि आपके उत्तर में "और" है, तो कक्षा को कई वर्गों में विभाजित करें। छोटे वर्ग हमेशा बड़े, सामान्य वर्गों से बेहतर होते हैं।
खुला/बंद सिद्धांत - OCP
बर्ट्रेंड मेयर ने ऑब्जेक्ट-ओरिएंटेड सॉफ्टवेयर कंस्ट्रक्शन नामक अपनी पुस्तक में ओपन/क्लोज्ड सिद्धांत की उत्पत्ति की।
सिद्धांत कहता है, "सॉफ़्टवेयर इकाइयां (वर्ग, मॉड्यूल, फ़ंक्शन इत्यादि) विस्तार के लिए खुली होनी चाहिए लेकिन संशोधन के लिए बंद होनी चाहिए "। इसका मतलब यह है कि हमें इकाई को बदले बिना व्यवहार बदलने में सक्षम होना चाहिए।
उपरोक्त उदाहरण में, हमारे पास एक कर्मचारी के लिए पेस्लिप-भेजने की कार्यक्षमता है, लेकिन यह सभी कर्मचारियों के लिए बहुत सामान्य है। हालाँकि, एक नई आवश्यकता उत्पन्न होती है:कर्मचारी के प्रकार के आधार पर एक पेस्लिप जनरेट करें। हमें पूर्णकालिक कर्मचारियों और ठेकेदारों के लिए अलग-अलग पेरोल जनरेशन लॉजिक की आवश्यकता है। इस मामले में, हम मौजूदा पेरोल जेनरेटर को संशोधित कर सकते हैं और इन कार्यात्मकताओं को जोड़ सकते हैं:
class PayslipGenerator
def initialize(employee, month)
@employee = employee
@month = month
end
def generate_payslip
# Code to read from database,
# generate payslip
if employee.contractor?
# generate payslip for contractor
else
# generate a normal payslip
end
# and write it to a file
end
end
हालाँकि, यह एक खराब पटर है। ऐसा करने में, हम मौजूदा वर्ग को संशोधित कर रहे हैं। यदि हमें कर्मचारी अनुबंधों के आधार पर अधिक पीढ़ी तर्क जोड़ने की आवश्यकता है, तो हमें मौजूदा वर्ग को संशोधित करने की आवश्यकता है, लेकिन ऐसा करने से खुले/बंद सिद्धांत का उल्लंघन होता है। वर्ग को संशोधित करके, हम अनपेक्षित परिवर्तन करने का जोखिम उठाते हैं। जब कुछ बदलता है या जोड़ा जाता है, तो इससे मौजूदा कोड में अज्ञात समस्याएं हो सकती हैं। ये अगर-और एक ही कक्षा के भीतर अधिक स्थानों पर हो सकते हैं। इसलिए, जब हम एक नया कर्मचारी प्रकार जोड़ते हैं, तो हम उन स्थानों को याद कर सकते हैं जहां ये मौजूद हैं। उन सभी को ढूंढना और संशोधित करना जोखिम भरा हो सकता है और समस्या पैदा कर सकता है।
हम इस कोड को इस तरह से रिफैक्टर कर सकते हैं कि हम कार्यक्षमता को बढ़ाकर कार्यक्षमता जोड़ सकते हैं लेकिन इकाई को बदलने से बच सकते हैं। तो, आइए हम इनमें से प्रत्येक के लिए एक अलग वर्ग बनाएं और एक ही generate
उनमें से प्रत्येक के लिए विधि:
class ContractorPayslipGenerator
def initialize(employee, month)
@employee = employee
@month = month
end
def generate
# Code to read from the database,
# generate payslip
# and write it to a file
end
end
class FullTimePayslipGenerator
def initialize(employee, month)
@employee = employee
@month = month
end
def generate
# Code to read from the database,
# generate payslip
# and write it to a file
end
end
सुनिश्चित करें कि इनका एक ही विधि नाम है। अब, इन वर्गों का उपयोग करने के लिए PayslipGenerator वर्ग बदलें:
GENERATORS = {
'full_time' => FullTimePayslipGenerator,
'contractor' => ContractorPayslipGenerator
}
class PayslipGenerator
def initialize(employee, month)
@employee = employee
@month = month
end
def generate_payslip
# Code to read from database,
# generate payslip
GENERATORS[employee.type].new(employee, month).generate()
# and write it to a file
end
end
यहां, हमारे पास जेनरेटर स्थिरांक है जो कर्मचारी प्रकार के आधार पर कक्षा को कॉल करने के लिए मानचित्र करता है। हम इसका उपयोग यह निर्धारित करने के लिए कर सकते हैं कि किस वर्ग को कॉल करना है। अब, जब हमें नई कार्यक्षमता जोड़नी होती है, तो हम बस उसके लिए एक नया वर्ग बना सकते हैं और इसे जनरेटर स्थिरांक में जोड़ सकते हैं। यह बिना कुछ तोड़े या मौजूदा तर्क के बारे में सोचने की आवश्यकता के बिना कक्षा का विस्तार करने में मदद करता है। हम किसी भी प्रकार के पेस्लिप जनरेटर को आसानी से जोड़ या हटा सकते हैं।
लिस्कोव प्रतिस्थापन सिद्धांत - LSP
लिस्कोव प्रतिस्थापन सिद्धांत कहता है, "यदि S, T का उपप्रकार है, तो T प्रकार की वस्तुओं को S प्रकार की वस्तुओं से बदला जा सकता है" ।
इस सिद्धांत को समझने के लिए, आइए पहले समस्या को समझें। ओपन/क्लोज्ड सिद्धांत के तहत, हमने सॉफ्टवेयर को इस तरह से डिजाइन किया है कि इसे बढ़ाया जा सकता है। हमने एक उपवर्ग Payslip जनरेटर बनाया है जो एक विशिष्ट कार्य करता है। कॉल करने वाले के लिए, जिस वर्ग को वे कॉल कर रहे हैं वह अज्ञात है। इन वर्गों को समान व्यवहार करने की आवश्यकता है ताकि कॉलर अंतर बताने में असमर्थ हो। व्यवहार से हमारा तात्पर्य है कि कक्षा में विधियाँ सुसंगत होनी चाहिए। इन वर्गों की विधियों में निम्नलिखित विशेषताएं होनी चाहिए:
- एक ही नाम है
- समान डेटा प्रकार के साथ समान संख्या में तर्क लें
- वही डेटा प्रकार लौटाएं
आइए हम पेस्लिप जनरेटर के उदाहरण को देखें। हमारे पास दो जनरेटर हैं, एक पूर्णकालिक कर्मचारियों के लिए और दूसरा ठेकेदारों के लिए। अब, यह सुनिश्चित करने के लिए कि इन पेस्लिप्स का व्यवहार सुसंगत है, हमें इन्हें एक बेस क्लास से इनहेरिट करने की आवश्यकता है। आइए एक आधार वर्ग को परिभाषित करें जिसे User
. कहा जाता है ।
class User
def generate
end
end
खुले/बंद सिद्धांत के उदाहरण में हमने जो उपवर्ग बनाया है, उसका कोई आधार वर्ग नहीं है। हम इसे आधार वर्ग के लिए संशोधित करते हैं User
:
class ContractorPayslipGenerator < User
def generate
# Code to generate payslip
end
end
class FullTimePayslipGenerator < User
def generate
# Code to generate payslip
end
end
इसके बाद, हम उन विधियों के एक सेट को परिभाषित करते हैं जो किसी भी उपवर्ग के लिए आवश्यक हैं जो User
. को इनहेरिट करता है कक्षा। हम इन विधियों को बेस क्लास में परिभाषित करते हैं। हमारे मामले में, हमें केवल एक ही विधि की आवश्यकता है, जिसे जनरेट कहा जाता है।
class User
def generate
raise "NotImplemented"
end
end
यहां, हमने जनरेट विधि को परिभाषित किया है, जिसमें एक raise
. है बयान। इसलिए, बेस क्लास को इनहेरिट करने वाले किसी भी उपवर्ग को जनरेट करने की विधि की आवश्यकता होती है। यदि यह मौजूद नहीं है, तो यह एक त्रुटि उत्पन्न करेगा कि विधि लागू नहीं की गई है। इस तरह, हम यह सुनिश्चित कर सकते हैं कि उपवर्ग सुसंगत है। इसके साथ, कॉलर हमेशा यह सुनिश्चित कर सकता है कि generate
विधि मौजूद है।
यह सिद्धांत चीजों को तोड़े बिना और बहुत सारे बदलाव किए बिना किसी भी उपवर्ग को आसानी से बदलने में मदद करता है।
इंटरफ़ेस अलगाव सिद्धांत - ISP
इंटरफ़ेस अलगाव सिद्धांत स्थिर भाषाओं पर लागू होता है, और चूंकि रूबी एक गतिशील भाषा है, इसलिए इंटरफेस की कोई अवधारणा नहीं है। इंटरफेस कक्षाओं के बीच अमूर्त नियमों को परिभाषित करते हैं।
सिद्धांत कहता है,
<ब्लॉकक्वॉट>ग्राहकों को उन इंटरफेस पर निर्भर होने के लिए मजबूर नहीं किया जाना चाहिए जिनका वे उपयोग नहीं करते हैं। - रॉबर्ट सी. मार्टिन
इसका मतलब यह है कि किसी भी वर्ग द्वारा उपयोग किए जा सकने वाले सामान्यीकृत इंटरफ़ेस की तुलना में कई इंटरफेस होना बेहतर है। यदि हम एक सामान्यीकृत इंटरफ़ेस को परिभाषित करते हैं, तो वर्ग को उस परिभाषा पर निर्भर रहना पड़ता है जिसका वह उपयोग नहीं करता है।
रूबी में इंटरफेस नहीं है, लेकिन आइए हम कुछ इसी तरह के निर्माण के लिए वर्ग और उपवर्ग की अवधारणा को देखें।
लिस्कोव प्रतिस्थापन सिद्धांत के लिए उपयोग किए गए उदाहरण में, हमने देखा कि उपवर्ग FullTimePayslipGenerator
सामान्य वर्ग उपयोगकर्ता से विरासत में मिला था। लेकिन उपयोगकर्ता एक बहुत ही सामान्य वर्ग है और इसमें अन्य विधियां हो सकती हैं। यदि हमारे पास कोई अन्य कार्यक्षमता होनी चाहिए, जैसे Leave
, इसे उपयोगकर्ता का उपवर्ग होना होगा। Leave
एक उत्पन्न विधि की आवश्यकता नहीं है, लेकिन यह इस पद्धति पर निर्भर करेगा। इसलिए, एक सामान्य वर्ग होने के बजाय, हम इसके लिए एक विशिष्ट वर्ग रख सकते हैं:
class Generator
def generate
raise "NotImplemented"
end
end
class ContractorPayslipGenerator < Generator
def generate
# Code to generate payslip
end
end
class FullTimePayslipGenerator < Generator
def generate
# Code to generate payslip
end
end
यह जनरेटर पेस्लिप पीढ़ी के लिए विशिष्ट है, और उपवर्ग को सामान्य User
पर निर्भर होने की आवश्यकता नहीं है कक्षा।
निर्भरता उलटा सिद्धांत - डीआईपी
डिपेंडेंसी इनवर्जन एक सिद्धांत है जो सॉफ्टवेयर मॉड्यूल को अलग करने के लिए लागू होता है।
<ब्लॉकक्वॉट>एक उच्च-स्तरीय मॉड्यूल को निम्न-स्तरीय मॉड्यूल पर निर्भर नहीं होना चाहिए; दोनों को अमूर्तता पर निर्भर होना चाहिए।
ऊपर वर्णित सिद्धांतों का उपयोग करते हुए डिजाइन, हमें निर्भरता उलटा सिद्धांत की ओर मार्गदर्शन करता है। कोई भी वर्ग जिसकी एक ही जिम्मेदारी होती है, उसे काम करने के लिए अन्य वर्गों की चीजों की आवश्यकता होती है। पेरोल उत्पन्न करने के लिए, हमें डेटाबेस तक पहुंच की आवश्यकता होती है, और रिपोर्ट तैयार होने के बाद हमें एक फाइल पर लिखने की आवश्यकता होती है। एकल उत्तरदायित्व सिद्धांत के साथ, हम एक वर्ग के लिए केवल एक ही कार्य करने का प्रयास कर रहे हैं। लेकिन, डेटाबेस से पढ़ने और फ़ाइल में लिखने जैसी चीज़ें एक ही कक्षा में की जानी चाहिए।
इन निर्भरताओं को हटाना और मुख्य व्यावसायिक तर्क को अलग करना महत्वपूर्ण है। यह परिवर्तन के दौरान कोड को तरल होने में मदद करेगा, और परिवर्तन का अनुमान लगाया जा सकता है। निर्भरता को उलटने की जरूरत है, और मॉड्यूल के कॉलर का निर्भरता पर नियंत्रण होना चाहिए। हमारे भुगतान पर्ची जनरेटर में, निर्भरता रिपोर्ट के लिए डेटा का स्रोत है; इस कोड को इस तरह व्यवस्थित किया जाना चाहिए कि कॉलर स्रोत को निर्दिष्ट कर सके। निर्भरता के नियंत्रण को उल्टा करने की आवश्यकता है और इसे कॉलर द्वारा आसानी से संशोधित किया जा सकता है।
ऊपर हमारे उदाहरण में, ContractorPayslipGenerator
मॉड्यूल निर्भरता को नियंत्रित करता है, यह निर्धारित करने के लिए कि डेटा को कहां पढ़ा जाए और आउटपुट को कैसे स्टोर किया जाए, यह वर्ग द्वारा नियंत्रित किया जाता है। इसे वापस करने के लिए, आइए एक UserReader
बनाएं वह वर्ग जो उपयोगकर्ता डेटा पढ़ता है:
class UserReader
def get
raise "NotImplemented"
end
end
अब, मान लीजिए कि हम चाहते हैं कि यह Postgres के डेटा को पढ़े। हम इस उद्देश्य के लिए UserReader का एक उपवर्ग बनाते हैं:
class PostgresUserReader < UserReader
def get
# Code to read data from Postgres
end
end
इसी तरह, हमारे पास FileUserReader
. से एक रीडर हो सकता है , InMemoryUserReader
, या किसी अन्य प्रकार का पाठक जो हम चाहते हैं। अब हमें FullTimePayslipGenerator
. को संशोधित करने की आवश्यकता है वर्ग ताकि वह PostgresUserReader
. का उपयोग करे एक निर्भरता के रूप में।
class FullTimePayslipGenerator < Generator
def initialize(datasource)
@datasource = datasource
end
def generate
# Code to generate payslip
data = datasource.get()
end
end
कॉलर अब PostgresUserReader
. पास कर सकता है एक निर्भरता के रूप में:
datasource = PostgresUserReader.new()
FullTimePayslipGenerator.new(datasource)
कॉलर का निर्भरता पर नियंत्रण होता है और जरूरत पड़ने पर वह आसानी से स्रोत को बदल सकता है।
निर्भरता को बदलना न केवल कक्षाओं पर लागू होता है। हमें कॉन्फ़िगरेशन को उलटने की भी आवश्यकता है। उदाहरण के लिए, Postgres सर्वर को कनेक्ट करते समय, हमें विशिष्ट कॉन्फ़िगरेशन की आवश्यकता होती है, जैसे DBURL, उपयोगकर्ता नाम और पासवर्ड। इन कॉन्फ़िगरेशन को कक्षा में हार्डकोड करने के बजाय, हमें उन्हें कॉलर से पास करना होगा।
class PostgresUserReader < UserReader
def initialize(config)
config = config
end
def get
# initialize DB with the config
self.config
# Code to read data from Postgres
end
end
कॉलर द्वारा कॉन्फिगरेशन प्रदान करें:
config = { url: "url", user: "user" }
datasource = PostgresUserReader.new(config)
FullTimePayslipGenerator.new(datasource)
कॉलर का अब निर्भरता पर पूर्ण नियंत्रण है, और परिवर्तन प्रबंधन आसान और कम दर्दनाक है।
समापन
सॉलिड डिज़ाइन कोड को अलग करने और परिवर्तन को कम दर्दनाक बनाने में मदद करता है। कार्यक्रमों को इस तरह से डिजाइन करना महत्वपूर्ण है कि वे डिकूप्ड, पुन:प्रयोज्य और परिवर्तन के लिए उत्तरदायी हों। सभी पांच ठोस सिद्धांत एक दूसरे के पूरक हैं और सह-अस्तित्व में होने चाहिए। एक अच्छी तरह से डिज़ाइन किया गया कोडबेस लचीला, बदलने में आसान और काम करने में मज़ेदार होता है। कोई भी नया डेवलपर कूद सकता है और कोड को आसानी से समझ सकता है।
यह समझना वास्तव में महत्वपूर्ण है कि सॉलिड किस प्रकार की समस्याओं का समाधान करता है और हम ऐसा क्यों कर रहे हैं। समस्या को समझने से आपको डिज़ाइन सिद्धांतों को अपनाने और बेहतर सॉफ़्टवेयर डिज़ाइन करने में मदद मिलती है।