Эшу быдлокодит
298 subscribers
128 photos
12 videos
7 files
169 links
Дневник C# разработчика.

Личка: @EshuMarabo
Гитхаб: https://github.com/vladzvx

Стек: C#, PostgreSQL
Download Telegram
А монга своей простотой однако развращает. После года плотной работы с ней, почти в любой ситуации, когда надо какое-то хранение состояния хочется просто насрать им записать его в монгу и пойти дальше.
На неделе надо было максимально быстро накидать незамысловатый UI для внутреннего пользования, так чтобы работало на Винде, посмотрел несколько вариантов реализации:
1. C# Win Forms
2. C# WPF.
3. C# MAUI
4. React.js

У Win Forms в наличии визуальный редактор: накидал элементов, сгенерировался c# код, чуть поправил его под себя - и готово.

У WPF - тоже есть редактор, но генерируется xaml разметка, что-то типа xml. Главная проблема, что его тоже нужно знать.

MAUI - тот же xaml. Не предполагает визуального редактора. Предлагаемый путь разработки - пересборка приложения на ходу, на живую: приложение запущено в дебаге, ты на ходу правишь xaml и смотришь результат. Заманчивой выглядит перспектива кроссплатформенности: одна и та же кодовая база собирается под Android, iOS и Windows. Главный недостаток MAUI - низкая распространенность. Изучать его имеет смысл если только для души.

React - это другой язык программирования - Java Script. Может быть собран в приложение под любую распространенную ОС, но основная точка приложения - веб сайты. Разработка идёт примерно как в MAUI: открыт браузер, меняется код - меняется внешний вид сайта.

В целом, наименьшее отвращение у меня вызвали React и MAUI. Но даже для решения простых задач в оба из них надо погружаться, это как минимум пара дней.

В итоге я зажал нос и решил свою задачу на Win Forms за несколько часов, после чего пошел дальше. Но с реактом я когда-нибудь разберусь!
👍4😁3
Есть такой продукт для обмена данными между микросервисами - RabbitMQ, я его неоднократно упоминал в канале выше. Это - брокер сообщений, вся суть его - передача информации из входной точки (обменника) к выходным (очереди), на которые подписываются сервисы. RabbitMQ поддерживает гарантированную доставку сообщения. Даже если рухнет мироздание вся инфраструктура, когда она оживет - брокер может поднять помещенные в него сообщения и продолжить передавать их подписчикам.

Нормально настроенный брокер позволяет существенно упростить жизнь, когда нужно маршрутизировать потоки информации между несколькими сервисами.

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

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

RabbitMQ позволяет принимать сообщения как синхронно, так и асинхронно. Для обоих способов предусмотрены специальные методы. Но вот беда - асинхронный прием сообщений не работает. Оказалось, сообщать RabbitMQ что я буду принимать асинхронные оповещения надо на этапе подключения к нему.

В остальном RabbitMQ прекрасен: удобно и быстро настраивается из с#, нагрузку держит.

#rabbitmq
👍3
Наткнулся на неочевидную проблему при приеме данных от RabbitMQ. Когда блямкает оповещение, оно представляется неким классом, имеющим поле типа ReadonlyMemorySpan<byte>, то есть по большому счету ссылка на область памяти с указанием размера.

Ну я и складировал эти классы для последующей обработки. Поддал нагрузки при тестировании - и из кролика полезла какая-то фигня, которую я туда не передавал.

Сделал копирование байтиков в массив сразу по получении - и проблема рассосалась.

#rabbitmq
😁1
Эшу быдлокодит
На неделе надо было максимально быстро накидать незамысловатый UI для внутреннего пользования, так чтобы работало на Винде, посмотрел несколько вариантов реализации: 1. C# Win Forms 2. C# WPF. 3. C# MAUI 4. React.js У Win Forms в наличии визуальный редактор:…
У меня таки дошли руки до раскуривания реакта, ещё немного и я смогу быть junior react developer!

В несколько подходов отработал основные концепции:
1. Хранение состояний, композиция хранилищ, перерисовка компонента при изменение состояния, относящегося к ней (например - таблицы при появлении новых данных).
2. Роутинг внутри сайта: переходы между логин-экран1-экран-2 и так далее.
3. Адаптивная верстка: на мобилке - один ui, в браузере - другой.
4. Потыкал самые распространенные компоненты, типа текстового ввода.
5. Разобрался с разметкой страниц (ни капли html, что характерно).
6. Научился принимать и отправлять данные как обычными запросами, так и веб советами.

