Database
 sql >> डेटाबेस >  >> RDS >> Database

समस्या डिजाइन के प्रमुख संकेतक

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

इस डिज़ाइन में आमतौर पर निम्नलिखित संकेतक होते हैं (एक समय में एक या कई):

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

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

हम हर फीचर के आधार पर इस समस्या को दूर करने जा रहे हैं।

कठोरता

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

लोकप्रिय कठोरता मामलों में से एक अमूर्त (इंटरफ़ेस, बेस क्लास, आदि) का उपयोग करने के बजाय वर्ग प्रकारों को स्पष्ट रूप से निर्दिष्ट करना है। नीचे, आप कोड का एक उदाहरण पा सकते हैं:

class A
{
  B _b;
  public A()
  {
    _b = new B();
  }

  public void Foo()
  {
    // Do some custom logic.
    _b.DoSomething();
    // Do some custom logic.
  }
}

class B
{
   public void DoSomething()
  {
    // Do something
   }
}

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

वर्कअराउंड एक अमूर्त है जो कक्षा ए के निर्माता के माध्यम से आईसीओम्पोनेंट इंटरफ़ेस पेश करना है। इस मामले में, यह अब विशेष वर्ग В पर निर्भर नहीं होगा और केवल आईकंपोनेंट इंटरफ़ेस पर निर्भर करेगा। lass को अपनी बारी में IComponent इंटरफ़ेस लागू करना चाहिए।

interface IComponent
{
  void DoSomething();
}

class A
{
  IComponent _component;
  public A(IComponent component)
  {
    _component = component;
  }

  void Foo()
  {
     // Do some custom logic.    
     _component.DoSomething();
     // Do some custom logic.
   }
}

class B : IComponent
{
  void DoSomething()
  {
    // Do something
  }
}

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

// Module 1 (Client)
static void Main()
{
  var product = new Product("milk");
  var productManager = new ProductManager();
  productManager.AddProduct(product);
  var consumer = new Consumer();
  consumer.PurchaseProduct(product.Name);
}

// Module 2 (Business logic)
public class ProductManager
{
  private readonly FileLogger _logger = new FileLogger();
  public void AddProduct(Product product)
  {
    // Add the product to the database.
    _logger.Log("The product is added.");
  }
}

public class Consumer
{
  private readonly FileLogger _logger = new FileLogger();
  public void PurchaseProduct(string product)
  {
     // Purchase the product.
    _logger.Log("The product is purchased.");
  }
}

public class Product
{
  public string Name { get; private set; }
  public Product(string name)
  {
    Name = name;
  }
}

// Module 3 (Logger implementation)
public class FileLogger
{
  const string FileName = "log.txt";
  public void Log(string message)
  {
    // Write the message to the file.
  }
}

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

// Module 1 (Client)
static void Main()
{
  var logger = new FileLogger();
  var product = new Product("milk");
  var productManager = new ProductManager(logger);
  productManager.AddProduct(product);
  var consumer = new Consumer(logger);
  consumer.PurchaseProduct(product.Name);
}

// Module 2 (Business logic)
class ProductManager
{
  private readonly ILogger _logger;
  public ProductManager(ILogger logger)
  {
    _logger = logger;
  }
  
  public void AddProduct(Product product)
  {
    // Add the product to the database.
    _logger.Log("The product is added.");
  }
}

public class Consumer
{
  private readonly ILogger _logger;
  public Consumer(ILogger logger)
  {
    _logger = logger;
  }

  public void PurchaseProduct(string product)
  {
     // Purchase the product.
    _logger.Log("The product is purchased.");
  }
}

public class Product
{
  public string Name { get; private set; }
  public Product(string name)
  {
    Name = name;
  }
}

// Module 3 (interfaces)
public interface ILogger
{
  void Log(string message);
}

// Module 4 (Logger implementation)
public class FileLogger : ILogger
{
  const string FileName = "log.txt";
  public virtual void Log(string message)
  {
    // Write the message to the file.
  }
}

