Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage Presentations Everyone Can Be a Full-Stack Engineer

Everyone Can Be a Full-Stack Engineer



Alex Cole discusses dynamic web apps, how serverless solutions compare to in-house stacks, and how product development changes when individual engineers can own features, end-to-end?


Alex Cole is a software engineer at Convex, building Convex’s reactive backend-as-a-service platform. He’s passionate about reactivity, TypeScript, databases, GraphQL, and mountains. Previously he worked at Asana, leading the Client Infrastructure team.

About the conference

QCon Plus is a virtual conference for senior software engineers and architects that covers the trends, best practices, and solutions leveraged by the world's most innovative software organizations.


Cole: I'm here to talk to you about why I think everyone can be a full stack software engineer. Currently, web apps are built often with large teams of engineers, with each engineer just owning a little piece of the puzzle. I think that there's a better model for developing modern web apps, one in which individual engineers get to own their feature, all the way from the top of the stack to the bottom. I think when you do it, this way, we can ship more product features faster, and individual engineers are able to think deeper about the product experience. When I say modern web app, what am I talking about? I'm talking about apps like these, apps like Facebook, Airbnb, Slack, Asana, Reddit. What do all of these have in common? First, they're websites that have dynamic content. We're no longer serving static HTML to everyone on the internet. Instead, different information is served to each user that's pulled from some database. The app is personal and has user generated content. The second thing is that these apps, at least when they're done well, are reactive. When a user loads the app, they'll see the changes to the data happening in real time. You don't have to refresh the page, but the most up to date content is pushed directly to the browser. The last thing is that these apps are all interactive. Not only can you view data, but you can add your own content, write posts, write messages. When you do that, you see your own edits update in real time. The sum total of all these properties together can make these apps when they're done really well just feel native. Users will no longer feel like they're on a website, but they feel like they're having a rich native experience. This is what I want to talk about. I want to talk about how you build apps like these, and how we can design the infrastructure for these apps to enable individual software engineers to own the whole stack.


Who am I? My name is Alex. I'm a software engineer at Convex. Convex is a reactive Backend as a Service. We're helping people build their web apps on top of our serverless infrastructure, so you don't have to manage all the infrastructure yourself. We've been doing a lot of thinking about what are the right ways to build web apps today. Before this, I worked at Asana. I was leading the client infrastructure team. This was a team that was building out the reactive web framework that Asana uses internally. I also did a lot of thinking there about, what are the right abstractions to give product engineers? How can we put product engineers into the pit of success? All of this combined means I care deeply about how we build modern reactive web apps. I want to tell you a bunch about my thinking.

Web App Architecture

First up, I want to talk about the architecture that most apps are using today. What is happening behind the scenes in these large web apps? What problems do these architectures hit? Let's start by talking through a example web app. What do we need if we want to get our app off the ground and serve to users? We're going to need a couple things. We're going to need to build a frontend, probably we'll build it in React. We'll write some React components and put together the UI that we really want to deliver to our users. That frontend is going to need to go and talk to some backend. We're going to need a way to run server-side business logic. Probably, we're going to define some endpoints or GraphQL schema and GraphQL resolvers to load and mutate data. The dotted line in this diagram represents the boundary between the client and the server. The frontend is going to make some requests to the backend. Then on top of that, we need some way to permanently store data. We're going to need some type of database, perhaps MySQL, or MongoDB. That's going to store data based on some schema for our app.

To start, this is it. Many apps will launch with a three-level architecture like this and get right off the ground running. Once our app is wildly successful, we're going to hit some limitations here. I think one of the first limitations we're going to hit is that an individual backend might not be powerful enough to serve all of our users. We could have problems like the backend is going down because there's just too many requests, or every time we rewrite the code in the backend, we have to swap it out for a new one and there's downtime. Likely, the first step as we're growing our application is that we're going to need to expand the backend to no longer be a single service. Instead, we'll run multiple copies of the backend and have a load balancer in front of them. This will give us some redundancy, so if one backend goes down, we'll be able to handle that fine. It will also help us because now when we redeploy code, we can have our load balancer talk to the new backends instead of the old ones, and do seamless transitions. Yes, Asana started out with an architecture very much like this.

Are we done? Are we ready to check off and just run our app and keep it in production like this? I think not. I think as our user base grows, we're not at the end of our scaling woes. I think the next part of our system diagram that may have issues is the database. Here, we're running a single database, which once again means that it can be a single point of failure. One, if our user base grows enough, we're no longer going to be able to handle our traffic in one database. If we don't have a database, we don't have an app. I think the next step in our scaling is that we're going to want to shard the database. Instead of running one big database, we're going to probably want to split our customer's content into separate shards where different shards live on different databases. This will let us horizontally scale the database layer and grow to more numbers of users. It also means that an outage on one database won't affect everybody. Also, surprisingly, Asana started out with a single database and reached those limits. As anyone who's done sharding knows, it's no easy task. When you're doing sharding, you're going to have to break up your work that maybe cross multiple different parts of your data model, into work of individual transactions on databases. You're going to need to only be able to do a transaction on one database. If you want to write data to multiple databases, you're going to have to think through the consistency of it yourself. That's fine. We're a big web app. We have a big team. We're going to have some people who have thought hard and long about MySQL, and the right way to shard, and they're going to split up our data into multiple databases.

What's next? Are our scaling woes and our performance problems over? Once again, I think it just keeps getting more complicated. Next up, I think we're probably going to need a way to improve performance beyond the database. For many apps, loading all of your data from a single database or a set of databases is fine. It's also increasingly popular to have a caching tier as well. Here, we'll have some cache nodes that are storing in-memory, a lot of the data from the database. These might be services like MySQL, or Redis, and instead of the backend, loading data straight from the database. At least for some kinds of content, it can go to the cache first, see if the data is in the cache, and then follow up and go to the database. If any of you have experience with caching, you will know that I just brushed under the rug a tremendous amount of complexity. As soon as you add a caching tier, now we're going to have to make sure that the data in the cache actually matches the data in the database. It is extremely easy to end up with cache inconsistencies where some user edits data in the cache, but fails to write to the database, or vice versa, where they write to the database, but don't update the cache. These might seem like small problems. The correct data is still saved in the DB, what's the issue? When the users are showing up on your site, what they're going to see is the information in the cache. If it differs from the database, they're going to believe that their content was lost or corrupted. Likely building out this infrastructure, we're now going to need more engineers with more expertise to make sure that the caching layer and the database stay in sync.

We did that. We've built the cache. Are we done? Are we ready to launch our web app and scale up to the entire user base? It keeps getting worse. I think the next problem we may run into is actually a product one, of, I said we were building these really interesting reactive, interactive apps, but the architecture diagram I've drawn here is really only about loading data and writing it. How are users going to see content when it changes? We're going to need to make it reactive. The standard way to make it reactive would be to change our frontend to no longer use HTTP to request its data, but instead have some long-lived WebSocket connection to the backend. That's the double ended arrow. Using a WebSocket means that we can still load data on the frontend by requesting it from our backend, but also, it'll keep a connection to the backend open, so the backend can push data all the way to the frontend. How is the backend going to know when to push what data? This will require yet another new piece of infrastructure. A common choice is to use a Pub/Sub service. The idea behind this is that the backends will be able to publish topics to the Pub/Sub service whenever they edit any information. They'll subscribe to the information that their clients currently care about. The Pub/Sub service will act as a Message Broker, letting backends know when information changes. Asana also did exactly this. Asana had an in-house Pub/Sub system they built themselves, and broke up the data model into these fine-grained Pub/Sub topics, and used those to push around information, so that anytime you're viewing content in the app, you would see it change in real time.

Once again, there was a lot of complexity here. There was a lot of complexity in getting in the correctness right, of how do you correctly publish and write to the database at the same time? You can't. There's complexity in making the frontend be able to understand the messages about changes to information. We're going to need some way for the frontend to have some local client store, and store all of this data and update it as it changes. We've already scaled up our team. We're going to have some set of people that are working just on reactivity in Pub/Sub. About now is when I run out of space on the screen, but that doesn't mean that the complexity stops growing. I think in many modern web apps, there's actually a lot more boxes in this diagram. Some other common choices are that if your product someday needs to have full text search, you want the ability for users to search for messages by the text in them, your existing database might not be able to handle that. You add in a whole nother database. We can start running something like Elasticsearch to fill those queries.

