skip to content
dz

Daniel Zenzes

marijkeluttekes.dev

Frontend ist kein Backend

HTML und CSS kann jeder irgendwie zusammenschustern, und genau deshalb sieht das Internet aus, wie es aussieht. Marijke Luttekes beschreibt den Unterschied gut: Ein Backend folgt Logik, ein Frontend folgt "kommt drauf an". Daten korrekt einzusammeln und abzulegen ist messbar und testbar. Dieselben Daten so auszuspielen, dass ein Mensch sie versteht und da findet, wo er sie sucht, hängt an vielen Faktoren wie Psychologie, Barrierefreiheit, Sprache und dreihundert Displaygrößen. Ein kaputtes Backend wirft Fehler.

Ein kaputtes Frontend sieht gut aus und funktioniert trotzdem nicht.

1 min read

Wer Omarchy bezahlt

Ein Nachtrag zu meinem Post 1Password finanziert Omarchy. Letzte Woche ging es mir um ein Tool, das ich seit Jahren nutze und für das ich wirklich gerne gezahlt habe. Jetzt bin ich eher neugierig, wer da noch alles mitmischt.

Fairerweise muss man sagen, dass die Omacom Foundation hier jeden Namen und jeden Betrag selbst offenlegt: Zwölf Gründungspatrons mit je einer Million Dollar. Vier weitere mit je hunderttausend. Firmengeld kommt bisher von zwei Seiten, 1Password und 37signals, je hunderttausend Dollar im Jahr über drei Jahre. Dazu Anfang September Token-Zusagen von Meta, Anthropic, OpenAI und Fireworks: Rechenzeit, kein Geld. Und seit dieser Woche kann sich jeder beteiligen.

Die Foundation beziffert das Ganze aktuell auf knapp fünfzehn Millionen Dollar, aufgebracht von einer kleinen Gruppe. Bei 37signals ist es im Grunde DHHs Geld. Bei 1Password finanzieren es die Kundenabos.

Genauso interessant wie die Summe ist, wohin sie fließt. Die Foundation ist exklusiver Sponsor von Hyprland, Hauptsponsor von Quickshell und mise und hat gerade einen Kernel-Entwickler fest angestellt. Diese Projekte haben eigene Nutzer und mit Omarchy sonst nichts zu tun. Wer mise benutzt, um seine Toolchain zu verwalten, hat sich für mise entschieden, nicht für die Omacom Foundation. Über den Umweg Omarchy redet sie jetzt trotzdem mit.

Die Foundation führt ihre Geldgeber zusätzlich auf einer eigenen Seite, oligarchy.fyi. Der Seitentitel lautet schlicht „Oligarchy“, die Beschreibung „Elite capital. Public code.“ Darunter läuft eine Zeile, die alle paar Sekunden umspringt: mal „Redistributing billionaire wealth, one ISO at a time.“, mal „An operating system with patrons, not customers.“, mal „Zero dollars. Several billionaires.“

Ist das ein Modell für Open-Source-Finanzierung? Für mich nicht. Es bringt schnell echtes Geld, aber es macht einen kleinen Kreis sehr reicher Leute zu der Instanz, die entscheidet, welche freie Software gefördert wird. Dass die Foundation das selbst oligarchy.fyi nennt, macht es nicht besser.

andadinosaur.com

Litterbox

Litterbox ist eine Safari-Erweiterung für iOS und macOS, kostenlos, ohne Abo, ohne Tracking. Trifft man auf einen Link zu X, zeigt die Erweiterung ein kleines Zeichen an und öffnet den Post auf Klick in einem Popup. Dafür nutzt sie dieselbe Embed-API, mit der X seine Einbettungen auf fremden Seiten ausliefert, und schickt dabei keine Cookies mit.

Für mich ist genau das der Punkt. Ich will ab und zu einen verlinkten Tweet lesen und dafür weder eingeloggt sein noch x.com meine Aufmerksamkeit und meine Daten geben. Nitter und xcancel haben das jahrelang geleistet und sich Ende August dem Druck von X gebeugt.

Bleibt die Frage, wie lange sich so eine App im App Store hält. Der Entwickler rechnet selbst damit, dass X die Embed-API abklemmen könnte. Bis dahin nutze ich Litterbox fleißig.

via Daring Fireball

thoughtbot.com

Is AI ruining my brain?

Früher war es die schnelle Suche bei Google, heute der Assistent, der auf alles eine Antwort weiß. Nur muss ich jetzt nicht mehr mehrere Seiten lesen oder meine Suche mehrfach anpassen. Nutzer erhalten eine plausibel wirkende Antwort in Sekunden. Da kann man Sally Hall nicht vorwerfen, dass sie beim Stricken plötzlich zu ChatGPT greifen will.

testdouble.com

Functionally Zen

Kyle Adams hat sieben Regeln für einfacheren Code aufgeschrieben, hergeleitet aus dem Zen of Python. Besonders eine Geschichte daraus: Er sollte für eine Medizin-App eine Dosisberechnung implementieren und wollte das als Funktion lösen. Ein Kollege wies ihn darauf hin, dass im zugrundeliegenden Lehrbuch längst Tabellen mit den gesuchten Werten standen, weil Ärzte früher ja auch nicht selbst gerechnet haben. Am Ende war es ein Dictionary-Zugriff statt eines Funktionsaufrufs, und damit gab es auch keine eigene Logik mehr, die man hätte testen müssen. Ich freue mich immer, wenn ich solche Details sehe und meinen Code dadurch einfacher machen kann.

Der Artikel dreht sich um Python, aber Adams begründet das zum Schluss mit JavaScript. Guido van Rossum hielt funktionale Primitive 2013 noch für zu unlesbar, heute gehören sie für viele zum Alltag.

1 min read

Eleventy: Markup statt Shortcode

Seit Juni 2022 nutze ich @11ty/eleventy-img für diesen Blog und habe es bisher immer nur brav aktualisiert, aber nie in die Doku geblickt. Mein Shortcode von damals, grob aus der damaligen Doku kopiert, hatte acht Argumente: Quelle, Alt, Klassen, Breiten, Formate, sizes.

async function imageshortcode(
	src,
	alt,
	className = undefined,
	imgClassName = undefined,
	widths = [400, 800, 1280],
	formats = ['webp', 'jpeg'],
	sizes = '100vw',
	includeOriginal = true
) {

Und baute daraus von Hand das passende <picture>/<source>-HTML zusammen:

const picture = `<picture ${pictureAttributes}>
	${sourceHtmlString}
	${imgHtmlString}
</picture>`;

Im Template sah der Aufruf dann so aus:

{% image "src/blog/bild.png", "Beschreibung", "", "" %}

Das aktuelle Plugin macht das überflüssig. Ein addPlugin, mehr ist nicht notwendig:

eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
	widths: [400, 800, 1280],
	formats: ['webp', 'jpeg', 'svg'],
	svgShortCircuit: true
});

Beim Build transformiert das Plugin jedes <img> im Output automatisch, inklusive loading="lazy" und decoding="async". Meine Blog-Bilder wurden zu normalem Markdown, mit normalen relativen Pfaden:

![Prototype Chain](prototype-1.svg)

Den Shortcode samt Helfer habe ich gelöscht. Artikel zu schreiben oder mal ein Bild einzubauen wird wesentlich einfacher.

Beim Umstieg ist mir bei ein paar Bildern aufgefallen, was der alte Shortcode nebenbei falsch gemacht hat. Er rasterisierte auch SVGs. Aus drei Diagramm-SVGs in meinem Post zu Prototypen in JavaScript und TypeScript wurden zwölf PNG/WebP-Versionen. Mit svgShortCircuit: true werden SVGs jetzt unverändert durchgereicht, und bei diesen Bildern macht das den Unterschied zwischen 2,8 MB und 236 KB. Kein Effekt über die ganze Seite, aber weniger Daten, die Besucher laden müssen.

Wer nur alle <img>-Elemente im bestehenden Code automatisch optimieren will: Der Code oben reicht schon, ganz ohne Shortcode oder Umschreiben bestehender Templates. Details zu weiteren Optionen findet ihr in der Doku.

brennan.day

Normalisierter Faschismus in Open Source

Brennan Kenneth Brown zieht die Linie, die ich gestern bewusst eng gezogen habe, konsequent weiter - von DHH über Ladybird bis Brave. Sein Kernpunkt, in einem Satz:

"Apolitical" has never meant a lack of politics. It's meant politics that current power doesn't have to defend.

Zwölf Millionäre, die genau wissen, wofür DHH öffentlich steht, haben trotzdem eine Million Dollar pro Kopf unterschrieben. Lest den ganzen Text. Er ist unbequemer als meiner. Das ist Absicht.

pnpm.io

pnpm 12 setzt auf Rust

Für mich bleibt pnpm die Paketverwaltung der Wahl im JavaScript-Ökosystem. Schon vorher war es deutlich schneller als die Konkurrenz, und dieser Umbau unter der Haube kann sicher nicht schaden.

Ich bin selbst ganz frisch auf der neuen Version unterwegs. Der Wechsel erfordert momentan auch noch einen manuellen Schritt. Gefühlt ist pnpm aber nochmal schneller geworden.

Das Turborepo-Projekt misst eine Verbesserung der Installationszeiten von 64 bis 90 Prozent unter Linux im Vergleich zu pnpm 10.28 - heise hat die Zahlen zusammengefasst.

Ich komme aus der 11er-Linie und habe deshalb selbst nachgemessen, auf einem MacBook Air mit M1: Eine Installation mit gelöschtem node_modules und gefülltem Store dauert unter pnpm 11.25.0 2,37 Sekunden und unter 12.1.0 nur noch 0,79 - rund dreimal so schnell. Ein Lauf, bei dem es nichts zu tun gibt, braucht statt 0,41 nur 0,06 Sekunden. Median aus je fünf Durchläufen mit --frozen-lockfile, beide Versionen auf demselben Store.

blog.stephaniestimac.com

On AI in coding

"But is the code correct?" He asked. And this, dear reader, is where the hard truth hit me. Jhey looked at the ChatGPT output. It had gifted me 5 lines of completely unnecessary code, and another bit was "fine" but not the most efficient way to write JavaScript. He made a few edits for me and left me to continue on with my CSS overhaul. -- The Web Witch's Blog

A few weeks ago, it took my colleague and me hours to find all the bugs that AI introduced into an application simply because someone had written code in a language and framework they were unfamiliar with.

I often use AI for development tasks, and it can be very useful - for example, when you need to apply similar changes to multiple files or when you want to improve your code style ("Tell me how this code can be written in a more readable way..."). However, AI can also produce a mess when you use it for something with which you have no experience. It's like working with a a new colleague who can be brilliant at times but would rather say something than admit that they can’t solve a problem. If AI only supports you on a topic you are familiar with, it will improve your speed and perhaps even the quality of your work. Maybe you can even learn how to improve the structure of your code or write that one specific test. If you have no experience with the topic you're working on, it can produce bugs and poor code; in the end, just copying and pasting code you don't understand won't make you a better programmer.

via Stephanie Stimac

1 min read

TIL: One file to rule them all: PEP-723 and uv

It's impressive what’s possible with Python nowadays! PEP-723 introduces a way to define metadata directly inside a Python file — including dependencies.

"This PEP specifies a metadata format that can be embedded in single-file Python scripts to assist launchers, IDEs and other external tools which may need to interact with such scripts."
PEP 723 – Inline script metadata

uv takes this a step further by handling virtual environments and dependencies seamlessly when executing such scripts.

For example, if you want to spin up a Flask server in one file, it looks like this:

# /// script
# requires-python = ">=3.12"
# dependencies = [
#   "flask",
# ]
# ///
from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return "Hello, World! 🚀"

if __name__ == "__main__":
    app.run(debug=True)

Save this file as server.py and run it with:

uv run server.py

Within seconds, the server is up and running. This makes it easy to execute Python scripts with external dependencies — without worrying about setting up a virtual environment manually.

Even better, you can make it a standalone executable script by adding this shebang at the top:

#!/usr/bin/env -S uv run --script

Now, the script will be executed using uv whenever it’s run (just ensure it's executable with chmod +x).

This approach offers a useful way to define and run Python scripts while handling dependencies — all within a single file.

Thanks to Rob Allen for writing about PEP-723 and how to use uv as a shebang line.

1 min read

Angular Migrations

In my current Angular projects, I strive to keep our growing application up-to-date with the latest stable features that Angular offers. The official migrations have been instrumental in achieving this. While some manual adjustments were necessary post-migration, the majority of my code transitioned smoothly.

Some migrations I highly recommend include:

  • inject() Functions: Migrates your application to use inject() for dependency injection.

  • Signal Inputs Migration: Converts existing @Input fields to the new signal-based input() API.

  • Signal Outputs Migration: Converts existing @Output fields to the new signal-based output() API.

  • Lazy-loaded Routes Migration: Converts eagerly loaded component routes to lazy-loaded ones.

I believe that offering migrations like these is incredibly helpful. Slowly but surely, Angular and I are becoming friends after all.

2 min read

New Hardware and Software in January

In January, I began adjusting some of my long-standing software and hardware habits.

🖥️ From iTerm2 to Ghostty

I had been using iTerm2 for years, and it consistently met my needs. Although they introduced some AI features, these were quickly made optional, and overall, I can still recommend the tool. Recently, I started exploring Ghostty, a terminal emulator developed by Mitchell Hashimoto. While it's still under development—e.g., settings must be edited in a file, though this is expected to change—it operates efficiently and integrates well with macOS. After configuring it, I decided to make it my new default terminal.

🤖 Monarch as a Spotlight Alternativ

For system searches and launching applications, I relied on Spotlight and never felt the need for more advanced tools like Alfred. However, after reading a recent post by Alexander Olma mentioning Monarch, I decided to give it a try. While I'm still evaluating it as my default launcher, I appreciate its enhanced capabilities, particularly the seamless initiation of web searches and integration with applications like Reminders. This experience has prompted me to explore alternatives beyond Spotlight.

🔎 Switching from Google to Kagi

Last year, I transitioned most of my email communication from Google to Fastmail, using iCloud for personal correspondence. The next step was to find an alternative search engine, leading me to Kagi. Although it requires a subscription fee, similar to Fastmail, I value my privacy and prefer not to exchange my data for free services. Kagi's integration with Safari is functional, and the search results have been satisfactory, making it a viable option for the foreseeable future.

⌨️ Adopting Logitech's MX Keys Mini

At my desk, I've decided to change my keyboard setup. While I still appreciate my NuPhy mechanical keyboard, its noise level isn't suitable for the office environment. I previously used Apple's Magic Keyboard but found myself favoring Logitech's MX Keys Mini, which I also use with my gaming PC. Seeking a quiet keyboard with a US layout, I chose Logitech's model as my new office standard.

🖱️ Experimenting with the MX Master Mouse

Having used a touchpad for years, I decided to experiment with a mouse to assess any potential benefits. Last week, I connected my MX Master to my Mac. While I'm not entirely certain about replacing my Magic Trackpad, I appreciate the touchpad's gestures for tasks like switching between screens or windows. I plan to spend more time adapting to the alternatives offered by the MX Master before making a final decision.