Shipping fast doesn't mean shipping trash [PART 2]
We finish the practical SOLID principles to still launch products fast
Hey, listen!
In last week’s issue, we started discussing how you can still ship fast but maintaining a decent level of code cleanup.
I didn’t want to put you to sleep by reading, so I split it into two parts.
Today we’re gonna see the LID principles…
It’s summer in Spain! Or at least regarding the calendar: 16 ℃ in Gijón 🥶
Last week we talked about Single Responsibility and Open—Closed principles.
We’re gonna explain today the 3 ones remaining:
Liskov Substitution
It was introduced by the Californian computer scientist Barbara Liskov.
She’s now 84 years old, so you can imagine how long this principle has been around—spoiler: since 1987.
It basically states that subclasses should replace base classes without affecting program behavior.
We can solve this by our classes depending on abstractions, and not on implementations.
In other words, depending on interfaces (protocols in Swift).
As we said in the first part, SOLID principles are linked with each other.
It turns out that when we conformed to Open—Closed principles, making abstractions of DatabaseService, NetworkService, etc… and injected dependencies, we were conforming as well to this principle.
Magic! 🪄
Interface Segregation Principle
This is a pretty straightforward one to understand.
If a class depends on an interface (protocol), it should need to implement all its methods.
If an interface defines several methods that a class won’t need, rather than forcing implementing them, for instance, leaving them blank, you should split that interface in smaller ones.
This can be better shown in code.
Let’s go back to our AuthenticationService
example. We can code something like this to authenticate with Firebase, for example:
Imagine that now, we need to do email authentication with another different provider and this provider lacks of social logins features, for instance.
Using AuthenticationProtocol
would violate the Interface Segregation principle, because we are forced to implement two functions that we don’t need:
Instead of that, we can better split AuthenticationProtocol in two new ones, so our new authentication service doesn’t need to implement social logins:
And we refactor our FirebaseAuthenticationService to conform to both protocols:
Therefore, what we did here was segregating our interfaces ✅
Dependency Inversion
“High-level modules should not depend on low-level modules. Both should depend on abstractions.”
In other words, depend on protocols.
Again, these principles depends strongly on each other.
The solution that we applied for satisfying the Open—Closed and Liskov Substitution principles, also conforms to the Dependency Inversion principle.
By doing this, our high-level modules or business logic, don’t depends on low-level modules (frameworks like CoreData, UIKit, Firebase SDK, etc…)
BONUS: Don’t Go Crazy Principle
We have to be flexible when applying these principles.
It’s necessary having them in mind to write flexible, scalable and maintainable code.
BUT.
We also want to ship fast our MVPs to validate them and probably we won’t touch that code anymore.
Thus, you don’t have go mad creating the craziest abstractions struggling to apply 100% to SOLID.
The more you program, the more you’ll find the right balance between shipping decent code and pushing it to production ASAP.
This week I added support for Anthropic Claude in my iOS boilerplate WrapFast. Thanks to SOLID, it was a piece of cake integrating it in the existing project 😚