Code lesen: Eine Superkraft für die Fehlersuche

2025-09-08

Dieser Beitrag beschreibt einen bedeutenden Karrierewechsel: von iterativem Programmieren zur proaktiven Fehlersuche. Anstatt sich nur auf testgetriebene Iteration zu verlassen, plädiert der Autor für das sorgfältige Lesen des Codes, um Probleme präventiv zu identifizieren. Der Schlüssel, so der Autor, liegt darin, den Code sorgfältig zu lesen, ein vollständiges mentales Modell des Programms zu erstellen und dann die Unterschiede zwischen diesem Modell und dem tatsächlichen Code in Git zu identifizieren. Der Beitrag schlägt vor, sich auf den Kontrollfluss und die Datenstrukturen zu konzentrieren und potenziell fehleranfällige Muster im Code zu identifizieren. Dieser Ansatz reduziert Fehler drastisch und verbessert die Codequalität.

Mehr lesen
Entwicklung Code lesen Fehlersuche

Elegante Retry-Schleifen: Vermeidung von Redundanz und unerwartetem Sleep

2025-08-27

Der Autor untersucht, wie man eine elegante Retry-Schleife schreibt, die die Anzahl der Wiederholungsversuche klar begrenzt, unnötiges Warten nach dem letzten Versuch vermeidet, den ursprünglichen Fehler meldet, wenn der Wiederholungsversuch fehlschlägt, und Code-Duplizierung verhindert. Es werden verschiedene Ansätze verglichen, wobei sich letztendlich eine `try while`-Schleife mit oberer Grenze durchsetzt, um die Beendigung zu gewährleisten und Probleme mit Grenzen und potenziellen Endlosschleifen früherer Lösungen zu beheben. Obwohl die endgültige Lösung nicht perfekt ist, stellt sie eine signifikante Verbesserung in Bezug auf Kürze und Robustheit gegenüber früheren Versuchen dar.

Mehr lesen
Entwicklung

Ein eleganter Trick in Zig: Partielles Matching von Enums

2025-08-09

Zig bietet eine elegante Lösung für das partielle Matching von Enums, wodurch redundanter Code und Laufzeitfehler vermieden werden. Der Artikel beschreibt eine clevere Technik mit `inline` und `comptime unreachable`, die es dem Compiler ermöglicht, unnötige `else`-Zweige zur Kompilierzeit zu überprüfen und so die Robustheit und Lesbarkeit des Codes zu verbessern. Dies ist besonders nützlich bei vielen Enum-Varianten und vereinfacht die Codelogik erheblich.

Mehr lesen
Entwicklung Kompilierzeitprüfung

Der verkannte Nutzen von `font-size-adjust`

2025-07-26

Dieser Artikel widerlegt das weit verbreitete Missverständnis bezüglich der CSS-Eigenschaft `font-size-adjust`. Der Autor argumentiert, dass `font-size` die Größe des Kastens um ein Glyph festlegt, nicht die Größe des Glyphs selbst, was zu Inkonsistenzen zwischen verschiedenen Schriftarten führt. Anstatt sich nur auf Schriftart-Fallbacks zu konzentrieren, kann `font-size-adjust` verwendet werden, um eine konsistentere Größe über verschiedene Schriftarten auf einer Seite hinweg zu gewährleisten. Der Autor empfiehlt, sie auf `ex-height 0.53` in einem CSS-Reset festzulegen, um eine bessere typografische Konsistenz zu erreichen.

Mehr lesen
Entwicklung

Minimalistischer RSS-Reader: Erstellen eines personalisierten Blog-Feeds mit Deno

2025-06-26

Genervt von überladenen RSS-Readern? Der Autor wählte einen anderen Ansatz und baute einen eigenen RSS-Reader mit Deno und einer einfachen Textdatei. Er zeigt nur die Titel und Links der drei neuesten Beiträge an, ohne lokale Volltextspeicherung oder Lesezeichen. GitHub Actions aktualisiert ihn täglich automatisch. Der Code ist prägnant, leicht verständlich und erweiterbar – ein Traum für Minimalisten.

Mehr lesen
Entwicklung

Schnelle Rust-Builds: Geheimnisse für CI unter 10 Minuten

2025-06-20

Es ist eine häufige Beschwerde, dass Rust langsam kompiliert, aber der Autor argumentiert, dass die meisten Rust-Projekte viel langsamer kompilieren als sie sollten. Am Beispiel von rust-analyzer (200.000 Codezeilen plus eine Million Zeilen an Abhängigkeiten) wurde eine CI-Pipeline von 8 Minuten auf GitHub Actions erreicht. Der Artikel beschreibt Strategien zur Optimierung der Kompilierzeiten, darunter die Nutzung von CI-Caching, die Aufteilung von CI-Aufgaben, die Deaktivierung von inkrementeller Kompilierung und Debug-Informationen, die Reduzierung von Abhängigkeiten, die Verwendung von `cargo build -Z timings` zum Profiling und die sorgfältige Architektur des Codes, um übermäßige generische Instanziierung an Crate-Grenzen zu vermeiden. Der Autor betont den Einfluss der Kompilierzeit auf die Entwicklerproduktivität und empfiehlt, die Kompilierzeiten regelmäßig zu optimieren, um die CI-Zeiten für große Rust-Projekte in einem angemessenen Bereich zu halten, z. B. etwa 10 Minuten.

