BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Presentations Maximizing Success with Limited Time, Resources, and Energy: Lessons from Startup Engineering

Maximizing Success with Limited Time, Resources, and Energy: Lessons from Startup Engineering

49:12

Summary

David Gudeman discusses battle-tested architectural patterns for resource-constrained engineering teams. Drawing from over a decade of startup experience, he explains how pairing GCP, Firebase, and Cloud Run accelerates product-market fit. Learn how to eliminate redundant frontend state, structure event-driven backends, and maintain lean DevOps while building for long-term scalability.

Bio

David Gudeman is co-founder and CTO @Velocity AI.

About the conference

Software is changing the world. QCon San Francisco empowers software development by facilitating the spread of knowledge and innovation in the developer community. A practitioner-driven conference, QCon is designed for technical team leads, architects, engineering directors, and project managers who influence innovation in their teams.

Transcript

David Gudeman: I'm David Gudeman. This talk is about something every startup faces, and it's how to build and succeed when you don't have enough time, money, or people. Over the past 10 years, I've learned a lot about what actually works when constraints are tight, and what doesn't. My goal today is to share some practical lessons from startup trenches, not theory, so frameworks, tools, decisions that have helped me and my teams move quickly, learn fast, and build products that actually shipped. How many people are working in a startup right now? How many people would like to start a startup? If you've worked in an early-stage startup, you know the feeling, there's never enough time, there's never enough resources. You're racing the clock, trying to get something in front of users before you run out of money. You're not trying to build something elegant. Maybe you would like to, but the reality is that you really can't prioritize that. You're trying to learn as quickly as possible, you're testing ideas, figuring out what people actually want, and learning from feedback before the runway disappears. That's what this talk is about, it's how to survive and thrive in that environment.

Overview

What we're going to cover is not necessarily about the right way to build software, I don't really think there's a right way. There's definitely a lot of wrong ways, but I don't know if there's a single right way. Instead, I'll walk you through some patterns that work repeatedly for me. Specific technologies and approaches that gave the small teams that I've led or I've worked on the leverage when resources were limited. We'll start out how to pick the right foundation, which in my case was Firebase and GCP. Then talk about building fast frontends, scalable backends, long-running services, and wrap up with key takeaways.

Who am I? It's been a long time in early-stage startups, probably too long, probably over 10 years at this point, going on 11 or 12. All startups were basically under 10 people. The first company I worked at was called Symphony, then it was called Actium, then it was acquired. When I joined, I was the first engineer, and it was like five people. By the time I left, it had grown to 70. They made a lot of mistakes, that company. I had to live with them. I made some of those mistakes, I had to live with them for five years. I went on to another startup called Tappity, which is an edutainment startup, and then I went to work at Triumph, and then I started my own company. Over that period of time, I worked in multiple kinds of roles. I was an IC, individual contributor, developer.

I transitioned for years, I was a product manager, just doing product requirements gathering, building consensus, and all that sort of stuff, and working on the other side of the engineering wall. Then I was an engineering manager, so leading a team of engineers. Now I'm the CTO, and I have to own all of it. Across all those experiences, I just noticed that you really want to make selections that don't slow down the team. The reality is, at startups, you don't have that many shots on the goal. You're going to have like whatever, 10 major pushes, and you want to maximize the time you have doing that, and minimize the amount of time you're like rebuilding stuff, or building things that aren't useful. I think everybody's had the experience, where everybody's exactly sure, they're 100% sure this is the thing, everyone's going to use it, everyone's going to pay for it. You sweat over it, and then it's like crickets. Nobody is using it. Somebody didn't do their due diligence, or whatever. Reality is that you can't really escape that, that's just the reality of startups, and so you want to just try to minimize the time between those episodes, and just trying to find PMF.

Here's the plan. We're going to go over platform selection, my philosophy, and what informs my decision making. How to do frontend. People often discount frontend. It's actually a huge tar pit, in my opinion. People get bogged down in it. They think it's easy. Then you're just like, why doesn't it look right? Why is the form not right? Why is the dashboard so hard to build, whatever. I'm going to go over some of the lessons I've learned in shipping frontends quickly. Some of the backend architectures that I think work well, the long-running processes. I'll talk briefly about some CI/CD choices that I've made.

Lesson 1: Platform Selection

For platform selection, every startup has to choose where its code is going to run, and teams often prioritize what I would consider like, maybe the wrong things to make this decision. I did it too. I used to do it. It's easy to focus on like, theoretical, ok, when we have a billion users, and we're going to have that perfect architecture. It's like, no, you got to get something out immediately. Niche capabilities, what big companies, like, Oracle's doing this? Like, we're not Oracle. Instead of what actually matters. I've learned is that your first goal isn't to design for massive scale, it's to choose a platform that helps you learn quickly and ship quickly. A foundation gives you that early speed, while still giving you the clean path to evolve as a product matures. That second part is really hard to know. Often you have to make a decision with limited information, and you have to live with it, especially at the platform selection time.

You make it once, and then you're stuck on it. To move is like a huge lift. Early on, the first five years of my career, I built everything on AWS, like pry AWS from my cold, dead hands, I'm not touching anything else, because everybody was using AWS. It's like, why risk something so foundational and so important? It worked. There weren't a lot of options. It was back in 2013, 2014, 2015. The first company I worked at was healthcare. That made a lot of sense, because there's just a lot of requirements, and it's hard to know what you're going to have to build. You have total control over security, networking, and all that stuff. Of course, that comes with a lot of friction. I don't know how many people here have wrestled with permissions on AWS, and you're trying to do something really simple, and the access control layer is just like, what is this?

Why do I have to run a CLI with some JSON to get one thing to talk to another thing? Those days add up. Every day lost is a day you're not shipping product, you're not learning. Those incremental losses can really damage velocity. I wasn't aware of other options, really. It was kind of Stockholm syndrome. I was inculcated. I lived with that.

Then I discovered Firebase by accident. It was a friend of mine, company had gone through YC, and he was kind of like a script kiddie. He built something, and it had gotten some traction, and I thought, this is going to be a complete mess. I'm going to go into this, and this thing's going to be a train wreck, and I'm going to have to clean this up, rebuild it. What I discovered, actually, is not that case at all. He built something that, actually, people were using, people were excited about. He didn't know all the ins and outs of cloud and Docker and all these things. It was working. I came in and I professionalized it. I migrated it to TypeScript. It was all untyped JavaScript, but nothing was formatted. I know it's shocking, sometimes you go into a codebase and it's just like, braces all over the place, and you're like, what's going on here?

I was exposed to Firebase, and I was like, this is actually pretty cool, because I don't have to fight with AWS Cognito and worry about the pool size and all these things. It just worked. It was insane scale. It just worked. I had a little bit of an awakening. Then I started exploring GCP, and I found it was quite an interesting platform. There's a lot of things. I haven't opened up AWS in a long time, so maybe it's changed, but when I used to open up, it was just like a collage of inscrutable services that you never know what half of them do. You're wondering if you're going to choose the wrong one. It sounds similar to this other one, am I going to spend two weeks trying both and seeing which one's right and wrong? You don't have time for that. With GCP, I didn't really experience that. It just was like, this is the thing, just use it, and it worked.

One of the most important things about Firebase and GCP is that you can start off with something just really dead simple, and you could really evolve it into something really professional in production, and best practice. I really appreciated that, because throwing away code, and rebuilding things is a nightmare. It's demoralizing. I feel like I'm stuck in mud when I'm rebuilding something. We're not learning. We're not making progress. Anything that lets me evolve the platform, the product, instead of just having to tear something out and rebuild it, I really value. I don't think Firebase highlights that enough. I don't know what the sentiment is, but I think a lot of people get the impressions for like, yes, script kiddies, and it's not a serious platform. It's like big boys wouldn't use it. That's not really the case. I discovered that at Tappity, and I basically did the same exact thing at Triumph.

