
एक CSS वेरिएबल, पाँच रिव्यू राउंड, और एक Swift टूलचेन जिसने झूठ बोला
GeekBye v2.0.7 ने पूरे ओवरले को समायोज्य रूप से पारदर्शी बना दिया — जो सुनने में एक-लाइन का CSS बदलाव लगता है और बिलकुल नहीं था। असली कहानी वह है जो कोड रिव्यू ने पकड़ी: दो ऐसी सतहें जिन्होंने फ़ीके होने से इनकार कर दिया, एक रिकॉर्डिंग बार जो उसी opacity पर गलत दिखता था, और एक कंपाइल किया गया बाइनरी जो 672 बाइट इधर-उधर हिलता रहा क्योंकि हमारे अपने डॉक्स ने एक रिव्यूअर को गलत Swift वर्शन बता दिया।
"ओवरले को पारदर्शी बनाओ" वह तरह का काम है जो एक स्लाइडर और एक CSS opacity प्रॉपर्टी जैसा लगता है। GeekBye v2.0.7 ने ठीक वही यूज़र-सामने वाला नतीजा शिप किया — एक अकेला समायोज्य "light mode" जो आपको असिस्टेंट के पैनलों के आर-पार, उनके पीछे जो कुछ भी हो उसे देखने देता है। पर इस रिलीज़ का दिलचस्प हिस्सा फ़ीचर नहीं है। यह वे पाँच रिव्यू राउंड हैं जो इसे ठीक करने में लगे, और एक कंपाइल किए गए बाइनरी की युद्ध-कथा जिसका साइज़ इसलिए बदल गया क्योंकि हमारे अपने दस्तावेज़ ने एक रिव्यूअर से झूठ बोला।
पूरे UI को पारदर्शी बनाने का सही तरीका
इसका भोला संस्करण यह है कि हर पैनल कॉम्पोनेंट पर एक opacity वैल्यू छिड़क दो और काम खत्म मान लो। यह एक मेंटेनेंस जाल है: एक दर्जन हार्डकोड वैल्यू जो उसी पल बिखरने लगती हैं जब कोई एक को छूता है।
इसके बजाय, v2.0.7 एक साझा CSS यूटिलिटी और एक प्रति-सतह टोकन का इस्तेमाल करता है। एक अकेला overlay-surface क्लास है जो किसी पैनल का बैकग्राउंड दो कस्टम प्रॉपर्टीज़ से गणना करता है: एक बेस opacity जो हर सतह अपने लिए घोषित करती है (कंट्रोल बार, चैट, ट्रांसक्रिप्ट बबल, कोड ब्लॉक, वगैरह — हर एक अपनी चुनती है), और एक ग्लोबल alpha मल्टिप्लायर जो ओवरले रूट पर सवार रहता है और यूज़र की स्लाइडर सेटिंग को दर्शाता है। हर सतह वही मल्टिप्लायर पढ़ती है; हर एक अपना चरित्र बनाए रखती है। अहम बात: सिर्फ़ पैनल बैकग्राउंड स्केल होता है — टेक्स्ट, आइकन और backdrop-blur पूरी तरह रेंडर रहते हैं, इसलिए "पारदर्शी" का मतलब कभी "अपठनीय" नहीं होता।
उस डिज़ाइन के दो फ़ैसले खासतौर पर बताने लायक हैं क्योंकि यही एक मददगार फ़ीचर और सपोर्ट टिकट पैदा करने वाले फ़ीचर के बीच का फ़र्क हैं:
- डिफ़ॉल्ट पूरी तरह अपारदर्शी है। opacity सेटिंग 100% पर शिप होती है — एक no-op। अपडेट पर किसी का ओवरले अचानक आर-पार नहीं दिखने लगा; पारदर्शिता तब मौजूद है जब आप उसकी ओर हाथ बढ़ाएँ, और तब तक अदृश्य।
- सेटिंग को रक्षात्मक ढंग से मान्य किया जाता है। min, max, डिफ़ॉल्ट और step के लिए सत्य का एक ही स्रोत है, और एक नॉर्मलाइज़र जो खाली/गायब मामले की पहरेदारी करता है। यह मायने रखता है एक JavaScript पंगे की वजह से:
Number(null)0होता है, इसलिए एक गायब सेटिंग को भोलेपन से coerce किया जाए तो ओवरले अपनी डिफ़ॉल्ट के बजाय अपनी सबसे पारदर्शी स्थिति में झटक जाता। नॉर्मलाइज़र ऐसा होने से पहले ही उसे पकड़ लेता है।
स्लाइडर खींचिए और पूरा ओवरले लाइव, रिकॉर्डिंग के बीच में ही, दोबारा रंग बदल लेता है, क्योंकि हर सतह उसी सेटिंग की सब्सक्राइबर है। कोई रीस्टार्ट नहीं, कोई रीलोड नहीं।
रिव्यू ने क्या पकड़ा (और जो एक सिंगल-मॉनिटर टेस्ट कभी न पकड़ता)
यहीं "एक CSS वेरिएबल" सरल होना बंद हो गया। रिव्यू में तीन बग सामने आए, और उनमें से दो अलग-अलग टोपी पहने एक ही सबक हैं।
एक पैनल जो फ़ीका होने को तैयार नहीं था। कीबोर्ड-शॉर्टकट ओवरले ठोस-का-ठोस बना रहा जबकि बाकी सब कुछ पारदर्शी हो गया। वजह: यह उस DOM सबट्री के बाहर रेंडर होता है जो opacity वेरिएबल ढोती है, इसलिए उसने ओवरले रूट से नीचे कैस्केड होती वैल्यू कभी inherit ही नहीं की। CSS कस्टम प्रॉपर्टीज़ DOM ट्री के ज़रिए inherit होती हैं — और अगर कोई नोड असल में वहाँ का वंशज नहीं है जहाँ आपने वेरिएबल सेट किया, तो उसे चुपचाप कुछ नहीं मिलता। फ़िक्स था उस पैनल पर भी वेरिएबल को लोकली सेट करना।
एक hover टिंट जो गायब हो गया। Fn/Assist बटनों की सियान hover चमक खो गई। पारदर्शिता यूटिलिटी ने बैकग्राउंड को !important से सेट किया (उसे सतह-डिफ़ॉल्ट के खिलाफ़ जीतना ही होता है), और इसने उसी एलिमेंट पर hover: बैकग्राउंड टिंट को रौंद डाला। स्पेसिफ़िसिटी की टक्कर। फ़िक्स था hover टिंट को उतना ही ज़ोरदार बनाना ताकि वह hover पर वापस जीत सके।
ये दोनों एक ही अंतर्निहित सच हैं: एक CSS वेरिएबल कैस्केड एक असली शुद्धता-सीमा है, कोई स्टाइलिंग विवरण नहीं। inheritance और स्पेसिफ़िसिटी तय करती हैं कि आपकी वैल्यू एलिमेंट तक पहुँचती भी है या नहीं, और गलत होने तक इनमें से कोई भी स्क्रीनशॉट में नहीं दिखता।
एक ही opacity, अलग रूप। सबसे सूक्ष्म वाला: रिकॉर्डिंग बार और आइडल बार को समान बेस opacity पर सेट किया गया था, फिर भी वे साफ़ अलग दिखते थे। क्यों? रिकॉर्डिंग पिल ने एक भारी backdrop-blur इस्तेमाल किया, और गहरे बैकग्राउंड पर एक तेज़ blur नतीजे को ज़्यादा गहरे की ओर औसत कर देता है — इसलिए बराबर alpha ने असमान रूप पैदा किया। इसके अलावा उसका एक हल्का बॉर्डर था जबकि आइडल बार का एक चमकीला ग्रेडिएंट-रिंग किनारा था। फ़िक्स ने blur स्तर और रिंग को मिला दिया। सबक ठहर गया: blur के तस्वीर में आते ही बराबर alpha बराबर रूप नहीं रहता। पारदर्शिता आपस में क्रिया करते प्रभावों की एक प्रणाली है, कोई एक अकेला नंबर नहीं।
वह बाइनरी जिसका साइज़ बदल गया क्योंकि डॉक्स ने झूठ बोला
अब युद्ध-कथा, और यह मेरा पसंदीदा किस्म है — वह जहाँ टूलिंग और डॉक्स आपस में असहमत होते हैं और एक सावधान रिव्यूअर क्रॉसफ़ायर में फँस जाता है।
GeekBye कुछ प्री-कंपाइल किए गए Swift बाइनरी शिप करता है (मीटिंग डिटेक्शन जैसी चीज़ों के लिए नेटिव हेल्पर)। चूँकि एक कंपाइल किया गया बाइनरी रिपो में चेक-इन होता है, हर डेवलपर को उसे बिलकुल एक ही Swift वर्शन से कंपाइल करना ही होगा — अलग टूलचेन एक जैसे सोर्स से अलग बाइट पैदा करते हैं, और इसका मतलब होता हर बार किसी के दोबारा बिल्ड करने पर एक भूतिया git conflict। इसलिए एक स्क्रिप्ट है जो एक खास वर्शन लागू करती है: Swift 6.3.x, बिल्ड-टाइम पर जाँचा गया।
इस रिलीज़ के रिव्यू के दौरान, एक रिव्यूअर ने चिह्नित किया कि एक बाइनरी को "रिपो-अनिवार्य टूलचेन" से मेल खाने के लिए दोबारा बनाया जाना चाहिए। डेवलपर ने ठीक वही किया — और बाइनरी का साइज़ 89,184 बाइट से 88,512 हो गया। कमिट मैसेज ने तो यहाँ तक कहा कि यह Swift 6.2.1, "रिपो-अनिवार्य टूलचेन," से दोबारा बनाकर "बाइट-स्थिर आउटपुट बहाल कर रहा है।"
बस, 6.2.1 गलत वर्शन था। बिल्ड-एनफ़ोर्समेंट स्क्रिप्ट को 6.3.x चाहिए था। दिक्कत यह थी कि गद्य दस्तावेज़ — README और कॉन्ट्रिब्यूटर गाइड — अब भी कुछ जगहों पर 6.2.1 कहते थे। तो एक ईमानदार रिव्यूअर और एक ईमानदार डेवलपर, दोनों सही काम करने की कोशिश में, डॉक्स के पीछे-पीछे सीधे ठीक वही आर्टिफ़ैक्ट कमिट करने चले गए जिसे अस्वीकार करने के लिए एनफ़ोर्समेंट स्क्रिप्ट मौजूद है। एक 6.3.x रिपो में एक 6.2.1 बाइनरी ठीक वही ड्रिफ़्ट है जो हर दूसरे डेवलपर के साफ़ दोबारा-बिल्ड को तोड़ देता।
अगले कमिट ने इसे ठीक किया — और फ़िक्स ही असली बात है। उसने सिर्फ़ बाइनरी को उसके 6.3.x रूप में वापस दोबारा नहीं बनाया (साइज़ 89,184 पर बहाल, बिलकुल वहीं जहाँ से शुरू हुआ था)। उसने डॉक्स में बासी "6.2.1" संदर्भों को भी सुधारा ताकि यह जाल दोबारा न बिछ सके। बाइनरी दो कमिट में 672 बाइट इधर और वापस उधर हिला, और असली बग कभी बाइनरी था ही नहीं। वह यह था कि सत्य के दो स्रोत — एनफ़ोर्समेंट स्क्रिप्ट और लिखित डॉक्स — आपस में असहमत थे, और एक इंसान ने गलत वाले पर भरोसा कर लिया।
इस रिलीज़ ने तीन बातें सिखाईं
- एक CSS-वेरिएबल कैस्केड एक शुद्धता-सीमा है। तीन में से दो रिव्यू बग एक ऐसे वेरिएबल पर आ टिके जो inherit नहीं हुआ और एक
!importantजिसने एक hover स्टेट कुचल दी। अगर किसी वैल्यू को inheritance के ज़रिए एलिमेंट तक पहुँचना है या स्पेसिफ़िसिटी के ज़रिए जीतना है, तो वह रास्ता लॉजिक है — उसे लॉजिक की तरह जाँचिए, स्टाइलिंग की तरह नहीं। - बराबर पैरामीटर असमान नतीजे दे सकते हैं। रिकॉर्डिंग बार और आइडल बार ने एक opacity साझा की और फिर भी अलग दिखे क्योंकि एक अलग blur ने नतीजा बदल दिया। जब आप किसी विज़ुअल प्रणाली को एक नंबर पर एकीकृत करें, तो जाँचिए कि हर सतह के इर्द-गिर्द बाकी वेरिएबल चुपके से यह न बदल रहे हों कि उस नंबर का मतलब क्या है।
- जब डॉक्स और एनफ़ोर्समेंट असहमत हों, तो असहमति को ठीक करो — सिर्फ़ लक्षण को नहीं। बग एक खराब बाइनरी नहीं था; वह एक डॉक था जिसने गलत टूलचेन का नाम लिया और एक एनफ़ोर्समेंट स्क्रिप्ट जो कुछ और कहती थी। बाइनरी को दोबारा बनाना लक्षण का इलाज है। सत्य के हर स्रोत को सहमत कराना असली फ़िक्स है, क्योंकि अगला रिव्यूअर भी डॉक्स पर भरोसा करेगा।
GeekBye v2.0.7 ने एकसमान पारदर्शिता शिप की, सारे किनारे-के-मामले रिव्यू हुए और टूलचेन डॉक्स सीधे किए गए। यह उस विश्वसनीयता स्प्रिंट से पहले की "शांत कारीगरी" रिलीज़ों में आखिरी है जो उसके बाद आया। इसके नीचे की नींव के लिए, देखिए एक असली वर्शन 2 में सचमुच क्या लगता है (v2.0.0); समकक्ष पॉलिश रिलीज़ के लिए, शांत सॉफ़्टवेयर: फ़्लिकर फ़िक्स और आंसर-मोड चिप (v2.0.3 + v2.0.5); और ओवरले किसी कॉल पर छिपा कैसे रहता है, इसके लिए स्क्रीन शेयरिंग के दौरान अदृश्य कैसे रहें।