senior junior developer
125 subscribers
89 photos
4 videos
70 links
Привет! Меня зовут Максим @senior_junior_dev, я Java-разработчик. Делюсь здесь своим опытом в индустрии.
Download Telegram
Не воруйте у себя семантику!

Я встречаю это сплошь и рядом и сам нередко попадаю в эту ловушку. Покажу, что имею в виду.

Пример 1
. Гигантские конструкторы с множеством nullable-аргументов для создания разных по смыслу экземпляров класса

Здесь обычно возникает один неприятный вопрос: "Какие поля обязательны для заполнения в конкретном случае, а какие наоборот — опциональны?". Каждый раз идти в документацию? Нет, спасибо.

Какие есть альтернативы?
1️⃣ подумать над созданием иерархии классов (которая, однако, может быть избыточной)
2️⃣ реализовать ряд фабричных методов например, createBlockedAccount(...), createNewAccount(...)
3️⃣ выделить несколько компактных конструкторов без "лишних" аргументов (не так очевидны, как фабричные методы, могут потребоваться сопроводительные комментарии)

Пример 2. Использование одних классов для моделей домена и для DTO

Обычно DTO чем-то отличаются от моделей, использующихся на уровне бизнес-логики сервиса. Один из антипаттернов — использовать везде один и тот же класс. Не поленитесь выполнить конвертацию из DTO и обратно. Если этого не делать, то возможны ситуации, когда:
📍nullable-поля будут использоваться как non-nullable
📍некоторые поля будут иметь неточные/неправильные имена и/или типы
📍будете зависеть от новых значений в поле с типом Enum и др.

Пример 3. Дата лучше булевого флага

Так как автоматизация до моего массажиста еще не дошла, то количество оставшихся массажей в абонементе я мониторил с помощью счетчика. Каждый раз, когда посещал массаж — вычитал из счетчика единичку. Всё просто! Конечно же, в какой-то момент я сбился со счёта, так как не помнил, учел ли я очередное посещение. А как надо было? Фиксировать даты посещений.

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

Пример 4. Обращайтесь с данными бережно!

На проводимых мной интервью в рамках System Design секции многие так и норовят уйти от сырых данных к доменным моделям, которые потребуются для реализации, например, одного из экранов мобильного приложения. Как затем развивать решение? Откуда брать недостающие данные? Память SSD/HDD-накопителей ничего не стоит. Спорно? Точно дешевле, чем упущенные возможности для продукта. Храните все по максимуму, удалить всегда успеете!

===

Какой бы я сделал вывод по работе с данными в системе?
1️⃣ по возможности не теряйте, не упрощайте и не обобщайте данные, которые потом будет не восстановить
2️⃣ опять же по возможности сами дообогащайте их необходимыми метаданными
3️⃣ но на уровне бизнес-логики работайте с максимально простыми и осмысленными моделями
👍4❤‍🔥22🌚2🔥1🤔1
Захотелось поделиться с вами, моими дорогими читателями, некоторыми приемами оптимизации запросов PostgreSQL. Но для того, чтобы оптимизировать запросы, нужны данные, на которых будем делать выборки.

Поэтому подготовил удобный Dockerfile c Postgres и генерацией датасета заданного размера с помощью тулкита TPC–H. Удивительно, но такую задачу как будто никто не решает. Никому не нужно? Или я плохо искал? Буду благодарен, если поделитесь другими подобными проектами, прикреплю их к посту 🙏

А что за TPC-H?

TPC-H — это бенчмарк (по-простому набор тестов), разработанный организацией Transaction Processing Performance Council (TPC) для оценки производительности СУБД, выполняющих аналитические (OLAP) запросы в стиле Decision Support Systems (DSS), как сами их и называют авторы.


Меня интересовал не весь проект TPC-H, а только инструмент генерации данных dbgen. Он генерирует данные для 8 таблиц, связанных между собой. Можно сгенерировать столько данных, сколько укажете в аргументе при сборке образа. Подробнее, как и какие будут генерироваться данные, можно прочитать в четвертой главе спецификации.

Не вдавался в подробности, но в TPC-DS генерируются еще более замысловатые данные для большего числа таблиц. Тут подробнее о других бенчмарках.

И всё же, какие есть альтернативы?

1️⃣Есть ряд вариантов, предлагающих заранее сгенеренные синтетические данные заданного размера (обычно небольшого). Например, Pagila. Почему-то тоже не нашел свежий образ / Dockerfile.

