Mike Cann's avatar
Mike Cann
4 months ago

Should You Still Learn to Code? A Convex Engineer's POV

For the first year and a half of my career, I mostly rejected AI coding tools. It was self-preservation more than principle. If I let ChatGPT make all my decisions for me, I wasn't building any intuition for how to make them myself. I'd have no framework for why I picked one approach over another. The honest answer would just be "ChatGPT told me to." And at Convex, where you're accountable for the code you ship, that's not where I wanted to be standing.

I'm Jordan, an infrastructure engineer at Convex, and I've been here a couple of years now. Before this I went through the standard big-tech internship pipeline. Both the path there and the path since have shaped how I think about the question a lot of new engineers are asking right now. Is learning to code worth it when AI can write so much of it for you?

From Harvey Mudd to big tech to Convex

I went to a small college called Harvey Mudd, about 45 minutes east of LA, with roughly 800 students. I didn't go in knowing I wanted to do software engineering. The school doesn't make you declare a major before you start, so I got to try math, physics, CS, and engineering before committing to anything.

I got lucky freshman year. A few of my roommates had interned at Facebook and Microsoft, and a CS class clicked with the way I already liked solving problems. I applied around and landed a spot at Facebook University. That's an eight-week program for first- and second-year CS students, meant to be a gentler introduction to how engineering works outside a classroom. I came back the next spring for their standard software engineering internship.

Then COVID hit, and Facebook sent us home halfway through the semester in early 2020. I did one semester remotely and then made a pretty simple calculation. Why keep paying for school when I could get paid to intern instead? Big-company software engineering internships are typically paid, so I took a semester off.

The next summer I interned at Asana. It had just IPOed and was around a thousand employees, a different world from Facebook's tens of thousands. I got a lot more ownership there. Teams owned entire service areas, so I could figure out what my team was working on and pick up something interesting instead of being handed a pre-scoped task. I worked on pricing and packaging, doing billing and provider migrations. That turned out to be more relevant to my future than I expected.

My last internship before graduating was at Netflix, on a team that had mostly hired senior engineers. The people were sharp, but mentorship wasn't part of the culture. It wasn't hostile so much as a place where people cared more about stability and pay than about experimenting. That experience, more than any other, pushed me toward startups. Asana had already shown me that smaller could mean more ownership, and after Netflix I knew I didn't want the big-company track. Post-graduation I found Convex and joined two and a half years ago.

Thrown into the deep end, on purpose

Convex was around 20 people when I joined. That makes for a completely different onboarding than a big company. At a big company, you usually know what you'll be doing from day one through day ninety, plus your manager, your mentor, and your project. At Convex it was closer to: here's your first project, figure it out.

That's stressful if you're not used to it, but it's also a good way to learn. In a company that small, there's no room for inconsequential projects. Every cog matters. The team backed that up by being around to answer questions and teach, so even though I got dropped into things fast, I wasn't dropped in alone.

My first real project was the postal service, the only service at Convex that's built on Convex itself. It handles the emails Convex sends to customers: plan-limit warnings, over-limit notices, and eventually spending limits and other lifecycle emails. Figuring out the usage thresholds, and when to trigger which email, taught me what it's like to build on the platform I now work on. It also surfaced what was great about the developer experience and what was still lacking. That mattered a lot at a point when we were still tweaking the core platform.

Deleting customer data on purpose

After the postal service, I moved into infrastructure. One of the more exciting projects I've worked on is cleaning up Convex's durable transaction log. That log is the record of every update to every document in a Convex table. Convex doesn't edit documents in place; every update becomes a new row. For customers with high update volumes, that log grows unbounded. It piles up inactive rows that are no longer visible from the current timestamp but still sit there taking up space.

I wrote an algorithm to calculate visibility windows and delete documents that fall outside them. If your retention window is three days, the system has to be able to reconstruct any database state from within those three days. If a document isn't visible in that window, it gets deleted. That one project cut Convex's database storage by more than half.

It was also a high-trust project, and it made me nervous in a useful way. Deleting the wrong thing there means deleting customer data. It meant writing deep SQL and learning Convex internals I hadn't touched before. That's the kind of project that only teaches you something because the stakes are real.

Why Convex runs multiple deployments on one machine

The other big infrastructure project I've worked on is Conductor. It's our multi-tenant service that hosts multiple Convex deployments on the same machine. Originally, each Convex deployment mapped to a single machine, and that doesn't scale. Resources can't be shared. Some projects run constantly, others sit mostly dormant, and a one-to-one mapping wastes capacity on both.

Two services made Conductor possible. Function-run executes the JavaScript for queries, mutations, and actions. It hands the reads and writes back to the committer to apply to the database. The sync service, which we call Usher, handles WebSocket connections and subscription state. It also decides which conductor or backend a given request should go to. Once both existed, we had the pieces to let one physical machine host many deployments and share CPU and memory across them, instead of provisioning idle capacity for every project.

We use Nomad, not Kubernetes, as the orchestration layer. Conductor is the binary that runs on a machine, and Nomad's job is to schedule and place conductors across the fleet. The unit Nomad reasons about is the conductor, not the individual deployment.

