Skip to content

पोस्ट

आपकी खामी दर को कम करने के लिए 4 प्रथाएं

17 नवंबर 2015 • 10 मिनट पढ़ना

आपकी खामी दर को कम करने के लिए 4 प्रथाएं

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

क्या खामियां टाली जा सकती हैं? नासा कोशिश करता है, लेकिन वे परीक्षण के ट्रकलोड भी करते हैं। उनका सॉफ्टवेयर शाब्दिक रूप से मिशन महत्वपूर्ण है – एक बार का सौदा। अधिकांश संगठनों के लिए, यह मामला नहीं है और बड़ी मात्रा में परीक्षण महंगा और अव्यावहारिक है। जबकि परीक्षण के लिए कोई विकल्प नहीं है, परीक्षण के बिना खामी-प्रतिरोधी कोड लिखना संभव है।

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

1. सरल कोड लिखें

सरल होना आसान होना चाहिए, लेकिन यह नहीं है। सरल कोड लिखना कठिन है।

कुछ लोग इसे पढ़ेंगे और सोचेंगे कि इसका मतलब सरल भाषा सुविधाओं का उपयोग करना है, लेकिन यह मामला नहीं है — सरल कोड मूर्ख कोड नहीं है।

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

माइक्रोसॉफ्ट साइक्लोमैटिक जटिलता को इस प्रकार परिभाषित करता है:

साइक्लोमैटिक जटिलता विधि के माध्यम से रैखिक रूप से स्वतंत्र पथों की संख्या को मापती है, जो सशर्त शाखाओं की संख्या और जटिलता द्वारा निर्धारित होती है। कम साइक्लोमैटिक जटिलता आम तौर पर एक विधि को इंगित करती है जो समझने, परीक्षण और बनाए रखने में आसान है।

कम साइक्लोमैटिक जटिलता क्या है? माइक्रोसॉफ्ट साइक्लोमैटिक जटिलता को 25 से नीचे रखने की सिफारिश करता है।

ईमानदारी से कहूं तो, मुझे माइक्रोसॉफ्ट की 25 की साइक्लोमैटिक जटिलता की सिफारिश बहुत अधिक लगी है। रखरखाव और जटिलता के लिए, मुझे आदर्श विधि आकार 1 से 10 लाइनों के बीच मिला है जिसमें 1 से 5 के बीच साइक्लोमैटिक जटिलता है।

बिल वैगनर ने प्रभावी C#, दूसरा संस्करण में विधि आकार पर लिखा:

याद रखें कि आपके C# कोड को मशीन-निष्पादन योग्य कोड में अनुवाद करना एक दो-चरणीय प्रक्रिया है। C# कंपाइलर IL उत्पन्न करता है जो असेंबलीज में वितरित होता है। JIT कंपाइलर आवश्यकतानुसार प्रत्येक विधि (या विधियों के समूह, जब इनलाइनिंग शामिल हो) के लिए मशीन कोड उत्पन्न करता है। छोटे कार्य JIT कंपाइलर के लिए उस लागत को परिशोधित करना बहुत आसान बनाते हैं। छोटे कार्य इनलाइनिंग के लिए उम्मीदवार होने की अधिक संभावना रखते हैं। यह केवल छोटापन नहीं है: सरल नियंत्रण प्रवाह उतना ही महत्वपूर्ण है। कार्यों के अंदर कम नियंत्रण शाखाएं JIT कंपाइलर के लिए चर को पंजीकृत करना आसान बनाती हैं। यह केवल स्पष्ट कोड लिखने के लिए अच्छी प्रथा नहीं है; यह है कि आप रनटाइम पर अधिक कुशल कोड कैसे बनाते हैं।

साइक्लोमैटिक जटिलता को परिप्रेक्ष्य में रखने के लिए, निम्नलिखित विधि में 12 की साइक्लोमैटिक जटिलता है।