2️⃣ Использовать реальные датасеты. Один из примеров — история поездок нью-йоркского такси, когда можно поработать с "живыми" данными. Но опять же придется привести данные к такому виду, чтобы их прожевала ваша БД.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2❤‍🔥1
Оптимизация PostgreSQL. Часть 1

Данные сгенерировали. Теперь можно и запросы повыполнять. Но прежде...

№0. Определимся с тем, что значит "запрос работает долго"

С каким SQL-запросом к нам могут прийти?
Мы перестали укладываться в метрики скорости загрузки веб-страницы с отчётом.

или таким
Раньше запрос выполнялся 5 секунд, а сейчас — 2 минуты.

или
На конфах рассказывают про 10 миллионов запросов в секунду, а мы держим просто 10.

или
На интеграционном стенде все летало, а на проде все очень медленно.

В каждом из примеров нельзя однозначно сказать, есть ли в принципе дефект производительности БД.

В любом случае для идентификации проблемы (если она вообще есть) мы должны опираться на метрики, не ограничиваясь метриками самой БД.

Придется учитывать множество факторов, а именно какие, сколько и как меняются во времени:
* объем и свойства хранимых данных;
* пользовательские сценарии и конкретные запросы, которые формируют профиль нагрузки.

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

№1. Долго на клиенте ≠ долго на сервере


Выполним запрос на клиенте с замером времени:
time psql -h localhost -p 5432 -U postgres -d tpch -c "SELECT * FROM customer;" 1>/dev/null
real 0m7.624s
user 0m6.911s
sys 0m0.395s

В postgresql.conf предварительно подключим расширение pg_stat_statements для сбора статистики по запросам:
shared_preload_libraries = 'pg_stat_statements'

и посмотрим среднее время выполнения запроса:
{...,"query":"SELECT * FROM customer",...,"mean_exec_time":1061.95576325,...,"rows":6000000,...}

Разница с временем выполнения на клиенте (real) в 6+ секунд! Оно и понятно: запрашивается большое количество строк — целых 6000000, которые участвуют в времязатратном I/O.

№2. Однородные запросы — устойчивый кэш

Если выполнить запрос выше несколько раз, то в статистике pg_stat_statements можно увидеть, что 1491 страница из 359840 были прочитаны из кэша:
...,"shared_blks_hit":1491,"shared_blks_read":358349,...

Чем больше вы запрашиваете одни и те же данные, тем больше страниц попадет в кэш, и тем больше страниц будет из него вычитываться впоследствии. Конечно, с этой точки зрения выгоднее делать запросы меньшего числа строк (страниц).

№3. EXPLAIN ANALYZE BUFFERS

У EXPLAIN есть много опций. Опция BUFFERS позволяет посмотреть на использование буферов по аналогии с pg_stat_statements:
EXPLAIN (ANALYZE,BUFFERS) SELECT c_name, c_phone FROM customer;

QUERY PLAN
----------
...
Buffers: shared hit=584 read=35400
...


№4. Index Scan vs Index Only Scan

Если с Index Scan в плане запроса знакомы чуть более чем все, то про понятие Index Only Scan исходя из моего опыта собеседований не знает практически никто. В чем между ними разница? Index Only Scan — это когда всё необходимое для выполнения запроса лежит в индексе и мы не пойдем в индексируемую таблицу. Такой индекс для запроса называется покрывающим (covering). Чтобы его сделать таковым часто используют директиву INCLUDE. Она позволяет включить в индекс колонки, которые не будут участвовать в поиске.

Найдем, например, все контакты богатых клиентов:

CREATE INDEX customer_acctbal_idx ON customer (c_acctbal) INCLUDE (c_name, c_phone);
EXPLAIN ANALYZE (SELECT c_name, c_phone FROM customer WHERE c_acctbal > 9999);

QUERY PLAN
----------
Index Only Scan using customer_acctbal_idx on customer ...


Исходя из этого легко выводится правило:

№5. SELECT * почти всегда плохо

Запрос, который ещё вчера выполнялся в рамках Index Only Scan, после появления очередной колонки пойдет за данными в таблицу. Даже если таких запросов у вас нет, то не забываем про правило №1: на время выполнения запроса влияет объем данных, который пройдет через I/O-операции. Также стоит рассмотреть возможность фильтрации и группировки на сервере, а не на клиенте.

Скоро вернусь со следующей частью 🫶
🔥4👌1
Оптимизация PostgreSQL. Часть 2

№6. Избегайте колонок с большими данными

PostgreSQL не очень приспособлен к работе с большими строками и массивами байт. Так сложилось исторически. Лучше взять MongoDB. Хорошая оптимизация 😃?

Механизм, который позволяет PostgreSQL обойти скромное ограничение размера одной страницы (8 кб) называется...

TOAST
— это сочетание сжатия данных и использования вспомогательной таблицы, в которую мы будем сгружать поля в колонках, которые весят более 2 килобайт. Из основной таблицы у нас будут указатели на TOAST-таблицу.

Я уж хотел расписать здесь все нюансы работы TOAST, но за меня гораздо лучше это сделают документация и статьи (одна из тех, что понравилась своей лаконичностью). Вам лишь надо помнить про такой механизм и то, что он дается бесплатно (упаковка/распаковка + работа с данными через указатели на отдельную таблицу).

№7. Играемся с числом WPR

Сам придумал эту абревиатуру. Она означает Workers Per Request. Так как все данные у нас побиты на страницы, то логично параллелить работу с ними, что и делает PostgreSQL. Убедимся в этом, изучив план запроса:
EXPLAIN (ANALYZE, BUFFERS) SELECT * FROM lineitem WHERE l_shipdate = '1996-02-12';

Gather  (cost=1000.00..1440944.55 rows=23732 width=117) (actual time=18.547..1262.696 rows=24553 loops=1)
Workers Planned: 2
Workers Launched: 2
Buffers: shared hit=420 read=1124724
-> Parallel Seq Scan on lineitem (cost=0.00..1437571.35 rows=9888 width=117) (actual time=45.016..1245.409 rows=8184 loops=3)
Filter: (l_shipdate = '1996-02-12'::date)
Rows Removed by Filter: 19987166
Buffers: shared hit=420 read=1124724
Planning Time: 0.056 ms
Execution Time: 1264.008 ms

Итак:
* Gather указывает на сбор результатов от параллельных воркеров
* вместо Seq Scan видим Parallel Seq Scan
* использовались 2 дополнительных воркера (Workers Planned: 2 и Workers Launched: 2)
* loops=3 вместо loops=1 при Seq Scan означает, что все данные были разбиты на 3 порции, по одной для каждого из воркеров

Если установить
SET max_parallel_workers_per_gather = 0;

то увидим классическое:
Seq Scan on lineitem  (cost=0.00..1874969.65 rows=23732 width=117) (actual time=15.584..3395.071 rows=24553 loops=1)
Filter: (l_shipdate = '1996-02-12'::date)
Rows Removed by Filter: 59961499
Buffers: shared hit=676 read=1124468
Planning Time: 0.049 ms
Execution Time: 3396.748 ms


Посмотрим, какие результаты получатся при разном количестве дополнительных воркеров. Занес все получившиеся результаты в таблицу (каждый тест запускал ~10 раз для получения достоверных результатов):
количество доп. воркеров | Execution Time, ms
---------------------------------------------
0 | 3396.748
1 | 1774.959
2 | 1264.008
3 | 942.845
4 | 801.769
5 | 690.721
6 | 628.289
7 | 571.944
8 | 567.589


При max_parallel_workers_per_gather >= 7 значения Workers Planned и Workers Launched оставались равными 7 и больше не поднимались. Видно, что рост производительности нелинейный: чем больше воркеров, тем меньше прирост. После превышения определённого числа потоков результат может становится даже хуже. С точки зрения ресурсов параллельный план использует суммарно больше CPU, чем один поток, так как каждый воркер нагружает отдельное ядро. Подробнее, как обычно, читаем в прекрасной доке.

Какие можно сделать выводы?
* выгодно увеличить число воркеров на ненагруженном сервере
* снижение числа воркеров приводит к экономному использованию ресурсов сервера, но запрос будет занимать больше времени при неполной утилизации процессора

Продолжение следует...
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥42
This media is not supported in your browser
VIEW IN TELEGRAM
Продолжаем следить за своим здоровьем!

После постов 1 и 2 прошел уже практически год, а это значит, что скоро пора сдавать мои ежегодные профилактические анализы крови.

