Stop met het maken van TUIs

Ik ben er de laatste tijd mee bezig mijn vrienden te overtuigen om native gebruikersinterfaces (UI) te bouwen. Een paar maanden geleden bouwde ik mijn eerste serieuze Mac-applicatie, en sindsdien heb ik meer native UI-dingen gebouwd dan in mijn hele carrière daarvoor. Laten we een korte tour doen.

Een tour door native interfaces

Dit is MDV.app, de beste Markdown-viewer ter wereld totdat iemand anders een serieuze markdown-viewer schrijft. Ik heb al veel over MDV geschreven en zal je niet vermoeien met meer pleidooien ervoor, maar het is geweldig.

Ik heb bijna geen hand gehad in het schrijven van deze UI-code. Waarom zou ik dat doen? Zoals de meeste gebruikersinterfaces vernieuwt MDV niets. Het is geen uitdagend probleem. Maar het bouwen van een goede UI is erg moeilijk: dit soort code is tedious, repetitief, nauwgezet en wordt beperkt door platformspecifieke conceptuele kennis. Het duurt jaren om goed te worden in dit soort werk. Daarom zou ik dit programma nooit handmatig schrijven. In plaats daarvan heb ik het 'opgeroepen' (via AI).

Verder gaan we:

Ik heb het afgelopen jaar Math Academy gevolgd, van Foundations I tot Machine Learning, wat je kunt inkorten tot "ik heb mezelf calculus geleerd". Ik hou veel van Math Academy, maar hier dient het slechts als opzet voor een andere SwiftUI-app die ik tot stand heb gebracht: een native calculator-stijl frontend voor SageMath, het standaard wiskundesysteem voor cryptografen.

Deze app doet drie belangrijke dingen voor me:

  • Het rendert Sage-output automatisch in LaTeX, wat handiger wordt naarmate je dieper in multivariable calculus duikt.
  • Het stelt Sage-methoden op objecten zoals vectoren, matrices en expressies beschikbaar via point-and-click (wat veel prettiger is dan herhaaldelijk trig_simplify typen).
  • Het biedt een "kleine taal" van shorthand-inputs die veelvoorkomende operaties (zoals "neem de gradiënt van deze expressie") snel maakbaar maakt. [1,2;3,4] is een matrix in dit systeem.

Ik breng deze applicatie niet uit. Als je hem wilt, maak dan een screenshot van dit gedeelte van het bericht en geef het aan Claude. Die bouwt wel iets nuttigs. Je ziet waar ik heen ga.

Dan is er DJ Roomba, mijn Apple Music-speler. De genre-map is een dubieuze functie. Wat niet dubieus is, is de ingebedde LLM-agent, die tool-calls heeft om mijn bibliotheek, mijn laatst gespeelde lijst en mijn komende tracks te lezen. "Ik ga naar de werkplaats in de kelder om een fotolijst te maken; geef me een no-skips playlist die bij de stemming past." Het blijkt dat de stemming "veel Kurt Vile en Tom Petty" is. Geen opmerkingen.

Het wordt ondersteund door een SQLite-database, een gezonde database met een redelijk schema, wat ook een verrassend nuttige functie was.

Ik weet niet echt wat ik van programma's als deze moet denken. Het is een AI-ondersteunde muziekspeler die 90% van de interface van Music.app bevat. Music.app is mijn eeuwige persoonlijke vijand in computing. Dit is het computing-equivalent van het slachten van een draak. Maar ik heb er geen enkele regel code in geschreven. Ontwikkel ik software, of configureer ik gewoon mijn computer?

Houd die gedachte vast.

Dit is mijn LLMwiki. Iemand zou een populair, breed gedeeld stuk moeten schrijven over hoe waardevol een zelfsturende wiki is, waarbij je bronmateriaal voert en vragen stelt, waarna de AI de wiki voor je schrijft. Een wild nuttig idee, ik ben blij dat ik eraan dacht.

Self Driving Wiki.app was leuk om te schrijven. In tegenstelling tot DJ Roomba, die direct een Responses API-client insluit, stuurt deze app onder de motorkap claude -p aan. Omdat ik ervan uitga dat agents beter werken met een bestandssysteem om in te graven, heb ik een macOS virtuele bestandssysteem-extensie opgeroepen, die een read-only weergave van de onderliggende SQLite-database reflecteert als een gemount bestandssysteem binnen de sandbox van de app.

Was dit waarschijnlijk onnodig? Maakt het de app vervelender om te installeren, bijvoorbeeld door hem om wat voor reden dan ook uit /Applications/ te moeten draaien? Ja, en ook ja. Maar dit soort 'yak-shaving' excursies waren de vreugde van softwareontwikkeling in het pre-LLM-tijdperk en ik ben blij dat ik ze vandaag de dag nog steeds kan ervaren.