В общем, можно начинать творить:)

#react #кодинг #js
До недавнего времени из-за ограничений браузера для организации постоянной связи браузер-бэкенд надо было или использовать веб-сокеты и гонять через них json-ы, или использовать web-gRPC, прибавляя дополнительный узел прокси сервера на бэке, роль которого сводилась к конвертации порезанного под браузер протокола в вид, понятный человеческому gRPC.

И тут совершенно случайно узнал, что в c# совсем недавно завезли поддержку браузерной gRPC. Осталось протестировать и насадить практику использования этого чуда инженерной мысли на фронте.
👍1
Оказалось довольно удобно совмещать ORM с хранением jsonb в постгресе. Делаешь модельку вида:

class Model
{
Int Field1,
String Field2,
String Field3,
InnerModel ClassField
}

В обычные поля таблицы кладешь то, по чему будут строиться индексы и какую-то важнейшую информацию, к которой нужен максимально быстрый доступ.

А остальные поля, которые надо будет только читать, в т.ч. содержащие подклассы и массивы, уезжают в поле, содержащее класс (ClassField в примере). Помечяешь поле атрибутом "хранить как jsonb" и ORM сама сериализует и десериализует его. В итоге, вместо веера из десятка таблиц, разложенных по нормальным формам, получаем одну, время чтения и модификации данных соответственно уменьшается.

Итого, лёгким движением руки Postgres превращается, Postgres превращается...
в мутанта, содержащего признаки реляционки и монги.

/Напевает себе под нос/ Денормализация! Денормализация!

#postgresql
😁3
Существует целая куча брокеров сообщений и того, что может быть использовано в их качестве. Kafka, RabbitMQ, ActiveMQ, NATS. Продукты от AWS, Microsoft Azure, Yandex Cloud. Notify в PostgreSQL, Queue в Тарантуле, очередь в Redis и ещё куча других решений.

При выборе брокера сообщений я бы задал один вопрос:

Вам понадобится практически неограниченное горизонтальное масштабирование, чтобы можно было сдерживать нелинейный рост нагрузки, превышающей ~10 тыс сообщений в секунду? А если ещё раз подумать?

Если да - то ваш путь лежит в мир боли Кафку и экосистему Apache, практически без вариантов. Возможно, облачные поделия и не уступят ей, но это не точно, да и в 2023 в России уже не особо актуально.

Если планируемый рост нагрузки не столь страшен - отталкиваться можно от используемого стека. Все живёт в Azure? Берём их брокер. У нас целый зверинец продуктов Apache? Можно ActiveMQ или простенькую конфигураци Kafka. Пишем на Go? NATS отлично впишется в качестве подключаемого модуля, прямо внутрь вашего приложения, правда он не умеет сохранять опубликованные в нем сообщения после падения.

Ну а если нет какой-то такой специфики - берём попсовый RabbitMQ, знакомый практически каждому бэкенд разработчику, и не выпендриваемся.
👍2
Forwarded from Sandbox
Я пытался трудоустроится джуном в мск, я использовал площадку hh. И не использовал другие площадки (просто потому что мне было лень). По правилам своего эксперимента у меня было законченное высшее и не было никакого опыта работы.

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


И того, изначально я составил простенькое резюме в которое я упихал свое ФИО и указал универ. т.к. более ничего у меня не было. С таким резюме я вышел на рынок и отправил 30 откликов отклики отправлялись на: стажировки, поиски разработчика, поиски разработчика без опыта, поиски джуниора, поиск разработчика с опытом 1-3. Так же дополнительно при отклике я прикладывал сопроводительное письмо, которое мне сгенерировал ИИ.

Из этих 30 откликов я получил 4 предложения пройти тестовое. Рассмотрев все 4, я решил что меня заинтересует только 1. (К нему мы еще вернемся).

Следующим шагом был большой спор в одном из чатов по результатам которого в резюме добавилось следующее: Фотография, ссылка на гитхаб с проектами, подробное описание технических книг, а так же в опыт было вписаны курсовые и дипломные работы. (Важно отметить, что я не врал и честно указал, что это именно курсовые и дипломные работы). С таким подходом я получил 3 года опыта. С новым резюме я отправил еще 30 откликов. Здесь все пошло куда живее, на каждый 3й отзыв я получал приглашение пройти тестовое задание.

