Best Practices for Firebase Realtime Database Development

News Rush has been using Firebase for 4 months now, and although there are things we would like to see improved (can you name a “perfect product?”), it has been a valuable addition to our stack for our mobile data sync requirements.

Along the way, we’ve learned some lessons about how best to use the platform to meet our needs. Firebase is a document-oriented / NoSQL database, and thus shares many of the characteristics of those platforms, but also has some unique traits of its own to learn. Here’s a quick brain-dump of what we discovered along the way.

RTFM!

SDK documentation is usually terrible, so many of us tend to skim for the high points and return to it later (or never).

The opposite is true here. The Guides and Samples are easy to follow, and the Reference docs are both thorough and deceptively brief. Almost every time our team had a question or issue, we found the solution in something we missed in the docs. We ultimately sat down and read every word straight through, and it was 3 hours well spent.

There is also a blog that is a treasure trove for finding solutions to real-world problems. Here are a few of the posts we found most critical in News Rush:

Corollary: “Schema-less” does not mean brain-less!

It is a common misconception that document-oriented databases make up-front planning about how data will be structured less important. This is a myth. If anything, we have found the opposite: they require more.

There is nothing unusual about saying good planning can help squeeze the most performance out of any software component. But in SQL databases it’s usually straightforward to fix planning mistakes either by just joining more tables, doing sub-queries, or doing bulk data updates. Since Firebase doesn’t have these concepts, take the time to sit down and actually model your data and access patterns ahead of time. You’ll be glad you did.

And RTFM!

Support is Confusing

There are a number of support options, but attempting to use the wrong one in a certain situation can be frustrating. Our experiences have been:

  • Slack: Community-oriented self-help and brainstorming not suited for other venues. Not suitable for “something is down.”
  • Support Form: The “official” support venue. Report “something is down” here. Feature requests likely to get a canned “we’ll consider it, but no promises” response.
  • Google Groups: Active involvement by the core team with the usual caveats about turnaround time in group-oriented mail systems. Best place for highly technical discussions about app internals and “weird” issues.
  • StackOverflow: Slow/unpredictable response times but best place for backup reference material. If you’ve read a Q&A on StackOverflow, you know the type of question that’s best to post there, too.

Refs and simple retrievals are “cheap”

In Firebase, a “ref” is like a pointer to data. It’s instinctive to want to cache or otherwise manage them, but in the current Firebase client libraries you should never do this. They’re really just wrappers around the URL references to data objects, and the event callbacks they provide access to can only have one listener at a time. If you need to reference an object from two different places, take two refs to it. It doesn’t “cost” more to do this.

A similar rule applies to data retrievals. Those coming from SQL databases are accustomed to trying to retrieve larger objects in as few queries as possible to eliminate round-trip time and query overhead. When flattening data structures, it’s tempting to copy “summary” data into multiple locations to allow a single retrieval to get everything required.

In Firebase, this is almost entirely the wrong decision. For one thing, simple key/ref-based retrievals are heavily optimized and Firebase offers massive horizontal scale for them. In our performance testing at News Rush, we also found that Firebase does much better with more, smaller objects. Even removing a few unnecessary fields can provide a measurable performance increase.

Just as with Redis’ optimized patterns for structures like hashes and sets, Firebase’s massive horizontal scalability is one of its key features. It shouldn’t just be a nice-to-have. It should be leveraged itself as a tool in your app designs.

Avoid arrays

The Firebase documentation already covers this topic. It’s all correct. Avoid them.

No dates

Firebase has no date object type and does not allow descending sorts. We just wrote a helper “update” function that takes native objects with Date fields and converts them to milliseconds-since-epoch values, and also adds corresponding negative number variants of those values. Sorting ascending on a negative-number time value provides the descending order desired.

One size does not fit all

It seemed like such a good idea at the time…

Leverage Firebase’s strengths. Don’t try to make it do every job you have. Here are some things Firebase is not:

  • A search engine. It has a few basic operations like prefix-matching, but that’s it. Use ELK, Algolia, etc. if you need full-powered search.
  • An API stack. Cloud Functions for Firebase looks very promising, but is still in Beta. If your app is anything more than a to-do list, plan how you’ll do server-side/trusted code execution.
  • A reporting engine. You may still want to leverage a relational database when you need to slice/dice/filter/mutate/munge/etc your data.
  • Self-hosted or fully usable offline. Offline functionality is provided via sync/persistence, but the Firebase cloud must be involved at first.

Set vs. update

There’s a big difference between SET and UPDATE operations. It affects what happens if a key doesn’t exist yet, particularly keys inside complex objects. Pay attention to it!

FirebaseUI is awesome!

Oh I should mention, there are FirebaseUI companion projects for a lot of platforms. Use them. They’re incredibly helpful for things like setting up a tableview to display a list of objects in a Firebase collection.

This library provides FUICollectionViewDataSource and FUITableViewDataSource classes (and their equivalents on Android) that make getting started on a mobile platform just a few lines of code. That running start was very nice when we were initially evaluating Firebase. We were able to put together a proof of concept in a few hours with very little learning involved compared to other options on the table.

When you’re ready for more sophistication and control, FirebaseUI is still useful because it also provides the lower-level data collection classes FUIArray and FUIIndexArray that let you drive things like tab headers and other oddball displays.

Did I miss anything? Share your own!