66 Punkte von GN⁺ 2025-08-18 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Eine Zusammenstellung nicht intuitiver Fallstricke, in die Entwickler häufig tappen, mit einer Einführung in die Ursachen leicht auftretender Bugs
  • Behandelt häufige Probleme in verschiedenen Technologien wie HTML, CSS, Unicode/Textkodierung, Fließkommazahlen und Zeit
  • Betont, dass durch subtile Unterschiede in Syntax und Verhalten zwischen einzelnen Sprachen und Frameworks Missverständnisse oder Fehler entstehen können
  • Erläutert anhand von Beispielen Fallstricke in zentralen Backend-Bereichen wie Nebenläufigkeit, Netzwerken und Datenbanken, die in realen Betriebsumgebungen auftreten können
  • Zeigt mithilfe verschiedener Beispiele und Referenzlinks Problemsituationen, Lösungsansätze und Verbesserungen bei unerwartetem Verhalten auf

HTML und CSS

  • Standardwert von min-width in Flexbox/Grid

    • min-width ist standardmäßig auto
    • min-width: auto wird durch die Größe des Inhalts bestimmt und hat Vorrang vor flex-shrink, overflow: hidden, width: 0 und max-width: 100%
    • Empfehlung: min-width: 0 explizit angeben
  • Unterschied zwischen horizontal und vertikal in CSS

    • width: auto versucht, den Platz des Elternelements auszufüllen, height: auto richtet sich nach dem Inhalt
    • width: auto bei inline-, inline-block- und float-Elementen erweitert sich nicht
    • margin: 0 auto zentriert horizontal, margin: auto 0 zentriert nicht vertikal (außer bei flex-direction: column, wo vertikale Zentrierung möglich ist)
    • Margin-Collapsing tritt nur vertikal auf
    • Wenn sich mit writing-mode: vertical-rl usw. die Layoutrichtung ändert, kehrt sich auch das Verhalten um
  • Block Formatting Context (BFC)

    • Ein BFC kann mit display: flow-root erzeugt werden (auch overflow: hidden/auto/scroll, display: table usw. sind möglich, haben aber Nebenwirkungen)
    • Sich überlappende vertikale Margins benachbarter Geschwister oder nach außen austretende Kind-Margins lassen sich mit einem BFC verhindern
    • Wenn ein Elternelement nur floatende Kinder enthält, kollabiert seine Höhe auf 0 → mit BFC behebbar
    • Bei vorhandenem border oder padding tritt kein Margin-Collapsing auf
  • Stacking Context

    • Bedingungen, die einen neuen Stacking Context erzeugen
      • Rendering-Eigenschaften wie transform, filter, perspective, mask, opacity
      • position: fixed oder sticky
      • gesetztes z-index + Positionierung mit absolute/relative
      • gesetztes z-index + Elemente innerhalb von Flexbox/Grid
      • isolation: isolate
    • Eigenschaften
      • z-index gilt nur innerhalb des jeweiligen Stacking Context
      • Die Koordinaten von position: absolute/fixed beziehen sich auf den nächstgelegenen positionierten Vorfahren
      • sticky funktioniert nicht über einen Stacking Context hinweg
      • Selbst overflow: visible wird durch den Stacking Context abgeschnitten
      • background-attachment: fixed wird relativ zum Stacking Context positioniert
  • Viewport-Einheiten

    • In mobilen Browsern ändert sich 100vh, wenn Adressleiste/Navigationsleiste beim Scrollen vom Bildschirm verschwinden
    • Aktuelle Lösung: 100dvh verwenden
  • Bezugsrahmen für Absolute Positioning

    • position: absolute bezieht sich nicht auf das Elternelement, sondern auf den nächstgelegenen relative/absolute- oder Stacking-Context-Vorfahren
  • Blur-Verhalten

    • backdrop-filter: blur berücksichtigt keine umliegenden Elemente
  • Aufhebung von Float

    • Wenn das Elternelement flex oder grid ist, hat float bei Kindelementen keine Wirkung
  • Prozentangaben bei width/height

    • Funktionieren nicht, wenn die Größe des Elternelements nicht vorab festgelegt ist (um zirkuläre Referenzen zu vermeiden)
  • Eigenschaften von Inline-Elementen

    • display: inline ignoriert width, height, margin-top und margin-bottom
  • Whitespace-Verarbeitung

    • Standardmäßig werden Zeilenumbrüche in HTML als Leerzeichen behandelt, aufeinanderfolgende Leerzeichen werden auf eines reduziert
    • <pre> verhindert die Reduzierung von Leerzeichen, hat aber besonderes Verhalten am Anfang und Ende
    • Leerzeichen am Anfang/Ende von Inhalten werden meist ignoriert, <a> ist jedoch eine Ausnahme
    • Leerzeichen/Zeilenumbrüche zwischen inline-block-Elementen werden als tatsächlicher Abstand dargestellt (bei flex/grid tritt das nicht auf)
  • text-align

    • Wirkt auf Text und Inline-Elemente, aber nicht auf die Ausrichtung von Block-Elementen
  • box-sizing

    • Standardwert ist content-boxpadding/border sind nicht enthalten
    • Bei width: 100% + gesetztem padding kann das Elternelement überschritten werden
    • Lösung: box-sizing: border-box
  • Cumulative Layout Shift

    • Werden bei <img> keine Attribute width und height gesetzt, kann verzögertes Laden von Bildern zu Layout-Verschiebungen führen
    • Empfehlung: Attribute setzen, um CLS zu vermeiden
  • Netzwerkanfragen bei Dateidownloads in Chrome

    • Werden im Netzwerk-Panel der DevTools nicht angezeigt (sie werden in einem anderen Tab verarbeitet)
    • Falls Analyse nötig ist: chrome://net-export/ verwenden
  • JavaScript-Parsing-Probleme in HTML

    • In Fällen wie <script>console.log('</script>')</script> wird das erste </script> als schließendes Tag erkannt
    • Siehe auch: Safe JSON in script tags

