0Pricing
Coding Interview Prep · Lektion

Das Framework für System-Design-Interviews

Gehen Sie das fünfstufige RADIO-Framework (Requirements, API, Data, Infrastructure, Optimise) durch und üben Sie seine Anwendung an einem URL-Shortener.

Das Framework für System-Design-Interviews ist eine kostenlose Coding Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Coding Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.

Warum Systemdesign in Interviews wichtig ist

Systemdesign-Interviews prüfen Ihre Fähigkeit, im großen Maßstab zu denken – wie würden Sie Twitter, YouTube oder einen URL-Verkürzer für Milliarden von Nutzern entwerfen? Im Gegensatz zu Programmieraufgaben mit einer einzigen richtigen Antwort ist Systemdesign offen: Sie müssen Abwägungen treffen und begründen. Rollen auf Senior- und Staff-Level widmen dieser Runde ausschließlich 30–45 Minuten.

Interviewer bewerten, ob Sie Anforderungen klären, die Auslastung abschätzen, eine übergeordnete Architektur vorschlagen, Schlüsselkomponenten detailliert betrachten und Abwägungen besprechen können – und dabei klar kommunizieren. Ein strukturiertes Framework verhindert, dass Sie abschweifen, und stellt sicher, dass Sie alle wichtigen Dimensionen abdecken.

# System design is not about a single correct answer.
# Interviewers look for:
eval_criteria = [
    'Ability to clarify requirements before designing',
    'Back-of-envelope capacity estimation',
    'High-level architecture with clear components',
    'Data modelling and storage choice',
    'Handling scalability (10x, 100x load)',
    'Trade-off discussion (consistency vs availability, etc.)',
    'Communication: talking through decisions as you make them',
]
for c in eval_criteria:
    print('-', c)

Überblick über das RADIO-Framework

Das RADIO-Framework bietet eine wiederholbare Struktur in fünf Schritten für jedes Systemdesign-Interview:

  • R – Anforderungen: funktionale und nichtfunktionale
  • A – API-Design: Welche Operationen stellt das System bereit?
  • D – Datenmodell: Welche Daten werden gespeichert und wie?
  • I – Infrastruktur: Komponenten auf hoher Ebene (Server, Warteschlangen, Caches)
  • O – Optimieren: Engpässe, Caching, Sharding, Replikation

Gehen Sie diese Schritte immer in dieser Reihenfolge durch, kehren Sie aber zu früheren Schritten zurück und verfeinern Sie sie, wenn neue Erkenntnisse entstehen. Verbringen Sie in jeder Phase ungefähr gleich viel Zeit. Springen Sie niemals direkt zum Zeichnen von Kästen, ohne vorher die Anforderungen zu klären.

RADIO = {
    'R': 'Requirements — What must the system do? What scale?',
    'A': 'API         — Define endpoints/operations the system exposes',
    'D': 'Data Model  — Entities, schemas, storage types',
    'I': 'Infra       — High-level architecture: servers, queues, caches, CDN',
    'O': 'Optimise    — Identify and address bottlenecks, trade-offs',
}
for step, desc in RADIO.items():
    print(f'[{step}] {desc}')

print('\nTiming guide for a 45-min interview:')
print('  R: 5 min | A: 5 min | D: 10 min | I: 15 min | O: 10 min')

Schritt R: Anforderungen klären

Beginnen Sie niemals mit dem Entwurf, ohne die Anforderungen zu klären. Fragen Sie nach funktionalen Anforderungen (was das System tut) und nichtfunktionalen Anforderungen (Skalierung, Latenz, Verfügbarkeit). Für einen URL-Verkürzer:

  • Funktional: eine URL verkürzen, zur ursprünglichen URL weiterleiten, optional benutzerdefinierte Aliase und Ablaufzeiten unterstützen
  • Nichtfunktional: Wie viele URLs pro Tag? Ist das System lese- oder schreiblastig? Anforderung an die Verfügbarkeit (99.9% oder 99.99%)? Akzeptable Latenz?

Wenn Sie Annahmen ausdrücklich nennen, zeigen Sie Ihre Erfahrung. Interviewer stellen oft bewusst vage Anforderungen, um zu sehen, ob Sie die richtigen Fragen stellen. Zwei Minuten für die Klärung ersparen Ihnen, das falsche System zu entwerfen.

