Telegram Web Link
Каталог настолок. Часть 1. Начало.

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

Дальнейшие сообщения по проекту будут под тегом #bgcatalog@eshu_coding

Путем наименьшего сопротивления было бы сваять браузер на React.js, а приложение - на том же реакте, или на котлине. Но я решил попробовать нестандартный путь - шарповый фреймворк Avalonia.UI. Он заявляется как тру кросс-платформенный: единая кодовая база для web, desktop, android и ios.

Пока я потратил часов 7 на утрамбовку браузерной авалонии в докер. Работающих примеров утрамбовки Avalonia в докер я так и не нашёл, пришлось собирать что-то по мотивам обсуждения в сообществе авалонии. Логика примерно такая: подсунуть результаты билда шарпового проекта в WASM в папку для раздачи статического контенда nginx. Пример докерфайла в репозитории. Для запуска надо стартовать docker-compose-avalonia.yml в корне решения.

#avalonia
#front
#проекты
Каталог настолок. Часть 2. Эксперименты для разработки фронта.

Некоторое время поэкспериментировал с Avalonia.UI, первые впечатления.

По сравнению с React.js, на котором начинаешь писать не приходя в сознание, прям тяжко. По ощущениям, тут нужно сначала продумать что делаешь, спроектировать все основные окна и переходы, а потом садиться кодить. Без этого получается какая-то фигня прям сразу.

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

По логике работы все достаточно сильно напоминает React.js: отдельно разметка и стили, отдельно - логика и контент.

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

В общем, для шарписта AvaloniaUI прям обязательный инструмент: возможность сделать mvp сразу для всех платформ - браузер, десктоп Линукс, Мак, Винда, мобильное приложение Андроид и iOS одним махом явно стоит того, чтобы немного помучаться на старте врубаясь в непривычную парадигму.

#avalonia
#bgcatalog@eshu_coding
Каталог настолок. Часть 3. Построение инфраструктуры.

Начал строить инфраструктуру для проекта домашнего каталога настолок (и частично для других будущих проектов).

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

Пока задействовано четыре отдельных виртуальных сервера:
1. Сервер с базой данных каталога - PostgreSQL 16
2. Сервер для апи и браузерного клиента.
3. Хранилище для образов, пакетов и прочих артефактов.
4. Отдельный сервер, на котором осуществляется билд образов, которые впоследствии пушатся в хранилище из п. 3

Все 4 сервера взяты в качестве виртуалок у RUVDS. Почему не запихнуть все на один сервер, возможно - железный, арендованный у того же selectel?

Сборка образов, если дополнительно не подкручивать какие-то настройки, съедает 100% CPU. Если туда же запихать базу и сервисы - они начнут лагать. Постоянные билды могут подразумевать солидный кэш пакетов и базовых образов. Скорость сборки мне пока проект мой личный некритична, потому HDD, 1 ядро. Но на сборку может требоваться солидное количество оперативки, иначе она просто отваливается по out of memory, поставил пока 2Гб.

Для хранения образов мне в перспективе нужно много места, при этом, оперативки и ядер мне тупо не нужно. Потому тут 1 ядро, 500 Мб оперативки и HDD, который у RUVDS можно раздуть до 600 Гб

Базе данных при росте будут критичны все параметры, но на время разработки я ограничиваюсь самым дешёвым конфигом - 1 ядро, 500 Мб оперативки, 10 Гб SSD, 3 из которых сразу отданы под своп.

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

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

#bgcatalog@eshu_coding
Совершенно ни к селу ни к городу вспомнил одну особенность RabbitMQ, просто запишу здесь чтобы не забыть.

Получая сообщения из RabbitMQ получатель должен подтвердить получение - ack (получено успешно) или nack (получено, но что-то пошло не так, можно указать, акутально ли еще сообщение). Но велик соблазн запустить какой-то процесс и сообщить кролику ack или nack уже по результатам его завершения.

