Looser dependencies with Swift

What kind of types do you use to manage dependencies between objects in Swift? How do you keep your objects that depend on others testable? How do you prevent an addition of a method from causing changes to test code? Couplings should be loose, but how to achieve that?

Assumptions

I’m making a few assumptions in this article:

  1. Your software has semi-permanent pieces — let’s call them services — that other parts of your software depend on. Model, networking, database layers, etc.
  2. Your services aren’t laser-focused, perfectly factored little gems that each provide just the right set of methods that everyone using them requires.
  3. You want to test the code that uses those services.

Everyone gets an interface

If you spent time in the enterprisey Java mines of the 90s and 00s like I did, you probably learned that your classes should have separate interfaces. And on the projects I saw, more often than not, there was nothing abstract about the interfaces: it was one interface per class, because most of them didn’t describe behavior, they just were there so it was possible to substitute them with dummies/mocks/fakes/whatevers¹ when writing tests.

In Objective-C land, it’s possible to substitute a class with another because it’s not particularly strongly typed, but that same paradigm has been pretty popular there too, with the difference that it’s called a protocol, not an interface. And the same thing in Swift.

So you have a ProfileService, and it implements ProfileServiceInterface, with the exact same set of public methods. You can agonize over whether it should be called ProfileServiceInterface or just ProfileService and have the implementation carry a more awkward name, if you want to pretend there’s abstraction happening here. Whatever makes you feel good.

struct Profile {
    let name: String
}

protocol ProfileServiceProtocol {
    func readLoggedInProfile() -> Profile
}

class ProfileService: ProfileServiceProtocol {
    func readLoggedInProfile() -> Profile {
        fatalError()
    }
}


class ProfileViewModel {
    private let profileService: ProfileServiceProtocol

    init(profileService: ProfileServiceProtocol) {
        self.profileService = profileService
    }
}

Square pegs

There’s a bunch of problems with the approach I described above, including:

  1. It’s arguably a misuse of protocols. Protocols are well suited to things where you have different behaviors hiding behind similar interfaces — collection type hierarchies being a favorite example — and in Swift’s case about code reuse. You aren’t describing behavior here, you’re just copying the implementation declarations.
  2. It cements a supply side view of the interface. Services evolve and rarely manage to stay tightly focused over their lifetimes. Once your interface has more than one method and more than one user, it’s almost certain some users are only going to care about a subset.
  3. Adding things to the protocol causes all implementations of that protocol — of which there can be several in tests — to change.

While we ignore that first point, Swift gives us a way to address the other issues: you can declare conformance to protocols outside the implementation. For dependencies, this means that the units that need profiles can each define their own protocol and declare that ProfileService implements it, moving from a supply side definition to a demand side one. Like this:

class ProfileViewModel {
    private let profileService: ProfileViewModelProfileServiceAPI

    init(profileService: ProfileViewModelProfileServiceAPI) {
        self.profileService = profileService
    }
}

protocol ProfileViewModelProfileServiceAPI {
    func readLoggedInProfile() -> Profile
}

extension ProfileService: ProfileViewModelProfileServiceAPI {}

And voilà: as long as the service implements the method described in the protocol, you’re done. You don’t need to worry about implementing the rest of it in tests and you can even use that protocol to evolve ProfileViewModel at a different pace from ProfileService.

Less protocol, more action

Really the above, with the depender defining the protocol of its dependency, is not too bad.

There’s a few small downsides:

  1. Protocols are top level objects in Swift, at least for now.
  2. Having a protocol means you have to have a type that implements it. That’s fine with the “just protocolify a concrete service” case, but can be a hassle in tests.
  3. Not usually an issue in this case, but protocols can be treacherous in that their behavior radically changes if you decide an associated type would be appropriate.

None of these are deal breakers, but there’s a way I find to be nicer: instead of defining a protocol for your dependency, just define a struct that carries closures. Swift's structs are both syntactically and performance-wise extremely lightweight and perfectly suited to the task of providing an insulation layer.

class ProfileViewModel {
    struct ProfileServiceAPI {
        let readLoggedInProfile: () -> Profile

        init(readLoggedInProfile: @escaping () -> Profile) {
            self.readLoggedInProfile = readLoggedInProfile
        }
    }

    private let profileService: ProfileServiceAPI

    init(profileService: ProfileServiceAPI) {
        self.profileService = profileService
    }
}

extension ProfileViewModel.ProfileServiceAPI {
    init(profileService: ProfileService) {
        self.init(
            readLoggedInProfile: profileService.readLoggedInProfile)
    }
}

