Is Code Generation a Bad Idea? šŸ¤”

JS - Jun 27 '23 - - Dev Community

Iā€™m building ZenStack: a full-stack development toolkit on top of Pirsma ORM that simplifies the development of a web app's backend. It uses the schema-first approach to generate access control-enabled APIs and front-end queries.

Upon introducing it to certain individuals, right after hearing the code generation part, their immediate reaction is like this:

No-code-generation

The benefit of code generation is not worth mentioning

The most benefit that code generation could bring is quite obvious: write less code. For example, in my last post, you can see how to get a scalable SaaS backend with less than 100 lines of schema file thanks to the code generation:

I could get it if, after hearing the whole picture, they say: Iā€™m not buy-in because the benefit doesnā€™t pay off the debts that code generation brings. But coming across these people who just up a tag on their heads, ā€œI never use code generation,ā€ leaves me pondering the reasons why they hate it so badly.

We use code generation every day

To the surprise of many people, especially those who hate code generation, they actually use code generation every day.

For instance, if you have ever used Svelte, on the home page of its official website, it directly shows you how the code generation works to convert the simple Svelte code to the actual Javascript that is actually running in the browser:

Svelte

Maybe you are a backend developer never used any frontend framework. Have you ever used Typescript? If so, I think you should be familiar with the command tsc and what it does. šŸ˜‰

Even if you are completely out of the javascript ecosystem unless you are still using assembly language, ode generation is an unavoidable aspect.

Some might say Iā€™m stealing concepts, as these are called compilation rather than code generation. So, what exactly distinguishes them?

The bad side of code generation

In the context of ZenStack, the notable difference is as below:

  • For compilation, code generation applies to all the code, and the resulting generated code is typically not a significant concern for developers
  • For ZenStack, code generation specifically targets a specific portion of the code, utilizing a distinct syntax. The remaining parts of the code then rely on the generated output from this specific code generation process.

Considering these, code generation in ZenStack does reveal some practical challenges:

1. Learning a new syntax

This is true. But I guess thatā€™s the price you need to pay if you want to use less to generate more.

2. Have to run generation command whenever changing the schema

It does sound like damage to the developer experience, apparently. However, separating the schema from the code carries an implicit advantageā€”it enforces a design pattern.

The schema serves as the contract between the different modules of your code base, similar to an interface in object-oriented programming. By adhering to the moral ā€œprogramming to interfaceā€, changes should first occur in the interface, or in this case, the schema. For instance, if your team has adopted GraphQL as your API, you are familiar with the efficiency it brings, allowing independent and parallel work between frontend and backend teams.

You might say even if it brings value like the interface, changing the interface does not require you to run the generation command.

While it is true that altering an interface does not require running a generation command, it is important to note that the frequency of changes in the schema is typically lower compared to other parts of the codebase. Moreover, the additional step of code generation serves as a reminder to exercise caution when changing the contract, which can be a good mindset to cultivate. However, if it really bothers you that much, automating it with a script that watches the schema changes and executes the generation command automatically in the background could be a viable solution.

3. Limited control and customization

Code generation comes with certain predefined rules. Some developers prefer having fine-grained control over everything, which limits their ability to customize. For instance, with RESTful APIs, you can add an endpoint anywhere in your codebase and directly include additional data in the response body. In contrast, with GraphQL, any API-related changes necessitate modifications to the schema first. However, when viewed from a different perspective, these limitations help address the maintenance challenges associated with RESTful APIs and contribute to the efficiency mentioned earlier.

It is essential to acknowledge that there is no one-size-fits-all approach, and it always involves making trade-offs.

Donā€™t hate a concept

Forget about the concept, try to get the whole picture by analyzing the specific pros and cons of an approach. Otherwise, you might miss the good stuff.

Preoccupied with a single leaf, you won't see the tree.Ā Preoccupied with a single tree, you'll miss the entire forest


If you donā€™t hate code generation, check out the schema-first approach ZenStack we are building. It uses the declarative data model on top of Prisma, adding access policy and validation rules, from which it will automatically generate APIs, including OpenAPI, tPRC route, and hooks for you.

If you do feel it could help you, I would be super happy if you could give me a star so it could really help more people to move fast! ā¤ļø

https://github.com/zenstackhq/zenstack

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .