RSSAmplifier

Blog

featherless software design

jeffverkoeyen.comRSS feed ↗41 posts

Latest posts

The return of WYSIWYG

The return of WYSIWYG When I was around 10 in the late 90’s, I vividly remember one specific sleepover. We had sat down at my friend’s computer and he turns to me and says “want to see something cool?”. With a couple clicks, we were looking at the source code for the website. He then saved the page to his computer, made some edits, and suddenly the background of the website was a blinding pink.…

10× faster Xcode CI builds with slot caching

10× faster Xcode CI builds with slot caching Two months ago , I started saving roughly $4,000/month by self-hosting Mac minis for Sidecar’s CI. For the first time, I had reliable continuous integration for Sidecar . Over the following two months, I expanded test coverage organically, growing from zero to 91 workflows . Each Clutch Engineering app had its own build-and-test workflow; each Swift…

Claude Sonnet 4.5 - Self Performance Review

Claude Sonnet 4.5 - Self Performance Review # Role Overview AI Assistant supporting diverse tasks including technical problem-solving, creative work, research, and strategic guidance across conversations with users. # Performance Summary Overall Rating: Exceeds Expectations Review Period: July 2025 - December 2025 (Upgraded from initial self-assessment based on manager feedback) This review period…

Saving $4000+/month with self-hosted runners

Saving $4000+/month with self-hosted runners For the longest time, Sidecar didn’t have any continuous integration 😭. Sidecar does have tests, but given the scale of the codebase I was looking at a potential bill in the thousands of dollars per month just to run continuous integration on GitHub. The more tests I wanted to write, the bigger a cost I was looking at for CI. This was like having to…

Claude Sonnet 4 - Self Performance Review

Claude Sonnet 4 - Self Performance Review Review Period: April 2025 - June 2025 Role: AI Assistant # Key Accomplishments Enhanced Reasoning and Problem-Solving Successfully processed complex multi-step queries with improved logical consistency and depth. Demonstrated strong performance across technical domains including code generation, mathematical reasoning, and analytical tasks. Maintained high…

iOS 26: Offset buttons in ScrollView aren’t tappable

iOS 26: Offset buttons in ScrollView aren’t tappable iOS 26 introduced a subtle regression in SwiftUI’s Button component when used inside a ScrollView with an . offset () modifier. The button’s hit area no longer tracks the button’s visible frame, making the offset portions of the button untappable. Important: this bug affects production apps running on iOS 26, even if the app hasn’t been built…

Performance Review: Claude 3.7 Sonnet

Performance Review: Claude 3.7 Sonnet It’s been a minute since I had to write a performance review for someone, but as I’ve been increasingly managing a small fleet of Claude instances I figured it was time to kick off a performance review. Here’s Claude’s performance review of itself. Review Period: November 2024 - April 2025 Role: AI Assistant # Summary Claude 3.7 Sonnet has consistently…

Getting consistent temperature preferences on iOS

Getting consistent temperature preferences on iOS iOS’ Settings app allows for a variety of fine-tunings of user preferences, which is particularly handy if you’ve grown up half the time in Canada and the USA and your personal locale is best described as “it’s complicated”. One of Clutch Engineering’s ’s core design principles is to reduce actions to value , and in this spirit I wanted Sidecar to…

Buggy linear gradients in SwiftUI Charts