Unicode und Textkodierung

  • Code Points und Grapheme Cluster

    • Grapheme Cluster sind die „Zeicheneinheit“ in einer GUI
    • Bei sichtbaren ASCII-Zeichen gilt: 1 Code Point = 1 Grapheme Cluster
    • Ein Emoji kann aus mehreren Code Points bestehen und dennoch ein einzelnes Grapheme Cluster bilden
    • In UTF-8 belegt ein Code Point 1 bis 4 Byte; Anzahl der Bytes und Anzahl der Code Points stimmen nicht überein
    • In UTF-16 belegt ein Code Point 2 oder 4 Byte (Surrogatpaar)
    • Der Standard setzt keine Begrenzung für die Anzahl der Code Points in einem Cluster, Implementierungen begrenzen dies jedoch oft aus Performancegründen
  • Unterschiede im String-Verhalten je nach Sprache

    • Rust: Verwendet intern UTF-8 für Strings, len() gibt die Byte-Anzahl zurück, direktes Indexing ist nicht möglich, chars().count() liefert die Anzahl der Code Points, UTF-8-Gültigkeit wird strikt geprüft
    • Golang: Strings sind faktisch Byte-Arrays, Länge und Indexing erfolgen byteweise, meist wird UTF-8 verwendet
    • Java, C#, JS: Basieren auf UTF-16, messen Länge in 2-Byte-Einheiten, auch Indexing erfolgt in 2-Byte-Einheiten, Surrogatpaare kommen vor
    • Python: len() gibt die Anzahl der Code Points zurück, Indexing liefert einen String, der genau einen Code Point enthält
    • C++: std::string hat keine Vorgaben zur Kodierung, verhält sich wie ein Byte-Vektor, Länge/Indexing erfolgen byteweise
    • Unter den genannten Sprachen gibt es keine, die Länge/Indexing auf Ebene von Grapheme Clustern bereitstellt
  • BOM (Byte Order Mark)

    • Manche Textdateien enthalten ein BOM, z. B. EF BB BF als Kennzeichnung für UTF-8-Kodierung
    • Wird vor allem unter Windows verwendet; Software außerhalb von Windows kann ein BOM unter Umständen nicht korrekt verarbeiten
  • Sonstige Hinweise

    • Beim Umwandeln von Binärdaten in Zeichenketten werden fehlerhafte Teile durch � (U+FFFD) ersetzt
    • Es gibt confusable characters (Zeichen, die sich gegenseitig sehr ähnlich sehen)
    • Normalisierung (Normalization): z. B. kann é als U+00E9 (ein einzelner Code Point) oder als U+0065+U+0301 (zwei Code Points) dargestellt werden
    • Es gibt Zero-width characters und Invisible characters
    • Unterschiede bei Zeilenumbrüchen: Windows verwendet CRLF \r\n, Linux/MacOS LF \n
    • Han unification: Je nach Sprache verwenden Zeichen mit leicht unterschiedlicher Form denselben Code Point
      • Schriftarten rendern dies passend, indem sie sprachspezifische Varianten enthalten
      • Bei der Internationalisierung muss die richtige Font-Variante gewählt werden

Gleitkommazahlen (Floating point)

  • NaN-Eigenschaften

    • NaN ist mit keinem Wert gleich, auch nicht mit sich selbst (NaN == NaN ist immer false)
    • NaN != NaN ist immer true
    • Ergebnisse von Operationen mit NaN propagieren in den meisten Fällen ebenfalls zu NaN
  • Spezielle Werte

    • Es gibt +Inf und -Inf, sie unterscheiden sich von NaN
    • -0.0 ist ein von +0.0 unterscheidbarer Wert
      • Bei Vergleichsoperationen sind sie gleich, in einigen Berechnungen verhalten sie sich jedoch unterschiedlich
      • Beispiel: 1.0 / +0.0 == +Inf, 1.0 / -0.0 == -Inf
  • Kompatibilität mit JSON

    • Der JSON-Standard erlaubt NaN und Inf nicht
      • JS JSON.stringify wandelt NaN und Inf in null um
      • Python json.dumps(...) gibt NaN und Infinity unverändert aus (Verstoß gegen den Standard)
        • Mit der Option allow_nan=False tritt bei NaN/Inf ein ValueError auf
      • Golang json.Marshal gibt bei vorhandenem NaN/Inf einen Fehler zurück
  • Präzisionsprobleme

    • Direkte Vergleiche von Gleitkommazahlen können fehlschlagen → empfohlen ist die Form abs(a - b) < ε
    • JS behandelt alle Zahlen als Gleitkommazahlen
      • Der sichere Integer-Bereich ist -(2^53 - 1) bis 2^53 - 1
      • Außerhalb dieses Bereichs ist die Integer-Darstellung ungenau
      • Für große Integer wird BigInt empfohlen
      • Wenn JSON Integer außerhalb des sicheren Bereichs enthält, kann das Ergebnis von JSON.parse ungenau sein
      • Zeitstempel in Millisekunden sind bis zum Jahr 287.396 sicher, bei Nanosekunden treten Probleme auf
  • Nichtanwendbarkeit von Rechengesetzen

    • Je nach Reihenfolge der Operationen gelten Assoziativgesetz und Distributivgesetz aufgrund von Präzisionsverlusten nicht streng
    • Parallele Berechnungen (Matrixmultiplikation, Summen usw.) können nichtdeterministische Ergebnisse erzeugen
  • Leistung

    • Division ist deutlich langsamer als Multiplikation
    • Wenn mehrfach durch denselben Wert geteilt wird, kann man optimieren, indem man zuerst den Kehrwert berechnet und dann multipliziert
  • Unterschiede je nach Hardware

    • Unterstützung für FMA (Fused Multiply-Add): Manche Hardware führt Zwischenberechnungen mit höherer Präzision aus
    • Behandlung des Subnormal range: Moderne Hardware unterstützt ihn, manche ältere behandelt ihn als 0
    • Unterschiede bei Rundungsmodi
      • Es gibt u. a. RNTE (auf die nächste gerade Zahl runden) und RTZ (auf 0 abschneiden)
      • x86/ARM kann dies als thread-lokalen veränderbaren Zustand setzen
      • Bei GPUs unterscheidet sich der Rundungsmodus je nach Instruktion
    • Unterschiede im Verhalten mathematischer Funktionen wie trigonometrische Funktionen oder Logarithmen
    • x86 hat eine Legacy-80-Bit-FPU und einen per-core rounding mode → Verwendung nicht empfohlen
    • Auch darüber hinaus können verschiedene Faktoren dazu führen, dass Gleitkommaergebnisse je nach Hardware unterschiedlich ausfallen
  • Methoden zur Verbesserung der Präzision

    • Den Berechnungsgraphen flach halten (weniger aufeinanderfolgende Multiplikationsstrukturen)
    • Vermeiden, dass Zwischenwerte extrem groß oder extrem klein werden
    • Hardware-Operationen wie FMA nutzen

Zeit (Time)

  • Schaltsekunde (Leap second)

    • Unix-Zeitstempel ignorieren Schaltsekunden
    • Beim Auftreten einer Schaltsekunde wird die Zeit in der Umgebung gestreckt oder verkürzt (Leap smear)
  • Zeitzone (Time zone)

    • UTC und Unix-Zeitstempel sind weltweit einheitlich
    • Menschenlesbare Zeit hängt von der jeweiligen lokalen Zeitzone ab
    • Es wird empfohlen, Zeitstempel in der DB zu speichern und erst in der UI umzuwandeln
  • Sommerzeit (DST)

    • In manchen Regionen wird die Uhr im Sommer um 1 Stunde angepasst
  • NTP-Synchronisierung

    • Während der Synchronisierung kann es vorkommen, dass die Zeit „rückwärts läuft“
  • Einstellung der Server-Zeitzone

    • Für Server wird UTC empfohlen
    • In verteilten Systemen entstehen Probleme, wenn Knoten unterschiedliche Zeitzonen verwenden
    • Nach dem Ändern der Systemzeitzone ist eine Neukonfiguration oder ein Neustart der DB erforderlich
  • Hardware-Uhr vs. Systemuhr

    • Die Hardware-Uhr kennt kein Zeitzonenkonzept
    • Linux: behandelt die Hardware-Uhr als UTC
    • Windows: behandelt die Hardware-Uhr als lokale Zeit

Java

  • == vergleicht Objektreferenzen, für den Vergleich des Objektinhalts muss .equals verwendet werden
  • Wenn equals und hashcode nicht überschrieben werden, beurteilen map/set die Gleichheit von Objekten referenzbasiert
  • Wenn der Inhalt eines key-Objekts in einer map oder eines Elementobjekts in einem set geändert wird, funktioniert der Container nicht mehr korrekt
  • Methoden, die List<T> zurückgeben, liefern je nach Fall ein veränderbares ArrayList oder ein unveränderliches Collections.emptyList(); beim Ändern des Letzteren tritt UnsupportedOperationException auf
  • Es gibt Fälle, in denen eine Methode, die Optional<T> zurückgeben soll, null zurückgibt (nicht empfohlen)
  • Wenn im finally-Block ein return ausgeführt wird, werden Ausnahmen aus try oder catch ignoriert und der Rückgabewert aus finally verwendet
  • Es gibt Bibliotheken, die interrupts ignorieren; außerdem kann die Initialisierung von Klassen einschließlich IO durch interrupts gestört werden
  • Bei Tasks, die in einem thread pool mit .submit() übergeben werden, werden Ausnahmen standardmäßig nicht ins Log geschrieben und können nur über das future geprüft werden; wird das future ignoriert, bleiben die Ausnahmen unbemerkt
    • scheduleAtFixedRate-Jobs werden bei einer Ausnahme stillschweigend beendet
  • Wenn ein Zahlenliteral mit 0 beginnt, wird es als Oktalzahl behandelt (0123 → 83)
  • Der Debugger ruft .toString() lokaler Variablen auf; da toString() bei einigen Klassen Nebenwirkungen hat, kann sich das Verhalten des Codes beim Debugging ändern (in der IDE deaktivierbar)

Golang

  • append() verwendet bei freier capacity denselben Speicher weiter; ein append auf eine subslice kann daher auch den Speicher des übergeordneten Bereichs überschreiben
  • defer wird beim Return der Funktion ausgeführt, nicht beim Ende eines Block-Scopes
  • defer erfasst veränderbare Variablen
  • Zu nil
    • Eine nil slice und eine leere slice sind verschieden
    • string kann nicht nil sein, es gibt nur den leeren String
    • Eine nil map kann gelesen, aber nicht beschrieben werden
    • Eigenartiges Verhalten bei interface nil: Wenn der data pointer null ist, aber die type info nicht null ist, ist es nicht gleich nil
  • Dead wait: Es gibt in Go reale Beispiele für derartige Nebenläufigkeits-Bugs
  • Es gibt verschiedene Timeout-Arten, ausführlich behandelt in net/http

C/C++

  • Wenn nach dem Speichern eines Zeigers auf ein std::vector-Element der Vektor wächst, kommt es zu einer Reallokation und der Zeiger wird ungültig
  • Ein std::string, der aus einem String-Literal erzeugt wurde, kann ein temporäres Objekt sein; ein Aufruf von c_str() ist dann riskant
  • Wird ein Container während der Iteration verändert, werden Iteratoren ungültig
  • std::remove löscht nicht wirklich, sondern ordnet Elemente nur um; zum Löschen ist erase nötig
  • Beginnt ein Zahlenliteral mit 0, wird es als Oktalzahl behandelt (0123 → 83)
  • Undefined behavior (UB): Bei der Optimierung kann UB beliebig verändert werden, daher ist jede Abhängigkeit davon riskant
    • Zugriff auf nicht initialisierten Speicher ist UB
    • Wird char* in einen Struct-Zeiger umgewandelt, ist der Zugriff vor Beginn der Objektlebensdauer UB; Initialisierung per memcpy wird empfohlen
    • Ungültiger Speicherzugriff (z. B. Nullzeiger) ist UB
    • Integer-Overflow/-Underflow ist UB (bei unsigned ist Underflow unter 0 möglich)
    • Aliasing: Wenn Zeiger verschiedener Typen auf denselben Speicher verweisen, kann durch die Strict-Aliasing-Regel UB entstehen
      • Ausnahmen: 1) Typen in einer Vererbungsbeziehung 2) Umwandlung in char*, unsigned char*, std::byte* (gilt nicht für die Rückumwandlung)
      • Für erzwungene Umwandlungen werden memcpy oder std::bit_cast empfohlen
    • Zugriff auf unaligned memory ist UB
  • Memory Alignment
    • Bei 64-Bit-Integern muss die Adresse durch 8 teilbar sein
    • Auf ARM kann unaligned Zugriff zu einem Crash führen
    • Wird ein Byte-Puffer direkt als Struct interpretiert, können Alignment-Probleme auftreten
    • Alignment kann durch Struct-Padding zu Speicherverlust führen
    • Einige SIMD-Befehle (z. B. AVX) können nur ausgerichtete Daten verarbeiten; meist ist ein Alignment von 32 Byte nötig

Python

  • Standardargumente von Funktionen werden nicht bei jedem Aufruf neu erzeugt, sondern der initiale Wert wird beibehalten

SQL Databases

  • Umgang mit Null

    • x = null funktioniert nicht; stattdessen muss x is null verwendet werden
    • Null ist nicht einmal sich selbst gleich (ähnlich wie NaN)
    • Ein Unique-Index erlaubt doppelte Null-Werte (mit Ausnahme von Microsoft SQL Server)
    • Wie Null bei select distinct behandelt wird, unterscheidet sich je nach DB
    • count(x) und count(distinct x) ignorieren Zeilen mit Null-Werten
  • Allgemeines Verhalten

    • Implizite Datumsumwandlungen können von der Zeitzone abhängen
    • Komplexe Join- + Distinct-Abfragen können langsamer sein als verschachtelte Queries
    • In MySQL (InnoDB) führt ein String-Feld, das nicht utf8mb4 verwendet, beim Einfügen von 4-Byte-UTF-8-Zeichen zu Fehlern
    • MySQL (InnoDB) ist standardmäßig nicht case-sensitive
    • MySQL (InnoDB) erlaubt implizite Umwandlungen: select '123abc' + 1; → 124
    • Gap Locks in MySQL (InnoDB) können Deadlocks verursachen
    • In MySQL (InnoDB) liefert eine Abweichung zwischen group by und select-Spalten nichtdeterministische Ergebnisse
    • In SQLite ist der Feldtyp ohne strict weitgehend bedeutungslos
    • Foreign Keys können implizite Locks auslösen und dadurch Deadlocks verursachen
    • Locking kann je nach DB die Repeatable-Read-Isolation verletzen
    • Verteilte SQL-Datenbanken unterstützen Locking möglicherweise nicht oder verhalten sich ungewöhnlich (je nach DB unterschiedlich)
  • Performance/Betrieb

    • Das N+1-Query-Problem erscheint nicht im Slow-Query-Log, weil jede einzelne Query schnell ist
    • Lang laufende Transaktionen können Lock-Probleme usw. verursachen → daher sollten Transaktionen schnell beendet werden
    • Fälle mit vollständigem Tabellen-Lock
      • In MySQL 8.0+ können das Hinzufügen eines Unique-Index oder eines Foreign Keys meist parallel verarbeitet werden
      • Bei älteren MySQL-Versionen kann ein vollständiger Tabellen-Lock auftreten
      • Fehlt bei mysqldump die Option --single-transaction, wird ein vollständiger Read Lock auf die Tabelle gesetzt
      • In PostgreSQL verursachen create unique index oder alter table ... add foreign key einen vollständigen Read Lock auf die Tabelle
        • Vermeidung: create unique index concurrently verwenden
        • Bei Foreign Keys die Methode ... not valid und anschließend validate constraint verwenden
  • Range-Abfragen

    • Nicht überlappende Bereiche:
      • Die einfache Bedingung p >= start and p <= end ist ineffizient (auch mit zusammengesetztem Index)
      • Effiziente Variante:
        select *   
        from (select ... from ranges where start <= p order by start desc limit 1)   
        where end >= p  
        
        (benötigt nur einen Index auf der Spalte start)
    • Überlappende Bereiche:
      • Mit einem normalen B-Tree-Index ineffizient
      • Empfohlen: Spatial Index in MySQL, GiST in PostgreSQL

Concurrency and Parallelism

  • volatile

    • volatile kann keinen Lock ersetzen und bietet keine Atomizität
    • Für durch Locks geschützte Daten ist volatile nicht nötig (der Lock garantiert die Memory Order)
    • C/C++: volatile verhindert nur bestimmte Optimierungen, fügt aber keine Memory Barrier hinzu
    • Java: Zugriffe auf volatile bieten sequentially-consistent ordering (die JVM fügt bei Bedarf Memory Barriers ein)
    • C#: Zugriffe auf volatile bieten release-acquire ordering (die CLR fügt bei Bedarf Memory Barriers ein)
    • Kann Fehloptimierungen im Zusammenhang mit der Umordnung von Speicher-Lese-/Schreibzugriffen verhindern
  • TOCTOU-(Time-of-check to time-of-use)-Problem

  • Behandlung von Constraints in der Anwendungsschicht bei SQL-DBs

    • Wenn Constraints, die sich nicht mit einem einfachen Unique-Index ausdrücken lassen (z. B. tabellenübergreifende Eindeutigkeit, bedingte Eindeutigkeit, Eindeutigkeit innerhalb eines Zeitraums), in der Anwendung erzwungen werden:
      • MySQL (InnoDB): Auf Repeatable-Read-Level ist nach select ... for update und anschließendem Insert sowie bei vorhandenem Index auf der Unique-Spalte die Gültigkeit dank Gap Lock gewährleistet (Gap Locks können bei hoher Last jedoch Deadlocks verursachen → Deadlock-Erkennung und Retry nötig)
      • PostgreSQL: Dieselbe Logik ist auf Repeatable-Read-Level bei konkurrierenden Zugriffen nicht ausreichend (Write-Skew-Problem)
        • Lösungen:
          • Serializable Isolation Level verwenden
          • DB-Constraints statt Anwendungslogik verwenden
            • Bedingte Eindeutigkeit → Partial Unique Index
            • Tabellenübergreifende Eindeutigkeit → doppelte Daten in separate Tabelle einfügen und dort per Unique-Index absichern
            • Ausschließlichkeit in Zeiträumen → Range-Typ + Exclude Constraint
  • Atomare Referenzzählung

    • Wenn wie bei Arc oder shared_ptr viele Threads denselben Zähler häufig ändern, leidet die Performance
  • Read-Write-Lock

    • Manche Implementierungen unterstützen kein Upgrade von einem Read Lock auf einen Write Lock
    • Der Versuch, bei gehaltenem Read Lock einen Write Lock zu erwerben, kann zu einem Deadlock führen

In vielen Sprachen üblich

  • Fehlende Null/None/nil-Prüfungen sind eine häufige Fehlerursache
  • Wird ein Container während einer Schleife verändert, kann es zu einem Data Race in einem Single-Thread-Kontext kommen
  • Fehler beim Teilen veränderlicher Daten: z. B. ist [[0] * 10] * 10 in Python keine korrekte Erzeugung eines 2D-Arrays
  • (low + high) / 2 kann zu Overflow führen → die sichere Variante ist low + (high - low) / 2
  • Kurzschlussauswertung (short circuit): Bei a() || b() wird b nicht ausgeführt, wenn a true ist; bei a() && b() wird b nicht ausgeführt, wenn a false ist
  • Der Standard eines Profilers umfasst oft nur CPU-Zeit → Wartezeiten wie z. B. auf die DB erscheinen nicht im Flamegraph und können zu Fehlinterpretationen führen
  • Regex-Dialekte unterscheiden sich je nach Sprache → ein Regex, das in JS funktioniert, muss in Java nicht funktionieren

Linux and bash

  • Nach einem Verzeichniswechsel zeigt pwd den ursprünglichen Pfad, der tatsächliche Pfad steht in pwd -P
  • cmd > file 2>&1 → stdout+stderr beide in die Datei, cmd 2>&1 > file → nur stdout in die Datei, stderr bleibt unverändert
  • Dateinamen sind groß-/kleinschreibungssensitiv (anders als unter Windows)
  • Für ausführbare Dateien gibt es ein Capability-System (prüfbar mit getcap)
  • Gefahr durch nicht gesetzte Variablen: Wenn DIR nicht gesetzt ist, kann rm -rf $DIR/ zu rm -rf / werden → vermeidbar mit set -u
  • Umgebung anwenden: Um ein Skript in der aktuellen Shell anzuwenden, source script.sh verwenden → für dauerhafte Anwendung in ~/.bashrc eintragen
  • Bash nutzt Command-Caching: Wird eine Datei innerhalb von $PATH verschoben, kann ENOENT auftreten → Cache mit hash -r aktualisieren
  • Werden Variablen ohne Anführungszeichen verwendet, werden Zeilenumbrüche als Leerzeichen behandelt
  • set -e: Beendet das Skript bei Fehlern sofort, funktioniert aber nicht innerhalb von Bedingungen (||, &&, if)
  • Konflikt zwischen K8s livenessProbe und Debugger: Ein Breakpoint-Debugger kann die gesamte App anhalten, wodurch Health Checks fehlschlagen → der Pod kann beendet werden

React

  • State direkt verändern im Rendering-Code
  • Hooks innerhalb von if/loop verwenden → Regelverstoß
  • Im Dependency-Array von useEffect notwendige Werte weglassen
  • In useEffect Clean-up-Code vergessen
  • Closure-Falle: Durch Capturing eines veralteten State entstehen Bugs
  • Daten an der falschen Stelle verändern → unreine Komponente
  • useCallback nicht verwenden → unnötige Re-Renders
  • Bei memoisierten Komponenten nicht memoisierten Werte übergeben → memo-Optimierung wird wirkungslos

Git

  • Rebase schreibt die Historie um

    • Nach einem Rebase führt ein normales Push zu Konflikten → es ist ein Force Push erforderlich
    • Wenn sich die Historie eines Remote-Branches geändert hat, sollte auch beim Pull --rebase verwendet werden
    • --force-with-lease kann in manchen Fällen verhindern, dass Commits anderer Entwickler überschrieben werden; wer aber nur fetch und nicht pull macht, ist dadurch nicht geschützt
  • Probleme mit dem Revert eines Merge

    • Ein Merge-Revert macht die Wirkung nicht vollständig rückgängig → wird derselbe Branch erneut gemergt, gibt es keine Änderung
    • Lösung: den Revert revertieren oder einen sauberen Weg wählen (backup → reset → cherry-pick → force push)
  • Hinweise zu GitHub

    • Selbst wenn ein Secret wie ein API-Key nach dem Commit per Force Push überschrieben wird, bleibt die Spur in GitHub erhalten
    • Wenn ein privates Repo B ein Fork des privaten Repo A ist und A später public wird, wird auch der Inhalt von B öffentlich (und kann selbst nach dem Löschen zugänglich bleiben)
  • git stash pop: Bei Konflikten wird der Stash nicht gedroppt

  • .DS_Store wird von macOS automatisch erzeugt → empfohlen wird **/.DS_Store in .gitignore

Networking

  • Manche Router und Firewalls trennen inaktive TCP-Verbindungen stillschweigend → dadurch können Connection Pools von HTTP-Clients und DB-Clients ungültig werden → Lösung: TCP keepalive konfigurieren
  • traceroute-Ergebnisse sind nur begrenzt zuverlässig → je nach Fall ist tcptraceroute nützlicher
  • TCP slow start kann zusätzliche Latenz verursachen → lässt sich durch Deaktivieren von tcp_slow_start_after_idle beheben
  • TCP-Sticky-Packet-Problem: Der Nagle-Algorithmus verzögert die Paketübertragung → lässt sich durch Aktivieren von TCP_NODELAY beheben
  • Bei Backends hinter Nginx muss Connection-Reuse konfiguriert werden → andernfalls können in Hochlastumgebungen Verbindungen wegen interner Portknappheit fehlschlagen
  • Nginx betreibt standardmäßig Packet Buffering → dadurch kann es bei SSE (EventSource) zu Verzögerungen kommen
  • Der HTTP-Standard verbietet keinen Body bei GET- und DELETE-Requests → manche nutzen einen Body, aber viele Libraries und Server unterstützen das nicht
  • Auf einer einzelnen IP lassen sich mehrere Websites hosten → unterschieden wird über den HTTP-Host-Header und SNI bei TLS → deshalb gibt es Websites, die nicht per bloßem IP-Zugriff erreichbar sind
  • CORS: Bei Requests von einer anderen Origin blockiert der Browser den Zugriff auf die Response → der Server muss den Header Access-Control-Allow-Origin setzen
    • Wenn auch Cookies übertragen werden sollen, sind zusätzliche Einstellungen nötig
    • Wenn Frontend und Backend dieselbe Domain und denselben Port verwenden, gibt es kein CORS-Problem

Other

  • YAML-Hinweise

    • YAML ist leerzeichenempfindlichkey:value ist fehlerhaft, key: value ist korrekt
    • Der Ländercode NO kann ohne Anführungszeichen als false interpretiert werden
    • Ein Git-Commit-Hash kann ohne Anführungszeichen in eine Zahl umgewandelt werden
  • Excel-CSV-Probleme

    • Excel führt beim Öffnen von CSV-Dateien automatische Umwandlungen durch
      • Datumsumwandlung: 1/2, 1-22-Jan
      • Ungenaue Umwandlung großer Zahlen: 1234567890123456789012345678901234500000
    • Die Ursache ist, dass Excel Zahlen intern als Floating Point verarbeitet
    • Durch dieses Problem wurde z. B. der Genname SEPT1 schon falsch verändert

Noch keine Kommentare.

Noch keine Kommentare.