052: Mobile App - Part 1 - Design and Technology Skip to main content

052: Mobile App - Part 1 - Design and Technology

This initial phase of a small Mobile App project presents motivations and goals for a new application, and gives directions around tooling selection.


The weekly mood

As already mentioned some time ago, I sometimes spend my freetime riding a roadbike. And as it belongs to, I feel both the need to have pleasure and to perform. At first I enjoy good weather, beautiful landscapes and spontaneous break-aways with mates. From time to time, I also expect to make or smash the numbers, simply by pushing it to technical and mental limits where applicable.

A few months ago I wrote a blog post about recording rides using a GPS / Running watch, and analysing calculated power data from Strava segment efforts. Now, I feel the need for something to show me how I perform while riding. Since the watch doesn't show more than speed and time like a cheap bike computer, I do need some extra. However, I want to achieve this with parsimony, that is without purchasing a Cycling power meter which price ranges from 500 to 2000 USD (display unit not included).

I believe this is a good topic for a Smartwatch or a Mobile app. Although there are tons of projects dedicated to riding on Marketplaces, I didn't find exactly what I am looking for. Worse, I found some horrible apps eating batteries or teasing the user for a premium subscribtion. Unlike GPS riding devices, Smartphones are in fact not optimized for long navigation and screening time.


Use-case description

Now that we have a good reason to building an App, let us talk about the functional scope. I would love to achieve an implementation of the Velocità ascensionale media (VAM), an absolute performance indicator developed by Michele Ferrari, a sport scientist unfortunately more famous for his supporting role in several doping cases in cycling, than for his prominent contributions to training research.

The VAM is the speed of elevation gain, usually stated in vertical metres per hour (Vm/h). Like for relative Watt-power, its value rises up with every gradient increase. Although it can obviously be measured only in climbs, it is a great tool that tells you how competitive you are, independently from inclination changes, riding technique, body weight, mechanical engine, road friction or air resistance. It is just you against road elevation. Moreover if you know your real-time VAM, then you can better manage your current effort and predict your performance, as required for example by a Time-trial (TT).

Note that the VAM is what analysts use to calculate a performance of professional cyclists based on known characteristics such as a climb profile, an athlete body and bike mass, a climbing time. Based on this value, they can not only conclude how much competitive and consistent the athlete is, independently from the climb, but also deduce relative Watt-power per Kg even though they don't have access to any Powermeter data.

I assume that the reason why bike computers typically do not support VAM, is that a point-in-time value would be displayed in a way that looks too random or too unreliable to the rider. Still, the VAM calculation is in fact very similar to the road inclination Grade (%). Indeed, the Grade (%) is equal to 100 x Ascent (m) / Track length (m), whereas the VAM (Vm/h) is equal to Ascent (m) x 3600 / Time (s).

I actually found that the VAM Data Field from Garmin Connect IQ store is a great option for climb-only workouts. However, it does not truely reflect your immediate effort, but your total ascent divided by your total time instead. During climbing portions of my rides, I'd actually be interested in a reasonably smooth measure of the last 5s effort with refresh every 1s, a so called sliding-window.

Based on the moving average, we could calculate both Grade (%) and VAM (Vm/h) to display, and eventually trigger symbols or colours for the corresponding difficulty and effort zone. In addition, it might be useful to provide both a manual toggle (to deactivate processing while keeping the App loaded) and an automatic trigger (to activate only when display is on and grade is positive).

UI-Mockup powered by sketchboard.io

Note that I might look into the Smartwatch SDK for developing my own Data Field in the future, but I don't see much value for the Architect to work with very specific Monkey C language and Garmin platform.


My experience of mobile development

I have very little experience in Mobile app development. Indeed the first and last time I did something in this area was 8 years ago. 

It was a hybrid Single Page Application (SPA) developed using SenchaTouch, a Javascript framework based on ExtJS UI library and the common Model View Controller (MVC) pattern. In this context, "hybrid" means that the app is embedded in a WebView and running on HTML5 thin layer which behaves almost like a device-native app. For the Graphical user interface (GUI), it means that Android widgets and iOS widgets pods are imitated by a dedicated library of components. For device-level access like in our telemetry use-case, it means using World Wide Web Consortium (W3C) APIs such as device motion (m/s) and orientation (x, y, z).

This revolutionising approach broke with traditional low-level development, based on Mobile Software development kits (Mobile SDK) such as Android SDK and iOS  SDK. I can't remember which exact version of SenchaTouch I used, but coding and build processes were not as easy as they should be. Still I already had a previous experience with Java Server Faces (JSF) and Google Web Toolkit (GWT) and therefore found it intuitive and convenient to pick and configure UI components from a pre-defined list.

My first mobile app was able to display the current date along with a splash picture depending on the current weather trend as delivered by a simple 3rd-party service. It then suggested a random, yet reasonable "challenge of the week" such as "call a friend" or "go jogging". It allowed the user to rate her/his progress and input some comment (local storage only). Finally, she/he could access his history from a list, although I wasn't quite satisfied with this part. The app loaded from a public web server and didn't work offline.


Mobile app development today

Since then, Mobile application development seems to have improved a lot, offering user and developer experiences (UX/DX), as well as better stability and performance. However, Javascript frameworks used for Frontend Web Development have a short life-cycle characterised by a quick ascent and a slow decline. For example, SenchaTouch reached its first stable version in 2011 and end-of-life in 2015. There are so many different alternatives that only few people will get in touch with or remember of it. 

In my opinion, graphical Web UI designer tools such as Hugo can be useful for writing static pages (ex. ) but not much for building a complete app. I assume that new services such as AWS Amplify are setting interesting trends for abstracting common infrastructure concerns such as authentication and storage, making backend development accessible to more and more people.

Let us now focus on current options for building cross-platform mobile apps from a single code base. Such apps do not yet follow the principles of Reactive programming (responsive, resilient, scalable, message driven), but they at least comply with the following levels of maturity:
  • decomposed = in order to increase component modularity at different layers, and interoperability with different APIs.
  • responsive = auto-adjust UI element positions and sizes based on the capabilities and configuration of the display.
  • progressive =  based on standards which offer Developers and Users a consistent Experience  (DX, UX) accross various runtime platforms (ex. Desktop, Browser, Mobile device).
Looking at available Open-Source frameworks, I took Ionic, Flutter and NativeScript on my shortlist because of their high maturity and popularity.


Ionic

Ionic is a hybrid Javascript framework (like SenchaTouch) which renders Progressive Web Applications (PWA) developed in HTML, CSS, Javascript, and optionally TypeScript. For reference, Typescript is a statically typed superset of Javascript which is developed by Microsoft and used to make Javascript development better. You can learn the framework via Udemy's Ionic courses.

Ionic core capability is a Command line interface (CLI) used for building and running PWA. It is developed in TypeScript and released under the MIT License. It installs as NPM module and operates on Node.js, a JavaScript runtime environment that executes JavaScript code outside Web browsers, and can therefore be used for backend applications.

While initial versions of Ionic PWA built atop of Apache Cordova (formerly Adobe PhoneGap) and AngularJS, later ones introduced Ionic's own cross-platform runtime Capacitor (claiming that Cordova becomes outdated), and became Web-framework-agnostic through the use of the Web Components standard (custom HTML-tags). Choosing between AngularVue.js or React is now just a matter of configuration. Not sure whether Next.js can already be integrated or is part of the roadmap.

Here is the code of the example App from Ionic React Quickstart:
// index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));
// App.tsx
import React from 'react';
import { Route } from 'react-router-dom';
import { IonApp, IonRouterOutlet } from '@ionic/react';
import { IonReactRouter } from '@ionic/react-router';
import Home from './pages/Home';

/* Core CSS required for Ionic components to work properly */
import '@ionic/react/css/core.css';

const App: React.FC = () => (
  <IonApp>
    <IonReactRouter>
      <IonRouterOutlet>
        <Route path="/home" component={Home} exact={true} />
        <Route exact path="/" render={() => <Redirect to="/home" />} />
      </IonRouterOutlet>
    </IonReactRouter>
  </IonApp>
);
This might be a question of preference or habit, however I don't like much the mix of syntax  (program instructions with embedded XML-tags) and approach (Typescript functional constructs with embbeded Javascript imperative  blocks, yet we don't see it in the example above but it's actually very common especially for handling events) as part of the same file.


The Ionic company was originally called Drifty and backed by venture capitals. In its commercial version, Ionic comes with additional support and features, i.e.:
  1. managed platform offering including infrastructure services such as an Identity provider (IdP), a connector to authentication and authorization services, an offline storage and a continuous delivery workflow.
  2. library of rich plugins for accessing device-level functionality like calendar, geolocation and filesystem, or deploying to native runtimes and stores is a Vendor-lock-in. Under the hood, it looks like those are just certified versions of Apache Cordova or Capacitor packages.

NativeScript

NativeScript is an(other) Javascript framework which allows for cross-platform development. It has the unique particularity of rendering both web apps and fully native apps for mobile platforms, using the Telerik (TK) framework, based on XML definitions of the NativeScript UI. In the case of a mobile app, the resulting UI uses the same APIs as if it were directly built using a Mobile SDK.

Here is the code of an example UI from Nikolay Diyanov's seismograph app:
<Page loaded="onPageLoaded" xmlns="http://www.nativescript.org/tns.xsd">
    <GridLayout margin="20" columns="auto, *">
        <StackLayout orientation="vertical" dock="top">
          <Button id="Start" tap="tapStart" text="Start"/>
          <Button id="Stop" tap="tapStop" text="Stop"/>
        </StackLayout>
    <Placeholder creatingView="creatingChart" col="1"/>
    </GridLayout>
</Page>
Since application logic is executed by the Javascript runtime of the target platform, without further need for code mutation or compilation, it has to be directly developed in Javascript, Angular, Vue.js or Typescript. The same example application shows how to use 3rd-party frameworks inside NativeScript Apps, namely TK UI library for data visualisation, and native iOS classes for telemetry. You can also use 3rd-party plugins such as NativeScript Android sensors. With that, I am still a bit concerned about version support and compatibility.

In addition to NativeScript CLI which runs on Node.js, a Desktop application and a Microsoft Visual Studio Code (VSCode) extension are available. First one called NativeScript Sidekick is especially useful for XML design and templating as mentioned further above. Recent announcements suggested that Sidekick will soon be merged into nStudio. With the VSCode extension, you finally benefit from Web syntax highlighting and device emulation (VSCode IntelliSense).

NativeScript was created by Progress in 2014. The project is actively maintained ever since. You can learn it via Udemy's NativeScript courses. It has over 700 plugins and templates originated from both official and community coders, and shared via a Marketplace. It is released under Apache license and is 100% free of use.



Flutter

Flutter is Google's solution to cross-platform development. I find it especially interesting because:
  1. It originally ran on the Android operating system (by Google), which is my main target platform, before extending to other platforms, whereas other frameworks are browser-first.
  2. Coding is done in Dart programming language (by Google), instead of a patchwork of technologies, even if other frameworks encourage the solely use of Typescript.
  3. Graphical design is done declaratively using Materials (by Google), as opposed to error-prone imperatives required by other frameworks. A Flutter Widget catalog is also available.
For reference, the huge advantage of Dart over Typescript resides in its capability to compile and run the same source code in 4 different ways:
  1. Atop of Dart VM.
  2. As native mobile code for Android and iOS.
  3. As Javascript code for any Web browser.
  4. As machine instructions.
Here is the code of the starter Flutter app:
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}
Although there are still a number of parenthesis and brackets to close, the code syntax is more clean and structured than for Typescript. In overall, Flutter SDK and framework benefit from impressively high quality, performance, automation, documentation and support standards. You can learn it either via Udemy's Flutter courses or via Manning's Flutter in Action (live-video).

Development plugins are available for both VSCode and Jetbrains IntelliJ IDEA / Android Studio. Application extensions are available from the central Google community developer publisher registry pub.dev. Finally, Flutter nicely integrates with Firebase mobile Backend-as-a-Service (BaaS) with FlutterFire, a set of plugins allowing to easily deploy, host and extend the developed application.



Take-away

We just talked about the evolution of Mobile app development, and took a closed look at a shortlist of mature Open Source frameworks, all of them allowing to address my mobile app requirements, and even more. So whatever the choice, it cannot be much wrong. Although my heart balances towards Google technology, there is a risk of developing too specific skills and assets. On the other hand, what I've seen from (the more widely used) Typescript so far does not really convince me that I will miss something if I do not go for it. Therefore let us catch-up with a Flutter session in Part 2 of this article series, and figure-out how far we can implement the VAMON application.

Comments