|
| 1 | +import htm from "htm"; |
| 2 | +import { createElement } from "react"; |
| 3 | +import { CodeSlide, DemoSlide, Lesson, QuestionsSlide } from "../Layouts/index.js"; |
| 4 | + |
| 5 | +const html = htm.bind(createElement); |
| 6 | + |
| 7 | +function Supplemental6() { |
| 8 | + return html` |
| 9 | + <${Lesson} title="Microservices" lessonId="supplemental_6" subtitle="Supplemental 6"> |
| 10 | + <section> |
| 11 | + <p>Most applications start as <em>monoliths</em>—everything in one codebase.</p> |
| 12 | + </section> |
| 13 | + <section> |
| 14 | + <p>A <em>monolithic application</em> is a single, unified software system where <em>all components are tightly coupled</em>.</p> |
| 15 | + </section> |
| 16 | + <section> |
| 17 | + <p>In a monolith, the <em>UI</em>, <em>business logic</em>, and <em>data layer</em> are all bundled together.</p> |
| 18 | + </section> |
| 19 | + <section class="ml-bullet-slide"> |
| 20 | + <h3>Monolithic architecture example</h3> |
| 21 | + <ul style=${{"font-size": ".9em"}}> |
| 22 | + <li class="fragment">Single codebase with all features</li> |
| 23 | + <li class="fragment">One database shared by all modules</li> |
| 24 | + <li class="fragment">Deploy the entire app as one unit</li> |
| 25 | + <li class="fragment">Scale by replicating the whole application</li> |
| 26 | + </ul> |
| 27 | + </section> |
| 28 | + <section> |
| 29 | + <p>Monoliths are <em>simple to start</em> with, but they <em>don't scale well</em> as apps grow.</p> |
| 30 | + </section> |
| 31 | + <section class="ml-bullet-slide"> |
| 32 | + <h3>Disadvantages of monoliths</h3> |
| 33 | + <ul style=${{"font-size": ".85em"}}> |
| 34 | + <li class="fragment"><em>Tight coupling</em> - Changes in one area can break unrelated features</li> |
| 35 | + <li class="fragment"><em>Slow deployment</em> - Must redeploy entire app for small changes</li> |
| 36 | + <li class="fragment"><em>Difficult scaling</em> - Can't scale individual features independently</li> |
| 37 | + </ul> |
| 38 | + </section> |
| 39 | + <section class="ml-bullet-slide"> |
| 40 | + <h3>Disadvantages of monoliths</h3> |
| 41 | + <ul style=${{"font-size": ".85em"}}> |
| 42 | + <li class="fragment"><em>Technology lock-in</em> - Hard to adopt new languages or frameworks</li> |
| 43 | + <li class="fragment"><em>Large codebase</em> - Difficult for new developers to understand</li> |
| 44 | + <li class="fragment"><em>Single point of failure</em> - One bug can crash the entire system</li> |
| 45 | + </ul> |
| 46 | + </section> |
| 47 | + <section> |
| 48 | + <p>As companies like <em>Amazon</em>, <em>Netflix</em>, and <em>Uber</em> grew, monoliths became <em>unmaintainable</em>.</p> |
| 49 | + </section> |
| 50 | + <section> |
| 51 | + <p>That's why they moved to <em>microservices architecture</em>.</p> |
| 52 | + </section> |
| 53 | + <section> |
| 54 | + <p><em>Microservices</em> break a large application into <em>small, independent services</em>.</p> |
| 55 | + </section> |
| 56 | + <section> |
| 57 | + <p>Each microservice is a <em>self-contained unit</em> that handles a specific <em>business capability</em>.</p> |
| 58 | + </section> |
| 59 | + <section class="ml-bullet-slide"> |
| 60 | + <h3>Microservices architecture example</h3> |
| 61 | + <ul style=${{"font-size": ".9em"}}> |
| 62 | + <li class="fragment">User service manages authentication</li> |
| 63 | + <li class="fragment">Order service handles purchases</li> |
| 64 | + <li class="fragment">Payment service processes transactions</li> |
| 65 | + <li class="fragment">Notification service sends emails/SMS</li> |
| 66 | + </ul> |
| 67 | + </section> |
| 68 | + <section> |
| 69 | + <p>Each service can be <em>developed</em>, <em>deployed</em>, and <em>scaled independently</em>.</p> |
| 70 | + </section> |
| 71 | + <section class="ml-bullet-slide"> |
| 72 | + <h3>Problems microservices solve</h3> |
| 73 | + <ul style=${{"font-size": ".85em"}}> |
| 74 | + <li class="fragment"><em>Independent deployment</em> - Update one service without touching others</li> |
| 75 | + <li class="fragment"><em>Technology flexibility</em> - Use different languages/frameworks per service</li> |
| 76 | + <li class="fragment"><em>Team autonomy</em> - Teams own specific services end-to-end</li> |
| 77 | + </ul> |
| 78 | + </section> |
| 79 | + <section class="ml-bullet-slide"> |
| 80 | + <h3>Problems microservices solve</h3> |
| 81 | + <ul style=${{"font-size": ".85em"}}> |
| 82 | + <li class="fragment"><em>Targeted scaling</em> - Scale only the services that need it</li> |
| 83 | + <li class="fragment"><em>Fault isolation</em> - One service failure doesn't crash everything</li> |
| 84 | + <li class="fragment"><em>Faster development</em> - Smaller codebases are easier to understand</li> |
| 85 | + </ul> |
| 86 | + </section> |
| 87 | + <section> |
| 88 | + <p>But microservices aren't <em>magic</em>—they introduce <em>complexity</em>.</p> |
| 89 | + </section> |
| 90 | + <section> |
| 91 | + <p>To build effective microservices, you need to follow <em>key architectural principles</em>.</p> |
| 92 | + </section> |
| 93 | + <section class="ml-bullet-slide"> |
| 94 | + <h3>Rules of microservices architecture</h3> |
| 95 | + <ul style=${{"font-size": ".82em"}}> |
| 96 | + <li class="fragment"><em>Single Responsibility</em> - Each service does one thing well</li> |
| 97 | + <li class="fragment"><em>Decentralized Data</em> - Each service owns its own database</li> |
| 98 | + <li class="fragment"><em>API-first Communication</em> - Services talk via well-defined APIs</li> |
| 99 | + </ul> |
| 100 | + </section> |
| 101 | + <section class="ml-bullet-slide"> |
| 102 | + <h3>Rules of microservices architecture</h3> |
| 103 | + <ul style=${{"font-size": ".82em"}}> |
| 104 | + <li class="fragment"><em>Independent Deployment</em> - Deploy without coordinating with other teams</li> |
| 105 | + <li class="fragment"><em>Design for Failure</em> - Assume services will fail and plan accordingly</li> |
| 106 | + <li class="fragment"><em>Observable Services</em> - Built-in logging, metrics, and tracing</li> |
| 107 | + </ul> |
| 108 | + </section> |
| 109 | + <section> |
| 110 | + <p>Let's look at how services <em>communicate</em> in a microservices architecture.</p> |
| 111 | + </section> |
| 112 | + <${CodeSlide} lang="typescript" badge="User Service API" fontSize=".35em" lineNumbers=true> |
| 113 | +// User service exposes REST API |
| 114 | +import express from 'express'; |
| 115 | +
|
| 116 | +const app = express(); |
| 117 | +
|
| 118 | +app.get('/users/:id', async (req, res) => { |
| 119 | + const user = await db.users.findById(req.params.id); |
| 120 | + res.json(user); |
| 121 | +}); |
| 122 | +
|
| 123 | +app.post('/users', async (req, res) => { |
| 124 | + const newUser = await db.users.create(req.body); |
| 125 | + res.status(201).json(newUser); |
| 126 | +}); |
| 127 | +
|
| 128 | +app.listen(3001, () => console.log('User service on :3001')); |
| 129 | + <//> |
| 130 | + <${CodeSlide} lang="typescript" badge="Order Service" fontSize=".35em" lineNumbers=true> |
| 131 | +// Order service calls User service |
| 132 | +import axios from 'axios'; |
| 133 | +
|
| 134 | +async function createOrder(userId, items) { |
| 135 | + // Fetch user info from User service |
| 136 | + const userResponse = await axios.get( |
| 137 | + \`http://user-service:3001/users/\${userId}\` |
| 138 | + ); |
| 139 | + |
| 140 | + const user = userResponse.data; |
| 141 | + |
| 142 | + // Create order with user details |
| 143 | + const order = await db.orders.create({ |
| 144 | + userId: user.id, |
| 145 | + userEmail: user.email, |
| 146 | + items |
| 147 | + }); |
| 148 | + |
| 149 | + return order; |
| 150 | +} |
| 151 | + <//> |
| 152 | + <section> |
| 153 | + <p>Services can communicate <em>synchronously</em> (REST, gRPC) or <em>asynchronously</em> (message queues).</p> |
| 154 | + </section> |
| 155 | + <${CodeSlide} lang="typescript" badge="Event-Driven Communication" fontSize=".33em" lineNumbers=true> |
| 156 | +// Order service publishes event |
| 157 | +import { EventEmitter } from 'events'; |
| 158 | +
|
| 159 | +const eventBus = new EventEmitter(); |
| 160 | +
|
| 161 | +async function createOrder(userId, items) { |
| 162 | + const order = await db.orders.create({ userId, items }); |
| 163 | + |
| 164 | + // Publish event instead of direct call |
| 165 | + eventBus.emit('order.created', { |
| 166 | + orderId: order.id, |
| 167 | + userId, |
| 168 | + total: order.total |
| 169 | + }); |
| 170 | + |
| 171 | + return order; |
| 172 | +} |
| 173 | +
|
| 174 | +// Notification service listens for event |
| 175 | +eventBus.on('order.created', async (event) => { |
| 176 | + await sendEmail(event.userId, \`Order \${event.orderId} confirmed!\`); |
| 177 | +}); |
| 178 | + <//> |
| 179 | + <section> |
| 180 | + <p>Now let's talk about the <em>tools and technologies</em> used to build microservices.</p> |
| 181 | + </section> |
| 182 | + <section class="ml-bullet-slide"> |
| 183 | + <h3>Communication protocols</h3> |
| 184 | + <ul style=${{"font-size": ".85em"}}> |
| 185 | + <li class="fragment"><em>REST</em> - Simple HTTP APIs with JSON (most common)</li> |
| 186 | + <li class="fragment"><em>gRPC</em> - High-performance binary protocol (faster than REST)</li> |
| 187 | + <li class="fragment"><em>GraphQL</em> - Flexible query language for APIs</li> |
| 188 | + <li class="fragment"><em>Message brokers</em> - RabbitMQ, Kafka for async communication</li> |
| 189 | + </ul> |
| 190 | + </section> |
| 191 | + <section class="ml-bullet-slide"> |
| 192 | + <h3>Service discovery and routing</h3> |
| 193 | + <ul style=${{"font-size": ".85em"}}> |
| 194 | + <li class="fragment"><em>API Gateway</em> - Single entry point for all client requests (Kong, AWS API Gateway)</li> |
| 195 | + <li class="fragment"><em>Service mesh</em> - Manages service-to-service communication (Istio, Linkerd)</li> |
| 196 | + <li class="fragment"><em>Load balancers</em> - Distribute traffic across service instances (NGINX, HAProxy)</li> |
| 197 | + </ul> |
| 198 | + </section> |
| 199 | + <section class="ml-bullet-slide"> |
| 200 | + <h3>Containerization and orchestration</h3> |
| 201 | + <ul style=${{"font-size": ".85em"}}> |
| 202 | + <li class="fragment"><em>Docker</em> - Package services into containers</li> |
| 203 | + <li class="fragment"><em>Kubernetes</em> - Orchestrate and scale containers</li> |
| 204 | + <li class="fragment"><em>Docker Compose</em> - Define multi-service environments locally</li> |
| 205 | + </ul> |
| 206 | + </section> |
| 207 | + <section class="ml-bullet-slide"> |
| 208 | + <h3>Observability and monitoring</h3> |
| 209 | + <ul style=${{"font-size": ".85em"}}> |
| 210 | + <li class="fragment"><em>Logging</em> - Centralized logging with ELK stack or Splunk</li> |
| 211 | + <li class="fragment"><em>Metrics</em> - Prometheus, Grafana for monitoring</li> |
| 212 | + <li class="fragment"><em>Tracing</em> - Distributed tracing with Jaeger or Zipkin</li> |
| 213 | + </ul> |
| 214 | + </section> |
| 215 | + <section> |
| 216 | + <p>Microservices aren't always the <em>right choice</em>—they add operational complexity.</p> |
| 217 | + </section> |
| 218 | + <section class="ml-bullet-slide"> |
| 219 | + <h3>When to use microservices</h3> |
| 220 | + <ul style=${{"font-size": ".85em"}}> |
| 221 | + <li class="fragment">Large teams working on different features</li> |
| 222 | + <li class="fragment">Need to scale specific parts independently</li> |
| 223 | + <li class="fragment">Different services have different tech requirements</li> |
| 224 | + <li class="fragment">Frequent deployments with minimal downtime</li> |
| 225 | + </ul> |
| 226 | + </section> |
| 227 | + <section class="ml-bullet-slide"> |
| 228 | + <h3>When to stick with a monolith</h3> |
| 229 | + <ul style=${{"font-size": ".85em"}}> |
| 230 | + <li class="fragment">Small team or early-stage startup</li> |
| 231 | + <li class="fragment">Simple application with few features</li> |
| 232 | + <li class="fragment">Limited DevOps resources or expertise</li> |
| 233 | + <li class="fragment">Unclear domain boundaries</li> |
| 234 | + </ul> |
| 235 | + </section> |
| 236 | + <section> |
| 237 | + <p><em>Start with a monolith</em>, then break it apart when complexity demands it.</p> |
| 238 | + </section> |
| 239 | + <section> |
| 240 | + <p>Companies like <em>Amazon</em> and <em>Netflix</em> evolved to microservices over <em>years</em>, not overnight.</p> |
| 241 | + </section> |
| 242 | + <section> |
| 243 | + <p>With microservices, you trade <em>simplicity</em> for <em>scalability and flexibility</em>.</p> |
| 244 | + </section> |
| 245 | + <${DemoSlide} /> |
| 246 | + <${QuestionsSlide} /> |
| 247 | + <//>`; |
| 248 | +} |
| 249 | + |
| 250 | +export default Supplemental6; |
0 commit comments