5 पॉइंट द्वारा GN⁺ 2023-10-31 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • बैकएंड आम तौर पर मोनोलिथ के रूप में शुरू होता है, लेकिन जब कई feature teams उसी codebase को छूने लगती हैं, तो coupling बढ़ सकती है और बदलाव की गति धीमी हो सकती है
  • माइक्रोसर्विसेज़ business function के हिसाब से सेवाओं को बाँटकर independent deployment और छोटी टीमों की autonomy पाने का तरीका हैं
  • अगर सेवाएँ जरूरत से ज्यादा छोटी हों, तो फायदे से अधिक operational burden बढ़ जाता है, और “micro” नाम उल्टा निर्णय को धुंधला कर सकता है
  • पूरी तरह अपनाने पर standardization, resource provisioning, remote calls से बचाव, CI/CD, operations, और eventual consistency तक व्यापक लागतें आती हैं
  • आम तौर पर मोनोलिथ में boundaries को पर्याप्त समझ लेने के बाद, जब growing pains बड़े हो जाएँ तब एक-एक करके अलग करना सुरक्षित होता है; microservices-first approach तब उपयुक्त है जब अनुभव और platform readiness मौजूद हो

जब मोनोलिथ बड़ा होता है तो दिखने वाली सीमाएँ

  • आधुनिक single-page JavaScript application का बैकएंड आम तौर पर RESTful HTTP API देने वाली और relational database इस्तेमाल करने वाली एक single stateless web service के रूप में शुरू होता है
  • यह service अलग-अलग business functions लागू करने वाले components या libraries से बनी होती है
  • जैसे-जैसे एक ही codebase में काम करने वाली feature teams बढ़ती हैं, components के बीच coupling बढ़ती है और teams के काम के क्षेत्र overlap होने लगते हैं
    • productivity घटती है, और बदलाव का असर कहाँ तक जाएगा इसका अनुमान लगाना मुश्किल हो जाता है
  • codebase पर्याप्त जटिल हो जाए तो कोई भी उसे पूरी तरह नहीं समझ पाता, जिससे नए features लागू करने और bugs ठीक करने में ज्यादा समय लगता है
  • भले ही बैकएंड team-wise libraries में बँटा हो, library में बदलाव अंततः service redeployment तक पहुँचता है
    • memory leak जैसा bug आ जाए तो पूरी service प्रभावित हो सकती है
    • गलत build को rollback करने पर सिर्फ bug बनाने वाली team नहीं, बल्कि सभी teams की गति प्रभावित होती है

service boundaries से मिलने वाली autonomy

  • monolithic backend की growing pains कम करने का एक तरीका बैकएंड को independently deployable services के समूह में बाँटना है
  • services API के जरिए communicate करती हैं, और API उसी process के अंदर component boundaries की तुलना में ऐसी boundaries बनाती है जिन्हें पार करना कठिन होता है
  • इस architecture को microservices architecture कहा जाता है, लेकिन micro शब्द गलतफहमी पैदा कर सकता है
    • services का छोटा होना अनिवार्य नहीं है
    • बहुत कम functionality वाली service फायदे से अधिक operational burden पैदा कर सकती है
  • अधिक उपयुक्त नाम service-oriented architecture हो सकता है, लेकिन इस नाम के साथ भी पुराना baggage जुड़ा है

छोटी teams और independent services से बनने वाली speed

  • बैकएंड को business function के अनुसार services में बाँटने पर हर service को एक छोटी single team develop और operate कर सकती है
  • छोटी teams अधिक प्रभावी होती हैं, क्योंकि communication cost team size के साथ वर्ग के अनुपात में बढ़ती है
  • जब हर team अपना release schedule तय करती है और codebase को control करती है, तो teams के बीच coordination कम होता है और decisions तेज होते हैं
  • service codebase छोटा हो तो developers के लिए समझना आसान होता है और नए hires का onboarding time भी घटता है
    • छोटा codebase IDE slowdown कम करके developer productivity में भी मदद करता है
  • मजबूत service boundaries की वजह से developers को बैकएंड का कोई हिस्सा बदलते समय पूरे system के बजाय केवल एक छोटे हिस्से को समझना पर्याप्त होता है
  • हर service स्वतंत्र रूप से scale कर सकती है और अपनी जरूरतों के अनुसार technology stack चुन सकती है
    • API consumers को इस बात की चिंता नहीं होती कि functionality अंदर कैसे implement की गई है
    • system के दूसरे क्षेत्रों को प्रभावित किए बिना नई technologies को experiment और evaluate करना आसान होता है
  • हर microservice का अपना data model और data store हो सकता है
    • developers दूसरे services को प्रभावित किए बिना schema बदल सकते हैं