इस मामले में, लॉगर प्रकार बदलते समय, क्लाइंट कोड (मुख्य) को संशोधित करने के लिए पर्याप्त है, जो लॉगर को प्रारंभ करता है और इसे उत्पाद प्रबंधक और उपभोक्ता के निर्माता में जोड़ता है। इस प्रकार, हमने आवश्यकतानुसार लकड़हारा प्रकार के संशोधन से व्यावसायिक तर्क की कक्षाओं को बंद कर दिया।

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

static void Main()
{
  var rectangle = new Rectangle() { W = 3, H = 5 };
  var circle = new Circle() { R = 7 };
  var shapes = new Shape[] { rectangle, circle  };
  ShapeHelper.ReportShapesSize(shapes);
}

class ShapeHelper
{
  private static double GetShapeArea(Shape shape)
  {
    if (shape is Rectangle)
    {
      return ((Rectangle)shape).W * ((Rectangle)shape).H;
    }
    if (shape is Circle)
    {
      return 2 * Math.PI * ((Circle)shape).R * ((Circle)shape).R;
    }
    throw new InvalidOperationException("Not supported shape");
  }

  public static void ReportShapesSize(Shape[] shapes)
  {
    foreach(Shape shape in shapes)
    {
       if (shape is Rectangle)
       {
         double area = GetShapeArea(shape); 
         Console.WriteLine($"Rectangle's area is {area}");
       }
       if (shape is Circle)
       {
         double area = GetShapeArea(shape); 
         Console.WriteLine($"Circle's area is {area}");
       }
    }
  }
}

public class Shape
{  }

public class Rectangle : Shape
{
  public double W { get; set; }
  public double H { get; set; }
}

public class Circle : Shape
{
  public double R { get; set; }
}

जैसा कि आप देख सकते हैं, एक नया पैटर्न जोड़ते समय, हमें शेपहेल्पर वर्ग के तरीकों को बदलना होगा। विकल्पों में से एक है, जैसा कि नीचे दिखाया गया है, ज्यामितीय पैटर्न (आयत और वृत्त) की कक्षाओं में प्रतिपादन के एल्गोरिथ्म को पारित करना है। इस तरह, हम संबंधित लॉजिक को संबंधित क्लास में इंसुलेट करेंगे जिससे कंसोल पर जानकारी प्रदर्शित करने से पहले शेपहेल्पर क्लास की जिम्मेदारी कम हो जाएगी।

static void Main()
{
  var rectangle = new Rectangle() { W = 3, H = 5 };
  var circle = new Circle() { R = 7 };
  var shapes = new Shape[]() { rectangle, circle  };
  ShapeHelper.ReportShapesSize(shapes);
}

class ShapeHelper
{
  public static void ReportShapesSize(Shape[] shapes)
  {
    foreach(Shape shape in shapes)
    {
       shape.Report();
    }
  }
}

public abstract class Shape
{
  public abstract void Report();
}

public class Rectangle : Shape
{
  public double W { get; set; }
  public double H { get; set; }
  public override void Report()
  {
     double area = W * H;
     Console.WriteLine($"Rectangle's area is {area}");
  }
}

public class Circle : Shape
{
  public double R { get; set; }
  public override void Report()
  {
     double area = 2 * Math.PI * R * R;
     Console.WriteLine($"Circle's area is {area}");
  }
}

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

स्थिरता

कोड को पुन:प्रयोज्य मॉड्यूल में विभाजित करते समय हम गतिहीनता की निगरानी कर सकते हैं। परिणामस्वरूप, परियोजना का विकास और प्रतिस्पर्धी होना बंद हो सकता है।

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

  • उपयोगकर्ता इंटरफ़ेस को वेब एप्लिकेशन में बदलकर बदलने के लिए;
  • कार्यक्रम की कार्यक्षमता को तीसरे पक्ष के ग्राहकों के लिए उपलब्ध वेब सेवाओं के एक सेट के रूप में प्रकाशित करने के लिए जिसका उपयोग उनके स्वयं के अनुप्रयोगों में किया जा सकता है।

इस मामले में, इन आवश्यकताओं को पूरा करना मुश्किल है, क्योंकि पूरा कोड निष्पादन योग्य मॉड्यूल में स्थित है।

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

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

