Back

Improve Developer Productivity with Generators and Team Conventions

Chris Ball
Chris BallTuesday, May 8, 2018
a man standing in the middle of a street

Team conventions and the tooling to enforce them can often be an afterthought on projects. Deciding on conventions for your team takes collaboration and time. Adding the required tooling to enforce them takes more time, so it tends to be something we avoid.

I recently gave two talks digging into this subject and the benefits of actually taking that time. The first was a lightning talk for Portland ReactJS and the second was a full-length talk for Boston ReactJS. This post summarizes those talks. The ideas presented here use React as an example context, but can apply to any project.

A familiar song and dance

When starting a new feature in a React app, we often start by creating a new component. But before any code is written, you need to think through a few things.

  1. What is the proper folder structure?
  2. Do I camel-case or title-case the file?
  3. Where should I put styles and how are they imported?
  4. Where do I put tests and how are they named?

To give a more concrete example, say your team has decided to create your app in a feature-based folder structure. In order to create a Select component, you need to create 3 (or more) files depending on how your team has decided to split things out.

Select component with four files

A feature-based folder structure

Even though creating these files is not complicated, think about how many actions you need to perform every single time you create a component using the structure above. You need to:

  1. Create a new folder with the name titleized.
  2. Create a component file with the name titleized. Copy and paste component content from another file.
  3. Create an index.js file that imports the component file.
  4. Create a styles file. Copy and paste the basic style layout.
  5. Create a stories file with the name titleized. Copy and paste story content from another file.

Sound like something to automate? Sure does. We’ll come back to that.

Code Reviews

Let’s say you finish the implementation of the component, and open a Pull Request. You might encounter feedback like the following:

“Can you add a test for this?”

“Actually, this is the old way we did this. Check out .”

Sound familiar? It probably does. This happens a lot.

What’s the problem?

Who (or what) is the source of truth for the way your team creates files? What about the way you write code? Often, this knowledge resides entirely in someone’s head or is non-existent. People tend to copy a file and follow the patterns established within it, but that pattern might not be the latest one. Even worse, it might be a bad example.

Developers work hard to not repeat ourselves in code but we often fail to apply that concept to our daily workflows. If you need to constantly calculate averages of a set of numbers, you might want to make a spreadsheet. Likewise, if you’re continually creating files that follow similar patterns you should look at ways to automate it.

Boilerplates and Starter kits

The React community has the concept of Boilerplates and Starter kits to help developers get started quickly. Most of them include a CLI to help you generate new files. The official React website even maintains a list.

The potential problem with these, is that they include a set of conventions. Libraries like styled-components or Redux or a certain folder structure. These conventions might work for you initially, but as your project evolves they may not.

To eat or not to eat sign

You probably don’t want to fork.

When your team decides to take a different approach from a Boilerplate or starter kit, you’re faced with an important decision. Should you fork the project? If you do, just remember:

If you fork a project you are now a maintainer and must keep it up-to-date.

Yeah that's not gonna happen image

A trend towards flexible conventions

Frontend development is constantly evolving, and some of the more recent changes are focused on “Zero Config”. But alongside this is a realization that the conventions included in these libraries need to be configurable as teams and projects evolve. A good example of this is Create React App and react-app-rewired.

I’d like you think about creating conventions for your team. You’ll likely start from past projects or open source examples, just make sure you’ve had some group discussion and can confidently say “this is how we do things”.

Think about folder structure, file naming, and the way you write the code within the file. Perhaps you want to generate a failing test to enforce actually writing them.

Once you have established patterns, you can determine how to template and automate them.

Why?

Generating files using a specified convention saves time, keystrokes, and clicks. But you also save something much more important.

Decision Fatigue (also known as Cognitive Depletion)

Don’t waste time on low value choices. Yehuda Katz gave a great keynote at Railsconf years ago that illustrates this point well. To sum it up, you can only make a certain number of decisions per day. Think of your ability to make decisions as a cup — you can fill it with many small decisions or a few large ones, but once it’s full, you’re done for the day.

This phenomenon does not only occur in programming. It can happen in any profession that needs to make frequent decisions every day. The best way to make it easier on yourself is to try to reduce the number of decisions you have to make however you can.

Barack Obama smiling in White House on left, Steve Jobs holding computer in the middle and Mark Zuckerberg

An easy way to reduce decision fatigue? Wear the same outfit every day.

Developer Experience

The other major reason to leverage generators and form explicit team conventions is for a better developer experience. Your team does this stuff every day, so why not make it as frictionless and enjoyable as possible?

Here are a few of the many benefits you’ll get by taking this approach:

  • No more copy and paste when creating new files
  • Automatically ensure that everyone is doing things “the new way”.
  • Simplify the onboarding of new developers
  • Automating anything makes developers happy

How

Sound like a win all around? Let’s look at a few ways to implement this approach. You will want to use a CLI to generate files for you, but make sure its easily customizable. Our favorite is Hygen.

Hygen

www.hygen.io

Getting Started

First, set up Hygen. The following examples show how to use Hygen to generate files for a React app, but Hygen can be used for plain JavaScript, static sites, and many other cases where you need to generate files.

$ brew tap jondot/tap $ brew install hygen

In your project folder, initialize it:

hygen init self hygen generator new --name component

Hygen will generate some files you can use as reference. We’ll add a few files to _templates/components/new to reflect the folder structure mentioned previously.

--- to: src/components/<%= h.inflection.classify(name) %>/<%= h.inflection.classify(name) %>.js --- <% classified = h.inflection.classify(name) -%> import React from 'react'; import styles from './styles'; const <%= classified %> = () => ( <div>Hello</div> ); export default <%= classified %>;
--- to: src/components/<%= h.inflection.classify(name) %>/index.js --- <% classified = h.inflection.classify(name) -%> export { default } from './<%= classified %>';
--- to: src/components/<%= h.inflection.classify(name) %>/styles.js --- <% classified = h.inflection.classify(name) -%> import { css } from 'react-emotion'; import { colors } from '../../styles'; import { mediaQuery } from '../../styles/breakpoints'; export default { container: css` margin-top: 0; color: ${colors.black}; ${mediaQuery.medium(css` color: ${colors.green}; `)} ` }
--- to: src/components/<%= h.inflection.classify(name) %>/stories.js --- <% classified = h.inflection.classify(name) -%> // @flow import React from 'react'; import { storiesOf } from '@storybook/react'; import { withInfo } from '@storybook/addon-info'; import <%= classified %> from './<%= classified %>'; const stories = storiesOf('<%= classified %>', module); stories.add( 'Default', withInfo(` # <%= classified %> Component This component does something, you should probably change this. `)(() => <<%= classified %> />), );

Want to get fancy? Prompt users if they want a functional or stateful component and generate accordingly:

--- to: src/components/<%= h.inflection.classify(name) %>/<%= h.inflection.classify(name) %>.js --- <% classified = h.inflection.classify(name) -%> <% if(componentType === 'functional'){ -%> import React from 'react'; import styles from './styles'; const <%= classified %> = () => ( <div classname={styles.container} />; ) <% } -%> <% if(componentType === 'stateful'){ -%> import React, { Component } from 'react'; import styles from './styles'; class <%= classified %> extends Component { state = {} render() { return ( <div className={styles.container} /> ); } } <% } -%> export default <%= classified %>;
module.exports = [ { type: 'list', name: 'componentType', message: 'Functional or Stateful?', choices: ['functional', 'stateful'], default: 'functional' ];

Want some starter templates that do this? Check out hygen-CRA.

Alternatives

If you don’t think Hygen is right for you, try Plop or Yeoman. Before we switched to Hygen, we even rolled our own.

The tool you use isn’t important, but the process is.

When things change

Regardless of the tool you choose, we’ve found co-locating generator templates with project code is best. When team preferences change, your generators can evolve right alongside them.

For example, say your team adopts TypeScript. The developer adding TypeScript support can simply update the generator templates to use TypeScript in the same Pull Request and everyone will generate TypeScript components going forward.

Productivity for the win

Find and extract conventions for your team by taking note of repetitive patterns. Note that conventions may differ from project to project or team to team within a company. That’s fine!

Eliminate low value choices and focus on the implementation details.

We’ve really loved the productivity boost that customizable generators have given us and the teams we’ve worked with. Next to updating a READMEor adding PR templates, it’s often one of our first contributions to a project. If you want to chat with us about this approach or want us to help you implement it for your team, say hi!

Share this post

twitterfacebooklinkedin

Related Posts:

Interested in working with us?

Give us some details about your project, and our team will be in touch with how we can help.

Get in Touch