At some point, we might want to be able to do things like send emails in the background. If we want to have background jobs, we're going to need some job queue where we can schedule jobs to happen, and workers that actually do the work. We're probably, as the site scales up, going to need to have analytics. People are going to want to know what users are doing on the site. How many users we have? We'll also need to add in a data warehouse. It just keeps going. I think yes, basically, as I've described here, this is the state of the art for modern web development. You're combining together a bunch of different services. It's your responsibility to wire them all up in the right way and keep them consistent. It works. I think almost every logo I have written on the first slide was built in this way.

Who's Going to Manage This Complex App?

There's also some downsides. I think one of the big questions comes down to the people involved. How many people are we going to need? How are they going to be divided up into teams? For this imaginary app, we're probably going to need a frontend team. We're going to need some people who know how to write really good JavaScript and TypeScript, CSS and HTML, because we're building a site for the web. There's a bunch of specific technologies that this team is going to have to be experts in. They're going to need to be understanding React, GraphQL. They're going to need to know how browsers work, and be thinking through the UI. On top of this, we're probably going to need a separate backend team. These are people that are going to be writing our backend business logic. Probably, we picked a backend language like Java, Python, or Ruby. We're going to need to be doing SQL queries from the backend in order to load our data. These engineers are going to have to think really hard about performance and security. We have a frontend team, a team that writes the backend business logic. What about all the other boxes in this diagram? We're also going to need to have another team, some SRE, DBA, or infrastructure team. This team would think a lot about scalability, reliability, correctness, and performance, and probably be doing a lot of writing configuration scripts, SQL, to keep the site running and everything correct and performant. This is a lot. I had a diagram that filled the whole slides of the architecture. We have three different teams here. We know we need all of that before I've even told you what app we're actually building. Pretty wild.

Web App Product Development

Just to round this out, let's think about what product development looks like in this model. Let's imagine now that we actually want to go and add a new feature to our app, given this architecture and these teams. As a toy feature to talk about adding, let's imagine that we're building a chat app like Slack. We want to add channels to the app for the first time. We already have a single channel chat app, but now we want to go and add the ability for users to have custom channels, send messages in those channels, see the full list of channels, all that good stuff. What do we need to do to add channels? First, we're going to need to think at the bottom of the stack. At the database layer, we need some way to define a SQL schema and define what our data model is. This is probably going to be a conversation between the backend team who is thinking about what kind of endpoints we need to write, and the infrastructure team who is thinking about scalability and performance. They're going to agree on a SQL schema. Once they do that, we're going to need to actually go update our database to have the schema. Maybe the infrastructure team is going to go add the schema, whatever appropriate indices we think we'll need, and also, generally scale up the services to support this new feature.

We have the schema, what's next? Next up, we're going to need the backend and frontend teams to talk to each other to define the API of the endpoints. If we're building a chat app, we probably need a way to load the list of channels. We're going to need a way to load messages that are in a specific channel. We're going to need to be able to create channels, delete channels, rename channels. We're going to need to make sure that the frontend team is getting all of their needs met by the endpoints, but also that they can be implemented by the backend team. Often, I've seen teams that will jump to GraphQL to solve this. Because this conversation is so difficult, it's often nice to have a rigid structured language in order to guide the conversation and write down the conclusions.

Backend and frontend teams, we've defined the API. Finally, the backend team can go and actually build the endpoints. They'll implement this API and use the SQL schema that the infrastructure team set up for them. Finally, only then can we actually go and build the components and actually build the UI. Now the frontend team can write the components, and we have built our new feature, end-to-end. How do we feel about this process? In total, we had over six different services involved. There were five steps. We had at least three teams. I think realistically, even for a small feature like this, it's going to take weeks. There's just too many moving parts involved, too many different people. The work of developing the feature has been split up between totally different teams, so that no team is thinking about this feature, end-to-end. Everybody is focusing on their part and throwing a bit of work over the wall.

Serverless Architecture