Пока идёт отладка - всё прекрасно. А стоит поддать нагрузки так, чтобы в неопределенном статусе оказались 50+++ сообщений - начинаются чудеса. Кролика начинает колбасить, лучшего определения тут не подберешь, например сообщение отданное в кролик может дойти до адресата. А может - не дойти:)

Нормального пути решения проблемы я не нашёл, помогало удаление очереди. Ну и профилактика.

#rabbitmq
К своему стыду не осознавал применительно к работе и играм сего подхода: если уверен в успехе - не выпендривайся:
Игра победителя
Давайте сегодня чуть-чуть отвлечемся от процессов, ИТ и всякого. Я вот люблю игры, особенно МОВА, особенно доту. Играю я редко, но постоянно замечаю нюанс: все члены моей команды пытаются победить... И из-за этого проигрывают. Да-да, именно так: люди проигрывают, потому что стараются выиграть. Я не сошел с ума: дайте мне буквально пару минут, и я все объясню.

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

Открытие его поразило. Оказалось, что новички и любители играют в принципиально другой теннис. Если в профессиональном теннисе побеждает игрок, который забил больше мячей, то в играх классом ниже побеждает тот, кто меньше пропустил. Саймон пошел еще дальше и свел все к выводу: "В профессиональном теннисе 80% игр выигрываются, а в любительском те же 80% проигрываются."

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

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

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

В доте и любых онлайн играх все то же самое. Если вы не профи и не тратите 8 часов в день на теннис или доту, предпочтите игру проигравшего и минимизируйте количество ошибок. Так вы начнете побеждать чаще.

Если интересно прочитать подробнее, вот книга Саймона
Forwarded from Так не сойдет
Не люблю доту, но с автором согласен ⬆️
Please open Telegram to view this post
VIEW IN TELEGRAM
Эшу быдлокодит
К своему стыду не осознавал применительно к работе и играм сего подхода: если уверен в успехе - не выпендривайся:
А если уверен в неуспехе, но ковыряться надо - можно пробовать любую дичь в рамках УК, хуже не будет:)
Я стараюсь не рекламировать пиратство в паблике, но текущая ситуация - это просто идеальный пример bus factor 1.

https://flibusta.site/node/681117

TLDR. Флибуста походу всё. Единственный ментейнер сейчас в больнице с раком мозга, а хостинг оплачен только на пару недель. А что будет потом - неизвестно. Очередной проект, который определил дух эпохи, лично для меня, скоро канет в лету.
Познакомился с занятным инструментом: Approval тестами. Понятно, зачем нужны юнит тесты: фиксировать работоспособное состояние бизнес логики. Понятно, зачем нужны интеграционные тесты: фиксировать работоспособное состояние нескольких компонентов системы.

А тут появляется ещё один достаточно удобный рубеж обороны от багов. Approval тест фиксирует состояние Api. Если каким-то образом были внесены любые изменения, меняющие контракт - тест будет заваливаться, пока изменения не будут в явном виде внесены в специальный файл и закоммичены.

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

#csharp
Небольшое наблюдение. Сейчас идёт седьмой крупный (от шести месяцев полной моей занятости) проект за мою карьеру в IT. Из них на трех у меня была полная свобода в плане написания тестов и возможности тянуть резину двигать сроки релиза.

Что характерно - именно эти три проекта, когда пришло время, просто запустились с минимальным предрелизным безумием. А все, где тестов не было - запускались с нервотрепкой и вычерпыванием бесконечного числа багов. При этом, основательный подход к разработке удлинял время от старта проекта до первого запуска в препрод процентов на 50-60. Вроде бы много.

Но если вспомнить, сколько времени проходило на оставшихся четырех проектах от первого запуска до состояния "работает приемлимо", то получается что на авральную пусконаладку уходило за 30% времени разработки. При том к концу её код обрастал костылями, затыкающими дыры, а я выдыхался до состояния выжатого лимона и терял в производительности на пару тройку месяцев или вообще менял работу.

