Jack Morris
dotSwift Talks Recap
Feb 16, 2020
Swift

A selection of talks from the recent iteration of dotSwift were recently made available, and whilst I was quite keen to go this year (a pesky ⛷ got in the way), I instead settled with watching a few of the recordings.

I love the quality of these talks, and the recordings, by the way. Personally I manage to stay far more engaged when the presentations are snappy, to the point, and well delivered, and all of the talks I checked out had these qualities. And they're all under 20 minutes! 👏

Below are some thoughts for a few that stood out for me.

MVC: Many View Controllers: Guilherme Rambo (@_inside)

I'm a little allergic to the acronyms that surround iOS app frameworks; I prefer to try and stay pragmatic, and I find myself gravitating to some flavour of MVC most of the time anyway. Guilherme's talk really resonated with me.

He describes “MVC with Sugar”, effectively a variant of MVC where heavy nesting of view controllers is encouraged. This helps skirt around the “Massive View Controller” pit that we can sometimes find ourselves in by being explicit about what each view controller is responsible for, rather than piling multiple responsibilities together into the same class.

He gives a few examples; a composition of view controllers to display different states, a generic collection view controller, and using view controllers themselves as “coordinators” (in the sense of the classic coordinator pattern), which I found the most compelling. However the main takeaway for me is that it's OK to use MVC, and you should feel comfortable adjusting it wherever you see fit. Favour composition of concepts, rather than applying one set of rules to your entire codebase.

He also provides a playground so you can try out his ideas in action.

Prototyping Custom UI in SwiftUI: Tobias Due Munk (@tobiasdm)

Tobias shows how you can rapidly (like, really rapidly) prototype a complex custom component using SwiftUI. He shares advice around building in interactability using @State, as well as some practical insight into framing subviews using .frame, and visualising their layout for debugging purposes.

He also shows off a few helpers. One is to “flip the ordering” around mask application, which makes perfect sense as soon as you see it. Rather than saying “here's some colour or pattern, mask it with this shape”, you can say “use this shape to mask the content of this colour or pattern”.

extension View {
  func maskContent<T: View>(using: T) -> some View {
    using.mask(self)
  }
}

// So, rather than...
SomeColorView().mask(MyShape())

// You could do...
MyShape().maskContent(using: SomeColorView())

The second is really interesting, and allows you to build conditional evaluation directly into the view. The example he gives is to use a property that conditionally applies a colour (using .maskContent) to the custom shape.

extension View {
  func `if`<T: View>(
    _ conditional: Bool, 
    transform: (Self) -> T
  ) -> some View {
    Group {
      if conditional {
        transform(self)
      } else {
        self
      }
    }
  }
}

var colorize = false
Gauge().if(colorize) { $0.maskContent(...) }

It's really quite amazing to see what he achieves in under 20 minutes. Whilst I'm still not won over by the current state of SwiftUI, this serves to demonstrate just how much potential it has for building custom UI.

Implementing Pseudo-Keywords through Functional Programming: Vincent Pradeilles (@v_pradeilles)

The combination of first-class functions and trailing closure syntax allow you to build functions in Swift that more closely resemble keywords. Vincent demonstrates this in his talk with two examples.

The first can be used to “weakify” self for callback closures (removing the need for the guard let self = self dance).

fetchData( weakify { data, strongSelf in
  strongSelf.doSomething(with: data)
})

Whilst useful, I found the second even more interesting. There are many circumstances where you may wish to “debounce” a closure execution, in the sense that you wish to ignore rapid invocations, instead waiting for a “pause” to execute. One example he provides is making a network request whilst a user is typing in a search field; you only want to make the request after the user has stopped typing, not on every character.

Vincent provides a function that transforms a closure so that invocations are “debounced” in this way.

let didScrollHandler = debounced { 
  // Only executed when the user _stops_ scrolling.
  // Rapid invocations will be cancelled.
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
  didScrollHandler()
}

At the conclusion of the talk he warns about overuse of such concepts, a warning I would certainly echo. Whilst it's tempting to implement many small helpers in the form of “keywords”, too much “magic” can make the resulting code extremely difficult to reason about. Crucially, it gets to a point where it no longer looks like Swift, and is very confusing to readers who may not be aware of this functionality.

When used appropriately however, the techniques that Vincent covers can certainly help to reduce boilerplate and improve the usability of commonly required transformations.

BFFs for Swift: Tim Condon (@0xTim)

Tim describes a very real problem: how do you handle the complexity imposed by your API on the client? Maybe you have to make a ton of network calls just to piece together the information that your client needs - what will this do to battery life, network consumption, or data loading latency?

He proposes the idea of a BFF—the “Backend For Frontend pattern”—where the client team maintains a backend that's used exclusively by that client. This backend talks to the main API, making as many calls as required (all very fast, as the services could be co-located), before aggregating data together in a way that's useful for its client. It can expose a separate API for its client, and the client won't need to worry about data complexities introduced by the main API.

In general I like the idea. I do wonder where the threshold is for building something like this; obviously if the main API is relatively simple, then it's probably not worth the effort.

The main gem comes at the end of this talk however, which made me want to go and immediately build a backend in Swift. The promise of sharing Codable models across the frontend/backend, and not have to think about underlying transport (who cares! It's Codable) is awesome stuff. Server-side Swift really looks like it has potential, and I'm more keen to try it out now than ever.

~

Thanks for reading! I'd love to hear your feedback; feel free to contact me directly.