Gus Continues to Work on Acorn

Flying Meat’s Gus Mueller on the life of an independent developer in reaction to Apple acquiring Pixelmator: But today I woke up, and got to work on Acorn. And I’ll do the same tomorrow and the day after that. I enjoy what I work on and I plan on doing it for many years to come. And I truly value my independence. I love being able to work on what I want, and when I want to.

Continue reading …

Org-Mode Emphasis Keymap with Mnemonics

In Emacs Org-Mode, the default key binding to “highlight” or “format” the selection is C-c C-x C-f. This will then ask for the org-mode syntax thingie to use, i.e. */_~=+. Literally, that’s the prompt. So you have to know which character to use to embolden text. That’s *. But which one is code? It’s ~. And = is for verbatim text, while + is for strike-through.

Continue reading …

Swift Concurrency Provides Compile-Time Feedback for Runtime Behavior

If you struggle with Swift 6 and Swift Concurrency (and who doesn’t), this may brighten your mood a bit: Matt Massicotte published a proper introduction.

My personal highlight is this:

[W]e can just play around with our types, their APIs and structure, and the compiler will give us feedback about their concurrent behaviors. You can often get considerable amounts of work done without even needing to run the code! That gives you a really fast feedback loop.

The ability to iterate on a design’s runtime behavior this way is cool.

I believe I, too, felt this effect when playing around with actor isolation. But Matt really nailed expressing what this means.

It’s compiler feedback for implicit assumptions we made in the past. We don’t need to test parts of concurrent behavior if we learn to wield this tool.

Well, this is the vision.

The reality in the past year(s) and the current discussion is dominated by expressing frustrations because it’s hard to understand. It would’ve been hard before, too, but now we can’t gloss over things like NSImage being inherently async when passing actor boundaries anymore because the compiler won’t let us. And some first party API’s aren’t even properly or fully ported to Swift concurrency support, yet. And documentation is sparse.

But I do share Matt’s excitement that vision and reality will eventually conflate, and we’ll be better off then.

Pi-hole on Unraid (as Local DNS to Access NAS Services Without a Roundtrip to Cloudflare)

Teaser image

I’m accessing my Nextcloud, Linkding, Calibre e-book server, and other “cloud” services hosted on the NAS in the other room via their online domain and a Cloudflare tunnel. That means traffic essentially needs to be routed from my Mac, through Cloudflares servers online, and then back to the NAS. With that, what could be network file transfers actually take forever with my Telekom DSL.

Continue reading …

Percent-Encode HTML Form Values so That Spaces Become ‘%20’ Instead of ‘+’

I had this great idea, using URL Schemes on macOS apps, assembled by very simple HTML files that contain a <form> only and produce a GET request so that the data is part of the URL: To my dismay, I discovered that all browsers encode spaces in input and textarea elements as plusses: +. Turns out that’s valid and expected.

Continue reading …

Global Day of Code Retreat 2024 Retrospective

Whenever I can, I participate in our local software craftspeople’s Global Day of Code Retreat (GDCR) in November. Yesterday was this year’s event. It was the first time I remember where I haven’t taken away something new for myself as a programmer. I learned much more about people. My mind has been occupiec with a lot of things in recent months, most of which were about our newborn baby. For me, having a child changed all priorities: the baby comes first.

Continue reading …

Running Unsigned Applications on macOS Sequoia

Sarah Reichelt (@troz@mastodon.social) published a short guide on how app permissions on macOS Sequoia work with unsigned apps, and how you can run them anyway.

The context menu trick doesn’t seem to work anymore, and you need to go to System Settings, it seems. (I’m not yet on Sequioa.)

TL;DR: You can still run unsigned apps, but it’s a bit more difficult. After trying once, you have to go to System Settings → Privacy & Security, scroll to the end and click Open Anyway for that app.

Composition Over Inheritance in NSViews

I find myself looking at an NSView subclass that actually doesn’t do much. It’s an opaque container for a text field that sets a label text. “Opaque” inasmuch as its outward appearance is being view, hiding the actual component’s complexity inside. This is just one example of an oft-repeated pattern: delegate to sub-views, using view composition instead of inheritance. This reduces the public API quite a bit by virtue of its opaque nature.

