1 पॉइंट द्वारा GN⁺ 2024-08-17 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Linus Torvalds के एक उद्धरण के आधार पर, अच्छा design code लिखने से पहले data structure और उनके रिश्तों को स्थिर रूप से तय करने से शुरू होता है
  • अच्छी तरह design किया गया data model application logic को स्वाभाविक रूप से सरल बनाता है और software को अधिक विश्वसनीय और समझने में आसान बनाता है
  • अगर data model को बाद के लिए टाल दिया जाए तो आगे का काम बढ़ जाता है, लेकिन शुरुआत में structure सही पकड़ लिया जाए तो migration और जटिल system विस्तार आसान हो जाता है
  • एक project में जटिल algorithm optimization की जगह data restructuring से समस्या की पूरी category ही हटा दी गई, और 500-line function को 50-line function और data structure से बदल दिया गया
  • व्यावहारिक काम में interface और database पर अधिक सख्त types लागू करने चाहिए, और code की बारीकियों से पहले data flow और component interaction को design करना चाहिए

data structure code design को तय करते हैं

  • Linus Torvalds Git को स्थिर और documented data structures वाला एक सरल design मानते हैं, और इस बात पर ज़ोर देते हैं कि code को data के आसपास रखा जाए
    • “खराब प्रोग्रामर code की चिंता करते हैं, और अच्छे प्रोग्रामर data structure और उनके रिश्तों की चिंता करते हैं” यह उद्धरण मुख्य वाक्य है
    • Git की सफलता के कारणों में से एक यह है कि उसका design data-केंद्रित रखा गया
  • अच्छे data structures code design और maintenance को आसान बनाते हैं, और software की reliability, system की समझ, और code readability को बढ़ाते हैं
    • application logic अक्सर data model का अनुसरण करता है
    • अगर data model के बारे में बाद में सोचा जाए तो आगे का workload बढ़ जाता है
    • अच्छी तरह design किया गया data model बाद की migration और जटिल system expansion को आसान बनाता है
  • एक वास्तविक project उदाहरण में जटिल algorithm को और चमकाने से ज़्यादा असर data restructuring ने दिया
    • data structure बदलकर पूरी problem category हटा दी गई
    • 500-line function को 50-line function और अच्छी तरह design किए गए data structure से बदल दिया गया
    • नया code तेज़ भी था और उसे समझना व maintain करना भी आसान था
    • हालांकि मौजूदा data को फिर से संरचित करना पड़ा, इसलिए मेहनत नीचे की layers में चली गई

complexity को data की तरफ ले जाना बेहतर है

  • The Art of Unix Programming में “Rule of Representation” समझाता है कि ज्ञान को data में रखना चाहिए ताकि program logic सरल और मजबूत बन सके
    • procedural logic को इंसानों के लिए verify करना कठिन होता है, लेकिन जटिल data structures को model करना और उनके बारे में तर्क करना अधिक आसान होता है
    • 50 nodes वाले pointer tree diagram में 50-line program flowchart की तुलना में अधिक अभिव्यक्ति और व्याख्यात्मक शक्ति हो सकती है
    • अगर transformation table को array initialization के रूप में व्यक्त किया जाए तो वही बात switch statement में लिखने की तुलना में अधिक पारदर्शी और स्पष्ट होती है
    • अगर code और data structure में से कहीं complexity रखनी ही हो, तो complexity को data structure की तरफ ले जाना बेहतर है

व्यावहारिक काम में पहले data flow design किया जाता है

  • सबसे सीधा व्यावहारिक तरीका है data से शुरू करना
    • interface या database पर अधिक सख्त types लागू करने से code complexity कम की जा सकती है
    • data structure पर पहले से अधिक समय तक सोचने की ज़रूरत होती है
    • इसका मतलब यह नहीं कि code महत्वपूर्ण नहीं है; सभी तत्व साथ मिलकर महत्वपूर्ण हैं
    • code details में जाने से पहले यह देखना उपयोगी है कि data कैसे flow करता है और components कैसे interact करते हैं
  • Senior Engineer(L5) की अपेक्षाओं के उदाहरण के तौर पर, FAANG में अधिक जटिल systems के लिए high-level design documents लिखना आम तौर पर शामिल होता है
    • इसमें team planning को lead करना और मध्यम से बड़े features के लिए अच्छा roadmap बनाना भी शामिल है
    • data flow और component interaction को पहले design करने की क्षमता, engineering के उच्च स्तर के प्रभाव से जुड़ी होती है

