radex.io
About me
👋 Hi there! I’m Radek, Lead Frontend Engineer at Presidential Title, Advisor&ex-CTO at Nozbe, Secretary of the Board at Warsaw Hackerspace.
I’m a software writer. I design, build, and maintain apps, and libraries to make apps. A particular interest of mine is making tools that help people be more productive.
I’m a proud generalist, always interested in broadening the spectrum of my craft. Since 2017, I’ve focused on building high-performance cross-platform apps.
Read on »
I gave the “Hermes Hacking” talk on the (excellent) React Native EU conference. It’s an introduction to how JavaScript engines work, for developers that have no background in parsers, compilers, or interpreters. I briefly cover lexing, parsing, AST interpretation, bytecode generation, garbage collection, with some Hermes-specific topics, and links to articles where you can learn more.
Give it a watch:
Read on »
Part of my job is to make JavaScript things go fast. Speed is a feature, and when working in an interpreted language, squeezing every last bit of performance can be the difference between a great product and unusable garbage.
Anyway, how cool would it be to make JavaScript itself go faster? I’m not a C++ programmer, but that didn’t stop me before, so I thought I’d give it a try anyway!
The objective
We’ll make a common operation, JSON.parse()
, faster. There are real world use cases where you’d want to parse large JSONs, such as initial login to an offline-first app, or deserializing persisted state at launch. By making it twice as fast, it could have real impact on users, as opposed to optimizing some obscure microbenchmark.
The JavaScript engine we’ll target is Hermes, used primarily by React Native. Improving V8 (Chrome, Node) or JSC (Safari, Bun) would have greater impact, but Hermes is relevant to my work.
Read on »
You’re an iOS developer. You’re excited about all the great new features iOS 10 brings, and you’re eager to implement them in your app. You want to start working on it right now so that you’re ready to ship on day one. But that’s still a few months away, and until then, you have to keep shipping new versions of your app every few weeks. Does that sound like you?
Of course, you can’t use Xcode 8 to compile your shipping app — it wouldn’t pass App Store validation. So you split your project into two branches, one stable, another for iOS 10 development…
And inevitably, it will suck. Branching works beautifully when merely working on a feature for a while. But try maintaining a huge branch for many months, with changes spread across the whole codebase, while the main branch also evolves, and you can brace yourself for some serious merging pains. I mean, have you ever tried to resolve .xcodeproj
merge conflicts?
In this article, I will show you how to avoid branching altogether. For most apps, it should be possible to have a single project file that will compile for both iOS 9 (Xcode 7) and iOS 10 (Xcode 8). And even if you do end up branching, these tips will help you minimize the difference between your two branches, and make syncing them less painful.
Read on »
guard
is one of my favorite features of Swift 2. It’s one of those subtle syntactical constructs we could totally do without. And yet having it is such a delightful win. It makes our methods cleaner and easier to read, it helps express the “early exit” intention, and adds a little extra safety.
However, it’s important to learn and understand how to use guard
properly. It has its place, but it’s not meant to replace if..else
and if let
in all cases. No matter how great guard
is, it can easily be misapplied and forced into places where other constructs do a better job.
Here are some basic guidelines for when to guard
, and when not to:
Read on »
A year ago, not long after Swift became a thing, I noticed a tendency among programmers to write it the way you’d write Objective-C. I thought that Swift was a different language, with different syntax, philosophy and capabilities, and so we should develop new conventions and approaches to it. I responded with Swifty methods, where I argued for a better, clearer way of naming things. Then, some time later, I started the Swifty APIs series to put those ideas in practice and explore how to design easy-to-use interfaces.
In the first article in said series, we took the NSUserDefaults
API:
… and we made it look like this:
The result was clearer, less verbose, and nicer looking than the original. We fixed some consistency issues and made it all fit better with Swift. This felt like a significant improvement.
And yet, as I’ve been actually using the new API, and learning Swift along the way, I realized that it wasn’t actually very Swifty at all. I drew inspiration from Ruby’s and Swift’s syntax in designing it, and that matters, but we didn’t improve it on a semantic level at all. We only put a Swifty coat of paint on a fundamentally Objective-C-like mechanism.
Read on »
Back in March, I gave a talk named “Swifty methods” on the Swift Summit conference in London. It’s a shorter, more compressed and refined version of the arguments I was making in the essay with the same name as well as the Swifty APIs series. I think it went quite well, so I encourage you to give it a watch on the Realm website:
(I wish I could just embed the YouTube video here, but the Realm team went to great lengths to nicely synchronize the recording with the slides, so it works better on their website)
Read on »
In Practical and efficient WatchKit tables with view model diffing, I presented a way of making Apple Watch apps that simplifies application code and results in superior performance by moving UI updating logic to the framework layer and making it smart about pushing updates over the radio.
Another way you can reduce iPhone—Watch traffic and make your app faster is by loading tables lazily. Instead of displaying everything at once, you only load a portion of the data, and then add more rows as needed. This can make a huge difference.
However, even though it sounds simple on paper, lazy loading can be surprisingly hard to do by hand. It’s trivial when you have relatively static data (for example, the calendar rows in Things). But when you have a combination of cached data and network fetches, and you allow users to manipulate the table in some way, there’s a lot of bookkeeping requried to do it right.
Unless you use the view model diffing architecture. Then it becomes simple again.
Read on »
Like interactive articles? Download Playground for this article.
Before Swift 2, there were three main ways of dealing with errors:
- Optionals: for the simplest cases when you don’t care about a reason why an operation failed.
- NSError: used by Cocoa frameworks; upon failure, a method sets an error object to the variable passed as a pointer. This method is undesirable because of its verbosity, and because it’s too easy to ignore errors.
- Result: an enumeration that’s either a
.Success(value)
or a .Failure(error)
; common pattern among Swift programmers.
(There are also Objective-C exceptions and runtime traps, but those are fatal errors.)
Swift 2 introduces a new error handling model where functions can throw an error, and callers can catch
them. This replaces NSError
in bridged Objective-C classes.
It will also largely replace Result
. The convenient, familiar, compact syntax of Swift 2 errors is simply better than Result
in most cases.
There is an argument to be made, however, that even in Swift 2, Result
still has a place. Since it’s a value, you can pass it as an argument (for example, to an async operation handler). You can put it in an array, deal with it lazily, or save in a property. And you can create functions to easily transform, compose and chain those values together.
Read on »
In this post, I will show you how to dramatically simplify the architecture of your WatchKit application and improve its performance. We will introduce a thin layer between your interface controller and the views (tables, rows, labels, images…). Together with a small set of additions to the WatchKit framework, this will free you from worrying about updating your UI in an efficient manner. Every time your data changes, you will simply tell the framework what you want to display, and the framework will intelligently compute the smallest required set of interface changes for you.
Read on »
Quick WatchKit Pro-Tip™ today.
Text on the Apple Watch can be awkward. You probably saw this when developing or using WatchKit apps: huge gaps left by long words wrapped into a new line, and ugly jagged edges in left-aligned blocks of text. Apple deals with this problem in their own apps by hyphenating text on screen. However, WKInterfaceLabel
doesn’t support hyphenation… Or that seems to be the common knowledge, anyway.
But it’s actually incorrect. WatchKit does support hyphenation, and it’s very easy.
Read on »
In the previous installment of Swifty APIs, we took a look at NSUserDefaults
and gave it a make-over. I pointed out some of its problems, like verbosity and inconsistent behavior, and tried to fix them. The resulting interface was, arguably, cleaner, easier to use, and felt more at home with Swift’s syntax.
Today on my plate is NSTimer
. This class has been a pet peeve of mine for a while. Perhaps I’ve been using it more often than most people (fun fact: one of my apps is essentially a fancy, special-purpose timer), but I really do think that for the simple, almost trivial function it serves, its API seems unnecessarily inconvenient. It feels outdated not just by Swift standards — it stayed unchanged for at least 15 years, despite advancements in Objective-C.
Either way, let’s make it better.
Read on »
Parsing JSON has been a hotly debated topic in the Swift community almost since day one. The staticly typed nature of Swift proved somewhat problematic when facing with this problem. In the world of Swift, the structure and types of data are well-defined and known at compile time. When decoding serialized objects, they’re not. At the same time, the new features of Swift enable different approaches and interesting solutions that simply had not been possible in Objective-C.
Anyway, this is a yet another article exploring different solutions to what seems to be a very mundane problem of dealing with JSON.
Read on »
In Swifty methods, I was arguing that we should resist the temptation to write Swift the way Objective-C used to be written. I argued that we should develop new approaches and conventions to designing interfaces, and that we should, once and for all, abolish Objective-C’s excessive verbosity.
Although it was very well received, the issue I’ve had with the essay is that the arguments I was making were all in the abstract. I gave some examples here and there, but they were low-level, and mostly silly.
And so I decided to start a series of articles called Swifty APIs, where I’m going to take some class or component from an Apple framework and show how I would design it with Swift in mind.
Today, we’ll dissect NSUserDefaults
and give it a little make-over. We’re going to make it less verbose, a bit cleaner, and more consistent with other classes. We’ll polish its rough edges and we’ll make use of Swift’s cool features along the way.
Read on »
If you prefer watching to reading, I also gave a talk on the same topic.
Most programmers learning and writing Swift now are people with existing experience in Objective-C. Many of them have worked with this language, writing iOS and Mac apps, for years. If you’re reading this, there’s a good chance this also describes you. It’s very tempting for us to write Swift the way we’d write Objective-C. It’s all too easy to cram existing habits, conventions and ways of thinking into Swift. But, of course, Swift is a very different language from its predecessor and so it requires new approaches.
Now, there has been a lot of great articles touching on Swift’s cool features like structs, enums, tuples and generics; some people even tried to write functional code in it, but today I want to talk about something more subtle and nuanced: methods.
Even something as trivial as method naming has been a great source of disagreement in the Objective-C community. The language is known for long, verbose names like performSelectorOnMainThread:withObject:waitUntilDone:
or tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
. Some people love it, some hate it. There have been good arguments on both sides, but it’s all a moot point — the truth is, that’s the Objective-C convention. And conventions are a good thing — it’s easier to read each other’s code and work together if we all decide on a common coding style.
But Swift, as a brand new language, doesn’t have established conventions yet, so the discussion is open again — and naming aside, there are many great features related to how we define methods that let us write cleaner code than in Objective-C.
So let’s explore the topic.
Read on »