Continue reading …

Alex Ozun: Type-Driven Design with Swift (SwiftCraft 2024)

Type-Driven Design with Swift by Alex Ozun from this year’s SwiftCraft is a recommended watch.

Alex covers concepts like replacing the notion of validation user input (with true/false results to represent its validity) with the notion of parsing – transforming unprocessed values into processed ones that uphold certain guarantees, like matching a string pattern. For example for email addresses.

The biggest idea tying all of the things Alex covers together is iteratively using Swift’s strong type system to sketch and then build a domain that ensures certain classes of mistakes are impossible to make. Because if you would try to do them, the compiler would complain.

I also put into my Zettelkasten a couple of concepts that didn’t have a home before, like

  • Black hole arguments to express requirements in types;
  • the idea that only compilation errors prevent faults in production;
  • “Type, Define, Refine” flow to give iterative type-writing a name;
  • that we can achieve type unions in Swift via enums;
  • the idea of “Parse, Don’t Validate”.

Checklists Appreciated Under Stress

Recently, our family grew by +1, and we got our lovely daughter back home for a couple of days. The experience in the hospital or clinic surrounding the birthing process before, during, and after made me realize that If you read life hacks and productivity tips including checklists, you’ll know the adage that “if it’s good enough for plane pilots, it’s good enough for you” or something like that. Over the past couple of weeks, I found that checklists would have been super useful in many situations around giving birth to a child. We did have a checklist with items to pack before heading to the hospital. But that was it.

Continue reading …

Typed Filters and callAsFunction

Swift is full of syntactic sugar. One particular taste of sweet is the callAsFunction feature. If a type has a method of that name, you can call an instance or value of that type like a function. That’s used in SwiftUI to pass actions around in the environment, for example. Quick demo: See how the call looks like there’s a function updateWidgets(newerThan:) but actually it’s calling the value itself?

Continue reading …

Fairphone Fairbuds Are a Great Idea (Only)

I wanted to write something positive about the Fairphone Fairbuds. Here it is: They are a great idea. That’s it. Please move on. Continue reading for gory details, but this really sums it up: Replaceable batteries at the cost of a larger form factor is a tradeoff I am absolutely willing to make and advocate for. I hope more companies try this in our greener future.

Continue reading …

Expecting a Child

In the not-too-distant future of late summer 2024, we’ll be expecting our first child. This is your opportunity to share with someone willing to listen what you usually have to bash into other people’s heads: What heartfelt wisdom do you have to share? Is there anything you wish you knew when you had your first child?

Continue reading …

Create Journal Note For a Previous Day in denote.el

Some days I forget to run Denote to create a new journal file for the day, and then the appropriately named note file is missing when I want to write down things later. That’s not how you use a daily journal, I know, but I use Emacs and denote.el to write down things like exercise logs or when I get sick, and these are information I can backfill easily the day after.

Continue reading …

MacMenuBar – Directory of Hundreds of Menu Bar Apps

Giles Turnbull shared a link today to a site I didn’t know:

https://macmenubar.com

It’s a directory of 950+ menu bar apps for macOS. I browsed it a bit, and while each page is a bit short (5 items per page), it’s great to discover new tools – and also check out UI design trends in menu bar apps.

For example, I’m surprised that there are still so many NSPopover style windows with the speech-bubble pointy thing (because almost all apps I use don’t use popovers anymore). At the same time, there are many apps with what looks like custom NSMenus to embed more complex views as menu items.

The Rake and Its Prongs

Teaser image

When you type in a text editor, you always type out of some range. When your insertion point or cursor is blinking at the end of a word you just typed, you expect to still be “in touch” with the word, and that the next key you press will for example add a character to that word. This is a useful deception for us human users. It’s not actually part of the technological underpinnings.

Continue reading …

If You Use KOMA-Script, Really Do Use KOMA-Script

KOMA-Script is Omakase. If you trust the package, you’re in good hands to get consistent output from compiling LaTeX documents. I’ve been using Markus Kohm’s KOMA-Script for most of my life with LaTeX in some way or another because the package’s document classes really nail typical German typesetting requirements, e.g. requirements of DIN letter formats (yes, there is a standard for layout and typesetting of letters!). And the scrbook document class ships with tasteful defaults for book typesetting.

