Fallstricke, auf die Entwickler achten sollten
(qouteall.fun)- 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-widthist standardmäßigautomin-width: autowird durch die Größe des Inhalts bestimmt und hat Vorrang vorflex-shrink,overflow: hidden,width: 0undmax-width: 100%- Empfehlung:
min-width: 0explizit angeben
-
Unterschied zwischen horizontal und vertikal in CSS
width: autoversucht, den Platz des Elternelements auszufüllen,height: autorichtet sich nach dem Inhaltwidth: autobei inline-, inline-block- und float-Elementen erweitert sich nichtmargin: 0 autozentriert horizontal,margin: auto 0zentriert nicht vertikal (außer beiflex-direction: column, wo vertikale Zentrierung möglich ist)- Margin-Collapsing tritt nur vertikal auf
- Wenn sich mit
writing-mode: vertical-rlusw. die Layoutrichtung ändert, kehrt sich auch das Verhalten um
-
Block Formatting Context (BFC)
- Ein BFC kann mit
display: flow-rooterzeugt werden (auchoverflow: hidden/auto/scroll,display: tableusw. 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
borderoderpaddingtritt kein Margin-Collapsing auf
- Ein BFC kann mit
-
Stacking Context
- Bedingungen, die einen neuen Stacking Context erzeugen
- Rendering-Eigenschaften wie
transform,filter,perspective,mask,opacity position: fixedodersticky- gesetztes
z-index+ Positionierung mitabsolute/relative - gesetztes
z-index+ Elemente innerhalb von Flexbox/Grid isolation: isolate
- Rendering-Eigenschaften wie
- Eigenschaften
z-indexgilt nur innerhalb des jeweiligen Stacking Context- Die Koordinaten von
position: absolute/fixedbeziehen sich auf den nächstgelegenen positionierten Vorfahren stickyfunktioniert nicht über einen Stacking Context hinweg- Selbst
overflow: visiblewird durch den Stacking Context abgeschnitten background-attachment: fixedwird relativ zum Stacking Context positioniert
- Bedingungen, die einen neuen Stacking Context erzeugen
-
Viewport-Einheiten
- In mobilen Browsern ändert sich
100vh, wenn Adressleiste/Navigationsleiste beim Scrollen vom Bildschirm verschwinden - Aktuelle Lösung:
100dvhverwenden
- In mobilen Browsern ändert sich
-
Bezugsrahmen für Absolute Positioning
position: absolutebezieht sich nicht auf das Elternelement, sondern auf den nächstgelegenenrelative/absolute- oder Stacking-Context-Vorfahren
-
Blur-Verhalten
backdrop-filter: blurberücksichtigt keine umliegenden Elemente
-
Aufhebung von Float
- Wenn das Elternelement
flexodergridist, hatfloatbei Kindelementen keine Wirkung
- Wenn das Elternelement
-
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: inlineignoriertwidth,height,margin-topundmargin-bottom
-
Whitespace-Verarbeitung
- Standardmäßig werden Zeilenumbrüche in HTML als Leerzeichen behandelt, aufeinanderfolgende Leerzeichen werden auf eines reduziert
- `` verhindert die Reduzierung von Leerzeichen, hat aber besonderes Verhalten am Anfang und Ende
- Leerzeichen am Anfang/Ende von Inhalten werden meist ignoriert, `` 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-box→padding/bordersind nicht enthalten - Bei
width: 100%+ gesetztempaddingkann das Elternelement überschritten werden - Lösung:
box-sizing: border-box
- Standardwert ist
-
Cumulative Layout Shift
- Werden bei `` keine Attribute
widthundheightgesetzt, kann verzögertes Laden von Bildern zu Layout-Verschiebungen führen - Empfehlung: Attribute setzen, um CLS zu vermeiden
- Werden bei `` keine Attribute
-
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
console.log('')wird das erste `` als schließendes Tag erkannt - Siehe auch: Safe JSON in script tags
- In Fällen wie
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::stringhat 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
- Rust: Verwendet intern UTF-8 für Strings,
-
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 == NaNist immer false) NaN != NaNist immer true- Ergebnisse von Operationen mit NaN propagieren in den meisten Fällen ebenfalls zu NaN
- NaN ist mit keinem Wert gleich, auch nicht mit sich selbst (
-
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.stringifywandelt NaN und Inf innullum - Python
json.dumps(...)gibt NaN und Infinity unverändert aus (Verstoß gegen den Standard)- Mit der Option
allow_nan=Falsetritt bei NaN/Inf einValueErrorauf
- Mit der Option
- Golang
json.Marshalgibt bei vorhandenem NaN/Inf einen Fehler zurück
- JS
- Der JSON-Standard erlaubt NaN und Inf nicht
-
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)bis2^53 - 1 - Außerhalb dieses Bereichs ist die Integer-Darstellung ungenau
- Für große Integer wird
BigIntempfohlen - Wenn JSON Integer außerhalb des sicheren Bereichs enthält, kann das Ergebnis von
JSON.parseungenau sein - Zeitstempel in Millisekunden sind bis zum Jahr 287.396 sicher, bei Nanosekunden treten Probleme auf
- Der sichere Integer-Bereich ist
- Direkte Vergleiche von Gleitkommazahlen können fehlschlagen → empfohlen ist die Form
-
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.equalsverwendet werden- Wenn
equalsundhashcodenicht ü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
Listzurückgeben, liefern je nach Fall ein veränderbaresArrayListoder ein unveränderlichesCollections.emptyList(); beim Ändern des Letzteren trittUnsupportedOperationExceptionauf - Es gibt Fälle, in denen eine Methode, die
Optionalzurückgeben soll,nullzurückgibt (nicht empfohlen) - Wenn im
finally-Block ein return ausgeführt wird, werden Ausnahmen austryodercatchignoriert und der Rückgabewert ausfinallyverwendet - 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 unbemerktscheduleAtFixedRate-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; datoString()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 überschreibendeferwird beim Return der Funktion ausgeführt, nicht beim Ende eines Block-Scopesdefererfasst 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 vonc_str()ist dann riskant - Wird ein Container während der Iteration verändert, werden Iteratoren ungültig
std::removelöscht nicht wirklich, sondern ordnet Elemente nur um; zum Löschen isterasenö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 permemcpywird 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
memcpyoderstd::bit_castempfohlen
- Ausnahmen: 1) Typen in einer Vererbungsbeziehung 2) Umwandlung in
- 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 = nullfunktioniert nicht; stattdessen mussx is nullverwendet 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 distinctbehandelt wird, unterscheidet sich je nach DB count(x)undcount(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
utf8mb4verwendet, 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 byundselect-Spalten nichtdeterministische Ergebnisse - In SQLite ist der Feldtyp ohne
strictweitgehend 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
mysqldumpdie Option--single-transaction, wird ein vollständiger Read Lock auf die Tabelle gesetzt - In PostgreSQL verursachen
create unique indexoderalter table ... add foreign keyeinen vollständigen Read Lock auf die Tabelle- Vermeidung:
create unique index concurrentlyverwenden - Bei Foreign Keys die Methode
... not validund anschließendvalidate constraintverwenden
- Vermeidung:
-
Range-Abfragen
- Nicht überlappende Bereiche:
- Die einfache Bedingung
p >= start and p file 2>&1→ stdout+stderr beide in die Datei,cmd 2>&1 > file→ nur stdout in die Datei, stderr bleibt unverändert
- Die einfache Bedingung
- Nicht überlappende Bereiche:
-
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
DIRnicht gesetzt ist, kannrm -rf $DIR/zurm -rf /werden → vermeidbar mitset -u -
Umgebung anwenden: Um ein Skript in der aktuellen Shell anzuwenden,
source script.shverwenden → für dauerhafte Anwendung in~/.bashrceintragen -
Bash nutzt Command-Caching: Wird eine Datei innerhalb von
$PATHverschoben, kannENOENTauftreten → Cache mithash -raktualisieren -
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
useEffectnotwendige Werte weglassen - In
useEffectClean-up-Code vergessen - Closure-Falle: Durch Capturing eines veralteten State entstehen Bugs
- Daten an der falschen Stelle verändern → unreine Komponente
useCallbacknicht 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
--rebaseverwendet werden --force-with-leasekann 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_Storewird von macOS automatisch erzeugt → empfohlen wird**/.DS_Storein.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 isttcptraceroutenützlicher- TCP slow start kann zusätzliche Latenz verursachen → lässt sich durch Deaktivieren von
tcp_slow_start_after_idlebeheben - TCP-Sticky-Packet-Problem: Der Nagle-Algorithmus verzögert die Paketübertragung → lässt sich durch Aktivieren von
TCP_NODELAYbeheben - 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-Originsetzen- 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 leerzeichenempfindlich →
key:valueist fehlerhaft,key: valueist korrekt - Der Ländercode
NOkann ohne Anführungszeichen alsfalseinterpretiert werden - Ein Git-Commit-Hash kann ohne Anführungszeichen in eine Zahl umgewandelt werden
- YAML ist leerzeichenempfindlich →
-
Excel-CSV-Probleme
- Excel führt beim Öffnen von CSV-Dateien automatische Umwandlungen durch
- Datumsumwandlung:
1/2,1-2→2-Jan - Ungenaue Umwandlung großer Zahlen:
12345678901234567890→12345678901234500000
- Datumsumwandlung:
- Die Ursache ist, dass Excel Zahlen intern als Floating Point verarbeitet
- Durch dieses Problem wurde z. B. der Genname SEPT1 schon falsch verändert
- Excel führt beim Öffnen von CSV-Dateien automatische Umwandlungen durch
1 Kommentare
Hacker-News-Kommentar
Einige Router und Firewalls trennen gelegentlich stillschweigend inaktive TCP-Verbindungen, ohne der Anwendung irgendein Signal zu geben. Code, der TCP-Connection-Pools aufrechterhält, wie HTTP-Client-Bibliotheken oder Datenbank-Clients, erlebt dadurch das Problem, dass Verbindungen ohne jede Warnung ungültig werden. Um das zu beheben, kann man systemweites TCP Keep-Alive konfigurieren oder bei HTTP Header wie
Connection: keep-alive,Keep-Alive: timeout=30, max=1000verwenden. Sobald eine TCP-Verbindung einmal aufgebaut ist, bleibt in zwischengeschalteten Routern kein Zustand erhalten. Das Problem sind Firewalls oder NAT-Session-Timeouts. Dabei kommt auch kein RST-Paket an. In einer K8s-Umgebung hatte ich einmal das Problem, dass dieconntrack-Modulkonfiguration zu niedrig war. Selbst wenn man HTTP Keep-Alive verwendet, hilft das nur bei der Wiederverwendung von Verbindungen und hält nicht die Netzwerkverbindung selbst aufrecht (Erklärungslink). HTTP Keep-Alive erzeugt tatsächlich keine Pakete, sondern verzögert nur das Schließen. TCP Keep-Alive hingegen erzeugt regelmäßig Pakete und setzt damit den Timer zurück.Methoden, die
Optional<T>zurückgeben, könnennullzurückgeben. Diese Praxis ist viel zu verwirrend. Wenn ich emotional etwas gelassener wäre, hätte ich wohl ein JEP eingereicht, das eine Annotation wie@java.lang.NonNullReferenceeinführt. Wenn man mit dieser Annotation einen Typ deklariert, sollte der Compiler Zuweisungen vonnullals Fehler behandeln. Zum Beispiel könnteAlphanullzugewiesen bekommen, währendBetaeinen Fehler wirft. Ich habe das Gefühl, man müsste sich auch in die Spezifikation ansehen, wie Dead-Code-Elimination injavactatsächlich funktioniert. Zum Beispiel könnte inif (true)der Teilb = nullin der Praxis entfernt werden und rechtlich gesehen dennoch zulässiger Code sein.In Kotlin ist so etwas bereits ein Compilerfehler; eine Annotation braucht man dort gar nicht erst.
Ich frage mich, ob man in einer Sprache mit
nullüberhauptOptional<T>braucht. Wenn man wie in Python beim Rückgabewert einer Funktion ohnehin prüfen muss und statt eines Optional-Objekts einfachT | Noneverwendet, ist der Unterschied eines Frameworks nicht mehr besonders klar. Wenn man keinen speziellen monadischen Stil nutzt, bleibt die Prüfung letztlich dieselbe.Es hieß, Java, C# und JS würden In-Memory-Strings in einer Art UTF-16 kodieren, aber für Java stimmt das nicht. Für C# und JS könnte es ebenfalls nicht stimmen. Wenn der String-Typ einer Sprache hinreichend undurchsichtig ist, dann ist die In-Memory-Darstellung ein Implementierungsdetail. In Java ist das seit Version 9 ausdrücklich klar (zugehöriger JEP-Link). Das ist auch ein Grund, warum Änderungen an Implementierungsdetails bei vorhandener FFI schwierig sein können. Außerdem wird über Zahlen in JS gesagt, die größte exakt darstellbare Ganzzahl sei
2^53−1, aber tatsächlich lassen sich auch viel größere ganze Zahlen wie2^100exakt darstellen.2^53−1bedeutet, dassn-1,nundn+1in IEEE Double alle exakt darstellbar sind. Daher ergeben sowohln == n-1als auchn == n+1den Wert false.Bei C# ist die In-Memory-Darstellung sehr stark festgelegt. Es gibt viele Fälle, in denen man mit
ReadOnlySpan<char>oder rohenchar*direkt auf den Puffer zugreift, daher istcharein UTF-16-Codepoint-Typ. Bei JS lässt sich das vielleicht irgendwie umgehen.Statt von einer „max accurate integer“ würde ich lieber von einer „max safe integer“ sprechen.
(Zum Thema Base64-Kodierung:) Dass In-Memory-Strings in Java, C# und JS keine Art UTF-16 sind, mag technisch korrekt sein, aber wenn man in einer UTF-8-basierten Sprache einen String Base64-kodiert und ihn dann in Java dekodiert, gibt es Fälle, in denen durch Javas UTF-16-Darstellung Probleme entstehen.
Tipps oder Informationen im Handbuchstil scheinen vor allem das schneller verständlich zu machen, was man ohnehin schon weiß oder fast schon wusste. Die meisten Handbücher sind weniger fürs eigentliche Lernen geeignet als für Ordnung und Wiederholung; um völlig Unerfahrene etwas zu lehren, sind sie ineffizient.
Ich habe den Artikel „Traceroute Isn’t Real“ wirklich mit großem Interesse gelesen. Ich hatte schon lange den Eindruck, dass Traceroute-Daten oft sehr ungenau oder bedeutungslos wirken, und es war hilfreich zu verstehen, warum das so ist (Originallink). Falls jemand neuere Informationen dazu hat, würde ich mich freuen.
Dieser Text ist weniger eine Sammlung echter Fallstricke oder Fallen als vielmehr eine Liste kleiner Tipps, die der Autor aus Erfahrung gelernt hat. Vieles gilt nur in sehr engen, spezifischen Kontexten, aber dieser Kontext wird nicht klar benannt, und manches wirkt sogar schlicht falsch. Deshalb sollte man den gesamten Text nicht zu wörtlich nehmen, sondern eher als eine Art Gedankenstrom oder Notizsammlung lesen.
Die Sache damit, dass Standardargumentwerte in Python nicht bei jedem Aufruf neu erzeugt werden, sondern gespeicherte Werte sind, ist etwas, das man besonders bei
datetime-Variablen unbedingt wissen sollte.setzuweisen, aber dassetwurde wiederverwendet, was zu einem Bug führte. Es dauerte ziemlich lange, bis ich die Ursache verstanden hatte.Bei der ersten „Falle“ auf der Seite hieß es,
min-width: autobestimme die Mindestbreite anhand des Inhalts, aber außerhalb von Flex/Grid stimmt das eigentlich nicht. Laut MDN wirdautobeiblock,inline,tableusw. auf 0 korrigiert (offizieller Dokumentationslink).Die eigentliche erste Falle ist, dass man „keine CSS-Eigenschaft isoliert lesen kann“. Wie der Name cascading schon sagt, werden Standardwerte und die Ergebnisse mehrerer Regeln irgendwo miteinander kombiniert, daher ist der Kontext des gesamten Dokuments wichtig.
Die Cascade bei CSS-Texteigenschaften kann ich noch einigermaßen nachvollziehen. Aber CSS-Layout ist aus Sicht des Seitendesigners, des Implementierers und auch des Nutzers viel zu schwer zu verstehen. Ich kann mich nicht damit anfreunden, für wen dieses Design eigentlich gedacht sein soll.
Insgesamt ist das ein brauchbarer Listenartikel, ich habe aber ein paar Anmerkungen.
-0.0und+0.0(negatives und positives Null) werden bei Gleitkomma-Vergleichen als gleich behandelt, aber man kann sie unterscheiden, etwa über das Bitmuster oder anhand der Ergebnisse1.0/-0.0 = -Unendlichkeitund1.0/0.0 = +Unendlichkeit.(low + high) / 2wegen Overflow-Risikolow + (high - low) / 2zu verwenden, aber wennlowoderhighnegativ sein können, verlagert man den Overflow-Bereich möglicherweise nur. Das ist ein wichtiges Thema bei allgemeiner binärer Suche.rebasekönne die History verändern, aberrebaseist per Definition ein Command, das History umschreibt.Auch wenn Nutzer beider Sprachen begrifflich dasselbe Zeichen erkennen, sollte man das nicht einfach als bloße „Schriftartvariante“ abtun. Nur weil der Unicode-Codepoint gleich ist, heißt das nicht, dass eine Zeichenersetzung sicher ist. Aus Sicht japanischer Nutzer kann so eine Ersetzung ein Grund sein, ein Produkt nicht zu verwenden.
Zwar unterscheidet man im Englischen und Französischen kein anderes A, aber es gibt Fälle wie
А(kyrillisch) undA(lateinisch), die gleich aussehen und dennoch unterschiedliche Codepoints haben. Auch bei der Han-Unification werden oft Zeichen mit recht unterschiedlichen Formen zusammengefasst, sodass Lernende des Japanischen oder Chinesischen tatsächlich Verwirrung erleben können. Zum Beispiel sieht das Zeichen '喝' (drink) je nach Darstellung, wie in diesem Link, ziemlich unterschiedlich aus. Wenn man es kopiert, ändert sich die Form teilweise sogar unmittelbar, was zeigt, wie komplex die Verarbeitung ist. Han-Unification ist in der Praxis ein ziemlich kniffliges Thema.Es wurde ein feiner Unterschied zwischen numpy und pytorch erwähnt, aber ohne konkrete Beispiele ist das kaum nützlich und liefert zu wenig Information, um als realistische Falle zu wirken.