One Weird Trick to Lose Size
Popular social networking apps are over 400 megs. With weekly releases, over one year you’ll download twenty gigs of data.
Since we launched Halide, the most unexpected compliment we’ve heard is about its size. At 11 megs, we’ll push less data in one year than a social network pushes in a single update.
“So you aren’t using Swift,” asked a friend. After all, Swift bundles its standard libraries into your app, bloating its size. Halide is almost entirely Swift.
How did we do it? Let’s start with the technical bits. A lot of this is a review of QA1795, but it’s important.
Measure, Don’t Guess
Export a build from Xcode. Choose “Save for Ad Hoc deployment.” Assuming your app supports app thinning (which it really should at this point), choose “Export for Specific Devices.” Make sure “Rebuild from bitcode” is checked.
Not only do you get a final representation of your package size, but you also get an App Thinning Report. Inspect your app package to find the biggest offenders.
Use Asset Catalogs
Keep your assets in asset catalogs. When you upload your app, Apple will slice it up into device-specific versions, so devices with 2x screens don’t get 3x assets, and vice versa.
Run PNG-crush
Before putting your assets in the catalog, run pngcrush. According to QA1681, Xcode will automatically crush assets for PNGs outside asset catalogues.
Try JPEGs for Photos
Restrict UI assets and similar fine linework to PNGs. This probably makes up most of the assets in your app, but if you have photographs, experiment with JPEGs. A little compression goes a long way.
It’s Time for a Difficult Conversation
After all this hard work, you’ve only shaved a few megabytes off a hundred meg behemoth. I don’t know how to tell you this, but you need less code.
Pick the Right Battles
Halide has about 15,000 lines of Swift. This includes a realtime video processor, a slew of custom controls, and our platform controlling AVFoundation. What’s interesting is the the code I didn’t write.
I shaved thousands of lines of boilerplate by leveraging Auto Layout. Many developers still insist on manual layout. Maybe they don’t understand Auto-Layout, or maybe they heard a story from a friend of a friend about how Auto-Layout is slow. (It isn’t.)
I’ve seen too many developers— especially at large companies— invent in-house layout engine. That’s just nuts. Don’t bloat your app with a bespoke framework when Apple bundles a fine layout engine with the OS.
We could cut another 100k by dropping Interface Builder. The User Manual and Settings are almost entirely IB, laid out with constraints. The high-level arrangement of the Camera UI is managed similarly. But we decided the productivity is worth the size in the short term.
Avoid Library Bloat
Inspect the package of many large apps and you’ll find dozens of third-party frameworks weighing anywhere from 100k to several megabytes.
I use zero third-party libraries. It’s a bit extreme, but we’re in a bit of a unique situation.
There just aren’t many third-party libraries that do what we need. The iOS dev community has a plethora of JSON mappers, but nothing for low-level manipulation of DNG files.
But what about the video processing I mentioned earlier? I can hear you shout, “GPUImage is extendable! It’s crazy to roll your own!”
From my experience with Periscope’s stack, we saw significant gains moving from GPUImage to an in-house solution. GPUImage is just fine if realtime image processing isn’t part of your business. But given our long term vision for Halide, and the role realtime rendering plays, it’s important to own this component.
I never passed on GPUImage because of file size. But as a consequence of rolling our own, I avoided bundling 125 unused filters in our app.
PSPDFKit has similar success replacing a larger framework that did too much:
We are excited to tell you that with PSPDFKit 6.8 for iOS we rewrote the core of our Digital Signature implementation for improved detection, validation and better error reporting. As a result, we also managed to completely drop our dependency on OpenSSL, reducing the size of our binary in the process.
Don’t catch Not-Invented-Here syndrome, but there are good reasons to avoid libraries.
Don’t Waste Resources on Analytics and A/B Tests
We don’t use any third-party analytics or crash reporting services. First and foremost, we don’t feel comfortable sending user data to advertising companies. But let’s set aside ideals for a moment.
Data isn’t free. In big apps, every action records an analytics event. Big apps need logging infrastructure— stuff uniquely identifies users, deduplicates requests, buffers logs, retries on failure, etc. It all adds up.
A/B tests are even worse. Your typical social network app is full of dead A/B tests that nobody went back to clean up.
We didn’t set out to avoid analytics and A/B tests because of the code bloat. It’s just our philosophy around products. Knowing too much data warps your mind. You find yourself optimizing for a local maximum, instead of making big bets that really move the needle.
So we use Apple analytics. It just works, without any code changes. It’s free. It respects the user’s privacy, requiring opt-in. Our opt-in rate is 32%, which is just fine for our needs.
There’s a time and place for analytics. We aren’t sure about our optimal price point, so we may experiment there. However, we’re keeping a wall between business-driven analytics and product development.
You Need Aligned Goals
We’re a two man team. We make money selling a product. Our growth is entirely organic. When users are happy, they tell friends about us. Small apps make us happy, and we think it’ll make users happy.
Our advice doesn’t help the apps with the most bloat. Social networks make money from advertisers, and advertisers need detailed analytics for ad targeting.
Big apps have hundreds of developers, making up dozens of teams, each with independent quarterly goals. The faster you go, the more goals you land, the more likely your promotion.
It’s understandable to think, “This library saves us a week, but adds a megabyte to our app. Well, we’re already hundreds of megabytes, so what’s another?”
Large organizations are full of reasonable ideas with unintended consequences.
Say an engineer wants to move up the tech ladder. Shipping features won’t get you a promotion. Building a new layout engine does. The company even gets recruiting-bait for the engineering blog.
The only solution is senior leadership declaring, “We are going to slim down our app.” Unfortunately, tech CEOs don’t use iPhones with 8 gigs of storage, and they don’t live in areas with shoddy speeds.
This isn’t a thankless effort. Since shipping Halide, we’ve gotten tons of messages from people from all over the world grateful for our efforts in keeping it small.
There really is one weird trick to lose size: focus on your customers.