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!

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 guideline, 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.

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 example you may need to modify some data after the user adds it to do clean up or something like that, you can create a cloud function that listens on new documents and then does whatever you need.

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

exports.newPartyCreated = functions.firestore
  .document('parties/{partyId}')
  .onCreate((snapshot, context) => {
    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 2 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. 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 reach out anytime and I’ll be happy to help!