Lessons Learned running a Startup on Firebase Part I

As engineers, you know the situation: Building from scratch is what gets us excited all the time! Things can get tricky though if you succumb to the siren song of the shiny and new, like Firebase, over the tried and trusted — a traditional web stack.

Paul Solbach
Praise

--

Today, we want to help you make informed decisions by sharing our experience with Firebase, a mobile and web development suite that rose to prominence after its acquisition by Google. Developing Praise, the “Instagram of quality journalism”, we ended up using Firebase in hopes of quick iteration cycles. We’re developing the building blocks of a social network where it’s all about real-time interaction, distribution of events and a solid user experience. While we quickly made progress, Firebase confronted us with quite a few trade offs. This is the first installment in a series about our development journey with the popular all-in-one solution. Some of our findings are undocumented, some may strike you as odd. Let’s go.

Firebase for Rapid Prototyping

Praise started out with the notion of a Graph database connecting an infinite amount of item types — we centered around Cayley and a bespoke Go backend, only to ditch the concept altogether a few weeks down the road in favour of a rather unwieldy Spring Boot Application. Praise was growing from an academic exercise into a very serious app, seed funding followed, we needed to speed things up. So we switched to Javascript exclusively and went all in on Firebase. These are the criteria that led to the decision:

  1. As a social network, we needed to implement user feeds at scale — something that Firebase promised to easily fulfill.
  2. While in prototype phase, we wanted to be front-end driven. We didn’t want to spend time on schema migrations, models and most importantly, infrastructure decisions.
  3. All development happens in Javascript
  4. Solid performance and availability

Firebase helped us concentrate on the product: authentication, API, infrastructure, hosting and more we simply got out of the box. But as always, there is a catch. While the basic Firebase API is really easy to grasp, dealing with its idiosyncrasies like security rules — a middle ground between authorization and consistency checks, can be painful and time-consuming to test against. Which brings us to our first topic.

Testing

Testing is the biggest trade-off with this type of serverless applications. Mostly because we’re not dealing with a local database. Rolling back and replaying transactions is not easily done with Firebase. Testing cloud functions is cumbersome — we’re triggering functions on database changes a lot, much like stored procedures in SQL. Before deciding to invest in Firebase, you might be well advised to glance over the unit testing documentation.

While you can run cloud functions locally, interfacing is only possible through a Node REPL. That means, piping lines of code into that REPL is an option — waiting for the result of an asynchronous function is not. To their credit, the Firebase team has programmatic access to local functions on their roadmap.

Support

Ideally, developers support each other through documentation. Firebase tutorials outside of the Google docs are scarce and subject to constant changes. Firebase is a moving target. We ran into multiple standard issues that we addressed either on Github or Stack Overflow. The Firebase team was very responsive and did their best to help. Only once did we resort to a more traditional bug filing that never went anywhere.

Hosting & Server Middleware

As a precursor to server-side rendering, we needed to deliver dynamic meta tags to Twitter and Facebook crawlers. Without these, no fancy Twitter cards or rich Facebook shares. While this requirement is purely web related and therefore outside of the Firebase sweet spot, we needed it. Yet at the same time, we didn’t want to leave the serverless world and set up all kinds of cloud resources just for this one feature.

Turns out, Firebase hosting offers access to a faux server layer out of the box — though it ain’t pretty: define cloud function handlers for routes inside your firebase.json. An approach that immediately reminded us of Zappa, one of the first killer apps done on top of AWS Lambda. With Zappa, you could run a whole Django app inside a cloud function. What seemed mind-blowing at the time has now become our awkward reality.

We set up a bare bones https function that runs Express to “hydrate” our index.html with dynamic meta tags — relative to the requested route. We quickly got working results.

{
"database": {
"rules": "rules/rules.json"
},
"hosting": {
"public": "./public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [{
"source": "**/",
"function": "app"
}]
}
}

And then the pitfalls started. The function had a cold start execution time of a whopping 7 seconds. After that it dropped to sub 100 milliseconds. To mitigate this, we introduced a) aggressive caching and b) restricted the paths for the Express function to trigger.

Firebase documentation states that routes are defined using the glob pattern. Which is not entirely true. We found that routes starting with modifiers are deemed invalid by Firebase. If you want to match all routes except x, you need to start your pattern with **/. No way around it.

“source”: “**/!(person|user|search|etc)”,

After deploying the fixed code, Firebase deploy threw a syntax error that we didn’t encounter running the official development server. While the error message didn’t hint at it, we needed a trailing slash in our “destination” value. Always prepend a slash to files, but leave it out if you target a cloud function.

While the Firebase example for dynamic responses suggested filtering by User-Agent, we decided to forego this as we now had the function trigger only where we needed it.

Finally, we set up Pingdom to prevent the function from being instantiated and thus keep execution times low. The result is far from ideal but good enough for now. We will move away from serverless at some point — unless Firebase comes up with a solution to deliver dynamic responses on web.

More to come

In Part II of this series, we’re diving into Custom Tokens to replace standard cookie-based User Sessions. Follow us here to get the latest posts right to your inbox.

--

--

Paul Solbach
Praise

Founder (@nma_vc W18) · Leibniz Institute for Media Research · Computational Journalism · Performance Marketing · Subscriber Acquisition · Recommender Systems