# Requirements questions for URL Shortener:
functional = [
    'Shorten a given URL to a 7-character alias',
    'Redirect short URL to original URL',
    'Allow custom aliases (optional)',
    'URL expiry (optional)',
    'Analytics: click count per URL (optional)',
]
non_functional = [
    '100 million new URLs per day (write: ~1160/sec)',
    '10:1 read:write ratio => 11,600 redirects/sec',
    'Redirects must be < 100ms p99 latency',
    '99.99% availability (< 1 hr downtime/year)',
    'URLs must be globally accessible',
]
print('Functional:')
for f in functional: print(' -', f)
print('\nNon-functional:')
for nf in non_functional: print(' -', nf)

Schritt R: Überschlagsrechnung

Schätzen Sie nach der Klärung der Anforderungen die Kapazität ab. Das zeigt, dass Sie über Skalierung nachdenken können, bevor Sie Lösungen vorschlagen. Wichtige Kennzahlen sind: Anfragen pro Sekunde (RPS), benötigter Speicher pro Tag und Jahr, Bandbreite sowie Arbeitsspeicher für Caching.

Verwenden Sie runde Zahlen und schätzen Sie großzügig. Interviewer achten auf die Größenordnung, nicht auf exakte Werte. Beispiel für einen URL-Verkürzer: 100M Schreibvorgänge/Tag ÷ 86400 ≈ 1160 Schreibvorgänge/Sek. 10B Lesevorgänge/Tag ÷ 86400 ≈ 115K Lesevorgänge/Sek. Jeder URL-Datensatz entspricht etwa 500 Bytes: 100M × 500B = 50 GB/Tag, 18 TB/Jahr.

# Back-of-envelope for URL Shortener
writes_per_day = 100_000_000        # 100 million URLs/day
read_write_ratio = 100              # 100:1 read/write
reads_per_day = writes_per_day * read_write_ratio
bytes_per_url = 500                 # url string + metadata
years_to_store = 5

print('=== Capacity Estimation ===')
print(f'Writes/sec:  {writes_per_day / 86400:.0f}')
print(f'Reads/sec:   {reads_per_day / 86400:,.0f}')
print(f'Storage/day: {writes_per_day * bytes_per_url / 1e9:.1f} GB')
print(f'Storage total ({years_to_store}y): {writes_per_day * bytes_per_url * 365 * years_to_store / 1e12:.1f} TB')

cache_hit_rate = 0.80
hot_urls = reads_per_day * (1 - cache_hit_rate)
print(f'\n80% cache hit rate: {cache_hit_rate*100}% of reads from cache')
print(f'DB reads/sec: {hot_urls / 86400:,.0f}')

Schritt A: API-Design

Definieren Sie die API-Oberfläche – die Operationen, die das System Clients und internen Diensten bereitstellt. Geben Sie HTTP-Methode, Endpunktpfad, Anfrageparameter und Antwortformat eindeutig an. Das bildet die Grundlage für den restlichen Entwurf: Alles andere dient der Implementierung dieser APIs.

Für einen URL-Verkürzer sind die beiden zentralen APIs: (1) POST /shorten, um eine Kurz-URL zu erstellen, (2) GET /{alias}, um weiterzuleiten. Optional: DELETE /{alias} zum Löschen, GET /{alias}/stats für Analytics. Geben Sie die Antwortcodes an (201 Created, 301 Redirect, 404 Not Found).

# API Design for URL Shortener
apis = [
    {
        'method': 'POST',
        'path': '/api/v1/shorten',
        'request': '{"long_url": "https://...", "alias": "optional", "expires_at": "optional"}',
        'response': '201 Created: {"short_url": "https://short.ly/abc1234", "alias": "abc1234"}',
    },
    {
        'method': 'GET',
        'path': '/{alias}',
        'request': 'No body',
        'response': '301 Redirect to long_url (or 404 Not Found)',
    },
    {
        'method': 'GET',
        'path': '/api/v1/{alias}/stats',
        'request': 'Optional: date range query params',
        'response': '200 OK: {"clicks": 42000, "unique_visitors": 15000}',
    },
]
for api in apis:
    print(f'{api["method"]} {api["path"]}')
    print(f'  Request:  {api["request"]}')
    print(f'  Response: {api["response"]}')
    print()