В этот раз наваял для себя вот такой списочек. Попытался отказаться от всего узкоспецифичного, оставив основательный мониторинг состояния организма в целом и основных его систем. Также оставил немногочисленные комментарии, чтобы внести некоторую ясность. Точную сумму пока не посчитал, но будет около 40-60 т.р в зависимости от финального списка. Чтобы сэкономить, нужно поискать актуальные промокоды и акции (просим за нас это сделать ChatGPT 🪖).

Это пока хороший черновик, который требуется еще раз поревьюить с ChatGPT (режим глубокого исследования — моё почтение!) и врачами 📝. Но это уже достаточно хорошая база, от которой можно отталкиваться, чтобы начать погружаться в тему.

Если вы хотите пойти по моим стопам, но не знаете, с чего начать, то могу порекомендовать такой алгоритм действий:
1) скопировать мой список анализов к себе в таблицу
2) с нейронкой в режиме глубокого исследования указываете свою специфику:
• какие цели преследуете (для меня — это профилактика заболеваний и коррекция питания, тренировок)
• какой у вас образ жизни (питание / тренировки / стрессы / курение / алкоголь)
• с чем связана работа (сидячая / стоячая / на ногах, вредное производство и т.п.)
• есть ли конкретные симптомы (например, болят суставы) и хроника (например, утомляемость, проблемы с ЖКТ)
• результаты предыдущих анализов
3) просите на основе оригинального списка скорректировать его под ваш запрос

Всех благ ❤️
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2
Как-то мимо меня прошла мартовская новость про релиз Apache Kafka 4.0. А на дворе уже осень и версия 4.1! Посмотрим, что нового?

«Неужто в Kafka завезли семантику очередей?!» — обрадовался я, когда увидел KIP-932: Queues for Kafka в Release Notes. А как тут не обрадоваться? Только посмотрите на анонс:

Additionally, we are excited to offer early access to Queues for Kafka, enabling Kafka to support traditional queue semantics directly.


Под early access здесь понимается NOT FOR PRODUCTION USE. Оно и понятно, фича экспериментальная. Но что непосредственно скрывается под громким заголовком "Queues for Kafka"?

This KIP introduces the concept of a share group as a way of enabling cooperative consumption using Kafka topics. It does not add the concept of a “queue” to Kafka per se, but rather that introduces cooperative consumption to accommodate these queuing use-cases using regular Kafka topics. Share groups make this possible.


Возможность одновременного чтения несколькими консьюмерами одной партиции в рамках share group? WHAT? Совсем не то, что я ожидал. Просто отказались от идеи легковесных консьюмеров из-за появившейся необходимости их синхронизации?

Но Tim Berglund, VP в Confluence, по секрету всему свету рассказал, что это лишь одна из фич и в 4.X семантика очередей все же должна появиться. Интересно! Посмотрим, как это будет реализовано.

Когда эмоции окончательно подутихли, то стало понятно, что самое главное в релизе — наконец-то полный отказ от ставшего родным, но всем надоевшего смотрителя зоопарка:
Apache Kafka 4.0 is a significant milestone, marking the first major release to operate entirely without Apache ZooKeeper.

Ну и, конечно, нельзя не упомянуть про новый механизм ребалансировки:
Kafka 4.0 also brings the general availability of KIP-848, introducing a powerful new consumer group protocol designed to dramatically improve rebalance performance.
Он включен по умолчанию и, как это обычно и бывает с Kafka, пользоваться им пока страшно. Пусть переживет пару релизов, чтобы поправили все баги 🎹

В остальном все понятно: что-то доработали, что-то оптимизировали, что-то поправили. Революции не произошло (как будто ее и не должно было случиться), но, эволюция налицо. Однозначно, лайк!

P.S. Решил посмотреть, как отзываются об "очередях" в Интернетах. Наткнулся на Kafka Queue: Your 101 Solution for Efficient Message Processing. Здесь вам предложат и Kafka Priority Queue, и Kafka Delay Queue и Windowed Queue 😐 Статья под авторством некой Nishtha Nagar. И это живой человек! Если провалиться в профиль, то увидим и ссылочку на LinkedIn, и список статей по самым разным темам под её авторством. Их аж 132! Столько проделано работы, но, судя по всему, на хорошую LLM заработанных денег не хватило.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤷‍♂3
Поархитектурим? 😋

