Chesterton की बीच वाली उंगली
(arp242.net)- Chesterton’s fence यह सलाह देता है कि जिस code का कारण समझ में न आए, उसे यूँ ही न बदलें, लेकिन बिना कारण छोड़ा गया code और commit history यही बोझ अगले developer पर डाल देते हैं
- इस repository में पिछले 13 साल की commit body मिलाकर कमांड के हिसाब से सिर्फ 295 पंक्तियाँ हैं, और dependabot·revert·typo से जुड़ी body हटाने पर यह 167 पंक्तियों तक रह जाती है
- commit title बड़े बदलावों पर भी “fix page A” जैसी पंक्तियों तक सीमित हैं, जो context नहीं देतीं; अलग documentation और code comments भी लगभग नहीं हैं, इसलिए बदलाव का कारण ट्रैक करना मुश्किल है
- code में अधूरी refactoring, हटाई गई features के अवशेष, जोड़ी गई लेकिन connect या इस्तेमाल न की गई features, और शायद किसी के काम न आने वाली features बची हुई हैं
- commit message और documentation में कम-से-कम इतना तो रहना ही चाहिए कि “क्या बदला जा रहा है, क्यों बदला जा रहा है, और यह समाधान अच्छा क्यों है”; अगर कुछ भी न छोड़ा जाए, तो बाद में आने वाले developer की लागत बहुत बढ़ जाती है
बिना वजह छोड़ा गया code जो बोझ पैदा करता है
- Chesterton’s fence एक रूपक है: अगर आपको समझ नहीं है कि कोई चीज़ वैसी क्यों है, तो उसे बिना सोचे-समझे नहीं बदलना चाहिए
- programming में भी ऐसा हो सकता है कि कोई अजीब दिखने वाला code “ठीक” करने के बाद बाद में पता चले कि उसकी उस अजीबियत के पीछे वजह थी
- इस मामले में उलटी समस्या सामने आती है
- अजीब code और decisions बहुत हैं, लेकिन वे ऐसे क्यों बने, इसका कोई रिकॉर्ड नहीं है
- पहले के developer सब जा चुके हैं, इसलिए पूछने के लिए कोई भी नहीं है
- repository की commit history लगभग कोई काम का context नहीं देती
- पिछले 13 साल की commit body कुल 295 पंक्तियाँ हैं
- dependabot, “revert commit”, “fix typo” commit body को हाथ से हटाने पर 167 पंक्तियाँ बचती हैं
- यानी लगभग महीने में एक पंक्ति जितना
- commit title भी ज़्यादातर “fix page A” जैसे हैं, जो बड़े बदलाव समझाने के लिए नाकाफ़ी हैं
- अलग documentation नहीं है, और code comments भी लगभग नहीं के बराबर हैं
- ऐसी स्थिति “हमने बहुत अजीब काम किए, लेकिन क्यों किए यह नहीं बताएँगे” वाली Chesterton’s middle finger के ज़्यादा क़रीब है
developer को कम-से-कम कौन-सा रिकॉर्ड छोड़ना चाहिए
- codebase में कई तरह का अधूरा या बचा हुआ code पड़ा है
- अधूरी refactoring
- हटाई गई features के अवशेष
- जोड़ी गई लेकिन connect या इस्तेमाल न की गई features
- ऐसी features जिन्हें शायद कोई इस्तेमाल नहीं करता
- कुल मिलाकर यहाँ Chesterton’s gap की समस्या भी काफ़ी गंभीर लगती है
- यानी “अभी fence नहीं है, तो बना देते हैं” जैसी सोच, जहाँ यह पूछा ही नहीं जाता कि fence की ज़रूरत सच में है भी या नहीं
- अच्छा लिखना मुश्किल है, लेकिन किसी तरह काम चलाने लायक explanation छोड़ना मुश्किल नहीं है
- change record को बुनियादी तौर पर तीन सवालों का जवाब देना चाहिए
- क्या बदला जा रहा है
- क्यों बदला जा रहा है
- यह समाधान अच्छा क्यों है
- कभी-कभी सिर्फ “Implement new feature X” ही काफ़ी हो सकता है, लेकिन ज़्यादातर मामलों में यह लिखने लायक बात होती है कि कोई feature क्यों या कैसे उस तरह जोड़ा गया
- bug fix, refactoring, और ठोस बदलावों में आम तौर पर कम-से-कम एक-दो पैराग्राफ में बदलाव और उसके कारण को दर्ज किया जा सकता है
- ऐसे रिकॉर्ड वैकल्पिक नहीं हैं; यह software developer के काम का हिस्सा हैं
- भाषा बहुत polished होना ज़रूरी नहीं
- एकदम perfect English होना ज़रूरी नहीं
- कोई भव्य essay लिखना ज़रूरी नहीं
- कुछ बातें छूट भी जाएँ, तो भी यह बिल्कुल कुछ न होने से बहुत बेहतर है
- अगर आप कुछ भी नहीं छोड़ते, तो बाद में आने वाले हर व्यक्ति पर समस्या का बोझ डाल देते हैं
1 टिप्पणियां
Lobste.rs की रायें
कभी-कभी उस समय यह साफ़ नहीं होता कि बाद में क्या महत्वपूर्ण हो जाएगा। commit तक पहुँचने वाली पूरी प्रक्रिया अगर सार्वजनिक रूप से दर्ज हो, तो बहुत मदद मिलती है, लेकिन शामिल सभी लोगों के पास पहले से इतना संदर्भ होता है कि कुछ बातें “बहुत ही obvious” मानकर छूट भी जाती हैं
अगर चर्चा दर्ज न हो, तो निर्णय-प्रक्रिया को digital archaeology की तरह खंगालना कहीं ज़्यादा मुश्किल हो जाता है। आख़िरकार कभी ऐसी स्थिति भी आती है जहाँ यह संभालना पड़ता है कि वह बाड़ वहाँ क्यों है, यह पता ही नहीं, और फिर मौजूदा संदर्भ व अभी के लोगों की system knowledge के आधार पर उसका आकलन करना पड़ता है
अगर प्रोजेक्ट में लंबे समय तक टिके रहकर पूरे system की समझ और instinct हासिल करने वाला कोई व्यक्ति हो, तो यह बहुत मददगार होता है। जो संगठन developers को replaceable cogs की तरह देखते हैं, वहाँ कोई भी इतना लंबे समय तक नहीं रुकता कि गहरी समझ बना सके, इसलिए वही गलतियाँ दोहराई जाती हैं और पहिया फिर से बनाया जाता है
इससे अगला व्यक्ति जब code देखे, तो उसके लिए यह समझ पाने की संभावना शून्य नहीं रहती कि इसे ऐसा क्यों किया गया
मैं कभी उन developers को समझ नहीं पाया जो commit message में बस “fix” या “WIP commit” जैसा कुछ लिखते हैं। शायद उन्होंने कभी गंभीर code archaeology नहीं की, या यह सोचा ही नहीं कि ऐसा करना संभव भी है
मैं हमेशा इस तरफ़ गलती करने की कोशिश करता हूँ कि जानकारी ज़्यादा हो। ताकि future me, अगला maintainer, या outage होने पर बुलाया गया कोई बेचारा इंसान, जब अंततः कुछ टूटे, तो कम से कम उसके कारण का पता लगाने की कुछ संभावना तो रहे
ऐसे में हर checkpoint के बाद क्या बदला, इसे दिमाग़ में track करना या उसके साथ meaningful explanation जोड़ना मुश्किल होता है, और commit को अच्छी तरह परिभाषित work unit में बाँटने के साधन की बजाय video game के “save” बटन की तरह इस्तेमाल किया जाने लगता है
दूसरी ओर, अगर किसी बड़े API refactoring के नतीजे में एक बड़ा commit बनाया जाए, तो design document के बराबर का explanation न हो तो शायद वह काफ़ी नहीं होगा, और अगर वह करना ही नहीं है तो लंबे message का मतलब भी धुंधला हो जाता है। लेकिन कुछ लोग इसे किसी medal की तरह लेते हैं और release notes में “bug fixes and feature improvements” जैसी पंक्तियाँ लिखना शुरू कर देते हैं, जो साफ़ तौर पर ग़लत निष्कर्ष है
कई developers यह बात बार-बार भूल जाते हैं कि बदलाव की पृष्ठभूमि पढ़कर समझने वाला “कोई दूसरा” व्यक्ति भविष्य का वही खुद भी हो सकता है। code block को देखकर सिर खुजलाते हुए
git blameचलाना और अपना ही नाम staring back पाना — यह अनुभव शायद सबको परिचित होगाअच्छे commit message ने अनगिनत बार issues, emails, chat logs खंगालकर क्यों ढूँढ़ने में लगने वाले घंटों, कभी-कभी दिनों तक का समय बचाया है। यहाँ तक कि उन मामलों में भी, जहाँ मुझे लगा था कि जवाब तो मुझे तुरंत पता होना चाहिए
अपने future self के प्रति दयालु रहना चाहिए। जो कुछ पता था, जो सोचा था, और जो भी चर्चा हुई थी, उसे git log में उंडेल देना बेहतर है। 5 साल बाद भी क्या अब भी उतना ही obvious रहेगा, यह कभी स्पष्ट नहीं होता
git blameमें अपना नाम देखकर चौंक जाने वाली बात मेरे साथ कम से कम उन चीज़ों में ज़्यादा नहीं होती जिनके पीछे कोई कारण था। सामने वाले के अजीब behavior जैसी random चीज़ों के लिए, जब तक उनकी process दिख न सके, उपयोगी explanation देना मुश्किल है; लेकिन जो कभी मुझे समझ में आता था, उसे दोबारा पढ़ने पर आमतौर पर फिर से समझ आ जाता हैमेरा सीखने का तरीका शायद lava layers की तरह जमा होने वाला है। high school के बाद से बहुत बदलने की बजाय, मैं जो जानता हूँ और जिन तरीकों से उसे इस्तेमाल कर सकता हूँ, उन पर बस लगातार परतें जोड़ता आया हूँ
हाल ही में किसी ने कहा कि अगर commit message एक वाक्य से लंबा हो तो वह ज़्यादातर समय की बर्बादी है। मैं इसका ज़ोरदार विरोध करना चाहता था, लेकिन इसके उलट बात साबित करने में उम्मीद से ज़्यादा अनाड़ी निकला।
एक सवाल यह है कि कौन-सी जानकारी commit message में होनी चाहिए, और कौन-सी inline comments, ADR, या किसी दूसरे लंबे फ़ॉर्म के दस्तावेज़ में जानी चाहिए।
मैं अब भी अच्छे commit messages लिखने की कोशिश करता हूँ, लेकिन काम पर तो अब इसकी कोई उम्मीद नहीं बची, और अपने निजी toy projects में भी मैं लगातार ऐसा नहीं कर पाता।
लेकिन आख़िरी code ऐसा होना चाहिए कि commit message पढ़े बिना भी समझ में आ जाए। अगर नए code में कोई बात ऐसी है जिसके लिए justification चाहिए, तो वह comment में होना चाहिए।
दूसरे शब्दों में, commit message यह समझाता है कि यह बदलाव अभी क्यों किया गया, और comments यह समझाते हैं कि बदलाव पूरा होने के बाद code उस हालत में क्यों है।
बड़े बदलावों के लिए, ख़ासकर नई features के लिए, कहीं न कहीं design document होना चाहिए। अगर review चाहिए, तो वह repository के अंदर का वास्तविक document हो सकता है, या issue tracker में भी हो सकता है।
commit message को उस document की तरफ़ इशारा करना चाहिए, और यह भी समझाना पड़ सकता है कि design के code में उतरते समय कौन-सी details बनीं। अगर संभव हो, तो design document का एक छोटा abstract भी शामिल करना अच्छा है। जब संभावित reviewers कई हों, तो इससे संकेत मिलता है कि किसे सबसे ज़्यादा ध्यान देना चाहिए, और यह पकड़ने में भी मदद मिलती है कि कहीं design चरण में feedback देने वाला कोई ज़रूरी व्यक्ति छूट तो नहीं गया।
git logयाjj logसे नहीं देखता, बल्कि लगभग हमेशा line annotation display के ज़रिए देखता हूँ।subject line आम तौर पर यह तय करने में बहुत काम की होती है कि और गहराई में जाने की ज़रूरत है या नहीं। अगर body में यह जानकारी हो कि बदलाव क्यों किया गया, तो वह तब मदद करती है जब उसका कारण सहज रूप से स्पष्ट न हो।
उदाहरण के लिए, भले ही काफ़ी code जोड़ा गया हो, “admin: add impersonation” अपने-आप में अक्सर काफ़ी होता है। लेकिन “auth: shorten JWT timeouts” के मामले में मैं एक-दो वाक्य देखना चाहूँगा कि timeouts कम करने की ज़रूरत क्यों पड़ी।
बहुत लंबे फ़ॉर्म के commit messages मुझे व्यवहार में काफ़ी बेकार लगते हैं। इस लेख में जो कारण बताए गए हैं, वे भी मोटे तौर पर वही हैं। लगता है कि ऐसा फ़ॉर्मेट उन workflows से आया है जहाँ commit message ही PR description बन जाता है, जैसे email-based workflow या Gerrit। ऐसे मामलों में यह नुकसानदेह तो नहीं है, लेकिन यह ज़रूर कहना मुश्किल है कि इससे हमेशा अतिरिक्त मूल्य जुड़ता है।
मेरी स्थिति भी मिलती-जुलती है। काम पर बड़े समूह में विस्तार से commit messages लिखने वाले सिर्फ़ मैं और एक दूसरा व्यक्ति हैं।
यह जान लेने पर भी कि बाड़ क्यों बनाई गई थी, यह ज़रूरी नहीं कि पता हो कि वह अभी वहाँ क्यों है। यहाँ तक कि Chesterton की बाड़ बनाने वाला व्यक्ति भी यह नहीं जान सकता कि उसे तोड़ा जा सकता है या नहीं
सिस्टम के बनते समय जो intended dependency tree था, वह किसी भी समय के वास्तविक dependency tree का सिर्फ़ एक subset होता है। इसलिए अगर कोई परफेक्ट developer भी आपको बता दे कि बाड़ क्यों बनाई गई थी, तब भी उसकी उपयोगिता सीमित रहेगी
वे यह जानते हैं कि वह क्यों बनाई गई थी, लेकिन “अगर इस बाड़ को हटा दें तो क्या टूटेगा?” इसका जवाब नहीं। https://xkcd.com/1172/ देख लें। कुछ मज़ेदार use case ऐसे हो सकते हैं जिन्हें महत्वहीन समझा जा सके, लेकिन ऐसे वैध उपयोग हमेशा होते हैं जिनके बारे में मूल developer खुद भी नहीं जानता था
मूल developer क्या सोच रहा था या उसने क्या पिया-फूँका था, यह जानना दिलचस्प हो सकता है, लेकिन वह जानकारी अपूर्ण और अप्रासंगिक के बीच कहीं पड़ती है
एक काल्पनिक उदाहरण लें: मान लें Chesterton की बाड़ मूल रूप से तब लगाई गई थी जब दोनों तरफ़ खेत थे, ताकि बच्चों को पानी भरे गड्ढे से दूर रखा जा सके। अब वहाँ हाईवे बन गया है, और संभव है कि वही बाड़ संयोग से हिरणों और गाड़ियों की टक्कर से होने वाली बड़े पैमाने की जानवरों और इंसानों की मौत रोकने वाली एकमात्र चीज़ बन गई हो
यह बात किसी को नहीं पता। हाईवे + बिना बाड़ वाला संयोजन न केवल कभी test नहीं हुआ, बल्कि कभी अस्तित्व में ही नहीं था, और हाईवे बनाने वालों या प्राकृतिक संसाधन विभाग को यह भी नहीं पता कि उस सड़क पर roadkill कम क्यों है। कुछ साल बाद सारे खेत मकानों में बदल जाएँ और वह मुख्य animal corridor न रहे, तो बाड़ बेकार भी हो सकती है, और नहीं भी
अगर यह आपको बनावटी लगे या अपने ऊपर लागू न लगता हो, तो मैं आपसे ईर्ष्या करता हूँ। मेरे अनुभव में, कुछ हद तक बड़े और बहुत पुराने न होने वाले संगठनों को छोड़ दें, तो ज़्यादातर जगह चीज़ें ऐसे ही चलती हैं
सच्चाई यह है कि हम जो कुछ भी करते हैं वह एक ecosystem का हिस्सा है, और उन चीज़ों पर निर्भर भी करता है और उनसे जुड़ा भी रहता है जिनसे स्पष्ट रूप से interact करने पर हमने कभी सहमति नहीं दी। API surface area को कम किया जा सकता है और implementation details को पड़ोसी का काम बनने से रोका जा सकता है, लेकिन अनचाहा coupling बढ़ती entropy जितना ही अपरिहार्य, लगभग ब्रह्मांड का नियम है
कुछ लोगों को यह बात nihilistic और defeatist लगती है। वे कह सकते हैं कि entropy से लड़ना नहीं चाहिए क्या। लेकिन मेरे हिसाब से समय और effort का सबसे अच्छा उपयोग तब होता है जब हम मान लें कि यह मूलतः लड़ने की नहीं बल्कि manage करने की चीज़ है
अगर आप यह मान कर चलें कि दुनिया की स्थिति आपको हमेशा पता हो सकती है, तो आप असफलता और self-blame पहले से बुक कर रहे हैं। जैसे 100% uptime जैसी कोई चीज़ नहीं होती, और ज़्यादातर मामलों में वह गलत लक्ष्य भी है
अगर आप मान लें कि आप किसी ऐसी प्रक्रिया को manage कर रहे हैं जिसमें कुछ हद तक Heisenberg-जैसी uncertainty है, तो आप अपने दिन के सीमित समय का बेहतर उपयोग करके अच्छे नतीजे देने वाले विकल्प चुन सकते हैं। ख़ासकर, proactive और reactive response के बीच समझदारी भरा संतुलन बना सकते हैं, और यह भी समझ सकते हैं कि reactive response को शून्य नहीं किया जा सकता, और कभी-कभी एक दिन की reactive response से बचने के लिए एक साल की proactive response करना समझदारी नहीं होती
तो commit में documentation कितना लिखना चाहिए? design docs या test plan कितने होने चाहिए? मुझे भी नहीं पता। लेकिन एक सुझाव दूँ तो: हर दस्तावेज़ पाठक के लिए लिखा जाता है
अगर आप codebase बदल रहे हैं, तो मौजूदा टीम के लोग, यहाँ तक कि बाद में जुड़ने वाले लोग भी, जाँच-पड़ताल करके यह समझ सकें कि बदलाव ने क्या किया और क्यों किया, और कुछ चेतावनियाँ भी हों—जैसे ख़तरनाक foothold या load-bearing bug के बारे में
यह आम तौर पर लंबा गद्य नहीं होना चाहिए, बल्कि ऐसे pointers होने चाहिए जो scene set करने वाले अतिरिक्त context तक ले जाएँ। जैसे: “इस step पर authentication की ज़रूरत इसलिए रखी गई क्योंकि यह हर बदलाव के लिए multiparty approval policy का हिस्सा है। see: go/multiparty”
इंसानों के लिए बने सिस्टम में perfection थोपना बहुत असुविधाजनक होता है। जैसे DRM, trusted computing, remote attestation, Faro Plague, smart contracts
ऐसा सिस्टम बेहतर है जिसे service mode में reboot करके ठीक किया जा सके। क्योंकि आगे software को लोगों के लिए सचमुच उपयोगी बनाने के लिए उसे किस दिशा में evolve होना चाहिए, यह पहले से नहीं जाना जा सकता। 100% सख़्ती से lock करने से बेहतर है उसे आसानी से ठीक किया जा सकने वाला बनाना
हम commit body लगभग नहीं लिखते, लेकिन title काफ़ी अच्छे लिख लेते हैं। अगर वही metric है, तो पता नहीं वह किस चीज़ को माप रहा है
बड़े codebase में साफ़ code और पर्याप्त test coverage अक्सर documentation से कहीं ज़्यादा उपयोगी होते हैं
कई बार बदलाव पूरी तरह उचित था और tests भी उसी हिसाब से update किए गए थे, लेकिन बाद में देखने पर यह बिल्कुल साफ़ नहीं होता कि वह बदलाव ज़रूरी क्यों था। ख़ासकर तब जब बदली हुई लाइन production में अनपेक्षित या अतिरिक्त व्यवहार पैदा करे
सीधा revert करना वांछनीय न भी हो सकता है, और ऐसे में यह जानना कि बदलाव क्यों किया गया था—उसका पूरा इतिहास—वाकई मददगार होता है
मैंने बहुत बार देखा है कि विचार सही था लेकिन परिणाम अनपेक्षित निकले। अगर मंशा पता हो, तो आप नई समस्या भी ठीक कर सकते हैं और मूल बदलाव का कारण भी बनाए रख सकते हैं, यानी वास्तव में सही बदलाव निकाल सकते हैं
अगर आप एक-पंक्ति commit पर अड़े हैं, तो कम से कम ticket number डालें ताकि वहाँ से इतिहास पढ़ा जा सके
मैंने 5 साल तक ऐसे codebase बचाने के लिए दूर-दराज़ और विचित्र जगहों पर घूमकर काफ़ी अच्छा पैसा कमाया है। @arp242, हमेशा अपनी फ़ीस बढ़ाइए, और https://archive.org/details/working-effectively-with-legacy-code को तकिए के नीचे रखकर सोइए
शुक्र है, AI कबाड़-जेनरेटर अब विशाल commit messages लिख देते हैं। कई बार वे असली बदलाव से कुछ हद तक संबंधित भी होते हैं, तो कम से कम वह समस्या तो हल हुई समझो