Schritt D: Datenmodell

Das Datenmodell legt fest, welche Daten Sie speichern und wie. Identifizieren Sie die zentralen Entitäten und ihre Attribute. Für einen URL-Verkürzer: eine urls-Tabelle mit alias (Primärschlüssel), long_url, created_at, expires_at und user_id. Eine optionale clicks-Tabelle kann für Analytics verwendet werden.

Die Wahl des richtigen Speichertyps ist entscheidend: eine relationale Datenbank für strukturierte Daten mit komplexen Abfragen, ein Key-Value-Store (Redis, DynamoDB) für O(1)-Lookups nach Alias in großem Maßstab und ein Objektspeicher (S3) für große Blobs. Für einen URL-Verkürzer ist ein anhand des Alias indizierter Key-Value-Store ideal für Lesezugriffe, ergänzt durch eine relationale Datenbank für Schreibzugriffe und Verwaltung.

# Data model for URL Shortener

# Core table (PostgreSQL)
urls_schema = '''
CREATE TABLE urls (
    alias       VARCHAR(16) PRIMARY KEY,   -- e.g., 'abc1234'
    long_url    TEXT NOT NULL,
    user_id     UUID REFERENCES users(id),
    created_at  TIMESTAMP DEFAULT NOW(),
    expires_at  TIMESTAMP,
    click_count BIGINT DEFAULT 0
);
CREATE INDEX ON urls(user_id);
'''

# Cache layer (Redis) for hot reads
redis_schema = '''
alias  =>  long_url       # O(1) GET on cache hit
TTL = 24 hours (or until expiry)
Cache eviction: LRU
'''

print('PostgreSQL schema:')
print(urls_schema)
print('Redis cache:')
print(redis_schema)
print('Storage split: Redis for hot reads (~80%), PostgreSQL for writes and cold reads')

Schritt I: Infrastruktur auf hoher Ebene

Skizzieren Sie die Infrastruktur auf hoher Ebene: Welche Server übernehmen welche Aufgaben, wie fließen Daten zwischen den Komponenten und welche externen Dienste werden verwendet? Für einen URL-Verkürzer im großen Maßstab:

  • Load Balancer: verteilt den Datenverkehr auf Replikate des Schreib- und Lesedienstes
  • Schreibdienst: erzeugt den Alias, prüft dessen Eindeutigkeit, schreibt in die DB und invalidiert den Cache
  • Lese-/Weiterleitungsdienst: prüft zuerst den Redis-Cache und greift bei einem Cache-Miss auf die DB zurück
  • Relationale Datenbank: maßgebliche Datenquelle (mit Lesereplikaten)
  • Redis-Cluster: speichert häufig verwendete URL-Zuordnungen für Lesezugriffe im Submillisekundenbereich zwischen
# ASCII architecture sketch
architecture = '''
         Clients
            |
       [Load Balancer]
       /             \\
  [Write API]    [Read/Redirect API]
      |                  |  |
  [Alias Gen]       [Redis Cache]
      |                  |
  [PostgreSQL]---->[Read Replicas]

Alias Generation:
- Base62 encoding of auto-incrementing ID
- 62^7 = 3.5 trillion unique URLs (enough for 5 years at 100M/day)
- OR random 7-char Base62 with collision check
'''
print(architecture)
print('Key design decisions:')
print('  - Read/Write split: separate services for scalability')
print('  - Cache-aside pattern: read from Redis, fallback to DB')
print('  - 301 vs 302 redirect: 301 cached by browser (less load), 302 always hits server (analytics)')

Schritt O: Optimieren und Engpässe behandeln

Die Optimierungsphase befasst sich mit Engpässen und der Skalierung des Systems. Bei einem URL-Verkürzer sind wichtige Punkte: die Weiterleitungslatenz (platzieren Sie Redis mit CDN- oder Edge-Caches näher bei den Nutzern), die Alias-Eindeutigkeit in großem Maßstab (verwenden Sie einen zentralen Ticket-Server oder einen Hash mit Kollisionsprüfung) und der DB-Schreibengpass (führen Sie Batch-Schreibvorgänge oder asynchrone Schreibvorgänge über eine Warteschlange durch).

