204 – App architecture

Let’s take a moment to discuss architecting our app. After all, we don’t want to go racing into the night without a map, at 100 mph screaming “I don’t know where we’re going, but we’re making good time.”

MVVM – The preferred design pattern for C#/XAML applications

As mentioned earlier we will be using a design pattern tailored for C#/XAML and proven with over a decade of use in WPF applications for Windows. This pattern is MVVM: Model, View, ViewModel. I’m not going to make an entire book here for MVVM, but it behooves us to touch on some basic principles so we are all on the same sheet of music as we move forward.

  • Model – That’s an object. An instance of your ‘Monster’ class in a game, or your ‘Animal’ class in a pet tracking app.
  • View – That’s a collection of UI Elements used to visually interact with your data. A view could be an entire page, or it could be a reusable control.
  • ViewModel – That’s the backing data for a view. Commonly it will have several properties that are instances of different models.
    • Let’s cover that just a bit more. The ViewModel for scheduling a work shift would probably have a Permissions property on it that governs what the current user can do. It might also have a Week object that represents the coming week being scheduled. It might have a SelectedWorker property of type Employee representing a given user that the manager might be looking at to see if they can be scheduled for the coming week. And so on. The ViewModel is a collection of properties for a given need.
    • Do not confuse that with ‘this view model is for this page’. That one-to-one relationship is a common mistake. The ViewModel is the properties and methods that go together for a need or purpose. But it can be the backing for many different views. That same ViewModel used by the manager for scheduling a work shift might also be used by the HR person on a similar but different page for scheduling vacation time. Someone in the maintenance department might use the same ScheduleViewModel to see when a machine is out of use for a week so it can be torn down and rebuilt.

In other words: Your page is a view, and it is binded to a ViewModel. When properties on your ViewModel change values, the UI elements on the page are updated and vice versa. The ViewModel is the BindingContext of the view (page).

If that’s all gibberish then check this entry that goes a bit deeper. If that is still gibberish then stop and study:

Despite my disclaimer that a ViewModel and View do not have to have a 1:1 relationship, that doesn’t mean that can’t have it either. In fact, it’s fairly common and there are even several NuGet packages built around navigation based on the idea that if you push a given ViewModel you want a de-facto page to appear. And let’s be honest, the mobile app space is mostly straight-forward programs with a limited purpose in life that tend to not have 50 variations on a page or have 200 different and unrelated functions. So, it’s not unreasonable to say a lot of mobile apps primarily have a one-ViewModel-to-one-Page relationship.

It’s also common to have a hybrid of relationships on one app. For example, your HomePage will probably always be your one and only HomePage: The center of your app where the user always returns to when done with something. Meaning it gets and keeps the same instance of the HomePageViewModel for the lifespan of the app. But you might want your DownloadFilePage to be fresh every time with no memory of the previous file downloaded. When you push a new DownloadFilePage you give it a new DownloadViewModel every time. And the UserViewModel probably backs 10 different views that each handle one aspect of the user: One for changing their password, one for assigning a new avatar image, one for assigning a new social media service to them. The other reason for this regards the built-in Navigation object that we are about to discuss. It has few methods but on is .PopToRoot() meaning clear everything and go back to your first page. If that first page is the Home page your user thinks of as ‘Home’ it makes your life a lot easier than if you push the LoginPage first and have to constantly unwind the Navigation queue to the 2nd or 3rd element.

Let’s keep that one part as a decision about our app: We are going to have a HomePage backed by a HomePageViewModel and they both live for the lifecycle of our app.

Navigation

We have a decision about our home page (architecturally speaking). Now what? Probably navigation. Let’s discuss how navigation works in a mobile app. First when we say ‘navigation’ we aren’t talking about turn-by-turn driving directions. We are talking about internal navigation from one page to another. Most mobile apps are designed around the idea that a cell phone isn’t a bunch of real estate and thus you move from one page with a small dedicated purpose, to another page with a small dedicated purpose. Take a social media app for example. One page is for viewing the current feed of posts. Another page is for setting your preferences. Another page just searches for new friends.

Xamarin.Forms provides a stack-based Navigation queue so developers don’t have to roll their own. This means you push pages on to the navigation stack to move forward to that page, and pop them off to go back. That’s it: Push/forward, Pop/back.

A couple things about The Xamarin site page for Navigation.

  • CarouselPage – This is still experimental, under development, being replaced by (or going to make use of) a CarouselView that you can put on any page, and basically something that nobody is happy with YET. Especially since the CarouselView doesn’t support binding so you can’t bind a collection of pages to it, like anyone would expect. I mean… Really?
  • MasterDetailPage, NavigationPage and TabbedPage – All good choices for a quick start and for your first few projects to get used to building Xamarin-based applications. At some point you’ll probably out grow them when you want to customize beyond what these read-to-go pages support. Maybe you want more control over the look and feel of the Tabs, or to redefine the ‘Hamburger’ menu icon look.
  • ContentPage – The most generic so you have to do more work up front. But also the most versatile since nothing has been done in advance to limit you.

NavigationPage – yes, we mentioned this already. If you look at the NavigationPage it is a page with content below a Navigation bar at the top, the bar has a back button and title etc. You provide a ContentPage as the content that is going below that title bar. Let’s break down the code that does that so we can better comprehend it; versus copy/paste somethis mysterious that ‘just works’ but we don’t know why.

Xamarin.Forms.Application.Current.MainPage =
new NavigationPage(new HomePage());

See that NavigationPage constructor taking another page as an argument? We’re passing in a new HomePage class (derived from ContentPage). Here’s the part I like about the NavigationPage… You can hide the Navigation bar at the top. That means your ContentPage becomes the full screen page with nothing added that you didn’t put there. My control freak enthusiast self likes that. My suggestion for starting out our test app is to use a NavigationPage with our own custom HomePage class. For now, we can keep the Navigation title bar because there is no reason not to and it gives us stuff for free that we can use: Like a standard ‘Back’ button. As we progress and want to customize beyond what it can do, then we will hide the built-in bar and make our own: Without having to change big parts of our underlying infrastructure.

When you create your app one of the early things you do is set the app’s MainPage. MainPage is special term to Xamarin navigation and not a class we make. We’re telling the app “Your Main Page is this: xyzPage”. As we just discussed we’re going to set it to a new NavigationPage and provide one of our ContentPages as the Page to be shown. Let’s look at that code again. At this point both sides of the assignment should make sense.

Xamarin.Forms.Application.Current.MainPage =
new NavigationPage(new HomePage());

I have seen many forum posts where people are having trouble with navigation usually to the effect of “how to go back”. In every one of them the person was not pushing new pages onto the queue. Instead they were using that same line of code: Constantly making the new page the MainPage – Wiping out the navigation queue so there was no history to traverse back. So as a rule, once you have set your HomePage – Leave it. Also, do not think of the HomePage as the first page your user will encounter. Commonly the first page is a Login page… Or maybe it’s a Welcome page… or maybe it’s a splash screen. None of those really fit the name “Home” page though, do they? The HomePage should be just that: The page is that is the central home of the user when they aren’t doing something specific.

The Xamarin site tutorials always show something like this, where you are pushing a new instance of a given page.

async void OnNextPageButtonClicked (object sender, EventArgs e)
await Navigation.PushAsync (new SomeOtherXamlPage());

There are pros and cons to that, that I never see discussed.

  • PRO:
    • You have a clean instance of the page with no old information on it.
    • It’s good for simple tutorials where you don’t want to confuse the reader or have to answer a bunch of questions about “What is an instance?” and why something isn’t working as expected and it later turns out to be two different instances of a page or its ViewModel
    • You’re not holding on to anything so you release memory back to your device and the app.
  • CON:
    • You have a clean instance of the page with no old information on it. Meaning you’ve lost any existing state you might have wanted.
    • Your app has to render the new page instance for the first time everytime, which is visible processing time. Read “visible UI lag”. The more your new page has to calculate to set itself up for the first time, the longer the lag. This is especially true for grabbing images off the device. For example, if your page has to calculate if something should be red or green based on a binding… should something be visible depending on a binding to an enum converter… Do you have 34 icons to read and render…
    • You have to bind the Page to its ViewModel object every time. Or generate a new ViewModel instance. Again, this is clean for one-off examples of navigation but don’t always play into the kind of re-use we have in live application.
    • Basically you’re exchanging memory for performance.

