Что я прочитал - не только ORM
Ссылка на оригинал: https://habr.com/ru/articles/818761/
Ссылка на гитхаб проекта: https://github.com/amaslyaev/noorm
Кратко
В статье автор описывает устройство ORM и основную, на его взгляд, проблему такого подхода — "персистетные объекты". И предлагает альтернативу в виде кастомной библиотеки, позволяющей работать с БД без использования персистетных объектов, при этом не засоряя основной код SQL-запросами.
Выдержка про проблему персистентных объектов:
Примечательно здесь то, что работа с базой данных идёт через персистентные объекты, являющиеся экземплярами «модельных» классов, описывающих структуру БД. Эти персистентные объекты умеют себя прочитать из базы и в неё себя записать. Они живут внутри открытой сессии. И ещё эти объекты умеют «лениво» дотягивать из базы связанные с ними другие персистентные объекты. Эти самые персистентные объекты — корень всех проблем:
1. По сути, это передача мутабельного объекта в другой процесс. Безобразно тупая затея. Мы запросили сущность «пользователь Вася» из базы данных в процесс своего бэкенда, и теперь где у нас теперь мастер-копия? Как мы их собираемся синхронизировать, в какой момент, и что собираемся делать с возможными коллизиями?
2. Что случается с живущими в сессии объектами когда сессия закрывается? Что если они продолжают быть нужны в логике приложения? Что если эта логика продолжает считать, что это по-прежнему нормальные объекты, принадлежащие живой сессии?
3. Невозможно найти единственно правильный баланс между eager- и lazy-загрузкой. Если увлекаемся lazy, получаем проблему N+1, и всё начинает страшно тормозить. Если увлекаемся eager, на каждый невинный чих ORM пытается вычитать полбазы, и тоже всё тормозит. Короче, у нас две педали, но обе они педали тормоза.
Какой подход предлагает автор взамен?
Выделение отдельного модуля с логикой БД и SQL-запросами, который может выглядеть примерно так:
from dataclasses import dataclass import noorm.sqlite3 as nm @dataclass class DbUser: id: int username: str email: str @nm.sql_fetch_all(DbUser, "SELECT rowid AS id, username, email FROM users") def get_users(): pass
Использование датакласса позволяет однозначно определить возвращаемую структуру данных и ограничить её тип, что может быть довольно полезно при использовании этой самой структуры. Кроме того, в подсказке в IDE будет выводиться весь набор её свойств.
Выводы
В целом, подход имеет место быть и я даже уже начал собирать небольшой пет-проект с использованием NoORM. В ближайшие дни будет несколько постов по этой теме. Подумываю о том, чтобы снять об этом даже полноценное видео (не о самом подходе, а скорее о пет-проекте).