public string ComplexityOf12(int status)
{
    var isTrue = true;
    var myString = "Chuck";

    if (isTrue)
    {
        if (isTrue)
        {
            myString = string.Empty;
            isTrue = false;

            for (var index = 0; index < 10; index++)
            {
                isTrue |= Convert.ToBoolean(new Random().Next());
            }

            if (status == 1 || status == 3)
            {
                switch (status)
                {
                    case 3:
                        return "Bye";
                    case 1:
                        if (status % 1 == 0)
                        {
                            myString = "Super";
                        }
                        break;
                }

                return myString;
            }
        }
    }

    if (!isTrue)
    {
        myString = "New";
    }

    switch (status)
    {
        case 300:
            myString = "3001";
            break;
        case 400:
            myString = "4003";
            break;

    }

    return myString;
}

एक सामान्य स्वीकृत जटिलता परिकल्पना यह मानती है कि जटिलता और खामियों के बीच सकारात्मक संबंध मौजूद है।

पिछली पंक्ति थोड़ी जटिल है। सबसे सरल शब्दों में — कोड को सरल रखने से आपकी खामी दर कम होती है।

2. परीक्षण योग्य कोड लिखें

अध्ययनों से पता चला है कि परीक्षण योग्य कोड लिखना, वास्तविक परीक्षण लिखे बिना खामियों की घटनाओं को कम करता है। यह इतना महत्वपूर्ण और गहन है कि इसे दोहराने की आवश्यकता है: परीक्षण योग्य कोड लिखना, वास्तविक परीक्षण लिखे बिना, खामियों की घटनाओं को कम करता है।

यह सवाल उठाता है, परीक्षण योग्य कोड क्या है?

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

परीक्षण योग्य कोड लिखना कठिन लग सकता है, लेकिन, वास्तव में, यह नियंत्रण का व्युत्क्रम (निर्भरता इंजेक्शन) और S.O.L.I.D सिद्धांतों का पालन करते समय आसान है। आप इसकी आसानी से आश्चर्यचकित होंगे और सोचेंगे कि इस तरह लिखना शुरू करने में इतना समय क्यों लगा।

3. कोड समीक्षा

एक विकास टीम जो सबसे प्रभावशाली प्रथा अपना सकती है वह कोड समीक्षा है।

कोड समीक्षा डेवलपर्स के बीच ज्ञान साझा करने की सुविधा देती है। अनुभव से बोलते हुए, अन्य डेवलपर्स के साथ कोड पर खुली चर्चा करने का मेरे कोड लिखने के कौशल पर सबसे बड़ा प्रभाव पड़ा है।

कोड पूर्ण पुस्तक में, स्टीव मैकनेल द्वारा, स्टीव कोड समीक्षाओं के लाभों पर कई केस स्टडी प्रदान करते हैं:

  • AT&T में 200 से अधिक लोगों वाले एक संगठन के एक अध्ययन ने संगठन ने समीक्षाएं शुरू करने के बाद उत्पादकता में 14 प्रतिशत की वृद्धि और खामियों में 90 प्रतिशत की कमी की सूचना दी।
    • एटना बीमा कंपनी ने निरीक्षण का उपयोग करके एक प्रोग्राम में 82 प्रतिशत त्रुटियां पाईं और अपने विकास संसाधनों को 20 प्रतिशत कम करने में सक्षम थी।
    • एक ही समूह के लोगों द्वारा विकसित 11 प्रोग्राम के एक समूह में, पहले 5 को समीक्षा के बिना विकसित किया गया था। शेष 6 को समीक्षा के साथ विकसित किया गया था। सभी प्रोग्राम उत्पादन में जारी होने के बाद, पहले 5 में प्रति 100 लाइनों में औसतन 4.5 त्रुटियां थीं। जिन 6 का निरीक्षण किया गया था उनमें प्रति 100 में केवल 0.82 त्रुटियां थीं। समीक्षाओं ने 80 प्रतिशत से अधिक त्रुटियों को कम किया।

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

4. यूनिट परीक्षण

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

माइक्रोसॉफ्ट ने यूनिट परीक्षण की प्रभावशीलता पर एक अध्ययन किया। उन्होंने पाया कि कोडिंग संस्करण 2 (संस्करण 1 में कोई परीक्षण नहीं था) स्वचालित परीक्षण के साथ तुरंत खामियों को 20% कम कर दिया, लेकिन अतिरिक्त 30% की लागत पर।

एक अन्य अध्ययन ने टेस्ट ड्रिवन डेवलपमेंट (TDD) को देखा। उन्होंने TDD का उपयोग नहीं करने वाली समान परियोजनाओं की तुलना में कोड गुणवत्ता में दो गुना से अधिक वृद्धि देखी। TDD परियोजनाओं को विकसित करने में औसतन 15% अधिक समय लगा। TDD का एक दुष्प्रभाव यह था कि परीक्षण पुस्तकालयों और API के लिए दस्तावेज के रूप में कार्य करते थे।

अंत में, परीक्षण कवरेज और पोस्ट-सत्यापन खामियों पर एक अध्ययन में:

… हम पाते हैं कि दोनों परियोजनाओं में परीक्षण कवरेज में वृद्धि प्रीरिलीज़ परिवर्तनों की संख्या के लिए समायोजित होने पर क्षेत्र में रिपोर्ट की गई समस्याओं में कमी से जुड़ी है…

एक उदाहरण

निम्नलिखित कोड में 4 की साइक्लोमैटिक जटिलता है।

    public void SendUserHadJoinedEmailToAdministrator(DataAccess.Database.Schema.dbo.Agency agency, User savedUser)
    {
        AgencySettingsRepository agencySettingsRepository = new AgencySettingsRepository();
        var agencySettings = agencySettingsRepository.GetById(agency.Id);

        if (agencySettings != null)
        {
            var newAuthAdmin = agencySettings.NewUserAuthorizationContact;

            if (newAuthAdmin.IsNotNull())
            {
                EmailService emailService = new EmailService();

                emailService.SendTemplate(new[] { newAuthAdmin.Email }, GroverConstants.EmailTemplate.NewUserAdminNotification, s =>
                {
                    s.Add(new EmailToken { Token = "Domain", Value = _settings.Domain });
                    s.Add(new EmailToken
                    {
                        Token = "Subject",
                        Value =
                    string.Format("New User {0} has joined {1} on myGrover.", savedUser.FullName(), agency.Name)
                    });
                    s.Add(new EmailToken { Token = "Name", Value = savedUser.FullName() });

                    return s;
                });
            }
        }
    }

आइए उपरोक्त कोड की परीक्षण योग्यता की जांच करें।

क्या यह सरल कोड है?

हां, यह है, साइक्लोमैटिक जटिलता 5 से नीचे है।

क्या कोई निर्भरताएं हैं?

हां। 2 सेवाएं हैं AgencySettingsRepository और EmailService

क्या सेवाएं मॉक करने योग्य हैं?

नहीं, उनका निर्माण विधि के भीतर छिपा हुआ है।

क्या कोड परीक्षण योग्य है?

नहीं, यह कोड परीक्षण योग्य नहीं है क्योंकि हम AgencySettingsRepository और EmailService को मॉक नहीं कर सकते।

रीफैक्टर किए गए कोड का उदाहरण

हम इस कोड को परीक्षण योग्य कैसे बना सकते हैं?

हम (कंस्ट्रक्टर इंजेक्शन का उपयोग करके) AgencySettingsRepository और EmailService को निर्भरता के रूप में इंजेक्ट करते हैं। यह हमें उन्हें एक परीक्षण से मॉक करने और अलगाव में परीक्षण करने की अनुमति देता है।

नीचे रीफैक्टर किया गया संस्करण है।

ध्यान दें कि सेवाओं को कंस्ट्रक्टर में कैसे इंजेक्ट किया जाता है। यह हमें नियंत्रित करने की अनुमति देता है कि SendMail कंस्ट्रक्टर में कौन सा कार्यान्वयन पारित किया जाता है। फिर डमी डेटा पास करना और सेवा विधि कॉल को इंटरसेप्ट करना आसान है।

public class SendEmail
{
    private IAgencySettingsRepository _agencySettingsRepository;
    private IEmailService _emailService;