Возьмем достаточно простую задачу: сервисы команд 1, 2 и 3 запрашивают один набор данных из мастер-системы (по одному фильтру), а сервис(ы) команды 4 запрашивают другие данные, но из того же сервиса мастер-системы. Данные могут запрашиваться как по определенной сущности (например, карты пользователя), а могут представлять из себя справочник (например, городов).

Нужно настроить кэш для этой системы.

Чтобы жизнь медом не казалась, запишем административно-технические нюансы, которые могут возникать:
👉 разные команды имеют разный ресурс на аналитику, разработку и тестирование, свои планы релизов и бизнес-цели
👉 время разработки решения на стороне мастер-системы может быть больше/меньше, чем на нашей стороне
👉 любая инфраструктура требует того, чтобы ее оплатили, развернули и поддерживали
👉 каждый новый сервис должен сопровождаться командой-мейнтейнером (закрытие уязвимостей; обновление версий библиотек, Java, Spring и др.)

Посмотрим, какие варианты получатся, если начинать их учитывать 👉

Архитектура 1: все сервисы идут напрямую в мастер-систему

Всё максимально просто!

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

Минусы. Дублирующиеся (за одними и теми же данными) вызовы к мастер-системе → избыточные нагрузка на БД + много трафика между кластерами. Сопровождение интеграции (в т.ч. обновление контракта) требуется на каждом сервисе +возможно дублирование логики.

Архитектура 2: общий кэш

Оптимизируемся!

Плюсы. Убираем дубли → снижение нагрузки на мастер-систему и latency. Минимальная дополнительная инфраструктура. Здесь и далее soft TTL поможет пережить недоступность в мастер-системе.

Минусы. Нет инвалидации со стороны мастер-системы. shared state → проблемы синхронизации:
* возможные проблемы десериализации из-за различий в схемах данных на сервисах (версионирование мастер-сервиса + различия алгоритмов сериализации на нашей стороне)
* различия процессов инвалидации + настроек TTL наших сервисов
* могут быть сложности со сбором метрик использования кэша сервисами
* кто будет владельцем кэша (обновление, траблшутинг и т.д.)?

Архитектура 3: cache per service

Для ненагруженных сервисов кэша может и не быть.

Плюсы.
Избавляемся от shared state → порешали большинство минусов Архитектуры 2. Дублирование вызовов снизилось в рамках одного сервиса, но...

Минусы. ... между сервисами никуда не делось. Много инфры. Храним в разных кэшах одни и те же данные → рассинхронизация из-за TTL + инвалидации.

Архитектура 4: добавляем кэш на мастер-системе

Сервис команды №2 начинает извлекать преимущества своей топорной архитектуры. Другие команды могут последовать её примеру.
Теперь кэш мастер-системы для нас — единая точка правды. Здесь проще настроить инвалидацию + можно обновлять кэш в фоне по событиям изменения состояния данных в БД (красным цветом условно обозначил канал обратной связи).

Плюсы. Высокая гибкость на нашей стороне. Дублирование вызовов теперь не нагружает БД.

Минусы. Сетевой трафик между кластерами не уменьшился. Еще больше инфраструктуры (если другие команды не отказались от локального кэша) → сложнее разбор инцидентов.

Архитектура 5: добавляем интеграционный слой

Все по заветам построения МС-архитектуры!

Плюсы. Сократили трафик между кластерами. Мало инфраструктуры...

Минусы. ... но появился интеграционный сервис (точка отказа + задержки + усложнение отладки и сопровождения). Кто будет его владельцем (обновление, траблшутинг и т.д.)? Проблема различия настроек инвалидации + TTL наших сервисов остаются.

Архитектура 6: обратная связь вместо кэша на мастере

Мастер-система не может / не хочет делать кэш на своей стороне. Сервис команды №4 отправляем по своему флоу, так как им нужны другие данные.

Плюсы. Всегда свежий кэш на нашей стороне.

Минусы. Нужно налаживать канал обратной связи, например, с помощью Kafka. Если кэш нужен по многочисленным сущностям (например, по каждому клиенту), то интеграция и кэш будут достаточно жирными.

А какую архитектуры выберешь ты?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
Про когнитивные искажения 🧐

На днях читал статью о Developer Experience (DevEx). Это про то, как сделать работу разработчиков наиболее эффективной, в том числе исключив разного рода раздражающие факторы. В ней было много отсылок к различным когнитивным искажениям, которые всплывали при сборе анемнеза с проблемной продуктовой команды.

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

