Skip to content
IRC-CodingIRC-Coding
3-Tier ModelLayered ArchitectureDTOService LayerRepository Pattern

3-Tier Architecture Explained: UI, Business, Data

Master 3-tier architecture: presentation, business logic, data access. Components, pros/cons, examples, exam prep.

S

schutzgeist

5 min read
3-Tier Architecture Explained: UI, Business, Data

type: article

keywords:

  • 3-Schichten-Modell
  • 3-Tier Architektur
  • Präsentation Business Daten
  • DTO

canonicalURL: https://www.irc-coding.de/3-schichten-modell-3-tier-architektur

Software Architecture: 3-Layer Model / 3-Tier

This article explains the 3-layer model (3-tier) — including exam questions, key takeaways, and tags.

In a Nutshell

The 3-layer model separates software logically into presentation, business logic, and data access — creating clear responsibilities, better maintainability, and testability.

Technical Overview

The three layers:

  1. Presentation (UI)
  2. Business Logic (Services/Use Cases)
  3. Persistence (Repository/ORM/DB)

Communication typically flows top-to-bottom. Each layer knows only the one directly below it. This keeps systems loosely coupled.

Key Exam Points

  • Separation of presentation, logic, and data access
  • Clear responsibilities
  • Improved testability and maintainability
  • Standard in Java/.NET/web projects (IHK-relevant)
  • Components can be swapped
  • Layers act as security barriers
  • Modularization reduces long-term costs
  • Architecture must be documented

Core Components

  1. Presentation layer
  2. Logic layer
  3. Data access layer
  4. Interfaces between layers
  5. Logging/error handling
  6. Unit tests in business layer
  7. DTOs
  8. Security layer
  9. Persistence (SQL/NoSQL)

Practical Example: Task Management with Python

What does this example show? A simple task management system in Python built strictly according to the 3-layer model. Data flows from the presentation layer (CLI) through the business layer (validation, rules) to the persistence layer (SQLite repository).

Why is this a good learning example? Each layer can be tested independently. The business layer doesn’t need a database, the presentation doesn’t need SQLite — they communicate only through clean method calls.

import sqlite3
from dataclasses import dataclass
from typing import List, Optional

# === Layer 3: Persistence (Data Access) ===
@dataclass
class TaskDTO:
    id: int; title: str; description: str; status: str

class TaskRepository:
    def __init__(self, db_path="tasks.db"):
        self.db_path = db_path
        with sqlite3.connect(db_path) as conn:
            conn.execute("""
                CREATE TABLE IF NOT EXISTS tasks (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    title TEXT NOT NULL, description TEXT,
                    status TEXT DEFAULT 'open')""")

    def create(self, task: TaskDTO) -> TaskDTO:
        with sqlite3.connect(self.db_path) as conn:
            c = conn.execute("INSERT INTO tasks (title,description,status) VALUES (?,?,?)",
                (task.title, task.description, task.status))
            task.id = c.lastrowid
            return task

    def get_all(self) -> List[TaskDTO]:
        with sqlite3.connect(self.db_path) as conn:
            rows = conn.execute("SELECT * FROM tasks").fetchall()
            return [TaskDTO(*r) for r in rows]

    def get_by_id(self, tid: int) -> Optional[TaskDTO]:
        with sqlite3.connect(self.db_path) as conn:
            r = conn.execute("SELECT * FROM tasks WHERE id=?", (tid,)).fetchone()
            return TaskDTO(*r) if r else None

    def update(self, task: TaskDTO) -> TaskDTO:
        with sqlite3.connect(self.db_path) as conn:
            conn.execute("UPDATE tasks SET title=?,description=?,status=? WHERE id=?",
                (task.title, task.description, task.status, task.id))
            return task

    def delete(self, tid: int) -> bool:
        with sqlite3.connect(self.db_path) as conn:
            return conn.execute("DELETE FROM tasks WHERE id=?", (tid,)).rowcount > 0


