Когда заходит речь о модных и передовых технологиях, ритейл, особенно строительный, — последнее место, где их станут искать. Ну что там может быть интересного: сайт на битриксе и мобильное приложение с программой лояльности? И в каких-то случаях этот стереотип не врёт, но «Леруа Мерлен» — совсем другая история. Наша IT‑инфраструктура мощна, как лапищи мемного волка, а команда разработки столь же хороша.
Но технологии — это благо и боль в одном флаконе, прямо как супергеройские способности. В этом посте пять наших специалистов самого разного профиля — от фронтенд‑разработчика до технического архитектора — расскажут, чем хороши их любимые инструменты, а в каких случаях надо не забывать страдать.
Но технологии — это благо и боль в одном флаконе, прямо как супергеройские способности. В этом посте пять наших специалистов самого разного профиля — от фронтенд‑разработчика до технического архитектора — расскажут, чем хороши их любимые инструменты, а в каких случаях надо не забывать страдать.
React
Илья Антонов
фронтенд-разработчик
Я использую React уже пять лет. До этого был фронтенд на кондовом jQuery, но в какой‑то момент стало понятно: так дальше нельзя. Для написания UI нужен UI‑фреймворк, а не костыль для браузеров десятилетней давности.
На момент перехода у нас был выбор из трёх технологий. Angular отпугнул своей сложностью. Vue.js тогда считался молодым фреймворком и вызывал определённый скепсис. Сейчас в «Леруа Мерлен» некоторые части фронтенда пишутся на Vue, но всё равно React кажется более зрелой технологией: больше комьюнити, готовых решений, вспомогательных модулей.
В React подкупает простота основной концепции. Думаю, каждый фронтенд‑разработчик, впервые с ней познакомившись, испытал небольшое «вау». UI как функция пропсов: меняешь аргументы — немедленно меняется вёрстка? Вау!
Конечно, любая простая концепция, сталкиваясь с реальной жизнью, неизбежно обрастает нюансами, оговорками, дополнениями, становясь в конце концов не такой уж простой. К React понадобился Redux, а к нему, в свою очередь, — Redux-Saga. Добавим, что у нас микрофронтендная архитектура, — и получится уже достаточно сложная вещь, которая если и вызовет «вау», то совсем в другой тональности.
Новые технологии создаются для того, чтобы играючи решать проблемы, стоявшие перед старыми
Саги, микрофронтенд, единое хранилище данных — каждая из этих концепций хороша, но в сочетании иногда вылезают непредвиденные побочные эффекты. Например, усложняются интеграционные тесты. Чтобы достоверно воссоздать окружение, в котором работает сага, нужно инициализировать хранилище целиком. Также не получается в полной мере воспользоваться преимуществами ленивой загрузки в Webpack Module Federation: приходится сразу запускать саги отдельных модулей. Впрочем, это уже проблемы не React самого по себе, а нашей архитектуры. Возможно, в будущем мы откажемся от саг в пользу чего-то другого.
Вернёмся к React. В чём ещё он доставляет неудобства? Мне не очень нравится переход на хуки. Конечно, у хуков есть свои преимущества: они упрощают решение многих задач, но при этом делают код концептуально более сложным. Среднестатистический разработчик лучше понимает ООП-парадигму, чем ФП. А хуки — это не только ФП, но ещё и некоторая «магия» на грани хака. Формально, конечно, никто не заставляет на них переходить: можно продолжать писать в ООП-стиле. Но по факту всем понятно, что раз такова «генеральная линия партии», то, чтобы пользоваться новейшими фичами React, в какой-то момент перейти придётся. И чем дольше тянуть, тем будет больнее.
Помните, выше я говорил о простоте и прозрачности основной концепции и о том, как она сталкивается с реальностью? То место, где удар о реальность оказался особенно жёстким, — это рендеринг. Facebook потратил немало усилий, чтобы оптимизировать рендеринг, но в результате его механизм перестал быть прозрачным. Теперь его профилирование иногда напоминает гадание на кофейной гуще. Надеюсь, в будущем появятся более удобные инструменты для этого.
Тем не менее, несмотря на озвученные проблемы, я считаю, что React — это лучший UI‑фреймворк для построения интерфейсов среднего масштаба. Vue близок по удобству, но он всё же лучше подходит для приложений поменьше. И небольшой, но приятный бонус — React Native. У нас есть пара мобильных приложений на нём, и это неплохой опыт. Но здесь, конечно, боль — производительность. Поэтому в основном мы пишем нативные приложения.
Compose Multiplatform
Алексей Гладков
технический архитектор
Прежде всего нужно сказать, что это очень молодая технология. Релиз Compose Multiplatform 1.0.0 состоялся совсем недавно — в декабре 2021 года. JetPack Compose, на котором он основан, релизнулся в июле. Однако для меня эти технологии уже старые знакомые: в «Леруа Мерлен» начинали пользоваться ими ещё с альфа-версий, принимали участие в тестировании. И, я бы сказал, мы гордимся этим.
Думаю, что Compose скоро станет индустриальным стандартом в мобильной разработке. Для этого есть все предпосылки. Google, судя по пресс-релизам, будет активно продвигать JetPack Compose как основное средство создания Android-приложений, так что игнорировать его в любом случае станет тяжело. А если так — почему бы не попробовать использовать мультиплатформенную версию фреймворка? За которой, между прочим, стоит JetBrains, а это уже кое-что говорит о качестве и перспективах.
Кроме того, у Compose нет действительно достойных конкурентов. Самый близкий — это Flutter от того же Google. Но у него есть один огромный недостаток — Dart. Не то чтобы это был плохой язык, но он так и не смог стать популярным за пределами своей ниши. И поиск Dart-разработчиков — квест не из простых. Видимо, люди в Google сами это поняли, раз выпустили конкурирующий фреймворк и начали его продвигать. Можно ожидать, что в будущем Flutter станет потихоньку отмирать.
Впрочем, справедливости ради нужно отметить, что Kotlin, на котором основан Compose, — также не самый распространённый язык. И всё же это JVM-совместимый язык общего назначения, и на него достаточно легко и приятно перейти с Java. Его перспективы видятся мне более радужными.
«Одно кольцо, чтобы править всеми»
Какие ещё есть конкуренты? Electron и React Native занимают несколько другую нишу. Приложение на них, вероятно, обойдётся дешевле, потому что проще и дешевле найти JS-разработчика, да и скорость разработки на JS выше (до момента, когда придёт пора выплачивать технический долг). Но есть одно огромное но — производительность. Скажем так, когда пишешь приложение на Compose, нужно специально приложить усилия, чтобы оно тормозило. Сделать какую-нибудь вьюху с таблицей на десятки тысяч ячеек или что-то подобное. В случае Electron нужно прилагать усилия, чтобы приложение не тормозило. React Native находится где-то посередине, но для оптимального UX всё равно лучше использовать что-то другое.
Если отвлечься от анализа рынка и поговорить о субъективных ощущениях, то Compose очень приятно использовать. Код получается лаконичным, выразительным. Одна из целей, заявленных Google при создании JetPack Compose, — уменьшение количества кода, избавление от многословия. С этой задачей Compose справляется прекрасно и при этом не теряет в гибкости.
Разумеется, есть и ложка дёгтя. Главная проблема заключается в том, что это молодая технология. Конечно, многое для неё уже сделано. Есть поддержка IDE, импорт макетов из Figma. Но при этом часто бывает, что сталкиваешься с проблемой, гуглишь её и получаешь два результата. Не в смысле «несколько ссылок на две разных страницы». Просто — два. Две строчки поисковой выдачи. Так что для StackOverflow‑ориентированного программирования это не лучший выбор.
Ну и, как говорил мой коллега выше, изящество концепций часто разбивается о суровую реальность. Что касается кроссплатформенности, то какие-то специфичные вещи всё равно приходится реализовывать нативно. Но это неизбежная проблема: нельзя создать кроссплатформенный фреймворк, не продырявив парочку абстракций.
Kotlin
Дмитрий Терехов
разработчик
В последние годы Kotlin быстро набирает популярность. В основном это происходит в мобильной разработке. Алексей уже рассказал о Compose, но Kotlin стал популярен ещё до него. Я читал данные, что 80 % кода 1000 топовых приложений в Google Play написано на Kotlin. Не знаю, правда или нет и как это считалось, но в принципе звучит правдоподобно.
Нельзя сказать, что Kotlin — нишевый язык для мобильной разработки: с серверной стороны он также хорош. Собственно, я и познакомился с ним в бэкенд-разработке, и там язык показал себя прекрасно. Всё начиналось с отдельных сервисов, а после решили все новые сервисы писать на Kotlin. Что отдельно приятно — интероперабельность с Java, возможность постепенно переводить проект с одного языка на другой либо использовать их параллельно на постоянной основе.
Чем не устроила чистая Java? Да не то чтобы совсем не устроила: это прекрасный язык, но местами слишком консервативный и многословный, c большим количеством ненужного boilerplate-кода. Разработка на Kotlin быстрее и приятнее. Также в нём много интересных фич. Если говорить о моих любимых — на первом месте однозначно корутины. Это оптимальный способ писать асинхронный код, намного более удобный, чем джавовские Future и @Async. На втором месте — пожалуй, Sequence. Ленивая коллекция — абстракция, которая позволяет работать с потоком данных как с обычной коллекцией. Ну и на третьем месте — удобство построения DSL. Очень просто и лаконично можно сделать свой язык описания данных на базе функций-билдеров. В официальной документации есть пример, как средствами Kotlin «реализовать» HTML. Всем интересующимся рекомендую ознакомиться. И это не случайная возможность языка, так и задумано, и возможности DSL-строительства в нём целенаправленно поддерживаются.
Логотип языка Kotlin по форме похож на остров Котлин в Финском заливе… Шутка: это просто стилизованная буква К
Kotlin — кроссплатформенный. Java создавалась с таким расчётом, чтобы «работать в каждой микроволновке». Но по факту она оказалась ограничена сервером и мобильными устройствами. Java-апплеты давно вымерли, Java на десктопе прославилась отвратительным UI (привет, Swing). Kotlin же компилируется в JS, и благодаря Compose Multiplatform можно писать на ней приложения для десктопа с вполне приятным интерфейсом.
Некоторые фичи Kotlin вызывают у меня двойственное отношение. Теоретически они должны упрощать жизнь, но на практике выходит по-всякому. Например, иммутабельность — спору нет, она сейчас в тренде, как и всякая прочая функциональщина. Но это требует особого выверта сознания, который есть не у каждого разработчика. И, несмотря на теоретические преимущества иммутабельности (безопасность, чистота кода и т. д.), на практике код становится сложнее и в неумелых руках может привести к большим потерям по памяти. Конечно, Kotlin не запрещает писать код с использованием привычных изменяемых структуры данных. Но концептуально язык заточен под иммутабельные коллекции, их возвращают все основные методы обработки коллекций (map, filter и прочие), и, разумеется, не хочется без необходимости плыть против течения.
Одной из главных фич языка считается null safety. Но знаете, иногда хочется поменьше null safety. В Kotlin переменные бывают nullable и не nullable. На практике же нередко случается третий вариант: теоретически nullable, но вот прямо сейчас бизнес-логика гарантирует, что не nullable. В Java в этом случае можно просто пренебречь проверками на null: если возникнет NPE, значит, с бизнес-логикой в любом случае что-то не так и надо дебажить. В Kotlin такой третьей опции нет, нужно городить частокол из двойных восклицательных знаков, заниматься прочими синтаксическими формальностями — и в итоге прийти к тому же отлавливанию NPE, только более многословному.
Наконец, реализация статических членов класса через сопутствующие объекты кажется мне излишне громоздкой. Но это уже мелочи.
Kubernetes
Павел Клюев
инженер по доступности сервисов
О Kubernetes сложно что-то рассказать. В смысле — сложно, например, ответить на вопрос «почему вы выбрали Kubernetes?» Может, потому, что это индустриальный стандарт? Нет, конечно, есть OpenShift и некоторые другие решения, но там под капотом всё равно Kubernetes. Если в вашем продукте в принципе требуется оркестрация контейнеров, вы будете использовать Kubernetes либо напрямую, либо в какой-то обёртке. Обёртки нужны либо мелкому клиенту, который не может сам разобраться в нюансах, либо крупному, который хочет быстро и без лишнего головняка.
Поэтому буду говорить не о самом Kubernetes, а о его использовании. На прошлой работе мы пришли к нему от архитектуры «одно приложение — один физический сервер». У нас были приложения с более-менее константной нагрузкой, а были «тяжёлые» вычисления, которые запускались раз в неделю, а в остальное время отведённые для них мощности простаивали. С помощью Kubernetes мы реализовали балансировку нагрузки: теперь неиспользуемые мощности доставались другим приложениям. Но, разумеется, Kubernetes — это не просто балансёр, а намного больше.
Без Kubernetes сложно представить себе микросервисную архитектуру. А без микросервисной архитектуры — современное высоконагруженное… да даже средненагруженное приложение. Но не все хорошо умеют в микросервисы. Был смешной случай, когда «распиливали» монолит на PHP, написанный таким образом, что всё оказалось связанным со всем. Модули были настолько плохо абстрагированы друг от друга, что для запуска любого из них требовалось приложение целиком. И промежуточная архитектура выглядела так: приложение разбили на микросервисы, но при этом каждый микросервис содержал приложение целиком. В каждом контейнере активен был только один какой-то компонент, остальное приложение тянулось за ним в нагрузку. Но, конечно, это проблема не Kubernetes, а разработчиков, не умеющих в decoupling.
Kubernetes в переводе с греческого значит «кормчий»
Если говорить о недостатках — ну, обёртки не существовали бы, если бы в них не было необходимости. Kubernetes требует некоторой культуры работы с ним, хорошего понимания его абстракций. Без этого понимания можно часами сидеть, уставившись в доки, и не понимать, откуда начинать делать то, что хочешь сделать. В этом плане OpenShift, например, намного дружелюбнее к новичку. Там отличный UI, в котором быстро понимаешь, что делаешь и зачем.
Есть две вещи, которые раздражают меня лично. Первая — когда только начал использовать какую-то фичу, а в следующей версии она уже deprecated. Нужно внимательно следить за развитием технологии, чтобы такого не было. И второе — писать Custom Resource Definitions. Трудоёмкая работа, которую не автоматизируешь: кто, кроме нас, напишет определения наших ресурсов? Хотя сами по себе CRD — отличная штука, в сочетании с Kubernetes API позволяют очень гибко автоматизировать управление ресурсами.
Airflow
Андрей Ларионов
руководитель практики инженеров данных
К необходимости использования Apache Airflow мы пришли не сразу. Конечно, запуск процессов преобразования данных — очень распространённая бизнес-задача. Но в самых простых случаях можно банально запускать запрос cron’ом. Когда этого перестаёт хватать? Когда становится не один запрос, а несколько, причём одни зависят от результатов других. И особенно — если мы хотим уметь прервать обработку данных, а затем корректно возобновить. Конечно, эта задача, в принципе, тоже решается на коленке: создаём в БД метатаблицу, куда складываем данные о ходе выполнения операций. Но это уже, как вы понимаете, намного более муторно. И всё сильнее искушение как-то эти вещи автоматизировать. Чем, собственно, Airflow и занимается.
Airflow — оркестратор процессов обработки данных. Или, в принципе, любых других процессов, но чаще всего его используют именно в области обработки данных. Его основная сущность — это DAG, направленный ациклический граф. Вершины этого графа — отдельные процессы, а стрелочки — то, какие процессы должны завершиться прежде, чем другие стартуют. У Airflow прекрасный UI, где эти DAG'и очень удобно смотреть.
Помимо этого, для описания процессов в Airflow есть коннекторы и операторы. Коннекторы отвечают за то, откуда данные брать (или куда класть), а операторы — за то, что с данными делать. И всё это описывается на языке Python, что приятно, поскольку он — один из самых лёгких и распространённых.
Пристегните ремни: сейчас ваши данные будут летать
Экосистема Airflow весьма развита. Готовые коннекторы и операторы покрывают примерно 90 % потребностей, редко приходится писать что-то своё. Из недавних случаев один был очень простым: надо было переопределить оператор, чтобы он кидал ошибку другого типа. Другой посложнее: периодически возникали ошибки при запуске задач на сервер Postgres в «Яндекс.Облаке». Стандартный Postgres-коннектор не умеет автоматически переключаться между master и slave.
Альтернативы у Airflow есть — например, Luigi или Argo. Luigi — модуль для Python, используемый для тех же задач, проще в эксплуатации, но менее гибкий. У Argo (и основанного на нём Kuberflow) упор больше на контейнеры, чем на процессы обработки данных. В общем-то, нельзя сказать, что кто-то из них лучше, а кто-то хуже: у каждого своя ниша.
Airflow невероятно гибкий. Как правило, весь потенциал этой гибкости не требуется конкретной организации с её конкретными задачами. Мы в какой-то момент обнаружили, что значительная часть DAG'ов имеет достаточно похожую, типовую структуру. И создали несколько инструментов, позволяющих такие DAG'и генерить из конфигурационных файлов. Об одном из этих инструментов я уже писал.
Я доволен Airflow практически полностью. С моей точки зрения, у него нет недостатков — только недочёты. Есть несколько запутывающих моментов в API, на которые регулярно напарываются новички. Во-первых, это параметр schedule_interval. Запланировал DAG, а он не выполняется? Это потому, что первое выполнение DAG'а планируется на start_date + schedule_interval. На выяснение этого нюанса я однажды убил целый рабочий день. Подозреваю, что это не рекорд.
Во-вторых, притча во языцех — execution_date. Все думают, что это момент начала выполнения DAG'а, пока не наткнутся на какое-нибудь непонятное поведение. Тогда лезут в документацию и узнают, что это начало текущего интервала. Тоже очень интуитивно. Впрочем, в грядущей версии Airflow разработчики обещали изменить название этого параметра. Так что вместо проблемы с его пониманием будут проблемы с миграцией.
Ну и наконец, возможно, и не минус, но особенность — время в UTC. У нас есть магазины в разных часовых поясах, соответственно надо следить, чтобы данные брались в правильных временных интервалах.
Расскажите в комментариях — каков ваш личный опыт работы с технологиями из статьи?