MVC in Flutter Part 2
By: Greg Perry
Tags: Flutter, Technology, Android App Development, Programming, Software Development

There’s A Pattern To It

Like many design patterns, MVC aims to separate ‘the areas of work’ or ‘the areas of responsibility’ when developing software. With MVC, this means separating ‘the interface’ from ‘the functionality’ from ‘the data’ that make up an application. Like most things in Life, it’s generally better if you break up a project into its separate working parts. In the case of MVC, these three separate working parts are given specific names:

Model — the source for data. In some implementations, it may also contain the business logic.

View — concerned with how data (not necessarily that in the Model) is displayed in the user interface.

Controller — controls what data is displayed, answers to both system events or user events, and, in many cases, contains the business logic.

The Lines Of Communications

Decoupling these three major areas in software allows for more modular code, for more code reuse, and for parallel development. With a decoupled system, one can easily change any part of that system without effecting the other parts of the system. Of course, there has to be a means of communicating between them; a consistent API that, in the case of MVC, allows the View and the Controller to ‘talk to’ each other, as well as ‘talk to’ the Model through the use of public functions calls and public class properties.

Note, in many configurations, the View can ‘talk to’ the Controller; the Controller can ‘talk to’ the Model, but the View is unaware of the Model and vice versa enforcing even further decoupling of the system.

In many such instances, the Controller is likely the brains of the app. It reacts to events from the system or from the user’s input and dictates how such events affect the model’s data source as well as determine what data is eventually displayed in the View. The View and the Model are each tightly coupled to the Controller (i.e. The View knows how to ‘talk to’ the Controller, and the Controller knows how to ‘talk to’ the Model ), however, each has no idea of the other’s existence. They do work together, but indirectly — through the Controller.

Such an arrangement allows one, for example, to switch out the Model and put in a different one supplying a completely different data source for example without one character change to the remaining code. The new Model would only have to conform to the API requirements allowing the Controller to ‘talk to’ it correctly. So too with the case of the View. One should be able to switch out the View with little consequence to the app’s remaining code.

Everything In Its Place

Design patterns provide structure. They provide a means to organize your code allowing developers familiar with the design pattern to ‘hit the ground running’ when assigned to the project. A design pattern can organize your code, your files and even the directories that make up your project.

In the original Stocks example, everything is just in one directory. Now let’s take a look at the other three apps and their directories below. Now since you know the meaning behind the words, Model, Controller and View, I bet you can tell at a glance what files are concerned with what in these apps, and in what directories those files reside. See? Organized. Consistent. Concise.

“Break things up to make things easier,” is the simple phrase I can use here. You could possibly deduce the app depicted in the middle screenshot might be a little simpler than the others — there are fewer directories. The other two apps have the directories: app and home. The directory, home, contains the ‘home screen’ and its accompanying code. There’s also the consistent use of three directories named, controller, model and view in all of the apps.

The first app, weather_cast, has separated the overall ‘app’ portion of the app from the ‘home screen’ portion of the app. The red arrow below highlights the class, Weather, that’s defined in a Dart file residing in the directory, home. It’s instantiated and passed to the ‘app’ portion of the app using the parameter, home. See below. Do you see the connection?

The class, WeatherApp, listed above is found in a Dart file stored in the directory, app. While the class, Weather, is found in the directory, home. See how that’s organized? In the first screenshot below, the class, WeatherApp, is found in a Dart file by the same name and is not only under the directory, app, but is actually stored in the directory, view. Its very location describes its role in the app. It’s the start of the app (and so it’s under the app directory) but most of it does involve the interface (and so it’s under the view directory). Now, how about the class, Weather, assigned to that parameter, home?

The class, Weather, can be found defined in the Dart file, home.dart, and that file is located in the directory, view, under the directory, home. See below.

This class extends the class, Widget. Makes sense since the parameter, home, in the WeatherApp class, is of type, Widget. Like the home parameter in the MaterialApp widget, this parameter takes in a widget to be the ‘home screen’ of the app. As a matter of fact, the class, Weather, here is indeed assigned to the home parameter of a MaterialApp widget created deep in the MVC framework. And so, in line with its role, this class is also stored in a directory called, view. Note, however, the name of its Dart file is named, home.dart and not weather.dart. Why?! Why not?! It imposes some standards.