I finished there, I was looking to do something else. Very similar situation, there was two younger individuals who had dropped out of Stanford, again, no experience, had cobbled together something with Firebase and functions. I just told them, ok, I already did this once, and so they hired me on the spot to do the exact same thing again. Similar story, but I had all those learnings from Tappity, and so I could do it even faster and better. It's a moving platform, what was App Engine turned into Cloud Run, and it was even better by the time I was doing it at Triumph. These codebases are usually generated from a CLI, so they have a very standard format. You come in, there's a folder called functions, and all the business logic is in there. I was able to migrate it to Cloud Run with TypeScript in under a week.

To me, that was an incredible feat with one person. I have a lot of experience under my belt, but the amount of leverage this platform offered was extraordinary. Firebase Functions are fine, but running it locally is a pain, testing it, all that sort of stuff is not great. It's good for getting started, and that's critical. Then the path towards moving towards like an Express app is amazing. One of the really nice things about that transition is that the API for Firebase Functions are Express requests. When you build all your business logic, and you build all the tooling around it, it's very easy to transition that to a very standard Express app running in a container on Node.js. You don't have to rewrite anything. There's some DevOps work, but you're not redoing any authorization, authentication stuff. That stuff stays in place. I thought that was really great.

Why is Cloud Run so cool? How many people have used Cloud Run here? What I've noticed is a lot of times you want to build something that, by default, it's zero, it just costs nothing. Because a lot of times, when you're experimenting and trying things, you're not getting a lot of utilization, and you really want to minimize the amount of burn for nothing. Those things can start to add up. If everything costs a little bit, at some point, your monthly bill is untenable, and it puts the pressure on to like, what are we doing? Does this make sense for us to run all this stuff? If at every step, it scales to zero, at least remove that pressure from the discussion, from the decisions, but keeping the door open for something that is likely to work when you do have a lot of users. Cloud Run is an intermediate between Firebase Functions and GKE, which is the managed Kubernetes system.

A lot of times, at least in my experiences, there'll be usually one person who has the expertise of getting all the local development set up and doing the DevOps. Not every person on the team has that familiarity, so that people can just run Node. You just tell them, run the script, do npm run dev, or node server.js, whatever, and they can just be productive in their local environment while you just have a Docker container deployed at Cloud Run, and that's handled for you as a managed service, is a really powerful tool and choice for very small teams. One person does have to get somewhat familiar with DevOps. Early on in my career, I was writing Ruby for AWS OpsWorks, and all this, Chef. I don't know if anybody's touched that stuff. That was pretty bad. There was a brief period of time, though, Docker was coming out, and I didn't have to invest too much time in that.

What are we doing? Similar playbook for Velocity. I'd done that twice. It worked twice, so I'm just going to do the same thing. I had an idea. I wanted to build it quickly, test it. I was able to do that. As I got more users, I was able to evolve it into Cloud Run, and Firebase, and Auth and everything like that worked great. This is now my third time. I did do a little bit more this time, and obviously, with my own company, I invested more in Pub/Sub async stuff, which I'll talk about later. Again, an evolution of what comes standard with the starter project for Firebase. I do mention that even GCP I did run into limitations. One I thought it would be important to highlight is that, because Velocity AI is a conversational intelligence product/platform, and there was no good way in Cloud Run to do WebSockets. The way that the infrastructure works, it doesn't play well. I will say that you will run into limitations, but it was a one way down the line and I didn't encounter it right away.

This is another thing that I've come across several times, like the Heroku type platforms. I'm curious, how many people are using Heroku or something like that? I know it's tempting. I've run into situations where you really need that knob, and that knob isn't there. I'll give you an example. I was integrating with a payment processor. I don't remember all the details, but I did have a very specific version of TLS with the specific enumerated list of ciphers. These one-click platforms. Maybe they do, but I'm saying that those types of requirements might emerge out of nowhere, and then, now what? Now you're provisioning some Azure thing, and then you have a load balancer that terminates whatever, and then you have to redirect writes. It's a nightmare. You have to remember all that, keep all the infrastructure in place. You want to minimize the chances of that happening, so not huge on the one-click deploy type of, you don't have to worry about anything, just put this thing in GitHub, just put this file in GitHub, and it'll just deploy everything. That's a little bit too much in that direction, and it's dangerous. Just my notes on that.

Lesson 2: Frontend Architecture

Lesson two, frontend architecture. Frontend, what are we going to do with frontend? Let's say you picked your platform. Let's say you agree with me, you're going with GCP and Firebase. How many people are doing frontend in their daily work? For those who aren't, there's these battles of frontend frameworks, and I'm in the React camp. I'll go over that quickly here. When I first started building UIs, this was 2013, it was still jQuery. Everything was imperative. You had to wire everything up, and all the state management was like, you want to make an API call, you do $.ajax. It was messy. It was a dark time. Not to mention testing, all that stuff was pretty rough. These single-page frameworks came out, and React really, this idea of declarative coding, and just basically declaring what you expect the UI to do, and then the library just handles it.

That was a huge lift for frontend. I think the thing that is the next part of that evolution, at least for me, and what I've observed, is Firestore. Firestore is a really interesting product because it is the database, but the client has access to it, and they have full push capability to the client in order to notify it when something changed in the database. My understanding, it's done with gRPC, and there's now some Google magic. It's not done through polling. It's not done through HTTP/1. It's really performant, and really incredible. That was always the gripe with frontend. A React developer is, state management? React's great, but what about state management? What I've done for the last four years is just put everything in Firestore. This is the idea. This is really nice, is that your database is the state. There is no duplicated state. You don't rebuild it on the frontend.

You don't fetch it once, and then keep track of like, I made a mutation, and let me persist that in the client and the database, and make sure I'll fetch it again. No, none of that stuff is happening. You push a change to the database, and it just refreshes it. If you architect your frontend correctly, you don't have to do any duplicated state management. That's a huge lift. I can't tell you the number of hours I spent duplicating what was in the database on the client, with a slight impedance mismatch. Like, it's SQL here, and then it doesn't really fit exactly right, so how am I going to nest this? Wrestling with these design decisions was just a complete waste of time. Instead of writing something that people can actually use.

Let's go here. Maybe I'll show some code to show you guys what it actually looks like. I'm going to show you guys something. Part of the platform is going to analyze a transcript, and we have a custom agent that will do a very specific thing. It's going to chunk the transcript, and then evaluate each chunk, and then take the output of each chunk, and then aggregate them. You can see, there's a lot of transparency going on. You see each chunk. You see the state of each chunk. You see the overall progress in a percentage. It's quite nice. It's quite transparent to the user what's going on. Building this, depending on the design choices you make, can take a long time. You can spend a lot of time wiring all that stuff up, and debugging it, and in this state when it's loading, and sometimes it has this weird flicker.

I wanted to show you guys something. Here, it's done. What does this look like in the code? This is the agent run progress. I'm just passing in the agent and the events. Once that comes in with React, it's all declarative. I just describe what I expect it to do. It's really clean, I'm not doing anything imperative. That's just regular React for anybody that's in frontend. I'll talk about the styling. This is the hook that I use to fetch those messages. I'm referencing the database here. I build a query, and it says something like, under this call for this specific agent, this is permission access, give me all the events for this specific thing. As those change, I get a new copy of the whole collection. I'm using the actual database as the state, because I fetch it right out. I put a listener on it.

Every time anything changes, I get a new copy of it, I pass it down in React, and I just render it. I'm not doing any data manipulation, state manipulation on the frontend. This is a huge lift. This cuts out sometimes like 30% of the code that you're writing, if you've done it correctly. If you have a small team, that adds up, that compounds especially if you add design patterns, which a lot of times I'll have like a more junior developer, they might not be able to build this specific helper function. If I set it up, they can copy it, or use AI to generate a new version of it, new addition to it. You can build with certain design patterns, you can build something that even for more junior people, they can extend it quite naturally, and you don't really have to keep an eye on it, watch them.

