Русский
Русский
English
Статистика
Реклама

Фронтенд-разработка

Минифицируем приватные поля в TypeScript. Доклад Яндекса

13.06.2020 14:36:10 | Автор: admin
Меня зовут Лёша Гусев, я работаю в команде разработки видеоплеера Яндекса. Если вы когда-нибудь смотрели фильмы или трансляции на сервисах Яндекса, то использовали именно наш плеер.

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


Конспект и видео будут полезны разработчикам, которые ищут дополнительные способы оптимизации своего кода и хотят узнать, как webpack, Babel и TypeScript могут в этом помочь. В конце будут ссылки на GitHub и npm.

С точки зрения структуры наш видеоплеер довольно типичный фронтенд-проект. Мы используем webpack для сборки, Babel для транспиляции кода, скин нашего плеера мы пишем на React, весь код написан на TypeScript.

Мы также активно используем опенсорсные библиотеки, чтобы реализовывать адаптивный видеостриминг. Одна из таких библиотека shaka-player, которая разрабатывается в Google, и нужна она для того, чтобы поддерживать в вебе адаптивный формат MPEG-DASH.

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



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



Кто-то, может быть, использовал плагин webpack-closure-compiler. Здесь на слайде сравнение webpack-closure-compiler с другими инструментами минификации webpack, и, как видно, closure-compiler по этому сравнению лидирует.



Почему он такой классный? Дело в том, что в closure-compiler есть так называемый advanced-уровень оптимизации. На этой страничке он кроется за переключалкой в radio button.

Что из себя представляют advanced-оптимизации и почему они такие классные? Это некоторый набор оптимизаций, которых нет в других инструментах. Рассмотрим некоторые из них.



Closure-compiler умеет инлайнить функции. Здесь он просто заинлайнил тело функции f и удалил объявление самой функции, так как она больше нигде не используется.



Он умеет удалять неиспользуемый код. Здесь объявлен класс A и класс B. По факту используется только один метод из класса A. Класс B был удален совсем. Из класса A method() был заинлайнен, и мы в итоге получили только console.log.



Closure-compiler умеет инлайнить и вычислять значения переменных на этапе сборки.



Еще он умеет минифицировать поля объектов. Здесь объявлен класс A со свойством prop, и после обработки closure-compiler свойство prop заменилось на короткий идентификатор a, за счет чего код стал меньше весить.

Это не все оптимизации. В статье можно подробно почитать, что еще может closure-compiler. Там довольно много чего крутого.

Когда я про это узнал, мне очень понравилось. Я захотел притащить все эти оптимизации к нам в проект. Что мне особенно понравилось, так это минификация полей объектов, а именно минификация приватных полей для TypeScript.



Если вы никогда не писали на TypeScript, то что такое приватные поля? Это такой синтаксический сахар, который просто удаляется при сборке, при компиляции TS-кода в JavaScript. Но если вы используете приватное поле за пределами класса, вы получите ошибку компиляции.

Почему мне понравилась идея минифицировать приватные поля?



У нас в проекте довольно много React-компонентов, написанных в ООП-стиле с классом. И есть TypeScript-код, в котором используются классы и приватные поля.

Давайте рассмотрим вот такой компонент. В нем есть приватное поле clickCount.



Сейчас при сборке и компиляции кода TypeScript оставляет название этого поля как есть, просто удаляет модификатор private. Было бы клево, если бы clickCount заменился на короткий идентификатор A.

Чтобы достичь этого, давайте попробуем использовать Closure Compiler в advanced-режиме как минификатор.

И тут можно столкнуться с проблемами. Давайте рассмотрим пример. Объявлен объект с полем foobar. Обратимся к этому полю. Здесь все хорошо. Closure Compiler отработает такой код корректно. Поле foobar будет переименовано.


Ссылка со слайда

Но если мы вдруг зачем-то будем обращаться к этому полю через строковой литерал, то после сборки получим no reference, ошибку в коде. Она связанна с тем, что в поле идентификатор foobar Closure Compiler переименует, а строковые литералы оставит как есть.


Ссылка со слайда

Следующий пример. Здесь мы объявляем метод у объекта, который внутри использует ключевое слово this. После сборки с помощью Closure Compiler и удаления мертвого кода, как видно на слайде, идентификатор this станет глобальным. Вы опять же получите ошибку в коде.

Примеры немножко утрированные, надеюсь, такие конструкции у себя в проектах вы не применяете. Тем не менее, есть более сложные случаи, когда advanced-оптимизации могут сломать ваш код. По ссылке вы можете посмотреть документацию Closure Compiler, какие ограничения он привносит на ваш код. Тем более нельзя гарантировать, что ваши внешние npm-зависимости после обработки Closure Compiler будут работать корректно.


Ссылка со слайда

Для нашего проекта это еще критичнее. Как я говорил, мы разрабатываем видеоплеер. Видеоплеер это встраиваемая библиотека. Если Closure Compiler переименует поле в нашей встраиваемой библиотеке, переименует публичный метод, то внешний код сломается и не сможет взаимодействовать с плеером.

Наверное, как-то нужно сказать Closure Compiler о том, что какие-то поля можно минифицировать, какие-то нельзя, какие-то, очевидно, публичные, какие-то приватные.

Но выходит, что advanced-оптимизации в общем случае не безопасны. Их можно сделать безопасными, если вы используете Closure Compiler на полную мощность.



Я немножко слукавил. Closure Compiler не просто минификатор, а целый комбайн. Он заменяет собой webpack, Babel и TypeScript. За счет чего и как ему это удается?


Ссылка со слайда

В Closure Compiler есть своя модульная система goog.provide, goog.require.


Ссылка со слайда

Есть своя транспиляция и вставка полифиллов для различных таргетов, для разных версий ECMASCRIPT.


Ссылка со слайда

Еще там есть свои аннотации типов. Только описываются они не как в TypeScript, а в JSDoc. Точно так же там можно пометить, например, модификаторы доступа public, private и подобные.