Continue reading …

Declarative Text Kit: Word Ranges

Teaser image

I figured out a way to consistently change a NSRange, e.g. of a selection of text or the insertion point in a text view, to select surrounding words in DeclarativeTextKit. But first off: Dear heavens! This wasn’t easy. I’m still not happy with the solution. While there are three to four hundred test cases (the vast majority is generated) that helped me narrow things down, I can tell you up front that I’m not proud of the resulting 160 lines of code.

Continue reading …

Hide macOS Menu Bar Icons (Bartender Alternatives)

Marco (@esamecar@social.lol) posted a list of alternatives. From that list, I filtered out MAS-only and Chinese-subtitled apps: I’m running Ice at the moment. You can organize menu bar icons into “always hidden” and just “hidden”. The latter will reveal itself when you e.g. click on the menu bar, the former won’t by default. You can bind shortcuts to show either or both of these groups.

Continue reading …

Declarative Text Kit: Token-Based Adapters

I’ve now finished adding an example adapter to get a structural representation of a Markdown code block to my app. It bridges the abstract syntax tree (or “token tree”) of libMultiMarkdown to NSTextStorage-compatible UTF-16 substring ranges – which DeclarativeTextKit works with, reducing code size and potential for errors even further:

Continue reading …

Declarative Text Kit: Expression and Evaluation

Teaser image

In DeclarativeTextKit, I found the abstraction of an “expression” in my vocabulary to represent the Domain-Specific Language’s instructions useful. Here is an example of a valid block of changes: This uses two kinds of Swift Result Builder to define the DSL’s grammar: The rules of the grammar are essentially this:

Continue reading …

Swift Package: FastSpring In-App Purchase

The recent release of TableFlip v1.6 is the first one that includes a new in-app purchase (IAP) component I assembled for my projects. It’s used in TableFlip to purchase a lifetime license within the app.

With future releases, the package will support in-app purchases of consumables or individual features, too.

Find package source code here:
https://github.com/CleanCocoa/FastSpringStore

The Swift Package Index listing:
https://swiftpackageindex.com/CleanCocoa/FastSpringStore

To use this in your app, all you need is:

  • A FastSpring account with the modern backend that everyone gets. (If you are still on “Classic”, you’ll know.)
  • Create an Embedded Storefront to display a very minimal shopping UI on a HTML page. Put this on your website or another trusted source: You will have to tell FastSpring that the form is legit with a domain-based allow-list, so you should really own the source.
  • Include the package in your app and point to the URL of your self-hosted embedded storefront.
  • Bonus: if you use my Trial and Licensing package, you can quickly unlock the app after a purchase has been made. The IAP component notifies your app on success.

With that in place, you can display a dedicated purchase window inside your app that doesn’t require a large context switch to the browser to make a sale:

TableFlip’s dedicated purchase window

The setup is quite short. I use a dedicated service object:

class PurchaseLicense {
    let store: FastSpringStore

    init() {
        self.store = FastSpringStore(
            storeURL: storeURL,
            purchaseCallback: { store, purchases in
                // Could have multiple purchased items, e.g. if you
                // offer in-app purchases of bundled features.
                assert(purchases.count == 1)
                guard let purchase = purchases.first else { return }

                for license in purchase.licenses {
                    // Unlock via license.licenseName & license.licenseCode, e.g.
                    // using the https://github.com/CleanCocoa/TrialLicensing package:
                    //
                    //   TrialLicensing.AppLicensing.register(
                    //       name: license.licenseName,
                    //       licenseCode: license.licenseCode
                    //   )
                }
            })
    }

    func showStore() {
        // Localize and customize the window title:
        store.showStore(title: "Purchase MyApp")
    }
}

I introduced this feature to my apps because its predecessor was a popular choice to purchase a license among WordCounter users. There, it is being picked for about 50% of license sales in total.

It appears that if the option exists, it will be used. I can’t tell whether having this option actually increases sales or not, though.

Declarative Text Kit: Inserting Strings and Lines With a Result Builder

