Shipping fast doesn't mean shipping trash [PART 1]
Practical SOLID principles to swiftly launch MVPS
Hey, listen!
I love shipping MVPs fast ⚡️
But.
I also love that my code doesn’t harm my retinas.
And do you know what?
You can still launch fast while not shipping trash…
Yesterday, I went surfing after a long time and I can’t barely move my arms 💀
You don’t need using the fanciest architecture to launch your MVPs.
TCA, Clean Architecture, DDD, Hexagonal Architecture… they are all fine for large projects, large teams and depending on their particular needs.
But, all of them are supported by a pretty solid pillars that you should know:
Uncle Bob’s S.O.L.I.D. principles
I recommend you, before spending time studying the latest and nicest architecture pattern, interiorize these principles.
You’ll still be launching code fast, but it will be:
Flexible
Maintainable
Scalable
Understandable
Testable (if that day comes at some point 😜)
You’ll see that, in the end, they are a pretty logical ones.
Furthermore, they are linked to each other.
Thus, when you apply one, you’re indirectly conforming to others.
With that being said, let’s do a quick overview…
S.O.L.I.D. stands for…
Single Responsibility
Probably the most straightforward and easier to understand.
Every piece of code should have its own responsibility.
If you are using MVC, don’t turn it into a Massive View Controller.
If you are using MVVM, don’t turn your VM into a Massive View Model.
For example, if you have a class that:
Performs network requests
Communicates with a database
Makes authentication logic
This should smell to you 😷
Instead of that, you can solve it creating each particular service:
This way, each service is responsible of each own stuff and you can reutilize them in other parts of your project.
Open—Closed
“Each piece of code should be open to extensions and closed for modifications”
This is probably the one that is more difficult to comply with, particularly in early stages of a product when the roadmap will pivot a lot.
It’s impossible to apply 100% this principle as we don’t know exactly what changes would be demanded in the future.
What we can do is minimize having to do changes, through making proper abstractions and dependency injection.
As we did in the previous snippet, we created abstractions with the protocols and we inject them within YourClass
.
Therefore, if we have to use a different database in the future (for example changing Firestore for Supabase) YourClass
won’t change, as long as we create a Supabase service that conforms to our DatabaseService
.
I want to illustrate this principle with a practical example that happened to me recently.
When I was developing WrapFast, my SwiftUI boilerplate to create AI wrappers fast (promo intended 😜), I faced the benefits of a solid code.
For the ChatGPT feature, I launched first with a ChatGPT service that communicates with the custom backend of the boilerplate.
This service conforms to a proper abstraction, ChatGPTProtocol:
Later on, after the release, AIProxy guys contacted me to integrate their product in WrapFast.
They provide a proxy backend as a service to easily manage OpenAI integrations in your projects, protecting your API key from being hacked.
Therefore, to implement this new functionality, my project was now open to extension, and I can do it without changing the ChatGPTService
.
That’s because the ViewModel using the service, was doing it by injecting it as a ChatGPTProtocol
type.
So, in disorder to integrate AIProxy I created this:
By doing this, my ViewModel, using an implementation of ChatGPTProtocol
, remains agnostic about the implementation details of the service.
I only need now to instantiate a different service in the composition layer, in order to create the VM:
So now, WrapFast users can choose freely between using AIProxy or the custom backend to call to ChatGPT API.
And they can do it by just injecting the proper dependency, without having to make further changes in either the VM or the previous service.
This is getting so long…
And Filipp scolded me for writing such long issues, so I’ll deliver the remaining three principles next week.
I hope you can understand from this that writing SOLID code doesn’t necessarily mean that you’ll ship slowly.
Other than that, it can even help you ship faster iterations…
See you next week.
Take care! 😙