A Better Flutter App #5
How to organize your app’s source code in a better way.
One of a series of articles detailing a comprehensive starter app. This app is generated by a template offered by the package, app_template, which uses the underlying framework, mvc_application, based on the MVC design pattern.
I Like Screenshots. Tap Caption For Gists.
As always, I prefer using screenshots in my articles over gists to show concepts rather than just show code. I find them easier to work with frankly. However, you can click or tap on their captions to see the code in a gist or in Github. Tap or click on the screenshots themselves to zoom in on them for a closer look.
No Moving Pictures, No Social Media
There will be gif files in this article demonstrating aspects of the topic at hand. However, it’s said viewing such gif files is not possible when reading this article on platforms like Instagram, Facebook, etc. They may come out as static pictures or simply blank placeholder boxes. Please, be aware of this and maybe read this article on medium.com
The Place For Things
In the graphic above there are five screenshots of the very same files and folders that make up the starter app’s Flutter project, app_template. So far, this series of articles has only really highlighted the framework, mvc_application, as it is supplying most of the functions and features so crucial and so fundamental to any successful Flutter app.
This article, however, will now introduce another essential characteristic, though not directly associated with the starter app, that nevertheless is important to the success and maintainability of that app’s project itself. It involves how those very files and folders that make up this Flutter project are organized and represented to the developer, and how doing so makes for faster development and easier maintainability.
What You See Is What You Get
A closer look at the project's second and third screenshots will demonstrate the importance of this essential characteristic. Please, look below and determine what do you see in the first picture of files and folders? What practical facts about this Flutter project can you glean from that first picture? I can tell you a few things that I know of this app just by looking at that first picture (and not just because I wrote the thing).
I can tell you there’s a database and there’s a home screen in the app. I can tell you the app is broken up into two parts: one part is concerned with just the home screen, the other part is concerned with the app as a whole. Lastly, I can tell you the app separates its interface, from its data, from its event handling, and the development likely uses the MVC design pattern (Model, View, and Controller) to organize and arrange the project’s source code.
Not too impressed? Well, let’s open up the folder, app, and try this little exercise again. From what I can now see in the second picture above, I know a database is definitely involved with the home screen and not with the app as a whole. In other words, with regards to MVC where M is for data, V is for the interface, and C is for event handling, the app-level contains no database but does have some screens and event handling. It is the home screen that contains all three.
This is deduced just by looking at the placement of the files and folders consistently named, controller, model, and view. You can now figure this out yourself — it’s pretty easy if you know what MVC stands for. By the way, when talking about ‘Design Patterns’ it’s more a discussion about the ‘placement’ of what makes up a software application. Unlike architectures, like Provider, BLoC, etc, it’s not about ‘how the logic is represented.’ Conceivably, such architectures can be embedded inside a design pattern.
Anyway, back to our little exercise. It may not be too impressive, but I’ve no doubt there’s a developer newly hired onto some project somewhere opening each and every file and folder trying to get an understanding of how its code is organized. They are no doubt putting in some time and effort — instead of all with just a glance. A subtle but profound shortcoming in the long term.
So what’s the big deal, you say? So newbies will have a bit of a learning curve at the beginning of such projects. So what? Any app worth its salt is going to get pretty big. All within reason of course. I mean, the app is likely for a phone — not for a Cray supercomputer. There’s going to be a lot of screens and a lot of code. Production-worthy apps are going to get a little complicated, and I know there’s a developer reading this article right now with import statements a mile-long in their project’s Dart files. They don’t follow a scheme or have an approach to organize the many ‘import’ statements. Well, the Dart team does, Organizing a library package, and I follow it.
The idea of using ‘export files’ that contain nothing but a list of export statements makes for a ‘cleaner’ list of import statements in your source code. Let’s quickly examine the three ‘export files’ first encountered in the starter app project. They’re found right inside the src/ folder. See below.
The first export file is the file, controller.dart. The screenshot of this file below reveals an ‘export list’ of other Dart files named, controller.dart. Again, when it comes to Design Patterns, it’s the ‘placement’ that is most significant, and so, note where these other ‘controller’ files are located.
The first one listed is the standard ‘controller’ file offered by the framework itself. The second and third ones, however, are coming from the project. Looking at their locations, you can deduce one contains the event handling code for the app as a whole while the last one will have the event handling code for the home screen: src/app/ & src/home/. Pretty straightforward.
Now let’s follow through and see what’s inside those ‘controller’ files. Looking at the ‘app level’ controller (the second file), it’s a list of export statements again, but now these Dart files involve actual source code. Code that is concerned with the general theme of the app and code involving a Timer class that needs to be initialized at the startup. See below. By the way, the Timer is for those read word pairs you see flashing by in the Counter app.
The third and last export statement with …/src/home/controller.dart takes us to the home screen’s controller file. As you see below, it‘s more interesting. It too has export statements listing actual source code. And again, by their locations, you can tell at a glance which code is involved with the app in general, which works with the contacts app, which works with the counter app, and which works with the word pairs app. Very very helpful in maintaining such apps.
…and all that code is then accessible by one import statement:
The remaining export files under the src/ folder follow the same approach — exporting additional counterparts until the source code for specific parts of the app is exported and thus accessible by one import statement. Very efficient. Very clean.
What are Your Imports?
Because of this approach, it’s even possible to get a sense of what’s going on within each individual library file (.dart file). For example, the imports listed in the screenshot below will tell you a few things about the code inside the Dart file. Firstly, we see the function, unawaited, is being used somewhere in the Dart file — some Future function instead of using the ‘await’ clause is not ‘waiting’ and instead is being passed into the unawaited() function. By the way, it’s good practice to sparingly use the ‘show’ clause on particular import statements so ‘the future you’ or other developers can later open up the file and see what specific functions are being used in that file…at a glance.
Looking again at the screenshot below, we know the controller, WordPairsController, is being exported from the second import statement — since we know now all controllers in this app are exported by the Dart file, src/controller.dart. The next import statement tells us that something in this Dart file is accessing a database — since we now know all data sources are exported by the Dart file, src/model.dart. Finally, we know some controller or lambda in this Dart file is also communicating back to the interface for some reason — since the Dart file, src/view.dart, gives you access to all the code concerned with this app’s interface. See how this all works?
All this demonstrates there’s a valuable consistency in the management of this project’s source code. Note, there’s no massive list of import statements at the start of the project’s Dart files. Many files just have two or three import statements — and yet looking that the start of a Dart file and its import statements will give you an idea of where everything lives and of what everything does. Very nice.
If anything, the one thing you should come away with here is at least consider implementing some sort of design pattern — a consistent approach at organizes your files and folders. When it comes to developing and maintaining larger; more comprehensive apps, your ‘future you’ and other developers on your team will thank you for it.