design patterns - चले जाओ। एकाधिक सार स्तर से त्रुटि को संभालने के लिए सर्वोत्तम अभ्यास




design-patterns go (2)

आपको या तो एक त्रुटि को संभाल करना चाहिए या इसे संभाल नहीं करना चाहिए, लेकिन इसे उच्च स्तर (कॉल करने वाला) में सौंपना चाहिए। त्रुटि को संभालने और इसे वापस करना बुरा व्यवहार है जैसे कि कॉलर भी ऐसा करता है, त्रुटि कई बार संभाली हो सकती है

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

यदि आप इसे संभाल नहीं करना चाहते हैं, लेकिन इसे उच्च स्तर तक सौंपना चुनते हैं, तो यह बिल्कुल ठीक हो सकता है, लेकिन आप जिस त्रुटि मान को प्राप्त करते हैं, उसे वापस नहीं लौटाएं, क्योंकि यह संदर्भ के बिना कॉलर के लिए अर्थहीन हो सकता है।

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

त्रुटियों की टिप्पणियों के लिए एक सार्वजनिक पुस्तकालय है: github.com/pkg/errors ; और उसके देवताओं: errors

यह मूल रूप से 2 फ़ंक्शंस है: 1 मौजूदा त्रुटि लपेटने के लिए:

func Wrap(cause error, message string) error

और लिपटे हुए त्रुटि को निकालने के लिए:

func Cause(err error) error

इन का उपयोग करना, यह है कि आपके त्रुटि के हैंडलिंग कैसे दिखते हैं:

func (o *ObjectOne) CheckValue() error {
    if o.someValue == 0 {
        return errors.New("Object1 illegal state: value is 0")
    }
    return nil
}

और दूसरा स्तर:

func (oT *ObjectTwoHigherLevel) CheckObjectOneIsReady() error {
    if err := oT.objectOne.CheckValue(); err != nil {
        return errors.Wrap(err, "Object2 illegal state: Object1 is invalid")
    }
    return nil
}

और तीसरा स्तर: केवल 2 स्तर की जांच करें:

func (oTh *ObjectThreeHiggerLevel) CheckObjectTwoIsReady() error {
    if err := oTh.ObjectTwoHigherLevel.CheckObjectOneIsReady(); err != nil {
        return errors.Wrap(err, "Object3 illegal state: Object2 is invalid")
    }
    return nil
}

ध्यान दें कि चूंकि CheckXX() तरीके त्रुटियों को संभाल नहीं करते हैं, वे कुछ भी लॉग नहीं करते हैं वे एनोटेट किए गए त्रुटियों को सौंप रहे हैं

अगर ObjectThreeHiggerLevel का उपयोग करने वाले किसी त्रुटि को संभालने का निर्णय लेता है:

o3 := &ObjectThreeHiggerLevel{}
if err := o3.CheckObjectTwoIsReady(); err != nil {
    fmt.Println(err)
}

निम्नलिखित अच्छा आउटपुट प्रस्तुत किया जाएगा:

Object3 illegal state: Object2 is invalid: Object2 illegal state: Object1 is invalid: Object1 illegal state: value is 0

एकाधिक लॉग्स का कोई प्रदूषण नहीं है, और सभी विवरण और संदर्भ संरक्षित किए जाते हैं क्योंकि हम errors.Wrap() इस्तेमाल करते हैं। errors.Wrap() जो एक त्रुटि मान उत्पन्न करता है जो एक string प्रारूपित करता है जो लिपटे त्रुटियों को सुरक्षित रखता है, पुनरावर्ती: त्रुटि स्टैक

आप ब्लॉग पोस्ट में इस तकनीक के बारे में अधिक पढ़ सकते हैं:

डेव चेनी: बस त्रुटियों की जांच न करें, उन्हें संतोषपूर्वक प्रबंधित करें

मैं सोच रहा हूं कि जाने में त्रुटि फार्म एकाधिक स्तर के अमूर्त को संभालने का सबसे अच्छा तरीका क्या है I हर बार अगर मुझे प्रोग्राम के लिए एक नया स्तर अमूर्त जोड़ना होगा, तो मुझे त्रुटि कोड को स्तर से उच्च स्तर तक स्थानांतरित करने के लिए मजबूर कर दिया गया है। इस प्रकार लॉग फ़ाइल में डुप्लिकेट कम्युनिकेट्स हैं या मुझे कम से कम संवाद फार्म स्तर को हटाना और उन्हें उच्च स्तर पर स्थानांतरित करने के लिए remmember करना होगा। बस उदाहरण के नीचे मैं प्रत्येक ऑब्जेक्ट को अधिक शीघ्र और सेलाअर कोड बनाने के लिए छोड़ दिया, लेकिन मुझे लगता है कि आप मेरी समस्या को समझते हैं

type ObjectOne struct{
    someValue int
}

func (o* ObjectOne)CheckValue()error{
    if o.someValue == 0 {
        SomeLogger.Printf("Value is 0 error program") // communicate form first level abstraction to logger
        return errors.New("Internal value in object is 0")
    }
    return nil
}

type ObjectTwoHigherLevel struct{
    objectOne ObjectOne
}

func (oT*  ObjectTwoHigherLevel)CheckObjectOneIsReady() error{
    if err := oT.objectOne.CheckValue() ; err != nil{
        SomeLogger.Printf("Value in objectOne is not correct for objectTwo %s" , err) //  second communicate
        return  err
    }
    return nil
}

type ObjectThreeHiggerLevel struct{
    oT ObjectTwoHigherLevel
}

func (oTh* ObjectThreeHiggerLevel)CheckObjectTwoIsReady()error{
    if err := oTh.oT.CheckObjectOneIsReady() ; err != nil{
        SomeLogger.Printf("Value in objectTwo is not correct for objectThree %s" , err)
    return err
    }
    return nil
}

परिणामस्वरूप लॉग फ़ाइल में मुझे डुप्लिकेट पोस्ट मिलते हैं

Value is 0 error program 
Value in objectOne is not correct for objectTwo Internal value in object is 0 
Value in objectTwo is not correct for objectThree Internal value in object is 0

इसके बदले में अगर मैं केवल किसी अतिरिक्त लॉग के बिना उच्च स्तर पर कुछ err हस्तांतरित करता हूं तो मैं हर स्तर पर मौजूद हर चीज को खो दिया।

यह कैसे हल? कैसे गुप्त डुप्लिकेट संचार? या मेरा तरीका अच्छा और एकमात्र है?

यदि मैं कुछ वस्तु बनाऊं तो कुछ निराशा होती है, जो कुछ अमूर्त स्तर पर डेटाबेस में कुछ खोजते हैं, तो मुझे लॉगफाइल में कुछ ही लाइनें मिलती हैं।


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

ऐसी एक लाइब्रेरी:

https://github.com/go-errors/errors

और कुछ ऐसे भी हैं जो मैं भूल गए थे।





error-handling