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

FrameworkLibrary
Who’s in control?The framework calls your codeYou call the library
StructureProvides project structure and conventionsJust a set of functions you import
ExamplesFlask, React, Django, AngularRequests, Lodash, Axios, SortableJS
AnalogyA house blueprint — you fill in roomsA 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:

FrontendBackend
What it isEverything the user sees and interacts withServer logic, data processing, APIs
Runs onThe user’s browserA server (or cloud)
LanguagesHTML, CSS, JavaScriptPython, JavaScript (Node.js), Java, Go, etc.
HandlesUI layout, styling, user interactions, navigationAuthentication, database queries, business logic, API endpoints
ExamplesA login form, a dashboard, a button that submits dataThe 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

FrameworkStyleBest For
FlaskMicro-framework — minimal core, add what you needSmall-to-medium apps, APIs, tools, learning. Flexible and lightweight.
DjangoBatteries-included — ORM, admin panel, auth, forms built inLarge apps, content sites, rapid prototyping with conventions
FastAPIModern async — auto-generated API docs, type hintsHigh-performance APIs, microservices, async workloads

JavaScript (Node.js)

FrameworkStyleBest For
ExpressMinimal, unopinionatedAPIs, lightweight servers, maximum flexibility
Next.jsReact-based fullstack — SSR, API routes, file-based routingProduction React apps with SEO, server-side rendering
Nest.jsOpinionated, TypeScript-first, modularEnterprise backends, teams wanting Angular-like structure

When to Use What

ScenarioGood ChoiceWhy
Quick internal toolFlaskMinimal setup, Python ecosystem
REST API with auto-docsFastAPIBuilt-in OpenAPI, type validation
Content-heavy websiteDjangoAdmin panel, ORM, templates
React app with SSRNext.jsServer + client rendering built in
Simple API, JS teamExpressLightweight, 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

FrameworkLanguageApproachLearning Curve
ReactJavaScript/JSXComponent-based, virtual DOM, one-way data flowMedium
VueJavaScriptProgressive, template syntax, two-way bindingEasy-Medium
AngularTypeScriptFull framework (routing, forms, HTTP, DI built in)Steep
SvelteJavaScriptCompiler — generates vanilla JS at build timeEasy
Vanilla JSJavaScriptNo framework — direct DOM manipulationDepends 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

ScenarioBest ChoiceWhy
Complex SPA with lots of stateReact or VueComponent model, efficient updates
Enterprise app, large teamAngularOpinionated structure, TypeScript
Server-rendered app + some interactivityVanilla JSNo framework overhead needed
Performance-critical, simple UISvelteCompiles to minimal vanilla JS
Learning web devVue or Vanilla JSApproachable, less abstraction

Server-Side Rendering vs Single-Page Apps

Server-Side Rendering (SSR)Single-Page App (SPA)
How it worksServer generates full HTML for each pageBrowser loads one HTML page, JS handles everything
NavigationFull page reload (or partial with HTMX/Turbo)JS swaps content, no page reload
SEOGood — search engines see full HTMLHarder — needs extra work (SSR, prerendering)
Initial loadFast — HTML arrives readySlower — must download JS bundle first
InteractivityRequires JS on top for dynamic behaviorSmooth, app-like feel
ComplexitySimpler architectureMore complex (client-side routing, state management)
ExamplesFlask + Jinja2, Django templates, PHPReact, Vue, Angular apps
HybridNext.js, Nuxt.js — SSR + client-side hydrationBest 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

EngineLanguageSyntax Style
Jinja2Python{{ var }}, {% if %}
EJSNode.js<%= var %>, <% if %>
HandlebarsJavaScript{{ var }}, {{#if}}
PugNode.jsIndentation-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 RoutingFrontend Routing
WhereServerBrowser
ResultReturns HTML or JSONSwaps UI components
Page reloadYes (traditional)No (SPA)
URL handlingServer processes each URLJS intercepts URL changes
Used withFlask, Django, ExpressReact 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

LibraryWhat It DoesUse Case
BootstrapCSS framework with grid system, components (modals, navbars, cards, forms), and responsive designRapid UI prototyping, admin tools, dashboards
Tailwind CSSUtility-first CSS — style with classes like text-lg, bg-blue-500, flexCustom designs without writing CSS files
Material UI (MUI)React component library following Google’s Material DesignReact apps wanting polished, consistent UI

Interactivity & UI Enhancement

LibraryWhat It DoesUse Case
SortableJSDrag-and-drop sorting for lists and gridsReorderable dashboards, kanban boards, movable card layouts
CodeMirrorIn-browser code editor with syntax highlighting, line numbers, themesEditing config files, code input fields, live previews
Mermaid.jsRenders diagrams (flowcharts, sequence diagrams, Gantt charts) from text definitionsDocumentation, architecture diagrams, inline visuals
svg-pan-zoomAdds pan and zoom controls to SVG elementsInteractive diagrams, network topology maps
Chart.jsSimple, responsive charts (line, bar, pie, etc.)Dashboards, analytics, data visualization
D3.jsLow-level data visualization — full control over SVG/CanvasComplex custom visualizations (steep learning curve)

HTTP & Data

LibraryWhat It DoesUse Case
AxiosHTTP client with interceptors, timeouts, and cancellationAPI calls from frontend or Node.js (alternative to fetch)
LodashUtility functions (deep clone, debounce, throttle, groupBy, etc.)Data manipulation shortcuts
Day.js / date-fnsDate manipulation and formattingDisplaying 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

ApproachHow It WorksProsCons
Plain CSSWrite .css files, link in HTMLNo build tools, full controlHard to maintain at scale
CSS Framework (Bootstrap, Tailwind)Pre-built classes and componentsFast development, consistencyCan feel generic (Bootstrap), large class strings (Tailwind)
CSS Preprocessor (SASS/SCSS)Adds variables, nesting, mixins to CSS; compiles to plain CSSOrganized, reusable stylesRequires build step
CSS-in-JS (styled-components)Write CSS inside JavaScript (React)Scoped to components, dynamicReact-specific, runtime overhead
CSS VariablesNative browser custom properties (--primary-color)No build step, works everywhereLimited 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

MonolithMicroservices
StructureOne codebase, one deploymentMany small services, each deployed independently
CommunicationFunction calls within the appHTTP/API calls between services
ComplexitySimpler to start, harder to scaleMore moving parts, easier to scale individual pieces
Best forMost projects starting out, small-medium teamsLarge-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.