Well, well… ok… let’s get real… Yeoman and Cookiecutter are not dead, it’s just that I wanted a catchy headline. 😁
What I mean is that suddenly a new competitor has emerged with lots of advantages, and it’s going to give them a good fight…
If you’re reading this, I guess you already know these tools, but just in case:
What are Yeoman and Cookiecutter?
Cookiecutter is a generator. Actually, until now, it’s the main referent in Python, and one of the most importants in any language.
Yeoman is another similar app written for NodeJS, and that —this time yes— is the main generator available today, worldwide… until today, at least.
Obviously these are not the only generators available, but you know how things work… we could pretend they are. 😉
And what is a generator?
Basically, they’re programs that, based on a template (also known as “scaffoldings”), they do a series of questions to the user and generate a “subproject”.
And why it Yeoman or Cookiecutter were not enough?
Both accomplish their jobs, but have these other fundamental problems:
The day 2 problem
Both are centered around one use case: create a subproject from zero.
That’s quite good, but software is rarely a finished product. Usually they are projects that keep on evolving. And if your template evolves too, how do you apply those updates to the subprojects you generated with it?
Yeoman has a not-so-good support for this, and Cookiecutter has none.
To me, being able to evolve the project is mandatory.
A very specific problem is deleting files. Most generators are focused on creating
files, but what if you suddenly move your isort
configs to a pyproject.toml
file
instead of that .isort.cfg
? Why shouldn’t that .isort.cfg
file be deleted in the
next update?
The problem of the multiple templates
Again, existing tools assume you are going to generate a subproject focused on a single thing. But what if you want to add your own stuff to your subprojects?
One example: let’s suppose you have some master templates to configure your CI/CD. These are private templates, tightly coupled with your particular infrastructure. If you use any generator to bootstrap a new project, why shouldn’t you be able to apply these templates too?
No other generator supports this AFAIK.
And why not just use a Git repository?
Back in 2017 I had to start maintaining a pretty complex template, and due to the problems generators had then (same ones as today), I opted for the dumb Git template.
Although that made updates relatively simple, it meant all of these problems:
-
History problems. Every time a subproject is updated, it downloads and merges all the new git history from the scaffolding.
-
Documenting problems. Any documentation (README or whatever) would be cloned to all subprojects, so you have to maintain it somewhere separately.
-
Testing problems. Tests would clone into each subproject, but there tests wouldn’t make sense anymore.
-
Updating problems. For example, let’s suppose your project uses Postgres, and when you created it, Postgres 10 was the latest version. Today it happens to be version 12.
If you change that, it would mean that subprojects that update would change Postgres version. That might not have sense because it could render old data no longer compatible.
So, even if you support more modern versions, the ones cloned with your template are outdated and you can never update them safely again.
-
Backwards-incompatible changes introduction problems. The normal thing to do with these kind of changes would be to just trust in a simple SemVer versioning that everybody understands, but with the previous problem explained, you just can’t version. Even if you could, those versions would get merged in the subprojects.
-
New features introduction problems. As long as these were not 100% backwards compatible, they’d almost guarantee broken updates in downstream subprojects.
-
Problems to have a private template. If you wanted to publish one template while still keeping some configurations private and merging both in the same subproject, you’d have to merge 2 templates in 1. This makes all previous problems worse.
Too many problems. Years later, some of them already became blocking problems.
Time had come to take the leap a generator.
Why it wasn’t enough with improving existing generators
Yes, it would have seemed easier to add that feature to one of those very known projects, but both of them had big outstanding design problems:
Yeoman’s problems
In reality, Yeoman is not a generator, but a framework for generators.
With Yeoman, you really don’t create a scaffolding, but a whole generator associated to a scaffolding.
At the end of the day, you end up producing a whole NodeJS app that you must publish to NPM for it to be used.
Yes, it might seem wonderful for an ECMAScript developer, but for the rest of mortals this becomes a steep learning curve that is of no interest at all, when all you want is a simple template for a project that probably even has no relation with ECMAScript at all.
Apart from that, it means to maintain JSON files manually! That should be considered a crime.
And, of course, if you want to program any logic in the template, it implies using ECMAScript, something I don’t particularly love.
Cookiecutter’s problems
With Cookiecutter, we don’t have to publish anything to PyPI, but:
-
The project has no funds.
-
Since 2016 they started talking about supporting updates, and still nothing has been done.
-
The same happens with the problem of having to write JSON by hand (although since 2014 this time).
Some other projects have emerged that use Cookiecutter as a library to build updates support on top of it. However, this reduced community support around the project, and it wouldn’t make sense if they were talking already about adding support for that directly into Cookiecutter.
After all of this, 3 years later the situation remained the same, so it was about time to get to work…
Copier enters to scene
OTOH, Copier already existed (I just helped giving it a new life for its version 3), but:
- It had a more modern code base,
- a more natural approach to template management,
- without needing to publish software packages,
- and with a more pleasant YAML syntax.
Well, if it was necessary to invest hours (many), better in something well designed.
Copier 3 advantages
Copier allows you to start working in a supereasy way, with a superlow learning curve:
- You’re not forced to add logic to your templates.
- You’re not forced to configure the template.
- You’re not forced to use git.
- You’re not forced to support template updates.
- You’re not forced to program.
- You don’t need to publish your template into any package registry.
However, if you need any of those characteristics:
-
You have available a templating engine that is easy to learn for anyone, no matter what’s your language of origin: Jinja 2.
If you’re interested, here’s the documentation to write templates.
-
The template can be configured with a simple (or complex, as you need)
copier.yml
file. -
If you publish your template in a Git repository, you just have to tell Copier to download it from there.
-
If you configure updates support in your template:
- Copier will use Git tags to update your subproject based on its original template.
- It will try to respect the history generated since your last update.
- It will run all the migrations programmed by the template designer (if any).
-
You can program your post-copy and pre/post-migration tasks:
- Directly as commands in you
copier.yaml
. - Or you can use a script in the source template.
- Or one in the destination subproject.
- Using your favorite language. Any executable works.
- Directly as commands in you
Obviously it’s not perfect, but we’ve done a big work with it, and it is born specifically to support updates, so no dirty patches or random external libraries to get that.
Summary
If you want a template manager that’s easy but powerful, that allows you to evolve without having to take unmodifiable decisions, and that doesn’t force you to write JSON, give Copier a chance. You won’t regret!