Что должен знать фронтендер
Что именно должен знать человек, когда в вакансии написано «знание JavaScript»? Уметь написать функцию, объяснить замыкание, найти утечку памяти? Формулировка одна, а работу за ней можно представить очень разную. С React, CSS и почти любым другим пунктом происходит то же самое.
В феврале 2024 года мы с Андреем Мелиховым попробовали составить карту технических навыков фронтенд-разработчика. Распределяли их между джуном, мидлом и сеньором, спорили, возвращали пункты обратно. Андрей опирался прежде всего на свой опыт в крупных компаниях, я — в том числе на работу с начинающими разработчиками в HTML Academy. Уже на уровне джуна в чате начали спрашивать, не слишком ли много мы требуем. Но размер списка мало что говорит, пока мы не договорились, насколько глубоко нужно знать каждый предмет.
Самостоятельность раньше названия грейда
Я предложил начать с того, как человек работает с задачей. Джуну ещё нужна помощь: разложить работу на части, разобраться в затруднении, проверить выбранный путь. Мидл может выполнить задачу самостоятельно. Сеньор способен объяснить решение другому и помочь ему разобраться; Андрей добавил сюда умение учить.
У этой схемы сразу есть ограничения. В небольшой компании один разработчик может отвечать за весь сайт, а в большой — годами заниматься определённой частью приложения. Требования к широте знаний и глубине в этих случаях будут разными. Даже внутри одной компании грейд обычно включает общение, ответственность и другие вещи, которых нет в перечне технологий. Мы сознательно оставили их за пределами этой карты, чтобы хотя бы техническую часть успеть разобрать.
И всё же разделение по самостоятельности помогает задавать вопросы точнее. Например, человек умеет пользоваться готовой сборкой. Сможет ли он изменить её под новую задачу? А разобраться, почему после обновления зависимостей перестал собираться проект? Во всех случаях речь идёт о сборке, но ожидания уже различаются.
Что входит в базу
Мы начали с HTML и CSS. Семантика, формы, встроенная проверка полей, базовая доступность — всё это относится к работе с разметкой с самого начала. Я добавил метаданные и микроразметку: страница существует в том числе для поисковиков и других программ, которые будут её читать.
В CSS мало знать, как записывается свойство. Нужны каскад, наследование и специфичность, иначе каждый конфликт стилей превращается в перебор вариантов. Нужны способы строить раскладку и понимание того, как организовать стили компонентов. Мы обсуждали БЭМ, атомарные классы, препроцессоры: разработчик может предпочитать один подход, но в чужом проекте встретить другой. Незнакомый подход ещё не делает проект неправильным.
На адаптивности мы разошлись. Я считал, что она нужна уже джуну; Андрей сначала предложил оставить её мидлу. Когда вернулись к этому вопросу, стало понятнее, что мы подразумевали разную работу. Написать медиавыражение и применить заданные правила начинающий разработчик должен уметь. Самостоятельно решить, как перестроится сложный интерфейс на разных экранах, — другое ожидание.
С JavaScript получился похожий разговор. Типы и приведение типов, функции, области видимости, замыкания, this, классы и прототипы нужны уже в начале. При этом от джуна мы не ждём знания всех внутренних механизмов движка. Он должен понимать код, с которым работает, и предвидеть его поведение. Если отправил запрос, результат не окажется в следующей строке сам собой: асинхронность нужна задолго до сложных приложений.
Отдельно мы вынесли браузер. Язык JavaScript и возможности среды, в которой он выполняется, часто смешивают. Работать с DOM, подписываться на события, отправлять запросы, хранить данные в браузере — повседневные задачи фронтендера, но одними знаниями синтаксиса они не покрываются. Сюда же относится представление о сети: что происходит, когда страница запрашивает данные, и где искать причину неудачного запроса.
Андрей добавил общие основы программирования: структуры данных, алгоритмы, оценку сложности. Я уточнил, что именно он ждёт от джуна. За словом «алгоритмы» часто представляют сложные задачи с собеседований, но речь начиналась со способности разложить задачу на последовательность действий. Какие данные есть, что должно получиться, что для этого нужно сделать? К этому я добавил читаемость кода: понятные названия нужны и в JavaScript, и в CSS, потому что с результатом будет работать кто-то ещё.
Андрей заметил, что начинающий разработчик постепенно осваивает перечисленное. Мы описывали подготовленного джуна, которому уже есть на что опереться. Одинаковой уверенности в каждой теме при выходе на первую работу от него не ждали.
Проверить то, что написал
Когда мы дошли до тестирования, Андрей спросил, что именно я хочу включить: написание модульных тестов? Я уточнил: речь пока о проверке собственной работы и способности разобраться, при каких условиях появляется ошибка. Для Андрея поиск и изоляция проблемы относились скорее к навыкам программирования. Мне было важнее, чтобы само это умение не потерялось.
Я замечал, что начинающие разработчики видят, как страница работает неправильно, но не знают, с какой стороны подойти. Можно убрать часть кода, оставить минимальный пример, посмотреть, сохраняется ли проблема. Можно проверить другой браузер и выяснить, связана ли ошибка с конкретным окружением. Так постепенно становится понятно, какая часть кода не работает и при каких условиях.
В чате возразили: если человек уже самостоятельно находит ошибки, это скорее мидл. Я с этим не согласился. От начинающего разработчика можно ожидать проверки собственной работы, даже если исправить сложную ошибку ему поможет кто-то ещё. Андрей поддержал сам принцип: отправлять задачу дальше, не попробовав то, что получилось, означает перекладывать свою работу на других.
Инструменты разработчика в браузере нужны для этого с первых задач. Посмотреть элемент и его стили, прочитать ошибку, поставить точку остановки, найти исходный код через карты кода. Глубокое исследование производительности можно осваивать позже, но консоль не должна оставаться местом, где появляются непонятные красные сообщения.
Один фреймворк и работающий проект
В 2024 году мы уже включали в начальную карту базовый TypeScript и один из распространённых фреймворков. Для TypeScript на этом уровне достаточно пользоваться типами и понимать сообщения инструмента. Самостоятельно строить сложные типы и разбираться в хитрых обобщениях — следующая ступень.
С фреймворком важен контекст компании. На вопрос, зачем вообще делать небольшой сайт на React, Андрей привёл пример общей библиотеки компонентов: компания уже вложилась в неё и использует в разных продуктах. Размер отдельной страницы тогда не объясняет весь выбор.
Я бы не превращал вопрос о первом фреймворке в борьбу за единственно правильный ответ. Начинающему разработчику нужно освоить один из них достаточно, чтобы выполнять задачи. Дальше он попадёт в проект со своими договорённостями и ограничениями. Базовые навыки всё равно понадобятся, какую бы библиотеку ни выбрала команда.
То же относится к инструментам вокруг приложения. Можно пользоваться npm, Yarn или pnpm, но прежде всего нужно понимать, откуда берутся зависимости и как они устанавливаются. Джун работает с готовой конфигурацией сборки, знает, что у неё есть исходные файлы и результат, умеет запустить проект. От него пока не требуется самостоятельно выбрать и настроить весь набор инструментов.
Мы отдельно обсудили библиотеки интерфейсов. Андрей не стал бы требовать знания конкретной библиотеки заранее. Гораздо полезнее способность прочитать её документацию и освоить те компоненты, которые уже использует команда.
Мидл разбирается в устройстве решения
На уровне мидла многие пункты карты повторяются, но меняется работа, которую человек способен выполнить сам. В JavaScript он увереннее обращается с замыканиями и асинхронностью, понимает прототипы, может разобраться в неожиданном поведении программы. В TypeScript уже описывает собственные структуры данных и использует обобщения там, где они нужны.
Я предложил добавить объектно-ориентированное и функциональное программирование. Чистые функции, функции высшего порядка, работа с неизменяемыми данными помогают организовать код. Андрей напомнил об обратной стороне: можно так увлечься выразительными конструкциями и библиотеками, что программу будет понимать один автор. Знакомство с подходом должно помогать команде читать и менять код, иначе польза сомнительна.
Во фреймворке уже недостаточно воспроизводить примеры из начальной документации. Нужно понимать, как он устроен, какие способы работы приняты в используемой версии, как с ним связаны маршрутизация и управление состоянием. И замечать, когда привычный способ устарел.
При этом Андрей предостерёг от превращения в «React-программиста», который за пределами React теряется. Я поддерживаю готовность разобраться в другом инструменте, когда этого требует работа. Но желание попробовать новый фреймворк ещё не даёт причины переписывать на нём действующий проект. Умение сменить инструмент и стремление менять его при любой возможности — разные вещи.
В этой части карты появились серверный рендеринг и статическая генерация. От мидла мы ожидали, что он сможет настроить их в своём проекте. Самостоятельно проектировать для этого всю инфраструктуру — уже более широкая задача. В разговоре мы несколько раз возвращались к этой границе: пользоваться возможностью, понимать её ограничения и спроектировать собственную реализацию нельзя считать одним навыком.
Почему страница работает медленно
С изображениями различие между уровнями хорошо видно. Начинающий разработчик должен выбрать подходящий формат и не отправить пользователю неоправданно тяжёлый файл. От мидла я ожидаю более внимательной работы: оценить размеры и качество, подготовить варианты для разных условий, разобраться в возможностях браузера. Приходится выбирать, где сохранить качество картинки, а где уменьшить файл, чтобы страница загружалась быстрее.
Так же растёт работа с доступностью. За семантической разметкой идут управление фокусом, проверка с клавиатуры, контраст, понимание того, как интерфейс читается вспомогательными технологиями. Одной привычки использовать правильные теги на все случаи не хватит.
Я настаивал, что мидл должен уметь исследовать производительность приложения. Если интерфейс тормозит или постепенно расходует всё больше памяти, нельзя каждый раз ждать, пока придёт старший разработчик и найдёт причину. Нужны профилирование, анализ памяти, понимание того, что именно измеряется. Скорость загрузки тоже связана с устройством приложения: какие ресурсы оно запрашивает, что мешает отрисовке, сколько кода приходится передать браузеру.
Здесь пригодится умение разбирать сборку. Обновить зависимость, понять конфликт версий, выяснить, почему вырос итоговый файл. Мы обсуждали, кому должна принадлежать настройка сборщика целиком. Андрей проводил границу выше: изменение рабочего проекта по силам мидлу, а выбор и устройство сложной сборки могут потребовать сеньора. Мидл уже должен понимать, что собирается и ради чего.
Знать о возможности до появления задачи
На браузерных API у нас снова возникло расхождение. Андрей предложил изучать некоторые из них по необходимости: за годы работы конкретная возможность может ни разу не понадобиться. В пример он приводил WebSocket.
Я согласен, что заранее освоить всё невозможно. Но разработчик должен хотя бы знать, что браузер умеет. Если он никогда не слышал о воркерах или доступных способах хранения данных, ему будет трудно увидеть задачу, для которой они подходят. Между «работал с этим в продакшене» и «вообще не знаю о существовании» есть полезный уровень знакомства.
Мы не смогли превратить это в строгую границу грейда. И вряд ли стоило. В одном продукте человек глубоко изучит обмен сообщениями, в другом — графику или работу без сети. Требовать одинаковой практики во всех направлениях означало бы подменить опыт работы перечнем просмотренных примеров.
С jQuery вопрос решился короче. Знание этой библиотеки мы не стали делать обязательным для всех. Если она используется в проекте, разработчик разберётся в её документации. Заранее изучать её только потому, что старых проектов ещё много, мы не предлагали.
Тесты и безопасность в ежедневной работе
Когда в приложении одновременно работают несколько человек, ручной проверки становится недостаточно. Мы добавили модульные и интеграционные тесты, проверку пользовательских сценариев, сравнение скриншотов. Андрей связывал необходимость автоматизации со своим опытом больших команд: изменения постоянно пересекаются, и без проверок всё труднее понимать, что сломалось.
Я добавил проверки производительности в процесс сборки. Недостаточно получить отчёт Lighthouse и оставить его лежать. Команда должна понять, какие изменения ухудшили результат и что с этим делать. Иначе измерение не влияет на работу.
С безопасностью мы затянули. Я поднимал её ещё при обсуждении джуна, затем мы вернулись к ней на уровне мидла. HTTPS, межсайтовые запросы, XSS, настройки кук и политика безопасности содержимого влияют на код интерфейса, даже если в компании есть отдельные специалисты по безопасности.
Например, разработчик добавляет в форму токен. Он должен понимать, от чего тот защищает и что произойдёт, если его убрать. Или пытается встроить страницу во фрейм и сталкивается с запретом политики безопасности: нужно найти причину, а не перебирать изменения наугад. У кук тоже есть ограничения и флаги с определённым назначением. Знание способа записать значение не объясняет, где и кому это значение будет доступно.
Протокол OAuth мы переносили между уровнями. В обычной задаче разработчик может подключать готовое решение, а при сложной авторизации приходится разбираться во всей последовательности переходов и обмена данными. Для этих задач нужен разный уровень знакомства с протоколом.
Сеньор справляется с незнакомой задачей
Чем дальше мы продвигались, тем труднее было продолжать список технологий. Можно добавить WebAssembly, устройство движка JavaScript, сложные операции с историей Git. Но из этого ещё не получается описание сеньора. Многие специалисты годами не используют часть этих возможностей и при этом решают очень сложные задачи в своей области.
Я предложил другой ориентир: сеньор способен разобраться с незнакомой задачей в вебе. Даже если раньше не работал с нужным инструментом или не сталкивался с такими ограничениями. Всего веба он заранее не знает, но может исследовать предмет и найти решение.
В пример я привёл вёрстку писем. У неё своя специфика, и опыт разработки обычных веб-интерфейсов не заменяет знакомства с ней. Но опытный разработчик должен суметь выяснить ограничения и организовать работу. Андрей привёл другой масштаб задач: устройство сложных продуктов вроде Figma требует решений, которые не возьмёшь из привычного набора приёмов для очередного сайта.
В компании эти ожидания могут относиться к разным должностям. Где-то над сеньором есть ещё несколько технических уровней, а где-то именно он остаётся человеком, к которому приходят со всем непонятным. Я бы учитывал это прежде, чем сравнивать названия в резюме.
Андрей добавил зависимость от проекта. Сеньор хорошо знает, почему система устроена именно так, какие ограничения у команды и где уже пробовали другой путь. При переходе в новую компанию это знание не переезжает вместе с ним. Придётся заново разбираться в чужих решениях, хотя способность разбираться никуда не исчезла.
Когда твоим решением пользуются другие
К концу разговора мы вернулись к компонентам интерфейса. Поначалу кажется, что это уже пройденная тема: мидл умеет написать компонент. Но Андрей предложил посмотреть на задачу шире. Сеньор может заметить проблему, с которой сталкиваются разные команды, и сделать решение, которым смогут пользоваться все. Такая работа не всегда приходит в виде готовой задачи.
Это проявляется и в инструментах. Почему тесты стали нестабильными? Из-за чего проверка занимает столько времени? Как обновить TypeScript в большом проекте, не остановив всю разработку? Здесь приходится видеть связи между частями системы и договариваться об изменениях, последствия которых затронут других людей.
Мы обсуждали, нужно ли отдельно записать в карту умение публиковать пакет. Я не увидел большой ценности в самой команде публикации: её можно найти в документации. Гораздо содержательнее решение, что именно стоит вынести в пакет, где провести его границы и как этим будут пользоваться другие проекты. То же с монорепозиторием: сложить код в одну папку и устроить совместную разработку нескольких приложений — разный объём работы.
В какой-то момент в карте уже оказались задачи, которые касаются бэкенда и инфраструктуры. Мы остановились на том, что использование Node.js для запуска инструментов ещё не означает готовности писать и обслуживать серверное приложение. Для него потребовался бы отдельный разговор. Наша карта и так разрослась, а начальный вопрос остался полезным для каждого её пункта: какую работу человек сможет выполнить самостоятельно и где ему понадобится помощь.