this->notes.
4.49K subscribers
56 photos
1 file
437 links
О разработке, архитектуре и C++.

Tags: #common, #cpp, #highload и другие можно найти поиском.
Задачки: #poll.
Мои публикации: #pub.
Автор и предложка: @vanyakhodor.
GitHub: dasfex.
Download Telegram
Про контент.

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

Наблюдения такие:
• было солидное количество докладов, которые уже рассказывали на других конференциях. Это стандартная практика, но она чувствуется гораздо сильнее в англоязычном пространстве, когда конференций и докладчиков в целом больше. Если сейчас в программу Meeting C++ 2026 заглянуть, там вы тоже солидное кол-во повторов найдёте.
• очень много говорят про фичи последних стандартов. Рефлексия. Контракты. Это логично, ведь всем хочется знать, как там фичи покруче использовать, но я в последнее время перестал пытаться ухватывать каждую новую функцию. Стараюсь смещать фокус в более фундаментальные вещи.
• безопасность и Rust. Ну вот популярные насущные топики. Что с них взять.

Было ощущение, что не всегда доклады в сетке расставлены равномерно. Где-то в большом зале мало людей, а в другом поменьше не протолкнуться. В последний день в один слот стояли Jason Turner, Matt Godbolt и Timur Doumler. Жоска!

Мне очень понравилось.

Несколько фотографий с конфы и из города в целом.

На фото номер 3 коллега из Bloomberg: Женя Селиверстов. У него блог есть: omniverse.ru

Последняя — с прогулки в соседнем Hythe, где мы случайно встретили огромного пса Scooby. Наш 6-килограммовый зверь был готов наброситься, но он не знает, как это не любить кого-то, так что обошлось.
👍15🔥6❤4
#list

0. [talk] Achieving Peak Performance for Matrix Multiplication in C++. Aliaksei Sala.

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

1. [article] How Google Measures and Manages Tech Debt.

Хорошая системная статья про то, как в Google пытаются мерять и бороться с техдолгом как явлением. Вряд ли вы найдёте радикальные откровения, но системность подхода на уровне.

2. [article, download pdf] Microservices Anti-Patterns: A Taxonomy.

Статья написана поверх опроса специалистов на тему антипаттернов при использовании микросервисов. Я — святая простота — некоторым типичным проблемам удивился, так как даже подумать не мог, что где-то считают это нормальным. Например, «local logging», который подразумевает хранение логов в рамках контейнера одного сервиса. То есть нельзя сразу везде искать. Жесть как так жить вообще можно...

Хотя с другими я не прям согласен как с проблемами. Имхо можно спокойно и без API-gateway пожить. И shared libraries вообще-то отличное решение, если адекватно ими пользоваться.

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

Не предлагаю прочитать всё внимательно. Скорее пробежаться глазами по табличкам с описанием отдельных проблем в середине.

3. [article] Build better software to build software better.

Чуваки из Slack рассказывали, как переделывали build-пайплайн.

Кроме очевидных поинтов мне очень понравилась мысль (нигде явным образом не сформулированная), что иногда использование тулинга требует подготовки и переделки системы под инструмент.

И может это даже окупится.

4. [article] p99 0 ms* autocomplete for 240 million domain names.
👍5❤2
#common

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

Например, сервис доставки продуктов, в котором я провёл 4 года, обладает (по крайней мере раньше) некоторыми интересными свойствами.

Во-первых, это жутко операционный бизнес.

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

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

Операционка — ограничение, которое всегда было и постоянно нужно учитывать.

Но это не то, про что я хочу рассказать. Ещё есть во-вторых: сервис не имел user generated content (UGC). Хотя он предоставлял какой-то контент (товары посмотреть). Всё, что вы видели в приложении, полностью создаётся или внимательно валидируется сотрудниками. В какой-нибудь социальной сети, живущей на UGC, в любой момент кто угодно может запостить абсолютно что угодно. А вот в сервисе доставки нет.

Почему это хорошо?

Я не говорю, что это хорошо. Я говорю, что это существующее ограничение, которое имеет свои плюсы.

Например, вы можете доверять данным. Это значит, что задач
• модерации
• антиспама
• соблюдения копирайта
просто не существует.
Вам не нужно удалять содержимое за мгновение, потому что юзер мог написать что-то не то и яростно кликает на кнопку Delete. За сутки отрастёт и ладно (преувеличиваю конечно, но суть ясна). А это даёт возможность обкладываться кешами по самое не хочу.