Если сравнивать микросистему webpack-Babel-TypeScript с Closure Compiler, то, на мой вкус, Closure Compiler проигрывает. У него чуть хуже документация, им умеют пользоваться меньше разработчиков. В целом не самый удобный инструмент.

Но я все-таки хочу оптимизации. Может, можно как-то взять Closure Compiler, взять TypeScript и объединить их?



Такое решение есть. Называется оно tsickle.


Ссылка со слайда

Это проект, который разрабатывается в Angular и занимается тем, что компилирует TypeScript-код в JS-код с аннотациями Closure Compiler.


Ссылка со слайда

Есть даже webpack loader, tsickle-loader называется, который внутри использует tsickle и заменяет собой tsickle loader. То есть он подгружает TypeScript-код в webpack и эмитит JavaScript с аннотациями. После чего можно запустить Closure Compiler как минификатор.



Проблема в том, что в README tsickle явно написано, что работа над проектом в процессе, и Google внутри его использует, но снаружи большого опыта использования этого проекта нет. И завязываться на отдельный компилятор от TypeScript не очень-то и хочется, потому что тогда вы будете отставать по фичам от TypeScript и не получать какие-то новые возможности.

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



Какие еще есть варианты? В TypeScript есть issue про предложение о минификации. Там идет обсуждение похожей реализации на Closure Compiler: оптимизировать код, используя знания о типах. Проблема в том, что этот issue открыт 15 июля 2014 года, там до сих пор ничего не происходит. Вернее, там происходит 145 комментариев, но результатов пока нет. Судя по всему, команда TypeScript не считает, что компилятор TypeScript должен заниматься минификацией. Это задача других инструментов.

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



Не так давно в Babel появилась поддержка TypeScript. Существует babel/preset-ypescript, который добавляет в Babel возможность парсить TypeScript-код и эмитить JavaScript. Он делает это путем удаления всех TypeScript-модификаторов.



Мы, кстати, не так давно перешли с ts-TS loader на Babel с использованием babel/preset-typescript и этим сильно ускорили сборку. Наконец-то настроили конкатенацию модулей в webpack, сделали еще некоторые оптимизации и настроили разные сборки под ES5- и ES6-браузеры. Про это можно узнать подробнее из доклада моего коллеги.

Окей, давайте попробуем написать babel-plugin, который будет минифицировать приватные поля, раз Babel умеет работать с TypeScript.


Ссылка со слайда

Как Babel работает? На эту тему есть много хороших материалов, статей и докладов. Можно начать, например, с этого материала на Хабре. Я лишь бегло расскажу, как происходит процесс обработки кода через Babel.

Итак, Babel, как и любой транспойлер кода, сначала парсит его и строит абстрактное синтаксическое дерево, abstract syntax tree, AST. Это некоторое дерево, которое описывает код.



Давайте попробуем на коротком кусочке кода посмотреть, как строится AST. Наша маленькая программа состоит из двух выражений. Первое выражение это Variable Declaration, объявление перемены. Из чего оно состоит? Из оператора VAR на схеме это Variable Declarator. У оператора есть два операнда идентификатор A, мы создаем переменную A, и Numeric Literal, мы присваиваем им значение 3.

Второе выражение в программе это Expression Statement, просто выражение. Оно состоит из бинарного выражения, то есть операции, у которой есть два аргумента. Это выражение +, первый аргумент a, второй 5, числовой литерал. Примерно так строятся абстрактные статические деревья.



Если вы хотите подробнее в это окунуться или когда-нибудь будете писать свой плагин для Babel, вам очень сильно поможет инструмент AST Explorer. Это онлайн-приложение, куда вы можете просто скопировать ваш код и посмотреть, как строится для него абстрактное синтаксическое дерево.

Здесь есть поддержка Babel и TypeScript. Очень удобный, практически незаменимый инструмент, чтобы заниматься написанием плагинов для Babel.


Ссылка со слайда

Когда мы построили AST, мы его трансформируем. Трансформация это превращение одного AST в новое, измененное. Как происходит трансформация? Это тот самый процесс, который вы описываете с помощью настроек Babel в файлике .babelrc или где-то еще.

Вы задаете список плагинов, которые вы трансформируете в ваше AST дерево.



Что такое плагин? Это просто функция, которая имплементирует паттерн Visitor. Babel обходит AST в глубину, в том порядке, как указано на схеме на слайде. Babel вызывает функцию вашего плагина, который возвращает объект с некоторыми методами.

В зависимости от того, в каком узле мы сейчас находимся, вызывается соответствующий метод объекта, который вернул плагин. Для идентификатора вызовется Identifier, для строки вызовется StringLiteral и т. д.

Подробно об этом можно узнать из документации Babel и воспользоваться AST Explorer, чтобы понять, какие операции в коде каким узлам в AST- дереве соответствуют.


Ссылка со слайда

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

Давайте напишем плагин, который модифицирует приватные поля. Спойлер: у меня ничего не получилось. Расскажу, почему.

Как будет работать наш плагин? Давайте возьмем какой-нибудь класс, в котором есть приватное поле. Наш плагин Visitor будет заходить во все узлы AST-дерева, соответствующего классу, и в MemberExpression. Это узел, соответствующий операции доступа к полю в объекте.


Ссылка со слайда

Если объект, к которому мы обращаемся, this, то надо проверить, является ли поле приватным.


Ссылка со слайда

Для этого нужно подняться вверх по AST-дереву и найти декларацию этого поля. Тут нам повезло: она имеет модификатор private, значит, можно переименовать это поле.


Ссылка со слайда

Магия! Все работает, классно. Плагин готов.

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


Ссылка со слайда

Рассмотрим пример. Тут мы добавили в наш класс еще один метод, внутри которого обращаемся к приватному полю не this, а другого инстанса этого класса. Это валидный код, мы обращаемся к приватному полю внутри класса, здесь все ок.

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

