कोई नंबर किसी उत्पाद में एक से अधिक जगहों से दाखिल होता है। वह फ़ॉर्म में टाइप होता है, क्लाइंट से गुज़रता है, किसी सेवा तक पहुंचता है, भंडारित होता है, और बाद में कोई ऑपरेटर उसे पढ़कर देखता है। इनमें से हर जगह एक सीमा है, और हर सीमा के पास मान जांचने का अपना अलग कारण है।
जो टीमें इन सबको एक ही जांच मान लेती हैं, उनके पास दोहरा तर्क बनता है जो धीरे-धीरे अलग-अलग दिशाओं में बहक जाता है, और दोनों दुनियाओं की सबसे बुरी स्थिति आ जाती है: प्रतिक्रिया धीमी, क्योंकि असली जांच दूर बैठी है, और अधिकार कमज़ोर, क्योंकि असल में चलती ही केवल तेज़ जांच है। परतों को अलग करना दोनों को ठीक कर देता है।
सत्यापन क्लाइंट पर रखें या सर्वर पर?
दोनों पर, और अलग-अलग कारणों से। क्लाइंट वह जगह है जहां देरी मायने रखती है। लंबा पहचानकर्ता टाइप करता उपयोगकर्ता गलत अक्षर के बारे में तुरंत जानना चाहता है, और हर कुंजी दबाने पर सर्वर तक चक्कर लगाना यह बताने का गलत तरीका है। वे स्थानीय, ऑफ़लाइन जांचें यहीं की चीज़ हैं जिनके लिए किसी बाहरी खोज की ज़रूरत नहीं पड़ती।
सर्वर वह जगह है जहां अधिकार मायने रखता है। क्लाइंट जो भी दावा करे, वह गढ़ा जा सकता है, सीधे एंडपॉइंट पर कॉल करके छोड़ा जा सकता है, या पुराने नियम-सेट वाले किसी पुराने बिल्ड से आ सकता है। सेवा को जो कुछ भी स्वीकार करे उस पर जांच दोबारा चलानी चाहिए, इसलिए नहीं कि उसे अपने क्लाइंट पर भरोसा नहीं, बल्कि इसलिए कि क्लाइंट उसके भरोसे की सीमा के भीतर आता ही नहीं।
दोनों परतों को एक ही विवरण और एक ही कार्यान्वयन साझा करना चाहिए, जिसे किसी पैकेज या बने हुए नतीजे के रूप में बांटा जाए, ताकि तेज़ जांच और असली जांच इस पर असहमत न हो सकें कि वैध मान कैसा दिखता है। जब वे बहक जाती हैं, तो लक्षण यह होता है कि क्लाइंट स्वीकार करता है और सर्वर ठुकरा देता है, जिसे उपयोगकर्ता फ़ॉर्म के अंत में समझ न आने वाली विफलता के रूप में भोगता है।
यहां चर्चा किए गए उदाहरण ढांचे के बारे में हैं। कोई असली खाता, पहचान या कार्ड नंबर किसी अनुरोध लॉग, परीक्षण फ़िक्स्चर या त्रुटि संदेश में नहीं आना चाहिए, और इस लेख में वर्णित मान केवल समझाने वाली आकृतियां हैं।
सीमा पर क्या जांचें और क्या आगे जाने दें
सीमा को वह पुष्ट करना चाहिए जिसे वह सस्ते में पुष्ट कर सकती है, और बाकी को डेटा के रूप में आगे भेज देना चाहिए।
किनारे पर जांचें: अक्षर-समूह, लंबाई, सामान्य रूप, और किसी ऐसी योजना का प्रकाशित चेक अक्षर जिसे सेवा जानती है। जल्दी और साफ कारण के साथ ठुकराएं, क्योंकि विकल्प यह है कि विकृत मान सिस्टम में और गहरे चला जाए, जिसके पास उसे बताने की शब्दावली ही नहीं है।
आगे जाने दें: वह सब जिसके लिए रजिस्टर में खोज चाहिए, जब तक सेवा का ऐसा संविदात्मक संबंध न हो जो वह खोज सस्ती बना दे। किसी सार्वजनिक एंडपॉइंट पर यह जांचना कि खाता मौजूद है, एक ही समय में सेवा-अवरोध का ज़रिया भी है और निजता का खतरा भी, क्योंकि वह फ़ॉर्म को ऐसा साधन बना देता है जिससे अंदाज़ा लगाया जा सके कि कोई मान जीवित है या नहीं।
सामान्य रूप एक बार दें, सीमा पर, और उसी सामान्य रूप को असली मान के रूप में रखें, जबकि मूल को दिखाने के लिए सुरक्षित रखें। इसके बाद आगे का सब कुछ एक ही रूप की तुलना करता है, और उस किस्म की गलतियां गायब हो जाती हैं जहां वही नंबर तीन अलग प्रारूपों में दिखता है।
त्रुटि प्रतिक्रियाओं का वर्गीकरण और उनका पुनः प्रयास अर्थ
हर अस्वीकृति का मतलब एक नहीं होता, और सबके लिए एक ही त्रुटि कोड रखना हर कॉलर को यह अनुमान लगाने पर मजबूर करता है कि उसे कैसे जवाब देना है।
| स्थिति | अर्थ | दोबारा कोशिश संभव |
|---|---|---|
| विकृत इनपुट | मान प्रारूप के नियम को तोड़ता है | नहीं — कॉलर को अलग डेटा भेजना होगा |
| चेक अक्षर विफल | आकृति वैध है पर अंकगणित मेल नहीं खाता | नहीं — वही कारण |
| असमर्थित योजना | सेवा की कोई लागू योजना इस आकृति से मेल नहीं खाती | नहीं — जब तक सेवा कवरेज न बढ़ाए |
| अस्थायी रूप से अनुपलब्ध | जांच के लिए ज़रूरी कोई निर्भरता बंद है या धीमी कर दी गई है | हां, बढ़ते अंतराल के साथ |
| दर सीमित | कॉलर अपनी अनुमत सीमा से आगे निकल गया | हां, जवाब में बताए अंतराल के बाद |
पहली चार को एक सामान्य खराब अनुरोध में समेट देना सबसे आम डिज़ाइन गलती है, क्योंकि इससे स्थायी इनपुट त्रुटि और अस्थायी ठहराव में फ़र्क़ करना नामुमकिन हो जाता है। फिर क्लाइंट गलत विफलताओं पर दोबारा कोशिश करते हैं या उन पर हार मान लेते हैं जो सफल हो सकती थीं।
मशीन द्वारा पढ़ने योग्य स्थिर कोड और उसके साथ मनुष्य द्वारा पढ़ने योग्य संदेश लौटाएं, और यह प्रलेखित करें कि कौन से कोड दोबारा कोशिश लायक हैं। इस वर्गीकरण को इंटरफ़ेस के अनुबंध का हिस्सा मानें: बाद में उसे बदलना हर उस पक्ष के लिए तोड़ने वाला बदलाव है जिसने अपना दोबारा कोशिश का तर्क उसी पर बनाया था।
विफल चेक को गायब नंबर क्यों नहीं बताना चाहिए?
क्योंकि दोनों कथनों की सच्चाई की शर्तें अलग हैं। विफल चेक अक्षर कहता है कि स्ट्रिंग अपने आप से मेल नहीं खाती, जिसे सेवा निश्चित रूप से जानती है। गायब नंबर कहता है कि ऐसा कोई खाता या रिकॉर्ड मौजूद ही नहीं, जिसे सेवा आमतौर पर जान ही नहीं सकती।
यह भ्रम दोनों दिशाओं में असली नुकसान करता है। यह सुनकर कि नंबर मौजूद नहीं है, सच्चा मान रखने वाला उपयोगकर्ता वैध लेन-देन छोड़ सकता है या कुछ और डाल देता है। और यह सुनकर कि नंबर वैध है क्योंकि चेक पास हो गया, उपयोगकर्ता यह मान बैठ सकता है कि खाता पुष्ट हो गया, जबकि पुष्ट हुआ केवल अंकगणित है।
सही संदेश स्ट्रिंग का वर्णन करता है: प्रारूप मेल खाया, या चेक अंक टिका नहीं, या कोई लागू नियम इनपुट को नहीं पहचानता। इस सूची का कोई भी हिस्सा दुनिया के बारे में कुछ दावा नहीं करता, और हर हिस्सा कॉलर को कुछ ऐसा बताता है जिस पर वह कार्रवाई कर सके। यही अनुशासन थोक कार्यों के भीतर भी लागू होता है, जहां गलत लगाई गई श्रेणी समीक्षक को ऐसा दोष ढूंढने भेज सकती है जो है ही नहीं; बड़ी फ़ाइलों के लिए श्रेणीकरण ठीक इसी अंतर पर बना है।
बाहरी लुकअप के लिए दर सीमा, टाइमआउट और फ़ॉलबैक
जैसे ही किसी जांच को प्रक्रिया के बाहर से डेटा चाहिए, उसे नेटवर्क कॉल की सारी विफलताएं विरासत में मिल जाती हैं। उनके लिए डिज़ाइन करना निराशावाद नहीं है; वह क्षरण और ठप्पे के बीच का अंतर है।
हर बाहरी कॉल के लिए ज़रूरी है कि उसका टाइमआउट उस अनुरोध से छोटा हो जिसके भीतर वह बैठी है, ताकि कोई धीमी निर्भरता पूरा बजट न खा जाए। उसे अस्थायी विफलताओं के लिए बढ़ते अंतराल और थोड़ी बेतरतीबी वाली दोबारा कोशिश की नीति चाहिए, और एक ऐसा तोड़ने वाला स्विच भी जिससे लगातार विफल होती निर्भरता को पूरी रफ़्तार से पुकारना बंद हो जाए।
उसे उस स्थिति के लिए भी तय व्यवहार चाहिए जहां खोज हो ही न सके। दो जवाब वैध हैं, और चुनाव उत्पाद का निर्णय है: अनुरोध विफल कर दें, या मान को अस्थायी रूप से स्वीकार करके असत्यापित चिह्नित कर दें। जो वैध नहीं है, वह यह कि पहुंच से बाहर की खोज को चुपचाप पास मान लिया जाए, क्योंकि वह ठप्पे को डेटा गुणवत्ता की समस्या में बदल देता है।
स्मृति में रखना मदद करता है और उसके अपने नियम चाहिए। केवल वही रखें जिसकी अनुबंध अनुमति दे, कुंजी सामान्य रूप पर रखें, और हर प्रविष्टि को उतनी आयु दें जितनी जल्दी वह तथ्य बदल सकता है। किसी अस्वीकृति को कभी ऐसे न रखें जैसे वह नंबर के बारे में जांचा हुआ तथ्य हो।
डेवलपर के लिए: अनुबंध, संस्करण और लॉग
नियम-सेट को API की संस्करणित निर्भरता मानें, कार्यान्वयन का भीतरी ब्यौरा नहीं।
यह बताएं कि किस नियम-सेट संस्करण ने कोई नतीजा बनाया, ताकि कॉलर जान सके कि व्यवहार में बदलाव उसके अपने बिल्ड से आया या सेवा से। जब कवरेज बदले तो नियम-सेट का संस्करण एंडपॉइंट से अलग रखें, और पुराने संस्करण उतने समय उपलब्ध रखें जितने में क्लाइंट बदलाव कर लें। जब कोई योजना नए पैरामीटर प्रकाशित करे, तो वह बदलाव एक नए संस्करण संख्या वाला डेटा अपडेट होना चाहिए, ऐसा कोड संपादन नहीं जिसके रिलीज़ नोट्स में व्यवहार का अंतर छूट जाए।
लॉग में नतीजे लिखें, पूरे मान कभी नहीं। योजना, नतीजा, नियम-सेट का संस्करण और संबंध जोड़ने वाला पहचानकर्ता दर्ज करें, और मान को लॉग पंक्ति से पूरी तरह बाहर रखें — त्रुटि वाले रास्तों में भी, क्योंकि मान सबसे ज़्यादा वहीं चूकते हैं।
अंत में याद रखें कि सीमा क्या साबित नहीं कर सकती। सत्यापित प्रारूप स्ट्रिंग के बारे में एक कथन है, जैसा केवल प्रारूप वाला मामला उन योजनाओं के लिए साफ करता है जिनमें अंकगणित ही नहीं है, और सत्यापन का तीन परतों वाला मॉडल परतों को अलग रखने का संदर्भ है।
आगे के कदम
उस एंडपॉइंट को लें जो आपका सबसे संवेदनशील पहचानकर्ता प्राप्त करता है, और उसकी हर जांच सूचीबद्ध करें, हर एक को स्थानीय अंकगणित या बाहरी खोज के रूप में चिह्नित करें। फिर पुष्टि करें कि क्लाइंट स्थानीय जांचें जल्दी चलाता है और सर्वर उन सबको दोबारा चलाता है; नंबर सत्यापन टूल वे शब्द दिखाता है जिन्हें क्लाइंट अंकगणित से ज़्यादा दावा किए बिना सुरक्षित रूप से दोहरा सकता है।