<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rakib Ahasan</title>
    <description>The latest articles on DEV Community by Rakib Ahasan (@rakibahasan).</description>
    <link>https://dev.to/rakibahasan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3216481%2Fdf5e74e0-d850-4f2c-822b-a2611f626f34.jpg</url>
      <title>DEV Community: Rakib Ahasan</title>
      <link>https://dev.to/rakibahasan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rakibahasan"/>
    <language>en</language>
    <item>
      <title>.NET System Design ও Application Architecture: A2Z সম্পূর্ণ গাইড</title>
      <dc:creator>Rakib Ahasan</dc:creator>
      <pubDate>Wed, 28 Oct 2026 08:37:24 +0000</pubDate>
      <link>https://dev.to/rakibahasan/net-system-design-o-application-architecture-a2z-smpuurnn-gaaidd-een</link>
      <guid>https://dev.to/rakibahasan/net-system-design-o-application-architecture-a2z-smpuurnn-gaaidd-een</guid>
      <description>&lt;p&gt;Oct 28, 2026 · &lt;a class="mentioned-user" href="https://dev.to/rakib"&gt;@rakib&lt;/a&gt; Ahasan&lt;/p&gt;

&lt;h2&gt;
  
  
  ভূমিকা: এই গাইড কেন, কার জন্য, কীভাবে পড়বেন
&lt;/h2&gt;

&lt;p&gt;System design শেখার সবচেয়ে বড় সমস্যা হলো তথ্য ছড়ানো: একটা ব্লগে CAP theorem, আরেকটায় Microservices, তৃতীয়টায় Redis। কোনোটাই বলে না কখন কোনটা লাগে। এই গাইডে সব একসাথে, একটা ধারাবাহিক গল্পের মধ্য দিয়ে, .NET (C# ও ASP.NET Core) এর উদাহরণসহ।&lt;/p&gt;

&lt;h3&gt;
  
  
  এই গাইড কাদের জন্য
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;যারা C# জানেন, কিন্তু "architecture" শব্দটা শুনলে ঘাবড়ে যান (Beginner)&lt;/li&gt;
&lt;li&gt;যারা ২-৩ বছর কাজ করছেন, কিন্তু কেন Clean Architecture বা CQRS লাগে বুঝতে পারেন না (Intermediate)&lt;/li&gt;
&lt;li&gt;যারা Senior/Lead হতে চান এবং system design interview বা real project এ trade-off নিয়ে সিদ্ধান্ত নিতে চান (Advanced)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  কীভাবে পড়বেন
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;আপনি কোথায়&lt;/th&gt;
&lt;th&gt;কী করবেন&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;একদম নতুন&lt;/td&gt;
&lt;td&gt;Part 1 থেকে ক্রমানুসারে পড়ুন, কোড হাতে লিখে চালান&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;কিছুটা অভিজ্ঞ&lt;/td&gt;
&lt;td&gt;Part 2, 3 ও 4 মন দিয়ে পড়ুন, বাকিগুলো স্কিম করুন&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interview প্রস্তুতি&lt;/td&gt;
&lt;td&gt;Part 1, 6, 7, 11, 12 আগে পড়ুন&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real project এ আটকে আছেন&lt;/td&gt;
&lt;td&gt;সূচি দেখে সরাসরি সংশ্লিষ্ট Part এ যান&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  গল্পের চরিত্র: ShopEasy
&lt;/h3&gt;

&lt;p&gt;পুরো গাইডে আমরা একটা কাল্পনিক ই-কমার্স অ্যাপ &lt;strong&gt;ShopEasy&lt;/strong&gt; ধরে এগোব। রাফি নামের একজন ডেভেলপার ঢাকায় একা এটা শুরু করে।&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;দিন ১:&lt;/strong&gt; ১০০ জন ইউজার, একটা ASP.NET Core অ্যাপ, একটা SQL Server। সব ঠিকঠাক।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;৬ মাস পর:&lt;/strong&gt; ১০,০০০ ইউজার। পেজ ধীর, কোড এলোমেলো, নতুন ডেভেলপার এসে কিছু বুঝছে না।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;১ বছর পর:&lt;/strong&gt; ঈদের সেলে ১ লক্ষ ইউজার একসাথে ঢুকল, সাইট বসে গেল। পেমেন্ট দুইবার কাটল।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;২ বছর পর:&lt;/strong&gt; ১০ জনের টিম, একসাথে কাজ করলে একে অন্যের কোড ভাঙছে।&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;প্রতিটি সমস্যার সমাধান হিসেবে একটা নতুন concept আসবে। এভাবে আপনি শুধু "কী" নয়, "কেন" ও শিখবেন। এটাই সত্যিকারের architect এর মানসিকতা।&lt;/p&gt;

&lt;h3&gt;
  
  
  System Design আসলে কী?
&lt;/h3&gt;

&lt;p&gt;সহজ কথায়: &lt;strong&gt;একটা সফটওয়্যার কীভাবে অনেক মানুষের জন্য, নির্ভরযোগ্যভাবে, দ্রুত এবং সাশ্রয়ীভাবে কাজ করবে, তার পরিকল্পনা।&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;বাড়ি বানানোর সাথে তুলনা করুন। ঘর (code) ঠিক থাকলেও যদি ভিত্তি (architecture) দুর্বল হয়, তিনতলার পর আর বাড়ানো যায় না। আবার একটা ছোট টিনের ঘরের জন্য আকাশচুম্বী ভবনের ভিত্তি বানানোও অপচয়। ভালো architect জানেন &lt;strong&gt;কখন কতটা লাগবে&lt;/strong&gt;।&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture vs Design: পার্থক্য
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Application Architecture&lt;/th&gt;
&lt;th&gt;System Design&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ফোকাস&lt;/td&gt;
&lt;td&gt;অ্যাপের ভেতরের কাঠামো, layer, module&lt;/td&gt;
&lt;td&gt;পুরো সিস্টেম: server, DB, cache, network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;প্রশ্ন&lt;/td&gt;
&lt;td&gt;কোড কীভাবে সাজাব?&lt;/td&gt;
&lt;td&gt;লক্ষ ইউজার কীভাবে সামলাব?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;উদাহরণ&lt;/td&gt;
&lt;td&gt;Clean Architecture, CQRS&lt;/td&gt;
&lt;td&gt;Load Balancer, Sharding, CDN&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;দুটোই একে অপরের সাথে জড়িত। এই গাইডে দুটোই পাবেন।&lt;/p&gt;

&lt;h3&gt;
  
  
  সবচেয়ে গুরুত্বপূর্ণ কথা: Trade-off
&lt;/h3&gt;

&lt;p&gt;System design এ "সেরা সমাধান" বলে কিছু নেই। আছে &lt;strong&gt;কোন পরিস্থিতিতে কোনটা উপযুক্ত&lt;/strong&gt;। প্রতিটি সিদ্ধান্তে কিছু পাওয়া যায়, কিছু ছাড়তে হয়। এই গাইডের প্রতিটি অধ্যায়ে আমরা এই প্রশ্ন করব: &lt;em&gt;এর দাম কী?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  প্রস্তুতি
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;C# এর basics (class, interface, async/await, LINQ)&lt;/li&gt;
&lt;li&gt;ASP.NET Core এর প্রাথমিক ধারণা&lt;/li&gt;
&lt;li&gt;SQL এর basics&lt;/li&gt;
&lt;li&gt;কোড চালাতে .NET 9 বা তার পরের SDK (এই গাইডের কোড .NET 8+ এ চলবে)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: ভিত্তি: নেটওয়ার্ক, Scalability ও Distributed ধারণা
&lt;/h2&gt;

&lt;p&gt;আপনি যদি এই Part ভালোভাবে বোঝেন, বাকি সব Part সহজ লাগবে। এখানে আমরা সেই শব্দগুলো শিখব, যেগুলো system design এর প্রতিটি আলোচনায় আসে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১.১ Client-Server মডেল
&lt;/h3&gt;

&lt;p&gt;আপনি ব্রাউজারে &lt;code&gt;shopeasy.com&lt;/code&gt; লিখলে যা ঘটে:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ব্রাউজার (&lt;strong&gt;Client&lt;/strong&gt;) একটা অনুরোধ (&lt;strong&gt;Request&lt;/strong&gt;) পাঠায়।&lt;/li&gt;
&lt;li&gt;কোনো কম্পিউটার (&lt;strong&gt;Server&lt;/strong&gt;) সেটা গ্রহণ করে, প্রসেস করে।&lt;/li&gt;
&lt;li&gt;সার্ভার একটা উত্তর (&lt;strong&gt;Response&lt;/strong&gt;) ফেরত দেয়।&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;রেস্টুরেন্টের উদাহরণ: আপনি (client) ওয়েটারকে অর্ডার দিলেন, রান্নাঘর (server) রান্না করল, ওয়েটার খাবার এনে দিল। ওয়েটার হলো network।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// সবচেয়ে ছোট ASP.NET Core server&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hello from ShopEasy!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ১.২ ব্রাউজারে URL লিখলে আসলে কী ঘটে (পুরো যাত্রা)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;DNS lookup:&lt;/strong&gt; &lt;code&gt;shopeasy.com&lt;/code&gt; একটা নাম। কম্পিউটার চেনে IP ঠিকানা (যেমন &lt;code&gt;203.0.113.10&lt;/code&gt;)। DNS হলো ইন্টারনেটের ফোনবুক, নাম দিলে IP বলে দেয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TCP connection:&lt;/strong&gt; client ও server এর মধ্যে সংযোগ তৈরি হয় (3-way handshake: SYN, SYN-ACK, ACK)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLS handshake:&lt;/strong&gt; HTTPS হলে এনক্রিপশন কী বিনিময় হয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP request:&lt;/strong&gt; &lt;code&gt;GET /products HTTP/1.1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server processing:&lt;/strong&gt; load balancer, web server, application, database।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP response:&lt;/strong&gt; &lt;code&gt;200 OK&lt;/code&gt; সহ JSON/HTML।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser render:&lt;/strong&gt; পেজ দেখানো।&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;প্রতিটি ধাপে সময় লাগে। এগুলো বোঝা মানে বোঝা, ধীর কোথায়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১.৩ HTTP: সার্ভারের সাথে কথা বলার ভাষা
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Method গুলো:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;কাজ&lt;/th&gt;
&lt;th&gt;Safe?&lt;/th&gt;
&lt;th&gt;Idempotent?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;ডেটা পড়া&lt;/td&gt;
&lt;td&gt;হ্যাঁ&lt;/td&gt;
&lt;td&gt;হ্যাঁ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;নতুন কিছু তৈরি&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PUT&lt;/td&gt;
&lt;td&gt;সম্পূর্ণ replace&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;হ্যাঁ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PATCH&lt;/td&gt;
&lt;td&gt;আংশিক পরিবর্তন&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;সাধারণত না&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;মুছে ফেলা&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;হ্যাঁ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Idempotent&lt;/strong&gt; মানে: একই request একাধিকবার পাঠালে ফলাফল একই থাকে। এটা Part 5 এ অত্যন্ত গুরুত্বপূর্ণ, কারণ নেটওয়ার্ক ফেল করলে client আবার চেষ্টা (retry) করে। ShopEasy তে পেমেন্ট দুবার কাটার মূল কারণ এটাই।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Status code এর পরিবার:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;2xx&lt;/code&gt; সফল (200 OK, 201 Created, 204 No Content)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3xx&lt;/code&gt; redirect (301, 302, 304 Not Modified)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;4xx&lt;/code&gt; client এর ভুল (400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 429 Too Many Requests)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;5xx&lt;/code&gt; server এর ভুল (500, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১.৪ Latency, Throughput ও Bandwidth
&lt;/h3&gt;

&lt;p&gt;তিনটি শব্দ প্রায়ই গুলিয়ে যায়। পানির পাইপের উদাহরণ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Latency:&lt;/strong&gt; পানি পাইপের এক মাথা থেকে অন্য মাথায় পৌঁছাতে কত সময় লাগে (যেমন ১২০ ms)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bandwidth:&lt;/strong&gt; পাইপ কত মোটা, অর্থাৎ সর্বোচ্চ কত পানি যেতে পারে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput:&lt;/strong&gt; আসলে প্রতি সেকেন্ডে কত পানি যাচ্ছে (যেমন ৫০০ request/sec)।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;প্রতিটি অপারেশনের আনুমানিক সময় জানা থাকলে design সহজ হয়:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;অপারেশন&lt;/th&gt;
&lt;th&gt;আনুমানিক সময়&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;মেমরি থেকে পড়া&lt;/td&gt;
&lt;td&gt;~100 ns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSD থেকে পড়া&lt;/td&gt;
&lt;td&gt;~100 µs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;একই datacenter এর মধ্যে network call&lt;/td&gt;
&lt;td&gt;~0.5 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database query (index সহ)&lt;/td&gt;
&lt;td&gt;~1-10 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ঢাকা থেকে সিঙ্গাপুর network round trip&lt;/td&gt;
&lt;td&gt;~60-80 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ঢাকা থেকে ইউরোপ/আমেরিকা&lt;/td&gt;
&lt;td&gt;~150-250 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(সংখ্যাগুলো আনুমানিক; হার্ডওয়্যার ও নেটওয়ার্ক ভেদে বদলায়।) শিক্ষা: &lt;strong&gt;network call ও disk মেমরির চেয়ে বহু গুণ ধীর&lt;/strong&gt;। তাই caching এত শক্তিশালী।&lt;/p&gt;

&lt;p&gt;পারসেন্টাইল: গড় (average) response time প্রায়ই মিথ্যা বলে। &lt;strong&gt;p95/p99 latency&lt;/strong&gt; দেখুন। p99 = ২০০ms মানে ৯৯% request ২০০ms এর মধ্যে শেষ হয়, বাকি ১% এর চেয়ে ধীর। বড় সিস্টেমে ১% ও লক্ষ লক্ষ মানুষ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১.৫ Scalability: সিস্টেম বড় হলে সামলানোর ক্ষমতা
&lt;/h3&gt;

&lt;p&gt;ShopEasy এর ঈদের সেলে ট্রাফিক ১০০ গুণ বাড়ল। দুটি উপায়:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vertical Scaling (Scale Up):&lt;/strong&gt; একই সার্ভারে বেশি CPU/RAM দেওয়া।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;সুবিধা: সহজ, কোড বদলাতে হয় না।&lt;/li&gt;
&lt;li&gt;অসুবিধা: একটা সীমা আছে, দাম অতিরিক্ত বাড়ে, single point of failure।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Horizontal Scaling (Scale Out):&lt;/strong&gt; আরও অনেক সার্ভার যোগ করা।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;সুবিধা: প্রায় অসীম বাড়ানো যায়, একটা সার্ভার গেলে বাকিরা চলে।&lt;/li&gt;
&lt;li&gt;অসুবিধা: জটিলতা বাড়ে (load balancing, shared state, data consistency)।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;উপমা: একজন সুপারম্যান শ্রমিক (vertical) বনাম অনেক সাধারণ শ্রমিক (horizontal)।&lt;/p&gt;

&lt;h4&gt;
  
  
  Stateless বনাম Stateful: Horizontal scaling এর চাবিকাঠি
&lt;/h4&gt;

&lt;p&gt;ধরুন ইউজারের shopping cart সার্ভার-১ এর মেমরিতে আছে। পরের request load balancer সার্ভার-২ তে পাঠাল। cart উধাও!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Stateful: scale করা যায় না&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CartController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_carts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// এই server এর মেমরিতে&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Stateless: state বাইরে (Redis/DB) রাখা হয়েছে&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CartController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ICartStore&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// যেকোনো server এ একই ফল&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt; application server কে stateless রাখুন। state যাবে database, cache বা বাইরের store এ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১.৬ Availability ও Reliability
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Availability&lt;/strong&gt; = সিস্টেম কত সময় চালু থাকে। "nine" দিয়ে মাপা হয়:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Availability&lt;/th&gt;
&lt;th&gt;বছরে সর্বোচ্চ বন্ধ থাকার সময়&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;99% (দুই নাইন)&lt;/td&gt;
&lt;td&gt;~৩.৬৫ দিন&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.9% (তিন নাইন)&lt;/td&gt;
&lt;td&gt;~৮.৭৬ ঘণ্টা&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.99% (চার নাইন)&lt;/td&gt;
&lt;td&gt;~৫২.৬ মিনিট&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;99.999% (পাঁচ নাইন)&lt;/td&gt;
&lt;td&gt;~৫.২৬ মিনিট&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;প্রতিটি অতিরিক্ত nine এর খরচ ও জটিলতা নাটকীয়ভাবে বাড়ে। ব্যবসার প্রয়োজন বুঝে লক্ষ্য ঠিক করুন; একটি ব্লগের জন্য ৯৯.৯৯৯% দরকার নেই।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reliability&lt;/strong&gt; = সিস্টেম ঠিকঠাক কাজ করছে কি না (ভুল ফলাফল দিচ্ছে না তো?)। একটা সিস্টেম available কিন্তু unreliable হতে পারে (সবসময় চালু, কিন্তু ভুল ব্যালেন্স দেখাচ্ছে)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redundancy:&lt;/strong&gt; একই কাজের জন্য একাধিক কপি রাখা, যাতে একটা ভাঙলে অন্যটা কাজ করে। &lt;strong&gt;Single Point of Failure (SPOF):&lt;/strong&gt; যে একটি জিনিস ভাঙলে পুরো সিস্টেম বসে যায়। Architect এর কাজ হলো SPOF খুঁজে বের করা।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SLI, SLO, SLA:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SLI:&lt;/strong&gt; আসলে কী মাপছেন (যেমন সফল request এর শতাংশ)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLO:&lt;/strong&gt; লক্ষ্য (যেমন ৯৯.৯% সফল)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLA:&lt;/strong&gt; গ্রাহকের সাথে চুক্তি, ভাঙলে জরিমানা।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১.৭ Distributed System এর মূল সমস্যা
&lt;/h3&gt;

&lt;p&gt;একটা সার্ভারে সব সহজ। একাধিক সার্ভার হলে নতুন সমস্যা আসে, যেগুলোকে বলে &lt;em&gt;Fallacies of Distributed Computing&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;নেটওয়ার্ক নির্ভরযোগ্য নয় (প্যাকেট হারায়)&lt;/li&gt;
&lt;li&gt;Latency শূন্য নয়&lt;/li&gt;
&lt;li&gt;সার্ভারগুলোর ঘড়ি হুবহু এক নয়&lt;/li&gt;
&lt;li&gt;যেকোনো মুহূর্তে একটা node ফেল করতে পারে&lt;/li&gt;
&lt;li&gt;Partial failure: কিছু অংশ কাজ করে, কিছু করে না। সবচেয়ে কঠিন, কারণ আপনি জানেন না অপর পাশ ফেল করেছে নাকি শুধু ধীর।&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  CAP Theorem
&lt;/h4&gt;

&lt;p&gt;Distributed data store এ তিনটি জিনিসের মধ্যে একসাথে সর্বোচ্চ দুটি পাওয়া যায়:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C (Consistency):&lt;/strong&gt; সবাই সবসময় একই সর্বশেষ ডেটা দেখে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A (Availability):&lt;/strong&gt; প্রতিটি request এর একটা উত্তর মেলে (ভুল/পুরনো হলেও)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;P (Partition tolerance):&lt;/strong&gt; নেটওয়ার্ক ভেঙে সার্ভারগুলো আলাদা হয়ে গেলেও সিস্টেম চলে।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;বাস্তবে network partition অনিবার্য, তাই প্রকৃত পছন্দ হলো &lt;strong&gt;CP বনাম AP&lt;/strong&gt;, partition চলাকালীন।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;গল্প:&lt;/strong&gt; ঢাকা ও চট্টগ্রামে ShopEasy এর দুটো ডেটাসেন্টার। দুটোর মাঝের লাইন কেটে গেল। একজন ইউজার ঢাকায় শেষ ১টা পণ্য কিনল, আরেকজন একই সময়ে চট্টগ্রামে।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CP বেছে নিলে:&lt;/strong&gt; চট্টগ্রাম বলবে "এখন অর্ডার নেওয়া যাচ্ছে না"। ডেটা সঠিক থাকল, কিন্তু সেবা বন্ধ।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AP বেছে নিলে:&lt;/strong&gt; দুজনের অর্ডারই নেবে, পরে ঝামেলা মেটাবে (একজনকে ক্ষমা চেয়ে refund)। সেবা চালু, কিন্তু ডেটা সাময়িক অসঙ্গত।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ব্যাংকের ব্যালেন্সে সাধারণত CP, সোশ্যাল মিডিয়ার "like count" এ AP চলে।&lt;/p&gt;

&lt;h4&gt;
  
  
  Consistency মডেল
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Strong consistency:&lt;/strong&gt; লেখার পরপর যে কেউ পড়লে নতুন মান পাবে। সহজ, কিন্তু ধীর ও ব্যয়বহুল।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Eventual consistency:&lt;/strong&gt; লেখার পর কিছুক্ষণ কেউ পুরনো মান দেখতে পারে, কিন্তু শেষে সবাই একই মানে পৌঁছায়। দ্রুত, scale করা সহজ।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read-your-writes:&lt;/strong&gt; আপনি নিজে যা লিখেছেন সেটা অন্তত নিজে দেখবেন।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;উদাহরণ: Facebook এ কমেন্ট করার পর বন্ধু দুই সেকেন্ড পর দেখে। এটা eventual consistency, আর তাতে কারও ক্ষতি নেই।&lt;/p&gt;

&lt;h4&gt;
  
  
  PACELC
&lt;/h4&gt;

&lt;p&gt;CAP শুধু partition এর সময়ের কথা বলে। PACELC বলে: partition (P) হলে A বা C বেছে নাও; নইলে (Else) স্বাভাবিক সময়েও &lt;strong&gt;Latency (L) বনাম Consistency (C)&lt;/strong&gt; এর মধ্যে বেছে নিতে হয়। শক্তিশালী consistency চাইলে একাধিক node এর সম্মতি লাগে, তাই ধীর হয়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১.৮ Load Balancer: ট্রাফিক ভাগ করার ট্রাফিক পুলিশ
&lt;/h3&gt;

&lt;p&gt;একাধিক server থাকলে ইউজারের request কোনটায় যাবে? Load Balancer ঠিক করে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Algorithm:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Round Robin:&lt;/strong&gt; পালা করে (১, ২, ৩, ১, ২, ৩...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least Connections:&lt;/strong&gt; যার কাজ কম, তাকে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IP Hash:&lt;/strong&gt; একই ইউজার সবসময় একই server এ (sticky session)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weighted:&lt;/strong&gt; শক্তিশালী server কে বেশি&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Layer 4 বনাম Layer 7:&lt;/strong&gt; L4 শুধু IP/port দেখে (দ্রুত)। L7 HTTP এর ভেতরে (URL, header) দেখে সিদ্ধান্ত নেয়, যেমন &lt;code&gt;/api/*&lt;/code&gt; এক জায়গায়, &lt;code&gt;/images/*&lt;/code&gt; অন্য জায়গায়। Nginx, HAProxy, Azure Application Gateway, AWS ALB জনপ্রিয়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Health check:&lt;/strong&gt; load balancer নিয়মিত জিজ্ঞেস করে "তুমি ঠিক আছো?" (&lt;code&gt;/health&lt;/code&gt; endpoint)। ফেল করলে সেই server কে ট্রাফিক দেওয়া বন্ধ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১.৯ Proxy, Reverse Proxy, CDN
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forward proxy:&lt;/strong&gt; ক্লায়েন্টের পক্ষ হয়ে বাইরে যায় (যেমন অফিসের ইন্টারনেট ফিল্টার)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reverse proxy:&lt;/strong&gt; সার্ভারের সামনে বসে, ক্লায়েন্টের request নিয়ে ভেতরের server এ পাঠায়। কাজ: load balancing, TLS termination, caching, নিরাপত্তা। (Nginx, YARP, Cloudflare)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN (Content Delivery Network):&lt;/strong&gt; ছবি, CSS, JS, ভিডিওর মতো static ফাইলের কপি বিশ্বজুড়ে edge সার্ভারে রাখে। ঢাকার ইউজার সিঙ্গাপুরের edge থেকে ছবি পায়, আমেরিকার origin server থেকে নয়। ফলে latency অনেক কমে।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১.১০ DNS এর আরেকটু গভীরে
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A record:&lt;/strong&gt; নাম থেকে IPv4&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CNAME:&lt;/strong&gt; এক নামের alias আরেক নাম&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TTL:&lt;/strong&gt; cache এ কতক্ষণ রাখা যাবে (কম TTL = দ্রুত বদল, বেশি DNS query)&lt;/li&gt;
&lt;li&gt;DNS দিয়েও load balancing ও geo-routing করা যায় (ইউজারকে কাছের region এ পাঠানো)।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Part 1 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Network ও disk ধীর; বেশি call মানে বেশি latency।&lt;/li&gt;
&lt;li&gt;Horizontal scaling এর শর্ত: app server stateless।&lt;/li&gt;
&lt;li&gt;Availability এর প্রতিটি nine এর দাম আছে; SPOF খুঁজুন।&lt;/li&gt;
&lt;li&gt;Distributed system এ failure স্বাভাবিক; CAP/PACELC তে trade-off বুঝে বেছে নিন।&lt;/li&gt;
&lt;li&gt;Load balancer, reverse proxy, CDN হলো ট্রাফিক সামলানোর প্রথম অস্ত্র।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 2: Code-level Design: SOLID, Principles ও Design Pattern
&lt;/h2&gt;

&lt;p&gt;বড় architecture এর আগে ছোট কোড ঠিক করতে হয়। ৬ মাস পর ShopEasy এর কোড এমন হয়েছে: একটা &lt;code&gt;OrderService&lt;/code&gt; ক্লাসে ২,০০০ লাইন, যেখানে অর্ডার, পেমেন্ট, ইমেইল, ইনভেন্টরি সব মিশে আছে। একটা জায়গা বদলালে তিন জায়গা ভাঙে। এই Part সেই সমস্যার সমাধান।&lt;/p&gt;

&lt;h3&gt;
  
  
  ২.১ খারাপ কোডের উদাহরণ (সমস্যা চিনুন)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;PlaceOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. validation&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Empty"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// 2. database&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SqlConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Server=...;Password=123"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// ... SQL insert ...&lt;/span&gt;

        &lt;span class="c1"&gt;// 3. payment&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"bkash"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* bkash API call */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaymentType&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* card API call */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// 4. email&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;smtp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SmtpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"smtp.gmail.com"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;smtp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;সমস্যা: একাধিক দায়িত্ব, hard-coded dependency, নতুন পেমেন্ট (Nagad) এলে এই ক্লাসই বদলাতে হবে, test লেখা প্রায় অসম্ভব (সত্যিকারের DB ও SMTP লাগে)। SOLID এগুলোই ঠিক করে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ২.২ SOLID: পাঁচটি মূলনীতি
&lt;/h3&gt;

&lt;h4&gt;
  
  
  S: Single Responsibility Principle (SRP)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;একটা ক্লাসের পরিবর্তনের কারণ একটাই হওয়া উচিত।&lt;/strong&gt; একটা ক্লাস একটা কাজ করবে।&lt;/p&gt;

&lt;p&gt;উপমা: একজন শেফ যদি রান্না, হিসাব, ডেলিভারি সব করে, কোনোটাই ভালো হয় না।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailNotifier&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  O: Open/Closed Principle (OCP)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;বাড়ানোর জন্য খোলা, বদলানোর জন্য বন্ধ।&lt;/strong&gt; নতুন ফিচার যোগ করতে পুরনো কোড না ছুঁয়ে নতুন কোড লিখুন।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ নতুন পেমেন্ট এলেই if-else বাড়ে&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"bkash"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Interface দিয়ে&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IPaymentMethod&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PaymentResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;PayAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BkashPayment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentMethod&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CardPayment&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentMethod&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NagadPayment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPaymentMethod&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* নতুন ফাইল, পুরনো কোড অক্ষত */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  L: Liskov Substitution Principle (LSP)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Parent এর জায়গায় Child বসালে প্রোগ্রাম ঠিকমতো চলতে হবে।&lt;/strong&gt; Child যেন parent এর প্রতিশ্রুতি না ভাঙে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Ostrich bird এর Fly() এ exception ছুড়লে LSP ভাঙে&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bird&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ostrich&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Bird&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotSupportedException&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ আলাদা interface&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IFlyable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Sparrow&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IFlyable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Fly&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ostrich&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* Fly নেই */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;লক্ষণ: কোডে বারবার &lt;code&gt;if (x is SpecificType)&lt;/code&gt; বা &lt;code&gt;NotImplementedException&lt;/code&gt; দেখলে LSP সম্ভবত ভাঙছে।&lt;/p&gt;

&lt;h4&gt;
  
  
  I: Interface Segregation Principle (ISP)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;বড় interface ভেঙে ছোট ছোট interface বানান।&lt;/strong&gt; ক্লায়েন্টকে এমন method মানতে বাধ্য করবেন না যা সে ব্যবহার করে না।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ মোটা interface&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IWorker&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Work&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Eat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ ছোট interface&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IWorkable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Work&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IFeedable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Eat&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  D: Dependency Inversion Principle (DIP)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;উচ্চস্তরের মডিউল নিম্নস্তরের concrete ক্লাসের ওপর নির্ভর করবে না; উভয়ই abstraction এর ওপর নির্ভর করবে।&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;উপমা: আপনার ল্যাপটপ চার্জার সরাসরি দেয়ালে ঝালাই করা নেই; মাঝে সকেট (abstraction) আছে, তাই যেকোনো চার্জার লাগে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;IOrderRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;IPaymentMethod&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;INotifier&lt;/span&gt; &lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// সবই abstraction&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;PlaceOrderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PayAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;notifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;এখন unit test এ fake/mock পাস করা যায়, ও production এ আসল implementation।&lt;/p&gt;

&lt;h3&gt;
  
  
  ২.৩ Dependency Injection (DI) ও IoC
&lt;/h3&gt;

&lt;p&gt;DIP হলো নীতি, &lt;strong&gt;DI&lt;/strong&gt; হলো সেটা বাস্তবায়নের কৌশল: dependency নিজে &lt;code&gt;new&lt;/code&gt; না করে বাইরে থেকে ঢুকিয়ে দেওয়া। .NET এ DI built-in।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IOrderRepository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SqlOrderRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPaymentMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BkashPayment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;INotifier&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;EmailNotifier&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lifetime (খুব গুরুত্বপূর্ণ):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lifetime&lt;/th&gt;
&lt;th&gt;মানে&lt;/th&gt;
&lt;th&gt;কখন&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Transient&lt;/td&gt;
&lt;td&gt;প্রতিবার নতুন instance&lt;/td&gt;
&lt;td&gt;হালকা, stateless সার্ভিস&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scoped&lt;/td&gt;
&lt;td&gt;প্রতি HTTP request এ একটা&lt;/td&gt;
&lt;td&gt;DbContext, Unit of Work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Singleton&lt;/td&gt;
&lt;td&gt;পুরো অ্যাপে একটা&lt;/td&gt;
&lt;td&gt;Cache, config, HttpClient factory&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;সাধারণ ভুল (Captive Dependency):&lt;/strong&gt; Singleton এর ভেতরে Scoped service ঢোকানো। Scoped instance আর কখনো ছাড়া পায় না, ফলে DbContext এর পুরনো state ও thread-safety সমস্যা হয়। .NET development mode এ এটা ধরে ফেলে।&lt;/p&gt;

&lt;p&gt;একই interface এর একাধিক implementation লাগলে .NET 8+ এ &lt;strong&gt;Keyed Services&lt;/strong&gt; আছে:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddKeyedScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPaymentMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BkashPayment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"bkash"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddKeyedScoped&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPaymentMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CardPayment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/pay"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nf"&gt;FromKeyedServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bkash"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;IPaymentMethod&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PayAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ২.৪ অন্যান্য মৌলিক নীতি
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DRY (Don't Repeat Yourself):&lt;/strong&gt; একই লজিক ৩ জায়গায় কপি করবেন না। তবে সতর্ক: দুটি কোড দেখতে একই, কিন্তু ভিন্ন কারণে বদলায়, সেগুলো জোর করে এক করলে ক্ষতি হয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KISS (Keep It Simple):&lt;/strong&gt; সহজ সমাধান আগে। জটিল design এর দরকার প্রমাণিত না হওয়া পর্যন্ত নয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YAGNI (You Aren't Gonna Need It):&lt;/strong&gt; "হয়তো ভবিষ্যতে লাগবে" ভেবে ফিচার বানাবেন না।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation of Concerns:&lt;/strong&gt; UI, business logic, data access আলাদা রাখুন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Law of Demeter:&lt;/strong&gt; &lt;code&gt;a.GetB().GetC().DoSomething()&lt;/code&gt; এভাবে চেইন করবেন না; শুধু নিকট বন্ধুর সাথে কথা বলুন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composition over Inheritance:&lt;/strong&gt; inheritance এর গভীর hierarchy এর চেয়ে composition (ক্লাসের ভেতর অন্য ক্লাস ব্যবহার) বেশি নমনীয়।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ২.৫ Design Pattern: পরীক্ষিত সমাধানের রেসিপি
&lt;/h3&gt;

&lt;p&gt;Design pattern হলো বারবার আসা সমস্যার প্রমাণিত সমাধান। তিন ভাগে: Creational (তৈরি), Structural (সাজানো), Behavioral (আচরণ)। নিচে বাস্তবে সবচেয়ে বেশি লাগে এমনগুলো।&lt;/p&gt;

&lt;h4&gt;
  
  
  Strategy: আচরণ বদলানো যায় এমন
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;সমস্যা:&lt;/strong&gt; ShopEasy তে শিপিং খরচের একাধিক নিয়ম (সাধারণ, এক্সপ্রেস, ফ্রি শিপিং)।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IShippingStrategy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;Calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StandardShipping&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IShippingStrategy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;Calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;60m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ExpressShipping&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IShippingStrategy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;Calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;150m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FreeShipping&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IShippingStrategy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;Calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Checkout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IShippingStrategy&lt;/span&gt; &lt;span class="n"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="nf"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Subtotal&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Calculate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;আপনি আগে যে &lt;code&gt;IPaymentMethod&lt;/code&gt; দেখলেন, সেটাও Strategy।&lt;/p&gt;

&lt;h4&gt;
  
  
  Factory: কোন ক্লাস বানাতে হবে সেই সিদ্ধান্ত লুকানো
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ShippingFactory&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IShippingStrategy&lt;/span&gt; &lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;switch&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Subtotal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;5000&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;       &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FreeShipping&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;IsExpress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExpressShipping&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt;                          &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StandardShipping&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Decorator: মূল কোড না ছুঁয়ে আচরণ যোগ
&lt;/h4&gt;

&lt;p&gt;ধরুন প্রতিটি repository call এ caching যোগ করতে চান, কিন্তু মূল ক্লাস বদলাতে চান না।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CachedProductRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IProductRepository&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IMemoryCache&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IProductRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetOrCreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"p:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AbsoluteExpirationRelativeToNow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ASP.NET Core এর &lt;strong&gt;middleware pipeline&lt;/strong&gt; ও Decorator/Chain of Responsibility এর বাস্তব উদাহরণ।&lt;/p&gt;

&lt;h4&gt;
  
  
  Observer / Event: একজনের খবরে অনেকে সাড়া দেয়
&lt;/h4&gt;

&lt;p&gt;অর্ডার হলে ইমেইল যাবে, ইনভেন্টরি কমবে, অ্যানালিটিক্স আপডেট হবে। &lt;code&gt;OrderService&lt;/code&gt; এদের কাউকে চেনে না; শুধু ঘোষণা করে "অর্ডার হয়েছে"।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;OrderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IEventHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendEmailHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEventHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReduceStockHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IEventHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;এই ধারণাই পরে Domain Events ও Message Broker এ বড় আকারে ফিরে আসবে।&lt;/p&gt;

&lt;h4&gt;
  
  
  Repository ও Unit of Work
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Repository:&lt;/strong&gt; ডেটাবেস অ্যাক্সেসের লজিক একটা interface এর পেছনে লুকায়, যাতে business logic জানে না ডেটা SQL এ আছে না MongoDB তে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Unit of Work:&lt;/strong&gt; একাধিক repository এর কাজ একটাই transaction এ কমিট করে (সবকিছু সফল, নয়তো কিছুই না)।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IUnitOfWork&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;সতর্কতা:&lt;/strong&gt; EF Core এর &lt;code&gt;DbContext&lt;/code&gt; নিজেই Repository + Unit of Work। এর ওপর আরেকটা generic &lt;code&gt;IRepository&amp;lt;T&amp;gt;&lt;/code&gt; বসালে অনেক সময় শুধু অকারণ স্তর বাড়ে ও LINQ এর শক্তি হারায়। ছোট/মাঝারি প্রজেক্টে সরাসরি DbContext, অথবা নির্দিষ্ট ও অর্থবহ repository (যেমন &lt;code&gt;IOrderRepository.GetPendingOrders()&lt;/code&gt;) ব্যবহার করুন।&lt;/p&gt;

&lt;h4&gt;
  
  
  Singleton
&lt;/h4&gt;

&lt;p&gt;পুরো অ্যাপে একটাই instance। .NET এ নিজে static singleton লেখার বদলে DI এর &lt;code&gt;AddSingleton&lt;/code&gt; ব্যবহার করুন। Global state লুকিয়ে test কঠিন করে, তাই সাবধান।&lt;/p&gt;

&lt;h4&gt;
  
  
  Builder, Adapter, Facade (সংক্ষেপে)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Builder:&lt;/strong&gt; জটিল অবজেক্ট ধাপে ধাপে বানানো (&lt;code&gt;WebApplication.CreateBuilder&lt;/code&gt; এই pattern)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapter:&lt;/strong&gt; বেমানান interface কে মানানসই করা। যেমন তৃতীয়পক্ষের bKash SDK কে নিজেদের &lt;code&gt;IPaymentMethod&lt;/code&gt; এ মোড়ানো।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facade:&lt;/strong&gt; জটিল সাবসিস্টেমের সামনে সহজ একটা দরজা।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ২.৬ Anti-pattern: যা এড়াবেন
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Anti-pattern&lt;/th&gt;
&lt;th&gt;সমস্যা&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;God Class&lt;/td&gt;
&lt;td&gt;একটা ক্লাস সব জানে ও সব করে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anemic Domain Model&lt;/td&gt;
&lt;td&gt;Entity তে শুধু property, সব লজিক service এ (Part 3 এ আরও)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service Locator&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;serviceProvider.GetService&amp;lt;T&amp;gt;()&lt;/code&gt; ছড়িয়ে দেওয়া; dependency লুকানো থাকে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premature Optimization&lt;/td&gt;
&lt;td&gt;প্রমাণ ছাড়াই "পারফরম্যান্সের জন্য" জটিল করা&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Over-engineering&lt;/td&gt;
&lt;td&gt;৫ ইউজারের অ্যাপে ১০ স্তর&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Magic String/Number&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;"bkash"&lt;/code&gt; ছড়িয়ে থাকা, constant/enum নেই&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  ২.৭ Clean Code এর অভ্যাস (সংক্ষেপে)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;নাম অর্থবহ রাখুন: &lt;code&gt;GetActiveCustomers()&lt;/code&gt;, &lt;code&gt;Get()&lt;/code&gt; নয়।&lt;/li&gt;
&lt;li&gt;ফাংশন ছোট ও একটা কাজের।&lt;/li&gt;
&lt;li&gt;মন্তব্য দিয়ে খারাপ কোড ঢাকবেন না; কোডই ব্যাখ্যা করবে।&lt;/li&gt;
&lt;li&gt;Exception দিয়ে স্বাভাবিক flow control করবেন না।&lt;/li&gt;
&lt;li&gt;Nullable reference types (&lt;code&gt;&amp;lt;Nullable&amp;gt;enable&amp;lt;/Nullable&amp;gt;&lt;/code&gt;) চালু রাখুন।&lt;/li&gt;
&lt;li&gt;Magic value এর বদলে &lt;code&gt;record&lt;/code&gt;, &lt;code&gt;enum&lt;/code&gt;, &lt;code&gt;const&lt;/code&gt;।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Part 2 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;SOLID মানে: ছোট দায়িত্ব, বাড়ানো সহজ, বদলানো নিরাপদ, abstraction এর ওপর নির্ভরতা।&lt;/li&gt;
&lt;li&gt;DI + interface = test করা যায় ও বদলানো যায় এমন কোড।&lt;/li&gt;
&lt;li&gt;Pattern মুখস্থ নয়, সমস্যা চিনে ব্যবহার করুন। সবচেয়ে বেশি কাজে লাগে Strategy, Factory, Decorator, Observer, Repository।&lt;/li&gt;
&lt;li&gt;YAGNI মনে রাখুন: pattern যেন জটিলতা বাড়ানোর অজুহাত না হয়।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 3: Application Architecture: কোড ও সিস্টেম কীভাবে সাজাবেন
&lt;/h2&gt;

&lt;p&gt;এখন প্রশ্ন: ShopEasy এর পুরো প্রজেক্ট কীভাবে সাজালে ১০ জনের টিম একসাথে কাজ করতে পারবে, আর ৫ বছর পরেও কোড বোঝা যাবে? উত্তর নির্ভর করে &lt;strong&gt;আপনার প্রয়োজন ও টিমের আকারের ওপর&lt;/strong&gt;। এখানে প্রতিটি style এর সুবিধা, অসুবিধা ও কখন ব্যবহার করবেন, সব থাকবে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.১ Monolith বনাম Microservices: সবচেয়ে বড় বিতর্ক
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Monolith:&lt;/strong&gt; পুরো অ্যাপ একটাই deployable ইউনিট (একটা &lt;code&gt;.exe&lt;/code&gt;/একটা docker image)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microservices:&lt;/strong&gt; অনেক ছোট ছোট স্বাধীন সার্ভিস, প্রতিটার নিজস্ব ডেটাবেস ও deployment।&lt;/p&gt;

&lt;p&gt;উপমা: Monolith হলো একটা বড় রেস্টুরেন্ট যার একটাই রান্নাঘর। Microservices হলো ফুড কোর্ট যেখানে প্রতিটি দোকান আলাদা, নিজের মতো চলে, কিন্তু সমন্বয়ের ঝামেলা বেশি।&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;বিষয়&lt;/th&gt;
&lt;th&gt;Monolith&lt;/th&gt;
&lt;th&gt;Microservices&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;শুরুতে গতি&lt;/td&gt;
&lt;td&gt;খুব দ্রুত&lt;/td&gt;
&lt;td&gt;ধীর (অনেক সেটআপ)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;একবারে সব&lt;/td&gt;
&lt;td&gt;প্রতিটি আলাদাভাবে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scaling&lt;/td&gt;
&lt;td&gt;পুরোটা একসাথে&lt;/td&gt;
&lt;td&gt;যেটার দরকার শুধু সেটা&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging&lt;/td&gt;
&lt;td&gt;সহজ (একটাই process)&lt;/td&gt;
&lt;td&gt;কঠিন (distributed tracing লাগে)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data consistency&lt;/td&gt;
&lt;td&gt;সহজ (এক transaction)&lt;/td&gt;
&lt;td&gt;কঠিন (eventual consistency, Saga)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;টিম&lt;/td&gt;
&lt;td&gt;ছোট টিমের জন্য ভালো&lt;/td&gt;
&lt;td&gt;অনেক স্বাধীন টিমের জন্য&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;অপারেশন খরচ&lt;/td&gt;
&lt;td&gt;কম&lt;/td&gt;
&lt;td&gt;বেশি (Kubernetes, monitoring, CI/CD)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technology&lt;/td&gt;
&lt;td&gt;একটাই stack&lt;/td&gt;
&lt;td&gt;প্রতিটি আলাদা হতে পারে&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;মূল শিক্ষা:&lt;/strong&gt; অনেক স্টার্টআপ শুরুতেই Microservices বানিয়ে "Distributed Monolith" এ পরিণত হয়, যেখানে microservices এর সব খরচ আছে কিন্তু সুবিধা নেই। &lt;strong&gt;ছোট টিম ও নতুন প্রডাক্ট হলে Modular Monolith দিয়ে শুরু করুন।&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.২ Layered (N-Tier) Architecture
&lt;/h3&gt;

&lt;p&gt;সবচেয়ে পরিচিত, সবচেয়ে পুরনো style। কোডকে স্তরে ভাগ করা:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Presentation (Controllers/UI)
        ↓
Business Logic (Services)
        ↓
Data Access (Repositories/EF Core)
        ↓
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt; ওপরের স্তর নিচেরটাকে ডাকে, উল্টোটা নয়।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ShopEasy.sln
 ├─ ShopEasy.Web        (Controllers)
 ├─ ShopEasy.Business   (Services)
 ├─ ShopEasy.Data       (EF Core, Repositories)
 └─ ShopEasy.Models     (Entities, DTOs)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;সুবিধা:&lt;/strong&gt; সহজ, সবাই চেনে, ছোট অ্যাপে চমৎকার।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;অসুবিধা:&lt;/strong&gt; ধীরে ধীরে Business স্তর Data স্তরের ওপর নির্ভরশীল হয়ে পড়ে (EF Core এর entity সর্বত্র ছড়ায়)। ডেটাবেস বদলানো কঠিন। Domain logic ছড়িয়ে যায়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.৩ Clean Architecture (Onion / Hexagonal এর পরিবার)
&lt;/h3&gt;

&lt;p&gt;Layered এর সমস্যা সমাধান করতে এই পরিবারের জন্ম। তিনটি নামে (Hexagonal/Ports &amp;amp; Adapters, Onion, Clean) মূল ধারণা একই:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Dependency Rule: নির্ভরতা সবসময় ভেতরের দিকে। ভেতরের স্তর বাইরের কিছু জানে না।&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;পেঁয়াজের স্তরের মতো কল্পনা করুন (ভেতর থেকে বাইরে):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Domain&lt;/strong&gt; (কেন্দ্র): Entity, business নিয়ম। কোনো framework এর ওপর নির্ভর করে না।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application:&lt;/strong&gt; Use case (যেমন "অর্ডার দাও")। Interface (port) ঘোষণা করে, যেমন &lt;code&gt;IOrderRepository&lt;/code&gt;।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Infrastructure:&lt;/strong&gt; EF Core, ইমেইল, bKash API। Application এর interface গুলো implement করে (adapter)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Presentation/API&lt;/strong&gt; (বাইরে): Controllers/Minimal API।&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;জাদুটা কোথায়:&lt;/strong&gt; Application স্তর &lt;code&gt;IOrderRepository&lt;/code&gt; interface ঘোষণা করে, আর Infrastructure সেটা বাস্তবায়ন করে। তাই Business logic জানেই না যে SQL Server আছে। কাল MongoDB এ গেলে শুধু Infrastructure বদলাবে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution structure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ShopEasy.sln
 ├─ ShopEasy.Domain          (কোনো dependency নেই)
 ├─ ShopEasy.Application     → Domain
 ├─ ShopEasy.Infrastructure  → Application, Domain
 └─ ShopEasy.Api             → Application, Infrastructure (শুধু DI সাজানোর জন্য)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;কোড উদাহরণ:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Domain&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;OrderStatus&lt;/span&gt; &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pending&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderItem&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderItem&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Items&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Total&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;AddItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;qty&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DomainException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Quantity must be positive"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Confirm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DomainException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Empty order"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confirmed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Application&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Infrastructure&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EfOrderRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;লক্ষ্য করুন &lt;code&gt;Order&lt;/code&gt; এর &lt;code&gt;private set&lt;/code&gt; ও &lt;code&gt;Confirm()&lt;/code&gt; method: business নিয়ম entity এর ভেতরেই। এটাই &lt;strong&gt;Rich Domain Model&lt;/strong&gt;। বিপরীত হলো &lt;strong&gt;Anemic Model&lt;/strong&gt; (শুধু getter/setter, সব লজিক service এ), যেটা এড়ানো ভালো।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কখন Clean Architecture:&lt;/strong&gt; মাঝারি-বড় প্রজেক্ট, জটিল business logic, দীর্ঘমেয়াদি, test সহজ করতে চান।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কখন নয়:&lt;/strong&gt; ছোট CRUD অ্যাপ, প্রোটোটাইপ। অনেক boilerplate ফাইল, ছোট অ্যাপে অপ্রয়োজনীয় জটিলতা।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.৪ Vertical Slice Architecture
&lt;/h3&gt;

&lt;p&gt;Layered এ একটা ফিচার (যেমন "অর্ডার দাও") ছড়িয়ে থাকে চারটা ফোল্ডারে (Controller, Service, Repository, Model)। Vertical Slice এ &lt;strong&gt;ফিচার অনুযায়ী&lt;/strong&gt; কোড সাজানো হয়, প্রতিটি slice এর সবকিছু একসাথে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Features/
 ├─ Orders/
 │   ├─ PlaceOrder/
 │   │   ├─ PlaceOrderCommand.cs
 │   │   ├─ PlaceOrderHandler.cs
 │   │   ├─ PlaceOrderValidator.cs
 │   │   └─ PlaceOrderEndpoint.cs
 │   └─ GetOrder/ ...
 └─ Products/ ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;সুবিধা:&lt;/strong&gt; একটা ফিচার বদলাতে এক জায়গায় কাজ, ছোট ছোট ফিচারে আলাদা সিদ্ধান্ত (সহজ ফিচারে সরাসরি DbContext, জটিলটায় domain model) নেওয়া যায়, টিমে merge conflict কম।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;অসুবিধা:&lt;/strong&gt; slice গুলোর মধ্যে কোড ডুপ্লিকেশনের ঝুঁকি, শৃঙ্খলা না থাকলে অগোছালো।&lt;/p&gt;

&lt;p&gt;ব্যবহারিক পরামর্শ: Clean Architecture এর ভেতরে Application স্তরকে Vertical Slice এ সাজানোও খুব জনপ্রিয়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.৫ CQRS ও MediatR
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CQRS (Command Query Responsibility Segregation):&lt;/strong&gt; ডেটা &lt;strong&gt;পরিবর্তনের&lt;/strong&gt; মডেল (Command) ও &lt;strong&gt;পড়ার&lt;/strong&gt; মডেল (Query) আলাদা রাখা।&lt;/p&gt;

&lt;p&gt;কেন? লেখার সময় আমরা কঠোর নিয়ম, validation, transaction চাই। পড়ার সময় চাই গতি ও সুবিধাজনক আকার (যেমন একটা ড্যাশবোর্ডে ৫টা table জোড়া ডেটা)। দুটোর প্রয়োজন আলাদা।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Level ১ (সহজ, প্রায় সবখানে চলে):&lt;/strong&gt; একই ডেটাবেস, কিন্তু Command ও Query এর কোড আলাদা।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Level ২:&lt;/strong&gt; আলাদা read database (যেমন read এর জন্য denormalized view বা Elasticsearch)। eventual consistency আসে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Command&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;PlaceOrderCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;CustomerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderLineDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PlaceOrderHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IOrderRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IUnitOfWork&lt;/span&gt; &lt;span class="n"&gt;uow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PlaceOrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlaceOrderCommand&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Qty&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Confirm&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;uow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Query: সরাসরি projection, entity লোড না করে&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;GetOrderSummaryQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderSummaryDto&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetOrderSummaryHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GetOrderSummaryQuery&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;OrderSummaryDto&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderSummaryDto&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetOrderSummaryQuery&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderSummaryDto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Total&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;MediatR&lt;/strong&gt; একটা জনপ্রিয় লাইব্রেরি, যা request কে সঠিক handler এ পৌঁছে দেয় ও Pipeline Behavior (validation, logging, transaction এর মতো cross-cutting কাজ) যোগ করার সুযোগ দেয়। কিছু সংস্করণ বাণিজ্যিক লাইসেন্সের আওতায় এসেছে, তাই প্রজেক্টে ব্যবহারের আগে বর্তমান লাইসেন্স নিয়ম দেখে নিন। চাইলে নিজেই সহজ dispatcher লিখতে পারেন, বা Wolverine/Mediator (source generator ভিত্তিক) এর মতো বিকল্প আছে। CQRS এর জন্য MediatR বাধ্যতামূলক নয়।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pipeline Behavior: প্রতিটি command এ স্বয়ংক্রিয় validation&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidationBehavior&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TReq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TRes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IValidator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TReq&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validators&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPipelineBehavior&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TReq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TRes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;TReq&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;notnull&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TReq&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RequestHandlerDelegate&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRes&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;failures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validators&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SelectMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ValidationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;কখন CQRS:&lt;/strong&gt; পড়া ও লেখার প্রয়োজন খুব আলাদা, জটিল domain, read-heavy সিস্টেম। &lt;strong&gt;কখন নয়:&lt;/strong&gt; সাধারণ CRUD।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.৬ Domain-Driven Design (DDD)
&lt;/h3&gt;

&lt;p&gt;DDD হলো জটিল business কে কোডে সঠিকভাবে মডেল করার পদ্ধতি। মূল কথা: &lt;strong&gt;ডেভেলপার ও ব্যবসায়ী একই ভাষায় কথা বলবে, আর কোড সেই ভাষা প্রতিফলিত করবে।&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strategic Design (বড় ছবি):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ubiquitous Language:&lt;/strong&gt; টিমের সবার জন্য একই শব্দভান্ডার। ব্যবসায়ী "Order" বললে কোডেও &lt;code&gt;Order&lt;/code&gt;, &lt;code&gt;Purchase&lt;/code&gt; বা &lt;code&gt;Transaction&lt;/code&gt; নয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bounded Context:&lt;/strong&gt; একটা মডেলের সীমানা। ShopEasy তে "Product" শব্দের অর্থ ভিন্ন: Catalog এ (নাম, ছবি, বর্ণনা), Inventory তে (স্টক সংখ্যা), Shipping এ (ওজন, আকার)। প্রতিটি context এ আলাদা মডেল রাখুন, একটা বিশাল &lt;code&gt;Product&lt;/code&gt; ক্লাস নয়। &lt;strong&gt;Microservices এর সীমানা ঠিক করার সবচেয়ে ভালো দিশা এই Bounded Context।&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Map:&lt;/strong&gt; context গুলোর পারস্পরিক সম্পর্ক (কে কার ওপর নির্ভর করে)।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tactical Design (কোডের building block):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Building block&lt;/th&gt;
&lt;th&gt;অর্থ&lt;/th&gt;
&lt;th&gt;উদাহরণ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Entity&lt;/td&gt;
&lt;td&gt;পরিচয় (ID) আছে, সময়ের সাথে বদলায়&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Order&lt;/code&gt;, &lt;code&gt;Customer&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Value Object&lt;/td&gt;
&lt;td&gt;পরিচয় নেই, মান দিয়ে চেনা, immutable&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Money&lt;/code&gt;, &lt;code&gt;Address&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregate&lt;/td&gt;
&lt;td&gt;সম্পর্কিত object এর গুচ্ছ, একটা consistency সীমানা&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Order&lt;/code&gt; (+ তার &lt;code&gt;OrderItem&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aggregate Root&lt;/td&gt;
&lt;td&gt;aggregate এর একমাত্র প্রবেশদ্বার&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Order&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain Event&lt;/td&gt;
&lt;td&gt;ব্যবসায় যা ঘটেছে&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OrderPlaced&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain Service&lt;/td&gt;
&lt;td&gt;কোনো entity তে না ঢোকা লজিক&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PricingService&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repository&lt;/td&gt;
&lt;td&gt;Aggregate root সংরক্ষণ ও আনা&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IOrderRepository&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Value Object উদাহরণ:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;struct&lt;/span&gt; &lt;span class="nf"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Currency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Money&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt; &lt;span class="p"&gt;+(&lt;/span&gt;&lt;span class="n"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Money&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Currency&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Currency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DomainException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Currency mismatch"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Currency&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;decimal price&lt;/code&gt; এর বদলে &lt;code&gt;Money&lt;/code&gt; ব্যবহার করলে "টাকা + ডলার" যোগ করার ভুল কম্পাইলার/রানটাইমেই ধরা পড়ে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aggregate নিয়ম:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;বাইরের কেউ aggregate এর ভেতরের object সরাসরি বদলাবে না; Root এর মাধ্যমে।&lt;/li&gt;
&lt;li&gt;এক transaction এ &lt;strong&gt;একটাই&lt;/strong&gt; aggregate বদলান।&lt;/li&gt;
&lt;li&gt;aggregate গুলো একে অপরকে শুধু ID দিয়ে চেনে (পুরো object রেফারেন্স নয়)।&lt;/li&gt;
&lt;li&gt;Aggregate ছোট রাখুন।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Domain Event:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Entity&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IDomainEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_events&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IReadOnlyList&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IDomainEvent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DomainEvents&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Raise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDomainEvent&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Order&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Entity&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Confirm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OrderStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Confirmed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;Raise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderConfirmed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c1"&gt;// ঘোষণা, কে শুনবে জানে না&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;কখন DDD:&lt;/strong&gt; জটিল business নিয়ম (ব্যাংকিং, বীমা, লজিস্টিক)। &lt;strong&gt;কখন নয়:&lt;/strong&gt; সাধারণ CRUD বা ডেটা-কেন্দ্রিক অ্যাপ। DDD এর strategic অংশ (Ubiquitous Language, Bounded Context) প্রায় সব প্রজেক্টে কাজে লাগে, tactical অংশ শুধু জটিল domain এ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.৭ Modular Monolith: বাস্তবে সবচেয়ে বুদ্ধিমান শুরু
&lt;/h3&gt;

&lt;p&gt;একটাই deployable, কিন্তু ভেতরে &lt;strong&gt;কঠোর সীমানাসহ স্বাধীন module&lt;/strong&gt; (প্রতিটি Bounded Context একটা module)।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ShopEasy (একটাই অ্যাপ)
 ├─ Modules/Catalog     (নিজের DbContext/schema, public API)
 ├─ Modules/Ordering
 ├─ Modules/Inventory
 └─ Modules/Payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Module গুলো একে অপরের ভেতরের ক্লাস ব্যবহার করবে না; শুধু ঘোষিত public interface/contract বা event এর মাধ্যমে।&lt;/li&gt;
&lt;li&gt;প্রতিটি module এর নিজস্ব ডেটাবেস schema, অন্য module এর table এ সরাসরি JOIN নয়।&lt;/li&gt;
&lt;li&gt;Module এর মধ্যে যোগাযোগ in-process (দ্রুত, সহজ transaction)।&lt;/li&gt;
&lt;li&gt;এই নিয়ম architecture test (যেমন &lt;code&gt;NetArchTest&lt;/code&gt;) দিয়ে স্বয়ংক্রিয়ভাবে প্রয়োগ করুন।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;সুবিধা:&lt;/strong&gt; Monolith এর সরলতা ও Microservices এর পরিষ্কার সীমানা, দুটোই। ভবিষ্যতে কোনো module আলাদা service এ সরানো সহজ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.৮ Microservices বিস্তারিত
&lt;/h3&gt;

&lt;p&gt;যখন প্রয়োজন সত্যিই আছে (বড় টিম, আলাদা scaling, স্বাধীন deployment):&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ভালো microservice এর বৈশিষ্ট্য:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;একটা Bounded Context (ব্যবসায়িক সামর্থ্য) এর মালিক&lt;/li&gt;
&lt;li&gt;নিজস্ব ডেটাবেস (&lt;strong&gt;Database per Service&lt;/strong&gt;; অন্যের DB তে ঢোকা নিষিদ্ধ)&lt;/li&gt;
&lt;li&gt;স্বাধীনভাবে deploy ও scale&lt;/li&gt;
&lt;li&gt;ছোট API/contract এর মাধ্যমে যোগাযোগ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;যোগাযোগের ধরন:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ধরন&lt;/th&gt;
&lt;th&gt;কী&lt;/th&gt;
&lt;th&gt;কখন&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Synchronous (HTTP/gRPC)&lt;/td&gt;
&lt;td&gt;সরাসরি call, উত্তরের জন্য অপেক্ষা&lt;/td&gt;
&lt;td&gt;তাৎক্ষণিক উত্তর লাগে (যেমন দাম জানা)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asynchronous (Message/Event)&lt;/td&gt;
&lt;td&gt;বার্তা পাঠিয়ে এগিয়ে যাওয়া&lt;/td&gt;
&lt;td&gt;ফলাফলের জন্য অপেক্ষা না করলেও চলে (ইমেইল, ইনভেন্টরি আপডেট)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Microservices এর লুকানো খরচ:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network failure, latency, retry, timeout (Part 7)&lt;/li&gt;
&lt;li&gt;Distributed transaction (Saga, Part 6)&lt;/li&gt;
&lt;li&gt;Distributed tracing ও কেন্দ্রীয় logging (Part 9)&lt;/li&gt;
&lt;li&gt;সংস্করণ সামঞ্জস্য (contract versioning)&lt;/li&gt;
&lt;li&gt;বেশি infrastructure ও DevOps দক্ষতা&lt;/li&gt;
&lt;li&gt;Testing এর জটিলতা (contract test, integration test)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Microservices এ যাওয়ার আগে চেকলিস্ট:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] টিম কি একাধিক স্বাধীন দলে ভাগ হয়েছে?&lt;/li&gt;
&lt;li&gt;[ ] আলাদা অংশের scaling এর প্রয়োজন সত্যিই ভিন্ন?&lt;/li&gt;
&lt;li&gt;[ ] Monolith এর deployment কি টিমের গতির বাধা?&lt;/li&gt;
&lt;li&gt;[ ] CI/CD, monitoring, container এর পরিপক্কতা আছে?&lt;/li&gt;
&lt;li&gt;[ ] Bounded Context পরিষ্কারভাবে চেনা গেছে?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;একটাও "না" হলে সম্ভবত এখনও সময় হয়নি।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strangler Fig Pattern:&lt;/strong&gt; পুরনো Monolith একবারে ফেলে নতুন বানানোর (Big Bang rewrite) ঝুঁকি এড়াতে ধীরে ধীরে একটা একটা ফিচার নতুন service এ সরান, সামনে একটা proxy/gateway দিয়ে ট্রাফিক ভাগ করুন, শেষে পুরনোটা আপনাআপনি ফাঁকা হয়ে যায়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.৯ Event-Driven Architecture (EDA)
&lt;/h3&gt;

&lt;p&gt;সার্ভিসগুলো সরাসরি একে অপরকে call না করে &lt;strong&gt;event&lt;/strong&gt; প্রকাশ করে; আগ্রহীরা শোনে ও সাড়া দেয়।&lt;/p&gt;

&lt;p&gt;ShopEasy তে: &lt;code&gt;Ordering&lt;/code&gt; প্রকাশ করল &lt;code&gt;OrderPlaced&lt;/code&gt;। &lt;code&gt;Inventory&lt;/code&gt; শুনে স্টক কমাল, &lt;code&gt;Notification&lt;/code&gt; ইমেইল পাঠাল, &lt;code&gt;Analytics&lt;/code&gt; হিসাব রাখল। Ordering এদের কাউকে চেনেই না, নতুন কেউ যোগ হলেও Ordering বদলাতে হয় না (loose coupling)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event এর ধরন:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event Notification:&lt;/strong&gt; "কিছু ঘটেছে" (ছোট বার্তা, দরকারে শ্রোতা জিজ্ঞেস করবে)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-Carried State Transfer:&lt;/strong&gt; event এ প্রয়োজনীয় ডেটাও থাকে (শ্রোতার আর ফেরত call লাগে না)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event Sourcing:&lt;/strong&gt; বর্তমান অবস্থা না রেখে &lt;strong&gt;ঘটনার ধারাবাহিক তালিকা&lt;/strong&gt; রাখা; যেকোনো সময়ের অবস্থা ঘটনাগুলো আবার চালিয়ে বের করা যায় (ব্যাংকের লেজারের মতো)। অডিট ও ইতিহাসে চমৎকার, কিন্তু জটিল; সবার জন্য নয়।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;সুবিধা:&lt;/strong&gt; loose coupling, সহজে নতুন কনজিউমার, প্রবল scalability। &lt;strong&gt;অসুবিধা:&lt;/strong&gt; প্রবাহ বোঝা ও debug কঠিন, eventual consistency, বার্তার ক্রম ও ডুপ্লিকেট সামলানো (Part 6)।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.১০ Serverless ও অন্যান্য style
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Serverless (Azure Functions, AWS Lambda):&lt;/strong&gt; server পরিচালনা না করে শুধু ফাংশন চালান, ব্যবহার অনুযায়ী বিল। সুবিধা: শূন্য ট্রাফিকে খরচ শূন্য, স্বয়ংক্রিয় scale। অসুবিধা: cold start, চলার সময়সীমা, vendor lock-in, স্থানীয় debug কঠিন। event-triggered কাজে (ছবি resize, scheduled job) দারুণ।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SOA (Service-Oriented Architecture):&lt;/strong&gt; Microservices এর পূর্বসূরি; বড় ও কেন্দ্রীয় bus (ESB) নির্ভর।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microkernel / Plugin:&lt;/strong&gt; ছোট কোর + প্লাগইন (VS Code এর মতো)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend for Frontend (BFF):&lt;/strong&gt; প্রতিটি ক্লায়েন্টের (web, mobile) জন্য আলাদা ছোট backend, যা ক্লায়েন্টের প্রয়োজনমতো ডেটা সাজায়।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৩.১১ কোন architecture কখন: সিদ্ধান্তের গাইড
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;পরিস্থিতি&lt;/th&gt;
&lt;th&gt;সুপারিশ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;১-৩ জনের টিম, নতুন প্রডাক্ট, MVP&lt;/td&gt;
&lt;td&gt;সরল Layered বা Vertical Slice Monolith&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;সাধারণ CRUD, অ্যাডমিন প্যানেল&lt;/td&gt;
&lt;td&gt;Layered, ন্যূনতম pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;জটিল business, দীর্ঘমেয়াদি&lt;/td&gt;
&lt;td&gt;Clean Architecture + DDD (tactical)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;৫-২০ জন, একাধিক ডোমেইন&lt;/td&gt;
&lt;td&gt;Modular Monolith&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;২০+ জন, স্বাধীন টিম, ভিন্ন scaling&lt;/td&gt;
&lt;td&gt;Microservices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ফাইল/ইভেন্ট ট্রিগার করা ছোট কাজ&lt;/td&gt;
&lt;td&gt;Serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read ও write এর চাহিদা অনেক আলাদা&lt;/td&gt;
&lt;td&gt;CQRS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;অডিট/ইতিহাস অপরিহার্য&lt;/td&gt;
&lt;td&gt;Event Sourcing (সতর্কভাবে)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;সোনালি নিয়ম:&lt;/strong&gt; সবচেয়ে সরল যা প্রয়োজন মেটায় তা দিয়ে শুরু করুন। যখন ব্যথা অনুভব করবেন, তখনই জটিলতা যোগ করুন, আগে নয়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৩.১২ ShopEasy তে প্রয়োগ
&lt;/h3&gt;

&lt;p&gt;রাফির টিম এখন ৮ জন। সিদ্ধান্ত: Microservices নয়, &lt;strong&gt;Modular Monolith&lt;/strong&gt; (Catalog, Ordering, Inventory, Payments)। প্রতিটি module Clean Architecture ধাঁচে, জটিল Ordering এ DDD, রিপোর্টিং এ CQRS এর পড়ার দিক। Module এর মধ্যে যোগাযোগ interface ও in-process event দিয়ে। এতে সবার কাজ আলাদা, ডেপ্লয় সহজ, আর ভবিষ্যতে Payments আলাদা service করা যাবে।&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 3 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Architecture মানে trade-off; "সেরা" নেই, "উপযুক্ত" আছে।&lt;/li&gt;
&lt;li&gt;Layered সহজ; Clean Architecture দীর্ঘমেয়াদি test-যোগ্য কোডের জন্য; Vertical Slice ফিচার-কেন্দ্রিক।&lt;/li&gt;
&lt;li&gt;CQRS: পড়া-লেখার মডেল আলাদা; DDD: জটিল business মডেল করা; Bounded Context: সীমানা।&lt;/li&gt;
&lt;li&gt;Modular Monolith বেশিরভাগ ক্ষেত্রে সবচেয়ে বাস্তবসম্মত শুরু।&lt;/li&gt;
&lt;li&gt;Microservices এর সুবিধা বাস্তব, কিন্তু খরচও বিশাল; প্রয়োজন প্রমাণিত হলে তবেই।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 4: Database Design: ডেটা সংরক্ষণ ও দ্রুত অ্যাক্সেস
&lt;/h2&gt;

&lt;p&gt;বাস্তবে বেশিরভাগ system এর বাধা application কোড নয়, &lt;strong&gt;database&lt;/strong&gt;। ShopEasy এর পেজ ধীর হওয়ার ৮০% কারণ ছিল খারাপ query ও index এর অভাব। এই Part সেই জায়গায় আপনাকে শক্ত করবে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৪.১ SQL বনাম NoSQL
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Relational (SQL):&lt;/strong&gt; table, row, column, সম্পর্ক (foreign key), শক্তিশালী transaction। (SQL Server, PostgreSQL, MySQL)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NoSQL:&lt;/strong&gt; একাধিক ধরন:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ধরন&lt;/th&gt;
&lt;th&gt;উদাহরণ&lt;/th&gt;
&lt;th&gt;কখন&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Document&lt;/td&gt;
&lt;td&gt;MongoDB, Cosmos DB&lt;/td&gt;
&lt;td&gt;নমনীয় কাঠামো, product catalog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key-Value&lt;/td&gt;
&lt;td&gt;Redis, DynamoDB&lt;/td&gt;
&lt;td&gt;cache, session, দ্রুত lookup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wide-Column&lt;/td&gt;
&lt;td&gt;Cassandra&lt;/td&gt;
&lt;td&gt;বিপুল লেখা, time-series&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graph&lt;/td&gt;
&lt;td&gt;Neo4j&lt;/td&gt;
&lt;td&gt;সম্পর্ক-কেন্দ্রিক (বন্ধুর বন্ধু)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search&lt;/td&gt;
&lt;td&gt;Elasticsearch&lt;/td&gt;
&lt;td&gt;full-text search&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;সিদ্ধান্তের নিয়ম:&lt;/strong&gt; সন্দেহ হলে &lt;strong&gt;Relational দিয়ে শুরু করুন&lt;/strong&gt; (PostgreSQL বা SQL Server)। সম্পর্ক, transaction ও আড-হক query এ এর শক্তি অসাধারণ। NoSQL নিন যখন নির্দিষ্ট প্রয়োজন আছে (বিপুল scale, নমনীয় schema, বিশেষ ডেটা মডেল)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Polyglot Persistence:&lt;/strong&gt; একই সিস্টেমে ভিন্ন কাজে ভিন্ন DB। ShopEasy: অর্ডার ও পেমেন্ট SQL এ, পণ্য সার্চ Elasticsearch এ, cart ও session Redis এ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৪.২ ডেটাবেস ডিজাইনের মূলনীতি
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Normalization
&lt;/h4&gt;

&lt;p&gt;ডুপ্লিকেট ডেটা সরানোর প্রক্রিয়া।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;খারাপ (সব একটা table এ):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OrderId&lt;/th&gt;
&lt;th&gt;CustomerName&lt;/th&gt;
&lt;th&gt;CustomerPhone&lt;/th&gt;
&lt;th&gt;Product&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;রাফি&lt;/td&gt;
&lt;td&gt;0171...&lt;/td&gt;
&lt;td&gt;Phone&lt;/td&gt;
&lt;td&gt;20000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;রাফি&lt;/td&gt;
&lt;td&gt;0171...&lt;/td&gt;
&lt;td&gt;Case&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;রাফির ফোন বদলালে সব row আপডেট করতে হবে; একটা ভুলে গেলে ডেটা অসঙ্গত।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ভালো:&lt;/strong&gt; &lt;code&gt;Customers&lt;/code&gt;, &lt;code&gt;Orders&lt;/code&gt;, &lt;code&gt;OrderItems&lt;/code&gt;, &lt;code&gt;Products&lt;/code&gt; আলাদা table, ID দিয়ে সংযুক্ত।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;1NF:&lt;/strong&gt; প্রতিটি cell এ একটাই মান (কমা দিয়ে একাধিক মান নয়)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2NF:&lt;/strong&gt; Composite key এর অংশের ওপর আংশিক নির্ভরতা নেই&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3NF:&lt;/strong&gt; Non-key column শুধু key এর ওপর নির্ভর করে, অন্য non-key এর ওপর নয়&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Denormalization
&lt;/h4&gt;

&lt;p&gt;পড়ার গতির জন্য ইচ্ছাকৃতভাবে কিছু ডুপ্লিকেট রাখা (যেমন Order এ &lt;code&gt;CustomerName&lt;/code&gt; এর কপি)। Read-heavy সিস্টেমে কাজে লাগে, তবে সংগতি রাখার দায় আপনার। &lt;strong&gt;নিয়ম:&lt;/strong&gt; আগে normalize করুন, প্রমাণিত দরকারে denormalize।&lt;/p&gt;

&lt;h4&gt;
  
  
  Primary Key এর পছন্দ
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Auto-increment int/bigint:&lt;/strong&gt; সহজ, ছোট, দ্রুত; কিন্তু আন্দাজযোগ্য (&lt;code&gt;/orders/5&lt;/code&gt; এর পর &lt;code&gt;/orders/6&lt;/code&gt;), একাধিক DB তে মেলানো কঠিন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GUID (UUID):&lt;/strong&gt; distributed এ স্বাধীনভাবে তৈরি করা যায়; কিন্তু random GUID clustered index এ page split ঘটিয়ে ধীর করে। সমাধান: sequential GUID (.NET 9 এ &lt;code&gt;Guid.CreateVersion7()&lt;/code&gt;) বা ULID।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ডেটা নিরাপত্তায়:&lt;/strong&gt; বাইরের API তে ধারাবাহিক ID প্রকাশ করলে ডেটা গণনা করা সহজ হয়; প্রয়োজনে public ID আলাদা রাখুন।&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Data Type বাছাই
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;টাকা: &lt;code&gt;decimal&lt;/code&gt; (কখনোই &lt;code&gt;float/double&lt;/code&gt; নয়, ভগ্নাংশ ভুল হয়)&lt;/li&gt;
&lt;li&gt;সময়: UTC তে &lt;code&gt;DateTimeOffset&lt;/code&gt;/&lt;code&gt;datetime2&lt;/code&gt; সংরক্ষণ করুন&lt;/li&gt;
&lt;li&gt;Unicode (বাংলা) এর জন্য &lt;code&gt;nvarchar&lt;/code&gt; (SQL Server) বা UTF-8 (PostgreSQL)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৪.৩ Index: দ্রুত query এর চাবিকাঠি
&lt;/h3&gt;

&lt;p&gt;বইয়ের শেষের সূচিপত্র (index) এর মতো। সূচি না থাকলে একটা শব্দ খুঁজতে পুরো বই পড়তে হয় (&lt;strong&gt;Full Table Scan&lt;/strong&gt;, O(n))। সূচি থাকলে সরাসরি পাতায় যাওয়া যায় (B-Tree, O(log n))।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- ১০ লক্ষ order এ এই query ধীর (scan)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;CustomerId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- index দিলে দ্রুত (seek)&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IX_Orders_CustomerId&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Index এর ধরন:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clustered:&lt;/strong&gt; ডেটা যে ক্রমে ডিস্কে সাজানো (টেবিলে একটাই; সাধারণত PK)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-clustered:&lt;/strong&gt; আলাদা সূচি যা মূল ডেটার দিকে ইঙ্গিত করে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composite:&lt;/strong&gt; একাধিক column (ক্রম গুরুত্বপূর্ণ)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Covering:&lt;/strong&gt; query এর সব দরকারি column index এই থাকে (&lt;code&gt;INCLUDE&lt;/code&gt;), মূল table এ যেতে হয় না&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unique, Filtered/Partial:&lt;/strong&gt; বিশেষ ক্ষেত্রে&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Composite index এর leftmost নিয়ম:&lt;/strong&gt; &lt;code&gt;(CustomerId, Status)&lt;/code&gt; index টি &lt;code&gt;WHERE CustomerId = ?&lt;/code&gt; ও &lt;code&gt;WHERE CustomerId = ? AND Status = ?&lt;/code&gt; এ কাজ করে, কিন্তু শুধু &lt;code&gt;WHERE Status = ?&lt;/code&gt; এ কাজে লাগে না।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index এর দাম:&lt;/strong&gt; প্রতিটি index পড়া দ্রুত করে, কিন্তু লেখা (INSERT/UPDATE/DELETE) ধীর ও জায়গা বেশি লাগায়। তাই সব column এ index দেবেন না। যে column গুলো &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;JOIN&lt;/code&gt;, &lt;code&gt;ORDER BY&lt;/code&gt; এ ঘনঘন আসে, সেগুলোতে দিন।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index নষ্ট করে যে ভুলগুলো:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nb"&gt;YEAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreatedAt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2026&lt;/span&gt;     &lt;span class="c1"&gt;-- column এ function: index কাজ করে না&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'%rafi'&lt;/span&gt;          &lt;span class="c1"&gt;-- শুরুতে wildcard: scan&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;Phone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1711111111&lt;/span&gt;         &lt;span class="c1"&gt;-- type mismatch (string কে number এর সাথে)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ঠিক করুন: &lt;code&gt;WHERE CreatedAt &amp;gt;= '2026-01-01' AND CreatedAt &amp;lt; '2027-01-01'&lt;/code&gt;।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution Plan&lt;/strong&gt; পড়তে শিখুন (SSMS এ "Include Actual Execution Plan", PostgreSQL এ &lt;code&gt;EXPLAIN ANALYZE&lt;/code&gt;)। "Index Seek" ভালো, "Table Scan" ছোট table ছাড়া সন্দেহজনক।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৪.৪ Transaction ও ACID
&lt;/h3&gt;

&lt;p&gt;উপমা: ব্যাংক ট্রান্সফার। ১০০০ টাকা A থেকে কেটে B তে যোগ হবে। মাঝপথে সার্ভার ক্র্যাশ করলে? টাকা উধাও হওয়া চলবে না।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Atomicity:&lt;/strong&gt; সব সফল নয়তো কিছুই নয়&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistency:&lt;/strong&gt; ডেটা সবসময় বৈধ অবস্থা থেকে বৈধ অবস্থায় যায় (constraint মানা হয়)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation:&lt;/strong&gt; একসাথে চলা transaction একে অপরকে বিভ্রান্ত করে না&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Durability:&lt;/strong&gt; কমিট হলে ক্র্যাশেও ডেটা থাকে
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BeginTransactionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Balance&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Balance&lt;/span&gt;   &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CommitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RollbackAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;SaveChangesAsync()&lt;/code&gt; একা নিজেই একটা transaction।)&lt;/p&gt;

&lt;h4&gt;
  
  
  Isolation Level ও সমস্যা
&lt;/h4&gt;

&lt;p&gt;একসাথে অনেকে ডেটা বদলালে যা ঘটতে পারে:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dirty Read:&lt;/strong&gt; কমিট না হওয়া ডেটা পড়া&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-repeatable Read:&lt;/strong&gt; একই transaction এ দুবার পড়ে ভিন্ন মান&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phantom Read:&lt;/strong&gt; একই query তে দ্বিতীয়বার নতুন row দেখা যায়&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Dirty&lt;/th&gt;
&lt;th&gt;Non-repeatable&lt;/th&gt;
&lt;th&gt;Phantom&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Read Uncommitted&lt;/td&gt;
&lt;td&gt;সম্ভব&lt;/td&gt;
&lt;td&gt;সম্ভব&lt;/td&gt;
&lt;td&gt;সম্ভব&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read Committed (সাধারণ default)&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;সম্ভব&lt;/td&gt;
&lt;td&gt;সম্ভব&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeatable Read&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;সম্ভব&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serializable&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;td&gt;না&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;উচ্চ isolation নিরাপদ, কিন্তু ধীর ও deadlock এর ঝুঁকি বেশি। SQL Server এ &lt;strong&gt;Read Committed Snapshot Isolation (RCSI)&lt;/strong&gt; ও PostgreSQL এ MVCC পড়াকে লেখা থেকে আলাদা রেখে ভালো পারফরম্যান্স দেয়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৪.৫ Concurrency নিয়ন্ত্রণ: ShopEasy এর "শেষ ১টা পণ্য" সমস্যা
&lt;/h3&gt;

&lt;p&gt;দুজন একসাথে শেষ ফোনটা কিনছে। দুজনেই দেখল স্টক = ১। দুজনেই অর্ডার করল। স্টক হলো -১! একে &lt;strong&gt;Lost Update / Race Condition&lt;/strong&gt; বলে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;১. Pessimistic Locking:&lt;/strong&gt; পড়ার সময়ই row লক করা; অন্যরা অপেক্ষা করে। নিরাপদ, কিন্তু ধীর ও deadlock ঝুঁকি।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;২. Optimistic Concurrency (EF Core এ জনপ্রিয়):&lt;/strong&gt; লক নেই; সংরক্ষণের সময় দেখা হয় অন্য কেউ ইতোমধ্যে বদলেছে কি না।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Stock&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Timestamp&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;RowVersion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;!;&lt;/span&gt;   &lt;span class="c1"&gt;// SQL Server&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stock&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DbUpdateConcurrencyException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// কেউ আগে বদলে ফেলেছে; আবার পড়ে পুনরায় চেষ্টা করুন, বা ব্যবহারকারীকে জানান&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;৩. Atomic আপডেট:&lt;/strong&gt; সবচেয়ে সহজ ও কার্যকর অনেক সময়।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stock&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteUpdateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stock&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Conflict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Out of stock"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;এক SQL এ "যদি স্টক থাকে, তবে কমাও", ফলে দুজন একসাথে পারে না।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৪.৬ ORM: EF Core বনাম Dapper
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;বিষয়&lt;/th&gt;
&lt;th&gt;EF Core&lt;/th&gt;
&lt;th&gt;Dapper&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ধরন&lt;/td&gt;
&lt;td&gt;পূর্ণ ORM&lt;/td&gt;
&lt;td&gt;Micro-ORM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL লেখা&lt;/td&gt;
&lt;td&gt;LINQ দিয়ে&lt;/td&gt;
&lt;td&gt;নিজে লেখেন&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change tracking&lt;/td&gt;
&lt;td&gt;আছে&lt;/td&gt;
&lt;td&gt;নেই&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Migration&lt;/td&gt;
&lt;td&gt;আছে&lt;/td&gt;
&lt;td&gt;নেই&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;গতি&lt;/td&gt;
&lt;td&gt;ভালো (সঠিক ব্যবহারে)&lt;/td&gt;
&lt;td&gt;সর্বোচ্চ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;কখন&lt;/td&gt;
&lt;td&gt;সাধারণ CRUD, domain model&lt;/td&gt;
&lt;td&gt;জটিল রিপোর্ট, গতি-সংবেদনশীল query&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;বাস্তব পরামর্শ:&lt;/strong&gt; একসাথে দুটো ব্যবহার করা যায়: লেখার জন্য EF Core, জটিল read query তে Dapper বা raw SQL।&lt;/p&gt;

&lt;h4&gt;
  
  
  EF Core এর সাধারণ সমস্যা ও সমাধান
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;১. N+1 Query সমস্যা (সবচেয়ে কুখ্যাত):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ ১টা query orders এর জন্য + প্রতিটি order এর জন্য আরও ১টা = N+1&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;     &lt;span class="c1"&gt;// lazy loading এ প্রতিবার DB hit&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ একটা query তে&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ আরও ভালো: শুধু যা দরকার&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ItemCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;১০০০ অর্ডার হলে আগেরটা ১০০১টা DB call; পরেরটা ১টা।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;২. শুধু পড়ার জন্য &lt;code&gt;AsNoTracking()&lt;/code&gt;:&lt;/strong&gt; change tracking এর খরচ বাঁচে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;৩. পুরো entity না এনে &lt;code&gt;Select&lt;/code&gt; projection:&lt;/strong&gt; ১০টা column লাগলে ৫০টা আনবেন না।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;৪. Pagination ছাড়া সব ডেটা আনা:&lt;/strong&gt; &lt;code&gt;.Take()/.Skip()&lt;/code&gt; বা Keyset pagination ব্যবহার করুন (Part 5)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;৫. &lt;code&gt;ToList()&lt;/code&gt; আগে filter পরে:&lt;/strong&gt; ❌ &lt;code&gt;db.Orders.ToList().Where(...)&lt;/code&gt; পুরো table মেমরিতে আনে। ✅ &lt;code&gt;Where&lt;/code&gt; আগে, &lt;code&gt;ToList&lt;/code&gt; শেষে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;৬. Cartesian Explosion:&lt;/strong&gt; একাধিক collection এ &lt;code&gt;Include&lt;/code&gt; করলে row সংখ্যা গুণ হয়। সমাধান &lt;code&gt;AsSplitQuery()&lt;/code&gt;।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;৭. Compiled Query, Bulk অপারেশন:&lt;/strong&gt; &lt;code&gt;ExecuteUpdate&lt;/code&gt;/&lt;code&gt;ExecuteDelete&lt;/code&gt; দিয়ে বড় আপডেট; বিপুল insert এ &lt;code&gt;EFCore.BulkExtensions&lt;/code&gt; জাতীয় লাইব্রেরি।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;৮. Migration:&lt;/strong&gt; schema পরিবর্তন কোডে ভার্সন করুন (&lt;code&gt;dotnet ef migrations add ...&lt;/code&gt;)। Production এ সরাসরি অ্যাপ চালু হওয়ার সময় migrate না করে CI/CD pipeline এ আলাদা ধাপ বা script হিসেবে চালানো নিরাপদ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৪.৭ বড় scale এর কৌশল
&lt;/h3&gt;

&lt;p&gt;ShopEasy তে ডেটা ও ট্রাফিক বাড়ছে; এক DB সার্ভার হাঁপিয়ে উঠছে। ধাপে ধাপে:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ধাপ ১: Query ও Index ঠিক করুন, Cache যোগ করুন।&lt;/strong&gt; (৯০% সমস্যা এখানেই মেটে।)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ধাপ ২: Vertical scaling:&lt;/strong&gt; বড় সার্ভার।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ধাপ ৩: Read Replica (Replication):&lt;/strong&gt; মূল DB (Primary) তে লেখা, কপি (Replica) গুলোতে পড়া।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Primary → Replica এ ডেটা অনুলিপি হয় (সাধারণত async)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replication lag:&lt;/strong&gt; সাময়িক পুরনো ডেটা (eventual consistency)&lt;/li&gt;
&lt;li&gt;Read-heavy অ্যাপে (বেশিরভাগ ওয়েব) বিরাট সুবিধা&lt;/li&gt;
&lt;li&gt;Primary ফেল করলে Replica কে Primary বানানো যায় (failover, high availability)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// পড়ার জন্য আলাদা connection string&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WriteDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;primaryConn&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ReadDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;replicaConn&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(এটাই CQRS এর বাস্তব ব্যবহারের একটা রূপ।)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ধাপ ৪: Partitioning:&lt;/strong&gt; একটা বিশাল table কে ছোট ভাগে ভাঙা (একই DB সার্ভারে)। যেমন &lt;code&gt;Orders&lt;/code&gt; কে মাস অনুযায়ী ভাগ। পুরনো ডেটা আর্কাইভ সহজ, query দ্রুত।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ধাপ ৫: Sharding (Horizontal Partitioning):&lt;/strong&gt; ডেটা একাধিক &lt;strong&gt;আলাদা DB সার্ভারে&lt;/strong&gt; ভাগ। যেমন ইউজার ID অনুযায়ী: ১-১০ লক্ষ Shard-A তে, ১০-২০ লক্ষ Shard-B তে।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shard key&lt;/strong&gt; বাছাই সবচেয়ে গুরুত্বপূর্ণ সিদ্ধান্ত; খারাপ key এ কিছু shard এ চাপ জমে (hot shard)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Range-based:&lt;/strong&gt; ID এর পরিসর অনুযায়ী (সহজ, কিন্তু hot spot ঝুঁকি)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hash-based:&lt;/strong&gt; ID এর hash দিয়ে (সমানভাবে ছড়ায়, কিন্তু range query কঠিন)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Directory-based:&lt;/strong&gt; একটা lookup table বলে দেয় কোন ডেটা কোথায়&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Hashing:&lt;/strong&gt; shard যোগ/বাদ দিলে কম ডেটা সরাতে হয়&lt;/li&gt;
&lt;li&gt;দাম: shard পেরিয়ে JOIN ও transaction কঠিন বা অসম্ভব; জটিলতা বিপুল&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;সোনালি নিয়ম:&lt;/strong&gt; Sharding শেষ অস্ত্র। প্রথমে index, cache, replica, partitioning ও ডেটা আর্কাইভ সব চেষ্টা করুন।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৪.৮ ডেটা আর্কাইভ, Soft Delete ও Audit
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Soft Delete:&lt;/strong&gt; &lt;code&gt;IsDeleted&lt;/code&gt; ফ্ল্যাগ; EF Core এর Global Query Filter দিয়ে স্বয়ংক্রিয়ভাবে লুকানো যায়। গোপনীয়তা আইনে (যেমন ইউজার ডেটা মুছে ফেলার অনুরোধ) সতর্ক থাকুন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Trail:&lt;/strong&gt; কে, কখন, কী বদলাল। &lt;code&gt;CreatedAt/By&lt;/code&gt;, &lt;code&gt;UpdatedAt/By&lt;/code&gt; বা আলাদা audit table। SQL Server এ Temporal Table আছে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ডেটা সংরক্ষণ নীতি (Retention):&lt;/strong&gt; পুরনো লগ/ডেটা কতদিন রাখবেন তা ঠিক করুন।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৪.৯ Backup, Recovery ও Migration কৌশল
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RPO (Recovery Point Objective):&lt;/strong&gt; সর্বোচ্চ কতটুকু ডেটা হারানো সহ্য করবেন (যেমন ৫ মিনিট)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RTO (Recovery Time Objective):&lt;/strong&gt; কত সময়ে পুনরায় চালু করতে হবে (যেমন ১ ঘণ্টা)&lt;/li&gt;
&lt;li&gt;নিয়মিত backup নিন এবং &lt;strong&gt;restore পরীক্ষা করুন&lt;/strong&gt;। যে backup কখনো restore করে দেখা হয়নি, সেটা backup নয়, আশা।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-downtime migration:&lt;/strong&gt; Expand → Migrate → Contract পদ্ধতি। নতুন column আগে যোগ করুন (নতুন ও পুরনো কোড দুটোই চলে), ডেটা সরান, শেষে পুরনোটা সরান। এক ধাপে column এর নাম বদলালে ডেপ্লয়ের সময় পুরনো কোড ভাঙে।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Part 4 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;সন্দেহে Relational; প্রয়োজন বুঝে NoSQL; Polyglot হতে পারে।&lt;/li&gt;
&lt;li&gt;Index পড়া দ্রুত করে কিন্তু লেখা ধীর করে; execution plan পড়ুন।&lt;/li&gt;
&lt;li&gt;Concurrency সামলান: atomic update বা optimistic concurrency।&lt;/li&gt;
&lt;li&gt;N+1, &lt;code&gt;AsNoTracking&lt;/code&gt;, projection, pagination: EF Core এর মৌলিক পারফরম্যান্স অভ্যাস।&lt;/li&gt;
&lt;li&gt;Scale এর ক্রম: query/index → cache → replica → partition → shard।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 5: API Design: সিস্টেমের মুখ
&lt;/h2&gt;

&lt;p&gt;API হলো আপনার সিস্টেমের সাথে বাইরের জগতের চুক্তি। একবার প্রকাশ করলে বদলানো কঠিন, কারণ মোবাইল অ্যাপ, পার্টনার সবাই এর ওপর নির্ভর করে। তাই শুরু থেকেই ভালোভাবে ডিজাইন করুন।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.১ REST এর মূলকথা
&lt;/h3&gt;

&lt;p&gt;REST একটা architectural style: &lt;strong&gt;resource কেন্দ্রিক&lt;/strong&gt;। সবকিছু একটা "জিনিস" (noun), তার ওপর HTTP method দিয়ে কাজ।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ভালো URL ডিজাইন:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;কাজ&lt;/th&gt;
&lt;th&gt;❌ খারাপ&lt;/th&gt;
&lt;th&gt;✅ ভালো&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;সব অর্ডার&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /getAllOrders&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /orders&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;একটা অর্ডার&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /getOrder?id=5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /orders/5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;নতুন অর্ডার&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /createOrder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /orders&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;আপডেট&lt;/td&gt;
&lt;td&gt;&lt;code&gt;POST /updateOrder&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PUT /orders/5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;মুছুন&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /deleteOrder/5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;DELETE /orders/5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;অর্ডারের আইটেম&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /getOrderItems/5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;GET /orders/5/items&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt; বহুবচন noun, ক্রিয়া নয়; ছোট হাতের অক্ষর ও hyphen; নেস্টিং ২ স্তরের বেশি নয়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;সঠিক Status Code ফেরত দিন:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;201 Created&lt;/code&gt; + &lt;code&gt;Location&lt;/code&gt; header নতুন resource তৈরিতে&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;204 No Content&lt;/code&gt; সফল কিন্তু ফেরত দেওয়ার কিছু নেই&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;400&lt;/code&gt; ভুল ইনপুট, &lt;code&gt;404&lt;/code&gt; পাওয়া যায়নি, &lt;code&gt;409&lt;/code&gt; সংঘর্ষ (conflict), &lt;code&gt;422&lt;/code&gt; যাচাই ব্যর্থ&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;401&lt;/code&gt; পরিচয় নেই (login করেনি), &lt;code&gt;403&lt;/code&gt; পরিচয় আছে কিন্তু অনুমতি নেই&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;429&lt;/code&gt; অনেক বেশি request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;৫০০ কখনো নিজে ছুড়বেন না কোনো স্বাভাবিক ব্যবসায়িক ভুলের জন্য।&lt;/strong&gt; ৫০০ মানে "আমাদের সার্ভারে সমস্যা"।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.২ ASP.NET Core তে API: Minimal API বনাম Controller
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Minimal API (আধুনিক, কম boilerplate):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/v1/orders"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{id:int}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IMediator&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;GetOrderSummaryQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PlaceOrderCommand&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IMediator&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"/api/v1/orders/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Controller:&lt;/strong&gt; বড় প্রজেক্টে সুপরিচিত কাঠামো, filter, model binding এর সুবিধা।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/v1/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMediator&lt;/span&gt; &lt;span class="n"&gt;mediator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{id:int}"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderSummaryDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;mediator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;GetOrderSummaryQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;দুটোই ঠিক; টিমের পছন্দ ও প্রজেক্ট বুঝে বেছে নিন। &lt;strong&gt;&lt;code&gt;CancellationToken&lt;/code&gt;&lt;/strong&gt; সবসময় পাস করুন: ক্লায়েন্ট সংযোগ ছেড়ে দিলে সার্ভারের কাজ থামে, সম্পদ বাঁচে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.৩ DTO: Entity সরাসরি বাইরে দেবেন না
&lt;/h3&gt;

&lt;p&gt;Database entity কখনো API response বা request হিসেবে সরাসরি ব্যবহার করবেন না।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কারণ:&lt;/strong&gt; ভেতরের কাঠামো ফাঁস, গোপন ফিল্ড (যেমন &lt;code&gt;PasswordHash&lt;/code&gt;) বেরিয়ে যাওয়ার ঝুঁকি, &lt;strong&gt;Mass Assignment আক্রমণ&lt;/strong&gt; (ক্লায়েন্ট &lt;code&gt;IsAdmin=true&lt;/code&gt; পাঠিয়ে দিল), আর DB বদলালে API ভাঙা।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Request DTO: শুধু যা ইউজার পাঠাতে পারবে&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;CreateProductRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Response DTO: শুধু যা দেখানো উচিত&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;ProductResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ৫.৪ Validation ও Error Response
&lt;/h3&gt;

&lt;p&gt;ইনপুট কখনো বিশ্বাস করবেন না। &lt;strong&gt;FluentValidation&lt;/strong&gt; বা &lt;code&gt;DataAnnotations&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateProductValidator&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AbstractValidator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreateProductRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CreateProductValidator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;NotEmpty&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;MaximumLength&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;RuleFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;GreaterThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Error এর আদর্শ ফরম্যাট:&lt;/strong&gt; RFC 9457 &lt;strong&gt;Problem Details&lt;/strong&gt; (.NET এ built-in):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddProblemDetails&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseExceptionHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// IExceptionHandler দিয়ে কাস্টমাইজ করুন&lt;/span&gt;

&lt;span class="c1"&gt;// ফল:&lt;/span&gt;
&lt;span class="c1"&gt;// { "type": "...", "title": "Validation failed", "status": 422,&lt;/span&gt;
&lt;span class="c1"&gt;//   "errors": { "Price": ["must be greater than 0"] }, "traceId": "..." }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Global Exception Handler:&lt;/strong&gt; প্রতিটি controller এ try-catch নয়; এক জায়গায় ধরুন, লগ করুন, ক্লায়েন্টকে নিরাপদ বার্তা দিন (stack trace কখনো নয়)।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.৫ Pagination: বিশাল তালিকা সামলানো
&lt;/h3&gt;

&lt;p&gt;১০ লক্ষ পণ্য একসাথে ফেরত দেওয়া যায় না।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Offset Pagination:&lt;/strong&gt; &lt;code&gt;GET /products?page=3&amp;amp;pageSize=20&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;সহজ, কিন্তু বড় পৃষ্ঠা নম্বরে ধীর (&lt;code&gt;OFFSET 1000000&lt;/code&gt; মানে ১০ লক্ষ row পেরিয়ে যেতে হয়) ও পড়ার মাঝে ডেটা বদলালে row ডুপ্লিকেট/হারায়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keyset (Cursor) Pagination:&lt;/strong&gt; &lt;code&gt;GET /products?after=12345&amp;amp;limit=20&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;afterId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Index ব্যবহার করে সবসময় দ্রুত, infinite scroll এর জন্য আদর্শ। দাম: নির্দিষ্ট পৃষ্ঠায় লাফ দেওয়া যায় না।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt; সবসময় একটা সর্বোচ্চ &lt;code&gt;pageSize&lt;/code&gt; সীমা রাখুন (যেমন ১০০)।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.৬ Filtering, Sorting ও Search
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;GET /products?category=phone&amp;amp;minPrice=10000&amp;amp;sort=-price&lt;/code&gt; (&lt;code&gt;-&lt;/code&gt; মানে descending)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;সতর্কতা:&lt;/strong&gt; sort/filter এর ফিল্ড নাম ইউজারের কাছ থেকে নিয়ে সরাসরি query তে বসাবেন না; অনুমোদিত তালিকা (allow-list) রাখুন। বিশাল full-text search এর জন্য database নয়, Elasticsearch/Azure AI Search জাতীয় ব্যবহার করুন।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.৭ API Versioning
&lt;/h3&gt;

&lt;p&gt;আজ আপনার API কাজ করে। কাল আপনি ফিল্ড বদলালেন, পুরনো মোবাইল অ্যাপ ভাঙল! ভার্সন দিয়ে বাঁচুন।&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;পদ্ধতি&lt;/th&gt;
&lt;th&gt;উদাহরণ&lt;/th&gt;
&lt;th&gt;মন্তব্য&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;URL path&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/api/v1/orders&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;সবচেয়ে স্পষ্ট ও জনপ্রিয়&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/orders?api-version=1.0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;সহজ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Header&lt;/td&gt;
&lt;td&gt;&lt;code&gt;X-Api-Version: 1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URL পরিষ্কার, কম আবিষ্কারযোগ্য&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;.NET এ &lt;code&gt;Asp.Versioning.Http&lt;/code&gt; প্যাকেজ।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ভাঙা-না-ভাঙা পরিবর্তন:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ নিরাপদ: নতুন ঐচ্ছিক ফিল্ড/endpoint যোগ&lt;/li&gt;
&lt;li&gt;❌ ভাঙে: ফিল্ড মুছা/নাম বদল, type বদল, নতুন বাধ্যতামূলক ইনপুট&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;পুরনো ভার্সন কবে বন্ধ হবে (&lt;strong&gt;Deprecation&lt;/strong&gt; নীতি) আগে জানান।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.৮ Idempotency: পেমেন্ট দুবার কাটা ঠেকানো
&lt;/h3&gt;

&lt;p&gt;ShopEasy এর সেই সমস্যা: ইউজার "Pay" চাপল, নেটওয়ার্ক ধীর, response ফেরেনি, অ্যাপ আবার চেষ্টা করল। দুবার টাকা কাটল।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;সমাধান: Idempotency Key।&lt;/strong&gt; ক্লায়েন্ট প্রতিটি আসল কাজের জন্য একটা অনন্য key পাঠায়। সার্ভার একই key দ্বিতীয়বার পেলে নতুন কাজ না করে আগের ফলাফল ফেরত দেয়।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/payments"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FromHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Idempotency-Key"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PaymentRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IPaymentGateway&lt;/span&gt; &lt;span class="n"&gt;gw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IdempotencyRecords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existing&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;existing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;gw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ChargeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IdempotencyRecords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;201&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// key এর ওপর unique constraint রাখুন&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"/payments/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(প্রোডাকশনে "processing" অবস্থার জন্য লক/অবস্থা-ট্র্যাকিং দরকার, নইলে একই key এ দুটো সমান্তরাল request একসাথে ঢুকতে পারে। key এর ওপর unique constraint এ এটা সামলানো যায়।)&lt;/p&gt;

&lt;p&gt;GET/PUT/DELETE প্রকৃতিগতভাবে idempotent; &lt;strong&gt;POST এর জন্য এটা আপনাকে বানাতে হবে।&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.৯ Rate Limiting ও Throttling
&lt;/h3&gt;

&lt;p&gt;এক ক্লায়েন্ট বা বট সবার সার্ভার দখল করতে পারে। রক্ষা:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRateLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RejectionStatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;429&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddFixedWindowLimiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PermitLimit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Window&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseRateLimiter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;...).&lt;/span&gt;&lt;span class="nf"&gt;RequireRateLimiting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;অ্যালগরিদম:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fixed Window:&lt;/strong&gt; প্রতি মিনিটে ১০০। সহজ; জানালার সীমানায় দ্বিগুণ burst সম্ভব&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sliding Window:&lt;/strong&gt; আরও মসৃণ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Bucket:&lt;/strong&gt; বালতিতে টোকেন জমে, প্রতি request এ একটা খরচ; ছোট burst অনুমোদিত, গড় হার নিয়ন্ত্রিত&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency Limiter:&lt;/strong&gt; একসাথে সর্বোচ্চ N টা চলমান request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;একাধিক server থাকলে counter শেয়ার করতে Redis লাগে। &lt;code&gt;Retry-After&lt;/code&gt; header দিন।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.১০ gRPC, GraphQL ও REST: কখন কোনটা
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;REST&lt;/th&gt;
&lt;th&gt;gRPC&lt;/th&gt;
&lt;th&gt;GraphQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;প্রোটোকল&lt;/td&gt;
&lt;td&gt;HTTP/JSON&lt;/td&gt;
&lt;td&gt;HTTP/2 + Protobuf (binary)&lt;/td&gt;
&lt;td&gt;HTTP + JSON, একটাই endpoint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;গতি&lt;/td&gt;
&lt;td&gt;ভালো&lt;/td&gt;
&lt;td&gt;সর্বোচ্চ&lt;/td&gt;
&lt;td&gt;ভালো&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ব্রাউজার সাপোর্ট&lt;/td&gt;
&lt;td&gt;সরাসরি&lt;/td&gt;
&lt;td&gt;সীমিত (gRPC-Web লাগে)&lt;/td&gt;
&lt;td&gt;সরাসরি&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contract&lt;/td&gt;
&lt;td&gt;OpenAPI&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.proto&lt;/code&gt; ফাইল (কঠোর)&lt;/td&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Streaming&lt;/td&gt;
&lt;td&gt;সীমিত&lt;/td&gt;
&lt;td&gt;দ্বিমুখী streaming&lt;/td&gt;
&lt;td&gt;Subscription&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;কখন&lt;/td&gt;
&lt;td&gt;পাবলিক API, সাধারণ&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;ভেতরের microservice যোগাযোগ&lt;/strong&gt;, কম latency&lt;/td&gt;
&lt;td&gt;বিভিন্ন ক্লায়েন্ট, নমনীয় ডেটা চাহিদা&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;GraphQL এ ক্লায়েন্ট ঠিক করে কী কী ডেটা চাই&lt;/strong&gt; (over/under-fetching কমে)। তবে caching, N+1, query জটিলতা সীমিত করা ও নিরাপত্তা সামলাতে বাড়তি যত্ন লাগে। .NET এ HotChocolate জনপ্রিয়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gRPC উদাহরণ:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;Inventory&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;CheckStock&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StockRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StockReply&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;StockRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;StockReply&lt;/span&gt;   &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;available&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ৫.১১ HTTP Caching ও Conditional Request
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Cache-Control: public, max-age=300&lt;/code&gt; ব্রাউজার/CDN কে ৫ মিনিট রাখতে বলে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ETag:&lt;/strong&gt; response এর "আঙুলের ছাপ"। ক্লায়েন্ট পরেরবার &lt;code&gt;If-None-Match: "abc"&lt;/code&gt; পাঠায়; ডেটা না বদলালে সার্ভার &lt;code&gt;304 Not Modified&lt;/code&gt; (বডি ছাড়া) দেয়, ব্যান্ডউইথ বাঁচে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimistic concurrency ও ETag/&lt;code&gt;If-Match&lt;/code&gt;:&lt;/strong&gt; আপডেটের সময় পাঠানো ETag না মিললে &lt;code&gt;412 Precondition Failed&lt;/code&gt;, ফলে একজনের বদল অন্যজন অজান্তে মুছে দেয় না।&lt;/li&gt;
&lt;li&gt;Output Caching (&lt;code&gt;app.UseOutputCache()&lt;/code&gt;) সার্ভার-পাশে response cache করে।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৫.১২ API Gateway ও BFF
&lt;/h3&gt;

&lt;p&gt;মাইক্রোসার্ভিসে ক্লায়েন্ট ১০টা সার্ভিসকে সরাসরি ডাকবে না। মাঝে &lt;strong&gt;API Gateway&lt;/strong&gt; একটা একক প্রবেশপথ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing, Authentication, Rate limiting, SSL termination, Logging এক জায়গায়&lt;/li&gt;
&lt;li&gt;Request aggregation (একাধিক সার্ভিস থেকে ডেটা জুড়ে একটা response)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;.NET এ &lt;strong&gt;YARP&lt;/strong&gt; (Yet Another Reverse Proxy, Microsoft এর), Ocelot; ক্লাউডে Azure API Management, AWS API Gateway, Kong।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BFF (Backend for Frontend):&lt;/strong&gt; মোবাইল ও ওয়েবের জন্য আলাদা gateway, যাতে প্রতিটি ক্লায়েন্ট ঠিক যা চায় তা পায়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.১৩ API ডকুমেন্টেশন
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;OpenAPI/Swagger&lt;/strong&gt; দিয়ে স্বয়ংক্রিয় ডকুমেন্টেশন। .NET 9 এ built-in &lt;code&gt;Microsoft.AspNetCore.OpenApi&lt;/code&gt; আছে; UI এর জন্য Scalar বা Swagger UI যুক্ত করা যায়। ভালো API ডকুমেন্টে উদাহরণ ও error কোড থাকে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৫.১৪ Async কাজ ও Webhook
&lt;/h3&gt;

&lt;p&gt;দীর্ঘ কাজ (রিপোর্ট তৈরি, ভিডিও প্রসেসিং) HTTP request এ আটকে রাখবেন না।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Async Request-Reply:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;POST /reports&lt;/code&gt; → &lt;code&gt;202 Accepted&lt;/code&gt; + &lt;code&gt;Location: /reports/job-77&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ক্লায়েন্ট &lt;code&gt;GET /reports/job-77&lt;/code&gt; poll করে → &lt;code&gt;status: processing&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;শেষে &lt;code&gt;status: completed, url: ...&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Webhook:&lt;/strong&gt; সার্ভার নিজেই ক্লায়েন্টের URL এ খবর পাঠায় (যেমন পেমেন্ট সফল হলে gateway আপনার সার্ভারে POST করে)। যাচাই করুন (signature), retry সামলান, idempotent রাখুন।&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 5 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Resource-ভিত্তিক URL, সঠিক method ও status code।&lt;/li&gt;
&lt;li&gt;DTO ব্যবহার করুন; entity বাইরে নয়।&lt;/li&gt;
&lt;li&gt;Pagination বাধ্যতামূলক; বড় ডেটায় keyset।&lt;/li&gt;
&lt;li&gt;POST এর জন্য Idempotency Key, রক্ষায় Rate Limiting।&lt;/li&gt;
&lt;li&gt;Public API তে REST, ভেতরে gRPC, নমনীয়তায় GraphQL; Gateway দিয়ে প্রবেশপথ এক।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 6: Caching, Messaging ও Asynchronous Processing
&lt;/h2&gt;

&lt;p&gt;ShopEasy এর ঈদের সেলের দিন হোমপেজ খুলতে ১০ সেকেন্ড লাগছে, কারণ প্রতিটি visitor এ একই "জনপ্রিয় পণ্য" query ডেটাবেসে যাচ্ছে। আবার অর্ডার করার সময় ইমেইল পাঠাতে গিয়ে ইউজারকে ৫ সেকেন্ড অপেক্ষা করতে হচ্ছে। এই Part এই দুই সমস্যার সমাধান: &lt;strong&gt;Cache&lt;/strong&gt; (একই কাজ বারবার না করা) ও &lt;strong&gt;Messaging&lt;/strong&gt; (ধীর কাজ পেছনে পাঠানো)।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৬.১ Caching: সবচেয়ে শক্তিশালী পারফরম্যান্স অস্ত্র
&lt;/h3&gt;

&lt;p&gt;উপমা: বারবার লাইব্রেরি গিয়ে একই বই না খুলে প্রয়োজনীয় পাতার ফটোকপি টেবিলে রাখা।&lt;/p&gt;

&lt;p&gt;মনে করুন, মেমরি থেকে পড়া ~100 ns, আর DB query ~5 ms (৫০,০০০ গুণ ধীর)। বহু ব্যবহারকারী একই ডেটা চাইলে cache বিরাট জয়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache কোথায় বসে (স্তর):&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Browser cache:&lt;/strong&gt; ক্লায়েন্টের নিজের কাছে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CDN:&lt;/strong&gt; ইউজারের কাছের edge সার্ভারে&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Gateway/Reverse proxy cache&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application in-memory cache:&lt;/strong&gt; অ্যাপের নিজের মেমরিতে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed cache (Redis):&lt;/strong&gt; একাধিক সার্ভারের শেয়ার করা&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database cache:&lt;/strong&gt; DB এর নিজস্ব buffer&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ৬.২ .NET এ Cache এর ধরন
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;১. In-Memory Cache (&lt;code&gt;IMemoryCache&lt;/code&gt;):&lt;/strong&gt; সবচেয়ে দ্রুত, কিন্তু প্রতিটি server এর নিজস্ব; একাধিক server এ আলাদা কপি, অসঙ্গত হতে পারে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMemoryCache&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProductDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetPopularAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetOrCreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"popular"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AbsoluteExpirationRelativeToNow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SlidingExpiration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OrderByDescending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SalesCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ProductDto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;২. Distributed Cache (&lt;code&gt;IDistributedCache&lt;/code&gt; + Redis):&lt;/strong&gt; সব সার্ভার একই cache দেখে। এটা network call (~১ ms), তাই memory এর চেয়ে ধীর, কিন্তু DB এর চেয়ে বহু দ্রুত।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddStackExchangeRedisCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Redis"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;৩. HybridCache (.NET 9+):&lt;/strong&gt; দুটো স্তর একসাথে (L1 in-memory + L2 Redis) এবং &lt;strong&gt;cache stampede protection&lt;/strong&gt; সহ। নতুন কোডে এটাই সবচেয়ে সুবিধাজনক।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHybridCache&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HybridCache&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ValueTask&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProductDto&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetOrCreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"product:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;LoadFromDbAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;৪. Output Caching ও Response Caching:&lt;/strong&gt; পুরো HTTP response cache।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৬.৩ Caching এর কৌশল (Pattern)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;কীভাবে কাজ করে&lt;/th&gt;
&lt;th&gt;কখন&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache-Aside (Lazy Loading)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;অ্যাপ আগে cache দেখে; না পেলে DB থেকে এনে cache এ রাখে&lt;/td&gt;
&lt;td&gt;সবচেয়ে সাধারণ, সবচেয়ে নিরাপদ শুরু&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read-Through&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;cache নিজেই DB থেকে আনে&lt;/td&gt;
&lt;td&gt;cache লাইব্রেরি সমর্থন করলে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write-Through&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;লেখার সময় cache ও DB দুটোতেই&lt;/td&gt;
&lt;td&gt;cache সবসময় সতেজ চাই, লেখা ধীর&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Write-Behind (Write-Back)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;আগে cache এ, পরে async DB তে&lt;/td&gt;
&lt;td&gt;লেখা অনেক, ডেটা হারানোর ঝুঁকি সহ্য্য&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Refresh-Ahead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;মেয়াদ শেষের আগেই আগাম নবায়ন&lt;/td&gt;
&lt;td&gt;পূর্বানুমেয় হট ডেটা&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cache-Aside কোড:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"product:&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Deserialize&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ProductDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Products&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// cache miss&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DistributedCacheEntryOptions&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;AbsoluteExpirationRelativeToNow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ৬.৪ Cache Invalidation: কম্পিউটার বিজ্ঞানের কঠিন সমস্যা
&lt;/h3&gt;

&lt;p&gt;প্রবাদ: "Computer science এ দুটো কঠিন জিনিস: cache invalidation আর নামকরণ।" কারণ cache এ থাকা ডেটা পুরনো (stale) হয়ে যেতে পারে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কৌশল:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TTL (Time-To-Live):&lt;/strong&gt; নির্দিষ্ট সময় পর মেয়াদ শেষ। সবচেয়ে সহজ; সামান্য পুরনো ডেটা সহনীয় হলে চমৎকার।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;সক্রিয় invalidate:&lt;/strong&gt; ডেটা বদলালে cache মুছে দেওয়া (&lt;code&gt;cache.Remove(key)&lt;/code&gt;)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-based:&lt;/strong&gt; ডেটা বদলের event শুনে বিভিন্ন সার্ভারের cache মোছা।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versioned key:&lt;/strong&gt; &lt;code&gt;product:5:v12&lt;/code&gt; (সংস্করণ বদলালে নতুন key)।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;সাধারণ সমস্যা:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache Stampede (Thundering Herd):&lt;/strong&gt; জনপ্রিয় key র মেয়াদ শেষ; এক মুহূর্তে হাজারো request সবাই DB তে যায়। সমাধান: লক/single-flight (HybridCache স্বয়ংক্রিয় করে), TTL তে র‍্যান্ডম জিটার, আগাম নবায়ন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache Penetration:&lt;/strong&gt; এমন key র বারবার অনুরোধ যা DB তেও নেই (যেমন &lt;code&gt;/products/-1&lt;/code&gt;); প্রতিবার DB hit। সমাধান: "পাওয়া যায়নি" ফলাফলও সংক্ষিপ্ত সময়ের জন্য cache, বা Bloom Filter।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cache Avalanche:&lt;/strong&gt; একসাথে অনেক key র মেয়াদ শেষ। সমাধান: TTL এ জিটার।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot Key:&lt;/strong&gt; একটা key এ বিপুল চাপ। সমাধান: local L1 cache, key প্রতিলিপি।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Eviction Policy:&lt;/strong&gt; মেমরি ভরলে কী ফেলা হবে: &lt;strong&gt;LRU&lt;/strong&gt; (সবচেয়ে কম সম্প্রতি ব্যবহৃত), LFU (সবচেয়ে কম ঘনঘন), FIFO।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কী cache করবেন, কী নয়:&lt;/strong&gt; ঘনঘন পড়া, কম বদলানো, তৈরি করা ব্যয়বহুল ডেটা (পণ্য তালিকা, কনফিগ, রেফারেন্স ডেটা)। ব্যবহারকারী-নির্দিষ্ট সংবেদনশীল ডেটা (ভুল key তে অন্যের তথ্য দেখানোর ঝুঁকি) ও দ্রুত বদলানো ডেটা (শেষ স্টক সংখ্যা) সতর্কভাবে। &lt;strong&gt;কখনো প্রমাণ ছাড়া cache যোগ করবেন না&lt;/strong&gt;; আগে মাপুন।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৬.৫ Redis: শুধু cache নয়
&lt;/h3&gt;

&lt;p&gt;Redis একটা in-memory data structure store:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;String:&lt;/strong&gt; সাধারণ cache, counter (&lt;code&gt;INCR&lt;/code&gt; atomic)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hash:&lt;/strong&gt; অবজেক্ট (যেমন user session)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;List:&lt;/strong&gt; queue, সাম্প্রতিক কার্যকলাপ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set / Sorted Set:&lt;/strong&gt; unique তালিকা, &lt;strong&gt;leaderboard&lt;/strong&gt;, rate limiting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pub/Sub, Streams:&lt;/strong&gt; বার্তা আদান-প্রদান&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Lock:&lt;/strong&gt; একাধিক সার্ভারে একই কাজ একবারই চালাতে&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;সতর্কতা: Redis মূলত মেমরিতে; persistence (RDB/AOF) থাকলেও এটাকে একমাত্র "source of truth" বানাবেন না, আর সংযোগ ব্যর্থ হলে অ্যাপ যেন DB তে fallback করতে পারে (graceful degradation)।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৬.৬ Message Queue: ধীর কাজ পেছনে পাঠানো
&lt;/h3&gt;

&lt;p&gt;অর্ডার দিলে: বিলিং, ইনভয়েস PDF, ইমেইল, SMS, স্টক আপডেট। সব একসাথে করলে ইউজার ১০ সেকেন্ড অপেক্ষা করে, আর ইমেইল সার্ভার ডাউন থাকলে পুরো অর্ডারই ব্যর্থ!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;সমাধান:&lt;/strong&gt; ইউজারকে বলুন "অর্ডার গৃহীত"। বাকি কাজের জন্য &lt;strong&gt;বার্তা (message)&lt;/strong&gt; queue তে রাখুন; আলাদা &lt;strong&gt;worker&lt;/strong&gt; পরে সেগুলো করবে।&lt;/p&gt;

&lt;p&gt;উপমা: রেস্টুরেন্টে ক্যাশিয়ার অর্ডার নিয়ে টিকিট রান্নাঘরে ঝুলিয়ে দেয়। ক্যাশিয়ার রান্নার জন্য অপেক্ষা করে না, পরের গ্রাহক নেয়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;শব্দাবলি:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Producer:&lt;/strong&gt; বার্তা পাঠায়&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queue/Topic:&lt;/strong&gt; বার্তা জমা থাকার জায়গা&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consumer:&lt;/strong&gt; বার্তা নিয়ে কাজ করে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broker:&lt;/strong&gt; পুরো ব্যবস্থার ম্যানেজার (RabbitMQ, Kafka, Azure Service Bus)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;সুবিধা:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Decoupling:&lt;/strong&gt; প্রেরক জানেই না কে নেবে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load leveling (Buffer):&lt;/strong&gt; হঠাৎ ট্রাফিক-ঢেউ queue শোষে নেয়, consumer নিজের গতিতে সামলায়&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilience:&lt;/strong&gt; consumer ডাউন থাকলেও বার্তা হারায় না&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; consumer সংখ্যা বাড়ালেই দ্রুত&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৬.৭ Queue বনাম Pub/Sub বনাম Stream
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Point-to-Point Queue:&lt;/strong&gt; প্রতিটি বার্তা &lt;strong&gt;একজন&lt;/strong&gt; consumer পায় (কাজ ভাগ করা: Competing Consumers)। উদাহরণ: ১০০০ ইমেইল ১০ জন worker ভাগ করে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish/Subscribe (Topic):&lt;/strong&gt; প্রতিটি বার্তা &lt;strong&gt;সব&lt;/strong&gt; subscriber পায়। &lt;code&gt;OrderPlaced&lt;/code&gt; → Inventory, Email, Analytics সবাই।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log/Stream (Kafka):&lt;/strong&gt; বার্তা মুছে যায় না, ক্রমানুসারে লগে থাকে; consumer নিজের অবস্থান (offset) মনে রেখে পড়ে, চাইলে পুরনোটা আবার পড়তে পারে (replay)।&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;RabbitMQ&lt;/th&gt;
&lt;th&gt;Kafka&lt;/th&gt;
&lt;th&gt;Azure Service Bus&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;মডেল&lt;/td&gt;
&lt;td&gt;Smart broker, queue/exchange&lt;/td&gt;
&lt;td&gt;Distributed log&lt;/td&gt;
&lt;td&gt;Managed enterprise broker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;গতি/ধারণক্ষমতা&lt;/td&gt;
&lt;td&gt;ভালো&lt;/td&gt;
&lt;td&gt;অসাধারণ (লক্ষ/সেকেন্ড)&lt;/td&gt;
&lt;td&gt;ভালো&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replay&lt;/td&gt;
&lt;td&gt;সাধারণত না&lt;/td&gt;
&lt;td&gt;হ্যাঁ&lt;/td&gt;
&lt;td&gt;সীমিত&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ক্রম (Ordering)&lt;/td&gt;
&lt;td&gt;queue তে&lt;/td&gt;
&lt;td&gt;partition এর ভেতরে&lt;/td&gt;
&lt;td&gt;session দিয়ে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;কখন&lt;/td&gt;
&lt;td&gt;সাধারণ task queue, routing&lt;/td&gt;
&lt;td&gt;ইভেন্ট স্ট্রিম, বিগ ডেটা, analytics&lt;/td&gt;
&lt;td&gt;Azure এ, নির্ভরযোগ্য enterprise messaging&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;.NET এ সহজ করার লাইব্রেরি: &lt;strong&gt;MassTransit&lt;/strong&gt;, &lt;strong&gt;Wolverine&lt;/strong&gt;, NServiceBus, বা সরাসরি client SDK। (বাণিজ্যিক লাইসেন্স নিয়ম বদলাতে পারে, ব্যবহারের আগে দেখে নিন।)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MassTransit উদাহরণ:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Event&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;OrderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;CustomerEmail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Publish&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;publishEndpoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Consumer&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SendConfirmationEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEmailSender&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IConsumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConsumeContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;mail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerEmail&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"Order &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; confirmed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Registration&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMassTransit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddConsumer&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SendConfirmationEmail&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UsingRabbitMq&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"rabbitmq://localhost"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureEndpoints&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ৬.৮ Messaging এর কঠিন সমস্যাগুলো (এখানেই পেশাদারিত্ব)
&lt;/h3&gt;

&lt;h4&gt;
  
  
  ১. Delivery Guarantee
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;At-most-once:&lt;/strong&gt; সর্বোচ্চ একবার, হারাতে পারে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;At-least-once:&lt;/strong&gt; অন্তত একবার, &lt;strong&gt;ডুপ্লিকেট হতে পারে&lt;/strong&gt; (সবচেয়ে সাধারণ)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exactly-once:&lt;/strong&gt; বাস্তবে প্রায় অসম্ভব, ব্যয়বহুল। কার্যকর সমাধান: At-least-once + &lt;strong&gt;Idempotent Consumer&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ২. Idempotent Consumer
&lt;/h4&gt;

&lt;p&gt;বার্তা দুবার এলে প্রভাব একবারের সমান হতে হবে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Consume&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConsumeContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;!.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessedMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AnyAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// আগেই করা হয়েছে&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;DoWorkAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProcessedMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ProcessedMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// কাজ + রেকর্ড একই transaction এ&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ৩. Retry ও Dead Letter Queue (DLQ)
&lt;/h4&gt;

&lt;p&gt;প্রক্রিয়া ব্যর্থ হলে: কয়েকবার retry (exponential backoff সহ: ১s, ২s, ৪s...)। তবু ব্যর্থ হলে &lt;strong&gt;Dead Letter Queue&lt;/strong&gt; এ রাখুন, যাতে একটা "বিষাক্ত বার্তা" (poison message) পুরো queue আটকে না দেয়। DLQ নিয়মিত পর্যবেক্ষণ করুন ও alert দিন।&lt;/p&gt;

&lt;h4&gt;
  
  
  ৪. Message Ordering
&lt;/h4&gt;

&lt;p&gt;ক্রম সবসময় নিশ্চিত নয়। যদি ক্রম জরুরি (যেমন একই অর্ডারের Created → Paid → Shipped), Kafka তে একই key (OrderId) কে একই partition এ পাঠান; অথবা consumer ক্রম-নিরপেক্ষ ডিজাইন করুন (version/timestamp দেখে পুরনো বার্তা বাদ)।&lt;/p&gt;

&lt;h4&gt;
  
  
  ৫. Outbox Pattern: ডেটাবেস ও বার্তার সামঞ্জস্য
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;সমস্যা:&lt;/strong&gt; অর্ডার DB তে সংরক্ষণ হলো কিন্তু ঠিক তখন অ্যাপ ক্র্যাশ করল, বার্তা পাঠানো হলো না। বা উল্টো: বার্তা গেল কিন্তু DB তে সেভ ব্যর্থ। কারণ DB ও broker আলাদা সিস্টেম, এক transaction এ আনা যায় না (&lt;strong&gt;Dual Write সমস্যা&lt;/strong&gt;)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;সমাধান: Transactional Outbox।&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;অর্ডার সংরক্ষণের &lt;strong&gt;একই transaction এ&lt;/strong&gt; &lt;code&gt;Outbox&lt;/code&gt; table এ বার্তাও লিখুন।&lt;/li&gt;
&lt;li&gt;আলাদা একটি background process Outbox পড়ে broker এ পাঠায়, সফল হলে "পাঠানো হয়েছে" চিহ্নিত করে।&lt;/li&gt;
&lt;li&gt;At-least-once ফলে consumer idempotent রাখুন।
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BeginTransactionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OutboxMessages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OutboxMessage&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Payload&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;CreatedAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CommitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// অর্ডার ও বার্তা: হয় দুটোই, নয় কোনোটাই&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MassTransit এ built-in Outbox সমর্থন আছে। &lt;strong&gt;Inbox Pattern&lt;/strong&gt; হলো consumer-পাশের অনুরূপ (ডুপ্লিকেট প্রতিরোধ)।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৬.৯ Saga Pattern: Distributed Transaction সামলানো
&lt;/h3&gt;

&lt;p&gt;Monolith এ একটা DB transaction সব ঠিক রাখে। Microservices এ &lt;code&gt;Order&lt;/code&gt;, &lt;code&gt;Payment&lt;/code&gt;, &lt;code&gt;Inventory&lt;/code&gt; আলাদা DB তে। একটা ধাপ ফেল করলে আগের ধাপগুলো কীভাবে ফেরত নেবেন? Two-Phase Commit (2PC) ধীর ও scalable নয়। সমাধান: &lt;strong&gt;Saga&lt;/strong&gt;, একাধিক local transaction এর ধারা, ব্যর্থ হলে &lt;strong&gt;Compensating Action&lt;/strong&gt; (উল্টো ক্ষতিপূরণ কাজ)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ShopEasy অর্ডার Saga:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Order তৈরি (Pending)&lt;/li&gt;
&lt;li&gt;Payment নেওয়া&lt;/li&gt;
&lt;li&gt;Inventory সংরক্ষণ&lt;/li&gt;
&lt;li&gt;Shipping শুরু → Order Confirmed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;যদি ধাপ ৩ ব্যর্থ (স্টক শেষ):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payment &lt;strong&gt;ফেরত (Refund)&lt;/strong&gt;  ← compensating action&lt;/li&gt;
&lt;li&gt;Order &lt;strong&gt;বাতিল (Cancelled)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;দুই ধরন:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choreography:&lt;/strong&gt; কেন্দ্রীয় নিয়ন্ত্রক নেই; প্রতিটি সার্ভিস event শোনে ও পরের event ছাড়ে। সরল, কিন্তু ধাপ বাড়লে প্রবাহ বোঝা কঠিন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration:&lt;/strong&gt; একটা কেন্দ্রীয় "Saga orchestrator" সবাইকে নির্দেশ দেয় (MassTransit State Machine, Temporal, Durable Functions)। প্রবাহ স্পষ্ট, কিন্তু orchestrator একটি নির্ভরতার কেন্দ্র।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;মনে রাখুন: compensation সবসময় নিখুঁত "undo" নয়। ইমেইল পাঠানো ফেরানো যায় না; একটা "ভুলের জন্য দুঃখিত" ইমেইলই ক্ষতিপূরণ। এভাবে চিন্তা করতে হবে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৬.১০ Background Job ও Scheduled Task
&lt;/h3&gt;

&lt;p&gt;সব কাজ বার্তার প্রয়োজন নেই; কিছু কাজ নির্ধারিত সময়ে বা পেছনে চলে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.NET এর built-in &lt;code&gt;BackgroundService&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StaleCartCleaner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceScopeFactory&lt;/span&gt; &lt;span class="n"&gt;scopeFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StaleCartCleaner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BackgroundService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ExecuteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;stoppingToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PeriodicTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromHours&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitForNextTickAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stoppingToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scopeFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateScope&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// Scoped service এর জন্য&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetRequiredService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AppDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Carts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UpdatedAt&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDays&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                              &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteDeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stoppingToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Cleanup failed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;// loop যেন না মরে&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHostedService&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StaleCartCleaner&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;সতর্কতা:&lt;/strong&gt; অ্যাপের একাধিক instance চললে প্রতিটি এই কাজ চালাবে! একবার চালাতে চাইলে distributed lock বা Hangfire/Quartz.NET এর মতো লাইব্রেরি (যা persistent job store ও cluster-aware) ব্যবহার করুন।&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;টুল&lt;/th&gt;
&lt;th&gt;কখন&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BackgroundService&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;সহজ, একক-instance বা idempotent কাজ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hangfire&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;persistent job, retry, ড্যাশবোর্ড, fire-and-forget/delayed/recurring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Quartz.NET&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;জটিল schedule (cron)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Azure Functions Timer&lt;/td&gt;
&lt;td&gt;serverless schedule&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Channel (&lt;code&gt;System.Threading.Channels&lt;/code&gt;):&lt;/strong&gt; একই process এর ভেতরে producer-consumer queue (বাইরের broker ছাড়া হালকা)। তবে process ক্র্যাশ করলে বার্তা হারায়; গুরুত্বপূর্ণ কাজে durable broker নিন।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৬.১১ ShopEasy তে প্রয়োগ
&lt;/h3&gt;

&lt;p&gt;রাফি এখন:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;হোমপেজের জনপ্রিয় পণ্য: &lt;strong&gt;HybridCache&lt;/strong&gt; (TTL ৫ মিনিট)&lt;/li&gt;
&lt;li&gt;পণ্য ছবি: &lt;strong&gt;CDN&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;অর্ডারের পর ইমেইল/SMS/ইনভয়েস: &lt;strong&gt;RabbitMQ + MassTransit + Outbox&lt;/strong&gt;, consumer গুলো idempotent&lt;/li&gt;
&lt;li&gt;প্রতি রাতের রিপোর্ট: &lt;strong&gt;Hangfire&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Order → Payment → Inventory: &lt;strong&gt;Saga (orchestration)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ফল: ঈদের সেলে হোমপেজ ২০০ ms, অর্ডার ১ সেকেন্ডে গৃহীত, ইমেইল সার্ভার ডাউন থাকলেও কোনো অর্ডার ব্যর্থ হয় না।&lt;/p&gt;

&lt;h3&gt;
  
  
  Part 6 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cache যোগ করার আগে মাপুন; Cache-Aside দিয়ে শুরু; HybridCache আধুনিক পছন্দ।&lt;/li&gt;
&lt;li&gt;Invalidation সবচেয়ে কঠিন; TTL + stampede প্রতিরোধ মাথায় রাখুন।&lt;/li&gt;
&lt;li&gt;ধীর ও অ-জরুরি কাজ queue তে; broker ও ডেটাবেসের সামঞ্জস্যে Outbox।&lt;/li&gt;
&lt;li&gt;At-least-once + Idempotent Consumer + Retry + DLQ হলো messaging এর চার স্তম্ভ।&lt;/li&gt;
&lt;li&gt;Distributed transaction এর জন্য Saga; compensation ভাবুন।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 7: Distributed System ও Resilience: ব্যর্থতা মেনেই বাঁচা
&lt;/h2&gt;

&lt;p&gt;মাইক্রোসার্ভিসে ShopEasy তে একটা অর্ডার এখন ৫টা সার্ভিস ডাকে। একটা সার্ভিস ধীর হলো (Payment gateway ৩০ সেকেন্ড নিচ্ছে)। ফল: Order সার্ভিসের সব thread আটকে গেল, তারপর API Gateway, তারপর পুরো সাইট ডাউন। একটা ছোট সমস্যা ঝর্ণার মতো সবখানে ছড়াল। এটাকে বলে &lt;strong&gt;Cascading Failure&lt;/strong&gt;। এই Part এ শিখব কীভাবে এমন না হয়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;মূলমন্ত্র:&lt;/strong&gt; "Everything fails, all the time" (ওয়ার্নার ভোগেলস, Amazon এর CTO)। ব্যর্থতা এড়ানো যায় না, তাই ব্যর্থতা মেনে নিয়ে নকশা করতে হয়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৭.১ Timeout: সবচেয়ে মৌলিক সুরক্ষা
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;ডিফল্ট &lt;code&gt;HttpClient&lt;/code&gt; timeout ১০০ সেকেন্ড।&lt;/strong&gt; এটা প্রায় সবসময় অনেক বেশি। কোনো নেটওয়ার্ক call এ timeout না থাকলে একটা ধীর নির্ভরতা আপনার সব thread খেয়ে ফেলতে পারে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHttpClient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPaymentClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PaymentClient&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://payment.internal"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Timeout&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// সীমা ঠিক করুন&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt; প্রতিটি বাইরের call (HTTP, DB, cache, queue) এ timeout দিন, এবং ভেতরের timeout বাইরের চেয়ে ছোট রাখুন। (ক্লায়েন্ট ৫s অপেক্ষা করে, কিন্তু সার্ভার ১০s ধরে কাজ করছে, এটা অপচয়।)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deadline propagation:&lt;/strong&gt; সম্পূর্ণ request এর একটা মোট সময়সীমা ধরে &lt;code&gt;CancellationToken&lt;/code&gt; সবখানে পাস করুন। ক্লায়েন্ট চলে গেলে বা সময় শেষ হলে পুরো শৃঙ্খলে কাজ বন্ধ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৭.২ Retry: আবার চেষ্টা, কিন্তু বুদ্ধি করে
&lt;/h3&gt;

&lt;p&gt;অনেক ব্যর্থতা ক্ষণস্থায়ী (transient): নেটওয়ার্ক ঝলক, ৫০৩, deadlock। আবার চেষ্টায় কাজ হয়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কিন্তু অন্ধ retry বিপজ্জনক:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retry Storm:&lt;/strong&gt; সার্ভার ধুঁকছে; ১০০০ ক্লায়েন্ট একসাথে retry করে তাকে শেষ করে দিল।&lt;/li&gt;
&lt;li&gt;অ-idempotent কাজ (POST payment) retry করলে ডুপ্লিকেট (Part 5 এর Idempotency Key)।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ভালো retry এর উপাদান:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;সীমিত সংখ্যক&lt;/strong&gt; (২-৪ বার)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exponential Backoff:&lt;/strong&gt; ১s → ২s → ৪s (মাঝের ফাঁক বাড়ানো)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jitter:&lt;/strong&gt; র‍্যান্ডম সময় যোগ, যাতে সবাই একসাথে না আসে&lt;/li&gt;
&lt;li&gt;শুধু &lt;strong&gt;retry-যোগ্য&lt;/strong&gt; ব্যর্থতায় (৫০৩, timeout, ৪২৯); ৪০০/৪০৪ এ নয়&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ৭.৩ Circuit Breaker: ফিউজ
&lt;/h3&gt;

&lt;p&gt;বাড়ির ফিউজের মতো: সমস্যা ধরা পড়লে সংযোগ কেটে দেয়, যাতে বড় বিপদ না হয়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;তিন অবস্থা:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Closed (স্বাভাবিক):&lt;/strong&gt; request যায়। ব্যর্থতা গোনা হয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open (কাটা):&lt;/strong&gt; ব্যর্থতা সীমা ছাড়ালে বন্ধ। request &lt;strong&gt;তৎক্ষণাৎ&lt;/strong&gt; ব্যর্থ (অপেক্ষা ছাড়াই), নির্ভরতাকে সুস্থ হওয়ার সময় দেয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Half-Open (পরীক্ষা):&lt;/strong&gt; কিছু সময় পর অল্প কয়েকটা request ছেড়ে দেখা। সফল হলে Closed, নইলে আবার Open।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ফল: Payment gateway ডাউন থাকলে প্রতিটি অর্ডার ৩০s আটকে না থেকে সাথে সাথে ব্যর্থ হয় (বা বিকল্প পথে যায়), আমাদের সার্ভার সুস্থ থাকে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৭.৪ Polly ও Microsoft.Extensions.Resilience
&lt;/h3&gt;

&lt;p&gt;.NET এ resilience এর জনপ্রিয় লাইব্রেরি &lt;strong&gt;Polly&lt;/strong&gt;। .NET 8+ এ এটি &lt;code&gt;Microsoft.Extensions.Http.Resilience&lt;/code&gt; এ সহজে &lt;code&gt;HttpClient&lt;/code&gt; এর সাথে মেলানো যায়।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddHttpClient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IPaymentClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PaymentClient&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://payment.internal"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddStandardResilienceHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;   &lt;span class="c1"&gt;// ডিফল্ট: rate limiter, total timeout, retry, circuit breaker, attempt timeout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;নিজের মতো কাস্টমাইজ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddResilienceHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"payment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRetry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HttpRetryStrategyOptions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;MaxRetryAttempts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;BackoffType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DelayBackoffType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Exponential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;UseJitter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Delay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromMilliseconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddCircuitBreaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HttpCircuitBreakerStrategyOptions&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;FailureRatio&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;MinimumThroughput&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;SamplingDuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;BreakDuration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Polly v8 এর Resilience Pipeline API এখানে দেখানো। পুরনো &lt;code&gt;Policy.Handle&amp;lt;...&amp;gt;()&lt;/code&gt; শৈলী v7 এর।)&lt;/p&gt;

&lt;h3&gt;
  
  
  ৭.৫ Bulkhead, Fallback ও Graceful Degradation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bulkhead (জাহাজের বদ্ধ কুঠুরি):&lt;/strong&gt; একটা কুঠুরিতে পানি ঢুকলেও বাকি জাহাজ ভাসে। কোডে: প্রতিটি নির্ভরতার জন্য আলাদা resource পুল/concurrency সীমা, যাতে একটা ধীর নির্ভরতা সব thread না খায়। (&lt;code&gt;ConcurrencyLimiter&lt;/code&gt;, আলাদা &lt;code&gt;HttpClient&lt;/code&gt;, আলাদা queue)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fallback:&lt;/strong&gt; ব্যর্থ হলে বিকল্প উত্তর।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Graceful Degradation:&lt;/strong&gt; সব ফিচার না পারলেও মূল কাজ চালু রাখা।&lt;/p&gt;

&lt;p&gt;ShopEasy তে "Recommendation" সার্ভিস ডাউন হলে:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ পুরো পণ্য পেজ ৫০০ ফেরত দিল&lt;/li&gt;
&lt;li&gt;✅ "আপনার জন্য সুপারিশ" অংশ লুকিয়ে বা জনপ্রিয় পণ্যের cached তালিকা দেখিয়ে বাকি পেজ স্বাভাবিক&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;পেমেন্ট ডাউন থাকলে অর্ডার "Pending Payment" রেখে পরে সম্পন্ন করার সুযোগ দেওয়া যেতে পারে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৭.৬ Load Balancing ও Service Discovery
&lt;/h3&gt;

&lt;p&gt;মাইক্রোসার্ভিসে সার্ভিসের instance সংখ্যা ও IP প্রতিনিয়ত বদলায় (scale up/down, deploy)। কোডে hard-coded IP চলে না।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Service Discovery:&lt;/strong&gt; সার্ভিস নিজেকে নিবন্ধন করে; অন্যরা নাম দিয়ে খুঁজে নেয় (Consul, Kubernetes DNS, Eureka)। Kubernetes এ &lt;code&gt;http://payment-service&lt;/code&gt; লিখলেই DNS ঠিক instance এ পাঠায়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client-side বনাম Server-side load balancing:&lt;/strong&gt; ক্লায়েন্ট নিজেই তালিকা থেকে বেছে নেয়, বা মাঝে একটা load balancer থাকে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Mesh (Istio, Linkerd):&lt;/strong&gt; retry, timeout, mTLS, tracing প্রতিটি সার্ভিসের পাশে &lt;strong&gt;sidecar proxy&lt;/strong&gt; দিয়ে কোডের বাইরে সামলায়। বড় সিস্টেমে কার্যকর, তবে জটিলতা বাড়ে।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;YARP দিয়ে Gateway (.NET):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ReverseProxy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Routes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"orders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ClusterId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"orders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/api/orders/{**rest}"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Clusters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"orders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"LoadBalancingPolicy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RoundRobin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"HealthCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Active"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/health"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Destinations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"d1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://orders-1:8080"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"d2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://orders-2:8080"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ৭.৭ Health Check
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHealthChecks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connString&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"db"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ready"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRedis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redisConn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"ready"&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Liveness: প্রক্রিয়াটা বেঁচে আছে? (ফেল করলে restart)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapHealthChecks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/health/live"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Predicate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// Readiness: ট্রাফিক নেওয়ার জন্য প্রস্তুত? (ফেল করলে load balancer ট্রাফিক বন্ধ রাখে)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapHealthChecks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/health/ready"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Predicate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ready"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Liveness আর Readiness আলাদা রাখুন। DB ডাউন হলে সব pod কে restart করা (liveness ফেল) সমাধান নয়; শুধু ট্রাফিক বন্ধ (readiness) যথেষ্ট।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৭.৮ Distributed System এর আরও মূল ধারণা
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Eventual Consistency এর সাথে বাঁচা
&lt;/h4&gt;

&lt;p&gt;মাইক্রোসার্ভিস ও replica তে ডেটা কিছুক্ষণ অসঙ্গত থাকতে পারে। UI/UX ও ব্যবসায়িক নিয়মে এটা মাথায় রাখুন:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;অর্ডার দেওয়ার পর পেজে "আপনার অর্ডার প্রক্রিয়াধীন" দেখান (লিস্টে আসতে সামান্য দেরি হতে পারে)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read-your-writes&lt;/strong&gt; এর জন্য লেখার পর কিছুক্ষণ primary থেকে পড়ুন&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Leader Election ও Consensus (ধারণা)
&lt;/h4&gt;

&lt;p&gt;কয়েকটি সার্ভারের মধ্যে একজনকে "নেতা" বাছতে বা একটা মানে সবার একমত হতে &lt;strong&gt;Consensus অ্যালগরিদম&lt;/strong&gt; (Raft, Paxos) লাগে। আপনি সাধারণত নিজে লিখবেন না; Redis Sentinel, etcd, ZooKeeper, বা ক্লাউড-ম্যানেজড সার্ভিস ব্যবহার করবেন। শুধু জানুন: কেন একাধিক node এর অর্ধেকের বেশির সম্মতি (&lt;strong&gt;Quorum&lt;/strong&gt;) লাগে (যাতে network partition এ দুটো দল আলাদা সিদ্ধান্ত না নেয়, "split-brain")।&lt;/p&gt;

&lt;h4&gt;
  
  
  Distributed Lock
&lt;/h4&gt;

&lt;p&gt;একাধিক server এ একই কাজ একবারই চালাতে (যেমন রাতের রিপোর্ট)। Redis (&lt;code&gt;RedLock&lt;/code&gt;), DB row lock বা কোনো coordinator। সতর্কতা: লক মেয়াদ ও ক্র্যাশ সামলান (লকধারী মরে গেলে যেন লক চিরকাল না থাকে), আর সম্ভব হলে লকের বদলে idempotent ডিজাইনকে প্রাধান্য দিন।&lt;/p&gt;

&lt;h4&gt;
  
  
  ঘড়ির সমস্যা
&lt;/h4&gt;

&lt;p&gt;দুটো সার্ভারের ঘড়ি হুবহু এক নয়। "কে আগে লিখেছে" নির্ণয়ে সার্ভারের wall-clock এর ওপর ভরসা করবেন না। Logical clock, version number, বা DB এর ক্রম ব্যবহার করুন। সময় সংরক্ষণে সবসময় UTC।&lt;/p&gt;

&lt;h4&gt;
  
  
  Fan-out ও Tail Latency
&lt;/h4&gt;

&lt;p&gt;একটা request ১০টা সার্ভিস ডাকলে মোট ধীরতা নির্ভর করে &lt;strong&gt;সবচেয়ে ধীরটির&lt;/strong&gt; ওপর। প্রতিটির p99 ১% ধীর হলেও, ১০টা ডাকলে প্রায় ১০% request ধীর হবে। তাই: সমান্তরালে ডাকুন (&lt;code&gt;Task.WhenAll&lt;/code&gt;), ডাকার সংখ্যা কমান, hedged request (ধীর হলে দ্বিতীয় প্রতিলিপিতেও পাঠান), cache।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;productTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;productClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stockTask&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inventoryClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;reviewTask&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reviewClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stockTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reviewTask&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// একটার পর একটা নয়, একসাথে&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ৭.৯ Chaos Engineering ও পরীক্ষা
&lt;/h3&gt;

&lt;p&gt;ব্যর্থতা সামলানোর কোড যদি কখনো পরীক্ষা না হয়, প্রকৃত বিপদে কাজ করবে না। Netflix এর Chaos Monkey এর ধারণা: ইচ্ছাকৃতভাবে সার্ভার বন্ধ করে দেখুন সিস্টেম টেকে কি না। শুরুতে ছোট: staging এ একটা নির্ভরতা বন্ধ করে দেখুন কী ঘটে। .NET এ Polly এর Chaos strategies দিয়ে কৃত্রিম ব্যর্থতা/বিলম্ব ঢোকানো যায়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৭.১০ Resilience চেকলিস্ট
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] প্রতিটি বাইরের call এ timeout আছে?&lt;/li&gt;
&lt;li&gt;[ ] Retry তে backoff ও jitter, এবং শুধু idempotent/retry-যোগ্য কাজে?&lt;/li&gt;
&lt;li&gt;[ ] Circuit breaker আছে?&lt;/li&gt;
&lt;li&gt;[ ] Bulkhead/concurrency সীমা দিয়ে একটা নির্ভরতাকে আলাদা রাখা হয়েছে?&lt;/li&gt;
&lt;li&gt;[ ] Fallback/graceful degradation ভাবা হয়েছে?&lt;/li&gt;
&lt;li&gt;[ ] Health check (liveness ও readiness আলাদা)?&lt;/li&gt;
&lt;li&gt;[ ] সব queue consumer idempotent?&lt;/li&gt;
&lt;li&gt;[ ] ব্যর্থতার পরিস্থিতি পরীক্ষা করা হয়েছে?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Part 7 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cascading failure ঠেকাতে Timeout, Retry (backoff+jitter), Circuit Breaker, Bulkhead, Fallback একসাথে ব্যবহার করুন।&lt;/li&gt;
&lt;li&gt;.NET এ &lt;code&gt;AddStandardResilienceHandler&lt;/code&gt; দিয়ে দ্রুত শুরু।&lt;/li&gt;
&lt;li&gt;Service Discovery ও Health Check মাইক্রোসার্ভিসের ভিত্তি।&lt;/li&gt;
&lt;li&gt;ঘড়ি, নেটওয়ার্ক, ক্রম কিছুই নিখুঁত নয়; সেই অনুযায়ী ডিজাইন করুন।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 8: Security: নিরাপত্তা শুরু থেকেই
&lt;/h2&gt;

&lt;p&gt;শেষে যোগ করা নিরাপত্তা সবসময় ফাঁকা থাকে। ShopEasy তে একদিন দেখা গেল, ইউজার URL এ &lt;code&gt;/orders/5&lt;/code&gt; কে &lt;code&gt;/orders/6&lt;/code&gt; করে অন্যের অর্ডার দেখতে পারছে। ভয়াবহ। এই Part এ নিরাপত্তার মৌলিক ও বাস্তব দিক।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৮.১ মৌলিক ধারণা
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication (AuthN):&lt;/strong&gt; আপনি কে? (পরিচয় যাচাই: login)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization (AuthZ):&lt;/strong&gt; আপনি কী করতে পারবেন? (অনুমতি)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;উপমা: অফিসে ঢুকতে আইডি কার্ড দেখানো (AuthN), আর কোন ফ্লোরে যেতে পারবেন তা কার্ডের অনুমতি (AuthZ)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CIA Triad:&lt;/strong&gt; Confidentiality (গোপনীয়তা), Integrity (অখণ্ডতা), Availability (প্রাপ্যতা)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;মূলনীতি:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Least Privilege:&lt;/strong&gt; শুধু যতটুকু দরকার ততটুকু অনুমতি&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Defense in Depth:&lt;/strong&gt; একাধিক স্তরে নিরাপত্তা, একটা ভাঙলে অন্যটা বাঁচায়&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero Trust:&lt;/strong&gt; ভেতরের নেটওয়ার্ক বলেও কাউকে অন্ধ বিশ্বাস নয়; প্রতিটি request যাচাই&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Secure by Default&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৮.২ Password ও Credential
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;কখনো password সরল টেক্সটে রাখবেন না; এমনকি সাধারণ hash (MD5/SHA-256) ও যথেষ্ট নয়।&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ব্যবহার করুন ধীর, salt-যুক্ত অ্যালগরিদম: &lt;strong&gt;bcrypt, scrypt, Argon2, PBKDF2&lt;/strong&gt;। ASP.NET Core Identity এর &lt;code&gt;PasswordHasher&lt;/code&gt; এটা সামলায়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Salt&lt;/strong&gt; হলো প্রতিটি password এর সাথে র‍্যান্ডম মান, যাতে একই password এর hash আলাদা হয় ও rainbow table অকার্যকর।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;আরও:&lt;/strong&gt; Multi-Factor Authentication (MFA), পাসওয়ার্ড লিক-তালিকার সাথে মিলিয়ে দেখা, ব্যর্থ লগইনে lockout/rate limit।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৮.৩ Session, Cookie ও Token
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cookie-ভিত্তিক Session:&lt;/strong&gt; সার্ভার session মনে রাখে, ব্রাউজারে ID পাঠায়। ব্রাউজার-অ্যাপে সহজ ও নিরাপদ (সঠিক ফ্ল্যাগে)। কিন্তু একাধিক সার্ভারে session শেয়ার করতে লাগে (Redis)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token-ভিত্তিক (JWT):&lt;/strong&gt; সার্ভার কিছু মনে রাখে না (stateless); token নিজেই তথ্য বহন করে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JWT (JSON Web Token) এর গঠন:&lt;/strong&gt; &lt;code&gt;header.payload.signature&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;header   = { "alg": "RS256", "typ": "JWT" }
payload  = { "sub": "42", "name": "Rafi", "role": "admin", "exp": 1790000000 }
signature= সাইন করা (গোপন কী দিয়ে), যাতে কেউ বদলালে ধরা পড়ে
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;গুরুত্বপূর্ণ:&lt;/strong&gt; JWT এর payload &lt;strong&gt;এনক্রিপ্ট করা নয়&lt;/strong&gt;, শুধু সাইন করা; যে কেউ পড়তে পারে। তাই গোপন কিছু রাখবেন না।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JWT এর ঝুঁকি ও সর্বোত্তম অভ্যাস:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Access token ছোট মেয়াদী&lt;/strong&gt; (৫-১৫ মিনিট); দীর্ঘ মেয়াদে &lt;strong&gt;Refresh token&lt;/strong&gt; (নিরাপদ জায়গায়, rotation সহ)&lt;/li&gt;
&lt;li&gt;একবার ইস্যু করা token সহজে বাতিল করা যায় না; তাই ছোট মেয়াদ ও দরকারে denylist/revocation&lt;/li&gt;
&lt;li&gt;ব্রাউজারে &lt;code&gt;localStorage&lt;/code&gt; এ token রাখলে XSS এ চুরির ঝুঁকি; &lt;code&gt;HttpOnly, Secure, SameSite&lt;/code&gt; cookie নিরাপদ বিকল্প&lt;/li&gt;
&lt;li&gt;অ্যালগরিদম ও &lt;code&gt;iss&lt;/code&gt;, &lt;code&gt;aud&lt;/code&gt;, &lt;code&gt;exp&lt;/code&gt; সবসময় যাচাই করুন
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JwtBearerDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddJwtBearer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authority&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://auth.shopeasy.com"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Audience&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"shopeasy-api"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TokenValidationParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;ValidateIssuer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ValidateAudience&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ValidateLifetime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ClockSkew&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      &lt;span class="c1"&gt;// এই ক্রম গুরুত্বপূর্ণ&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ৮.৪ OAuth 2.0 ও OpenID Connect (OIDC)
&lt;/h3&gt;

&lt;p&gt;আপনি "Google দিয়ে Login" ক্লিক করেন। ShopEasy আপনার Google password কখনো দেখে না। এটাই OAuth/OIDC।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OAuth 2.0:&lt;/strong&gt; &lt;strong&gt;Authorization&lt;/strong&gt; এর ফ্রেমওয়ার্ক। "এই অ্যাপকে আমার ডেটায় সীমিত অ্যাক্সেস দিন।"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenID Connect:&lt;/strong&gt; OAuth এর ওপর &lt;strong&gt;Authentication&lt;/strong&gt; স্তর (ইউজার কে, তা জানায়)।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Authorization Code Flow with PKCE&lt;/strong&gt; (ব্রাউজার/মোবাইল ও আজকের সেরা অনুশীলন):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;ব্যবহারকারীকে Identity Provider (IdP) এ পাঠানো হয়, সেখানে login&lt;/li&gt;
&lt;li&gt;IdP একটা &lt;strong&gt;code&lt;/strong&gt; ফেরত পাঠায়&lt;/li&gt;
&lt;li&gt;অ্যাপ সেই code বিনিময়ে &lt;strong&gt;access token (+ ID token, refresh token)&lt;/strong&gt; নেয় (PKCE এই বিনিময় চুরি থেকে রক্ষা করে)&lt;/li&gt;
&lt;li&gt;অ্যাপ access token দিয়ে API ডাকে&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Client Credentials Flow:&lt;/strong&gt; সার্ভার-থেকে-সার্ভার (কোনো ইউজার নেই)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;নিজের Identity Server না বানানো ভালো।&lt;/strong&gt; ম্যানেজড সার্ভিস (Microsoft Entra ID, Auth0, Keycloak, AWS Cognito) বা মানসম্মত লাইব্রেরি ব্যবহার করুন। ASP.NET Core Identity নিজস্ব ইউজার ডেটাবেসের জন্য, .NET 8+ এ Identity API endpoints আছে। (Duende IdentityServer শক্তিশালী কিন্তু বাণিজ্যিক লাইসেন্স লাগতে পারে।)&lt;/p&gt;

&lt;h3&gt;
  
  
  ৮.৫ Authorization: Role, Claim, Policy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Role-based&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Roles&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Admin"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="c1"&gt;// Policy-based (নমনীয়, প্রস্তাবিত)&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthorizationBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CanRefund"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireClaim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"permission"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"orders.refund"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddPolicy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Adult"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RequireAssertion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="cm"&gt;/* বয়স ≥ 18 */&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/orders/{id}/refund"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Refund&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;RequireAuthorization&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CanRefund"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;সবচেয়ে সাধারণ ও বিপজ্জনক ভুল: BOLA/IDOR (Broken Object Level Authorization)।&lt;/strong&gt; মানে "এই ইউজার এই নির্দিষ্ট রেকর্ডের মালিক কি না" যাচাই না করা। ShopEasy তে &lt;code&gt;/orders/5&lt;/code&gt; সমস্যা ছিল এটাই।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ শুধু login যথেষ্ট ধরা হয়েছে&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/orders/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ মালিকানা যাচাই&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/orders/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ClaimsPrincipal&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindFirstValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ClaimTypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NameIdentifier&lt;/span&gt;&lt;span class="p"&gt;)!);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// অন্যের হলে 404, অস্তিত্বও ফাঁস নয়&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;RequireAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;সাধারণত Controller এ নয়, query তেই মালিকানা ফিল্টার রাখুন। বড় সিস্টেমে resource-based authorization (&lt;code&gt;IAuthorizationService&lt;/code&gt;) ব্যবহার।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৮.৬ OWASP Top 10: বাস্তবে যা যা ঘটে
&lt;/h3&gt;

&lt;p&gt;OWASP হলো ওয়েব নিরাপত্তার সবচেয়ে সুপরিচিত তালিকা (সংস্করণ ও ক্রম হালনাগাদ হয়; বর্তমান তালিকা OWASP এর সাইটে দেখুন)। মূল ঝুঁকিগুলো:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ঝুঁকি&lt;/th&gt;
&lt;th&gt;কী&lt;/th&gt;
&lt;th&gt;প্রতিরোধ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Broken Access Control&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;অনুমতি ছাড়া অন্যের ডেটা/কাজ&lt;/td&gt;
&lt;td&gt;প্রতিটি request এ সার্ভারে মালিকানা/role যাচাই; default deny&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Injection (SQL)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ইনপুটে ঢোকানো SQL কোড&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Parameterized query&lt;/strong&gt;; কখনো string জুড়ে SQL নয়&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cryptographic Failures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;দুর্বল/অনুপস্থিত এনক্রিপশন&lt;/td&gt;
&lt;td&gt;HTTPS সর্বত্র; আধুনিক অ্যালগরিদম; সংবেদনশীল ডেটা এনক্রিপ্ট&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Insecure Design&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;নকশাতেই ত্রুটি&lt;/td&gt;
&lt;td&gt;Threat modeling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Misconfiguration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ডিফল্ট পাসওয়ার্ড, খোলা debug&lt;/td&gt;
&lt;td&gt;হার্ডেনিং, ন্যূনতম এক্সপোজার&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vulnerable Components&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;পুরনো/ঝুঁকিপূর্ণ NuGet প্যাকেজ&lt;/td&gt;
&lt;td&gt;নিয়মিত আপডেট, &lt;code&gt;dotnet list package --vulnerable&lt;/code&gt;, Dependabot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Authentication Failures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;দুর্বল login&lt;/td&gt;
&lt;td&gt;MFA, rate limit, lockout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integrity Failures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;সাইন-না-করা আপডেট/ডেটা&lt;/td&gt;
&lt;td&gt;সাইন যাচাই, CI/CD সুরক্ষা&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logging Failures&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;আক্রমণ ধরা পড়ে না&lt;/td&gt;
&lt;td&gt;নিরাপত্তা ঘটনা লগ ও alert&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSRF&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;সার্ভারকে দিয়ে ভেতরের URL ডাকানো&lt;/td&gt;
&lt;td&gt;বাইরে থেকে পাওয়া URL এর allow-list&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;SQL Injection উদাহরণ:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ ভয়ংকর: ইনপুট "x'; DROP TABLE Users;--"&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"SELECT * FROM Users WHERE Name = '&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ EF Core LINQ (স্বয়ংক্রিয় parameter)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Raw SQL হলেও parameterized&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromSqlInterpolated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"SELECT * FROM Users WHERE Name = &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// (FromSqlRaw এ string interpolation কখনো নয়)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;XSS (Cross-Site Scripting):&lt;/strong&gt; আক্রমণকারী ওয়েবপেজে স্ক্রিপ্ট ঢোকায়। প্রতিরোধ: আউটপুট এনকোড (Razor/Blazor স্বয়ংক্রিয় করে; &lt;code&gt;Html.Raw&lt;/code&gt; এ সতর্ক), Content-Security-Policy header, ইনপুট যাচাই।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CSRF (Cross-Site Request Forgery):&lt;/strong&gt; ভুক্তভোগীর login অবস্থা ব্যবহার করে অন্য সাইট থেকে জাল request। প্রতিরোধ: SameSite cookie, Anti-forgery token (&lt;code&gt;[ValidateAntiForgeryToken]&lt;/code&gt;; cookie-ভিত্তিক সাইটে জরুরি)। Bearer-token API তে সাধারণত CSRF সমস্যা কম।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mass Assignment:&lt;/strong&gt; DTO ব্যবহার করুন (Part 5)।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৮.৭ Secret ও Configuration ব্যবস্থাপনা
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Connection string, API key, password কখনো Git এ কমিট করবেন না।&lt;/strong&gt; (একবার কমিট হলে ইতিহাসে থেকে যায়; ধরে নিন ফাঁস হয়েছে, সাথে সাথে বদলান।)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ডেভেলপমেন্ট:&lt;/strong&gt; &lt;code&gt;dotnet user-secrets&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;প্রোডাকশন:&lt;/strong&gt; Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, Kubernetes Secrets (এনক্রিপশন সক্রিয় করে)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managed Identity:&lt;/strong&gt; অ্যাপ নিজেই ক্লাউডের পরিচয়ে Key Vault/DB তে ঢোকে, কোনো password কোডে বা কনফিগে নেই। সবচেয়ে নিরাপদ।&lt;/li&gt;
&lt;li&gt;Secret নিয়মিত rotate করুন; লগে কখনো secret প্রিন্ট নয়।
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAzureKeyVault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://shopeasy-kv.vault.azure.net/"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;   &lt;span class="c1"&gt;// Managed Identity/dev credential&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ৮.৮ ডেটা সুরক্ষা ও গোপনীয়তা
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Encryption in Transit:&lt;/strong&gt; সর্বত্র HTTPS/TLS (&lt;code&gt;app.UseHttpsRedirection()&lt;/code&gt;, HSTS)। সার্ভিস-থেকে-সার্ভিস mTLS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption at Rest:&lt;/strong&gt; DB/ডিস্ক এনক্রিপশন; সংবেদনশীল কলাম (NID, কার্ড) আলাদা এনক্রিপ্ট&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;কার্ডের তথ্য নিজে রাখবেন না;&lt;/strong&gt; PCI-DSS জটিল। Payment gateway এর tokenization ব্যবহার করুন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PII (ব্যক্তিগত তথ্য):&lt;/strong&gt; শুধু প্রয়োজনীয়টুকু সংগ্রহ (Data Minimization), লগে মাস্ক, আইন (যেমন GDPR বা স্থানীয় ডেটা সুরক্ষা আইন) অনুযায়ী মুছে ফেলা/রপ্তানির সুযোগ রাখুন&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ASP.NET Core Data Protection API:&lt;/strong&gt; cookie/token এনক্রিপশনের কী একাধিক সার্ভারে শেয়ার করুন (নইলে এক সার্ভারের cookie অন্যটি পড়তে পারে না)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৮.৯ API ও অবকাঠামো সুরক্ষা
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CORS:&lt;/strong&gt; শুধু বিশ্বস্ত origin অনুমোদন (&lt;code&gt;AllowAnyOrigin&lt;/code&gt; + credentials এক সাথে নয়)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Headers:&lt;/strong&gt; &lt;code&gt;Strict-Transport-Security&lt;/code&gt;, &lt;code&gt;Content-Security-Policy&lt;/code&gt;, &lt;code&gt;X-Content-Type-Options: nosniff&lt;/code&gt;, &lt;code&gt;X-Frame-Options&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting ও WAF&lt;/strong&gt; (Web Application Firewall: Cloudflare, Azure Front Door) বট ও সাধারণ আক্রমণ ঠেকায়&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ইনপুট সীমা:&lt;/strong&gt; request body এর আকার সীমা, ফাইল আপলোডে type/আকার/ভাইরাস স্ক্যান, সংরক্ষণ ওয়েব-রুটের বাইরে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container নিরাপত্তা:&lt;/strong&gt; non-root ইউজার, ছোট base image, image স্ক্যান&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;নেটওয়ার্ক:&lt;/strong&gt; DB ইন্টারনেটে খোলা নয়; private network/VNet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dependency নিরাপত্তা:&lt;/strong&gt; &lt;code&gt;dotnet list package --vulnerable&lt;/code&gt;, Dependabot/Renovate, SBOM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Log:&lt;/strong&gt; কে কখন কী করল (বিশেষত অ্যাডমিন কাজ)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৮.১০ Threat Modeling: STRIDE
&lt;/h3&gt;

&lt;p&gt;ডিজাইনের সময়ই জিজ্ঞেস করুন "কী ভুল হতে পারে?" STRIDE:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt;poofing (ভুয়া পরিচয়)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;T&lt;/strong&gt;ampering (ডেটা বদল)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;R&lt;/strong&gt;epudiation ("আমি করিনি" অস্বীকার; audit log সমাধান)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I&lt;/strong&gt;nformation Disclosure (তথ্য ফাঁস)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D&lt;/strong&gt;enial of Service (সেবা বন্ধ)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E&lt;/strong&gt;levation of Privilege (অনুমতি বাড়ানো)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;প্রতিটি data flow ও trust boundary তে এই ছয়টি প্রশ্ন করুন।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৮.১১ নিরাপত্তা চেকলিস্ট
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] সর্বত্র HTTPS, HSTS&lt;/li&gt;
&lt;li&gt;[ ] Password Argon2/bcrypt/PBKDF2 দিয়ে হ্যাশ; MFA সমর্থন&lt;/li&gt;
&lt;li&gt;[ ] প্রতিটি endpoint এ authentication ও resource-level authorization (BOLA)&lt;/li&gt;
&lt;li&gt;[ ] সব ইনপুট যাচাই; DTO ব্যবহার; parameterized query&lt;/li&gt;
&lt;li&gt;[ ] Secret কোডে নেই; Key Vault/Managed Identity&lt;/li&gt;
&lt;li&gt;[ ] CORS, security header, rate limiting&lt;/li&gt;
&lt;li&gt;[ ] Dependency নিয়মিত আপডেট ও স্ক্যান&lt;/li&gt;
&lt;li&gt;[ ] সংবেদনশীল ডেটা এনক্রিপ্ট; লগে PII/secret নেই&lt;/li&gt;
&lt;li&gt;[ ] Audit log ও নিরাপত্তা alert&lt;/li&gt;
&lt;li&gt;[ ] Error বার্তায় ভেতরের তথ্য (stack trace) ফাঁস হয় না&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Part 8 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;AuthN ≠ AuthZ; সবচেয়ে বড় ঝুঁকি অনুমতি যাচাই ভুলে যাওয়া (BOLA)।&lt;/li&gt;
&lt;li&gt;নিজে crypto বা identity server বানাবেন না; প্রমাণিত সমাধান ব্যবহার করুন।&lt;/li&gt;
&lt;li&gt;Secret কোডের বাইরে, Managed Identity সবচেয়ে ভালো।&lt;/li&gt;
&lt;li&gt;Defense in Depth ও Least Privilege; ডিজাইনের সময় threat model।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 9: Observability, DevOps ও Cloud
&lt;/h2&gt;

