Sponsored Link
How iOS apps actually make money
RevenueCat’s State of Subscription Apps report is out, analyzing 115,000+ subscription apps and more than $16B in revenue. Use it to benchmark your pricing, trials, and conversion rates against what’s actually working across the app economy.
The original cargo cult came from World War II; electric boogaloo. Pacific tribes observed cargo planes distributing supplies & food to soldiers. In short order, they began ritualistically copying military practices: marching about, building runways, and talking on fake radios. This imitation was done in the vain hope of summoning more planes, with more supplies.
It’s fun to point and laugh at the silly historical tidbit, until you realise that in tech, we often do the exact same thing.
“Cargo culting” in tech is when we observe and imitate the behaviour of top companies, without understanding the underlying reasoning. You know what I mean: OKRs. Dashboards. SCRUM. Story points.
The behaviour is at its most insidious in the engineering department. You aren’t just cosplaying as a big Silicon Valley swingin’ d*ck, you’re actively kneecapping the productivity of your org, forever.
Distributed Microservices™ is the most famous case study. Popularised by Amazon in the early 2000s (when they had billions in sales and 40m customers). At scale. Desperately imitated by companies (and sold by consultancies) with microscopic sales and nano customers. (Nah, no customers). Even Amazon is seeing the light.
Complexity debt is orders of magnitude worse than tech debt, because you are paying it every time you touch your system.
It’s insidious because engineers love introducing complexity. You need an iron fist to prevent them introducing the latest networking paradigm, shipping a proprietary UI rendering system, or re-architecting the app to RIBs (sorry, Alex Bush).
I’m deeply impressionable, and no stranger to the allure of the cargo cult. When I CTO’d my own startup, I made the decision to roll a serverless stack so we’d scale 2 da moon 🚀, even though a $5 box could trivially handle our meagre DAUs.
Today we’re focusing on mobile engineering, because I have a lot of war stories to draw on. And we’ll cover the full roster of cargo-culting deadly sins:
👑 Pride: Knowing better than Apple about UI frameworks
🤑 Greed: Everything must be available offline
🧨 Wrath: My architecture is bigger than yours
⚙️ Envy: We must adopt Google’s build system
🍆 Lust: Let’s make our networking stack polyamorous
🤤 Gluttony: Om-nom-nom all the modules
⛓️ Sloth: Automate all the things!
👑 Pride
Knowing better than Apple about UI frameworks
Apple gives you UIKit and SwiftUI. One’s performant, and one’s nice to write.
But we want to have our cake and eat it. If we re-write the app in HypeUI, we can get blazing-fast UIKit performance with easy SwiftUI-style syntax! Kind of.
This is fun for side projects, but consider migrating your entire codebase:
Now you have inconsistency between most screens across the codebase, slowing down every context switch.
Invents years of make-work to re-write screens that already work.
Velocity suicide.
This is even worse in the age of AI: perhaps you know the framework inside and out. But the training data is scarce, and your agent will start to hallucinate like it’s 2022.
This is, in my experience, the deadliest sin. I’ve seen it slow feature development to a glacial crawl. If scroll performance is a problem, give UIKit a go. If it’s still a problem, simplify your UI.
🤑 Greed
Everything must be available offline
Sometimes you want everything. Offline-first architecture, total reliability, and sub-millisecond latency.
Over-zealous local persistence won’t kill you, but it’ll slow you down. Lots. The rubric for cargo culting is “copy what Meta does”, but even Meta doesn't bother doing this on your news feed!
There’s a dark, oft-whispered-about practice that’s even more harmful to your productivity than persisting everything: sync engines. Automatically ensuring the local user data is eternally kept up-to-date with the backend representation.

This might not sound that bad, until you try it.
You’re introducing distributed system problems to a f*cking client app! You better at least be rolling “last write wins”, or I’ll really kick off.
Look. Persisting some stuff is good.
You’ll usually want some caching. And some data is great to have locally for fast retrieval or offline availability. For some apps, keeping important user data like voice notes or documents offline is obviously a requirement. But for 96% of apps, 96% of data does not need to be persisted.
🧨 Wrath
My architecture is bigger than yours
We’ve all felt like this at some point.
I can’t believe they chose to run vanilla MVC for this app! All the interactions and navigation are run through a view controller extension in a different file! This is dumb. I could totally improve this by using MVVM+C.
You’re not doing your job as a developer if you don’t think the people who originally built the software you’re maintaining were total morons.
But it’s dangerous when you actually try to change things.
Consistency is a superpower for a codebase. Your devs can land on the folder for a screen, know which file does what, how the navigation works, where data is fetched, and where user interactions are handled. All the moving parts are easily searchable, making debugging, maintenance, and new feature work super straightforward.
Architectural churn destroys this hard-won institutional knowledge.
My advice? Pick an architecture and religiously stick to it. Unless you have non-overlapping feature teams who never touch each other’s systems, a-la Monzo’s famously laissez-faire “let teams pick whatever” strategy, architectural inconsistency will hurt you forever. Trust me, this creates years of tech debt.

⚙️ Envy
We must adopt Google’s build system
This is the bread-and-butter cargo culting justification.
Oh no! Our build times are ticking up! Our dependency graph is getting a little heavy. Better consult my two amigós, Buck and Bazel! 🏜️🤠
This will achieve 3 things:
It looks phenomenal on your CV.
You can’t be fired, because no-one else understands how to change the config.
Your build times are fixed, but nobody can really get anything else done.
Google rolls a custom build system. Uber rolls a custom build system. Meta rolls a custom build system. What could possibly be different between your 100k-line project and their 100m-line project? Other than a paltry 99.9m lines of code?

Bazel was created by Google to solve Googley problems like “git stopped working in our monorepo”. These tools are designed to build your whole system and unify deployment across backend and frontend, but there’s a second level of this sin: deploying a hyper-complex build system for a single platform alone, negating the entire point.
Look. I love Tuist. They don’t pay me. Yet 😏.
Pedro, pls sponsor my Substack 🙏
It’s the everyman’s alternative build system, and solves problems like “xcodeproj files suck arse” or “caching modules speeds up your builds a whole bunch”, not “our repo literally won’t fit on your hard drive”.
Maaaaaybe you can justify a hyperscale build system like Buck if you’re a team of ex-Facebookers building a company, and want to just use what you know. But you’re creating more work down the line: onboarding overhead for every new team member, forever, and a dramatic maintenance burden. Why take the hit?





