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

Вначале, как и в большинстве компаний, сначала использовалась как «укороченная Java». Но в конце концов, по мере того, как все больше и больше команд запускали проекты Scala, практика Scala как реального языка программирования FP улучшалась, и мы начали видеть перспективы создания более надежных и безопасных программ. Сегодня большая часть наших новых программных проектов использует Scala и расширенные библиотеки функционального программирования, такие как cats, doobie, circe или комбинаторы синтаксического анализатора.
Однако внедрение действительно функционального кода в крупной компании-разработчике программного обеспечения, такой как Criteo, не без труда. Давайте поговорим о том, что хорошо сработало, а также о том, где лежат драконы.
Исходя из опыта императивного программирования
С самого начала Criteo был в основном магазином .NET, где основным языком программирования был C #. Само собой разумеется, что разработчики Criteo очень хороши, но, как и в большинстве крупных технологических компаний, у них в основном императивный опыт программирования и многолетний опыт работы с Java, C # или C ++.

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

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

У которого, кстати, точно такая же сложность времени выполнения :)
Но да, большинство разработчиков сочтут это решение подозрительным, особенно в отношении его «производительности». Возможно, потому, что это выглядит слишком высокоуровневым, а хорошие разработчики так много знают о внутренней структуре данных, что хотят «контролировать» то, что на самом деле происходит.
Так что внедрить функциональное программирование таким способом обычно сложно.
Представляем JVM на Criteo
Помимо того, что Criteo является магазином .NET, исторически также широко использовался SQL Server в качестве хранилища данных. Но с экспоненциальным ростом компании быстро стало невозможно хранить наши аналитические данные в кластере SQL Server, даже гигантском, и даже с шардингом!

Итак, кто-то умный начал экспериментировать с Hadoop, и мы наконец получили кластер Hadoop. И вместе с тем тысячи серверов Linux и JVM!
Первоначально весь код, который мы написали, представлял собой простую задачу сокращения Java-карты, но вскоре мы начали использовать каскадирование, чтобы абстрагироваться от большей части сложности Hadoop, а затем масштабирование, чтобы абстрагироваться от большей части сложности каскадирования :)
Так появилась первая база кода Scala в Criteo! И делать flatMap` на терабайтах данных настолько круто, что всем это нравилось :)
Зона ScaVa
С большой властью приходит большая ответственность. И по мере того, как все больше людей начали использовать гигантский кластер Hadoop для обработки и производства тонны данных, ответственным командам потребовалось создать больше инструментов, чтобы поддерживать их на высоком уровне качества.
Планировщики, платформы выполнения, парсеры SQL, что угодно, Scala стал естественным выбором для этих проектов. Команды разработки данных также тратили много времени на работу с большими данными, используя обычные подозреваемые в Spark и Scalding, и мы быстро поняли, что использование Scala в экосистеме больших данных и использование Scala для разработки приложений - это совсем другое дело. Запуск нового проекта Scala, не связанного с большими данными, с нуля оказался пугающим из-за огромного выбора стилей и библиотек, доступных начинающим разработчикам Scala.

В то время мы в основном писали смесь Java и Scala, которую назвали ScaVa. Нередко было видеть Java-код, появляющийся в проекте Scala, потому что «мне было проще сделать это таким образом», или сравнивать коллекции Java с коллекциями Scala, чтобы быть уверенным в окончательной производительности приложения.
Наш стек разработки укрепился вокруг стека Twitter Scala, в основном потому, что мы разделяли тот же набор проблем, что и Twitter, особенно в отношении объемов данных и производительности. Эти библиотеки (Finagle, Scalding, Algebird) в конечном итоге оказались очень важными для Criteo, так как они предоставили критически важные функции, такие как метрики и трассировка, в сложной программной архитектуре. Но они также не были очень скалайскими в том смысле, что не разделяли некоторых из наших растущих опасений по поводу чистоты, типизации или сосредоточения на шаблонах функционального программирования.
Выращивание нового поколения разработчиков FP
Этот необходимый первый шаг экспериментирования со Scala и гибридным стилем разработки императив / FP позволил нам улучшить культуру FP в Criteo: больше семинаров, больше людей посещают конференции Scala, больше внимания уделяется безопасности и надежности наших программ.

Со временем Criteo превратился в магазин Scala, и с этим начал нанимать все больше и больше разработчиков, заинтересованных в Scala и функциональном программировании. Тогда не только Scala, но и люди с разным опытом работы с OCaml, F # или даже Haskell присоединились и помогли нам улучшить наши методы функционального программирования с помощью Scala.
Мы начали интегрировать более продвинутые библиотеки Scala, и сегодня большинство наших проектов Scala построено на проектах сообщества Typelevel, таких как cats, fs2, doobie, algebra и т. Д.
Мои инструменты больше не работают

Однако ряд проблем затрудняет адаптацию разработчиков к более продвинутому стилю FP. Главный из них заключается в том, что переход от модели императивного программирования к модели функционального программирования - это не только скачок в способе мышления, но и оставляет множество инструментов на обочине.
Самая важная из них - IDE. Разработчики любят свою IDE - она так много для них делает! Проблема в том, что хорошие IDE созданы для требовательных программистов. Например, пошаговый отладчик - это обычный способ, которым разработчики пытаются исправить свои программы. Но для программ FP с ленивой оценкой это работает не так хорошо. Я видел, как многие разработчики пытались отладить программу Scala таким образом, застревая на операции сортировки, которая не была выполнена «на месте», как многие ожидают.
IDE также не поддерживают очень продвинутые функции Scala, такие как макросы и сложные типы, из-за чего некоторые люди не хотят включать некоторые в остальном очень полезные библиотеки, просто чтобы не увидеть, что их IDE полностью потеряна, не может правильно ввести выражение и возмутительно сообщать о ложной ошибке в их идеальном коде!
Franken-Scala для больших данных

Scala для больших данных и науки о данных имеет очень мало общего с остальной частью экосистемы Scala. Они используют один и тот же базовый язык, но стиль и задачи очень разные.
Например, возьмем синтаксический анализ JSON: в то время как классический разработчик Scala, вероятно, предпочтет надежность кода и выразительность при синтаксическом анализе JSON и выберет такую библиотеку, как Circe, при написании работы с большими данными, связанной с миллиардами одноуровневых документов JSON, вы, вероятно, предпочтете производительность и потребление памяти и выберите самый быстрый парсер JSON для (вероятно) Java, который вы можете найти!
В общем, когда я работаю над программой Scala, я кодирую столько ограничений, сколько могу, в свой тип, и когда моя программа компилируется, она обычно работает или, по крайней мере, я очень близок к тому, чтобы понять это правильно! Однако при работе над заданием Scala для больших данных его компиляция обычно проста, но на правильную работу в кластере Hadoop могут уйти дни!
Это связано с тем, что использование Scala (или Java) при разработке работы с большими данными на Hadoop сопряжено с большой случайностью. От всей магии сериализации в сети до проблем с путями к классам, форматов файлов и т. Д.
Это оказывается очень понятным: большинство гарантий, предоставляемых Scala, разрушаются на границах ввода-вывода. Работа с большими данными имеет большую и сложную поверхность, контактирующую с внешним миром, и эта сложность доминирует над проблемой.
Преследуемый призраками старых узоров

Большинство разработчиков, переходящих на Scala, не приходят с широко открытыми глазами и невиновными. Обычно за плечами у них годы практики программирования, и если они провели большую часть своей карьеры, работая в среде императивного программирования, то они выучили множество шаблонов и «лучших практик», о которых теперь им приходится несколько забыть.
Классический вопрос от Java-разработчика, переходящего на Scala, звучит так: «Хорошо, а где же каркас для внедрения зависимостей?» DI стал настолько важным в Java, что появились целые инструменты и решения, посвященные этой проблеме. Нельзя сказать, что это не проблема в Scala, но обычно простые решения, построенные на неявных контекстах, делают свою работу, и очень редко и не очень идиоматично добавлять структуру DI в вашу кодовую базу Scala - особенно если это вносит изменчивость повсюду!
У нас также есть такая же дискуссия об использовании (особенно на ранних этапах) return`, который часто предпочитается в Java и императивном программировании, но является скачком в потоке управления, а не идиоматическим в Scala.
Отчаянно ища новые правильные модели

В конце концов новичок в Scala и FP должен забыть многие практики, которые они усвоили с течением времени, и поэтому они ищут новые «правильные» шаблоны, которые можно применить к своей блестящей новой проблеме Scala.
Опять же, здесь есть ловушка, поскольку только опыт может различить, что полезно, а что нет, и какой шаблон применять в той или иной ситуации. К сожалению, сообщения в блогах и другие интернет-мудрости, обещающие всевозможные необычные новые методы программирования, весьма привлекательны для новичков-программистов на Scala!
Scala, будучи очень богатым языком программирования со многими экспериментальными функциями, также не помогает. Разработчику требуется время, чтобы понять, что использовать, как это использовать и какой стиль следует принять.
К счастью, это легче сделать в команде и по ходу выстроить единый стиль в компании, поскольку все больше и больше проектов Scala рождаются и умирают.
Criteo - настоящий магазин Scala!
Несмотря на все проблемы внедрения функционального кода в крупной компании-разработчике программного обеспечения, такой как Criteo, мы можем сказать, что сегодня это настоящий успех и что Criteo действительно является магазином Scala. Scala широко используется для большой типологии проектов, в том числе для самых требовательных, таких как обслуживание более 10 миллиардов изображений продуктов, сгенерированных по запросу, которые выполняются службой Scala, распространяемой по всему миру во всех наших центрах обработки данных.
Мы также стараемся вносить свой вклад в сообщество Scala и открывать исходный код для большей части наших инструментов Scala, таких как, например, Cuttle - наш исполнитель и планировщик заданий, vizsql для анализа и управления SQL-запросами, Babar для профилирования запущенных распределенных приложений. на Hadoop, наш потоковый HTTP-клиент / сервер (lolhttp) и наш инструмент документации кода socco.
Скоро конференция НАБД!
Если вы хотите узнать больше о нашем функциональном путешествии или узнать о других областях нашей работы в области крупномасштабной обработки данных, а также о других компаниях, таких как Spotify, Datadog, Twitter, Taboola или Google, присоединяйтесь к нам на нашем Это не очередная конференция по большим данным, которая состоится в Париже 4 и 5 июня.

Обновление: конференция NABD состоялась, но если вы хотите продолжить изучение этих тем, проверьте наши открытые возможности!

Гийом Борт
Инженер по надежности данных Criteo Labs