Web Development - Frameworks and Architecture
web development frameworks frontend backend
What is a Framework?
A framework is a pre-built foundation that provides structure, conventions, and common functionality so you don’t start from scratch. It dictates the architecture — you plug your code into its structure.
Framework vs Library
| Framework | Library | |
|---|---|---|
| Who’s in control? | The framework calls your code | You call the library |
| Structure | Provides project structure and conventions | Just a set of functions you import |
| Examples | Flask, React, Django, Angular | Requests, Lodash, Axios, SortableJS |
| Analogy | A house blueprint — you fill in rooms | A toolbox — you pick what you need |
The key difference is “inversion of control.” With a library, you decide when to call it. With a framework, it decides when to call you (via hooks, routes, lifecycle methods, etc.).
Frontend vs Backend
Every web application has two sides:
| Frontend | Backend | |
|---|---|---|
| What it is | Everything the user sees and interacts with | Server logic, data processing, APIs |
| Runs on | The user’s browser | A server (or cloud) |
| Languages | HTML, CSS, JavaScript | Python, JavaScript (Node.js), Java, Go, etc. |
| Handles | UI layout, styling, user interactions, navigation | Authentication, database queries, business logic, API endpoints |
| Examples | A login form, a dashboard, a button that submits data | The code that validates credentials, queries the database, returns a response |
Fullstack
“Fullstack” means working on both frontend and backend. A fullstack framework (like Django or Next.js) provides tools for both sides. A fullstack developer is comfortable building the UI and the server logic.
How They Connect
┌─────────────────────┐ ┌─────────────────────┐
│ FRONTEND │ │ BACKEND │
│ │ HTTP │ │
│ HTML / CSS / JS │◄───────►│ Flask / Django / │
│ React / Vue / │ Request │ Express / FastAPI │
│ Vanilla JS │ Response│ │
│ │ (JSON) │ Database, Auth, │
│ Runs in BROWSER │ │ Business Logic │
└─────────────────────┘ └─────────────────────┘
Backend Frameworks
Python
| Framework | Style | Best For |
|---|---|---|
| Flask | Micro-framework — minimal core, add what you need | Small-to-medium apps, APIs, tools, learning. Flexible and lightweight. |
| Django | Batteries-included — ORM, admin panel, auth, forms built in | Large apps, content sites, rapid prototyping with conventions |
| FastAPI | Modern async — auto-generated API docs, type hints | High-performance APIs, microservices, async workloads |
JavaScript (Node.js)
| Framework | Style | Best For |
|---|---|---|
| Express | Minimal, unopinionated | APIs, lightweight servers, maximum flexibility |
| Next.js | React-based fullstack — SSR, API routes, file-based routing | Production React apps with SEO, server-side rendering |
| Nest.js | Opinionated, TypeScript-first, modular | Enterprise backends, teams wanting Angular-like structure |
When to Use What
| Scenario | Good Choice | Why |
|---|---|---|
| Quick internal tool | Flask | Minimal setup, Python ecosystem |
| REST API with auto-docs | FastAPI | Built-in OpenAPI, type validation |
| Content-heavy website | Django | Admin panel, ORM, templates |
| React app with SSR | Next.js | Server + client rendering built in |
| Simple API, JS team | Express | Lightweight, huge ecosystem |
Frontend Frameworks
Modern frontend frameworks solve a common problem: building interactive UIs that update efficiently when data changes. They provide a component model — you build small, reusable pieces (components) that compose into full pages.
The Options
| Framework | Language | Approach | Learning Curve |
|---|---|---|---|
| React | JavaScript/JSX | Component-based, virtual DOM, one-way data flow | Medium |
| Vue | JavaScript | Progressive, template syntax, two-way binding | Easy-Medium |
| Angular | TypeScript | Full framework (routing, forms, HTTP, DI built in) | Steep |
| Svelte | JavaScript | Compiler — generates vanilla JS at build time | Easy |
| Vanilla JS | JavaScript | No framework — direct DOM manipulation | Depends on complexity |
React
The most popular frontend framework. Uses JSX (HTML-like syntax in JavaScript) and a virtual DOM for efficient updates.
function Welcome({ name }) {
return <h1>Hello, {name}!</h1>;
}
function App() {
const [count, setCount] = useState(0);
return (
<div>
<Welcome name="Alice" />
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
</div>
);
}Strengths: Massive ecosystem, huge job market, flexible, great for SPAs. Weaknesses: Just the view layer — need to pick your own routing, state management, etc.
Vue
Similar to React but with a more approachable template syntax and built-in reactivity.
<template>
<div>
<h1>Hello, {{ name }}!</h1>
<button @click="count++">Clicked {{ count }} times</button>
</div>
</template>
<script>
export default {
data() {
return { name: "Alice", count: 0 };
}
};
</script>Strengths: Gentle learning curve, great docs, progressive adoption. Weaknesses: Smaller ecosystem than React, fewer job postings.
Vanilla JavaScript (No Framework)
Direct DOM manipulation using browser APIs. No build step, no abstractions.
// Example: Fetch data and update the page
fetch('/api/v1/data')
.then(response => response.json())
.then(data => {
document.getElementById('result').textContent = data.message;
});
// Event listener
document.querySelector('#submit-btn').addEventListener('click', () => {
// Handle click
});Strengths: No dependencies, no build tools, fast load times, full control. Weaknesses: Manual DOM updates get tedious for complex UIs, no component reuse model.
When Vanilla JS makes sense: Server-rendered apps where JS adds interactivity on top (like a Flask + Jinja2 app with Bootstrap), internal tools, simple interactions.
Comparison: When to Use What
| Scenario | Best Choice | Why |
|---|---|---|
| Complex SPA with lots of state | React or Vue | Component model, efficient updates |
| Enterprise app, large team | Angular | Opinionated structure, TypeScript |
| Server-rendered app + some interactivity | Vanilla JS | No framework overhead needed |
| Performance-critical, simple UI | Svelte | Compiles to minimal vanilla JS |
| Learning web dev | Vue or Vanilla JS | Approachable, less abstraction |
Server-Side Rendering vs Single-Page Apps
| Server-Side Rendering (SSR) | Single-Page App (SPA) | |
|---|---|---|
| How it works | Server generates full HTML for each page | Browser loads one HTML page, JS handles everything |
| Navigation | Full page reload (or partial with HTMX/Turbo) | JS swaps content, no page reload |
| SEO | Good — search engines see full HTML | Harder — needs extra work (SSR, prerendering) |
| Initial load | Fast — HTML arrives ready | Slower — must download JS bundle first |
| Interactivity | Requires JS on top for dynamic behavior | Smooth, app-like feel |
| Complexity | Simpler architecture | More complex (client-side routing, state management) |
| Examples | Flask + Jinja2, Django templates, PHP | React, Vue, Angular apps |
| Hybrid | Next.js, Nuxt.js — SSR + client-side hydration | Best of both worlds, more complexity |
SSR is a great starting point — especially for tools, dashboards, and content sites. You don’t always need a SPA.
Template Engines
Template engines let you generate HTML on the server by mixing static markup with dynamic data. The server fills in the values before sending HTML to the browser.
Jinja2 (Python — used with Flask/Django)
<!-- base.html — master layout -->
<html>
<head><title>{% block title %}My App{% endblock %}</title></head>
<body>
<nav>{{ user.name }}</nav>
{% block content %}{% endblock %}
</body>
</html>
<!-- page.html — extends the base -->
{% extends "base.html" %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<h1>Welcome, {{ user.name }}!</h1>
{% for item in items %}
<div class="card">{{ item.title }}</div>
{% endfor %}
{% endblock %}Key features: Template inheritance (extends/block), loops, conditionals, filters ({{ name|upper }}), macros (reusable snippets).
Other Template Engines
| Engine | Language | Syntax Style |
|---|---|---|
| Jinja2 | Python | {{ var }}, {% if %} |
| EJS | Node.js | <%= var %>, <% if %> |
| Handlebars | JavaScript | {{ var }}, {{#if}} |
| Pug | Node.js | Indentation-based (no closing tags) |
Routing
Routing maps URLs to code — it determines what happens when a user visits a specific URL.
Backend Routing
The server decides what to do based on the URL path and HTTP method.
# Flask routing — decorator-based
@app.route("/")
def home():
return render_template("index.html")
@app.route("/api/v1/users", methods=["GET"])
def list_users():
return jsonify(users)
@app.route("/api/v1/users/<int:user_id>", methods=["GET"])
def get_user(user_id):
return jsonify(find_user(user_id))Blueprint routing — Flask lets you organize routes into modular blueprints (like plugins). Each tool or feature gets its own blueprint with its own URL prefix:
# Each tool registers as a blueprint
bp = Blueprint("my_tool", __name__, url_prefix="/tools/my-tool")
@bp.route("/")
def index():
return render_template("my_tool/index.html")
@bp.route("/run", methods=["POST"])
def run_tool():
return jsonify({"result": "done"})Frontend Routing (SPAs)
In a single-page app, the browser handles navigation without full page reloads. A JavaScript router maps URLs to components.
// React Router example
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users" element={<UserList />} />
<Route path="/users/:id" element={<UserDetail />} />
</Routes>
</BrowserRouter>
);
}Backend vs Frontend Routing
| Backend Routing | Frontend Routing | |
|---|---|---|
| Where | Server | Browser |
| Result | Returns HTML or JSON | Swaps UI components |
| Page reload | Yes (traditional) | No (SPA) |
| URL handling | Server processes each URL | JS intercepts URL changes |
| Used with | Flask, Django, Express | React Router, Vue Router |
APIs in Web Development
An API (Application Programming Interface) in web dev usually means a set of backend endpoints that accept requests and return JSON data. The frontend calls these endpoints to get or send data without reloading the page.
When You Create an API
- Frontend needs dynamic data — fetch user info, submit a form, update a dashboard
- Multiple clients — web app, mobile app, CLI tool all hit the same API
- Third-party integrations — other systems need to interact with your app
- Separation of concerns — frontend and backend developed independently
Request/Response Cycle
Browser Server
│ │
│ POST /api/v1/generate-key │
│ { "hostname": "fw01" } │
│──────────────────────────────►│
│ │ ── Validate input
│ │ ── Process request
│ │ ── Build response
│ 200 OK │
│ { "success": true, │
│ "data": { "key": "..." }, │
│ "meta": { "request_id": "abc" } }
│◄──────────────────────────────│
│ │
│ Update page with result │
Common API Response Pattern
{
"success": true,
"message": "Key generated successfully",
"data": {
"api_key": "LUFRPT14..."
},
"meta": {
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}Including a request_id in responses is a best practice for debugging and audit trails.
Common Frontend Libraries
Libraries you add to a project to handle specific tasks — you call them, they don’t dictate your structure.
CSS Frameworks & UI
| Library | What It Does | Use Case |
|---|---|---|
| Bootstrap | CSS framework with grid system, components (modals, navbars, cards, forms), and responsive design | Rapid UI prototyping, admin tools, dashboards |
| Tailwind CSS | Utility-first CSS — style with classes like text-lg, bg-blue-500, flex | Custom designs without writing CSS files |
| Material UI (MUI) | React component library following Google’s Material Design | React apps wanting polished, consistent UI |
Interactivity & UI Enhancement
| Library | What It Does | Use Case |
|---|---|---|
| SortableJS | Drag-and-drop sorting for lists and grids | Reorderable dashboards, kanban boards, movable card layouts |
| CodeMirror | In-browser code editor with syntax highlighting, line numbers, themes | Editing config files, code input fields, live previews |
| Mermaid.js | Renders diagrams (flowcharts, sequence diagrams, Gantt charts) from text definitions | Documentation, architecture diagrams, inline visuals |
| svg-pan-zoom | Adds pan and zoom controls to SVG elements | Interactive diagrams, network topology maps |
| Chart.js | Simple, responsive charts (line, bar, pie, etc.) | Dashboards, analytics, data visualization |
| D3.js | Low-level data visualization — full control over SVG/Canvas | Complex custom visualizations (steep learning curve) |
HTTP & Data
| Library | What It Does | Use Case |
|---|---|---|
| Axios | HTTP client with interceptors, timeouts, and cancellation | API calls from frontend or Node.js (alternative to fetch) |
| Lodash | Utility functions (deep clone, debounce, throttle, groupBy, etc.) | Data manipulation shortcuts |
| Day.js / date-fns | Date manipulation and formatting | Displaying dates, time calculations |
Using Fetch (Built-in — No Library Needed)
// GET request
const response = await fetch('/api/v1/data');
const data = await response.json();
// POST request with JSON body
const response = await fetch('/api/v1/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice', action: 'create' })
});
const result = await response.json();SortableJS Example (Drag-and-Drop)
// Make a container's children draggable
import Sortable from 'sortablejs';
new Sortable(document.getElementById('card-container'), {
animation: 150,
handle: '.drag-handle', // Only drag from this element
ghostClass: 'sortable-ghost', // CSS class for the drop placeholder
onEnd: function (evt) {
// Save the new order
const newOrder = [...evt.from.children].map(el => el.dataset.id);
fetch('/settings/layout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ order: newOrder })
});
}
});CSS Approaches
| Approach | How It Works | Pros | Cons |
|---|---|---|---|
| Plain CSS | Write .css files, link in HTML | No build tools, full control | Hard to maintain at scale |
| CSS Framework (Bootstrap, Tailwind) | Pre-built classes and components | Fast development, consistency | Can feel generic (Bootstrap), large class strings (Tailwind) |
| CSS Preprocessor (SASS/SCSS) | Adds variables, nesting, mixins to CSS; compiles to plain CSS | Organized, reusable styles | Requires build step |
| CSS-in-JS (styled-components) | Write CSS inside JavaScript (React) | Scoped to components, dynamic | React-specific, runtime overhead |
| CSS Variables | Native browser custom properties (--primary-color) | No build step, works everywhere | Limited logic compared to SASS |
CSS Variables Example
/* Define variables (great for theming / dark mode) */
:root {
--primary-color: #2a9d8f;
--bg-color: #ffffff;
--text-color: #333333;
}
[data-theme="dark"] {
--bg-color: #1a1a2e;
--text-color: #e0e0e0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
}Project Architecture Patterns
Monolith vs Microservices
| Monolith | Microservices | |
|---|---|---|
| Structure | One codebase, one deployment | Many small services, each deployed independently |
| Communication | Function calls within the app | HTTP/API calls between services |
| Complexity | Simpler to start, harder to scale | More moving parts, easier to scale individual pieces |
| Best for | Most projects starting out, small-medium teams | Large-scale apps with independent teams |
Start monolith, split later — premature microservices add complexity you probably don’t need yet.
Blueprint / Plugin Architecture
A pattern where each feature is a self-contained module that registers itself with the main application. New features are added by dropping a new module into the project — no modification to core code needed.
app/
├── core/ # App factory, shared config
├── tools/
│ ├── tool_a/ # Self-contained blueprint
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates/
│ ├── tool_b/ # Another blueprint
│ └── tool_c/ # Drop in a new folder = new tool
└── registry.py # Discovers and registers all blueprints
This is a powerful pattern for internal tools and extensible applications — each tool is isolated, testable, and deployable without touching others.