Admittedly, having been an Android developer in a past life, I’m more attune to the Material design and not the Cupertino design. For example, I’m not familiar with a Cupertino version of the Divider widget — if, in fact, there is one. As a result, I’m using Material’s Divider class in both interfaces. Further, there doesn’t appear to be a Cupertino-counterpart for the ListTile widget. I had to find one, CupertinoListTile. There’s some further tweaks required, but I feel the article has met its intent regardless.

TL;DR

All By Design

As with separating the ‘platform code’ in my apps, I also tend to separate the data, the Interface, and the logic that makes up my apps following the Model-View-Controller design pattern. Far from an original concept, the MVC software design pattern was first introduced by Trygve Reenskaug while visiting the Xerox Palo Alto Research Center back in the 1970s. For some 40 years, it would be a prominent approach to software development. Of course, Google formally endorses the Provider architecture for separating aspects of your app into manageable parts. Why MVC in this case? Personal preference.

And so, instead of having the example code all in one file, for instance, you’ll find following some sort of ‘software design pattern’ like MVC will organize your code in such a fashion to make it much easier to then maintain and even change as time goes by. Further, following such an approach allows new developers to take over duties that much easier and that much faster. Let me show you what I mean.

Below is a screenshot of the ‘main entry file’ of the example again, but now much of the source code is found elsewhere, no longer making it one big monolithic program file. Following best practices in Dart, while the code in the directory, lib/, is considered public and accessible to other Dart packages, code under the directory, lib/src/, is private, and that’s where the rest of the example code now lives.

In fact, at a glance, you can see there are now three additional directories: controller, model, and view. If you’re familiar with the MVC design pattern, you’d guess correctly then the code responsible for the example’s data would be under the directory, model, the interface code would be found under the directory, view, and all the code that responses to user and system events (the logic) would be under the directory, controller. By the way, organizing your source code in such a way, also allows separate teams of developers to work in those separate areas in conjunction with each other, or when advantageous…separately — in theory, allowing for more efficient use of time and resources.

Separate Platforms

Opening up those directories now relieves all the source code that makes up the example app in this article. If you examine the directory names closely, in time, you’d probably figure out what each dart file is responsible for.

For example, we see below the library file, main.dart, which now contains only what it needs to do its part. There’s no longer any extra code masking what this file is to accomplish. It’s cleaner. More efficient. Note, both the library file, material.dart and cupertino.dart, has access to the function, runApp(), however, I’m only using one of them. At this point, which one you use would be a personal preference. Also, I like using the ‘show’ clause in import statements. It’s so that, at a glance, I can then see what is used in a particular library file — my own personal preference.

So what else is going on in that file? Well, of course, the ‘MyApp’ widget is passed to the runApp() function. Now, where is that file? There is an import statement to ‘show’ where that widget is, of course, but you can see in the screenshot below it’s under the directory, controller. It’s been placed there by design to describe its role in this example app. Now things are a little more organized. Let’s take a look at that file next.

My App

Like the file, main.dart, this file contains only what it needs to perform its role. As you know from reading this article, the MyApp class essentially establishes the foundation for the remaining widgets to be called from and thus displayed in this app. In most cases, this will be based on the platform this app is running on. Of course, there are now those named parameters: android, iOS, and switchUI to dictate the interface used. The logic of all this resides now in this one lone file. If, down the road, someone changes those parameters, for example, the rest of the code will not be affected — not directly anyway. The rest of the code will be none the wiser. Further, a team leader could now more readily control who has access to this file to make such changes. Nice feature, no? Nice and clean.

What else does that file do? Oh yes! It determines the ‘home’ widget to be called to display the app’s interface. The screenshot below highlights where that file resides. It’s under the directory, view/home/. Make sense. It involves the app’s interface (view) and involves the ‘home’ widget (home), and so, that’s where it lives. Of course, the last import in the screenshot above conveys that location. Note, by convention, it’s discouraged to actually use the ‘relative path’ in import statements. The full notation starting with the package’s name is preferable, but since I just slapped this together as a supplement read to this article, please forgive my indolence.

And so, it determines the ‘home’ widget, and in fact, it’s in a file named, home.dart . Unlike Java, its resident class does not have to be the same name as the file and is called, RandomWords. It’s in the screenshot below. Of course, we already know how it determines which ‘interface’ to display.

Again, we’re taking advantage of the fact that two components make up a StatefulWidget. This allows us to not only separate the type of interfaces logically but also physically in this case. The two State objects involved now live in two separate locations in the directory structure in two separate files. Both are highlighted in the screenshot below.

Note, with this arrangement, now there’s no “stepping on each other's toes” when separate developers are assigned to these interfaces: One for android, the other for iOS for example. They’re working on separate files now! Each using separate libraries for their widgets: material.dart and cupertino.dart

The View Of Android And iOS

Looking now at the two classes, RandomWordsAndroid and RandomWordsApple, we can see what’s all involved with a quick glance at their import statements. We see the import statements in each that references the StatefulWidget counterpart, RandomWords. However, it’s the last import statement in each that may perk your interest.

The last import statement in each introduces the ‘Controller’ of this design pattern. Those familiar with MVC will know this is ‘the brains’ of the operation. It is common practice in this design pattern to have the interface (View) readily access a reference of the app’s logic in the form of a Controller. In this case, the Controller is responsible for the generating of names, and as it happens, in the screenshots below, the Controller’s variable, wordPair, is purple in colour, and so you can readily see where it comes into play throughout the code. And so, the two screenshots represent the View in the app’s design pattern, and the variable, wordPair, represents the Controller in the app’s design pattern.