#csharp
#tests
Подумал тут - насколько шикарный инструмент для сбора крайне интересных данных сайты типа https://jsonformatter.org и https://jsoncompare.org. Представляете - разработчик/тестировщик в недрах большой корпорации возится в json-е, возвращаемом каким-нибудь сервисом для запуска ядерных ракет для обработки персональных данных. А json здоровый и нечитаемый. Что-то не сходится, надо сравнивать, ну он и запуливает json на форматирование/сравнение.

Как по мне, одно из первых правил информационной безопасности - из внутренней сети этих сайтов быть не должно видно вообще.

#кодинг
#иб
Попал я на обучение постгресу. Достаточно продвинутый уровень, для миддл разработчиков и выше, ранее активно пользовавшихся MS SQL или Oracle. У меня основная СУБД в стеке - PostgreSQL, но интересного и нового довольно много. Далее будет что-то типа заметок, содержащих новые для меня вещи, которые я узнал.

1. Штатная среда для написания запросов для постгреса - PgAdmin, очень функциональна в плане администрирования базы. Я всю жизнь сидел на DataGrip. Она хороша для написания запросов, спору нет. Но для сложных вещей, связанных с администрированием - лучше использовать PgAdmin. Как минимум, многие запросы для администрирования (ограничения для пользователей, собственные типы данных) проще сгенерировать через UI чем по кусочкам собирать копипастя из документации. В дополнение там очень подробный визуализатор внутренних объектов базы: в ui можно посмотреть кастомные типы, расширения, инструменты для полнотекстового поиска. В DataGrip или Dbeaver все намного беднее в этом плане.

2. Очень понравилось что-то типа кастомного типа: Domain. Это унаследованный базовый тип с прикрученным к нему ограничением на диапазон значений. Например - терминал аэропорта. Предположим, есть терминалы A, B, C, D, E. Унаследуемся от текстового типа, поставим ограничение - только одна заглавная буква из этого диапазона.

3. Механизм TOAST. Когда размер поля в таблице превышает определенное (настраиваемое) значение, в таблицу пишется ссылка на элемент "теневой таблицы", куда собственно записываются данные из поля. Для типа text по дефолту это 2Кб. Максимальное значение - 1Гб, обусловлено особенностями самого постгреса. Для записываемого в теневую таблицу значения можно настроить механизм сжатия. Кроме простой экономии занимаемого места, достигается и буст производительности: при чтении данных из таблицы, например при полном сканировании, вместо тяжёлых значений читаются десятки байт, содержащих ссылку на нужное место теневой таблицы, куда постгрес полезет только в случае реальной нужды.

#postgresql
Продолжаю конспект интересных вещей, услышанных на обучении постгресу. Начало выше.

4. Механизм шардирования постгреса на партицированную таблицу, партиции которой - foreign table на других инстансах постгреса - нормальная практика, применяется, например, в Авито.

5. Постгресовский varchar от типа text под капотом отличается только наличием проверки на размер, потому если проверка на размер не нужна - просто используем text.

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

7. Есть крайне полезное расширение для диагностики таблиц и индексов: pgstattuple. Ставишь его, делаешь select * from pgstatindex('my_index') и тебе выдаётся статистика, насколько разреженный индекс. И по этой статистике принимаешь обоснованное решение, пора ли индекс перестраивать.

8. Вместо limit + offset для пагинации возвращаемых результатов лучше использовать fetch: он гибче.

#postgresql
Продолжение заметок по новым фишкам постгреса, которые я узнал на обучении. Начало выше.

9. Я узнал о существовании фильтрованных индексов. Например, при создании btree индекса по дате указываешь > 01.01.2024 - и твой индекс будет работать только на данные в указанном тобой условии. Собственно, можно оставить архивированое в архиве и работать только со свежими данными.