Другое преимущество: объём данных не растёт так непредсказуемо.
Никакой пользователь на загрузит гигабайт фоток за полдня. Не придёт злостный робот-спамер с вредными комментариями (придут другие, но про это когда-нибудь потом).
Вам буквально проще заниматься capacity planning.

Более того, скорее всего данные в целом меняются не очень часто -> вы получаете систему вида «few writes, many reads». Значит возможно данным не нужно появляться мгновенно (что тоже не всегда правда, но мы теоретизируем) и можно обрабатывать их более сложными и долгими способами. Можно в конце концов взять 1000 самых популярных поисковых запросов (если у вас поиск есть) и посчитать самые релевантные ответы на них. Раз в сутки пересчитывать одной большой долгой кронкой.

У вас вероятно нет горячих и холодных данных (ну может с какого-то момента есть, но до этого вам нужно ещё дожить, когда в системе с UGC всё может произойти завтра).

Я не говорю, что все отпавшие задачи выше — фигня какая-то. Нет. Они очень интересны. Но у вас трейдофы смещаются в сторону и позволяют оптимизироваться под вещи, которые не могут быть возможны в UGC системах. Всё вокруг вы можете оптимизировать под чтение, а не запись.

Иногда от UGC можно умело избавляться -> не добавлять сложные последствия. Например, не показывать отзывы юзеров на товары, а показывать AI-суммаризацию (CEO вам ещё спасибо скажет: AI добавили, нифига себе модные).

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

Попробуйте потратить время на этой неделе, чтобы глубже ощутить подобные ограничения в вашем проекте.

@thisnotes. Patreon.
Спасибо Artyom Garkavy и niki4smirn.
От мегапатрона Artyom Garkavy вам:

Try it today: google.com.
👍17❤8
Давайте новый тег заведём: #perf

Во-первых, надо понять, что я вообще понимаю под перфом, ведь понятие очень широкое. Так как мои интересы лежат в районе эффективности распределённых систем, то перф для меня — всё, что позволяет делать эти распределённые системы быстрыми. В зависимости от системы вам может понадобиться решать проблемы разного характера. Где-то это про сделать ручку для обработки данных батчами, чтобы по сети поменьше ходить. Где-то научиться нормально пользоваться БДшкой. Где-то надо почаще попадать в L1 кеш и префетчить данные. А где-то вообще выбросить всё что есть и сделать заново в другой парадигме. Вся широта проблем меня занимает. В разной мере в разное время.

На самом деле я бы расширил понятие перфа до слова эффективность. И разговаривал бы ещё про то, что такое эффективность команды или всех разработчиков на стеке Х. Что такое developer experience. Почему унификация помогает средне-большой компании экономить деньги и вот это всё. Тут конечно надо быть осторожным и не уйти в степь вида «дайте-ка я ещё померяю, кто у меня в команде больше коммитов делает и буду им оценочку на ревью повыше ставить». Я за здравое понимание «эффективности разработки», а не за вот это корпоративное обмазаться метриками и всем в нос им потом тыкать.
Но такие вещи я постараюсь в тег не заносить, чтобы не обманывать хардкорных си плюс плюс подписчиков.

Во-вторых, начать тег я хочу с концепции. Концепция хорошо показана в докладе с CppCon 2014: Data-Oriented Design and C++ от Mike Acton. Это даже тот самый классический доклад, который всем показывают по теме.

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

Суть хорошо показана в первой части (где-то первые 30 минут, дальше начинаются примеры кода). Кратко её сформулировать можно так: данные это всё. Основная проблема: при решении задач мы часто оперируем ментальными моделями, которые хорошо выглядят с точки зрения нашего человеческого понимания объектов, трансформаций данных и решения проблемы «переложить объект слева направо». Но так как компуктеры работают не так, как мы думаем, необходимо взять себя в руки и подумать про то, как данные должны трансформироваться (фактически единственно важный вопрос при проектировании). И из этого ответа у вас вытекают все возможности решений.

