BLOG

Mehr Produktivität für Rust-Entwickler mit Cursor

Aleksandr Meshcheriakov
February 24, 2026
Table of Contents:

KI-gestütztes Programmieren hat sich von einer Neuheit zum Standard entwickelt. Bei ilert haben wir Mitte 2023 mit KI-gestützter Programmierung begonnen und schnell erkannt, dass der Erfolg stark vom richtigen Kontext und den richtigen Arbeitsabläufen abhängt. Dies gilt insbesondere für Rust. Obwohl die Sprache für unsere Backend-Infrastruktur von zentraler Bedeutung ist, machen es ihre strengen Compiler-Regeln und ausgeprägten idiomatischen Ansätze für moderne LLMs bekanntermaßen schwierig, sie zu beherrschen. 

Daher haben wir viel Zeit in die Optimierung unserer AI-First-Entwicklungspraktiken investiert – eine Investition, die Entwicklungsprobleme erfolgreich beseitigt und unser Onboarding deutlich vereinfacht hat.

In diesem Artikel beschreiben wir unseren Weg von lokalen Code-Bearbeitungen zu einem strukturierten, kontextbasierten Workflow mit Cursor. Wir stellen die genauen Strategien, Rule-Files und Planungsworkflows vor, die die KI von einem Spielzeug zu einem zuverlässigen Mitwirkenden gemacht haben.

Unser Weg von Code-Snippets zu Multi-Agent-Workflows

Wir sind immer offen für neue Technologien und beobachten aktiv alle Trends, um die besten Lösungen in unsere Arbeitsprozesse zu integrieren. Die KI war keine Ausnahme. Zunächst betrachteten wir KI als „besseres Stack Overflow”. Anfänglich nutzten wir ChatGPT zum Schreiben von Code-Snippets. Wir erstellten mehrere Custom-GPTs zum Schreiben von Unit-Tests und Dokumentationen. Dann abonnierten wir GitHub Copilot für die intelligente Autovervollständigung. Und dann kam Cursor. Zunächst waren wir ziemlich skeptisch, da das Tool ziemlich viele Fehler hatte und das Ergebnis weit von dem entfernt war, was wir uns vorgestellt hatten. Aber seine Fähigkeit, den Index der Codebasis zu nutzen, war vielversprechend.

Phase 1: Isolierte Aufgaben

Anfangs haben wir Cursor für isolierte Aufgaben verwendet. Ein Entwickler beauftragte ChatGPT zum Beispiel damit, „einen POST-Endpunkt für die Incident-Entität zu implementieren”. Der Umfang der Aufgaben war gering und die Ergebnisse waren oft unzuverlässig. In Rust führte dies oft zu Code, der zwar funktionierte, aber nicht idiomatisch war oder unsere bestehende Architektur verletzte.

Phase 2: Lebendige Dokumentation und Rule files

Wir erkannten, dass die KI nur so gut war wie der Kontext, den sie „sehen“ konnte. Anstatt jedoch den Kontext in jeden Chat einzufügen, wählten wir einen anderen Ansatz: Wir behandelten Dokumentation und Regeln als erstklassige Code-Artefakte.

Wir führten zwei wichtige Praktiken ein:

  • .cursor/rules/: Projektspezifische Regeldateien (wie rust-coding.mdc), die Cursor automatisch in jede Interaktion lädt. Diese Regeln kodieren unsere technischen Standards – Fehlerbehandlungsmuster, Parallelitätsmodelle, bevorzugte Crates –, sodass die KI jede Aufgabe bereits mit dem „Wissen“ um unsere Konventionen beginnt.
  • Lebendige Dokumentation: Dateien wie ARCHITECTURE.md, die Entscheidungen dokumentieren, nicht Implementierungsdetails.

Diese Phase brachte den Durchbruch, da der Kontext persistent verfügbar war und automatisch eingebunden wurde. Kein Kopieren und Einfügen mehr. Die KI übernahm einfach unsere Engineering-Kultur aus dem Repository selbst. Die genauen Regeldefinitionen und Dateistrukturen, die das ermöglichten, werden wir später in diesem Artikel vorstellen.