Mehr lesen
Entwicklung

Das Koordinationsproblem von Open Source: Lehren aus Linux-Desktop und LSP

2025-06-20

Der Autor nutzt seine Erfahrungen mit NixOS und einer KDE-Anwendung als Ausgangspunkt, um die Herausforderungen der Koordinierung von Open-Source-Software in der Linux-Desktop-Umgebung zu diskutieren. Er hebt das Fehlen eines einheitlichen API-Standards auf dem Linux-Desktop hervor, was zu einem fragmentierten Software-Ökosystem führt, das als "Escher-artige Perpetuum Mobile" beschrieben wird. Dies steht im Gegensatz zur Veröffentlichung des Language Server Protocol (LSP) durch Microsoft vor zehn Jahren. Obwohl die Implementierung mittelmäßig war, löste seine bloße Existenz das Koordinationsproblem für IDE-Funktionen und trieb den Fortschritt der Branche voran. Der Autor argumentiert, dass die mangelnde Koordinationsfähigkeit der Open-Source-Community zu einer verpassten Gelegenheit geführt hat, ein einheitliches IDE-Protokoll vor dem LSP zu erstellen. Der Erfolg von Linux ist jedoch auf den vordefinierten API-Standard von POSIX zurückzuführen, der die Koordinationsaufwände reduziert. Dieser Artikel regt zur Reflexion über die Koordinationsmechanismen der Open-Source-Community und die Entwicklungsmodelle von Software-Ökosystemen an. Kategorie: Technologie

Mehr lesen
Technologie

Zwei Faustregeln für effizienten Code

2025-05-17

Dieser Artikel beschreibt zwei praktische Tipps zur Verbesserung der Code-Effizienz: das Verschieben von `if`-Bedingungen nach oben und von `for`-Schleifen nach unten. Das Verschieben von `if`-Bedingungen in die aufrufende Funktion reduziert Verzweigungen, vereinfacht den Kontrollfluss und verbessert die Lesbarkeit. Das Verschieben von `for`-Schleifen dorthin, wo Batches von Daten verarbeitet werden, nutzt die Vorteile der Batchverarbeitung, verbessert die Leistung und ermöglicht möglicherweise die Vektorisierung. Diese beiden Tipps ergänzen sich und verbessern die Code-Effizienz, insbesondere bei der Verarbeitung großer Datenmengen.

Mehr lesen
Entwicklung

Über die skalare Selektion hinaus: Batch-Verarbeitung von Ereignisströmen für Effizienz

2025-05-15

Der Autor beschreibt die Ineffizienz des skalaren Selektions-Anti-Patterns im Design von zustandsbehafteten Diensten, veranschaulicht an einem LSP-Server. Die Verarbeitung von Ereignissen einzeln führt zu Verzögerungen und Ressourcenverschwendung. Die vorgeschlagene Lösung besteht darin, Ereignisströme stapelweise zu verarbeiten. Eine `batch_stream`-Funktion führt eingehende Ereignisse zu Batches zusammen, wodurch die Effizienz deutlich verbessert wird. Bei geringer Last verhält sie sich wie eine Einzelereignisverarbeitung, bei hoher Last reduziert sie jedoch den Overhead drastisch und steigert die Leistung.

Mehr lesen
Entwicklung Ereignisgesteuert

Zigs Comptime: Leistungsstarke, aber zurückhaltende Metaprogrammierung

2025-04-20

Zigs Comptime-Funktion ist bekannt für ihre Fähigkeiten: Generics, bedingte Kompilierung und mehr. Sie ist jedoch absichtlich restriktiv und erlaubt keine dynamische Codegenerierung, benutzerdefinierte Syntaxerweiterungen, Laufzeittypinformationen (RTTI) und E/A. Dieser Artikel untersucht die Gründe für diese Einschränkungen und zeigt, wie Zig durch partielle Auswertung und Typspezialisierung eine effiziente und leicht verständliche Metaprogrammierung erreicht. Ein Beispiel für eine benutzerdefinierte Druckfunktion zeigt, wie Zig typsichere Laufzeitreflexion ohne RTTI durchführt. Der Artikel lobt abschließend die einzigartige Eleganz von Zig in der Metaprogrammierung; obwohl weniger leistungsstark als Alternativen, ist sie in der Praxis bemerkenswert effizient und einfach zu verwenden.

Mehr lesen

Debugger als REPL: Run to Cursor und Quick Evaluate Expression in IntelliJ IDEA

