Новогодняя загадка для любимых подписчиков. Как новая аватарка связана с названием канала❓
Об админках.
Представим, что вы работаете с малым или средним бизнесом, и у вас стоит задача, написать бэкенд, рядом с которым обязательно должна быть админка. И по разным причинам вы не хотите иметь дело с CMS. Возможно у вас аллергия на wordpress или вы недостаточно тертый калач, чтоб связываться с Bitrix/Drupal😔
Давайте попробуем разобраться, какие решения для админ панелей существуют на данный момент в разрезе разных языков программирования и технологий. Но прежде, я бы хотел перечислить требования, которым должна удовлетворять хорошая админ панель.
1. Функциональность 🫡. Очевидно, админка должна выполнять свои функции. Причем, это должен быть не просто CRUD для моделей (data grids, формы). В идеале админка должна понимать связи между моделями, и должна давать возможность делать CRUD операции со связанными сущностями. Аутентификация, авторизация - само собой. Должен быть форм билдер - возможность декларативно описывать кастомные формы.
2. Расширяемость 🤏. Из коробки админка должна давать возможность изейше решать 90% всех задач по управлению данными. Но если припрет написать что-то кастомное - такая возможность должна быть доступна без костылей.
3. Популярность 🍑. Какую бы библиотеку вы не использовали, важно быть уверенным, что эта библиотека завтра непревратится в тыкву будет заброшена. Иначе говоря, размер комьюнити вокруг того или иного решения важен. Обычно это коррелирует с количеством звездочек на гитхабе.
4. Нестыдность 👑 (опционально). Внешний вид админ панели должен соответствовать реалиям 2025, а не 2005 года. Это часто сопровождается использованием современных js и css фреймворков под капотом. Но этот пункт я не считаю обязательным, поскольку он вступает в прямое противоречие с пунктом 3, который для меня лично более важен. Тем не менее, я оставляю этот пункт как требование, потому что красивая админ панель может произвести благостное впечатление на пользователей. А пользователи в нашем случае (напоминаю, имеем дело с малым и средним бизнесом), это люди близкие к бизнесу. Так что было бы неплохо, если они были бы довольны красивой админкой, и рассказали бизнесу, какие мы пиздатые разработчики, такую красивую админку запилили.
5. Понимаемость 🤷 (опционально). Здесь речь идет про документацию и примеры, которые обеспечат быстрое погружение и старт разработки. Особое внимание я бы уделил наличию демо. Мне кажется, что работающий живой пример, с доступной кодовой базой - это прям +100 очковгриффиндору привлекательности решения. Опять же, это опциональное требование, поскольку, разобравшись в каком-то решении один раз, дальше это уже не будет проблемой. Если с остальными пунктами все в порядке, на этот пункт мы сможем закрыть глаза со временем. Но к сожалению именно этот пункт может отпугнуть разработчиков в самом начале.
И тут я хочу прерваться, и про конкретные решения поговорить уже в следующем посте.
В комментариях поделитесь, согласны ли вы с требованиями выше, и что бы выхотели добавить или убрать.
Представим, что вы работаете с малым или средним бизнесом, и у вас стоит задача, написать бэкенд, рядом с которым обязательно должна быть админка. И по разным причинам вы не хотите иметь дело с CMS. Возможно у вас аллергия на wordpress или вы недостаточно тертый калач, чтоб связываться с Bitrix/Drupal😔
Давайте попробуем разобраться, какие решения для админ панелей существуют на данный момент в разрезе разных языков программирования и технологий. Но прежде, я бы хотел перечислить требования, которым должна удовлетворять хорошая админ панель.
1. Функциональность 🫡. Очевидно, админка должна выполнять свои функции. Причем, это должен быть не просто CRUD для моделей (data grids, формы). В идеале админка должна понимать связи между моделями, и должна давать возможность делать CRUD операции со связанными сущностями. Аутентификация, авторизация - само собой. Должен быть форм билдер - возможность декларативно описывать кастомные формы.
2. Расширяемость 🤏. Из коробки админка должна давать возможность изейше решать 90% всех задач по управлению данными. Но если припрет написать что-то кастомное - такая возможность должна быть доступна без костылей.
3. Популярность 🍑. Какую бы библиотеку вы не использовали, важно быть уверенным, что эта библиотека завтра не
4. Нестыдность 👑 (опционально). Внешний вид админ панели должен соответствовать реалиям 2025, а не 2005 года. Это часто сопровождается использованием современных js и css фреймворков под капотом. Но этот пункт я не считаю обязательным, поскольку он вступает в прямое противоречие с пунктом 3, который для меня лично более важен. Тем не менее, я оставляю этот пункт как требование, потому что красивая админ панель может произвести благостное впечатление на пользователей. А пользователи в нашем случае (напоминаю, имеем дело с малым и средним бизнесом), это люди близкие к бизнесу. Так что было бы неплохо, если они были бы довольны красивой админкой, и рассказали бизнесу, какие мы пиздатые разработчики, такую красивую админку запилили.
5. Понимаемость 🤷 (опционально). Здесь речь идет про документацию и примеры, которые обеспечат быстрое погружение и старт разработки. Особое внимание я бы уделил наличию демо. Мне кажется, что работающий живой пример, с доступной кодовой базой - это прям +100 очков
И тут я хочу прерваться, и про конкретные решения поговорить уже в следующем посте.
В комментариях поделитесь, согласны ли вы с требованиями выше, и что бы выхотели добавить или убрать.
Продолжаем об админках.
Пробежимся по наиболее популярным технологиям и языкам программирования в попытке составить какую-то картину.
1. golang / nodejs🔤 🔤 🔤 🔤 🔤 . Ну тут все понятно. здесь микрофреймворки, поэтому админок ожидать не приходится.
Вообще чутье подсказывает, что админки стоит искать там, где есть крепкая связка фреймворк + ORM. golang и nodejs не об это совершенно.
2. java (spring). "НИ-ХУ-Я, вот просто НИ-ХУ-Я". Это было одним из сюрпризов. Технология стара, как говно мамонта. Я ожидал, что здесь будет куча решений. Но мои ожидания - это мои проблемы. Нет, какие-то решения все же есть, например SnapAdmin, но это молодая билиотека, и с ней ничего пока неясно. Из популярного есть jhipster, но это генератор кода, который хоть и позволяет нагененрировать UI компоненты (на ангуляре), но это все же не то. Короче говоря, в 2024 году мир java все еще не настроен на быстрые решения для бизнеса.
3. ruby (on Rails). Здесь существуют 2 популярных решения ActiveAdmin и RailsAdmin. И если первое решение еще выглядит современно и построено с использованием всяких TailwindCSS, то второе это просто какая-то бабкина радость (картинка прилагается). Документация ActiveAdmin понятная, но мне показалось, что функционал куций. Я уже говорил про то, что админка должна уметь работать со связями. Здесь это делается при помощи отдельных внутренних страниц, что не есть гуд. Редитторы подтверждают мои опасения, и советуют вообще никаких админок не использовать. Там же некоторые советуют попробовать Avo, который выглядит неплохо и имеет более богатый функционал, но он какой-то полу-платный и звезд на гитхабе меньше. Тут можно посмотреть информацию о всех гемах в категории Rails Admin Interfaces.
4. python (django). Ну тут все просто. В django есть своя админка из коробки, и это очень круто, ведь не надо ничего выбирать. Более того, ее хвалят, потому что у нее богатый функционал, и она очень хорошо кастомизируется. Даже несмотря на то, что дефолтный вариант выглядит простовато и использует jQuery, всегда можно накатить, что-то вроде django-unfold, и вот у вас уже куча красивых виджетов и тейлвинд. Обычно, когда спрашивают про админку, то всегда имеет место сравнение с django admin. Это о многом говорит.
5. php (symfony и laravel). Про symfony скажу кратко: есть EasyAdmin. Ну есть и есть. Много от него ждать не стоит. Он от вас тоже ничего не ждет.
Про Laravel хочется остановиться подробнее, ибо этотговнофреймворк специализируется на том, чтоб вы могли завтра уже в продакшне что-то запустить. И конечно здесь есть своя нативная админка Nova, которая даже хороша, но она платная🤡. И это на фоне того, что кроме Novы, у нас есть еще куча вариантов, а именно Filament, Orchid и сейчас набирает популярность Moonshine. Также есть генератор Backpack.
Для своего пет проекта я вот как раз выбрал Filament, и мне тут есть что сказать. Во-первых, это 20к звезд на гитхабе, это своя экосистема с плагинами, это возможность делать свои свистелки-перделки на фронтенде, не написав ни одной строчки js. Это больше чем просто админка. Filament базируется на технологии Livewire, которая позволяет писать динамичные фронтенд компоненты на пхп. И конечно же у этого всего есть обратная сторона: Filament непростой в освоении. Что-то пошло не так - все, ты в очке. Что - то не работает - ты в очке. Ты читаешь доку - ты в очке. Короче, ты часто в очке первое время. Но когда ты не в очке, ты счастлив. Ведь у тебя столько всего работает из коробки, и оно такое красивое, а ты при этом пхпист.
Orchid и Moonshine хорошие админки, и они не уступают Django admin. Обе просты в освоении, и приятны на глаз. Но к сожалению, ни одна из них не сможет дать тебе тех же ощущений от разработки, что дает Filament.
6. ASP.NET. Простите, дотнетчики, мне это не интересно=) Но вроде там есть платные админки какие-то
В заключении хочу сказать, что админ панель - это довольно серьезное бизнес требование. Для нового проекта может иметь смысл сократить пару сотен часов разработки, выбрав соответствующую технологию.
Пробежимся по наиболее популярным технологиям и языкам программирования в попытке составить какую-то картину.
1. golang / nodejs
Вообще чутье подсказывает, что админки стоит искать там, где есть крепкая связка фреймворк + ORM. golang и nodejs не об это совершенно.
2. java (spring). "НИ-ХУ-Я, вот просто НИ-ХУ-Я". Это было одним из сюрпризов. Технология стара, как говно мамонта. Я ожидал, что здесь будет куча решений. Но мои ожидания - это мои проблемы. Нет, какие-то решения все же есть, например SnapAdmin, но это молодая билиотека, и с ней ничего пока неясно. Из популярного есть jhipster, но это генератор кода, который хоть и позволяет нагененрировать UI компоненты (на ангуляре), но это все же не то. Короче говоря, в 2024 году мир java все еще не настроен на быстрые решения для бизнеса.
3. ruby (on Rails). Здесь существуют 2 популярных решения ActiveAdmin и RailsAdmin. И если первое решение еще выглядит современно и построено с использованием всяких TailwindCSS, то второе это просто какая-то бабкина радость (картинка прилагается). Документация ActiveAdmin понятная, но мне показалось, что функционал куций. Я уже говорил про то, что админка должна уметь работать со связями. Здесь это делается при помощи отдельных внутренних страниц, что не есть гуд. Редитторы подтверждают мои опасения, и советуют вообще никаких админок не использовать. Там же некоторые советуют попробовать Avo, который выглядит неплохо и имеет более богатый функционал, но он какой-то полу-платный и звезд на гитхабе меньше. Тут можно посмотреть информацию о всех гемах в категории Rails Admin Interfaces.
4. python (django). Ну тут все просто. В django есть своя админка из коробки, и это очень круто, ведь не надо ничего выбирать. Более того, ее хвалят, потому что у нее богатый функционал, и она очень хорошо кастомизируется. Даже несмотря на то, что дефолтный вариант выглядит простовато и использует jQuery, всегда можно накатить, что-то вроде django-unfold, и вот у вас уже куча красивых виджетов и тейлвинд. Обычно, когда спрашивают про админку, то всегда имеет место сравнение с django admin. Это о многом говорит.
5. php (symfony и laravel). Про symfony скажу кратко: есть EasyAdmin. Ну есть и есть. Много от него ждать не стоит. Он от вас тоже ничего не ждет.
Про Laravel хочется остановиться подробнее, ибо этот
Для своего пет проекта я вот как раз выбрал Filament, и мне тут есть что сказать. Во-первых, это 20к звезд на гитхабе, это своя экосистема с плагинами, это возможность делать свои свистелки-перделки на фронтенде, не написав ни одной строчки js. Это больше чем просто админка. Filament базируется на технологии Livewire, которая позволяет писать динамичные фронтенд компоненты на пхп. И конечно же у этого всего есть обратная сторона: Filament непростой в освоении. Что-то пошло не так - все, ты в очке. Что - то не работает - ты в очке. Ты читаешь доку - ты в очке. Короче, ты часто в очке первое время. Но когда ты не в очке, ты счастлив. Ведь у тебя столько всего работает из коробки, и оно такое красивое, а ты при этом пхпист.
Orchid и Moonshine хорошие админки, и они не уступают Django admin. Обе просты в освоении, и приятны на глаз. Но к сожалению, ни одна из них не сможет дать тебе тех же ощущений от разработки, что дает Filament.
6. ASP.NET. Простите, дотнетчики, мне это не интересно=) Но вроде там есть платные админки какие-то
В заключении хочу сказать, что админ панель - это довольно серьезное бизнес требование. Для нового проекта может иметь смысл сократить пару сотен часов разработки, выбрав соответствующую технологию.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🆒2
Screenshot 2025-01-18 at 17.18.45.jpeg
18.3 KB
Тока шо наткнулся на настоящий бриллиант нейминга. Это как раз в коде Filament. Го в комментах делиться аналогичными находками в библиотеках. Посмотрим, у кого длинее😏
😁7🤯1👌1
Сегодня у нас обзор на книгу Адама Беллемара "Создание событийно-управляемых микросервисов".
Плюсы:
* Качественная бумага
* Разборчивый шрифт
* Страницы перелистываются
Минусы
* Содержание
* Перевод
Данная книга - прекрасный образец бесполезной книги по программированию. Когда ее читаешь, то ты можешь находиться в одном из двух состояний: ты все понимаешь, потому что ты уже это знаешь, либо ты ничо не понимаешь и не поймешь после прочтения. Причем второе состояние возникает чаще первого. Перехода между состояниями нет.
Автор любит наваливать очень много абстрактного текста, приправленного столь же абстрактными картинками (см. фото). Из этой книги вы не узнаете про типы коммуникации между микросервисами (например, что такое pub-sub или 2 queues request-response), не узнаете, что такое transaction outbox или CQRS, и вы даже не увидите ни одной строчки реального кода микросервиса. Да и реальных примеров не будет. Зато будет много тескта в стиле "учитывайте бизнес требования! читайте документацию! занимайтесь физкультурой! снимайте штаны, прежде чем покакать!" 💪
Мне кажется на обложке книги изображен сам автор. Иначе, я не могу объяснить, откуда вообще весь этот текст взялся.
И если содержание книги похоже на торт из трижды переваренного кала, то перевод книги - вишенка на этом торте. Переводчик здесь оторвался по полной. Например, deadlock внезапно перевели как виртуальный тупик🤡 Шаблон sidecar - это, оказывается, КОЛЯСКА!!! не знали, да? попытка загуглить "шаблон коляска" выдает трафареты детских колясок😁 И, наконец, мое любимое: repartioning перевели как переподразделение, а copartioning как соподразделение. Можно развить идею. Например, если хочется немножко переподразделить что-то, то это будет подпереподразделение🤡
Короче автор и переводчик - это прям Биба и Боба. Один зачем-то высрал ненужный трактат ни о чем, другой это приправил "колясками". В итоге, читать невозможно, да и не сильно то нужно.
Какой вывод? Не все книги полезны. Не будьте как я, читайте отзывы перед покупкой😘
Плюсы:
* Качественная бумага
* Разборчивый шрифт
* Страницы перелистываются
Минусы
* Содержание
* Перевод
Данная книга - прекрасный образец бесполезной книги по программированию. Когда ее читаешь, то ты можешь находиться в одном из двух состояний: ты все понимаешь, потому что ты уже это знаешь, либо ты ничо не понимаешь и не поймешь после прочтения. Причем второе состояние возникает чаще первого. Перехода между состояниями нет.
Автор любит наваливать очень много абстрактного текста, приправленного столь же абстрактными картинками (см. фото). Из этой книги вы не узнаете про типы коммуникации между микросервисами (например, что такое pub-sub или 2 queues request-response), не узнаете, что такое transaction outbox или CQRS, и вы даже не увидите ни одной строчки реального кода микросервиса. Да и реальных примеров не будет. Зато будет много тескта в стиле "учитывайте бизнес требования! читайте документацию! занимайтесь физкультурой! снимайте штаны, прежде чем покакать!" 💪
Мне кажется на обложке книги изображен сам автор. Иначе, я не могу объяснить, откуда вообще весь этот текст взялся.
И если содержание книги похоже на торт из трижды переваренного кала, то перевод книги - вишенка на этом торте. Переводчик здесь оторвался по полной. Например, deadlock внезапно перевели как виртуальный тупик🤡 Шаблон sidecar - это, оказывается, КОЛЯСКА!!! не знали, да? попытка загуглить "шаблон коляска" выдает трафареты детских колясок😁 И, наконец, мое любимое: repartioning перевели как переподразделение, а copartioning как соподразделение. Можно развить идею. Например, если хочется немножко переподразделить что-то, то это будет подпереподразделение🤡
Короче автор и переводчик - это прям Биба и Боба. Один зачем-то высрал ненужный трактат ни о чем, другой это приправил "колясками". В итоге, читать невозможно, да и не сильно то нужно.
Какой вывод? Не все книги полезны. Не будьте как я, читайте отзывы перед покупкой😘
🤣11😁2❤1🫡1
Я капец как не люблю и не умею рисовать. Каждый раз, когда мне надо что-то где-то изобразить, у меня происходит вспотевание лба и других частей тела. Даже если я использую что-то вроде draw.io, где уже есть куча готовых элементов - перетаскивай и используй - у меня всегда выходит какой-то разноцветный кал 🌈
Поэтому я все больше проникаюсь декларативным рисованием диаграмм. В частности, мне очень зашел mermaid🧜♀️
Под "декларативным рисованием" я подразумеваю работу с диаграммами с помощью специального конфигурационного файла. Непосредственная отрисовка диаграмм отводится ПО, которое принимает на вход этот файл, а на выходе получается уже готовая картинка. Любые изменения в существующей диаграмме делаются через модицикацию конфига.
Именно так и работает mermaid. Отрисовка диаграммы выполняется в контексте определенной нотации, например Flowchart, Entity Relationship, Gantt и др. Mermaid поддерживает более 20 различных нотаций. Для каждой нотации существует свой описательный язык.
Очевидные плюсы такого подхода, по сравнению с традиционными рисовалками в стиле "драг-н-дроп прямоугольник":
* стандартизованность - единое представление одних тех же типов элементов
* diagram as code с возможностью положить диаграмму в vcs и отслеживать историю изменений
* local first approach (привет obsidian и его клоны)
Но существует также и неочевидный плюс. Подобный подход позволяет думать, рисуя. Потому что я не отвлекаюсь на построение лэйаута для элементов, выравание их, покраску, выбор размера шрифта и прочие очень важные действия. Все эти проблемы уже решили за меня. Вместо этого я могу сконцентрироваться на сути диаграммы, на абстрактном отношении между ее элементами. А ее визуальное представление помогает мне понять, чего не хватает или что здесь лишнее. При таком подходе диаграмма выступает одним из инструментов проектирования.
Подобное можно испытать не только в mermaid. Например, существует C4 нотация для построения диаграммы архитектуры ПО. Чаще всего C4 используется для документации уже существующей архитектуры. Однако недавно мне довелось заниматься проектированием системы с нуля (в рамках обучающего курса, ничего серьезного). Я использовал PlantUML для построения С4 диаграммы этой системы. И в какой-то момент, поймал себя на мысли, что я проектирую с использованием этой диаграммы, используя PlantUML в качестве языка проектирования. Очень круто!
А какие же минусы такого подхода? Главный и наверное единственный минус - нужно разобраться в нотации и в описательном языке выбранного инструмента. Это потребует от вас какое-то время на вкатывание. Но благо, в том же memaid документация строится на конкретных примерах. Так что пара часов максимум - и вы уже шарите в этой теме.
Но даже в этом минусе я вижу плюс. Вам надо будет изучить нотацию выбранного типа диаграммы, а значит, у вас будет правильное понимание примитивов данной нотации, вы не изобразите нестандартизованную херню.
В общем, если вы часто чего-то рисуете с помощью перетаскивания стрелочек, то я рекомендую попробовать посмотреть в сторону mermaid и подобного тулинга. Если вы редко рисуете, то тут уже на ваше усмотрение. В таком случае проще может быть накидать что-то драг-н-дропом, чем разбираться в документации.
В комментах поделитесь, где вы рисуете ваши диаграммы?
Поэтому я все больше проникаюсь декларативным рисованием диаграмм. В частности, мне очень зашел mermaid🧜♀️
Под "декларативным рисованием" я подразумеваю работу с диаграммами с помощью специального конфигурационного файла. Непосредственная отрисовка диаграмм отводится ПО, которое принимает на вход этот файл, а на выходе получается уже готовая картинка. Любые изменения в существующей диаграмме делаются через модицикацию конфига.
Именно так и работает mermaid. Отрисовка диаграммы выполняется в контексте определенной нотации, например Flowchart, Entity Relationship, Gantt и др. Mermaid поддерживает более 20 различных нотаций. Для каждой нотации существует свой описательный язык.
Очевидные плюсы такого подхода, по сравнению с традиционными рисовалками в стиле "драг-н-дроп прямоугольник":
* стандартизованность - единое представление одних тех же типов элементов
* diagram as code с возможностью положить диаграмму в vcs и отслеживать историю изменений
* local first approach (привет obsidian и его клоны)
Но существует также и неочевидный плюс. Подобный подход позволяет думать, рисуя. Потому что я не отвлекаюсь на построение лэйаута для элементов, выравание их, покраску, выбор размера шрифта и прочие очень важные действия. Все эти проблемы уже решили за меня. Вместо этого я могу сконцентрироваться на сути диаграммы, на абстрактном отношении между ее элементами. А ее визуальное представление помогает мне понять, чего не хватает или что здесь лишнее. При таком подходе диаграмма выступает одним из инструментов проектирования.
Подобное можно испытать не только в mermaid. Например, существует C4 нотация для построения диаграммы архитектуры ПО. Чаще всего C4 используется для документации уже существующей архитектуры. Однако недавно мне довелось заниматься проектированием системы с нуля (в рамках обучающего курса, ничего серьезного). Я использовал PlantUML для построения С4 диаграммы этой системы. И в какой-то момент, поймал себя на мысли, что я проектирую с использованием этой диаграммы, используя PlantUML в качестве языка проектирования. Очень круто!
А какие же минусы такого подхода? Главный и наверное единственный минус - нужно разобраться в нотации и в описательном языке выбранного инструмента. Это потребует от вас какое-то время на вкатывание. Но благо, в том же memaid документация строится на конкретных примерах. Так что пара часов максимум - и вы уже шарите в этой теме.
Но даже в этом минусе я вижу плюс. Вам надо будет изучить нотацию выбранного типа диаграммы, а значит, у вас будет правильное понимание примитивов данной нотации, вы не изобразите нестандартизованную херню.
В общем, если вы часто чего-то рисуете с помощью перетаскивания стрелочек, то я рекомендую попробовать посмотреть в сторону mermaid и подобного тулинга. Если вы редко рисуете, то тут уже на ваше усмотрение. В таком случае проще может быть накидать что-то драг-н-дропом, чем разбираться в документации.
В комментах поделитесь, где вы рисуете ваши диаграммы?
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🦄1
Если же говорить о не декларативных рисовалках, то приятным открытием прошлого года стал Excalidraw. Это тот редкий случай, когда простота и "красивость" выделяет продукт среди конкурентов. Вы только посмотрите на стиль получающихся картинок! Это супер мило😍
В excalidraw очень "примитивная" стандартная библиотека примитивов, что также является плюсом по мне. Но если хотите, можно скачать кучу готовых специализированных библиотек.
Из недостатков: это local first тулза. Синхронизация и колаборация доступны только в платной версии. Приходится ставить расширение для хрома, чтобы манагерить свои рисунки.
Но эти минусы почему-то не отпугивают пользователей. 90к звезд на гитхабе говорят сами за себя ⭐️
Кстати, на собесах по системному дизайну часто используют именно excalidraw. И мне кажется, что причина в его простоте. Люди без проблем разбираются, как им пользоваться в процессе.
В excalidraw очень "примитивная" стандартная библиотека примитивов, что также является плюсом по мне. Но если хотите, можно скачать кучу готовых специализированных библиотек.
Из недостатков: это local first тулза. Синхронизация и колаборация доступны только в платной версии. Приходится ставить расширение для хрома, чтобы манагерить свои рисунки.
Но эти минусы почему-то не отпугивают пользователей. 90к звезд на гитхабе говорят сами за себя ⭐️
Кстати, на собесах по системному дизайну часто используют именно excalidraw. И мне кажется, что причина в его простоте. Люди без проблем разбираются, как им пользоваться в процессе.
✍4🔥1
На работе уважаемые разработчики из индии за 3 недели накидали прототип микросервиса с использованием python фреймворка FastAPI. Моя задача теперь выкинуть весь код к хуям довести прототип до ума. Решил подойти к задаче, как профи. Поэтому потратил неделю на изучение этого вашего питона и FastAPI. И знаете, это капец сложно! Ниже поясняю за базар.
Немного вводных данных. FastAPI - фреймворк, который построен на асинхронном питоне (asyncio), т.е. мы везде имеем наши любимые async - await. Вроде после js проблем быть не должно. FastAPI имеет очень подробную документацию. Она будто для дебилов написана и затрагивает не только сам фреймворк, но даже разработку на python в целом.
Но FastAPI начал меня страпонить практически сразу. Сначала я решил познакомиться с миграцией баз данных. В документации меня ждала лишь ссылка на библиотеку alembic. Сама по себе библиотека потная и душная. Самые душные миграции в моей жизни. Однако при тестировании все миграции применялись к public схеме в постгресе. И я никак не мог понять, а как блэт поменять схему-то. Благо, я оказался такой не один, и ребята тем же вопросом задались. Еще и оказалось, что с асинхронным драйвером там свои танцы с бубнами. Пиздец 🤡
Далее, как передать database connection во все хэндлеры запросов? Я слышал, что в FastAPi есть DI. Решил познакомиться с ним поближе. Он странный. Но в доке написано "This is very useful when you need to... Share database connections". "Отлично! А как? Как мне создать пулл коннекшнов при старте приложения, а потом использовать их везде?" Нет ответа в доке! А люди-то тоже интересуются в интернете, например тут и тут. Ребята из индии на каждый запрос к бд коннектятся от безысходности😔
Тоже самое про MQ. Захотел при старте приложения подконнектиться к Rabbit MQ и слушать, че там происходит. Вроде разобрался, как при старте FastAPI коннекшн сделать. Вопрос, где его хранить, ведь он потом еще понадобится для отправки сообщений? Ну положил в глобальную переменную, штош 🤡 Кстати, у драйвера aio-pika для Rabbit MQ периодически отваливается коннекшн без реконнекта или эксепшна. Приложение тихонько перестает слушать, че там у вас в очереди происходит. Пока хз, че с этим делать. Будем смотреть.
Лан, давайте про сам питон. Стоит ли говорить, что большая часть всего, что есть в интернете по питону - это про синхронный питон. Ансинхронщина же будто припиздрячена костылями к этому самому синхронному питону. Изза этого часто непонятно, а какую библиотеку выбрать. Например, есть мегапопулярный адаптер для постгреса psycopg. Но он изначально был без поддержки asyncio. Но щас вроде завезли в 3й версии. Но почему-то все советуют asyncpg. Тоже самое с клиентом для RabbitMQ, потому что есть синхронный pika (но с asyncio коннектором), а есть aio-pika.
Если хочешь в бэкграунде че-то поделать с помощью asyncio.create_task, то обязательно надо сохранить куда-то сам task, потому что, если этого не сделать, то сборщик мусора может эту корутину удалить. Так в доке написано. Я прям охерел с этой прикормки 😳 Самое прикольное, что в инете все примеры че то забивают на это. Хз, что делать, на всякий случай в глобальную переменную все сохранил. Люблю глобальные переменные 😊
Кстати, захотел эту переменную с тасками типизировать, ну типа указать, что у меня тут коллекция Taskи хранит. Так и не понял как это сделать! Где типы для asyncio?
IDE помогает слабо. Куча библиотек написана без типов.
context manager (ну это который with pampam() as huita) проглатывает исключения 😳 я так понимаю, это зависит от реализации конкретного менеджера. но все же, для меня это не совсем ожидаемое поведение. Неожиданно и то, что исключения тупо пропадают в корутине, которая task в бэкграунде.
logger из коробки не работал че-то у меня. Ну вот ребята со стэкоферфлоу помогли.
Вообщем, может создаться впечатление, что я тут жалуюсь. Но это не совсем так. Это я свой опыт пытаюсь переложить на незнакомый инструмент. И он ложится неидеально, это нормально. Надо подпривыкнуть 😊 Надеюсь, получится освоить этот популярный язык, и наконец-то по-настоящему войти в айти!💪
Немного вводных данных. FastAPI - фреймворк, который построен на асинхронном питоне (asyncio), т.е. мы везде имеем наши любимые async - await. Вроде после js проблем быть не должно. FastAPI имеет очень подробную документацию. Она будто для дебилов написана и затрагивает не только сам фреймворк, но даже разработку на python в целом.
Но FastAPI начал меня страпонить практически сразу. Сначала я решил познакомиться с миграцией баз данных. В документации меня ждала лишь ссылка на библиотеку alembic. Сама по себе библиотека потная и душная. Самые душные миграции в моей жизни. Однако при тестировании все миграции применялись к public схеме в постгресе. И я никак не мог понять, а как блэт поменять схему-то. Благо, я оказался такой не один, и ребята тем же вопросом задались. Еще и оказалось, что с асинхронным драйвером там свои танцы с бубнами. Пиздец 🤡
Далее, как передать database connection во все хэндлеры запросов? Я слышал, что в FastAPi есть DI. Решил познакомиться с ним поближе. Он странный. Но в доке написано "This is very useful when you need to... Share database connections". "Отлично! А как? Как мне создать пулл коннекшнов при старте приложения, а потом использовать их везде?" Нет ответа в доке! А люди-то тоже интересуются в интернете, например тут и тут. Ребята из индии на каждый запрос к бд коннектятся от безысходности😔
Тоже самое про MQ. Захотел при старте приложения подконнектиться к Rabbit MQ и слушать, че там происходит. Вроде разобрался, как при старте FastAPI коннекшн сделать. Вопрос, где его хранить, ведь он потом еще понадобится для отправки сообщений? Ну положил в глобальную переменную, штош 🤡 Кстати, у драйвера aio-pika для Rabbit MQ периодически отваливается коннекшн без реконнекта или эксепшна. Приложение тихонько перестает слушать, че там у вас в очереди происходит. Пока хз, че с этим делать. Будем смотреть.
Лан, давайте про сам питон. Стоит ли говорить, что большая часть всего, что есть в интернете по питону - это про синхронный питон. Ансинхронщина же будто припиздрячена костылями к этому самому синхронному питону. Изза этого часто непонятно, а какую библиотеку выбрать. Например, есть мегапопулярный адаптер для постгреса psycopg. Но он изначально был без поддержки asyncio. Но щас вроде завезли в 3й версии. Но почему-то все советуют asyncpg. Тоже самое с клиентом для RabbitMQ, потому что есть синхронный pika (но с asyncio коннектором), а есть aio-pika.
Если хочешь в бэкграунде че-то поделать с помощью asyncio.create_task, то обязательно надо сохранить куда-то сам task, потому что, если этого не сделать, то сборщик мусора может эту корутину удалить. Так в доке написано. Я прям охерел с этой прикормки 😳 Самое прикольное, что в инете все примеры че то забивают на это. Хз, что делать, на всякий случай в глобальную переменную все сохранил. Люблю глобальные переменные 😊
Кстати, захотел эту переменную с тасками типизировать, ну типа указать, что у меня тут коллекция Taskи хранит. Так и не понял как это сделать! Где типы для asyncio?
IDE помогает слабо. Куча библиотек написана без типов.
context manager (ну это который with pampam() as huita) проглатывает исключения 😳 я так понимаю, это зависит от реализации конкретного менеджера. но все же, для меня это не совсем ожидаемое поведение. Неожиданно и то, что исключения тупо пропадают в корутине, которая task в бэкграунде.
logger из коробки не работал че-то у меня. Ну вот ребята со стэкоферфлоу помогли.
Вообщем, может создаться впечатление, что я тут жалуюсь. Но это не совсем так. Это я свой опыт пытаюсь переложить на незнакомый инструмент. И он ложится неидеально, это нормально. Надо подпривыкнуть 😊 Надеюсь, получится освоить этот популярный язык, и наконец-то по-настоящему войти в айти!💪
❤3🤔1🤯1🤡1🏆1
Помню, в далеких 2010х годах, когда я еще занимался подготовкой людей, одним из важных навыков для программиста считалось "умение гуглить". Без этого базового умения было очень тяжело учиться программировать. Поэтому, если у кого-то намечался пробел в этом навыке, необходимо было это как можно быстрее исправить.
Сейчас есть такое ощущение, будто у меня самого образовался пробел с этим. Во всяком случае, найти что-либо полезное в гугле стало значительно труднее.
Как вы помните, я старательно стараюсь вкатиться в айти, как питон разработчик. Поэтому приходится очень много гуглить. И как же это тяжко большинстве случаев!😔
Ну вот вам пример из последнего: запрос "aioboto3 get s3 file content type" в гугле не возвращает нихера! Это конкретный запрос, который должен приводить к ответу про вызов метода "head_object" у s3 клиента в библиотеке aioboto3. DeepSeek отвечает на раз, да еще и с примером кода.
Часто, когда мне надо что-то найти по программированию, я добавляю "reddit" к поисковой строке, потому что на реддите очень много крутой инфы, но гугл этого почему-то не видит, поэтому надо ему помогать. Либо при аналогичных запросах без "reddit" (например, про "топ чего то там...") будет выдавать мусорный и/или проплаченный контент.
На мой субъективный взгляд, качество поисковой выдачи гугла по технической тематике существенно снизилось😢 Гугл все еще неплохо справляется с запросами про конкретные ошибки или исключения. Но если мне нужно спросить про какую-то базу, то я скорее пойду в chatGPT или DeepSeek. Например, недавно я хотел изучить contextvars в python. Гугл уверенно отправляет на официальную документацию, которая, на мой взгляд, не очень удачная. По ней даже непонятно толком, зачем нужны эти contextvars. DeepSeek же вообще красавчик, все раскидал, с примерами, с чувством, с расстановкой. Если же вы хотите узнать про еще более классическую базу (например, how tcp connection established), то это сразу LLM, гугл будет тратой времени.
Пока что гугл остается местом номер 1, куда я иду за инфой, но как-будто это скоро может поменяться.
Делитесь, есть ли у вас ощущения, что гугл скатился, или я один такой? Может быть будущее за специализированными поисковиками или LLM?
Сейчас есть такое ощущение, будто у меня самого образовался пробел с этим. Во всяком случае, найти что-либо полезное в гугле стало значительно труднее.
Как вы помните, я старательно стараюсь вкатиться в айти, как питон разработчик. Поэтому приходится очень много гуглить. И как же это тяжко большинстве случаев!😔
Ну вот вам пример из последнего: запрос "aioboto3 get s3 file content type" в гугле не возвращает нихера! Это конкретный запрос, который должен приводить к ответу про вызов метода "head_object" у s3 клиента в библиотеке aioboto3. DeepSeek отвечает на раз, да еще и с примером кода.
Часто, когда мне надо что-то найти по программированию, я добавляю "reddit" к поисковой строке, потому что на реддите очень много крутой инфы, но гугл этого почему-то не видит, поэтому надо ему помогать. Либо при аналогичных запросах без "reddit" (например, про "топ чего то там...") будет выдавать мусорный и/или проплаченный контент.
На мой субъективный взгляд, качество поисковой выдачи гугла по технической тематике существенно снизилось😢 Гугл все еще неплохо справляется с запросами про конкретные ошибки или исключения. Но если мне нужно спросить про какую-то базу, то я скорее пойду в chatGPT или DeepSeek. Например, недавно я хотел изучить contextvars в python. Гугл уверенно отправляет на официальную документацию, которая, на мой взгляд, не очень удачная. По ней даже непонятно толком, зачем нужны эти contextvars. DeepSeek же вообще красавчик, все раскидал, с примерами, с чувством, с расстановкой. Если же вы хотите узнать про еще более классическую базу (например, how tcp connection established), то это сразу LLM, гугл будет тратой времени.
Пока что гугл остается местом номер 1, куда я иду за инфой, но как-будто это скоро может поменяться.
Делитесь, есть ли у вас ощущения, что гугл скатился, или я один такой? Может быть будущее за специализированными поисковиками или LLM?
❤4
Если судить по вашим вялым реакциям на мои околотехнические посты, то либо вы устали от этих лонгридов, либо я исписался😔 Будем надеяться на второй вариант, поэтому сегодня разгрузочный пост. Будем говорить про время.
Знаете, я не очень люблю чистить зубы. Не в том плане, что я их не чищу. Просто, это очень скучное занятие. И если кто-то скажет "я каждый день с нетерпением жду утра и вечера, чтоб можно было до блеска надраить свои клыки", то я буду с осторожностью относиться к такому человеку 🤨
Недавно у меня появилась электрическая зубная щетка. Она работает по таймеру. Подразумевается чистка каждого из 4х сегментов пасти по 30 секунд. Итого, весь сеанс чистки зубов занимает 2 минуты. Получается, я провожу по 2 минуты утром и вечером каждый день наедине с этим вибрирующим устройством😏
В один из таких прекрасных моментов я подумал, а сколько я трачу времени в год на чистку зубов. Получается, 4 * 365 = 1460 минут. Как математик, я вам могу уверенно заявить, что 1460 минут это примерно 24 часа. Итого, каждый год ровно сутки я пердолю свои зубы!
Меня это немного шокировало. Представляете, целые сутки вот так незаметно тратятся на такую повседневную рутину за год! Это натолкнуло меня на определенные размышления.
Нас в жизни зачастую сопровождают довольно много нелюбимых занятий, но которые, тем не менее, надо делать. И мой способ справляться с ними - ковырять их помаленьку, но регулярно. Это всегда даст результат на дистанции. Некоторые предпочитают откладывать такие дела, а потом выделять большое временное окно для решения всей проблемы сразу. Понятно, что это все индивидуально, и зависит еще и от мыслетоплива, необходимого для включения в контекст (чистка зубов вообще контекста не подразумевает, слава богу). Но мне кажется, что равномерная нагрузка - это более щадащий способ для организма и психики справляться с подобными задачами. Я рот топтал чистить зубы сутки подряд, или по 2 часа раз в месяц. Даже если это принесло бы пользу зубам. Но 4 минуты каждый день - окей, штош.
Второй момент. 4 минуты каждый день - это сутки в год. И это сутки "полезного" дела. Если мы тратим каждый день время на что-то "бесполезное", и не 4 минуты, а больше, то у нас это может вылиться в "недели хуйни" в год. Я щас не говорю про то, что не надо там отдыхать, смотреть фильмы, гамать, спать. Это просто скорее мысль о том, чтоб более аккуратно относиться к тому, куда утекает время. Если оно тратится на то, что не приносит радость или какие-то другие цели не позволяет достичь - нахер это все.
И третий момент. Все что можно автоматизировать - лучше автоматизировать. Если бы можно было автоматизировать чистку зубов (или хотя бы сделать ее невидимой) за вменяемые деньги, то shut up and take my money.
Короче, никаких вам советов или инструкций, как жить. Я тут вам не коуч. Думайте сами, ауф🐺
Знаете, я не очень люблю чистить зубы. Не в том плане, что я их не чищу. Просто, это очень скучное занятие. И если кто-то скажет "я каждый день с нетерпением жду утра и вечера, чтоб можно было до блеска надраить свои клыки", то я буду с осторожностью относиться к такому человеку 🤨
Недавно у меня появилась электрическая зубная щетка. Она работает по таймеру. Подразумевается чистка каждого из 4х сегментов пасти по 30 секунд. Итого, весь сеанс чистки зубов занимает 2 минуты. Получается, я провожу по 2 минуты утром и вечером каждый день наедине с этим вибрирующим устройством😏
В один из таких прекрасных моментов я подумал, а сколько я трачу времени в год на чистку зубов. Получается, 4 * 365 = 1460 минут. Как математик, я вам могу уверенно заявить, что 1460 минут это примерно 24 часа. Итого, каждый год ровно сутки я пердолю свои зубы!
Меня это немного шокировало. Представляете, целые сутки вот так незаметно тратятся на такую повседневную рутину за год! Это натолкнуло меня на определенные размышления.
Нас в жизни зачастую сопровождают довольно много нелюбимых занятий, но которые, тем не менее, надо делать. И мой способ справляться с ними - ковырять их помаленьку, но регулярно. Это всегда даст результат на дистанции. Некоторые предпочитают откладывать такие дела, а потом выделять большое временное окно для решения всей проблемы сразу. Понятно, что это все индивидуально, и зависит еще и от мыслетоплива, необходимого для включения в контекст (чистка зубов вообще контекста не подразумевает, слава богу). Но мне кажется, что равномерная нагрузка - это более щадащий способ для организма и психики справляться с подобными задачами. Я рот топтал чистить зубы сутки подряд, или по 2 часа раз в месяц. Даже если это принесло бы пользу зубам. Но 4 минуты каждый день - окей, штош.
Второй момент. 4 минуты каждый день - это сутки в год. И это сутки "полезного" дела. Если мы тратим каждый день время на что-то "бесполезное", и не 4 минуты, а больше, то у нас это может вылиться в "недели хуйни" в год. Я щас не говорю про то, что не надо там отдыхать, смотреть фильмы, гамать, спать. Это просто скорее мысль о том, чтоб более аккуратно относиться к тому, куда утекает время. Если оно тратится на то, что не приносит радость или какие-то другие цели не позволяет достичь - нахер это все.
И третий момент. Все что можно автоматизировать - лучше автоматизировать. Если бы можно было автоматизировать чистку зубов (или хотя бы сделать ее невидимой) за вменяемые деньги, то shut up and take my money.
Короче, никаких вам советов или инструкций, как жить. Я тут вам не коуч. Думайте сами, ауф🐺
❤8🔥3
Сегодня расскажу про реальный кейс в разработке, который не тянет на выступление на конференции, но вполне сгодится для канала. Для описания буду использовать фреймворк S.T.A.R (Situation, Task, Action, Result).
Situation
Как вы все наверное слышали, компания Notion ушла из РФ. На тот момент все существующие аналоги работали очень плохо. А главное, не работал экспорт данных в эти самые аналоги. Notion великодушно предоставил возможность экспортировать данные в виде html файлов 😢
Многие использовали Notion как площадку для организации онлайн курсов. Так случилось, что один известный UX дизайнер Илона тоже использовала Notion для своего курса. Тут ее обзор на альтернативы Notion в момент ухода. Поэтому от Илоны поступило распоряжение, что-нибудь придумать, ведь я же программист😎
Итого, мы имеем пачку html файлов, организованных в странную структуру папок, которые ссылаются друг на друга. Там же где-то внутри находятся все медиа. И если открыть корневой html в браузере, это даже работает. Но нам нужно давать доступ до курса только тем, кто заплатил за него.
Task
что-нибудь придумать Организовать доступ до html файлов для тех, кто оплатил курс
Action
Понимая, что дело пахнет веб программированием, я сразу начал смотреть, а че там по хостингам. Будучи откровенным жадюгой, я решил, что не намерен платить гигантские косты за раздачу html 40 людям💰
Традиционно, самый дешевым способом захостить свой код являются клауд функции, где ты платишь только за вычисления. Однако, как только ты выходишь за пределы вычислений, там с тебя 3 шкуры сдерут. Кроме того, непонятно, на сколько перфоманс клауд функций позволяет быстро отдавать статику. Вдруг там будут затупы на старте. Поэтому сразу отказался от этого.
Принял решение, что сниму самый дешевый VPS и захостю все там. И это будут шикарные 1 CPU (3+ Ghz), 1 Gb RAM, 10 GB NVMe за 7 рублей в день. Обратите внимание, что на данном железе должно крутиться не только само приложение, но и ubuntu вместе с бд.
Кстати про бд, я решил не рисковать и не связываться с записью данных в файлик или sqlite, а сразу использовать нормальную бд MySQL. Почему так? дело в том, что помимо MySQL на этом же сервере можно развернуть phpmyadmin (pma) - и вот мы имеем админку для бедных из коробки! И в будущем эти 300 мб ОЗУ полностью оправдали себя.
Ну и теперь про само приложение. Как я уже сказал, нам нужно отдавать статику. Но часть этой статики должна быть прикрыта аутентификацией, а часть должна оставать в свободном доступе. Я сразу отмел всякие пхп и питоны, потому что, извините меня, но поднимать ларавель на отдачу каждого файлика - это никакой оперативы не напасешься.
Из технологий, с которыми я более менее знаком остались nodejs и golang. Поскольку, в день выбора технологии я был в адеквате, то победил golang 🤡 А если серьезно, то когда в nodejs научится не терять коннекшн к бд, тогда и поговорим.
Деплой было решено делать с помощью контейнеризации и такого великолепного инструмента, как docker compose. В итоге весь сетап представляет собой 4 контейнера: MySQL, pma, nginx и само приложение на golang. Nginx отвечал за ssl сертификаты.
Result
Итого, буквально из говна и палок в кратчайшие сроки было изготовлено решение, которое позволило "заказчику" провести очередной поток Пояснительного курса. Более того, данное решение получилось захостить на клубне картошки 🥔
Но это было только начало. Аппетиты клиента росли, и вскоре появились новые тебования 😱 Но об этом я расскажу в следующей части, которая будет больше про бизнес и про то, как может эволюционировать такой продукт
Situation
Как вы все наверное слышали, компания Notion ушла из РФ. На тот момент все существующие аналоги работали очень плохо. А главное, не работал экспорт данных в эти самые аналоги. Notion великодушно предоставил возможность экспортировать данные в виде html файлов 😢
Многие использовали Notion как площадку для организации онлайн курсов. Так случилось, что один известный UX дизайнер Илона тоже использовала Notion для своего курса. Тут ее обзор на альтернативы Notion в момент ухода. Поэтому от Илоны поступило распоряжение, что-нибудь придумать, ведь я же программист😎
Итого, мы имеем пачку html файлов, организованных в странную структуру папок, которые ссылаются друг на друга. Там же где-то внутри находятся все медиа. И если открыть корневой html в браузере, это даже работает. Но нам нужно давать доступ до курса только тем, кто заплатил за него.
Task
Action
Понимая, что дело пахнет веб программированием, я сразу начал смотреть, а че там по хостингам. Будучи откровенным жадюгой, я решил, что не намерен платить гигантские косты за раздачу html 40 людям💰
Традиционно, самый дешевым способом захостить свой код являются клауд функции, где ты платишь только за вычисления. Однако, как только ты выходишь за пределы вычислений, там с тебя 3 шкуры сдерут. Кроме того, непонятно, на сколько перфоманс клауд функций позволяет быстро отдавать статику. Вдруг там будут затупы на старте. Поэтому сразу отказался от этого.
Принял решение, что сниму самый дешевый VPS и захостю все там. И это будут шикарные 1 CPU (3+ Ghz), 1 Gb RAM, 10 GB NVMe за 7 рублей в день. Обратите внимание, что на данном железе должно крутиться не только само приложение, но и ubuntu вместе с бд.
Кстати про бд, я решил не рисковать и не связываться с записью данных в файлик или sqlite, а сразу использовать нормальную бд MySQL. Почему так? дело в том, что помимо MySQL на этом же сервере можно развернуть phpmyadmin (pma) - и вот мы имеем админку для бедных из коробки! И в будущем эти 300 мб ОЗУ полностью оправдали себя.
Ну и теперь про само приложение. Как я уже сказал, нам нужно отдавать статику. Но часть этой статики должна быть прикрыта аутентификацией, а часть должна оставать в свободном доступе. Я сразу отмел всякие пхп и питоны, потому что, извините меня, но поднимать ларавель на отдачу каждого файлика - это никакой оперативы не напасешься.
Из технологий, с которыми я более менее знаком остались nodejs и golang. Поскольку, в день выбора технологии я был в адеквате, то победил golang 🤡 А если серьезно, то когда в nodejs научится не терять коннекшн к бд, тогда и поговорим.
Деплой было решено делать с помощью контейнеризации и такого великолепного инструмента, как docker compose. В итоге весь сетап представляет собой 4 контейнера: MySQL, pma, nginx и само приложение на golang. Nginx отвечал за ssl сертификаты.
Result
Итого, буквально из говна и палок в кратчайшие сроки было изготовлено решение, которое позволило "заказчику" провести очередной поток Пояснительного курса. Более того, данное решение получилось захостить на клубне картошки 🥔
Но это было только начало. Аппетиты клиента росли, и вскоре появились новые тебования 😱 Но об этом я расскажу в следующей части, которая будет больше про бизнес и про то, как может эволюционировать такой продукт
😁5👏2🙉1
⚠️И сразу в догонку поясню, что пост выше надо воспринимать с некоторой долей юмора и обязательно в контексте задачи. Это не про "бест практисес". Хостить базу данных на том же сервере, что и ваше приложение, скорее нельзя, чем можно. Если вы так делаете, то вы должны отдавать себе отчет обо всех рисках, которые вы несете в этом случае!
👍2🐳1🌚1