И того я имел на руках 14 приглашений на 60 откликов.
Мной было выполнено 10 тестовых из которых я получил ответ на 4. Очень часто за тестовым заданием шло еще одно таким образом фильтр сузился до 2х собеседований.

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

Важные замечания. Не нужно врать, но опыт должен быть заполнен. Вас никто не позовет на собес, без тестового, вы сделаете очень много работы в стол. Если не отчаиваться - то точно получится. Если вы тупы как пробка, будет сложно, возможно стоит еще поучиться.

На весь эксперимент было потрачено около 3х недель. Итогов к сожалению не будет, т.к. принять предложения я не успел, да и не собирался.
👍3👏3
Sandbox
Я пытался трудоустроится джуном в мск, я использовал площадку hh. И не использовал другие площадки (просто потому что мне было лень). По правилам своего эксперимента у меня было законченное высшее и не было никакого опыта работы. К сожалению эксперимент получился…
Небольшая ремарка: на джуна собеседовался сеньор, скрывший реальный опыт работы, в остальном - не пытавшийся выглядеть джуном.

В общем-то я бы скидывал этот текст всем желающим сейчас вкатиться в IT, опыт крайне познавательный.
🤡2
Совершил третий подход к библиотеке Quartz - инструменту для управления фоновыми задачами в шарповом сервисе. И таки познал его дзен. Первый раз я смотрел его джуном. У меня закипели мозги и я в ужасе закрыл его. Второй раз я уже был мидддом. Подумал: прикольно, но избыточно. И вот третий подход.

Предположим у нас есть сервис. Раз в секунду он совершает какой-то запрос. Повесили вечный цикл/таймер и живём дальше.

Спустя какое-то время нам потребовалось делать серию запросов куда-то раз в 5 минут. Мы все ещё живём на таймерах.

Добавилась необходимость содержать пару локальных кешей, обновляя/чистя их по расписанию. У нас таймеры, нам ок.

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

А потом добавилась длинная и тяжёлая задача задач, которая должна запускаться в 13:13 по пятницам 13 го. Длится она около 30 минут. Мы уже очень хотим красивое управление периодами с помощью Cron, но наваяли костылей и поехали дальше.

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

Чтобы не скатываться в такое есть специализированный инструмент, упомянутый выше. Периодичность выполнения можно конфигурировать как передавая Cron - выражение, так и единицы времени/интервалы. Можно настроить приоритеты задач, общее число доступных потоков и много чего ещё.

Но больше всего мне понравилась возможность сгруппировать задачи. Задача задач помечается как относящаяся к одной группе с теми, с кем совместно она кладет внешний сервис. И вот, в час Х она просто говорит одной строкой своей группе: поспите, пока я работаю. И они просто спят. А когда она оканчивает свою работу ещё одной строкой говорит: проснитесь!

Кроме Quartz есть ещё библиотека Hangfire, но мне она пока кажется избыточной, как Quartz когда-то:)

#кодинг
#csharp
👍2🔥1
Сегодня плотно познакомился с картографическим сервисом HereMaps.

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

Открыл документацию - все описано просто превосходно, снабжено примерами и комментариями. Довольно странный личный кабинет с системой выдачи ключей доступа к запросам, но я видел и не такое. И тут началось развлечение: оказалось, что новым пользователям не дают использовать хорошо документированную версию апи 7.2, только 8+.

А документации по ней... Тупо нет, только какие-то обрывочные примеры. И changelog, что изменилось при переходе с прошлой версии.

А изменилось многое, в запросе изохронов - и запросы и ответы. Вместо массива с парами координат - строка-абракадабра. И ни в changelog-е, ни в примерах не написано, а что это собственно за формат кодирования?

Base64? Нет. Wkt? Нет. Google encoded polyline? Хм, Бранденбургские ворота у нас находятся на 900й широте? Наверное всё-таки нет.

Спасибо доброму человеку, навёл на репозиторий HereMaps на гитхабе, где выложены кусочки кода, которые можно скопипастить себе в проект и которые декодируют строку в нечто человекочитаемое. Называется эта пакость flexible-polyline и является немного измененным алгоритмом Google encoded polyline.

В целом, подход красивый, объем исходящего трафика жмет неплохо и удобен для хранения изохронов в базе. Не хватило всего двух вещей: упоминания об этом формате в документации и пакета с готовым декодером вместо копипасты с репозитория.

#кодинг
Читаю я Рихтера, никого не трогаю. И тут мне открываются новые колдунства в организации межпоточного взаимодействия в c#, о котором я вообще не слышал, а в коде, даже в самом дремучем легаси, никогда не видел. Ключевое слово volatile, Volatile Read и Volatile Write. Дожили.

Пока до конца не осознал что это за звери и нужны ли они мне современном c#, но очень интересно открывать для себя что-то новое.

#Рихтер
#книги
👍6🤡2
Наткнулся на очень интересный инструмент для махинаций с кодом на c# на стадии пост-компиляции: fody.

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

#кодинг
#csharp
🤯2
Я ранее пару раз упоминал систему сбора метрик Prometheus. Суть ее использования простая: на этапе написания приложения мы используем достаточно простые инструменты и развешиваем метрики вида:
1. Количество и время выполнения запроса1
2. Число ошибок при выполнении запроса2, и т.д.

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

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

Столкнулся на неделе с интересной проблемой: надо было наладить сбор метрик с произвольного числа сервисов (100-200-300), раскиданных по произвольным местам в интернете. Сервисы оживают и умирают в своем ритме.

Обычно Prometheus сам ходит по сервисам и "скреппит" с них метрики. В данном случае такое невозможно. Но на помощь приходит push-gateway: рядом с прометеусом ставится ещё один сервис из экосистемы (в докере), куда все сервисы принудительно отправляют метрики. А прометеус уже сам опрашивает этот сервис.

Отдельно отличное впечатление произвела Graphana - средство для построения графиков и рисования дашбордов.

Указываешь ей: прометеус - там. И при создании графика она сразу на выбор предлагает выбрать одну из его метрик. Больше всего понравился визуальный конструктор запроса на PromQL, с помощью которого формируются данные для графика. Оно и так просто, а с конструктором запросов все низводится до уровня "для дебилов".

Я долгое время хотел сделать сложное преобразование с многокомпонентной метрикой (состоящей из нескольких временных рядов). Несколько раз подступался, но углубляться в недра PromQL и читать доки было лень. В итоге, в графановском конструкторе я нашаманил нужное преобразование за 5 минут.

В целом, экосистема Prometheus производит крайне приятное впечатление, рекомендую всем. Кроме сбора самопальных метрик, можно собирать метрики компонентов инфраструктуры: баз данных, брокеров сообщений. А ещё есть экспортёры системных параметров (CPU, RAM, диск). А в качестве вишенки на торте в экосистеме Prometheus есть система сбора и агрегации логов - loki, знакомство с ней меня ожидает в будущем.

P.S. И Prometheus, и Graphana, и push-gateway ставятся через docker-compose с помощью банальной копипасты из примеров, без включения мозга.
👍1
Kafka vs RabbitMQ, часть 1. Описание эксперимента.

Проводил интересный эксперимент: сравнивал между собой брокеры сообщений: Apache Kafka и RabbitMQ под нагрузкой на сообщениях разного размера. В этом посте - описание условий эксперимента, результаты - далее по тегу #kafkavsrabbitmq

Оба брокера брал as-Service, то есть администрирование берет на себя хозяин облака. Под капотом RabbitMQ as Service - 1 инстанс, под капотом Kafka as Service - кластер из 9 .

На 12 серверах раскидал клиентские сервисы: по 70 генераторов данных (Producer) и по 200 потребителей (Consumer). Producer-ы в один поток последовательно генерируют сообщение (массив случайных байт заданного размера), отправляют его в брокер и ждут заданное время до отправки следующего сообщения. Consumer-ы в один поток читают. Режим чтения в Kafka - latest, то есть топики вычитываются не сначала. Сделал центральный сервис конфигурации, куда скидываются POST-запросом настройки сервисов: адреса брокеров и текущие настройки эксперимента - размеры сообщения и задержка после успешной отправки сообщения для регулировки нагрузки. Сервисы раз в некоторое время (от 15 до 30 секунд) ходят за свежей конфигурацией, и, если она поменялась - перенастраиваются.

Данные распределяются по 120 "обменным точкам" - Exchange в RabbitMQ, Topic в Kafka. Доставляются в среднем по 3 раза, везде стоит автоматическое подтверждение получения сообщения Consumer-ом.

Со всех сервисов собирается ряд метрик:


- Сообщений отправлено
- Сообщений получено
- Байт отправлено
- Байт получено
- Время отправки сообщения
- Число ошибок при отправке
- Число ошибок при получении

Бомбил сообщениями следующих размеров:


- 150 байт
- 5Кб
- 100Кб