Очевидно, чем больше ошибок, о существовании которых мы знаем (когда и почему они возникают), тем меньше шансов их допустить. На картинке выше, как пишут сами авторы, попытка собрать их все в одном месте. Запомнить все — выглядит неподъемно, если не подходить к изучению систематически.

Да и нужно ли? Кажется, что универсальный метод, которым можно пользоваться — чаще задаваться вопросами: "А что, если я ошибаюсь?", "Какие плюсы есть у альтернативного решения?", "Достоверны ли мои знания?", "На что я опираюсь при принятии решения?". На мой взгляд, умеренно сомневаться в своем решении, обсуждать его сильные и слабые стороны с коллегами, принимать конструктивную критику — одно из важных качеств сильного инженера.

Для понимания, о чем идет речь, привел несколько примеров из своего опыта и опыта коллег.

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

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

Эвристика доступности — это когнитивное искажение, которое возникает, когда мы при принятии решения полагаемся на информацию, которая легко приходит на ум, вместо того, чтобы искать более надежные и точные данные.
На собеседованиях, чтобы ничего не забыть, я фиксирую качество ответа по каждому заданному вопросу. Если этого не делать, то можно легко зациклиться на одном неправильном ответе и поставить крест на хорошем кандидате.

Феномен негативного восприятия — это когнитивное искажение, при котором отрицательная информация, события или эмоции оказывают на человека более сильное влияние, чем позитивные, даже если их значимость одинакова.

По результатам проведения ассессмента в отзыве я стараюсь не давить на слабые стороны, а отмечаю возможные точки роста. Одна неаккуратная фраза может восприниматься очень болезненно, "перечеркивая" в понимании разработчика всю проделанную подготовительную работу.

Замечаете в себе проявления когнитивных искажений? Как с ними боретесь?

P.S. Понравился еще такой закон:
Закон Вебера–Фехнера — это психофизиологический закон, описывающий, как человек воспринимает изменение интенсивности раздражителей (звука, света, веса и т.д).
Например, если вы держите в руке 1 кг, то прибавление 0,1 кг вы, скорее всего, почувствуете, в отличие от ситуации, когда вы изначально держите 10 кг. Кажется, что закон можно хорошо переложить на IT: если менеджеру дать сразу много новых подчиненных 😃, то он это почувствует, а если каждый месяц — по два новых, то он не будет воспринимать разницу как значительную, хотя может уже с трудом справляться с нагрузкой.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5🤔2
Яндекс, за что ты с собой так? 😢
Please open Telegram to view this post
VIEW IN TELEGRAM
😁9
Провел System Design Interview для своего менти. Решали вот какую несложную на первый взгляд задачу:

В мобильном приложении нужно отобразить пользователю историю его заправок.

Откуда получаем данные? Сейчас есть 2 партнёра, они пушат в нашу систему заказы по REST API в разных форматах (но все необходимые и даже больше поля есть).

Каждый партнёр отвечает за разные сети заправок. Партнёров потенциально может быть много (десятки).

Пока функциональность довольно скромная, но инвестор верит в это направление, поэтому нужно сразу закладываться на развитие функциональности и рост нагрузки в будущем. Сначала ориентируемся на 100 rps на чтение и 1000 rps на запись.

Получившееся решение представлено на скрине. Запросы партнёров попадают в кластер через Gateway. Data Preparation Service приводит все сообщения к единому формату и пишет в Kafka. Если Kafka недоступна, то PostgreSQL выступает временным хранилищем для реализации паттерна Transactional Outbox. Fuel Stats Service перекладывает данные в MongoDB. Он же по запросу с МП через отдельный Gateway отдает список заказов по пользователю. В Redis на постоянной основе храним данные по заказам таксистов и временно заказы обычных пользователей. Инвалидацию проводим по событиям из Kafka. Для сбора аналитики User Stats Service вычитывает Kafka в отдельной Consumer Group.

Что получилось хорошо?
⭐️ Технологии в целом подобраны адекватно требованиям.
⭐️ Есть предпосылки для применения CQRS.
⭐️ Kafka при необходимости даёт возможность перечитать одни и те же данные разным потребителям, в том числе для целей аналитики.
⭐️ Redis значительно снизит нагрузку на БД.

Что можно улучшить?
🎯 Не храним сырые данные. Это значительно усложняет доработку функциональности в будущем. Недавно как раз писал пост на эту тему.
🎯 PostgreSQL в качестве fallback-сценария для Kafka не самый удачный вариант с точки зрения пропускной способности на запись. В первую очередь нужно уточнить возможность партнёра отправить сообщение повторно перед тем, как усложнять архитектуру решения.
🎯 Data Preparation Service может плохо переживать пиковые нагрузки, особенно если будет нагружен логикой/интеграциями.
🎯 Data Preparation Service потенциально нужно будет разделить под разные схемы сообщений от разных поставщиков при разрастании логики.
🎯 REST API, названия сервисов и модель данных требует дополнительной проработки.
🎯 Fuel Stats Service на будущее лучше освободить от обязанности перекладывать сообщения из Kafka для более гранулярного масштабирования.
🎯 Нужно рассмотреть альтернативы MongoDB, Kafka и Redis (например, Cassandra, NATS/Pulsar, Hazelcast/KeyDB/Valkey) с точки зрения возможностей API, консистентности чтения, пропускной способности на чтение/запись, простоты организации кластера.

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

P.S. Поздравляю всех с окончанием длинной рабочей недели. Хорошо, что на сегодня я взял отпуск🤣.
Please open Telegram to view this post
VIEW IN TELEGRAM
7👏42
Давно нужно было это сделать, но всё руки не доходили... Начал изучать Python.

До этого, конечно, приходилось писать небольшие скрипты, но этот процесс сопровождался непрерывным гуглением синтаксиса. А ведь Python теперь знать обязательно — это базовый язык для AI ML. "Spring AI есть!" — скажете вы. Но он значительно отстает от мирового стандарта...

По рекомендации прошел бесплатный курс от Hexlet по базовому синтаксису. В экспресс-режиме (около 5 часов) прошел все 76 занятий. Очень понравилось! Если и другие курсы от Hexlet такие же последовательные и проработанные, то не могу не позавидовать тем, кто вкатывается сейчас в айти.

Сам я вкатывался в C++ и Java по легендарным книгам C++ за 21 день и Java. Руководство для начинающих больше 10 лет назад. Каждую из них осилил в период летних каникул дней за 30 (по 8-10 рабочих часов каждый день), выполняя все практические задания. Это был настоящий ад 😕 Впоследствии еще 2 раза перечитывал книгу по Java, каждый раз находя новые для себя нюансы, которые не мог воспринять в предыдущих итерациях.

А у вас как быстро получилось первые навыки получить?

P.S. В контексте прохождения курса по Python показалось забавной фраза:
Этим языки программирования отличаются от разговорных языков: здесь нет места для интерпретаций.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2😁21
Только ленивый не написал про сбой Cloudflare, случившийся 18 ноября. Я не написал 😃. Событие, действительно, всколыхнуло IT-сообщество, по двум причинам:
1) оно задело многих пользователей
2) нельзя упустить возможность поддеть Rust 👏

Меня это происшествие нисколько не коснулось, а беспокоит абсолютно другое...

Последний месяц я собирал ошибки программного обеспечения, которые уже стали частью моей day to day рутины. Скрины прилагаются 😈

На первом Тинь и Яндекс.Такси предлагают мне познакомиться с понятием nullability. На втором то же самое мне предлагает сделать Сторисграм. На третьем уже Яндекс.Маркет предлагает последний месяц добавить товар в корзину, который я не могу выкупить. Корм этот, судя по нашей кошке — испортился. Она его перестала есть. Не знаю, баг это или фича. На четвертом — милый баг Telegram с неопределившейся й и немилый баг (нет на скринах), когда сообщение, открытое в чате на нескольких устройствах, я не никак мог удалить, наверное, с неделю.

К софтверным багам добавилась духовка, которая иногда не реагирует на нажатия сенсорных кнопок. Решается проблема выключением из сети (сопровождающейся перезагрузкой ее небольшой ОС!). А Алиса в прошедшую среду не могла свет в комнате выключить. Приходилось идти к выключателю ножками!

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

P.S. Иронично, что в это же время с коллегами обсуждали, как выводить тестирование на новый уровень, чтобы не ограничиваться написанием отдельных разрозненных тестов, а сформировать сквозную архитектуру (пайплайн), которая будет способствовать появлению первых тестов уже на этапе аналитики. Они же должны лечь в основу юнит- и интеграционного тестирования. А заканчиваться все должно НТ и UI-тестами. Осталось только воплотить идеи в жизнь 🎵
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥3😢1