Using generators to improve developer productivity

Carlos Cuesta - May 28 '22 - - Dev Community

A few weeks ago at N26, we did get stuff done week, during this time the product and engineering teams have the opportunity to try or build anything we like.

I decided to spend the week adding a code generation tool to the Web project
automating a bit of the coding work while improving the developer experience.

In this article, I'll walk through the experience and the outcome of implementing a tool to generate code πŸ‘¨β€πŸ’»

What is a code generator?

A code generator is a tool that given a set of rules and inputs creates code, files, and folders.

To name a few popular ones πŸ‘‡

All of them will create code based on specific rules taking into account the inputs provided by the user. Here's a simple example πŸ‘‡

Code generator teaser

What's the problem?

Imagine, you start the day working on a new task and you need to create a feature, before writing any code you will need to consider a few things:

  • Folder structure and architecture πŸ“‚
  • Naming files convention πŸ“‘
  • Where to put the feature πŸ—‚
  • How you should write the tests πŸ§ͺ

I'm sure the project you're working on has a list of conventions and patterns defined that explains how you should work in the codebase.

However, every time you are going through this process it requires you to think πŸ€” about those conventions to make the decision.

Where is the source of truth? 🧐

As software engineers we work very hard to not repeat code building abstractions, automating manual workflows...

What about writing code? In the same way, we advocate for automating processes such as deployments, we should also make an effort to the non-creative part of coding such as scaffolding.

Why you should use them?

Generating code will save you time ⏰ and will increase the productivity of the team πŸ“ˆ

Developer experience

In a team that is constantly growing it is important to make sure that everyone is aligned and able to build things efficiently.

Having a great Developer Experience will boost the confidence a developer has with the codebase.

Trust, empowers people to be more productive and agile ⚑️, to name a few of the many benefits you'll get by using generators:

  • Ensure everyone is doing things "as expected" according to the project conventions πŸ’–
  • Reduce friction when working with the codebase πŸ€”
  • Ease the onboarding of new joiners πŸ†•
  • Decrease the development time πŸš€

Decision fatigue

The most important thing is that your teammates will not have to spend time on low-value decisions, such as deciding how a component is structured.

Turns out our decision-making process gets worse the more decisions we make.

This is called decision fatigue. For example, Steve Jobs, limited his everyday clothing down to one outfit to avoid making a decision.

Using code generators

Sounds good right 😍? Let's take a look at how we can implement code generators in our project πŸ‘€

Choosing the right tool

I didn't want to reinvent the wheel, my focus was set on the outcome of generating code, not building a tool that solves this problem.

There are a lot of Open Source projects that will do an awesome job generating code. Here's the list of the ones I considered:

I decided to go with Hygen at N26 because:

  • Great monorepo support
  • Easy to maintain. You'll only need to care about .EJS template files and prompts.
  • No configuration required
  • High value with low effort, writing a generator is very simple.

Plop is also a great tool but creating a generator is more complex since you need to spend more time writing code and the tool demands extra time on the configuration part compared to Hygen.

Yeoman is another valid option, but maintaining generators requires you to manage and publish packages to a registry and I would say the use-case of this tool is more suited to scaffolding projects instead of smaller parts of a codebase.

Getting started

It's time to create our code generator πŸ₯³. First, install Hygen as a devDependency in your project:

$ npm install -D hygen
Enter fullscreen mode Exit fullscreen mode

Define a script inside the package.json to use the script binary:

{
  "scripts": {
    "generators": "hygen"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now we can run Hygen through the generators script:

$ npm run generators
Enter fullscreen mode Exit fullscreen mode

After running the command, you'll see that Hygen is telling us we don't have any generators.

Error: please specify a generator.
Hygen v6.2.0
Enter fullscreen mode Exit fullscreen mode

By default, hygen will read the generator files from a folder named _templates.

If you want to change this behavior, create a file named .hygen.js at the root level of your project, like this:

const path = require('path')

module.exports = {
  templates: path.join(__dirname, 'generators'),
}
Enter fullscreen mode Exit fullscreen mode

Creating a generator

A generator is composed of one or more actions, every action contains two items:

  • Templates: *.ejs 🧩
  • Prompts: prompt.js ⁉️

Let's build a simple generator that creates a React component πŸ€“. At the end of the post, you'll find a GitHub repository with a lot of different examples πŸ‘

The first thing we need to create is the generator folder that will contain the action:

  • Generator: component
  • Action: react
$ mkdir -p generators/component/react
Enter fullscreen mode Exit fullscreen mode
Templates

Template files define the code that will be created after running the generator, these files are written using a template language called Embedded JavaScript templates.

Every template starts with a frontmatter header. On this header, you will define the metadata of the template using the following properties πŸ”

Property Type Usage
to String The destination of the file once compiled.
from String Use an external file as template.
force Boolean Overwrite existing files
unless_exists Boolean Execute the generator unless file already exists.
inject Boolean Inject the contents into an existing file instead of creating a new one.
after Regex Inject the template after the regex
before Regex Inject the template before the regex
prepend Boolean Inject the template at the start of the file
append Boolean Inject the template at the end of the file
at_line Regex Inject the template at the specified line number
skip_if Regex Skip injection if regex matches.
eof_last Boolean Trim the newline from the end of the injection.
sh String Trigger a shell command after compiling the template

Now, let's add a template file named index.ejs inside the react action folder we created previously:

$ touch generators/component/react/index.ejs
Enter fullscreen mode Exit fullscreen mode

As I mentioned before, we want to create a React component, so we need to specify the location of the file where the component is going to be created.

We can do that using the to property.

---
to: src/components/<%= h.changeCase.pascalCase(name) %>/index.js
---
Enter fullscreen mode Exit fullscreen mode

As you can see, we're using a variable called name on the header. This value will be provided by the prompts of the generator ⁉️

Then, we need to write the body of the template, where we define the code that will be generated once the template is compiled. I'm reusing the name variable in the body as well to create the name and export of the component ✨

---
to: src/components/<%= h.changeCase.pascalCase(name) %>/index.js
---

const <%= h.changeCase.pascalCase(name) %> = () => (
  <section>
    <h1>Hey! πŸ‘‹</h1>
    <h2><code><%= h.changeCase.pascalCase(name) %></code></h2>
  </section>
)

export default <%= h.changeCase.pascalCase(name) %>
Enter fullscreen mode Exit fullscreen mode
Prompts

In case you need to ask for user input, optionally you can use a prompt file. This is very useful to customize the output of the generator. Prompts are defined using a library named Enquirer.

Inside of the same react πŸ“, we will create a prompt.js file to ask for the variable defined as name in the template:

module.exports = [
  {
    type: 'input',
    name: 'name',
    message: 'Write the name of your component'
  }
]
Enter fullscreen mode Exit fullscreen mode

There are a ton of different input types available πŸ”‘, take a look at this link to get the complete list.

Now it's time to finally run our generator πŸ₯³ using the script along with the name and the action:

$ npm run generators component react
Enter fullscreen mode Exit fullscreen mode

You'll be asked for the prompts and finally the magic will happen! πŸ¦„

Code generator demo

Demo

Take a look at carloscuesta/codegenerators-demo πŸ•Ή if you want to play and see more complex examples!

Automate all the things!

It's time for you to find out repetitive tasks and patterns to extract them into a generator! πŸš€

I'm very happy with the productivity boost and the consistency that a tool like this can bring to a team ❀️

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