{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "DevCore.net-Blog",
  "language": "de",
  "home_page_url": "https://devcore.net/",
  "feed_url": "https://devcore.net/feed.json",
  "description": "Endgültige Antwort zu KI, Cyberspace und Informatik",
  "author": {
    "name": "Roman Hirsch",
    "url": "https://devcore.net/"
  },
  "items": [
    {
      "id": "https://devcore.net/posts/mysql-daten-komprimieren/",
      "url": "https://devcore.net/posts/mysql-daten-komprimieren/",
      "title": "Speicher sparen mit COMPRESS() und UNCOMPRESS()",
      "content_text": "Große Log-Dateien fressen Speicherkontingent? COMPRESS() ist dein Freund! -- Speichern (komprimieren) INSERT INTO logs (content) VALUES (COMPRESS('großer text hier...')); -- Auslesen (dekomprimieren) SELECT UNCOMPRESS(content) FROM logs WHERE id = 1; Die Magie: zlib-Komprimierung reduziert Textdaten auf 20-30% der ursprünglichen Größe. Idealfall: Logs, alte Artikel, Backup-Metadaten. Achtung: Die CPU-Kosten für Komprimierung/Dekomprimierung lohnen sich vor allem bei größeren Datenmengen – bei kleinen Texten überwiegt der Overhead!",
      "date_published": "2026-01-12T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/json-in-mysql/",
      "url": "https://devcore.net/posts/json-in-mysql/",
      "title": "JSON direkt in MySQL: Flexibilität trifft Datenbank",
      "content_text": "MySQL hat Superkräfte mit JSON! Statt mühsame Normalisierung brauchst du nur: -- Speichern INSERT INTO users (profile) VALUES ('{\"name\":\"John\",\"age\":30}'); -- Abfragen SELECT profile->>'$.name' AS name FROM users; -- Suchen SELECT JSON_SEARCH(profile, 'one', 'John') FROM users; -- Aktualisieren UPDATE users SET profile = JSON_SET(profile, '$.age', 31) WHERE id = 1; Vorteile: Kein Schema-Overhead, direkter Zugriff auf verschachtelte Daten, perfekt für halbstrukturierte Daten. Tipp: Indexiere JSON-Pfade mit GENERATED COLUMNS für bessere Performance! Hinweis zu MariaDB ⚠️ Achtung: Die moderne JSON-Syntax (-&gt; und -&gt;&gt;) funktioniert in MariaDB noch nicht. Verwende stattdessen JSON_VALUE() für einen ähnlichen Effekt: -- MariaDB: statt ->> SELECT JSON_VALUE(profile, '$.name') AS name FROM users; JSON_VALUE() ist zukunftssicher und wird auch in neueren MySQL-Versionen unterstützt.",
      "date_published": "2026-01-19T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/array-formulare/",
      "url": "https://devcore.net/posts/array-formulare/",
      "title": "Formularverarbeitung mit Array-Namen vereinfachen",
      "content_text": "Komplizierte Formularverarbeitung? Nutze HTML-Arrays! &lt;!-- HTML --> &lt;input name=\"user[name]\"> &lt;input name=\"user[email]\"> &lt;input name=\"product[sku][]\"> &lt;input name=\"product[sku][]\"> // PHP - automatisch strukturiert! $_POST['user']['name'] // \"John\" $_POST['user']['email'] // \"john@test.de\" $_POST['product']['sku'][0] // \"SKU123\" $_POST['product']['sku'][1] // \"SKU456\" Vorteil: Automatische Strukturierung, kein manuelles Parsing, weniger Code. Gold-Regel: Immer $_POST validieren bevor du es nutzt!",
      "date_published": "2026-01-26T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/if-reihenfolge/",
      "url": "https://devcore.net/posts/if-reihenfolge/",
      "title": "If-Bedingungen optimieren: Richtige Reihenfolge spart Zeit",
      "content_text": "Die Idee: Wenn du mehrere Bedingungen mit || kombiniertst, stoppt PHP sobald eine wahr ist (Short-Circuit-Evaluation). Ordne deine Checks strategisch: // ❌ Schlecht: Teure DB-Abfrage zuerst if ($this->expensiveDbQuery() || $variable === '123') { } // ✅ Gut: Schnelle Variablenprüfung zuerst if ($variable === '123' || $this->expensiveDbQuery()) { } Erspart dir eine ganze DB-Abfrage, wenn die erste Bedingung passt. Mit &amp;&amp; funktioniert es genauso – auch hier sollten billige Checks zuerst kommen. Faustregel: Billige Operationen zuerst, teure Operationen zuletzt – das gilt für beide || und &amp;&amp;. So einfach ist Leistungsoptimierung!",
      "date_published": "2026-02-02T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/webp-bildformat/",
      "url": "https://devcore.net/posts/webp-bildformat/",
      "title": "WebP: Das unterschätzte Bildformat",
      "content_text": "Das Problem: WebP spart ~30% Bandbreite gegenüber JPEG, findet aber wenig Anwendung. Warum nicht mehr Websites WebP nutzen: Unwissenheit – Viele kennen WebP gar nicht Kompatibilität-Angst – &quot;Was wenn alte Browser nicht unterstützen?&quot; (Fallback ist einfach!) Workflow-Trägheit – Bestehendes Tooling müsste angepasst werden Wahrnehmung – Mythos: PNG/JPEG hätten bessere Qualität (stimmt nicht!) &lt;!-- So easy: Fallback für alte Browser --> &lt;picture> &lt;source srcset=\"image.webp\" type=\"image/webp\"> &lt;img src=\"image.jpg\" alt=\"Fallback\"> &lt;/picture> Browser-Support: 97%+ der modernen Browser. Kein Grund mehr zu warten! Meine Faustregel: WebP für neue Projekte, schrittweise Migration für bestehende.",
      "date_published": "2026-02-09T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/user-agent-debugging/",
      "url": "https://devcore.net/posts/user-agent-debugging/",
      "title": "User-Agent-Debugging mit geheimem Key",
      "content_text": "Wenn du im Frontend schnell debuggen willst, nutze einen geheimen Hash im User-Agent. Nur wenn der Hash stimmt, gibt das Backend Debug-Infos aus (z. B. Timing, Cache-Hit/Miss, interne Steps). $ua = $_SERVER['HTTP_USER_AGENT'] ?? ''; $token = $_ENV['UA_DEBUG_TOKEN'] ?? ''; $debug = $token !== '' &amp;&amp; str_contains($ua, 'DevCoreDebug/' . $token); if ($debug) { header('X-Debug-Info: ' . json_encode(['dbMs' => 42, 'cache' => 'MISS'])); } Warum gut: Du erzeugst keinen Debug-Noise für normale User, siehst direkt im echten Frontend, was passiert, und kannst alles ohne extra UI-Flag aktivieren. Wichtig: Das ist kein Security-Feature, sondern nur ein Debug-Schalter; gib keine sensiblen Daten aus und wechsle den Token regelmäßig.",
      "date_published": "2026-02-16T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/eleventy/",
      "url": "https://devcore.net/posts/eleventy/",
      "title": "Eleventy: schlankes SSG bei voller Kontrolle",
      "content_text": "Eleventy ist das perfekte SSG, wenn du mit Markdown, Nunjucks oder HTML schreiben willst und dir der Build nicht im Weg stehen soll. Du legst ein paar Markdown-Dateien, packst deine Assets daneben und lässt Eleventy rendern. Layouts oder Includes kannst du dazuschalten, aber sie sind optional der ganze Ablauf bleibt minimal. Probiere es in 2 Schritten aus: echo \"Hello World\" > index.md npx @11ty/eleventy",
      "date_published": "2026-02-23T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/honey-pot-formular/",
      "url": "https://devcore.net/posts/honey-pot-formular/",
      "title": "Honey Pot im Formular: Spam mit einem Feld vermeiden",
      "content_text": "Spam-Formulare kommen häufig automatisch zustande. Ein zusätzliches Feld, das Menschen nicht sehen (und Bots trotzdem ausfüllen), filtert gefühlt 98 % der Einsendungen, weil du die Verarbeitung sofort abbrichst, sobald das Feld Inhalt hat. &lt;input type=\"text\" name=\"unused\" aria-hidden=\"true\" autocomplete=\"off\" tabindex=\"-1\" /> [name=\"unused\"] { position: absolute; left: -9999px; } Serverseitig reicht ein einfacher Check: läuft da was rein? Dann verwirfst du den Eintrag und sparst dir die komplexen „I’m not a robot“-Checkboxen, das JavaScript und externe APIs.",
      "date_published": "2026-03-01T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/guard-clauses/",
      "url": "https://devcore.net/posts/guard-clauses/",
      "title": "Guard Clauses: Weniger Verschachtelung, klarere Logik",
      "content_text": "Die Idee: Prüfe Ausnahmefälle zuerst und verlasse die Funktion sofort. So bleibt alles sauber. // ❌ Tief verschachtelt function createInvoice(?User $user, array $items) { if ($user) { if ($user->isActive()) { if ($items) { return Invoice::fromItems($user, $items); } } } return null; } // ✅ Guard Clauses function createInvoice(?User $user, array $items) { if (!$user) { return null; } if (!$user->isActive()) { return null; } if (!$items) { return null; } return Invoice::fromItems($user, $items); } Vorteil: Weniger Einrückung, schneller erfassbar, leichter zu testen.",
      "date_published": "2026-03-05T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/nested-css/",
      "url": "https://devcore.net/posts/nested-css/",
      "title": "Nested CSS: So benutzt du es",
      "content_text": "Nested CSS nutzt du direkt im Eltern-Block mit &amp; für States, Klassen und Elemente. .card { padding: 1rem; border: 1px solid var(--border); &amp; h2 { margin: 0 0 0.5rem; } &amp;:hover { border-color: var(--accent); } &amp;.is-featured { background: var(--surface-highlight); } @media (min-width: 48rem) { padding: 1.5rem; } } Damit bleiben Elemente, Hover-State und Responsive-Anpassung direkt an der Komponente. In manchen Fällen wird damit SCSS für genau solche Verschachtelungen obsolet.",
      "date_published": "2026-03-08T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/virtual-columns/",
      "url": "https://devcore.net/posts/virtual-columns/",
      "title": "VIRTUAL Columns in MySQL: Berechnete Spalten ohne Speicher",
      "content_text": "Statt berechnete Werte im Code vorzubereiten oder redundant in der DB zu speichern, übernimmt MariaDB/MySQL das selbst: -- Nachträglich zu einer bestehenden Tabelle hinzufügen ALTER TABLE orders ADD COLUMN gross DECIMAL(10,2) AS (net * (1 + tax_rate)) VIRTUAL; VIRTUAL bedeutet: kein eigener Speicherplatz – der Wert wird beim Lesen berechnet. Die Alternative STORED schreibt ihn physisch in die Tabelle. Vorteil: Kein Trigger, kein App-Code, keine Synchronisations-Fehler – die Spalte ist immer korrekt. Index: Nutzt du die VIRTUAL Column in einer WHERE-Bedingung, lohnt sich ein Index darauf – sonst muss MariaDB/MySQL den Ausdruck für jede Zeile im Scan berechnen: ALTER TABLE orders ADD INDEX idx_gross (gross); Der Unterschied ist dramatisch: Abfragen auf großen Tabellen fallen damit von mehreren Sekunden auf wenige Millisekunden – bei mir von 4 Sekunden auf 80 ms. Verwendest du die Spalte hingegen nur im SELECT, ist kein Index nötig: Der Ausdruck wird erst nach dem Filtern berechnet, also nur für die Zeilen, die bereits alle anderen Bedingungen passiert haben.",
      "date_published": "2026-03-12T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/generatoren/",
      "url": "https://devcore.net/posts/generatoren/",
      "title": "Große Datenmengen in PHP: Speicher sparen mit Generatoren",
      "content_text": "Statt erst ein riesiges Array aufzubauen, kannst du Werte mit yield einzeln erzeugen und direkt weiterverarbeiten. function userIds(PDO $db): Generator { $stmt = $db->query('SELECT id FROM users'); while (($id = $stmt->fetchColumn()) !== false) { yield (int) $id; } } foreach (userIds($db) as $id) { processUser($id); } Ohne Generatoren landet oft alles zuerst in einem Array, etwa per fetchAll() oder durch manuelles Sammeln. Das kostet bei vielen Datensätzen schnell unnötig viel RAM. Vorteile: Weniger Speicherverbrauch, schnellerer Start der Verarbeitung, sauberere Trennung zwischen Datenquelle und Verarbeitung. Wichtig: Generatoren sind ideal für sequentielle Verarbeitung. Wenn du alle Werte mehrfach brauchst oder zufällig darauf zugreifen willst, ist ein echtes Array oft immer noch die richtige Wahl.",
      "date_published": "2026-03-16T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/server-timings/",
      "url": "https://devcore.net/posts/server-timings/",
      "title": "Server-Timing: Performance-Daten direkt in den DevTools",
      "content_text": "Mit dem Server-Timing HTTP-Header verschickst du Performance-Metriken direkt an den Browser. Diese tauchen sofort im DevTools unter Network → Timings auf. Format: Server-Timing: db;dur=123;desc=&quot;Query&quot; In PHP: $start = microtime(true); // ... Datenbankabfrage oder andere Operation ... $duration = (microtime(true) - $start) * 1000; // Dauer header(\"Server-Timing: db;dur=$duration;desc=\\\"Database\\\"\", true); Live Demo: https://server-timing-hono.deno.dev/ – öffne DevTools, schau in Network → Timing",
      "date_published": "2026-03-20T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/early-hints/",
      "url": "https://devcore.net/posts/early-hints/",
      "title": "Early Hints: Kritische Assets vor der eigentlichen Antwort laden",
      "content_text": "103 Early Hints ist ein HTTP-Status, mit dem der Server dem Browser schon vor der eigentlichen Response wichtige Hinweise schicken kann, z. B. welche CSS- oder Font-Dateien direkt geladen werden sollen. HTTP/1.1 103 Early Hints Link: &lt;/assets/css/main.css>; rel=preload; as=style Link: &lt;/assets/fonts/ibm-plex-sans.woff2>; rel=preload; as=font; type=\"font/woff2\"; crossorigin HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Wo hilft das? Vor allem bei SSR, langsamen Datenbankabfragen oder generell hohem TTFB. Der Browser kann kritische Assets schon anfordern, während das Backend noch an der finalen HTML-Antwort arbeitet. Wichtig: Early Hints bringt vor allem etwas für Assets, die du sehr sicher brauchst. Für wechselnde oder unklare Ressourcen ist der Effekt gering oder du preloadest unnötig.",
      "date_published": "2026-03-25T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/ipv6/",
      "url": "https://devcore.net/posts/ipv6/",
      "title": "IPv6: Warum die Zukunft damit nur einfacher werden kann",
      "content_text": "IPv6 wird oft nur auf mehr Adressen reduziert. Der eigentliche Gewinn kommt aber erst dann, wenn immer mehr Netze nativ umsteigen: weniger NAT, weniger Port-Forwarding, weniger CGNAT und insgesamt weniger historische Workarounds. Dadurch werden Netze und Software einfacher. Endpunkte sind wieder direkter erreichbar, die Planung wird sauberer und selbst im Protokoll fällt Ballast weg, weil IPv6 keine Header-Prüfsumme mehr hat, die Router bei jedem Hop neu berechnen müssen. IPv6 ist nicht automatisch schneller oder sicherer, aber deutlich aufgeräumter. Je mehr umsteigen, desto mehr verschwinden Sonderfälle und desto einfacher wird Infrastruktur langfristig. Viele Mobilfunknetze zeigen schon heute, dass IPv6-first in der Praxis längst funktioniert.",
      "date_published": "2026-04-01T00:00:00Z"
    }
    ,
    {
      "id": "https://devcore.net/posts/tmpfs-cache/",
      "url": "https://devcore.net/posts/tmpfs-cache/",
      "title": "TMPFS auf ~/.cache: Mehr wert als man zuerst denkt",
      "content_text": "~/.cache auf tmpfs zu legen ist auf Desktop-Systemen oft überraschend nützlich. Genau dort landen Browser-Cache, Thumbnails, Build-Reste und anderer Kram, der nach einem Neustart meist nicht wirklich fehlt. Gerade Browser schreiben permanent kleine Dateien. Allein dadurch kommen viele unnötige Schreibzugriffe zusammen. Wenn ~/.cache im RAM liegt, ist das schneller erledigt und die SSD wird nicht dauernd mit Wegwerfdateien beschäftigt. tmpfs /home/USERNAME/.cache tmpfs rw,nosuid,nodev,noatime,uid=1000,gid=1000,mode=700 0 0 Pfad, uid und gid musst du an dein System anpassen. Natürlich ist tmpfs nicht gratis: Der Platz kommt aus dem RAM und nach einem Neustart ist der Cache weg. Aber genau das ist hier meistens eher ein Vorteil als ein Nachteil. Meine Faustregel: Wenn genug RAM da ist, lohnt sich tmpfs auf ~/.cache fast immer. Schon allein wegen der Browserdateien.",
      "date_published": "2026-04-12T00:00:00Z"
    }
    
  ]
}
