Закон Хика гласит:

Время, необходимое человеку для принятия решения, является результатом возможных выборов, которые он или она имеет: увеличение количества вариантов увеличивает время принятия решения.

Обращаясь к технологиям, выбор нового инструмента - это массовое осознание новых возможностей, а процесс изучения этого нового инструмента еще больше усиливает его. На каждом этапе пути по умолчанию используется трение.

Что касается генераторов кода, hygen имеет первостепенную цель проектирования - минимизировать это трение. Остальное - бонус.

Каждый инструмент генератора кода имеет механизм создания шаблонов. Но есть также метаданные; например, где разместить новый файл. Для создания метаданных мы поместили вступительную часть в тот же файл шаблона, как и Jekyll, и каждый вдохновленный Jekyll генератор блогов, появившийся за последние несколько лет (их много!).

Если у вас есть собственный статический блог, созданный с помощью Jekyll, или любого другого инструмента, созданного на его основе, то это должно быть вам очень знакомо.

---
to: hygen-examples/mailers/<%= message || 'unnamed'%>/html.ejs
inject: true
before: "const modules = ["
skip_if: newModule
---

Для рендеринга мы используем ejs - повсеместный, неограниченный (в отличие от лишенного логики) шаблонизатора. Мы не занимаемся беспощадной войной. Если вы хотите логики в ваших шаблонах - вперед; мы верим, что вы несете ответственность. Есть много способов прострелить себе ногу, но прежде всего мы хотим быть прагматичными.

С точки зрения синтаксиса вариант ejs вероятно существует на каком бы то ни было языке, с которого вы пришли.

import View from './view'

storiesOf('<%= Name %>', module)
  .addDecorator(withKnobs)
  .addDecorator(withTests('<%= Name %>'))
  .add('default', () => <View />)

И мы используем подход с включенными батареями; набор встроенных команд, которые помогут вам перейти к следующему шагу.

$ hygen init self
Loaded 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 mygen
Loaded templates: _templates
       added: _templates/mygen/new/hello.ejs.t

Также есть интуитивно понятный синтаксический анализ аргументов.

$ hygen module new --name auth --tokens bcrypt

И фантастические подсказки, любезно предоставленные вопрошающим.

$ hygen database setup --host localhost
? Select database (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◯ Postgres
 ◉ sqlite
 ◯ MySQL

hygen не навязывает вам новый язык программирования, настройку проекта или рабочий процесс. Поскольку он находится в вашем проекте и в вашем существующем рабочем процессе и настройке, он просто наследует их.

Закон Паркинсона

Давайте на минутку возьмем закон Паркинсона. Это проблема для всех известных мне фреймворков генераторов.

Работа расширяется, чтобы заполнить все время, доступное для ее завершения.

Когда вы настроили генерацию кода как отдельный проект в репо или вне его (скажем, с cookiecutter или yeoman), это станет вещью. Блестящая новая игрушка.

В лучшем случае это становится продуктом, за которым вы ухаживаете, который вырывает вас из контекста каждый раз, когда вы хотите настроить шаблон. В худшем случае он становится устаревшим и не обслуживается - работа вложена, а ценность так и не извлечена.

Rails сделали это первыми

Генераторы для оптовых проектов по-прежнему хороши, когда вам нужен целый стартовый проект, хотя я сомневаюсь, что они выживут, учитывая всплеск начальных проектов, для которых вы можете просто git clone и двигаться дальше.

Они также менее хороши, если вы хотите встроить рабочий процесс генератора в свой существующий проект, как это сделали Rails, когда положили начало идее о том, чтобы генераторы были основной частью продуктивности разработчиков, в массовое внедрение для первый раз.

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 и Thor, фреймворк генераторов, который он использовал, изменили моё представление о генераторах кода. До тех пор, когда мне нужно было сгенерировать код (в основном для сущностей ORM, ах, когда у нас были!), Я был поглощен текстовыми шаблонами .NET T4.

Это было 7 лет назад. Я продолжал делать генераторы с Тором и друзьями, надеясь на скачок производительности. Но это стали проекты, которые я поддерживал, которые, как ни странно, отнимали драгоценное время - они снижали отдачу от общей производительности.

Список покупок

Это означает только одно. Список покупок для фреймворка генератора, который не мешает вам.

  • Эргономичность процесса - я не хочу компилировать свои генераторы или размещать их на собственном конвейере CI.
  • Эргономика разработчика - легкий доступ и легкий вызов.
  • Низкое трение - ловушка успеха. Каждый шаг, который я делаю, должен вести меня к следующему.
  • Независимый от технологий - не хочу новый стек технологий.
  • Контекстный - если я нахожусь на уровне данных, мне нужны генераторы данных.
  • Масштабируемость - должна работать для нескольких команд, выполняющих итерацию над большой и модульной кодовой базой.
  • Многофункциональность - простой дизайн не означает недостаток функций.
  • Гибкость - дайте мне возможность прострелить ногу, если я захочу.
  • Встраиваемый - можно встраивать в другие проекты.
  • Супер настраиваемый - настройки по умолчанию в порядке, но дайте мне аварийные люки.
  • Чисто, целеустремленно - сначала будь полезным, только потом будь крутым.

Вот что стало hygen.

Hygen

Вы можете использовать его прямо сейчас, в любом открытом проекте. Вот как создать генератор, который добавляет документ с уценкой в ​​вашу docs/ папку.

$ npm i -g hygen
$ cd your-project
$ hygen init self
$ hygen generator new --name docs

Изменить _templates/docs/new/hello.ejs.t:

---
to: docs/<%= name %>.md
---

Hi!
I'm a document about <%= name %>

А потом переименовать. Имя файла не имеет значения, оно предназначено для вас, для целей бухгалтерского учета.

$ mv _templates/docs/new/{hello,new-doc}.ejs.t

Вот и все! Сделаем документ:

$ hygen docs new --name architecture

Loaded templates: _templates
       added: docs/architecture.md

А теперь давайте проверим наш новый генератор:

❯ gs
A  _templates/docs/new/new-doc.ejs.t
A  _templates/generator/new/hello.ejs.t
A  _templates/generator/with-prompt/hello.ejs.t
A  _templates/generator/with-prompt/prompt.ejs.t

_templates - это контекстная папка. hygen ищет его в папке, из которой он запущен. Таким образом, у вас могут быть разные варианты одного и того же генератора из разных частей вашего проекта, или, может быть, в сценарии монорепо разные команды имеют свои собственные наборы генераторов в зависимости от того, где в монорепо работает команда.

Обратите внимание, что команда hygen generator new также отмечена (части generator/new и generator/with-prompt). Это часть принципа «гибкости».

Мы понимаем, что, возможно, вам не нравится стандартный hygen генератор для новых генераторов. Идите и измените это; затем отметьте его и попросите свою команду просмотреть его. После этого изменения все новые генераторы, которые вы создаете, будут включать ваш новый способ их создания.

Мощность генератора

hygen позволяет создавать генераторы, которые добавляют несколько файлов, делают инъекции в существующие файлы, имеют подсказки для взаимодействия с пользователем и многое другое.

Вот как избавиться от усталости от шаблонов Redux.

Сейчас я выбираю уток, чтобы убрать немного шаблонов и запечь модульность в любом приложении, которое я создаю.

Моя типичная архитектура Redux будет выглядеть так:

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

Добавление модуля

Добавить новый модуль очень просто с hygen. Вот как выглядят ваши шаблоны:

_templates/
  module/
    new/
      index.ejs.t
      view.ejs.t
      state.ejs.t
      inject_boot.ejs.t   <--- adds a 'require' clause to boot.js

Вот как выглядит index:

---
to: app/modules/<%= name %>/index.js
---
//
// requires, mappings, etc....
//
export default connect(...)(<%= Name %>)

Аналогичный трюк применим для view и state.

Как бы мы добавили строку require, учитывая, что boot.js выглядит так?

// ... 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 ...

Построим inject_boot:

---
to: app/modules/boot.js
inject: true
skip_if: <%= name %>
after: "const modules = ["
---
require('./<%= name %>).default,

Готово! Создание нового модуля говорит следующее:

$ hygen module new --name settings

Используйте Hygen сегодня

hygen предназначен не только для Redux, документации или других вариантов использования, которые мы приводим в документации. Это для всего, потому что почти ничего не навязывает.

Больше информации можно увидеть на сайте hygen.io, где находится документация. Но если вам нужно более мягкое вступление, в README также есть дайджест-форма и hygen, построенная с нулевой конфигурацией и без привязки к строкам, так что это не повредит.

Так что, если вам нравится сначала что-то пробовать, просто установите его, сделайте несколько генераторов и посмотрите, подходит ли он вам.