If your page can be rendered once and not thrown away… then re-pushed later… without fear of its state being wrong, then it might be worth keeping your page(s) as properties of your application view model so you can re-use them. One example might be your PreferencesPage. If you have a page where you set up your preferences to English, blue theme, large font, soft volume {…} you know those are going to be the same values the next time the user opens that page. They might open it 10 times in one session because they make an adjustment then try it out, make another adjustment and try it out. If you keep that page you can push it out again and again without having to reload the VM or re-render the page itself, making the UI feel ‘snappy’.

When you have a concern about the page state, such as more data downloaded from a server or the user has logged off and a new user logged in, then you can nullify the existing page instance and make a new instance. This pattern does require a bit more attention to detail on the part of the developer which is probably why it’s not discussed in the intro tutorials by Xamarin. But the boost in responsiveness can be worth it for the moderately experienced developer. If all of that was gibberish don’t panic. It will either become clear when you see it in code, or it is something you’ll dissect & study and grow to understand.

Design flaws to avoid:

  • Doing too much
    • Separation of responsibility is paramount to create coding that can be easily maintained for years. You want your “ReadFile()” method to ONLY read a file. It does not also populate the page, it does not make decisions about what to do next based on the content, it does not perform a NavigationBack when it is done. It reads a file and returns the contents to the caller: That’s it.
    • The same goes for your XAML pages. A page describes where things go. A stack of labels here, 4 com port status controls there, and a button. The page does not define the theme of the app, it does not choose colors, it does not choose font sizes etc. If you put those things on the page, and you have 20 pages, and you decide to re-theme from red to blue… What do you the developer now have to do? You have to scrub through 20 pages and re-colorize everything.
  • Moving too fast
    • Everyone wants to see everything yesterday. Especially bosses. The guy that knows nothing about software development wants to tell you how to develop. That’s never good. Usually it’s something like “Just throw together something that looks good so I can get a screen-shot for approval from the 7th floor. We’ll go back later and make it all better next quarter.” Does anyone ever get the chance to go back and clean up crap from last quarter? NO! So, stand your ground. Don’t call something ‘done’ unless you consider it a work of art that you would sign your name to.
    • If you’re just doing a project for learning you’re the boss. Don’t talk yourself into doing crap just so you can move forward. If some bit of code, you wrote isn’t right… isn’t robust… Fix it. When you move on to the next part you want that last part in your rear-view mirror and not have to return to it later.
  • Don’t bring old ways into new projects
    • If you’ve been a developer since WinForms (or earlier) you have a lot of habits and ways of doing things that have served you well for decades. Most of them are still good. But remember some of those tried-and-true ways of doing things really are DECADES old, and may not apply to second decade of the 21st century hardware, operating systems, and probably not to strategies for cross-platform apps with 90%+ reusable code.
    • Logic doesn’t know anything about the UI
    • We do not use Button.Click()
    • We do not make 15 extra properties just for UI formatting needs. (Because our logic does not know anything about the UI)
  • Your ViewModels knowing too much about each other.
    • Sometimes you need for one ViewModel to know something specific about another. Good or bad is arguable but even the best of pros will say sometimes its unavoidable. But you don’t want everyone to know everything about each other because then you have the same spaghetti and interdependent mess you have with WinForms of the 1990’s.
  • Avoiding work up front often leads to 10x more work later
    • Let’s say you have 10 pages and they all know how to call back to the Application Navigation queue. Seems like a good idea at first: When you click the ‘Settings’ button it pushes the ‘Settings’ page to the top of the queue. It works fine when you start your solution and it’s a small project. Then it grows. And grows. Then you have 40 pages that all do this. Then your boss says “Oh, we need to be able to move forward and backward.” Well… You can’t do that with a stack because you’ve popped off the pages and their gone. Now you have to make your own navigation scheme. Wait for it… Then you realize you have 40 pages that all make their own calls to the built-in scheme all over the place. Oh crap…
    • This is where abstracting away some things is good. If you had built a NavigationLayer class and given it the “PushPage” and “PopPage” methods that did nothing more than call the build-in queue you wouldn’t be looking at working the weekend because you wouldn’t have to change 80 calls. You would just update the methods in your NavigationLayer.
    • The same goes for any major mechanism. If you have 100 direct SQL database calls and the boss says “We’re changing database engines” then you’re crapping your pants. But if you have a DataAccessLayer with methods for “GetRecord” and “SaveRecord” you just have to change engine support in one place.