Architecture diagram of ConductorArchitecture diagram of Conductor

Building Chef taught us why Convex works well with AI

Outside of core infrastructure, I also worked on Chef. It's the AI app-building platform we built to show what AI looks like when it's paired tightly with Convex. The bet was simple. Developers already like working with Convex's abstractions by hand, so those same abstractions should make life easier for an AI trying to glue together a database, a backend, and a frontend. That's the same kind of cross-system complexity a human developer deals with.

There wasn't a blueprint for building it. We sat in rooms, sketched architecture, made trade-offs in favor of simplicity, and shipped. The lessons from building Chef came down to one thing: type checking. It's hard to know whether AI-generated SQL or backend code works. But Convex is type-safe from the frontend all the way to the backend, and that end-to-end typing gives an AI tool something close to a built-in correctness signal. Large models do their best work when they get clear, immediate feedback on whether what they wrote is right. It's the same way TypeScript's compiler acts like a fast test suite for JavaScript. Because Convex carries types across the whole stack, AI tools built on it can move faster and more autonomously without flying blind.

Day to day I write a mix of Rust and TypeScript, probably a bit more Rust. LLMs tend to write TypeScript faster in practice, partly because there's less compile-time friction than with Rust. With Rust I lean on autocomplete more than generation.

Why I rejected AI tools before I trusted them

I mentioned this at the start, but it's worth being specific about why. For the first year and a half of my career, I mostly avoided AI coding tools. I hadn't yet built the judgment to know whether the code they produced was any good. Without that judgment, you can't use them well. You either click accept on everything and hope, or you second-guess everything and get none of the speed benefit.

At Convex specifically, you're accountable for what you ship, and "the AI wrote it" isn't a defense. Once I'd built that underlying skill, delegating became useful. I already knew how I would have solved a given problem, so I could evaluate the AI's version against that baseline, make small corrections, and move on. That's where AI has been most useful for me. It executes on my judgment faster, once that judgment already exists.

I don't think there's a single right way to code, and taste is a real part of the job. Code at Convex looks different from code at other companies, because different teams and different engineers prioritize different things. That variation isn't a bug. Humans stay in the loop for a while yet. As long as a codebase spans a database, a backend, and a frontend that aren't unified into one platform, reasoning about the constraints between those layers is hard for an LLM. Someone still has to own that reasoning. I haven't seen a tool that gives an LLM the kind of accountability I'd trust to let it safely fix code on its own. Observability and automated fixes are getting better, but they're not there yet.

What I'd tell a high schooler deciding whether to learn to code

Say a high schooler asked me whether to learn to code or just learn to prompt well. My answer is yes. Learning to code is still worth it, because software engineering is problem solving at its core, and prompting is a tool on top of that, not a replacement for it. Learn to use the tools well, but learn the fundamentals too. Understanding how software really works is what builds the intuition to use any tool better, including the next one that replaces today's. That means object-oriented principles, how databases behave, and the trade-offs different designs make. It's part of why we don't let candidates lean on AI in our own coding interviews. The fundamentals are what we're trying to see.

Whether kids will need to learn something like the Liskov Substitution Principle by name, I'm less sure. Roles will probably shift toward more product sense over time. But if you want to build software that holds up, you need the fundamentals and the ability to reason through trade-offs yourself. If all you've ever done is describe what you want and let a model produce it, you don't get that depth. I worry about people cruising on AI output long enough that they never build the intuition it's supposed to be accelerating. Ask a model to make every decision for you, and you never build a framework for making decisions of your own. Trying things, and sometimes failing at them, is a real part of how engineers learn. That's part of the human experience, honestly, not a phase to skip.

That's also why I still like tackling hard problems myself instead of delegating them by default. Now and then I'll use AI to rough out a proof of concept. But writing the code myself is how I keep that muscle from atrophying. For routine work that doesn't teach me anything new, delegating to AI is the right call. It frees me up for the harder problems where my judgment matters.

Components: letting the ecosystem build what we don't have to

One of the reasons I joined Convex was to work on things I cared about instead of being told what to build. Components have been one of the bigger things I've gotten to shape. We shipped them around November 2024. They work like sandboxed backends you can install into your own Convex backend with a single npm command. Each one comes with its own data schema and function execution environment.

Early on, every component was built by the Convex team, and the authoring experience wasn't great, mostly because we had a lot of competing priorities. Over the past few months, that's changed. We've:

  • cleaned up the API for exposing component internals to the apps built on top of them
  • added a dedicated codegen command for component development
  • refreshed the templates
  • published a components authoring guide

Components matter because they let people split codebases apart. Other companies can own and maintain their own integrations with Convex, instead of everything running through us. We've already built things like a Stripe component and a Work OS component. As the developer base keeps growing, I expect more people to want to maintain components of their own, which points toward a real ecosystem of drop-in functionality over time. The whole premise of Convex is making software development easier, and components are a direct extension of that. Instead of everyone solving the same problem independently, someone solves it well once and the rest of us install it.

All gas, no breakages

Convex is the reactive backend platform that keeps up with you and your agents. Database, functions, workflow, sync, search, file storage, and more. All TypeScript, zero glue.

Get started