Frameworks and startup time

I've been playing with this project the last two weeks and am really excited about it. Thanks for making it and providing such clear documentation and videos!

As someone who works on a large project, one huge selling point for me is that making the code more modular can lead to faster compile times. Two issues I'm concerned with are the impact of dynamically linking frameworks on startup time and the complexity of managing dozens of frameworks.

In the example TicTacToe project I see 13 frameworks and the app is not that complicated.

I guess I'm wondering:

  1. Is a super modular approach like the one in TicTacToe feasible given the impact on startup time?
  2. If a super modular approach isn't feasible, what factors or heuristics should developers consider when deciding how to break their features up between frameworks?
  3. What tools or workflows people would recommend for managing a project with lots of framework targets (I could see xcconfigs helping a lot here)?

I know that some of this will depend on the specifics of your project, but I think there are probably some general guidelines we could come up with as well. I think it would be cool to gather up some best practices and possibly link to them in the readme since the modularity is such a huge feature of the architecture.

1 Like

Hi @tsabend, good questions!

We feel that many of these things have answers that are independent of the architecture. In any app that has decided to become modular (even vanilla UIKit) you will face these problems unfortunately. Perhaps people will try out modules more frequently with TCA since it's a little easier, and so that may expose more people to these problems, but the problems are there regardless :/

Here's some answers to your questions:

We haven't done any benchmarking recently, but from what we've seen in recent WWDC talks (like this one) is that the situation with many frameworks has gotten much better. I don't think the current guidance is to limit the number of dynamic frameworks (they used to recommend 6!).

However, if there are still problems these days then there are some tricks in the community for creating static frameworks, and so perhaps a little bit of infrastructure work is needed to get something like that set up.

This will vary wildly for teams and applications. One possible approach for very large teams where a group of engineers own a particular feature is to split out modules for each team's core feature. This would allow them to build in isolation and their compile times should only slow down as they add more code not as everyone else adds more code.

This even scales to teams that act more as a "platform" for other features, i.e. they build a feature that other teams plug into and configure. It is possible to fully disentangle all of the dependencies so that a team can build such a platform without having to depend on everyone who wants to plug into them, thus allowing them to build and iterate without being slowed down by other teams adding more code.

SPM actually shines in this regard. You can very easily create a sub-directory, do swift package init, create a whole bunch of little libraries in there in a very lightweight way, and then just drag-and-drop that directory into Xcode to get instant access to every library in the package. You could have a package for each screen in your application, which would allow you to build that feature (and only its dependencies) in isolation, and run it in isolation, either in a shell application in the simulator or in SwiftUI previews (unfortunately not playgrounds due to a bug in Xcode/SPM :frowning:)


We do have plans to discuss modularity a lot more, and so these questions and people's experiences will be valuable for understanding what people are looking for. @stephencelis and I have consulting with multiple companies of various sizes and that has informed a lot of how we think about these problems and what approaches work.

3 Likes

Thanks for the prompt and thorough reply. Definitely agree that these issues exist outside of the scope of TCA, I think the combination of composability + previews has me re-weighing some of the tradeoffs.

I haven't played too much with SPM but after using it to grab TCA for this little side project I'm excited to see it continue to mature.

Thanks again for all the work that went into this.

TicTacToe doesn't do this, but it's possible to modularize in a more lightweight way using a single, local Swift package that contains all of the modules your app needs to build (you can drag that local package directly into your Xcode project, as @mbrandonw mentioned). There are a couple quirks to be mindful of:

  1. I don't think SPM packages play nicely with Xcode previews yet (haven't checked in a couple Xcode versions, though!). So while you can modularize your domain model and logic, views still need to live in framework or app targets if you want to use Xcode previews.
  2. While framework errors cascade nicely in Xcode and surface in the UI as you expect, a mixed Xcode/SPM project does not surface SPM errors in a nice way if you are building an Xcode target that depends on an SPM package. Switching schemes helps, but is definitely inconvenient.

Hopefully these things get better with the next version of Xcode!

1 Like

Best way to see the impact of frameworks on your apps launch time is to set the DYLD_PRINT_STATISTICS environment variable in Xcode and run on a device. Swift frameworks should have much less of an impact on launch times then Obj-C did, especially since there's no + load for framework authors to really screw with your launch times.

5 Likes