How a full-stack developer who got laid off twice ended up working on the Kotlin toolchain at Google.
How a full-stack developer who got laid off twice ended up working on the Kotlin toolchain at Google.
One of my first meetings at my new team was an API review for a Kotlin Multiplatform (a way to share Kotlin code across Android, iOS and the web) testing library. On the call were some of the most talented and experienced engineers I had ever worked with. For weeks I had been sitting in their meetings understanding half of what was said. Then this one started, and everyone had a strong, well-reasoned opinion about the smallest details: how a parameter-based assert should be named, what it should take, how it should read at the call site.
I felt right at home.
It took me years, and two layoffs, to get to that meeting. Now I think I was heading there the whole time.
I started out building WordPress sites and later moved to backend work, but I kept getting curious about whatever was underneath.
At Biobot, an agtech company whose devices reported over SMS, my job was the backend, but I liked spending time with the hardware team asking how they programmed the device. I wanted to understand things like why the main loop shut the radio down to save battery. Poking around their code is how I ended up working on their SMS message encoding.
Later I got into functional programming and kept wishing our ORM worked more like Ecto, the database library from Elixir's Phoenix framework. Eventually I wrote a small library to get some of that pipeline-style validation. It was probably my first time caring about how other developers would use something I built.
It all goes back to college, when I'd ask my professors where a file should live, while still naming my variables dog1 and dog2. I never liked arbitrary decisions, and where code lives seemed important for keeping things simple. That API review at Google was the first time I was surrounded by people who cared about those small decisions as much as I did.
The first time I was laid off was when Google shut down Stadia. I was there working as a contractor and had been living in Mountain View for only three months. My wife and I had recently gotten married, partly so we could stay together and get her visa. Suddenly all of that felt uncertain. I was scared, and I felt like a failure.
The second time was different. I had left a great company to join a startup because I believed in the project, and honestly because the money was good. My contract said full-time employee, but the company had no legal entity in Mexico, so I was paid as a contractor for tax purposes. When a new CTO decided to close the Mexico operation, it happened almost overnight.
This time I wasn't scared. I just didn't want to depend on someone else's decision ever again. So, a bit hot-headed, I decided I wasn't going to interview anywhere. I was going to start a consulting company.
That's how I learned how hard it is to do business in Mexico. I was awful at selling, and I ended up getting more job offers than business deals. After a few weeks I went back to my old friend LeetCode, as a backup plan and to ease my wife's anxiety.
That's when Google came along, for the third time, with a role in Mexico City. Neither my wife nor I wanted to move there. We were comfortable in our hometown, Chihuahua, and I had been working remotely for a while. I mostly took the interview as practice for the other ones I had lined up, so I didn't prepare much. A few days after the onsite, they told me I was moving on to team matching.
I matched with two teams: YouTube's cross-platform UI library team, and a new team Google was starting in Mexico City to own the Kotlin Native toolchain, the part that compiles Kotlin into native code so it can run on iOS. The team didn't exist yet. Until my manager was hired, I reported to my skip-level manager and worked alongside the Java and Kotlin libraries team. I was so excited about the chance to work on a compiler that the decision made itself.
Convincing my wife was harder. The last time Google had moved us, it ended with Stadia shutting down, so trusting them again wasn't easy, even though this time I would be a full-time employee by law and not just by title. She agreed because I told her it was my dream job. She tried to keep her job working remotely, lost it anyway, and went through eight stressful months looking for a new one. She has a job now and she's happy, but she doesn't love the idea of living here forever.
My first real task was porting a lint check (think of an ESLint rule) from Error Prone, a Java static analysis library, to Android Lint (which, despite its name, is neither only for Android nor just a linter). The code reviews were tough. I got more than 100 comments, and the change took a month to submit. At one point I had to set that check aside and start on another one, just so I could land something.
On the toolchain side, I started by removing the multi_framework action. In Bazel, the open-source version of Google's build system, each build step is called an action. To use Kotlin from an iOS app, the Kotlin code gets compiled into an Apple framework, a package that Swift and Objective-C can import. Building it is one of the slowest steps in the build. A while before I joined, it had been split into several smaller actions because builds on Intel Macs were timing out. My job was to put it back together.
I was still in startup mode, where "move fast and break things" is basically the motto. I found out the hard way that you don't do that at that depth in the stack of a monorepo, where thousands of other teams build on top of your change. Along with the split, I removed a flag that was disabling some LLVM optimization phases. A few days later, an engineer from Google Workspace reported that their builds were running out of memory.
At that point I didn't know enough about compilers to understand how each phase affected memory or wall time. So I started with the phases the old flag had disabled, and then went into JetBrains' Kotlin compiler source to find what else I could turn off. From there I brute-forced it, bisecting combinations until builds stopped breaking. I couldn't simply disable everything that had been disabled before, because some phases ran whole-program analysis and behaved differently now that the framework was built in one step.
Once I found the fastest combination that worked, I submitted the fix. The framework action for Google Docs got 25% faster than it was before I touched anything. That was my first real win.
Looking back, I was really biased for action, and also a bit reckless. It was my first time working with dependency graphs at this scale. Some actions have more than 10k dependencies on the classpath. But coming from startups, I was used to figuring things out on my own. When something broke, nobody was going to explain it to me, so I went and read the code. I didn't think the Kotlin compiler was off limits just because I didn't understand it, and it isn't, especially now with AI.
Our team in Mexico City has grown to eight people. Kotlin Native is still young, and Google is one of the companies pushing its limits, so a lot of our work ends up in the compiler itself. In the last two years we've contributed to the upstream Kotlin compiler, helped Google Docs move to building entirely on Kotlin Multiplatform, tracked down a lot of missing symbols when linking against Apple libraries, and kept Google on almost the latest version of the compiler. Because our team had a good track record with build performance, I also ended up owning Kotlin annotation processing for Google.
Let's say that you're coming from web development, like me, to a language or toolchain team; here's what helped me:
I still think about that API review. Back then I couldn't follow most of our meetings, but I already knew what it was like to care about where a file should live or what an assert should be called. That turned out to matter a lot more than I expected. If you're a web developer who keeps getting curious about what's underneath, follow that. It's a real path in.