I've been wanting to get my feet wet with protocol-oriented programming for a while now. The difficulty lay in the fact that the app I write is a mismash of old and new, Objective-C and Swift. Protocol-oriented programming seems to really like having a Swift-only environment. So I decided to throw out reality for a few hours and decide how I would architect the model layer of the app if I were starting from scratch today.

It was an brain-tingling prospect. All Swift! Protocols! Generics! Non-Int Enums! I'll never go back, I can't! I won't!

I started with my model collection. The Collection class was one of the oldest classes in the app and while it had been re-written in Swift, it was mostly a straight port without taking advantage of much Swift-specific coolness.

class Collection {
      private(set) var models: [ModelType]()
      let dataSource: DataSource
      let tableName: String
      var sortDefinition: SortDefinition?

      func add(model: ModelType)
      func remove(model: ModelType)
      func destroy(model: ModelType)
      func commit()
      func fetch()
      func sort()
}

There was a lot more to it, but this would do to start. The Collection class was a similar concept to the NSManagedObjectContext that you get with CoreData. It held models, fetched model data from the data source and committed changes to the models back to the data source. In this brave new world of Swiftitude, I knew I wanted to rewrite this class with one feature in particular: generics.

class Collection<T: ModelType> {
      private(set) var models: [T]()
      let dataSource: DataSource
      let tableName: String
      var sortDefinition: SortDefinition?

      func add(model: T)
      func remove(model: T)
      func destroy(model: T)
      func commit()
      func fetch()
      func sort()  
}

You smell that, kids? Smells like the future.

This let the compiler know that I'm going to be throwing all kinds of stuff in there. I constrained it to ModelType because I knew that, realistically, it was only going to be things adhereing to the ModelType protocol that I was going to put in there. I did have a moment of "well, what does this even get me?" But stay tuned, there's more.

I was going to start fleshing out the methods, when the Swift Spirit whispered in my ear, "Use the protocols...".

I wondered how, or why and then I remembered there was a very good business reason for using protocols on my Collection class. There were models that the user could mutate and save those changes back to the DataSource, but there were others should not be edited by the user, but were still fetched into the Collection. These models didn't need the mutating functions like commit() and, in fact, shouldn't have them.

And thus a protocol was born.

I fired up a new .swift file and named the new protocol Persistable.

protocol Persistable {
    // Some model-specific mutating features go here
}

Now, I could have some of my models be persistable to the DataSource while others would be essentially read-only. I went back to my Collection and pulled the mutating functions into their own extension.

class Collection<T: ModelType> {
      private(set) var models: [T]()
      let dataSource: DataSource
      let tableName: String
      var sortDefinition: SortDefinition?

      func fetch()
      func sort()  
}

extension Collection where T: Persistable {
      func add(model: T)
      func remove(model: T)
      func destroy(model: T)
      func commit()  
}

Cool, cool. Now all of the functions that changed the collection once it had been loaded from the database would only be available if the models it contains are Persistable.

That was it; I had the need, the need for refactoring class functionality into protocols and extensions.

The sort function wasn't just a simple sort, but a sort that was based in business logic. Each model communicated to the Collection what its sort capabilities were. Some models, however, were simply back-end data that didn't really need to be sorted at all. ⌘-N

protocol Sortable {
    // Some model-specific sort methods go here
}

⌘-SHIFT-O File Name: Collection.swift

class Collection<T: ModelType> {
      private(set) var models: [T]()
      let dataSource: DataSource
      let tableName: String
      var sortDefinition: SortDefinition?

      func fetch()
}

extension Collection where T: Persistable {
      func add(model: T)
      func remove(model: T)
      func destroy(model: T)
      func commit()  
}

extension Collection where T: Sortable {
      func sort()  
}

Extensions can't hold stored properties, so sortDefinition had to stay in the main class implementation, but sort() got its own little home and would only be available if the models in the Collection were sortable.

Not only was protocol-oriented programming a new way of doing things, but it could acutally be useful. If commit() wasn't popping up in my code completion for a Collection, it would spur me to remember that that model shouldn't (and now, couldn't) be edited. The core of the class was lean and methods were organized in a logical manner instead of one mega-class definition that does All The Things.

I had to return to reality, but I made sure to save my project. This wouldn't be the last time I would visit this Swift-only fantasy land...