SOLID तत्व का महत्वाचे आहेत आणि विकासकर्ते ते का वगळतात

SOLID तत्व का महत्वाचे आहेत आणि विकासकर्ते ते का वगळतात

सर्वजण SOLID तत्वांबद्दल बोलतात. तुमचे सिनियर डेव्हलपर कोड रिव्यूमध्ये त्यांचा उल्लेख करतात. तुमचे आर्किटेक्चर डॉक्युमेंटेशन त्यांचा संदर्भ देते. पण वास्तविक प्रकल्प SOLID समजून घेणार्‍या संघ असूनही का अव्यवस्थित बकवास बनतात? उत्तर: SOLID समजणे आणि त्याच्या साथ खरोखर बांधणे हे पूर्णपणे वेगळ्या गोष्टी आहेत [1].

बहुतेक विकासकर्ते SOLID लवकर शिकतात, डोके हलवतात, आणि नंतर ज्या क्षणी अंतिम मुदत येते तेव्हा या तत्वांचे उल्लंघन करतात. मला तुम्हाला दाखवू द्या जिथे रबर रस्त्यावर टेकला - आणि ते का कठीण असते.

SOLID म्हणजे काय, आणि आपल्याला त्यांची काळजी का घ्यायला हवी?

SOLID हे पाच डिজाइन तत्व आहेत जे घट्ट जोडणी कमी करतात आणि कोड व्यवस्थापनयोग्यता सुधारतात [1]. या संक्षिप्ताक्षरचा अर्थ:

  • Single Responsibility Principle — एका क्लासला बदलायचे एक कारण असावे
  • Open/Closed Principle — क्लास विस्तारासाठी खुली असणे चाहिए, सुधारणेसाठी बंद
  • Liskov Substitution Principle — सबटाइप त्यांच्या बेस प्रकारांचे स्थानापन्न असणे आवश्यक आहे
  • Interface Segregation Principle — ग्राहक ज्या इंटरफेसचा उपयोग करत नाहीत त्यावर अवलंबून असू शकत नाहीत
  • Dependency Inversion Principle — ठोस अंमलबजावणीवर नहीं तर अमूर्ततावर अवलंबून रहा

या तत्वांशिवाय, कोडबेस कठोर होतात. एका जागेतील एक बदल पाच इतर जागांना तोडतो. नई सुविधा साठी लिगेसी कोडला स्पर्श करावे लागते जो “कार्य करतो पण कोणीही त्याला स्पर्श करू इच्छित नाही”. चाचणी लिहिणे अशक्य आहे. बहुतेक प्रकल्प येथे रहातात [2].

SOLID सह, तुमचा कोडबेस श्वास घेतो. बदल अलिप्त राहतात. नई सुविधा प्रणाली द्वारे प्रसारित होत नाहीत. चाचण्या वियोगात चालतात. नई विकासकर्ताना आवडणे साठी 10-वर्षीय कोडद्वारे पुरातात्विक खोदकाम करण्याची आवश्यकता नाही.

वास्तविक उल्लंघन: SOLID कोठे हरापत जातो

देवता वर्ग — सर्वकाही एक जागी

मी यह शंभर वेळा पाहिले आहे. एक UserManager वर्ग जो वापरकर्ता डेटा, ईमेल पाठवणे, पासवर्ड हॅशिंग, लॉगिंग, पेमेंट प्रोसेसिंग, आणि प्रमाणीकरण हाताळतो. सर्व एक फाइलमध्ये. सर्व गुंफलेले [3].

class UserManager {
    public void createUser(String email, String password) {
        validateEmail(email);
        hashPassword(password);
        saveToDatabase(email, password);
        sendWelcomeEmail(email);
        logUserCreation(email);
        chargeSignupFee(email);
        trackAnalyticsEvent(email);
    }
    
    private void sendWelcomeEmail(String email) { /* ... */ }
    private void saveToDatabase(String email, String password) { /* ... */ }
    private void chargeSignupFee(String email) { /* ... */ }
    // 50 अधिक पद्धती असंबंधित गोष्टी करत आहेत
}

हे Single Responsibility Principle पूर्णपणे उल्लंघन आहे. ईमेल कसे पाठवायचे हे बदलायचे आहे? तुम्ही UserManager सुधारा. पेमेंट तर्क बदलायचे आहे? तुम्ही UserManager सुधारा. नवीन लॉग फॉर्मॅट जोडायचे आहे? तुम्ही UserManager सुधारा. आता तुम्ही स्वागत ईमेल टेम्पलेट बदलू इच्छित असताना पेमेंट कोड चाचणी करत आहात.

निराकरण: वेगळ्या वर्गांमध्ये विभागा [1]. एक वापरकर्ता स्थिरतेचे हाताळे. दुसरा ईमेल पाठवतो. तिसरा पेमेंट प्रक्रिया करतो. चौथा लॉगिंग हाताळतो. आता प्रत्येक वर्गला बदलायचे एक कारण आहे.

घट्ट जोडणी — पेमेंट सिस्टम समस्या

तुम्ही एका विशिष्ट पेमेंट प्रदानकर्त्यावर थेट अवलंबून असलेला कोड लिहितात: StripePaymentProcessor. हे कार्य करते. तुमचा व्यवसाय वाढतो. आता तुम्ही PayPal समर्थन करू इच्छित आहात. किंवा क्रिप्टोकरन्सी. किंवा काही नवीन स्थानिक पेमेंट प्रणाली [4].

class OrderService {
    private StripePaymentProcessor stripe = new StripePaymentProcessor();
    
    public void processOrder(Order order) {
        // ... validation code ...
        stripe.charge(order.getAmount());
    }
}

PayPal समर्थन जोडण्यासाठी, तुम्ही OrderService सुधारा. क्रिप्टो जोडण्यासाठी, तुम्ही पुन्हा सुधारा. तुम्ही प्रत्येक पेमेंट प्रदानकर्त्यासाठी व्यावसायिक तर्क कोड सुधारत आहात. हे Open/Closed Principle चे उल्लंघन करते — तुमचा कोड विस्तारासाठी खुला असावा (नवीन पेमेंट प्रकार) पण सुधारणेसाठी बंद [2].

निराकरण: अमूर्तातावर अवलंबून राहा:

interface PaymentGateway {
    void charge(BigDecimal amount);
}

class OrderService {
    private PaymentGateway gateway;
    
    public OrderService(PaymentGateway gateway) {
        this.gateway = gateway;
    }
    
    public void processOrder(Order order) {
        gateway.charge(order.getAmount());
    }
}

PayPal जोडायचे आहे? एक PayPalPaymentGateway तयार करा, त्याचा इंजेक्शन करा, पूर्ण. तुमचा OrderService कधीही बदलत नाही [4].

मोठे इंटरफेस — न वापरलेल्या पद्धतीचे अंमलबजावणी करण्यास भाग पाडणे

तुम्ही एक इंटरफेस तयार करा जो “व्यापक” आहे:

interface PaymentProcessor {
    void charge(BigDecimal amount);
    void refund(BigDecimal amount);
    void setupRecurringPayment(BigDecimal amount, Frequency frequency);
    void validateCard(String cardNumber);
    void handleChargebackDispute(String transactionId);
}

नंतर एक CryptoCurrencyPayment वर्ग या इंटरफेसचा अंमलबजावणी करतो. क्रिप्टोकरन्सी पुनरावृत्ती पेमेंट करत नाही असे मानून. त्याला चार्जबॅक नाही. विकासकर्ते अर्ध्या पद्धती साठी NotImplementedException फेकण्यास भाग पाडले जातात [3].

हे Interface Segregation Principle चे उल्लंघन करते. अद्याप लहान, केंद्रीभूत इंटरफेस तयार करा:

interface Chargeable {
    void charge(BigDecimal amount);
}

interface Refundable {
    void refund(BigDecimal amount);
}

interface RecurringBillable {
    void setupRecurring(BigDecimal amount);
}

आता CryptoCurrencyPayment फक्त Chargeable अंमलबजावणी करतो. कोणते झूठे अंमलबजावणी नाहीत. कोणता गोंधळ नाही [3].

SOLID तत्व पालन करणे असे का कठीण आहे

समजणे की आपण SOLID का उल्लंघन करतो हे नियम लक्षात ठेवण्यापेक्षा अधिक महत्वाचे आहे.

अंतिम मुदत सापळा

तुम्ही 10 दिवसाच्या स्प्रिंटच्या 9 व्या दिवसावर आहात. सुविधा पूर्ण केली जाणे आवश्यक आहे. तुम्ही UserManager वर्ग रीफॅक्टर करू शकता, त्याला योग्यरित्या विभागू शकता, अवलंबितता इंजेक्ट करू शकता. किंवा तुम्ही 5 मिनिटात विद्यमान वर्गात एक पद्धती जोडू शकता.

तुम्ही पद्धती जोडता [5].

उद्या, आणखी एक अंतिम मुदत. विद्यमान वर्गात आणखी एक छोटी जोड. सप्ताहाच्या दोन व्या दिवशी, तुम्ही SOLID इतक्या वेळा उल्लंघन केले आहे की त्याला ठीक करणे दिवसांचे लागेल. महिना दोघाने, कोणीही त्या कोडला स्पर्श करू शकत नाही. हे बहुतेक प्रकल्पांचे अंत आहे. कारण विकासकर्ते आळशी आहेत या कारणामुळे नाही. कारण अंतिम मुदत वास्तविक आहेत आणि रीफॅक्टरिंगला अप्रत्याशित वेळ लागतो.

तत्वांची अस्पष्टता

Single Responsibility सोपे वाटते: बदलायचे एक कारण. पण “एक कारण” म्हणजे काय? एक User वर्ग ईमेल आणि पासवर्ड वैधतेसह एक जबाबदारी किंवा दोन आहे? एक Payment वर्ग चार्ज आणि रिफंड दोन्ही हाताळणे एक जबाबदारी आहे? [5]

भिन्न विकासकर्ते यह वेगळ्या रीतीने सांगितात. मी असे संघ पाहिले आहे जे वापरकर्ता ईमेलला पाच वेगळ्या वर्गांमध्ये विभागतात (अत्यधिक अभियांत्रिकी). मी असे इतर संघ पाहिले आहे ज्यांनी एक वर्गात 50 पद्धती ठेवल्या आहेत (कमी अभियांत्रिकी). कोणता उजळ रेषा नाही.

अत्यधिक अभियांत्रिकी आणि अत्यधिक अमूर्तता

कनिष्ठ विकासकर्ते SOLID बद्दल वाचतात आणि वेडे जातात. ते प्रत्येक समस्येला प्रत्येक तत्व लागू करतात. एक साधारण फॉर्म वैधता वर्ग तीन अमूर्त वर्ग, दोन इंटरफेस, आणि अवलंबितता इंजेक्शन कंटेनरमध्ये रीफॅक्टर करले जाते [5].

कोड वाचणे अधिक कठीण बनते, सोपे नाही. तुम्हाला पाच फाइलींमध्ये उड्डाण करण्याची आवश्यकता आहे जे तीन ओळींचा तर्क असावे. तुमचा चाचणी सुइट वास्तविक कोडपेक्षा अधिक जटिल होतो.

SOLID तत्व साधने आहेत, कायदे नाही. एक साधारण स्क्रिप्टला SOLID आवश्यक नाही. एक युटिलिटी फंक्शनला SOLID आवश्यक नाही. एक एकबारी डेटा प्रोसेसिंग जॉबला SOLID आवश्यक नाही. SOLID वर्षे राहणार्‍या आणि सतत बदल आवश्यक असणार्‍या कोडबेससाठी महत्वाचे आहे [5].

संघ संरेखण कठीण आहे

अगदी जर तुमचा संघ SOLID पालन करण्यास सहमत असेल, तरीही त्याचा अर्थ लगातार वादविवादाचा स्रोत आहे [5].

  • सिनियर डेव्हलपर म्हणतात: “या वर्गात खूप पद्धती आहेत, विभागा.”
  • कनिष्ठ डेव्हलपर म्हणतात: “पण सर्व पेमेंट संबंधित आहे, एकत्र असावे.”
  • आर्किटेक्ट म्हणतात: “तुम्हाला दोघांना इंटरफेस सेग्रिगेशन समस्या दिसत नाही येथे.”

