uk
Feedback
Позовите Олега | Архитектура и разработка

Позовите Олега | Архитектура и разработка

Відкрити в Telegram

Привет. Меня зовут Олег (@mifleo) - я team lead команды разработки в бигтехе, архитектор, разработчик, ментор и консультант, а так же спикер на различных конференциях. Тут пишу про IT, разработку, карьеру, софтскилах и о себе. Wellcome)

Показати більше
1 118
Підписники
+124 години
+447 днів
+15630 день
Архів дописів
Всем привет. Выкладываю запись стрима про распределенные транзакции на YouTube 📺. Рассказал про сагу и как можно применить темпорал в этом всё. Смотретите, оставляйте комменатрии, лайки. Важно услышать ваше мнение 💋 А так же, со следующей недели стартует мой интенсив по System Design где я буду рассказывать как создавать сложные, отказоустойчивые архитектры. Если для тебя актуальная подготовка к интервью или хочешь прокачать свои архитектурные навыки, то я жду тебя на интенсиве! Сейчас действие скидки закончилось, но ты можешь написать мне в ЛС и мы договоримся 🎩

⚠️Внимание, ШОК КОНТЕНТ про индексы: планировщик не должен использовать индексы для ускорения запроса. Я постоянно сталкиваюсь с заблуждением, что индекс обязан быть использован и обязан ускорять запрос. Но только это не так. Давайте разберёмся что к чему. Если говорить про PostgreSQL (да и про MySQL), то у планировщика есть 4 способа доступа к данным *️⃣Seq path — читает heap-страницы таблицы последовательно и проверяет строки на соответствие условию. Это не обязательно «строки по порядку» в логическом смысле, а именно физическое чтение страниц heap. В EXPLAIN это Seq Scan. *️⃣Index path — обходит индекс, получает TID подходящих строк и по этим TID читает heap-строки. Хорош для относительно малой селективности, когда random I/O по heap ещё окупается. *️⃣ Bitmap path — обычно состоит из двух узлов: Bitmap Index Scan строит bitmap потенциальных tuple locations, а Bitmap Heap Scan по этому bitmap читает heap-страницы и достаёт строки. Такой подход позволяет читать одну heap-страницу один раз, даже если на ней много подходящих строк. *️⃣ Index-only path — пытается ответить только по индексу без чтения heap, если все нужные колонки есть в индексе и visibility map позволяет не проверять heap. Т.е. индекс конкурирует, как минимум, с двумя альтернативными способами получить данные. Так почему планировщик должен предпочесть индекс? Например, если нужно прочитать бОльшую часть таблицы (при высокой селективности или фильтрации по широкому деапозону). Seq Scan читает таблицу большими последовательными блоками. Если всё равно придётся достать много строк, то дешевле пройти таблицу целиком, чем прыгать по индексу и для каждой найденной записи отдельно ходить в heap. Это дешевле с точки зрения затраченных ресурсов на чтения с диска. Ещё Seq Scan часто выбирается на маленьких таблицах. Даже если индекс есть, стоимость открыть индекс, пройти его, сходить в heap и собрать результат может быть выше, чем просто прочитать несколько страниц таблицы целиком. А вот если условие селективное, т.е. возвращает мало строк, тогда индекс будет предпочтительнее. Index Scan быстро находит подходящие записи в индексе, получает TID и идёт в heap за строками. Это хорошо, когда таких переходов в heap немного. Но если подходящих строк много, Index Scan становится дорогим: он может делать много random access по heap-страницам. А эти данные не факт что в одной странице же, это больше переходов по диску. А это риск для планировщика. Ещё, если запрос сортирует данные в определённом порядке, выгодно положить и индекс в этом порядке, это упростит планировщику получение данных и добавит очков индексу при оценке плана запроса. Bitmap Scan часто выбирается как промежуточный вариант: строк уже слишком много для обычного Index Scan, но ещё не настолько много, чтобы выгоднее был Seq Scan. Обычный Index Scan может прыгать в heap много раз
index → heap page 17
index → heap page 981
index → heap page 42
index → heap page 17
index → heap page 318
...
Bitmap Scan сначала собирает все найденные TID, группирует их по heap-страницам, а потом читает heap более компактно:
прочитать page 17
прочитать page 42
прочитать page 318
прочитать page 981
...
Полезен ещё при использовании нескольких индексов в запросе. PostgreSQL может построить bitmap по одному индексу, bitmap по другому индексу, а потом объединить их через BitmapAnd. Index Only Scan выбирается, когда запрос можно обслужить из индекса почти без обращения к heap. Если все нужные данные есть в индексе, PostgreSQL может не читать heap-строки. Только тут важный момент: из-за MVCC он должен понимать, видима ли строка текущей транзакции. Для этого используется visibility map. Если heap-страница помечена как all-visible, heap читать не нужно. Если нет — PostgreSQL всё равно сходит в heap. По этому, не удивляйтесь, если вы добавили всё из select'а в index, но он не применяется, потому что таблица постоянно обновляется. А откуда планировщик знает, сколько результатов вернётся, если он не выполнял запрос? Он же только план оценивает. Об этом мы поговорим чуть позже🔤

Привет! Когда у тебя одна локальная база, то бизнес инвариант можно обернуть транзакцией и база данных позаботится об атомарности. А что, если у тебя распределенная система с множеством разных баз? Через 15 минут, в 19-00, начинаю открытый урок про распределенные транзакции. Как обеспечить консистентность и атомарность в мире распределенных систем. ➡️Подключиться

Всем привет! Думаю, что большенство знают что такое ACID и как работают локальные транзакции. А вот что делать, если у вас не то что базы распределеннае, так они ещё на разных технологиях сделаны. Как тогда быть? Решений тут можно предложить сразу несколько: от наивных ручных попыток синхронизации, до устойчевых архитектурных решений. Я это к чему? Готовлю сейчас открытый урок по распределенным транзакциям и получается прям очень круто. Приходите завтра, 30.06 в 19-00, будет очень интересно ☄️ А записаться можно тут ➡️ ➡️ ЗАПИСАТЬСЯ

Привет! В микросервисах нельзя просто открыть транзакцию, вызвать пять сервисов и сделать COMMIT. Если бизнес-операция проход
Привет! В микросервисах нельзя просто открыть транзакцию, вызвать пять сервисов и сделать COMMIT. Если бизнес-операция проходит через несколько сервисов — оплата, склад, доставка, уведомления, внешние провайдеры — она почти неизбежно становится долгоживущим процессом. И в этом процессе всё может пойти не так: — деньги списались, но следующий шаг упал; — событие пришло дважды; — внешний сервис ответил с задержкой; — retry повторил операцию, которую нельзя было повторять; — состояние в сервисах разъехалось; — компенсация тоже не выполнилась. На открытом уроке мы поговорим не про абстрактную теорию, а про практическую проблему: как проводить бизнес-операции между несколькими сервисами, если у нас нет общей транзакции и каждый шаг может упасть, повториться или зависнуть. На уроке разберём как с этим работать и реализуем на практике способ обработки распределённых транзакций. Приходи, будет познавательно! 🔥🔥🔥 🗓️ Дата: 30.06 ⏰Время: 19:00 💻Формат: онлайн 🆓Участие: бесплатно ➡️ ➡️ ЗАПИСАТЬСЯ

AI замедляет разработку 😱 ...недавно заявили в твиттере Amazon Web Services. Выкатили пост, что AI разработка не ускоряет команду, а делает её медленнее. Звучит достаточно провакационно, учитывая, что вокруг только и разговоров, что AI скоро всех разрабов отправит на мороз. Я не знаю, на каких метриках Амазон собирал свою статистику. Сложно судить какой у них адпошн в компании, учитывая, что она огромная. Но, если пофантазировать и представить куда чаще всего втыкают AI, можно порассуждать на эту тему. И так, самый частый кандидат на внедрение ИИ это... разработка. Я думаю, что никто не удивлён. 🙃 Разработка это долгий процесс, сложный, дорогой. Это сначала ж надо спроектировать, потом код написать, потом тесты. Вот где можно ускорить процесс поставки. Если разобраться, что на самом деле происходит, то от ускорения разработки поставка только замедляется. Но почему? Всё просто. Процесс поставки чаще всего выглядит вот так (упрощённо): 1. Сбор требований 2. Написание спецификации 3. Грумминг 4. Декомпозиция 5. Разработка 6. Ревью 7. Тестирование 8. Релиз Если поток сбалансирован, то задачи равномерно по нему проходят и не скапливают в какой-то фазе. А вот если нет... Представьте скоростную многополсную магистраль. По ней могут ехать тысячи машин. А что будет, если посредине воткнуть тоннель в один ряд. Даже сужение на одну полосу может создать транспортный коллапс на много километров. Кто ездит по пятницам на дачу — привет. И вот нам предлагают не ускорять поток машин, а увеличивать их количество. А после этого, кто во что горазд. Кто-то, например, сносит тоннель и машины просто едут в обход. Т.е. пропускаем ревью и тестирование. А что? Кодинг агент тесты написал, а работающий код не может же быть плохим? Почему это работает именно так, прекрасно описано в книге Голдратта "Цель", где изложена его теория ограничений систем. Я её перечитываю раз в год, чтобы не забывать, что пропускная способность каждой системы ограничена. А как тогда нужно? Опять же, у Голдратта всё написано: нужно увеличивать пропускную способность узкого места вашей системы. Но, если просто добавить мощности в узкое место, оно переместится куда-то ещё. Например, классическая история, задачи зависают в тестировании. Окей, давайте наймём ещё тестировщиков. Например 2 тестера на одного разраба. Тогда узким местом может стать как релиз (сборка происходит долго, апрувится и только спустя месяц уезжает), так и сама разработка — ревью кода занимает много времени, нанятые тестировщики сидят, скучают. AI действительно может ускорить поставку, но только если вся ваша система увеличит пропускную способность. А что говорит ваш опыт? ⸻ Давайте оставаться на связи

Привет! Недавний открытый урок я записывал, но качество видео получилось отвратительное. Сегодня я сел переписать этот разбор. Прошло отлично, пошёл монтировать, и ... понял, что отключил звук на микрофоне и видео записалось без звука 🫣 И вот, с третего раза, всё-таки получилось. К вашему внимаю моя попытка №53 провести разбор задачи по system design https://www.youtube.com/watch?v=n-xY-dkD5KQ

​​Открытый разбор закончился, маркетингвая часть тоже, спасибо всем, кто пришёл. 🤩 Теперь я предлагаю перейти на страницу интенсива и сделать выбор тарифа, пока есть места 😀

Всем привет! В 19-00 начну открытый разбор архитектурной задачи по проектированию серивса уведомлений. Подключайтесь сюда https://gouujyqz.ktalk.ru/app/stream/auditoriums/10e0059c-04a6-4339-b2f6-b7935db80413

Всем привет! Накопилось несколько интересных заметок для вас, но я пока их приберегу. А сегодня хочу напомнить. что завтра, 1
Всем привет! Накопилось несколько интересных заметок для вас, но я пока их приберегу. А сегодня хочу напомнить. что завтра, 16.06 в 19-00 поведу открытый разбор задачи по System Design по проктированию сервиса уведомлений. И представлю свой образовательный продукт. 🎁 Всем, кто придёт на вебинар, от меня будет небольшой бонус: гайд по сбору ФТ и НФТ. 🎁 Записаться можно тут @mifle_courses_bot Всех жду! Ссылку пришлю. Приходите, будет вайбово. 🖤

Всем привет. 🤩 Кто давно меня читает или знает лично, тот в курсе: я много лет занимаюсь архитектурой, проектированием надёж
Всем привет. 🤩 Кто давно меня читает или знает лично, тот в курсе: я много лет занимаюсь архитектурой, проектированием надёжных систем и обучением разработчиков. За это время я видел много кейсов, где архитектура постепенно деградирует: появляются костыли, лишние зависимости, странные очереди, неочевидные ретраи, проблемы с консистентностью, мониторинг «для галочки» и решения, которые уже никто не может нормально объяснить. Сейчас навык проектирования становится ещё важнее. Код всё чаще можно делегировать AI-агенту. Архитектурное решение — нет. Агент может быстро написать сервис, какую-то логику, тесты или миграции. Вот только он не решит (на самом деле решит, но ты не сможешь узнать правильно или нет) за тебя, какие требования важны, где границы системы, какую нагрузку нужно выдержать, где нужен синхронный контур, где асинхронный, как хранить данные, как обрабатывать отказы и какие trade-offs придётся защищать. Поэтому я запускаю интенсив по System Design и архитектуре.
Лично я устал от скучных лекций с кучей теории. Собрал в интесиве максимум практики: как разбирать архитектурные задачи, считать нагрузку, выбирать компоненты, проектировать API, работать с базами, очередями, кешами, мониторингом, масштабированием и отказами.
 Подробности про интенсив расскажу отдельно, а начать предлагаю с открытого разбора архитектурной задачи. Будем проектировать notification service. На разборе посмотрим: — какие требования нужно собрать перед проектированием; — как оценить нагрузку; — какие компоненты нужны в такой системе; — где нужны очереди, базы, кеши и воркеры; — как масштабировать сервис; — какие trade-offs нужно учитывать; — какие ошибки чаще всего делают в такой архитектуре; — как защитить итоговое решение. Перед разбором я подготовил небольшой бонус — короткую диагностику архитектурных навыков. За несколько вопросов можно понять, где сейчас просадка: требования, нагрузка, базы, очереди, масштабирование, observability или аргументация решений. Пройти диагностику и зарегистрироваться на открытый разбор можно в боте: @mifle_courses_bot