Can we do better? What does a better model look like? What does a world look like in which people could actually own their features, end-to-end? To say the negative version here, in this existing model, how could anyone be a full stack engineer? It seems completely infeasible for a single engineer to be thinking about or owning this much infrastructure? It seems impossible. How could we do it? What would it look like? I think the thing I want to talk about next is, what a serverless architecture would look like for building a complex web app like this. How does serverless change things? How does it change the teams that are building the apps? Before we talk about what architecture we're actually going to use, I think we should come back to this complicated one that we had before, and focus in on the question of, what part is the app? I drew all of these boxes before I even told you what app we're building. What parts of these boxes actually have to do with the product features we're building? I think there's a couple of bits here. On the frontend side, we're going to have different React components depending on what app we're building. The React components are specific to the user experience we want to give.

Similarly, on the backend, there's bits of business logic. We talked about the fact that every new product feature is going to need new endpoints or adjustments to the endpoints. When you condense down what is an endpoint, all it really is, is a function. We need a function that's going to be taking in an HTTP request and returning some data to the frontend. There's some functions on the backend. Then the last piece that changes and is part of our app is the database schema. Every app needs to store information in the database, but the schema they use to store it depends on your data model in particular. I claim that this is really it. When I think about what is the app, there's the React components, there's functions in the backend, and there's a database schema. Everything else in this diagram, that's just scaffolding to get these three things in place. If we want to remove as much unnecessary complexity as possible, where do we end up? If we want to empower engineers to edit the whole app, how do we do it? I think we need to do a few things. We need to remove all this excess complexity. We want to focus in on just those three things, your React components, your functions, and your schema, and manage everything else centrally. The second thing is that if we want engineers to actually be able to edit the whole app themselves, we need to write all of these pieces in the same language. Given the realities of web development today, I think we have to pick JavaScript or TypeScript, because that's the one that can run in the browser. Then once we've done this, profit. If we can remove all the complexity and write everything in the same language, I think we're going to be in a really good place. Let me convince you of this.

In this serverless architecture, these are the only things we need. We need React components, some way to build the UI. We need backend serverless functions, some way to have backend business logic and run code on the server. We need a schema. We need to describe how we want to save our data in a database. Unlike the previous diagrams, this is it. I'm not going to be pulling out any more complexity here because there isn't any more. I think these three ingredients really give us everything we need to build the app.

Serverless Responsibilities

When we've done this, let's break down what the responsibilities are. If you're using a serverless architecture like this, you have to manage just those three things. You'll have to write UI components. You'll have to write serverless functions. You'll have to define a schema. Where did all of the other parts go? How are those getting taken care of? If you're using a serverless provider, you're giving them the responsibility for handling the scalability, correctness, caching, and performance, reactivity, backups, availability hosting, the whole list. I think we didn't do anything totally revolutionary here. I just took the responsibilities that used to be spread across a large engineering team, and offloaded them into a serverless hosting provider. Yes, and having personally worked on a large engineering team building Asana, I can tell you that a large fraction of engineers were actually focused on all of these problems, and not the UI components, the functions, and the schema. By giving the provider all of these responsibilities, it will let you focus in on building the parts of the app that actually affect your user experience.

Serverless Product Development

That sounds good in theory, but what does product development actually look like in this serverless environment? What I want to do is walk through the same example we did before. I want to just show you how that would work if you're using Convex. I think a lot of the same ideas apply to many other serverless providers. This is the one that I know well. When you're using Convex, you write your schema in TypeScript. Before you added messages to your chat app, your schema might look like this. Here, this is a TypeScript file. We're importing some helpers, defineSchema, defineTable, and s. We're defining a schema that just has a single table, messages. Messages are just objects that have two properties on them, author and body, and both of them are string. A very minimal chat app where people can post messages and say who posted them.

If we now want to expand this into a chat app that has channels, we're just going to go ahead and add channels to our schema. Here, I've updated the schema. Now there's another table called channels. Each channel is just an object that has a string name. Then we need to connect the messages to the channel somehow. In Convex, the way you can do that is by referencing the ID of the objects in the other table. Here, now messages have a channel property, and that's just the ID of a channel. This is how we handle foreign key references. To define the schema, took 30 seconds. What's next? We need to define the backend functions. Once again, in Convex, this is all just written in TypeScript. This is an example of the kinds of functions you might need to build this multi-channel chat app. The first function would live in a file like listChannels.js, or listChannels.ts. It's using query here, which is saying that this is a Convex query function. In Convex, query functions let you load data, and they're automatically reactive. Whenever you load a query function, Convex will also push to you a new version of the data whenever the underlying data changes.

In this case, what do we want to do? We want to go to the database. We'll query the channels table, and just collect all the channels that we find. That way, we can list all of the channels in our little Slack channels picker. I should say though that in a Convex query function, you can write arbitrary TypeScript, and it'll still be reactive. If we wanted to take the length of this list and list how many channels there are, we could get a live updating number of the number of channels in the app. We don't just want to list the channels, we also need a way to add new channels. We can define that using this Convex mutation in addChannel file. Here, this is a mutation that takes in the name, string, and then inserts a new document into the channels table with that name. Nothing revolutionary here. I think the cool part is that the same engineer who went and wrote the schema, could easily hop over here and start writing the functions. They're just in the same code base, TypeScript code: nothing magical, nothing special.

Then the last piece is that we actually need to use these functions to build components and add on that new UI for our new user experience. In this example, we'll probably want to make a new React component called channels list. What does that do? We need to load the channels if we want to list them. Convex gives you a useQuery hook. UseQuery takes in the name of a query function, and just gives you a reactive version of the result. This is a live updating set of channels. Then based on those, we're going to render some UI. Maybe we map through all the channels. For each channel, we render a link that lets you load the messages in that channel. That's it. You can load data from queries on the frontend. You can call mutations. That gives you all of the tools you need to build any interactive experience.

I think when we've done this, it is both completely obvious and also somewhat revolutionary. We've taken a process that was going to take weeks for 3 different teams to complete, and I just described how to do it in 10 minutes. By using the same language and the same abstractions at every layer of the stack, it's now realistic for individual engineers to understand all of this and own their feature, end-to-end. Instead of having people split up on what part of the stack they're working on, you can now have teams that are just focused on their parts of the data model and their features, and can think through how to build those features, end-to-end.

Serverless Bonuses

On top of that, I think there are some things that you get with serverless that are actually just hard to build in traditional architectures. Let me give you my two examples of what you get for free by using serverless that may have never been able to be built using a traditional model. The first one is reactivity by default. When I say that, what do I mean? Often, in an app, you're starting in the way that I did in my example, where you start by calling endpoints and loading nonreactive data. Then adding on a Pub/Sub system, which will give you some amount of reactivity, but perhaps only to the things that you actually manually built it for. It's very common to have apps where the chat portion of the app is reactive, but the other views are not because that would be extra infrastructure and extra engineering complexity. In Convex though, you actually get this for free. Any time that you load a query on the frontend, Convex pushes you updates to that query whenever the data changes. An example of the experience I mean, is look at these two windows. There's one here that's creating a channel, and then one that is viewing the channels list. In Slack, for example, when you go and hit new channel and click the Create button, the new channel pops up in the channels list immediately. I think this is a detail that can take an enormous amount of work in a traditional architecture. If you're using a centralized system like Convex that understands the data that query functions load, then it can push newer updates to those query functions whenever the underlying data changes.

The second freebie that you get in this system is end-to-end type safety. Because we've written all of our code in TypeScript on every layer of the stack, we can give you really good precise generated types. What do I mean by this? Here, I'm inside of a React component, channels list, and I'm calling the useQuery hook in Convex. UseQuery now understands what query functions we've defined, and autocompletes them automatically. Here, you can see that there's a listChannels query function, and a listMessages query function in our code base. Often, this thing can be built in other frameworks, but requires complex code generation to take your SQL schema and turn it into TypeScript, or take your GraphQL schema and build your types for your GraphQL client. In Convex, this is all piped together in end-to-end correct automatically.

Similarly, the types can actually just flow all the way from the database layer up into your UI. Our listChannels query function was loading a list of channel objects. Here, when we load those channels on the frontend, you can see that it's just an array of documents that each have an ID, a creation time, and a name. One field that we defined, two system fields that got added, but we can see them all in our editor right here. I think this also helps engineers move faster across all layers of the stack, because they know that the types are going to guide them through the process.

