Thoughts, reflections, and ideas

The motivations behind building Tuist

Posted on

It's been a long time working on xcodeproj and Tuist, two open source projects that I'm very proud of. Before I started working on xcodeproj, the library that Tuist depends on, I'd worked on other open source projects that were Swift libraries. They had a much smaller scope and were intended to be used as a helpers and time savers in iOS apps.

The motivation to build Tuist came to me when I was working at SoundCloud. We handled the growth of the project, which brought an increase in build times, by splitting up the project into smaller projects and frameworks. It was back then when I realized how hard and cumbersome maintaining Xcode projects can be. Before I moved on from the company, there were around 8 frameworks, each with 3 targets within a project. Most of them were very similar, but we could barely reuse anything between them, just the build settings. Not only it was cumbersome, but also an error-prone setup. From time to time, we got linking errors and compilation issues caused by small changes that seemingly had no relation with the errors raised. I then set out to build Tuist, with the goal of making it easier to work with Xcode projects at any scale and with any experience.

I wanted to build Tuist in Swift, but I needed a way to read, update and write Xcode projects, like CocoaPods had with xcodeproj. Unfortunately, there wasn't such a thing on the Swift community, so I worked on the Swift brother of that library, xcodeproj. It was while I was working on the library when Yonas opened an PR on the repository. How came someone was already using the library when it as not ready to be used yet? After a quick chat where I asked him what led him to use the project, I realized that we was building a Xcode project generator, something that to some extent, overlapped with what I wanted to achieve with Tuist.

I had a sadness feeling. Someone had had a similar idea while I was doing some groundwork for that idea to become real. After sleeping over it a few nights, I decided to pause the idea of Tuist, and rather focus on releasing the first version of xcodeproj, which would support the generator that Yonas was building, XcodeGen, as well as any other tools that the community decided to build. During that time I realized two things. The first one was that, even though XcodeGen had things in common with the ideas that I had for Tuist, the goals were completely different. The second realization was that by giving up on the idea of building Tuist I lost the motivation for building xcodeproj. I was building a library, with the plans of using it, but I had decided not to.

An inner voice told me to make Tuist real, but another pushed the idea back to not seem like a competition with XcodeGen. The evolution of XcodeGen continued to prove me that we were aiming for different goals and principles and that there was no reason to feel bad about building Tuist. On one side, XcodeGen was coming up with a declarative interface for defining projects and taking the opportunity to simplify and making the definition of projects easier. On the other side, Tuist aimed to abstract complexities of Xcode projects at any scale, and make it easier not only to generate projects but build, test and release them.

Another area in which both projects diverge is the design principles. XcodeGen prefers configuration over conventions. Most of the attributes that are supported by Xcode projects are also supported by XcodeGen. If you need a tool that helps you define and generate Xcode projects with no conventions imposed by the tool, XcodeGen is your tool. On the other side, Tuist compares to Rails. It comes with simple and strong conventions weakly held, which are aimed over configuration. These conventions abstract developers from common complexities, like linking dependencies, and encourage them to follow good practices.

As you might know, many people criticize Rails for being so opinionated. I've seen similar comments on issues and pull requests on the Tuist repository. They are understandable so I take the opportunity to introduce them to XcodeGen and encourage them to use it.

I've had a few downs while working on Tuist, times when I thought I'd rather stop working on it and work on a project that people would like to use. Seeing people neglecting the use of it, or considering the use of other tools can be demotivating. I took me some time to accept that as something normal and not let it impact my motivation for the project. I took me also time to accept that working on a long-term project, like Tuist is, means that you get a moment of hype when you first release and announce it, that's when your motivation goes to the highest pick, and then it fades away. I was too used to the excitement of publishing tiny libraries and framework fairly frequently, which helped fed my ego.

I'd love Tuist to be thoroughly designed and continue to stay firm in its conventions. I'm trying hard to get people involved with their project and make them feel part of it as I feel. I few days back, I felt glad when I checked my GitHub notifications on Octobox, and I saw that contributors had been working on new features for the project while I'd been on vacation. It's a moment when you see that all the work that you did bootstrapping the project, creating a website, writing documentation and some other tasks, pays off.

I'm very excited to see all the ideas and features that we are in the backlog for Tuist. To give you a sneak peak of what's coming, . is working on supporting static transitive dependencies. This will allow configuring dependencies and their dependencies as static libraries with resources that will get automatically bundled and copied into the right product directories. Changing between dynamic and static linking will be easier than ever after we merge this feature in.

Moreover, xx and xx are working on re-structuring the project targets to make the logic of projects generation reusable. They found it practical and they'd like to extend it with their own additions. The current generation logic is very coupled to the Tuist's API so they are making it more agnostic.

I'm working on adding two commands, build and test so that you can build and test your projects by just running tuist build and tuist test in the directory where the project is defined. Most of the xcodebuild arguments will be inferred for you. What excites me the most about this features is that developers won't have to maintain Fastfiles or depend on Fastlane anymore. Another fact that I find exciting is that I'm porting the well-known xcpretty into Swift. I'll most likely extract it into a separate repository so that developers can use it in their own projects.

Slow but steadily, the baby is growing. We want to make sure that we are taking steps in the right direction and that we continue to be aligned with our values. Moreover, we keep improving our test suite, to which we recently added acceptance tests with Cucumber that test real scenarios. With projects and teams already depending on Tuist from their workflows, is crucial to make sure the tool works reliably and that minor versions don't break their projects.

It seems it was yesterday when I ran swift package generate to bootstrap the project. I can't wait to see all the features that we'll land on the project.