अलविदा, Clean Code (2020)
(overreacted.io)- एक graphics editor के resize code को duplication हटाने पर केंद्रित होकर दोबारा लिखने और फिर उसे revert करने के अनुभव के ज़रिए यह दिखाता है कि Clean Code के प्रति जुनून असल में बदलाव को आसान बनाने की क्षमता को नुकसान पहुँचा सकता है
- मौजूदा implementation में Rectangle, Oval, Header, TextBlock के हर handle के लिए formulas दोहराए गए थे, और नई implementation ने direction और shape को अलग करके उन्हें compose करने के तरीके से duplication हटाने की कोशिश की
- refactoring के तुरंत बाद code size आधा हो गया और बदलाव की जगहें भी एक जगह सिमट गईं, लेकिन बाद में अगर shape- या handle-specific special behavior की ज़रूरत पड़ती, तो abstraction उल्टा बाधा बन सकती थी
- technical judgment से भी बड़ा मुद्दा यह था कि original code लिखने वाले सहकर्मी से सलाह किए बिना सीधे master में check in कर दिया गया, जो team में trust building को नुकसान पहुँचा सकता है
- “साफ-सुथरापन” लक्ष्य नहीं, बल्कि complex systems से निपटने का एक tool भर है; code कैसा दिखता है, उससे ज़्यादा अहम यह है कि team मिलकर बदलावों पर प्रतिक्रिया दे पा रही है या नहीं
Graphics editor के resize code में दोहराव
- graphics editor canvas में rectangles और ovals जैसी shapes को किनारों पर मौजूद छोटे handles से resize करने वाला code था
- implementation काम कर रही थी, लेकिन हर shape और handle direction के लिए position और size calculate करने वाले formulas दोहराए गए थे
RectangleमेंresizeTopLeft,resizeTopRight,resizeBottomLeft,resizeBottomRightजैसे methods थेOvalमेंresizeLeft,resizeRight,resizeTop,resizeBottomजैसे methods थेHeaderऔरTextBlockके भी अपने-अपने resize methods थे
- user Shift दबाता तो resize के दौरान aspect ratio बनाए रखना भी handle करना पड़ता था, जिससे formulas और बढ़ गए थे
Duplication हटाने के लिए abstraction
- repetition दो axes पर दिख रही थी
- same direction वाले handles के बीच repetition:
Oval.resizeLeft()औरHeader.resizeLeft()दोनों left handle drag करने की action हैं - same shape के अंदर methods के बीच repetition:
Ovalके कई methods सब oval से ही deal करते हैं
- same direction वाले handles के बीच repetition:
- नई structure ने code को
DirectionsऔरShapesमें बाँटकर direction-wise behavior और shape-wise behavior को compose करने की कोशिश कीDirectionsमेंtop,left,bottom,rightरखे गएShapesमेंOval,Rectangleरखे गएcreateHandle,createBoxसे handles और shapes को combine किया गया
- इस तरीके में
fourCorners,fourSides,twoSidesजैसे handle configurations बनाए गए, और उनका उपयोग करकेRectangle,Oval,Header,TextBlockबनाए गए
Refactoring के तुरंत बाद का भ्रम
- refactoring के बाद कुल code size आधा हो गया और duplication गायब हो गया जैसा लगा
- माना गया कि किसी specific direction या shape का behavior बदलते समय कई methods के बजाय केवल एक जगह modify करनी होगी
- देर रात change को master में check in कर दिया, और लगा कि सहकर्मी के messy code को साफ-सुथरे ढंग से सुलझा दिया है
अगले दिन सामने आई समस्या
- अगले दिन manager ने change revert करने को कहा, और उस समय यह समझना मुश्किल था क्योंकि नए code को पुराने code से ज्यादा साफ माना जा रहा था
- समय बीतने पर समझ आया कि यह judgment दो वजहों से सही था
- original code लिखने वाले व्यक्ति से बात किए बिना code दोबारा लिखकर check in कर दिया गया था
- duplication कम करने के बदले requirements बदलने की ease sacrifice कर दी गई थी
- एक healthy engineering team को लगातार trust build करना होता है, और सहकर्मी के code का large-scale rewrite collaboration को बड़ा झटका दे सकता है
गलत abstraction की लागत
- बाद में कई shapes के कई handles के लिए बहुत सारे special cases और behaviors की ज़रूरत पड़ी
- नई abstraction structure में ऐसी requirements को support करने के लिए code कई गुना ज्यादा complex हो सकता था
- इसके उलट, पुरानी “messy” structure में हर method अलग था, इसलिए ऐसे changes apply करना अपेक्षाकृत आसान था
- code duplication हटाना free नहीं होता; कोई capability हासिल करने के बदले दूसरी capability खोनी पड़ सकती है
“साफ-सुथरापन” पर फिर से सोचना
- “Clean Code” और duplication हटाने के जुनून वाला दौर कई developers के साथ हो सकता है
- जब अपने लिखे code पर confidence नहीं होता, तो strict lint rules, naming rules, file structure, zero duplication जैसी measurable चीज़ों से pride जोड़ना आसान होता है
- जब abstraction बनाना आ जाता है, तो हर repetitive code देखकर abstraction को virtue मानकर उसे लागू करने की इच्छा हो सकती है
- “clean” या “dirty” का एहसास वास्तव में किन engineering outcomes से जुड़ता है, इस पर गहराई से सोचना चाहिए
- code कैसा दिखता है, इतना ही नहीं; team के लोगों के साथ मिलकर code कैसे change और modify होता है, यह महत्वपूर्ण है
Clean Code को छोड़ने का समय
- Clean Code लक्ष्य नहीं, बल्कि complex system को समझने की एक कोशिश है
- जब codebase में किसी change का क्या असर होगा, इसका भरोसा न हो, तो यह दिशा दिखाने वाला defense mechanism बन सकता है
- शुरुआत में function extraction या class refactoring से complex code को simple बनाने का अनुभव अच्छा लग सकता है
- लेकिन वहीं रुककर “Clean Code zealot” नहीं बन जाना चाहिए
- Clean Code को guide बनने दें, लेकिन किसी point पर उसे छोड़ना भी चाहिए
1 टिप्पणियां
Hacker News राय
कोड duplication कभी-कभी ठीक हो सकता है, लेकिन यह Clean Code के खराब होने का सबूत नहीं है
लगता है refactoring थोड़ी ज्यादा कर दी गई थी; अगर बस “दोहराई जा रही गणित की 10 lines” को function में निकाल दिया जाता, तो वह ज्यादा साफ होता
जिसने वे 10 lines function में नहीं निकालीं, उस teammate ने भी बहुत अच्छा नहीं किया था, इसलिए मैं होता तो PR reject कर देता, लेकिन खुद उसे दोबारा नहीं लिखता
किसी और के PR को दोबारा लिख देना discussion की गुंजाइश बंद कर देने वाला तेज़ अपमान है, और अक्सर हमें यह भी नहीं पता होता कि code उस तरह लिखे जाने का context क्या था
coding standards न हों तो PR को review करके reject करना चाहिए; “Clean Code मायने नहीं रखता” वाली सोच के साथ commit होने दिया, तो कुछ महीनों में codebase ऐसा बन जाएगा जिस पर कोई काम नहीं करना चाहेगा
यहां सीखने वाली बात Clean Code नहीं, बल्कि communication और consideration है
मूल लेखक से यह सीखने का मौका भी छिन जाता है कि low-quality code असल में समय कैसे बर्बाद करता है
भले ही Clean Code approach बेहतर हो, यहां मुख्य बात code नहीं है, बल्कि बिना उपयोगी feedback दिए अपना समय बर्बाद करना है
सबसे अच्छा यह होता कि मूल लेखक अपना standard बढ़ाता, और आप वह दूसरा काम करते जिसे सच में ठीक करने की जरूरत थी। यानी सही जवाब code review था
ऐसे लोग वास्तविक समस्या हल करने के बजाय गैर-समस्या हल करते हैं और साथ में भविष्य की समस्याएं भी पैदा कर देते हैं
पहली implementation में ऐसी 10 lines जैसी बहुत छोटी code को abstract न करना ही सही है। जो code ठीक वही काम करता है, उसे बाद में बदलना आसान होता है, और अप्रमाणित फायदे के लिए 10 lines को abstract करने का मतलब कम है
Clean Code बिल्कुल भी महत्वपूर्ण नहीं है, और उससे मिलते-जुलते अधिकतर rules या “principles” भी महत्वपूर्ण नहीं हैं। बल्कि ये वे चीजें हैं जिन्हें वे लोग पकड़ते हैं जो समय के साथ codebase में मधुमक्खी के छत्ते जैसी structure खड़ी करके उसे justify करना चाहते हैं
नतीजतन code अक्सर overly abstracted, बदलने में कठिन, धीमा और समझने में मुश्किल हो जाता है
अगर कोई principle चाहिए, तो बस यह देखें कि program असल में जो करता है—data transformation—उसे स्पष्ट और आसानी से बदले जा सकने वाले रूप में कैसे व्यक्त किया जाए
SOLID principles में से ज्यादातर यह देखने में मदद नहीं करते कि data transformation क्या है और कैसे होता है, या उल्टा बाधा बनते हैं, इसलिए वास्तविक program समझने में आमतौर पर उनका उपयोग कम है
सुझाए गए refactoring को देखें तो वे 10 lines असल में identical नहीं थीं, सिर्फ मिलती-जुलती थीं
rectangle के top-left corner को resize करने का formula और ellipse के bottom-right को बदलने का formula अलग हैं। ऊपर से वे मिलते-जुलते दिखते हैं, लेकिन कहीं
+की जगह-आ जाता हैइस case में complexity geometry itself में है, और इसे “abstract” करने से गंदगी सिर्फ कहीं और चली जाएगी, मूल रूप से गायब नहीं होगी
किसी special number system जैसी चतुर mathematical abstraction हो सकती है, लेकिन अगर वह language में built-in नहीं है, तो basic integers के साथ special operations implement करने की cost, मिलने वाले फायदे से ज्यादा होने की संभावना है
“Clean Code” को rebranding की जरूरत है
25 साल से ज्यादा के career में design patterns, abstraction, duplication removal आदि के खिलाफ अंतहीन backlash देखता आया हूं
हमेशा वही वजहें आती हैं: abstraction code को और complex बना देती है, Clean Code लिखने का समय नहीं है, यह सब taste और opinion ही है
लेकिन Clean Code का उद्देश्य requirements बदलने पर code को अधिक simple और maintainable बनाना है
software की value इसी में है कि वह समय के साथ बदल सकता है। अगर ऐसा न हो, तो implementation और maintenance में कहीं आसान और सस्ते fixed circuits इस्तेमाल किए जा सकते हैं
अगर refactoring यह लक्ष्य हासिल नहीं कर पाई, और boss यह convincingly कह सकता है कि future requirement changes के लिए यह अधिक मुश्किल maintainable हो गया है, तो वह code “clean” था ही नहीं
मूल लेखक से चर्चा न करना Clean Code के दायरे से बाहर का process और etiquette issue है। किसी ने rude तरीके से मनमानी की, इससे Clean Code की value खत्म नहीं हो जाती
मशहूर किताब Clean Code “duplication न होना” को well-designed system की शर्त बताती है, और duplication को extra work, extra risk और unnecessary complexity का मुख्य दुश्मन कहती है
इस definition के हिसाब से duplication removal, simplification का synonym बन जाता है, जो गलत है
duplication हटाना dependency introduce करना है। अगर वह dependency problem को अच्छे से model करती है, तो वह अच्छी abstraction और simplification हो सकती है; नहीं तो वह abstraction का मुखौटा पहना compression ही है
संदर्भ के लिए, यह quote Clean Code में आने वाले Kent Beck के Simple Design के उल्लेख से जुड़ा है
एक तो यह subjective feeling कि कोई code अच्छा है, और दूसरा किताब Clean Code और संबंधित guidelines को follow करना
ज्यादा से ज्यादा लोगों को लगने लगा है कि ये दोनों काफी हद तक अलग हैं। किताब की कुछ guidelines follow करने पर उल्टा बिल्कुल भी clean न होने वाला code निकल सकता है
ideal दुनिया में हर कोई clean code लिखना चाहेगा, लेकिन कम लोग महसूस कर रहे हैं कि Clean Code उस लक्ष्य को पाने का अच्छा तरीका है
खासकर over-abstraction और duplication removal को बहुत से लोग messy code का स्रोत मानने लगे हैं
कभी-कभी technical debt product requirements में ही encoded होता है, इसलिए उसे refactoring या best practices से ठीक नहीं किया जा सकता; बस दर्द कम किया जा सकता है
Clean Code का उद्देश्य और उसके practical results बहुत अलग होते हैं। क्योंकि लोग requirements सामने होने पर भी code की future state का अंदाजा आमतौर पर नहीं लगा पाते
Clean Code “what if?” जैसा भयानक सवाल बुलाता है, और यह releases को अंतहीन टालने वाला Pandora’s box बन सकता है
लगभग हमेशा जो पता है उसी के हिसाब से code करना, और domain experience वाले व्यक्ति को architecture lead करने देना बेहतर है
अच्छी abstractions में से काफी कुछ पहले से libraries में मौजूद है। हालांकि अफसोस, हमेशा ऐसा नहीं होता
bad abstraction समय खाती है, और code team के दूसरे लोगों से communication भी है, इसलिए मैं कैसे सोचता हूं इससे कहीं ज्यादा महत्वपूर्ण यह है कि teammates communication को कैसे receive करते हैं
एक सहकर्मी ने copy-paste करके बहुत सारा code लिखा था, और आपने commit के बाद उसे refactor किया
सहकर्मी ने boss से शिकायत की, boss ने आपको डांटा, और आप इस नतीजे पर पहुंचे कि अगली बार codebase में गंदगी छोड़ देंगे
यहां सीखने लायक बात तो है, लेकिन इसका मतलब यह नहीं कि copy-paste करना function लिखने से बेहतर है
refactoring को मूल लेखक को tag करके अलग change के रूप में review के लिए डालना चाहिए था
हालांकि सहकर्मी ने सीधे आपसे बात नहीं की और बात boss तक पहुंचाई, और boss ने उसे revert करने को कहा—यह काफी खराब संकेत है
संभावित जवाब “नहीं, वजह यह है…” या कभी-कभार “हां, सही है, कल कर दूंगा” जैसा हो सकता था
बिना हंगामे के सब लोग समस्या से बच जाते, और शायद कोई कुछ सीख भी लेता
लेकिन लेखक ने एक अहम context जोड़ा है। उन्होंने requirements बदलने की संभावना को duplication घटाने के बदले छोड़ दिया था, और बाद में हर shape के handle के लिए बहुत सारे special cases और behavior चाहिए हो गए
यह accidental DRY और essential DRY का फर्क दिखाता है
अक्सर library A और B आपस में consistent दिखती हैं, इसलिए code एक जैसा हो जाता है, लेकिन असल में यह संयोग हो सकता है
अगर lib A को wrap करने वाला wrapper और lib B को wrap करने वाला wrapper एक जैसा code रखते हों, लेकिन वे पूरी तरह अलग चीजों को wrap कर रहे हों, तो उन्हें abstract करने का नतीजा खराब होगा
“15” के साथ भी यही है। अगर “सभी lists हमेशा 15 items दिखाएं” है, तो 15 को abstract करना सही है, लेकिन अगर “homepage के top 15 songs” और “song के नीचे default 15 comments” अलग-अलग चीजें हैं, तो उन 15 को बांधना और खराब चुनाव है
दूसरा red flag यह है कि refactoring खुद भी अच्छी refactoring नहीं थी। modularity कम है, coupling अब भी है, और सिर्फ duplication थोड़ा कम हुआ है
यह ऐसा सुनाई दे सकता है जैसे “तुमने जो code लिखा था वह खराब था, इसलिए मैंने दोबारा लिख दिया। कोई दिक्कत है?”
सबसे अच्छा उपाय शायद “late review” के रूप में explanation मांगना, solution suggest करना, और उम्मीद करना होगा कि मूल लेखक उसे बस ignore न करे
मुख्य बात यह समझना है कि code भविष्य में बदलता है। requirements भी बदलती हैं और related code भी
अगर आप ऐसी abstraction बनाते हैं जो बदलाव की क्षमता को सीमित करती है, तो आप भविष्य के अपने आप की codebase को adapt करने की क्षमता को नुकसान पहुंचाते हैं
खासकर जिन abstractions में बहुत समय और मेहनत लगती है, उनसे emotional attachment हो जाती है, और बदलाव को उस elegant solution में fit करने के चक्कर में और समय बर्बाद हो जाता है
KISS सही है
यह मामला “कोई भी show-off करने वाले व्यक्ति को पसंद नहीं करता” वाली समस्या जैसा दिखता है
खासकर यह तब अक्सर होता है जब junior developer ने अभी यह नहीं सीखा होता कि काम सिर्फ उसके और computer के बीच नहीं, बल्कि उसके, computer और दूसरे लोगों के बीच होता है
अगर cleaner version में मूल लेखक से सच में बातचीत की जाती और बेहतर तरीके पर सहमति बनती, तो उसे स्वीकार किए जाने की संभावना ज्यादा थी
लेख का title “Goodbye, Clean Code” से ज्यादा team में काम करना सीखा होना सही लगता है
ज्यादा जटिल code को threat की तरह लिया गया होगा, और management chain के जरिए दबाए जाने लायक competitor समझा गया होगा
junior लोगों को समझना चाहिए कि यह बात context-dependent है। कई workplaces में simplicity, flexibility से ज्यादा अहम होती है; confusing language features से बचा जाता है; और keyboard के सामने लंबे समय बिताने वाली working style और ऐसी languages पसंद की जाती हैं
दूसरी तरफ lifelong learning, software craftsmanship और process reflection को महत्व देने वाली philosophy ऐसे environments से पूरी तरह टकराती है
बेहतर बनने की कोशिश उन लोगों में लोकप्रिय नहीं होती जो grow नहीं कर रहे
दोनों valid life choices हैं। software ऐसी जगह भी है जहां 7 घंटे काम करके घर जाना आसान है, और यह exploration की ऐसी दुनिया भी है जहां imagination और intellect ही सीमा हैं
अगर आप नई चीजें discover करना चाहते हैं, तो अनजान चीजों से डरने वाले लोगों के साथ दशकों बिताने से सावधान रहें
और संक्षेप में कहें तो, अगर आपके colleagues के साथ incentives misaligned हैं, तो छोड़ने पर विचार करें
इस लेख के लंबे समय तक पसंद किए जाने की वजह है, और इसने उसी जाल में फंसने वाले कई developers की आंखें खोली हैं
अकेले काम करते हुए भी आप clean abstraction को जरूरत से ज्यादा design कर सकते हैं और भविष्य में वही abstraction आपको काट सकती है
समस्या यह है कि change बिना review के सीधे main branch में commit हो जाता है
हर code change के लिए peer review होना चाहिए—चाहे pair programming हो या traditional PR—ताकि इस तरह बात बढ़ने से रोकी जा सके
boss खराब boss था। डांटने के बजाय उसे यह पहचानना चाहिए था कि अच्छी process गायब है
code review culture वाली team में अगर कोई उत्साही नया developer ऐसा प्रयास करता, तो कोई सहकर्मी कहता “धन्यवाद, लेकिन यह सही नहीं है” या “अच्छा idea है, इसे ऐसे करके देखते हैं”
अलग से, मेरा मानना है कि बिना अच्छे कारण के code refactor नहीं करना चाहिए। खराब code भी ऐसा code हो सकता है जिसे शायद ही कभी modify करना पड़े
refactor करने का सबसे अच्छा समय तब होता है जब behavior बदलना हो और आपको एहसास हो कि मौजूदा structure इसे बहुत मुश्किल बना रहा है
दुर्भाग्य से लगता है कि यहां गलत सबक सीख लिया गया
समझ नहीं आता कि सब लोग सिर्फ़ यह क्यों कह रहे हैं कि उसे इसकी जगह क्या करना चाहिए था। यह अपने-आप में पूरी तरह उचित सीख है
finance में हम लगातार ऐसे products से निपटते हैं जो कुछ हद तक मिलते-जुलते होते हैं, लेकिन बिल्कुल एक जैसे नहीं होते। stock options और foreign exchange options दोनों options हैं, दोनों में strike price होती है और दोनों की pricing Black-Scholes के किसी version से होती है, लेकिन असल में वे बहुत अलग होते हैं
नए जुड़ने वाले व्यक्ति के लिए बहुत-से behavior को common कर देने का प्रलोभन बड़ा होता है, और हम अक्सर original post के boss की स्थिति में होते हैं, जहाँ युवा developer से कहना पड़ता है कि शांत रहें और चीज़ों को अलग-अलग रखें
बात clean code को अलविदा कहने की नहीं है, बल्कि यह है कि अत्यधिक abstraction से बचना ही असल में clean code बनाए रखने का तरीका है
सामान्य handle जो करता है वह affine transformation है, यानी translation, rotation, scaling और reflection; और अगर uniform scaling हो तो similarity transformation है। यह किसी भी shape पर काम करने की guarantee रखता है
असली समस्या यह है कि जिस चीज़ को आप पर्याप्त नहीं जानते, उसका abstraction नहीं करना चाहिए। खासकर तब, जब आपको यह न पता हो कि भविष्य में क्या possibilities आ सकती हैं
उदाहरण के लिए अगर आप सोचते हैं कि ellipse केवल circle और ellipse ही होते हैं, तो पहला “सच्चा” oval आने पर आपको काफ़ी हैरानी होगी
लेखक messy code और “non-clean” code के बीच सक्रिय रूप से distinction नहीं करता, इसलिए दूसरे लोग distinction करने की कोशिश कर रहे हैं
DRY valuable है, लेकिन abstraction की cost होती है। यह हमेशा trade-off है
Haskell जैसी languages पसंद होने की एक वजह यह है कि abstraction maximalism coding level पर नहीं, बल्कि language level पर मौजूद है
Applicative को क्या करना चाहिए, इस पर सब सहमत होते हैं। challenge idea से code तक जाने वाली pipeline में और दाईं तरफ़, यानी problem के लिए सही Applicative ढूँढने की ओर shift हो जाता है
ज़्यादातर object-oriented design patterns का ऐसे environment में natural और well-defined counterpart होता है, और वे project-specific abstractions घटाने में मदद करते हैं
beginners के लिए language सीखने की शुरुआती cost बड़ी होती है, और अक्सर ऐसा होता है कि कोई दूसरा Haskell code खोलते ही करीब 12 compiler extensions दिख जाते हैं जिन्हें समझना पड़ता है
फिर भी वे compiler extensions बाद में हर project में साथ ले जाए जा सकते हैं, इसलिए मैं इसे net gain मानता हूँ
experts के लिए downside यह है कि cats RAM कितना खाएगा, इसका अंदाज़ा लगाने के लिए PhD चाहिए
अगर कोई code Applicative या Monad का इस्तेमाल करता है, तो उन laws की वजह से उसके behavior का पता चलता है
object-oriented design patterns में ऐसे laws नहीं होते। वे loosely defined concepts या patterns हैं, इसलिए personal interpretation और customization के लिए खुले हैं, लेकिन वे यह बताने वाले concrete laws नहीं देते कि वे ठीक-ठीक क्या हैं और किस behavior या output की उम्मीद करनी चाहिए
हालांकि blog post का example देखते हुए कहना पड़ेगा कि clean code path पर चलते-चलते भविष्य वाले अपने ही पैर पर कुल्हाड़ी मारने वाली घटनाएँ सच में बहुत हुई हैं
अगर बाद में फिर समझने के लिए abstraction पढ़नी पड़े, तो वह abstraction उपयोगी नहीं है
object-oriented approach सबसे natural जहाँ fit बैठती है, वे GUI widgets और editor implementation हैं
object-oriented के बाकी rules को जोड़ने वाला rule है: मत पूछो, करवाओ
इस example में handles known तरीके से share किए जाते, और हर shape के control points होते। box handle बदलने पर
updateControlPoints(changedHandle)call किया जा सकता है, और control point बदलने परupdateBoxHandles(changedControlPoint)call किया जा सकता हैऔर भी साफ़ separations संभव होंगे, लेकिन मैं ऐसा ही करता
लेकिन कौन-सी parsing library इस्तेमाल करनी है,
Data.Text.StrictऔरData.Text.Lazyमें से क्या लेना है, point-free style कितना इस्तेमाल करना है,.और>>>या दूसरे combinators में से क्या लेना है, कौन-से language extensions इस्तेमाल करने हैं—इन पर सहमति आसानी से नहीं बनतीHaskell पसंद है, लेकिन यह दूसरी languages जैसी समस्याओं से गुजरता है। लोग सच में इस बात पर सहमत नहीं हो पाते कि काम करने का best तरीका क्या है
Haskell type system और predictable performance मिल जाएगी
दोहराए जा रहे math वाले हिस्से को बस अलग function में ले जाकर resize functions से call करना चाहिए था
resize functions खुद इसलिए दोहराए हुए लग रहे थे क्योंकि वे interface बना रहे थे, इसलिए उन्हें हटाने वाली refactoring गलत थी
लेकिन उन functions ने जो math किया था, वह code साफ़ करने के लिए पूरी तरह valid target था
नतीजे में बहुत-से छोटे और pure functions बन जाते हैं, लेकिन testing और refactoring आसान होने से यह problem नहीं बनता
एक ही problem solve करने के कई तरीके और patterns होते हैं, लेकिन जिस existing interface को दूसरे लोग इस्तेमाल कर रहे हैं उसे उखाड़ देना अच्छी शुरुआत नहीं है
abstraction का फायदा यह है कि बाकी चीज़ों को नुकसान पहुँचाए बिना अंदरूनी हिस्से को ज़्यादा flexible बनाया जा सकता है
जैसा आपने कहा, अच्छा पहला step यह है कि नीचे की तरफ़ ज़्यादा flexible math functions बनाए जाएँ और बाकी सब वैसा ही रहने दिया जाए
उसके बाद team के साथ इस पर गहराई से बात की जा सकती है कि interface साफ़ facade देते हुए implementation को abstract कैसे रखा जाए
यहां जो बताया गया है, वह खराब abstraction जैसा लगता है
असली समस्या यह है कि लोग सिर्फ दो-तीन उदाहरण देखकर design कर लेते हैं, और यह जांचते नहीं कि वह future use को संभालने जितना general है या नहीं
abstraction नीचे से ऊपर की ओर करना चाहिए, ऊपर से नीचे की ओर नहीं
ऐसा single point बनाने की जरूरत नहीं है जहां सब कुछ हो और जो
2^ncombinations संभालेफिर भी duplication घटाया जा सकता है, एक जगह से बदलाव किया जा सकता है, और जरूरत पड़ने पर custom बदलाव करने की क्षमता भी बची रहती है
इसलिए सिर्फ “खराब abstraction से बचो” या “future use को accommodate करो” कहना काफी नहीं है
आम तौर पर कोई भी future predict नहीं कर सकता
abstraction सही लगने पर भी बेहद सावधानी से इस्तेमाल करना चाहिए। कट्टर skeptic बनना बेहतर है
math code में एक चीज छूते ही सब कुछ प्रभावित होता है
किसी point पर कुछ duplicate code छोड़ देना, code structure के clues या comments से similarity दिखाना, और समय के साथ core differences को comments में highlight करना आसान हो जाता है
इस तरह के code के लिए clean code approach बदलती requirements को अच्छी तरह handle नहीं करती
अंत में यह अक्सर helper functions के ऐसे गुच्छे में बदल जाता है जिनमें call site के हिसाब से कई code paths होते हैं
कभी-कभी इसे abstract किया जा सकता है, और कुछ लोगों ने शायद नोटिस कर लिया होगा कि पिछला वाक्य object-oriented polymorphism का वर्णन कर रहा था
लेकिन exact requirements पहले से कैसे पता होंगी? इतनी early stage में “clean code” की कोशिश करने का नतीजा सिर्फ खराब abstraction या overengineering होगा
सही तरीका है कुछ न करना, संभावित problems को note करना, और problem domain के बारे में और जानने तक इंतजार करना
मूल example की तरह थोड़ा duplicate लेकिन आसानी से समझ आने वाला code मुझे ज्यादा परेशान नहीं करता
लेकिन अगर वही issue तीन जगह fix करना पड़े या नए feature का code तीन जगह जोड़ना पड़े, तो मैं चिंतित होता हूं
तब मैं सोचने लगता हूं कि जिस code को बदलना या जोड़ना है, उसे किसी तरह common location में push किया जा सकता है या नहीं
लोग design patterns या DRY पढ़ते हैं, सीखने की प्रक्रिया में आम तौर पर उन्हें गलत apply करते हैं, और फिर उसकी जिम्मेदारी original text पर डाल देते हैं
Rob Pike ने कभी कहा था कि Go के वैसा बनने की एक वजह यह थी कि “छोटी dependency से छोटी copy बेहतर है”
जितना ज्यादा programming करता हूं, इसका मतलब उतना ज्यादा समझ आता है
repetition अपने आप में समस्या नहीं है। अहम बात यह समझना है कि आप अभी किस unit को पढ़ रहे हैं और शायद modify करने वाले हैं
DRY का मतलब अक्सर एक और abstraction जोड़ना होता है, और अगर वह abstraction पर्याप्त रूप से orthogonal नहीं है, तो अब आपको एक नहीं बल्कि दो units पर विचार करना पड़ता है, इसलिए आपने हालात और खराब कर दिए हैं