Why I am Using Code Generation Again, Part I

In the nineties, I used Rational Rose and Perl to generate a lot of C++ code. I’m not sure if I knew the term at the time, but we also created DSLs (Domain Specific Languages) that probably fell into the “… poorly specified, half-implemented Lisp” trap.

Back then, I would say that I used code generation to overcome the limited expressiveness of my programming language. There was a lot of boilerplate in C++ (and later Java and C#) that I didn’t want to write—I didn’t even want it to be part of the source. I considered the DSL to be the source in these cases.

When I moved onto iOS development, I used code generation sparingly. It somewhat complicates the build process and the Swift language designers prioritized expressiveness enough to make it less necessary.

But, recently, I’ve begun to use code generation more while using Typescript. Typescript is a lot like Swift, so it’s expressive enough, but the main difference is that I am using Typescript to access things that don’t have types in their built-in API (SQL and GraphQL), but do have an underlying type system.

I decided to use TypeORM and TypeGraphQL, which allow me to define types that map onto the database and are passed around in the the GQL, and so on my backend, I have a strongly typed API to both. These systems are based on “decorators”, to tackle the problem of boilerplate code. But TypeORM generates the SQL to build the schema and each migration as I add to it, so there is code generation as well.

This is great for the backend. My server ends up exposing a GQL API which can also provide a schema. But, I still have the problem of having a typed API to GQL from my front-end. For this, I ended up using GraphQL Code Generator, which can connect to a GraphQL server, read the schema and your GQL queries, and generate a nice typed API, including React hooks for fetching your data.

Even with all of this, I didn’t think of myself as generating code. I was not writing parsers or generators—I was just using a system that happened to generate code. But having this system in my build flow already (and the fact that GQL code generator can have plugins) made it inevitable that I would eventually be generating my own code.

GQL Codegen is already doing all of the heavy lifting of getting the schema and parsing it—you can write a new plugin in a few lines of code. Once I wrote the plugin, I could delete hundreds of lines of boilerplate code around doing GQL mutations without having to resort to typeless wrappers. I’ll provide some details in Part II.