Хабрахабр

[Перевод] Зачем человеку Scala?

Здравствуйте, коллеги.

12. Не так давно мы допечатали книгу Одерски, Спуна и Веннерса о Scala 2. Ведь до Scala 3 еще далеко.

Автор сегодняшней статьи — Адам Уорски, сооснователь компании «SoftwareMill» и опытный Scala-разработчик. У него получилось интересное резюме сильных сторон современного языка Scala, которое мы и предлагаем вашему вниманию.

Не считая обсуждения этих пленарных выступлений, многочисленные дискуссии идут в twitter, в сообществах Slack, а также на reddit (см. После пленарной лекции Мартина Одерски на ScalaDays, где он изложил планы на Scala 3 и пленарной лекции Джона де Гоуса на конференции Scalapeño о будущем Scala в сообществе Scala продолжаются оживленные дискуссии. 1, 2). напр.

Вот в чем вопрос!

Однако, значительная часть споров связана с различными интуитивно ощутимыми или фактическими недостатками Scala как языка. Все это очень интересно и познавательно для специалистов, уже работающих в экосистеме Scala. Как и в большинстве дискуссий, внимание приковывают самые слабые и эмоциональные тезисы, и эти дебаты — не исключение. Эти моменты могут отпугивать людей «со стороны», вызывая у них вопросы: «А зачем мне вообще пользоваться Scala?», «А вдруг это тупиковый путь?», «Повторит ли Scala 3 успех Python 3?» и т.д.

Каковы технические и деловые доводы в пользу работы с эти языком? Поэтому сделаем шаг назад: зачем вам вообще мог бы потребоваться язык Scala?

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

Важнейшее достоинство Scala – это гибкость при определении абстракций. Начнем с того, что язык Scala особенно хорош для определенных предметных областей (но не для всех!). Иногда приходится использовать неявный параметр или метод расширения; в редких случаях остается только прибегать к макрокомандам. В вашем распоряжении – ряд простейших «кирпичиков» для этого; иногда определить абстракцию не сложнее, чем использовать класс, методы и лямбда-выражения. Однако, есть варианты.

Например, речь может идти о распределенном или конкурентном программировании. Таким образом, Scala отлично вам подойдет, если требуется сориентироваться в сложной предметной области. Для этого существует два основных подхода: акторный, реализуемый при помощи Akka, и в духе FP, представленный Monix/cats-effect и Scalaz/ZIO (если бы вы хотели подробнее почитать о сравнении этих инструментов – я написал серию статей как раз на эту тему). Наладить параллелизм очень сложно, а в Scala есть ряд библиотек, упрощающих эту задачу путем построения абстракций.

Возможности Scala также позволяют вывести на новый уровень моделирование типичных бизнес-приложений. Однако, разумеется, речь может идти и о других предметных областях. В случае с распределенными системами мы сталкиваемся с технической сложностью. Но в данном случае речь уже о сложности другого порядка. Например, в книге Дебасиша Гхоша (Debasish Ghosh) “Functional and reactive domain modeling” объясняется, как совместить DDD с функциональным и реактивным программированием. При программировании бизнес-логики в приложениях речь идет уже о сложности предметной области как таковой.

Сложность языка

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

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

Таким образом, при относительно небольшом количестве базовых возможностей (по размеру грамматики Scala проще Kotlin, Java или Swift!) — что, в свою очередь, облегчает обучение – варианты комбинаций гораздо многочисленнее.

Не думаю. Не слишком ли широкий выбор? Подробнее об этом см. Программист, как компетентный и ответственный профессионал, более чем в состоянии выбрать наилучший вариант, чтобы решить конкретную задачу. в статье “Простой стек Scala”.

Java, только лучше

Но я считаю, что именно Scala, а не Kotlin, по-прежнему заслуживает такого звания. Сейчас много говорят, что Kotlin вытеснил Scala в качестве “как Java, только лучше”. На то есть две основные причины:

Это связано с природой Scala как таковой: писать на нем код удобно прежде всего при помощи неизменяемых данных. Во-первых, неизменяемость в языке Scala первостепенна. Но дело и в том, как спроектирована и написана стандартная библиотека языка Scala; неизменяемы все структуры данных, используемые «по умолчанию». К таким данным относятся, в частности: val (как единицы первого класса), case-классы, функции высшего порядка, т.д. Благодаря неизменяемости упрощается целый ряд вещей, особенно в нашем мире высокой конкуренции, где выигрывают именно те языки, где предпочитается неизменяемость.

Такие обертки преобладают при программировании в асинхронном или реактивном стиле, и наличие языковых конструкций, упрощающих работу, скажем, с такой базой кода, где активно используются Future – еще один аргумент в пользу Scala. Во-вторых, в Scala поддерживаются конструкторы типов, типы высшего порядка и типы классов (объявляемые неявно), что серьезно упрощает работу с оборачивающими/контейнерными типами, например, с Promise, Future или Task.

Роль их примерно такова, как у паттернов проектирования в Java, однако, они более гибкие и простые в использовании, как только вы крепко усвоите их смысл. Что такое типы классов? По этому поводу есть несколько отличных руководств, например, 1, 2.

Это такие типы как Future или Option, служащие “контейнерами” или “обертками” для других типов. Что насчет конструкторов типов? Типы высшего порядка позволяют писать код, обеспечивающий абстрагирование любой обертки. Так, у вас может быть Option[String] или Future[Int]. например. См. 1, 2.

Дело не только в том, что большинство высокопроизводительных «реактивных» вычислений с минимальными задержками выполняются с применением асинхронного ввода/вывода, для которого просто просятся именно такие конструкции. Вдруг вам интересно, зачем вообще прибегать к Future/Task? Другие причины приводятся в этой дискуссии на reddit и в моей статье “Зачем возиться с обертками?”.

На первый взгляд это может быть неочевидно: если у вас за плечами опыт Java или Ruby, то осознать эти аспекты Scala вы сможете не сразу. Работа в преимущественно неизменяемой среде, а также возможность с удобством обращаться с такими конструкциями как Future, Promise или Task (и абстрагировать их!) радикально преображает ваш код. Но, даже с образовательной точки зрения полезно разобраться, как устроен «функциональный» подход и, что гораздо важнее, почему он может оказаться весьма достойной альтернативой.

Естественно, и у Scala, и у Kotlin есть ряд общих преимуществ по сравнению с Java, например:

  • Более компактный синтаксис
  • Меньше стереотипного кода
  • Более насыщенная система типов
  • Отсутствие языкового балласта

Именно для этого и созданы компьютеры: выполнять скучные, рутинные повторяющиеся задачи. В то же время, оба языка открывают доступ к экосистеме библиотек и фреймворков JVM.
Чем насыщеннее система типов (в Scala она богаче, чем в Kotlin, а в Kotlin – богаче чем в Java), тем больше работы по верификации выполняется компилятором, а не человеком. Проверка применимости типов – определенно, как раз одна из таких задач.

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

ФП vs OOП

Я – сторонник синтеза, особенно потому, что ФП и ООП на мой взгляд – не альтернативные подходы, а дополняющие друг друга. Еще один вопрос, часто поднимаемый в таких дискуссиях – должен ли язык Scala и далее придерживаться синтеза ООП и ФП, либо развиваться по чисто функциональному пути.

этот ответ на reddit в более раннем треде, где превосходно объясняется референциальная прозрачность). ФП – это программирование при помощи функций, правда, не любых, а референциально прозрачных (см. Нет ни одной причины, по которой два этих подхода не могли бы сосуществовать, и Scala это уже продемонстрировал! В ООП коммуникация с объектами организована при помощи “сообщений” или, в нашей терминологии, вызовов виртуальных методов.

Все это – элементы успешной комбинации двух парадигм. В твите о достоинствах Scala Джон де Гоус упоминает некоторые черты ООП, полезные и при чисто функциональном подходе, в частности, модули первого класса (получаемые путем композиции объектов), точечный синтаксис (вызов методов в объектах) и классы/экземпляры типов как конструкции первого класса. Может быть, еще какие-то не за горами?

Один из незавершенных аспектов – это предлагаемый синтаксис методов расширения, который должен прийти на смену гораздо более путаным неявным преобразованиям. Проект «синтеза» еще не закончен, здесь определенно остается поле для обсуждения. Некоторые предложения лучше, другие требуют доработки, но хорошо, что они поступают, и о них идут дискуссии; благодаря ним язык живет и, в конечном счете, в нем закрепляется наилучшее решение. Другой – оптимизация синтаксиса классов типов; предложение по этому поводу, высказанное некоторое время назад, явно сырое и не охватывает некоторые из наиболее распространенных случаев использования монад в Scala.

Scala 3

В нем появится ряд интересных возможностей, в частности, непрозрачные типы, параметры типажей, новый подход, связанный с метапрограммированием, типы объединения и & пересечения, неявные типы функций – вот всего несколько примеров. Scala 3 выйдет через два года. Конечно, здесь возникает (обоснованная) обеспокоенность по поводу миграции.

Поскольку Scala – статически типизированный язык, такая задача решаема в больших масштабах и гораздо проще, чем, например, на Python. Уже известно, что будет представлен специальный инструмент для автоматической миграции кода со Scala 2 на Scala 3 при помощи scalafix. Поскольку на магию рассчитывать не приходится, миграцию этих фрагментов нужно будет выполнить вручную. Но, разумеется, никакой магии тут нет: даже если этот инструмент на 99% обеспечит правильное покрытие кода, все равно останется 1% наиболее проблемных случаев.

Даже с учетом этого, предлагаемые изменения не являются революционными. Таковы издержки работы с активно развивающимся языком: вы получаете новейшие возможности, но некоторые из них на поверку оказываются не столь хороши и нуждаются в доработке. Язык Scala 3 очень похож на Scala 2, никаких серьезных изменений парадигмы не предвидится.

Тогда как ранее миграция между старшими версиями Scala (напр. Обнадеживает тот факт, что команда Scala всерьез подходит к миграции. 8 на 2. с 2. В них участвуют три основных стороны: EPFL, ScalaCenter и Lightbend все они (зачастую вместе) работают на облегчение миграции. 9) была довольно обременительна, последние миграции прошли гораздо лучше. Например, существует двоично-совместимый инструмент MIMA, а также в сообществе постоянно создаются многочисленные новые библиотеки, призванные обеспечить удобную работу с новыми версиями Scala.

Наконец, пока не законченный инструмент TASTY (который, соответственно, пока нельзя оценить) должен обеспечить использование двоичных файлов из Scala 2 в Scala 3.

Итак, зачем же использовать Scala?

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

Scala используется не только для реализации Spark как такового, но и для определения самих вычислений. Кроме того, не забываем и о Spark, ведущей платформе для распределенного анализа данных. Вот вам еще одна data science-ориентированная абстракция, скрывающая сложную вычислительную модель.

Резюме

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

Не существует однозначно выигрышного подхода к Scala; можно придерживаться или более императивного подхода Akka, или более функционального подхода Cats и Scalaz. Scala позволяет вам развивать свой стиль программирования, каким бы языком вы раньше ни занимались: Java, Ruby или только пробуете себя в программировании.

Однако, на самом деле в этом заключается огромное преимущество. Вот где можно усмотреть проблему: в сообществе Scala есть фракции, придерживающиеся “реактивного”, “синтетического” OOП/ФП подхода и чистого ФП. На этом, в свою очередь, отлично можно выучиться нестандартному решению задач и обогатить собственный инструментарий. Благодаря такому разнообразию ведутся дискуссии, высказывается множество различных мнений с разных точек зрения.

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

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть