सरल आईओएस सॉफ्टवेयर डिज़ाइन के चार नियम

1990 के दशक के अंत में, चरम प्रोग्रामिंग विकसित करते समय, प्रसिद्ध सॉफ्टवेयर डेवलपर केंट बेक सरल सॉफ्टवेयर डिजाइन के लिए नियमों की एक सूची के साथ आया था।

केंट बेक के अनुसार, एक अच्छा सॉफ्टवेयर डिजाइन:

  • सभी परीक्षण चलाती है
  • कोई दोहराव नहीं है
  • प्रोग्रामर का इरादा व्यक्त करता है
  • कक्षाओं और विधियों की संख्या को कम करता है

इस लेख में, हम चर्चा करेंगे कि कैसे व्यावहारिक iOS उदाहरण देकर इन नियमों को iOS विकास की दुनिया में लागू किया जा सकता है और चर्चा की जा सकती है कि हम उनसे कैसे लाभ उठा सकते हैं।

सभी परीक्षण चलाती है

सॉफ्टवेयर डिजाइन हमें एक ऐसी प्रणाली बनाने में मदद करता है जो इरादा के अनुसार काम करती है। लेकिन हम यह कैसे सत्यापित कर सकते हैं कि एक प्रणाली शुरू में अपने डिजाइन के अनुसार कार्य करेगी? इसका उत्तर परीक्षणों को बनाने से है जो इसे मान्य करते हैं।

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

आइए उन दो सिद्धांतों पर चर्चा करें जो परीक्षण लेखन और सिस्टम डिज़ाइन को सरल बना सकते हैं। और वे एकल जिम्मेदारी सिद्धांत और निर्भरता इंजेक्शन हैं।

एकल जिम्मेदारी सिद्धांत (एसआरपी)

एसआरपी में कहा गया है कि एक वर्ग के पास एक होना चाहिए, और परिवर्तन का केवल एक कारण होना चाहिए। एसआरपी सबसे सरल सिद्धांतों में से एक है, और सही पाने के लिए सबसे कठिन में से एक है। जिम्मेदारियों का मिश्रण कुछ ऐसा है जो हम स्वाभाविक रूप से करते हैं।

आइए कुछ कोड का एक उदाहरण प्रदान करें जिसे परीक्षण करना वास्तव में कठिन है और इसके बाद SRP का उपयोग करके इसे फिर से भरना। फिर चर्चा करें कि इसने कोड को कैसे परीक्षण योग्य बनाया।

मान लीजिए कि हमें वर्तमान में अपने वर्तमान दृश्य नियंत्रक से एक भुगतान दृश्य नियंत्रक प्रस्तुत करने की आवश्यकता है, तो भुगतान दृश्यकारक को अपने भुगतान उत्पाद की कीमत के आधार पर अपना दृष्टिकोण कॉन्फ़िगर करना चाहिए। हमारे मामले में, कीमत कुछ बाहरी उपयोगकर्ता घटनाओं के आधार पर परिवर्तनशील है।

इस कार्यान्वयन के लिए कोड वर्तमान में निम्न की तरह दिखता है:

हम इस कोड का परीक्षण कैसे कर सकते हैं? हमें पहले क्या परीक्षण करना चाहिए? क्या मूल्य छूट की सही गणना की गई है? हम छूट का परीक्षण करने के लिए भुगतान की घटनाओं का कैसे मजाक उड़ा सकते हैं?

इस वर्ग के लिए लेखन परीक्षण जटिल होगा, हमें इसे लिखने का बेहतर तरीका खोजना चाहिए। ठीक है, सबसे पहले बड़ी समस्या का समाधान करें। हमें अपनी निर्भरता को अनसुना करने की जरूरत है।

हम देखते हैं कि हमारे पास हमारे उत्पाद को लोड करने के लिए तर्क हैं। हमारे पास भुगतान ईवेंट हैं जो उपयोगकर्ता को छूट के लिए योग्य बनाते हैं। हमारे पास छूट, एक छूट गणना और सूची चलती है।

तो चलिए इन्हें केवल स्विफ्ट कोड में अनुवाद करने का प्रयास करते हैं।

