Congrats on the launch!
HN user
sond813
Apple recommends 400ms for startup time because that's how long the app open animation takes. It's also hard to tell from just one flamegraph how long it will really take in prod, that's why the percentages are nice to use. I've mostly used percentiles like p95 to track and prioritize mobile perf work. 600ms on one phone could be 2s on older hardware with other factors slowing it down, but it depends on the distribution of doordash users.
We've seen this happen with system fonts as well, apps sometimes bundle the San Francisco font with an app instead of relying on a system font. There may be some reasons to include the font or sound file, such as if it changes in different versions of the OS. Of course that would make the app inconsistent with the rest of the OS, which may not be the best behavior. We discuss some other tradeoffs with bundling these system resources on our blog post which covers the Spark app: https://www.emergetools.com/blog/posts/7AppsThatCouldSaveYou...
I tried it out with Yelp and Twitter, both had a lot of bloat due to not stripping binaries. You can see this in the large "String Table" in both screenshots.
Yelp also has a large exports section for the main app binary, that's usually a sign of a problem because the main binary doesn't need to export any symbols, only frameworks do that.
Twitter has a handful of 4MB images, much bigger than images you'd expect in an app. I took a look at a few of these and they are just gradient background images that could have been drawn with something like core graphics to completely eliminate the need for an image.
Twitter: https://emergeassets.s3.us-west-1.amazonaws.com/Screen+Shot+...
Yelp: https://emergeassets.s3.us-west-1.amazonaws.com/Screen+Shot+...
Building up the cache at launch/dynamic link time does have a performance hit of a few ms, but if you know it will save you many runtime checks it can be worth it. Definitely makes sense for the runtime to have the lazy behavior built in. Hopefully the dyld cache will help get the best of both solutions by persisting a cache across multiple launches.
It’s ms, that slow because every protocol conformance in every dylib needs to be checked. When this gets to 100k+ like in many large apps it takes multiple milliseconds
Looks like a great improvement to my workflow, does it require write access to GitHub or can it be read only? Any plans to support GitLab?
There’s also a linker flag that lets you use this format on older OS versions. It seems to work (I tested as far back as iOS 13.4.1) but couldn’t find any documentation to guarantee it won’t cause issues https://developer.apple.com/forums/thread/683596
The mach-o format supports a “fat binary” that contains multiple architectures and then the App Store can only deliver one of those architectures to a particular device. Bitcode lets Apple recompile a different architecture slice using this format. However, since this change is unrelated to the architecture it can’t take advantage of this format.
I always had trouble getting notified when a release was blocked from App Store review since it required getting an email and then logging into App Store Connect to find the reason for rejection. Does Runway help surface rejection reasons into other tools?
Interesting idea, I assume Apple would solve the versioning problem the same way Google is currently handling it. Apple is doing something like this already but there isn't too much detail other than the mention of update packages here: https://developer.apple.com/documentation/xcode/reducing_you...
Currently identifying sources and offering suggestions for how to make improvements. For many apps this can reveal a lot of opportunity!
Yep this is exactly the problem I'm trying to solve! A lot of large app companies have switched from Xcode to third party build systems like Buck or Bazel. This can make things faster but even more confusing. I've found analyzing the actual build products to be the best solution to make sure nothing unintended is happening.
Uber's article focuses on binary size, but the App Store 309mb number is app bundle size. 120mb of this is not coming from the binary. I have a breakdown of this here: https://news.ycombinator.com/item?id=25380198
App size can be measured in many ways like download size, install size, binary size, thinned size. I wrote about the most important ones here: https://docs.emergetools.com/docs/what-is-app-size
Starbucks has a separate China app. I suspect a part of this is due to app size because there are regions specific SDKs. Another is likely security. Regulations in some countries require data to be shared with the government and they don't want SDKs that collect this data to be included in more privacy focused regions.
Google encourages this with feature modules and app bundles. Apple doesn't allow it because they've always been against downloading executable code that doesn't go through app review. Same reason they don't like game streaming or downloading react native at runtime.
I'd like to see them open up this possibility in a controlled way one day. Something like a review process for feature modules that could be updated in a similar process to full apps.
I’m the founder of a YC company in the current batch focused on solving this exact problem! https://www.emergetools.com
We parse Obj-C and Swift runtime metadata to determine size contributions of individual types and functions in your app. We use this analysis to post PR comments with granular size diffs to help devs write smaller, better code.
I tried it out on the Uber app and immediately noticed a disproportionate impact from their code-gen dependency injection framework, Needle. The codegen is responsible for over 30k classes in the app binary, and contributes over 10mb! In general codegen is a common problem with Swift binary sizes, and the fewer reference types generated the better, it even helps with startup time!
We’ve written a blog post with case studies about how 7 of the most popular iOS apps could reduce their size: https://medium.com/swlh/how-7-ios-apps-could-save-you-500mb-...
Great question, we've definitely thought about this. Seems like the trends are as users get better tech the apps get more ambitious with their capabilities and performance will always be something worth spending time on.
Thanks, this sounds interesting! Feel free to email me at noah@emergetools.com
Android support is definitely on our roadmap!
It's 200mb now before a prompt shows warning users of the size they are about to download.
Exactly! Emerge aims to make it as easy as possible to fix app size issues, so you can prioritize it similar to other bug fixes. With our pull request comments alerting you to size increases right when they happen you can easily see why size increased and remedy it all before the change makes it to users.
That's great to know! This integration is helpful for just knowing the size of an app and being alerted if it goes over a threshold, but it doesn’t provide any insight into where that size actually comes from. Adding a Bitrise integration for Emerge is definitely on our roadmap though!
Interesting thanks for sharing! It looks like __bitcode is used for static but not dynamic libraries so it might not always be reliable. I've also found that apps can include bitcode for frameworks but not the main app binary, but if it's included for the main app it is required to be included in frameworks. That's why Emerge checks for the presence of bitcode only in the main app executable.
Definitely! We want to reduce cellular download size as well. In the particular case of Dropbox, their download size is around 100mb right now. I just did a quick test by deleting the duplicate localizations in their Frameworks and zipping the .app which reduced compressed size by ~17mb (17%) so these optimizations would help significantly. This is one of the reasons I prefer to just measure install size. It's difficult to reason about all the combinations, but by reducing install size you're always on the right track to an overall smaller app.
In my experience working on large apps like Airbnb we try to get ahead of the problem even before approaching the cellular limit, since a smaller size helps acquire and keep users, and we want to avoid architecture decisions that would become a problem down the road.
It's not too rare for one of these low hanging fruit optimizations to be accidentally introduced in a large company, with testing on every PR you can catch them before they‘re introduced. Binary size is definitely what changes most often at these large companies and that's why our continuous monitoring lets developers know exactly the granular binary size affect of a PR. With a lot of code, things like exposing Swift functions to Obj-C which introduce new metadata can frequently be mistakenly added. For enterprise companies we also track the biggest modules in their binary, so eng managers can get a better understanding of where the size is coming from.
Good question! Many apps are trying to expand around the world and have a global presence. This is actually what originally inspired the idea for Emerge. App size is crucial if you are trying to break into new markets where users might not have the latest iPhone or be on 5G. Generally, we don't think companies want to exclude users because of a technical issue, and engineers are motivated to build the most performant apps they can. A healthy app size is also a good indicator of a high quality app since it affects other metrics such as download and app launch time.
Thanks! We have some docs on image optimizations here: https://docs.emergetools.com/docs/optimize-images Emerge will automatically compress images as jpg and convert to HEIC and report the size diff do you. We aren't doing automated video optimizations yet but if this would be useful for you please reach out!
App thinning goes a long way if you're supporting multiple architectures, but if your app has a lot of code it can still get very big, very fast. There are many companies that have dedicated teams to trying to handle app size, but we've found that our tooling offers more without the maintenance and eng resource cost of building it internally. To support independent developers and small startups we offer a free Growth plan and have significant discounts available for higher build volumes. We think this is a fair alternative to having a development team or even one engineer focused on this problem.
Emerge is designed to help you reduce both! We go into detail on the differences between them (and other ways of measuring size) in our docs: https://docs.emergetools.com/docs/what-is-app-size
Absolutely right! I left out some details to try to keep the post concise. 4 years ago at Airbnb we had the watch app problem, but now a Swift watch app wouldn’t be an issue since the latest OSs don’t require embedded Swift standard libraries. The tweet that started this thread cited the 300+mb size of Uber’s app, which looks like the current install size (not thinned), that’s why I used it as the benchmark in my explanation.
Lately Apple has been featuring size more prominently on the App Store, and it appears to be displaying the install size. This is also what users see when they look at which apps are taking up storage on their device in Settings. I think it’s important to reduce both, so users see a good number and downloads are fast/efficient. It is a very welcome change that binary encryption doesn’t negate all the gains from compression anymore. I had noticed it in the numbers but looked around for an official statement and didn’t find any, if you happen to know where this was announced I’d appreciate a link!