Hier is iets wat ik constant gebruik: een semi-geautomatiseerde food macro tracker. De app is een eenvoudige agent die GPT5 aanstuurt, zeer korte maaltijdbeschrijvingen neemt (zoals "schat eens hoeveel calorieën ik heb binnen gekregen door cakebeslag en cream cheese frosting te proeven, maar ik heb geen cake gegeten") en deze vertaalt naar schattingen van de inname.

Hier is een menu-bar applicatie die temperaturen in mijn huis bijhoudt met goedkope kleine TP-Link temperatuursensoren die de Chinese Communistische Partij toegang geven tot mijn Apple TV. Normaal gesproken zou ik na het samenstellen van zoiets veel meer kunnen vertellen over de protocollen en HTTP API's die deze dingen gebruiken, maar ik heb geen enkel werk verzet om dat uit te zoeken. Alles wat ik kan vertellen is dat er twee verschillende inlogpaden zijn om informatie te krijgen: vanuit hun cloud en direct van de kleine sensor-pods.

Ten slotte, en spreekmakend over mijn Apple TV, presenteer ik de heilige graal van macOS native desktop softwareontwikkeling: een werkende menu-bar Apple TV afstandsbediening. Een paar jaar geleden zou ik hier heel veel geld voor hebben betaald, want ik ben precies het soort nerd dat een open MacBook op schoot heeft terwijl hij met zijn partner House Of Ninjas kijkt. (En voor mijn Roku TV en mijn Denon receiver, aangezien dit een universele afstandsbediening is).

Direct communiceren met een Apple TV is een hel. Maar het blijkt dat mensen dit al hadden uitgevogeld en Python-libraries hadden geschreven om dit te doen. Ik "gebruik" die libraries niet, omdat dit een native Swift-app is, maar dat maakt niet uit: alles wat in Python is geschreven, had net zo goed geïmplementeerd kunnen worden in Swift, C#, of Brainfuck. Het is allemaal hetzelfde voor een frontier-model.

Ik ben me enigszins bewust van de situatie. Opscheppen over een reeks SwiftUI-interfaces die ik heb gegenereerd, nodigt duidelijk uit tot klinische en meedogenloze kritiek op hun visuele ontwerp. Laat maar komen. Maar: als langdurig klant van de App Store claim ik dat deze ontwerpen allemaal een stap boven het gemiddelde niveau liggen. Vijf jaar geleden zou ik dolgelukkig zijn geweest als ik een macOS UI-persoon in mijn team had die output van deze kwaliteit leverde.

De waarheid is dat ik deze dingen nauwelijks als "apps" beschouw (ik ben niet van plan ze te distribueren). Het zijn artefacten van het feit dat ik mijn computer dingen voor me laat doen, op de manier waarop ik dat wil. Als Unix-nerd heb ik dit altijd kunnen doen, in de taal van de command line. Nu is het net zo gemakkelijk om dat soort werk te doen met grafische interfaces.

***

De paradox van de terminal

We bouwen terminal-interfaces omdat we dat moeten, niet omdat we dat zouden moeten willen.

Eerst een woord over CLI's en TUI's: Command-line interfaces (CLI) en Terminal User Interfaces (TUI) zijn beide producten uit de jaren 70, gevormd rond de beperkingen van teletype-interfaces en domme videoterminals. Beiden neigen ernaar verouderd, vijandig en beperkt te zijn ten opzichte van grafische interfaces. Maar deze tendensen zijn intrinsiek aan TUI's, en niet aan CLI's. CLI's hebben doelen waarvoor ze onvervangbaar zijn. Het bouwen van een CLI is bijna altijd een goed idee. Het bouwen van een TUI bijna nooit.

In 1999 schreef Neal Stephenson een essay over command line interfaces dat het veld van mens-computerinteractie ongeveer 20 jaar terugzette. Hierin stelt hij de priesterschap van Unix-nerds die CLI's hanteren voor als machtige Morlocks, die de hele computingindustrie op hun schouders dragen. De Eloi gebruiken GUI's zoals Microsoft Word. Omdat dit hoogwaardige fan-service is, is "In The Beginning Was The Command Line" een van de heilige teksten van ons vakgebied geworden, ondanks dat er 25 jaar later erg weinig van overeind blijft.

In werkelijkheid bestaan terminal-interfaces niet vanwege enige speciale "machine sympathy" die ze creëren tussen computers en hun operators. TUI's bestaan in plaats daarvan om slechts twee redenen: modems, en het feit dat Unix-nerds geen Motif wilden leren.