माइक्रोसर्विसेज़ जोड़ने वाली वास्तविक लागत

  • माइक्रोसर्विसेज़ पूरे system में अधिक moving parts जोड़ती हैं, और यह लागत मुफ्त नहीं है
  • माइक्रोसर्विसेज़ को पूरी तरह अपनाने की लागत तभी चुकाने लायक है जब उसे दर्जनों development teams में distributed amortization के जरिए फैलाया जा सके
  • development experience

    • हर service में अलग-अलग languages, libraries और data stores इस्तेमाल करना संभव है, लेकिन इससे application maintenance कठिन हो सकता है
    • software stacks पूरी तरह अलग हों तो developers के लिए एक team से दूसरी team में जाना मुश्किल होता है
    • logging जैसी सभी services को चाहिए common functionality देने के लिए अपनाई गई हर language के लिए libraries support करनी पड़ती हैं
    • कुछ स्तर की standardization जरूरी है
    • recommended languages और technology portfolio अपनाने वाली teams को अच्छा development experience देकर कुछ technologies के उपयोग को ढीले ढंग से प्रोत्साहित किया जा सकता है
  • resource provisioning

    • कई independent services को support करने के लिए servers, data stores और अन्य general-purpose resources आसानी से create किए जा सकने चाहिए
    • हर team को resource creation का अपना अलग तरीका बनाने नहीं देना चाहिए
    • provisioned resources को फिर configure करना पड़ता है, और इसे संभालने के लिए काफी automation चाहिए
  • communication

    • remote calls महंगी होती हैं और system के टूटने के नए तरीके पेश करती हैं
    • failures के लिए तैयार रहने हेतु timeouts, retries और circuit breakers जैसे defensive mechanisms चाहिए
    • network communication की performance loss कम करने के लिए asynchronous processing और batching भी इस्तेमाल करनी चाहिए
    • ये elements system complexity बढ़ाते हैं
    • remote client access और third-party APIs के उपयोग की वजह से monoliths भी समान समस्याओं से गुजर सकते हैं, लेकिन पैमाना छोटा होता है
  • continuous integration, delivery, deployment

    • continuous integration यह सुनिश्चित करता है कि automated build और tests चलने के बाद code changes main branch में merge हों
    • code changes merge होने पर उन्हें production-जैसे environment में automatically publish और deploy होना चाहिए
    • उस environment में integration tests और end-to-end tests चलाकर यह confirm किया जाता है कि microservice उन दूसरी services को तोड़ नहीं रही जिन पर वह निर्भर है
    • individual microservice tests monolith tests से अधिक कठिन नहीं होते, लेकिन सभी microservices की integration testing कहीं अधिक कठिन होती है
    • individual services के interact करने पर बेहद subtle और unexpected behavior सामने आ सकता है
  • operations

    • monolith के विपरीत, हर service-owner team के लिए अलग operations team रखना कहीं अधिक महंगा है
    • service develop करने वाली team आम तौर पर उसी service की on-call responsibility भी लेती है
    • team को हर sprint में तय करना पड़ता है कि development work और operational burden में किसे prioritize किया जाए, और इनके बीच friction पैदा होता है
    • system failures debug करना भी कठिन हो जाता है
    • पूरी application को local machine पर चलाकर debugger से step through नहीं किया जा सकता
    • moving parts ज्यादा होने से failure modes भी ज्यादा होते हैं
    • हर level पर अच्छी logging और monitoring महत्वपूर्ण हो जाती है
  • eventual consistency

    • application को कई services में बाँटने पर data model अब सिर्फ एक data store में मौजूद नहीं रहता
    • अलग-अलग data stores में records को atomically update करना और strong consistency guarantee करना धीमा, महंगा और implement करना कठिन है
    • ऐसी architecture को आम तौर पर eventual consistency स्वीकार करनी पड़ती है