You just look for those design patterns, say, did you follow this design pattern? They'll be able to build rich UIs like the one that I just showed you guys. I hope that makes that point clear. I know it's code, and I showed you just one example. The point of that is really to stress that if you can find any way to remove the duplicated state management on the client, that's a huge win. This is the way that I've done it. I haven't seen anything else. I experimented with GraphQL. How many people use GraphQL? It didn't really work the way I wanted to. It's nice, you have discoverability for frontend people. They can go in, and they can type with that little graphical interface to see what the backend offers. It standardizes the API, the handshake between the client and the backend. Other than that, it's still not great. I found that Firestore is really the answer to this question. That's for reads.

What about writes? Writes aren't actually good to do from the client. There's a lot of good reasons for that. It's offered by Firestore, but I don't recommend it. Primarily, I've done B2B SaaS. The reason is that a lot of times you have a lot of complex data validation rules. You really can't do that in Firestore rules well. It's really messy. You can put permissions on reads, but in terms of data validation, or if you have side effects that you want to happen, like you're dead in the water. My strong suggestion if you're following to this point, is you put all the annotations behind just a simple REST endpoint. All the reads go through subscriptions, Firestore, and all the writes are hidden behind a REST endpoint where you can do anything you want. I'll show you. I guess there's another one here. That's for writes. What about the actual UI?

What do I use and why? Again, I focus primarily with B2B SaaS, and there's a couple things that come up a lot. Forms, complex forms, over and over again. You need to make little warning signs and little exclamation points, like all the form validation, the styling, Rich Form controls. You want a thing that expands, you click on here. One field is linked to another. Again, another area where you do not want to waste your time rebuilding that stuff. There's a lot of good frameworks out there, and if you find yourself rebuilding complex form controls, you're wasting your time. Don't do it. It's a bad idea. I'll show you guys an example of what I consider a complex form control. How many people have heard of Tailwind? Tailwind is also great. I want to minimize the number of files. I don't want to have a separate styling file.

That's a pain. Also, AI is really good at generating Tailwind. That's a recent development. It's another reason to use Tailwind is because you can just, in language, say using Tailwind, make it look like this. Or I've used it to be like, make an interface using Tailwind, to make something that looks familiar to a Salesforce user. It looks good. It's easy to debug. Sometimes there'll be little issues that you have to fix. It's very easy to debug and figure it out. That's my point there.

Let me show you guys briefly what I mean by Rich Form controls. I don't know how many people end up having to do this. I've had to do this many times in my career, is that you have what I would consider a complex data structure. You have to create a form to edit it. There might be complicated rules. In this case, this is part of our system. I need this to be dynamic. I need the number of entries to be dynamic. Each entry needs to have these validation rules. For example, this can't be empty. How am I going to build that? You don't want to be building a hand-coded version of that. Ant Design offers it all out of the box. The styling's not bad. I didn't style these. All that stuff just came out of the box with Ant Design. I'll give you an example.

Going back to the way that I approach using Firestore for the UI, I'm going to change this from mandatory to not. I'm just going to update it. You can see now it's not red. That's Firestore. I just said, send a mutation, it immediately updated. Before the form is done going away, it's somehow been pushed to the client and re-rendered. It looks good. Don't judge the styling. We don't have a designer. I just wanted to understand the levels. I think it's clear the benefit. I didn't have to re-compute what the state should be on the frontend for this complex data structure, and then update it. It just did that from Firestore. This type of form, like I have add objective. What success criteria it's going to use. Edit the step. Order, I need to update the order of these. A lot of things like this, you can waste your time building.

Again, when I was talking to our customer, they would have sworn that ordering thing was critical. It's absolutely critical. We had to have it. Was it really that critical? Not really, actually. That's happening all the time. My point is that you're never going to be able to argue, it's not actually critical. You just have to build it and move on. The best answer is just have something in your toolbox and build it quickly and don't argue about it. You have to have this special reordering modal. Fine, here it is, done, move on. They didn't use it? Ok, whatever. I don't want to sound bitter, but that is the reality is that with startups you don't know what the signal is a lot of times. It may be critical. It's impossible to know. My answer to that, when you don't have a lot of information is to build velocity, just build the things and move on.

