There will be no singularity – Telegram
There will be no singularity
1.99K subscribers
248 photos
15 videos
5 files
995 links
Smartface, technologies and decay
@antonrevyako
Download Telegram
Судя по результатам голосования под предыдущим постом, тут собрался дружный коллектив извращенцев...

Ну что ж, мои маленькие «мои вкусы весьма специфичны», как вам такое?


https://www.zombodb.com/
Моя любимая тема на побомбить - ORM vs SQL. Я даже накопил много мнений уважаемых людей по этому поводу, и обязательно сделаю подборку.

А пока вот баян от сисадминтулс:
https://news.1rj.ru/str/sysadmin_tools/3924

И вот еще один от Егора "ООП" Бугаенко
https://www.yegor256.com/2014/12/01/orm-offensive-anti-pattern.html
штош...
мощь!
🔍 Теперь можно grep'нуть по всему github'у нужное вам вхождение прямо из браузера: https://grep.app/ #линк #github
а что вы скажете на то, что я все-таки сделал ORM наоборот?..

(вы недавно за это голосовали - https://news.1rj.ru/str/nosingularity/623)
Год назад AWS представили CodeGuru (я изложил тогда свое мнение об этом).
Это сервис по автоматизации поиска ошибок в Java-сорцах.

Работает оно не как статический анализатор, а на базе AI. Таких сервисов не один и это довольно скользкий путь. Все же знают про garbage in - garbage out?

Тогда я ванговал, что концепции галерной перепродажи джунов за ценник синьора скоро будет тяжеловато, т.к. заказчик будет видеть отчеты о качестве прям в админке AWS.

Прошел год и говорят, что AWS сделали CodeGuru для Python...
Музыкальная пауза

Поймал себя на мысли, что для деда мои музыкальные вкусы довольно специфичны.
В список к Пошлая Молли, Буерак, Пасош и Оля и Секретный Завод добавились еще одни тягомотные страдальцы - ssshhhiiittt!

Еще неплохо получается у Тося Чайкина

В свое оправдание могу заменить, что, скорее всего, это тяжелое наследие Radiohead, NIN и брит-попа. Подозреваю, что где-то еще произошел левак с Depeche Mode. Но думать об этом не хочется...
Что такое ORM наоборот?

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

1) Все пишется на одном языке, который знает разработчик любого грейда
2) Схема базы описываться в коде приложения, т.е. мы имеем один источник правды
3) Одна модель - один релейшен. CRUD может сгенерировать сам фреймворк.
4) Запросы собираются в коде и полностью соответствуют схеме
5) ORM все знает про маппинг типов базы в типы языка программирования
6) Вся логика в приложении, база только хранит данные

Из 2 и 4 следует еще один плюс - при миграции сложно будет все сломать.
Насколько я понимаю, без типизации сломать таки будет несложно, но давайте предположим, что мы все пишем на языках с явной типизацией. (хехе)

Не будем выявлять слабые места в этом списке. Лучше посмотрим на текущую ситуацию с разработкой приложений с использованием реляционных баз на чистом SQL.
Очевидные минусы:
1) Нужно знать +1 язык программирования (SQL)
2) Нужно разбираться в тонкостях работы используемой базы
3) Маппинг типов может зависеть от используемой библиотеки и об этом нужно знать
4) Приходится писать избыточный код - один раз на SQL и в приложении, чтобы отдать данные потребителю.

И самое неприятное - НЕТ НИКАКОЙ ГАРАНТИИ СООТВЕТВИЯ ЗАПРОСОВ И СХЕМЫ, а так же ТИПОВ РЕЗУЛЬТАТА ЗАПРОСА И ТИПОВ ВНУТРИ ПРИЛОЖЕНИЯ.
Каждые изменения в схеме влекут за собой ручную проверку, много тестов, переписывание типов и схем для протоколов.

А плюсы?
1) Можно максимально гибко использовать возможности базы
2) В большинстве случаев можно избежать проблемы N+1, что очень благотворно сказывается на производительности приложения и бюджете на железо
3) Вычисления рядом с данными делаются намного быстрее, чем те же вычисления в приложении

Кроме того, нормализация данных не подразумевает, что мы запихиваем одну доменную сущность в одну таблицу. Т.е. CRUD, затрагивающий 1 таблицу практически никогда не имеет смысла.
Создание или изменение бизнес сущности генерирует изменения в нескольких таблицах. Если выполнять все эти операции в одном запросе c common table expression, то все это выполнится (или нет) в пределах 1 транзакции. Иначе нам придётся реализовывать все нужные шаги в приложении с соответствующим количеством сетевых взаимодействий.

Но как же нам быть, если мы по какой-то причине уже хорошо знаем SQL, умеем CTE, LATERAL, FILTER, IS DISTINCT OF и знаем как оптимизировать count, но нам надоело контролировать целостность руками и писать кучу лишнего кода внутри приложения только для того, чтобы прокинуть данные от базы к клиенту?

Я предлагаю взять лучшее от обоих миров: пишем на SQL, а (почти) весь код приложения будет генерироваться автоматически!

Что нам для этого понадобится?
1) DDL в одном или нескольких файлах
2) Каждый отдельный DML-запрос придется теперь не собирать в коде приложения, а хранить в виде отдельного файла
3) Какое-то соглашение по именованию объектов в сгенерированном коде: как бы будем генерить имена типов, контроллеров, моделей и всего остального
4) Шаблоны кода для интересующего нас языка программирования
5) Маппер типов базы в типа интересующего нас языка программирования

Берем DDL, DML, извлекаем из DML метадату о результате (типы, nullability, класс количества строк), генерируем код (+ схемы, + тесты) и экономим больше половины рабочего времени!

Бонусом идут:
1) Автоматический контроль за изменением типов возвращаемых запросом значений при рефакторинге базы или запроса
2) Автоматический контроль за соответствием типов в запросе и коде приложения
3) Интеграция в CI
4) Все бенефиты статического анализатора holistic.dev :)


Ну как?
Чувствую, что к предыдущему посту требуется пояснительная бригада.

Я не призывал заменить все приложения на SQL. Я ж не из компании Oracle :)
И не из Lingualeo :)

Совершенно необязательно подобным образом генерировать весь код приложения. Можно генерировать код только для точек сопряжения приложения и базы.

Мне любезно подсказали инструмент, который решает ту же проблему:
https://github.com/adelsz/pgtyped

Задумано красиво - берем запросы, берем готовую запущенную(!) базу, делаем prepared statements, понимаем что будет на выходе.

Несомненный плюс - невозможно накосячить. Типы будут экспортированы точно так как нужно, а не так, как запрограммировал какой-то анон из интернета.

Но не обошлось без минусов:
- работает только с Postgresql
- экспортирует только в ts
- ничего не знает про nullability результатов
- ничего не знает про класс количества строк

Если про первые 2 пункта все понятно, то про важность последних поговорим отдельно.

Если вы пишете не на Java, где любая переменная может быть null, то довольно много логики может быть завязано на то, может ли переменная принимать значение null или нет.
Читаешь из ответа поле и используешь его в качестве индекса массива или имени свойства объекта? Молодец, лови undefined! Или сегфолт.
Или проверяй каждый раз - null или нет. И думай что делать, если null, которого быть не должно.

WTF класс количества строк?
Статическими методами, естественно, невозможно оценить сколько точно строк вернет запрос. Но можно попробовать рассчитать количество в следующих категориях - NONE, ONE, ONE OR NONE, MANY, MANY OR NONE. Если вы пишете на js и используете pg-promise, то в нем есть методы с соответствующими названиями, которые автоматически делают assert.

Зачем?
Обычно я привожу такой пример.
Пишите вы финансовую систему. Есть у вас запрос, который создает ордер на вывод денег. И запрос сложный. С кучей изменяющих данные CTE, джойны из вьюх и вот это все.
И вы знаете, что он вернет ровно одну строку, в которой будет id нового ордера.
На самом деле вы ДУМАЕТЕ, ЧТО ЗНАЕТЕ. В случае со сложными запросами это практически нереально оценить на глаз. Особенно человеку, который только онбордится в проект.
Но допустим, что это реально так.

Вы написали тесты на этот функционал все вроде бы ок.

Но вот нужно сделать новую фичу. Вы, или что хуже, новый сотрудник, рефакторит базу. В процессе удаляет какой-то существующий констрейнт. Например, NOT NULL становится NULL.
Внимание, вопрос: сломается ли что-то из 500/1000/2000 запросов в вашей базе?

А это мы сейчас проверим! У нас же есть тесты! (гыгыгы)
Давайте опустим тот момент, что тесты не покрывают все возможные комбинации данных в базе.

Запустили тесты и... Все ок :) Старое поведение не поменялось.
Все задеплоили, ушли домой.

Но, как обычно, в ночь с пятницу на субботу, начали массово поступать данные от новой фичи.

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

-----

Есть еще много полезных вещей, которые можно извлечь из запроса, если парсить его целиком, а не читить, как pgtyped.

Например, список всех релейшенов (таблицы, вьюхи) и типы воздействия на них (SELECT/INSERT/UPDATE/DELETE)
Или список всех связей, которые есть в join/where.
Продолжают поступать ссылки на различные тулзы, связанные с SQL. У меня есть подборка, куда я все это добро добавляю:
https://github.com/antonrevyako/useful-links/blob/master/opensource-sql-tools.md

Так же есть пост с подборкой экзотических применений SQL:
https://news.1rj.ru/str/nosingularity/595
Новых баз развелось настолько много, что до сих пор есть такие, про которые я ничего не слышал :)
Вот 3 последних открытия:

edgedb.com - combines the simplicity of a NoSQL database with relational model’s powerful querying, strictness, consistency, and performance

materialize.com - Incrementally-updated materialized views - in ANSI Standard SQL and in real time.

github.com/dolthub/dolt - is a SQL database that you can fork, clone, branch, merge, push and pull just like a git repository
​Помнится, еще был такой проект, который блокчейн поверх postgresql делал:


https://github.com/postgrespro/pg_credereum

Видеоблог с летсплеем баз что-ли запилить? :)
Как вы думаете, сколько времени уйдет на поиск этой проблемы в проде?

https://twitter.com/lukaseder/status/1336607250765508608

А использовал бы holistic.dev - таких проблем бы не было:
https://holistic.dev/playground/23136705-a747-44f8-8fe0-881c17edc222

> Alias "expiration_date" equal to the field name in relation "public.license" (alias-equal-to-field-name)


На самом деле до прода бы это, скорее всего, не дошло. Но лишние 30-60 минут бы съело, если бы заметили на этапе тестов. Или больше, если тестов нет :)
Именно поэтому правила про архитектуру мне нравиться писать больше, чем про производительность :)