सहा महिने, तुमचा कोडबेस असे दिसते की तीन भिन्न लोकांनी SOLID चे तीन भिन्न अर्थांसह लिहिले. कोड रिव्यू वैशिष्ट्य शिपिंग या बदल्या तत्वांबद्दल वादविवाद बनतो.

लिगेसी कोड रीफॅक्टरिंगसाठी महाग आहे

बहुतेक प्रकल्प स्वच्छपणे सुरू होत नाहीत. ते एक फाइलमध्ये सर्वकाही सुरू होतात. नंतर त्याची वाढ होते. नंतर SOLID महत्वाचे असते. नंतर त्याचा रीफॅक्टरिंग एक दुःस्वप्न बनतो.

तुम्ही फक्त UserManager वर्ग विभागू शकत नाही. त्याला कोडबेसमधून 500 अवलंबितता आहेत. डेटाबेस कनेक्शन स्ट्रिंग हार्डकोडेड. कॉन्फिगरेशन बेक केले. जागतिक स्थिती सर्वत्र विखुरली आहे [5].

त्याचा “योग्य” रीफॅक्टरिंग मतलब 200 फाइलींना स्पर्श करणे. काहीतरी तोडण्याचा धोका जास्त आहे. तुमच्या चाचण्या (जर अस्तित्वात असल्यास) धीमी आणि नाजूक आहेत कारण ते देवता वर्गावर अवलंबून आहेत.

प्रकल्पांना अजूनही SOLID का आवश्यक आहे

या सर्व आव्हानांसह, SOLID पालन करणार्‍या प्रकल्प नाटकीयरीत्या राखणे सोपे आहेत [1]. गोष्ट अशी आहे: तुम्हाला पहिल्या काही महिन्यांसाठी SOLID उल्लंघन करण्याचा वेदना जाणवत नाही. तुम्हाला एक वर्षानंतर जाणवते.

एक वर्षानंतर देवता वर्गात सुविधा जोडल्यानंतर, त्या एक पेमेंट प्रोसेसिंग पद्धतीचा आकार आता 200 ओळी आहे. हे तीन भिन्न पेमेंट प्रदानकर्ते, लिगेसी पेमेंट प्रकार, आणि VIP वापरकर्ता स्तर प्रणालीसाठी किनारे प्रकरणे हाताळते. जेव्हा तुम्हाला चौथा प्रदानकर्ता जोडायचे आहे, तेव्हा तुम्ही या पद्धतीला बदलू भीत आहात.

घट्ट जोडणीनंतर एक वर्षानंतर, डेटाबेस लेयर रीफॅक्टरिंग मतलब 50 फाइलींना स्पर्श करणे. मोठे इंटरफेसनंतर एक वर्षानंतर, नवीन अंमलबजावणी जोडणे मतलब पाच वर्गांमध्ये स्टब पद्धती लिहिणे.

SOLID अप्रत्याशित महाग आहे. दीर्घकाळीन सस्ते आहे.

प्रकल्प जे कधीही हा धडा शिकले नाहीत ते “लिगेसी कोड” सह समाप्त होतात जो बदलता येत नाही कारण त्याला खूप जोखीम आहे. नई सुविधा सप्ताहांऐवजी दिवसांचे लागतात. साधारण बग निराकरण साठी सहा गुंफलेले वर्ग समजून घेणे आवश्यक आहे. तेव्हा लोक संपूर्ण प्रणाली पुन्हा लिहितात (जे जवळजवळ कधीही उपाय नाही).

End

स्रोत

  1. SOLID Principles with Real Life Examples - GeeksforGeeks
  2. SOLID Design Principles Explained: Building Better Software Architecture - DigitalOcean
  3. SOLID Design Principles: The Single Responsibility Explained - Stackify
  4. The Dependency Inversion Principle in Java - Baeldung
  5. 5 Problems Faced When Using SOLID Design Principles - Better Programming