This article is written to discuss and provide a beginner friendly perspective on architecture, why it’s important, and how to implement it.
It is also meant to provide a starting point for people, especially by using keywords that people can then search up and learn more about each separate aspect discussed here, letting this article also function as an appendix of sorts, allowing beginners to have a high level overview of all the components that go into an architecture.
Also, while the focus of this article is architecture for a Flutter app, the concepts discussed (or more likely, just mentioned), are applicable across most languages or frameworks.
In case Flutter is not where you mean to apply an architecture, or if you want to learn more about the principles behind an architecture, along with all the components that go into one, you should check out these concepts/ideas:
- The SOLID principles
- Architecture Patterns
- Dependency Inversion
- State / State Management
Architecture is an especially important part of software development in general, as it helps organize code in an orderly and predictable manner, so as to
keep your sanity keep code readable and allow for the modularization of your code, and its importance, along with the reasons why developers go to the trouble of implementing one, only get more numerous as a project grows.
The most important reason by far for using an architecture, however, is to separate the business logic from the presentation code. The benefits this provides are immense, and include easier:
- Manageability of code
- Scalability of code
- Testability of code
- Readability of code
The presentation code is code that handles the UI, for example the code that determines the color, shape or border radius of a button.
The business logic is code that handles the logic, for example what to do when the user presses a button.
Dart and Flutter allow for business logic to be mixed in with the presentation code, which, while fine for small projects or prototypes, cause problems that only compound as the size of your project grows.
Ok, but how?
For the most part, an architecture starts out by following certain rules when coding.
Splitting up large chunks of code into separate files or classes (or in the case of Flutter, Widgets), dependency injection (in any of a variety of methods), modularizing functionality into services, managing state etc.
Do these consistently, and with a pattern to its naming and implementation, and boom, you got yourself an architecture, one that is a custom fit for your needs too.
This is however, usually not how its done, with most people opting for an already existing architecture pattern, so as to not have to re-invent the wheel.
An architecture is most closely tied to the following parts of your app, but they affect and are in turn affected by nearly every part of your app:
- Your State Management solution
- Your chosen method of Dependency Injection
- Your Network & Connectivity code (API calls, code handling online Database CRUD operations, etc)
- Your Data Persistence solution (The type of database you use will determine how you handle, format, cleanup (if needed) and overall prepare the data to be represented in your UI)
As mentioned above, an architecture holds together
Now architectures are usually separated into patterns, such as these:
- MVVM (Model—View—View Model)
- MVC (Model—View—Controller)
- MVP (Model—View—Presenter)
Now right of the bat, you can clearly see similarities in their abbreviations, quite rightly indicating that, underneath it all, they share nearly identical theories and concepts, and were, for the most part, born of the same need.
Explaining the theory behind each, and the reason for so many of them is, frankly speaking, beyond the scope of this article.
However, we will go over the concepts they share, in an effort to better prepare you for which ever architecture you end up choosing.
Hint: Like with most technologies, for the most part the decision boils down to two things: prior familiarity, and ease of use, and you can’t really go wrong choosing one over the other, especially among the battle-tested, long-living architecture patterns mentioned above (of which there are many more).
So, my advice would be to browse just a bit, then settle on which ever feels relatively more intuitive
The Forest, Not The Trees
The best way to picture the above mentioned ( or for the most part, any architecture pattern ) is vertically, with the top most part being what is seen by the user, with incrementally increasing business logic being mixed in as we traverse down the layers (of which there are usually 3 or 4), until we reach the bottommost layer, which consists entirely of your services, network code, API calls and core logic.
A quick definition for beginners, a ‘service’ is nothing more than a class that wraps commonly linked functionality.
For example, the DriveVehicle service can be one of the services used by our app, and it can have the forward( ) , backward( ), parallelPark( ) and, most importantly, the drift( ) methods_._
So, any class that does anything can be thought of as a service.
It is extremely wise to, from the get-go, separate your business logic from you presentation logic, as that allows for cleaner, more intuitive looking code (Remember, even for most personal projects, rarely will you write code that will never be seen by anyone else, and you may forget what a function or method did yourself, and even if none of these seem like problems you’ll face, it is still better to write cleaner code, if not for anything else other than practice.
At the lowest level, we have the core logic of our app, surrounded ( and wrapped ) by our services, along with the authentication and data input from any external databases or APIs we use , coupled with (ideally) error handling for these.
Here is also where we perform the first round of “sanitization” on our data (I write this during the all encompassing chaos that is the ‘Rona, and when that word has seen record use, and I cannot help but smile), to properly format it to our needs, before passing it up to the next level.
This is the in-between layer in our 3 layer architecture, and in 4 layer architectures, would usually be divided into two parts, serving as a continuation of the bottom layer, preparing data and passing it up, or handling lower level essential functionality.
In a 3 layer application, it would be where a lot of the heavy lifting takes place, from data formatting for presentation to the user, to handling user input, button presses, to things such as screen navigation, animation logic, etc.
This, while also handling more functions, serves as a gateway of sorts, parsing data into visuals presented to the user, and parsing user input into commands, requests and data carried out and manipulated by your services or other logic.
This is your presentation layer. It is where you design out your UI. It comprises your buttons, sliders, containers, columns, rows etc., anything visual should ideally be here.
It should include only the widgets that actually render on screen, with functionality being provided ideally solely by function calls that defer business logic to the layer underneath.
The End Of The Beginning
This article is a starting point of sorts, merely scratching the surface of a vast and very important aspect of software development.
If you have gotten this far, you should most likely have the basics of why an architecture is important and a general idea of how it all works down, and now comes the fun part.
Go out and research a bit more, find an architecture pattern that clicks, or one that seems less confusing then the rest, and start learning it’s nuances.
I wish you all the very best in implementing this in your app!
Till next time!
Some things have been oversimplified for the sake of newcomers, and some I may have gotten wrong myself.
If you have found incorrect information, please do not hesitate to contact me, and I will update this or any other article to reflect the correct information.
To err is human, after all