In fact, the other file, weatherapp.dart, should be named, app.dart. No? That’s a wonderful change from Java! In Dart, you don’t have to name the file after the class defined inside. In fact, the Dart library file can contain any number of classes, any number of high-level functions, and any number of high-level variables. That’s huge! Gives the developer options. Love it.

As it is, when it came to rewriting the Stock app using MVC, I decided to keep the file names used in the original Stocks app — to highlight their differences when it came to the directory structure. But as you see in the second screenshot above, the two files indicated could have just as easily been named app.dart and home.dart respectively instead.

The Details They Tell

Looking again at the directory structure of the two app: weather_cast & stocks_mvc, the standard practice of grouping the source code in the appropriate directories (controller, model and view) allows you (or another developer) sometime in the future to readily see what’s involved in different parts of app at a glance. Let’s take a look at the screenshots below.

You can readily see there’s a database (or data source) involved with the ‘home widget’ in the first app, weather_cast. That’s because you see there’s a directory, model, under the directory, home. I can also tell you at a glance there’s a Drawer widget displayed in the home widget because of the directory, drawer. Further, as you can readily see, there’s an ‘application-wide’ database in the other app, stocks_mvc. That’s because there’s no directory, model, under the ‘home’ directory, but under the directory, app. You know all this by simply looking at the directory structure. Organized. Concise.

All At A Glance

Let’s open up all the ‘MVC’ directories in each app now. All the source code that makes up the ‘Controller’, the ‘Model’, and the ‘View’ of each app is now readily on display below. Tell me, what do you see?

Well, knowing what we know about MVC, we then also know in the first screenshot, the class in the file, view/weatherapp.dart, can talk to the class in the file, controller/weatherapp.dart. We know the file, view/home.dart, can talk to the file, controller/home.dart, and the file, controller/home.dart, can talk to the file, model/weather_model.dart. We know all this by just looking at the directories. Such a relationship exists as well in the second screenshot.

What else do we know? We know there are two separate views or screens involved with the ‘home’ widget. One is the home screen itself (home.dart) while there’s a secondary screen (location.dart) that appears to involve ‘locations.’ As I mentioned earlier, we can see the home widget uses a Drawer as part of the interface. There’s also a directory called, child, found with the home widget. The home widget’s build() function is listed below highlighting where the widgets found in this child directory are actually instantiated— many are assigned to a parameter named, child. See the connection now?

Below is the contents on that directory, child. You can see the name of each file, in this case, match up with the name of the residing class. As such, it allows you to see at a glance what class is defined where.

What’s In The Drawer

Looking at the second screenshot above, we see there’s a subdirectory found in the directory, drawer. The name of the directory is called, weather_locations. You can readily see it contains its own set of “MVC” components. So, what does that tell you? It tells you ‘weather locations’ contains its own screen, its own database, and its own Controller. All with a glance. Nice.

Three Exports All Round

Now you’ve no doubt noticed the three Dart files consistently listed in each of the app’s src directories. What’s that all about, do you think? Well, it’s all about organizing your code, about allowing the expedition of development, and about the ease of code maintenance in the future. All traits to aspire to when developing apps, no?

The approach I’m about to detail now was, in fact, conceived out of the Dart documentation itself, organizing a library package. It involves the common practice of using a single Dart file residing in the app’s directory, lib, to dictate what will make up its public API by ‘exporting’ still other Dart files hidden in the subdirectory, lib/src. This allows a user to get at an app’s functionality by importing just this one file or possibly just a few other files instead of importing many many Dart files. It provides a level of control as to what is publicly accessible when it comes to the app’s source code. This approach has also been applied when developing apps with this MVC framework.

Export The Weather

The first example app, weather_cast, have those three files under the directory, lib. As you may have guessed, one exports all the Controller code, one exports all the Model code, and one exports all the View code — or you could say, ‘exposes’, all the code in those three areas of responsibility that make up the app. All three are listed below. In fact, all three “MVC” export files from all three example apps are listed below.