'Grug Brained Developer' (2022)
(grugbrain.dev)- लंबे विकास अनुभव से बार-बार मिलने वाला सबसे बड़ा सबक यह है कि जटिलता codebase की “स्थायी दुश्मन” है, और यह ऐसी स्थिति बना देती है जहाँ छोटा बदलाव भी किसी बिल्कुल असंबंधित हिस्से को तोड़ देता है
- जटिलता को घटाने का सबसे शक्तिशाली साधन features और abstractions को “no” कहना है, लेकिन जब व्यावहारिक समझौता ज़रूरी हो, तब 80/20 solution कम code से ज़्यादातर value देता है
- design और testing में बहुत जल्दी abstraction करने के बजाय, system का आकार साफ़ होने के बाद अच्छे boundary points ढूँढने पर ज़ोर दिया जाता है, और unit tests से ज़्यादा लंबे समय तक टिकने वाले integration tests को महत्व दिया जाता है
- tools, type system, logging, debugger, API design को developer का cognitive load कम करना चाहिए, और type system का बड़ा व्यावहारिक लाभ IDE autocomplete में है
- DRY, separation of concerns, microservices, SPA, generics, और ज़रूरत से ज़्यादा refactoring जैसे अच्छे नाम वाले तरीके भी अगर code को समझना और maintain करना कठिन बना दें, तो वे जटिलता के रास्ते बन जाते हैं
जटिलता codebase का सबसे बड़ा जोखिम है
- जटिलता शुरुआत में समझ में आने वाले system को अचानक संभालना कठिन बना देती है, और एक जगह का बदलाव दूसरी, असंबंधित लगने वाली जगह को भी तोड़ देता है
- जटिलता अच्छे इरादे वाले developers या project managers के माध्यम से भी आ सकती है, और कभी-कभी खुद लाई गई जटिलता ही समस्या की जड़ होती है
- जटिलता को खत्म करने वाला कोई万能 “club” नहीं है; सबसे अच्छा उपाय है कि उसे शुरू से अंदर आने ही न दिया जाए
“no” और “ok”: मना करना और व्यावहारिक समझौता
- जटिलता को रोकने का सबसे अच्छा हथियार “no” है
- “वह feature नहीं बनाया जाएगा”
- “वह abstraction नहीं बनाई जाएगी”
- लेकिन “no” अच्छा engineering advice हो सकता है, फिर भी ज़्यादा reward या promotion के लिहाज़ से नुकसानदेह हो सकता है
- जब वास्तविकता में समझौता करना पड़े, तब “ok” कहकर 80/20 solution खोजा जाता है
- यानी इच्छित value का 80% code के 20% से हासिल करना
- इसमें सारे सजावटी features नहीं होते और यह थोड़ा बदसूरत लग सकता है, लेकिन यह ज़्यादातर value देता है और जटिलता कम रखता है
- project manager अगर detailed requirements भूल जाए, बदल दे, या नौकरी छोड़ दे, तो कई बार 80/20 तरीका बेहतर विकल्प साबित होता है
design और code decomposition बहुत जल्दी करना जोखिमभरा है
- project के शुरुआती चरण में system का आकार अभी “पानी” की तरह अस्पष्ट होता है, इसलिए बहुत जल्दी decomposition से बचा जाता है
- समय के साथ अच्छे boundary points सामने आने लगते हैं
- बाकी system के साथ interface संकरा हो
- कम functions या abstractions से अंदर की जटिलता छिपाई जा सके
- abstraction बहुत जल्दी बना देने पर गलत abstraction बनने की संभावना बढ़ती है, इसलिए इंतज़ार करने को ज़्यादा अहमियत दी जाती है
- जो developer शुरुआत में ही बड़ी abstraction बनाना चाहता है, उसे UML जैसे फेंक देने योग्य artifacts देना या अगले दिन चलने वाला demo माँगना मददगार हो सकता है
- शुरुआती prototype असल में चलने वाले code और वास्तविक constraints को जल्दी सामने लाता है
testing “बाद में एक साथ” नहीं, बल्कि “आकार बनते समय साथ-साथ”
- testing कई समस्याएँ रोकती है, लेकिन domain को समझने से पहले ही test first को मजबूर करने वाले तरीके का विरोध किया जाता है
- prototype के बाद जब code ठोस होने लगे, तब ज़्यादातर tests लिखना बेहतर माना जाता है
- “मेरी machine पर तो चल रहा है” कहकर tests छोड़ देना बहुत खराब रवैया है
- test types के बारे में पसंद साफ़ है
- unit tests: project की शुरुआत में उपयोगी, लेकिन implementation बदलने पर आसानी से टूट सकते हैं और refactoring को कठिन बना सकते हैं
- end to end: पूरे system का behavior दिखाते हैं, लेकिन टूटने पर कारण समझना कठिन होता है, और अगर बार-बार टूटें तो इन्हें नज़रअंदाज़ करना आसान हो जाता है
- integration tests: system correctness देखने लायक ऊँचे स्तर पर होते हैं, और debugger से कारण खोजने लायक नीचे भी, इसलिए सबसे बेहतर संतुलन के करीब हैं
- boundary point API स्थिर हो जाए, तो उसके आसपास integration tests में मज़बूती से निवेश किया जाता है
- end-to-end tests को सबसे आम UI functionality और कुछ अहम edge cases तक सीमित रखकर छोटा और व्यवस्थित collection बनाए रखा जाता है
- mocking केवल ज़रूरत पड़ने पर, और जहाँ संभव हो बड़े boundary points के स्तर पर ही इस्तेमाल किया जाता है
- bug मिलने पर अपवादस्वरूप पहले उसे regression test से reproduce करके फिर fix करना पसंद किया जाता है
Agile, refactoring, Chesterton's Fence
- Agile अपने आप में सबसे बुरी चीज़ नहीं है और development organization के एक तरीके के रूप में इस्तेमाल हो सकती है, लेकिन उसे विफलता के बहाने की तरह इस्तेमाल करने वाले “agile shaman” से सावधान रहना चाहिए
- prototype, अच्छे tools, और अच्छे developers की hiring software की सफलता के लिए ज़्यादा महत्वपूर्ण हैं; कोई भी process हर समस्या का silver bullet नहीं है
- refactoring खासकर project के बाद के चरण में, जब code स्थिर हो जाए, उपयोगी है; लेकिन refactoring जितनी बड़ी होगी, विफलता की संभावना उतनी बढ़ेगी
- इसे छोटे हिस्सों में बाँटकर करें
- system को जहाँ तक संभव हो लगातार चलने की स्थिति में रखें
- हर चरण के बाद ही अगले चरण पर जाएँ
- ज़रूरत से ज़्यादा abstraction refactoring failure और system failure तक ले जा सकती है
- Chesterton's Fence इस सोच से जुड़ता है कि बदसूरत दिखने वाले code को भी हटाने से पहले यह समझना चाहिए कि वह वहाँ क्यों है
- जो code चल रहा है, वह perfect न हो तब भी उसका सम्मान करना चाहिए, और system जितना बड़ा हो, पहले उसे समझने में उतना समय देना चाहिए
microservices और tools
- microservices system को सही तरह बाँटने की कठिन समस्या में network calls भी जोड़ देते हैं
- tools developer की productivity और understanding को बहुत बढ़ा सकते हैं
- नए environment में tools सीखने पर समय लगाना फायदेमंद होता है
- 2 हफ्ते tools सीखने में लगाने से development speed 2 गुना हो सकती है
- documentation न हो, तो दूसरे developers से पूछना और खुद गहराई में जाना ज़रूरी हो सकता है
- IDE का code completion यह सुनिश्चित करता है कि हर API याद रखना न पड़े, और Java development में यह लगभग अनिवार्य है
- अच्छा debugger बहुत महत्वपूर्ण है
- conditional breakpoints
- expression evaluation
- stack navigation
- नए developers को उपलब्ध debugger को गहराई से सीखना चाहिए; यह उन्हें university classes से भी ज़्यादा computer के बारे में सिखा सकता है
type system, expressions, DRY
- type system का सबसे बड़ा मूल्य उस tool support में है जहाँ dot लगाने पर संभावित actions की सूची दिखाई देती है
- type correctness भी अच्छी चीज़ है, लेकिन code completion और navigation का व्यावहारिक मूल्य उससे बड़ा है
- type system का बहुत ज़्यादा abstract इस्तेमाल करने वाले developers से सावधान रहना चाहिए
- generics खास तौर पर जोखिमभरे हो सकते हैं
- ज़्यादातर मामलों में इन्हें container classes तक सीमित रखना बेहतर माना जाता है
- छोटे conditional expressions को एक ही line में ठूँसने के बजाय, meaningful नाम वाले intermediate variables में बाँट देना debugging और understanding दोनों के लिए बेहतर है
- DRY अच्छी सलाह है, लेकिन इसमें संतुलन चाहिए
- सरल और स्पष्ट duplicate code कई बार जटिल callbacks, closures, या object model से बेहतर होता है
- अगर duplication हटाने से ही जटिलता बढ़ जाए, तो नुकसान हो सकता है
separation of concerns, closures, logging
- Separation of Concern एक शक्तिशाली विचार है, लेकिन व्यवहार में यह कई files के बीच आना-जाना कराकर behavior समझने में समय बर्बाद कर सकता है
- इसके विकल्प के रूप में locality of behavior को तरजीह दी जाती है
- अगर code को “जिस चीज़ पर वह काम करता है” उसके पास रखा जाए, तो उसे देखते ही समझ आता है कि वह क्या करता है
- closures collection operations को abstract करने के लिए उपयुक्त हैं, लेकिन नमक की तरह थोड़ी मात्रा ही काफी है
- JavaScript का “callback hell” closures के अत्यधिक उपयोग से पैदा हुई जटिलता का उदाहरण है
- logging खासकर cloud deployment environment में बहुत महत्वपूर्ण है
- हर बड़े logic branch पर log छोड़ें
- कई machines से गुजरने वाली requests में request ID शामिल करें ताकि logs को जोड़ा जा सके
- जहाँ संभव हो log levels को dynamically adjust करें
- जहाँ संभव हो user-specific log levels से किसी खास user की समस्या debug करें
- logging libraries जटिल हो सकती हैं, लेकिन logging infrastructure को सही तरह बनाना बाद में बड़ा लाभ देता है
concurrency, optimization, API
- concurrency डरने लायक क्षेत्र है, इसलिए जहाँ तक संभव हो simple models पसंद किए जाते हैं
- stateless web request handlers
- ऐसे remote work queues जो एक-दूसरे पर निर्भर न हों
- simple API
- web में optimistic concurrency अच्छा फिट हो सकता है
- Java के ConcurrentHashMap जैसे concurrency data structures भी सावधानी से इस्तेमाल करने चाहिए
- optimization तभी शुरू करनी चाहिए जब actual performance profiling से कोई ठोस समस्या सामने आ जाए
- सिर्फ CPU को नहीं देखना चाहिए
- network access कई CPU cycles के बराबर महँगा होता है, इसलिए जहाँ संभव हो उसे कम करना चाहिए
- nested loops देखकर तुरंत
O(n^2)हटाने में लग जाना जटिलता बढ़ा सकता है
- अच्छी API ऐसी होनी चाहिए जिससे developer को बहुत ज़्यादा सोचना न पड़े
- अगर API author implementation या domain perspective में फँस जाए, तो API इस्तेमाल करना कठिन हो जाता है
- simple cases के लिए simple API, और complex cases के लिए अलग से more complex API देना layering का अच्छा तरीका है
- object-oriented design में behavior जहाँ तक संभव हो उसी object पर होना चाहिए
- Java के stream/collector examples को ऐसे API के रूप में आलोचना की जाती है जो आम कामों को भी अनावश्यक रूप से घुमा देती है
parsing, Visitor Pattern, frontend
- parser के लिए recursive descent तरीका मज़ेदार और सुंदर माना जाता है
- parser generators में generated code को समझना और debug करना कठिन होता है, और वे grammar की recursive nature को छिपा देते हैं
- वास्तविक production parsers ज़्यादातर recursive descent होते हैं, और Bob Nystrom की Crafting Interpreters की सिफारिश की जाती है
- Visitor pattern को संक्षेप में “bad” कहा गया है
- frontend और backend को अलग करके, SPA libraries और GraphQL JSON API को HTTP से जोड़ने का तरीका जटिलता के दो अलग घोंसले बनाने जैसा है
- साधारण websites या forms को database में डालने वाले कामों के लिए भी बड़े frontend libraries इस्तेमाल करने की प्रवृत्ति से सावधान रहने को कहा गया है
- जटिलता कम करने के लिए htmx और hyperscript बनाए गए
- simple HTML बनाए रखें
- बहुत अधिक JavaScript से बचें
- React नौकरियों और कुछ application types के लिए बेहतर हो सकता है, लेकिन इसे frontend complexity के रास्ते में प्रवेश मानकर देखा गया है
trends, FOLD, impostor syndrome
- development में trends बहुत हैं, और frontend में यह और भी अधिक दिखाई देता है
- जो भी नया approach खुद को revolutionary बताए, उस पर संदेह रखना चाहिए
- computing में ज़्यादातर ideas पहले कभी न कभी आज़माए जा चुके हैं
- बुरे ideas नए नामों से लौट सकते हैं
- जब senior developer खुलकर कहता है “यह इतना complex है कि समझना मुश्किल है”, तो यह अच्छी बात है
- FOLD का मतलब Fear Of Looking Dumb है, यानी मूर्ख दिखने के डर से जटिलता को जटिल मानने की हिम्मत न होना
- जब senior कहता है कि चीज़ complex है, तब junior के लिए भी यह मानना आसान हो जाता है कि उसे समझ नहीं आया
- खासकर युवा developers में FOLD वह बड़ा स्रोत है जिससे जटिलता ताकत पाती है
- developers अक्सर इस भावना के बीच झूलते रहते हैं कि वे सब कुछ नियंत्रित कर रहे हैं, और इस भावना के कि उन्हें कुछ भी नहीं आता; impostor syndrome बहुत आम है
- अगर सबको impostor जैसा लगता है, तो कोई भी वास्तव में impostor नहीं है, और युवा developer निराशा और चिंता के बावजूद अपना career जारी रख सकता है
सुझाई गई पढ़ाई और निष्कर्ष
- सुझाई गई पढ़ाई
- आख़िरी निष्कर्ष वही है जो शुरुआत में था: जटिलता बहुत, बहुत बुरी है
1 टिप्पणियां
Hacker News की रायें
यह अजीब है कि समझदार लोग पतंगों की तरह complexity की ओर खिंचे चले जाते हैं
over-engineer करने की इच्छा से लड़ना सीखने में सालों लग जाते हैं
एक बार यह दिखने लगे तो इसे अनदेखा करना मुश्किल हो जाता है, और अब मैं तुरंत बता सकता हूँ कि code over-engineered है या नहीं
अफसोस, लगभग 99% code over-engineered लगता है, और developers पर अपनी अप्रतिस्थापनीयता और billable hours को अधिकतम करने का incentive जोरदार तरीके से काम करता है
पूरी तरह mechanical और ego-less दिखने वाले developers भी अक्सर over-engineering कर बैठते हैं, और यह अवचेतन रूप से होता है
कई developers अपने लिखे code की हर line के बारे में सचेत होकर नहीं सोचते; वे बस एक लक्ष्य तय करते हैं और पहला code निकाल देते हैं जो उन्हें उस लक्ष्य के थोड़ा करीब ले जाए, इसलिए उन्हें पता ही नहीं चलता कि हर step पर बेहतर विकल्प मौजूद था
पहला, मुझे मजेदार puzzles पसंद हैं। खासकर commercial code, अगर सही से बनाया जाए, तो अक्सर काफी boring होता है, इसलिए अवचेतन में मैं ऐसी features को आगे बढ़ा देता हूँ जिनका implementation मजेदार हो। यहाँ मजेदार का मतलब अंततः ऐसी feature है जो सब कुछ जरूरत से ज्यादा complex बना देती है
दूसरा, जब मैं कुछ program कर रहा होता हूँ, तो मेरे द्वारा चुना गया हर विकल्प स्वाभाविक और जरूरी लगता है। बाद में code से दूरी बनाकर, नई नजर से उसे फिर समझने की कोशिश करता हूँ, तभी दिखता है कि मैंने कितना गड़बड़ कर दिया था
अधिकतर समस्याओं में सबसे obvious solution अक्सर काफी complex होता है, और simple solution कहाँ खोजना है यह जानने के लिए समझदारी, skill और domain knowledge चाहिए। simple और साफ solution शायद ही कभी obvious होता है
“हम आधी-अधूरी message queue धीरे-धीरे implement कर रहे हैं। बस standard message queue इस्तेमाल करें”, “हम bug-भरा custom binary framing protocol बना रहे हैं। बस protobuf/msgpack इस्तेमाल करें”, “data लाने के लिए custom RPC protocol मत बनाओ, HTTP पर REST इस्तेमाल करो। इससे बीच में nginx लगाकर backend responses cache कर सकते हैं और custom cache भी फेंक सकते हैं”
आखिरकार अगर समय हो और वैसा करने पर reward मिले, तो perfect, simple और repetition-free code लिखा जा सकता है। लेकिन अधिकतर मामलों में किसी चीज़ को release करने, और उसे release करने में लगी मेहनत, बुद्धि और design क्षमता से अपनी technical capability दिखाने को reward मिलता है
स्वाभाविक नतीजा यह होता है कि सब कुछ फूला हुआ, over-engineered temporary fixes का ढेर बन जाता है, जिसे हर 3–7 साल में फिर से लिखा जाता है
मैंने data नहीं देखा है, लेकिन लगता है कि “rewrite half-life” का संबंध attrition rate या average tenure से हो सकता है। लोग over-engineering से बचने की ज्यादा कोशिश करें तब भी शायद वह फिर से लिखा ही जाएगा
perfectionist होने के नाते यह सचमुच खलता है, लेकिन कई बार सबसे अच्छे simple solution पर अधिक देर सोचने की तुलना में complex और over-engineered चीज़ बनाना ज्यादा reward पाता है। बेहतर organizations भी होंगी, लेकिन software engineer के रूप में 9 साल काम करने के बाद भी मुझे अभी तक नहीं मिलीं
open source projects सबसे अच्छे counterexample लगते हैं, लेकिन अच्छी libraries भी maintainer बदलने पर rewrite हो जाती हैं या नया version आ जाता है। open source और HN के कई full-time software engineers जिस enterprise junk को देखते हैं, उनके बीच monetary incentives बहुत अलग हैं। यह अच्छी तरह सँवारे गए academic paper और जल्दबाजी में लिखे work email की तुलना जैसा है
मुझे याद है Handmade Hero के Casey ने अपनी programming style को “compression-based” कहा था। यानी पहले code लिखो, फिर जो चीजें साथ belong करती हैं उन्हें धीरे-धीरे अलग करो
abstraction तब करो जब repetition हो, न कि conscious design करके abstraction करो। मैं धीरे-धीरे इस तरीके का ज्यादा इस्तेमाल कर रहा हूँ
इसका अपने-आप यह मतलब नहीं कि वह गलत है, लेकिन अगर बात दूसरे लोगों के काम की quality आँकने की हो, तो उसमें मजबूत bias होने की संभावना ज्यादा लगती है
मुझे यह site सचमुच बहुत पसंद है और यह हमेशा हँसा देती है। खासकर मेरा सबसे पसंदीदा हिस्सा microservices है
“grug को समझ नहीं आता कि बड़े दिमाग वाले लोग सबसे मुश्किल समस्या, यानी system को सही तरह से बाँटने का काम, क्यों लेते हैं और उसमें network calls भी जोड़ देते हैं। grug को यह बहुत confusing लगता है”
“complexity बहुत, बहुत बुरी है”
“अगर complexity और Tyrannosaurus के साथ 1:1 लड़ाई में से चुनना हो, तो grug Tyrannosaurus चुनेगा। कम से कम grug Tyrannosaurus को देख तो सकता है”
type वाले हिस्से से मुझे शिकायत है
grug कहता है कि type system की 90% से ज़्यादा वैल्यू इसमें है कि keyboard पर dot दबाते ही जादू की तरह विकल्पों की list आ जाती है, लेकिन हमारी कंपनी के juniors अक्सर production में ऐसे code deploy करते हैं जो null access की वजह से टूट जाता है, और Sentry हमें वह बता देता है
intensive development period में हर junior developer पर रोज़ करीब एक detected null access bug निकल आता है
static checking वाला सही type system इस्तेमाल करें तो IDE में “यह null हो सकता है, पक्का?” जैसा warning मिलना बहुत मददगार होगा
और static types न हों तब भी autocomplete संभव है
“बड़े-दिमाग type system के जादूगर कहते हैं कि type correctness ही type system का मूल है, लेकिन grug ने देखा है कि ऐसे जादूगर अक्सर code deploy नहीं करते. deploy न हुआ code किसी अर्थ में सही हो सकता है, लेकिन grug जिस correctness की बात करता है वह नहीं” वाला हिस्सा बदतमीज़ और गैर-ज़रूरी है
मैंने ज़्यादातर C, PHP, Python, Haskell और typed Python में code deploy किया है, और typed languages में production तक पहुँचने वाले bugs की दर बहुत कम होती है. types पसंद करने की यह भी एक वजह है
साथ ही refactoring बहुत आसान हो जाती है. किसी widely used चीज़ को बदलते समय पूरी codebase में टूटे हुए call sites को कुछ seconds में भरोसेमंद तरीके से देख सकते हैं, और बढ़ती हुई codebase को iterative तरीके से सुधारने में यह बहुत मदद करता है
बल्कि आप एक pragmatic type system को स्वीकार करते हैं, जो कुछ समस्याएँ पकड़ता है और सबसे बढ़कर autocomplete magic देता है, लेकिन पूर्ण correctness proof के लिए ज़रूरी हर detail में आपको फँसाता नहीं
वह C या Java level की static typing को ठीक या अच्छा मानता है, और Rust या Scala में दिखने वाली ज़्यादा flashy चीज़ों को समय की बर्बादी समझता है. मुझे लगता है कि वह पूरी तरह गलत है, लेकिन ज़िंदगी ऐसी ही है
मैंने “बड़े-दिमाग type system जादूगर” को ऐसे समझा कि वह ज़रूरी नहीं कि code लिखने वाला व्यक्ति हो, बल्कि उदाहरण के लिए वह जो इस topic पर courses बेचता है और लोगों को hype करता है
लेख के शुरू में Agile के बारे में भी “जादूगर” शब्द आता है, और ऐसे काफी लोग हैं जिनका काम actual software development से ज़्यादा courses बेचने जैसा है
type hierarchy पर अटक जाने वाले लोगों के साथ काम करना बहुत मुश्किल होता है, और justification आम तौर पर “अगर ऐसा हो जाए तो” और “लेकिन वह sound नहीं है” वाली दुनिया में ही रहती है
type systems से होने वाली quality degradation में से बहुत कुछ उन लोगों से आता है जो मानते हैं कि अगर पर्याप्त types डाल दिए जाएँ तो bugs पूरी तरह रोके जा सकते हैं, जबकि यह सच नहीं है
लगता है अगले कुछ महीनों में सब HTMX train पर चढ़ने वाले हैं, और यह बहुत से युवा developers के दिमाग हिला देगा, दुनिया भर में काफी energy बचाएगा और बहुत लोगों को खुश करेगा
फिर जब ये curious युवा लोग htmx.org के links दबाते-दबाते hyperscript तक पहुँचेंगे, तो वह Dusk till Dawn में vampires के अचानक निकल आने वाले पल जैसा होगा
JavaScript complexity से थका कोई व्यक्ति एक simple JavaScript library बनाता है, लोग उसकी simplicity की वजह से उस पर टूट पड़ते हैं, फिर सभी web features support करने पड़ते हैं तो library complex हो जाती है, और फिर उस complexity से थका कोई और व्यक्ति एक simple JavaScript library बनाता है
मैंने pure JavaScript से शुरुआत की, IE5/6 से कई साल लड़ता रहा, jQuery ने सबको बचाया, AngularJS पसंद नहीं आया इसलिए skip किया, और React beta आते ही functional programming ideals की वजह से उसे पसंद किया. अब मैं transpiling, hot reload, Typescript और भारी React libraries के ढेर में रास्ता बना रहा हूँ
Intercooler और HTMX से भी कुछ projects बनाए हैं. HTMX कुल मिलाकर solid है, लेकिन यह इस कस्बे से गुजरने वाली पहली train नहीं है
htmx पर असली criticism देखना चाहता हूँ
व्यक्तिगत रूप से मुझे लगता है कि web की बड़ी ongoing चुनौती pages को अच्छे से update करने का तरीका ढूँढना रही है, और हम हर तरह की कोशिशें करते रहे हैं. इसलिए fatigue होती है, और कुछ ideas radical हो जाते हैं या समय के साथ junk बन जाते हैं
Htmx grug-style में कम करने और YAGNI पर ज़ोर देने वाली एक reaction जैसा दिखता है
future अनिश्चित है, लेकिन signals जैसे काम अब भी sacred work जैसे लगते हैं. कई directions में बहुत कोशिशें हो रही हैं, और हम यह front और दूसरे fronts अभी भी explore कर रहे हैं
MobX और Svelte वगैरह भी पहले ही लंबा सफर तय कर चुके हैं. सफर अभी खत्म नहीं हुआ और complexity नाम के monster से लगातार उलझना weakness का संकेत नहीं, बल्कि मैं यह मानना चाहूँगा कि भले conservative या grug-style thinking उसे ऐसा समझे, यह सिर्फ simple approach नहीं बल्कि simple और good तक पहुँचने की जरूरी कोशिश है
_="on load wait 5s then transition opacity to 0 then remove me"ओह, नहीं
_="on htmx:error(errorInfo) fetch /errors {method:'POST', body:{errorInfo:errorInfo} as JSON} "ओह, नहीं!
developer के तौर पर 30 साल काम किया है, और मानता हूँ कि शुरुआती दिनों में मैं arrogant था और सोचता था कि मैं दूसरों से ज़्यादा smart हूँ. उस समय मैं हर complexity demon को पसंद करने वाला “बड़े-दिमाग” वाला था
10 साल बाद मैं “Grug brain” developer के ज़्यादा करीब हो गया, और अब जानता हूँ कि perfect न भी हो, तो भी चलने वाले सबसे simple solution पर ध्यान देना चाहिए. यह ठीक है क्योंकि इससे सही चीज़ के करीब पहुँचना और iterative improvement संभव होता है
developer के तौर पर आप जो सबसे अच्छी चीज़ कर सकते हैं वह है code delete करना. अभी हमारे यहाँ 2 साल से maintained एक requirement अचानक अब requirement नहीं रही, और बहुत सारा code निकाल फेंकने के विचार से मैं सच में excited हूँ. क्योंकि इससे सब कुछ और simple हो जाएगा
जैसे शरीर से महसूस हो रहा हो कि space मुक्त हो रही है
Grug का ज़िक्र एक हफ्ते पहले Philosophy of Software Design वाले लेख के comments में भी आया था, और मुझे लगता है तब चर्चा काफ़ी अच्छी रही थी। https://news.ycombinator.com/item?id=38011938
“grug के बारे में मेरी भी बिल्कुल यही भावना है। मुझे नहीं लगता कि लोग सच में इस बात पर सहमत होते हैं कि सरल क्या है, इसलिए अपनी ‘सरलता’ को ऐसा दिखाना कि जैसे कोई आदिम इंसान भी उससे सहमत होगा, डींग जैसा लगता है”
सरलता अक्सर खोजने के लिए सबसे जटिल चीज़ों में से एक होती है। मैंने बहुत से ऐसे लोग देखे हैं जो मानकर चलते हैं कि उनके आसपास की हर चीज़—सिवाय उनके अपने काम के—जटिल है और उसे सरलता की ओर मोड़ना चाहिए। यह authority से चिपके रहने वाला ख़तरनाक रूप से कमज़ोर रवैया लगता है
grug brain philosophy यह है कि जब तक बिल्कुल टाला न जा सके, हर कीमत पर सरलता चुनी जाए
grug की नज़र में big brain philosophy यह है कि जब तक बिल्कुल टाला न जा सके, हर कीमत पर reusability चुनी जाए
इस philosophy की समस्या यह है कि यह पहली पीढ़ी के design choices को जड़ बना देती है और iterative improvement को और कठिन कर देती है
यह सही है कि सरलता खोजना कठिन है, लेकिन सरलता खोजने की कुंजी iterative improvement है
local minima इस बात पर निर्भर करते हुए खिसकते हैं कि आप जो बना रहे हैं उसकी complexity कितनी है, इसलिए कई काफ़ी समझदार राय एक साथ सही हो सकती हैं
यह perfect metric नहीं है, लेकिन दिशा सही है, और log scale पर यह बहुत अच्छा काम करता है
Chesterton’s fence का concept मैंने अनगिनत बार इस्तेमाल और समझाया है, और उसका नाम जानकर अच्छा लगा
नए developers के साथ काम करते समय यह सच में बहुत बार होता है। वे “पुराना legacy कचरा” देखते ही पहली प्रतिक्रिया में उसे उखाड़ फेंकना या सब छोड़कर शुरुआत से फिर बनाना चाहते हैं
कुछ मामलों में उन्हें खुद कोशिश करने देना भी सीखने का मौका हो सकता है, लेकिन यह याद रखना अच्छा है कि हमसे पहले वाले लोग सभी पूरी तरह मूर्ख नहीं थे, और आम तौर पर उन्होंने ऐसा किसी वजह से किया था
कभी-कभी वह वाकई गंदा पुराना code होता है जिसे बदलना चाहिए, लेकिन ऐसे मामलों में भी उसमें अक्सर उस domain में कुछ बनाने के लिए समझने और संभालने पड़ने वाले तमाम कोनों और edge cases का कठिनाई से हासिल किया गया record छिपा होता है
testing वाला हिस्सा सच में अच्छा है। यह उन बातों से बिल्कुल मेल खाता है जो मैं वर्षों से सीखता आया हूँ
bugs खोजने के लिए integration tests सही जगह हैं
mock objects काम को जरूरत से ज़्यादा जटिल बना देते हैं; अभी भी कभी-कभी इस्तेमाल करता हूँ, लेकिन systematic तरीके से इस्तेमाल करने से बचता हूँ
unit tests refactoring के सामने बहुत fragile होते हैं, जबकि integration tests refactoring में मदद करते हैं
unit tests लिखना और maintain करना ज्यादा कठिन है, लेकिन fail होने पर उन्हें समझना और debug करना कहीं आसान होता है, इसलिए वे long term में बहुत बेहतर टिकते हैं
सबसे खराब test वह integration test है जो चुपचाप इस बात पर निर्भर करता है कि कोई दूसरा integration test पहले चल चुका है। 99% समय सही रहता है, लेकिन किसी change से order बदलते ही टूट जाता है
अगर team के पास सरल code है तो tests बहुत मदद करते हैं। लेकिन अगर team के पास सरल code नहीं है—और आम तौर पर नहीं होता—तो tests लिखने में समय लगाने से बेहतर है code को सरल बनाने में समय लगाना
किसी leaf function को unit मानना अक्सर बहुत low-level होता है, लेकिन अपेक्षाकृत stable interface वाला बड़ा module testing के लिए productive अच्छा unit हो सकता है
“complexity बहुत बहुत बुरी है”
“complexity soul demon के खिलाफ सबसे अच्छा हथियार जादुई शब्द ‘नहीं’ है”
“दुखद लेकिन सच: ‘हाँ’ सीखने के बाद fail होने पर दूसरे grug को दोष देना सीखना ideal career advice है”
यह grug की जटिल wisdom है
उस समय भी चर्चा हुई थी
The Grug Brained Developer - https://news.ycombinator.com/item?id=31840331 - जून 2022, 374 comments