Про отдых. Всем привет. Вы умете отдыхать? Расслабление, восстановление и вот это вот всё? Отключаться от внешних раздражител
+4
Про отдых. Всем привет. Вы умете отдыхать? Расслабление, восстановление и вот это вот всё? Отключаться от внешних раздражителей? Мыслей о работе, деньгах, счетах? Если да, то я вам искренне завидую. Честно говоря, даже на отдыхе, мне сложно отвязаться от всех мыслей, задач, груза ответственности. Хотя для меня, есть один вид отдыха, который действительно освобождает голову и даёт возможность переключиться и отвлечься. Рыбалка. Особенно активная. Я не из тех, кто будет до глубокой ночи кормить комаров, лишь бы вытащить тровейную рыбу. Или кто будет на дрейфующей льдине гоняться за ещё одной поклёвкой. Да и что делать с пойманой рыбой — не знаю. В основном, отпускаю обратно. Увлекает сам процесс и удовольствие от него. Результат не предсказуем и не гарантирован, если зацикливаться на нём, можно быстро выгореть и бросить такой вид хобби. Интересно, что это кореллирует почти со всеми занятиями в жизни. Если не ловить наслаждение от процесса, то можно быстро бросить любое дело, потому что результат не гарантирован и не обязателен. А когда достигнут, становится не таким интересным, каким было до этого. В эти выходные совершили поездку семьёй в Карелию. 4 часа в одну сторону, 4 часа обратно. Лес, река, природа, семья, друзья. Для меня это переключение было важным и нужным. Следующие несколько месяцев лета будут очень насыщенными работой и проектами. ⭐️ стартует очередной поток System Design для студентов университета Иннополис. В этот раз лекции полностью на английском. ⭐️ лекции по архитектуре под высокие нагрузкт в Otus, где я уже третий год веду занятия про индексы, базы, распределённые системы и архитектуры. ⭐️ новые интересные треки на работе ⭐️ буду запускать свой образовательный проект, о котором расскажу уже завтра. 🤗 А пока немного фотокарточек из Карелии. Делитесь фотками ваших хобби и отдыхов в треде ⤵️

После поста про хайдоад сразу 5 человек отписалось 😀 Наверное подумали, что это реклама и я сказачно на этом разбогател. Или посто конференции не любят. Но коварный план у меня был. Коварный план разыграть билет онлайн доступа на Saint HighLoad++ 2026. 💵 Тем более нужно для этого всего ничего: ✅ Быть подписаным на мой канал ✅ Сделать репост в публичный чат \ свой канал \ к себе в историю какой-то из постов из моего канала ✅ Прислать скриншот репоста в комментарий к этому посту А уже через неделю подведу итог и передам проходку! Чтобы вам было легче выбрать пост, вот мои любимые: Что не так с CAP-теоремой? Я тимлид, но почему мне так грустно? Разбор задачи system design - передача местоположения курьеров. Серия постов про шаблоны низшего порялдка. Про порядок полей в составном индексе.

