Different Types of Architectures in Web Products

Serhii Koziy
4 min readNov 28, 2024

As web products evolve, selecting the right architecture becomes critical to ensure scalability, maintainability, and efficiency. In this article, I’ll break down some of the common web architectures, provide examples where relevant, and explain tricky concepts in simpler terms.

1. Monolithic Architecture

What It Is

A monolithic architecture is a single, unified application where all components — UI, business logic, and database operations — are tightly integrated. It’s like having a single piece of software handling everything in one big package.

Code Example

Here’s an example of a Node.js Express app written in a monolithic way:

const express = require('express');
const app = express();

app.get('/users', (req, res) => {
// Business logic and database handling here
const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
res.json(users);
});
app.post('/users', (req, res) => {
// Directly handle input and save to database
res.status(201).json({ message: 'User created' });
});
app.listen(3000, () => console.log('Server running on port 3000'))

Everything is centralized in one application. While simple to set up, it can become unwieldy as the application grows.

Pros:

  • Simple to develop and deploy.
  • Easier to debug in the early stages.

Cons (or the “tricky parts”):

  • Hard to scale — adding features means modifying the whole app.
  • If one part fails, the whole system can go down.

2. Microservices Architecture

What It Is

This approach breaks the application into small, independent services. Each service is responsible for a specific functionality, like user management or payment processing. It’s like a team of specialists, each doing one job well.

Code Example

Imagine a user service and an order service communicating with each other:

User Service (user-service.js):

const express = require('express');
const app = express();

app.get('/users', (req, res) => {
const users = [{ id: 1, name: 'Alice' }];
res.json(users);
});
app.listen(3001, () => console.log('User service running on port 3001'));

Order Service (order-service.js):

const express = require('express');
const axios = require('axios');
const app = express();

app.get('/orders', async (req, res) => {
const users = await axios.get('http://localhost:3001/users');
res.json({ orders: [{ id: 101, user: users.data[0] }] });
});
app.listen(3002, () => console.log('Order service running on port 3002'));

Each service runs independently and communicates via APIs.

Pros:

  • Scalability: You can scale individual services as needed.
  • Resilience: If one service fails, the others can still function.

Cons:

  • Complex to set up (requires orchestration tools like Kubernetes).
  • Testing and debugging can be tricky since components interact over the network.

3. Serverless Architecture

What It Is

In serverless architecture, developers focus solely on writing code, while the cloud provider handles the infrastructure. It’s like going to a restaurant where you only need to decide what to eat (code) while the chef (cloud) does the cooking (manages servers).

Code Example

Here’s a basic AWS Lambda function using JavaScript:

exports.handler = async (event) => {
const name = event.queryStringParameters.name || 'Guest';
return {
statusCode: 200,
body: JSON.stringify({ message: `Hello, ${name}!` }),
};
};

You deploy this function, and AWS takes care of running it when triggered by an event.

Pros:

  • Cost-effective: You only pay when your function runs.
  • No server management.

Cons:

  • Vendor lock-in: You’re tied to the cloud provider’s ecosystem.
  • Cold start latency: Functions may take longer to start if they’ve been idle.

4. Single-Page Application (SPA) Architecture

What It Is

An SPA loads a single HTML page and dynamically updates content without reloading the page. It’s like an app that gets all its tools upfront and then works independently without going back to the toolbox.

Code Example

Here’s a React SPA:

App.js:

import React, { useState, useEffect } from 'react';

const App = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('/api/users')
.then((res) => res.json())
.then((data) => setUsers(data));
}, []);
return (
<div>
<h1>User List</h1>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
};
export default App;

The server only serves the /api/users endpoint, while the SPA handles rendering on the client.

Pros:

  • Fast user experience (no full-page reloads).
  • Great for interactive applications.

Cons:

  • Poor SEO (can be mitigated with server-side rendering).
  • Initial load can be heavy due to JavaScript bundling.

5. Progressive Web Application (PWA)

What It Is

PWAs combine the best of web and mobile apps. They work offline, load quickly, and can be installed on your device. It’s like a web app with superpowers!

Code Example

Here’s a Service Worker for offline caching in a PWA:

service-worker.js:

self.addEventListener('install', (event) => {
event.waitUntil(
caches.open('v1').then((cache) => {
return cache.addAll(['/index.html', '/styles.css', '/app.js']);
})
);
});

self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});

Pros:

  • Offline capability.
  • Feels like a native app.

Cons:

  • Complex to set up compared to traditional web apps.
  • Limited access to some native device features.

6. Event-Driven Architecture

What It Is

In this architecture, components communicate by producing and consuming events. Think of it as a “publish-subscribe” system, like a news service where updates are sent to subscribers.

Code Example

Using Node.js with an event emitter:

const EventEmitter = require('events');
const eventEmitter = new EventEmitter();

// Subscriber
eventEmitter.on('userCreated', (user) => {
console.log(`Welcome email sent to ${user.name}`);
});
// Publisher
eventEmitter.emit('userCreated', { name: 'Alice', email: 'alice@example.com' });

Pros:

  • Decoupled services: Components don’t need to know about each other.
  • Great for real-time applications.

Cons:

  • Debugging can be challenging due to asynchronous behavior.
  • Requires reliable event processing infrastructure.

Final Thoughts

Each architecture has its strengths and weaknesses. Choosing the right one depends on your product’s size, goals, and team expertise. Start simple, and as your product grows, consider whether your architecture needs to evolve to handle new challenges.

Sign up to discover human stories that deepen your understanding of the world.

No responses yet

Write a response