&lt;p&gt;রাত ২টায় ফোন: "সাইট ধীর!" আপনি জানেন না কোথায় সমস্যা: কোন সার্ভিস, কোন query, কোন সার্ভার। &lt;strong&gt;যা মাপা যায় না, তা ঠিকও করা যায় না।&lt;/strong&gt; এই Part এ শিখব সিস্টেমকে "দেখার" উপায় ও নিরাপদে deploy করার পদ্ধতি।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.১ Observability এর তিন স্তম্ভ
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;স্তম্ভ&lt;/th&gt;
&lt;th&gt;কী বলে&lt;/th&gt;
&lt;th&gt;উদাহরণ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Logs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;কী ঘটেছে (ঘটনার বিবরণ)&lt;/td&gt;
&lt;td&gt;"Order 5 payment failed: timeout"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metrics&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;কতটা/কত ঘন (সংখ্যা, সময়ের সাথে)&lt;/td&gt;
&lt;td&gt;request/sec, error rate, p99 latency, CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Traces&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;একটা request পুরো সিস্টেমে কোথায় কত সময় নিল&lt;/td&gt;
&lt;td&gt;Gateway 5ms → Order 20ms → Payment 3000ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Monitoring&lt;/strong&gt; জানে "কী ভাঙছে" (পূর্বনির্ধারিত প্রশ্ন); &lt;strong&gt;Observability&lt;/strong&gt; আপনাকে নতুন, অপ্রত্যাশিত প্রশ্ন করতে দেয় ("কেন শুধু বুধবারে মোবাইল ইউজাররা ধীর?")।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.২ Logging: Serilog ও Structured Logging
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Unstructured log (খারাপ):&lt;/strong&gt; &lt;code&gt;"User 42 placed order 5 for 1200"&lt;/code&gt;: খুঁজতে regex লাগে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured log (ভালো):&lt;/strong&gt; ফিল্ডসহ, query করা যায়।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ string interpolation: structured হয় না&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Order &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; placed by &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ message template: id ও userId আলাদা searchable ফিল্ড&lt;/span&gt;
&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Order {OrderId} placed by {UserId} total {Total}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Serilog সেটআপ:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSerilog&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enrich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromLogContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enrich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ordering"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteTo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CompactJsonFormatter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteTo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Seq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://seq:5341"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;        &lt;span class="c1"&gt;// বা Elasticsearch, Loki, Application Insights&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseSerilogRequestLogging&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Log Level:&lt;/strong&gt; &lt;code&gt;Trace &amp;lt; Debug &amp;lt; Information &amp;lt; Warning &amp;lt; Error &amp;lt; Critical&lt;/code&gt;। Production এ সাধারণত Information+।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;লগের নিয়ম:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Correlation ID/Trace ID&lt;/strong&gt; প্রতিটি লগে, যাতে এক request এর সব লগ জোড়া যায়&lt;/li&gt;
&lt;li&gt;Password, token, কার্ড, PII লগ নয়&lt;/li&gt;
&lt;li&gt;Exception এ stack trace সহ &lt;code&gt;log.LogError(ex, "...")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;অতিরিক্ত লগ খরচ ও গোলমাল বাড়ায়; অর্থবহ ঘটনা লগ করুন&lt;/li&gt;
&lt;li&gt;কেন্দ্রীয় লগ সংগ্রহ (Seq, ELK/Elastic, Grafana Loki, Azure Monitor); প্রতিটি সার্ভারে ঢুকে ফাইল পড়া নয়&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৯.৩ Metrics ও চার সোনালি সংকেত
&lt;/h3&gt;

&lt;p&gt;Google SRE এর "Four Golden Signals":&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Latency:&lt;/strong&gt; কত সময় লাগছে (p50, p95, p99)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traffic:&lt;/strong&gt; কত request&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Errors:&lt;/strong&gt; কত শতাংশ ব্যর্থ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saturation:&lt;/strong&gt; সম্পদ কতটা ভরা (CPU, মেমরি, DB connection pool, queue গভীরতা)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;আরও পরিচিত কাঠামো: &lt;strong&gt;RED&lt;/strong&gt; (Rate, Errors, Duration) সার্ভিসের জন্য; &lt;strong&gt;USE&lt;/strong&gt; (Utilization, Saturation, Errors) সম্পদের জন্য।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// কাস্টম business metric (System.Diagnostics.Metrics)&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderMetrics&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_placed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;OrderMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IMeterFactory&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;meter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ShopEasy.Orders"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;_placed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;meter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateCounter&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"orders.placed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;OrderPlaced&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;paymentMethod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;_placed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValuePair&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"payment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paymentMethod&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Business metric ও গুরুত্বপূর্ণ:&lt;/strong&gt; শুধু CPU নয়, "প্রতি মিনিটে কত অর্ডার" দেখুন। অর্ডার হঠাৎ শূন্যে নামলে সার্ভার সুস্থ থাকলেও সমস্যা আছে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.৪ Distributed Tracing ও OpenTelemetry
&lt;/h3&gt;

&lt;p&gt;মাইক্রোসার্ভিসে একটা অর্ডার ৫টা সার্ভিস ঘোরে। ধীর কোথায়? &lt;strong&gt;Trace&lt;/strong&gt; এক request এর পুরো যাত্রার ম্যাপ। প্রতিটি ধাপ একটা &lt;strong&gt;span&lt;/strong&gt;, সবাই একই &lt;strong&gt;Trace ID&lt;/strong&gt; শেয়ার করে (HTTP header &lt;code&gt;traceparent&lt;/code&gt; দিয়ে এক সার্ভিস থেকে পরেরটায় পৌঁছায়, W3C Trace Context)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenTelemetry (OTel)&lt;/strong&gt; হলো এই বিষয়ে মান ও ভেন্ডর-নিরপেক্ষ সমাধান; .NET এ এটাই প্রচলিত পথ।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOpenTelemetry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ordering"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithTracing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAspNetCoreInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHttpClientInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddEntityFrameworkCoreInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ShopEasy.Orders"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOtlpExporter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;                 &lt;span class="c1"&gt;// Jaeger, Tempo, Azure Monitor, Datadog ইত্যাদিতে&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAspNetCoreInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRuntimeInstrumentation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMeter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ShopEasy.Orders"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOtlpExporter&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;নিজের span:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ActivitySource&lt;/span&gt; &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ShopEasy.Orders"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;activity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Source&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartActivity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"CalculateDiscount"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;SetTag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"order.id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;জনপ্রিয় টুল: &lt;strong&gt;Prometheus + Grafana&lt;/strong&gt; (metrics), &lt;strong&gt;Jaeger/Tempo&lt;/strong&gt; (trace), &lt;strong&gt;Loki/Seq/ELK&lt;/strong&gt; (log), Azure Application Insights, Datadog, New Relic। .NET Aspire dashboard স্থানীয় ডেভেলপমেন্টে এগুলো একসাথে দেখায়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.৫ Alerting ও Incident Response
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Alert হবে লক্ষণে (symptom), কারণে নয়:&lt;/strong&gt; "error rate &amp;gt; ৫%" বা "p99 &amp;gt; ২ সেকেন্ড" (ব্যবহারকারী ক্ষতিগ্রস্ত)। "CPU ৮০%" একা কোনো সমস্যা নয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert fatigue এড়ান:&lt;/strong&gt; বেশি alert মানে কেউ আর পাত্তা দেয় না। শুধু যেগুলোতে &lt;strong&gt;তৎক্ষণাৎ মানুষের পদক্ষেপ&lt;/strong&gt; লাগে, সেগুলো pager এ।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SLO ও Error Budget:&lt;/strong&gt; SLO ৯৯.৯% মানে মাসে ~৪৩ মিনিট ব্যর্থতা "বাজেট"। বাজেট ফুরালে নতুন ফিচার থামিয়ে স্থিতিশীলতায় মন দিন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runbook:&lt;/strong&gt; প্রতিটি alert এর সাথে "কী করবেন" লিখিত।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blameless Postmortem:&lt;/strong&gt; ঘটনার পর দোষারোপ নয়, "কী শিখলাম ও কী বদলাব"।&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৯.৬ Docker: যেখানে চলবে সেই পরিবেশসহ প্যাকেজ
&lt;/h3&gt;

&lt;p&gt;"আমার মেশিনে চলে!" সমস্যার সমাধান। &lt;strong&gt;Container&lt;/strong&gt; অ্যাপ, তার runtime ও dependency একসাথে প্যাকেজ করে; যেকোনো জায়গায় একইভাবে চলে। ভার্চুয়াল মেশিনের চেয়ে হালকা (OS kernel শেয়ার করে)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-stage Dockerfile (.NET):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# ধাপ ১: build (SDK দিয়ে, বড় image)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/sdk:9.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; *.csproj .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet restore                      &lt;span class="c"&gt;# আলাদা ধাপে, যাতে layer cache কাজে লাগে&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;dotnet publish &lt;span class="nt"&gt;-c&lt;/span&gt; Release &lt;span class="nt"&gt;-o&lt;/span&gt; /app &lt;span class="nt"&gt;--no-restore&lt;/span&gt;

&lt;span class="c"&gt;# ধাপ ২: final (শুধু runtime, ছোট ও নিরাপদ)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:9.0&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app .&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; $APP_UID                           # non-root&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["dotnet", "ShopEasy.Api.dll"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Docker Compose&lt;/strong&gt; দিয়ে স্থানীয়ভাবে পুরো সিস্টেম (API + SQL + Redis + RabbitMQ) একসাথে:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8080:8080"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ConnectionStrings__Default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Server=db;Database=shop;User=sa;Password=${DB_PASSWORD};TrustServerCertificate=true"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcr.microsoft.com/mssql/server:2022-latest&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ACCEPT_EULA&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Y"&lt;/span&gt;
      &lt;span class="na"&gt;MSSQL_SA_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${DB_PASSWORD}&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt; Container stateless ও disposable (যেকোনো মুহূর্তে মরতে/নতুন হতে পারে); কনফিগ environment variable এ; লগ stdout এ; secret image এর ভেতরে নয়।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.৭ Kubernetes (K8s): Container এর ম্যানেজার
&lt;/h3&gt;

&lt;p&gt;শত শত container কে কে চালাবে, ফেল করলে কে আবার তুলবে, লোড বাড়লে কে বাড়াবে? Kubernetes।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;মূল ধারণা:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pod:&lt;/strong&gt; একটা বা একাধিক container এর ক্ষুদ্রতম একক&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; কয়টা pod চলবে ও কীভাবে আপডেট হবে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service:&lt;/strong&gt; pod গুলোর সামনে স্থির নাম/IP ও load balancing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ingress:&lt;/strong&gt; বাইরের ট্রাফিকের প্রবেশপথ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ConfigMap/Secret:&lt;/strong&gt; কনফিগ ও গোপন তথ্য&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HPA (Horizontal Pod Autoscaler):&lt;/strong&gt; CPU/মেট্রিক দেখে pod বাড়ায়-কমায়&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Namespace:&lt;/strong&gt; পরিবেশ/টিম আলাদা করা
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;ordering&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;RollingUpdate&lt;/span&gt;           &lt;span class="c1"&gt;# একটা একটা করে pod বদলায়, downtime নেই&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;ordering&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;ordering&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;api&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;shopeasy/ordering:1.4.2&lt;/span&gt;
          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[{&lt;/span&gt; &lt;span class="nv"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;8080&lt;/span&gt; &lt;span class="pi"&gt;}]&lt;/span&gt;
          &lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;250m"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;256Mi"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;limits&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;   &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;cpu&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;500m"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;memory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;512Mi"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;livenessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;  &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;/health/live&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;  &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;8080&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;readinessProbe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;httpGet&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;/health/ready&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;8080&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;সতর্কতা:&lt;/strong&gt; Kubernetes শক্তিশালী কিন্তু জটিল, শেখা ও পরিচালনার খরচ বেশি। ছোট টিমের জন্য ম্যানেজড বিকল্প (Azure App Service, Azure Container Apps, AWS ECS/Fargate, Google Cloud Run) প্রায়ই যথেষ্ট ও সহজ। প্রয়োজন প্রমাণিত না হলে K8s এড়ান।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.৮ CI/CD: স্বয়ংক্রিয় build, test ও deploy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CI (Continuous Integration):&lt;/strong&gt; প্রতিটি কোড পরিবর্তনে স্বয়ংক্রিয়ভাবে build ও test; সমস্যা তাড়াতাড়ি ধরা&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CD (Continuous Delivery/Deployment):&lt;/strong&gt; পাস করা কোড স্বয়ংক্রিয়ভাবে (বা এক ক্লিকে) প্রোডাকশনে&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;একটা আদর্শ pipeline:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Code commit/PR&lt;/li&gt;
&lt;li&gt;Build + restore&lt;/li&gt;
&lt;li&gt;Unit test + coverage&lt;/li&gt;
&lt;li&gt;স্ট্যাটিক বিশ্লেষণ ও dependency/নিরাপত্তা স্ক্যান&lt;/li&gt;
&lt;li&gt;Docker image build ও registry তে push&lt;/li&gt;
&lt;li&gt;Staging এ deploy + integration/smoke test&lt;/li&gt;
&lt;li&gt;অনুমোদন (দরকারে) → Production deploy&lt;/li&gt;
&lt;li&gt;Health check যাচাই; ব্যর্থ হলে স্বয়ংক্রিয় rollback&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;GitHub Actions উদাহরণ:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-dotnet@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;dotnet-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9.0.x"&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnet restore&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnet build --no-restore -c Release&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dotnet test --no-build -c Release&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;অন্যান্য: Azure DevOps Pipelines, GitLab CI, Jenkins। &lt;strong&gt;Infrastructure as Code (IaC):&lt;/strong&gt; অবকাঠামো কোডে (Terraform, Bicep, Pulumi), ক্লিক করে নয়; ভার্সন নিয়ন্ত্রিত ও পুনরুৎপাদনযোগ্য।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.৯ নিরাপদ Deployment কৌশল
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;কৌশল&lt;/th&gt;
&lt;th&gt;কীভাবে&lt;/th&gt;
&lt;th&gt;সুবিধা/অসুবিধা&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rolling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;একটা একটা instance বদলানো&lt;/td&gt;
&lt;td&gt;সহজ; পুরনো ও নতুন ভার্সন কিছুক্ষণ একসাথে (সামঞ্জস্য লাগে)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blue-Green&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;দুটো পূর্ণ পরিবেশ; ট্রাফিক একবারে সুইচ&lt;/td&gt;
&lt;td&gt;তাৎক্ষণিক rollback; খরচ দ্বিগুণ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Canary&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;প্রথমে ৫% ট্রাফিক নতুন ভার্সনে, ঠিক থাকলে বাড়ানো&lt;/td&gt;
&lt;td&gt;ঝুঁকি কম; জটিল&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Feature Flag&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;কোড deploy করে ফিচার বন্ধ রাখা, পরে চালু&lt;/td&gt;
&lt;td&gt;deploy ও release আলাদা; ঝামেলা হলে সুইচ অফ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Database পরিবর্তন সবসময় backward-compatible রাখুন (Part 4 এর Expand-Contract), নইলে rolling deploy এ ভাঙবে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.১০ Cloud ধারণা
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;সেবার স্তর:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;IaaS:&lt;/strong&gt; ভার্চুয়াল মেশিন (আপনি OS থেকে সামলান)। যেমন Azure VM, EC2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PaaS:&lt;/strong&gt; প্ল্যাটফর্ম (আপনি শুধু কোড দেন)। যেমন Azure App Service&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FaaS/Serverless:&lt;/strong&gt; ফাংশন। যেমন Azure Functions, Lambda&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SaaS:&lt;/strong&gt; তৈরি সফটওয়্যার&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Azure বনাম AWS (মূল সেবার সমতুল্যতা, .NET প্রসঙ্গে):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;কাজ&lt;/th&gt;
&lt;th&gt;Azure&lt;/th&gt;
&lt;th&gt;AWS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ওয়েব অ্যাপ হোস্ট&lt;/td&gt;
&lt;td&gt;App Service&lt;/td&gt;
&lt;td&gt;Elastic Beanstalk / App Runner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Container&lt;/td&gt;
&lt;td&gt;Container Apps / AKS&lt;/td&gt;
&lt;td&gt;ECS-Fargate / EKS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Serverless&lt;/td&gt;
&lt;td&gt;Functions&lt;/td&gt;
&lt;td&gt;Lambda&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL DB&lt;/td&gt;
&lt;td&gt;Azure SQL&lt;/td&gt;
&lt;td&gt;RDS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NoSQL&lt;/td&gt;
&lt;td&gt;Cosmos DB&lt;/td&gt;
&lt;td&gt;DynamoDB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;Azure Cache for Redis&lt;/td&gt;
&lt;td&gt;ElastiCache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Queue/Bus&lt;/td&gt;
&lt;td&gt;Service Bus&lt;/td&gt;
&lt;td&gt;SQS / SNS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ফাইল&lt;/td&gt;
&lt;td&gt;Blob Storage&lt;/td&gt;
&lt;td&gt;S3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret&lt;/td&gt;
&lt;td&gt;Key Vault&lt;/td&gt;
&lt;td&gt;Secrets Manager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring&lt;/td&gt;
&lt;td&gt;Application Insights&lt;/td&gt;
&lt;td&gt;CloudWatch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;(সেবার নাম ও ফিচার বদলায়; সিদ্ধান্তের আগে সংশ্লিষ্ট ক্লাউডের হালনাগাদ ডকুমেন্ট দেখুন।)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloud এর গুরুত্বপূর্ণ ধারণা:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Region ও Availability Zone (AZ):&lt;/strong&gt; Region ভৌগোলিক এলাকা, AZ সেই এলাকার ভেতরের আলাদা ডেটাসেন্টার। একাধিক AZ তে চালালে একটা ডেটাসেন্টার গেলেও টিকে থাকে। একাধিক Region তে Disaster Recovery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-scaling:&lt;/strong&gt; লোড অনুযায়ী স্বয়ংক্রিয় বাড়া-কমা&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Management:&lt;/strong&gt; ক্লাউড খরচ নীরবে বাড়ে। বাজেট alert, অপ্রয়োজনীয় রিসোর্স বন্ধ, Reserved/Spot instance বিবেচনা, ডেটা ট্রান্সফার ফি লক্ষ্য রাখা&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Well-Architected Framework:&lt;/strong&gt; Azure/AWS দুটোরই ডিজাইন নির্দেশিকা (নির্ভরযোগ্যতা, নিরাপত্তা, খরচ, পারফরম্যান্স, অপারেশনাল শ্রেষ্ঠত্ব)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenancy:&lt;/strong&gt; একই অ্যাপে একাধিক গ্রাহককে (SaaS) সেবা; ডেটা বিচ্ছিন্নতার মডেল (shared DB with TenantId, schema per tenant, DB per tenant)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ৯.১১ .NET Aspire
&lt;/h3&gt;