Всем привет! В этом году я не выступал и не посещал никакие конференции. И, честно говоря, уже порядком по ним соскучился. Совсем скоро, 22 и 23 июня в Питере пройдёт Saint HighLoad++ 2026. Я там буду и планирую походить на доклады. Вообще, в этом году ну очень много докладов про ИИ, внедрении ИИ и проечее ИИ. Я насчитал 20 из 50 докладов на HL. Т.е. больше 1/3, что дофига для конференции про высокие нагрузки. А про ахитектуру всего 1 доклад, 1 воркшоп, и игра по System Design (что, кстати, очень интересно, жаль я не смог поучасвовать в отборе). Вот мой топ потенциально инетересных докладов, которые хочу послушать: Я люблю копаться в кишках баз данных, по этому воркшоп "Допиливаем свой форк Постгреса свистелками" хочу посетить и попробовать собрать что там получится. Мне часто приходится дебажить агентов, когда сам пишу с их помощь, по этому воркшоп "Смотри, как думает агент: Observability AI-агентов с Langfuse" выглядит очень привлекательным. Схожу на доклад Ивана Поддубного "Уровни зрелости внедрения AI в процессы разработки", поскольку часто сам вижу внедрения ИИ в команды и, чаще всего, очень топорное. Послушаю "Как жить без строгой консистентности и не терять деньги", надеюсь это не доклад-пересказ документации. Автор доклада из финтеха, интересно как финтех уживается с evantual consistency. А если и вы будете на конфе, то подходте поболтать и обсудить доклады и воркшопы.🫰

Всем привет! В этом году я не выступал и не посещал никакие конференции. И, честно говоря, уже порядком по ним соскучился. Совсем скоро, 22 и 23 июня в Питере пройдёт Saint HighLoad++ 2026. Я там буду и планирую походить на доклады. Вообще, в этом году ну очень много докладов про ИИ, внедрении ИИ и проечее ИИ. Я насчитал 20 из 50 докладов. Т.е. больше 1/3, что дофига для конференции про высокеи нагрузки. А про ахитектуру всего 1 доклад, 1 воркшоп, и игра по System Design (что, кстати, очень интересно, жаль я не смог поучасвовать в отборе). Вот мой топ докладов, которые хочу послушать: Я люблю копаться в кишках баз данных, по этому воркшоп "Допиливаем свой форк Постгреса свистелками" хочу посетить и попробовать собрать что там получится. Мне часто приходится дебажить агентов, когда сам пишу с их помощь, по этому воркшоп "Смотри, как думает агент: Observability AI-агентов с Langfuse" выглядит очень привлекательным. Схожу на доклад Ивана Поддубного "Уровни зрелости внедрения AI в процессы разработки", поскольку часто сам вижу внедрения ИИ в команды и, чаще всего, очень топорное. Послушаю "Как жить без строгой консистентности и не терять деньги", надеюсь это не доклад-пересказ документации. Автор доклада из финтеха, интересно как финтех уживается с evantual consistency. А если и вы будете на конфе, то подходте поболтать и обсудить доклады и воркшопы.🫰

Привет, мои юнные архитекторы. 👨‍💻 Сегодня я хоче разобрать с вами задачу из System Design Interview. Будем проектировать платёжную систему. В чём интерес в такой системе? В первую очередь в том, что мастшабирование тут вообще не первостепенно. Везде, где есть деньги, важна исключительная надёжность 🤑 Го читать — https://teletype.in/@mifleo/payment-system-design А потом давайте обсудим в комментариях! ⸻ Давайте оставаться на связи

Привет! 📞 Я иногда разгоняю на софтовые темы, сегодня хочу поговорить о внедрении изменений. Предположим, ты в своей команде ты видишь какой-то процесс, который нужно изменить или изменений пришли "сверху" и нужно их произвести у себя, или это какие-то вынужденные меры. Для каждого случая может потребоваться своя стратегия. Вообще, тема внедрения изменений достаточно объемная и глубокая. От неверно выбранной стратегии даже хорошие изменения часто загибаются. Самый простой способ: директивно "спускаем" своё решение.
"Команда, со следующего вводим WIP-лимиты".
Даже у понимающих и лояльных сотрудников начинается отрицание, потому что никто не любит перемены. Так устроена челочечиская психика. А не понятные перемены мы не любим ещё больше. Лучшим исходом будет, что, пока ты следишь за процессом и контролируешь его, оно как-то работает. Как только контроль ослабляется, то процесс уходит на помойку. С дугой стороны, очень легко наткнуться на протест. Молчаливый или открытый. Или саботаж. И ты можешь подумать, блин, ну все же знают, что дают WIP лимиты. Ограничиваем и выравниваем поток, делаем контролируемую поставку. Чё они сопротивляются-то? Я же знаю, как лучше будет. Конечно, далеко не все знают о лимитах и об их пользе, что они делают и зачем. Конечно, совершенно точно, никто не знает твою цепочку рассуждений, какую проблему ты хочешь решить и почему именно так. Самое постое лечение тут, это развенуть принятие решение в сторону: "Команда, я вижу проблему, что тестирование захлёбывается в задачах" или "задачи скапливаются в код ревью и не двигаются дальше, что будем делать?". Идеально, когда решение формулиуется всей командой даже если ты его знаешь. Так решение становится общим и понятны, и его морально легче принять. У процесса должен быть владелец. Классно, если у изменения был какой-то противник и его удалось перетащить на свою сторону, если назначить этого бывшего противника смотреть за новым процессом ты выигрываешь комбо: противник становится адпетом и новый процесс остаётся под присмотром. Окей, а как понять, что это изменение реально что-то сделало лучше? Это важный поинт. Во-первых, нужно измерять. Перед началом улучшения прикинь текущую точку А и куда в итоге хочется прийти, как понять что мы пришли и как это померять. Можно вести дневник по внедрению изменения. Записывать что стало лучше, что хуже и т.д. Такой подход будет работать и для не крупных инициатив внутри команды. А в следующей заметке я расскажу как внедрить крупное изменение. Обсудим? ⸻ Давайте оставаться на связи

Всем привет. Продолжаю делиться нетленной классикой. На очереди «Чистый код» — одна из самых известных книг о качестве кода.
Всем привет. Продолжаю делиться нетленной классикой. На очереди «Чистый код» — одна из самых известных книг о качестве кода. Её часто советуют джунам как обязательную базу, но нормально читается и осознаётся она как раз после того, как у тебя уже были реальные проекты, легаси, спорные ревью и функции на несколько экранов. Мартин разбирает повседневные вещи: имена переменных и функций, размер методов, комментарии, форматирование, обработку ошибок, тесты, классы, границы модулей, работу с чужим кодом. Буд-то и ничего прям нового. Но ценность книги как раз в том, что она заставляет внимательнее смотреть на мелкие решения, из которых потом собирается общая сложность проекта. Главная мысль, которую я забрал из книги: код читают чаще, чем пишут. Я убеждён, в том числе и это отличает грейд разработчика: писать код для чтения. Любой участок, который сегодня кажется очевидным, через полгода превращается в задачу на археологию, если в нём спрятаны неявные допущения, странные имена, побочные эффекты и логика, размазанная по нескольким уровням. Хорошее (говорящие) имя функции, переменной или класса должно сокращать количество вопросов у читателя. Прямо помогать понять, что происходит и зачем. Если название врёт, слишком общее или требует знания контекста из головы автора, оно уже создаёт долг. Отдельно полезны главы про функции. Мартин довольно сильно продвигает идею маленьких функций с одним уровнем абстракции. С этим можно спорить, особенно в современных проектах, где чрезмерная нарезка иногда ухудшает навигацию. Но сама проверка полезная: функция должна быть понятна как единый шаг алгоритма. Если внутри смешаны валидация, бизнес-логика, работа с БД, форматирование ответа и логирование, сопровождение быстро дорожает. Кстати, комментарии в книге разобраны хорошо. Идея Мартина в том, что комментарий не должен компенсировать плохой код. Если можно выразить намерение через имя, структуру или тип, лучше сделать это в коде. Комментарии нужны там, где без них нельзя объяснить контекст, ограничение, компромисс или неочевидное решение. С тестами позиция тоже понятная: тестовый код — часть системы, а не мусор рядом с ней. Если тесты хрупкие, нечитаемые и требуют постоянного переписывания при любом изменении, команда постепенно перестаёт им доверять. Это один из самых практичных тезисов книги: плохие тесты не спасают качество, они сами становятся источником энтропии. При этом книгу не стоит воспринимать как набор законов. (как и любую другую, кстати) Некоторые советы выглядят слишком категорично. Например, идеи про экстремально маленькие функции, отказ от комментариев или отдельные ООП-подходы могут плохо ложиться на конкретный стек, стиль команды или доменную сложность. «Чистый код» полезнее читать не как инструкцию, а как набор инженерных проверок: что усложняет понимание, где спрятан побочный эффект, почему этот участок страшно менять. Мой основной вывод: чистота кода — это скорость безопасных изменений. Код может работать сегодня, проходить тесты и даже выглядеть аккуратно, но быть дорогим в сопровождении. Проверка кода начинается тогда, когда приходит новое требование, меняется бизнес-правило или разработчик без контекста должен быстро внести правку. Читать лучше не залпом, а с примеркой на свой код. Взял главу про функции — открыл пару рабочих классов и посмотрел, где смешаны уровни абстракции. Прочитал про имена — прошёлся по DTO, сервисам, методам и тестам. Так книга даёт больше пользы. Хотя сам я её прочёл залпом. Итог: «Чистый код» стоит прочитать, но без религиозного отношения. В ней есть спорные места, возрастные примеры и категоричные формулировки. Но базовый навык, который она тренирует, до сих пор важен: смотреть на код глазами человека, который будет его читать, менять и отвечать за последствия этих изменений. Обсудим? ⸻ Давайте оставаться на связи

Привет, мои юнные архитекторы. Обычно кэш в мы используем для ускорения чтения. Да? 😄 Схема такая:

read from Redis
if miss -> read from PostgreSQL/MySQL
put result to Redis
При изменении данных приложение пишет в базу, а кэш инвалидирует или обновляет. Это обычный cache-aside. "Правда" остаётся в базе. Потеря кэша в такой схеме неприятна, но не приводит к потере бизнес-данных. Но есть и другой вариант: приложение сначала пишет данные в ин-мемори (напиме, редис), быстро подтверждает операцию клиенту, а потом отдельный процесс асинхронно переносит изменения в постоянное хранилище. Такой подход обычно называют: • write-behind cache; • write-back cache; • cache-first write path; • буферизация записи через Redis. Схема выглядит просто:

PHP application
  -> Redis
  -> async worker
  -> PostgreSQL/MySQL
Быстрая запись, меньше нагрузки на базу, возможность переживать пики и флашить данные пачками. Но при таком write path Redis становится частью механизма хранения, а не просто ускорителем чтения. Можно ли это вообще называть кешом теперь? Кэш как часть write path Кэш можно удалить и восстановить из основного хранилища. Если после потери Redis теряются подтверждённые пользователю действия, Redis используется уже как write buffer или временное хранилище. Для такой роли нужны другие требования: - durability; - порядок применения изменений; - идемпотентность; - восстановление после сбоев; - контроль backlog; - backpressure. Название “кэш” в этом месте часто мешает. Оно создаёт ощущение, что слой можно потерять без последствий. Для cache-first систем это неверно. Рассмотрим, где cache-first подойдёт. Такой подход может работать для данных, где допустима eventual consistency и ограниченная потеря части событий. Например: - просмотры; - лайки и реакции; - rate limiting state; - сессии; - временные агрегаты; - игровые события; - телеметрия; - clickstream; - промежуточное состояние, которое можно пересчитать. В этих сценариях write-behind может быть нормальным компромиссом между скоростью записи и строгостью гарантий. Для денег, заказов, остатков, прав доступа, юридически значимых действий и сложных бизнес-инвариантов такой подход требует отдельного обоснования. Чаще всего безопаснее писать сначала в durable storage или durable log. Основной риск: окно между Redis и базой Пример на PHP:

$redis->hSet("user:{$userId}", 'email', $newEmail);

$redis->rPush('pending_writes', json_encode([
    'operation_id' => $operationId,
    'type' => 'user_email_changed',
    'user_id' => $userId,
    'email' => $newEmail,
]));

return new JsonResponse(['status' => 'ok']);
Клиент получил 200 OK. Постгрес ещё не обновлён. Изменение находится только в Redis и будет применено позже фоновым воркером. Для такой схемы нужно заранее ответить на несколько вопросов: - что произойдёт при падении Redis до flush в PostgreSQL; - включён ли AOF; - какой режим appendfsync используется; - что будет при failover до репликации; - как воркер поймёт, что запись уже применена; - что произойдёт при повторной обработке операции; - как сохраняется порядок изменений по одной сущности; - откуда система будет восстанавливаться после аварии. Без ответов на эти вопросы клиентский 200 OK означает только успешную запись в буфер, а не сохранность данных. Потеря подтверждённых записей Если запись подтверждена клиенту после Redis, но до PostgreSQL не дошла, сбой Redis может привести к потере данных. Для счётчиков или аналитики это иногда допустимо. Для смены email, оплаты, бронирования или изменения прав — обычно нет. Тут важно понять, а какие у нас гарантии записи? Если бизнес-смысл операции требует сохранности, подтверждать её после записи только в Redis такое себе решение. Redis может быть быстрым буфером, но сама операция должна иметь durable-точку: базу, журнал, очередь или другой устойчивы страдж. Если ты думаешь "Ну, сначала пишем в Redis, потом воркер переложит в базу.", то кое-что от тетбя ускользает 😀 Продолжу с ледующем посте🔤 ⸻ Давайте оставаться на связи

Привет. Видели уже RFC по дженерикам в php? В PHP обсуждают RFC Bound-Erased Generic Types — попытку добавить нативные generi
Привет. Видели уже RFC по дженерикам в php? В PHP обсуждают RFC Bound-Erased Generic Types — попытку добавить нативные generics: Box<T>, Repository<User>, function map<T>(). Сейчас generics в PHP живут в PHPDoc в рамках статанализаторов или пхп шторма:

/**
 * @template T
 * @param T $value
 * @return T
 */
function id($value) {
    return $value;
}
RFC предлагает перенести это в синтаксис языка:

function id<T>(T $value): T {
    return $value;
}

final class Box<T> {
    public function __construct(public T $value) {}
}
Классно, что появится общий подход вместо абстрактного @template в phpdoc для станализаторов. RFC даёт общий синтаксис, bounds, defaults, variance и Reflection metadata:

final class Repository<T : Entity> {}

final class Cache<K = string, V = mixed> {}

interface Producer<+T> {}
interface Consumer<-T> {}
Для крупных проектов и библиотек это полезно: generic-контракт становится частью API, а не комментарием рядом с ним. Но подход спорный. Очень. Это bound-erased generics. Type parameter в runtime стирается до своего bound. Если bound не задан — до mixed.

function id<T>(T $value): T {}
Здесь T в runtime фактически превращается в mixed.

function save<T : Entity>(T $entity): void {}
Здесь T стирается до Entity. Совсем не то, чего хотелось бы, правда? Короче, конкретный type argument не становится полноценной runtime-проверкой.

final class Box<T : object> {
    public function set(T $value): void {}
}

$box = new Box::<User>();
$box->set(new Order());
Если Order — объект, runtime может это принять. С точки зрения Box<User> это ошибка, но ловить её должен static analyzer. Ещё неприятнее выглядит такой пример:

function id<T>(T $value): T {}

id::<int>("hello");
Вы могли подумать, что ::<int> должен запретить строку. Но RFC описывает другое поведение: turbofish проверяет generic-аргумент, arity и bounds, но не ужесточает runtime-тип параметра. Если T стёрся до mixed, строка пройдёт. Я работал с языком, когдам никакой типизации небыло вовсе, а в последние годы язык усиливал runtime-типизацию: scalar types, return types, union/intersection types, typed properties, readonly. Я как разработчик привык: если тип написан в сигнатуре языка, движок его проверяет. С generics по этому RFC вообще не так. Синтаксис выглядит как часть языка, но значительная часть гарантий остаётся на стороне стат анализа (который не часть языка совершенно). Если не обмазаться статанализом, то чуда не случится. Ещё один минус для меня — RFC не закрывает самый частый PHP-сценарий:

/** @return list<User> */
/** @param array<string, Order> $orders */
array<int, string>, list<User>, non-empty-list<User> в этот RFC не входят. А именно массивы — главный источник generic-аннотаций в обычном коде. В общем, RFC прикольный как стандартизация @template и база для тулинга. Он улучшит контракты для стстанализа, Reflection и публичные API библиотек. Но как полноценные дженерики в языке подход кастрированный. Box<User> не становится железным runtime-контрактом. Runtime проверяет bounds, а не полную параметризацию. Вообще, если примут, имхо, получается очень фиговая комбинация: - синтаксис как у языка - семантика как у комментариев - обязательного чекера нет - runtime-проверка частичная Обсудим? ⸻ Давайте оставаться на связи