Для сбора и визуализации метрик использовалась связка prometheus-push-gateway, Prometheus и Graphana. Сервисам известен адрес push-gateway, они сами туда сбрасывают метрики, prometheus их вычитывает.

В общем, получил лвлап и кучу экспириенса: зверинец из 550 сервисов я ещё не пас.

#rabbitmq
#kafka
👍1
Kafka vs RabbitMQ, часть 2. Результаты измерений.

Измерялась сферическая производительность брокера в ваккуме, под конкретную задачу (под NDA).

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

Размер сообщения: 150 байт
Kafka - 3000
RabbitMQ - 5000

Размер сообщения: 5 Кб
Kafka - 1100
RabbitMQ - 3600

Размер сообщения: 100 Кб
Kafka - 580
RabbitMq - 1000

#rabbitmq
#kafka
#kafkavsrabbitmq
Kafka vs RabbitMQ, часть 3. Некоторые впечатления и наблюдения по результатам эксперимента.

1. На практике для себя подтвердил вывод из прочитанного ранее.
2. В отличие от RabbitMQ, для Kafka, даже as-Service всеравно нужен опытный, знающий человек который умеет готовить именно её.
3. При экспоненциальном росте нагрузки Kafka урезает отдачу, а RabbitMQ - прием сообщений.
4. Kafka подключает нового клиента довольно долго. При подключении потребителя в момент, когда Kafka находится в режиме приёма "цунами" сообщений, на клиента по началу вываливается целая куча сообщений, а потом поток урезается до общего уровня.
5. Расстановка метрик вообще, и Prometheus в частности - огонь. Не так много дополнительных приседаний и из нескольких дашбордов понятно происходящее в 550 микросервисах. Prometheus с push-gateway на прием очень экономичны по оперативной памяти (съедали не больше 4-5 Гб), но требовательны к CPU: съедалось на постоянной основе 30+% от 8 ядер сервера.

#rabbitmq
#kafka
#kafkavsrabbitmq
👍1
Сегодня продолжил трогать экосистему Prometheus.

Наконец дошли руки до системы сбора логов - Loki. Вообще, при развертывании "по фен-шую" между сервисами, генерирующими логи и Loki должна использоваться прокладка - Promtail. Promtail осуществляет сбор, анализ, агрегацию и ротацию логов, после чего укладывает их в Loki. Визуализация осуществляется, как и в случае с Prometheus с помощью Graphana.

Но я немного схалтурил и настроил прямую запись из приложения в Loki. Заводится все с ходу, на дефолтных официальных докер образах.

Для централизованной системы анализа логов важно построение поисковых индексов по логам, чтобы из безумного потока отбирать только важное. В ELK стеке индексы конфигурируются из UI при рисовании дашбордов.

В Loki в моей конфигурации об индексировании приходится думать на этапе разработки приложения: надо заложить в сообщения логов метки (например текст {errorType42}), и сообщить отправителю, что их надо индексировать.

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

#prometheus
На неделе познал дзен DDD - domain driven design - подхода к проектированию ПО. Основная суть - разделение мух и котлет - бизнес логики (domain), технического кода по трансформации данных при движении по приложению (application) и взаимодействия с внешним миром (infrastructure).

Раньше во всех моих проектах был сильный перекос: в одном случае 90% проекта приходилось на domain, в другом - infrastructure с примесью application.

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

В общем-то самое главное, что даёт "познание дзена DDD" в моем случае - не запоминание догматики правильного построения приложения, а возможность осознанно посмотреть на задачу с новой точки зрения.
🔥3
На неделе перешагнул ещё одну важную ступеньку: освоил гитлаб на базовом уровне. Собрал пока экспериментальный стенд вида: мы коммитим в репозиторий, сам собирается докер образ, сохраняется в хранилище образов, после чего вытягивается оттуда и запускается на машине.

Система непрерывной поставки/развертывания с гитлабом выглядит примерно так: есть центральная машина на которой стоит гитлаб. На той же или на соседних машинах установлены Gitlab Runner-ы, выполняющие команды гитлаба.

Вариантов использования Runner-ов масса, я пока остановился на самом простом: выполнение последователльности консольных команд, забитых в скрипте CI/CD.

При коммите Runner, отвечающий за сборку образов, собирает новый образ и сохраняет его в хранилище. Если сборка и сохранение прошли успешно - в дело вступает второй Runner, на машине, где собственно крутится проект. Вытягивает последнюю версию, гасит старый контейнер, запускает новый из нового образа.

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

#devops
#gitlab
👍7