अगर आप कुछ नहीं करने वाले हैं, तो कम से कम सही तरीके से कुछ न करना सीखें
(devblogs.microsoft.com)- किसी खास platform या retired status के कारण वास्तविक functionality उपलब्ध न करा सकें, तब भी मौजूदा apps न टूटें इसके लिए documented API contract के भीतर “कुछ न करने” वाला व्यवहार design करना चाहिए
- Xbox जैसे environment में, जहाँ printing infrastructure नहीं है,
NotSupportedExceptionकी तुलना में 0 printers वाला successful response PC के हिसाब से लिखे गए apps के लिए ज्यादा सुरक्षित है - यह तरीका inert API कहलाता है: API surface और specification को बनाए रखते हुए वास्तव में कोई उपयोगी काम न करने वाला design
- Retire हो रहे widget API में अगर
CreateWidgetsuccessful होकरnullptrलौटाता है, तो caller विरोधाभासी स्थिति में पड़ता है; इसलिए documentedERROR_CANCELLEDfailure path अधिक consistent है - सही inert API केवल functionality हटाता है, और existing code द्वारा पहले से handle किए जाने वाले failure paths का इस्तेमाल करके exceptions, invalid handles और crashes घटाता है
Functionality न हो तब भी API contract बचा रहता है
- कभी-कभी API को कुछ भी न करने वाला बनाना पड़ता है, लेकिन यह निष्क्रिय व्यवहार भी existing code और documented behavior के अनुरूप होना चाहिए
- गलत design किया गया निष्क्रिय व्यवहार exceptions, विरोधाभासी return values और invalid states पैदा कर सकता है, जिससे app crash या अनावश्यक user errors हो सकते हैं
Xbox पर printing API को निष्क्रिय करने का तरीका
- Windows में व्यापक printing infrastructure है, लेकिन Xbox में यह infrastructure नहीं है
- Xbox पर जब कोई app print करने की कोशिश करे और printing function
NotSupportedExceptionthrow करे, तो समस्या बड़ी हो सकती है- Xbox पर installed apps मुख्यतः PC पर test किए गए होने की संभावना ज्यादा है
- PC पर printing हमेशा संभव होती है, इसलिए unhandled exception app crash में बदल सकता है
- exception catch कर भी लिया जाए, तो user को “support team को incident code दें” जैसा error message दिख सकता है
- बेहतर design यह है कि printing function सफल हो, लेकिन बताए कि कोई installed printer नहीं है
- app printer selection UI दिखाएगा और empty list display करेगा
- user printer न होने की बात देखकर print request cancel कर सकता है
- जो apps printer install करने में मदद करना चाहते हैं, उनके लिए installation function तुरंत return कर सकता है और ऐसा result code दे सकता है जिसका मतलब हो कि user ने operation cancel कर दिया
inert API की शर्तें
- इस तरह के “कुछ न करने” वाले behavior को inert कहा जाता है
- inert API में API surface वैसा ही मौजूद रहता है और specification के मुताबिक behave करता है, लेकिन वास्तव में कोई उपयोगी काम नहीं करता
- मुख्य बात यह है कि documentation के साथ consistent रहते हुए और existing code में समस्या पैदा करने की संभावना सबसे कम रखते हुए कुछ न किया जाए
- printing API में ऐसा function भी जोड़ा जा सकता है जो check करे कि printing itself possible है या नहीं
- app इस function का इस्तेमाल करके उन systems पर Print button छिपा सकता है जहाँ printing बिल्कुल supported नहीं है
- जो apps simply मान लेते हैं कि printing possible है, वे भी “ऐसा system जहाँ printers नहीं हैं और installation attempt का भी कोई असर नहीं होता” जैसा व्यवहार करेंगे
Retire हो रहे widget API में किन designs से बचना चाहिए
- retire होने वाले API में widget handle बनाने वाला function, widget handle लेने वाला function और widget handle बंद करने वाला function है
- शुरुआती proposal यह था कि
CreateWidgetS_OKreturn करे और*widget = nullptrset करे- call successful है, लेकिन valid handle नहीं मिला — ऐसी स्थिति बनती है
- कुछ actual test code में success का निर्णय return value से नहीं, बल्कि handle
nullहै या नहीं, इससे किया जा रहा था
EnableWidgetद्वारा “invalid handle” return करने वाला design भी caller को confuse करता है- app
CreateWidgetकी success के बाद मिले handle कोEnableWidgetमें pass करता है - API जवाब देता है कि वह handle valid नहीं है
- caller ऐसी विरोधाभासी स्थिति में पड़ता है: “widget मांगा और मिला, लेकिन फिर दिखाने पर कहा जा रहा है कि यह widget नहीं है”
- app
documented failure path से सुधारा गया design
- मौजूदा documentation में
ERROR_CANCELLEDreturn value है, जिसका मतलब है कि user ने widget creation cancel कर दिया - app को पहले से external conditions के कारण widget न बन पाने की संभावना handle करनी होती है, इसलिए widget creation को हमेशा user cancellation के रूप में fail कराया जा सकता है
- संशोधित design का flow सरल है
CreateWidget*widget = nullptrरखता है औरHRESULT_FROM_WIN32(ERROR_CANCELLED)return करता है- widget creation हमेशा fail होता है, इसलिए कोई valid widget handle मौजूद नहीं होता
GetWidgetAliases,EnableWidget,Closehandle invalid होने का संकेत देने वालाE_HANDLEreturn करते हैं
- इस तरीके में widget नहीं है, इसलिए dummy alias बनाने की भी जरूरत नहीं
- क्योंकि valid widget मौजूद नहीं है, app के लिए normal तरीके से alias request करने की कोई स्थिति भी नहीं बनती
Desktop API को दूसरे environment में लाते समय मानदंड
- Desktop पर printing API हमेशा मौजूद था, और “printer list लाने” वाला function exceptions न throw करे — ऐसा documented है
- इस API को Xbox पर लाते समय existing desktop apps चलते रहें, इसके लिए “Xbox में printers नहीं हैं” इस तथ्य को ईमानदारी से return करने वाला inert behavior सही है
- “कितने printers हैं?” इस सवाल पर exception throw करना documented API contract से मेल नहीं खाता
- existing API को retire करते समय भी यही principle लागू होता है
- उपयोगी काम न करे, तब भी API behavior contract के साथ consistent होना चाहिए
- ऐसे return values और states का उपयोग करना जरूरी है जिन्हें existing code पहले से handle कर सकता है
2 टिप्पणियां
Lobste.rs टिप्पणियाँ
मज़ाक अपनी जगह, लेकिन मैं इस तरह की ज़रूरत से ज़्यादा defensive programming और user experience से सहमत नहीं हूँ। ऐसा करने पर software बिना किसी स्पष्ट वजह के अपना काम नहीं करता, और यह पता लगाने का भी कोई तरीका नहीं बचता कि ऐसा क्यों हुआ। App को errors पकड़कर जहाँ तक संभव हो user-friendly message बनाना चाहिए, और अगर यह संभव न हो तो कम से कम मूल error message ही user को दिखाना चाहिए। अगर यह background task है, तो error log होना चाहिए
मैं मानता हूँ कि यह लेख app developer नहीं बल्कि API developer के नज़रिए से लिखा गया है। इसलिए API errors को document किया जाना चाहिए, और caller की तरफ़ से कार्रवाई की जा सके ऐसे error messages दिए जाने चाहिए
और सिर्फ़ access permission न होने की वजह से UI में button छिपा देना भी मुझे पसंद नहीं है। अगर जगह हो, तो button दिखाना लेकिन disable रखना बेहतर है, और जब user उस पर mouse hover करे तो उसे यह बताने वाला message देना चाहिए कि इसे enable कैसे किया जा सकता है
कुल मिलाकर, strict correctness माँगना बेहतर है। लेकिन अगर आपके existing users 1 अरब हैं, तो जहाँ तक संभव हो चीज़ें न तोड़ना बहुत समझदारी है, और user के नज़रिए से यह बस काम करता है, इसलिए system level पर इसका वास्तविक मूल्य भी बनता है। आख़िरकार रवैया यह होना चाहिए: जल्दी fail करो, लेकिन इतनी बार fail मत करो कि सब कुछ टूट जाए
यह API से ज़्यादा ABI stability का मामला है। Windows में 15 साल पहले build किया गया software भी जहाँ तक संभव हो नए operating system पर चलता रहना चाहिए। Function signature बदली नहीं जा सकती, इसलिए जिन APIs का अब कोई मतलब नहीं रहा उन्हें भी चलते रहने देने के लिए ऐसे भले झूठ बोलने पड़ते हैं
उदाहरण के लिए, API आज भी ऐसा दिखाती है मानो Active Desktop अभी भी मौजूद हो। विकल्प यह है कि बहुत सारा पुराना existing software टूट जाए
फिर समझ ही नहीं आता कि वह feature हट गया है या इस बीच किसी दूसरी screen में छिप गया है
लेकिन अगर app ऐसा नहीं करता, तो उसे इस्तेमाल करने वाले लोग Windows को दोष देते हैं। App को नहीं, Windows को दोष देते हैं — यहाँ तक कि जब app crash भी हो जाए तब भी
इसलिए Microsoft workaround बनाता है। Print job को बस गायब हो जाने देना कहीं आसान है, और तब user थोड़ा सोचकर मान लेता है, “अरे हाँ, printer तो है ही नहीं”
ifguards जोड़ देता है। हर बार ऐसा देखते ही मुझे यह लेख याद आता हैइसलिए मैंने agent को कहा है कि null checks बार-बार न डाले, बल्कि harmless functions का इस्तेमाल करे, और declaration के समय एक बार verify कर ले कि value कभी null नहीं होगी
Hacker News की रायें
मैंने इसे errors को निगलने वाली पद्धति के रूप में सीखा है, और इसे खराब practice मानता हूँ
यह न सिर्फ Xbox पर print न कर पाने वाली असली समस्या को हल नहीं करता, बल्कि software कितना टूटा हुआ है उसे छिपाकर bugs ढूँढ़ना और testing को कहीं ज्यादा मुश्किल बना देता है
Go का
panicअच्छा है क्योंकि वह runtime में दुरुपयोग करने या recover करने के लिए नहीं बना, बल्कि testing के समय programmer से गलती हुई है, यह जोरदार siren बजाकर बताने वाला tool हैअगर system के अंदर के actors अपनी खामियों या errors को सक्रिय रूप से छिपाएँ, तो कारण ढूँढ़ना और ठीक करना exponentially मुश्किल हो जाता है
जिन B2B, microservices, API-केंद्रित systems पर मैं काम करता हूँ, उनमें spec से बाहर requests को जल्दी fail कराना ही सही है
लेकिन Windows ने compatibility के लिए बहुत ज्यादा पीछे तक accommodate किया है, और SimCity जैसे टूटे हुए मशहूर software को memory patch तक करके बचाने के उदाहरण भी हैं: https://arstechnica.com/gadgets/2022/10/windows-95-went-the-...
Desktop environment में, जहाँ user system code ठीक नहीं कर सकता, कई मामलों में correctness से ज्यादा end-user experience अहम होता है
BSOD क्यों आया, यह महत्वपूर्ण नहीं; Microsoft ने यह सीखा कि खराब software या hardware की वजह से Microsoft की reputation खराब होती है
निजी तौर पर मैं गलत input या conditions पर जल्दी fail या halt करने वाले design को पसंद करता हूँ, लेकिन इस environment में इस approach की value भी समझ आती है
अहम चीज context है, किसी एक तरफ को dogmatically लागू करना नहीं
उदाहरण के लिए nuclear reactor या high-frequency trading के design में Chen वाला approach नहीं लाना चाहिए, और game engine के लिए यह शानदार approach हो सकता है
Runtime components को “हानिरहित रूप से inactive” रखना है या नहीं, यह implementation में
panicआए या नहीं, उससे पहले का design decision हैइस मामले में “Xbox पर print करना” का अर्थ तय करना Microsoft का काम है
इसे error के रूप में define किया जा सकता है, या theoretically बाद में support संभव लेकिन अभी perform करने का कोई practical तरीका न होने वाले feature के रूप में define किया जा सकता है
USB printer लगाकर, अगर GB Printer को support करने वाले Gameboy game के expansion port जैसी “game” को print करने का तरीका पता है, तो theory में Xbox पर भी print हो सकता है
Xbox game का print करने की कोशिश करना अनिवार्य रूप से मूलभूत error नहीं है; इसे error define करना भी application portability जैसे trade-offs वाला एक choice भर है
Xbox की तरह selectable printer न होने वाली selection screen दिखा सकते हैं, API से झूठ बुलवा सकते हैं कि उसने print कर दिया, या सचमुच printing support कर सकते हैं
“Xbox पर print” का अर्थ error के रूप में define करने के बाद ही, उस error का throw न होकर निगल लिया जाना implementation या debugging की समस्या बनता है
संभव handling दो हैं: machine में printer कभी हो ही नहीं सकता, इसलिए error देना; या machine में printer कभी हो ही नहीं सकता, इसलिए खाली printer list लौटाना
दोनों valid हैं, लेकिन user space को न तोड़ने वाला सिर्फ एक है
“जोरदार siren बजाना” testers या developers के लिए अच्छा है, लेकिन end users के लिए खास नहीं
end user के नजरिए से, error को निगलना app crash होने से बेहतर है
क्या fail हुआ यह पता नहीं चलता: मेरे computer का software, hardware, Ethernet cable या Wi-Fi, switch, router, cable modem, घर तक आने वाली internet cable, ISP, या जिस remote system से connect करना है—इनमें से कहाँ, इस बारे में कोई सुधार नहीं हुआ
नकारात्मक प्रतिक्रिया अपेक्षित है, लेकिन यही गंदी-सी चीज वह वजह है कि Word ’97 document या 30 साल पहले MS-DOS के लिए compiled game पर click करने पर वह उम्मीद के मुताबिक खुल जाता है
Backward compatibility हमेशा messy होती है, और या तो imperfect तरीके से होती है या बिल्कुल नहीं होती
आखिरकार GOG इस्तेमाल करना पड़ता है, और GOG भी अंततः environment को virtualize करता है
उदाहरण के लिए, मुझे नहीं लगता कि कोई original Sim City को Windows 11 पर install करके सफल होगा
Formatting installed printer driver पर निर्भर करती थी
इसके उलट 35 साल पुरानी LaTeX file आज भी ठीक काम करती है
Word यह guarantee नहीं दे सकता था कि उसी computer और उसी version में दोबारा खोलने पर formatting नहीं बदलेगी, और इसी वजह से मैंने TeX सीखा
Games में भी Microsoft ने GFWL बंद करके ढेरों games तोड़ दिए
Original Dark Souls Steam पर re-release होने तक playable नहीं था, इसलिए pirated version इस्तेमाल करना पड़ा
“supported नहीं है” वाला dialog दिखता है, और dosbox download किया जा सकता है, लेकिन यह “बिल्कुल उम्मीद के मुताबिक” नहीं है
लगभग हर बार या तो हार माननी पड़ी या GOG से फिर खरीदा, और असल में compatibility issues सुलझाकर रखे गए काम के लिए पैसे दिए
UI जितना झुंझलाहट भरा कुछ नहीं, जो संकेत देता है कि डिवाइस असल में मौजूद हो सकते हैं, लेकिन अभी नहीं हैं
आखिर में समय लगाने के बाद ही पता चलता है कि वे डिवाइस supported नहीं हैं, और वह screen बस किसी ने बनाया हुआ mockup था
अगर app ने output unsupported होने की स्थिति के लिए तैयारी नहीं की है और output exception throw करता है, तो app शायद वहीं crash हो जाएगा
output unsupported होने के लिए तैयार app को explicit API से पहले यह check करना चाहिए कि output supported है या नहीं, और supported न हो तो output UI नहीं दिखाना चाहिए
लेख ऐसे app के बारे में नहीं, बल्कि इस बारे में है कि जो app पहले check नहीं करते, उन्हें कैसे handle किया जाए
bug app में है, लेकिन अच्छा platform खराब apps को भी बस मरने देने के बजाय जितना हो सके चलाने की कोशिश करनी चाहिए
Microsoft की भूमिका यह सुनिश्चित करने की है कि software provider ने printer पर विचार नहीं किया, सिर्फ इसलिए app crash न हो
जब app print करना चाहे तो user से printer चुनने को कहना और खाली list दिखाना—लगता है Microsoft ने 30 साल में कुछ नहीं सीखा: https://www.reddit.com/r/hacking/comments/djvzd/windows_nt_l...
लेख में सुझाई गई ठोस दिशा, यानी user के दुख झेलने से पहले component को दुख झेलना चाहिए, यह बात सही है, लेकिन framing बहुत खटकती है
“कभी-कभी API को ऐसा बनाना पड़ता है कि वह कुछ न करे”, “output function का
NotSupportedExceptionthrow करना गलत है” जैसी बातें बिल्कुल भी general advice नहीं हैंयह घटिया clients को support करने के लिए hacking है, और कभी-कभी ज़रूरी तो होती है, लेकिन यह सामान्य या generalize की जा सकने वाली सलाह नहीं है
इस तरह की अभिव्यक्ति में Microsoft developer के तौर पर झेले गए दर्द को भीतर तक अपना लेने के निशान दिखते हैं
अगर client बदला नहीं है और API उसे break कर देता है, तो घटिया client नहीं, API है
जो भी platform व्यापक रूप से adopted है और backward compatibility को गंभीरता से लेता है, उसमें यह बिल्कुल सामान्य और generalizable काम है
Windows इसका प्रमुख उदाहरण है, लेकिन Linux kernel ABI, glibc, web platform, Java आदि में भी यही होता है
समय पीछे घुमाकर clients को फिर से compile या फिर से write नहीं किया जा सकता
अगर client पहले से
NotSupportedExceptioncheck कर रहा है तो वही return करना चाहिए, लेकिन अगर नहीं, तो अलग approach चाहिएयह Windows है
users जिन applications पर निर्भर हैं, उन्हें break नहीं किया जा सकता
अगर “घटिया” या गलत तरह से काम करने वाला client app है, तो उसे उम्मीद के मुताबिक चलाने के लिए जितने workaround, shim, compatibility hack चाहिए, सब लगाने होंगे
भले ही SimCity को चलाने के लिए खास memory management code डालना पड़े, तब भी यही बात है
आपका customer उस client पर निर्भर है, और आपके बदलाव की वजह से वह रुक गया तो वह दोष आपको देगा
यहाँ सब “कुछ न करने” और “error handling” पर अटके हैं, लेकिन शायद लेख यह अच्छी तरह समझा नहीं पाया कि वह सारे problems निगलकर kumbaya गाने की बात नहीं कर रहा
असली context ऐसे software के लिए emulation और compatibility है जो बदलने वाला नहीं है, और यह ज्यादातर स्थितियों से बहुत अलग है
Microsoft खुद भी दोनों की सीमा अक्सर धुंधली कर देता है, इसलिए और confusion होता है, लेकिन यहाँ बात सामान्य error handling की नहीं है
emulation मूल रूप से झूठ बोलने का काम है
Xbox में असल में printer जोड़ने का कोई तरीका नहीं है, आप Linux पर Windows game चला रहे हैं, और fake iPhone असल में AWS का ARM server हो सकता है
अगर झूठ बोलना है तो भरोसेमंद तरीके से बोलना होगा, ताकि existing applications चलते रहें
जब Microsoft कहता है कि existing Windows apps को Xbox पर port किया जा सकता है, तो Windows apps के साथ यह वादा था कि वे print कर सकते हैं, इसलिए Xbox को झूठ बोलना होगा कि यह काम संभव दिखे
दूसरी तरफ, अगर program use-after-free कर रहा है और आप चुपचाप ऐसे bypass कर दें जैसे bug है ही नहीं, तो वह सही handling नहीं है
क्योंकि किसी ने यह वादा नहीं किया कि existing use-after-free तक नए platform पर bug-level compatibility के साथ चलेगा
आपने यह बस इसलिए मान लिया क्योंकि ऐसी interpretation आपके पसंदीदा रुख को support करती है
असल में लेख की बात कल मैं Xbox के लिए program लिखूँ और print करना चाहूँ, तब भी वैसी ही लागू होती है
इसमें कहीं यह अलग करके नहीं कहा गया कि यह behavior सिर्फ पुराने और unmaintained software पर लागू है
यह approach मुझे अच्छी भी लगती है और बुरी भी
instinctively, मुझे problems को malicious compliance से handle करना पसंद नहीं
दूसरी तरफ, अगर लक्ष्य यह है कि output broken होने पर भी ज्यादा users platform पर ज्यादा software चला सकें, तो मैं पूरी तरह सहमत हूँ कि यह अच्छा फैसला है
इस comment thread में बात अजीब थी
Microsoft जो भी करे, उससे नफरत करने वाले लोग जरूर हैं
blog का मुख्य point apps (UWP) को XBOX पर लाने की process को frictionless बनाना है
बिना recompilation, बिना गंदे
ifdef, बिना extra काम के app “बस चल” जाए, और उसके बाद developer app को XBOX platform के हिसाब से adjust कर सकेअहम बात यह है कि developer बिना किसी effort के app को XBOX पर ला सका, और यह platform और developer दोनों के लिए अच्छा है
user के लिए printer list खाली है, इसलिए यह साफ signal है कि print नहीं किया जा सकता
सबसे बढ़कर, app crash नहीं होता या “समस्या हुई है। बाद में फिर कोशिश करें” जैसे सबसे खराब error नहीं दिखाता
वह message बेहतर user experience नहीं है
developer app को फिर से compile करके ज्यादा explanatory message डाल सकता है, लेकिन तब बात फिर से शुरू पर लौट आती है
मसलन, error निगलने वाला आरोप असल मुद्दा बिल्कुल नहीं है
इस लेख की आलोचना करने वाले लोग जो मुख्य बात चूक रहे हैं, वह यह है कि यहाँ exception फेंकने वाली कोई exceptional situation है ही नहीं
इस डिवाइस से कोई printer जुड़ा नहीं है, और इस मामले में definition के हिसाब से ऐसा ही है, इसलिए app को उस स्थिति को साफ़-सुथरे तरीके से handle करना चाहिए, crash नहीं होना चाहिए
laptop किसी printer तक पहुँच नहीं पा रहा है, सिर्फ़ इसलिए वह exception नहीं फेंकेगा
Settings में printer जोड़ने के बाद, installation के दौरान “Color Profiles” tab पर चले जाएँ, तो timing सही होने पर gnome-control-center crash हो जाता है
ध्यान से देखें तो वह available printers को enumerate करने की कोशिश कर रहा था; उसे पता है कि printer होना चाहिए, लेकिन अभी information मौजूद नहीं है, इसलिए वह सीधे crash हो जाता है
अच्छी बात यह है कि GNOME के printer installation पूरा करने तक कुछ seconds इंतज़ार करके Settings फिर से खोलना काफ़ी है
फिर भी, अलग-अलग backgrounds वाले end users को desktop ठीक से इस्तेमाल कराने वाली core app हो, तो ideal दुनिया में उसे कभी crash नहीं होना चाहिए
boundary conditions के बारे में सोचना कठिन है, और यह कल्पना करना उससे भी कठिन है कि boundary condition handling की अपनी भी boundary conditions होती हैं
सही हो या ग़लत, कम-से-कम लेखक “यह खराब app है, इसलिए इसे Wayland support के लिए फिर से लिखना चाहिए” से ज़्यादा गहराई से सोच रहा है
एक समय था जब browsers का HTML code में errors होने पर भी अपनी तरफ़ से पूरी कोशिश करके page दिखाना एक शानदार strategy माना जाता था
author की मंशा का जितना हो सके अनुमान लगाकर आगे बढ़ना, और यह मानना कि errors खराब हैं और users errors नहीं चाहते—कुछ ऐसा ही था
लगा था कि हमने उस experience से सीखा है, लेकिन शायद ऐसा नहीं है
strict validation से उसे replace करने की XHTML की कोशिश fail हो गई, और इसके बजाय सफल HTML5 ने पीछे जाकर explicitly define किया कि हर संभव invalid sequence को कैसे interpret किया जाना चाहिए, ताकि browsers कम-से-कम consistent तरीके से behave करें
अगर शुरुआती browsers किसी अनदेखे tag से मिलते ही error दिखा देते, तो browser की नई features जन्म लेते ही दम तोड़ देतीं
HelloऔरWorld!input करके देखें, तो हमारी हासिल की हुई wisdom की बदौलत अब पता चल सकता है कि error आता है या नहींलेकिन अगर वह अब भी ठीक से render होता है, तो इसका मतलब हो सकता है कि अभी सीखने को बहुत कुछ बाकी है, या फिर कुछ खास तरह के errors को gracefully handle करना और exceptional situations में crash होना भी मायने रखता है
1999 में time travel करके चले जाएँ तो भी शायद बहुत ज़्यादा कमी महसूस नहीं होगी