1 टिप्पणियां

 
GN⁺ 2024-08-17
Hacker News की राय
  • वह Substack लेख ऐसा लगता है जैसे इस Stack Exchange पोस्ट से कई quotes सीधे कॉपी कर लिए गए हों: https://softwareengineering.stackexchange.com/questions/1631...

    • URL को https://read.engineerscodex.com/p/good-programmers-worry-abo... से बदल दिया गया है। कुछ महीने पहले भी कुछ समय तक ऐसा Substack spam चला था, लगता है वही malicious actor फिर शुरू हो गया है
    • quotes का क्रम तक नहीं बदला गया, यह काफ़ी बेधड़क है
  • “मुझे flowchart[code] दिखाइए और table[schema] छिपा दीजिए, तो मैं लगातार उलझा रहूंगा। मुझे table[schema] दिखाइए, तो आम तौर पर flowchart[code] की ज़रूरत नहीं पड़ेगी। वे अपने-आप स्पष्ट होंगे।” — Fred Brooks, “The Mythical Man Month”, अध्याय 9

    • Quake में डूबे अपने बचपन के दिनों में, मैंने John Carmack को पत्र लिखकर पूछा था कि aspiring programmers के लिए उनकी कोई सलाह है या कोई पसंदीदा किताब। हैरानी की बात है कि उन्होंने काफ़ी सोच-समझकर जवाब दिया, और उसमें यह बात थी:
      “The Mythical Man Month पढ़ो। मुझे याद है कि मैं सोचता था कि इतनी पुरानी किताब आज के software development से जुड़ी बात नहीं कह सकती, लेकिन मैं गलत था।”
    • मैं यह quote साझा करने ही आया था क्योंकि यह बहुत सही है। बस वह पल अपवाद है जब database schema बदलने की लागत code बदलने की लागत से कहीं ज़्यादा हो जाती है।
      तब application developers database का दुरुपयोग शुरू कर देते हैं, क्योंकि वे ज़्यादा तेज़ होते हैं और उनके पास करने को ज़्यादा काम होता है
  • data structures और types एक ही चीज़ नहीं हैं। data structure bit patterns और दूसरे bit patterns के references, यानी pointers या relationships, होते हैं।
    types programming language में इस्तेमाल के तरीके के अनुसार ऐसे bit patterns पर constraints लगाते हैं, लेकिन इनके अलावा भी वे कई language features को व्यक्त कर सकते हैं। अनावश्यक abstraction से जटिल type hierarchy बनाना “data structures की चिंता करना” नहीं है, और यह ऐसा failure pattern है जिसमें smart engineers भी अक्सर फंस जाते हैं

    • यह subtle लेकिन महत्वपूर्ण point है। types data structure के schema को सीमित और specify करने के लिए उपयोगी tool हो सकते हैं, लेकिन types की चिंता करना और data structures की चिंता करना काफ़ी अलग बातें हैं
    • types वे data structures हैं जिन्हें language पहचानती है। इसलिए tooling ऐसी checks कर पाती है जो साधारण data structures पर नहीं कर सकती
    • data structure एक स्थिर algorithm है। हर operation में वह कुछ मिलाता-जुलाता और हिलाता-डुलाता है, लेकिन कुल मिलाकर स्थिर रहता है—जैसे कोई Turing machine, जिसके handles लोग कभी-कभार ही घुमाते हैं।
      types disk पर मौजूद bits हैं
    • अच्छी बात कही। data structures को types के बराबर मान लेना मुद्दे की अति-सरल व्याख्या है।
      यहां असल में कहना यह है कि समस्या पर गहराई से सोचो और ऐसी structure मत चुनो जो बाद में अड़चन बने। उदाहरण के लिए देखो कि Unix pipes कितनी दूर तक फैले, और कितने domains और use cases तक expand हुए। यह human और machine constraints का सम्मान करते हुए systems बनाने के तरीके को visualize करने का शानदार तरीका है।
      Ken Thompson और अन्य लोगों को भी यह समझने में काफ़ी समय लगा कि pipes जैसी चीज़ Unix में सार्थक है। यह insight आसानी से नहीं मिली; system के सही building blocks खोजने की जिद और आगे के काम की ज़रूरत पड़ी
    • एक ही data structure पर अलग-अलग types लगाए जा सकते हैं। Pascal का typedef operator यही करता है
  • Linus हमेशा उन बातों को अच्छे से समेट देता है जिन्हें दूसरे लोग धुंधले तौर पर सोच रहे होते हैं। लेख में कही गई बात उस DDD से भी मिलती-जुलती है जो अब एक खोई हुई कला बन गई है।
    यहां “खो गई” से मतलब यह है कि आजकल मिलने वाले ज्यादातर developers अपने domain को समझने और entities व उनके interactions को model करने के बजाय, algorithms और JSON को इधर-उधर सरकाने में ज्यादा दिलचस्पी रखते हैं। आधुनिक AWS-आधारित design में यह अक्सर कमजोर आधार वाले DynamoDB GSI के गुच्छों, anemic objects, और hack के ऊपर hack चढ़ाती script-जैसी “service” layer के रूप में दिखता है। शायद यह एक implicit assumption था कि service boundary के अंदर domain context पर्याप्त रूप से अच्छी तरह define हो जाएगा, लेकिन मुझे नहीं लगता कि यह अच्छी assumption है।
    पता नहीं हमारी industry ने design की कठोरता कहां खो दी—school में, interview pipeline में, standards कम करने की वजह से, या इन सबके कारण

    • मुझे लगता है industry ने software design को कभी गंभीरता से लिया ही नहीं। इसे हमेशा नकारात्मक शब्दों में देखा जाता है, politically incorrect या निरर्थक माने जाने वाले लोगों से जोड़ा जाता है, और comments में ऐसे बहुत लोग आ जाते हैं जो सिर्फ इसलिए सब कुछ खराब कह देना चाहते हैं क्योंकि किसी ने कभी कुछ गलत किया था।
      इससे भी खराब बात यह है कि design ने एक बड़ा पाप किया है: इसे आसानी से automate नहीं किया जा सकता। इसलिए लोग tools द्वारा थोपा गया design बिना आलोचनात्मक सोच के अपना लेते हैं, और इस विचार से असहज हो जाते हैं कि उन्हें अपने काम के बारे में ज्यादा गहराई से सोचना चाहिए। हर कोई इस सोच को किसी “expert” को outsource करना चाहता है।
      समस्या यह भी है कि इसे ठीक से पढ़ाया नहीं जाता, इसे कई सालों तक खुद सीखना पड़ता है, और code की तुलना में इसे कम वास्तविक माना जाता है, इसलिए कम महत्वपूर्ण समझा जाता है। लेकिन ऐसी धारणा आखिरकार आप जो बना सकते हैं उसके स्तर को advanced beginner stage तक बांध देती है। Programmers सामूहिक रूप से standards को जितना हो सके उतना नीचे रखने का चुनाव करते हैं, और इस विषय पर लगभग केकड़ों जैसी मानसिकता दिखती है—एक-दूसरे को नीचे खींचने वाली
    • Anemic domain model को काफी पहले ही anti-pattern के रूप में पहचाना जा चुका था[1]। यह आम तौर पर primitive obsession[2] के साथ दिखता है, और नतीजा यह होता है कि strings और numbers जैसे primitive types पर तरह-तरह के validation और check code जगह-जगह बिखर जाते हैं।
      Syntax के स्तर पर वे एक जैसे नहीं होते, इसलिए duplicate नहीं लगते, लेकिन functionally वही काम करने वाला code duplication बहुत बन जाता है।
      1 https://martinfowler.com/bliki/AnemicDomainModel.html
      2 https://wiki.c2.com/?PrimitiveObsession
    • Industry मुख्य रूप से software design करने के बजाय code लिखने को reward करती है।
      मुझे लगता है इसकी वजह यह है कि खराब code के नतीजे कम दिखाई देते हैं। खराब पुल गिर जाता है, लेकिन खराब code बस refactor होता है या और ज्यादा code से replace हो जाता है। Management जिसे नहीं समझती ऐसी एक text file, management जिसे नहीं समझती दूसरी text file में बदल जाती है।
      और एक बार कुछ चलने लगे तो blackout हो जाता है। पूरी तरह चल पड़े temporary hack जितना permanent कुछ नहीं होता। लेकिन 1000 temporary hacks मिलकर अच्छी तरह engineered system नहीं बनाते। मेरे हिसाब से software development में maturity का मतलब code लिखने से ज्यादा data और relationships पर focus करना है। उसे code में बदल सकना चाहिए, लेकिन working code को data model में बदलने के बजाय data और relationships को code में बदलना चाहिए
    • मैंने अब तक यह समझाने वाला कोई मजबूत कारण नहीं देखा कि anemic objects इतने taboo क्यों हैं। मैंने देखे हुए ज्यादातर DDD functions भी बस लंबे-चौड़े getters और setters ही थे।
      Domain entity में सारी logic रखी जा सकती है, इसका मतलब यह नहीं कि हमेशा रखनी ही चाहिए। उदाहरण के लिए अगर यह जांचना हो कि username पहले से मौजूद है या नहीं, तो उसे ऐसी domain entity के अंदर कैसे करेंगे जो data access layer पर “depend नहीं कर सकती”? अक्सर लोग “domain service” जैसी चीज सुझाते हैं, लेकिन तब business logic कई जगहों पर फैल जाती है, जो DDD के मकसद के उलट लगता है।
      Philosophy के रूप में DDD मुझे काफी पसंद है, लेकिन “tactical DDD” patterns से मुझे बेहद चिढ़ है। मुझे लगता है बहुत लोग Domain-Driven Design को Domain-Driven Implementation के बराबर मान लेते हैं। जहां उचित हो वहां rich domain बनाने की कोशिश करता हूं, लेकिन यह हर project के लिए सही नहीं है और मैं terminology में उलझना नहीं चाहता। “Name” type value object है या aggregate root, इसमें मेरी दिलचस्पी नहीं। सबसे बढ़कर bounded context ज्यादा महत्वपूर्ण है। मैं यह भी मानता हूं कि DDD कभी-कभी application complexity बढ़ा सकता है और बदले में बहुत कम दे सकता है। मैं इसे कभी भी silver bullet नहीं कहूंगा।
      आगे भी DDD का इस्तेमाल करूंगा, लेकिन यह एहसास झटकना मुश्किल है कि DDD शायद यह बताने की कोशिश है: “देखो, object-oriented programming इतनी भी बुरी नहीं है, है ना?” और मुझे यह भी पक्का नहीं कि वह लक्ष्य हासिल होता है या नहीं
    • दशकों तक CPU performance, memory size, disk space, network speed आदि के exponential growth ने खराब design की कीमत को काफी हद तक मिटा दिया। इसलिए code monkeys जितनी तेजी से keyboard पीटते हुए garbage code निकालते रहे, वह आम तौर पर चल जाता था
  • Professional engineering शुरू करने से पहले मैं Matlab, R और शुरुआती Python जैसे statistical systems में रोज data और statistical analysis करता था, इसलिए यह बात दिलचस्प लगती है।
    इसलिए मेरी engineering perspective हमेशा दो चीजों पर आधारित रही है: functional state और data workflow को manage करना।
    10 साल तक software engineering को profession के रूप में करने के बाद लगा कि Minsky या Shannon जैसे ज्यादातर “scientific” engineers computing world को state management, data transformation और computational overhead management के रूप में समझाते थे। Software के दिग्गज और pioneers सभी data और state को बहुत महत्वपूर्ण मानते थे, शुरुआती computing असल में लगभग पूरी तरह यही थी, और उम्मीद थी कि आगे भी यही pattern जारी रहेगा।
    इसके उलट, engineering system design में ऐसी fundamental assumptions में बिल्कुल consistency नहीं है जिन्हें हमेशा सही मानकर सभी follow करते हों; अगर कुछ है भी, तो वह ज्यादातर fashion जैसा है। अधिकांश operational software में robustness, antifragility और state management की तुलना में business schedule engineering priorities और structure को कहीं ज्यादा तय करता है।
    Guilds या unions जैसे professional organizations को software engineers लगभग सार्वभौमिक रूप से reject करते हैं। IEEE को गंभीरता से न लेने पर कोई नुकसान नहीं होता, इसलिए वास्तव में कोई भी उसे गंभीरता से नहीं लेता। नतीजा यह है कि civil या biomedical engineering की तरह practice को enforce करने या self-regulate करने की व्यवस्था नहीं है, और वहां भी उसका उपयोग मुश्किल से ही होता है।
    कुल मिलाकर software development की वर्तमान स्थिति अपनी बेहद ऊंची और philosophical जड़ों से पूरी तरह कट चुकी है, और इसे असल में वे companies चला रही हैं जो पैसे वालों के लिए पैसा कमाने वाले systems को प्राथमिकता देती हैं। इसलिए “अच्छा” क्या है, इसका incentives से लगभग कोई संबंध नहीं है

  • “अगर आप मुझे flowchart [code] दिखाएँ और tables [data structures] छिपा दें, तो मैं लगातार उलझन में रहूँगा। अगर आप मुझे tables दिखा दें, तो आम तौर पर flowchart की ज़रूरत नहीं होती। क्योंकि वे स्पष्ट होंगे।” — Fred Brooks

    • लगता है यह quote इस बात को मिस करता है कि persistence model और वास्तविक data structures अलग हो सकते हैं, और शायद अलग होने भी चाहिए।
      बेस tables से 1:1 मिलाना बेहद restrictive है, और मेरे हिसाब से इससे ऐसा model बनता है जो modern languages द्वारा दी जाने वाली expressiveness खो देता है
  • यह मूल रूप से functional programming और category theory का दृष्टिकोण है।
    कोई data object होता है, और उसकी structure कैसे transform हो सकती है, इस पर constraints दिए जाते हैं। फिर program logic पूरी तरह उन transformations के बारे में हो जाती है जो उस structure को preserve करते हैं।
    transformations सरल और reason करने में आसान हो जाते हैं, और अंत में एक graph बचता है जिसमें transformations edges हैं और structures nodes। आम तौर पर किसी भी arbitrary imperative program की तुलना में इस पर reason करना आसान होता है

    • वह functional programming और category theory का दृष्टिकोण नहीं है। यह सभी language philosophies का दृष्टिकोण है, और object-oriented या procedural पसंद करने वाले लोग भी यही तर्क देंगे। Data types को सही तरह define करना महत्वपूर्ण है और यह सभी languages और paradigms पर लागू होता है।
      functional programming का दृष्टिकोण इससे अधिक इस ओर है कि objects को transform नहीं करना चाहिए और mutation से बचना चाहिए; यह चर्चा उससे अलग है। Category theory का मूल कई गणितीय क्षेत्रों में समान रूप से दिखने वाले relationship patterns से निपटना है, और यहाँ चर्चा की जा रही बात से इसका बिल्कुल संबंध नहीं है। शायद वे type theory कहना चाह रहे थे, लेकिन वह भी संबंधित नहीं है
  • पहले मैंने यह निष्कर्ष निकाला था: code में हम जो भी काम करते हैं, उसके data पर लिए गए एक अच्छे निर्णय की तुलना में बहुत कम समय तक टिकने की संभावना होती है।
    https://www.swyx.io/data-outlasts-code-but

    • अच्छे निर्णय दिखाई नहीं देते। ऐसा लगता है कि सिर्फ खराब निर्णय ही हमेशा टिके रहते हैं
  • यह principle business level पर भी लागू होता है। मैं लगातार ऐसे business analysts से dealing कर रहा हूँ जो processes (code) पर अटके रहते हैं, लेकिन पहले entities और उनके relationships (data) को समझने में समय नहीं लगाते।
    नतीजा यह होता है कि जब कुछ बनाने का समय आता है, तो वे developers से यह communicate नहीं कर पाते कि data model कैसा होना चाहिए। Processes implement हो जाते हैं, और data model को सावधानी से design करने के बजाय उसी समय जैसे-तैसे जोड़ दिया जाता है