हमने एक भुगतान प्रबंधक बनाया, जो भुगतान से संबंधित हमारे तर्क का प्रबंधन करता है, और अलग-अलग मूल्य-निर्धारणकर्ता को यह आसानी से परीक्षण करने योग्य बनाता है। इसके अलावा, एक डेटा-लोडर जो हमारे उत्पादों को लोड करने के लिए नेटवर्क या डेटाबेस इंटरैक्शन के लिए जिम्मेदार है।

हमने यह भी उल्लेख किया कि हमें छूटों के प्रबंधन के लिए जिम्मेदार वर्ग की आवश्यकता है। चलो इसे CouponManager कहते हैं और इसे उपयोगकर्ता छूट कूपन का प्रबंधन करते हैं।

हमारा भुगतान देखने वाला नियंत्रक तब निम्न प्रकार देख सकता है:

हम अब जैसे परीक्षण लिख सकते हैं

  • testCalculatingFinalPriceWithoutCoupon
  • testCalculatingFinalPriceWithCoupon
  • testCouponExists

और कई अन्य! अब अलग-अलग ऑब्जेक्ट बनाकर हम अनावश्यक नकल से बचते हैं और एक कोड भी बनाते हैं जिसके लिए परीक्षण लिखना आसान है।

निर्भरता अन्तःक्षेपण

दूसरा सिद्धांत है डिपेंडेंसी इंजेक्शन। और हमने ऊपर के उदाहरणों से देखा कि हमने पहले से ही अपने ऑब्जेक्ट इनिलाइज़र पर निर्भरता इंजेक्शन का उपयोग किया है।

ऊपर की तरह हमारी निर्भरता को इंजेक्ट करने के दो प्रमुख लाभ हैं। यह इस बात पर स्पष्ट करता है कि हमारे प्रकार की निर्भरताएं क्या निर्भर करती हैं और यह हमें नकली वस्तुओं को डालने की अनुमति देती है जब हम वास्तविक के बजाय परीक्षण करना चाहते हैं।

एक अच्छी तकनीक हमारी वस्तुओं के लिए प्रोटोकॉल बनाना और वास्तविक और नकली वस्तु द्वारा निम्नलिखित की तरह ठोस कार्यान्वयन प्रदान करना है:

अब हम आसानी से तय कर सकते हैं कि हम किस वर्ग को निर्भरता के रूप में इंजेक्ट करना चाहते हैं।

चुस्त युग्मन परीक्षणों को लिखना मुश्किल बनाता है। तो, इसी तरह, हम जितने अधिक परीक्षण लिखते हैं, उतने अधिक हम DIP जैसे उपकरण का उपयोग करते हैं और निर्भरता इंजेक्शन, इंटरफेस, और युग्मन को कम करने के लिए अमूर्त।

कोड को अधिक परीक्षण योग्य बनाने से न केवल इसे तोड़ने के हमारे डर को खत्म किया जाता है (क्योंकि हम परीक्षण को लिखेंगे जो हमें वापस भेज देंगे) बल्कि क्लीनर कोड लिखने में भी योगदान देता है।

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

कोई दोहराव नहीं है

डुप्लीकेशन एक अच्छी तरह से डिज़ाइन किए गए सिस्टम का प्राथमिक दुश्मन है। यह अतिरिक्त कार्य, अतिरिक्त जोखिम का प्रतिनिधित्व करता है, अनावश्यक जटिलता जोड़ता है।

इस अनुभाग में, हम चर्चा करेंगे कि हम iOS में सामान्य दोहराव को हटाने के लिए टेम्पलेट डिज़ाइन पैटर्न का उपयोग कैसे कर सकते हैं। यह समझने में आसान बनाने के लिए कि हम वास्तविक जीवन की चैट के कार्यान्वयन को लागू करने जा रहे हैं।

मान लीजिए कि हमारे पास वर्तमान में हमारे ऐप में एक मानक चैट अनुभाग है। एक नई आवश्यकता सामने आती है और अब हम एक नए प्रकार की चैट को लागू करना चाहते हैं - एक लाइव-चैट। एक चैट जिसमें अधिकतम 20 वर्णों वाले संदेश होने चाहिए और जब हम चैट दृश्य को खारिज करते हैं तो यह चैट गायब हो जाएगी।

इस चैट में हमारी वर्तमान चैट के समान दृश्य होंगे लेकिन कुछ अलग नियम होंगे:

  1. चैट संदेश भेजने का नेटवर्क अनुरोध अलग होगा।

2. चैट संदेश संक्षिप्त होना चाहिए, संदेश के लिए 20 से अधिक वर्ण नहीं।

3. हमारे स्थानीय डेटाबेस में चैट संदेशों को जारी नहीं रखा जाना चाहिए।

मान लीजिए कि हम एमवीपी आर्किटेक्चर का उपयोग कर रहे हैं और वर्तमान में हम अपने प्रस्तोता में चैट संदेश भेजने के लिए तर्क को संभालते हैं। आइए लाइव-चैट नामक हमारे नए चैट प्रकार के लिए नए नियम जोड़ने का प्रयास करें।

एक निष्कपट कार्यान्वयन निम्नलिखित की तरह होगा:

लेकिन क्या होगा अगर भविष्य में हम और अधिक चैट प्रकार होंगे?
अगर हम यह जोड़ना जारी रखते हैं कि हर फ़ंक्शन में हमारी चैट की स्थिति की जाँच करें, तो कोड पढ़ने और बनाए रखने के लिए कठिन हो जाएगा। इसके अलावा, यह शायद ही परीक्षण योग्य है और राज्य जाँच सभी प्रस्तुतकर्ता के दायरे में दोहराई जाएगी।

यह वह जगह है जहाँ टेम्पलेट पैटर्न उपयोग में आता है। टेम्प्लेट पैटर्न का उपयोग तब किया जाता है जब हमें एल्गोरिथ्म के कई कार्यान्वयन की आवश्यकता होती है। टेम्पलेट को परिभाषित किया गया है और फिर आगे विविधताओं के साथ बनाया गया है। इस पद्धति का उपयोग तब करें जब अधिकांश उपवर्गों को समान व्यवहार लागू करने की आवश्यकता हो।

हम चैट प्रस्तुतकर्ता के लिए एक प्रोटोकॉल बना सकते हैं और हम अलग-अलग तरीकों को लागू करते हैं जिन्हें चैट प्रस्तुतकर्ता चरणों में ठोस वस्तुओं द्वारा अलग-अलग लागू किया जाएगा।

अब हम अपने प्रस्तुतकर्ता को IChatPresenter के अनुरूप बना सकते हैं

हमारे प्रस्तोता अब अपने अंदर सामान्य कार्यों को बुलाकर भेजने वाले संदेश को संभालते हैं और उन कार्यों को सौंपते हैं जिन्हें अलग तरीके से लागू किया जा सकता है।

अब हम ऐसी वस्तुएँ बना सकते हैं जो प्रस्तुतकर्ता के चरणों के आधार पर आधारित हों और इन कार्यों को उनकी आवश्यकताओं के आधार पर कॉन्फ़िगर करें।

यदि हम अपने दृश्य नियंत्रक में निर्भरता इंजेक्शन का उपयोग करते हैं तो हम दो अलग-अलग मामलों में एक ही दृश्य नियंत्रक का पुन: उपयोग कर सकते हैं।

डिज़ाइन पैटर्न का उपयोग करके हम वास्तव में अपने iOS कोड को सरल बना सकते हैं। यदि आप इसके बारे में अधिक जानना चाहते हैं, तो निम्नलिखित लेख आगे की व्याख्या प्रदान करता है।

अर्थपूर्ण

एक सॉफ्टवेयर परियोजना की लागत का अधिकांश हिस्सा दीर्घकालिक रखरखाव में है। कोड को पढ़ना और बनाए रखना आसान है, सॉफ्टवेयर डेवलपर्स के लिए बहुत जरूरी है।

हम अच्छा नामकरण, एसआरपी और लेखन परीक्षण का उपयोग करके अधिक अभिव्यंजक कोड पेश कर सकते हैं।

नामकरण

नंबर एक चीज जो कोड को अधिक अभिव्यंजक बनाती है - और यह नामकरण है। यह नाम लिखना महत्वपूर्ण है:

  • आशय प्रकट करें
  • विघटन से बचें
  • आसानी से खोजा जा सकता है

जब कक्षाओं और कार्यों के नामकरण की बात आती है, तो वर्गों और उपयोगकर्ता क्रियाओं या क्रिया वाक्यांशों के नामों के लिए संज्ञा या संज्ञा-वाक्यांश का उपयोग करने के लिए एक अच्छी चाल है।

