कोडेबल: गलत एनम वैल्यू को हैंडल करना

May 09 2023
अपने कोडबेस की सुरक्षा करना: अप्रत्याशित एनम मूल्यों से निपटना कभी ऐसी स्थिति का सामना करना पड़ा जहां आपका ऐप कहीं से भी दुर्घटनाग्रस्त होना शुरू हो गया, जिसकी जांच से पता चलता है कि बैकएंड ने कुछ एनम आधारित फ़ील्ड के लिए एक मूल्य प्रदान किया है जो कोड में एनम के अंदर मौजूद नहीं है? निम्नलिखित उदाहरण पर विचार करें: ओह, मुझे कुछ चाय बहुत पसंद है लेकिन क्या होगा यदि हम JSON डेटा में पसंदीदा पेय को चाय से जूस में बदल दें (एक मान जो एनम, पेय के अंदर मौजूद नहीं है)? संदेश के भाग पर फ़ोकस करें: "अमान्य स्ट्रिंग मान जूस से पेय को प्रारंभ नहीं किया जा सकता" यदि यह खेल के मैदान के कोड के बजाय एक वास्तविक ऐप होता, तो ऐप क्रैश हो जाता। तो, हम इस तथ्य का कैसे ध्यान रखते हैं कि भले ही बैकएंड प्रतिक्रिया में एक अमान्य मान भेजता है, हमारा ऐप एकमुश्त दुर्घटनाग्रस्त होने के बजाय इसे संभालने में सक्षम होना चाहिए? तरीकों में से एक, और मेरा निजी पसंदीदा:

अपने कोडबेस की सुरक्षा करना: अप्रत्याशित एनम मूल्यों से निपटना

Unsplash पर Kostiantyn Li द्वारा फोटो

कभी ऐसी स्थिति का सामना करना पड़ा जहां आपका ऐप कहीं से भी दुर्घटनाग्रस्त होना शुरू हो गया, जिसकी जांच से पता चलता है कि बैकएंड ने कुछ एनुम आधारित फ़ील्ड के लिए एक मूल्य प्रदान किया है जो कोड में एनम के अंदर मौजूद नहीं है?

निम्नलिखित उदाहरण पर विचार करें:

import Foundation

struct Person: Codable {
    let name: String
    let favouriteBeverage: Beverage
}

enum Beverage: String, Codable {
    case Tea
    case Coffee
}

let jsonString = """
{
    "name": "Shubham Bakshi",
    "favouriteBeverage": "Tea"
}
""".data(using: .utf8)!

let decodedJSON = try! JSONDecoder().decode(Person.self, from: jsonString)

switch decodedJSON.favouriteBeverage {
    
case .Tea:
    print("Ohhh I love some Tea")
    
case .Coffee:
    print("Coffee is no Tea but meh, I'll take it")
}

ओह्ह मुझे कुछ चाय बहुत पसंद है

लेकिन क्या होगा अगर हम favouriteBeverageJSON डेटा को चाय से जूस में बदल दें (एक मान जो एनम, बेवरेज के अंदर मौजूद नहीं है )?

let jsonString = """
{
    "name": "Shubham Bakshi",
    "favouriteBeverage": "Juice"
}
""".data(using: .utf8)!

संदेश के भाग पर फ़ोकस करें: "अमान्य स्ट्रिंग मान रस से पेय प्रारंभ नहीं कर सकता"

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

तरीकों में से एक, और मेरा व्यक्तिगत पसंदीदा: गलत एनम फॉलबैक तंत्र।

यह तंत्र कहता है लेकिन कमोबेश एक प्रोटोकॉल है जो हर चीज का ख्याल रखता है। तो अब हम शुरू करें …।

/// This is useful in case the backend specifies some value that does not 
/// exist inside the enum as in such cases the app crashes since it fails to 
/// parse the enum.
/// 
/// This ensures that in case an invalid value is specified, the app will 
/// not crash but rather resort to a value specified for 
/// `fallbackForIncorrectEnumValue`
///
protocol IncorrectEnumFallbackMechanism: RawRepresentable, Codable {
    
    /// Fallback value in case the backend returns an incorrect value for 
    /// the enum
    static var fallbackForIncorrectEnumValue: Self { get }
}

extension IncorrectEnumFallbackMechanism where RawValue: Codable {
    
    init(from decoder: Decoder) throws {
        
        // Fetching the value specified inside the JSON
        let value = try decoder.singleValueContainer().decode(RawValue.self)
        
        // Creating the instance based on the provided value or falling back 
        // to a default value in case the provided value for creating is 
        // invalid
        self = Self(rawValue: value) ?? Self.fallbackForIncorrectEnumValue
    }
    
    /// Since `RawRepresentable` declares a `encode(coder:)` by default so we 
    /// don't need to implement that explicitly
}

enum Beverage: String, IncorrectEnumFallbackMechanism {
    
    static var fallbackForIncorrectEnumValue: Beverage = .SomeWeirdBeverage
    
    case Tea
    case Coffee
    
    case SomeWeirdBeverage
}

इंतज़ार! वह क्या है?

कोई फर्क नहीं पड़ता कि बैकएंड हमें किस रूप में भेजता है favouriteBeverage, हम इसे संभाल सकेंगे, या इसे पी सकेंगे, जो भी हो!

तो हमारा पूरा कोड अब इस तरह दिखेगा:

import Foundation

/// This is useful in case the backend specifies some value that does not
/// exist inside the enum as in such cases the app crashes since it fails to
/// parse the enum.
///
/// This ensures that in case an invalid value is specified, the app will
/// not crash but rather resort to a value specified for
/// `fallbackForIncorrectEnumValue`
///
protocol IncorrectEnumFallbackMechanism: RawRepresentable, Codable {
    
    /// Fallback value in case the backend returns an incorrect value for
    /// the enum
    static var fallbackForIncorrectEnumValue: Self { get }
}

extension IncorrectEnumFallbackMechanism where RawValue: Codable {
    
    init(from decoder: Decoder) throws {
        
        // Fetching the value specified inside the JSON
        let value = try decoder.singleValueContainer().decode(RawValue.self)
        
        // Creating the instance based on the provided value or falling back
        // to a default value in case the provided value for creating is
        // invalid
        self = Self(rawValue: value) ?? Self.fallbackForIncorrectEnumValue
    }
    
    /// Since `RawRepresentable` declares a `encode(coder:)` by default so we
    /// don't need to implement that explicitly
}

struct Person: Codable {
    let name: String
    let favouriteBeverage: Beverage
}

enum Beverage: String, IncorrectEnumFallbackMechanism {
    
    static var fallbackForIncorrectEnumValue: Beverage = .SomeWeirdBeverage
    
    case Tea
    case Coffee
    
    case SomeWeirdBeverage
}

let jsonString = """
{
    "name": "Shubham Bakshi",
    "favouriteBeverage": "Juice"
}
""".data(using: .utf8)!

let decodedJSON = try! JSONDecoder().decode(Person.self, from: jsonString)

switch decodedJSON.favouriteBeverage {
    
case .Tea:
    print("Ohhh I love some Tea")
    
case .Coffee:
    print("Coffee is no Tea but meh, I'll take it")
    
case .SomeWeirdBeverage:
    print("Wait! What is that?")
}

बस इतना ही, लोग! हैप्पी कोडिंग!

आप मेरे साथ LinkedIn पर जुड़ सकते हैं या अन्य चैनलों के माध्यम से मुझसे संपर्क कर सकते हैं