Parting Thoughts

A couple conclusions and parting thoughts to walk away with. The first one is that most of the complexity in modern web apps has nothing to do with the app at all. Our standard infrastructure and pieces that we wire together actually are amazingly complex. That's part of what necessitates these large engineering teams, where each individual engineer only owns a tiny part of the stack. Second, if we can remove this complexity, first, it obviously saves time. If there's things that your team doesn't need to manage, you can focus more on the other options. It also changes how you actually work. When you're only focusing in on the parts of the app that have to do with your app, you can think about them more holistically, and own the same thing, own features end-to-end. The last thing, everyone can be a full stack engineer. Once you remove all the unnecessary complexity, it is completely feasible for engineers to work all the way from the schema layer up to the UI, and think about an entire product feature.

Questions and Answers

Dunphy: You talked about outsourcing our infra to teams who specialize in areas we would normally manage in-house. While this sounds great in theory, to me, is there actually a complexity tradeoff here when we outsource these critical tasks?

Cole: I definitely think about it as just moving around the complexity, not necessarily trading it off. There is some inherent complexity in building the infrastructure for a modern web app. It's just a question of here's the in-house team doing it or an external team. I also think it's interesting to put this in the larger arc of like, how has engineering big web apps changed over time? It used to be that you would have a server sitting in your garage that you would manage yourself and buy. Now with hosted platforms, like AWS, people switch to using EC2. In addition, people are increasingly using more managed databases like RDS. I think the line about like, which parts of the infrastructure you manage, and which ones you're paying to manage, is just continually moving up. Sooner or later, people are also not going to want to be provisioning their own backends, and that type of thing.

Dunphy: Perhaps it's not exactly more complex, it's just a different type of complexity.

Cole: Yes, for sure. The complexity is now moving into the realm of specialists who are building this as their business.

Dunphy: I think many people who have really not tried this architecture may have a perception that it's not ready for large scale production applications. What is your response to this? Are there any companies you know who are using serverless architecture at scale?

Cole: Yes, for sure. I think as with any new technology, a lot of the early adopters are smaller companies who are more willing to try it out and take a risk. I think anecdotally, I'm definitely hearing about big companies that are dipping their toe in, testing the waters, using it for small features or small parts of their app. Some companies that are also just building their apps on top of it. Certainly, AWS Lambda, I think probably the biggest serverless product out there right now has a ridiculously long, impressive list of logos on their website. It seems like Zillow, Coinbase, lots of people are switching and using Lambdas to simplify their stack. I think certainly the trend is undeniable that, yes, more companies are using this in the future.

Dunphy: Is that something you would recommend to get started with serverless is just try it out in some small section of an app or some small new feature.

Cole: I think, like any new technology, you don't want to move your entire web app onto this and assume that it will work and be fine. I think finding small ways to test it out, make sure that it works for you and your technology, I think is always a good way to get started.

Dunphy: How do you manage migrations of schema?

Cole: Obviously, this thing varies depending on which product you're using. In the case of Convex, the schemas are actually pretty interesting, because you can use Convex either with a schema where you explicitly write out what tables you have, and what types those tables have. Then they generate TypeScript types, or even without a schema where you just put in data and pull it out and keep track of this on your own. I think Convex currently has limited ad hoc schema migration capabilities. You definitely can go and write mutations that read out your data in one format and write it back in another. We also are planning to add more automated schema migrations, where you can write a transform from your documents from one format to another and have that run automatically.

Dunphy: How do you imagine these principles to work for teams having multiple frontends, web and mobile, or even only mobile?

Cole: I think the dream is that a lot of this just applies directly. Certainly, if you have an app that is only mobile, I still think it's a really good model to have the same engineers building out the app as the people building out the backend, because they can think holistically about their feature. I'm also excited and interested in ways to break down the barriers between web and mobile at companies that have both. When I worked at Asana, there was actually a very hard line between the web engineers and the mobile engineers. Product features that required launching in both were these like complicated coordination game. I think with new frameworks like React Native, where you can build your mobile app in React components, just like your web app, some of these boundaries are becoming a little looser. I'm excited about ways in which the same engineers can build product in all the platforms.