Again, to summarize, in my solution to frontend, is that it should work like this one-way data flow. You have a web app, it's subscribed to the database. You want to change it, you make a POST request. It mutates a record in Firestore. Firestore just behaves what Firestore does, it re-renders it, and you arc that to your code so that it just reflects the state of the database. Right now, this is the best. Maybe with AI, they'll come up with something. Maybe it won't matter anymore, it'll just build all the UIs for us. Right now, it's not doing that. That's my solution.

Lesson 3: Backend Architecture

Let's talk about backend. If you've got your frontend in order, what do we do with backend? The way to think about it, and again, this is my opinion, is it's got to be fast to build, it's got to be easy to evolve, and it's got to be cheap to run. Those are really the critical things when you're just evolving early on. Why is Cloud Run good for that? It has all the strappings of like Kubernetes, really. It has a lot of the built-in qualities that people would reach for Kubernetes for. It's a lot easier to get set up and manage. You get the service where it scales to zero, so I'm not paying for servers. I can just trust that if nothing's being used, it's just not charging our bank account. It's using just regular containers, uses just Docker. That's a huge win because Docker is the standard.

I spent a lot of time wrestling with Docker, so I'm familiar with it. I know a lot of people aren't, but it's actually not that hard to learn. There's a lot of boilerplate, and I think AI is good at helping people. The first individual I worked with at Tappity knew nothing about Docker, but he tells me, yes, I was chatting with Claude and it did some Docker thing. I think that's going to become much more common. It's accessible, even for people that maybe don't do it professionally. If you don't have a full-time DevOps person, I think Cloud Run is a great solution.

What is my recommendation? Like I mentioned before, Firebase Functions use an Express style API. The request that you're interacting with, if you have HTTP functions, is just an Express request. If you really can't do anything fancy, you can start with Firebase Functions, and as your product matures, maybe you get another team member who's maybe more backend-oriented. You can easily evolve this into just a traditional Express app. I know some people are like, Express is old, but I'm like, it's pretty simple. It's so standard at this point. I'm trying to think if AWS Lambda also behaves like that. I can't recall. I think the Express request object is in many cases standardized across the industry. You can use it as a contract to build business logic around, and it's quite nice. You can easily embed that in Cloud Run. This is really my recommendation. If you're starting out very beginning, you have an idea, you want to just kick the tires, get something out, get a user using it, use just Firebase Functions with JavaScript, and just trust that if it does get legs, you can evolve it into something more mature.

Instead of wasting building some fancy backend, and it turns out the idea was bad in the first place, and it's a waste of time. What did I actually do? This is because of an individual I was working early with. He was all into Python. I'm not a huge Python guy, but he was doing the backend. I was like, fine, you can do Python. We ended up going with Python and aiohttp. I think that's fine. Would I do it again? Probably not. I'd just do JavaScript, because I think that's the easiest. Python's also all right. I got to learn Python, which is cool. Again, it's not a hard rule. It's my recommendation to go with Express and JavaScript. I didn't even do that for Velocity. That's for request and response.

Lesson 4: Long-Running Services

What about long-running services? If you have something that's like, you need to kick off, you need to do a POST, update a document, that's great. Cloud Run's great for that. Let's say you need to have an agent run in the background, or run a report, or something of that nature, something that's not online. Cloud Run doesn't really work for that. It dies. It's not going to wait for any internal process. It's not going to stay alive for that. Once their HTTP handshake is over, you have 30 seconds until it just shuts down. You do have to have an answer for that. Again, it's something that usually comes in later as your product evolves. You can run into it early. GCP has a nice solution for this, Google Cloud Functions and Pub/Sub. I'll give you guys an example. When a user finishes a call, I'll publish an event to anything that's subscribed and it'll just call a Python function that's in the same codebase as my Cloud Run codebase, sharing all the same data models, all the same helper functions, everything's the same.

I'll just run it in this Cloud Function until it's finished. It's quite an elegant solution from a code organization standpoint because you don't have a separate codebase. You don't have a separate project or anything like that. It just all lives in the same repo. You just deal with it with like a little bit more infrastructure setup and DevOps.

Let me show you guys what it looks like. Going back to, this is the post_call_agent we ran. What does actually happen in the background? I have this one function, create and run post_call_agent. Depending on if it's local or not, when you're developing locally, you don't want to be publishing to a cloud service and then looking in the cloud logs like this. It's not workable. You do have a little bit of control flow, like if local. It's not perfect, but it's acceptable in my opinion. In one case, and this is in production, I'll publish a message. I'll take the arguments. I'll encode it and I'll just publish a message. I have a listener that runs in a Cloud Function that'll just eat that message and then run the code. Or if it's local, I'll just run a task in the background. This function, if you go look at it, it's the same function I have in main.

Main is the entry point to all the functions. My point in highlighting this is that you can build all your business logic by declaring functions and putting it all in there, and just put it in two different places for calling. That's good for testing. That's good for your mental model organization-wise, design patterns. It keeps everything a little bit simple, especially with a small team and you can't have too many moving parts. You get cognitive overload. There's that.

Let me show you guys this. The event-driven architecture is great. I have a lot of that in my code. I'm integrating with a lot of services. I'm going to go into Zoom, Teams, Salesforce, Google Calendar, Outlook. All these systems are just event streams. I do find myself reaching for these offline processes quite often because you don't want to process each request online. You have Microsoft waiting for you to finish doing whatever you want to do. I'll find this actually. I'll show you guys how it actually looks. Like I said, main is where the functions live and server.py is where online stuff is. That's it. Those are the two files, the two entry points to both service, one long running and one online. How we deploy. I deploy everything with Google Cloud build. This is the YAML file. It's a little bit long, but that's all it takes to have everything automatically built. I have one cloud build, and that's the service, the CI/CD service for GCP. It builds my Cloud Run containers, deploys them. It builds my Cloud Functions, deploys those. It builds my frontend, deploys that. Does all of it every time I push. I'm doing nothing locally.

Summary and Key Takeaways

The key summary is like, my strong suggestion is go with Firebase, start quickly, move quickly. Get started, just get something in front of a user. Don't spend too much time vacillating over what platform, what's the long-term. It's not worth it. Trust that you can evolve this thing into a true production service with GCP. I've done it three times at this point. Design Tailwind for frontend, Cloud Run, Pub/Sub, functions for backend.

Questions and Answers

Participant 1: Looking at Firebase and the reactive event, so the centric aspect of that, it reminds me of one of the microservice tenants where you only have a single service that should access the database. In the case of Firebase, this is probably not true because you want to have that interoperation between different applications.

David Gudeman: They all live in the same database, but you can specify rules. I'll quickly show the rules file. You can specify rules in Firestore. It looks something like this, those are indexes like this. It's all in special little language. You build functions, for example, isAdmin. Anybody who is admin can access. You can say things like, getUserAccountId, is it equal to account_id? You can silo data at that layer.

Participant 2: Will you certainly integrate using different platforms, between GCP, AWS, Azure, or what makes you make the decision? Is that the right decision?

David Gudeman: No, just the scars in trying to use all the platforms. I spent five years at AWS. I don't know if anybody here has used the equivalent of AWS, is like AppSync and their little answer to Firebase. It's really bad. You have to run migrations. It's like, what is this? You know what I'm talking about? Like this migration business. Like, you made a change in the UI, you run a migration on every service that this thing touches. Like, no. That's the reason, is basically just like, I've tried a lot of them, and I just find that the friction is much higher. If you're a mature company and you have 10 DevOps people, who cares? When you're tiny, it can really kill momentum. That's the reason why.

 

See more presentations with transcripts

 

Recorded at:

Software is changing the world. QCon San Francisco empowers software development by facilitating the spread of knowledge and innovation in the developer community. A practitioner-driven conference, QCon is designed for technical team leads, architects, engineering directors, and project managers who influence innovation in their teams.

Sep 22, 2026

BT