    public SendEmail(IAgencySettingsRepository agencySettingsRepository, IEmailService emailService)
    {
        _agencySettingsRepository = agencySettingsRepository;
        _emailService = emailService;
    }

    public void SendUserHadJoinedEmailToAdministrator(DataAccess.Database.Schema.dbo.Agency agency, User savedUser)
    {
        var agencySettings = _agencySettingsRepository.GetById(agency.Id);

        if (agencySettings != null)
        {
            var newAuthAdmin = agencySettings.NewUserAuthorizationContact;

            if (newAuthAdmin.IsNotNull())
            {
                _emailService.SendTemplate(new[] { newAuthAdmin.Email },
                GroverConstants.EmailTemplate.NewUserAdminNotification, s =>
                {
                    s.Add(new EmailToken { Token = "Domain", Value = _settings.Domain });
                    s.Add(new EmailToken
                    {
                        Token = "Subject",
                        Value = string.Format("New User {0} has joined {1} on myGrover.", savedUser.FullName(), agency.Name)
                    });
                    s.Add(new EmailToken { Token = "Name", Value = savedUser.FullName() });

                    return s;
                });
            }
        }
    }
}

परीक्षण उदाहरण

नीचे अलगाव में परीक्षण का एक उदाहरण है। हम मॉकिंग फ्रेमवर्क FakeItEasy का उपयोग कर रहे हैं।

    [Test]
    public void TestEmailService()
    {
        //Given

        //Using FakeItEasy mocking framework
        var repository = A<IAgencySettingsRepository>.Fake();
        var service = A<IEmailService>.Fake();

        var agency = new Agency { Name = "Acme Inc." };
        var user = new User { FirstName = "Chuck", LastName = "Conway", Email = "chuck.conway@fakedomain.com" }

        //When

        var sendEmail = new SendEmail(repository, service);
        sendEmail.SendUserHadJoinedEmailToAdministrator(agency, user);


        //Then
        //An exception is thrown when this is not called.
        A.CallTo(() => service.SendTemplate(A<Agency>.Ignore, A<User>.Ignore)).MustHaveHappened();

    }

समापन

खामी-प्रतिरोधी कोड लिखना आश्चर्यजनक रूप से आसान है। गलतफहमी न करें, आप कभी भी खामी-मुक्त कोड नहीं लिखेंगे (यदि आप पता लगाते हैं कि कैसे, मुझे बताएं!), लेकिन इस लेख में रूपरेखा दी गई 4 प्रथाओं का पालन करके आप अपने कोड में पाई गई खामियों में कमी देखेंगे।

संक्षेप में, सरल कोड लिखना साइक्लोमैटिक जटिलता को लगभग 5 के आसपास रखना और विधि आकार को छोटा रखना है। परीक्षण योग्य कोड लिखना नियंत्रण का व्युत्क्रम और S.O.L.I.D सिद्धांतों का पालन करते समय आसानी से प्राप्त किया जाता है। कोड समीक्षा आपको और टीम को डोमेन और आपके द्वारा लिखे गए कोड को समझने में मदद करती है — बस अपने कोड को समझाना पड़ता है समस्याओं को प्रकट करेगा। और अंत में, यूनिट परीक्षण आपके कोड की गुणवत्ता में नाटकीय रूप से सुधार कर सकता है और भविष्य के डेवलपर्स के लिए दस्तावेज प्रदान कर सकता है।

लेखक: Chuck Conway एक AI इंजीनियर हैं जिनके पास सॉफ्टवेयर इंजीनियरिंग का लगभग 30 साल का अनुभव है। वह व्यावहारिक AI सिस्टम बनाते हैं—कंटेंट पाइपलाइन, इंफ्रास्ट्रक्चर एजेंट, और ऐसे टूल जो वास्तविक समस्याओं को हल करते हैं—और अपनी सीख को साझा करते हैं। सोशल मीडिया पर उनसे जुड़ें: X (@chuckconway) या YouTube और SubStack पर उनसे मिलें।

↑ शीर्ष पर वापस जाएं

आपको यह भी पसंद आ सकता है