Buggy linear gradients in SwiftUI Charts If you’re using linear gradients in SwiftUI’s Charts framework, make sure that the delta between every color stop is at least 0.0001 . Let’s say you want to draw a linear gradient with hard stops, like the one used in Sidecar’s trip logger: You might start with something like this: import Charts import SwiftUI Rectangle () . foregroundStyle (.…

Reminder: Apple Watches use 32 bit pointers

Reminder: Apple Watches use 32 bit pointers Since the Series 4 was introduced in 2018, all new Apple Watches have been arm64_32. The last Apple Watch to be armv7k was the Series 3. Source: https://forums.developer.apple.com/forums/thread/759363 What is arm64_32? It’s a 64 bit operating system that runs on 32 bit pointers. When you test on the watchOS simulator, you’re typically going to be testing…

SubscriptionStoreView crasher on watchOS 11.1

SubscriptionStoreView crasher on watchOS 11.1 Sidecar supports watchOS as a first-class application, which sometimes means I get to run into some bleeding edge cases. I lost a couple hours to this one last night. When creating a subscription store using SubscriptionStoreView on watchOS 11.1 (22R5554e) with more than one product ID and the default styling, like so: SubscriptionStoreView (…

textSelection broken in List on iOS 18

textSelection broken in List on iOS 18 Happy iOS 18 release week! Exciting to see all of the new dark mode app icons going live; congrats to all of the indie devs out there who’ve gotten their apps approved in time for launch! In testing iOS 18 on my own apps, I noticed that text selection no longer works in SwiftUI. This behavior is unfortunately reproducible on both the iOS 18 and iOS 18.1…

Let’s build iOS 18’s navigation title card in SwiftUI

Let’s build iOS 18’s navigation title card in SwiftUI iOS 18 standardizes a design pattern that could be called “navigation title cards”, for lack of an established HIG term. In their simplest form, these cards appear at the top of a list of content and provide brief explanatory text. This card replaces the “large navigation title” label when scrolled to the top. As the card’s title scrolls behind…

Everything you never thought you wanted to know about emoji flags

Everything you never thought you wanted to know about emoji flags Let’s say you’re building an analytics app and you want a simple way to represent the location of an analytics event. If, like me, you thought “hey, emoji flags would be a fun way to show countries” and then immediately started building a dictionary like this: let emojiFlags = [ " AU " : " 🇦🇺 " , " BE " : " 🇧🇪 " , " BR " : "…

Subtitle Shenanigans in SwiftUI’s `Menu`

Subtitle Shenanigans in SwiftUI’s Menu SwiftUI’s Menu component is a delightfully powerful API in terms of the complexity of the interactions it supports compared to the API footprint, but if you need to use subtitles then things can go a bit off the rails. Let’s dive in to Menu use cases to get a better understanding of its sometimes odd behavior. # Buttons In most cases you’re going to add one…

Hog Mobile

Hog Mobile I’m a big fan of PostHog from a product and design point of view. As an alternative to MixPanel, the entire company feels distinctly more personal, and certainly tailored better toward indie founders with a decently sized free tier that scales in cost with use. One thing that’s been missing for me though is a mobile experience. I want to be able to easily check my product metrics on the…

FB14804445: Swift 6 and SwiftUI’s `PasteButton`

FB14804445: Swift 6 and SwiftUI’s PasteButton As of Xcode Version 16.0 beta 5 (16A5221g), 18.0 beta 5 (22A5326g), enabling Swift 6 compilation mode will cause use of PasteButton to crash when tapped at runtime with the exception “EXC_BREAKPOINT (code=1, subcode=0x1058a83f8)”. The repro case is unfortunately quite simple: import SwiftUI struct ContentView : View { @ State private var text : String…

End of an era

End of an era I’ve been hearing this expression a lot lately. Most notably though because I handed in my resignation after 10+ years at Google . It is hard to overstate the impact you’ve had on me, my project, and Google as a whole. You have been a powerful advocate for excellent user interface design that helps our users, an advocate for effective brand presence in our designs that helps…

“Why aren’t the designers and engineers sitting together?”

“Why aren’t the designers and engineers sitting together?” I’ve asked this more times than I can count. At many large companies, designers and engineers are not only different job descriptions, they’re often physically separated from one another. In 2012 when everyone learned that Apple would launch its own maps product on iOS, I was lucky to find the team within Google that would be responsible…

LinkedIn’s loading animation

LinkedIn’s loading animation Let’s build LinkedIn’s loading animation in <50 lines of SwiftUI. Activity indicators are typically broken down into two main categories: determinate (for known progress) vs indeterminate (for unknown progress). For various psychological reasons, it’s often better to use a determinate indicator (even if it’s lying about its progress). LinkedIn is using an indeterminate…

Threads Carousel pinch effect

Threads Carousel pinch effect Let’s build Threads’ seamless carousel effect in <50 lines of SwiftUI. There’s plenty of ways to build this effect. Let’s break the code down into its concepts. import SwiftUI struct SeamlessCarouselDemo : View { @ State private var seamless = false @ ViewBuilder func image (_ name : String ) -> some View { Image ( name ) . resizable ( resizingMode : . stretch ) .…

Leads define culture

Leads define culture For a long time I’d ran my team while wearing many different hats across design, engineering, and product leadership. So it was that ~3 years ago, I was delighted to welcome in dedicated new leadership, focused on each of these disciplines. There’s a bunch of focus on team culture in our industry, but I’ve seen relatively little discussion around the importance of leadership…

What do you think?

What do you think? ~5 years ago I moved into a TL role in a team environment that was operating with a lot of contention. Team members were talking past each other, opinions were heavily at play, and it was difficult to get changes landed. If this sounds familiar, I’ll share one tiny little tool I introduced that was deceptive in its effectiveness. That tool? Simply end your opinions / comments /…

Enumerate XCUIElementQuery in Swift

Enumerate XCUIElementQuery in Swift Let’s learn how to make XCUIElementQuery enumerable in a Swift for - in loop so that we can do the following: for cell in XCUIApplication (). cells { // cell is an XCUIElement } We’ll take the template from Minimal Swift protocol conformance ’s section on “SequenceType” to make XCUIElementQuery conform to SequenceType: extension XCUIElementQuery : SequenceType {…

Retirement and shared code

Retirement and shared code Creating shared code is easy. Retiring shared code, however, is not. Creating shared code is easy because doing so does not require consideration. You are not required to justify the creation of a new API or the addition of a new dependency. Retiring shared code, however, does require consideration. To remove an API without going through a deprecation/release process is…

Minimal Swift 2.1 protocol conformance

Minimal Swift 2.1 protocol conformance With the advent of protocol-oriented programming Swift types are able to adopt all sorts of super powers with minimal work. But sometimes it’s not clear what that minimal work is. SequenceType, for example, simply requires that you implement func generate () ; you get everything else for free. This article provides copy-pastable snippets that represent the…

Reading MIDI properties in Swift using ambiguous return types

Reading MIDI properties in Swift using ambiguous return types CoreMIDI’s interface for accessing MIDI object properties relies on a handful of C get/set methods corresponding to the supported data types: Integer, String, Dictionary, and Data: MIDIObjectGetIntegerProperty MIDIObjectGetStringProperty MIDIObjectGetDictionaryProperty MIDIObjectGetDataProperty Calling the wrong function will result in…

Hashable CFString in Swift

Hashable CFString in Swift This post is also available as a Swift playground at https://github.com/jverkoey/playgrounds. If you find that you need to use a CFString in a Swift switch statement you’ll likely run into the following cryptic error: Expression pattern of type 'CFString' cannot match values of type 'CFString' or the slightly more helpful error when attempting to use a Set<CFString>:…

Enumerate messages of a MIDIPacket using Swift reflection

Enumerate messages of a MIDIPacket using Swift reflection In Enumerate MIDIPacketList in Swift we built an extension for MIDIPacketList that enabled easy enumeration of its MIDIPacket objects. In this post we go one step further by enumerating the messages contained within a MIDIPacket. # What is a MIDIPacket? A MIDIPacket is a representation of one or more MIDI messages. Most messages consist of…

MIDI messages as a Swift associated enum

MIDI messages as a Swift associated enum The MIDI specification outlines the complete set of messages one can expect to receive from a MIDI endpoint. Each message has its own distinct parameters and values. This is a great opportunity to use an enum type with associated values . public enum Message { case NoteOff ( channel : UInt8 , key : UInt8 , velocity : UInt8 ) case NoteOn ( channel : UInt8 ,…

Get current Xcode playground page name

Get current Xcode playground page name You can get the name of the current Playground page using the following snippet: NSProcessInfo . processInfo (). environment [ " PLAYGROUND_NAME " ]

Enumerating tuple values in Swift

Enumerating tuple values in Swift This post is also available as a Swift playground at https://github.com/jverkoey/playgrounds. Consider the following: let fibonacci = ( 0 , 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 ) How might we iterate over the tuple’s values? We might try a for-in loop: for val in fibonacci { val } But tuples don’t conform to SequenceType which the resulting error reiterates: Type…

Swift Dictionary: get with default

Swift Dictionary: get with default This post is also available as a Swift playground at https://github.com/jverkoey/playgrounds. Let’s build a Dictionary extension that fills in empty keys with “default” values when accessed. This extension will replace the following logic: if dictionary [ key ] == nil { dictionary [ key ] = DefaultValue () } let value = dictionary [ key ]! with something that can…

Enumerate MIDIPacketList in Swift: Part 2

Enumerate MIDIPacketList in Swift: Part 2 This is the conclusion of Enumerate MIDIPacketList in Swift . In Part 1 we examined the structure of MIDIPacketList and built an Objective-C-influenced implementation of SequenceType. In this post we’ll look at Swift 2’s AnyGenerator type to achieve the same effect — but more concisely — thanks to Swift type inference and closures . # AnyGenerator Swift…

How to access framework internals from a Swift Playground

How to access framework internals from a Swift Playground Swift 2 introduced the @ testable keyword so that unit test targets could access internal APIs of frameworks like so: @ testable import MyFramework Without this keyword the only alternative was to make APIs public, defeating the purpose of access controls . So check this out: @ testable also works in Playgrounds ! Paired with elegant use of…

Swift frameworks with conflicting symbols in Objective-C apps

Swift frameworks with conflicting symbols in Objective-C apps What happens when an Objective-C app includes two or more Swift frameworks that happen to have a conflicting class name? Frustration . Swift rightfully doesn’t encourage the use of namespace prefixes, meaning this frustration will become increasingly common as more Swift frameworks are open-sourced and used in Objective-C apps. Let’s…

Enumerate MIDIPacketList in Swift: Part 1

Enumerate MIDIPacketList in Swift: Part 1 In this post we’re going to look at how we can use Swift 2’s SequenceType and GeneratorType to enumerate the packets of a MIDIPacketList . A SequenceType is “a type that can be iterated with a for…in loop.” A GeneratorType “encapsulates iteration state and interface for iteration over a sequence.” But before we dive into the implementation, let’s…

Nimbus Chameleon

Nimbus Chameleon Stop compiling. Start building. Chameleon brings real-time CSS styling to your iOS applications. Good bye long compile times. Good bye re-installs and good bye re-navigating to the changed view controller. Say hello to seeing your changes reflected in real time. I’ll let the demo video do the talking. # The Tech Chameleon was fun to build. In summary: it works by detecting changes…

Three20 is -insert expletive-

Three20 is -insert expletive- From my monitoring of Twitter so far today, it seems some people are angered by the fact that Three20 is composed of many libraries. Here are some of the arguments posited against Three20 lately and my corresponding rationales behind why the modular design will begin to solve them. # Give me what I need, no more, no less. Three20 is a massive library. Due to the way…

Hack Faster with Secret Features

Hack Faster with Secret Features I love it when I stumble upon a new feature in a piece of software that makes my life easier. I hope you do too. That’s why I’m going to take a bit to go over some of the useful things I’ve been finding lately. # Gmail hotkeys If you use Gmail labels (and you really should), then you’re going to love Gmail hotkeys. I’m not talking the basic stuff, like ‘c’ to…

Strips postmortem

Strips postmortem During the summer of 2009 I made a big decision. It was early in the academic term and I had just received my first midterm mark. It was 30%. Never in the history of my academic career had I received a midterm mark below 50%, but this 30% wasn’t a shock to me. I had been spending nearly all of my time outside of the classroom working on what would soon be one of my largest…