2 of October - MS Stage Free Online conference: .NET, MS SQL, MS Azure, Cosmos DB. REGISTER
×Закрыть

Node.js как индивидуальный помощник Front-end-разработчика

Привет, меня зовут Александр и я Frontend-разработчик в компании SPD-Ukraine с пятилетним стажем. Иногда в нашей работе мы сталкиваемся с монотонными задачами, но от них никуда не деться. В некоторых случаях таких задач встречается достаточно много, и их просто приходится делать, скрипя зубами. Если у вас в блокноте есть список «step-by-step» документации и таких списков уже накопилось немало, то вполне возможно эта статья заставит вас пересмотреть необходимость создания таких списков.

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

Предыстория

Проект, над которым я сейчас работаю, это совокупность взаимосвязанных между собой сайтов и приложений. Их frontend написан на разных фреймворках, в некоторых случаях — на чистом JS, а backend построен на микросервисах.

Проект имеет довольно солидный возраст, и его кодовая база уже насчитывает более 100+ репозиториев и тысячи страниц документации. Каждый репозиторий по-своему уникален, со своими особенностями запуска, настройки, флова при локальной разработке и деплое и т.д.

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

Проблема

Те задачи, с которыми мне довелось столкнуться в первые месяцы работы, предполагали частый запуск/перезапуск проектов. Чтобы проверить определенный функционал, мне приходилось постоянно менять настройки в config файлах и запускать от трех до шести серверов, в зависимости от того, над чем я конкретно работал. При запуске каждого проекта я постоянно подглядывал в readme его репозитория, а также искал отдельные wiki страницы со списком проблем и рекомендаций. Держать все в голове было просто невозможно.

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

Сложно даже описать боль, которую испытываешь, когда в очередной раз пытаясь запуститься, у тебя что-то не работает. И после 1-2 часов отчаянных попыток найти баг в последних коммитах, общениях в чатах с описанием проблемы и поисков решения в документации проекта, ты находишь неправильную настройку в заигнореном гитом setting локальном файле. По сути я тратил до 30 % своего времени на запуск/перезапуск серверов каждый день.

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

Решение

Как я уже говорил, я Frontend-разработчик и мне редко приходится писать код, который бы работал вне браузера. Здесь я понимал, что мне нужен скрипт, который бы работал с файловой системой моего ПК, а также имел доступ к терминалу. Конечно же моим выбором стал Node.js так как не нужно дополнительно изучить синтаксис.

Вот небольшой пример одной из инструкций, которые у меня были вынесены в блокнот:

  1. Зайти в папку «foo/bar/config» репозитория «server-repo».
  2. Изменить переменную «PRODUCT_NAME» в config файле.
  3. В табе #1 терминала запустить серверную часть приложения «server-repo» репозитория.
  4. Открыть таб#2 терминала и зайти в папку «client-js-repo» репозитория откуда запускается npm команда.
  5. Запустить билд «npm run build:dev-watch» для JS части приложения.
  6. Открыть таб #3 терминала и зайти в папку «assets-repo».
  7. Запустить компиляцию sass файлов для определенного продукта: npm run serve-and-watch -- —env.product=${product_name} —env.app=commerce

И т.д.... Всего таких шагов я насчитал от 5 до 12 в зависимости от проекта и задачи.

Идея была проста — мне нужен был помощник, которому бы я делегировал выполнение инструкций и шагов и не держал всю информацию в голове и заметках. По сути все, что я хотел сделать — это создать интерактивный интерфейс, которому я мог бы давать задания на понятном языке. Он бы послушно запускал одну из инструкций в зависимости от того, что я ему скажу. Что-то типа — запусти проект «Foo» c продуктом «Bar». И все. Я не хотел запоминать, что для этого необходимо открыть репозиторий «A», в нем зайти в папку «foo/bar/settings/» и там найти файл «my_settings.py». В этом файле изменить переменную «PRODUCT_ID», потом открыть другой репозиторий, зайти в папку... и т.д, я думаю, вы понимаете, о чем я.

Проект я назвал «Alfred» и приступил к написанию кода...

