2014-12-13

Пол года с Groovy и Grails

Пол года уже как пишу на Groovy/Grails и пора бы уже сформулировать отношение к этим вещам в письменном виде. Сравнивать буду, естественно, с Python/Django. Совсем немного пощупал cherrypy/jinja когда готовил олимпиаду для студентов, но они не сильно отличаются.
TL;DR версия: groovy восхитителен, джависты, для мелких тасков крутейшая штука, берите и используйте, grails не нравится потому, что рвет связность кода, особенно заметно на больших масштабах и совершенно немодульный.

Дальше будет описание отдельных аспектов и иногда сравнение.


Пакетность

Как бы ни ругали монструозные скрипты Maven, Apache Foundation родил нечто крутое: repo1.maven.org. Совершенно простой и открытый репозиторий, который можно спокойно отзеркалить, в который можно залить свои либы - стал стандартом де-факто, базовой частью остальных пакетных менеджеров.

Groovy пошел еще дальше: пакетный менеджер встроенный прямо в язык - grape. Пишешь перед импортами @Grab(group='org.springframework', module='spring', version='2.5.6') и либа скачивается. Волшебство и никакой магии, прямо как я люблю.

Джавовые библиотеки в целом гораздо богаче аналогов чем в pypi, хотя бы в силу большей распространенности java.

В python нужно использовать сторонний менеджер, в 3.4 наконец то вкрутили pip из коробки. Но до аналога @Grab логичный шаг еще не сделан.

Функциональщина и DSL

По поводу бесшовного мигрирования с java: представьте, что lombok и guava уже встроены в язык - уже одного этого достаточно для миграции Но есть еще мешок сахара.  Функциональный стиль написания кода становится легким и непринужденным - то что только начинают осваивать в java-8 мире. Необязательность ";", "()" и "return", синтаксическое описание списков и мапов, опциональная типизация, safe-navigation и elvis-operator, ненужные геттеры-сеттеры, красивый синтаксис при использовании closure в качестве аргумента, дающий богатые возможности по написанию DSL - это стало must-have инструментами.

Вообще, все в groovy пронизано идеей DSL, начиная от упрощенного синтаксиса (все-же победнее чем в ruby), до доступа к AST. Все это позволяет создавать человеко-читаемые конфиги, которые на самом деле являются исполняемым кодом на groovy. Под человеком я имею ввиду бизнес-аналитика уровня "могу написать простенький селект с фильтрацией". Когда такой человек начинает читать и успешно править DSL-код - это говорит о многом. DSL эта такая фича, после освоения которой будешь спрашивать себя: как я жил без этого раньше.

Грельсы

Grails - full-stack framework, как они пишут про себя и именно это является проблемой. Для небольшого проекта convention over configuration это отличная идея, резко сокращает объем написания boilerplate кода. маленькому проекту грельсы будут как из пушки по воробьям. А вот в большом проекте начинаются те самые проблемы, за которые ругают maven. Как только пытаешься свернуть с проторенной дорожки, начинаются непролазные дебри. А это неизбежно придется сделать, что-то серьезное неизбежно потребует нестандартных решений: что-то подменить, что-то допилить, где-то изменить логику. 

Вот тут-то и начинаются проблемы: очень тяжело ковырять full-stack, его приходится постоянно таскать с собой даже если тебе не нужна web-часть. То, за что мне так нравилась java, идеология модульности, здесь заменили на огромную spring-кувалду, которой ты вынужден забивать сваи, и гвозди, и шурупы - вообще все что видишь вокруг.

Я скучаю по guice, по его простоте и элегантности. Pivotal действительно стоит подумать о модульности (ведь даже spring модульный, по крайней мере был, когда я на него смотрел). Чтобы можно было разбить доменную модель, сервисный слой, веб-часть

ORM

Разработчики доабстрагировались до маразма и грельсовый GORM настолько неинтуитивен и далек от SQL, что им совершенно невозможно пользоваться без открытой документации в мало-мальски нетривиальных ситуациях (а они обязательно будут, см выше). Маппинг объектов мне тоже не нравится, поскольку, тоже разрывает связанность: вместо задания аннотациями атрибутов у отдельных полей, все собрано в кучу, крайне error-prone. И когда тебе нужно замапить объект приходится идти в документацию, потому что запомнить это совершенно невозможно. Сон разума породил чудовище или тяжелые наркотики, я не знаю. Хотя тривиальные CRUD случаи - абсолютно не требуют мозговых усилий.

Layout

Идеология, положенная в структуру проекта "давайте скинем в отдельную кучу view, в другую кучу controller, в третью service, а в четвертую - domain" - абсолютно порочна. В подавляющем большинстве случаев на один view приходится один контроллер и один сервис. Все это должно быть объединено в один логический модуль и лежать рядом. Они связаны между собой by-desing, и раскидать их по трем кучкам означат разорвать код. На предыдущем проекте, только спустя два года стало понятно, что организовывать код по слоям очень плохая идея и мы потихоньку начали организовывать его в модули.

Еще одна очень плохая идея - в функцию render передаем viewname, который будет искаться с таким же путем как у контроллера, но в папке view по имени _viewname.gsp чтозанах? Это нихера не очевидно, это магия, а я ненавижу хреновых волшебников. Когда я первый раз столкнулся с этим, и обнаружил это зарывшись глубоко в исходники фреймворка, удивлению моему не было предела. Нельзя разрывать имя темплейта и физический путь, тем более ценой каких-то четырех символов.

Итог

Напрашивается закономерный вывод: хитрожопые Pivotal заманивают в свои сети простотой начала проекта, который бегло вырастает до среднего размера, но дальше обязательно появятся проблемы, на них которых неплохо заработать консультированием. Вообще как могут давать "High-level design overview and best practices" люди, которые постоянно нарушают связность кода? - Я сомневаюсь что они используют в реальной практике свое детище.