Sprechen Sie Abwägungen ausdrücklich an: 301-Weiterleitungen senken die Serverlast, beeinträchtigen aber die Genauigkeit der Analyse; 302-Weiterleitungen lassen sich nachverfolgen, erhöhen aber die Latenz. Lange Cache-Ablaufzeiten senken die DB-Last, bergen aber das Risiko veralteter URLs. Wenn Sie diese Spannungsfelder verstehen, signalisiert das Denken auf Senior-Level.

# Key optimisation discussion points
optimisations = {
    'Read latency': [
        'Redis cluster in multiple regions (CDN-edge caching)',
        '301 redirect for non-tracked URLs (client caches)',
        '302 redirect when click analytics are needed',
    ],
    'Write throughput': [
        'Async writes: accept request, enqueue to Kafka, batch-commit to DB',
        'Ticket server (centralised ID generator) to avoid UUID collision',
        'Or: hash(user_id + timestamp + random) with retry on collision',
    ],
    'Availability': [
        'Multi-AZ PostgreSQL with automatic failover',
        'Redis Sentinel or Redis Cluster for HA cache',
        'Health checks + circuit breaker on each service',
    ],
    'Storage': [
        'Partition urls table by hash(alias) for horizontal scaling',
        'Archive expired URLs to cold storage (S3)',
    ],
}
for area, points in optimisations.items():
    print(f'{area}:')
    for p in points: print(f'  - {p}')
    print()

Alias-Erzeugung: Base62-Kodierung

Ein zentrales technisches Detail von URL-Verkürzern ist die Erzeugung kurzer, eindeutiger Aliase. Der Standardansatz: Verwenden Sie eine autoinkrementierende Ganzzahl-ID aus der Datenbank und kodieren Sie sie in Base62 (Ziffern 0-9, Buchstaben a-z, A-Z). Eine 7 Zeichen lange Base62-Zeichenfolge kann 62^7 ≈ 3,5 Billionen eindeutige URLs darstellen – genug für Jahrzehnte bei 100M pro Tag.

Das ist kollisionsfrei, da jede ID eindeutig ist, und erzeugt kurze, URL-sichere Zeichenfolgen. Die Zuordnung ID→alias ist deterministisch und umkehrbar. Der Nachteil: Sequenzielle IDs erzeugen vorhersehbare Aliase, was ein Sicherheitsrisiko darstellt. Mischen Sie das Base62-Alphabet oder verwenden Sie einen Zähler-Offset, um die Vorhersagbarkeit zu verringern.

import string

BASE62_CHARS = string.digits + string.ascii_lowercase + string.ascii_uppercase
BASE = 62

def encode_base62(num):
    if num == 0:
        return BASE62_CHARS[0]
    result = ''
    while num:
        result = BASE62_CHARS[num % BASE] + result
        num //= BASE
    return result

def decode_base62(s):
    result = 0
    for c in s:
        result = result * BASE + BASE62_CHARS.index(c)
    return result

# Generate aliases for IDs 1, 100, 1000, 10^9
for id_ in [1, 100, 1000, 1_000_000, 10**9, 3_521_614_606207]:
    alias = encode_base62(id_)
    decoded = decode_base62(alias)
    print(f'ID {id_:20,} => alias "{alias}" (len={len(alias)}) => decoded={decoded}')

RADIO auf das Design eines Twitter-Feeds anwenden

Wenden wir RADIO kurz auf das Entwerfen eines Twitter-ähnlichen Newsfeeds an, um zu zeigen, dass sich das Framework verallgemeinern lässt:

  • R: Nutzer veröffentlichen Tweets, folgen anderen Nutzern und sehen einen Feed mit Tweets der Personen, denen sie folgen. Skalierung: 300M Nutzer, 500M Tweets/Tag, der Feed muss in <2s geladen werden.
  • A: POST /tweets, GET /feed, GET /timeline/{user_id}
  • D: tweets-Tabelle (id, user_id, content, created_at); follows-Tabelle (follower_id, followee_id); Feed-Cache pro Nutzer
  • I: Der Fan-out-Dienst schreibt neue Tweets in die Feeds der Follower (vorab berechnet); Cassandra für schreiblastige Follow-/Tweet-Tabellen; Redis für Feed-Caches
