Это моя история о том, как я устраняю дублирование кода в организации, имеющей много похожих приложений. Я буду говорить о проектах внешнего интерфейса, использующих NPM, но это решение можно применить к любому проекту.

Сценарий

Допустим, вы работаете в организации. У вас есть 10 команд, разрабатывающих фронтенд-приложения. Каждое приложение будет развернуто на одном веб-сайте. Они предоставляют разные функции, но имеют много общего, например цвета, тестовые среды, фиктивные объекты, общую структуру кода…

У вас есть «шаблон проекта», в котором есть все последние общие функции.

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

В качестве примера такого шаблонного проекта я буду использовать React Boilerplate.

Проблема

Я бы сказал, главная проблема здесь — обслуживание.

Приложения обычно имеют разные имена в package.json и разное содержимое в папке app.

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

Разработчики могут добавлять функции в приложения и не утруждать себя добавлением их в проект шаблона.

Решение

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

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

  • .editorconfig
  • .gitattributes
  • .travis.yml

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

  • package.json
  • .gitignore

Создать диктатора

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

dictator-react-boilerplate содержит весь код шаблона react-boilerplate. Он настраивается в рамках диктата. Диктат выглядит примерно так:

{
  "message": "Copy react-boilerplate",
  "actions": [
    {
      "beSupersetOfJsonFile": "react-boilerplate/package.json",
      "target": "package.json"
    },
    {
      "copyFrom": "react-boilerplate",
      "target": "."
    },
    {
      "haveLineContaining": ["*.tgz"],
      "target": ".gitignore"
    }
  ]
}

Что значит:

  • Пусть package.json в приложении является надмножеством package.json в диктаторе.
  • Скопируйте все файлы из папки react-boilerplate в корень.
  • Добавьте «*.tgz» в .gitignore

Используйте диктатора

Вы можете запустить диктатор как инструмент командной строки, если не используете NPM:

npx dictator-react-boilerplate

Я использую диктатор, указав его в своем package.json:

{
  "name": "react-boilerplate-example",
  "version": "1.2.3",
  "description": "asdasasd",
  "scripts": {
    "prepare": "dictator-react-boilerplate"
  },
  "devDependencies": {
    "dictator-react-boilerplate": "0.0.8"
  }
}

Это означает, что когда я запускаю npm install, диктатор будет применяться и диктовать мое приложение.

Продиктованное приложение может управлять некоторыми частями приложения. В моем случае у меня есть .dictatorconfig.json в корне приложения, содержащий:

{
  "ignore": [
    "/README.md",
    "/.github/*",
    "/.github/**/*",
    "/app",
    "/package-lock.json",
    "/Changelod.md"
  ]
}

Чтобы использовать новую версию проекта шаблона, я просто обновляю версию в своем package.json!

Вот пример использования этого диктатора:
https://github.com/tomasbjerre/dictator-react-boilerplate-example