Phase 3: Plan Mode – Architektur vor Implementierung

Die Einführung von Plan Mode war der nächste Entwicklungsschritt in unserem Prozess und verlagerte unseren Workflow von „Code generieren und iterieren” zu „zuerst entwerfen, dann gezielt implementieren”.

Selbst mit geeigneten Regeln führt das sofortige Wechseln in die Code-Generierung oft zu Lösungen, die technisch korrekt, aber architektonisch fragwürdig sind – Tech Debt garantiert. 

Um dem entgegenzuwirken, haben wir eine Strategie implementiert, die wir als „Dreierregel“ bezeichnen: Bei jeder wesentlichen Änderung beginnen wir mit Plan Mode und formulieren den Prompt wie folgt:

Goal: Implement JWT middleware for the HTTP service.

1. Scan ARCHITECTURE.md and README.md for related parts of the service
2. Scan the codebase to fill gaps in understanding
3. Propose 3 distinct architectural approaches
4. For each, list pros/cons and impact on maintainability and performance

In Kombination mit unseren Rule Files stellt der Plan Mode sicher, dass die KI Code generiert, der mit unserer langfristigen Vision übereinstimmt. Die Spezifikation und die Implementierung bleiben im gleichen Kontext, sodass wir die Architektur überprüfen können, bevor auch nur eine einzige Zeile Code geschrieben wird.

Ein Hinweis zur Kontext-Entropie im Plan Mode: Wir haben eine bestimmte Einschränkung in der aktuellen Version von Cursor festgestellt: Wenn man einen generierten Plan zu oft iteriert, neigt das Modell dazu, Einschränkungen und nützliche Lösungen, die in der ersten Version festgelegt wurden, zu „vergessen”. 

Um diese Kontextverschiebung zu verhindern, nutzen wir für komplexe Aufgaben zuerst den Ask Mode, bevor wir in Plan Mode wechseln. So können wir Anforderungen und Randfälle im Voraus klären, was zu einem robusten Anfangsplan führt, der weniger Nachbearbeitungen erfordert.

Phase 4: Multi-Agent-Orchestrierung

Die neueste Entwicklung geht über einen einzelnen KI-Assistenten hinaus und hin zu orchestrierten Multi-Agenten-Systemen. Anstatt dass ein einzelner Agent alles übernimmt, orchestrieren wir nun spezialisierte Unteragenten, die jeweils über spezifische Tools und Fachkenntnisse verfügen.

Das allgemeine Muster sieht wie folgt aus: Der Orchestrator-Agent auf oberster Ebene koordiniert die Sub-Agenten:

  • Architekt-Agent: Betrachtet das Problem aus einer übergeordneten Perspektive, bewertet mehrere Lösungen und schlägt möglicherweise vor, einen POC zu erstellen, bevor eine Entscheidung getroffen wird.
  • Implementierungs-Agenten: Die Entwickler, die die geplanten Änderungen ausführen.
  • Review-Agenten: Qualitätsprüfer, die architektonische Standards, SOLID-Regeln, saubere Tests usw. sicherstellen.

Die Stärke liegt in der Parallelisierung und Spezialisierung, wodurch der Kontext und Fokus der LLMs effektiv verwaltet werden können. Unsere ersten Ergebnisse zeigen eine bis zu doppelt so hohe Iterationsgeschwindigkeit bei komplexen Aufgaben. Wir werden diesen Ansatz in zukünftigen Artikeln ausführlich erklären. Starten wir zunächst mit den Grundlagen der AI-First-Entwicklung.

Context Engineering: Warum Dokumentation der neue Code ist

Bevor es KI gab, war die Dokumentation oft das Letzte, was geschrieben wurde, und das Erste, was veraltet war. Ein menschlicher Entwickler konnte die Lücke zwischen einer veralteten README-Datei und dem tatsächlichen Code überbrücken. Der KI fehlt diese Intuition. Wenn Ihre Dokumentation Ihrem Code widerspricht, wird die KI eine Brücke zwischen beiden konstruieren, was zu Code führt, der korrekt erscheint, aber stillschweigend fehlschlägt.

Wir erkannten, dass wir, um Cursor effektiv zu machen, unsere Denkweise auf „AI-First-Dokumentation” umstellen mussten.

Das Kontextfenster sauber halten

Sobald man ein Repository in Cursor öffnet, indexiert es den Code, um den Projektkontext zu verstehen. Wenn dieser Index mit veralteten Architekturentscheidungen gefüllt ist, verschlechtert sich die Vorhersagequalität des Modells.

Um dem entgegenzuwirken, haben wir ein strenges Protokoll eingeführt: Dokumentation ist eine Compile-Time-Dependency.

  • Die Datei ARCHITECTURE.md: Jeder Dienst enthält diese Datei. Sie listet keine Endpunkte auf (die sich häufig ändern), sondern Entscheidungen. Dadurch erhalten die KI und neue Entwickler ein Verständnis für das „Warum” hinter dem Code.
  • Standardisierte Ordnerstruktur: Wir setzen ein einheitliches Layout für alle Rust-Dienste durch (src/domain, src/infrastructure, src/api). Da jedes Projekt identisch aussieht, kann die KI mit nahezu hundertprozentiger Genauigkeit vorhersagen, wo eine neue Datei hingehört, sodass wir weniger Pfade in Eingabeaufforderungen angeben müssen.

Der „Fix the Rule“-Loop

Eine unserer effektivsten Produktivitätsänderungen betraf den Umgang mit KI-Fehlern. Wenn Cursor zuvor Code generierte, der gegen unsere Muster verstieß, haben wir den Code einfach mit Folgebefehlen umgeschrieben. Jetzt behandeln wir einen KI-Fehler als Dokumentationsfehler.

Wenn Cursor Code generiert, der Probleme mit dem Borrow Checker verursacht oder zu einem Deadlock führt, korrigieren wir nicht nur den Code, sondern patchen auch die Rule File oder andere Kontextdokumentationen. Wir fragen: „Welche Anweisung fehlte, die diesen Fehler ermöglicht hat?“ So führt jeder Fehler zu einer dauerhaften Verbesserung für das gesamte Team.

Der Erfolgsfaktor: unsere Rust-Regeln

Die Dokumentation liefert den Kontext, aber Rules liefern die Einschränkungen. Anfangs nutzten wir eine einzelne .cursorrules-Datei im Stammverzeichnis des Repositorys. Jetzt verwenden wir mehrere RULE-Files in .cursor/rules/:

  • Sprachspezifische Regeln
  • Allgemeine Best Practices für die Programmierung
  • Refactoring-Regeln
  • Regeln für die Sicherheitsanalyse

Die Trennung der Dateien erleichtert ihre Wartung, reduziert den LLM-Kontext und erleichtert ihre Wiederverwendung in verschiedenen Projekten. Für Rust verwenden wir eine spezielle Regeldatei rust-coding.mdc (siehe Anhang). Hier gehen wir auf einige wichtige Punkte ein.

Wichtige Einschränkungen, die wir durchsetzen

1. Modularität

  • Die Regel: main.rs so klein wie möglich halten – nur main(), das die Konfiguration lädt und runtime.block_on(run(...)) aufruft. Der asynchrone Einstiegspunkt soll in einer eigenen Datei run.rs stehen. In lib.rs und mod.rs sollen nur Module aufgelistet werden. Module sollten nach Domänen gruppiert werden (z. B. src/http, src/config, src/use_case_xx).
  • Der Grund: Die schlanken Haupt- und Lib-Module erleichtern die Testbarkeit und die Lebenszyklusanalyse. Domänenordner und optionale umfangreiche Abhängigkeiten (z. B. Kafka) vereinfachen die Integrationsprüfung, ohne dass die gesamte Infrastruktur hochgefahren werden muss.