2025-03-28

Der Autor war müde von traditionellen Debuggers, insbesondere von den Einschränkungen von gdb und lldb bei nativem Code. Er entdeckte einen leistungsstarken Workflow in IntelliJ IDEA. Durch die Kombination von "Run to Cursor" und "Quick Evaluate Expression" verwandelt sich der Debugger in eine REPL. "Run to Cursor" führt das Programm bis zur Cursorposition aus, während "Quick Evaluate Expression" die Auswertung von Ausdrücken (sogar neu eingegebenen Code!) im aktuellen Stack-Frame ermöglicht. Dieser Ansatz ersetzt das schrittweise Debugging durch eine experimentellere, zweidimensionale Interaktion im Editor, nutzt Code-Completion und bietet eine deutlich effizientere Debug-Erfahrung.

Mehr lesen
Entwicklung

Lange Optionen in Skripten verwenden

2025-03-22

Viele Kommandozeilenprogramme unterstützen kurze (-f) und lange (--force) Optionen. Während kurze Optionen für die interaktive Verwendung praktisch sind, sind lange Optionen in Skripten weitaus überlegen. Ihre bessere Lesbarkeit und selbsterklärende Natur verbessern die Wartbarkeit und das Verständnis. Beispielsweise ist in Git `git switch --create release-{today} origin/main` deutlich übersichtlicher als `git switch -c my-new-branch`, insbesondere in komplexen Skripten.

Mehr lesen
Entwicklung lange Optionen

Hardcore Rust: Ein Raytracer ohne dynamische Speicherzuweisung

2025-01-30

Dieser Beitrag beschreibt eine Fallstudie zum Schreiben einer Rust-Anwendung mit einer minimalen, künstlich eingeschränkten API (keine dynamische Speicherzuweisung). Der Autor kritisiert RAII (Resource Acquisition Is Initialization) dafür, zu unübersichtlichem Ressourcenmanagement zu führen, und schlägt einen „Hardcore-Modus“ vor: Aufteilung des Programms in eine `std`-Binärdatei und eine `#![no_std] no_alloc`-Bibliothek, wobei nur die Binärdatei direkt Ressourcen vom Betriebssystem anfordern darf. Anhand eines Spielzeug-Raytracers wird detailliert erklärt, wie Pixel-Puffer, Parallelisierung, der Speicherzuweiser und die Szenenanalyse in diesem „Hardcore-Modus“ gehandhabt werden, was letztendlich zu einem Raytracer ohne dynamische Speicherzuweisung führt.

Mehr lesen
Entwicklung

Invarianten: Ein mächtiges Werkzeug zum Schreiben korrekten Codes

2025-01-12

Dieser Artikel untersucht das Konzept von „Invarianten“ in der Programmierung und deren Anwendung. Ausgehend von einem kleinen Beispiel – dem Schreiben einer Variante der binären Suche, die den Einfügepunkt berechnet – zeigt der Autor, wie das Definieren und Aufrechterhalten von Invarianten zu korrektem Code führt. Invarianten, so der Artikel, sind Eigenschaften, die während der gesamten dynamischen Entwicklung eines Systems wahr bleiben und das Denken vereinfachen, indem sie die Komplexität vermeiden, die mit der Berücksichtigung mehrerer Ausführungspfade verbunden ist. Beispiele von Projekten wie Cargo, rust-analyzer und TigerBeetle veranschaulichen die Vorteile der Verwendung von Invarianten in großen Systemen, wie z. B. verbesserte Wartbarkeit und Leistung. Der Autor fasst zusammen, wie wichtig Invarianten sowohl in der Klein- als auch in der Großprogrammierung sind, und hebt ihren Wert beim Schreiben korrekten und effizienten Codes hervor.

Mehr lesen
Entwicklung Programmiertechniken

Revolutionäre Idee: Magit-Prinzipien auf das Versionskontrollsystem jj anwenden

2024-12-13

Der Autor schlägt einen neuartigen Ansatz vor: die Magit-Versionskontrolloberfläche von Emacs (die Textdateien als Benutzeroberfläche verwendet) auf das entstehende jj-Versionskontrollsystem anzuwenden. Der Artikel hebt hervor, dass die textbasierte Benutzeroberfläche von Magit Effizienz und Portabilität bietet. Durch die Nutzung des LSP-Protokolls kann eine Magit-ähnliche Erfahrung in verschiedenen Editoren implementiert werden, wodurch redundante Entwicklung vermieden wird. Der Autor sieht die Generierung spezifischer Textdateien (wie .jj/status.jj) und die Verwendung von LSP-Funktionen wie semantische Token, Faltungsbereiche und Sprung zur Definition vor, um Magit-ähnliche Versionskontrolloperationen zu erreichen. Das endgültige Ziel ist die Erstellung einer effizienten und plattformübergreifenden Benutzeroberfläche für die jj-Versionskontrolle.

Mehr lesen
Entwicklung