Teaser image

There’s been progress on the Declarative Text Kit API idea, and today I want to share an insight into building a DSL with Swift Result Builders. A detail that I didn’t grok until I built it. {{TOC}} Inserting text into a string, text view, or other kind of text buffer is simple enough: you need a location and then use the appropriate API to put a string into the target there.

Continue reading …

It’s Easier With Meaning

It is easier to close Threads if you have a great book waiting for you.

It is easier to press pause on Spotify if you can play the piano.

It is easier to avoid Uber Eats if you know how to cook.

It can be hard, but it’s easier if you have something meaningful to do.


This is almost verbatom from iA’s “No Thanks”. I merely rearranged the sentences to highlight the beauty.

Use and Then Reduce Open Source Dependencies

Teaser image

Use open source liberally to make progress. Avoid open source dependencies in the long run if you can. Start a project by ingesting open source libraries to make progress fast and see if your product works. That’s fine. If it’s not too much, you can leave them in. But when the product matures, and if you offer a library yourself, you may benefit from reducing dependencies to ease product maintenance. Pick what you really need:

Continue reading …

Zettelkasten (Not) Needed?

As the saying goes, if the title of a post is a question, the answer is “no”. I don’t know how you would sensibly apply that to this one 🙂 Most of the days, for most of the time, I’m a software developer. I code, I plan, I think and learn. At other times, I’m writing things: on this blog, for book manuscripts, as letters and email; to plan, to help, to teach and to share.

Continue reading …

Dynamic Actor Isolation Can Help During the Transitional Phase

Matt Massicotte:

Making just one type @MainActor can result in cascade of errors at all usage sites where the compiler now cannot provide that MainActor guarantee. This virality can make it really hard to incrementally adopt concurrency with targeted changes. Perhaps that’s not too big a deal for smaller code bases/teams, but I bet this is a killer for big projects. So what do you do?

You make use of dynamic isolation to contain the spread!

Instead of throwing (static) type annotations around, you can ease into the adoption of actor isolation with (dynamic) preconditions and running blocks of structured and unscructured concurrent code.

Niki Tonsky: Hardest Problem in Computer Science: Centering Things

Niki Tonski with a very well-illustrated post on centering text, icons, and UI elements.

The problem is explored in great detail. Every big company fails at this. Type (font) design and UI design and icon design are all part of the problem.

After the build-up, this part killed me:

What can be done: icons fonts

STOP.

USING.

FONTS.

FOR.

ICONS.

I recommend looking at the pictures to spot all the annoying alignment problems and have a good time with this.

Always Be Changing Existing Code

Why change perfectly servicable code today when there are problems to solve? “I’d be changing it again next week. So where’s the value? Might as well keep it as-is.” When you are inclined to change code without defects, this could indicate a new understanding that needs expressing. Changing existing code to reflect a new understanding is all we have. This is how we pay off debt in our design.

Continue reading …

Enable SwiftUI Button Click-Through for Inactive Windows on macOS

On macOS, there’s 1 active window that receives your key input. Then there’s all the other windows, which are potentially invisible or obstructed by other windows. These inactive windows can be brought to the front and made active with a click. Then you can interact with these windows like normal. With inactive but visible windows, you cannot select items from lists, for example. The UI reflects this with a greyed-out or dimmed representation. You need to click once to activate the window (on the surface of the window, so to speak), then another time to interact with the control.

Continue reading …

“Soulslike”

Programming is a Soulslike. Dark Souls is notoriously difficult. You need to memorize enemy movements and patterns to get good at the game. You cannot beat it casually. The “Git Gud” meme traces back to this whole ordeal: You need to become a better player, learn the movements and patterns, in order to beat the game.

Continue reading …

Masterclass of Decoupling: Diablo II Resurrected

Decoupling is hard work, especially when taken to extremes – as the team of Diablo II did when they decoupled the whole rendering stack of the original game from the rest of the engine to reuse both independently. Today I learned that Diablo II Resurrected is a true remaster: new 3D graphics, but the engine hasn’t changed. In an interview with Eurogamer, Rob Gallerani pointed out that

Continue reading …

Negate KeyPath Values with not()

