Protect yourself from models !

You probably use models in your code every day and so do I. The major problem with a model is that it will surely evolve. It will evolve because the business will require a change or because a new feature will be needed and thus will require the model to change or because the api will have new fields or different informations. The best case is that this evolution will not touch your code, the worst case is that this evolution will destroy your code. But in any case you depend on this model and this is generally bad…

Now what I do when I work with a model is that I use Dependency Inversion to protect myself against it.

Let’s take an example (in Swift) :

struct City {
	var name: String
}

class User {
	var firstName = "Fred"
	var lastName = "Fauquette"
	var cityOfBirth = City(name: "Brussel")
}

Those are my models. They were defined long before I arrived and the team requires me to use them which I will not do.

On the other hand I will write this piece of code before :

protocol UserProtocol {
	var name: String {get}
	var cityOfBirthName: String {get}
}

Why ? Because in my User Story, it is requested to display the full name of the user and the name of his/her city of birth. Then I will start writing my own code like this :

class MyPresenter {
	var user: UserProtocol
	init(user: UserProtocol) {
		self.user = user
		print(displayInfo())
	}
	func displayInfo() -> String {
		return user.name + " born in " + user.cityOfBirthName
	}
}

This enables me to work with my own model if I want, like this :

class MockUser: UserProtocol {
	var name = "Me"
	var cityOfBirthName = "Charleroi"
}

var myTestPresenter = MyPresenter(user: MockUser())

I could even unit test the MyPresenter class like this :

class MyPresenterTests: XCTestCase {
	func testPresenter() {
		var myTestPresenter = MyPresenter(user: MockUser())
		XCTAssertEqual("Me born in Charleroi", myTestPresenter.displayInfo())
	}
}

So far I did not even use the model at all and I worked completely independently from the existing code. My own code if 100% bullet proof as it is unit tested and if someone makes a change in the model I don’t even know it and do not need it.

Now the last thing is to do the wiring, for this, I will extend the functionality of the existing models to make them implement my interface (protocol), like this (again in Swift but it also works for other languages) :

extension User: UserProtocol {
	var name: String {
		return firstName + " " + lastName
	}
	var cityOfBirthName: String {
		return cityOfBirth.name
	}
}

This is where you start to interact with the existing model, but it’s relatively easy to maintain and if it breaks you will know quickly where and why. You can now change your implementation from MockUser to real User like this :

//var myTestPresenter = MyPresenter(user: MockUser())
var myPresenter = MyPresenter(user: User())

I hope that you see why you should protect yourself from the models you will use.

One thought on “Protect yourself from models !”

Leave a Reply

Your email address will not be published. Required fields are marked *