SwiftLint doing its best to ease conflict

Anyone who has ever worked in a team knows only too well that there is no such thing as one true way of formatting code. Everyone has their own way of formatting and provided it compiles, all of those formatting choices are valid. So when it comes to formatting, it really is a personal choice based on some aesthetic. Often one of the first questions I ask when joining a new team is:

"Can I see the coding style guide?"

However when there is a style guide and you've read and followed it you will still get this most frustrating of PR comments:

"That's not how we do things here"

because a style guide is only good for when it's written and often the team's style changes but the guide stays the same. It can feel like playing a game that you can't win as a new joiner, and if the team you join is large enough with multiple developers reviewing your PRs it can really hit your confidence. So as well as reducing my stress during PRs I also insist on having a coding style guide because of the following benefits:

  • Quicker to review code
  • Easier to spot bugs
  • Improved intrateam communication
  • Improved team moral
  • Quicker on-boarding of new joiners

Getting to those benefits, however, can be a very painful process, potentially involving hours of discussion about mundane formatting points like: "where should the opening { go" or "if there should be a space after (". And once you have the coding style guide agreed you then have to enforce the rules and remember them yourself 😮. In the past I've experimented with automatic formatters but they have always felt "a bit broken" however for the past few months I've been experimenting with SwiftLint and have found it to be a very low impact way of enforcing a coding style guide.

SwiftLint 🏎️

On it's GitHub readme it's described as:

"A tool to enforce Swift style and conventions, loosely based on GitHub's Swift Style Guide."

and can be installed via Homebrew, CocoaPods or directly from source. As a team when we were trying out SwiftLint, there wasn't a pod to be installed so we used Homebrew but have recently switched over to using the pod to ensure that everyone has the same version installed. Following the Xcode integration setup described in the readme we set about disabling the majority of rules in the .swiftlint.yml. Due to the way that SwiftLint integrates into Xcode compiling the project shows the instances were SwiftLint believes you have broken one of the rules - I say believe because it's possible for SwiftLint to make mistakes but the authors of SwiftLint already have those covered and this allows you to disable rules directly in the source code using either of the following comment instructions:

// swiftlint:disable:next [insert_rule_name]
// swiftlint:disable:this [insert_rule_name]
// swiftlint:disable:previous [insert_rule_name]

We ended up with our .swiftlint.yml file looking like:

excluded: # paths to ignore during linting. Takes precedence over `included`.
  - Pods

  - force_cast
  - type_name
  - force_try
  - function_body_length
  - nesting
  - variable_name
  - control_statement
  - line_length
  - trailing_whitespace
  - statement_position
  - type_body_length
  - todo
  - valid_docs
  - missing_docs
  - file_length
  - function_parameter_count
  - cyclomatic_complexity
  - unused_closure_parameter
  - for_where
  - unused_optional_binding
  - redundant_void_return
  - void_return
  - vertical_parameter_alignment
  - unused_enumerated
  - redundant_discardable_let
  - empty_parentheses_with_trailing_closure

opt_in_rules: # some rules are only opt-in
  - force_https
  - empty_count
  - conditional_binding_cascade
  - explicit_failure_calls
  - explicit_init
  - redundant_nil_coalescing
  - syntactic_sugar

line_length: 120

    name: "Avoid asserting 'false'"
    regex: '((assert|precondition)\(false)'
    message: "Use assertionFailure() or preconditionFailure() instead."
    severity: warning

As you can see with SwiftLint you are even able to define custom rules. In the above snippet, we have decided to discourage the use of assert and precondition so that it shows up as a warning when they are used.

However this post isn't really about the contents of the .swiftlint.yml file but rather about the reduction of conflict that ensued once SwiftLint was switched on among team members. When we were enforcing/using a similar coding style guide as described in this earlier post for Objective-C we did so manually by leaving comments about infringements on PRs which in a team dynamic can begin to break down the bonds between team members. I find that people can be surprisingly robust when facing criticism that they feel is valid or significant enough; but criticise on something that they think is trivial and this is a cocktail for annoyance and hurt feelings. People and especially (if you allow me to generalise) programmers are not great at talking about what annoys them while that annoyance is small enough to be dealt with. Instead the annoyance grows and becomes resentment and before you know it you have people arguing rather than debating. Now there are many ways to overcome this however I found to my surprise that SwiftLint was one of those ways.

Peace among team members

Leaving everyone's ego alone 😈

With SwiftLint it's a tool rather than a person that is providing the initial feedback, freeing up the PRs to be about the bigger issues in the code. This ability to provide regular feedback throughout the development process without damaging anyone's ego is I think the main strength of SwiftLint. As the rules that SwiftLint is enforcing are driven by the Swift community, it results in the conversations about which rules to opt into (or as the case may be - opt out of) much more impersonal. Rather than two developers directly arguing for or against each other's rule/style (which can result easily in a confrontational debate) instead each developer is arguing for or against a rule/style which no one person has raised - this more easily allows one party to change their mind without their ego being too badly bruised. While we would like to think that as developers we are driven by logic and reason, it's been my experience that a good percentage of what we do is driven by "how it feels" and that instinctive sense that "our way is the best way". All of which is tied to our sense of self-worth/ego - once we are able to reduce the role of our ego in a debate/conversation we are able to more quickly reach a position which most people can accept).

I went into my SwiftLint experiment focused on the different rules it had and how enforcing those rules would produce a better code base. In the end I got all of that and a better team 🏄.

If you haven't used SwiftLint or are still unconvinced of its benefits, there is a great talk on it here.