कब अलग करना चाहिए

  • application को services में बाँटने से पूरे system की complexity काफी बढ़ जाती है
  • सामान्य तौर पर monolith से शुरू करना और केवल पर्याप्त कारण होने पर ही उसे तोड़ना बेहतर है
  • services के बीच boundaries सही तरीके से तय करना कठिन है, इसलिए monolith के अंदर boundaries को इधर-उधर करके उपयुक्त जगह ढूँढना ज्यादा आसान है
  • जब monolith पर्याप्त mature हो जाए और growing pains बढ़ने लगें, तब microservices को एक-एक करके अलग किया जा सकता है
  • microservices-first approach तभी शुरू करना उचित है जब पहले से अनुभव हो, इसके लिए platform बनाया गया हो, या platform बनाने में लगने वाला समय ध्यान में रखा गया हो

1 टिप्पणियां

 
GN⁺ 2023-10-31
Hacker News की रायें
  • लेख से मोटे तौर पर सहमत हूं, लेकिन उलट कर देखें तो कुछ मामलों में लागत उठाना वाजिब भी हो सकता है: पुराने third-party dependency compatibility issues को अलग service में निकालकर दर्दनाक refactoring या खुद से reimplementation से बचा जा सकता है, high-availability core system की deployment constraints को दूसरे systems की deployment रोकने से रोका जा सकता है, और बड़े customers जिन design constraints को बदल नहीं सकते उन्हें isolate किया जा सकता है
    इसका मतलब यह नहीं कि यह मुफ्त है; मतलब यह है कि एक simple monolith को कचरे के ढेर में बदलने से, risky deployments से उसे हिलाने से, या खराब tech stack वाले business partner से बंधने से बचने के लिए यह चुकाने लायक लागत हो सकती है

    • मुझे लगता है यह बस एक-दो services रखने जैसा है। यह “microservices” के बराबर नहीं है
      Microservices क्या वह approach नहीं है जिसमें internal components को मूल रूप से libraries या classes के बजाय services बनाया जाता है?
    • एक और बात जोड़ें तो, अलग-अलग programming languages आसानी से इस्तेमाल कर पाने का फायदा है। हर language हर problem के लिए अच्छी fit नहीं होती
      Machine learning inference service Python में, server-side rendering UI Rails में, और I/O व concurrency-heavy service Go में लिखने जैसा हो, तो इन तीनों को अलग services में बांटने का अतिरिक्त बोझ justified हो सकता है
    • अच्छे design के कई तरीके हैं, और इसका मतलब यह नहीं कि microservices को जल्दबाजी में अपनाना चाहिए
      मुझे microservices पसंद हैं, लेकिन premature optimization और premature scaling उतने ही खराब हो सकते हैं जितना वह technical debt जो बाद में बिल्कुल अलग दिशा में optimize करने की जरूरत पड़ने पर पैदा होता है
    • पहले point में मुझे समझ नहीं आता कि इसे अलग service के रूप में निकालना, clear API वाले interface से wrap करने से बेहतर क्यों है
    • ऐसे मामले शायद पूरे codebase के 10% से कम पर ही लागू होंगे
  • किसी चीज को अलग service में निकालने का समय तब होता है, जब ऐसा न करने पर कोई problem manageable तरीके से हल नहीं हो सकती
    boundaries enforce करने के लिए architectural complexity बढ़ाना organizational discipline की कमी का समाधान नहीं हो सकता, लेकिन mid-sized tech companies लगातार इसे ऐसे ही treat करती हैं। अगर domain boundaries कमजोर होने से problem आ रही है, तो service extract करने पर भी उसके अच्छी तरह हल होने की संभावना कम है

    • Last responsible moment एक ऐसी strategy है जिसमें decision को तब तक टाला जाता है, जब तक और टालने की cost अभी decision लेने की cost से ज्यादा न हो जाए”
      उद्धरण: https://www.oreilly.com/library/view/software-architects-han...
    • कहा जाता है कि boundaries enforce करने के लिए architectural complexity बढ़ाना organizational discipline की कमी का समाधान नहीं है, लेकिन असल में हम हमेशा यही करते हैं
      Tests pass होने तक PR रोकने वाला CI/CD भी organizational discipline problem को हल करने के लिए एक महंगा technical solution है
    • यह कुछ ऐसा लगता है जैसे कोई SISP solution problem ढूंढ रहा हो। या जैसे root cause समझे बिना problem पर solution फेंक दिया गया हो
    • HN पर ऐसा लगता है कि microservices कभी justified हो ही नहीं सकते—यह meme काफी फैल गया है, लेकिन पूरी industry ऐसी नहीं है, इसलिए अजीब लगता है
      Domain name resolution किसी external service से कराना ठीक है, यह सब मानते हैं, और recursive DNS resolver व cache को monolith में integrate करने वाले लोग बहुत कम हैं। फिर भी जिम्मेदारियों का यह पुराना विभाजन example के तौर पर ठीक से स्वीकार नहीं किया जाता
    • मैंने हमेशा इसे deferred execution का सबसे अच्छा example माना है। Companies कितनी बार गलत होती हैं, यह हैरान करता है
      समस्या शायद यह है कि जितना “अच्छा” employee होता है, वह value दिखाने के लिए उतना ही ज्यादा उत्साहित होता है, जिससे over-engineering होती है और आखिर में नरक बन जाता है
  • Microservices
    grug को समझ नहीं आता कि big brain लोग system को सही तरह decompose करने की सबसे कठिन problem उठाकर उसमें network calls भी क्यों जोड़ देते हैं
    grug को यह बहुत confusing लगता है
    https://grugbrain.dev/#grug-on-microservices

    • लगता है grug ने बड़े teams को एक-दूसरे के domains और data models पर पैर रखते, किसी specific implementation में lock-in होते, और team-level feature launches के लिए भारी organizational effort की जरूरत पड़ते नहीं देखा है। Microservices और हर team का अपने data store को control करना team velocity बढ़ाता है
      “SCALE_REASONS की वजह से FOO_TABLE access approach को modernize करने के लिए MySQL से DynamoDB पर जाना चाहता हूं, लेकिन 59 teams में से 32 teams FOO_TABLE को direct access कर रही हैं या हमारी class के private methods direct call कर रही हैं। Priorities अलग हैं, इसलिए वे teams FOO_SERVICE इस्तेमाल करने पर migrate नहीं कर सकतीं या sharded tables इस्तेमाल करने के लिए अपनी query approach नहीं बदल सकतीं। अब FOO_TABLE को scale करना कई quarters का काम बन जाता है, और teams को धीरे-धीरे update करने देना पड़ेगा। 1–2 साल बाद शायद अभी जल रही पुरानी approach retire की जा सके। तब तक on-call का मजा लीजिए”
      Microservices में team को पता चलेगा कि table scale नहीं हो रही, लेकिन data API के जरिए दिया जाता है। अगले sprint में migration plan और execute कर देंगे, और API users को लगेगा कि यह बहुत तेज हो गया है
    • Autocomplete के लिए static typing जरूरी नहीं है। JetBrains में Ruby या Python जैसी languages के लिए भी autocomplete वाले IDE हैं
      Modern Ruby का REPL खोलें तो autocomplete और syntax checking के लिहाज से static typed language IDE से जो उम्मीद होती है, उसका काफी हिस्सा मिल जाता है
    • Network calls introduce करना powerful चीज है। असल में physically enforced पार न की जा सकने वाली boundary बन जाती है, और दोनों services को एक-दूसरे को isolated मानकर deal करना पड़ता है
      Isolation को हल्के में नहीं लेना चाहिए; यह software में जोड़े जा सकने वाले सबसे powerful features में से एक है। यह performance बढ़ा सकता है, failure boundaries बना सकता है, और security boundaries दे सकता है
      यह actor model की core concept जैसा है। दो components एक-दूसरे की memory share और modify करने के बजाय, actor या microservice जैसे दो isolated systems सिर्फ defined protocol से communicate करते हैं
  • मुझे लगता है कि लोग modularity को गलत समझते हैं। modularity ज़रूरी है, लेकिन मुझे यह भी लगने लगा है कि एक और अहम architecture principle है: single vortex principle
    software system में vortex, data flow का loop होता है। अगर आप data को कहीं भेजते हैं और processed result वापस लेते हैं, या किसी भी तरह उस data से प्रभावित होते हैं, तो वहाँ vortex है। mutable variable बहुत छोटे vortex का उदाहरण है
    single vortex principle का मतलब है कि आदर्श रूप से software system में सिर्फ एक vortex होना चाहिए, या यूँ कहें कि हर component को पता होना चाहिए कि उसका vortex किस दिशा में घूम रहा है
    जब दो vortex बनाने वाले modules को एक में मिलाते हैं, तो अगर vortex की direction मेल खाती है तो composition आसान होती है; अगर opposite direction हो तो यह तय करना पड़ता है कि नए vortex की direction क्या होगी, इसलिए मामला पेचीदा हो जाता है। इसलिए सबसे अच्छा यह है कि सभी modules के vortex एक ही direction में हों और मिलकर एक vortex बनाएं
    यह principle Flux pattern, CQRS, event sourcing, immutability जैसे ideas का generalization है

    • बहुत अच्छा point है, और लगता है कि सिर्फ इसी topic पर कई लेख लिखे जा सकते हैं। service A, B को call कर सकती है, B, C को call कर सकती है, और C फिर A को call कर सकती है; ऐसा हो तो समस्या पैदा होती है
      या A में कुछ अप्रत्याशित हो जाए तो C block हो सकता है। आदर्श रूप से parent को सिर्फ child को call करना चाहिए और parent पर निर्भर नहीं होना चाहिए; अगर यह fail होता है तो architecture भी fail हो गई
    • यह concept मुझे पसंद आया
      architecture diagram देखते समय आधी लड़ाई यह समझने की होती है कि क्या asynchronous/synchronous है, push/pull क्या है, और flow की direction और order क्या है
      enterprise service bus और message queue ऐसी जगहों पर vortex बनाने का solution लगते हैं जहाँ दोनों directions मेल नहीं खातीं
    • यह vortex concept दिलचस्प है। जानना चाहूँगा कि इसे पढ़ने के लिए कोई किताब या online resource है क्या
    • आखिर से दूसरे paragraph को, खासकर rationale वाले हिस्से को, मैं ठीक से नहीं समझ पाया। क्या इसे थोड़ा और विस्तार से समझाया जा सकता है?
  • एक जगह यह बात है कि समस्या है “adopt की गई हर language के लिए एक-एक करके, सभी services को चाहिए होने वाली logging जैसी common functionality देने के लिए support करनी पड़ने वाली libraries की संख्या”
    यही हमारे microservices छोड़ने का सबसे बड़ा कारण था। 2023 के tools, खासकर pure cloud-native या infinitely scalable FaaS environment में, ऐसी चिंता पर mental bandwidth खर्च करना पूरी तरह waste है। bank और financial institution जैसे customer segments के लिए तो और भी, क्योंकि वे हर third-party dependency की बहुत कड़ी जाँच करते हैं
    अभी हम gzip में करीब 250MB के single monolithic .NET binary distribution के साथ चल रहे हैं, और दरार के कोई संकेत नहीं हैं। अगर आप 10–100MB के SaaS distribution को लेकर “मेरा exe अब L2 में fit नहीं होता” जैसी बारीक चिंताएँ कर रहे हैं, तो निश्चिंत रहें। monolithic software journey तो अभी शुरू भी नहीं हुई है
    अगर कभी ऐसी garbage heaps में से किसी एक को फिर से लिखना पड़े, तो क्या यह कहीं आसान नहीं होगा कि हर commit globally consistent एक ही जगह पर हो?

    • मुझे यह false dichotomy लगता है। जिन microservices organizations से मेरा सामना हुआ, उनमें से ज़्यादातर ने इसी तरह के कारणों से approved languages सिर्फ 2–3 रखीं, और अगर team दिखा दे कि उसके पास कोई दूसरा option नहीं है तो leadership exception allow कर सकती थी
      microservices का मतलब यह नहीं कि वह lawless zone है और हर team पूरे organization को ध्यान में रखे बिना काम कर सकती है। teams के बीच कुछ हद तक consistency बनाए रखने के लिए rules हो सकते हैं और होने भी चाहिए
    • असल में microservices में यह कहीं आसान है। support करने के लिए clear interface होता है, और code monolith के बाकी हिस्से के साथ French braid की तरह उलझा नहीं होता
      सबसे अच्छा code वह है जिसे फेंककर फिर से लिखना आसान हो। practical तौर पर पुराना code ज्यादा हाथों से गुजरता है, और खराब होता जाता है; सबसे बढ़कर, कोई उसे maintain करना नहीं चाहता
    • अहम बात यह है कि उस monolith पर कितने developers काम कर रहे हैं। binary size आम तौर पर वह वजह नहीं होती जिससे teams monolith को तोड़ना शुरू करती हैं
    • “सब कुछ एक जगह हो और हर commit globally consistent हो तो क्या यह कहीं आसान नहीं होगा?” यह वाक्य मुझे हमेशा थोड़ा मजेदार लगता है। दोनों camps इसे अक्सर कहते हैं, लेकिन शायद ही कभी दूसरे पक्ष के नज़रिए से सोचते हैं
      microservices पसंद करने वाले कहते हैं कि service को कैसे behave करना चाहिए इसका clear contract होता है और उस service का codebase काफी छोटा होता है, इसलिए change या rewrite करना आसान है
      monolith पक्ष कहता है कि सब कुछ एक बड़े धागे के गुच्छे जैसा है, इसलिए एक धागा बदलने के लिए बस यह जानना होता है कि वह दूसरे धागों से कहाँ जुड़ता है, इसलिए change या rewrite करना आसान है
      कौन सही है, पता नहीं। कई सालों से codebase को microscope से देखने वाले long-tenured लोगों के लिए monolith बेहतर हो सकता है, और बाकी लोगों के लिए microservices
    • कोई यह नहीं कहता कि सभी microservices को एक ही language नहीं इस्तेमाल करनी चाहिए
  • release management के नज़रिए से देखें तो monolith से microservices की ओर जाना अक्सर गलत वजहों से होता है
    वास्तविक बदलाव की एकमात्र वाजिब वजह performance bottleneck से जुड़ी scalability problem लगती है। बाकी सब software development की complexity को system maintenance में shift करने जैसा ही है
    बेशक developers को यह पसंद आएगा, क्योंकि दूसरी teams के साथ तालमेल बैठाने का बड़ा बोझ कम हो जाएगा। लेकिन features कब और कैसे implement होते हैं, microservices में सही तरह test होते हैं, production में activate और centrally manage होते हैं—यह साफ़ करना तब बहुत कठिन हो जाता है जब development teams के बीच communication पर्याप्त mature न हो। और वही immaturity अक्सर monolith तोड़ने की असली वजह होती है

    • सही वजहें भी बहुत हैं, और गलत वजहें भी बहुत हैं। अगर कई stakeholders हों, business requirements लगातार बदल रही हों, और developers 10 से ज्यादा हों, तो independently deploy/test/release किए जा सकने वाले units रखने की पर्याप्त वजह हो सकती है
      इसके उलट, developers कम हों और context अच्छी तरह defined हो, तो कई microservices संभालना तकलीफदेह है
      “बाकी सब software development की complexity को system maintenance में shift करना है” — अगर software active development में है तो यह बात plausible लगती है। development महंगा है। distributed system का maintenance cost, एक बड़ी monolith develop करने की cost से कम भी हो सकता है; आखिरकार यह situation पर निर्भर करता है
    • हमारे app के इस हिस्से को अलग component में निकालने की एकमात्र वजह भी यही है। यह इतना बड़ा हो गया है कि effectively maintain करना मुश्किल है, और app के बाकी हिस्से को हम जैसा है वैसा ही रहने देंगे
  • “मोनोलिथ की लागत” वाला लेख कहाँ है? यहाँ तो वह दिख नहीं रहा। असल में सभी लोग बिना समझे माइक्रोसर्विसेज़ लागू कर रहे हैं, इसलिए सिर्फ वही समस्या दिखती है
    अगर सभी लोग बिना समझे मोनोलिथ बना रहे होते, तो “मोनोलिथ खराब है” वाले लेख बहुत बड़ी संख्या में दिखते
    लोग यह नहीं समझते कि दोनों सिस्टम आखिरकार समान मात्रा की समस्याएँ पैदा करते हैं। यह एक हाथी से काम करवाने और 1000 चूहों से काम करवाने के फर्क जैसा है। दोनों में समस्याएँ आती हैं, बस समस्याएँ अलग होती हैं
    दोनों में से किसी एक को चुन लेने से समस्याएँ गायब नहीं होतीं। किसी भी तरफ समस्या आएगी, और एक को चुनकर उसका समाधान देना होगा। अगर किसी कंपनी में “कौन-सा architecture है” ही सबसे बड़ी बाधा है, तो मैं वहाँ काम करना चाहूँगा

    • आज हम माइक्रोसर्विसेज़ में जरूरत से ज्यादा डूबे हुए हैं, क्योंकि अतीत में मोनोलिथ खराब है वाले लेख करीब 8 ट्रिलियन थे। अभी यह इस बात का反action है कि लोगों को समझ आया कि लागत के मुकाबले फायदा उनके लिए सही नहीं था
  • अगर मोनोलिथ अच्छी तरह decomposed है, तो उसी जगह deploy की गई माइक्रोसर्विसेज़ से वह कैसे अलग है? शायद सिर्फ interface में। function call RPC बन जाता है, और components को अलग-अलग संभालने के फायदे मिलते हैं, जैसे patching के लिए थोड़ा overhead स्वीकार करना
    distributed माइक्रोसर्विसेज़ और एक ही location में मौजूद माइक्रोसर्विसेज़ में क्या फर्क है? deployment ज्यादा जटिल होता है, लेकिन processes को अधिक उपयुक्त hardware पर समझदारी से रखा जा सकता है। failure modes बढ़ते हैं, लेकिन ज्यादा fault tolerance मिलती है
    इसका कोई universal answer नहीं है। अगर फायदे चाहिए, तो लागत चुकानी पड़ेगी। मेरे हिसाब से ऐसी माइक्रोसर्विसेज़ बनाम मोनोलिथ बहसें या तो किसी pattern को गलत लागू करने से, या जीवन आसान बनाने वाले tools की कमी से, या अक्सर 10 साल पुराने software को लगातार refactor और redesign न करने से पैदा होती हैं, जिससे initial architecture चाहे जो भी हो, उस पर काम करना पीड़ादायक हो जाता है

    • मोनोलिथ से माइक्रोसर्विसेज़ में जाना कोई मामूली बदलाव नहीं है, चाहे शुरुआत में decomposition कितना भी अच्छा रहा हो। बेशक design खराब हो तो migration और कठिन हो जाता है
      “function call RPC बन जाता है” कहना सरल लगता है, लेकिन उस पल से client app को DNS server unavailable, hostname resolution failure, host unreachable, connection refused, authentication denied, untrusted TLS certificate, rate limit exceeded, 301 permanent redirect, result preparation delay, timeout जैसे सभी execution paths handle करने पड़ते हैं
      अच्छी तरह decomposed app को भी इन्हें robust तरीके से handle करने के लिए async queue, request rate limiting, result cache, logged backoff retry, configurable client credentials/trust store/resource URL, और failure logging सक्षम करने के लिए redesign करना पड़ सकता है
      local function call में जो data context में था, उसे उपलब्ध कराने के लिए RPC functions और parameters भी अलग से चाहिए होंगे। साथ ही monolith UI को अब users तक network latency और failures पहुँचाने पड़ सकते हैं, जो पहले संभव ही नहीं थे
      सबसे अच्छी तरह बनाया गया monolith भी माइक्रोसर्विसेज़ में refactor करने के लिए काफी मेहनत माँगता है
    • “function call RPC बन जाता है” के पीछे नए failure modes और ज्यादा plumbing work आता है
      क्या इस RPC call को safe तरीके से retry किया जा सकता है? exponential backoff? API load balancer सही चल रहा है या नहीं—तो monitoring भी चाहिए। माइक्रोसर्विसेज़ के बीच tracing कैसे करेंगे? अब OpenTelemetry जैसी चीज़ चाहिए हो जाती है
      माइक्रोसर्विसेज़ architecture में breakpoint लगाकर debugging कितनी ज्यादा कठिन हो जाती है? दो माइक्रोसर्विसेज़ के बीच database transaction को rollback कैसे करेंगे? एक साधारण function call अचानक बहुत ज्यादा जटिल हो जाती है
    • माइक्रोसर्विसेज़ पर चर्चा करते समय समर्थक पक्ष लगभग हमेशा इस concept के मूल हिस्से, यानी micro को भूल जाता है। services अपने-आप में तो सबको पता हैं और जरूरत पड़े तो बना ली जाती हैं; वह कोई ऐसा concept नहीं है जिसे बेचने की जरूरत हो
      इस concept का बचाव करते समय हर बार यह calculation से छूट जाता है कि services को बहुत छोटा रखने की requirement कितनी fragmentation पैदा करती है। और साफ कहें तो अगर एक monolith और एक microservice है, तो वह microservices नहीं हैं। microservices शब्द का मतलब यह imply करता है कि सब कुछ छोटी-छोटी services में टूटा है और कोई monolith नहीं है
      माइक्रोसर्विसेज़ के पक्ष में दिए जाने वाले ज्यादातर तर्क उसी क्षण ढह जाते हैं जब समझ आता है कि उन्हें अनिवार्य रूप से “micro” होना है। और अगर वह requirement छोड़ दें, तो कोई नया या गहरा प्रस्ताव बचता ही नहीं
    • developer के नजरिए से फर्क interface में है। monolith को synchronized और correct बनाए रखने के लिए हर तरह के tools हैं, लेकिन inter-process communication में मदद करने वाले tools static evaluation नहीं कर सकते और बिल्कुल interactive भी नहीं होते
      operations के नजरिए से “deployment ज्यादा जटिल है” कहना बहुत बड़ा understatement है। हर package अपनी अलग विशेषताओं और समस्याओं वाला, अलग से manage करने योग्य object होता है
    • atomic transactions खो जाते हैं। इस वजह से हर business action कई orders of magnitude ज्यादा complex हो जाता है
  • जैसे frontend developers सोचते हैं कि React/Vue/Svelte जैसे frontend framework या library के बिना “modern web app” नहीं बनाया जा सकता, वैसे ही आजकल लगता है कि “monolith” का मतलब किसी डरावने विशाल tar ball को single instance के रूप में चलाना है, इसलिए वह “scale नहीं करता”—यह धारणा घूम रही है, लेकिन यह बेतुकी है
    एक और बात दिखती है कि कुल code मात्रा बहुत बढ़ जाती है, और ज्यादातर services 20% business/domain code और 80% network message send/receive handling से बनी होती हैं। आप इसे कितना भी छिपाएँ, आखिरकार वह वहीं है, और किसी न किसी तरह network से निपटना ही पड़ेगा
    frontend madness की तरह यह microservices cult भी तब खत्म होगा जब economy खराब होगी और ऐसी विनाशकारी Babel towers को सहारा देने के लिए पैसा नहीं बचेगा
    साथ ही, माइक्रोसर्विसेज़ की अपनी जगह भी है। कुछ companies के भीतर, जहाँ लागत से ज्यादा value मिलती है, वहाँ यह सही है

    • लोग माइक्रोसर्विसेज़ के बारे में जो बात miss करते हैं, वह यह है कि लक्ष्य आमतौर पर तकनीकी समस्या नहीं बल्कि organization और people problems हल करना होता है
      per-service independent scaling जैसे technical benefits भी हैं, लेकिन सबसे बड़ा फायदा clear ownership boundaries और unnecessary tight coupling को रोकना है
      अगर एक छोटी team single product बना रही है, तो संभव है कि वह organizational problem अभी मौजूद ही न हो जिसे माइक्रोसर्विसेज़ हल करती हैं, इसलिए इसकी जरूरत न हो। उस case में माइक्रोसर्विसेज़ premature optimization हैं, यानी ऐसी समस्या हल करने की कीमत चुकाना जो अभी है ही नहीं
    • React/Vue/Svelte frameworks नहीं बल्कि view libraries हैं, और मैं इस stance पर अंत तक कायम रहूँगा
      आगे कहूँ तो frontend complexity पूरी तरह दिमाग में है: https://bower.sh/front-end-complexity
    • मैं मानता हूँ कि कई websites JavaScript और frameworks का जरूरत से ज्यादा इस्तेमाल करती हैं। लेकिन desktop-grade web app बनाते समय, अगर विशाल mess नहीं बनाना और अंततः इन्हीं frameworks में पहले से मौजूद concepts को दोबारा invent नहीं करना, तो क्या इस्तेमाल करना चाहिए, यह जानना चाहूँगा
  • लेख मानो यह मानकर चलता है कि development organization पूरी तरह बिगड़ी हुई है और control से बाहर है। sprint के दौरान क्या करना है यह तय नहीं कर पाते, चुपके से third-party libraries और अनजान languages ले आते हैं, और incompatible changes को चुपचाप production में deploy कर देते हैं
    अगर developers बेवकूफ नहीं हैं, तो microservices भी ज़्यादा आसान लगेंगी

    • दुर्भाग्य से, team में कोई बेवकूफ होना, या उसी project पर काम करने वाली पूरी team का बेवकूफ होना, काफी आम है
      अगर आप smart और सक्षम developers वाली team में काम करते हैं, तो मुझे यकीन है कि microservices ज़्यादा आसान होंगी। हालांकि तब तो सब कुछ ही ज़्यादा आसान हो जाएगा
    • हर developer नई job में शुरुआती कुछ महीनों तक अनिवार्य रूप से बेवकूफ ही होता है। क्योंकि existing system कैसे काम करता है, यह समझने के लिए जरूरी जानकारी absorb करने में समय लगता है