Clean Architecture for Dart and Flutter Apps: Introduction, the Usecase, and the Benefits
It should help you tame complexity not add to it
I have a very weird relationship with Clean Architecture: I only started learning it the very week it got attacked on Twitter. Read on, I will tell you why...
When I went through the comments that resulted from the chatter, I realized that the people I looked up to at that time in my learning journey all spoke well of it, and the few who didn't say they arrived at more or less the same structure. It is like avoiding State Management solutions like Bloc and RiverPod only to end up writing your version.
I wrote a very well-received article on finally getting State management using Riverpod. Among the questions I got, the only one I deflected because I couldn't give a valid answer was what Architecture I used.
Around that time, I was recently contracted for my first team project. I knew we had to have an agreed set of standards since I was aware of all the things that could go wrong when working in a team without one.
As a result, "Clean Architecture" became a no-brainer for me.
But make no mistake...
All Architectures promise the same thing
It doesn't matter whether it is MVVM, MVC, Domain Driven Design, or Test Driven Design — all code architectures promise the same thing: Maintainable, Scaleable, Testable, and Robust Code — Clean Architecture is not in any way different.
Maintainable: Code that is easy to understand and modify, ensuring future updates and enhancements can be made without excessive effort.
Scaleable: Code that can handle increased workload or demand by adapting to growing requirements while ensuring optimized performance.
Testable: Code designed for easy testing using mocks instead of real data sources. This makes identifying and resolving issues and bugs through automated testing processes possible.
Robust: Code that is resilient to errors and changes, ensuring modifications in one part of the codebase do not adversely affect other components, promoting stability and reliability.
While code architecture implementation varies, they all achieve the benefits above by separation of concerns and by adhering to a combination of the following guiding principles:
Single source of truth (SSOT)
Unidirectional data flow (UDF), and
Dependency Inversion (DI) ---[more on all of these later].
But the benefits are clear
One of the most notable advantages lies in the independence it affords your application from specific databases or backend API infrastructures. This independence becomes particularly crucial for startups, especially those leveraging Platform as a Service (PaaS) or Software as a Service (SaaS) solutions during their initial growth stages.
In such a dynamic environment, the ability to rapidly adapt to changing needs is paramount. Clean architecture offers a seamless pathway for accommodating such shifts.
For instance, you can effortlessly migrate from utilizing services like Firebase Authentication to implementing a self-managed Node.js REST API server without causing major disruptions to your codebase.
Maybe you are hitting Google Map API call limits, or the charges are quickly ballooning, you can swiftly shift to MapBox and the only thing you have to change are the API endpoints and configurations related to map services; every other aspect of your application can remain unchanged and still function seamlessly.
Your codebase also becomes independent of UI
Mobile UI can easily be Swapped for Web, Desktop, or Console UI while still maintaining the same app logic — this is a very big deal particularly when working with a cross-platform framework like Flutter.
Moreover, Clean Architecture eliminates the need to wait for backend development to conclude. Developers can test individual components for correctness and robustness without external dependencies, ensuring functionality regardless of the eventual backend implementation.
These benefits become increasingly true when building or maintaining large-scale apps as your architectural choice will determine how fast you can add new features or upgrade existing systems.
But the Devil is in the Details
It's easy to tout principles like CLEAN, SOLID, or MVVM — but it doesn't mean anything unless you write code that conforms to them that your codebase will benefit from.
In the episodes to come in this series, I will use various examples that touch on the common key components of a modern app: Getting Remote data from a REST API, Local Caching, Error Handling, Input Validation and many more.
While most articles on this topic were written around Bloc, this one will revolve around Riverpod because I believe it's the future. Lol, just kidding, I just love it and respect the Author, Remi Rousselet.
But this also proves a point: Clean architecture makes you framework-independent, it doesn't revolve around any State management ideology as you could easily Swap Riverpod with Signals or the next new cool idea when you are reading this and everything will still work fine.
Until then, see you later. Bye.