Write Beautiful Swift With Tailor

Even if you are working alone on a software project, it is a good idea to adopt a coding style to make sure the code you write is consistent. This is especially true if you work in a team of developers.

Most developers have strong opinions about how code should be written and formatted. Do you put the curly brace of an if statement on a separate line or on the same line as the condition of the if statement? I am sure you have an answer at the ready and an argument or two.

In today's post, I would like to show you Tailor, a wonderful tool to enforce a set of guidelines and best practices to write beautiful Swift.

Installation

With Swift open source, developers of open source projects make an extra effort to make their tools compatible with multiple platforms and Tailor is no different. Tailor is compatible with macOS, Linux, and Windows. In this tutorial, I show you how to use Tailor on macOS.

Tailor's website lists a number of installation options. On macOS, the easiest option to install Tailor is through Homebrew. Note that Tailor has a dependency on Java and Homebrew may prompt you to install Java first.

brew install tailor

Command Line

For this tutorial, I will be using an application that manages a shopping list. You can download the application from GitHub if you would like to follow along.

Tailor is a command line tool and getting started with Tailor is as easy as executing the following command.

tailor NoteViewController.swift

This is the output I am seeing in Terminal. As you can see, Tailor is very strict by default. Fortunately, we can tell Tailor that we would like it to ignore some of its rules.

The output generated by Tailor.

With the following command, we tell Tailor to inspect the same file and ignore warnings related to trailing whitespace. This is much better. Don't you think?

tailor --except=trailing-whitespace NoteViewController.swift

The output generated by Tailor.

Xcode

What I like most about Tailor is its seamless integration with Xcode. Navigate to the root of the project and execute the following command.

tailor --xcode=./Notes.xcodeproj

Even though it may seem as if nothing has happened, the above command has added a build phase to the project's default target. Open the project in Xcode to see for yourself.

Adding a Build Phase for Tailor

Build the project to see how Tailor works in combination with Xcode. Warnings and errors are automatically visible in the Issue Navigator on the left. How nice is that?

Warnings and errors are visible in the Issue Navigator.

There is one problem, though. The Issue Navigator is cluttered with warnings about trailing whitespace. To remedy this, we need to update the build phase Tailor added for us. Change the script of the build phase to tell Tailor to ignore rules related to trailing whitespace.

if hash tailor 2>/dev/null; then
  tailor --except=trailing-whitespace
else
  echo "warning: Please install Tailor from https://tailor.sh"
fi

Configuration

You can also tell Tailor to include or exclude particular files and folders. At the root of the project, add a file named .tailor.yml. Before Tailor inspects the project against its rules, it loads the contents of this file and configures itself accordingly. This is what the configuration file could look like for a project that uses CocoaPods to manage dependencies.

include:
  - Classes

exclude:
  - Pods

Tailor now includes every source file in the Classes folder and ignores the source files in the Pods folder. There's no need to lint third party libraries.

We can also enable and disable rules in .tailor.yml. Earlier, we updated the build phase Tailor added to disable the trailing whitespace rule. It is much easier, and recommended, to disable the rule in Tailor's configuration file for the project.

except:
  - trailing-whitespace

Remove the exception from Tailor's build phase and build the target again. The result should be the same.

Disabling Violations

I already mentioned that Tailor is very strict. There will be times that you want Tailor to ignore a particular violation. At the same time, you don't want to disable the rule that causes the violation for the entire project. The solution is quite simple. Add the following comment to the line you want Tailor to ignore.

@IBAction func save(sender: UIBarButtonItem) {
    if let title = titleTextField.text, let content = contentTextView.text { // tailor:disable
        // Update Note
        note.title = title
        note.content = content
        note.updatedAt = NSDate().timeIntervalSinceReferenceDate

        // Pop View Controller From Navigation Stack
        navigationController?.popViewControllerAnimated(true)
    }
}

What's Next?

There is much more you can do with Tailor, such as colorizing output and forcing builds to fail if particular rules are violated. The latter is especially useful in combination with continous integration.

You can read more about Tailor on its website and on GitHub, which also includes a complete list of Tailor's rules. Give it a try if you want to step up your game with Swift. Questions? Leave them in the comments below or reach out to me on Twitter.