twone twone - 4 months ago 19
Swift Question

Prefer optional or non-optional when designing domain?

While defining model for my application what properties should I declare as optional and what as non-optional? What aspects I need to consider?

E.g I want to create entity

Car
. What type
engine
should be?

struct Car {
let engine: Engine?
}


or

struct Car {
let engine: Engine

init(engine: Engine) {
self.engine = engine
}
}


or

struct Car {
let engine: Engine = Engine()
}

Answer

Introduction

Many of us (me included) were not familiar with this problem.

Infact Objective-C (and many other languages like C, Java 1...7, etc...) forced a variable with a primitive type (Int, Double, ...) to always be populated. And they also always forced a reference/pointer variable to always be potentially nil. Se over the years we just adapted to these constraints.

Initially many Swift developers used implicitly unwrapped optionals

var something: Something!

This is the closest thing to declaring a reference variable in a way that behave similarly to the programming languages mentioned above but this way we don't really use the power of Optionals.

When should I declare a property of my model as optional?

The question you have to ask yourself is

In my data domain, can this entity exist and have no value for this specific property?

If the answer is no, then the property should be declared as non optional.

Example

A User struct representing the user of an app will always have a username and password populated.

struct User {
    let username: String
    let password: String
    let profileImageURL: NSURL?
}

On the other hand it could have a nil value for profileImageURL maybe because the user didn't upload a profile picture.

In this case a User value without a username just doesn't make sense, it can't happen and when dealing with a User value we should always have the guarantee (provided by the compiler) that there is username value in it.

So we make username non optional

It really depends on the domain

The "optionality" of the property of an Entity can differ from data domain to data domain.

E.g. this entity for a mailing list system

struct Person {
    let name: String?
    let email: String
}

makes sense because we could not know the name but we know for sure its email address.

On the other hand the same entity in another context like an Address Book could become

struct Person {
    let name: String?
    let email: String?
}

because maybe we created/saved an empty card.

Thumb of rule

As personal advice I suggest you to avoid optional values when you have doubts about it. If you declared a non optional property something that should actually be optional the problem will come up very soon.

On the other hand if you declared optional something that should be non optional you could never find out.

Important

And of course NEVER use a value of the domain of the property/variable to represent the absence of value

let birthyear = -1 //