2. Das „Sync main”-Muster

Eine der größten Herausforderungen für Cursor mit Rust ist die Handhabung von Rust-Lifetimes in asynchronem Code. Dies führt dazu, dass viele unnötige Klone oder Mutexe erzeugt werden, was zu unbeabsichtigter Komplexität führt.

  • Die Regel: „Starte main() im Sync-Modus, konfiguriere die Anwendung und starte dann am Ende die Tokio-Laufzeitumgebung.”
  • Der Grund dafür: Dadurch wird die KI gezwungen, langlebige Ressourcen (wie Datenbankpools oder Konfigurationsobjekte) im Stack-Frame der main-Funktion zuzuweisen, bevor die Tokio-Laufzeitumgebung gestartet wird. Cursor kann einen Trick mit Box::leak(Box::new(some_global)) anwenden, um 'static Referenzen zu erhalten, was die Laufzeitverwaltung weiter vereinfacht.

3. Datenmodellierung und Konfiguration

  • Die Regel: Newtype-IDs, serde für DTOs mit camelCase, derive_builder für komplexe Konstruktionen, validator für eingehende DTOs. Die config-Crate mit YAML und Umgebungsüberschreibungen verwenden, damit alle Einstellungen beim Start validiert werden.
  • Der Grund: Eine konsistente DTO-Darstellung und -Validierung an der Grenze stärkt APIs, liefert klare Fehlermeldungen und sorgt dafür, dass die KI jedes Mal die gleichen Muster generiert.

4. Fehlerbehandlung

  • Die Regel: „Definiere eine thiserror-Enumeration für Businesslogik über alle Anwendungsfälle und verwende anyhow für generische Fehler.“
  • Der Grund: Dies verhindert, dass die KI zu viele benutzerdefinierte Fehler-Enumerationen erstellt, und stellt gleichzeitig sicher, dass die Geschäftslogik von abgleichbaren Fehlern profitieren kann. Wir bevorzugen die From-Trait-Implementierung gegenüber map_err() und verbieten unwrap() im Produktionscode, um sauberen und idiomatischen Rust-Code zu ermöglichen.

5. Verhindern von Async-Problemen

  • Die Regel: „Das Halten von std::sync::Mutex über einen .await hinweg ist strengstens verboten.“
  • Der Grund: Dies ist ein klassischer Rust-Fehler, der die Tokio-Laufzeit blockiert. Syntaktisch sieht es korrekt aus und lässt sich kompilieren.

6. Beobachtbarkeit und externe Kommunikation

  • Die Regel: Verwende tracing mit strukturierten Feldern; verwende impl FromRequest for Claims für Actix-Authentifizierung; nutze reqwest mit Wiederholungsversuchen und Beobachtbarkeits-Middleware für ausgehende HTTP-Anfragen.
  • Der Grund: Manchmal entscheidet sich Cursor für die Verwendung von awc::Client, aber er ist nicht Send, was beispielsweise die Übergabe an tokio::spawn erschwert. Daher setzen wir einen reqwest-basierten Client zusammen mit seinen Middlewares für produktionstaugliche Fehlertoleranz und Beobachtbarkeit durch.

Die vollständige Rules-File finden Sie im Anhang am Ende dieses Artikels. Sie können sie in .cursor/rules/rust-coding.md ablegen und an Ihren Stack anpassen.

Experiment: Keine Regeln vs. Regeln vs. Planung

Um die jeweiligen Auswirkungen auf unseren Workflow bestimmen zu können, haben wir einen kontrollierten Versuch durchgeführt, indem wir Cursor in drei Konfigurationen denselben Befehl gaben:

  1. Naked: Keine Rule-Files.
  2. Geführt: Mit rust-coding.mdc.
  3. Architektonisch: Mit Rule-File + Plan Mode.

Hinweis zur Verzerrung: Wir mussten den „Naked”-Versuch auf einem neuen Cursor-Konto durchführen. Wir haben festgestellt, dass die in der Cloud gespeicherten Einbettungen von Cursor „hartnäckig” sind; auch ohne Regeldateien „erinnerte” es sich an unsere früheren Muster aus anderen Sitzungen. Ein neues Konto war notwendig, um die tatsächliche Basisleistung zu sehen. Und hier ist eine weitere Implikation: Wenn Cursor Code mit schlechten Mustern in Kontakt kommt, kann es sein, dass es diese in dem neuen Code wiederholt. Seien Sie also vorsichtig, womit Sie Cursor „füttern”. 

Der Prompt ist absichtlich recht vage gehalten, um die Verzerrung in Cursor zu untersuchen:

Implement the service in Rust:
- HTTP server based on Actix with JWT authentication
- Consume each Kafka topic defined in the YAML configuration
- On each message, make a POST call to /forward on the downstream service with hostname configured via environment variable
- Expose Kafka producer statistics at /stats

Szenario Nr. 1: "Naked" Cursor (keine Rules-Datei)

Das generierte Projekt ließ sich nicht kompilieren. Wir stellten fest, dass der Kafka-Consumer mit tokio::spawn gestartet wurde, wobei ein gemeinsam genutzter awc::Client übergeben wurde. awc::Client implementiert das Trait Send nicht, da er auf den Single-Thread-Typen von Actix (z. B. Rc) basiert. tokio::spawn verlangt jedoch, dass das Future das Send implementiert. Daher lehnt der Compiler diese Variable ab.

Das problematische Snippet:

pub fn spawn_consumers(config: Config, stats: SharedStats, client: awc::Client, downstream_host: String) {
    for topic in config.topics {
        let client = client.clone();
        tokio::spawn(async move {
            if let Err(e) = run_topic_consumer(..., client, ...).await {
                // handle error
            }
        });
    }
}

Der Code fördert weder Wartbarkeit noch Erweiterbarkeit:

  • Die Module bestehen aus einer flachen Sammlung von Dateien im Verzeichnis /src ohne domänenspezifische Gruppierung.

  • Viele Module vermischen unterschiedliche Verantwortlichkeiten, etwa Nachrichtenverarbeitung und HTTP-Aufrufe in kafka.rs oder das Laden von Umgebungsvariablen und das Einrichten von Server-Routen in main.rs.

Szenario Nr. 2: Mit einer Rule-Datei, kein Plan Mode

Mit aktivierter Rule-Datei kompiliert das Projekt erfolgreich. Cursor wählt einen Send-sicheren HTTP-Client auf Basis von reqwest, inklusive einer separaten Fassade für den HTTP-Client.

Allerdings konnten wir feststellen, dass die Modularity-Regeln nicht vollständig umgesetzt wurden. Es gab beispielsweise keine modulare Gruppierung nach Scope und Funktionalität; sämtliche Source-Files lagen in einem einzigen Ordner. Noch gravierender: Es gab zu viele Error-Enums – eines in kafka.rs, ein weiteres in config.rs usw. Offensichtlich hatte Cursor unsere Rule hier missverstanden.

Auf diese Weise erhält man zwar einen funktionierenden, kompilierbaren Service, architektonisch bleibt jedoch Optimierungspotenzial. In diesem Fall scheint Cursor kein projektweites Architekturdenken zu verfolgen. Und genau hier kommt der Plan Mode ins Spiel.

Szenario Nr. 3: Mit Rule-Datei und Plan Mode

Mit aktivierter Rule-Datei und Start im Plan Mode von Cursor folgt der generierte Service den meisten Regeln konsistent: Der HTTP-Client und die Konfiguration befinden sich in dedizierten Modulen, die modulare Struktur mit http/, forwarding/, server/ und shared/ ist klar umgesetzt – gut geeignet für Tests und Erweiterungen.

Die main.rs ist entsprechend schlank und übersichtlich:

fn main() -> anyhow::Result<()> {
    tracing_subscriber::fmt()
        .with_env_filter(EnvFilter::from_default_env())
        .init();

    let config_path = std::env::var("CONFIG_PATH").unwrap_or_else(|_| "config.yaml".into());
    let path = PathBuf::from(&config_path);
    let config = AppConfig::load(&path).context("load config")?;

    let runtime = tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .context("create runtime")?;

    runtime.block_on(run(config))?;
    Ok(())
}

Ergebnisse: Von Autoren zu Reviewern

Nach jahrelanger Optimierung unserer Cursor-Workflows hat sich der Einfluss auf unsere Engineering-Geschwindigkeit deutlich gezeigt:

1. Optimierte Einarbeitung

Der größte Überraschungseffekt einer strikten Rule-Datei und „AI-First Documentation“ zeigte sich beim Onboarding. Wenn ein neuer Engineer zu ilert kommt, muss er nicht zunächst alle unsere Coding-Guides auswendig lernen, bevor er produktiv beitragen kann. Cursor fungiert als Pair-Programmer, der unsere Konventionen bereits kennt.

2. Von Syntax zu Architektur

Unsere Engineers verbringen heute deutlich weniger Zeit mit Boilerplate-Code, mit dem Rust-Borrow-Checker oder mit dem Debugging schwer nachvollziehbarer Async-Runtime-Fehler. Die AI übernimmt das „Plumbing“. Dadurch gewinnt unser Team Freiraum, um sich stärker auf komplexe Business-Logik zu konzentrieren und mehr Aufmerksamkeit auf entscheidende Details zu legen. 

Wir haben uns faktisch vom „Code Writer“ zum „Code Reviewer und Architekten“ entwickelt.

3. Vorhersagbarkeit im großen Maßstab

Indem wir Prompts und Regeln wie Code behandeln, haben wir ein Maß an Konsistenz erreicht, das in wachsenden Teams schwer aufrechtzuerhalten ist. Das Aufsetzen neuer Microservices und deren Integration in unsere Infrastruktur-Landschaft wurde zur Routine. Die Anzahl der Code-Review-Iterationen ist drastisch gesunken.

Fazit

Wenn Sie Rust-Entwickler oder Engineering Leader sind und Ihre Produktivität steigern möchten, sollten Sie KI nicht wie einen Chatbot behandeln. Betrachten Sie sie vielmehr wie einen Junior Engineer. Geben Sie ihr ein Handbuch (.cursor/rules/), liefern Sie Kontext (ARCHITECTURE.md) und zwingen Sie sie, erst zu denken, bevor sie Code schreibt.

Aus unserer Erfahrung ergibt sich folgende Checkliste für eine effektive Entwicklung mit Cursor:

1. Design iterieren, einmal implementieren:
Starten Sie größere Änderungen im Plan Mode und lassen Sie sich von der KI verschiedene Lösungsansätze vorschlagen. Nutzen Sie in komplexen Fällen zunächst den Ask Mode, bevor Sie in den Plan Mode wechseln.

2. Dokumentation als Dependency behandeln:
Pflegen Sie eine KI-optimierte Dokumentation (kompakt, strukturiert und widerspruchsfrei), die zentrale Entscheidungen und Constraints klar festhält.

3. Der „Fix-the-Rules“-Loop:
Wenn die KI einen Fehler macht, korrigieren Sie nicht nur den Code. Aktualisieren Sie Ihre Rules so, dass diese Fehlerklasse künftig systematisch vermieden wird.

4. Kontext bewusst steuern:
Achten Sie darauf, welche Inhalte Sie indexieren. Verwenden Sie .cursorignore, um irrelevante Informationen auszuschließen. Wenn Sie Cursor eine Legacy-Codebase mit schlechten Patterns geben, wird sie diese reproduzieren.

Die Tools sind bereit. Jetzt liegt es an uns, mit ihnen die Zukunft zu gestalten.

Anhang: Unsere Rust-Rules

Hier finden Sie unsere vollständige rust-coding.mdc. Sie können diese kopieren und an Ihre Bedürfnisse anpassen.