Фактически весь перф это про data oriented design. Ведь вам не нужно ускорять то, что согласно данным не нужно ускорять. И нужно то, что нужно. Вам нужно знать, как ваши данные выглядят, какие там взаимосвязи. Как они используются. Желательно знать как можно больше. Вы хотите решать задачу для наиболее common случая, потому что это статистически принесёт больше пользы.

Короче знайте свои данные.

Есть ещё доклад Vittorio Romeo «More Speed & Simplicity: Practical Data-Oriented Design in C++». Несмотря на какой-то околоискуственный пример, тут неплохо показана попытка сдвига мышления от привычной OOP парадигмы в сторону DOD.
Особенно, пусть это и не относится особенно к делу, красиво задвинул в конце про адекватный интерфейс для SoA.

У меня вот прям после некоторого количества информации по этой теме какой-то сдвиг в голове случился, и некоторые вещи обрели новый, более устойчивый смысл, а некоторые его радикально потеряли. Будем наблюдать, какие плоды это в итоге принесёт.

@thisnotes. Patreon.
Спасибо Artyom Garkavy и niki4smirn.
На правах мегапатрона послание подписчикам от Artyom Garkavy:

Try it today: google.com.
👍17❤2
#perf

Попробовал собрать в кучку (кажется, немного сумбурно всё же) мысли по двум моментам:
• что искать в данных и как их собирать, чтобы на них можно было быть oriented
• чуть более разнообразные, чем обычно, примеры применения DOD.

https://thisnotes.dev/blog/dod_examples/

Да, на инглише, теперь иногда будет так.

Ещё можете подписаться на newsletter: https://thisnotes.substack.com/subscribe
Может вам на почту удобнее получать.

@thisnotes. Patreon.
Спасибо Artyom Garkavy и niki4smirn.
🔥8❤3👍3
#cpp #books

Да, книга 2001ого года. Мы ровесники.
И да, в ней в основном обсуждаются какие-то решения, которые сегодня уже всем знакомы и лежат в стандартной библиотеке сто лет. Но есть но...

Содержание:
1. Policy-Based Class Design.
Глава рассказывает про сложности создания качественного кастомизируемого дизайна общих классов и почему множественное наследование не помогает в решении проблемы экспоненциального роста потенциальных версий ваших компонент. Есть примеры использования различных policy.
В конце обсуждается, как декомпозировать ваш класс на policy. Есть такой совет: «Anything that can be done in more than one way should be identified and migrated from the class to a policy». Важно помнить, что книга для пишущих общего вида библиотеки. Скорее всего для общего решения в продуктовом коде правильнее будет сказать: «Выносите то, что прямо сейчас нужно вынести». Не наперёд, а в моменте.

2. Techniques.
Вторая глава рассказывает про набор отдельных утилиток и возможностей языка, которые могут применяться в более общих решениях. Некоторые из них:
- compile-time assertions (до static_assert)
- partial template specialization
- integral constant to type (дед std::integer_constant)
- type-to-type mapping
- type selection (std::conditional)
- TypeTraits (правда тут это класс с константами, а не как у нас «вчера» шаблонные структуры)

3. Typelists.
Typelists конечно не поддерживают произвольное количество аргументов (потому что шаблоны не умели). Выглядят они так:

typelist<type1, typelist<type2, type3>>

Дальше реализовываются разные операции и рассказывается про применение класса.

4. Рассказывает про проблемы стандартного аллокатора и после введения локальных понятий поясняет реализацию small-object аллокатора.

5. Про паттерн Command и generalized functor для его реализации. Фактически std::function.

6. Рассказывает про реализацию Singleton.

Причём довольно подробно описывая проблемы разных подходов. В итоге приходим к Meyers singleton. После небольшого chatgpt-like фактчека оказалось, что именно в этой книге Andrei Alexandrescu подарил миру это название.
Далее он рассматривает самоназванную KDL problem (которая легко может возникнуть на практике) и изобретает Phoenix singleton для её решения.
К концу главы обсуждается реализация singletone для многопоточного случая и общая policy-based реализация.

7. Про умные указатели.
Кто такие, как пользоваться и как должны быть реализованы с точки зрения различных случаев на практике.

8 и 9. Про фабрики и абстрактные фабрики.

10. Посвящена паттерну visitor.

11. Реализации мультиметодов.
Это как бы перегрузка функций, которая знает чуть больше, чем положена. Кратко можно пояснить так:

class Shape {};
class Asteroid : public Shape {};
class Spaceship : public Shape {};

void Collide(Asteroid& a, Spaceship& s) { /* Logic 1 */ }
void Collide(Shape& s1, Shape& s2) { /* Logic 2 */ }

И вот обычно вы бы вызвали Collide на основании того, какая ссылка была передана. Если Asteroid был передан как Shape, то вызовется общая функция для Shape. Вот мультиметоды позволяют понять, какой объект на самом деле лежит в памяти и вызвать для него соответствующую перегрузку.

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

Сегодня конечно книга выглядит уже скорее как исторический артефакт. Но!
• первая глава про policy-based design всё ещё актуально, потому что говорит концептуальные вещи. Мне она сильно запомнилась и помогла на некоторые концепции иначе смотреть.
• большинство других глав полезны с точки зрения понимания, как стоит смотреть на проектирование общих решений.

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

@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
👍20❤8🔥2
#common

Сидите вы себе спокойно, разрабатываете поиск каких-нибудь объектов. Может это товары, может странички вики, может код. Что угодно. Ваш поиск — качественный keyword search.

Почесали вы репу и решили, что надо улучшать качество. Обучили новую модель, которая умеет понимать СмЫсЛ и выдавать эмбеддинги объектов. Эмбеддинги вы складываете в какую-нибудь векторную БД. Поиск там работает из коробки.

Вопрос: как интегрировать два поиска?

Проблема тут понятная: так как модели поиска работают различно, взять скор каждого объекта и сравнить со скорами объектов из другого поискового движка просто нельзя (это не имеет смысла, ведь в одном движке скор может быть от 0 до 1, а в другом [0; 1000]; считаются по-разному, означают разное).

Что делать?

Reciprocal Rank Fusion (RRF) — алгоритм объединения нескольких списков результатов поиска в один общий. Идея за ним простая: вместо сравнения сырых скоров из разных поисковых систем мы будем смотреть только на позицию айтема в изначальных списках.
Выражается формулой:

RRF(doc) = SUM( 1 / (k + rank_i(doc) ), i in [1; N]


doc — документ
N — количество поисковых систем/движков
rank_i(doc) — позиция документа doc в i-м списке
k — некоторая константа, положим 60.

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

Давайте быстрый пример. Keyword search выдал (номер-документ):

1 A
2 B
3 C
4 D

а vector search:

1 C
2 A
3 E
4 B

Тогда

RRF(A) = 0.0325
RRF(B) = 0.0317
RRF(C) = 0.0323
RRF(D) = 0.0156
RRF(E) = 0.0159

Итоговый результат выглядит так:

1 A
2 C
3 B

D и E можем опустить по некоторому трешхолду или просто потому что они не встретились в результатах обоих движков.

Почему мы взяли k=60?

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

Плюсы RRF:
• не требует никакого обучения. Простой математический метод.
• очень легко реализовать. Джуна посадите и чекните PR через день.
• неплохо работает даже в самом базовом виде. Без подкручивания k.
• устойчив к разным шкалам score, потому что их не использует.
• очень легко добавлять новые движки.

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

Фактически RRF — первый бейзлайн для гибридного поиска. Но если хочется качество получше (то есть перестать просто «смешивать» документы, а реально понимать «что лучше показать юзеру»), нужно обучать отдельную модель, которая переранжирует результаты ещё раз. Может она даже будет тяжёлой, но в силу того, что работать ей надо не со всем набором документов, а только с топ-X найденных, это обычно не проблема.

@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
❤20🔥6👍4😁1
#cpp

Представьте вот такой код:

auto object = GetObject(params...);

auto another = object;
MessAround(object);

// (1) you want to write some logic here

Где MessAround — функция, которая непредсказуемым образом меняет значение вашего object. То есть значение соответствует всем инвариантам, но вы не знаете, какое конкретно.

Как вы будете писать код в (1)?

Вы наверное проверите какие-то свойства вашего object. Может он там empty()/isNull()/valid(). Или может вы сразу решите его почистить: clear(). Или может присвоить что-нибудь туда захотите: object = Object{1, 2, 3}.
Или можете вообще сравнить его с чем-то (вдруг там всё-таки какое-то конкретное значение появилось):

if (object == "str_val"_obj) {...}


Делаете ли вы что-то неправильное? Должен ли компилятор вам подсказать проблему в таком коде? Может UBsan? Может clang-tidy?

Да нет.

Более того, даже если вы сделаете что-то такое:

auto first = object["first"];

Вы возможно ничего плохого не сделали. Вы просто не знаете, что точно там лежит. MessAround туда могло подложить что угодно.

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

Использовать объект после MessAround это примерно то же самое, что написать функцию, решающую некоторую задачу в вакууме. На примере функции, решающей любую задачу:

void solve(Object obj) {...}

Вы опять же про этот obj ничего не знаете. Вам надо проверить разные корнер кейсы. А потом как-то там решать вашу проблему.

Чем эти примеры отличаются от работы с переменной после std::move?

Да ничем.

Мы так яро привыкли к правилу «использовать переменную после std::move опасно», что в нашей ментальной модели это часто равносильно undefined behaviour. Уже само это действие вызывает подозрения. Code smell так называемый.

Хотя никакого UB тут нет. UB может возникнуть от того, что вы пользуетесь объектом, предполагая, что у него есть какие-то свойства. Точно так же и в нашей функции solve, которая может не учесть какие-то потенциальные входные данные. Пытаться разыменовать пустой указатель, не проверив его, неправильно.

И к сожалению эта ошибка стала достаточно частой, чтобы мы выработали ощущение неправильности происходящего. Само действие стало табу. В clang-tidy вон проверка отдельная есть (которую приходится игнорировать с NOLINT).

Отсюда рождаются ментальные модели вида
• «после std::move ничего нельзя»
• «после std::move можно только переприсваивать или уничтожать объект, всё остальное запрещено».
Это упрощения, которые мы себе придумали, чтобы меньше думать. И они почти всегда работают. Но иногда всё же нет.

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

P.S. Важно подчеркнуть ещё один факт.
Состояние объекта после std::move — всем известное «valid but unspecified». По стандарту это работает для стандартной библиотеки. Но кажется, мы уже настолько к этому привыкли, что считаем это данностью в любом случае. Не то чтобы это ожидание обосновано. Авторы библиотек делают что хотят. Но наверное писать ломающий это ожидание код всё-таки не надо.
А для стандартной библиотеки довольно просто понять, можно ли вызывать метод у мувнутого объекта: у метода не должно быть precondition. Например у std::vector::front он есть: !empty(); у std::vector::clear такого нет.

@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
👍14👎4
Фиксируем результаты.

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

• География (>560).
РФ 65%, 11% Беларусь, несколько ожидаемых для меня стран одинакового размера (Сербия, Польша, UK по паре процентов). Чуть больше на остальную европу и столько же на остальной мир (по 8%).

• Род занятий (≈560).
86% разработчики. Ещё 5% — ML-enjoyers. В остальном либо очень мало, либо непонятно кто.

• Опыт (≈570).
Тут всё согласно нормальному распределению (что интересно, учитывая произвольность выбранных интервалов). Большинство (26%) 3-5 лет. По 20% на 1-3 и 5-10. По 14% на <1 года и 10-20 лет. И 6% имеют >20 лет.

Подтвердил ожидания.

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

• Грейд (≈560).
8% не работают. Я надеюсь, это ваш осознанный выбор.
Столько же студентов/стажёров и джунов. 32% middle. 29% senior. Всё до этого момента выглядит ожидаемо.
6% подписчиков переросли senior (уважаемо, особенно если вы не просто себе лычку выбили). Порядка 6% — руководители (в основном IC, но есть и пару M2+, и даже один C-level, кто бы вы ни были).

Фактически получается, что аудитория у меня всё-таки больше опытная, чем неопытная. Это конечно хорошо, но возможно с толканием базы надо быть осторожнее.

• Размер компании (545).
Не то чтобы это радикально важно, но даёт примерную картинку, насколько разные инженерные практики вы видите. Потому что компания размером 50 явно отличается от компании в 20к человек. Хотя и одна компания в 20к может радикально отличаться от другой компании в те же 20к.

Значит вы разнообразные ещё и в самом опыте, и в проблемах, с которыми приходится сталкиваться.

23% в супергигантах каких-то. Почти 40% в небольших компаниях до 1000 человек. Остальные в серединке.

• ЯП (520).
Ожидаемо, большинство из вас трогает C++ (75%), C (21%), Python (47%) и Go (21%). Остальное поменьше. Rust всего 7%. Молодой ещё видимо.
Java/Kotlin и Js/Ts по 10%.

На Cobol никто не пишет. Слава богу.

• ЯП интересы (≈470).
Rust увлекает почти половину подписчиков (меня пока нет). Остальное +/- матчится с тем, что фактически используется.

• Сфера (≈550).
Половина — бэкендеры. Всё остальное в меньшинстве.
Получается, средний подписчик — C++ бэкендер. Это довольно необычное сочетание для мира разработки.
И я такой же. И такая комбинация мне очень нравится. Хорошо, что мы друг друга нашли.

• Интересы (≈460).
>40 % — backend. ≈30% — DB. 56% — low-level performance (значит можно и даже нужно больше уделять этому внимания). 38% конкретно backend performance (и сюда). 54% concurrency (и сюда!!).
Пятая часть подписчиков ещё интересуются engineering management (значит я буду время от времени что-то про это писать, но не увлекаться).

• Карьерная задача (≈510).
1/10 ищет первую работу. Успехов вам.
1/4 растёт до senior. Если будете делать правильные вещи, то получится достаточно быстро. Тут важно быть надёжным работягой и не подводить важных людей. Вы этому научитесь.
13% хотят вырасти дальше senior. Я тут концептуально понимаю, как это, но на практике пока не наработал. Давайте разбираться вместе.
8% хотят двигаться в сторону EM и дальше (см. канал Андрея и его community).
7% и 14% процентов хотят в бигтех или более технический домен. Значит вам нужно понять, чего ждут от хорошего кандидата и пойти усиленно над этим работать. Если не понимаете, что надо, приходите ко мне поговорить.
1/5 кайфует от жизни. Рад за вас!

• Уровень понимания (≈490).
1/4 понимает всё.
45% тратит некоторые усилия на вникнуть. То есть не прям очевидно, но достаточно понятно.
1/5 чуть сложнее. Улавливают концепции, но есть сложности с деталями.
Меньшинству очень сложно. Приходите с вопросами, чего вы!
5% шутников не вникают, потому что им не интересно. Ну штош!

Получается, что большинство понимает всё довольно успешно. Варианта 2: либо я пишу очень понятно (круто); либо топики базовичковые (надо грузить вас чем-то более сложным).

Повторим когда-нибудь, когда вас станет гораздо больше. Будем думать, как это применять теперь мощно.
❤22👍7
#cpp

В стандартной библиотеке иногда встречаются функции, которые не выглядят однозначно. Один из таких примеров: std::exchange:

template< class T, class U = T >
T exchange( T& obj, U&& new_value );


Что делает функция?

Она присваивает obj new_value, и возвращает старое значение obj. Т.е. код ниже эквивалентен:

auto var = std::exchange(a, b);

auto var = a;
a = b;

(я конечно опустил детали move/forward, потому что сейчас важна концепция)

Зачем эта функция нужна? Явно не для сокращения кода на строчку каждый раз, когда у вас возникает подобная ситуация. В стандартную библиотеку ради такого вряд ли бы добавили что-то. Скорее ради упрощения какой-то частой операции. Или для выражения какой-то конкретной семантики.

Вот тут как раз второй случай. Примеры:
• хотим сбросить флаг, при этом прочитав старое значение:

if (std::exchange(shutdown_requested_, false)) {
shutdown();
}

• передача владения в move-кторе:

Widget(Widget&& other)
: handle_(std::exchange(other.handle_, nullptr)) {}

• извлечение текущего состояние (с переходом в следующее):

auto old_state = std::exchange(state_, State::Running);
process(old_state);

• получить значение optional и очистить его:

auto value = std::exchange(pending_value_, std::nullopt);


Плохие примеры:
• присваивание:

std::exchange(enabled_, true);

enabled_ = true;

• старое значение можно выразить очевиднее:

auto old = std::exchange(counter_, counter_ + 1);

auto old = counter_++;

• когда содержит сложное вычисление:

auto old = std::exchange(
state_,
compute_next_state(state_, request, dependencies));

Тут надо разбираться в порядке evaluation. Код может быть не таким очевидным.
• использовать функцию ради одной строки:

auto old_name = std::exchange(name_, new_name);

Тут нет какого-то внятного изменения состояния. Просто пачка переприсваиваний.
• swap:

auto old = std::exchange(a, b);
b = old;

std::swap(a, b);


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

Я бы никогда её не юзал.

И хотя пост про то, что так не надо, некоторые из вас про неё не знали и обязательно станут пихать куда не стоит. Окститесь!!

@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
❤16🔥7👍6😁3
#perf

Осознанно не пишу ничего про ИИ, но не удержался.

Есть такой хорошо известный в среднего размера (а может даже и в широких) кругах чувак — Антон Самохвалов. Я несколько раз его периодами читал, но так как мои интересы не очень матчились с его контентом, я переставал. Недавно узнал про концепцию, которой я очень хочу с вами поделиться. Про неё ниже. В целом сейчас, я кажется, в каком-то смысле до контента Антона «дорос», так что в этот раз планирую на канале задержаться.

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

Поинт такой: раз сегодня с засилием LLM код становится дешёвым, появляется смысл делать (или даже нет смысла НЕ делать) некоторые оптимизации (да и проекты в целом), за которые раньше ни за что бы никто не сел.
Более того, generic решения уходят в прошлое, потому что имея систему, вы можете три доллара понять, что нужно ВАМ в конкретном случае и наклодить частное решение под ваш конкретный юзкейс. Перф даётся проще, если вы знаете, где его искать.

Примеры:
• посмотрел на конкретный паттерн использования памяти и написал аллокатор ровно под него: https://t.iss.one/itpgchannel/4165
• perfect hash с доработками для фиксированного набора расширений файлов: https://t.iss.one/itpgchannel/4184
• огромная стейт машина, которую наклоденерил за 7 часов: https://t.iss.one/itpgchannel/4313
• научился писать данные максимально эффективно на своё конкретное железо в своём конкретном S3: https://t.iss.one/itpgchannel/4484
• тут Антон и сам бы справился, но сэкономил себе нормально так ресурса: https://t.iss.one/itpgchannel/4242

Тут общая концепция словами автора: https://t.iss.one/itpgchannel/4344
и продолжение: https://t.iss.one/itpgchannel/4379

Думаю, вы ощутили, что имелось в виду выше.

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

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

Человек трудящийся уходит в прошлое. В дело вступает человек думающий. У разработчика без глубокой картины происходящего, с узким кругозором, и агент будет использоваться кустарно, чтобы подпереть да подкрутить. Если вы найдёте способы и силы развиваться качественно в текущих условиях, вы не то чтобы станете легитимными 10х, но и всеми 228х разработчиками.

Качайтесь и читайте Антона: @itpgchannel.

@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.

Хотите advent about bad parts стандартной библиотеки в декабре? Если хотите, тыкайте 🌚. Если нет: 🗿.
🌚65👍14🗿2❤1🤪1
#highload

Давайте представим, что у вас есть пару датацентров и по какой-то причине вы потеряли некоторые. Чуть ли не все. Что делать?

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

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

В такой ситуации (как и во многих других) жизненно необходимо уметь правильно функционально деградировать. Вспомним пост от начала года: https://t.iss.one/thisnotes/399

Год назад примерно в окрестности этого времени я активно исследовал, что нужно сделать, чтобы иметь инструмент вида «по кнопке отключить всё кроме самого важного». К сожалению, бизнес устроен так, что такими долгосрочными вещами заниматься почти наверняка нельзя. Это всегда nice to have. До тех пор, пока попа не отвалится (конечно, и я мог бы лучше продавать проекты, но как есть). Прийти к чему-то материальному и полезному не получилось.

Ну что ж.

@thisnotes. Patreon (сюда можно донатить, чтобы мои дц жили вечно), newsletter.
Спасибо Artyom Garkavy и niki4smirn.
😁23👍4😢3❤2🥴1🫡1
#common

На хабре есть отдельный вид постов: перевод.

Значит осуждаю переводы по нескольким причинам:
• перевод не добавляет ценности.
Статья уже написана.
• в переводе так или иначе теряется стиль автора.
При неумелом переводе ещё и смысл искажается.
• человек, переводивший контент, получает плюсики.
Лайкают же не факт перевода, а контент. А мог бы изначальный автор получить доп просмотры у себя на сайтике.
• в век засилия ллм ещё неизвестно, кто и как там переводил.
Возможно постящий/-ая (я не хочу использовать слово автор) исполнил роль копирующего туда-сюда устройства.
• перевод существует для тех, у кого проблемы с иностранным языком.
Я уверен, что 99.99% переводов делаются с английского. Если вы читаете статью на русском, потому что вам сложен English (fabric, details), подучите язык. Вы же всё-таки программисты. Инженеры. Вам столько документации читать придётся. А вы статью не можете осилить.

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

На всякий случай, скрываться не буду. Моя первая статья на хабре (t.iss.one/thisnotes/91) тоже была переводом. В своё оправдание хочу сказать:
• я изменился
• это не был просто перевод.
Это была расшифровка куска доклада на английском. Причём не вот эта расшифровка, как любят всякие крупные конференции поверх докладов статьи выкладывать. С «мм», «ну вот тут так сделаем», «видите на слайде вот это место?» (нет, не вижу, я читаю текст, а не смотрю видео). А внятная адаптация контента на конкретную тему. Я поверх потом ещё статью сам писал, так что там в каком-то смысле цепочка была так запущена.

Я бывает кликну на статью на хабре. Название интересное. Вижу, что перевод. Через секунду уже читаю оригинал.

Иногда до абсурдного доходит: https://habr.com/ru/articles/841698/

@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
😁17👎13👍1🗿1
#highload

Sharding 101.

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

Задача шардирования: разбить данные на куски, если одна машинка не справляется держать всё (потому что данных слишком много или нагрузка очень большая).

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

Шардировать можно:
• по значениям ключей.
Очень просто: берёте все значения (или их префиксы, например по первому символу в uuid) и для последовательных ренджей выделяете по шарду ([a-c] -> shard 1, [d-g] -> shard 2, ...). Проблема в том, что нужно выбрать такие ренджи, чтобы шарды были примерно одинаковыми. Если паттерн наличия данных/нагрузки приводит к hot шардам, проблема. Шарды всегда можно сплитить на побольше и поменьше. Можно автоматически. По ключам хорошо, если вам важно иметь рядом данные, ключи которых тоже рядом. Но это не всегда так. Можно
• по хешам от ключей.
Посчитали хеш и взяли остаток от деления на кол-во шардов. Правда решардинг (+/-1 шард) приводит к полному решардингу данных. Можно делать много виртуальных шардов для маленького кол-ва реальных хостов (Count(virtual) — большое составное число, произведение большого кол-ва первых простых числе в идеале, так проще).
Лучше разбивать хеши на ренджи. Отсюда растёт consistent hashing: организовываете всё пространство хешей в логическое кольцо, расставляете на нём шарды. Найти ближайший шард для ключа == взять следующий по часовой стрелке. Так вы сокращаете кол-во перераспределений данных при появлении/пропаже шардов. Тут есть разные варианты реализации (rendezvous hashing, jump consistent hashing, etc).

Это всё было stateless sharding. Но иногда вам нужна чуть более сложная логика. И хранить информацию о том, что где хранится, нужно в отдельной БД. Пару примеров, когда это оправдано:
• динамический шардинг.
Вы пишете систему, которая по каким-то вам известным правилам умеет делить/мержить шарды.
• может у вас мессенджер.
Хранить чаты можно частями по блокам (для очень больших чатов это м.б. выгодно). Новые блоки можно начинать писать на новые шарды, когда на старых места уже нет.
• гео-шардинг.
Причём со сложной конфигурацией для большого кол-ва регионов и клиентов в них.

В общем случае всегда, когда у вас есть какая-то метадата.

Про вот этот второй вариант stateful шардирования с какой-то application логикой часто забывают на system design собеседованиях. Потому что про них редко говорят в туториалах и разборах. А зря. Там есть много полезных и красивых вариантов.
Важно только не забыть, что сервис с метаданными, — доп точка отказа.

А может вы вообще можете забить на это всё, ведь паттерны работы с данными простые. Возьмите тогда Amazon DynamoDB, которая умеет шардироваться автоматически (и по объёму, и по нагрузке) и не думайте про это.
Только посчитайте, сколько это будет стоить.

@thisnotes. Patreon, newsletter.
Спасибо Artyom Garkavy и niki4smirn.
❤10👎2🥴2