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