&lt;p&gt;.NET Aspire হলো ক্লাউড-নেটিভ, বিতরিত অ্যাপ বানানোর একটা অ-মতবাদী (opinionated) stack। স্থানীয়ভাবে একাধিক সার্ভিস, DB, Redis, RabbitMQ একসাথে চালানো, service discovery, কনফিগ, OpenTelemetry ও ড্যাশবোর্ড প্রায় স্বয়ংক্রিয়ভাবে মেলে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// AppHost প্রজেক্ট: সিস্টেমের গঠন কোডে&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DistributedApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRedis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cache"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSqlServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sql"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;AddDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"shopdb"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddProject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordering_Api&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"ordering"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddProject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Web&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"web"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// service discovery স্বয়ংক্রিয়&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;মাইক্রোসার্ভিস বা একাধিক নির্ভরতার প্রজেক্টে ডেভেলপার অভিজ্ঞতা চমৎকার করে। (Aspire দ্রুত বিবর্তিত হচ্ছে; ব্যবহারের আগে সর্বশেষ ডকুমেন্ট দেখুন।)&lt;/p&gt;

&lt;h3&gt;
  
  
  ৯.১২ Configuration ও 12-Factor App
&lt;/h3&gt;

&lt;p&gt;আধুনিক ক্লাউড অ্যাপের নীতিমালা (সবগুলো না মানলেও মূলগুলো জরুরি):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;একটাই কোডবেস, একাধিক deploy&lt;/li&gt;
&lt;li&gt;Dependency স্পষ্ট ঘোষণা (&lt;code&gt;.csproj&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;কনফিগ পরিবেশে (environment), কোডে নয়&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Backing service (DB, cache) কে সংযুক্ত রিসোর্স হিসেবে দেখুন&lt;/li&gt;
&lt;li&gt;Build/Release/Run আলাদা&lt;/li&gt;
&lt;li&gt;Process stateless&lt;/li&gt;
&lt;li&gt;দ্রুত চালু ও সুন্দরভাবে বন্ধ (graceful shutdown: &lt;code&gt;IHostApplicationLifetime&lt;/code&gt;, চলমান request শেষ করে বন্ধ)&lt;/li&gt;
&lt;li&gt;লগ event stream হিসেবে stdout এ&lt;/li&gt;
&lt;li&gt;Dev/Staging/Prod যতটা সম্ভব সদৃশ
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// অগ্রাধিকার ক্রমে (পরেরটা আগেরটাকে ওভাররাইড করে)&lt;/span&gt;
&lt;span class="c1"&gt;// appsettings.json → appsettings.{Environment}.json → user-secrets(dev) → Environment variables → Command line&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetConnectionString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Default"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Options pattern: টাইপ-সেফ কনফিগ&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;PaymentOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BindConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Payment"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ValidateDataAnnotations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ValidateOnStart&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;                &lt;span class="c1"&gt;// ভুল কনফিগে অ্যাপ চালুই হবে না, রাতে নয়, এখনই ধরা&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Part 9 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Logs + Metrics + Traces: তিনটিই দরকার; OpenTelemetry মানসম্মত পথ।&lt;/li&gt;
&lt;li&gt;Structured logging, correlation ID; alert হবে লক্ষণে, সংখ্যায় কম।&lt;/li&gt;
&lt;li&gt;Docker multi-stage, Compose স্থানীয় পরিবেশে; Kubernetes প্রয়োজন হলে, নইলে ম্যানেজড PaaS।&lt;/li&gt;
&lt;li&gt;CI/CD ও IaC; নিরাপদ deploy (rolling, blue-green, canary, feature flag)।&lt;/li&gt;
&lt;li&gt;Cloud এ Multi-AZ, auto-scaling, খরচ নজরদারি।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 10: Performance, Capacity Planning ও .NET Internals
&lt;/h2&gt;

&lt;p&gt;"সাইট ধীর" শুনলে বেশিরভাগ ডেভেলপার অনুমানে কোড বদলাতে শুরু করে। পেশাদার আগে &lt;strong&gt;মাপে&lt;/strong&gt;। Donald Knuth এর কথা: "অকাল optimization সব অনিষ্টের মূল।" এই Part এ শিখব কীভাবে মেপে, সঠিক জায়গায়, সঠিক উপায়ে দ্রুত করবেন।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১০.১ Performance এর সোনালি নিয়ম
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;আগে মাপুন, তারপর বদলান।&lt;/strong&gt; Profiler ছাড়া অনুমান প্রায়ই ভুল।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bottleneck খুঁজুন।&lt;/strong&gt; সিস্টেমের গতি সবচেয়ে ধীর অংশ ঠিক করে। ১% অংশ ১০ গুণ দ্রুত করলে লাভ নগণ্য।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;বেশিরভাগ সময় বাধা I/O&lt;/strong&gt; (DB, নেটওয়ার্ক), CPU নয়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;সবচেয়ে সস্তা জয় আগে:&lt;/strong&gt; index, N+1 ঠিক, cache, compression।&lt;/li&gt;
&lt;li&gt;পরিবর্তনের পরে &lt;strong&gt;আবার মাপুন&lt;/strong&gt;, সত্যিই উন্নতি হয়েছে কি না।&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;পারফরম্যান্স সমস্যা খোঁজার ক্রম:&lt;/strong&gt; ইউজার-অভিজ্ঞতা (ব্রাউজার, ছবি, JS) → নেটওয়ার্ক → API/অ্যাপ → ডেটাবেস।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১০.২ async/await: .NET এর সবচেয়ে বড় scalability হাতিয়ার (এবং ফাঁদ)
&lt;/h3&gt;

&lt;p&gt;উপমা: ওয়েটার (thread) এক টেবিলের রান্নার জন্য রান্নাঘরের সামনে দাঁড়িয়ে অপেক্ষা করলে ১০ টেবিল সামলাতে ১০ জন ওয়েটার লাগে। &lt;code&gt;async&lt;/code&gt; মানে ওয়েটার অর্ডার দিয়ে অন্য টেবিলে চলে যায়, খাবার তৈরি হলে ফিরে আসে। কম thread এ বেশি request।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Thread আটকে রাখে (Thread Pool Starvation এর কারণ)&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;               &lt;span class="c1"&gt;// sync I/O&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// .Result: ডেডলক/আটকে থাকার ঝুঁকি&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Thread মুক্ত রাখে&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsNoTracking&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I/O (DB, HTTP, ফাইল) এ &lt;strong&gt;সবসময় async&lt;/strong&gt;, শেষ পর্যন্ত ("async all the way")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;.Result&lt;/code&gt; / &lt;code&gt;.Wait()&lt;/code&gt; / &lt;code&gt;.GetAwaiter().GetResult()&lt;/code&gt; এড়ান&lt;/strong&gt;: Thread Pool Starvation (সব thread আটকে, সাইট জমে যায়)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;async void&lt;/code&gt; শুধু event handler এ; অন্যত্র &lt;code&gt;async Task&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;CPU-বাউন্ড ভারী কাজে async এর লাভ নেই (&lt;code&gt;Task.Run&lt;/code&gt; ASP.NET এ সাধারণত অপ্রয়োজনীয়)&lt;/li&gt;
&lt;li&gt;স্বাধীন কাজ সমান্তরালে: &lt;code&gt;await Task.WhenAll(a, b, c)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ValueTask&lt;/code&gt; শুধু প্রমাণিত হট পাথে (প্রায়ই সুবিধা তুচ্ছ)&lt;/li&gt;
&lt;li&gt;লাইব্রেরি কোডে &lt;code&gt;ConfigureAwait(false)&lt;/code&gt; (ASP.NET Core অ্যাপ কোডে দরকার নেই)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১০.৩ Memory ও Garbage Collector (GC)
&lt;/h3&gt;

&lt;p&gt;.NET স্বয়ংক্রিয় memory পরিচালনা করে, কিন্তু অনেক অকারণ allocation GC কে ব্যস্ত রাখে এবং request ধীর করে (GC pause)।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;মূল ধারণা:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack:&lt;/strong&gt; ছোট, দ্রুত; value type, local variable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Heap:&lt;/strong&gt; বড় অবজেক্ট, GC পরিচালিত&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generation 0/1/2:&lt;/strong&gt; নতুন অবজেক্ট Gen0 এ (সস্তা সংগ্রহ); বেঁচে থাকলে উঁচু প্রজন্মে। &lt;strong&gt;Gen2 সংগ্রহ ব্যয়বহুল&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LOH (Large Object Heap):&lt;/strong&gt; ~৮৫,০০০ বাইটের বেশি অবজেক্ট; ফ্র্যাগমেন্টেশন ও Gen2 চাপ বাড়ায়&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ব্যবহারিক কৌশল:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ লুপে string জোড়া: প্রতিবার নতুন string&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ StringBuilder&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;','&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ বড় array বারবার না বানিয়ে পুল&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Rent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ব্যবহার */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;ArrayPool&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;.&lt;/span&gt;&lt;span class="n"&gt;Shared&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Span&amp;lt;T&amp;gt; দিয়ে কপি ছাড়া slicing&lt;/span&gt;
&lt;span class="n"&gt;ReadOnlySpan&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AsSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;HttpClient&lt;/code&gt; প্রতি request এ &lt;code&gt;new&lt;/code&gt; নয়; &lt;code&gt;IHttpClientFactory&lt;/code&gt; (socket exhaustion ও DNS সমস্যা এড়ায়)&lt;/li&gt;
&lt;li&gt;বড় ফাইল/response &lt;strong&gt;stream&lt;/strong&gt; করুন, পুরোটা মেমরিতে নয়&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;IDisposable&lt;/code&gt; (DB connection, stream) ঠিকমতো &lt;code&gt;using&lt;/code&gt; দিয়ে ছাড়ুন&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory Leak এর সাধারণ কারণ:&lt;/strong&gt; static collection এ জমা, event handler unsubscribe না করা, বিশাল cache এ সীমা নেই&lt;/li&gt;
&lt;li&gt;সংগ্রহ ও লুপে LINQ এর অতিরিক্ত অ্যালোকেশন (হট পাথে সচেতন থাকুন, সাধারণ কোডে পাঠযোগ্যতাই আগে)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১০.৪ মাপার টুল
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;টুল&lt;/th&gt;
&lt;th&gt;কাজ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;BenchmarkDotNet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;micro-benchmark: কোডের একটা অংশের গতি ও মেমরি নির্ভরযোগ্যভাবে মাপা&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;dotnet-counters / dotnet-trace / dotnet-dump&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;চলমান অ্যাপের মেট্রিক, trace, মেমরি dump&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Visual Studio / JetBrains dotTrace, dotMemory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;profiler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Application Insights / OpenTelemetry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;production এ ধীর endpoint ও dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQL Profiler / Query Store / EXPLAIN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ধীর query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;k6, JMeter, NBomber, Locust&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;load test&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Load Testing এর ধরন:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Load test:&lt;/strong&gt; প্রত্যাশিত ট্রাফিকে ঠিক চলে কি না&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stress test:&lt;/strong&gt; সীমা ছাড়িয়ে কোথায় ভাঙে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spike test:&lt;/strong&gt; হঠাৎ ট্রাফিক-ঢেউ (ঈদের সেল)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Soak test:&lt;/strong&gt; দীর্ঘ সময় (লিক, ক্লান্তি ধরা পড়ে)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;প্রোডাকশন-সদৃশ পরিবেশে ও বাস্তবসম্মত ডেটায়&lt;/strong&gt; পরীক্ষা করুন; খালি ডেটাবেসে ফল প্রতারণাপূর্ণ।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১০.৫ Capacity Planning: Back-of-the-Envelope হিসাব
&lt;/h3&gt;

&lt;p&gt;System design interview ও বাস্তব পরিকল্পনা, দুটোতেই কাজে লাগে। উদ্দেশ্য নিখুঁত সংখ্যা নয়, &lt;strong&gt;মাত্রা (order of magnitude)&lt;/strong&gt; বোঝা।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কাজের সংখ্যা:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;১ দিন ≈ ৮৬,৪০০ সেকেন্ড ≈ ~১ লক্ষ সেকেন্ড (হিসাব সহজ করতে)&lt;/li&gt;
&lt;li&gt;১ কোটি request/দিন ÷ ১ লক্ষ ≈ &lt;strong&gt;১০০ request/সেকেন্ড (গড়)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;পিক সাধারণত গড়ের ২-১০ গুণ → ধরুন ৫ গুণ = &lt;strong&gt;৫০০ RPS&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ShopEasy হিসাব (ধরে নেওয়া সংখ্যা):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Daily Active Users (DAU): ১০ লক্ষ&lt;/li&gt;
&lt;li&gt;প্রতি ইউজার দিনে ৫০টি request → ৫ কোটি request/দিন&lt;/li&gt;
&lt;li&gt;গড় RPS = ৫ কোটি ÷ ১ লক্ষ ≈ ৫০০; পিক ৫ গুণ ≈ ২,৫০০ RPS&lt;/li&gt;
&lt;li&gt;যদি একটা সার্ভার ~৫০০ RPS সামলায় (মেপে দেখে), তাহলে পিকে ~৫টা + নিরাপদ মার্জিন/redundancy = ৮-১০টা সার্ভার&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Storage হিসাব:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;দিনে ৫০,০০০ অর্ডার × ২ KB = ~১০০ MB/দিন → বছরে ~৩৬ GB। ছোট!&lt;/li&gt;
&lt;li&gt;পণ্য ছবি: ১০ লক্ষ পণ্য × ৫ ছবি × ২০০ KB = ~১ TB। ফাইল স্টোরেজ/CDN এ, DB তে নয়&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Read:Write অনুপাত:&lt;/strong&gt; ই-কমার্স সাধারণত read-heavy (১০০:১)। তাই cache ও read replica কার্যকর।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bandwidth:&lt;/strong&gt; ২,৫০০ RPS × ৫০ KB response = ~১২৫ MB/s ≈ ১ Gbps। CDN ও compression তখন জরুরি।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latency Budget:&lt;/strong&gt; মোট লক্ষ্য ৩০০ ms হলে ভাগ করুন: নেটওয়ার্ক ৫০, Gateway ১০, API ৭০, DB ১০০, বাকি মার্জিন। কোনো অংশ বাজেট ছাড়ালে বোঝা যায় কোথায় কাজ।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কয়েকটি স্মরণীয় সংখ্যা (আনুমানিক):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;একটা সাধারণ ওয়েব সার্ভার/অ্যাপ instance: শত থেকে কয়েক হাজার RPS (কাজের ওপর নির্ভর)&lt;/li&gt;
&lt;li&gt;একটা ভালো SQL সার্ভার: হাজার থেকে দশ হাজার সাধারণ query/সেকেন্ড&lt;/li&gt;
&lt;li&gt;Redis: প্রতি সেকেন্ডে লক্ষ operation&lt;/li&gt;
&lt;li&gt;Kafka: প্রতি সেকেন্ডে লক্ষ লক্ষ বার্তা (cluster এ)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(এগুলো মোটামুটি ধারণা; আপনার কাজের ধরনে &lt;strong&gt;নিজে মেপে&lt;/strong&gt; নিন।)&lt;/p&gt;

&lt;h3&gt;
  
  
  ১০.৬ Scaling এর ধাপ: ShopEasy এর যাত্রার সারাংশ
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ধাপ&lt;/th&gt;
&lt;th&gt;ইউজার (আনুমানিক)&lt;/th&gt;
&lt;th&gt;কী করবেন&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;১&lt;/td&gt;
&lt;td&gt;~১০০-১,০০০&lt;/td&gt;
&lt;td&gt;একটাই সার্ভার, একটাই DB। সরল ও পর্যাপ্ত।&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;২&lt;/td&gt;
&lt;td&gt;~১০,০০০&lt;/td&gt;
&lt;td&gt;Index, query ঠিক; DB আলাদা সার্ভারে; CDN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;৩&lt;/td&gt;
&lt;td&gt;~১ লক্ষ&lt;/td&gt;
&lt;td&gt;একাধিক app server + Load Balancer (stateless); Redis cache; read replica&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;৪&lt;/td&gt;
&lt;td&gt;~১০ লক্ষ&lt;/td&gt;
&lt;td&gt;Message queue, background worker; auto-scaling; DB পারটিশনিং; search ইঞ্জিন&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;৫&lt;/td&gt;
&lt;td&gt;১০ লক্ষ+&lt;/td&gt;
&lt;td&gt;Microservices (যদি টিম/ডোমেইন দাবি করে); sharding; multi-region&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;সংখ্যাগুলো কেবল দিকনির্দেশ।&lt;/strong&gt; বাস্তবে ঠিক হয় ট্রাফিক ধরন ও কাজের জটিলতা দিয়ে। কোনো সংখ্যায় লাফ দেওয়ার আগে মাপুন।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability নীতি:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;আগে Stateless বানান&lt;/li&gt;
&lt;li&gt;Database ই সাধারণত প্রথম বাধা; সেখান থেকে শুরু&lt;/li&gt;
&lt;li&gt;পড়া ও লেখা আলাদা করে ভাবুন&lt;/li&gt;
&lt;li&gt;ভারী ও ধীর কাজ অ্যাসিঙ্ক&lt;/li&gt;
&lt;li&gt;সম্ভব হলে কাজ ভাগ করুন (partition), যাতে সমান্তরালে চলে&lt;/li&gt;
&lt;li&gt;স্বয়ংক্রিয় scaling, কিন্তু সীমা ঠিক রাখুন (খরচ ও downstream নির্ভরতা বাঁচাতে)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১০.৭ ফ্রন্টএন্ড-সংলগ্ন ও নেটওয়ার্ক পারফরম্যান্স
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compression:&lt;/strong&gt; &lt;code&gt;app.UseResponseCompression()&lt;/code&gt; (Brotli/Gzip), JSON আকার কমে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP/2, HTTP/3:&lt;/strong&gt; একই সংযোগে একাধিক request, Kestrel সমর্থন করে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static asset:&lt;/strong&gt; CDN, দীর্ঘ cache + ফাইলনামে hash (cache busting), ছবি অপ্টিমাইজ (WebP/AVIF), lazy loading&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payload ছোট করা:&lt;/strong&gt; শুধু দরকারি ফিল্ড; pagination; &lt;code&gt;System.Text.Json&lt;/code&gt; (Newtonsoft এর চেয়ে সাধারণত দ্রুত); source generator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connection Pooling:&lt;/strong&gt; DB connection পুল (ADO.NET ডিফল্টে আছে); পুল ফুরালে request আটকে যায়। &lt;code&gt;Max Pool Size&lt;/code&gt; ও দীর্ঘ-চলা transaction এর দিকে নজর&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keep-Alive ও HttpClient পুনর্ব্যবহার&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১০.৮ সাধারণ .NET পারফরম্যান্স ফাঁদ (সংক্ষিপ্ত তালিকা)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ফাঁদ&lt;/th&gt;
&lt;th&gt;সমাধান&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;N+1 query&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Include&lt;/code&gt;/projection/&lt;code&gt;AsSplitQuery&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;Select *&lt;/code&gt; ও পুরো entity&lt;/td&gt;
&lt;td&gt;projection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pagination নেই&lt;/td&gt;
&lt;td&gt;keyset/offset + সীমা&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;.Result&lt;/code&gt;/&lt;code&gt;.Wait()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;async all the way&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;new HttpClient()&lt;/code&gt; প্রতিবার&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IHttpClientFactory&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;বড় object cache এ সীমাহীন&lt;/td&gt;
&lt;td&gt;সাইজ সীমা, মেয়াদ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;লুপের ভেতরে DB/HTTP call&lt;/td&gt;
&lt;td&gt;batch করুন&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;অতিরিক্ত লগ&lt;/td&gt;
&lt;td&gt;লেভেল ঠিক রাখুন&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exception দিয়ে স্বাভাবিক flow&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;TryParse&lt;/code&gt;, ফলাফল-টাইপ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regex অকার্যকর (ReDoS)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;RegexOptions.Compiled&lt;/code&gt;/source generator, timeout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reflection/dynamic হট পাথে&lt;/td&gt;
&lt;td&gt;source generator&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Part 10 এর সারসংক্ষেপ
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;আগে মাপুন (profiler, load test, trace), তারপর optimize।&lt;/li&gt;
&lt;li&gt;I/O তে async all the way; &lt;code&gt;.Result&lt;/code&gt; নয়।&lt;/li&gt;
&lt;li&gt;অকারণ allocation কমান; &lt;code&gt;IHttpClientFactory&lt;/code&gt;, stream, পুল।&lt;/li&gt;
&lt;li&gt;Capacity planning এ order of magnitude; DAU → RPS → সার্ভার/স্টোরেজ।&lt;/li&gt;
&lt;li&gt;Scale করুন ধাপে ধাপে; প্রয়োজনের আগে নয়।&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 11: Case Study: তিনটি সম্পূর্ণ System Design
&lt;/h2&gt;

&lt;p&gt;তত্ত্ব শিখলেন; এখন প্রয়োগ। প্রতিটি case study তে একই কাঠামো অনুসরণ করব (Part 12 এর ফ্রেমওয়ার্ক): প্রয়োজন → হিসাব → উচ্চস্তরের নকশা → ডেটা মডেল → গভীরে সিদ্ধান্ত → ট্রেড-অফ।&lt;/p&gt;

&lt;h3&gt;
  
  
  Case Study ১: URL Shortener (যেমন bit.ly)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;সমস্যা:&lt;/strong&gt; লম্বা URL কে ছোট করে (&lt;code&gt;sho.rt/aB3xK9&lt;/code&gt;), ছোটটায় ঢুকলে মূলটায় redirect।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ১: প্রয়োজন
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Functional:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;লম্বা URL দিলে ছোট URL তৈরি&lt;/li&gt;
&lt;li&gt;ছোট URL এ ঢুকলে redirect&lt;/li&gt;
&lt;li&gt;(ঐচ্ছিক) কাস্টম alias, মেয়াদ, ক্লিক-অ্যানালিটিক্স&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Non-functional:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redirect অত্যন্ত দ্রুত (&amp;lt; ১০০ ms) ও উচ্চ availability&lt;/li&gt;
&lt;li&gt;Read-heavy: প্রতি ১ তৈরিতে ~১০০ redirect&lt;/li&gt;
&lt;li&gt;Short code অনুমানযোগ্য নয়, ডুপ্লিকেট নয়&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ধাপ ২: হিসাব (ধরে নিচ্ছি)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;নতুন URL: ১০ কোটি/মাস ≈ ~৪০ write/সেকেন্ড&lt;/li&gt;
&lt;li&gt;Redirect (১০০:১): ~৪,০০০ read/সেকেন্ড গড়; পিক ~১২,০০০&lt;/li&gt;
&lt;li&gt;৫ বছর সংরক্ষণ: ১০ কোটি × ১২ × ৫ = ৬০০ কোটি রেকর্ড। প্রতিটি ~৫০০ বাইট → &lt;strong&gt;~৩ TB&lt;/strong&gt;। (একটা আধুনিক ক্লাস্টারে সম্ভব)&lt;/li&gt;
&lt;li&gt;Short code দৈর্ঘ্য: Base62 (&lt;code&gt;a-z, A-Z, 0-9&lt;/code&gt;) এ ৭ অক্ষর = 62^7 ≈ ৩.৫ ট্রিলিয়ন সংমিশ্রণ। ৬০০ কোটির জন্য যথেষ্ট&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ধাপ ৩: উচ্চস্তরের নকশা
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → CDN/Load Balancer → API Servers (stateless, .NET)
                                 ├── Cache (Redis): code → longUrl
                                 └── Database (code → longUrl)
                                 └── (async) Queue → Analytics Worker → Analytics DB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ধাপ ৪: API
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/urls"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateUrlRequest&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IUrlService&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LongUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomAlias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;shortUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"https://sho.rt/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{code}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IUrlService&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ResolveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;permanent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;301 বনাম 302:&lt;/strong&gt; ৩০১ (স্থায়ী) ব্রাউজার cache করে, ফলে সার্ভারে hit কমে কিন্তু ক্লিক গণনা হারায়। অ্যানালিটিক্স চাইলে ৩০২।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ৫: Short code তৈরির কৌশল (মূল সিদ্ধান্ত)
&lt;/h4&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;পদ্ধতি&lt;/th&gt;
&lt;th&gt;কীভাবে&lt;/th&gt;
&lt;th&gt;সমস্যা&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hash (MD5/SHA) এর প্রথম ৭ অক্ষর&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;URL এর hash&lt;/td&gt;
&lt;td&gt;সংঘর্ষ (collision) সম্ভব; পরীক্ষা ও retry লাগে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Random Base62&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;র‍্যান্ডম ৭ অক্ষর&lt;/td&gt;
&lt;td&gt;সংঘর্ষ সম্ভব (unique constraint + retry)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Counter + Base62&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;একটা বাড়তে থাকা সংখ্যাকে Base62 এ রূপান্তর&lt;/td&gt;
&lt;td&gt;সংঘর্ষ নেই; কিন্তু অনুমানযোগ্য, আর কাউন্টার distributed এ জটিল&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pre-generated Key Service (KGS)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;আগে থেকে অনেক unique key তৈরি করে রাখা; চাইলে একটা দেওয়া&lt;/td&gt;
&lt;td&gt;সরল ও দ্রুত; KGS এর availability নিশ্চিত করতে হবে&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;সিদ্ধান্ত:&lt;/strong&gt; Counter-based ID (Snowflake-জাতীয় বা ডেটাবেস sequence ব্লক বরাদ্দ করে প্রতি সার্ভারে) + Base62 এনকোড। অনুমানযোগ্যতা সমস্যা হলে সংখ্যাকে অদলবদল (permutation/obfuscation) করুন। প্রতিটি API সার্ভার একসাথে ১০০০ ID এর ব্লক নিয়ে স্থানীয়ভাবে বিতরণ করে, প্রতিবার DB তে না গিয়ে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Base62&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Chars&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Chars&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="m"&gt;62&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;/=&lt;/span&gt; &lt;span class="m"&gt;62&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ধাপ ৬: ডেটা মডেল ও ডেটাবেস
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Urls(Code PK, LongUrl, UserId, CreatedAt, ExpiresAt)&lt;/code&gt;। সরল key-value access pattern (শুধু code দিয়ে খোঁজা), জটিল JOIN নেই। তাই SQL (PostgreSQL) বা NoSQL (DynamoDB/Cassandra) দুটোই চলে। শুরুতে SQL; বিপুল scale এ key-value store।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ৭: Scaling ও অপ্টিমাইজেশন
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cache (Redis):&lt;/strong&gt; জনপ্রিয় URL সামান্য সংখ্যক; ২০% URL এ ৮০% ট্রাফিক (Pareto)। Cache-Aside, LRU eviction, TTL। ফলে DB তে খুব কম hit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read replica&lt;/strong&gt;, তারপর &lt;strong&gt;sharding&lt;/strong&gt; (shard key = code এর hash)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics অ্যাসিঙ্ক:&lt;/strong&gt; ক্লিক event queue তে ফেলে আলাদা worker; redirect এর পথ ধীর হয় না&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;মেয়াদোত্তীর্ণ লিংক পরিষ্কার:&lt;/strong&gt; background job&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limit ও অপব্যবহার প্রতিরোধ:&lt;/strong&gt; ম্যালওয়্যার/ফিশিং লিংক চেক, তৈরির rate limit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ট্রেড-অফ:&lt;/strong&gt; Cache এ মুছে ফেলা/বদলানো লিংকের পুরনো ডেটা কিছুক্ষণ থাকতে পারে (TTL ও invalidation)। Redirect এ eventual consistency গ্রহণযোগ্য।&lt;/p&gt;




&lt;h3&gt;
  
  
  Case Study ২: E-Commerce Order System (ShopEasy এর কেন্দ্র)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;সমস্যা:&lt;/strong&gt; ঈদের সেলে হাজারো ইউজার একসাথে কিনছে; স্টক ঠিক রাখা, পেমেন্ট নিরাপদ, কোনো অর্ডার হারানো বা দুবার প্রক্রিয়া নয়।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ১: প্রয়োজন
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;পণ্য ব্রাউজ/সার্চ, cart, checkout, পেমেন্ট, অর্ডার ট্র্যাকিং, ইমেইল/SMS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;কঠোর সঠিকতা:&lt;/strong&gt; স্টকের বেশি বিক্রি নয়, পেমেন্ট ডুপ্লিকেট নয়&lt;/li&gt;
&lt;li&gt;ঈদের সময় ১০-২০ গুণ spike; ৯৯.৯% availability (checkout এ)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ধাপ ২: Bounded Context (Part 3 এর DDD)
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Catalog&lt;/code&gt; (পণ্য), &lt;code&gt;Cart&lt;/code&gt;, &lt;code&gt;Ordering&lt;/code&gt;, &lt;code&gt;Inventory&lt;/code&gt;, &lt;code&gt;Payment&lt;/code&gt;, &lt;code&gt;Shipping&lt;/code&gt;, &lt;code&gt;Notification&lt;/code&gt;, &lt;code&gt;Identity&lt;/code&gt;।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;স্থাপত্য সিদ্ধান্ত:&lt;/strong&gt; শুরুতে &lt;strong&gt;Modular Monolith&lt;/strong&gt;। চাপের অংশ (Catalog পড়া, Payment) পরে আলাদা করা যাবে।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ৩: উচ্চস্তরের প্রবাহ
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client → CDN → API Gateway (YARP: auth, rate limit)
   → Catalog (read-heavy: Redis + Elasticsearch)
   → Cart (Redis, user-keyed)
   → Ordering → [Payment, Inventory, Shipping] (Saga)
   → Outbox → Message Broker → Notification, Analytics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ধাপ ৪: Catalog (পড়া-ভারী)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;মূল ডেটা SQL এ; সার্চ ও ফিল্টারের জন্য &lt;strong&gt;Elasticsearch&lt;/strong&gt; (পণ্য ইভেন্টে সিঙ্ক, eventual consistency)&lt;/li&gt;
&lt;li&gt;ছবি &lt;strong&gt;CDN&lt;/strong&gt; এ; পণ্য পেজ HybridCache&lt;/li&gt;
&lt;li&gt;দাম ও স্টক সামান্য পুরনো দেখালেও চলে, কিন্তু &lt;strong&gt;checkout এ আবার যাচাই&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ধাপ ৫: Cart
&lt;/h4&gt;

&lt;p&gt;স্থায়ী নয়, দ্রুত বদলায়, ইউজার-কেন্দ্রিক। &lt;strong&gt;Redis Hash&lt;/strong&gt; (&lt;code&gt;cart:{userId}&lt;/code&gt; → পণ্য ও পরিমাণ), মেয়াদ ৭ দিন। লগইনের আগে অতিথির cart কে (cookie) লগইনের পর মার্জ।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ৬: Checkout ও Inventory: কঠিনতম অংশ
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;সমস্যা:&lt;/strong&gt; শেষ ১০টা ফোন, ১০,০০০ জন একসাথে কিনতে চায়।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;কৌশল: Reservation (সাময়িক সংরক্ষণ)।&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checkout এ স্টক &lt;strong&gt;Reserve&lt;/strong&gt; (atomic, শর্তসাপেক্ষ আপডেট), মেয়াদ ১৫ মিনিট&lt;/li&gt;
&lt;li&gt;পেমেন্ট সফল হলে Reservation &lt;strong&gt;নিশ্চিত&lt;/strong&gt;; ব্যর্থ বা মেয়াদোত্তীর্ণ হলে স্টক &lt;strong&gt;ফেরত&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Atomic: যথেষ্ট স্টক থাকলে তবেই কমাও (race condition নেই)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExecuteSqlInterpolatedAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$@"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;    UPDATE Inventory&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;    SET Available = Available - &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, Reserved = Reserved + &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;    WHERE ProductId = &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; AND Available &amp;gt;= &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;qty&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updated&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Out of stock"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;অতি-হট পণ্যে (ফ্ল্যাশ সেল) এক row এ হাজারো লেখা &lt;strong&gt;hot row lock contention&lt;/strong&gt; ঘটায়। সমাধান: স্টক কয়েকটা "বালতি" (slot) এ ভাগ করা, Redis এ atomic &lt;code&gt;DECR&lt;/code&gt; দিয়ে দ্রুত গেট, ও পরে DB তে সামঞ্জস্য; এবং waiting room/queue দিয়ে ট্রাফিক নিয়ন্ত্রণ।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ৭: Order Saga (Part 6)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;স্বাভাবিক প্রবাহ:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OrderCreated(Pending)
 → ReserveStock ✔
 → ChargePayment ✔
 → OrderConfirmed → ShipOrder → Notify
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ব্যর্থতা সামলানো:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;যেখানে ব্যর্থ&lt;/th&gt;
&lt;th&gt;ক্ষতিপূরণ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Stock নেই&lt;/td&gt;
&lt;td&gt;Order বাতিল (কিছু ফেরত দিতে হবে না)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment ব্যর্থ&lt;/td&gt;
&lt;td&gt;স্টক Release, Order বাতিল&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment সফল কিন্তু Shipping ব্যর্থ&lt;/td&gt;
&lt;td&gt;পুনরায় চেষ্টা; শেষে Refund + স্টক Release&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payment gateway timeout (সফল না ব্যর্থ অজানা)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;অবস্থা অজানা&lt;/strong&gt;: gateway এ status query/webhook এর অপেক্ষা; স্বয়ংক্রিয়ভাবে পুনর্মিলন (reconciliation)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Orchestration&lt;/strong&gt; পছন্দ (MassTransit State Machine বা Durable Functions): প্রবাহ স্পষ্ট, সহজে ট্র্যাক ও debug।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ৮: Payment নিরাপত্তা ও সঠিকতা
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;কার্ডের তথ্য নিজে ধরবেন না; gateway এর hosted page/tokenization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency Key&lt;/strong&gt; (Part 5) প্রতিটি পেমেন্ট চেষ্টায়&lt;/li&gt;
&lt;li&gt;gateway থেকে &lt;strong&gt;Webhook&lt;/strong&gt; এর মাধ্যমে চূড়ান্ত অবস্থা (signature যাচাই, idempotent handler)&lt;/li&gt;
&lt;li&gt;নিয়মিত &lt;strong&gt;Reconciliation job&lt;/strong&gt; (দৈনিক gateway রিপোর্টের সাথে আমাদের রেকর্ড মেলানো)&lt;/li&gt;
&lt;li&gt;Money এর জন্য &lt;code&gt;decimal&lt;/code&gt;/Money value object, একক মুদ্রা, পূর্ণসংখ্যায় (পয়সা) সংরক্ষণ বিবেচনা&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ধাপ ৯: Order এর অবস্থা (State Machine)
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Pending → PaymentPending → Paid → Shipped → Delivered&lt;/code&gt;; বিকল্প &lt;code&gt;Cancelled&lt;/code&gt;, &lt;code&gt;Refunded&lt;/code&gt;। কেবল &lt;strong&gt;বৈধ transition&lt;/strong&gt; অনুমোদিত (Domain model এ, &lt;code&gt;Order.Confirm()&lt;/code&gt; ইত্যাদিতে), অবৈধ ধাপে exception।&lt;/p&gt;

&lt;h4&gt;
  
  
  ধাপ ১০: Spike সামলানো (ঈদের সেল)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;আগে থেকে &lt;strong&gt;scale out&lt;/strong&gt; (নির্ধারিত সময়ে auto-scaling) ও cache গরম (warm-up)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Waiting Room:&lt;/strong&gt; ট্রাফিক সীমা ছাড়ালে ইউজারকে লাইনে রাখা, সিস্টেম বাঁচানো&lt;/li&gt;
&lt;li&gt;Checkout ছাড়া অনাবশ্যক ফিচার সাময়িক বন্ধ (graceful degradation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt;, বট প্রতিরোধ (CAPTCHA/WAF)&lt;/li&gt;
&lt;li&gt;Load test আগে (Spike test)&lt;/li&gt;
&lt;li&gt;DB connection pool ও queue গভীরতা পর্যবেক্ষণ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ট্রেড-অফ:&lt;/strong&gt; Strong consistency (স্টক, পেমেন্ট) ধীর কিন্তু প্রয়োজনীয়; Catalog, সার্চ, রিভিউ eventual consistency তে স্বচ্ছন্দ। &lt;strong&gt;একই সিস্টেমে বিভিন্ন অংশে ভিন্ন consistency&lt;/strong&gt;; এটাই পরিপক্ক design।&lt;/p&gt;




&lt;h3&gt;
  
  
  Case Study ৩: Notification System (ইমেইল, SMS, Push)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;সমস্যা:&lt;/strong&gt; অর্ডার, OTP, প্রমোশন: কোটি কোটি বার্তা, বিভিন্ন চ্যানেলে, নির্ভরযোগ্যভাবে, ডুপ্লিকেট ছাড়া।&lt;/p&gt;

&lt;h4&gt;
  
  
  প্রয়োজন
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;চ্যানেল: Email, SMS, Push, In-app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OTP&lt;/strong&gt;: সেকেন্ডে পৌঁছানো (উচ্চ অগ্রাধিকার); &lt;strong&gt;প্রমোশন&lt;/strong&gt;: ধীরে চললেও চলে&lt;/li&gt;
&lt;li&gt;ইউজারের পছন্দ ও opt-out সম্মান করা&lt;/li&gt;
&lt;li&gt;ডুপ্লিকেট নয়, বার্তা হারানো নয়&lt;/li&gt;
&lt;li&gt;Third-party (Twilio, SendGrid ইত্যাদি) ধীর বা ডাউন হতে পারে&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  নকশা
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;সার্ভিস (Order, Auth...) → Notification API
     → Validation + Preference check + Template
     → Outbox → Message Broker
          ├── high-priority queue  (OTP, লেনদেন)
          ├── normal queue         (অর্ডার আপডেট)
          └── bulk queue           (প্রমোশন)
     → Channel Workers (Email / SMS / Push), প্রতিটি আলাদাভাবে scalable
     → Provider Adapter (Strategy: SendGrid | SES | Twilio ...)
     → Delivery status (webhook) → Notification DB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  মূল সিদ্ধান্ত
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;অগ্রাধিকার-ভিত্তিক আলাদা queue:&lt;/strong&gt; প্রমোশনের বিশাল ব্যাচ OTP আটকাবে না (&lt;strong&gt;Noisy Neighbor&lt;/strong&gt; প্রতিরোধ, Bulkhead)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provider abstraction (Strategy/Adapter):&lt;/strong&gt; &lt;code&gt;IEmailProvider&lt;/code&gt; এর পেছনে একাধিক ভেন্ডর; একটা ডাউন হলে &lt;strong&gt;Fallback&lt;/strong&gt; অন্যটিতে (Circuit Breaker সহ)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency:&lt;/strong&gt; প্রতিটি বার্তার একটা unique key; consumer ডুপ্লিকেট প্রত্যাখ্যান করে (ইউজার একই OTP দুবার পাবে না)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retry + backoff + DLQ:&lt;/strong&gt; ব্যর্থ বার্তা পুনরায়, শেষে DLQ এ ও alert&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting (provider ও ইউজার-ভিত্তিক):&lt;/strong&gt; provider এর সীমা মানা; এক ইউজারকে স্প্যাম নয়&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Template ও লোকালাইজেশন:&lt;/strong&gt; বাংলা/ইংরেজি; ভেরিয়েবল প্রতিস্থাপন&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled/Delayed বার্তা:&lt;/strong&gt; "সকাল ৯টায় পাঠান" (delayed queue / scheduler)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ট্র্যাকিং:&lt;/strong&gt; Sent → Delivered → Opened/Failed webhook থেকে অবস্থা হালনাগাদ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;অ্যানালিটিক্স অ্যাসিঙ্ক:&lt;/strong&gt; মূল পথ ধীর নয়
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ISmsProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SendResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FailoverSmsSender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ISmsProvider&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FailoverSmsSender&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SendResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogWarning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{Provider} failed, trying next"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;NotificationFailedException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"All providers failed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ট্রেড-অফ:&lt;/strong&gt; exactly-once অসম্ভব, তাই At-least-once + idempotency। অত্যন্ত জরুরি OTP তে সামান্য ডুপ্লিকেট চেয়ে হারানো খারাপ, তাই ডুপ্লিকেট সহনীয়, হারানো নয়।&lt;/p&gt;




&lt;h3&gt;
  
  
  কেস স্টাডি থেকে শিক্ষা (সূত্র)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;প্রয়োজন ও সংখ্যা দিয়ে শুরু&lt;/strong&gt; (অনুমান নয়)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read-heavy&lt;/strong&gt; হলে cache ও replica; &lt;strong&gt;Write-heavy&lt;/strong&gt; হলে queue, partition&lt;/li&gt;
&lt;li&gt;ধীর, ঝুঁকিপূর্ণ বা তৃতীয়-পক্ষ নির্ভর কাজ &lt;strong&gt;অ্যাসিঙ্ক&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;সঠিকতা-সংবেদনশীল অংশে (টাকা, স্টক) &lt;strong&gt;strong consistency ও idempotency&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;প্রতিটি নির্ভরতার জন্য ব্যর্থতার পরিকল্পনা (timeout, retry, fallback)&lt;/li&gt;
&lt;li&gt;সরল দিয়ে শুরু, মাপার পর জটিল করুন&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 12: বাস্তব জীবনের পদ্ধতি: Framework, Trade-off ও Roadmap
&lt;/h2&gt;

&lt;p&gt;এতক্ষণ আপনি অনেক "হাতিয়ার" শিখলেন। এখন শেখার সময় &lt;strong&gt;কখন কোনটা ধরবেন&lt;/strong&gt; এবং &lt;strong&gt;কীভাবে সিদ্ধান্ত নেবেন ও ব্যাখ্যা করবেন।&lt;/strong&gt; এটাই একজন সিনিয়র/আর্কিটেক্টকে আলাদা করে।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১২.১ System Design এর ৭-ধাপ ফ্রেমওয়ার্ক
&lt;/h3&gt;

&lt;p&gt;যেকোনো নতুন সিস্টেম (প্রজেক্টে বা ইন্টারভিউতে) এই ক্রমে ভাবুন:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;প্রয়োজন স্পষ্ট করুন (Requirements)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Functional: সিস্টেম কী করবে?&lt;/li&gt;
&lt;li&gt;Non-functional: কতজন ইউজার? কত দ্রুত? কতটা নির্ভরযোগ্য? নিরাপত্তা? বাজেট? সময়সীমা?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;প্রশ্ন করুন।&lt;/strong&gt; অস্পষ্টতা নিয়ে নকশা শুরু করবেন না।&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;সীমা ও অনুমান (Constraints &amp;amp; Assumptions):&lt;/strong&gt; টিমের আকার ও দক্ষতা, বাজেট, বিদ্যমান সিস্টেম, আইনি বিধি।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;হিসাব (Estimation):&lt;/strong&gt; DAU, RPS, স্টোরেজ, bandwidth (Part 10)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;উচ্চস্তরের নকশা (High-level Design):&lt;/strong&gt; প্রধান উপাদান (ক্লায়েন্ট, Gateway, সার্ভিস, DB, Cache, Queue) ও তাদের সংযোগ। আগে সরল নকশা।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ডেটা মডেল ও API:&lt;/strong&gt; মূল entity, সম্পর্ক, access pattern, প্রধান endpoint।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;গভীরে যাওয়া (Deep Dive):&lt;/strong&gt; সবচেয়ে কঠিন/ঝুঁকিপূর্ণ অংশ (স্টক রেস, ID তৈরি, ডুপ্লিকেট প্রতিরোধ)।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bottleneck, ব্যর্থতা ও Trade-off:&lt;/strong&gt; কোথায় ভাঙবে? কীভাবে scale হবে? কী ছাড়লাম, কেন?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;সময় ভাগ (ইন্টারভিউয়ে ৪৫ মিনিট):&lt;/strong&gt; প্রয়োজন ৫-৮, উচ্চস্তর ১০-১৫, গভীরে ১৫-২০, শেষে ৫।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১২.২ সিদ্ধান্ত নেওয়ার প্রশ্নমালা
&lt;/h3&gt;

&lt;p&gt;যেকোনো প্রযুক্তি/কৌশল বাছাইয়ের আগে নিজেকে জিজ্ঞেস করুন:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;কোন সমস্যা সমাধান করছি?&lt;/strong&gt; (সমস্যা প্রমাণিত, নাকি কল্পিত?)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;সরলতম বিকল্প কী?&lt;/strong&gt; সেটা কেন যথেষ্ট নয়?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;এর দাম কী?&lt;/strong&gt; (জটিলতা, শেখার সময়, অপারেশন, খরচ, ভেন্ডর-নির্ভরতা)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;টিম কি এটা চালাতে পারবে?&lt;/strong&gt; রাত ২টায় কে ঠিক করবে?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;উল্টানো কত কঠিন?&lt;/strong&gt; (Two-way door বনাম one-way door সিদ্ধান্ত। সহজে ফেরানো যায় এমনটা দ্রুত নিন, ফেরানো কঠিনটা সাবধানে)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;বিকল্প কী কী ছিল, কেন বাদ দিলাম?&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১২.৩ Architecture Decision Record (ADR)
&lt;/h3&gt;

&lt;p&gt;ছয় মাস পরে কেউ জিজ্ঞেস করবে: "কেন আমরা MongoDB নিলাম না?" কেউ মনে রাখবে না। তাই সিদ্ধান্ত &lt;strong&gt;লিখে রাখুন&lt;/strong&gt;: ছোট একটা ফাইল (&lt;code&gt;docs/adr/0007-use-postgresql.md&lt;/code&gt;), Git এ কোডের সাথে।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# ADR-0007: অর্ডার ডেটাবেস হিসেবে PostgreSQL&lt;/span&gt;

&lt;span class="gu"&gt;## অবস্থা&lt;/span&gt;
গৃহীত (২০২৬-১০-২৮)

&lt;span class="gu"&gt;## প্রেক্ষাপট&lt;/span&gt;
অর্ডার ও পেমেন্টে শক্তিশালী ACID transaction ও জটিল রিপোর্টিং লাগবে। টিম SQL এ দক্ষ।

&lt;span class="gu"&gt;## সিদ্ধান্ত&lt;/span&gt;
PostgreSQL ব্যবহার করব (ম্যানেজড সার্ভিসে)।

&lt;span class="gu"&gt;## বিকল্প&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; MongoDB: নমনীয় schema, কিন্তু multi-document transaction ও রিপোর্টিং জটিল
&lt;span class="p"&gt;-&lt;/span&gt; SQL Server: ভালো, কিন্তু লাইসেন্স খরচ বেশি

&lt;span class="gu"&gt;## পরিণতি&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; ACID, পরিপক্ক ইকোসিস্টেম, কম খরচ
− অতি-বিশাল scale এ sharding জটিল (বর্তমান প্রয়োজনে প্রযোজ্য নয়)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;সিদ্ধান্ত বদলালে পুরনোটা মুছবেন না; "Superseded by ADR-0015" চিহ্নিত করুন। ইতিহাসই শিক্ষা।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১২.৪ বিখ্যাত ট্রেড-অফের সারণি (স্মরণীয়)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ট্রেড-অফ&lt;/th&gt;
&lt;th&gt;একদিকে&lt;/th&gt;
&lt;th&gt;অন্যদিকে&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Consistency বনাম Availability&lt;/td&gt;
&lt;td&gt;সঠিক কিন্তু মাঝে মাঝে অনুপলব্ধ&lt;/td&gt;
&lt;td&gt;সবসময় চালু কিন্তু সাময়িক পুরনো&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency বনাম Throughput&lt;/td&gt;
&lt;td&gt;প্রতিটি দ্রুত&lt;/td&gt;
&lt;td&gt;মোট বেশি কাজ (batching)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Normalize বনাম Denormalize&lt;/td&gt;
&lt;td&gt;সঙ্গত ডেটা&lt;/td&gt;
&lt;td&gt;দ্রুত পড়া&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monolith বনাম Microservices&lt;/td&gt;
&lt;td&gt;সরল&lt;/td&gt;
&lt;td&gt;স্বাধীন scaling/টিম&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sync বনাম Async&lt;/td&gt;
&lt;td&gt;সরল ও তাৎক্ষণিক উত্তর&lt;/td&gt;
&lt;td&gt;সহনশীল ও scalable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build বনাম Buy&lt;/td&gt;
&lt;td&gt;সম্পূর্ণ নিয়ন্ত্রণ&lt;/td&gt;
&lt;td&gt;দ্রুত ও কম রক্ষণাবেক্ষণ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQL বনাম NoSQL&lt;/td&gt;
&lt;td&gt;সম্পর্ক ও ACID&lt;/td&gt;
&lt;td&gt;নমনীয়তা ও বিপুল scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cache&lt;/td&gt;
&lt;td&gt;গতি&lt;/td&gt;
&lt;td&gt;পুরনো ডেটার ঝুঁকি&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Index&lt;/td&gt;
&lt;td&gt;দ্রুত পড়া&lt;/td&gt;
&lt;td&gt;ধীর লেখা ও বেশি জায়গা&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong বনাম Eventual consistency&lt;/td&gt;
&lt;td&gt;সহজ যুক্তি&lt;/td&gt;
&lt;td&gt;scalable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  ১২.৫ সাধারণ ভুল (যা সবাই করে)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;শুরুতেই Microservices&lt;/strong&gt;: বিতরিত জটিলতা কিন্তু সুবিধা নেই (Distributed Monolith)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resume-Driven Development&lt;/strong&gt;: প্রযুক্তি বাছা কারণ "CV তে ভালো দেখাবে", প্রয়োজন নয়&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;অকাল অপ্টিমাইজেশন ও অতিরিক্ত নকশা (Over-engineering)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;বিপরীতে:&lt;/strong&gt; একেবারে নকশাহীন "Big Ball of Mud"&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;মাপার আগেই scaling-এর চেষ্টা&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ব্যর্থতা ভুলে যাওয়া&lt;/strong&gt;: Timeout, retry, idempotency নেই&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shared Database&lt;/strong&gt; একাধিক সার্ভিসের মধ্যে (লুকানো coupling)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observability পরে ভাবা&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;নিরাপত্তা শেষে যোগ করা&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Golden Hammer&lt;/strong&gt;: একটা প্রিয় টুল সবখানে ("যার হাতে হাতুড়ি, সবই পেরেক")&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ডকুমেন্টেশন ও সিদ্ধান্ত না লেখা&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;অপারেশনাল খরচ উপেক্ষা&lt;/strong&gt;: কে মনিটর করবে, কে on-call?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;টিমের সক্ষমতা বিবেচনা না করা&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache যোগ করে ডেটা সঠিকতার কথা ভুলে যাওয়া&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Big-bang rewrite&lt;/strong&gt;: Strangler Fig ই নিরাপদ&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ১২.৬ Testing কৌশল (আর্কিটেকচারের অঙ্গ)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Test Pyramid:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit test (বেশি, দ্রুত):&lt;/strong&gt; একক ক্লাস/লজিক। xUnit/NUnit + Moq/NSubstitute। Domain logic এখানে সবচেয়ে ভালো (Clean Architecture এর সুবিধা)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration test (মাঝারি):&lt;/strong&gt; আসল DB, queue সহ। &lt;strong&gt;Testcontainers&lt;/strong&gt; দিয়ে Docker এ সত্যিকারের SQL/Redis/RabbitMQ চালিয়ে। ASP.NET Core &lt;code&gt;WebApplicationFactory&lt;/code&gt; দিয়ে পুরো API পরীক্ষা&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contract test (মাইক্রোসার্ভিসে):&lt;/strong&gt; সার্ভিসগুলোর চুক্তি মানা হচ্ছে কি না (Pact)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-End (কম, ধীর):&lt;/strong&gt; মূল ব্যবহারকারী যাত্রা&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architecture test:&lt;/strong&gt; &lt;code&gt;NetArchTest&lt;/code&gt;/&lt;code&gt;ArchUnitNET&lt;/code&gt; দিয়ে নিয়ম প্রয়োগ (যেমন "Domain কখনো Infrastructure ব্যবহার করবে না")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Load/Performance, Security, Chaos test&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrdersApiTests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WebApplicationFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IClassFixture&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;WebApplicationFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Program&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;GetOrder_WithoutAuth_Returns401&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/v1/orders/1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unauthorized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;টেস্ট নীতি:&lt;/strong&gt; আচরণ পরীক্ষা করুন, বাস্তবায়ন নয়; mock সীমিত রাখুন (ডেটাবেস mock করার চেয়ে Testcontainers প্রায়ই বেশি আস্থা দেয়)।&lt;/p&gt;

&lt;h3&gt;
  
  
  ১২.৭ টেকনিক্যাল ঋণ (Technical Debt) ও Refactoring
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Technical debt:&lt;/strong&gt; আজকের শর্টকাট, কাল সুদসহ শোধ। সবসময় খারাপ নয় (ইচ্ছাকৃত, সচেতন ঋণ মাঝে মাঝে বুদ্ধিমানের কাজ), তবে &lt;strong&gt;দৃশ্যমান রাখুন ও পরিশোধের পরিকল্পনা করুন।&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ঋণের তালিকা রাখুন; প্রতি স্প্রিন্টে কিছু অংশ পরিশোধ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boy Scout Rule:&lt;/strong&gt; কোড যেমন পেয়েছেন তার চেয়ে একটু ভালো রেখে যান&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refactor নিরাপদে:&lt;/strong&gt; আগে টেস্ট, ছোট ধাপ, আচরণ অপরিবর্তিত&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strangler Fig&lt;/strong&gt; বড় পরিবর্তনে&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১২.৮ আর্কিটেক্ট হিসেবে নরম দক্ষতা
&lt;/h3&gt;

&lt;p&gt;প্রযুক্তি অর্ধেক; বাকি অর্ধেক মানুষ।&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;যোগাযোগ:&lt;/strong&gt; জটিল ধারণা সহজে বোঝান (ডায়াগ্রাম আঁকুন, উপমা দিন)। &lt;strong&gt;C4 Model&lt;/strong&gt; (Context, Container, Component, Code) স্তরে স্তরে ডায়াগ্রামের ভালো পদ্ধতি&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ব্যবসা বুঝুন:&lt;/strong&gt; প্রযুক্তি ব্যবসার সেবক। "এতে ব্যবসার কী লাভ?" বলতে পারুন&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ঐক্যমত তৈরি:&lt;/strong&gt; আদেশ নয়, বুঝিয়ে সম্মতি; RFC/ADR প্রক্রিয়া&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;শুনুন ও শিখুন:&lt;/strong&gt; যিনি প্রতিদিন কোড লেখেন, তাঁর ব্যথা বুঝুন&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;"জানি না" বলতে শিখুন&lt;/strong&gt;, তারপর খুঁজে বের করুন&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;টিমকে এগিয়ে নিন:&lt;/strong&gt; মেন্টরিং, কোড রিভিউ&lt;/li&gt;
&lt;li&gt;আর্কিটেক্ট হাতে-কলমে কোডও লেখে; আইভরি টাওয়ারে নয়&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ১২.৯ আপনার শেখার Roadmap (Beginner → Advanced)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;পর্যায় ১: ভিত্তি (১-২ মাস)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] C# ও ASP.NET Core ভালোভাবে; DI, Middleware, Configuration&lt;/li&gt;
&lt;li&gt;[ ] HTTP, REST, SQL ও EF Core, index&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[ ] SOLID ও কয়েকটি design pattern&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;প্রজেক্ট:&lt;/strong&gt; একটা Layered CRUD API (ShopEasy v1)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;পর্যায় ২: মাঝারি (২-৪ মাস)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Clean Architecture/Vertical Slice, CQRS&lt;/li&gt;
&lt;li&gt;[ ] Authentication (JWT/OIDC), Authorization&lt;/li&gt;
&lt;li&gt;[ ] Caching (Redis), Docker, CI/CD&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[ ] Logging/Serilog, Unit + Integration test&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;প্রজেক্ট:&lt;/strong&gt; ShopEasy v2 (Clean Architecture, Docker, CI, auth, cache)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;পর্যায় ৩: উন্নত (৪-৮ মাস)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Messaging (RabbitMQ + MassTransit), Outbox, Saga&lt;/li&gt;
&lt;li&gt;[ ] Resilience (Polly), OpenTelemetry, Health checks&lt;/li&gt;
&lt;li&gt;[ ] DDD, Modular Monolith, তারপর Microservices&lt;/li&gt;
&lt;li&gt;&lt;p&gt;[ ] Kubernetes/ক্লাউড (Azure/AWS)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;প্রজেক্ট:&lt;/strong&gt; ShopEasy v3 (Modular Monolith → একটা সার্ভিস আলাদা, Event-driven)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;পর্যায় ৪: বিশেষজ্ঞ (চলমান)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] System design case study নিয়মিত অনুশীলন (URL shortener, chat, feed, ride-hailing)&lt;/li&gt;
&lt;li&gt;[ ] পারফরম্যান্স প্রোফাইলিং, load test&lt;/li&gt;
&lt;li&gt;[ ] বড় সিস্টেমের ইঞ্জিনিয়ারিং ব্লগ পড়ুন (Netflix, Uber, Stripe, Discord)&lt;/li&gt;
&lt;li&gt;[ ] ওপেন সোর্স কোড পড়ুন (ASP.NET Core, eShop reference)&lt;/li&gt;
&lt;li&gt;[ ] নিজে লিখুন ও শেখান (ব্লগ, টক): শেখানোই গভীরতম শেখা&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;বই (প্রস্তাবিত):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Designing Data-Intensive Applications&lt;/em&gt;: Martin Kleppmann (ডেটা সিস্টেমের বাইবেল)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Clean Architecture&lt;/em&gt;: Robert C. Martin&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Domain-Driven Design&lt;/em&gt;: Eric Evans; &lt;em&gt;Implementing DDD&lt;/em&gt;: Vaughn Vernon&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Building Microservices&lt;/em&gt;: Sam Newman&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;System Design Interview&lt;/em&gt; (Vol 1 ও 2): Alex Xu&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Release It!&lt;/em&gt;: Michael Nygard (resilience)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Fundamentals of Software Architecture&lt;/em&gt;: Mark Richards ও Neal Ford&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Reference প্রজেক্ট (পড়ে শিখুন):&lt;/strong&gt; Microsoft এর &lt;code&gt;eShop&lt;/code&gt; (.NET microservices/Aspire), &lt;code&gt;eShopOnWeb&lt;/code&gt; (Clean Architecture)। (সংগ্রহশালার বর্তমান অবস্থা GitHub এ দেখে নিন।)&lt;/p&gt;

