By Casey Liss
 

In developing for Apple platforms — particularly iOS — there are many arguments that are disputed with the same fervor as religion or politics. Storyboards are evil, or they’re the only way to write user interfaces. AutoLayout is evil, or it’s the only reasonable way to write modern UI code. SwiftUI is ready for production, or it’s merely a new/shiny distraction from real code. All Swift files should be linted, or only overbearing technical leads bother with linting.

Today, I’d like to dip my toe into the pool by discussing linting. Linters are tools that look at your source code and ensure that very obvious errors are not made, and that a style guide is being followed. As a silly example, both of these pieces of Swift code are valid:

struct Person {
    var id: Int? = nil
}
struct Person {
    var id: Int?
}

A linter would have an opinion about the above. It may encourage you to use the bottom version — var id: Int? — because the explicit initialization of nil is redundant. By default, an Optional will carry the default value of nil, implicitly.

SwiftLint

In my experience, the first time I really ran into a linter was once I started doing Swift development full-time in 2018. The team I was on dabbled lightly in using SwiftLint, the de facto standard linter for Swift projects. The tough thing about swiftlint is that it has a lot of rules available — over 200 as I write this. Many of those rules are… particular. It’s very easy to end up with a very opinionated set of rules that are trying to change your code into something unfamiliar.

Trust me when I say some of these rules are quite a lot to swallow. One of my absolute " favorite " rules is trailing_whitespace, which enforces absolutely no whitespace at the end of a line of code. 🙄

Even if you want to embrace SwiftLint in your project, you then needed to parse through 200+ rules in order to figure out what they are, whether or not they’re useful, and how many times your own existing code violates each one. No thank you.

swiftlint-autodetect

Enter the new project swiftlint-autodetect by professional grump (but actually good guy) Jonathan Wight. This project — as with all clever ideas — is brilliant in its simplicity. When run against an existing codebase, it will run SwiftLint against all rules, and then figures out which ones are not violated at all. These rules that your code is already passing are then output as a ready-to-use SwiftLint configuration file.

swiftlint-autodetect generate /path/to/project/directory

The generated file will have all currently known SwiftLint rules included, but the ones where violations would occur are commented out, so they are ignored by SwiftLint. Using this file, you can integrate SwiftLint into your build process, painlessly, without having to change your code to meet some weird-ass esoteric linting requirement. 😗 👌🏻

Increasing Coverage

I’m very nearly ready to release a new project, and I’m doing some cleanup and refactoring to get ready for its release. I decided to add SwiftLint support using swiftlint-autodetect, but then I wanted to investigate what SwiftLint rules I was violating, but perhaps shouldn’t be.

Conveniently, swiftlint-autodetect has another trick up its sleeve: it can also output a count of the number of violations for each rule. Additionally, it will mark with an * which rules you can instruct SwiftLint to fix automatically using swiftlint --fix. That makes it easy to start at the bottom of the resulting list, where the counts are low, and use that as a guide to slowly layer on more and more SwiftLint rules, as appropriate.

swiftlint-autodetect count /path/to/project/directory

This is exactly what I’ve done: I started with the automatically generated file, and then went up the list that count generated to turn on rules that seemed to be low-hanging fruit. Some I decided to leave disabled; some I decided to enable and bring my code into compliance.

y tho

Thanks to the combination of these two subcommands on swiftlint-autodetect, I am now linting my source code before every build. I’ve fixed some inconsistencies that I know would bother me over time. I’ve also found a couple spots where taking a slightly different approach can help improve performance/consistency.

Because — not despite — I’m an individual developer, I find it’s important to use the tools available to you to help you keep your code clean, correct, and working. Though I don’t deploy every tool under the sun, I do think having some combination of CI, unit testing, and linting is a very great way to use computers as a bit of parachute that, normally, your peer developers would provide.