Раньше со Scala я сталкивался изредка, присматривался и только думал писать на этом языке что-то для себя, полный стереотипов «оооо, как всё тут сложно».
Однако новые вызовы и потребности решать рабочие задачи на чем-то более продвинутом привели меня к изучению этого языка посерьёзней, чем простой «Hello world».
Поскольку я несколько лет плотно работаю с созданием/использованием Python’овского кода, то в записи будут мелькать сравнения с Python’ом; как по мне, так проще провести понятные мне аналогии. Опыт работы с новым языком только-только формируется, и это наполовину вынужденное знакомство со Scala оставило ряд противоречивых впечатлений.
Да, Scala сложна!
Первое впечатление обманчиво. Туториалы не предвещают никакой сложности, но тривиальные задачи вида «стянуть по сети архив, распаковать в память, распарсить содержимое и построить с него структуру данных» подобно ведру холодной воды на голову резко отрезвляют.
«С чего начать?…»
Кривая обучения очень крутая. Учить нужно всё, много и сразу, не вылезая часами с документации, исходников и поисковиков.
Бесполезный StackOverflow
SO — не тот ресурс, на котором стоит искать ответы на вопросы вида «как мне?…». В случае Scala он бесполезен, потому что язык подразумевает понимание задаваемого вопроса. На SO в лучшем случае есть только копипаст без объяснения, КАК оно работает.
Иначе же, нагуглить ответ…
как мне свернуть
List
вHashMap
?
…можно быстро, потом вставить этот таинственный кусок символов, и полчаса разбираться, почему он не работает. А можно за то же время прочесть документацию и самому всё понять.
Почти бесполезный REPL
Язык компилируемый, и для того же «Hello World» недостаточно просто написать несколько строк и как-то
запустить — нужно скомпилировать, и не просто со scalac
— надо настраивать gradle
. Хотя, может, для
однострочника хватит и scalac
.
Это сразу разрывает привычный многим разработчикам-новичкам цикл REPL, используемый не как рабочий блокнот, а как песочница.
- что-то написал
- как-то запустил
- получил какую-то ошибку
- погуглил
- исправил
- GOTO 1
В Scala это не работает, и для эффективной работы приходится менять привычки с учетом того, что запуск дорогой по времени, и код писать надо сразу рабочий (по возможности). Да, с ростом навыков REPL используется по прямому назначению — как место для идей и заметок, но как средство изучения языка он неудобен.
f(t: Type[_])(implicit all: (the, things)) = ???
Типы. Они везде. Система типов мощная, стройная, и местами сигнатуры методов очень кучерявые. К счастью, адских порождений Некрономикона не так уж и много, хотя бывает и такое…
def unlift[A](implicit FG: Arr[F, G] <~< (F ~> G), GF: Arr[G, F] <~< (G ~> F)): F[A] <=> G[A] =
new (F[A] <=> G[A]){
def from = GF(self.from).apply
def to = FG(self.to).apply
}
…что можно вызвать дух самого Хаскелла Брукса Карри, если прочитать это в пентаграмме.
Но длительная работа с принудительной строгой статической типизацией приводит к любопытным последствиям. Вместо быстрой реализации прототипа из спичек и желудей оказывается проще смоделировать черновую реализацию на уровне типов данных, затем определить методы их обработки без какой-либо реализации, и уже потом начинать имплементировать их.
Такой подход позволяет увидеть недостатки архитектуры приложения ещё до того, как оно будет написано, и принуждает доказывать компилятору, что ты не верблюд.
Изменяемое состояние? return? NO WAY!
Никаких переменных, только константы. Строго говоря, var
в языке есть, но переменные предлагается использовать
только в случае крайней необходимости; то же относится и к структурам данных.
«Ключевое слово» return
тоже есть, но его использование считается очень грязным
хаком, и не зря.
Так и приходится писать — без переменных, без return
. После языков, где не возбраняется переопределять что
угодно и досрочно выйти откуда угодно такие ограничения ошеломляют, но в Scala есть ФП!
Функциональщина
Тут она везде. Изменение какого-то внутреннего состояния в Scala можно сделать гораздо изящнее, элегантнее, проще — не в пример циклам или императивному подходу.
Если придерживаться стиля кода, то он читается не в пример легче аналогов на Python/JS, и алгоритмы почти дословно отображают бизнес-логику.
Но не всё так радужно: вся эта магия становится интуитивно простой и понятной только после определённого упорства и читания исходников, примеров; без определённого стартового набора знаний о ФП все эти свертки, сопоставления с образцом и монады выглядят со стороны какой-то тёмной магией, к сожалению.
Коллекции
Есть какие угодно, на всякий вкус. Но реализация под капотом чересчур усложнена. Даже разработчикам языка это не нравится; к их чести, в 2.13 ситуация изменится к лучшему.
Но для новичка всё же стоит потратить несколько вечеров и разобраться, что там есть, кроме Array
, Vector
,
Stack
и List
, дабы не умножать свои велосипеды.
Отдельно отмечу синтаксис для работы с коллекциями; если к seq1 ++ seq2
или там 1 :: 2 :: 3 :: Nil
со
временем привыкаешь, то на (lst /: Map.empty[Int, Int]) { (a, b) => … }
вместо нормального foldLeft
без
грусти не посмотреть.
it should be “free DSL” in { scala }
Выразительные возможности языка даже чересчур большие, чем я от него ждал. Любую (sic!) задачу можно решить тремя разными простыми способами, двумя неочевидными, дюжиной сложных и одним таким, что энтерпрайзный FizzBuzz в сравнении с ним прост и понятен.
Странно названые методы, неявные преобразования и возможность произвольно смешивать стили кода в запущенных случаях приводят к совершенно нечитаемой стене текста, не понятного через полгода даже автору.
Пожалуй, это первый язык, в котором передо мной всерьёз встал вопрос самоограничения и жесткого следования стилю кода.
Экосистема
Количество готовых инструментов для вообще всего огромное. Мне, как новичку, было очень трудно после уютного и привычного PyPI разобраться не то, что в подходящих — даже в популярных библиотеках.
Simplifying Sparky Stuff
Отдельные вещи в Apache Spark удобнее писать на Scala, да и Python’овские API до сих пор поддерживается не столь полноценно — правда, ситуация начала меняться в гораздо лучшую сторону.
Так стоит ли связываться?..
Точного ответа на вопрос у меня пока что нет. Какие-то одноразовые прототипы или непритязательные по сложности сервисы привычней и легче писать на интерпретируемых языках, время до выкатки на продакшен гораздо меньше. Но при выборе инструмента для разработки чего-то посложнее микросервиса либо с серьёзными требованиями по надёжности/производительности я теперь буду рассматривать всерьёз и Scala.
Да и потом, изучение столь мощного инструмента помогает всерьёз и надолго подтянуть свои профессиональные навыки. Но будет сложно.
Очень сложно.