चिपचिपापन

दो प्रकार के होते हैं:

  • विकास चिपचिपापन
  • पर्यावरण चिपचिपापन

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

एक साधारण उदाहरण के रूप में, हम स्थिरांक वाले कार्य पर विचार कर सकते हैं जिन्हें अन्य घटकों (मॉड्यूल 2 और मॉड्यूल 3) द्वारा उपयोग किए जाने के लिए एक अलग मॉड्यूल (मॉड्यूल 1) में (डिजाइन द्वारा) रखा जाना है।

// Module 1 (Constants)
static class Constants
{
  public const decimal MaxSalary = 100M;
  public const int MaxNumberOfProducts = 100;
}
 
// Finance Module
#using Module1
static class FinanceHelper
{
  public static bool ApproveSalary(decimal salary)
  {
    return salary <= Constants.MaxSalary;
  }
} 
 
// Marketing Module
#using Module1
class ProductManager
{
  public void MakeOrder()
  {
    int productsNumber = 0;
    while(productsNumber++ <= Constants.MaxNumberOfProducts)
    {
      // Purchase some product
    }
  }
}

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

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

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

अनावश्यक जटिलता

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

class DataManager
{
  object[] GetData()
  {
    // Retrieve and return data
  }
}

यदि डेवलपर डेटाबेस (WriteData) में डेटा लिखने के लिए DataManager में एक नई विधि जोड़ता है, जिसका भविष्य में उपयोग किए जाने की संभावना नहीं है, तो यह एक अनावश्यक जटिलता भी होगी।

एक अन्य उदाहरण सभी उद्देश्यों के लिए एक इंटरफ़ेस है। उदाहरण के लिए, हम सिंगल प्रोसेस मेथड के साथ एक इंटरफ़ेस पर विचार करने जा रहे हैं जो स्ट्रिंग प्रकार के ऑब्जेक्ट को स्वीकार करता है।

interface IProcessor
{
  void Process(string message);
}

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

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

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

अनावश्यक दोहराव

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

अनावश्यक पुनरावृत्ति डेवलपर्स की लापरवाही के साथ-साथ डिजाइन की कठोरता/नाजुकता के कारण हो सकती है जब ऐसा करने के बजाय कोड को दोहराना अधिक कठिन और जोखिम भरा होता है। हालांकि, किसी भी मामले में, दोहराव एक अच्छा विचार नहीं है, और कोड को लगातार सुधारना आवश्यक है, पुन:प्रयोज्य भागों को सामान्य तरीकों और कक्षाओं में पास करना।

खराब पठनीयता

आप इस सुविधा की निगरानी तब कर सकते हैं जब किसी कोड को पढ़ना और यह समझना मुश्किल हो कि इसे किस लिए बनाया गया है। खराब पठनीयता के कारण कोड निष्पादन (वाक्यविन्यास, चर, वर्ग), एक जटिल कार्यान्वयन तर्क, आदि के लिए आवश्यकताओं का अनुपालन न करना हो सकता है।

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

void Process_true_false(string trueorfalsevalue)
{
  if (trueorfalsevalue.ToString().Length == 4)
  {
    // That means trueorfalsevalue is probably "true". Do something here.
  }
  else if (trueorfalsevalue.ToString().Length == 5)
  {
    // That means trueorfalsevalue is probably "false". Do something here.
  }
  else
  {
    throw new Exception("not true of false. that's not nice. return.")
  }
}

यहां, हम कई मुद्दों को रेखांकित कर सकते हैं। सबसे पहले, विधियों और चर के नाम आम तौर पर स्वीकृत सम्मेलनों के अनुरूप नहीं होते हैं। दूसरे, इस पद्धति का कार्यान्वयन सबसे अच्छा नहीं है।

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

तीसरा, अपवाद का पाठ आधिकारिक शैली के अनुरूप नहीं है। इस तरह के ग्रंथों को पढ़कर, ऐसा महसूस हो सकता है कि कोड एक शौकिया द्वारा बनाया गया है (फिर भी, कोई मुद्दा हो सकता है)। यदि यह एक बूलियन मान लेता है तो विधि को इस प्रकार फिर से लिखा जा सकता है:

public void Process(bool value)
{
  if (value)
  {
    // Do something.
  }
  else
  {
    // Do something.
  }
}

यदि आपको अभी भी एक स्ट्रिंग लेने की आवश्यकता है तो रिफैक्टरिंग का एक और उदाहरण यहां दिया गया है:

public void Process(string value)
{
  bool bValue = false;
  if (!bool.TryParse(value, out bValue))
  {
    throw new ArgumentException($"The {value} is not boolean");
  }  
  if (bValue)
  {
    // Do something.
  }
  else
  {
    // Do something.
  }
}

हार्ड-टू-रीड कोड के साथ रिफैक्टरिंग करने की सिफारिश की जाती है, उदाहरण के लिए, जब इसके रखरखाव और क्लोनिंग से कई बग होते हैं।

नाजुकता

प्रोग्राम की नाजुकता का मतलब है कि संशोधित होने पर आसानी से क्रैश किया जा सकता है। क्रैश दो प्रकार के होते हैं:संकलन त्रुटियाँ और रनटाइम त्रुटियाँ। पहले वाले कठोरता का पिछला भाग हो सकते हैं। बाद वाले सबसे खतरनाक होते हैं क्योंकि वे क्लाइंट साइड पर होते हैं। तो, वे नाजुकता के संकेतक हैं।

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

इसके अलावा, जिस कार्यक्षमता को संशोधित नहीं किया जा रहा है वह अक्सर क्रैश हो जाती है। यह विभिन्न घटकों के तर्क के उच्च युग्मन से ग्रस्त हो सकता है।

विशेष उदाहरण पर विचार करें। यहां एक विशेष संसाधन (रिसोर्सयूरी के रूप में परिभाषित) तक पहुंचने के लिए एक निश्चित भूमिका (रोल किए गए पैरामीटर के रूप में परिभाषित) के साथ उपयोगकर्ता प्राधिकरण का तर्क स्थिर विधि में स्थित है।

static void Main()
{
  if (Helper.Authorize(1, "/pictures"))
  {
    Console.WriteLine("Authorized");
  }
}

class Helper
{
  public static bool Authorize(int roleId, string resourceUri)
  {
    if (roleId == 1 || roleId == 10)
    {
      if (resourceUri == "/pictures")
      {
        return true;
      }
    }

    if (roleId == 1 || roleId == 2 && resourceUri == "/admin")
    {
      return true;
    }

    return false;
  }
}

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

static void Main()
{
  var picturesResource = new Resource() { Uri = "/pictures" };
  picturesResource.AddRole(1);
  if (picturesResource.IsAvailable(1))
  {
    Console.WriteLine("Authorized");
  }
}

class Resource
{
  private List<int> _roles = new List<int>();
  public string Uri { get; set; }
  public void AddRole(int roleId)
  {
    _roles.Add(roleId);
  }
  public void RemoveRole(int roleId)
  {
    _roles.Remove(roleId);
  }
  public bool IsAvailable(int roleId)
  {
    return _roles.Contains(roleId);
  }
}

इस मामले में, नए संसाधनों और भूमिकाओं को जोड़ने के लिए, प्राधिकरण तर्क कोड को संशोधित करना बिल्कुल भी आवश्यक नहीं है, अर्थात वास्तव में तोड़ने के लिए कुछ भी नहीं है।

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

अक्सर, नाजुकता खराब डिज़ाइन के अन्य पहचानकर्ताओं जैसे कठोरता, खराब पठनीयता और अनावश्यक पुनरावृत्ति का एक पिछला हिस्सा है।

निष्कर्ष

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL, तालिका संरचना को कैसे अपडेट करें

  2. INSTEAD OF ट्रिगर्स के बारे में रोचक बातें

  3. क्या इंटेल सर्वर सीपीयू स्पेस में बर्बाद हो गया है?

  4. शुरुआती के लिए एसक्यूएल अद्यतन

  5. विशेष द्वीप