As part of our work as software developers at Raizlabs, we are constantly evaluating the latest development tools used around the industry. It is always fun to see what other people are working on, and sometimes we find a tool that changes how our entire company works. Unfortunately, that’s not the case with Firebase, but it is a great tool to have in your belt, and it shows a lot of promise.
Firebase is a back-end as a service solution that has far more features than its competitors. It features a realtime database, authentication system, storage hosting, push server, and a whole bunch more. The application we were building with Firebase was an iOS app with a accompanying web admin portal to administer content.
Most of this article is specific to our interaction with the realtime database feature. We did interact with many of the other features of Firebase, but our experience with those was more straightforward. I’d be happy to talk more about it in future posts—let me know in the comments!
It seems that Firebase has a solution for everything. Looking at their site, they have ads, analytics, push notifications, full document storage, and more.
The entire database is backed by a real-time connection to the back end, and if you use the Firebase SDK, you get live updates in your app any time something changes. This is ridiculously powerful. You don’t have to constantly poll the server or build pull-to-refresh controls into your app, and no need to send a push notification if you want to control the app updates.
You can hit the ground running, writing only native code, and fly through screens in your app. The SDK handles all network traffic, which saves you from having to write a networking layer. Since the Firebase database is schemaless, you can define your data model in your app without having to make changes to any server code. I haven’t seen another service that has allowed us to get moving as quickly as Firebase has. We didn’t use any of the Firebase’s UI libraries, but with them, you can write entire sections of an app in hours.
Building for multiple platforms using the same database and backend is a breeze with Firebase. They have an SDK for all the popular languages, and as far as I can tell they are pretty close to feature parity across all platforms. There is a bit of code duplication on each of your clients for some of the business logic unless you build a server in front of Firebase, but chances are that your overall code savings from their SDK and feature set will be worth the duplication.
There have been a few cases where things haven’t quite worked out, but for 99% of our app, simply following the documentation carefully led to things just working as advertised. This increased our confidence in the product, and removed time spent poking through others’ code, especially server-side, trying to figure out where bugs were coming from.
That the database is real time is great, but it also creates a few issues when trying to interact with it when you don’t care about getting real-time updates. For example, if you want a list of post that a user has written, you tell the server to listen for
ChildAdded events on your query, and you receive a callback for each post. The issue with this is that if the user doesn’t have any posts, you’ll never get a callback, and there isn’t a concept of being “finished loading,” because the connection stays open. Because of this, things like empty states are hard to do without setting up multiple queries or storing extra information in the database.
The other issue with the real-time database is that you have to worry about race conditions and having multiple people update the same record at the same time. The SDK has a nice way of handling this using transaction blocks, but this is another thing that you have to worry about as you code.
Firebase gives you some access control for specific parts of your app, but there is a lot to be desired here. Controlling access to a certain nodes of data for only a few users becomes challenging by editing Firebase’s database rules file, and you really don’t want to rely on the business logic of your application to keep a user from accessing something they don’t have permission to.
Also, there is a high potential for data loss. It is very easy to accidentally delete your entire database when you are in the console. Two wrong clicks and all your data is gone! And finally, if you’re trying to copy data over to a different instance, the
import JSON feature is great, but note that it will probably result in your accidentally losing some data at some point as the import deletes all the data at the current tree and replaces it with the imported JSON, rather then a merge, so don’t try this out on production until you have played around with it a bit.
In the apps we build, we typically need to support different server environments: dev, stage, and production at the minimum, possibly more. Firebase made this difficult, at least on iOS, by requiring you to have a plist file that is correctly named
GoogleService-Info.plist to load all of the environment parameters. While you can configure your own, and we found our way around this issue for the most part, certain features like analytics and crash reporting were not easy to get working.
The Firebase database is structured like a giant JSON file. Because of this, there isn’t really the concept of relationships. While there are a lot of “schemaless” databases coming out lately, they usually provide some out-of-the-box way of handling simple relationships. Firebase requires you to build all of that yourself, including some complicated code for deduplication in your database. If your database requires a lot of relationships, it’s worth modeling out how your database will be constructed in Firebase before choosing to use it.
So far, Firebase seems like a good tool; it just requires a different way of thinking about how you work with apps. There are, however a few things that will make me think twice before using it again:
Firebase currently doesn’t support sorting and filtering by multiple keys. You can only do it by one key, and if you want to both sort and filter, those both have to happen off the same key. For example, if you want to get a list of posts by a particular user that are sorted by the last updated date, you can’t. You would have to get all the posts by that user and sort client-side. This isn’t that big of a deal, unless you start getting into thousands of posts. Also, making a request for something as simple as the count of a query is not possible without fetching the entire dataset.
Our application had too much data to download it all to the device at once, so we wanted to fetch it in pages of 30 entries each. There are multiple ways to go about this in Firebase, but they all involve extra code and CPU cycles. One method is to replace your query with a new query asking for the first 60, but now you are potentially re-importing the initial 30 entries that you already have. At least Firebase is caching them all, but it is still extra application code and battery drain to ignore these. When you are re-requesting the first couple of hundred entries every time, it does start to take its toll. The other option is to have multiple queries that you are observing, one for each group of 30. This also adds complications since everything is realtime and you have to keep track of each query and make sure to un-subscribe.
Firebase is unrivaled, as far as I am concerned, when it comes to how quickly you can move as a developer. Its real-time interaction features can save you from having to write huge parts of an app. In return, you have to make a few sacrifices, and you can’t think about the data in the same way as a more typical API. In the case of building production apps, it’s worth working through all of your requirements before you jump in, but for proof-of-concept or fun projects, Firebase will definitely be my first choice.