Хочу заметить, что у меня нет коммерческого опыта работы с Node.js. Если вы знаете JavaScript на среднем уровне и посмотрели официальную документацию для Node.js и пару обучающих видео с Ютуба, вам вполне этого хватит для того, чтобы начать успешно реализовывать несложные задачи, которые будут экономить вам время, а самое главное развиваться даже там, где казалось бы рутинная работа неизбежна.

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

Итак, папка «Alfred», в ней файлы «cli.js», «package.json» и папка «modules».

Для того чтобы запускать наш инструмент непосредственно из терминала, в package.json добавляем:

"bin": {
    "alfred": "./cli.js"
  }

Также, неплохо бы при установке пакетов установить модуль «ttab» глобально, так как он дает возможность управлять вкладками терминала:

"scripts": {
    "preinstall": "npm install ttab@0.6.1 -g",
  }

В «cli.js» с помощью npm модуля «inquirer.js» я реализовал взаимодействие с Альфредом.

#!/usr/bin/env node
const chalk = require("chalk");
const inquirer = require("inquirer");
const User = process.env.USER;

// Modules
const runServer = require('./modules/servers');
const deployMessages = require('./modules/other/deploy_messages');
const onboardingModule = require('./modules/onboarding');
const showDocs = require('./modules/documentation');
const variablesUsage = require('./modules/variables_usage');
const systemCheck = require('./modules/system_check');
const newtFlowHelpers = require('./modules/newt_flow');

const modulesMap = new Map([
        ['Servers', runServer],
        ['Onboarding', onboardingModule],
        ['Messages deployment', deployMessages],
        ['Available variables and strings', variablesUsage],
        ['System check', systemCheck],
        ['NEWT flow helpers', newtFlowHelpers],
        ['Documentation', showDocs],
        ['Exit', async () => 'Exit'],
    ]
);

const run = async () => {
    const questions = [
        {
            name: 'helper',
            type: 'list',
            message: chalk.green(`Hi ${User}, how can I help you?`),
            choices: Array.from(modulesMap.keys())
        }
    ];
    let answers = await inquirer.prompt(questions);
    return modulesMap.get(answers['helper'])().then(data => data ? console.log(chalk.yellow(data)) : '');
};
run();

Для того чтобы я мог выполнять команды с помощью node.js прямиком из терминала, я использовал пакет «shelljs» в своих модулях. Все функции и сценарии я хранил в папке «modules». На этом все — максимально просто.

Запускаем терминал, пишем «alfred», говорим, что нужно сделать, помощник выполняет.

Теперь запуск проекта проходил довольно просто — я запускал Альфреда, и у нас с ним происходил диалог:

Что тебе надо?
Запусти-ка мне проект.
Какой?
«Foo»
А какой продукт?
«Bar»
Ок

После этого диалога Альфред все делал за меня. Он находил нужные файлы с настройками, менял в них значение переменных, открывал отдельное окно терминала и в разных табах запускал сервера...одна операция, которая раньше занимала у меня 5–6 минут, теперь требовала секунд 10 моего времени.

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

Я пытался автоматизировать практически все, что мог в моем рабочем процессе. Следующее, за что я взялся, научил Альфреда копировать файлы и менять в них содержание. Это было очень полезно при создании новых продуктов, где 50% работы заключалась в том, чтобы скопировать файлы и пройтись по ним, меняя название продуктов, картинки и прочее.

Кое-где приходилось оптимизировать изображения и даже выполнять скрипты на Python, написанные другими разработчиками ранее, передавая в них данные из CLI — в этом случае я создавал некую «обертку» вокруг той работы, которая была сделана до меня. Никто ведь не запрещает мне написать код, который будет принимать значение из CLI, выполнять несколько функций на JS, а потом результат этих функций передавать как параметр для Python скрипта через терминал.

Ниже приведен пример модуля который просто выполняет скрипты пайтона для создания (онбординга) новых продуктов, но ввод аргументов, необходимый для выполнения скрипта, реализован через CLI на node.js. Здесь мы просто использовали написанный ранее код на Python, но теперь нам не надо запоминать в какую директорию заходить чтобы его выполнить, как называются нужные нам скрипты, какие аргументы они принимают и т.д. Все что нужно указать — это ID и имя продукта, которые у нас спросит Альфред.

const shell = require('shelljs');
const inquirer = require("inquirer");
const chalk = require("chalk");
const config = require("../../config/");

module.exports = async () => {
    let questions = [
        {
            name: 'id',
            type: 'input',
            message: chalk.green('Please type brand ID')
        },
        {
            name: 'name',
            type: 'input',
            message: chalk.green('Please type brand name')
        }
    ];

    let answers = await inquirer.prompt(questions);

    shell.exec(`
        cd ${config.SHARED_MEDIA_DIR} && 
        python onboard_brand.py ${answers['id']} -n "${answers['name']}" -i ${config.ONB_IMAGES_DIR}/${answers['id']} &&
        python migrate_brand_style.py ${answers['id']}
    `);
};

Руководствовался я простым подходом — документация, которая описывала процесс выполнения определенной задачи или флова, как в случае запуска серверов или онбордингa(создания) новых продуктов, просто была переписана в JavaScript код. Теперь, чтобы ее выполнить, было достаточно попросить Альфреда сделать это вместо тебя.

Так же очень полезным оказался скрипт, который выполнял простой мониторинг системы. Его основой функционал заключался в том, чтобы заходить в папки, выполнять команды из терминала и сохранять его вывод. После выполнения проверок создавался html-документ с таблицей, которую можно было открыть в браузере и посмотреть результат проверки.

Конечно же Альфред никак не заменял такие инструменты как Webpack, Gulp или Grunt так как решал совершенно другие задачи. Он не являлся частью кодовой базы ни одного из проектов, а вместо этого был именно «помощником» который выполнял задания через CLI.

Выводы

Хотелось бы отметил несколько пунктов:

  • С помощью node.js практически любой сценарий при работе с файловой системой ПК может быть реализован и задокументирован в коде, что позволяет значительно увеличить скорость разработки.
  • Одной из особенностей, с которыми придется столкнуться Frontend-разработчику при написании кода на node.js — это постоянная работа с асинхронным кодом, написание которого сложнее в понимании и отладке, чем работа с синхронным. Конечно же во фронтенд разработке мы так же сталкивается с асинхронностью, но в большинстве случаях это происходит при обработке AJAX запросов или работе с браузерными событиями.
  • Не стоит ограничивать свое воображение — если возникает чувство, что какую-то часть работы можно автоматизировать или улучшить, но как это сделать нет ни малейшего понятия, главное начать писать код шаг за шагом, решая проблемы, которые возникают.
  • Не нужно стремится к совершенству при написании инструмента, если он понадобится только вам.
  • Node.js — это все тот же JavaScript работающий в другом окружении. Если вы уже успешно пишите код на JS для браузера, разобраться с тем как начать писать серверный JavaScript у вас не составит особого труда.

Основной посыл этой статьи в том, что если вы являетесь Frontend-разработчиком в 2020, хочется вам этого или нет, но рано или поздно вам придется познакомиться с Node.js. В моем случае, это близкое знакомство состоялось в тот момент, когда я понял, что мне придется автоматизировать свой рабочий процесс, если я хочу спокойно работать с кодом, а не тратить кучу времени на всякую ерунду.

LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Лайк. Я недавно писав консольну утиліту, і зрозумів одну річ — не треба ніякого пітону, аби писати консольні утиліти! І це круто, бо набагато легше тримати в голові один фреймворк з одними апі, аніж переключатися на спеціалізовані мови(хоча які тепер спеціалізовані) з їхніми фреймворками у яких своє АПІ. Крос-платформенні фреймворки це няшки. В моєму випадку то був .net core.

Напевно якби я писав якусь консольну лібу, то краще б було обрати пітон, бо ж він є у багатьох лінукс дистрибутивах, але коли це бізнес додаток, то нічого складного декількома командами поставити потрібний рантайм.

Ну і висновок зі статті — все ж T-shaped краще за I-shaped.

Основной посыл этой статьи в том, что если вы являетесь Frontend-разработчиком в 2020, хочется вам этого или нет, но рано или поздно вам придется познакомиться с Node.js.

Не всегда это нужно. Я пишу фронт-енд, но для бекенда использую Java

Подписаться на комментарии