10. Увидел на практике, как использовать хинты для оптимизации запросов. С хинтами забавная история: контрибьюторы постгреса встали стеной против введения их в ядро СУБД. Потому японский Ростелеком в какой-то момент реализовал их в виде расширения pg_hint, которое может поставить себе любой желающий, если ему дадут админы и безопасники:)

11. Узнал некоторые особенности индексов, о которых раньше не задумывался.
Хэш индексы немногим быстрее btree, но при этом лишены упорядочивания, ускорения запросов по интервалу, возможности сортировать таблицу по ним. Зато, если мы строим их по большим строкам, по которым надо будет искать только на условие равенства - они дают существенный выигрыш по размеру индекса. При этом, размер хэша меняется, подстраиваясь под данные так, чтобы был минимум коллизий.
Есть такой тип индекса - BRIN. Отлично работает для индексации неизменяемого вечнохранимого набора данных, ранжированных по какому-то параметру. Занимает мизерное пространство на диске, но в большинстве кейсов бесполезен.

#postgresql
Еще небольшая порция заметок про постгрес.

12. Параметры конфигурации, например work mem, можно менять непосредственно для пользователя. Соответственно, можно делать разные настройки для юзеров - аналитиков и юзеров, под которыми в базу ходят сервисы.

13. Узнал о существовании разных джоинов - hash, merge и nested loop join. Первый использует хэш таблицу, чтобы объединить данные из разных таблиц, второй - использует сортировки, третий тупо перебирает данные. Первый хорош для джоина неиндексированных данных. Второй берет сортировку исходя из индексов, соответственно хорош при наличии сортированных (btree) индексов по обеим колонкам, по которым осуществляется джоин. Третий хорош, чтобы сджоинить мизерную таблицу с большой.

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

#postgresql
Окончание заметок про постгрес.

15. Если у нас возник дедлок строки или какой-то запрос барабанит вечность - идем в представления pg_locks и pg_stat_activity, ищем источник проблемы и делаем с ним pg_cancel_backend или pg_terminate_backend.

16. Триггеры плохи не только сложностью отлова багов, но и тем что за счёт вызова доп функции на plsql, что трудозатратно.

17. Чистка мусора - vacuum - срабатывает автоматически при обновлении 20% записей. Можно подкрутить персональные настройки вакуумирования для таблиц.

18. Настройки постгреса идут из расчета, грубо говоря не более 8 ядер. Если на сервере ядер больше - можно просто выкручивать настройки параллельных воркеров пропорционально. Также диски где стоит postgres должны быть заполнены не более чем на половину, чтобы не было чудес.

#postgresql
Эшу быдлокодит
#dotnext, просмотр в записи. B-Tree индексы в PostgreSQL. Доклад получился крайне полезным: в связной легкодоступной форме пересказали то, что я в общем-то знал по устройству внутрянки BTree индексов. Кроме того, в процессе доклада всплыла ещё масса полезностей…
Нашел запись примерно того же доклада от того же автора, выкладываю тут. Наверное, это одна из самых толковых кратких лекций, которые я слышал за долгие годы.

Обучение, заметки из которого я выкладывал выше - более масштабное мероприятие длиной в неделю.

#postgresql
#ef_core
#db_design
#postgresql

Тонкости JSONB в PostgreSQL и EF Core: Как постичь дзен?

Сегодня мы рассмотрим работу с JSONB в базе данных PostgreSQL совместно с родной для .NET ORM от Microsoft — Entity Framework Core.

Мы разберём, как удобно хранить данные в денормализованном виде, как защититься от параллельных изменений и как поступать, когда необходимо выстраивать отношения между сущностями, чьи атрибуты упакованы в JSONB. Помимо этого, мы затронем такие темы, как optimistic concurrency, data encryption, миграции подобных сущностей и их версионирование.

Итак, начнём.

Тонкости JSONB в PostgreSQL и EF Core: Как постичь дзен?
2025/07/07 13:08:11
Back to Top
HTML Embed Code: