As a professional developer, it’s my job to work with the code that I’m given, even if it’s not ideal or aligned with my own coding style. That doesn’t mean I can’t have my preferences and peeves. Sometimes I inherit Swift code that looks like this:
The main thing this code has going for it is that it’s terse, which can be a good thing for some Swift code. But there are problems:
MARK:comments aren’t uniformly applied, which makes it hard to tell at a glance when one section ends and the next begins.
- Alternating use of single and double line breaks suggest incorrect impressions of logical groupings.
- There’s no overarching system to how the methods are grouped and ordered. Some are superclass overrides, others are custom methods, others are IBActions, etc. In order to know if a method is implemented, you have to read or search the entire file.
- Essential dependencies are exposed as read/write properties, even though they should only be set once. Most likely the only reason these properties are exposed as vars is because the view controller is initialized via a storyboard, which doesn’t permit custom init methods.
- Members aren’t given explicit access levels, so it isn’t clear to the reader which methods and properties are meant to be used by other members in the module, and which ones are just lazily defaulting to
- Documentation-level comments use a mix of two and three slash formatting, and are placed at inconsistent locations.
When I encounter code like that, I try to clean it up:
- The code is separated into sections by member type and access level. Properties are all above the
initsection, methods are below it. Both the property and method sections are further divided (roughly) by access level: Public/Internal, Overrides, Interface Builder, and Private.
MARK:headers are added at the top of every code section.
- No more than one empty line is used between any two sections. No blank lines are placed between property declarations (except for those that have documentation).
- Everything that can be made private has been made private. This includes dependencies. Dependencies are passed in as arguments to a new static factory method which initializes and correctly configures the view controller from a storyboard. Interface Builder outlets and actions have also been marked private, since those should not be accessible outside of this class. Though this sacrifices the ability to use segues and storyboard references, the clarity and reliability gained via explicit “injected” dependencies far outweighs those losses.
- Documentation uses the style seen throughout the Swift Standard Library (three slashes, truncated to 80 character line lengths).
Here’s how it looks with some of the details above removed, in order to capture all code sections in one screenshot:
I don’t expect everyone to agree with my preferences. This is just what I like. But I think I can make pretty good objective arguments for the principles I’m trying to put into practice:
- Nothing is exposed to the module (or anything else for that matter) that isn’t expressly designed to be freely used at that access level.
- All external dependencies are explicitly required at (or near) init time, heavily discouraging (if not outright preventing) misuse.
- A consistent, logical organization is used when breaking up code sections, so it takes less effort to find a given method or property when you need to review it.
- Broader access levels are moved near the top so that the exposed API surface is easier to see without having to jump to a generated interface.
- Documentation uses platform-consistent formatting so it’s easier to distinguish from an implementation-detail comment.