Ik kan ze niet kwalijk nemen. Ik moest in het midden van de jaren 90 een klein beetje Motif-werk doen en dat heeft me 29 jaar lang afgeschrikt van UI-ontwikkeling. Curses is niet spectaculair, maar je kunt het binnen 5 minuten leren. Ik maak een grapje niet: je zou vandaag niet voor rauwe curses kiezen voor een TUI, maar vraag ChatGPT om een korte samenvatting (zonder tijd te verspillen aan het uitleggen van concepten) van het absolute minimum dat je nodig hebt om pico te schrijven. Neem de code die hij geeft en compileer het; het werkt. Het is duidelijk waar je heen moet. Er zit gewoon niet veel aan.

Een agent kan betrouwbaar een native macOS-interface bouwen die redelijk is, simpelweg door de SwiftUI-frameworks te gebruiken op de manier die Apple voorschrijft. Dit is een verschil tussen native applicaties en web-interfaces: eentonigheid is hier een goed ding; native apps horen eruit te zien als andere native apps.

Maar er is een probleem met TUI's: zelfs met een goed framework, zoals Ratatui, Textual of Bubbletea, vecht je tegen de terminal om asymptotisch dicht te komen bij wat elk native framework uit de doos goed doet. Scrollen en scroll-doelen zijn een duidelijk voorbeeld. Drag-and-drop is een ander. Tekstselectie wordt lastig wanneer je in-band signalering gebruikt om venstergrenzen te tekenen! Meerdere zwevende vensters. En dit alles nog voordat we bij afbeeldingsverwerking komen.

Je kunt een uur besteden en een redelijke versie krijgen van veel standaardbedieningen in een TUI-framework: een datumkiezer, een beveiligd tekstveld, een voortgangsbalk, een teksteditor. Maar de meeste zullen niet zo goed zijn als de systeemversies van dezelfde widgets, en ze zullen niet goed samenwerken zonder nog meer werk.

Al deze zaken werken simpelweg direct uit de doos in native UI.

Weerlegging van veelgebruikte TUI-argumenten

Je staat waarschijnlijk op het punt om me in onomstotelijke termen uit te leggen waarom we in 2046 allemaal TUI's zullen gebruiken en waarderen. Laat me een paar van je argumenten anticiperen.

Argument 1: TUIs zijn economische en snelle interfaces met een hoge informatiedichtheid. Nerds houden niet alleen van ze vanwege hun retro-esthetiek; ze waarderen dat ze complexe taken in seconden kunnen uitvoeren met slechts een paar toetsaanslagen.

Dit zijn allemaal ware uitspraken, maar om dat argument overtuigend te maken, zou ik die alinea moeten beginnen met het woord "alleen", en als ik dat deed, zou ik liegen. Grafische interfaces zijn vaak niet economisch, compact of keyboard-gericht. Maar dat komt meestal omdat ze niet voor nerds zijn ontworpen. Niets houdt je tegen om een compacte en economische GUI te ontwerpen. Het is al gedaan!

Voor mij zijn deze TUI-voordelen juist een krachtig argument om meer grafisch werk te doen, omdat het makkelijk en goedkoop is geworden om hiermee te experimenteren. Ik wil graag een native UI zien die alles vastlegt wat geweldig is aan Magit of Lazygit (zonder dat ik het zelf hoef te bouwen).

Argument 2: TUIs werken over SSH-verbindingen. Als je een gebruikersinterface op productie (prod) nodig hebt, wordt dat een TUI. Het probleem met dit argument is dat je waarschijnlijk geen gebruikersinterface op prod nodig hebt. Je hebt een command-line interface op prod nodig die door een gebruikersinterface op je MacBook kan worden aangestuurd. Iedereen die ooit iets met bpftrace heeft gedaan, zou dit in zijn vezels moeten voelen. Gelukkig is hier een precedent voor: kijk naar Emacs TRAMP, dat SSH-verbindingen efficiënt verbergt en een native (en grafische) editor-ervaring biedt voor externe bestanden, die zelfs werkt met LSP's en Magit.

Argument 3: Mensen zullen zeggen dat TUI's toegankelijk zijn. Het probleem met dit argument is dat het waarschijnlijk onjuist is. Ik ben geen gebruiker van toegankelijkheidsfuncties, maar ik baseer me op de ervaringen van mensen die a11y-werk doen. Denk aan sprekers die beschrijven hoe schermlezers alle regel-voor-regel updates van TUI-"chrome" lezen: hash-teken, hash-teken, hash-teken, dash, dash. Dat klinkt slecht.

Moderne native UI-frameworks zijn vanaf het begin ontworpen om toegankelijkheid goed aan te pakken. SwiftUI houdt twee UI-bomen bij: een visuele en een semantische toegankelijkheidsboom. Er zijn TUI-frameworks die bewonderenswaardig proberen dit goed te doen, maar toegankelijkheid is geen reden om TUI's boven GUI's te verkiezen.