Swift KeyPath is a great shortcut for property-based mapping and filtering of collections: When you need a simple transformation, the simplest probably being the boolean negation operator, you only have two choices: So either you use the key path and separate the negation – which makes it harder to read as “I want the opposite of X”. Or you drop the key path and use a regular closure.

Continue reading …

Disable XeLaTeX Character Sequence Mappings for Inverted Question Mark and Inverted Exclamation Mark

I spend a couple of hours investigating the XeLaTeX purgatory where character mapping live. I didn’t know what these were before, too, don’t worry. I’ll walk you through it. The observable behavior is the following. Let’s say you start with Markdown with “dumb” quotes like this: … and use a conversion tool like Pandoc or MultiMarkdown to turn it into LaTeX, and you pick German quotation marks (the non-guillemet ones). You’ll see why it’s important for this example to use the German quotation marks. They are different from the curly quotes you know from English texts.

Continue reading …

You Absolutely (Do Not) Need to Comment Your Code

Of course you don’t need comments in your code. But your future self appreciates explanations: What is this nested loop good for? What is its purpose? Comments provide context, and shortcuts for understanding: “you don’t need to read this, just think of it as …” Once you explain what the purpose is, suddenly you may also find a way to express the intent clearly in code.

Continue reading …

Oh, You’re Making Apps, So You Are Working for Apple/Google/…?

Octavi Navarro reports that (some) people think (some of) his games should be free instead of paid: I’ve got hundreds of “this game should be free” angry reviews over the years but I find it shockinge every time. These are not evil corporation executives, but consumers (most probably underpaid workers themselves) who advocate very vocally against remunerated work.

Continue reading …

How to Disallow GPTBot Crawling in robots.txt

To tell OpenAI’s web crawler to skip your site, add these lines to your robots.txt (see docs): (via Hidde de Vries) The outlook is bleak: There’s no way to win this if you don’t want to be scraped at all, ever, except by not putting things online. If they don’t scrape your content, they scrape the copycat sites as Rik Schennink pointed out. Or ignore the robots.txt rule. (How could you tell, anyway?)

Continue reading …

Developer Voices on Property-Based Testing Made Me Realize PBT’s Value

I listened to “Automate Your Way to Better Code: Advanced Property Testing (with Oskar Wickström)” and I believe that Property-Based Testing (PBT) clicked for me a bit now. Maybe. It never made sense to me before, but Oskar Wickström has a lot of actually interesting examples.

My highlights are instances where you have to think outside the box, like a good puzzle:

  • You cannot describe complex actions on random data directly (like cutting gaps from audio tracks); but you can offer inverse actions, like undo operations, and then essentially test that applying an action, undoing it, redoing it, then undoing it again doesn’t change the result.
  • Testing a search function, you can’t actually test the search (without implementing the search functionality inside the tests again) because you don’t know the test data. But you can test that filtering the search results works, because filtering should product subsets of the unfiltered search.
  • You can describe web apps as state machines with valid transitions and then go ballistics with trying all kinds of interactions. That’s the promise of Quickstrom: You don’t need to specify each state of the web page as an example, but you specify the properties of each valid state and then ensure that no combination of interactions and button presses produces an invalid state. (Relying on app introspection, this probably works much better on the web with headless browsers than in Xcode/on mobile.)

None of this sounds like a replacement for what unit tests would do. But they do sound like a much better high-level approach to regression testing!

If nothing else, I’m intrigued to learn more about this now.

Can absolutely recommend this episode.

Actually, I recommend the whole podacst.

Portable Every-Day-Carry Paper Kanban

I found this among my notes from 2013, and think it’s a fun little tool for analog productivity – the portable Kanban board! It’s a foldable personal Kanban board, suitable as an Every Day Carry in either A3 or A4 size (or US Letter or whatever). This produces four quadrants and the folded size is ideal to stuff it into a backpack, book, or maybe even your pants. Thus, it’s convenient to transport to university, school, or work.

Continue reading …

Splitting Large Tasks is not a Mathematical Process

Teaser image