Окей, можно написать тут костыль, который будет рассматривать все MemberExpression и искать, а в данном случае пытаться искать, поднимаясь вверх по AST-дереву, декларацию идентификатору foo. Здесь это легко, она описывается в теле функции, в заголовке функции. Можно понять, что у нее стоит тип foo, значит, это поле тоже нужно переименовать.

Звучит как какой-то костыль, будто нам не хватает информации о знании типа.


Ссылка со слайда

Рассмотрим еще один пример. Здесь мы this присваиваем переменную и обращаемся к полю bar из этой переменной. Это тоже валидный код. Но в итоге я получал такое. Здесь тоже нужен костыль, который будет разбирать такие обращения, искать, что this foo на самом деле this, что у него тип foo. И в этом случае bar нужно точно так же переименовать.

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

Я расстроился и уже было похоронил эту идею.



Но потом я вернулся в тот долгий тред про минификацию в TypeScript и увидел там комментарий Евгения Тимохова.



Он писал, что реализовал TypeScript в трансформер, который занимается минификацией приватных полей. И этот трансформер вроде бы даже работает.



У Евгения немножко другой подход. В своем трансформере он не переименовывает поля полностью, как я хотел, а добавляет к ним префикс, нижнее подчеркивание private нижнее подчеркивание.



Чтобы потом минифицировать такие поля, он предлагает использовать uglifyJS или terser, то есть uglifyJS с поддержкой ES6, и настроить минификацию полей, название которых соответствует регулярным выражениям.

Почему трансформер Евгения работает, а подход, который выбрал я, ни к чему не привел?


Ссылка со слайда

Тут нам потребуется немножко поговорить о том, как работает TypeScript. TypeScript это ведь тоже транспойлер. Он занимается тем, что берет TypeScript-код и парсит его. Но вместе с парсингом TypeScript еще запускает Type Checker. И при построении AST-дерева TypeScript обогащает его информацией о типах идентификаторов. Это как раз та самая информация, которой мне не хватало в моем Babel-плагине.

Дальше компилятор TypeScript может трансформировать AST-дерево точно так же, как Babel. Построить новое AST-дерево и эмитить из него JavaScript-код.

На этапе трансформации можно подключить кастомный трансформер. Это точно такой же плагин, точно такая же сущность, как плагин Babel, только для TypeScript. Она использует такой же паттерн Visitor и реализует примерно те же идеи.

Как это все использовать? Проблема в том, что в CLI компилятора TypeScript нет возможности подключать кастомные трансформации. Если вы хотите такое делать, вам потребуется пакет ttypescript.


Ссылка со слайда

Это не опечатка, а обертка над компилятором TypeScript, которая позволяет в настройках компилятора в tsconfig указать возможность использовать кастомную трансформацию. Здесь кастомная трансформация будет просто браться из node_modules.


Ссылка со слайда

Такая фича есть и в ts-loader. Там тоже можно задать функцию getCustomTransformers, которая позволит вам применить кастомный трансформер на этапе сборки.



Когда я решил попробовать этот подход, то столкнулся с проблемой. У нас-то в проекте используется Babel и babel/preset-typescript. Как вы помните из рассказа, мы на него переехали из ts-loader и получили кучу профита, сделали кучу оптимизаций. Откатываться обратно и терять все это мне не хотелось.

Окей, будем делать свой велосипед еще раз. Как выглядит сейчас пайплайн сборки в моем проекте? Мы подгружаем TypeScript-код в Babel loader и эмитим из него JS. Тут мне нужна сущность, которая перед Babel позволит запускать TypeScript-трансформер.

В Babel этого сделать нельзя, потому что он не запускает компилятор TypeScript. Как я говорил, он просто вырезает модификаторы TypeScript из кода.


Ссылка со слайда

Идею такой сущности я подсмотрел в проекте react-docgen-typescript-loader. Это такой loader для webpack, который пригодится, если вы используете Storybook. Storybook инструмент, который позволяет строить визуальные гайды и документацию к вашим React-компонентам.



Чем занимается этот loader? Он подгружает TypeScript-код, обрабатывает его и эмитит TypeScript-код с дополнительными полями у React-компонентов. Поля называются docgenInfo, и в них содержится информация для Storybook, чтобы построить документацию к React-компоненту, используя не propTypes, а аннотации TypeScript.

Потом этот код, заэмиченный в react-docgen-typescript-loader, как-то обрабатывается. Например, с помощью TS loader и Babel. В итоге, когда он попадает в Storybook, тот успешно строит документацию по полям docgenInfo.

Мне нужна похожая штука. Мне нужен webpack loader. Как это сделать?


Ссылка со слайда

Webpack loader это просто функция. Она принимает исходный код файла в виде строки и возвращает исходный код, тоже может его как-то модифицировать.

Здесь на слайде очень глупый loader, который занимается тем, что все ваши файлы превращает в код, содержащий console.log(Hello World!).


Ссылка со слайда

Loader может быть и синхронный. Можно получить callback, сделать асинхронную операцию. Вернее, что-то прочитать с диска или сделать что-то подобное и вызвать callback с новым модифицированным source.



Какой пайплайн должен быть у меня? Мне нужен loader, который подгружает TypeScript, запускает на нем кастомный трансформер. Я хочу применить трансформер, который минифицирует приватные поля и эмитит TypeScript.

Дальше я смогу его обработать с помощью Babel loader, как я делал это сейчас, и эмитить JS. А нашлепка из моего кастомного loader будет опциональной. Если что-то пойдет не так, я всегда смогу ее отключить, и максимум, что я здесь потеряю, минификацию приватных полей. И это не потребует от меня перестройки всего остального пайплайна сборки.

Окей, мы разобрались, как писать loader. Функция, которая обрабатывает source. Теперь нужно понять, как применить на наш файл кастомную TypeScript-трансформацию.


Ссылка со слайда

Для этого нам потребуется TypeScript Transformation API как раз тот самый программный API, который позволяет обработать исходный код на TypeScript, применить к нему трансформацию и заэмитить TypeScript-код. Это то, что нужно моему loader.