Dunphy: This is what got me into the React community. I produce the conference, Reactathon. I've been very close to the React community for a long time. It was really the keynote in I think it was 2014 or 2015, when they introduced React Native that I was like, this is game changing. It's proven to be. Now we have technologies like Expo, for those of you who are interested in cross platform development, I would highly encourage you to check that out. Expo is a technology where you can build for mobile across platforms and web with the same code. It's just incredible.

Can you host Convex on Azure Serverless infra such as App Service?

Cole: No, not yet. Convex internally is running on top of AWS, but we actually manage all that for you. That's an implementation detail that we don't actually talk about. I think if there's demand for more different hosting options, and that thing, certainly we're willing to expand and be more flexible there.

Dunphy: How did quality assurance adopt this transformation to serverless architecture?

Cole: I actually don't have that much experience with quality assurance. When I was working at Asana, the way that things mostly worked is we relied really heavily on automated tests, so that we could ensure code is working. Asana would actually release code twice a day, which is just so fast, that having like manual QA process is not really possible. In general, I don't think switching to serverless drastically changes how your team has to do QA. If you're using automated tests, you can certainly write automated tests against serverless infrastructure, just like you could with your traditional infrastructure. If you want to do a manual QA process, I think that's also just as easy to do as ever. Maybe in some ways, even easier if you can spin up a backend without having to provision servers and have some staging environment that your QA people use, because you don't actually have to manage the servers. Having a second deployment of Convex out there to test against is super easy.

Dunphy: Does this model imply your product will be a monolith? Do all teams need to work in the same repo and have the same SDLC, software development life cycle?

Cole: Certainly, my hot take is that I actually love monoliths. I think that having everything in the same repo makes it easier for developers to cross boundaries and jump into parts of the code that they don't normally work on. I think, yes, having a single software development life cycle is a often pretty simple model for most teams, unless you're getting up to some huge scale and really want to separate deployments into more granular units. That being said, if you wanted to split things up more, that's also an option. You certainly could use serverless and have a separate repo for your backend and a separate repo for your frontend. I think getting more granular than that, though, is actually not very common. In a traditional architecture, you may have many microservices and want to deploy these all separately. Now that you're not really managing deployment at all, it's being managed by your serverless hosting provider. I think the benefit of splitting up these microservices into tiny little pieces, at least in my mind, no longer makes sense, because you're not even managing deployments. If you're using Netlify or Vercel and deploying every time a new commit is pushed, I don't think that this sharding up into pieces is really necessary anymore.

Dunphy: How would you recommend going with React Native in brownfield, a hybrid, or a rewrite?

Cole: I think my understanding right now is it's an emerging technology. Plenty of people are still building apps in a more traditional way, using Swift or Java to build native iOS and Android things. I would consider React Native if you have a team that is already used to writing React components. I think that makes it much easier to start an iOS project. I don't know that much, though, about the integration between React Native and traditional apps. I think if you're in a brownfield environment where you're trying to transition your app to a new technology, I would just make sure that there's a really good incremental migration plan. In general, I'm always scared about do it all at once rewrites where you stop the world and rewrite your app in a new framework. At Asana, we were always very careful to make sure our rewrites were incremental so we could ship pieces as we went. That made it possible to make some really big changes to our infrastructure.

Dunphy: Why did you leave Asana for Convex? What excites you about Convex, that perhaps you didn't get while working at Asana?

Cole: At Asana, I worked a lot on the reactive data loading framework that Asana built in-house called Luna. I think it was cool to see how this supercharged our product engineers and enabled them to build new features really rapidly. I think part of my excitement in coming into Convex is getting to work on the same thing, but building it for the rest of the community. Because I think that there were a lot of cool things going on at Asana that, yes, I'm excited to bring to the rest of engineers.

Dunphy: Why were you so excited to join Convex?

Cole: I think they were thinking about a lot of the same kinds of problems in good ways. Also, it's fun to join a small team with a lot of good people.


See more presentations with transcripts


Recorded at:

Apr 07, 2023