विभिन्न डिज़ाइन पैटर्नों का उपयोग करते समय भी कभी-कभी क्लास के नाम में कमांड या विज़िटर जैसे पैटर्न नामों को जोड़ना अच्छा होता है। तो पाठक को तुरंत पता चल जाएगा कि उस बारे में जानने के लिए सभी कोड को पढ़ने की आवश्यकता के बिना वहां किस पैटर्न का उपयोग किया जाता है।

SRP का उपयोग करना

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

लिखित परीक्षा

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

कक्षाओं और विधियों की संख्या कम से कम करें

एक वर्ग के कार्यों को छोटा रहना चाहिए, एक फ़ंक्शन को हमेशा केवल एक ही कार्य करना चाहिए। यदि किसी फ़ंक्शन में बहुत अधिक पंक्तियाँ होती हैं, तो ऐसा हो सकता है कि यह क्रिया करने वाली क्रियाएं हैं जिन्हें दो या अधिक अलग-अलग कार्यों में विभाजित किया जा सकता है।

एक अच्छा तरीका शारीरिक रेखाओं को गिनना है और अधिकतम चार से छह पंक्तियों के लिए लक्ष्य बनाने की कोशिश करना है, ज्यादातर मामलों में कुछ भी जो उस संख्या से अधिक हो जाता है उसे पढ़ना और बनाए रखना कठिन हो सकता है।

IOS में एक अच्छा विचार कॉन्फ़िगरेशन कॉल्स को काटना है जो हम आमतौर पर viewDidLoad या viewDidAppear फ़ंक्शन पर करते हैं।

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

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

IOS में एक ज्ञात समस्या UIViewControllers का बड़ा आकार है। यह सही है कि ऐप्पल व्यू कंट्रोलर डिज़ाइन के द्वारा, इन वस्तुओं को एक ही उद्देश्य के लिए रखना कठिन है, लेकिन हमें अपनी पूरी कोशिश करनी चाहिए।

UIViewControllers को छोटा बनाने के कई तरीके हैं मेरी प्राथमिकता एक आर्किटेक्चर का उपयोग करना है जिसमें VIPER या MVP जैसी चिंताओं का बेहतर पृथक्करण है लेकिन इसका मतलब यह नहीं है कि हम इसे Apple MVC में भी बेहतर नहीं बना सकते।

कई चिंताओं को अलग करने की कोशिश करके हम किसी भी वास्तुकला के साथ बहुत अच्छे कोड तक पहुंच सकते हैं। विचार एकल-उद्देश्य कक्षाएं बनाने के लिए है जो दर्शकों के नियंत्रकों के लिए सहायक के रूप में सेवा कर सकते हैं और कोड को अधिक पठनीय और परीक्षण योग्य बना सकते हैं।

कुछ चीजें जिन्हें किसी भी बहाने से देखा जा सकता है, वे हैं कंट्रोलर:

  • नेटवर्क कोड लिखने के बजाय सीधे नेटवर्क मैनजर होना चाहिए जो नेटवर्क कॉल के लिए जिम्मेदार हो
  • व्यू कंट्रोलर्स में डेटा में हेरफेर करने के बजाय, हम बस एक DataManager को एक वर्ग बना सकते हैं जो इसके लिए जिम्मेदार है।
  • UIViewController में UserDefaults स्ट्रिंग्स के साथ खेलने के बजाय हम उस पर एक मुखौटा बना सकते हैं।

निष्कर्ष के तौर पर

मेरा मानना ​​है कि हमें ऐसे घटकों से सॉफ़्टवेयर की रचना करनी चाहिए, जो एक चीज़ के लिए सही, सरल, छोटे, ज़िम्मेदार हों।

इस लेख में, हमने केंट बेक द्वारा सरल डिजाइन के लिए चार नियमों पर चर्चा की और व्यावहारिक उदाहरण दिए कि कैसे हम उन्हें iOS विकास परिवेश में लागू कर सकते हैं।

यदि आपको यह लेख अच्छा लगा हो तो अपना समर्थन दिखाने के लिए ताली बजाना सुनिश्चित करें। कई और लेख देखने के लिए मुझे फॉलो करें जो आपके iOS डेवलपर के कौशल को अगले स्तर तक ले जा सकते हैं।

यदि आपके पास कोई प्रश्न या टिप्पणी है तो यहाँ एक नोट छोड़ें या मुझे arlindaliu.dev@gmail.com पर ईमेल करें।