This is Part 2 of a series of articles that explore and seek to provide newcomers with a high-level overview of what all the parts of an app consist of and do, so that they can hit the ground running.You can read Part 1 here.
Where we left off
In the last post, we talked about 3 of the 6 broad aspects that need to be considered when developing an app. They were:
- The UI
- The State Management solution
- The Dependency Injection solution
In this post, we’ll talk about the other 3, which are:
- The Local Data Persistence solution
- The Network and Connectivity code/combo/framework
- The Architecture Pattern
So, without further ado, let’s get started!
Local Data Persistence
Local Data Persistence is one of the more straightforward components that goes into making an app.
For nearly every app, there will be some data that needs to be stored locally, on the user’s device.
Unless of course, you have a cloud database, or very rarely, an app that does not need to store anything.
Local data storage can be of two main types:
- Key-Value pairs
- Tabular / Relational Databases
Key-Value pair type storage is mainly for storing bits and pieces of data. It does not have any easy way to maintain the relationships between different data ( For example, a value of 165 by itself is not useful unless there is a way to easily relate that that is the height of a person in centimeters ).
Key-Value pairs can be used to store things such as names, boolean values ( or enums ) to remember the user’s settings and preferences, etc. The only thing it cannot easily store is data that has relationships with other stored data.
They are usually faster and more responsive than the second type of database.
Some of the more popular packages used for key-value pair data storage are:
- Shared Preferences
Tabular / Relational Databases are traditional SQL databases, with tables containing rows and columns of data that are related to each other. They can be used to store large amounts of data about users, user generated content, etc.
They are usually slower than key-value pair storages.
Some of the more popular packages used for Tabular / Relational Databases are:
Note: There are also NoSQL databases, and one for Flutter is Sembast.
Network and Connectivity
Network and connectivity is one of the more complex aspect of apps that require it, as it can sometimes prove to be difficult to implement, due to its asynchronous nature.
Simply put, you cannot store all the data required or served by an app locally, or even implement very computation heavy functionality, such as data analysis or OCR / ML technology locally in an app, due to a plethora of reasons, going from performance all the way to file size.
Furthermore, if your app serves up user generated content, or any other form of real-time data ( such as, say, the weather ) then it must have a way to get new data to be able to display it to the user.
Networking code handles the API calls and such required for this communication, connecting servers with newly generated content or real-time data, or servers with the ability to run computationally taxing workloads to the app, allowing the app to serve the user better.
Some of the more popular packages used for network and connectivity code are:
The last part of the puzzle is the architecture, the framework or the rules, coding practices/conventions and ADD HERE that hold all of these other components together, allowing data to flow between all of them in a predictable, testable, scalable and most importantly manageable manner.
Firstly, regardless of what some sources may tell you, there is a thing called over-engineering, and there is a line, an albeit blurry sometimes but definitely present line, separating foresight and leaving room to grow and scale, and using a solution designed for software that operates on a completely different scale, and comprises off and requires a much more extensive list of components, services etc. ADD HERE
The needs of software like the kind above mentioned will rarely align with anything else, and as such, the solutions used to solve their problems will most likely only increase the complexity of yours, without much to show for it.
This does not mean that those solutions should never be used, it only means that adequate research should be done with the needs, both current and future of your app being kept in mind.
With that being said, let’s continue on to the functions of an architecture. An architecture works most closely with the state-management and dependency injection solutions of your app, as those are some of the primary things that benefit from the structure provided by an architecture pattern.
At the most basic level, an architecture can even be as simple as arranging the various files that consist your app into self-explanatorily named folders and such, with the splitting of functionality into services and classes and functions that (depending on whether you feel the need to do so) are themselves split across several files.
But this type of architecture is not the type we are interested in. We are interested in architecture for our code, not the files the code is kept in.
As with state management, architecture patters also come in a wide variety of shapes and sizes, and most of them work quite well, with the only reason someone might choose one over the other being personal preference.
Some of the more widely adopted architecture patterns that can be ( relatively ) easily implemented in Flutter are:
Explaining these architectural patterns, or going further in depth into the theory behind these patterns, which is largely the same for each pattern, is beyond the scope of this article.
Just know that they all work by separating the code that handles the logic from the code that handles the UI, and by doing this, make the code more readable, manageable and scalable.
The End (For now)
And with that, we reach the end of another post. In this post, we covered the last 3 broad components that go into a Flutter app.
In the next article, I’ll share some of the packages I use for each of these components, along with my thoughts on each and why I selected that particular package.The post ends now, but the adventure continues!
Thank you for reading this far, and I hope you learnt something new!
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