# === Layer 2: Business Logic ===
class TaskService:
    def __init__(self, repo: TaskRepository):
        self._repo = repo

    def create_task(self, title: str, description="") -> TaskDTO:
        if not title or len(title.strip()) == 0:
            raise ValueError("Titel darf nicht leer sein")
        if len(title) > 100:
            raise ValueError("Titel max. 100 Zeichen")
        return self._repo.create(TaskDTO(0, title.strip(), description, "open"))

    def complete_task(self, task_id: int) -> TaskDTO:
        task = self._repo.get_by_id(task_id)
        if not task:
            raise ValueError(f"Task {task_id} nicht gefunden")
        task.status = "done"
        return self._repo.update(task)

    def list_open_tasks(self) -> List[TaskDTO]:
        return [t for t in self._repo.get_all() if t.status != "done"]


# === Layer 1: Presentation (CLI) ===
class TaskCLI:
    def __init__(self, service: TaskService):
        self._service = service

    def run(self):
        while True:
            print("\n1=Neuer Task  2=Offene Tasks  3=Abschließen  4=Beenden")
            choice = input("Wahl: ")
            if choice == "1":
                title = input("Titel: ")
                desc = input("Beschreibung: ")
                try:
                    task = self._service.create_task(title, desc)
                    print(f"Task {task.id} erstellt")
                except ValueError as e:
                    print(f"Fehler: {e}")
            elif choice == "2":
                for t in self._service.list_open_tasks():
                    print(f"[{t.id}] {t.title} ({t.status})")
            elif choice == "3":
                tid = int(input("Task-ID: "))
                try:
                    self._service.complete_task(tid)
                    print("Abgeschlossen")
                except ValueError as e:
                    print(f"Fehler: {e}")
            elif choice == "4":
                break


if __name__ == "__main__":
    repo = TaskRepository()
    service = TaskService(repo)
    cli = TaskCLI(service)
    cli.run()

Advantages and Disadvantages

Advantages

  • Structured, maintainable application
  • Easy component replacement
  • Good testability

Disadvantages

  • More initial effort
  • Overhead for very small projects

Typical Exam Questions (with Answers)

  1. What does the 3-layer model describe? Presentation, logic, data access.
  2. Which layer validates input? Business logic.
  3. What belongs to the data access layer? Database access, SQL/ORM, repositories.

FAQ — Common Questions About the 3-Layer Model

Q: What’s the difference between the 3-layer model and 3-tier architecture? A: The 3-layer model describes logical separation (presentation, business, persistence) — all layers can run on one server. 3-tier architecture describes physical separation across three machines: client, application server, and database server. In exams, both terms are often used interchangeably.

Q: Why shouldn’t you access the database directly from the UI? A: Direct database access from the UI creates tight coupling. Database schema changes require updates everywhere the UI touches the database. Business rules (validations) can’t be controlled centrally. SQL injection attacks are harder to prevent. The business layer acts as a central control and security checkpoint.

Q: Where exactly are the boundaries between layers? A: The presentation layer knows only the business layer and passes raw data to it. The business layer validates and passes DTOs to the persistence layer. The persistence layer knows only SQL/ORM. If you see method names like “validate” or “check” in a repository, the boundary is violated.

Q: What is a DTO and why do you need it? A: A DTO (Data Transfer Object) carries only data and contains no logic. In the Python example, TaskDTO is a DTO. DTOs decouple layers because each layer only needs to know the DTO format — not the internal structures of other layers.

Q: When doesn’t the 3-layer model make sense? A: With very small scripts (a few hundred lines), the overhead is unnecessary. Once you need unit tests or the database should be swappable, separation pays off. Rule of thumb: single-person scripts can be flat; team projects or maintainable applications need 3 layers.

Summary

For IHK projects, this model is ideal because it’s easy to diagram and justify. Key point: no SQL in controllers, no database access from the UI.

Learning Strategy

  1. Sketch the model for a system (shop, blog).
  2. Implement a CRUD app strictly by layers.
  3. Explain layer separation in project documentation.
  4. Enforce separation technically through packages/namespaces.

Further Reading

  1. https://c4model.com/
Back to Blog
Share:

Nächster Artikel in Software Architecture

Weiterlesen
3-Tier Architecture Explained: UI, Business, Data

Related Posts