Argument 4: TUI's zijn cross-platform. Ik kan een agent native UI voor me bouwen op Windows en Linux, en ik ben er zeker van dat ik tot iets redelijks kom. Maar ik heb geen Windows- of Linux-desktops om die interfaces op te testen. Er is een belangrijk onderscheid tussen vibe-coding en vibe-shipping. Iemand zal binnenkort een app shipen die hij letterlijk niet heeft bekeken of gebruikt. Maar dat zal ik niet zijn.

Ondertussen, als ik een TUI bouw, kan ik er redelijk zeker van zijn dat Linux-gebruikers dezelfde ervaring krijgen als ik. Dat is niet niets. Maar onthoud: ik bouw geen applicaties voor anderen. Ik bouw ze voor mezelf. TUI-beperkingen zijn een veel te grote prijs om te betalen om Linux-gebruikers van programma's te bedienen die ik niet eens wil publiceren.

Een paar jaar geleden zouden deze argumenten absurd zijn geweest. Niet omdat TUI's goed waren, maar omdat native UI geen redelijke vraag was. Als bewijs daarvan: we hebben een groot deel van het laatste decennium geleefd met Electron-apps. Dat kwam omdat native UI moeilijk goed te doen was. Maar dat is niet meer zo, en we zouden het vaker moeten doen.

***

Hoe je begint met native ontwikkeling

Ik kan alleen spreken voor macOS-ontwikkeling, maar ik ga ervan uit dat GTK 4 in Linux en WinUI 3 in Windows vergelijkbaar eenvoudig zijn. Als ik je interesse heb gewekt: er is niet veel nodig om een redelijke native macOS-app te maken.

Wat ik deed was zoeken naar vaardigheden: ik heb een macOS-design skill, een basis typografie skill en Paul Hudsons SwiftUI skill gebruikt. Ook heb ik de Swift-taal skill van Airbnb gebruikt, omdat ik er nog steeds om geef of de gegenereerde code idiomatisch is.

Zorg ervoor dat je "computer-use" (of hoe Codex het ook noemt) hebt ingeschakeld. Je wilt dit kunnen starten, lunch gaan maken, en terugkomen bij een app die goed genoeg werkt om prettig te debuggen. Dat werkt veel beter wanneer de agent de app kan zien en besturen.

Mijn grootste winst in levenskwaliteit is dat ik nooit Xcode hoef te openen. Gelukkig heeft mijn vriend Josh een puur Makefile-gestuurd buildproces gebouwd. Ik heb Claude dit gewoon naar elk nieuw project gekopieerd.

In feite is dat nu mijn volledige proces: ik kopieer een template app-directory, open Claude of Codex daarin, en vertel hem wat ik wil bouwen. Ik gebruik een vergelijkbaar proces om TUI-apps te bouwen (vertel je agent om tmux te gebruiken om de TUI te testen, dat werkt uitstekend). Maar het is me niet duidelijk of ik ooit nog een TUI wil bouwen.

***

Conclusie

Frontend-programmeurs, backend-programmeurs, luister naar mij. Ik kom niet om de TUI's te begraven, maar om jullie te smeken te stoppen met het bouwen van nieuwe.

Ik geef het meteen toe: ik heb nooit echt van TUI's gehouden. In de jaren 90 was ik een Mutt-persoon (na Elm en voor Pine) — tot het moment dat ik daarmee kon stoppen en een grafische mail-reader kon gebruiken.

Maar het interessante hier is niet of je van terminal-interfaces houdt of niet. Ik merk simpelweg iets op dat volgens mij nog niet is doorgedrongen: na decennia waarin softwareontwikkeling werd verdeeld in "frontend" en "backend", en frontend verder in "web" en "native", hebben agents die grenzen grotendeels opgeheven. Je kunt nu standaard kiezen voor het bouwen van native gebruikersinterfaces, en die interfaces zullen redelijk goed zijn.

Als jij, net als ik, decennia lang hebt gedacht dat je een systems-programmeur bent die geen UI-code produceert, of erger nog, dat je positie in de industrie is om UI-code te produceren waarbij vensters worden getekend uit ASCII-tekens, dan is het tijd om te hercalibreren.

Het is één ding om geen interesse te hebben in de gebruikersinterface, of zelfs een goede UI te verafschuwen ten gunste van vreemde esthetiek uit de jaren 70. Maar als je het type Unix-Morlock bent die stiekem een Eloi-sympathisant was, en interfaces zoals NetNewsWire, Transmit, Little Snitch en Audio Hijack waardeerde: stop en luister naar me. Als je niet hebt geprobeerd om een van je 500 wegwerpbare CLI's om te zetten in een native app, doe je jezelf tekort. Ga een native UI bouwen. Het zal waarschijnlijk je manier van denken veranderen.