अलीकडील एका डिप्लॉयमेंटमुळे तीन मायक्रोसर्व्हिसेस बिघडल्या, जरी प्रत्येक युनिट टेस्ट, इंटिग्रेशन टेस्ट आणि मॉक-सर्व्हर चेक यशस्वी झाला होता. टीमने त्यांच्या API मॉक्सच्या जागी कॉन्ट्रॅक्ट टेस्टिंगचा वापर सुरू केला. सहा महिन्यांत कॉन्ट्रॅक्टची संख्या तीनवरून ४७ वर पोहोचली आणि मासिक इंटिग्रेशन-फेल्युअर रेट दोन घटनांवरून शून्य झाला.
मॉक्स तुमचे संरक्षण का करू शकत नाहीत
मॉक सर्व्हर फक्त कन्झ्युमरला अपेक्षित असलेल्या स्वरूपाची नक्कल करतो; प्रोव्हायडर प्रत्यक्षात तेच स्वरूप प्रदान करतो की नाही, हे तो कधीच तपासत नाही. जर प्रोव्हायडरने एखादे फील्ड बदलले—समजा name वरून display_name केले—तर मॉक अजूनही जुनाच पेलोड (payload) परत करतो, कन्झ्युमरच्या टेस्ट्स 'ग्रीन' राहतात आणि प्रत्यक्ष सिस्टिम क्रॅश होते. मंगळवारी दुपारी २ वाजता झालेली प्रोडक्शन फेल्युअर नेमकी हीच होती: मॉकने वास्तविक कॉन्ट्रॅक्टबद्दल "खोटे" बोलले होते.
कॉन्ट्रॅक्ट टेस्टिंगमधील त्रुटी भरून काढते
कॉन्ट्रॅक्ट टेस्टिंगमुळे कोणताही कोड प्रोडक्शनमध्ये जाण्यापूर्वी API च्या दोन्ही बाजू एका सामायिक व्याख्येवर (shared definition) सहमत होण्यास भाग पाडल्या जातात. यासाठी दोन सामान्य दृष्टिकोन आहेत:
- Consumer-driven contracts – कन्झ्युमर सर्व्हिस अपेक्षा लिहिते; प्रोव्हायडर सर्व्हिस त्यांची पडताळणी करते. हे एकत्र विकसित होणाऱ्या अंतर्गत मायक्रोसर्व्हिसेससाठी चांगले काम करते.
- Provider-driven contracts – प्रोव्हायडर एक स्पेसिफिकेशन प्रकाशित करतो; कन्झ्युमर त्यांच्या कोडची त्याविरुद्ध तपासणी करतात. सार्वजनिक APIs साठी हा सामान्य पॅटर्न आहे.
पहिला दृष्टिकोन सामान्यतः मायक्रोसर्व्हिस आर्किटेक्चरमधील बिघडलेल्या इंटिग्रेशन्सना रोखतो.
कन्झ्युमर-ड्रिव्हन कॉन्ट्रॅक्ट कसे काम करते
- कन्झ्युमर एक टेस्ट लिहितो जी प्रोव्हायडरकडून त्याला नेमके काय हवे आहे याचे वर्णन करते.
- टेस्ट रन केल्यावर एक pact file तयार होते – एक JSON डॉक्युमेंट जे त्या अपेक्षांची नोंद करते.
- प्रोव्हायडर त्याच्या CI पाइपलाइनमध्ये पॅक्ट फाईलच्या विरुद्ध आपली वास्तविक सर्व्हिस रन करतो.
- जर प्रोव्हायडरने एखादे फील्ड बदलले, तर पडताळणी (verification) अयशस्वी होते आणि बिल्ड ब्लॉक केले जाते.
पडताळणी प्रत्यक्ष प्रोव्हायडर कोडवर चालत असल्यामुळे, कोणताही ब्रेकिंग चेंज (breaking change) डिप्लॉयमेंटनंतर नाही, तर सुरुवातीलाच पकडला जातो.
तुमच्या टेस्ट पिरामिडमध्ये कॉन्ट्रॅक्ट टेस्ट्स कुठे असाव्यात
- Unit tests – वेगवान, विलगीकृत (isolated) लॉजिकची चाचणी घेतात.
- Contract tests – मध्यम वेग, API करार पाळले जातात की नाही याची खात्री करतात.
- End-to-end tests – संथ, पूर्ण बिझनेस फ्लोची चाचणी घेतात.
कॉन्ट्रॅक्ट टेस्ट्सना युनिट टेस्ट्सचा जलद फीडबॅक आणि एंड-टू-एंड सूट्सचे व्यापक कव्हरेज यांच्यातील दुवा (bridge) म्हणून पहा. जे इंटिग्रेशन पॉइंट्स वारंवार बिघडतात त्यांना लक्ष्य करा आणि दोन किंवा तीन महत्त्वाच्या एंडपॉइंट्सपासून सुरुवात करा.
वास्तविक जगातील अवलंबनाचा किस्सा
या लेखाची प्रेरणा देणाऱ्या टीमने त्यांच्या सर्वात नाजूक कॉल्ससाठी तीन कॉन्ट्रॅक्ट्सपासून सुरुवात केली. सहा महिन्यांनंतर त्यांच्याकडे बहुतेक इंटर-सर्व्हिस ट्रॅफिक कव्हर करणारे ४७ कॉन्ट्रॅक्ट्स होते. त्या काळात API ब्रेकॅजच्या घटना दरमहा दोनवरून शून्य झाल्या.
कॉन्ट्रॅक्ट टेस्टिंग कधी फायदेशीर ठरणार नाही
- तुम्ही एक सोलो डेव्हलपर आहात आणि सर्व सर्व्हिसेस एकाच रिपॉझिटरीमध्ये ठेवल्या आहेत.
- API अत्यंत स्थिर आहे आणि अनेक वर्षांपासून बदललेला नाही.
- तुम्ही एखादे प्रोटोटाइप बनवत आहात जे लवकरच काढून टाकले जाईल.
अशा परिस्थितीत, कॉन्ट्रॅक्ट्स मेंटेन करण्याचा ओव्हरहेड फायद्यापेक्षा जास्त असू शकतो.
संभाव्य तोटे आणि ते कसे कमी करावेत
- कॉन्ट्रॅक्ट्सना त्यांनी वर्णन केलेल्या कोडसोबतच व्हर्जन (versioned) ठेवा.
- जुने (stale) कॉन्ट्रॅक्ट्स टाळण्यासाठी प्रत्येक CI रनमध्ये पडताळणी स्वयंचलित (automate) करा.
- अनवधानाने होणारे ब्रेकॅज पकडण्यासाठी पुल रिक्वेस्टमध्ये (pull requests) कॉन्ट्रॅक्टमधील बदलांची पुनरावलोकन (review) करा.
निष्कर्ष
जर तुम्ही अजूनही तुमच्या सर्व्हिसेस एकमेकांशी संवाद साधू शकतात हे स्वतःला पटवून देण्यासाठी हाताने तयार केलेल्या मॉक्सवर अवलंबून असाल, तर तुम्ही एका खोट्या आश्वासनावर विश्वास ठेवत आहात. कॉन्ट्रॅक्ट टेस्टिंग त्या विश्वासाला एका पडताळण्यायोग्य करारात बदलते, ज्यामुळे प्रोडक्शनमध्ये पोहोचण्यापूर्वीच ब्रेकिंग चेंज पकडले जातात आणि, टीमच्या आकडेवारीनुसार, इंटिग्रेशन फेल्युअर पूर्णपणे काढून टाकता येतात.
