<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Modular-Monolith on TECHFOR by Suriya Sonphu</title><link>http://suriyasonphu.com/tags/modular-monolith/</link><description>Recent content in Modular-Monolith on TECHFOR by Suriya Sonphu</description><generator>Hugo -- gohugo.io</generator><language>th</language><lastBuildDate>Fri, 08 Aug 2025 00:00:00 +0000</lastBuildDate><atom:link href="http://suriyasonphu.com/tags/modular-monolith/index.xml" rel="self" type="application/rss+xml"/><item><title>การสร้าง Full Stack Web Application: Vue.js + Tailwind CSS + ASP.NET Core 9 Minimal API ด้วย Modular Monolith Architecture</title><link>http://suriyasonphu.com/post/2025-08-08-fullstack-vue-tailwind-dotnet-modular-monolith/</link><pubDate>Fri, 08 Aug 2025 00:00:00 +0000</pubDate><guid>http://suriyasonphu.com/post/2025-08-08-fullstack-vue-tailwind-dotnet-modular-monolith/</guid><description>&lt;img src="http://suriyasonphu.com/post/2025-08-08-fullstack-vue-tailwind-dotnet-modular-monolith/fullstack-cover.svg" alt="Featured image of post การสร้าง Full Stack Web Application: Vue.js + Tailwind CSS + ASP.NET Core 9 Minimal API ด้วย Modular Monolith Architecture" />&lt;h2 id="บทนำ-full-stack-development-คออะไร">บทนำ: Full Stack Development คืออะไร?
&lt;/h2>&lt;p>&lt;strong>Full Stack Development&lt;/strong> หมายถึงการพัฒนาทั้งส่วน frontend (ฝั่งผู้ใช้) และ backend (ฝั่งเซิร์ฟเวอร์) ของเว็บแอปพลิเคชัน นักพัฒนา full stack คือผู้ที่สามารถทำงานได้ทั้งส่วนของ user interface ที่ผู้ใช้มองเห็นและโต้ตอบได้ และส่วนของ server logic ที่ทำงานเบื้องหลัง&lt;/p>
&lt;h3 id="องคประกอบหลกของ-full-stack-development">องค์ประกอบหลักของ Full Stack Development:
&lt;/h3>&lt;ul>
&lt;li>
&lt;p>&lt;strong>Frontend (Client-side)&lt;/strong>: สิ่งที่ผู้ใช้เห็นและโต้ตอบ&lt;/p>
&lt;ul>
&lt;li>User Interface (UI)&lt;/li>
&lt;li>User Experience (UX)&lt;/li>
&lt;li>Client-side logic และการทำงานโต้ตอบ&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Backend (Server-side)&lt;/strong>: เครื่องยนต์ที่ขับเคลื่อนแอปพลิเคชัน&lt;/p>
&lt;ul>
&lt;li>Server logic และ APIs&lt;/li>
&lt;li>การจัดการฐานข้อมูล&lt;/li>
&lt;li>Authentication และความปลอดภัย&lt;/li>
&lt;li>Business logic&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Database&lt;/strong>: ที่เก็บและจัดการข้อมูล&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>DevOps&lt;/strong>: การ deploy และจัดการ infrastructure&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>ในบทความนี้ เราจะสร้าง full stack application ที่สมบูรณ์โดยใช้เทคโนโลยีสมัยใหม่: &lt;strong>Vue.js&lt;/strong> สำหรับ frontend, &lt;strong>Tailwind CSS&lt;/strong> สำหรับการจัดแต่งหน้าตา และ &lt;strong>ASP.NET Core 9 Minimal API&lt;/strong> สำหรับ backend โดยจัดระบบด้วย &lt;strong>Modular Monolith&lt;/strong> architecture&lt;/p>
&lt;h2 id="vuejs-คออะไร">Vue.js คืออะไร?
&lt;/h2>&lt;p>&lt;strong>Vue.js&lt;/strong> เป็น progressive JavaScript framework สำหรับสร้าง user interfaces และ single-page applications (SPAs) สร้างโดย Evan You ในปี 2014 Vue.js ได้กลายเป็นหนึ่งใน frontend frameworks ที่ได้รับความนิยมมากที่สุด เคียงข้างกับ React และ Angular&lt;/p>
&lt;h3 id="คณสมบตหลกของ-vuejs">คุณสมบัติหลักของ Vue.js:
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Progressive Framework&lt;/strong>: สามารถใช้ Vue.js แบบค่อยเป็นค่อยไป - ใช้เพียงส่วนหนึ่งของหน้าเว็บหรือสร้างแอปพลิเคชันทั้งหมด&lt;/li>
&lt;li>&lt;strong>Reactive Data Binding&lt;/strong>: UI อัปเดตอัตโนมัติเมื่อข้อมูลเปลี่ยน&lt;/li>
&lt;li>&lt;strong>Component-Based Architecture&lt;/strong>: สร้าง components ที่ห่อหุ้มและจัดการ state ของตัวเอง&lt;/li>
&lt;li>&lt;strong>Virtual DOM&lt;/strong>: การ render ที่มีประสิทธิภาพสำหรับความเร็วที่เหมาะสม&lt;/li>
&lt;li>&lt;strong>ง่ายต่อการเรียนรู้&lt;/strong>: syntax ที่เรียบง่าย เข้าใจง่ายสำหรับผู้เริ่มต้น&lt;/li>
&lt;/ol>
&lt;h3 id="ขอดของ-vuejs">ข้อดีของ Vue.js:
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>ขนาด bundle เล็ก&lt;/strong>: โหลดเร็ว&lt;/li>
&lt;li>&lt;strong>เอกสารที่เยี่ยม&lt;/strong>: ครอบคลุมและเข้าใจง่ายสำหรับผู้เริ่มต้น&lt;/li>
&lt;li>&lt;strong>ระบบนิเวศที่ดี&lt;/strong>: เครื่องมือและไลบรารีที่หลากหลาย&lt;/li>
&lt;li>&lt;strong>รองรับ TypeScript&lt;/strong>: การผสานรวม TypeScript อย่างเต็มรูปแบบ&lt;/li>
&lt;li>&lt;strong>Composition API&lt;/strong>: วิธีสมัยใหม่ในการจัดระเบียบ component logic&lt;/li>
&lt;/ul>
&lt;h3 id="ตวอยาง-vuejs-component">ตัวอย่าง Vue.js Component:
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-vue" data-lang="vue">&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">template&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">div&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;user-profile&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">h2&lt;/span>&amp;gt;{{ &lt;span style="color:#a6e22e">user&lt;/span>.&lt;span style="color:#a6e22e">name&lt;/span> }}&amp;lt;/&lt;span style="color:#f92672">h2&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">p&lt;/span>&amp;gt;{{ &lt;span style="color:#a6e22e">user&lt;/span>.&lt;span style="color:#a6e22e">email&lt;/span> }}&amp;lt;/&lt;span style="color:#f92672">p&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">button&lt;/span> &lt;span style="color:#f92672">@click&lt;/span>&lt;span style="color:#e6db74">=&amp;#34;updateProfile&amp;#34;&lt;/span>&amp;gt;&lt;span style="color:#a6e22e">อัปเดตโปรไฟล์&lt;/span>&amp;lt;/&lt;span style="color:#f92672">button&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#f92672">template&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">script&lt;/span> &lt;span style="color:#a6e22e">setup&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">import&lt;/span> { &lt;span style="color:#a6e22e">ref&lt;/span>, &lt;span style="color:#a6e22e">reactive&lt;/span> } &lt;span style="color:#a6e22e">from&lt;/span> &lt;span style="color:#e6db74">&amp;#39;vue&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">user&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">reactive&lt;/span>({
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">name&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#e6db74">&amp;#39;สมชาย ใจดี&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">email&lt;/span>&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#e6db74">&amp;#39;somchai@example.com&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">updateProfile&lt;/span> &lt;span style="color:#f92672">=&lt;/span> () =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// อัปเดตโปรไฟล์ผู้ใช้
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#a6e22e">console&lt;/span>.&lt;span style="color:#a6e22e">log&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;โปรไฟล์ถูกอัปเดตแล้ว!&amp;#39;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>อ้างอิง&lt;/strong>: &lt;a class="link" href="https://vuejs.org/" target="_blank" rel="noopener"
>Vue.js Official Documentation&lt;/a>&lt;/p>
&lt;h2 id="tailwind-css-คออะไร">Tailwind CSS คืออะไร?
&lt;/h2>&lt;p>&lt;strong>Tailwind CSS&lt;/strong> เป็น utility-first CSS framework ที่ให้ utility classes ระดับต่ำสำหรับสร้างการออกแบบที่กำหนดเองได้โดยตรงใน markup แทนที่จะเขียน custom CSS คุณจะประกอบการออกแบบด้วยการรวม utility classes ขนาดเล็กที่มีจุดประสงค์เดียว&lt;/p>
&lt;h3 id="คณสมบตหลกของ-tailwind-css">คุณสมบัติหลักของ Tailwind CSS:
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Utility-First&lt;/strong>: classes ที่สร้างมาล่วงหน้าสำหรับ CSS properties ทั่วไป&lt;/li>
&lt;li>&lt;strong>Responsive Design&lt;/strong>: utilities สำหรับ responsive design ที่สร้างไว้แล้ว&lt;/li>
&lt;li>&lt;strong>ปรับแต่งได้&lt;/strong>: ระบบการออกแบบที่กำหนดค่าได้สูง&lt;/li>
&lt;li>&lt;strong>ประสิทธิภาพ&lt;/strong>: ลบ CSS ที่ไม่ใช้อัตโนมัติ&lt;/li>
&lt;li>&lt;strong>ประสบการณ์นักพัฒนา&lt;/strong>: รองรับ IDE และเครื่องมือ debugging ที่เยี่ยม&lt;/li>
&lt;/ol>
&lt;h3 id="ขอดของ-tailwind-css">ข้อดีของ Tailwind CSS:
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>การพัฒนาอย่างรวดเร็ว&lt;/strong>: สร้าง interfaces ได้เร็วโดยไม่ต้องเขียน custom CSS&lt;/li>
&lt;li>&lt;strong>การออกแบบที่สอดคล้อง&lt;/strong>: ระบบการออกแบบที่สร้างไว้แล้วรับประกันความสอดคล้อง&lt;/li>
&lt;li>&lt;strong>Mobile-First&lt;/strong>: responsive design ตั้งแต่ต้น&lt;/li>
&lt;li>&lt;strong>ขนาด Bundle เล็ก&lt;/strong>: รวมเฉพาะ CSS ที่คุณใช้จริง&lt;/li>
&lt;li>&lt;strong>ไม่ต้องเปลี่ยนบริบท&lt;/strong>: จัดแต่ง components โดยไม่ต้องออกจาก HTML&lt;/li>
&lt;/ul>
&lt;h3 id="ตวอยางการใช-tailwind-css">ตัวอย่างการใช้ Tailwind CSS:
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&amp;lt;!-- วิธี CSS แบบดั้งเดิม --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">div&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;card&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">h2&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;card-title&amp;#34;&lt;/span>&amp;gt;สวัสดีครับ&amp;lt;/&lt;span style="color:#f92672">h2&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">p&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;card-description&amp;#34;&lt;/span>&amp;gt;นี่คือคำอธิบาย&amp;lt;/&lt;span style="color:#f92672">p&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">button&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;btn btn-primary&amp;#34;&lt;/span>&amp;gt;คลิกที่นี่&amp;lt;/&lt;span style="color:#f92672">button&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&amp;lt;!-- วิธี Tailwind CSS --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">div&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;bg-white p-6 rounded-lg shadow-md&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">h2&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;text-2xl font-bold text-gray-900 mb-2&amp;#34;&lt;/span>&amp;gt;สวัสดีครับ&amp;lt;/&lt;span style="color:#f92672">h2&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">p&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;text-gray-600 mb-4&amp;#34;&lt;/span>&amp;gt;นี่คือคำอธิบาย&amp;lt;/&lt;span style="color:#f92672">p&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">button&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> คลิกที่นี่
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">button&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="tailwind-css-classes-ทใชบอย">Tailwind CSS Classes ที่ใช้บ่อย:
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>Layout&lt;/strong>: &lt;code>flex&lt;/code>, &lt;code>grid&lt;/code>, &lt;code>container&lt;/code>, &lt;code>mx-auto&lt;/code>&lt;/li>
&lt;li>&lt;strong>Spacing&lt;/strong>: &lt;code>p-4&lt;/code> (padding), &lt;code>m-2&lt;/code> (margin), &lt;code>space-y-4&lt;/code>&lt;/li>
&lt;li>&lt;strong>Typography&lt;/strong>: &lt;code>text-xl&lt;/code>, &lt;code>font-bold&lt;/code>, &lt;code>text-center&lt;/code>&lt;/li>
&lt;li>&lt;strong>Colors&lt;/strong>: &lt;code>bg-blue-500&lt;/code>, &lt;code>text-red-600&lt;/code>, &lt;code>border-gray-300&lt;/code>&lt;/li>
&lt;li>&lt;strong>Responsive&lt;/strong>: &lt;code>sm:text-lg&lt;/code>, &lt;code>md:grid-cols-2&lt;/code>, &lt;code>lg:px-8&lt;/code>&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>อ้างอิง&lt;/strong>: &lt;a class="link" href="https://tailwindcss.com/" target="_blank" rel="noopener"
>Tailwind CSS Official Documentation&lt;/a>&lt;/p>
&lt;h2 id="aspnet-core-9-minimal-api-คออะไร">ASP.NET Core 9 Minimal API คืออะไร?
&lt;/h2>&lt;p>&lt;strong>ASP.NET Core Minimal API&lt;/strong> เป็นแนวทางที่เรียบง่ายในการสร้าง HTTP APIs ด้วย ASP.NET Core เปิดตัวใน .NET 6 และปรับปรุงในเวอร์ชันต่อๆ มารวมถึง .NET 9 Minimal APIs ช่วยให้คุณสร้าง APIs ได้โดยใช้ code น้อยและไม่ซับซ้อน&lt;/p>
&lt;h3 id="คณสมบตหลกของ-minimal-api">คุณสมบัติหลักของ Minimal API:
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Boilerplate น้อย&lt;/strong>: เขียน code น้อยกว่าแบบ controllers ดั้งเดิม&lt;/li>
&lt;li>&lt;strong>ประสิทธิภาพ&lt;/strong>: ประสิทธิภาพสูงด้วย overhead ที่น้อย&lt;/li>
&lt;li>&lt;strong>Syntax เรียบง่าย&lt;/strong>: เข้าใจและเขียนง่าย&lt;/li>
&lt;li>&lt;strong>คุณสมบัติที่สร้างไว้&lt;/strong>: model binding, validation และรองรับ OpenAPI อัตโนมัติ&lt;/li>
&lt;li>&lt;strong>Hosting&lt;/strong>: ผสานรวมกับ ASP.NET Core hosting model&lt;/li>
&lt;/ol>
&lt;h3 id="ขอดของ-minimal-api">ข้อดีของ Minimal API:
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>การพัฒนาอย่างรวดเร็ว&lt;/strong>: สร้าง APIs ได้เร็วด้วยการตั้งค่าที่น้อย&lt;/li>
&lt;li>&lt;strong>เหมาะกับ Microservices&lt;/strong>: เหมาะสำหรับ services ขนาดเล็กที่มีจุดมุ่งหมายเฉพาะ&lt;/li>
&lt;li>&lt;strong>Cloud Native&lt;/strong>: เหมาะสำหรับสภาพแวดล้อม containerized&lt;/li>
&lt;li>&lt;strong>คุณสมบัติ C# สมัยใหม่&lt;/strong>: ใช้ประโยชน์จากคุณสมบัติล่าสุดของภาษา C#&lt;/li>
&lt;li>&lt;strong>การผสานรวม&lt;/strong>: ทำงานร่วมกับไลบรารี .NET อื่นๆ ได้อย่างราบรื่น&lt;/li>
&lt;/ul>
&lt;h3 id="ตวอยาง-minimal-api">ตัวอย่าง Minimal API:
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">using&lt;/span> Microsoft.EntityFrameworkCore;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> builder = WebApplication.CreateBuilder(args);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// เพิ่ม services ลงใน container&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddDbContext&amp;lt;AppDbContext&amp;gt;(options =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> options.UseSqlite(&lt;span style="color:#e6db74">&amp;#34;DataSource=app.db&amp;#34;&lt;/span>));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddEndpointsApiExplorer();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddSwaggerGen();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> app = builder.Build();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// กำหนดค่า HTTP request pipeline&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> (app.Environment.IsDevelopment())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> app.UseSwagger();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> app.UseSwaggerUI();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.UseHttpsRedirection();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// กำหนด API endpoints&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.MapGet(&lt;span style="color:#e6db74">&amp;#34;/api/products&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">async&lt;/span> (AppDbContext db) =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> db.Products.ToListAsync())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .WithName(&lt;span style="color:#e6db74">&amp;#34;GetProducts&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .WithOpenApi();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.MapGet(&lt;span style="color:#e6db74">&amp;#34;/api/products/{id}&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">async&lt;/span> (&lt;span style="color:#66d9ef">int&lt;/span> id, AppDbContext db) =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> db.Products.FindAsync(id) &lt;span style="color:#66d9ef">is&lt;/span> Product product
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ? Results.Ok(product)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> : Results.NotFound())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .WithName(&lt;span style="color:#e6db74">&amp;#34;GetProduct&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .WithOpenApi();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.MapPost(&lt;span style="color:#e6db74">&amp;#34;/api/products&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">async&lt;/span> (Product product, AppDbContext db) =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> db.Products.Add(product);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> db.SaveChangesAsync();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Results.Created(&lt;span style="color:#e6db74">$&amp;#34;/api/products/{product.Id}&amp;#34;&lt;/span>, product);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.WithName(&lt;span style="color:#e6db74">&amp;#34;CreateProduct&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.WithOpenApi();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.Run();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Models&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Product&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> Id { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span> Name { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">set&lt;/span>; } = &lt;span style="color:#66d9ef">string&lt;/span>.Empty;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">decimal&lt;/span> Price { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span> Description { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">set&lt;/span>; } = &lt;span style="color:#66d9ef">string&lt;/span>.Empty;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">AppDbContext&lt;/span> : DbContext
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> AppDbContext(DbContextOptions&amp;lt;AppDbContext&amp;gt; options) : &lt;span style="color:#66d9ef">base&lt;/span>(options) { }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> DbSet&amp;lt;Product&amp;gt; Products { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>อ้างอิง&lt;/strong>: &lt;a class="link" href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis" target="_blank" rel="noopener"
>ASP.NET Core Minimal APIs Documentation&lt;/a>&lt;/p>
&lt;h2 id="ตวอยางโปรเจค-e-commerce-product-catalog">ตัวอย่างโปรเจค: E-commerce Product Catalog
&lt;/h2>&lt;p>มาสร้าง e-commerce product catalog อย่างง่ายที่แสดงให้เห็นว่าเทคโนโลยีทั้งหมดนี้ทำงานร่วมกันอย่างไรใน modular monolith architecture&lt;/p>
&lt;h3 id="โครงสรางโปรเจค">โครงสร้างโปรเจค:
&lt;/h3>&lt;pre tabindex="0">&lt;code>ECommerceApp/
├── frontend/ # Vue.js + Tailwind CSS
│ ├── src/
│ │ ├── components/
│ │ ├── views/
│ │ ├── services/
│ │ └── main.js
│ ├── index.html
│ └── package.json
├── backend/ # ASP.NET Core 9 Minimal API
│ ├── Modules/
│ │ ├── Products/
│ │ ├── Orders/
│ │ └── Users/
│ ├── Shared/
│ │ ├── Database/
│ │ └── Infrastructure/
│ ├── Program.cs
│ └── ECommerceApp.csproj
└── README.md
&lt;/code>&lt;/pre>&lt;h3 id="การตดตง-frontend-vuejs--tailwind">การติดตั้ง Frontend (Vue.js + Tailwind):
&lt;/h3>&lt;p>&lt;strong>ProductList.vue:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-vue" data-lang="vue">&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">template&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">div&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;container mx-auto px-4 py-8&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">h1&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;text-3xl font-bold text-gray-900 mb-8&amp;#34;&lt;/span>&amp;gt;&lt;span style="color:#a6e22e">แคตตาล&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">็&lt;/span>&lt;span style="color:#a6e22e">อกส&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">ิ&lt;/span>&lt;span style="color:#a6e22e">นค&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">้&lt;/span>&lt;span style="color:#a6e22e">า&lt;/span>&amp;lt;/&lt;span style="color:#f92672">h1&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">div&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">div&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">v-for&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;product in products&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">:key&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;product.id&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">div&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;p-6&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">h3&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;text-xl font-semibold text-gray-900 mb-2&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {{ &lt;span style="color:#a6e22e">product&lt;/span>.&lt;span style="color:#a6e22e">name&lt;/span> }}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">h3&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">p&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;text-gray-600 mb-4&amp;#34;&lt;/span>&amp;gt;{{ &lt;span style="color:#a6e22e">product&lt;/span>.&lt;span style="color:#a6e22e">description&lt;/span> }}&amp;lt;/&lt;span style="color:#f92672">p&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">div&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;flex justify-between items-center&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">span&lt;/span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;text-2xl font-bold text-blue-600&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#960050;background-color:#1e0010">฿&lt;/span>{{ &lt;span style="color:#a6e22e">product&lt;/span>.&lt;span style="color:#a6e22e">price&lt;/span> }}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">span&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#f92672">button&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#f92672">@click&lt;/span>&lt;span style="color:#e6db74">=&amp;#34;addToCart(product)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">class&lt;/span>&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#34;bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">เพ&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">ิ่&lt;/span>&lt;span style="color:#a6e22e">มลงตะกร&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">้&lt;/span>&lt;span style="color:#a6e22e">า&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">button&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#f92672">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#f92672">template&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#f92672">script&lt;/span> &lt;span style="color:#a6e22e">setup&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">import&lt;/span> { &lt;span style="color:#a6e22e">ref&lt;/span>, &lt;span style="color:#a6e22e">onMounted&lt;/span> } &lt;span style="color:#a6e22e">from&lt;/span> &lt;span style="color:#e6db74">&amp;#39;vue&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">import&lt;/span> { &lt;span style="color:#a6e22e">productService&lt;/span> } &lt;span style="color:#a6e22e">from&lt;/span> &lt;span style="color:#e6db74">&amp;#39;../services/productService&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">products&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">ref&lt;/span>([])
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">fetchProducts&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">async&lt;/span> () =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">response&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">await&lt;/span> &lt;span style="color:#a6e22e">productService&lt;/span>.&lt;span style="color:#a6e22e">getAll&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">products&lt;/span>.&lt;span style="color:#a6e22e">value&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#a6e22e">response&lt;/span>.&lt;span style="color:#a6e22e">data&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> } &lt;span style="color:#66d9ef">catch&lt;/span> (&lt;span style="color:#a6e22e">error&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">console&lt;/span>.&lt;span style="color:#a6e22e">error&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;เกิดข้อผิดพลาดในการดึงข้อมูลสินค้า:&amp;#39;&lt;/span>, &lt;span style="color:#a6e22e">error&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">addToCart&lt;/span> &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#a6e22e">product&lt;/span>) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// เพิ่มลงตะกร้า logic
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#a6e22e">console&lt;/span>.&lt;span style="color:#a6e22e">log&lt;/span>(&lt;span style="color:#e6db74">&amp;#39;เพิ่มลงตะกร้า:&amp;#39;&lt;/span>, &lt;span style="color:#a6e22e">product&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">onMounted&lt;/span>(() =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#a6e22e">fetchProducts&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>})
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#f92672">script&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Product Service:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-javascript" data-lang="javascript">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// services/productService.js
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">import&lt;/span> &lt;span style="color:#a6e22e">axios&lt;/span> &lt;span style="color:#a6e22e">from&lt;/span> &lt;span style="color:#e6db74">&amp;#39;axios&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">API_BASE_URL&lt;/span> &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;https://localhost:7070/api&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">export&lt;/span> &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#a6e22e">productService&lt;/span> &lt;span style="color:#f92672">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#a6e22e">getAll&lt;/span>() {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> &lt;span style="color:#a6e22e">axios&lt;/span>.&lt;span style="color:#a6e22e">get&lt;/span>(&lt;span style="color:#e6db74">`&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>&lt;span style="color:#a6e22e">API_BASE_URL&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/products`&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#a6e22e">getById&lt;/span>(&lt;span style="color:#a6e22e">id&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> &lt;span style="color:#a6e22e">axios&lt;/span>.&lt;span style="color:#a6e22e">get&lt;/span>(&lt;span style="color:#e6db74">`&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>&lt;span style="color:#a6e22e">API_BASE_URL&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/products/&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>&lt;span style="color:#a6e22e">id&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">`&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#a6e22e">create&lt;/span>(&lt;span style="color:#a6e22e">product&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> &lt;span style="color:#a6e22e">axios&lt;/span>.&lt;span style="color:#a6e22e">post&lt;/span>(&lt;span style="color:#e6db74">`&lt;/span>&lt;span style="color:#e6db74">${&lt;/span>&lt;span style="color:#a6e22e">API_BASE_URL&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">/products`&lt;/span>, &lt;span style="color:#a6e22e">product&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="การตดตง-backend-aspnet-core-9-minimal-api">การติดตั้ง Backend (ASP.NET Core 9 Minimal API):
&lt;/h3>&lt;p>&lt;strong>Program.cs:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">using&lt;/span> Microsoft.EntityFrameworkCore;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">using&lt;/span> ECommerceApp.Modules.Products;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">using&lt;/span> ECommerceApp.Modules.Orders;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">using&lt;/span> ECommerceApp.Shared.Database;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> builder = WebApplication.CreateBuilder(args);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// เพิ่ม services ลงใน container&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddDbContext&amp;lt;AppDbContext&amp;gt;(options =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> options.UseSqlite(builder.Configuration.GetConnectionString(&lt;span style="color:#e6db74">&amp;#34;DefaultConnection&amp;#34;&lt;/span>)));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// เพิ่ม CORS&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddCors(options =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> options.AddPolicy(&lt;span style="color:#e6db74">&amp;#34;AllowFrontend&amp;#34;&lt;/span>, policy =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> policy.WithOrigins(&lt;span style="color:#e6db74">&amp;#34;http://localhost:3000&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .AllowAnyHeader()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .AllowAnyMethod();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddEndpointsApiExplorer();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddSwaggerGen();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ลงทะเบียน module services&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddProductModule();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>builder.Services.AddOrderModule();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">var&lt;/span> app = builder.Build();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// กำหนดค่า HTTP request pipeline&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">if&lt;/span> (app.Environment.IsDevelopment())
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> app.UseSwagger();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> app.UseSwaggerUI();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.UseHttpsRedirection();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.UseCors(&lt;span style="color:#e6db74">&amp;#34;AllowFrontend&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// แมป module endpoints&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.MapProductEndpoints();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.MapOrderEndpoints();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>app.Run();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Product Module:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Modules/Products/ProductModule.cs&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">using&lt;/span> Microsoft.EntityFrameworkCore;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">using&lt;/span> ECommerceApp.Shared.Database;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">namespace&lt;/span> ECommerceApp.Modules.Products;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">ProductModule&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> IServiceCollection AddProductModule(&lt;span style="color:#66d9ef">this&lt;/span> IServiceCollection services)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> services.AddScoped&amp;lt;IProductService, ProductService&amp;gt;();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> services;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> WebApplication MapProductEndpoints(&lt;span style="color:#66d9ef">this&lt;/span> WebApplication app)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#66d9ef">group&lt;/span> = app.MapGroup(&lt;span style="color:#e6db74">&amp;#34;/api/products&amp;#34;&lt;/span>).WithTags(&lt;span style="color:#e6db74">&amp;#34;Products&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">group&lt;/span>.MapGet(&lt;span style="color:#e6db74">&amp;#34;/&amp;#34;&lt;/span>, GetProducts);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">group&lt;/span>.MapGet(&lt;span style="color:#e6db74">&amp;#34;/{id}&amp;#34;&lt;/span>, GetProduct);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">group&lt;/span>.MapPost(&lt;span style="color:#e6db74">&amp;#34;/&amp;#34;&lt;/span>, CreateProduct);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">group&lt;/span>.MapPut(&lt;span style="color:#e6db74">&amp;#34;/{id}&amp;#34;&lt;/span>, UpdateProduct);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">group&lt;/span>.MapDelete(&lt;span style="color:#e6db74">&amp;#34;/{id}&amp;#34;&lt;/span>, DeleteProduct);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> app;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task&amp;lt;IResult&amp;gt; GetProducts(IProductService productService)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> products = &lt;span style="color:#66d9ef">await&lt;/span> productService.GetAllAsync();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Results.Ok(products);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task&amp;lt;IResult&amp;gt; GetProduct(&lt;span style="color:#66d9ef">int&lt;/span> id, IProductService productService)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> product = &lt;span style="color:#66d9ef">await&lt;/span> productService.GetByIdAsync(id);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> product != &lt;span style="color:#66d9ef">null&lt;/span> ? Results.Ok(product) : Results.NotFound();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task&amp;lt;IResult&amp;gt; CreateProduct(Product product, IProductService productService)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> createdProduct = &lt;span style="color:#66d9ef">await&lt;/span> productService.CreateAsync(product);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Results.Created(&lt;span style="color:#e6db74">$&amp;#34;/api/products/{createdProduct.Id}&amp;#34;&lt;/span>, createdProduct);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task&amp;lt;IResult&amp;gt; UpdateProduct(&lt;span style="color:#66d9ef">int&lt;/span> id, Product product, IProductService productService)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (id != product.Id) &lt;span style="color:#66d9ef">return&lt;/span> Results.BadRequest();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> updatedProduct = &lt;span style="color:#66d9ef">await&lt;/span> productService.UpdateAsync(product);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> updatedProduct != &lt;span style="color:#66d9ef">null&lt;/span> ? Results.Ok(updatedProduct) : Results.NotFound();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task&amp;lt;IResult&amp;gt; DeleteProduct(&lt;span style="color:#66d9ef">int&lt;/span> id, IProductService productService)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> success = &lt;span style="color:#66d9ef">await&lt;/span> productService.DeleteAsync(id);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> success ? Results.NoContent() : Results.NotFound();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="ทำไม-modular-monolith-ถงสำคญ">ทำไม Modular Monolith ถึงสำคัญ?
&lt;/h2>&lt;p>&lt;strong>Modular Monolith&lt;/strong> รวมข้อดีของทั้ง monolithic และ microservices architectures ทำให้เป็นทางเลือกที่ยอดเยี่ยมสำหรับแอปพลิเคชันหลายประเภท โดยเฉพาะเมื่อเริ่มต้นโปรเจคใหม่&lt;/p>
&lt;h3 id="ขอดของ-modular-monolith">ข้อดีของ Modular Monolith:
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>ความเรียบง่าย&lt;/strong>: deployment unit เดียว ง่ายต่อการพัฒนาและ debug&lt;/li>
&lt;li>&lt;strong>ประสิทธิภาพ&lt;/strong>: ไม่มี network latency ระหว่าง modules&lt;/li>
&lt;li>&lt;strong>ความสอดคล้อง&lt;/strong>: database transactions เดียวข้าม modules&lt;/li>
&lt;li>&lt;strong>ความเร็วในการพัฒนา&lt;/strong>: การพัฒนาที่เร็วขึ้นด้วยการแชร์ code และไลบรารี&lt;/li>
&lt;li>&lt;strong>การปรับปรุงง่าย&lt;/strong>: สามารถแยกเป็น microservices ทีหลังได้หากจำเป็น&lt;/li>
&lt;/ol>
&lt;h3 id="หลกการสำคญ">หลักการสำคัญ:
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>ขอบเขต Module ที่ชัดเจน&lt;/strong>: แต่ละ module มีความรับผิดชอบที่กำหนดไว้อย่างชัดเจน&lt;/li>
&lt;li>&lt;strong>การเชื่อมต่อแบบหลวม&lt;/strong>: modules สื่อสารผ่าน interfaces ที่กำหนดไว้อย่างดี&lt;/li>
&lt;li>&lt;strong>ความเหนียวแน่นสูง&lt;/strong>: functionality ที่เกี่ยวข้องอยู่ด้วยกันภายใน module&lt;/li>
&lt;li>&lt;strong>Infrastructure ร่วม&lt;/strong>: เรื่องทั่วไปเช่น logging, configuration, database&lt;/li>
&lt;/ol>
&lt;h3 id="เมอไรควรใช-modular-monolith">เมื่อไรควรใช้ Modular Monolith:
&lt;/h3>&lt;ul>
&lt;li>&lt;strong>เริ่มโปรเจคใหม่&lt;/strong>: เริ่มด้วย monolith แล้วแยกทีหลังหากจำเป็น&lt;/li>
&lt;li>&lt;strong>ทีมขนาดเล็กถึงกลาง&lt;/strong>: การประสานงานและการพัฒนาที่ง่ายขึ้น&lt;/li>
&lt;li>&lt;strong>ขอบเขต domain ไม่แน่นอน&lt;/strong>: เรียนรู้ domain ก่อนแยก&lt;/li>
&lt;li>&lt;strong>ความต้องการประสิทธิภาพ&lt;/strong>: latency ต่ำกว่าระบบแบบกระจาย&lt;/li>
&lt;li>&lt;strong>ความต้องการความสอดคล้อง&lt;/strong>: ต้องการ ACID transactions ข้าม modules&lt;/li>
&lt;/ul>
&lt;h3 id="ตวอยางโครงสราง-module">ตัวอย่างโครงสร้าง Module:
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Modules/Products/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> ProductModule.cs &lt;span style="color:#960050;background-color:#1e0010">#&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">การกำหนดค่า&lt;/span> module &lt;span style="color:#960050;background-color:#1e0010">และ&lt;/span> endpoints
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> Models/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> Product.cs &lt;span style="color:#960050;background-color:#1e0010">#&lt;/span> Product entity
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> ProductDto.cs &lt;span style="color:#960050;background-color:#1e0010">#&lt;/span> Data transfer objects
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> Services/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> IProductService.cs &lt;span style="color:#960050;background-color:#1e0010">#&lt;/span> Service &lt;span style="color:#66d9ef">interface&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> ProductService.cs &lt;span style="color:#960050;background-color:#1e0010">#&lt;/span> Service implementation
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> Data/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> ProductRepository.cs &lt;span style="color:#960050;background-color:#1e0010">#&lt;/span> Data access layer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Modules/Orders/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> OrderModule.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> Models/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> Services/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> Data/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Shared/&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> Database/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> AppDbContext.cs &lt;span style="color:#960050;background-color:#1e0010">#&lt;/span> Shared database context
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> Infrastructure/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">├──&lt;/span> Logging/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">│&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> Configuration/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> Common/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#960050;background-color:#1e0010">└──&lt;/span> BaseEntity.cs &lt;span style="color:#960050;background-color:#1e0010">#&lt;/span> Shared &lt;span style="color:#66d9ef">base&lt;/span> classes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="เสนทางการยายไป-microservices">เส้นทางการย้ายไป Microservices:
&lt;/h3>&lt;p>หากแอปพลิเคชันของคุณเติบโตและคุณต้องการแยกเป็น microservices โครงสร้างแบบ modular ทำให้การเปลี่ยนแปลงนี้ง่ายขึ้น:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>ระบุขอบเขต Module&lt;/strong>: modules กลายเป็นขอบเขต service&lt;/li>
&lt;li>&lt;strong>แยกฐานข้อมูล&lt;/strong>: ให้แต่ละ service มีฐานข้อมูลของตัวเอง&lt;/li>
&lt;li>&lt;strong>เพิ่มชั้น Communication&lt;/strong>: แทนที่การเรียกตรงด้วย HTTP/messaging&lt;/li>
&lt;li>&lt;strong>Deploy อิสระ&lt;/strong>: แต่ละ service ได้ deployment pipeline ของตัวเอง&lt;/li>
&lt;/ol>
&lt;h2 id="สรป">สรุป
&lt;/h2>&lt;p>การสร้าง full stack applications ด้วย &lt;strong>Vue.js&lt;/strong>, &lt;strong>Tailwind CSS&lt;/strong> และ &lt;strong>ASP.NET Core 9 Minimal API&lt;/strong> โดยใช้ &lt;strong>Modular Monolith&lt;/strong> architecture ให้:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>ประสบการณ์การพัฒนาสมัยใหม่&lt;/strong>: เทคโนโลยีล่าสุดและแนวปฏิบัติที่ดีที่สุด&lt;/li>
&lt;li>&lt;strong>การพัฒนาอย่างรวดเร็ว&lt;/strong>: การทำซ้ำและ deployment ที่รวดเร็ว&lt;/li>
&lt;li>&lt;strong>สถาปัตยกรรมที่ขยายได้&lt;/strong>: สามารถเติบโตจาก monolith ไป microservices&lt;/li>
&lt;li>&lt;strong>ประสบการณ์นักพัฒนาที่ยอดเยี่ยม&lt;/strong>: เครื่องมือและเอกสารที่ยอดเยี่ยม&lt;/li>
&lt;li>&lt;strong>ประสิทธิภาพ&lt;/strong>: แอปพลิเคชันที่รวดเร็วและมีประสิทธิภาพ&lt;/li>
&lt;/ul>
&lt;p>วิธีการนี้เหมาะสำหรับผู้เริ่มต้นเขียนโปรแกรมเพราะให้:&lt;/p>
&lt;ul>
&lt;li>การแยกส่วนงานที่ชัดเจน&lt;/li>
&lt;li>แนวปฏิบัติการพัฒนาสมัยใหม่&lt;/li>
&lt;li>สถาปัตยกรรมที่ขยายได้&lt;/li>
&lt;li>แหล่งเรียนรู้ที่ยอดเยี่ยม&lt;/li>
&lt;/ul>
&lt;p>เริ่มต้นด้วย stack นี้ เรียนรู้พื้นฐาน และค่อยขยายความรู้ของคุณเมื่อแอปพลิเคชันมีความซับซ้อนมากขึ้น&lt;/p>
&lt;h2 id="อางอง">อ้างอิง
&lt;/h2>&lt;ul>
&lt;li>&lt;a class="link" href="https://vuejs.org/" target="_blank" rel="noopener"
>Vue.js Official Documentation&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://tailwindcss.com/" target="_blank" rel="noopener"
>Tailwind CSS Documentation&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis" target="_blank" rel="noopener"
>ASP.NET Core Minimal APIs&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.microsoft.com/en-us/dotnet/" target="_blank" rel="noopener"
>.NET 9 Documentation&lt;/a>&lt;/li>
&lt;li>&lt;a class="link" href="https://www.milanjovanovic.tech/blog/modular-monolith-architecture" target="_blank" rel="noopener"
>Modular Monolith Architecture&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Modular Monolith: สถาปัตยกรรมที่ผสมผสานข้อดีของ Monolith และ Microservices</title><link>http://suriyasonphu.com/post/2025-07-27-modular-monolith-architecture/</link><pubDate>Sun, 27 Jul 2025 00:00:00 +0000</pubDate><guid>http://suriyasonphu.com/post/2025-07-27-modular-monolith-architecture/</guid><description>&lt;img src="http://suriyasonphu.com/post/2025-07-27-modular-monolith-architecture/modular-monolith-cover.png" alt="Featured image of post Modular Monolith: สถาปัตยกรรมที่ผสมผสานข้อดีของ Monolith และ Microservices" />&lt;h2 id="modular-monolith-คออะไร-และทำไมถงเปนทางเลอกทนาสนใจ">Modular Monolith คืออะไร และทำไมถึงเป็นทางเลือกที่น่าสนใจ
&lt;/h2>&lt;p>Modular Monolith เป็นสถาปัตยกรรมซอฟต์แวร์ที่ผสมผสานข้อดีของ &lt;strong>Monolith&lt;/strong> และ &lt;strong>Microservices&lt;/strong> เข้าด้วยกัน โดยการจัดระเบียบโค้ดให้เป็นโมดูลที่มีขอบเขตชัดเจน (bounded context) แต่ยังคงการ deploy เป็นหน่วยเดียวกัน&lt;/p>
&lt;h3 id="ปญหาของ-traditional-monolith">ปัญหาของ Traditional Monolith
&lt;/h3>&lt;p>&lt;strong>Traditional Monolith&lt;/strong> มักจะประสบปัญหา:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Tightly Coupled Code&lt;/strong>: โค้ดทุกส่วนผูกติดกันแน่น ยากต่อการแก้ไข&lt;/li>
&lt;li>&lt;strong>Single Point of Failure&lt;/strong>: หากส่วนใดส่วนหนึ่งเสีย ระบบทั้งหมดล้มเหลว&lt;/li>
&lt;li>&lt;strong>Technology Lock-in&lt;/strong>: ต้องใช้เทคโนโลยีเดียวกันทั้งแอปพลิเคชัน&lt;/li>
&lt;li>&lt;strong>Difficult to Scale&lt;/strong>: ไม่สามารถปรับขนาดแค่ส่วนที่ต้องการได้&lt;/li>
&lt;/ul>
&lt;h3 id="ปญหาของ-microservices">ปัญหาของ Microservices
&lt;/h3>&lt;p>แม้ &lt;strong>Microservices&lt;/strong> จะแก้ปัญหาหลายอย่างของ Monolith แต่ก็มีความซับซ้อนเพิ่มขึ้น:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Distributed System Complexity&lt;/strong>: ความซับซ้อนของระบบกระจาย&lt;/li>
&lt;li>&lt;strong>Network Latency&lt;/strong>: ความล่าช้าจากการสื่อสารผ่าน network&lt;/li>
&lt;li>&lt;strong>Data Consistency&lt;/strong>: ปัญหาความสอดคล้องของข้อมูล&lt;/li>
&lt;li>&lt;strong>Operational Overhead&lt;/strong>: ต้องการทีม DevOps ที่แข็งแกร่ง&lt;/li>
&lt;li>&lt;strong>Development Complexity&lt;/strong>: ความซับซ้อนในการพัฒนาและ debug&lt;/li>
&lt;/ul>
&lt;h3 id="modular-monolith-ทางออกทสมดล">Modular Monolith: ทางออกที่สมดุล
&lt;/h3>&lt;p>Modular Monolith นำเสนอวิธีการที่สมดุล:&lt;/p>
&lt;p>&lt;strong>✅ ข้อดีที่ได้รับ:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Modularity&lt;/strong>: การแบ่งโมดูลที่ชัดเจนตาม business domain&lt;/li>
&lt;li>&lt;strong>Loose Coupling&lt;/strong>: โมดูลสื่อสารผ่าน interfaces ที่กำหนดไว้&lt;/li>
&lt;li>&lt;strong>Single Deployment&lt;/strong>: ง่ายต่อการ deploy และ maintain&lt;/li>
&lt;li>&lt;strong>Easier Testing&lt;/strong>: ทดสอบได้ง่ายกว่า distributed systems&lt;/li>
&lt;li>&lt;strong>Gradual Migration&lt;/strong>: สามารถแยกเป็น microservices ได้ในอนาคต&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>⚠️ ข้อควรพิจารณา:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Technology Constraint&lt;/strong>: ยังคงถูกจำกัดเทคโนโลยีหลัก&lt;/li>
&lt;li>&lt;strong>Shared Database&lt;/strong>: อาจมีปัญหา data coupling&lt;/li>
&lt;li>&lt;strong>Resource Scaling&lt;/strong>: ไม่สามารถ scale แต่ละโมดูลแยกได้&lt;/li>
&lt;/ul>
&lt;h2 id="โครงสรางของ-modular-monolith-e-commerce-application">โครงสร้างของ Modular Monolith E-commerce Application
&lt;/h2>&lt;p>ผมได้สร้างตัวอย่าง &lt;a class="link" href="https://github.com/suriyasonp/modular-monolith-ecommerce" target="_blank" rel="noopener"
>Modular Monolith E-commerce Application&lt;/a> ด้วย C# และ ASP.NET Core เพื่อแสดงให้เห็นการประยุกต์ใช้หลักการนี้ในการพัฒนาระบบจริง&lt;/p>
&lt;h3 id="-architecture-overview">🏗️ Architecture Overview
&lt;/h3>&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-text" data-lang="text">&lt;span style="display:flex;">&lt;span>ECommerceApp/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>├── src/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── ECommerceApp/ # Main Web API Application
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Controllers/ # API Controllers
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Program.cs # Application entry point
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ └── ECommerceApp.csproj
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── ECommerceApp.Shared/ # Shared Kernel
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Events/ # Domain Events
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Kernel/ # Base entities, interfaces
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ └── ECommerceApp.Shared.csproj
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ └── Modules/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── Orders/ # Orders Module
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Application/ # Use cases, commands, queries
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Domain/ # Domain entities, events
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Infrastructure/ # Data access, repositories
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── OrdersModule.cs # Module registration
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ └── ECommerceApp.Modules.Orders.csproj
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── Products/ # Products Module
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Application/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Domain/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── Infrastructure/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ ├── ProductsModule.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ │ └── ECommerceApp.Modules.Products.csproj
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ └── Customers/ # Customers Module
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── Domain/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── Infrastructure/
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ ├── CustomersModule.cs
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>│ └── ECommerceApp.Modules.Customers.csproj
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="-หลกการสำคญของ-modular-monolith">🎯 หลักการสำคัญของ Modular Monolith
&lt;/h3>&lt;p>&lt;strong>1. Modules (โมดูล)&lt;/strong>
แต่ละโมดูลแทนความสามารถทางธุรกิจที่แตกต่างกัน เช่น Orders, Products, Customers&lt;/p>
&lt;p>&lt;strong>2. Encapsulation (การห่อหุ้ม)&lt;/strong>
โมดูลซ่อนรายละเอียดภายในและเปิดเผยเฉพาะ functionality ที่จำเป็นผ่าน interfaces&lt;/p>
&lt;p>&lt;strong>3. Shared Kernel (แกนร่วม)&lt;/strong>
ส่วนที่ใช้ร่วมกัน เช่น base entities, common utilities, domain events&lt;/p>
&lt;p>&lt;strong>4. Communication (การสื่อสาร)&lt;/strong>
โมดูลสื่อสารผ่าน interfaces หรือ domain events หลีกเลี่ยงการพึ่งพาโดยตรง&lt;/p>
&lt;p>&lt;strong>5. Single Deployment (การ Deploy เดียว)&lt;/strong>
โมดูลทั้งหมดถูก deploy ร่วมกันเป็นหน่วยเดียว&lt;/p>
&lt;h2 id="การออกแบบโมดลตาม-domain-driven-design">การออกแบบโมดูลตาม Domain-Driven Design
&lt;/h2>&lt;h3 id="products-module">Products Module
&lt;/h3>&lt;p>&lt;strong>Domain Layer:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Product&lt;/span> : BaseEntity
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span> Name { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span> Description { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">decimal&lt;/span> Price { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> StockQuantity { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> UpdatePrice(&lt;span style="color:#66d9ef">decimal&lt;/span> newPrice)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (newPrice &amp;lt;= &lt;span style="color:#ae81ff">0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">throw&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> ArgumentException(&lt;span style="color:#e6db74">&amp;#34;Price must be positive&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Price = newPrice;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Raise domain event&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RaiseDomainEvent(&lt;span style="color:#66d9ef">new&lt;/span> ProductPriceUpdatedEvent(Id, newPrice));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> UpdateStock(&lt;span style="color:#66d9ef">int&lt;/span> quantity)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (StockQuantity + quantity &amp;lt; &lt;span style="color:#ae81ff">0&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">throw&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> InvalidOperationException(&lt;span style="color:#e6db74">&amp;#34;Insufficient stock&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> StockQuantity += quantity;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RaiseDomainEvent(&lt;span style="color:#66d9ef">new&lt;/span> ProductStockUpdatedEvent(Id, StockQuantity));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Application Layer:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">UpdateProductPriceCommand&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> Guid ProductId { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">decimal&lt;/span> NewPrice { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">UpdateProductPriceHandler&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">readonly&lt;/span> IProductRepository _repository;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task&amp;lt;Result&amp;gt; Handle(UpdateProductPriceCommand command)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> product = &lt;span style="color:#66d9ef">await&lt;/span> _repository.GetByIdAsync(command.ProductId);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (product == &lt;span style="color:#66d9ef">null&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Result.Failure(&lt;span style="color:#e6db74">&amp;#34;Product not found&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> product.UpdatePrice(command.NewPrice);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> _repository.UpdateAsync(product);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> Result.Success();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="orders-module">Orders Module
&lt;/h3>&lt;p>&lt;strong>Domain Layer:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Order&lt;/span> : BaseEntity
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> Guid CustomerId { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> OrderStatus Status { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> List&amp;lt;OrderItem&amp;gt; Items { &lt;span style="color:#66d9ef">get&lt;/span>; &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">set&lt;/span>; } = &lt;span style="color:#66d9ef">new&lt;/span>();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">decimal&lt;/span> TotalAmount =&amp;gt; Items.Sum(item =&amp;gt; item.TotalPrice);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> Order Create(Guid customerId, List&amp;lt;OrderItem&amp;gt; items)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> order = &lt;span style="color:#66d9ef">new&lt;/span> Order
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> CustomerId = customerId,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Status = OrderStatus.Pending,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Items = items
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> };
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> order.RaiseDomainEvent(&lt;span style="color:#66d9ef">new&lt;/span> OrderCreatedEvent(order.Id, customerId));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> order;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> Confirm()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">if&lt;/span> (Status != OrderStatus.Pending)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">throw&lt;/span> &lt;span style="color:#66d9ef">new&lt;/span> InvalidOperationException(&lt;span style="color:#e6db74">&amp;#34;Only pending orders can be confirmed&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Status = OrderStatus.Confirmed;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RaiseDomainEvent(&lt;span style="color:#66d9ef">new&lt;/span> OrderConfirmedEvent(Id));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="การสอสารระหวางโมดล">การสื่อสารระหว่างโมดูล
&lt;/h3>&lt;p>&lt;strong>Interface-based Communication:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ใน Orders Module&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">interface&lt;/span> &lt;span style="color:#a6e22e">IProductService&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Task&amp;lt;Product?&amp;gt; GetProductAsync(Guid productId);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Task&amp;lt;&lt;span style="color:#66d9ef">bool&lt;/span>&amp;gt; IsProductAvailableAsync(Guid productId, &lt;span style="color:#66d9ef">int&lt;/span> quantity);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ใน Products Module&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">ProductService&lt;/span> : IProductService
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">readonly&lt;/span> IProductRepository _repository;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task&amp;lt;Product?&amp;gt; GetProductAsync(Guid productId)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">await&lt;/span> _repository.GetByIdAsync(productId);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task&amp;lt;&lt;span style="color:#66d9ef">bool&lt;/span>&amp;gt; IsProductAvailableAsync(Guid productId, &lt;span style="color:#66d9ef">int&lt;/span> quantity)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> product = &lt;span style="color:#66d9ef">await&lt;/span> _repository.GetByIdAsync(productId);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> product != &lt;span style="color:#66d9ef">null&lt;/span> &amp;amp;&amp;amp; product.StockQuantity &amp;gt;= quantity;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>Event-based Communication (สำหรับอนาคต):&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">OrderConfirmedEvent&lt;/span> : IDomainEvent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> Guid OrderId { &lt;span style="color:#66d9ef">get&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> DateTime OccurredOn { &lt;span style="color:#66d9ef">get&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> OrderConfirmedEvent(Guid orderId)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> OrderId = orderId;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> OccurredOn = DateTime.UtcNow;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Event Handler ใน Products Module&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">OrderConfirmedEventHandler&lt;/span> : IEventHandler&amp;lt;OrderConfirmedEvent&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task Handle(OrderConfirmedEvent @event)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Update inventory, send notifications, etc.&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="การตดตงและรนแอปพลเคชน">การติดตั้งและรันแอปพลิเคชัน
&lt;/h2>&lt;h3 id="prerequisites">Prerequisites
&lt;/h3>&lt;ul>
&lt;li>.NET 8.0 SDK&lt;/li>
&lt;li>Visual Studio Code หรือ Visual Studio&lt;/li>
&lt;/ul>
&lt;h3 id="การเรมตนใชงาน">การเริ่มต้นใช้งาน
&lt;/h3>&lt;p>&lt;strong>1. Clone Repository:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>git clone https://github.com/suriyasonp/modular-monolith-ecommerce.git
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cd modular-monolith-ecommerce
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>2. รันแอปพลิเคชัน:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># วิธีที่ 1: ใช้ script (แนะนำ)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./run.sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># วิธีที่ 2: รันด้วยตนเอง&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dotnet build
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dotnet run --project src/ECommerceApp/ECommerceApp.csproj
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>3. เข้าถึง API:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Swagger UI&lt;/strong>: &lt;a class="link" href="http://localhost:5000/swagger/index.html" target="_blank" rel="noopener"
>http://localhost:5000/swagger/index.html&lt;/a>&lt;/li>
&lt;li>&lt;strong>API Base URL&lt;/strong>: &lt;a class="link" href="http://localhost:5000/api" target="_blank" rel="noopener"
>http://localhost:5000/api&lt;/a>&lt;/li>
&lt;li>&lt;strong>Sample Products&lt;/strong>: ข้อมูลจะถูกสร้างอัตโนมัติเมื่อเริ่มระบบ&lt;/li>
&lt;/ul>
&lt;h3 id="การทดสอบ-api">การทดสอบ API
&lt;/h3>&lt;p>&lt;strong>Quick Test Script:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./test-api.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>การทดสอบด้วยตนเอง:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># ดู Products ทั้งหมด&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl http://localhost:5000/api/products
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># สร้าง Customer ใหม่&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -X POST http://localhost:5000/api/customers &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;Content-Type: application/json&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -d &lt;span style="color:#e6db74">&amp;#39;{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;firstName&amp;#34;: &amp;#34;สมชาย&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;lastName&amp;#34;: &amp;#34;ใจดี&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;email&amp;#34;: &amp;#34;somchai@example.com&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;address&amp;#34;: {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;street&amp;#34;: &amp;#34;123 ถนนสุขุมวิท&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;city&amp;#34;: &amp;#34;กรุงเทพฯ&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;state&amp;#34;: &amp;#34;กทม&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;zipCode&amp;#34;: &amp;#34;10110&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;country&amp;#34;: &amp;#34;ไทย&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> }&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e"># สร้าง Order ใหม่&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>curl -X POST http://localhost:5000/api/orders &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -H &lt;span style="color:#e6db74">&amp;#34;Content-Type: application/json&amp;#34;&lt;/span> &lt;span style="color:#ae81ff">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ae81ff">&lt;/span> -d &lt;span style="color:#e6db74">&amp;#39;{
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;customerId&amp;#34;: &amp;#34;customer-guid-here&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;items&amp;#34;: [
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> {
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;productId&amp;#34;: &amp;#34;product-guid-here&amp;#34;,
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> &amp;#34;quantity&amp;#34;: 2
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> }
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> ]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e6db74"> }&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="api-endpoints-ทสำคญ">API Endpoints ที่สำคัญ
&lt;/h2>&lt;h3 id="products-api">Products API
&lt;/h3>&lt;ul>
&lt;li>&lt;code>GET /api/products&lt;/code> - ดูสินค้าทั้งหมด&lt;/li>
&lt;li>&lt;code>GET /api/products/{id}&lt;/code> - ดูสินค้าตาม ID&lt;/li>
&lt;li>&lt;code>POST /api/products&lt;/code> - เพิ่มสินค้าใหม่&lt;/li>
&lt;li>&lt;code>PUT /api/products/{id}/price&lt;/code> - อัปเดตราคาสินค้า&lt;/li>
&lt;li>&lt;code>PUT /api/products/{id}/stock&lt;/code> - อัปเดตสต็อกสินค้า&lt;/li>
&lt;/ul>
&lt;h3 id="customers-api">Customers API
&lt;/h3>&lt;ul>
&lt;li>&lt;code>GET /api/customers&lt;/code> - ดูลูกค้าทั้งหมด&lt;/li>
&lt;li>&lt;code>GET /api/customers/{id}&lt;/code> - ดูลูกค้าตาม ID&lt;/li>
&lt;li>&lt;code>POST /api/customers&lt;/code> - เพิ่มลูกค้าใหม่&lt;/li>
&lt;/ul>
&lt;h3 id="orders-api">Orders API
&lt;/h3>&lt;ul>
&lt;li>&lt;code>GET /api/orders&lt;/code> - ดูออเดอร์ทั้งหมด&lt;/li>
&lt;li>&lt;code>GET /api/orders/{id}&lt;/code> - ดูออเดอร์ตาม ID&lt;/li>
&lt;li>&lt;code>GET /api/orders/customer/{customerId}&lt;/code> - ดูออเดอร์ของลูกค้า&lt;/li>
&lt;li>&lt;code>POST /api/orders&lt;/code> - สร้างออเดอร์ใหม่&lt;/li>
&lt;li>&lt;code>POST /api/orders/{id}/confirm&lt;/code> - ยืนยันออเดอร์&lt;/li>
&lt;li>&lt;code>POST /api/orders/{id}/ship&lt;/code> - จัดส่งออเดอร์&lt;/li>
&lt;li>&lt;code>POST /api/orders/{id}/deliver&lt;/code> - ส่งมอบออเดอร์&lt;/li>
&lt;/ul>
&lt;h2 id="ขอดและขอเสยของ-modular-monolith">ข้อดีและข้อเสียของ Modular Monolith
&lt;/h2>&lt;h3 id="-ขอด">✅ ข้อดี
&lt;/h3>&lt;p>&lt;strong>1. ความเรียบง่ายในการ Deploy&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Deploy เป็นหน่วยเดียว ลดความซับซ้อนของ infrastructure&lt;/li>
&lt;li>ไม่ต้องกังวลเรื่อง service discovery หรือ load balancing&lt;/li>
&lt;li>การ rollback ทำได้ง่าย&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>2. ประสิทธิภาพ&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ไม่มี network latency ระหว่างโมดูล&lt;/li>
&lt;li>การสื่อสารเป็น in-process calls&lt;/li>
&lt;li>Transaction ข้าม modules ทำได้ง่าย&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3. การพัฒนาและ Debug&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Debug ได้ง่ายกว่า distributed systems&lt;/li>
&lt;li>IDE support ดีกว่า&lt;/li>
&lt;li>End-to-end testing ง่ายกว่า&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>4. ต้นทุนการดำเนินงาน&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Infrastructure requirements ต่ำกว่า&lt;/li>
&lt;li>ไม่ต้องมีทีม DevOps ขนาดใหญ่&lt;/li>
&lt;li>Monitoring และ logging ง่ายกว่า&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>5. ความยืดหยุ่นในอนาคต&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>สามารถแยกเป็น microservices ได้เมื่อจำเป็น&lt;/li>
&lt;li>โมดูลที่ออกแบบดีสามารถ extract ออกมาได้ง่าย&lt;/li>
&lt;/ul>
&lt;h3 id="-ขอเสย">⚠️ ข้อเสีย
&lt;/h3>&lt;p>&lt;strong>1. ข้อจำกัดด้านเทคโนโลยี&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ต้องใช้เทคโนโลยีหลักเดียวกัน&lt;/li>
&lt;li>ยากต่อการใช้ different tech stacks&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>2. การ Scale&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ไม่สามารถ scale แต่ละโมดูลแยกได้&lt;/li>
&lt;li>Resource utilization อาจไม่เหมาะสม&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3. Database Coupling&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>หากใช้ shared database อาจมีปัญหา coupling&lt;/li>
&lt;li>Schema migration ต้องระวังผลกระทบ&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>4. Team Independence&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ทีมยังคงต้อง coordinate ใน deployment&lt;/li>
&lt;li>Shared codebase อาจเป็นปัญหาในทีมใหญ่&lt;/li>
&lt;/ul>
&lt;h2 id="เมอไหรควรใช-modular-monolith">เมื่อไหร่ควรใช้ Modular Monolith
&lt;/h2>&lt;h3 id="-เหมาะสำหรบ">🎯 เหมาะสำหรับ:
&lt;/h3>&lt;p>&lt;strong>1. ทีมขนาดเล็กถึงกลาง (2-20 คน)&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>มีทรัพยากรจำกัดสำหรับ infrastructure complexity&lt;/li>
&lt;li>ต้องการ development velocity สูง&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>2. แอปพลิเคชันใหม่&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ยังไม่แน่ใจเรื่อง domain boundaries&lt;/li>
&lt;li>ต้องการ rapid prototyping และ iteration&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3. Requirements ยังไม่ชัดเจน&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>Business requirements เปลี่ยนแปลงบ่อย&lt;/li>
&lt;li>ต้องการความยืดหยุ่นในการปรับเปลี่ยน&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>4. Limited DevOps Capability&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ทีมยังไม่พร้อมสำหรับ distributed systems&lt;/li>
&lt;li>Infrastructure automation ยังไม่เข้มแข็ง&lt;/li>
&lt;/ul>
&lt;h3 id="-ไมเหมาะสำหรบ">🚫 ไม่เหมาะสำหรับ:
&lt;/h3>&lt;p>&lt;strong>1. องค์กรขนาดใหญ่ที่มีทีมมาก&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ทีมต้องการ independence สูง&lt;/li>
&lt;li>มี different release cycles&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>2. Requirements ที่แตกต่างกันมาก&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>แต่ละส่วนมี scalability requirements ต่างกัน&lt;/li>
&lt;li>ต้องการ different technologies&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3. Compliance และ Security ข้อจำกัดสูง&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ต้องการ isolation ระหว่าง components&lt;/li>
&lt;li>มี regulatory requirements ที่เข้มงวด&lt;/li>
&lt;/ul>
&lt;h2 id="การวางแผน-migration-path">การวางแผน Migration Path
&lt;/h2>&lt;h3 id="phase-1-เรมตนดวย-modular-monolith">Phase 1: เริ่มต้นด้วย Modular Monolith
&lt;/h3>&lt;pre tabindex="0">&lt;code>Traditional Monolith → Modular Monolith
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Activities:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ระบุ domain boundaries&lt;/li>
&lt;li>สร้าง modules ตาม business capabilities&lt;/li>
&lt;li>Implement interfaces สำหรับ inter-module communication&lt;/li>
&lt;li>เพิ่ม domain events infrastructure&lt;/li>
&lt;/ul>
&lt;h3 id="phase-2-ปรบปรง-module-independence">Phase 2: ปรับปรุง Module Independence
&lt;/h3>&lt;pre tabindex="0">&lt;code>Tightly Coupled Modules → Loosely Coupled Modules
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Activities:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>แยก databases per module&lt;/li>
&lt;li>ใช้ event-driven communication&lt;/li>
&lt;li>Implement distributed tracing&lt;/li>
&lt;li>เพิ่ม monitoring per module&lt;/li>
&lt;/ul>
&lt;h3 id="phase-3-selective-microservices-extraction">Phase 3: Selective Microservices Extraction
&lt;/h3>&lt;pre tabindex="0">&lt;code>Modular Monolith → Hybrid Architecture
&lt;/code>&lt;/pre>&lt;p>&lt;strong>Activities:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ระบุ modules ที่เหมาะสมสำหรับ extraction&lt;/li>
&lt;li>Extract modules ที่มี different scaling needs&lt;/li>
&lt;li>Implement API gateways&lt;/li>
&lt;li>Setup service mesh&lt;/li>
&lt;/ul>
&lt;h2 id="best-practices-สำหรบ-modular-monolith">Best Practices สำหรับ Modular Monolith
&lt;/h2>&lt;h3 id="-การออกแบบ-architecture">🏗️ การออกแบบ Architecture
&lt;/h3>&lt;p>&lt;strong>1. ใช้ Domain-Driven Design&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// แยก bounded context ชัดเจน&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">namespace&lt;/span> ECommerceApp.Modules.Orders.Domain
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Order&lt;/span> { } &lt;span style="color:#75715e">// Order ใน Orders context&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">namespace&lt;/span> ECommerceApp.Modules.Catalog.Domain
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Product&lt;/span> { } &lt;span style="color:#75715e">// Product ใน Catalog context&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>2. Dependency Direction&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ❌ ผิด: High-level module พึ่งพา low-level&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">OrderService&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> SqlOrderRepository _repository; &lt;span style="color:#75715e">// Direct dependency&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// ✅ ถูก: Dependency Inversion&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">OrderService&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">readonly&lt;/span> IOrderRepository _repository; &lt;span style="color:#75715e">// Interface dependency&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>3. Module Registration&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">ModuleExtensions&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> IServiceCollection AddOrdersModule(&lt;span style="color:#66d9ef">this&lt;/span> IServiceCollection services)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> services.AddScoped&amp;lt;IOrderRepository, SqlOrderRepository&amp;gt;();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> services.AddScoped&amp;lt;OrderService&amp;gt;();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> services.AddMediatR(&lt;span style="color:#66d9ef">typeof&lt;/span>(OrdersModule));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">return&lt;/span> services;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="-การจดการ-communication">🔄 การจัดการ Communication
&lt;/h3>&lt;p>&lt;strong>1. Synchronous Communication&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Interface-based communication สำหรับ immediate consistency&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">interface&lt;/span> &lt;span style="color:#a6e22e">IInventoryService&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Task&amp;lt;&lt;span style="color:#66d9ef">bool&lt;/span>&amp;gt; IsAvailableAsync(Guid productId, &lt;span style="color:#66d9ef">int&lt;/span> quantity);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Task ReserveAsync(Guid productId, &lt;span style="color:#66d9ef">int&lt;/span> quantity);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>2. Asynchronous Communication&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Event-based communication สำหรับ eventual consistency&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">OrderConfirmedEvent&lt;/span> : IDomainEvent
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> Guid OrderId { &lt;span style="color:#66d9ef">get&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> List&amp;lt;OrderItem&amp;gt; Items { &lt;span style="color:#66d9ef">get&lt;/span>; }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">[EventHandler]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">UpdateInventoryHandler&lt;/span> : IEventHandler&amp;lt;OrderConfirmedEvent&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task Handle(OrderConfirmedEvent @event)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Update inventory asynchronously&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="-การจดการ-data">🗃️ การจัดการ Data
&lt;/h3>&lt;p>&lt;strong>1. Shared Database with Schema Separation&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-sql" data-lang="sql">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Orders schema
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">SCHEMA&lt;/span> Orders;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> Orders.Orders (...);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> Orders.OrderItems (...);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">-- Products schema
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">SCHEMA&lt;/span> Products;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> Products.Products (...);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">CREATE&lt;/span> &lt;span style="color:#66d9ef">TABLE&lt;/span> Products.Categories (...);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>2. Database per Module (Advanced)&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">OrdersDbContext&lt;/span> : DbContext
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">protected&lt;/span> &lt;span style="color:#66d9ef">override&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> OnConfiguring(DbContextOptionsBuilder optionsBuilder)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> optionsBuilder.UseSqlServer(connectionString, options =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> options.MigrationsHistoryTable(&lt;span style="color:#e6db74">&amp;#34;__OrdersMigrationsHistory&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Orders&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="-การทดสอบ">🧪 การทดสอบ
&lt;/h3>&lt;p>&lt;strong>1. Module Integration Tests&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">[Test]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task CreateOrder_WithValidProducts_ShouldSucceed()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Arrange&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> productService = ServiceProvider.GetService&amp;lt;IProductService&amp;gt;();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> orderService = ServiceProvider.GetService&amp;lt;IOrderService&amp;gt;();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Act&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> result = &lt;span style="color:#66d9ef">await&lt;/span> orderService.CreateOrderAsync(customerId, orderItems);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Assert&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Assert.IsTrue(result.IsSuccess);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>2. Contract Tests&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#a6e22e">[Test]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> ProductService_ShouldImplementIProductService()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#75715e">// Verify that ProductService implements all required interfaces&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">var&lt;/span> productService = &lt;span style="color:#66d9ef">new&lt;/span> ProductService();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Assert.IsInstanceOf&amp;lt;IProductService&amp;gt;(productService);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="real-world-considerations">Real-world Considerations
&lt;/h2>&lt;h3 id="-production-enhancements">🔧 Production Enhancements
&lt;/h3>&lt;p>&lt;strong>1. Database Integration&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#75715e">// Replace in-memory repositories with Entity Framework Core&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>services.AddDbContext&amp;lt;OrdersDbContext&amp;gt;(options =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> options.UseSqlServer(connectionString));
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>services.AddScoped&amp;lt;IOrderRepository, EfOrderRepository&amp;gt;();
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>2. Authentication &amp;amp; Authorization&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .AddJwtBearer(options =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> options.TokenValidationParameters = &lt;span style="color:#66d9ef">new&lt;/span> TokenValidationParameters
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ValidateIssuer = &lt;span style="color:#66d9ef">true&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ValidateAudience = &lt;span style="color:#66d9ef">true&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ValidateLifetime = &lt;span style="color:#66d9ef">true&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ValidateIssuerSigningKey = &lt;span style="color:#66d9ef">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> };
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> });
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>3. Input Validation&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">CreateOrderCommandValidator&lt;/span> : AbstractValidator&amp;lt;CreateOrderCommand&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> CreateOrderCommandValidator()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RuleFor(x =&amp;gt; x.CustomerId).NotEmpty();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RuleFor(x =&amp;gt; x.Items).NotEmpty();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> RuleForEach(x =&amp;gt; x.Items).SetValidator(&lt;span style="color:#66d9ef">new&lt;/span> OrderItemValidator());
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>4. Error Handling&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">GlobalExceptionMiddleware&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">async&lt;/span> Task InvokeAsync(HttpContext context, RequestDelegate next)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">try&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> next(context);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">catch&lt;/span> (DomainException ex)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> HandleDomainExceptionAsync(context, ex);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">catch&lt;/span> (Exception ex)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">await&lt;/span> HandleGenericExceptionAsync(context, ex);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="-monitoring-และ-observability">📊 Monitoring และ Observability
&lt;/h3>&lt;p>&lt;strong>1. Health Checks&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>services.AddHealthChecks()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .AddDbContextCheck&amp;lt;OrdersDbContext&amp;gt;(&lt;span style="color:#e6db74">&amp;#34;orders-db&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .AddDbContextCheck&amp;lt;ProductsDbContext&amp;gt;(&lt;span style="color:#e6db74">&amp;#34;products-db&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .AddUrlGroup(&lt;span style="color:#66d9ef">new&lt;/span> Uri(&lt;span style="color:#e6db74">&amp;#34;https://external-api.com/health&amp;#34;&lt;/span>), &lt;span style="color:#e6db74">&amp;#34;external-api&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>2. Logging&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>services.AddSerilog((context, config) =&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> config.ReadFrom.Configuration(context.Configuration)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .Enrich.WithProperty(&lt;span style="color:#e6db74">&amp;#34;Module&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Orders&amp;#34;&lt;/span>)
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .WriteTo.Console()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .WriteTo.File(&lt;span style="color:#e6db74">&amp;#34;logs/orders-.log&amp;#34;&lt;/span>, rollingInterval: RollingInterval.Day);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>});
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>3. Metrics&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-csharp" data-lang="csharp">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">OrderMetrics&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>{
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">private&lt;/span> &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">readonly&lt;/span> Counter OrdersCreated = Metrics
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> .CreateCounter(&lt;span style="color:#e6db74">&amp;#34;orders_created_total&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Total number of orders created&amp;#34;&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#66d9ef">public&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> IncrementOrdersCreated() =&amp;gt; OrdersCreated.Inc();
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="ขอสรป">ข้อสรุป
&lt;/h2>&lt;p>Modular Monolith เป็นสถาปัตยกรรมที่เหมาะสมสำหรับองค์กรหลายประเภท โดยเฉพาะทีมที่ต้องการประโยชน์ของ modularity แต่ยังไม่พร้อมสำหรับความซับซ้อนของ microservices&lt;/p>
&lt;h3 id="-key-takeaways">🔑 Key Takeaways:
&lt;/h3>&lt;p>&lt;strong>1. เริ่มต้นอย่างเรียบง่าย&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ใช้ Modular Monolith เป็นจุดเริ่มต้น&lt;/li>
&lt;li>Focus บน domain modeling และ clean boundaries&lt;/li>
&lt;li>ปรับปรุงแบบค่อยเป็นค่อยไป&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>2. ออกแบบให้พร้อมสำหรับการเปลี่ยนแปลง&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ใช้ interfaces สำหรับ inter-module communication&lt;/li>
&lt;li>Implement domain events infrastructure&lt;/li>
&lt;li>เตรียม monitoring และ observability&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>3. วางแผน Migration Path&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>ระบุ modules ที่อาจต้อง extract ในอนาคต&lt;/li>
&lt;li>ออกแบบ data access patterns ที่รองรับการแยก&lt;/li>
&lt;li>สร้าง culture ของ modular thinking&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>4. Focus บน Business Value&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>อย่าให้ technical complexity บดบัง business goals&lt;/li>
&lt;li>ใช้สถาปัตยกรรมที่เหมาะสมกับทีมและ context&lt;/li>
&lt;li>Remember: Architecture คือ means ไม่ใช่ end&lt;/li>
&lt;/ul>
&lt;h3 id="-next-steps">🚀 Next Steps:
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>ศึกษาโค้ด&lt;/strong>: ดู &lt;a class="link" href="https://github.com/suriyasonp/modular-monolith-ecommerce" target="_blank" rel="noopener"
>repository&lt;/a> เพื่อเข้าใจ implementation details&lt;/li>
&lt;li>&lt;strong>ทดลองเรียกใช้&lt;/strong>: รัน &lt;code>./test-api.sh&lt;/code> เพื่อดูฟีเจอร์ทั้งหมด&lt;/li>
&lt;li>&lt;strong>เพิ่มฟีเจอร์&lt;/strong>: ลองสร้างโมดูลใหม่ตามแพทเทิร์นที่กำหนด&lt;/li>
&lt;li>&lt;strong>นำไปใช้จริง&lt;/strong>: ปรับแต่งสำหรับ production environment&lt;/li>
&lt;/ol>
&lt;p>Modular Monolith ไม่ใช่ silver bullet แต่เป็นเครื่องมือที่มีประสิทธิภาพสำหรับการสร้างระบบที่ maintainable, scalable และ evolvable ในระยะยาว&lt;/p>
&lt;h2 id="แหลงอางอง">แหล่งอ้างอิง
&lt;/h2>&lt;ol>
&lt;li>&lt;a class="link" href="https://github.com/suriyasonp/modular-monolith-ecommerce" target="_blank" rel="noopener"
>Modular Monolith E-commerce Repository&lt;/a> - ตัวอย่างการ implement&lt;/li>
&lt;li>&lt;a class="link" href="https://domainlanguage.com/ddd/" target="_blank" rel="noopener"
>Domain-Driven Design&lt;/a> - Eric Evans&lt;/li>
&lt;li>&lt;a class="link" href="https://www.kamilgrzybek.com/design/modular-monolith-primer/" target="_blank" rel="noopener"
>Modular Monoliths&lt;/a> - Kamil Grzybek&lt;/li>
&lt;li>&lt;a class="link" href="https://samnewman.io/books/building_microservices/" target="_blank" rel="noopener"
>Building Microservices&lt;/a> - Sam Newman&lt;/li>
&lt;li>&lt;a class="link" href="https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html" target="_blank" rel="noopener"
>Clean Architecture&lt;/a> - Robert C. Martin&lt;/li>
&lt;li>&lt;a class="link" href="https://docs.microsoft.com/en-us/aspnet/core/" target="_blank" rel="noopener"
>ASP.NET Core Documentation&lt;/a> - Microsoft Docs&lt;/li>
&lt;li>&lt;a class="link" href="https://blog.bytebytego.com/p/monolith-vs-microservices-vs-modular" target="_blank" rel="noopener"
>Monolith vs Microservices vs Modular Monoliths&lt;/a> - Monolith vs Microservices vs Modular Monoliths&lt;/li>
&lt;/ol>
&lt;hr></description></item></channel></rss>