Примерно как это работает? Сначала нужно получить TS program, это объект, который содержит коллекцию файлов и настройки компилятора TypeScript. Нам нужно распарсить исходный файл и получить для него AST. Потом мы трансформируем это дерево и подключаем здесь myCustomTransformer, нашу кастомную трансформацию. И получаем в переменной result новое AST. Дальше мы его можем сериализовать обратно в TypeScript-код. Этим занимается компонент printer.

Кажется, ничего не мешает использовать это в webpack loader. Единственная проблема: документация по Transformation API не очень хорошая. И вообще, документация по внутренним сущностям компилятора в TypeScript сильно проигрывает аналогичной документации Babel. Но если вы захотите окунуться в это, начать можно с пул-реквеста в репозитории в TypeScript, где Transformation API сделали публичной.



Итак, что в итоге делает мой loader? Подгружает TypeScript-код и с помощью TypeScript Transformation API применяет на него кастомную трансформацию. Эмитит уже модифицированный TypeScript-код обратно. Дальше я скармливаю его Babel, который эмитит JavaScript.

Итоговую реализацию loader я выложил в npm, можно посмотреть исходный код на GitHub и даже подключить и использовать в вашем проекте:

npm install -D ts-transformer-loader

Всю эту прекрасную конструкцию мы даже покатили в продакшен.



Какой профит дала вся эта возня? Сырой непожатый код нашего бандла уменьшился на 31 килобайт, это почти 5%. Результаты в gzip и brotli не такие классные, потому что код и повторяющиеся идентификаторы там и так хорошо сжимаются. Но выигрыш порядка 2%.

Уменьшение непожатого кода на 5% не очень крутой выигрыш. Но 2% в минифицированном коде, который вы гоняете по сети, можно даже заметить на мониторингах.

Вот ссылка на мои заметки. Спасибо.
Подробнее..

Публичное техническое собеседование на мидл фронтенд-разработчика 15 июня в 19.00

07.06.2021 18:08:54 | Автор: admin
15 июня в 19:00 (Мск.) Яндекс.Практикум проведёт открытое публичное собеседование на тестовую вакансию мидл фронтенд-разработчика. Будут два собеседующих, кандидат и вакансия, на которую он откликнулся. Участники смогут не только следить за происходящим, но и задать вопросы спикерам.

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



Ведущие


Семён Левенсон Frontend-разработчик в Яндекс.Дзен, в роли первого собеседующего.

Алексей Малинов ex. Frontend-разработчик в Яндекс.Маркет, в роли второго собеседующего.

Владимир Сурыгин фронтенд-разработчик с полуторалетним стажем, в роли собеседуемого, выпускник курса Мидл Фронтенд-разработчик.

Вебинар пройдет 15 июня в 19.00 (Мск). Подробности и регистрация.
Подробнее..

Статический генератор сайтов Hugo. Фронтенд реалии

15.12.2020 00:22:12 | Автор: admin
В 2020 практически весь мир фронтенда заполонили Javascript фреймворки. Только и слышно о React, Angular, Vue и иногда в далеких просторах можно услышать тихий шепот Svelte. Разработчики умело используют эти инструменты для создания крутых продуктов, но есть и динозавры которые все еще предпочитают статику или jquery, а может их жизнь, вынуждает к этому или специфические задачи. Каждый день мир веб-разработки пополняется новыми технологиями, и сегодня речь пойдет о статических генераторах сайтов.
Статический генератор сайта программа, которая из различных исходных файлов (картинок, шаблонов в разных форматах, текстовых файлов и т.п) генерирует статический HTML-сайт. Один из ярких представителей Hugo. Разработчики позиционируют Hugo, как самая быстрая в мире платформа для создания сайтов.
Самая быстрая в мире платформа для создания сайтов

Ознакомиться с документацией можно на официальном сайте фреймворка. Далее речь пойдет об основных преимуществах, особенностях (здесь немного введения в фреймворк) и недостатках данного продукта. Эта статья не являться полноценным туториалом по Hugo. Я лишь пытаюсь сделать краткое введение в технологию и изложения некоторых мыслей из личного опыта, чтоб читатель смог решить стоит ли ему тратить время для более детального ознакомления с фреймворком и добавления его в свой арсенал фронтенд-разработки.

Несколько слов о HUGO


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

Hugo is one of the most popular open-source static site generators. With its amazing speed and flexibility, Hugo makes building websites fun again.

На момент написания статьи доступная версия фреймворка v0.79.0. Hugo еще не имеет стабильной версии, но это не мешает создавать с помощью него гибкие и масштабируемые сайты.

Он подойдет как для создания лендингов, многостраничников так и для создания более сложных продуктов: блог, новостной портал и даже интернет-магазин.

Установить фреймворк можно практически на любую современную платформу в несколько команд. Инструкция по установке для Windows, macOs, Linux очень хорошо описана в документации и не вызывает у разработчиков дополнительной головной боли.

Основные преимущества Hugo


  • Очень быстрый и гибкий
  • Для него легко настроить хостинг
  • Безопасный
  • Хорошая структура исходников
  • Возможность хранить содержимое в удобном формате (YAML, JSON или TOML)
  • Поддержка тем. Есть готовый набор тем, более 200
  • Легко SEO-оптимизировать
  • i18n с коробки
  • Хорошая поддержка таксономии
  • Быстрый в освоении. Исчерпывающая документация

Документация


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

Структура


После установки фреймворка, сайт можно легко создать с помощью команды:

hugo new site website-name

Далее hugo сгенерирует следующую структуру проекта:



Content & data. Основной контент или содержимое сайта храниться в формате .md в папке content. В роле контента могут выступать ваши статьи, новости, продукты интернет магазина и прочее. Каталог data используется для хранения файлов конфигурации, которые Hugo может использовать при создании вашего веб-сайта. Вы можете записать эти файлы в формате YAML, JSON или TOML.

Archetypes. Архетипы используют для создания содержимого сайта на основе заготовок. Это экономит время и обеспечивает единообразие для сайтов, использующих несколько типов контента. Вы также можете создавать свои собственные архетипы с предварительно настроенными полями основного материала.

I18n. Этот каталог предназначен для хранения конфигурации сайта на различных языках.

Resources. Hugo использует этот каталог для хранения кеша. Это ускоряет сборку сайта.

Static. Здесь храниться весь статический контент (CSS, JavaScript, и т.п).

Layouts. Хранит шаблоны в виде файлов .html, которые определяют, как просмотры вашего контента будут отображаться на статическом веб-сайте.

Themes. Для хранения различных тем.

Public. Сгенерированные исходники веб-сайта. Именно эту директорию следует заливать на хостинг.

Разработка


Как было указано выше, Hugo имеет около 200 готовых тем, которые можно легко установить и использовать. Это значительно ускоряет процесс разработки. Темы включают в себя не только отличные дизайнерские, но и хорошие программные решения. Можно найти много интересного для разработки если покопаться в исходниках (код каждой темы в открытом доступе на github).

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

Одно из приятных нововведений последних релизов поддержка scss с коробки. Теперь не нужно дополнительно настраивать сборку с помощью различных сборщиков, Hugo умеет распознавать scss и минимизировать его. Так же можно легко минимизировать и js с коробки.
По поводу различных сборок разработчики предоставляет несколько интересных готовых решений на github.

В целом хранения содержимого в текстовом формате оставляет приятный след на душе, особенно удобно хранить различные конфигурации в формате YAML (с коробки так, можно настроить другой удобный формат). Преимущество такого способа хранения контента сможет ощутить не только разработчик, но и заказчик, которому можно смело отдать папку с контентом для редактирования. Ему не нужно будет копаться в полотне html кода, а всего лишь редактировать текстовый файл. Алгоритм добавления нового плагина, пункта меню, или гугл аналитики привлекает.

Если речь идет о новом плагине ваши действия сводятся к тому что вам нужно:

  1. Физически переместить исходники плагина в директорию проекта (к примеру в папку static)
  2. Указать название нового плагина в файле конфигурации проекта

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

Деплой


Все просто, вам нужен обычный хостинг. Загружаете туда папку public и наслаждаетесь сайтом.
Но что же делать если мы хотим backend? Для этого существует ряд сторонних сервисов которые предоставляют услуги по размещению веб-сайтов созданных с помощью статических генераторов. Так же есть CMS системы для статических генераторов. Загружая туда свой продукт у вас и заказчика есть возможность с комфортом редактировать содержимое сайта, создавать новые посты / продукты, загружать медиафайлы и прочее. Один из ярких примеров forestry.

Минусы


  • Нет стабильной версии. Порой неожиданно при сборке проекта могут возникнуть некоторые баги, однако Hugo активно развивается и вы можете оставить фидбек разработчикам, которые часто выпускают новые релизы и фиксят баги.
  • Использование html. Возможно кого-то это смутит. Многие разработчики привыкли использовать шаблонизаторы.
  • Привлекательные конкуренты. Статический генератор Gatsby вдохновлен идеями React может показаться куда привлекательнее Hugo, учитывая популярность js-фреймворка.

Заключение


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

Как не закопаться в рефакторинге на фронте. Советы новичку

13.08.2020 22:14:38 | Автор: admin
С тех пор как вам доверяют не только кодить под строгим контролем, но и принимать даже минимальные решения, вы становитесь в полной мере ответственны за будущее проекта. В том числе, за стоимость его последующей поддержки. Имея опыт с действительно долгосрочными историями, мы собрали несколько советов о том, как не стрелять в ноги себе, своим коллегам и тем, кто придет на проект после вас.
Бывалым наши советы могут показаться очевидными. А вот новичкам настоятельно рекомендуем к прочтению. Потратьте время на воплощение этих идей в своих проектах, чтобы потом не тратить еще больше на бесконечный рефакторинг.
Сходные идеи можно высказать практически в любой сфере разработки, но мы будем говорить о них на примере проектов на React-е.

image



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

Задумайтесь о типизации


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

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

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

Разделите код на блоки, выделите логику


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

Очень наглядно польза от этого принципа была видна на проекте с большими формами, о котором мы недавно писали (http://personeltest.ru/aways/habr.com/ru/company/maxilect/blog/511322/). В том проекте проверки в блоках и видимость этих блоков изначально были связаны между собой. Но когда мы собрали всю связь полей в одном месте, отслеживать изменения логики стало гораздо легче. А главное мы смогли переиспользовать код в новом похожем проекте.

Единого стандарта на структуру проекта не существует тут придется опираться на свои знания. Есть два подхода, которые могли бы подойти для многих проектов: File Type First и Feature First.
Чтобы нащупать отправную точку для поиска структуры, удобной именно в вашем случае, рекомендуем обратиться к документации. Там обычно описаны best practice. Например, React и Redux в документации предлагают стандарты организации логики и файловой структуры проекта. При наличии определенного опыта можно экспериментировать и отклоняться от стандартов, если это позволяет обойти какие-то ограничения для конкретного проекта, но для большинства случаев в этом нет необходимости. И, конечно, не стоит забывать о таких базовых принципах, как SOLID. Неплохая статья о том, как применять эти принципы в React-е: http://personeltest.ru/aways/habr.com/ru/company/ruvds/blog/428079/. Хорошая статья о чистой архитектуре: http://personeltest.ru/aways/habr.com/ru/post/499078/.

По организации кодовой базы в React и связанным с этим вопросам есть неплохая, хоть и давно не обновляемая, подборка материалов: https://github.com/markerikson/react-redux-links/blob/master/project-structure.md.

Сформулируйте соглашение о коде


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

Придерживайтесь выбранной парадигмы


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

Помните о тестах


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

Отдельно хочется отметить интеграционные и end-to-end тесты.
Интеграционные тесты необходимо запускать каждый раз после исправления багов или добавления новых фич, чтобы убедиться, что корректировки ни на что не повлияли. Мы на своих проектах стараемся запускать их автоматом, когда заливаем результаты своей работы (мы это реализовали через hook). Не отработали тесты не стоит заливать изменения в проект. Сначала надо все поправить.

Но интеграционные тесты касаются только фронтенда. End-to-end тесты более медленные и проверяют взаимодействие приложения со всеми зависимыми элементами. Эти тесты имитируют действия пользователя. Тут мы ничего не мокируем, а действительно ждем ответов бэкенда и проверяем взаимодействия внутри всей экосистемы проекта, используя Cypress (в качестве аналога можем порекомендовать также Puppeteer).

Думайте перед обновлением, но не отказывайтесь от него


В мире фронтенда все меняется очень быстро версии фреймворков сменяют друг друга, появляются более удачные библиотеки. Стоит поддерживать их актуальность, но не надо делать это фанатично.
Как и типизация, о которой мы говорили выше, любое обновление стоит ресурсов (т.е. косвенно денег). Но есть несколько моментов, из-за которых нельзя полностью отказаться от обновлений.
Во-первых, поддержка даже самых удачных библиотек иногда заканчивается. В этой ситуации придется уйти на более перспективные аналоги.
Во-вторых, работа со старым стеком технологий редко вдохновляет разработчиков. Если вы понимаете, что команду не удержать на каком-нибудь покрывшемся пылью Backbone, или замечаете, что устаревший стек критически влияет на приток новых разработчиков, придется обновляться.

Обновления стоит воспринимать, как часть естественного порядка вещей. Но перед сменой библиотеки или обновлением фреймворка всегда необходимо проводить исследование. Подойдет ли вам новая версия? Как вообще организовать переход? И конечно, планировать все нужно заранее.
Обновления крайне сложны, если на проекте нет тестов. Даже маленькая библиотека по работе с датами может затрагивать самые разные части проекта, а ее обновление ведет за собой полное регрессионное тестирование. С ростом проекта это нельзя будет сделать качественно, имея в арсенале только ручные тесты.

А хорошо ли вы делаете сейчас?


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

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

Быть может, у вас есть свои советы? Оставляйте в комментариях!

P.S. Мы публикуем наши статьи на нескольких площадках Рунета. Подписывайтесь на наши страницы в VK, FB, Instagram или Telegram-канал, чтобы узнавать обо всех наших публикациях и других новостях компании Maxilect.

P.P.S. Заглавная картинка с прошедшего недавно архитектурного конкурса Playhouse Competition.
Подробнее..

Будни такси ВКонтакте

17.12.2020 10:10:32 | Автор: admin
Артем Пулявин руководит фронтенд-разработкой в Ситимобил и на конференции FrontendConf 2020 рассказал про такси ВКонтакте: как проект начинался и каким он стал.

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



О продукте


Такси ВКонтакте это сервис на платформе VK Mini Apps, который позволяет заказывать такси внутри приложения ВКонтакте. Такси ВКонтакте официальный суббренд Ситимобил, то есть такой же бренд наравне с Ситимобил.

Сейчас мы делаем где-то 20% от общих поездок Ситимобила. Но есть города, где мы лидируем например, в Казани среди всех агрегаторов мы занимаем 40-50% рынка. Почему-то в Казани очень любят ВК и все сидят на ВК такси.

В целом, до Ситимобила нам еще далеко пока это 1 к 5, но если считать от общего трафика, то это очень даже много. На старте никто не верил в нас: Такси ВКонтакте кто этим будет пользоваться, зачем на это тратить ресурсы и время? И когда мы делали 30 поездок, нас серьезно никто не воспринимал. Но мы захватили потерянную часть аудитории, которой нет в Ситимобил (там люди от 25 до 45) молодых людей от 16 до 23 лет. Сейчас мы делаем больше ста тысяч поездок и мы официальная большая платформа.

Такси ВКонтакте это:
  • ~ 4 миллиона пользователей в vk.cm/taxi;
  • ~ 250 тысяч подписчиков в vk cm/vktaxi;
  • >100 тысяч поездок в день;
  • ~ 250 тысяч DAU (активных пользователей в день);
  • ~ 2.2 миллиона MAU (активных пользователей в месяц).

Наша команда сейчас состоит из 12 человек:
  • 2 product-менеджера;
  • 5 фронтенд-разработчиков;
  • 1 бэкенд-разработчик;
  • 1 дизайнер;
  • 2 аналитика;
  • 1 QA.

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



Начинали мы как экспериментальный проект внутри Ситимобил. Экспериментальный потому, что никто на тот момент не знал, будет ли кто-то вообще пользоваться такси внутри ВКонтакте. Нам нужно было сделать MVP и проверить эту гипотезу. Сделать MVP это собрать команду, которая будет разрабатывать этот продукт, и обычно это долго и дорого, а нам нужно было быстро.

Мы нашли аутсорсеров, которые за несколько месяцев сделали нам первую версию проекта. Тогда мы назывались ВК такси. Мы разместили в нашей официальной группе Ситимобил новость про новый сервис и ссылку на него. Никакой рекламы не делали, но в течение месяца мы увидели, что сервис генерирует 30 поездок в день. И эта маленькое, но хорошее число было показателем того, что сервис интересен мы поняли, что сервис можно развивать. И весной 2019 года мы сформировали для этого внутри Ситимобил маленькую команду из 3 человек:
  • 2 фронтенд-разработчика;
  • 1 product-менеджер.

VK Mini APPs


ВКонтакте движется в сторону SuperApp, где пользователь может удовлетворить все свои насущные проблемы: заказать еду, такси, химчистку, вызвать клининг, поиграть в игрушки и т.д. В результате весной 2018 года была анонсирована платформа VK Mini APPs. По сути это WebView, который запускает URL c вашим сайтом, а вы в нем что-то показываете. Для того, чтобы вы могли коммуницировать с родительским приложением в ВКонтакте, ВК предоставляет библиотеку VK Bridge (раньше она называлась VK Connect). Через нее можно сделать запрос к VK API, получить данные пользователя, а помимо этого:
  • Включить / отключить нотификации Mini Apps;
  • Получить консистентные данные из VK Storage это хранилище, которое закрепляется за пользователем ВК, и неважно, на каком девайсе он авторизован.
  • Платить через VK Pay внутреннюю платежную систему внутри ВК;
  • Запросить геопозицию через VK Bridge, используя нативные инструменты самого девайса:



Наш эксперимент


Итак, на момент старта у нас было три человека, 30 поездок в день и legacy аутсорс кодовая база. Перед нами стояло две задачи:
  1. Вырастить функционал проекта ВК такси до уровня Ситимобил. На старте у нас было маленькое примитивное приложение. Всё, что оно могло делать построить маршрут: после нажатия кнопки Заказать такси, мы могли увидеть на карте, как к вам едет машина, а после поездки оценить её. И на этом всё. Это очень сильно отставало от того, что было в большом Ситимобил.
  2. Рост O2R до уровня Ситимобил. При заказе такси вы указываете точку А и точку В и видите цену заказа. После этого вы нажимаете ЗАКАЗАТЬ, к вам приезжает машина и вы уезжаете. Так вот время от момента, когда вы только посмотрели калькуляцию и до момента, как уехали это наша внутренняя метрика Order2Ride. И нам нужно было показать, что проект ВК Такси конкурентоспособен, и для этого поднять эту метрику до уровня Ситимобил.

Единственным вариантом поднять метрику и дорастить базовый функционал был пилить фичи.

VK UI


Нашей команде из трех человек product поставлял задачи, оформленные в виде mock-up у нас не было дизайнера. Поэтому нас очень сильно выручила библиотека VK UI, которую вместе с VK Bridge предлагает Mini Apps.

VK UI это набор компонентов, написанных на ReactJS (именно поэтому наше приложение написано на ReactJS), и они очень схожи с компонентами самого ВК. Поэтому, хотя пользователь уже вовсю использует Mini Apps, ему кажется, что он и не выходил за пределы ВК всё так же нативно, как будто он пользуется внутренним сервисом ВКонтакте.



Много тестирования


Из-за того, что у нас был единственный Mini App, мы тратили очень много времени на тестирование.

В нашем Mini App был режим разработки в двух режимах для теста и для релиза. Переключался он только на уровне приложения в тестовом режиме наше приложение смотрело на тестовую площадку, а в релизном на прод. И это тратило очень много нашего времени вместо того, чтобы работать параллельно.

А когда нам нужно было протестировать большую задачу например, движение машины на карте, то единственным способом было проверить это реально вызвать такси и уехать куда-то. У нас было два офиса: один на Белорусской, второй у метро Аэропорт. Так что для теста мы заказывали такси и ехали к коллегам, на обед и так же возвращались назад так проходили у нас e2e тесты. И на это тоже уходило очень много времени.

Quality Assurance


Понятно, чтобы разгрузить нас, нужен был QA. Но перед наймом QA мы решили, что нам нужно больше тестовых площадок нельзя же давать QA возможность переключать режимы. Мы пообщались с командой ВК, и они нам предложили классное решение создать для нас больше отдельных Mini Apps, без включения общего доступа (но вручную администраторов мы туда могли добавлять). Для каждого Mini App было несколько веток и свой отдельный url, который подгружал этот Mini App. При пуше запускался наш GitLab CI и релизил пуш на url, смотрящий на одну из тестовых Mini App.

Таких тестовых площадок мы сделали три (сейчас их гораздо больше):
  1. Stage был предназначен для разработчиков. Они разрабатывали (и до сих пор так делают) всё локально. И когда им нужно поработать с реальным VK Bridge внутри ВК, они релизят приложение на stage и смотрят, как оно реально работает.
  2. Test эту площадку мы отдали тестерам.
  3. Демо-площадка для PM, чтобы он мог показывать наши эксперименты директору по продукту и давать нам фидбэк.

У нас по-прежнему один QA, он по-прежнему всё делает руками. Но мы сейчас работаем над автоматизацией хотим прогонять UI тесты на Cypress + PhantomJS. Чтобы при пуше или создании MergeRequest запускался пайплайн, генерил видео и закидывал его в MergeRequest,. И по результату можно посмотреть по видео, что пошло не так. Постепенно мы к этому придем.

Оптимизация devs и QA


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

Мы создали маленькую утилиту, которая автоматически выкатывала ветку на тестовую площадку. В JIRA появлялись ссылки на MergeRequest, QA запускал скрипт и выкатывал нужную фичу-ветку на свой стенд и там ее тестировал. Так наш QA не зависел от разработчика (и снял с него часть работы), а разработчик не тратил время на раскатку для QA.

Но почему-то процесс разработки у нас все равно не ускорялся.

Мы проанализировали наш flow: разработчик берет задачу, переводит ее в IN PROGRESS, далее CODE REVIEW и TESTING. Эту ветку мы деплоили на DEMO и показывали productу, и если product говорил, что все ОК, мы релизились. Если нет, то возвращали в IN PROGRESS и дорабатывали:



И стало понятно, что мы тратим много времени на подготовку демо, и это в условиях, когда у нас нет дизайнера. Хотя разработчики сами решали какие-то проблемы из-за этого, все равно не все use cases были описаны и дизайн не был детализирован, а об edge cases вообще никто не думал. Поэтому мы поставили этап DEMO после IN PROGRESS:



И получили профит! Разработчик выкладывал задачу productу на демо и получал от него фидбэк. Они могли даже вместе сесть и начать что-то править по ходу. Например, забавно было с фичей Разделить поездку с друзьями. Мы ее пилили в спокойном режиме, а product, увидев, загорелся: Классная фича! Давайте быстрее. Будем показывать ее в рекламе. И нам пришлось максимально подключить все ресурсы, чтобы ее срочно зарелизить.

И как только product говорил, что это то, что он хочет, разработчик переводил задачу на CODE REVIEW, и там получали код, который готов идти на production без каких-либо правок. Тестировщик это все тестировал, и мы релизились. Это очень сильно сократило наш Time То Market, и так мы работаем до сих пор.

А что со стабильностью?


Логи


С первого дня, как мы вытащили кодовую базу наших аутсорсеров и подключили New Relic Browser, начали сыпаться ошибки. Ошибок было очень много и разных, начиная от того, что у нас не было полифилов на старых девайсах и заканчивая ошибками какой-то бизнес-логики. Мы это все быстро пофиксили и все приложение покрыли New Relic логами. Логи сделали трех уровней info, warning, critical:



Мы используем обычную rest-ручку и кидаем эвенты с контекстом на бэкенд. Все эвенты обрабатываются Filebeat через Logstash в Elasticsearch, а мы в итоге видим всё это в Kibana:



Мы можем задать конкретный id пользователя и посмотреть все эвенты, которые произошли, чтобы понять, на каком этапе что отвалилось:



Вначале, когда мы дергали эту рестовую ручку и кидали по логу за раз, мы уперлись в наш rate limit, так как сисадмины выставили rate limit на бэкенде на количество запросов. Поэтому мы сгруппировали логи в несколько стримов:
  • Apps logs пачка по 5 штук. Например, пользователь пришёл на какой-то экран, нажал на какую-то кнопку, сделал запрос, получил данные.
  • Analytics logs пачка по 10 штук. Таких логов очень много наши аналитики строят по ним дашборды.
  • Important logs (например, событие открытия приложения app_open). Это важные логи, которые мы сбрасываем моментально. Например, если приложение не загрузилось, то мы смотрим, а произошел app_open или нет. И если произошёл, то ищем, в чем же реально возникла проблема у пользователя.
  • По time out каждую секунду, даже если не набрали пачку из 5 или 10 логов.

А еще у нас есть логи балансировщика. По ним мы можем увидеть вызовы пользователем всех методов, которые он вызывал (что он отправлял, что получил, где запятисотило, что не так ответили мы). По ним тоже можно инцидент расследовать.

У нас нет алертов


Сейчас New Relic мы используем как дашборд фона наших ошибок. Но и не только ошибок. Например, мы можем увидеть, сколько открытий приложения было за полчаса или сколько раз мы обращались в storage ВК за какое-то время (и если обращений стало меньше, то это сигнал, что что-то идет не так).

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

Ребята на бэкенде используют New Relic алерты строят графики, base line, и если график выходит за base line, им приходит СМС (или звонит девушка из Алабамы) о том, что все плохо. Но мы не видим в этом смысла, потому что у нас нагрузка и так всегда большая, поэтому как раз по девиации фона ошибок мы и видим, если что не так пошло во время релиза.

Например, мы использовали фон ошибок New Relic, когда Google Tag Manager перевели в асинхронный режим и на 10% ускорили загрузку приложения. Еще был момент, когда у аутсорсеров в bundle грузилось много ненужных библиотек, и мы это увидели благодаря New Relic вырезали и вычистили все ненужные. Но он все же не покрывает все наши потребности, поэтому мы используем и другие инструменты.

Дополнительно мы проводим Smoke-тестирование на production когда релизим, тестировщик проверяет базовое flow поездки. И здесь нам важнее, чтобы сама процедура заказа работала. Может отвалиться история заказа, рейтинг водителя это не страшно. Главное, чтобы человек мог зайти, выбрать точки А и В, нажать ЗАКАЗАТЬ, и к нему бы приехал водитель.

Sentry


Если New Relic дает общую картину, то Sentry мы используем для групповых вещей. Он позволяет группировать ошибки по версии ВК, по платформе, показывает их частотность и помогает своими breadcrumbs. Например, пришел какой-то запрос на сервер, потом еще один, а потом пользователь куда-то кликнул и произошел exception. Для разбора таких инцидентов мы и используем Sentry.

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



По id клиента в ВКонтакте нам нужно понять, что у него случилось: не запускается приложение, не загрузился bundle, VK Bridge не инициализировался, поездка не совершилась или что-то другое. Чтобы понять конкретную проблему, мы используем логи.

В заключение


Выводы, которые я сделал для себя за год работы над этим проектом:
  1. Следите за Time То Market. Для нас Time То Market была метрикой выживаемости и ее сокращение дало нам лучший профит. Мы зарелизили большое количество фич, нагнали аудиторию, в нас поверили и команда ВК, и внутри компании, и мы достигли тех результатов, которые сейчас имеем. Поэтому экспериментируйте. Если видите какие-то блокеры, меняйте процесс ничего страшного в этом нет.
  2. Данных для расследования инцидентов мало не бывает. Используйте различные инструменты, покройте все ваше приложение логами, и тогда вы можете четко понимать, что же пошло не так у конкретного пользователя. VK Mini Apps это круто. Очень рекомендую эту платформу, потому что аудитория в приложении ВК порядка 200 млн. Делая Mini Apps вы можете попасть в ротацию, в саджесты вы сразу, без какой-либо рекламы, будете доступны своей аудитории. Здесь можно свой pet-project замутить или проект в рамках компании перевести на Mini Apps.

Конференция FrontendConf 2021 пройдет 29 и 30 апреля 2021 года (да, офлайн!) в Москве, в бизнес-центре Radisson Slavyanskaya.

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

И еще одна хорошая новость в преддверии фронтенд-конференции. 22 декабря в 17 часов будет открытый митап для всех неравнодушных к красивым и производительным интерфейсам Frontend: от эстетики к хардкору. Вы узнаете, как создавать красивые анимации, сохраняя высокую производительность. И можно ли автоматизировать тестирование UI, используя только хэшированные классы и немного магии при сборке проекта.

В программе будет доклад о Лотти и создании приветственных экранов от Максима Кузнецов. После него выступит Илья Тупицкий и расскажет про автотестирование по hash-классам, а в конце встречи будет обсуждение Хорошие практики современного фронтенда. Регистрация на митап здесь.

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

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru