Latest news about Bitcoin and all cryptocurrencies. Your daily crypto news habit.
hygen is a code generator that lives in your project and scales with your team. It's fast, flexible, and perfectly fits modular code bases.
For the impatient, you check out the documentation and how to use it with Redux, React Native, and Express.js.
But if youâd like a story about software design as well, keep reading. The story is told by hijacking a couple of fundamental user experience design laws (well, theyâre not really laws, but, yea).
Hickâs Law
Hickâs law states that:
The time it takes for a person to make a decision is a result of the possible choices he or she has: increasing the number of choices will increase the decision time.
Turning to technology, choosing a new tool is a massive uptake of new choices, and the process of learning that new tool amplifies it even more. Every step of the way, friction is the default.
As far as code generators go, hygen has a primary design goal that is to minimize this friction. The restâââis bonus.
Every code generator tool has a templating engine. But thereâs also meta data; like where to place the new file at. To do metadata we placed a front-matter in the same template file, just like Jekyll does, and every Jekyll inspired blog generator that surfaced over the last few years (thereâs plenty!).
If you have your own static blog generated with Jekyll, or any other tool thatâs inspired by it, then this should be super familiar.
---to: hygen-examples/mailers/<%= message || 'unnamed'%>/html.ejsinject: truebefore: "const modules = ["skip_if: newModule---
To render, we use ejs - a ubiquitous, non restricted (as opposed to logic-less) templating engine. We donât deal with the logic-less flamewar. If you want logic in your templates, go ahead; we trust that you're responsible. There's plenty of ways to shoot your own foot but above all we want to be pragmatic.
From a syntax point of view a variant of ejs probably exists in what ever language you're coming from.
import View from './view'storiesOf('<%= Name %>', module) .addDecorator(withKnobs) .addDecorator(withTests('<%= Name %>')) .add('default', () => <View />)
And we take a batteries included approach; a set of built-in commands to guide you to the next step.
$ hygen init selfLoaded templates: src/templates added: _templates/generator/with-prompt/hello.ejs.t added: _templates/generator/with-prompt/prompt.ejs.t added: _templates/generator/new/hello.ejs.t$ hygen generator new --name mygenLoaded templates: _templates added: _templates/mygen/new/hello.ejs.t
Thereâs also intuitive argument parsing.
$ hygen module new --name auth --tokens bcrypt
And fantastic prompts, courtesy of inquirer.
$ hygen database setup --host localhost? Select database (Press <space> to select, <a> to toggle all, <i> to invert selection)âŻâŻ Postgres â sqlite ⯠MySQL
hygen doesn't impose on you a new programming language, project setup, or workflow. Because it lives in your project, and in your existing workflow and setup, it just inherits those.
Parkinsonâs Law
Letâs hijack Parkinsonâs law for a moment. This is the problem with every generator framework IÂ know.
Work expands so as to fill all of the time available for its completion.
When you have code generation set up as a separate project in or out of your repo (say, with cookiecutter or yeoman), it will become a thing. A shiny new toy.
At best, it becomes a product you look after that throws you out of context every time you want to tweak a template. At worst, it becomes stale and unmaintainedâââwork invested, and value never extracted.
Rails Did It First
Wholesale project generators are still good for when you need an entire starter-project, although I doubt will survive given the surge of starter projects for which you can just git clone and move on.
Theyâre also less great if you want to embed a generator workflow into your existing project, like Rails did when it kickstarted the idea of having generators be a core part of developer productivity into mass adoption for the first time.
class CreateMigration < Thor::Actions::CreateFile def migration_dir File.dirname(@destination) end def migration_file_name @base.migration_file_name end def identical? exists? && File.binread(existing_migration) == render end...
Rails and Thor, the generator framework it used, changed the way I thought about code generators. Up until then, when I needed to generate code (mostly for ORM entities, ah the times we had!) I was sucked up into .NETâs T4 Text Templates.
That was 7 years ago. I kept making generators with Thor and friends hoping for productivity spikes. But these became projects I maintained which sucked up valuable time, counter-intuitivelyâââthey were lowering the returns in general productivity.
The Shopping List
That only means one thing. A shopping list for a generator framework that stays out of your way.
- Process ergonomicsâââI donât want to compile my generators, or have them on a CI pipeline of their own.
- Developer ergonomicsâââeasily accessible and easily invoked.
- Low frictionâââthe pitfall of success. Each step I take should lead me to the next.
- Technology agnosticâââdonât want a new tech stack.
- Contextualâââif Iâm on the data layer, I want data generators.
- Scalableâââshould work for multiple teams iterating over a large and modular codebase.
- Feature packedâââsimple design doesnât mean a poor number of features.
- Flexibleâââgive me a way to shoot my foot if I want to.
- Embeddableâââcan be composed into other projects.
- Super customizableâââdefaults are OK, but give me escape hatches.
- Clean, intentfulâââfirst be useful, only then be cool.
Thatâs what hygen became.
Hygen
You can use it right now, in what ever project you have open. Hereâs how to make a generator that adds a markdown document to your docs/Â folder.
$ npm i -g hygen$ cd your-project$ hygen init self$ hygen generator new --name docs
Edit _templates/docs/new/hello.ejs.t:
---to: docs/<%= name %>.md---Hi!I'm a document about <%= name %>
And then rename. The name of the file doesnât matter, itâs for you, for bookeeping purposes.
$ mv _templates/docs/new/{hello,new-doc}.ejs.t
Thatâs it! Letâs make a doc:
$ hygen docs new --name architectureLoaded templates: _templates added: docs/architecture.md
And now letâs check our new generator in:
⯠gsA _templates/docs/new/new-doc.ejs.tA _templates/generator/new/hello.ejs.tA _templates/generator/with-prompt/hello.ejs.tA _templates/generator/with-prompt/prompt.ejs.t
_templates is a contextual folder. hygen looks for one, at the folder youâre running it from. This way you can have different flavors of the same generator happen from different parts of your project, or maybe in a mono-repo scenario just different teams having their own sets of generators based on where in the mono-repo a team works at.
Note that the hygen generator new command is also checked in (the generator/new and generator/with-prompt parts). This is part of the "flexibility" principle.
We acknowledge that it may be that you don't like the vanilla hygen generator for new generators. Go ahead and change it; then check it in and have your team review it. After this change all new generators you build will incorporate your new way to make them.
Power to the Generator
hygen lets you build generators that add multiple files, make injections to existing files, have prompts for interactivity with the user, and more.
Hereâs how to ease some Redux boilerplate fatigue.
These days I choose ducks, to remove a little bit of boilerplate and have modularity baked in any app IÂ build.
My typical Redux architecture would look like this:
app/ components/ icon.js avatar.js modules/ boot.js <---- glues modules together, requires chat, app, and auth. chat/ index.js <---- the 'connect' bit for Redux. view.js <---- the view, separated, for testing. state.js <---- reducer, actions, types, selectors. app/ index.js view.js state.js auth/ index.js view.js state.js
Adding a Module
Adding a new module is very easy with hygen. Here's how your templates look like:
_templates/ module/ new/ index.ejs.t view.ejs.t state.ejs.t inject_boot.ejs.t <--- adds a 'require' clause to boot.js
Hereâs how index looks like:
---to: app/modules/<%= name %>/index.js---//// requires, mappings, etc....//export default connect(...)(<%= Name %>)
A similar trick would do for view and state.
How would we add a require line given that boot.js looks like this?
// ... some bootstrapping code ...const modules = [ // <--- we want to inject a line here! require('chat').default, require('auth').default, require('app').default,]// ... rest of bootstrapping code ...
Letâs build inject_boot:
---to: app/modules/boot.jsinject: trueskip_if: <%= name %>after: "const modules = ["---require('./<%= name %>).default,
And weâre done! Generating a new module is saying this:
$ hygen module new --name settings
Use Hygen Today
hygen isnât just for Redux or documentation, or the other use cases that we line out in the documentation. Itâs for everything, because it imposes almost nothing.
Thereâs more to see on hygen.io where the documentation lives at. But if you want a more gentle intro thereâs also the digest form in the README and hygen is built with zero configuration and no strings attached so no harm done trying it.
So if you like trying things first, just install it, make a few generators and see if it fits you.
Build faster by generating code with Hygen.io was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.
Disclaimer
The views and opinions expressed in this article are solely those of the authors and do not reflect the views of Bitcoin Insider. Every investment and trading move involves risk - this is especially true for cryptocurrencies given their volatility. We strongly advise our readers to conduct their own research when making a decision.