&lt;h3&gt;
  
  
  ১২.১০ সম্পূর্ণ চেকলিস্ট: নতুন সিস্টেম লঞ্চের আগে
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;স্থাপত্য ও কোড&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] প্রয়োজন ও non-functional লক্ষ্য লিখিত (SLO সহ)&lt;/li&gt;
&lt;li&gt;[ ] উপযুক্ত architecture style (সরলতম যা চলে)&lt;/li&gt;
&lt;li&gt;[ ] কোড স্তরবদ্ধ, DI, SOLID; ADR আছে&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ডেটা&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] সঠিক index; N+1 নেই; pagination আছে&lt;/li&gt;
&lt;li&gt;[ ] Concurrency ও transaction সঠিক&lt;/li&gt;
&lt;li&gt;[ ] Backup ও restore পরীক্ষিত; migration নিরাপদ&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;API&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] ভার্সনিং, validation, DTO, Problem Details&lt;/li&gt;
&lt;li&gt;[ ] Idempotency (POST), rate limiting&lt;/li&gt;
&lt;li&gt;[ ] OpenAPI ডকুমেন্ট&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Resilience&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Timeout, retry (backoff+jitter), circuit breaker&lt;/li&gt;
&lt;li&gt;[ ] Idempotent consumer, DLQ, Outbox&lt;/li&gt;
&lt;li&gt;[ ] Graceful degradation, health check&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;নিরাপত্তা&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] AuthN/AuthZ, BOLA যাচাই, HTTPS&lt;/li&gt;
&lt;li&gt;[ ] Secret Key Vault এ; dependency স্ক্যান&lt;/li&gt;
&lt;li&gt;[ ] CORS, header, input validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Observability&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Structured log + correlation ID&lt;/li&gt;
&lt;li&gt;[ ] Metric (golden signals + business) ও trace (OTel)&lt;/li&gt;
&lt;li&gt;[ ] Alert, runbook, dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Delivery&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] CI/CD, স্বয়ংক্রিয় test&lt;/li&gt;
&lt;li&gt;[ ] Container, IaC, নিরাপদ deploy ও rollback&lt;/li&gt;
&lt;li&gt;[ ] Load test; খরচ বাজেট alert&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  উপসংহার: "বস" হওয়ার আসল রহস্য
&lt;/h3&gt;

&lt;p&gt;আপনি এই গাইডে যা শিখলেন, তার সারকথা কয়েকটি বাক্যে:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;সরল দিয়ে শুরু করুন।&lt;/strong&gt; জটিলতা অর্জন করতে হয়, উপহার নয়।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;মাপুন, অনুমান করবেন না।&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ব্যর্থতা অনিবার্য;&lt;/strong&gt; সেই অনুযায়ী ডিজাইন করুন।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;প্রতিটি সিদ্ধান্ত একটা ট্রেড-অফ;&lt;/strong&gt; কী পেলেন আর কী ছাড়লেন, তা জানুন ও বলুন।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;প্রয়োজনের আগে scale করবেন না, প্রয়োজনের পরে ফেলেও রাখবেন না।&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;কোড অন্যের জন্য লিখুন&lt;/strong&gt; (ছয় মাস পরের আপনিও "অন্য")।&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;প্রযুক্তি টিম ও ব্যবসার সেবা করে।&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;সিস্টেম ডিজাইন কোনো মুখস্থ বিদ্যা নয়; এটা &lt;strong&gt;চিন্তার পদ্ধতি।&lt;/strong&gt; একজন সত্যিকারের বস প্রতিটি নতুন সমস্যায় জিজ্ঞেস করেন: &lt;em&gt;"প্রয়োজন কী? সীমা কী? সরলতম সমাধান কী? কোথায় ভাঙবে? এর দাম কী?"&lt;/em&gt; এই পাঁচটি প্রশ্ন যে অভ্যাসে পরিণত করেছে, সে নতুন যেকোনো প্রযুক্তি এক সপ্তাহে বুঝে ফেলতে পারে।&lt;/p&gt;

&lt;p&gt;আপনার পরবর্তী পদক্ষেপ: একটা ছোট প্রজেক্ট নিন, ShopEasy হোক বা নিজের আইডিয়া। এই গাইডের ক্রমে একটা একটা করে প্রয়োগ করুন, ভুল করুন, মাপুন, শিখুন। পড়া আর করার মধ্যে যে ফাঁক, সেটাই আপনার আসল শিক্ষক।&lt;/p&gt;

&lt;p&gt;শুভকামনা।&lt;/p&gt;




&lt;p&gt;&lt;em&gt;এই লেখার সংখ্যা, লাইব্রেরির নাম/লাইসেন্স ও সেবার ফিচার সময়ের সাথে বদলায়; প্রয়োগের আগে সংশ্লিষ্ট অফিসিয়াল ডকুমেন্ট দেখে নিন।&lt;/em&gt;&lt;/p&gt;

</description>
      <category>systemdesign</category>
      <category>distributedsystems</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>AI Agent-এর জন্য API: শূন্য থেকে শুরু, .NET ডেভেলপারের শেখার নোট</title>
      <dc:creator>Rakib Ahasan</dc:creator>
      <pubDate>Mon, 12 Oct 2026 06:09:07 +0000</pubDate>
      <link>https://dev.to/rakibahasan/ai-agent-er-jny-api-shuuny-theke-shuru-net-ddebhelpaarer-shekhaar-nott-63m</link>
      <guid>https://dev.to/rakibahasan/ai-agent-er-jny-api-shuuny-theke-shuru-net-ddebhelpaarer-shekhaar-nott-63m</guid>
      <description>&lt;h2&gt;
  
  
  এই লেখা কেন
&lt;/h2&gt;

&lt;p&gt;আমি .NET ব্যাকএন্ড ডেভেলপার। এতদিন API বানিয়েছি ফ্রন্টএন্ড বা মোবাইল টিমের জন্য। কিন্তু ইদানীং বারবার শুনছি, "AI Agent আপনার API ব্যবহার করবে।" আমি জানতে চাইলাম, এর মানে কী, আর আমার API-তে কী বদলাতে হবে।&lt;/p&gt;

&lt;p&gt;এই লেখা সেই শেখার নোট। কোনো বিশেষজ্ঞের লেখা না, একজন শিক্ষার্থীর গুছিয়ে লেখা সারাংশ, যাতে আপনি একবার পড়েই পুরো বিষয়টা বুঝে ফেলেন।&lt;/p&gt;




&lt;h2&gt;
  
  
  এক নজরে (TL;DR)
&lt;/h2&gt;

&lt;p&gt;AI Agent মানুষের মতো API ব্যবহার করে না। সে ডকুমেন্টেশন পড়ে না, আন্দাজ করে না, error দেখে নিজে debug করে না, আর খুব দ্রুত retry করে। তাই ৫টা কাজ করতে হয়:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;কাজ&lt;/th&gt;
&lt;th&gt;সহজ ভাষায়&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;১&lt;/td&gt;
&lt;td&gt;সম্পূর্ণ schema ও description&lt;/td&gt;
&lt;td&gt;Agent-কে স্পষ্ট করে বলো কী পাঠাতে হবে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;২&lt;/td&gt;
&lt;td&gt;সব জায়গায় একই নিয়ম&lt;/td&gt;
&lt;td&gt;একই ধরনের জিনিস একইভাবে লেখো&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;৩&lt;/td&gt;
&lt;td&gt;Structured error&lt;/td&gt;
&lt;td&gt;ভুল হলে বলে দাও কী ঠিক করতে হবে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;৪&lt;/td&gt;
&lt;td&gt;Idempotency&lt;/td&gt;
&lt;td&gt;দুবার call এলেও যেন দুবার কাজ না হয়&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;৫&lt;/td&gt;
&lt;td&gt;সুচিন্তিত operation&lt;/td&gt;
&lt;td&gt;কম কিন্তু কাজের operation দাও&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  আগে কিছু শব্দ পরিষ্কার করি
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Agent:&lt;/strong&gt; এমন একটা প্রোগ্রাম যেখানে LLM নিজে সিদ্ধান্ত নিয়ে বিভিন্ন tool ও API call করে কাজ শেষ করে। যেমন "এই customer-এর জন্য অর্ডার দাও" বললে সে নিজেই ঠিক করে কোন API কোন ক্রমে call করবে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAPI spec:&lt;/strong&gt; আপনার API-র machine-readable বর্ণনা (Swagger যা দেখায়, তার আসল উৎস)। কোন endpoint আছে, কী পাঠাতে হয়, কী ফেরত আসে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency:&lt;/strong&gt; একই request একাধিকবার পাঠালেও ফলাফল একবার পাঠানোর মতোই হওয়া।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP (Model Context Protocol):&lt;/strong&gt; AI Agent-কে বাইরের tool ও data-র সাথে যুক্ত করার একটা open protocol। এক ধরনের "AI-র জন্য USB পোর্ট"।&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  মানুষ ডেভেলপার বনাম AI Agent
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;বিষয়&lt;/th&gt;
&lt;th&gt;মানুষ ডেভেলপার&lt;/th&gt;
&lt;th&gt;AI Agent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ডকুমেন্টেশন&lt;/td&gt;
&lt;td&gt;পড়ে, বুঝে নেয়&lt;/td&gt;
&lt;td&gt;মূলত OpenAPI spec ও description-এর উপর নির্ভর করে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;অস্পষ্ট ফিল্ড&lt;/td&gt;
&lt;td&gt;অনুমান করে, জিজ্ঞেস করে&lt;/td&gt;
&lt;td&gt;ভুল অনুমান করতে পারে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error পেলে&lt;/td&gt;
&lt;td&gt;message পড়ে debug করে&lt;/td&gt;
&lt;td&gt;message-এ নির্দেশনা না থাকলে একই ভুল বারবার করতে পারে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;গতি&lt;/td&gt;
&lt;td&gt;ধীর&lt;/td&gt;
&lt;td&gt;খুব দ্রুত, ভুলও দ্রুত বাড়ে&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;এই পার্থক্য থেকেই নিচের ৫টা নিয়ম আসে।&lt;/p&gt;




&lt;h2&gt;
  
  
  একটা কাল্পনিক উদাহরণ
&lt;/h2&gt;

&lt;p&gt;বোঝার সুবিধার জন্য ধরুন একটা Order API আছে, আর Agent-কে বলা হলো "২টা পণ্যের অর্ডার দাও।" (এটা কল্পনা, বাস্তব ঘটনা না।)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spec-এ &lt;code&gt;quantity&lt;/code&gt;-র type লেখা নেই, তাই Agent &lt;code&gt;"2"&lt;/code&gt; (string) পাঠাল।&lt;/li&gt;
&lt;li&gt;Server উত্তর দিল &lt;code&gt;{"error": "Invalid input"}&lt;/code&gt;। কোন ফিল্ড ভুল সেটা নেই।&lt;/li&gt;
&lt;li&gt;Agent একই request আবার পাঠাল। একই উত্তর।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;মানুষ হলে ডকুমেন্টেশন খুলত। Agent-এর কাছে শুধু spec আর response। দুটোই অস্পষ্ট হলে সে আটকে যায়। এই ধরনের পরিস্থিতি এড়াতেই নিচের নিয়মগুলো।&lt;/p&gt;




&lt;h2&gt;
  
  
  ১. সম্পূর্ণ Schema ও অর্থবহ Description
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt; প্রতিটা ফিল্ডে type, format, constraint ও description দিন।&lt;/p&gt;

&lt;p&gt;.NET-এ request model-এ attribute দিলে OpenAPI spec-এ সেগুলো আসে:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;PlaceOrderRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"যে customer অর্ডার করছেন তার ID"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;CustomerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"পণ্যের ID"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;ProductId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"পণ্যের সংখ্যা (পূর্ণসংখ্যা, কমপক্ষে ১)"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Quantity&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Endpoint-এর description-ও ভাবুন। "Gets the data" এর চেয়ে "Returns a paginated list of invoices filtered by status and date range" Agent-কে অনেক ভালো সংকেত দেয়।&lt;/p&gt;

&lt;h2&gt;
  
  
  ২. সব জায়গায় একই নিয়ম (Consistency)
&lt;/h2&gt;

&lt;p&gt;Agent একটা endpoint থেকে pattern শিখে বাকিগুলোতে খাটায়। একটায় status &lt;code&gt;pending&lt;/code&gt;, আরেকটায় &lt;code&gt;IN_PROGRESS&lt;/code&gt;, তৃতীয়টায় &lt;code&gt;done&lt;/code&gt; থাকলে সে বিভ্রান্ত হয়।&lt;/p&gt;

&lt;p&gt;একটা convention ঠিক করে সব জায়গায় মানুন:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;নামকরণ (camelCase বা snake_case, দুটোই না)&lt;/li&gt;
&lt;li&gt;ID-র format (যেমন সবখানে &lt;code&gt;uuid&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Pagination-এর ধরন&lt;/li&gt;
&lt;li&gt;Error-এর কাঠামো&lt;/li&gt;
&lt;li&gt;Status value-র লিখনরীতি&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ৩. Structured Error
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;নিয়ম:&lt;/strong&gt; Error-কে Agent-এর জন্য নির্দেশনা বানান: কোন ফিল্ড ভুল, কী পেয়েছি, কী কী মান বৈধ।&lt;/p&gt;

&lt;p&gt;ASP.NET Core-এ RFC 9457 (Problem Details) built-in আছে। সাথে নিজের ফিল্ড যোগ করা যায়:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Problem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Invalid field value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Field 'status' received invalid value 'processing'."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;StatusCodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Status400BadRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"receivedValue"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"processing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"allowedValues"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"pending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"shipped"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"delivered"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"cancelled"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ফলাফল JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Invalid field value"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Field 'status' received invalid value 'processing'."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"receivedValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"processing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"allowedValues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"pending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shipped"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"delivered"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cancelled"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;{"error": "Invalid input"}&lt;/code&gt;-এর সাথে তুলনা করুন। এটা পেলে Agent পরের চেষ্টায় ঠিক মান পাঠাতে পারে।&lt;/p&gt;

&lt;h2&gt;
  
  
  ৪. Idempotency
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;সমস্যা:&lt;/strong&gt; Network timeout হলে Agent (বা যেকোনো client) retry করে। &lt;code&gt;POST /orders&lt;/code&gt; দুবার গেলে দুটো অর্ডার তৈরি হতে পারে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;সমাধান:&lt;/strong&gt; client একটা &lt;code&gt;Idempotency-Key&lt;/code&gt; header পাঠায়। Server সেই key মনে রাখে। একই key আবার এলে নতুন অর্ডার তৈরি না করে আগের ফলাফল ফেরত দেয়।&lt;/p&gt;

&lt;p&gt;শেখার জন্য একটা সরল স্কেচ (in-memory, production-এ Redis বা database লাগবে):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;seenKeys&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ConcurrentDictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/orders"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequest&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PlaceOrderRequest&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"Idempotency-Key"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// TryAdd atomic: একই key দুটো parallel request-এ এলে একটাই সফল হবে&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;seenKeys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Conflict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"এই key দিয়ে request আগেই এসেছে।"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// ... অর্ডার তৈরি করুন ...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;গুরুত্বপূর্ণ বিষয় দুটো:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Atomic check:&lt;/strong&gt; "আগে দেখি আছে কিনা, তারপর সেট করি", দুই ধাপে করলে দুটো parallel request-ই পার পেয়ে যেতে পারে। Redis-এ &lt;code&gt;SET NX&lt;/code&gt; বা database-এ unique constraint এই কাজ করে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;আসল সিস্টেমে&lt;/strong&gt; আগের সফল response সংরক্ষণ করে ফেরত দেওয়া উচিত, শুধু Conflict না। এই স্কেচ কেবল ধারণা বোঝানোর জন্য।&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ৫. সুচিন্তিত Operation, শুধু CRUD না
&lt;/h2&gt;

&lt;p&gt;প্রতিটা endpoint Agent-কে tool হিসেবে দিলে তার সামনে অনেক বিকল্প থাকে, ভুল বাছাইয়ের সম্ভাবনাও বাড়ে। কিছু ভালোভাবে বর্ণনা করা operation বেশি কাজের।&lt;/p&gt;

&lt;p&gt;উদাহরণ: অর্ডার দিতে যদি customer খোঁজা → stock দেখা → অর্ডার তৈরি, তিনটা call লাগে, তাহলে একটা &lt;code&gt;PlaceOrder&lt;/code&gt; operation বানানো যায়। Agent-কে ধাপগুলো সাজাতে হয় না, মাঝপথে ভুলের জায়গাও কমে।&lt;/p&gt;




&lt;h2&gt;
  
  
  MCP: Agent-এর জন্য আরেক ধাপ
&lt;/h2&gt;

&lt;p&gt;MCP দিয়ে আপনার operation-গুলো এমনভাবে expose করা যায় যে MCP-সমর্থিত Agent সেগুলো সহজে খুঁজে পায় ও ব্যবহার করে। .NET-এর জন্য official C# SDK আছে। একটা tool দেখতে মোটামুটি এরকম:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;McpServerToolType&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderTools&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;McpServerTool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"নির্দিষ্ট customer-এর জন্য নতুন অর্ডার তৈরি করে।"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;PlaceOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Customer-এর ID"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"পণ্যের ID"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;productId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"সংখ্যা, কমপক্ষে ১"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// এখানে আপনার existing application logic কল করুন&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"created"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;SDK দ্রুত বদলায়, তাই setup-এর সঠিক কোড &lt;a href="https://github.com/modelcontextprotocol/csharp-sdk" rel="noopener noreferrer"&gt;official repository&lt;/a&gt; থেকে দেখে নিন।&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;এখানেও ৫ নম্বর নিয়ম খাটে: সব endpoint MCP tool বানাবেন না। শুধু যেগুলো Agent-এর সত্যিই লাগবে।&lt;/p&gt;




&lt;h2&gt;
  
  
  চেকলিস্ট
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] OpenAPI spec সম্পূর্ণ: প্রতিটা ফিল্ডে type, format, constraint&lt;/li&gt;
&lt;li&gt;[ ] Description-এ intent আছে, শুধু input/output না&lt;/li&gt;
&lt;li&gt;[ ] Error structured: ফিল্ডের নাম ও বৈধ মান সহ&lt;/li&gt;
&lt;li&gt;[ ] State পরিবর্তনকারী endpoint-এ idempotency&lt;/li&gt;
&lt;li&gt;[ ] Response ছোট ও focused&lt;/li&gt;
&lt;li&gt;[ ] যেখানে সম্ভব composite operation&lt;/li&gt;
&lt;li&gt;[ ] Pagination, naming, status value সব জায়গায় একই&lt;/li&gt;
&lt;li&gt;[ ] Authentication ও rate limit spec-এ উল্লেখ আছে&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  নিজে হাতে করে দেখার ছোট কাজ
&lt;/h2&gt;

&lt;p&gt;পড়ে বোঝা আর করে বোঝা আলাদা। ১-২ ঘণ্টায় করা যায়:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;একটা ছোট &lt;code&gt;POST /orders&lt;/code&gt; endpoint বানান (ইচ্ছা করে type ও error অস্পষ্ট রেখে)।&lt;/li&gt;
&lt;li&gt;MCP-সমর্থিত একটা client বা Agent দিয়ে সেটা call করান, আর কোথায় আটকায় দেখুন।&lt;/li&gt;
&lt;li&gt;৫টা নিয়ম একে একে প্রয়োগ করুন, প্রতিবার আচরণ কেমন বদলাল লিখে রাখুন।&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  আরও পড়ার জন্য
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://modelcontextprotocol.io" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/csharp-sdk" rel="noopener noreferrer"&gt;MCP C# SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.rfc-editor.org/rfc/rfc9457" rel="noopener noreferrer"&gt;RFC 9457: Problem Details for HTTP APIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://spec.openapis.org" rel="noopener noreferrer"&gt;OpenAPI Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  শেষ কথা
&lt;/h2&gt;

&lt;p&gt;API এতদিন ডেভেলপারদের জন্য ডিজাইন হয়েছে। এখন তার কনজিউমার হিসেবে Agent-ও আসছে, যারা আন্দাজ বা debug করে না। যে API-র schema পরিষ্কার, error নির্দেশনামূলক আর retry নিরাপদ, সেটা Agent আর মানুষ, দুজনের জন্যই ভালো।&lt;/p&gt;

&lt;p&gt;আপনার API-তে এই ৫টার মধ্যে কোনটা সবচেয়ে আগে করবেন? কমেন্টে জানান।&lt;/p&gt;

&lt;p&gt;&lt;em&gt;আগের লেখা: &lt;a href="https://dev.to%E0%A6%A4%E0%A7%8B%E0%A6%AE%E0%A6%BE%E0%A6%B0-link"&gt;Repository, MediatR, CQRS নিয়ে Production-এর শিক্ষা&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>api</category>
      <category>ai</category>
      <category>mcp</category>
    </item>
    <item>
      <title>কখন Repository, MediatR আর CQRS দরকার — আর কখন Overkill</title>
      <dc:creator>Rakib Ahasan</dc:creator>
      <pubDate>Sat, 10 Oct 2026 15:19:29 +0000</pubDate>
      <link>https://dev.to/rakibahasan/repository-mediatr-cqrs-production-e-yaa-shikhechi-26m6</link>
      <guid>https://dev.to/rakibahasan/repository-mediatr-cqrs-production-e-yaa-shikhechi-26m6</guid>
      <description>&lt;h2&gt;
  
  
  ভূমিকা: কেন এই লেখা
&lt;/h2&gt;

&lt;p&gt;তিন বছর আগের একটা ইনসিডেন্ট থেকে এই লেখার শুরু। প্রোডাকশন সার্ভিসের ডেটাবেজ প্রোভাইডার চেঞ্জ করতে গিয়ে দেখলাম আমার কোডবেসে ডেটা অ্যাক্সেস লজিক ছড়িয়ে আছে — কন্ট্রোলারে &lt;code&gt;DbContext&lt;/code&gt;, সার্ভিসে raw SQL, কোথাও &lt;code&gt;DbSet&lt;/code&gt;-এর উপর LINQ। প্রোভাইডার চেঞ্জ করতে গিয়ে প্রায় পুরো Application লেয়ার টাচ করতে হলো। সেটা ছিল আমার জন্য বড় শিক্ষা — abstraction-এর অভাবে ছোট একটা change কত বড় হয়ে যায়।&lt;/p&gt;

&lt;p&gt;সেই দিন থেকে আমি ডিজাইন প্যাটার্নগুলো সিরিয়াসলি পড়তে শুরু করি। পরের প্রজেক্টে যখন Repository প্যাটার্ন ঠিকভাবে প্রয়োগ করলাম, তখন ঠিক উল্টো অভিজ্ঞতা হলো — মাইগ্রেশন Infrastructure লেয়ারেই সীমাবদ্ধ থাকল। সেটাই এই লেখার মূল সূত্র। এটা কোনো টিউটোরিয়াল না — প্রোডাকশন এক্সপেরিয়েন্স থেকে আমার future self-এর জন্য লেখা নোট, আপনাদেরও কাজে লাগবে।&lt;/p&gt;




&lt;h2&gt;
  
  
  ১. Repository Pattern: Abstraction-এর লাভ এবং খরচ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  প্যাটার্নটা কী করে
&lt;/h3&gt;

&lt;p&gt;Repository প্যাটার্ন ডেটা অ্যাক্সেস লজিককে ডোমেইন লজিক থেকে আলাদা করে। ডোমেইন লেয়ার জানে না ডেটা কোথা থেকে আসছে — SQL Server, MySQL, Redis, নাকি in-memory। এটাই &lt;em&gt;persistence ignorance&lt;/em&gt;।&lt;/p&gt;

&lt;h3&gt;
  
  
  Production-এ কী হয়েছিল
&lt;/h3&gt;

&lt;p&gt;পরের প্রজেক্টে — একটা ব্যাংকিং API — Repository প্যাটার্ন ঠিকভাবে প্রয়োগ করেছিলাম। যখন &lt;strong&gt;MSSQL থেকে MySQL-এ&lt;/strong&gt; মাইগ্রেট করার দরকার পড়ল, শুধু Infrastructure লেয়ার চেঞ্জ করতে হয়েছিল। Controller, Handler, Validator — কিছুই টাচ করতে হয়নি। প্রথম প্রজেক্টে যেটা প্রায় পুরো Application লেয়ার ছুঁয়ে ফেলেছিল, এখানে সেটা এক লেয়ারে আটকে গেল। এটাই Repository প্যাটার্নের সবচেয়ে বড় প্রমাণ।&lt;/p&gt;

&lt;h3&gt;
  
  
  কিন্তু এর খারাপ দিক
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;EF Core-এর পাওয়ার লুকিয়ে ফেলে:&lt;/strong&gt; Repository মেথডের ভেতরে &lt;code&gt;Include()&lt;/code&gt;, &lt;code&gt;AsNoTracking()&lt;/code&gt;, complex projection লুকিয়ে ফেললে পারফরম্যান্স টিউনিং কঠিন হয়ে যায়। Specific query optimization লাগলে অ্যাবস্ট্রাকশনটাই বাধা হয়ে দাঁড়ায়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository Explosion:&lt;/strong&gt; প্রতিটা এনটিটির জন্য আলাদা Repository বানালে ২০টা এনটিটি = ২০টা ইন্টারফেস + ২০টা ক্লাস। Maintain করা কষ্টকর।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex query-তে rigid:&lt;/strong&gt; মাল্টি-টেবিল join বা dynamic filter-এ Repository মেথড ফুলে যায়। তখন Query Object বা Specification pattern দরকার হয়।&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  আমি কী করেছি
&lt;/h3&gt;

&lt;p&gt;শুধু Aggregate Root-এর জন্য Repository বানিয়েছি। বাকি read-heavy query-গুলো Dapper বা raw SQL দিয়ে সরাসরি করেছি। ফলাফল: &lt;strong&gt;write side-এ abstraction, read side-এ performance।&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// শুধু Aggregate Root-এর জন্য, domain-এর ভাষায়&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IOrderRepository&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  "Repository is an anti-pattern" বিতর্ক
&lt;/h3&gt;

&lt;p&gt;একটা পরিচিত যুক্তি আছে: EF Core-এর &lt;code&gt;DbContext&lt;/code&gt; নিজেই Unit of Work, আর &lt;code&gt;DbSet&lt;/code&gt; অনেকটা Repository-র মতোই কাজ করে। তাই তার উপর আরেকটা Repository অনেকের কাছে অপ্রয়োজনীয় লেয়ার। আমি এটা পুরোপুরি অস্বীকার করি না — সেজন্যই সব এনটিটির জন্য Repository বানাইনি। কিন্তু provider বদলানোর ঝুঁকি বা domain purity যেখানে সত্যিই দরকার, সেখানে এই লেয়ারের দাম উসুল হয়।&lt;/p&gt;

&lt;h3&gt;
  
  
  Alternatives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generic Repository (&lt;code&gt;IRepository&amp;lt;T&amp;gt;&lt;/code&gt;):&lt;/strong&gt; একটাই Repository, CRUD মেথড। কিন্তু domain-specific মেথডের অভাব।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Repository at all:&lt;/strong&gt; সরাসরি Handler-এ &lt;code&gt;DbContext&lt;/code&gt; inject। Small project-এ সবচেয়ে simple।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query Object Pattern:&lt;/strong&gt; Complex query আলাদা ক্লাসে encapsulate করা। Repository-র চেয়ে flexible। .NET-এ &lt;code&gt;Ardalis.Specification&lt;/code&gt; লাইব্রেরি এর জনপ্রিয় implementation।&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ২. MediatR + CQRS: Pipeline-এর শক্তি
&lt;/h2&gt;

&lt;h3&gt;
  
  
  CQRS আসলে কী
&lt;/h3&gt;

&lt;p&gt;CQRS = Command Query Responsibility Segregation। মানে: Command state পরিবর্তন করে, Query state পড়ে। এর বেশি কিছু না। Event Sourcing বা আলাদা ডেটাবেজ লাগে না।&lt;/p&gt;

&lt;p&gt;বেশিরভাগ .NET অ্যাপে CQRS মানে: "read আর write operation-এর জন্য আলাদা ক্লাস থাকা।"&lt;/p&gt;

&lt;h3&gt;
  
  
  MediatR কীভাবে এলো
&lt;/h3&gt;

&lt;p&gt;MediatR হলো Mediator pattern-এর একটা in-process implementation। Controller থেকে &lt;code&gt;mediator.Send(command)&lt;/code&gt; কল করলে MediatR সঠিক handler খুঁজে বের করে execute করে।&lt;/p&gt;

&lt;h3&gt;
  
  
  আসল পাওয়ার: Pipeline Behaviors
&lt;/h3&gt;

&lt;p&gt;MediatR-এর সবচেয়ে বড় advantage হলো Pipeline Behaviors। এগুলো handler-এর আগে বা পরে execute হয়। আমি FluentValidation-কে pipeline behavior হিসেবে সেট করেছি — ফলে invalid input কখনোই handler-এ পৌঁছায় না।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Controller: thin, just dispatches&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;CreateOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateOrderCommand&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orderId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_mediator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Controller-এ কোনো business logic নেই। শুধু command dispatch। Logic থাকে handler-এ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateOrderHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IOrderRepository&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IRequestHandler&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CreateOrderCommand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CreateOrderCommand&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;আর validation pipeline behavior হিসেবে একবারই লেখা হয়, সব command-এর জন্য কাজ করে:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ValidationBehavior&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
    &lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IValidator&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;validators&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IPipelineBehavior&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;TRequest&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;notnull&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;TRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RequestHandlerDelegate&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;validators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ValidateAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;failures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SelectMany&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ValidationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  কিন্তু এর সমস্যা
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Navigation Issue:&lt;/strong&gt; &lt;code&gt;Send&lt;/code&gt; মেথডে "Go to Definition" চাপলে MediatR interface-এ যায়, আসল handler-এ না। ম্যানুয়ালি handler খুঁজতে হয়। IDE plugin ছাড়া frustrating।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflection Overhead:&lt;/strong&gt; MediatR startup-এ handler খুঁজতে reflection ব্যবহার করে। Standard app-এ negligible, high-performance system-এ matter করে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boilerplate:&lt;/strong&gt; ৩টা টেবিলের CRUD API-তে MediatR ব্যবহার করলে ৪৭টা extra ক্লাস তৈরি হয়, real benefit ছাড়াই।&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  আমার Rule of Thumb
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;10+ distinct operations&lt;/strong&gt; → MediatR-এর value আছে&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3-4 endpoints&lt;/strong&gt; → plain service class-ই best&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex cross-cutting concerns&lt;/strong&gt; (validation, logging, caching) → MediatR pipeline দুর্দান্ত&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple CRUD&lt;/strong&gt; → MediatR overkill&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Alternatives
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plain DI Services:&lt;/strong&gt; সবচেয়ে simple। Controller সরাসরি সার্ভিস কল করে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wolverine:&lt;/strong&gt; MediatR-এর lightweight alternative। Command/Query dispatch-এ কম overhead।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Dispatcher:&lt;/strong&gt; নিজে একটা in-process dispatcher বানানো। Control বেশি, boilerplate কম।&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ৩. CQRS-এর Silent Killer: Overengineering
&lt;/h2&gt;

&lt;h3&gt;
  
  
  যে ভুলটা আমি দেখেছি
&lt;/h3&gt;

&lt;p&gt;একটা প্রজেক্ট দেখেছি — ৫০০ ইউজারের একটা অ্যাপ। অথচ CQRS, event bus, mediator, ৫টা সার্ভিস লেয়ার। একটা ফিল্ড ডেটাবেজ থেকে return করতে ৩টা ইন্টারফেস, ১৭টা ফাইল, ৫টা প্রজেক্ট পার হতে হয়।&lt;/p&gt;

&lt;p&gt;Complexity তখনই ভালো যখন real problem solve করে। নাহলে complexity নিজেই একটা problem।&lt;/p&gt;

&lt;h3&gt;
  
  
  কখন CQRS ব্যবহার করবে
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Read এবং Write-এর requirements significantly আলাদা হলে&lt;/li&gt;
&lt;li&gt;Read path-এ heavy caching বা projection দরকার হলে&lt;/li&gt;
&lt;li&gt;Write path-এ complex business rules enforce করতে হলে&lt;/li&gt;
&lt;li&gt;Team বড় হলে — ownership আর clarity-র জন্য&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  কখন করবে না
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Simple CRUD অ্যাপ&lt;/li&gt;
&lt;li&gt;Read এবং Write-এর logic প্রায় same&lt;/li&gt;
&lt;li&gt;Small team, যেখানে extra layer maintain করার bandwidth নেই&lt;/li&gt;
&lt;li&gt;Startup-এ যেখানে speed matter করে&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;এক বাক্যে: &lt;em&gt;"If your domain models are being modified primarily to satisfy a specific UI screen, it is time to consider CQRS."&lt;/em&gt; অন্যথায় simple-ই থাকো।&lt;/p&gt;




&lt;h2&gt;
  
  
  ৪. ডিজাইন প্যাটার্ন: কখন আর কখন না
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;প্যাটার্ন&lt;/th&gt;
&lt;th&gt;কখন ব্যবহার করবে&lt;/th&gt;
&lt;th&gt;কখন এড়িয়ে যাবে&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Repository&lt;/td&gt;
&lt;td&gt;Multiple data source, migration risk, domain purity দরকার&lt;/td&gt;
&lt;td&gt;Simple CRUD, EF Core-এর full power দরকার&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MediatR&lt;/td&gt;
&lt;td&gt;10+ operations, cross-cutting concerns, team collaboration&lt;/td&gt;
&lt;td&gt;3-4 endpoints, simple CRUD&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CQRS&lt;/td&gt;
&lt;td&gt;Read/write asymmetry, complex domain, scaling needs&lt;/td&gt;
&lt;td&gt;Simple CRUD, same logic both sides&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Alternatives এক নজরে
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Alternative&lt;/th&gt;
&lt;th&gt;কোথায় ভালো&lt;/th&gt;
&lt;th&gt;Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Generic Repository&lt;/td&gt;
&lt;td&gt;Simple CRUD&lt;/td&gt;
&lt;td&gt;Domain-specific মেথড থাকে না&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;DbContext&lt;/code&gt; সরাসরি&lt;/td&gt;
&lt;td&gt;Small project, কম boilerplate&lt;/td&gt;
&lt;td&gt;Data access logic handler-এ ঢুকে যায়, provider বদলানো কঠিন&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Query Object / Specification&lt;/td&gt;
&lt;td&gt;Complex read query&lt;/td&gt;
&lt;td&gt;আরেকটা abstraction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wolverine&lt;/td&gt;
&lt;td&gt;MediatR-এর lightweight বিকল্প&lt;/td&gt;
&lt;td&gt;MediatR-এর চেয়ে ছোট কমিউনিটি&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Vertical Slice (feature folder)&lt;/td&gt;
&lt;td&gt;Feature অনুযায়ী কোড সাজানো, layer-hopping কম&lt;/td&gt;
&lt;td&gt;টিমকে convention মানতে হয়&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plain DI Services&lt;/td&gt;
&lt;td&gt;সবচেয়ে simple&lt;/td&gt;
&lt;td&gt;Cross-cutting concern নিজেকে সামলাতে হয়&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  আমার সবচেয়ে বড় শিক্ষা
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"Can I explain why this pattern exists in my codebase in one sentence?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;উত্তর যদি হয় "কারণ এটা best practice" — আবার ভাবো। উত্তর যদি হয় "কারণ আমাদের read path-এ heavy caching লাগে এবং write path-এ complex validation" — তাহলে রাখো।&lt;/p&gt;




&lt;h2&gt;
  
  
  উপসংহার
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository&lt;/strong&gt; মানে abstraction, কিন্তু abstraction-এর খরচ আছে। যেখানে migration risk বা multiple data source আছে, শুধু সেখানে ব্যবহার করো।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MediatR&lt;/strong&gt; মানে pipeline, কিন্তু pipeline মানে indirection। 10+ operations থাকলে value আছে, নাহলে boilerplate।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CQRS&lt;/strong&gt; মানে read আর write আলাদা করা — event sourcing বা separate database না। Simple-এ simple রাখো।&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;এগুলো টুল, ধর্ম না। সঠিক সময়ে সঠিক টুল ব্যবহার করাই আসল engineering।&lt;/p&gt;

&lt;p&gt;আপনার প্রজেক্টে কোন প্যাটার্নটা সবচেয়ে বেশি কাজে লেগেছে, বা কোনটা overkill মনে হয়েছে? কমেন্টে জানান।&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>.NET Folder Structure: A to Z</title>
      <dc:creator>Rakib Ahasan</dc:creator>
      <pubDate>Fri, 09 Oct 2026 09:00:00 +0000</pubDate>
      <link>https://dev.to/rakibahasan/net-folder-structure-a-to-z-467g</link>
      <guid>https://dev.to/rakibahasan/net-folder-structure-a-to-z-467g</guid>
      <description>&lt;h2&gt;
  
  
  শুরুর কথা
&lt;/h2&gt;

&lt;p&gt;প্রজেক্ট শুরু করলে ফাইল থাকে হাতে গোনা ৫-৬টা। দুই মাস পর সেটা হয়ে যায় ২০০টা। তখন হঠাৎ payment-এ একটা bug ধরতে হবে, আর তুমি বুঝতেই পারছ না কোন ফোল্ডারে ঢুকবে।&lt;/p&gt;

&lt;p&gt;অনেকেই এই জায়গায় ১০ মিনিট শুধু ফাইল খুঁজে সময় নষ্ট করে। টিমে নতুন কেউ এলে তো তার অবস্থা আরও খারাপ।&lt;/p&gt;

&lt;p&gt;তাই আমি folder structure-কে বলি প্রজেক্টের map। map ঠিক থাকলে যেকোনো জায়গায় ২ সেকেন্ডে পৌঁছে যাওয়া যায়।&lt;/p&gt;




&lt;h2&gt;
  
  
  ১. Clean Architecture-এর মূল ধারণা
&lt;/h2&gt;

&lt;p&gt;Clean Architecture-এ ৪টা layer থাকে। পেঁয়াজের খোসার মতো ভাবো, একটার ভেতরে আরেকটা।&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────┐
│   Presentation (API)            │
│  ┌───────────────────────────┐  │
│  │   Infrastructure          │  │
│  │  ┌─────────────────────┐  │  │
│  │  │   Application       │  │  │
│  │  │  ┌───────────────┐  │  │  │
│  │  │  │   Domain      │  │  │  │
│  │  │  └───────────────┘  │  │  │
│  │  └─────────────────────┘  │  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;মূল নিয়ম:&lt;/strong&gt; বাইরের layer ভেতরের layer-কে চেনে। ভেতরের layer বাইরের কাউকে চেনে না।&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;মানে Domain জানেই না SQL Server কী জিনিস। Application জানে না Controller কী। কিন্তু API সবাইকে চেনে।&lt;/p&gt;

&lt;p&gt;এভাবে করার কারণ সোজা। Database বদলাবে, UI বদলাবে, কিন্তু business logic মোটামুটি একই থাকবে। তাই সেটাকে আলাদা করে সুরক্ষিত রাখি।&lt;/p&gt;




&lt;h2&gt;
  
  
  ২. চারটা Layer, একে একে
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Domain: বাড়ির ইট
&lt;/h3&gt;

&lt;p&gt;প্রজেক্টের কেন্দ্র। Business-এর আসল ধারণাগুলো এখানে থাকে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;থাকে:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entities&lt;/strong&gt;: যেমন &lt;code&gt;Student&lt;/code&gt;, &lt;code&gt;Course&lt;/code&gt;, &lt;code&gt;Enrollment&lt;/code&gt;। দেখতে table-এর মতো, কিন্তু business rule সহ&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value Objects&lt;/strong&gt;: যেগুলোর আলাদা id লাগে না, যেমন &lt;code&gt;Money&lt;/code&gt;, &lt;code&gt;Address&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enums&lt;/strong&gt;: &lt;code&gt;EnrollmentStatus.Active&lt;/code&gt;, &lt;code&gt;PaymentStatus.Paid&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain Events&lt;/strong&gt;: &lt;code&gt;StudentEnrolled&lt;/code&gt;, &lt;code&gt;PaymentCompleted&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;থাকে না:&lt;/strong&gt; database, API, &lt;code&gt;DbContext&lt;/code&gt;, &lt;code&gt;HttpContext&lt;/code&gt;, আর প্রায় কোনো NuGet package-ই না।&lt;/p&gt;

&lt;h3&gt;
  
  
  Application: বাড়ির নকশা
&lt;/h3&gt;

&lt;p&gt;এখানে ঠিক হয় কী হবে আর কীভাবে হবে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;থাকে:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Services&lt;/strong&gt;: &lt;code&gt;EnrollmentService&lt;/code&gt;, &lt;code&gt;PaymentService&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interfaces&lt;/strong&gt;: &lt;code&gt;IEnrollmentRepository&lt;/code&gt;, &lt;code&gt;IEmailSender&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DTOs&lt;/strong&gt;: &lt;code&gt;EnrollmentRequestDto&lt;/code&gt;, &lt;code&gt;PaymentResponseDto&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validators&lt;/strong&gt; (FluentValidation) আর &lt;strong&gt;Mappings&lt;/strong&gt; (AutoMapper)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;থাকে না:&lt;/strong&gt; database connection, HTTP call, কোনো concrete implementation।&lt;/p&gt;

&lt;p&gt;একটা প্রশ্ন সবাই করে: &lt;code&gt;IEnrollmentRepository&lt;/code&gt; এখানে, তাহলে implementation কোথায়? উত্তর, Infrastructure-এ। এটাই Dependency Inversion।&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure: বাড়ির প্লাম্বিং
&lt;/h3&gt;

&lt;p&gt;বাইরের জগতের সাথে সব যোগাযোগ এখানে। Database, payment gateway, email, file system।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;থাকে:&lt;/strong&gt; &lt;code&gt;AppDbContext&lt;/code&gt;, repository-র implementation, &lt;code&gt;AdyenPaymentService&lt;/code&gt;, &lt;code&gt;SendGridEmailService&lt;/code&gt;, EF configuration, migrations।&lt;/p&gt;

&lt;p&gt;একটা মজার টেস্ট: পুরো Infrastructure project মুছে দিলেও Application layer টের পাবে না। কারণ সে শুধু interface চেনে।&lt;/p&gt;

&lt;h3&gt;
  
  
  Presentation (API): বাড়ির দরজা
&lt;/h3&gt;

&lt;p&gt;HTTP request এখান দিয়েই ঢোকে।&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;থাকে:&lt;/strong&gt; Controllers, Middleware, Filters, আর &lt;code&gt;Program.cs&lt;/code&gt; (DI setup আর pipeline)।&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Controller-এ business logic লিখো না। Controller শুধু HTTP সামলাবে, বাকি কাজ service-এর।&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;বাড়ির সাথে তুলনা&lt;/th&gt;
&lt;th&gt;কাজ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Domain&lt;/td&gt;
&lt;td&gt;ইট, সিমেন্ট&lt;/td&gt;
&lt;td&gt;মূল উপাদান&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application&lt;/td&gt;
&lt;td&gt;নকশা&lt;/td&gt;
&lt;td&gt;কী হবে, কীভাবে হবে&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Infrastructure&lt;/td&gt;
&lt;td&gt;প্লাম্বিং, বিদ্যুৎ&lt;/td&gt;
&lt;td&gt;বাইরের সাথে যোগাযোগ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Presentation&lt;/td&gt;
&lt;td&gt;দরজা&lt;/td&gt;
&lt;td&gt;সবার প্রবেশপথ&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  ৩. বাস্তব Folder Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SchoolApp/
├── src/
│   ├── SchoolApp.Domain/
│   │   ├── Entities/        (Student, Course, Enrollment)
│   │   ├── ValueObjects/    (Money, Address)
│   │   ├── Enums/
│   │   ├── Events/
│   │   └── Common/          (BaseEntity)
│   │
│   ├── SchoolApp.Application/
│   │   ├── Services/
│   │   ├── Interfaces/
│   │   ├── DTOs/
│   │   ├── Validators/
│   │   └── Mappings/
│   │
│   ├── SchoolApp.Infrastructure/
│   │   ├── Persistence/     (AppDbContext, Repositories, Configurations)
│   │   ├── Services/        (AdyenPaymentService, SendGridEmailService)
│   │   └── Migrations/
│   │
│   └── SchoolApp.API/
│       ├── Controllers/
│       ├── Middleware/
│       ├── Program.cs
│       └── appsettings.json
│
└── tests/
    ├── SchoolApp.UnitTests/
    └── SchoolApp.IntegrationTests/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ৪. Request-এর যাত্রা
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP Request
   ↓
Controller            (API)
   ↓
Service               (Application)
   ↓
Repository Interface  (Application)
   ↓
Repository Impl       (Infrastructure)
   ↓
DbContext → Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;উপর থেকে নিচে যায় request, নিচ থেকে উপরে আসে response। প্রতিটা layer শুধু তার ঠিক পরের layer-কে ডাকে। Controller সরাসরি &lt;code&gt;DbContext&lt;/code&gt; ধরবে না।&lt;/p&gt;




&lt;h2&gt;
  
  
  ৫. ছোট একটা উদাহরণ: Enrollment
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Controller (API)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"enroll"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Enroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EnrollmentRequestDto&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_enrollmentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnrollAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Service (Application)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EnrollmentResponseDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;EnrollAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EnrollmentRequestDto&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;course&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_courseRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CourseId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Seats&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;BusinessException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"No seats available"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;enrollment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Enrollment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StudentId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;course&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_enrollmentRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enrollment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_mapper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EnrollmentResponseDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;enrollment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Repository (Infrastructure)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Course&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetByIdAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Courses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;খেয়াল করো, Service-এ business rule (&lt;code&gt;Seats &amp;lt;= 0&lt;/code&gt;) আছে কিন্তু database-এর নাম নেই। Repository-তে database আছে কিন্তু কোনো business rule নেই। এটাই পুরো ব্যাপারটার সারকথা।&lt;/p&gt;




&lt;h2&gt;
  
  
  ৬. নতুনদের ৬টা কমন ভুল
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Controller-এ business logic লেখা।&lt;/strong&gt; সবচেয়ে বেশি দেখা যায়।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain-এ &lt;code&gt;DbContext&lt;/code&gt; ব্যবহার।&lt;/strong&gt; Domain database চেনে না।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application-এ concrete class ব্যবহার।&lt;/strong&gt; সবসময় interface নাও।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository-তে business logic ঢোকানো।&lt;/strong&gt; Repository শুধু data আনবে-নেবে।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;সব কিছু এক project-এ ফেলে রাখা।&lt;/strong&gt; অন্তত আলাদা folder তো করো।&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DTO ছাড়া Entity return করা।&lt;/strong&gt; Entity সরাসরি বাইরে পাঠিও না।&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  ৭. কখন এই structure লাগবে না?
&lt;/h2&gt;

&lt;p&gt;সত্যি কথা, ছোট প্রজেক্টে এটা overkill। ৫-১০টা endpoint-এর জন্য ৪টা project আর ২০টা folder বানালে দেখবে মাত্র ৩টা class-এর জন্য এত ঝামেলা।&lt;/p&gt;

&lt;p&gt;আমার নিয়ম: &lt;em&gt;কোনো pattern তখনই আনো, যখন সেটা না থাকার কষ্ট, রক্ষণাবেক্ষণের কষ্টের চেয়ে বেশি।&lt;/em&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;প্রজেক্টের সাইজ&lt;/th&gt;
&lt;th&gt;যা করবে&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;৫-১০ endpoint&lt;/td&gt;
&lt;td&gt;এক project, simple folder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;২০-৫০ endpoint&lt;/td&gt;
&lt;td&gt;এক project, আলাদা folder (Domain, Services, Data)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;৫০+ endpoint বা টিমে ২+ জন&lt;/td&gt;
&lt;td&gt;Clean Architecture&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  শেষ কথা
&lt;/h2&gt;

&lt;p&gt;Folder structure আসলে দায়িত্ব ভাগ করে দেওয়ার ব্যাপার। Database-এর কাজ database করবে, business-এর কাজ business, আর presentation-এর কাজ presentation।&lt;/p&gt;

&lt;p&gt;প্রতিটা class যখন শুধু নিজের কাজটাই করে, তখন পুরো প্রজেক্ট বোঝা সহজ হয়, test করা সহজ হয়, আর বদলানোও সহজ হয়।&lt;/p&gt;

&lt;p&gt;এটা কোনো কঠিন নিয়ম না। এটা common sense।&lt;/p&gt;

</description>
      <category>dotnetcore</category>
      <category>csharp</category>
      <category>cleancode</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
