Js Mobile Dev About Courses Articles Youtube Services Contact

3 Things you can do right now to improve your Ionic and Firebase app performance

Libraries and Versions

Backend: Firebase all

Are your users complaining because your app is taking long times to load?

We all know how impatient our users can be (mostly because we're also impatient when it comes to waiting for sites to load).

You want to give your users the best experience possible when using your app, and even though there are lots of things we can do, one of the most important parts of an app we need to prioritize is performance.

It's not only about the 100% lighthouse score, it's also because app performance has a real impact on people's lives.

Think about it, when was the last time you tried to load your app on a slow connection? No wifi, no stability?

Today you'll learn 3 things you can do right now inside your app to improve the performance.

Duplicate your data (responsibly!)

Reading > Writing.

It takes a while to interiorize that, but it's true, your app is going to be reading data from the database a lot more than writing it, that's why in NoSQL databases we forget about normalization, and we instead optimize our data for reading.

For example, let's say you have a party planner app, where you store information about both the parties, and the guests of those parties.

One common solution can be to have 2 collections in Firestore one for guests and another one for parties.

And then relate parties and guests by their IDs, that way you know who went to what party.

Something like this:

{
  "guests": {
    "guest1": {
      "name": "Jorge",
      "lastName": "Vergara",
      "age": 31,
      "parties": ["event1"]
    },
    "guest2": {
      "name": "Andres",
      "lastName": "Ebratt",
      "age": 30,
      "parties": ["event1"]
    }
  },
  "parties": {
    "event1": {
      "eventName": "Birthday party",
      "eventDate": "27-09-2017",
      "guestList": ["guest1", "guest2"]
    }
  }
}

This kind of works, if you need to know who came to event1 you have the list of IDs and can get those guests from the database.

Same if you want to know which parties did guest1 attend to, you have the ability to get that information now.

That's the kind of data structure you'd create if you were using an SQL database.

But NoSQL databases don't work in the same way, and Firestore doesn't have JOIN queries, so, if you'd want to open the detail page for event1 and show the details and the guest list, you'd end up doing 1 database call to get the event details, and then one database call for each guest in guestList to get their details from the database.

That's not optimal, it increases the wait time for our users, and it creates a higher cost for us, since we're paying Firebase for every read/write we do to our database.

Instead, to make it easier on our app, we can set up something like this:

{
  "guests": {
    "guest1": {
      "name": "Jorge",
      "lastName": "Vergara",
      "age": 31,
      "parties": [
        {
          "eventName": "Birthday party",
          "eventDate": "27-09-2017"
        }
      ]
    },
    "guest2": {
      "name": "Andres",
      "lastName": "Ebratt",
      "age": 30,
      "parties": [
        {
          "eventName": "Birthday party",
          "eventDate": "27-09-2017"
        }
      ]
    }
  },
  "parties": {
    "event1": {
      "eventName": "Birthday party",
      "eventDate": "27-09-2017",
      "guestList": [
        {
          "name": "Jorge",
          "lastName": "Vergara"
        },
        {
          "name": "Andres",
          "lastName": "Ebratt"
        }
      ]
    }
  }
}

Now, whenever you go to an event detail page, you got all the information you need to display the user in one database call, reducing both your costs and the wait time for the user.

If you're coming from an SQL background (MySQL, PostgreSQL, etc.) you might think this is just plain wrong, but in NoSQL, data duplication isn't a bad thing, in fact, it's a best practice!

Stop counting documents

Sometimes we need to know our numbers, things like, how many guests attended a party, or how many parties have a guest been a part of?

With our current data structure, we have to do a lot of database reads to get those numbers. For example, let's say you want to know how many parties are in the system.

One thing you'd do is to get the list of parties from the database and then count the number of documents that query returns.

The biggest issue with this is that it will query the database and read ALL the documents in the parties collection every time you need that number.

Which means that you'd be performing all of those database reads (and paying for them!).

One thing we can do, is to keep data aggregators in the database.

For example, whenever a new party is created, you can add that to an aggregator document, for example:

{
  "parties": {
    "--stats--": {
      "totalPartyCount": 2,
      "totalActivePartyCount": 1
    },
    "event1": {
      "eventName": "Birthday party",
      "eventDate": "27-09-2017",
      "guestList": [
        {
          "name": "Jorge",
          "lastName": "Vergara"
        },
        {
          "name": "Andres",
          "lastName": "Ebratt"
        }
      ]
    },
    "event2": {
      "eventName": "BBQ",
      "eventDate": "27-09-2017",
      "guestList": [
        {
          "name": "Andres",
          "lastName": "Ebratt"
        }
      ]
    }
  }
}

That way, whenever you want to know that kind of information, you'd only need to read that document and have all the data ready for your users.

Send code to the server

One thing that can help with the performance of your app is to have your app do less.

Seriously, let the app do less work.

You can achieve that by sending all the extra work to the server.

As a rule of thumb, I like to send to the server whatever it's either 1) resource intinsive to do or 2) it's for the app and the user doesn't need it there.

Our previous aggregator feature is an excellent example, because it's something we need for our app, but not something the suer cares about at the moment of creating an event.

For things like these, you can create Cloud Functions, They're one of firebase most used services, you write your JavaScript or TypeScript function, and then you let Google handle the scaling, management, etc.

For our previous example, you can create a Firestore trigger that can listen on new documents being added to a collection, in our case, the parties collection.

And whenever a new document is added, it will add a +1 to both the totalPartyCount and the totalActivePartyCount properties.

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();

exports.newPartyCreated = functions.firestore
  .document('parties/{partyId}')
  .onCreate(
    (
      snapshot: FirebaseFirestore.DocumentSnapshot,
      context: functions.EventContext
    ) => {
      const increment = admin.firestore.FieldValue.increment(1);

      return db.doc(`parties/--stats--`).set(
        {
          totalPartyCount: increment,
          totalActivePartyCount: increment,
        },
        { merge: true }
      );
    }
  );

Since all that code is running on Firebase servers, all your app needs to do is create the task, the Cloud Function will fire up and do the aggregation for you.

Next Steps

Now you know 3 things you can do to increase your app's performance, one thing you can do right now is take a pen and paper and audit your app, ask yourself these questions:

  1. In what pages am I making multiple database calls? Can I reduce that to one call if I duplicate part of the data?
  2. Is my app counting documents on runtime? Can I create an aggregator to fix that?
  3. What functionality doesn't need to be inside the app? Can I create a cloud function for it?

And if you need help implementing any of those, remember that you can leave a comment below and I'll be happy to help!


Become a Mobile Developer using JavaScript

Leave your email below and you'll get one or two emails a month sharing articles, videos, or courses that will help you jump-start your development with Ionic, Firebase, and Angular 🚀.

    I don't do the spam thing, you can one-click unsubscribe at any time