Now you don’t have an extra top-level protocol and you don’t need a type to implement the protocol with, which can make the code a lot nicer to test: with protocols, more often than not, I find myself writing the equivalent of ProfileViewModel.ProfileServiceAPI in tests anyway, and have it implement the protocol. This cuts out that one extra step. And the struct retains basically all the benefits of the one protocol per depender approach, keeping your dependencies loose and adaptable.

One downside can be that closures don’t have named parameters. If you’re wrapping an API with lots of those, it’s simple enough to add methods to your struct that restore the names:

class ProfileService {
    func readLoggedInProfile() -> Profile {
        fatalError()
    }

    func readProfile(ofUser name: String) -> Profile? {
        fatalError()
    }
}

class OtherUserViewModel {
    struct ProfileServiceAPI {
        private let readUserProfile: (String) -> Profile?

        init(readUserProfile: @escaping (String) -> Profile?) {
            self.readUserProfile = readUserProfile
        }

        func readProfile(ofUser name: String) -> Profile? {
            return self.readUserProfile(name)
        }
    }

    private let profileService: ProfileServiceAPI

    init(profileService: ProfileServiceAPI) {
        self.profileService = profileService
    }
}

extension OtherUserViewModel.ProfileServiceAPI {
    init(profileService: ProfileService) {
        self.init(
            readUserProfile: profileService.readProfile(ofUser:))
    }
}

You could continue one step further: in some cases it may make sense to forego that struct completely and instead just inject the closures directly into the class using them. But having the struct there may make it easier to see afterwards where they're coming from.

Over the course of these changes we've made the view model depend only on the signatures of the functions it requires, regardless of who implements them and what else they implement. It's now easier to test and to evolve. None of this will prevent you from tying your codebase and yourself into knots with a badly designed dependency graph, but if should help at least locally.

Footnotes

  1. If you remember the difference between a dummy, a mock and a fake you’re better, or more thoroughly brainwashed, than me. Take your pick.
Article page

GraphQL with Swift

Know that thing where you start writing a tool for something, discover it needs (for some values of “need”) something slightly complicated, you decide to write a library for said complicated thing, then discover you don’t need the tool you were working on in the first place but decide to write the library anyway?

So I wrote GraphQLer (pronounced “graph quiller”), a library for generating GraphQL from Swift. It’s not the only Swift GraphQL library around, but I believe it’s far simpler — mostly by being far less ambitious — than the other solutions. Throwing in the kitchen sink seems to be popular in this space, forcing you to shape your code around the libraries. That may work out great in some situations, but it wasn’t what I wanted.

GraphQLer just defines a bunch of data types that model the things found in the spec, and functions for turning those data types into strings. Its only purpose is to make it easier to write syntactically valid GraphQL documents. It has no dependencies — it doesn’t even import Foundation — and you handle all networking and responses as you see fit.

It works with the Swift Package Manager. There’s also a Xcode workspace and a playground, but you need to run SPM to get an Xcode project. I'll add an Xcode project if I have to to make it work with Carthage, but the WWDC 2019 keynote is tomorrow and I'm hoping there will be surprises related to SPM.

PS. A shout out to jazzy and GitHub Pages: it's ridiculous how easy it is to publish documentation for a Swift project these days.

Article page

annotate-git-commit

I got into the feature branch workflow back when I was using Mercurial. I’ve since discovered that Mercurial’s branches aren’t really suitable for short-lived branches and switched to Git for a variety of reasons, but I still wish my commits carried with them metadata about what they were related to.

I also still wish my VCS had a sane UI, but that’s an unrelated topic.

Anyway, my Git branches, when I’m working with a ticketing system, usually carry in their name a ticket identifier in an easily parseable format. I wrote a small too for extracting that ticket identifier and pasting it to the bottom of my commit messages: annotate-git-commit. You can use it with Git’s prepare-commit-msg hook.

Article page

TODO.swift

I saw this Swift trick a few years ago on Twitter. I can’t recall who it was, sorry. It sounded way too clever at first, but after a while I tried and decided I love it. Now it’s one of those things I add to every project.

Sometimes you just want to get on with declaring your functions without worrying about the actual implementations. A small enough function with good enough name and types is pretty much done. Filling out the body is just something that will distract you and make you lose the big picture by bogging you down in the details.

The problem with incomplete functions is that they make the type checker unhappy. Have a return type but no return statement? That’s a compilation error. And the more interesting your types, the harder it is to make a temporary hack to placate the compiler.

Swift offers an escape hatch: the Never type. Call a function that returns Never and you don’t need to worry about writing a return. So this will compile:

func foo(zap: Bar) -> Fnord {
    fatalError("Unimplemented")
}

The code will compile, it will just crash at run time. Exactly what we wanted. But we can do better.

