मॉकिंग निर्भरता के साथ कार्यात्मक शैली कैसे मदद करती है?


10

हाल ही में जावा पत्रिका के एक अंक में केंट बेक के साथ साक्षात्कार से:

Binstock: आइए चर्चा करते हैं microservices की। मुझे ऐसा लगता है कि माइक्रोसर्विसेज पर परीक्षण-प्रथम इस अर्थ में जटिल हो जाएगा कि कुछ सेवाओं, कार्य करने के लिए, अन्य सेवाओं के पूरे समूह की उपस्थिति की आवश्यकता होगी। क्या आप सहमत हैं?

बेक: ऐसा लगता है कि एक ही वर्ग के व्यापार के बारे में एक ही वर्ग है या बहुत से छोटे वर्ग हैं।

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

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

उसके कहने का आशय क्या है? कार्यात्मक शैली आपको बाहरी निर्भरता का मजाक उड़ाने से कैसे मुक्त कर सकती है?



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

जवाबों:


8

एक शुद्ध कार्य यह है कि:

  1. विल हमेशा एक ही तर्क दिया एक ही परिणाम दे
  2. कोई भी देखने योग्य साइड इफेक्ट नहीं है (जैसे राज्य परिवर्तन)

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

bool UserLogin(string username, string password)
{
    var user = _database.FindUser(username);
    if (user == null)
    {
        return false;
    }
    if (user.FailedAttempts > 3)
    {
        return false;
    }
    // Password hashing omitted for brevity
    if (user.Password != password)
    {
        _database.RecordFailedLoginAttempt(username);
    }
    return true;
}

यह बहुत स्पष्ट है कि यह एक शुद्ध कार्य नहीं है:

  1. यह फ़ंक्शन हमेशा दिए गए usernameऔर passwordसंयोजन के लिए समान परिणाम नहीं देगा क्योंकि परिणाम डेटाबेस में संग्रहीत उपयोगकर्ता रिकॉर्ड पर भी निर्भर करता है।
  2. फ़ंक्शन डेटाबेस की स्थिति को बदल सकता है, अर्थात इसके दुष्प्रभाव हैं।

यह भी ध्यान रखें कि इस फ़ंक्शन को यूनिट टेस्ट करने के लिए हमें दो डेटाबेस कॉल्स को मॉक करने की आवश्यकता है, FindUserऔर RecordFailedLoginAttempt

यदि हम इस कोड को अधिक कार्यात्मक शैली में रिफलेक्टर करते तो शायद हम कुछ इस तरह से समाप्त हो सकते:

bool UserLogin(string username, string password)
{
    var user = _database.FindUser(username);
    var result = UserLoginPure(user, password);
    if (result == Result.FailedAttempt)
    {
        _database.RecordFailedLoginAttempt(username);
    }
    return result == Result.Success;
}

Result UserLoginPure(User user, string pasword)
{
    if (user == null)
    {
        return Result.UserNotFound;
    }
    if (user.FailedAttempts > 3)
    {
        return Result.LoginAttemptsExceeded;
    }
    if (user.Password != password)
    {
        return Result.FailedAttempt;        
    }
    return Result.Success;
}

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


क्या आपकी व्याख्या: अनिवार्यता-शैली = राज्य-व्यवस्था की सूक्ष्म -व्यवस्था और कार्यात्मक-शैली = स्टेटलेस microservies ?
k3b

माइक्रो सेवाओं के बारे में बिट को छोड़कर @ k3b क्रमबद्ध करें। बहुत ही साधारण शैली में राज्य में हेरफेर शामिल है जबकि कार्यात्मक शैली राज्य हेरफेर के बिना शुद्ध कार्यों का उपयोग करती है।
जस्टिन

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

कार्यात्मक दृष्टिकोण को परिणाम और उपयोगकर्ता के साथ एक जोड़ी वापस करनी चाहिए, क्योंकि असफल प्रयास पर, Result.FailedAttempt मूल के रूप में एक ही डेटा के साथ एक नए उपयोगकर्ता के साथ परिणाम है, सिवाय इसके कि एक और असफल प्रयास और एक शुद्ध कार्य करता है एक पैरामीटर के रूप में दिए गए उपयोगकर्ता पर साइड इफेक्ट्स प्रेरित करते हैं।
उदयकाल

मेरी पिछली टिप्पणी के अंतिम भाग के लिए सुधार: "और एक शुद्ध कार्य उस उपयोगकर्ता पर दुष्प्रभाव को प्रेरित नहीं करता है जो एक पैरामीटर के रूप में दिया जाता है।"
उदयकाल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.