The Ship to the Stars

The Ship to the Stars

ยท

7 min read

Welcome back to "Don't Panic - The Guide to the Galaxy of .NET MAUI Development" series!

Today's cosmic quest revolves around the project/app through which we'll navigate the vast universe of .NET MAUI development. In our last cosmic log, we waved goodbye to the Blazor variant of the project. Today, we roll up our sleeves and elevate the initial project template to a useful level.

From the Template to "Mark Zero"

In our template, logic is stashed in the Code-Behind, much like hidden treasures in a space cargo hold. This is the first space anomaly we'll rectify. <-Model View ViewModel (MVVM)->

MVVM

I first encountered MVVM in a project within the dental Industry, around 2007. It was a time when we witnessed a transition from MFC to WPF. A savvy colleague was tasked with testing the waters with "Avalon." Alas, we didn't get to steer that ship to its destination โ€“ another developer crew took over. Pirates?! Ah, the good old space days! ๐Ÿ˜„

Back then, it was like the Wild West of coding: "Who needs SVN? I'll just float around text files and make a div" โ€“ These were the wizards who could convert hex to decimal in their sleep. But enough about the olden days.

I've always viewed Model-View-ViewModel as an evolutionary step in software engineering - from MVC, MVP... to MVVM. It separates concerns like a starship separates its decks, allowing, say, a UI team (the View crew) and a logic team (the ViewModel engineers) to work simultaneously. Over time, many have had their own interpretations of what's allowed in this pattern. I'd boil it down to "all is fine as long Separation of Concern".

Today, we have a few Nuget Packages that'll save us loads of boilerplate code, almost like having a warp drive for coding!

With these, we'll be able to establish a connection between the View (xaml, xaml.cs) and the ViewModel (.cs).

One way to tether our ViewModel to the View is by using the constructor in the .xaml.cs file.

public partial class WatchPage : ContentPage
{
    public WatchPage(Watch vm)
    {
        InitializeComponent();
        BindingContext = vm;
    }
}

The rest of the magic happens in the XAML and the ViewModel. Imagine it like piloting the same spaceship with different navigation systems (ViewModels), altering its course and behavior. Similarly, we can pair our steadfast ViewModel with various Views, each presenting a different visual representation. Ah, the joys of Separation of Concern.

Architecture - A Galaxy of Choices

Now, how shall we craft our app's architecture? I'm keen on not anchoring myself to just one technology. This project should be my playground, allowing me to leap between technologies, comparing and contrasting them like a cosmic explorer.

I'll consult our trusty sidekick for some insights.
Hey, PixelMarv ...


"Ah, the ever-expanding universe of Tech Stack, frameworks and solutions to develop,"