You can write your own function that returns Never as long as you ensure it never returns. Like, for example, by calling fatalError as we did in the previous example:

func TODO() -> Never { fatalError("Unimplemented") }

func foo(zap: Bar) -> Fnord {
    TODO()
}

That’s an clear improvement: less need for repeating yourself, and easier to find in the code. The next small step will be to ditch the parentheses by switching to a computed property:

var TODO: Never { fatalError("Unimplemented") }

func foo(zap: Bar) -> Fnord {
    TODO
}

Not a huge improvement, but better, anyway.

There’s one more thing we can do: we can make it harder to forget these in the code. TODO doesn’t cause errors, but we can make it cause a warning by abusing Swift’s deprecation annotation. And because you care for the quality of your code base you fix all warnings and so can’t help but notice the new ones when you compile.

@available(*, deprecated, message: "Unimplemented")
var TODO: Never { fatalError("Unimplemented") }

func foo(zap: Bar) -> Fnord {
    TODO
}

Now the TODO line inside Foo will cause a warning:

'TODO' is deprecated: Not implemented

You’ll get a nice warning reminding you to implement the function before merging your code in, but you can do it when you’re ready.

Article page

Converting UNIX dates to a readable format on Mac

I tend to run into UNIX dates — large numbers representing points in time as seconds since the first second of 1970, something like 1500000000 for 2017-07-14 05:40:00 — all the time in my work, dealing with servers, web APIs, etc.

Here's how to make them readable on a Mac. All text below assumes macOS 10.13.

Terminal

The most straightforward solution is probably to open Terminal.app and run date:

# Outputs Fri Jul 14 05:40:00 EEST 2017
date -r 1500000000

# Outputs 2017-07-14 05:40:00
date -r 1500000000 +'%F %T'

Services: shell + AppleScript

Command line isn't your only option. macOS has a Services menu where you can add all sorts of useful things that operate on your selection:

Services menu screenshot

You can create a Service menu item pretty easily from the date invocation above.

  1. Launch Automator
  2. Create a new document. Select Service when Automator prompts for a type.
  3. Add "Run Shell Script" action. Select /bin/sh as the shell. Set the following as the content:

    sh xargs -I INPUT date -r INPUT +'%F %T'

  4. Add a "Run AppleScript" action. Set the following as the content:

    applescript on run {input, parameters} tell me to display dialog input with title "Date" buttons "OK" return input end run 5. Save the document, select text anywhere, select the \<Program Name> → Services → \<Your Automator document name> menu item, and you'll get a dialog box with the converted date.

Services: Javascript

Starting a shell, invoking (with no input validation) a couple of command line tools, then piping that to AppleScript is not very satisfactory.

You might be able to eliminate the first step and do all of it in AppleScript. But that would mean writing more AppleScript. I prefer to avoid that.

macOS offers another option: JavaScript for Automation, also known as JXA. Not exactly the greatest of languages either, but it's not as read only as AppleScript. And while its standard library is not great, it can handle dates. So we can reduce our Automator script to one action and improve our input validation at the same time.

  1. Start by again creating a new service in Automator.
  2. Add a "Run JavaScript" action. Set the following as content:

    ```javascript function run(input, parameters) { const app = Application.currentApplication(); app.includeStandardAdditions = true;

    const inputInt = parseInt(input);
    if (isNaN(inputInt)) {
        app.displayAlert("Not an integer: " + input);
        return input;
    }
    
    const d = new Date(inputInt * 1000);
    
    app.displayDialog(d.toISOString(), {
        withTitle: "Date",
        buttons: ["Close"],
        defaultButton: "Close",
    });
    
    return input;
    

    } ```

  3. Now again save the document. The new service is available in the Services menu.

Here's the window you get:

Date dialog screenshot

The output from toISOString isn't quite as nice as %F %T from date, but if you're used to ISO dates, it's not bad. Making it prettier is left as an exercise to the reader. Start with Mozilla's documentation for Date.

There you have it! Maybe some day we can use Swift and the Foundation libraries for automation, but meanwhile I can live with the JS solution.

Article page

Netstrings for Swift

I published another small Swift library: swift-netstring implements reader and writer for D. J. Bernstein's Netstrings format in Swift.

Netstrings is a specification for length-prefixed and delimited byte strings, useful mostly as a low-level building block for network protocols. With swift-netsring you can parse incoming data from a socket or some other stream by wrapping the stream in a simple closure that reads bytes synchronously. Or you can feed it an array of bytes.

You can find examples in the repo in the README, in a Swift playground and in tests. There's also API documentation (a big thank you to Jesse Squires for an excellent guide for setting up docs on GitHub pages for a Swift project.)

Article page