---
description: "ilert's Rust coding rules"
globs: ["src/**/*.rs"]
alwaysApply: true
---

# Modularity
- Group modules by business functionality: `src/payments`, users. Common utilities go into `src/shared`
- In lib.rs or mod.rs only list modules	
- Keep main.rs concise: it should contain only main() that calls configuration functions from other modules and launches the runtime
- Define run.rs with run() that is the entry point of the async runtime
- Heavy dependencies like Kafka producers should be optional, optimized for testing
- Separate boundaries under facades like Client classes for downstream HTTP services

# Data Modeling
- Newtype Pattern: Wrap primitive types for entity IDs (e.g., `#[derive(PartialEq, Eq, Hash, Copy, Clone)] struct UserId(u64);`)
- Annotate DTO structs for JSON requests and responses with `#[derive(Debug, Clone, Deserialize, Serialize)]`, `#[serde(rename_all = "camelCase")]`
- Annotate enums with `#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]` and `#[derive(Clone, Display, Debug)]`, `#[serde(rename_all = "SCREAMING_SNAKE_CASE")]`
- For complex object construction, utilize `derive_builder` with `#[builder(setter(into))]`
- Use `validator` (`#[derive(Validate)]`) on incoming DTOs

## Concurrency
- Start the main() in sync mode (no #[actix_web::main]), configure the application, then launch the async runtime at the end with `runtime.block_on(run(...))`
- Pass complex variables initialized in main() as 'static obtaining the reference with `Box::leak(Box::new(something))`
- Wrap shared writable state with `tokio::sync::RwLock` (`Arc<RwLock>`), locking for the shortest period of time
- If the shared writable state requires change notification, use `tokio::sync::watch`
- Strictly forbid holding `std::sync::Mutex` or `std::sync::RwLock` across an `.await` point
- Handle graceful job cancellation and timeouts using `tokio::select!`
- For long-term async background jobs, like message consumers, use `&'static self` and initialize the instance before the launch of the async runtime

# Error Handling
- Use descriptive error types using `thiserror` v2, preserving source via `#[from]` or `#[source]`. Fall back to `anyhow` for short-scoped generic errors that are later mapped to `thiserror`; use `.context()`
- Avoid `map_err()` — instead, implement the `From` trait for the target error type
- Strictly avoid unwrap() in production code. But `.context()` for critical errors during application launch is fine

# Observability
- Use `tracing` for logging and tracing, attaching key-value pairs with important context
- Check the log level before dumping complex debug data with `if tracing::enabled!(tracing::Level::DEBUG)`

# External Communication
- For authentication in Actix use `impl FromRequest for Claims`
- Use middlewares for observability (`reqwest-tracing` for clients, custom for servers)
- Utilize timeouts and retries with backoff for outgoing requests (`reqwest-retry`)

# Config and Utilities
- Use `config` v0.15 and YAML configurations, with flexible environment overrides by `.add_source(Environment::default()).set_override_option("some.deep.key", std::env::var("CUSTOM_VAR").ok())`
- Use `itertools` to ease iterator transformations (`use itertools::Itertools; iter.join(", "); iter.chunks(10); iter.unique()`)
- Avoid adding comments, keep existing

Blog-Beiträge, die dir gefallen könnten:

Sind Sie bereit, Ihr Incident-Management zu verbessern?

Kostenlos starten
Unsere Cookie-Richtlinie
Wir verwenden Cookies, um Ihre Erfahrung zu verbessern, den Seitenverkehr zu verbessern und für Marketingzwecke. Erfahren Sie mehr in unserem Datenschutzrichtlinie.
Open Preferences
Danke! Deine Einreichung ist eingegangen!
Hoppla! Beim Absenden des Formulars ist etwas schief gelaufen.
Danke! Deine Einreichung ist eingegangen!
Hoppla! Beim Absenden des Formulars ist etwas schief gelaufen.
Danke! Deine Einreichung ist eingegangen!
Hoppla! Beim Absenden des Formulars ist etwas schief gelaufen.