NameDateTech Stack and LanguagesUsed PrimarilyExpectation for the FutureSeparation of ConcernsInversion of ControlModularityTestabilityMaintainability
Model-View-Controller (MVC)1980sVarious (JavaScript, PHP, Ruby, etc.)Traditional applicationsLimited use in modern complex appsXX
Event-Driven Architecture (EDA)1990sLanguage Agnostic (JavaScript, Java, C#, etc.)Asynchronous event handlingSpecific use casesXXX
Model-View-Presenter (MVP)2000sVarious (Java for Android, C# for .NET)Web and mobile applicationsOvershadowed by advanced patternsXXX
Service-Oriented Architecture (SOA)Early 2000sLanguage Agnostic (Java, .NET, etc.)Enterprise solutions and backendCommon in enterprise backendsXXX
Model-View-ViewModel (MVVM)2005.NET Maui, C#, XAMLModern mobile and web appsHighly popular in modern developmentXXXX
Clean Architecture2012Language Agnostic (Commonly used with Java, Kotlin, Swift)Scalable, maintainable appsIncreasing tractionXXXXX
VIPER2014Swift for iOSComplex mobile applicationsNiche due to learning curveXXXX
Flux Architecture2014JavaScript (React, React Native)React Native appsUnidirectional data flow in React NativeXX
Redux Architecture2015JavaScript (React, React Native)State management in React NativeWidely used in React NativeXX
Microservices Architecture2010sLanguage Agnostic (Java, Go, Python, etc.)Complex, scalable systemsIncreasingly popularXXXX

This table, dear travelers of the .NET MAUI cosmos, is a star map of sorts. It charts the diverse galaxies of mobile development architectures, their primary missions (use cases), and now, the technology stacks and languages they speak โ€“ a kind of intergalactic Rosetta Stone. Plus, it showcases their allegiance to the sacred design principles of the coding universe.

With a whimsical beep, PixelMarv concludes, "There you have it. A guide to not just the what and the why, but also the how of mobile development architectures. Because knowing is half the battle, and the other half? Well, it's not panicking."

thanks PixelMarv


In our project, I will combine the approach of Clean Architecture with MVVM. For those who are not yet familiar with Clean Architecture, here's some background knowledge:
->The Clean Architecture<-

This reveals the name of the project as well. It will be an app that I, as a developer, will use to start the day. The project name is Chronos, and it will be an app that I would describe as a TimeKeeper. However, it will be tailored to the needs and possibilities of a software developer.

chronos**.app** (Applicaton Startup)
chronos**.Core** (Entities/Model)
chronos.usecases (Application Business Rules e.g. SetAlarm)
chronos**.presenters** (Interface Adapters / ViewModels)
Framework (Plugins)
- chronos.UI (XAML + CodeBehind)
- chronos.DataStore ( Entity Framvework Models + Repositories)
- numpitz.Device (Device Services & Platform specific implementatons)

A significant aspect that enables this architecture is constructor injection. You've already seen this above in the xaml.cs file. The creation of the class that is injected there is taken care of by the framework for me. Within the chronos.app/MauiProgram.cs, all services that we bring to life via constructor injection are registered. For example, .AddUIServices()

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseMauiCommunityToolkit()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
            });

        builder.Services
        // Plugins - Frameworks & Drivers
            .AddDeviceServices()
            .AddDataStoreServices()
            .AddUIServices()
            .AddPresenterServices() // <- Presenters - Interface Adapters
            .AddUseCaseServices();  // <- Use Cases  - Application Business Rules 

        // Entities - Enterprise Business Rules
        // NOOP     ยฏ\_(ใƒ„)_/ยฏ

        return builder.Build();
    }
}

In case you're wondering, I've used extension methods to carry out the initialization in the actual projects. The registration of the WatchPage (our View) happens there ...

namespace numpitz.device;

public static class ServiceCollectionExtensions
{
    public static IServiceCollection AddUIServices(this IServiceCollection services)
        => services.AddTransient<WatchPage>();
}

Analogous to this handling, each component has its own service registration in its own extension method.

Chronos.app and the first Stories to be done

In the stories, I will always indicate how they affect the code base. You must know that everything has its price. Characteristics that are influenced by adjustments:
- Function -> userstories and requirements
- Opearatonal -> performance, awailability, runtime behavior
- Developmental -> maintainability, degree of managing technical depts, portability.

This perspective comes from ->Kevlin Henney's presentation at NDC London 2023<-. (minute 24 in the video) and I agree on it.

In this project, I will visually represent the impact using a triangle. Each story will show the effects, and I will try to learn from them because we don't want our ship to fall apart along the way.

And so, dear cosmic coders and interstellar developers, we're approaching the end of this chapter in our adventure through the galaxy of .NET MAUI. It's been an absolute blast writing and sharing these nuggets of wisdom with you.

But fear not, this is not a goodbye, merely a brief pause in our journey. The next chapter promises to be even more thrilling, as we set our course towards the uncharted territories of our very own app, 'Chronos', and its GitHub repository - a treasure trove of code waiting to be explored!

So, keep your space suits ready and your coding fingers nimble, for our adventure is far from over. Until we meet again, may your code be bug-free and your spirits high. Ad astra, dear friends, to the stars and beyond!


About

ย