Notes on a Language Agnostic Project Template DSL

Mature languages all have build tools, and many have requirements around where files should be located. Some systems, like Gulp and Grunt (JavaScript), simply require a config file to be present in the project root, and the rest of the structure is up to you. Others, like sbt and Maven (Scala and Java), are more opinionated in their recommendations.

When learning a new framework or language, one of the things I like to do is plan out a structure of the project. Sometimes I’ll want to do this even before writing any code. I believe it encourages good design, and gets me thinking about packages and apis before I get myself into too much trouble.

In practical terms, this means creating some directories and files. This is especially the case with the wild-west anarchy of JavaScript projects

A modest idea

To aid in this layout/design process, I’d like help from a utility. Here is how it would work. I want to be able to write a simple text file to disk, execute a command that reads the file, and have a new project’s directory structure generated automatically. The file I have in mind would look like this (a React.js project example):

/my-project
  /app
    /components
      header.jsx
      footer.jsx
      listItem.jsx
    /services
      core.js
      util.js
    /public
    /views
      index.html
    app.jsx
  main.js
  README.md
  Gulpfile.js
  package.json
  .gitignore

That’s 18 lines of text. Sketching it out in vim or Sublime Text would be relatively quick. After the file (named project.dirz) is written to disk, I’d like to execute a command (provsionally called dirz) like this:

$ dirz project.dirz

The command would read the file and automatically create the corresponding directory structure. The other files would be created as empty files, as if I had run the touch command for each of them. Effectively, the project.dirz file contains a domain specific language (DSL) for powering the creation of project skeletons.

Empty files and directories are fine for many things, but as an extension to the language, I would like to be able to provide an optional template for any of the files. For example, a lot of packages.json files look the same, and maybe I always want to provide the same defaults. In the dirz language, I could provide a template just for this file by adding a template name after that filename like so:

/my-project
  /app
    /components
      header.jsx
      footer.jsx
      listItem.jsx
    /services
      core.js
      util.js
    /public
    /views
      index.html
    app.jsx
  main.js
  README.md
  Gulpfile.js
  package.json  package-json.dirz  # comments
  .gitignore

But we could automate even more. Manually typing a frequently-used template name is tedious, so I could instead pass a flag to the dirz command that would apply common templates based on filenames. Something like:

$ dirz --templates gulp-react

The specification for the templates that apply to the gulp-react project type could live in a global cache managed by the dirz utility. Perhaps this particular spec would apply defaults to README.md, Gulpfile.js, package.json, and .gitignore. Using the templates flag with a project type would be the (more reusable) equivalent of manually typing out the following file and executing it directly with dirz:

/my-project
  /app
    /components
      header.jsx
      footer.jsx
      listItem.jsx
    /services
      core.js
      util.js
    /public
    /views
      index.html
    app.jsx
  main.js
  README.md     readme-standard.dirz
  Gulpfile.js   gulpfile.dirz
  package.json  package-json.dirz  
  .gitignore    node-gitignore.dirz

The templates flag would only be concerned with applying templates to files. It would not apply any directory structure. That is still controlled by the DSL. However, if you want to reuse a whole structure, templates, directories, and all, I’m thinking you can just pass the project name like this:

$ dirz gulp-react

And the whole project would be created. Directory structure, templates, and named blank files.

Why not use git?

You might be wondering why this is better than simply cloning a “seed” project from GitHub. I have two answers.

  1. Many “seed” projects are examples with working code, and it discourages the user from doing their own thing, and going through the necessary steps to create a project that successfully builds and runs. Seed projects also create a lot of cruft, and that means mental clutter, too.
  2. Cloning seed projects means hunting around on GitHub. That’s totally fine, but there are a lot of examples out there that are just blog posts or Stack Overflow posts. Having a tool like dirz lets you quickly sketch out a project with ideas borrowed from multiple sources.

My plan is to write the tool in Go, thanks to its built in template language, speed, and ability to compile to portable executables on just about any platform.