Metaprogramming
616 subscribers
103 photos
1 video
155 links
μετά- «между, после, через» (греч.)

Жизнь программиста за пределами программирования: алгоритмы, психология, инвестиции, иное.
Download Telegram
Продолжаем цикл "Django глазами Rails-разработчика" (1/3)

Скопилось некоторое количество заметок для себя, которые, как мне кажется, могут быть полезны любому Rails-разработчику, начавшему использовать Django (или наоборот, хоть и в меньшей мере). Не смотря на то, что заметки по понятной причине (поводом для их создания служило, в первую очередь, раздражение от необходимости в очередной раз бороться с фреймворком на ровном месте) сфокусированы на каких-то "острых углах", в целом впечатление довольно ровное и, местами, даже положительное (позитив будет в конце).

Поехали: на что надо обращать внимание Rails-pазработчику в отношении Django, чтобы избежать когнитивного диссонанса и сэкономить время.

1. В Django нет единого кодстайла. Переходя с Rails, где формат названия классов (и файлов, в которых лежат классы), методов, модулей, путей и т.д. строго формализован, и ожидая от фреймворка разрекламированно элегантного языка подобного, рискуешь получить когнитивный диссонанс. В разных популярных библиотеках название метода может быть setup, set_up, setUp: это норма.
2. Примеры кода из документации могут просто не работать в окружении той же версии, для которой написана документация. Часто "есть нюанс", который описан где-то на соседних страницах.
3. Всё может падать без поднятия исключений. Например, сломаться какая-то функция в шаблоне или логгирование – узнать об этом можно только по отсутствию эффекта, сообщения об ошибке может не быть.
4. Пожалуй, худший язык шаблонов из всех существующих. В целом эзотерический синтаксис вызова "хелпер"-функций (которые, создавая дополнительную сложность, разделяют на "фильтры" и "теги") усложняется отсутствием элементарной функциональности: невозможно взять элемент из хеша (по ключу, хранящемуся в переменной), невозможно вызвать метод прокинутого в шаблон объекта (хотя можно взять значение любого атрибута), нельзя сделать присвоение переменной (например, для конкатенации двух строк), и т.д. Хотелось бы оправдать такую ограниченость шаблонов соображениями безопасности (например, liquid-шаблоны известного e-commerce сервиса Shopify, используемые для кастомизации вида пользовательских витрин/магазинов, используют похожий синтаксис, не позволяя при этом писателю шаблона "вылезти из песочницы"), но это будет большой натяжкой: всё равно можно залезть куда угодно через переданные объекты, пользовательский код шаблонов исполнять нельзя.
5. Для нормальной отладки надо использовать сторонние решения (например, debug toolbar). Например, вы иначе не сможете посмотреть код SQL-запросов – в логах их отображение прямолинейным путём не получиться добиться. Впрочем, типовые сторонние решения удобные и достойные, сглаживающие этот недостаток фреймворка.
6. Кстати, про SQL-запросы: в Django нет SQL-кеша. Достали из базы модель по одному и тому же primary key десять раз – получите десять запросов в базу.
7. Открытые (и актуальные) баги десятилетней давности во фреймворке и брошенные мейнстримные пакеты – это норма.
8. Обновление на одну минорную версию какого-то там пакета, который являлся зависимостью какого-то там ещё пакета, который является зависимостью пакета, который вы используете, которое всё сломало – запросто. См. предыдущие посты по тегу про отсутствие встроенного менеджера пакетов (с той функциональностью, которая есть во всех других современных языках – например, lock-файлом) и необходимость использовать сторонние решения.
9. Кстати, про пакеты. В мире Rails для каждой распространённой задачи (как правило) есть гем, являющийся явным "гегемоном". В Django (как правило) существует два и более способа что-то сделать (поддерживаемых pypi пакета), причём оба плохи.

#programming #django #rails
Продолжаем цикл "Django глазами Rails-разработчика" (2/3)

В продолжение предыдущего поста:

10. И в целом, в Python/Django, в отличие от Ruby/Rails, регулярно встречаются ситуации, когда есть два (три, четыре...) способа сделать элементарную вещь, причём все плохие. Например, в Python нет нормальной интерполяции строк (и в Django аналогично с интерполяцией фрагментов HTML). Зато есть три (или четыре?) плохих способа. В Python нет нормального способа проверить существование файла – опять, вместо этого предлагают три-четыре костыля. Нет нормального фреймворка для тестирования (справедливости ради, здесь всё же есть мейнстримный pytest, т.е. только одно плохое решение, а не несколько, что хотя бы избавляет от мук выбора). И т.д.
11. В Django работа с почтой реализована на уровне Rails 2.x (то есть примерно 2007 года).
12. В Django ужасно некрасивый по форме и кривой по функциональности ORM. В Rails в целом понимают, что ORM нужен для пяти операций, которые покрывают 90% функциональности. В Django прямо заявляют, что ORM должен покрывать 100% кейсов, а про SQL забудьте, это другой уровень абстракции. Поэтому то, что в Rails решается вставкой SQL-кода из пяти ключевых слов в одну функцию внутри scope-а (метода класса; в Django аналогом будет метод "менеджера"), в Django превращается в попытку описать ограниченными и криво работающими примитивами Django-классов то, чего вы хотите получить, но сильно обходным путём (по сути такое описание AST-дерева SQL инструкции через сборку Django-классов, определяющих узлы этого дерева). Подобный идиотизм был и в Phoenix-е (фреймворке на Elixir-е), но там всё же мучения были, по воспоминаниям, гораздо меньше из-за того, что функциональный язык для таких штук прямо приспособлен.
13. Кстати, про ORM. В Django крайне затруднительно создать работающее виртуальное (computed, не существующее в базе данных) поле. В Rails с этим никаких проблем: определяем атрибут в модели, просто как в обычном Ruby-классе, и в формах всё работает. Впрочем, см. п.5 в следующем посте.

#programming #django #rails
Продолжаем цикл "Django глазами Rails-разработчика" (3/3)

В завершении цикла обещанный позитив:

1. В шаблонах Django используется интересный и, в целом, функциональный механизм наследования. Он более последовательный и логичный чем система layouts и partials из Rails. В Django любую вьюху можно отнаследовать от любой другой (например, зашитой в сторонний пакет или встроенную админку), а затем точно также отнаследовать ещё одну и т.д. Родительская вьюха через инструкцию block (аналог content_for из Rails) обозначает места, куда дочерняя может (через ту же инструкцию) вставить контент (заменив или дополнив тот, что туда прописала одна из родительских вьюх). Вещи типа двух (трёх, четырёх...) лэйаутов для одной вьюхи реализую логично и прямолинейно, в отличие от Rails, где это делается с помощью хитрых манёвров и велосипедостроения.
2. В Django встроенная админка с довольно неплохой функциональностью. В целом она вызывает смешаные чувства восхищения и раздражения. Первое – когда делаешь нечто стандартное, а второе – когда пытаешься дописать свою функциональность (пусть создатели фреймворка и не сделали этот процесс очень удобным или элегантным, но явно предусмотрели все необходимые "точки расширения"). Увы, я не пользовался active-admin или аналогичными гемами, поэтому не могу сравнить с прямыми аналогами из мира Rails: наверное, там примерно такое же впечатление осталось бы.
3. До какого-то времени в Python не было оператора case. "Используйте if или хеши (dict-ы)". В последнюю версию добавили pattern matching, который, на первый и беглый взгляд, производит впечатление менее небрежной работы, чем аналог из последних версий Ruby (на практике в обоих языках использовал эту фичу, пока что, весьма мало для вердикта).
4. В Django встроено управление пользователями. Создавая новый проект, не надо с нуля создавать модель пользователя, функциональность управления паролями, расписывать логику токенов подтверждения почты и вот это всё. На мой взгляд, это удобней использования рубишного гема devise (который, зачастую, добавляет уже слишком много всего).
5. В Django есть встроенная абстракция "форм" (form objects). Промежуточный слой между моделями (прибиты гвоздями к базе данных) и интерфейсом пользователя (который вовсе не обязан вводить данные в том формате, который используется у вас в БД) это очевидная необходимость, и в Rails не является частью фреймворка только из-за специфических анахроничных взглядов DHH на архитектуру типового веб-приложения. (Частично компенсируется наличием сторонних gem-ов.)

#programming #django #rails
Rails credentials without active support

Для тех, кому нужно было зачем-то расшифровывать rails credentials в стороннем приложении без подключения active support – набросал решение.

#programming #rails