Это моя история о том, как я устраняю дублирование кода в организации, имеющей много похожих приложений. Я буду говорить о проектах внешнего интерфейса, использующих 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