We use cookies
This site uses cookies. By continuing to use our site, you agree to use of cookies.
In this blog post I share my thoughts on why I think Tuist is a good choice to scale up Xcode projects, and guide the reader through what I believe are key features to make that easy.
If you are considering the adoption of Tuist, you might wonder why a project like yours should make such a move. The idea of adding a new tool to your toolbox might sound intimidating ― it certainly is. But believe me, this is one that you won’t regret about. Despite having done our best to convey the idea behind Tuist, and why it’s an important piece when scaling up projects, I feel we lacked a good summary.
After bootstrapping new projects and targets in Xcode, it’s up to the developers to ensure that projects are consistently configured and structured. Some developers might see that as something great, but that comes with some downsides:
You might have seen teams solving this problem at the build settings level by extracting them into reusable Xcode Build Configuration Files. Still, we should not disregard that settings are just a piece of the cake ― There are also build phases, targets, or schemes, for which Xcode doesn’t provide any way to reuse them. Other teams resort to scripts that run some checks on the projects, but that results in a poor experience for developers because those checks are not built into their workflows.
Tuist solves this by providing project description helpers. All you need to do is to define what types of projects are supported, and codify them into functions that return templated projects:
That makes it possible to create a new feature framework that is consistent with the rest.
For instance,
I can create a new Search feature framework by creating a Search
directory,
and placing the following Project.swift
file in it:
Note how idiomatic and concise the definition of projects is ― your project is defined in one line.
If there’s something that bothered me when using Xcode daily, it was how hard it becomes to maintain a dependency graph. At some point, you extract some logic into a transitive framework. After following a very manual process, other projects fail to compile. You probably forgot to embed that framework into some products that have it as a transitive dependency.
I’ve talked to developers that think that it’s developers’ fault because they don’t know how to do things in Xcode. I’d counter-argue that when the dependency graph is large, there’s so much they need to know to do things right, that the process becomes not just very manual, but error-prone. Having this mindset often leads to a terrible bus factor. There’s a person in the team that did the initial work of creating projects and frameworks, and what’s often considered “the person that knows Xcode well”.
In Tuist, we tasked ourselves with simplifying that until the point that anyone could add/remove dependencies easily. We imagined how we’d like the user interface to be, and we built the rest from there:
When people compare Tuist to YAML-based project generators,
the beauty of the dependencies API pops in my mind.
My answer is always that it really depends on what you want for your projects.
If you want to move away from .pbxproj
files and describe things in simpler YAML files using the same Xcode’s concepts and ideas,
YAML-based project generation is your friend.
However, if you want to work with simpler concepts and ideas, and be more conventional, Tuist is your tool.
Our principle is that simplicity and consistency are vital to scale up projects.
Some well-known companies that adopted a YAML-approach for the generation of projects ended up building a tool on top of it. While that’s something large companies can do, you might not want to find yourself in the situation where you need to build a tool yourself. Moreover, having tools on top of other tools adds indirections, which in fact, complicates optimization and debugging.
Xcode delegates catching errors to its build system.
The problem with that is that approach is that there are certain errors that the build system doesn’t know how to misconfigurations in the project. For example, if there’s a circular dependency, the compilation will fail with an error along the lines of: “X not found”
. What would you think as a developer? Is it not found because I didn’t configure the right search paths? Should I change the order in which targets are compiled in my scheme? The last thing you’d probably think is that there’s a circular dependency.
To prevent that, Tuist tries to catch errors as early as possible. We know developers’ time is a precious asset, and they should not spend it debugging Xcode errors unrelated to their changes. We can’t catch everything, but we do our best. Especially around the dependency graph.
Thanks to it, any developer can add a new framework to the dependency graph with the confidence that if they are doing something wrong, Tuist will catch it. Isn’t that great? Let me repeat that again: anyone can modify the graph with confidence. I can’t stress enough how great that is to grow your projects. If you make something wrong, you know that tuist generate
will tell you.
In the entrepreneurial jargon, we’d say that we are democratizing scaling up projects.
The benefit of having knowledge on your project is that we can provide streamlined workflows that leverage Apple’s building blocks (e.g. xcodebuild
, simctl
).
Here are some of the features that we are planning,
and that you’ll be able to opt-in easily if you are already using Tuist:
xcodebuild
in combination with the --only-testing
argument. tuist run
,
to run any app in the selected destination (e.g. iOS simulator).
A good use case for this feature is trying out an example app from any of the frameworks of the project,
without having to open Xcode. tuist doc
command, inspired by Cargo’s doc command, will generate dynamic documentation from the code that belongs to the project in the directory where the command is run from. Thanks to it, you will no longer have to depend on another tool, or add more configuration files. At Tuist, we are aiming to help teams be productive when working with projects of any scale.
We are aware that not all the projects can have a tooling or infrastructure team, and for that reason, we are designing features optimizing for zero configuration. Instead of having to depend on many tools to do your job (e.g. project generators, Fastlane, Rake, documentation generator), you’ll depend on just one that will make your projects the source of truth.
Unlike many developers, we believe that a large scale doesn’t mean complexity. Therefore, we are making a huge effort to not port complexity from Xcode over to Tuist. Furthermore, we are providing developers guidance on our community forum and Slack group, to get rid of the accidental complexity that they have accumulated over the years.
If there’s one important thing that I’d like you to take away from this blog post, that is: large != complex
.