Here’s an anecdote for you: Imagine a dev team that performs task estimates expressed in “story points”, Agile style, and encounters a large estimate. Large, in this team, means “13 or more.” Then in one of these sessions, a specific task initially received an estimation of 13 story points. This marks the team’s threshold for considering the division of tasks into more manageable pieces by convention.

Continue reading …

SwiftUI Field Guide

Chris Eidhof and team launched the SwiftUI Field Guide website today.

I noticed that Chris fiddled with JavaScript animations and layout representations to mimick SwiftUI as close as possible and wondered what kind of e-book could be upcoming, but it turns out it’s a website!

Change the alignment or the alignment guide offset interactively and check out the result. There is so much detail!

As a resource to learn, the approximations are more than good enough. They are excellent and by virtue of being interactive, they are also much better to get a feeling for everything than the SwiftUI documentation’s images can ever be. There’s only so much an API documentation can teach you before you need to observe how it really behaves.

Since it’s in a browser, the preview is of course even faster than Xcode Previews would be, and without the crashes. (Oh, the crashes …)

I wish the SwiftUI Field Guide had been available a year ago when I had to figure out so many things through trial and error!

Some sections apparently aren’t finished yet (they’re greyed-out), but you can learn a lot about the reverse-engineered layout system’s inner workings.

When Actions of NSSegmentedControl in Toolbars Do Not Fire In Their Overflow Menu Item State, Do This

In this fourth and probably still not final part of my series on NSToolbarItems with segmented controls, I just want to share a problem and a quick fix that Nathan Manceaux-Panot brought up today. The series spans 8 years and is this: Nathan recently went through the series to implement segmented controls in toolbars but discovered that the overflow menu items would not enable (a validation problem) and when they enable, they don’t fire the action. When he brought this up today, I investigated.

Continue reading …

Life Hack: Label Your Trash Bins

Teaser image

I can’t for the life of me remember which trash bin bag size to buy. Once I find a fit, it’ll be months before I buy the next batch. By then, I’ve long forgotten which one I bought. Some more expensive ones have the bag’s size printed all over them. That helps exactly one (1) time: until you buy a cheaper make of the same size. Next time, it’s guessing time again.

Continue reading …

32-Bit Cafe: Personal Website Ideas

Here’s a truly inspirational list of things to do from the 32-Bit Cafe, “a community of like-minded website hobbyists and professionals helping to make the personal web fruitful and bountiful again”. It covers these topics:

  • Page Ideas
  • Potential Website Topics
  • CSS & Page Design
  • Art & Graphic Design
  • Technical Tasks
  • Accessibility
  • Interactivity
  • Social

It’s a refreshing read (and brings up a lot of nostalgia)!

via Jack Baty

Have You Ever Sent an Email with a File Attachment that is Located on a Server?

Today was a day of convergence. Our home server/NAS had a lot of SATA-related kernel errors and drive failures in the past weeks that I couldn’t track down. I replaced the drive and the cables and things have quieted down. This means I was SSH’ing into the server quite a bit this month. Mild data loss ans corrupted file systems included.

Continue reading …

Transformative Reading … 2017 Edition?!

So I found this list of books I read and which I wanted to put on this blog in my inbox. It’s from a migration from OmniFocus to Emacs/org-mode from 2019, and the title is “Transformative Reading 2017”. What were the picks back then? And being 7 (!) years wiser, what do I think about the picks now? Here’s the list. I don’t know why I originally ordered them this way, but I left it as-is.

Continue reading …

ChatGPT Shell: Confirm Before Closing and Split Compose Buffer

Teaser image

I admit: I’ve been relying heavily on ChatGPT to get to grips with some PHP things. Asking for interpretation, alternatives, and PHP 8-specific stuff was a lot of help. I’ve been using this in a separate floating window (aka ‘frame’) in Emacs next to my editing context, and that was great. Until I accidentally closed the buffer and lost the history.

Continue reading …

Timestamps with Weekdays

I’ve recently created a note in my Zettelkasten with a structure I haven’t used before: a timeline. It’s basically an enumerated list with 40 items and a divider that marks “now”. Things above the divide are in the past; things below the divide are in the future. I’m collecting rough things to keep in mind below the divide (like a GTD tickler file would). Above the divide, the granularity increases as I track individual things that happened.

Continue reading …