I'm Neil, and I’m a software developer in the UK. I mostly work with iOS, and occasionally write about it too, along with various other things.
Check out my blog posts here, or read more about my current setup. And here’s my now page, with everything I’m up to these days. You can find me in more places around the web on my links page.
If you like my writing, please consider buying me a coffee to show your support. Thanks!
This would actually be pretty fun, if not for the stress of being incredibly late for his date with Florence, Jonesy thought. He’d had a complete blackout this afternoon, caught up in the flow of his work, and didn’t realise the time until it was getting dark. So now he was bombing down the road in his Porsche 911, testing out its acceleration, and racing every traffic light.
Hoooooonk! He was weaving through the traffic on the dual carriageway into the city centre now, rushing past the evening’s usual commuters meandering home from work. Forget fast and slow lanes, he thought. Just look for the gaps, and go for them, like that F1 driver once said. Nobody wants to have an accident, they’ll slow down if there’s not quite enough space. I wish I didn’t have to annoy everyone but I don’t have time to wait here.
That was close, he thought, as a Range Rover slammed on its brakes. Good thing they saw me in time, my little sports car would not win that fight. Florence was going to be so pissed off. This was the third time he’d been this late. He might not get another chance. And she was amazing. Funny, clever, ambitious, passionate. Everything he’d ever dreamed of.
He raced up to an HGV. There’s a chance to undertake if I’m quick, he thought to himself excitedly, get it before it merges back to the slow lane, it’s got a massive blind spot there. Woohoo! That was fun. Go get that electric Kia next. Boom, no match for good old fossil fuels today. Maybe I should take Florence out for a spin; she’s a bit of an adrenaline junkie, she’d love this.
Single lanes now, and the car in front was obviously not even hitting the speed limit. There’s a gap in oncoming traffic, drop to a lower gear and floor it, you can get past here. Yes! That was amazing, he thought to himself. He could floor it, there was nobody ahead now.
No, wait, shit, there’s a car pulling out of that junctio-
.
If you liked this article, please consider buying me a coffee to support my writing.
Long ago, moustaches were a sign of a gentleman. Someone who wore a moustache was trustworthy, honourable, and of the right sort, if you know what I mean. Knew the right people, looked the part, spoke correctly. Understood when to look the other way, and what’s more understood when not to look at all.
This moustache was unlike those fine specimens of years gone by. It lacked decorum. Etiquette. It had an extravagant twirl. A twirl that declared this moustache’s owner would not in fact follow common decency but instead trample over it, much like he’d trampled the convention of sensible moustaches.
The man whose face this moustache adorned was certainly not a gentleman. This man did not even wear a tie. He considered such fine attire to be the mark of someone pretentious and stuffy. The cheek!
This moustachioed man was, in fact, a private investigator. If there was anything farther from a gentleman, it was unheard of in polite society. A private investigator! Someone who made it their purpose in life to pry into the personal affairs of others. Someone who had so little going on in their life that they had to disseminate the intimate knowledge of upstanding citizens who had the right to expect the courtesy of privacy. Someone who hunted down tawdry affairs which were best laid to rest, and delighted in sharing with the world the shame of a gentleman. And to top it off, after committing the worst invasion of privacy, they are brazen enough to describe themselves as private investigators!
Really, it was too much. This little man, his funny accent and his ridiculous moustache must leave the estate at once, lest he trap them all in the library and share one’s darkest affairs with all.
If you liked this article, please consider buying me a coffee to support my writing.
This is a great post by Dave Rupert on how much more there is to software development than just writing lines of code. His non-exhaustive list is 31 items long.
I tend to measure myself or view work productivity through the lens of “How much code did I write?” and that does a great disservice to myself and what I do.
I've had jobs before that have measured developer productivity by things like number of PRs merged or number of screens created. And it's easy to get caught up in that sometimes, and feel like you've not done much because you haven't written as much code as you think you should have. This is a good post to come back to when I need to feel better about not having written a lot of code recently.
If you liked this article, please consider buying me a coffee to support my writing.
The familiar sound rang out. The sound of defeat. The little red plumber fell down a hole, again. Another life lost, go back to the start. George threw down the controller in resignation, and went out for a walk. Super Mario World: just another thing he’d failed at.
The last couple of years had been hard on George. On his darker days, he felt like all 28 years of his life had been a challenge. Like he’d been playing a video game on hard mode.
George was a father, to three beautiful children who he got to spend a few hours with every other weekend. He was divorced, as of last year, when his trial separation had become a permanent ending. His wife’s new boyfriend had moved in surprisingly quickly after that. The kids had a new dad, George thought. I’ve been completely replaced, so depressingly easily.
This replacement did not, however, take his place financially. George was still paying regular payments to his ex-wife, to help look after the kids he rarely saw, and the upkeep (and indeed the mortgage) of the house in which he was no longer resident. Those payments had become another source of stress, when George lost his job six months ago.
He walked on, past the site of a pub which was in the process of being demolished, in favour of an office block. The pub had character, George thought. A beautiful old brick building, crawling with ivy. To replace it with yet another glass block was an insult.
He was replaceable too, it turned out. In his marriage, and also in the job that he’d loved for almost a decade. Not only that, he was replaced by a computer. A glorified random number generator. An LLM, built to create soulless images from prompts written by project managers, and executives, and other people without an artistic bone in their body. As a graphic designer, he was irrelevant now. Nobody was paying for a human to create art when you could get some machine-generated bullshit for a fraction of the price. He was 28 years old. He supposedly still had forty years left in his career. What was he meant to do now? Nobody was hiring for his job any more. Overnight his whole career path had vanished.
Still he walked, reaching the footbridge over the new motorway. When he’d be a kid, this had been a field that he’d played in every day. Now it was just another pollution-filled testament to humanity’s inevitable, unstoppable, destructive march toward progress.
He’d been replaced. He had no future. No family life. No career. No friends to speak of, because he’d been so focused on his work that he’d neglected so much else. The world was falling apart.
This was it. The end. He couldn’t go on like this. It was too much.
He jumped.
…
And he woke up with a sharp intake of breath. What was this? What just happened? He was falling, and then… what, exactly? Where was he? It looked like an arcade, but with VR headsets everywhere. He looked at the machine in front of him. “Life Isn’t Fair”. What? And at the bottom of the game setup screen: Hard Mode. Hard Mode! It was a fucking game! His whole life really was a simulation, and he was playing it on Hard Mode! He was shocked, but even more, he was furious.
George felt fuzzy for a moment. He blinked, and looked down. Game Over? And I only got to 28? David had hit 68 last week. He’d never live 28 down.
“Right, still got time before I need to be home for dinner. One more go.”
If you liked this story, please consider buying me a coffee to support my writing.
Some people seem to love Liquid Glass. Others hate it.
It’s a bold aesthetic choice. It’s flashy. It adds a layer of “look at this” to the UI. It certainly gives the devices a unique and consistent Apple OS identity.
While the designers at Apple say it’s all about putting content front and centre, it actually distracts from the content with its appearance. The glass effect “curves” and distorts the content underneath it. And the contrast and readability issues have been discussed repeatedly over the summer. See these screenshots of beta 4, when Apple walked back some legibility improvements in favour of more transparency, for example.
As another, small, example (which is just a design issue, with no accessibility issues) see the GIF in this Mastodon post. It’s so distracting, getting in the way of the actual content.
Compare to Material Design Expressive on Android. It’s fun. It’s got personality. It’s fluid. But it’s not the central character in the UI. It doesn’t have a negative effect on the UI, making it harder to use or getting in the way.
The UI of the most popular operating systems can be fun, but it should be simple, uncontroversial, unnoticeable. It should be butter, not marmite.
If you liked this article, please consider buying me a coffee to support my writing.
I've had the 1st generation Apple Watch Ultra since it came out. Since then, I've worn it on my left wrist, in the standard orientation with the Digital Crown on the right. I've been constantly annoyed by the way the Digital Crown is pressed far too easily when I lean.
I didn't realise this, but I lean on my hands all the time. And leaning pushes the back of my hand back against the buttons on my Watch. I spent the best part of three years triggering Siri, taking screenshots accidentally, and even making a couple of accidental emergency calls, because I was holding in the Digital Crown without realising. Either this watch has a weird design or my wrist does, but something isn't right here.
Anyway, I did what I'd resisted for years, and swapped the watch around. I now wear it with the Digital Crown on the left of the screen. I've been doing this for a couple of months, and it works really well. I adapted to the new button layout pretty quickly, even after a decade of wearing Apple Watches. I get no more accidental button presses, even though the Action button is on the right now. Because it doesn't stick out, it doesn't get pressed when I lean.
It looks seriously weird to me. But it works so much better. (Proving again that design is how it works, it's not just about aesthetics!)
If you liked this article, please consider buying me a coffee to support my writing.
In Running Track, I have a screen that shows details about a run, including a map of the route. I’ve been rewriting parts of the app in SwiftUI recently, and that screen has given me a headache!
To have a consistent look across the app, I set UINavigationBarAppearance on launch. This gives me a standard background colour, tint colour and title font.
static func setNavigationBarAppearance() {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = UIColor(.primaryColor)
appearance.tintColor = UIColor(.darkBackgroundText)
appearance.titleTextAttributes = [
.foregroundColor: UIColor(.darkBackgroundText),
.font: RTTextStyle.display4.font
]
appearance.largeTitleTextAttributes = [
.foregroundColor: UIColor(.darkBackgroundText),
.font: RTTextStyle.display2.font
]
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
}
There’s no equivalent of this in SwiftUI. No way to set navigation bar style globally. (I don’t know why not.)
For some reason, if you have a SwiftUI Map in your UI, it will override any global UINavigationBarAppearance you set. When the Map is in my View, it sets the navigation bar to the default style, a white background in light mode and a dark one in dark mode. (This applies whether you use NavigationStack or NavigationView.)
That means you can’t use UINavigationBarAppearance to style the navigation bar on that screen.
There are two fixes for this, and both involve giving up on UINavigationBarAppearance and moving to the SwiftUI method of styling individual views explicitly: 1. Style this navigation bar explicitly, and leave the rest to UINavigationBarAppearance. 2. Get rid of UINavigationBarAppearance and explicitly style every view that lives in a NavigationStack.
You can style a navigation bar in SwiftUI with modifiers, but you have to apply them to each view individually:
someView
.toolbarBackground(Color(.primary), for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar) // otherwise it's hidden until you scroll
.toolbarColorScheme(.dark, for: .navigationBar) // a hack to get white text and button tints
I’m not able to go with the first solution, modifying only the View containing the map, because SwiftUI doesn’t give the same control over navigation bar styling that UIKit does.
For example, I change the text colour and font in my UINavigationBarAppearance setup. But can’t change these in SwiftUI’s navigation bar. So I can’t have an exception just for the screen containing the map, without it looking different to the rest of the app. I need to completely change my navigation bar style.
So I’ve had to go nuclear and get rid of UINavigationBarAppearance.
I created a modifier to reduce some of the repetition, but I have to set it on every View that's presented in a NavigationStack:
struct NavigationBarStyle: ViewModifier {
func body(content: Content) -> some View {
content
.toolbarBackground(Color(.primary), for: .navigationBar)
// otherwise it's hidden until you scroll
.toolbarBackground(.visible, for: .navigationBar)
// a hack to get white text and button tints
.toolbarColorScheme(.dark, for: .navigationBar)
}
}
extension View {
func navigationBarStyle() -> some View {
self.modifier(NavigationBarStyle())
}
}
If anyone has a better solution to this, let me know!
(Note: This issue is specific to rendering a Map, so if you're not using a Map in your UI you may not need to worry about this.)
If you liked this article, please consider buying me a coffee to support my writing.