# Fan-out on Write vs Fan-out on Read trade-off
fan_out_strategies = {
    'Fan-out on Write (Push)': {
        'How': 'When user A posts, immediately write to all followers feeds',
        'Pro': 'O(1) feed read — feed is precomputed',
        'Con': 'Celebrities with 10M followers => 10M writes per post; very slow write',
        'Best for': 'Users with few followers (regular users)',
    },
    'Fan-out on Read (Pull)': {
        'How': 'When user reads feed, query followees tweets and merge',
        'Pro': 'Writes are fast (one DB write per tweet)',
        'Con': 'Feed read is slow: must query all N followees',
        'Best for': 'Celebrity accounts (few reads per post)',
    },
    'Hybrid': {
        'How': 'Push for regular users, pull for celebrities',
        'Pro': 'Balances read and write cost',
        'Con': 'More complex implementation',
        'Best for': 'Production systems like Twitter',
    },
}
for strategy, details in fan_out_strategies.items():
    print(f'{strategy}:')
    for k, v in details.items(): print(f'  {k}: {v}')
    print()

Häufige Fehler in System-Design-Interviews

Vermeiden Sie diese häufigen Fehler, die System-Design-Interviews zum Scheitern bringen:

  • Zu schnell Lösungen vorschlagen: Wenn Sie bereits Boxen zeichnen, bevor Sie die Anforderungen geklärt haben, deutet das auf schlechte Engineering-Gewohnheiten hin
  • Keine Schätzungen: Ohne Kenntnis der Größenordnung ist das Design reine Spekulation
  • Überengineering: Ein Design für 1 Milliarde Nutzer zu entwerfen, obwohl in der Aufgabenstellung 10.000 Nutzer genannt werden, verschwendet Interviewzeit
  • Keine Abwägungen: Jede Entscheidung hat Vor- und Nachteile. Wenn Sie diese nicht erwähnen, deutet das auf ein oberflächliches Verständnis hin
  • Schweigen: Interviewer müssen Ihren Denkprozess nachvollziehen können. Erläutern Sie Ihre Entscheidungen, während Sie sie treffen
# Checklist: before you stop talking, verify you covered:
checklist = [
    '[ ] Asked clarifying questions about scale and constraints',
    '[ ] Made capacity estimates (RPS, storage, bandwidth)',
    '[ ] Defined the API surface clearly',
    '[ ] Described the data model and storage choices',
    '[ ] Drew a high-level architecture with named components',
    '[ ] Identified the main bottleneck and proposed a solution',
    '[ ] Discussed at least one trade-off explicitly',
    '[ ] Verified the design meets the stated requirements',
]
for item in checklist:
    print(item)

Kurzer Test

Testen Sie Ihr Verständnis der Konzepte aus Data Structures & Algorithms — Coding Interview Prep in dieser Lektion.

Zusammenfassung der Lektion

In dieser Lektion haben Sie gelernt: Das RADIO-Framework strukturiert System-Design-Interviews in Requirements, API, Data Model, Infrastructure und Optimise, Sie sollten funktionale und nichtfunktionale Anforderungen stets klären und vor einem Designvorschlag Kapazitätsschätzungen vornehmen und Abwägungen ausdrücklich besprechen – jede Designentscheidung hat Vor- und Nachteile, die Sie im Interview erläutern sollten. Als Nächstes sehen wir uns an, wie Sie anhand von Zugriffsmustern, Konsistenz und Skalierbarkeit zwischen SQL- und NoSQL-Speicher-Engines wählen.

Häufig gestellte Fragen

Ist die Lektion „Das Framework für System-Design-Interviews“ kostenlos?

Ja — der vollständige Text von „Das Framework für System-Design-Interviews“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Coding Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Das Framework für System-Design-Interviews“?

Gehen Sie das fünfstufige RADIO-Framework (Requirements, API, Data, Infrastructure, Optimise) durch und üben Sie seine Anwendung an einem URL-Shortener. Du übst Coding Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Coding Interview Prep zu starten?

Keine Vorkenntnisse erforderlich. Coding Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.

Wie lange dauert die Lektion „Das Framework für System-Design-Interviews“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Coding Interview Prep-Lektion Code schreiben und ausführen?

Ja. Jede Coding Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Das Framework für System-Design-Interviews
  2. Skalierbare Datenspeicherung: SQL vs. NoSQL
  3. Caching, CDNs und Load Balancing
  4. Rate Limiter und Twitter-Feed entwerfen
← Zurück zu Coding Interview Prep