Greg Perry

Nov 26, 2021

6 min read

A Better Flutter App #6

How the ‘separation of work’ is an advantage with change.

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.

No Moving Pictures, No Social Media

Let’s begin.

Other Stories by Greg Perry

The Areas Of Responsibility

As an example, you’ll note when walking through the code for the starter app there is a distinct ‘separation of work’. The MVC design pattern delegates a separate portion of an app’s source code to three distinct roles: code for the Interface, code for the event handling, and code for the data. Doing this will allow any future requests for change in a particular aspect of the app to only affect that particular part of the app. For example, if a change request involves the complete replacement of the app’s data source, ideally, the other two portions of the app should not be affected in the least — again, making for a quick turnaround.

View > Controller > Model

Let’s depict this in the Counter app as an example. Note the second gif file below to the right now has a counter of type double incrementing by its 100th decimal place. Granted, this is a really simple example, but imagine an app switching out a more complex data source — what would be the changes necessary using this design pattern? Let’s examine those changes made here.

Count On It

counter_view.dart

Hence, switching out the integer counter with a counter of type double did not require one bit of the code listed above to be changed — not one bit. That’s powerful. By the end of the article, we’ll see where the changes had to finally be made. Ironically, I suspect the ‘counter app’ from the original starter app would require more extensive changes.

Now, in the screenshots below, you can see the Counter app’s interface (both the StatefulWidget and the State object). It’s there, where the controller, CounterController, is introduced to the app’s interface. The controller is instantiated in the StatefulWidget to a final instance variable called, con, and actually passed to the State object (of type StateMVC) as a parameter. Note, now in that State object, it’s necessary to cast the property, controller, (of type ControllerMVC) back to CounterController so as to then access ‘the data’ it has access to.

counter_view.dart

Note, an alternate approach would be to instantiate the controller where it’s only needed — in the State object. See below. This would leave the StatefulWidget a little ‘lighter.’ In fact, the only time I have the Controller in the StatefulWidget is when I wish the StatefulWidget to have its own functions (an external API) calling, in turn, the functions in the Controller. However, that’s for another story.

counter_view.dart

You can see, highlighted in the Controller’s screenshot below, the API used by the Interface. Remember, it’s the getter, data, and the callback function, onPressed, back in the State object. Also highlighted here is the third and last component of the design pattern, the Model. The Model represents the code responsible for the app’s data. In the screenshot above, the class, CounterModel, is instantiated to the property field, _model.

counter_controller.dart

When it comes down to it, the class, CounterModel, can be changed completely unbeknownst to the rest of the app. For such a simple start app, this design pattern is very much a case of overkill. However, for a typical production-worthy app with its local database, its augmented reality plugin, its Firebase Firestore, its Web Services, etc., future change requests could be easily performed with little circumstance. Look below, and you see two classes with the same name: One will increment an integer; the other increments a double. Switching between them out is a breeze.

counter_model.dart
counter_model.dart

Imagine a team of developers working together on a larger app. Possibly with separate developers delegated to each of those three aspects of the app (Data, Interface, and Logic). Give them a standard API, and any future changes are not a problem.

Cheers.

A Better Flutter App #7

Handle App Lifecycle Events

→ Other Stories by Greg Perry