image
Прошло больше полугода с момента выхода фреймворка для C++ ???? userver в open-source. За это время мы многое узнали, на многом настрадались, а главное — получили много приятных сюрпризов.

И мы решили об этом написать. Рассказ будет полезен тем, кто ведёт или планирует вести свой open-source проект или занимается контрибьютами. Остальным будет интересно почитать про чужое набивание шишек и что вообще open-source даёт проекту.

Неожиданная помощь


Чтобы анонс о выходе фреймворка в open-source прошёл более гладко, мы выложили исходники чуть заранее и плотно занялись обустройством на GitHub: настройкой CI, оформлением, тестированием и выкладкой документации. В итоге ко времени анонса у нас уже был готовый к использованию шаблон сервиса на основе фреймворка userver со всеми настроенными CI и сборками.

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

Beta — это хорошо


image
Потребности компании зачастую совершенно не совпадают с пожеланиями пользователей из open-source. То, что успешно используется годами в продакшене внутри компании, может не подойти новому пользователю из-за фактора, которого просто нет в корпоративной среде.

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

Чтобы подчеркнуть, что мы знаем, что есть над чем работать, мы выложили фреймворк в статусе беты. Решение себя оправдало: многие сообщения от пользователей попадали под регулярку «А как вы вообще выкладываетесь без технологии \s+. А, хотя это бета, тогда ОК!»

Анонс


Итак, анонс.

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

Разумеется, не обошлось и без курьёзов. Например, мы отдали в отдел PR материал с общим посылом: «Сегодня мы анонсируем выход в open-source фреймворка userver для создания высоконагруженных IO-bound приложений на C++». Материал после некоторых трансформаций отправился в публикацию как «Анонсируем выход первого в мире набора инструментов, который позволяет создавать высоконагруженные приложения». К счастью, удалось вовремя остановить процесс.


У нас есть доска с от руки нарисованными ачивками за сомнительные достижения — эта появилась как раз после этой истории

C++ сборка — это очень, очень мучительно


Первое, с чем стали приходить люди после анонса выхода в open-source — проблемы со сборкой.

Мы с C++ не сталкивались, что там за проблемы такие?
C++ богат различными компиляторами, версиями стандартных библиотек и стандартов C++, платформами, системами сборок и способами установки пакетов.

Если вы хотите быть дружелюбны к хотя бы половине ваших пользователей, то придётся поддержать:

  • хотя бы топ-3 популярных ОС Linux + docker + MacOS;
  • 3 последних стандарта C++;
  • 2 компилятора;
  • 2 стандартные библиотеки;
  • 3 архитектуры железа;
  • установку через скачивание пакетов;
  • использование системных пакетов ОС;
  • использование пакетного менеджера conan;
  • дебажную и релизную сборку.


Это как раз одна из тех проблем, которые внутри крупной компании практически не возникают: кто-то давным давно уже всё настроил и все вещи разрабатываются фактически под пару платформ. Ну, или есть отдельная команда людей, которая занимается проблемами сборки.

И тут мы простого решения для open-source не придумали, поэтому пошли по сложному пути: поддержать по мере сил и возможностей все конфигурации, которые интересны нашим активным пользователям. Отдельное спасибо тем, кто принёс готовые правки под свои любимые платформы!

Roadmap и Changelog


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

Показать, что мы настроены серьёзно, помогло следующее:

  • Настройка автоматической синхронизации коммитов из внутреннего репозитория на GitHub. В результате, зайдя репозиторий, можно увидеть, что последний коммит сделан ~2 часа назад. Это знак того, что проект активно развивается.
  • Changelog. Смысл тот же, что и у прошлого пункта — показать темпы развития проекта.
  • Roadmap. Помогает людям понять, что у проекта есть план развития, мы движемся в сторону релиза и он близок.
  • Каналы поддержки в Telegram. Они позволяют нам прислушиваться к желаниям новых пользователей и оперативно дорабатывать фреймворк под их нужды.


Бенчмарки — это полезно


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

  • Задачу для бенчмарка не получилось реализовать лаконично? Значит, что-то в интерфейсах фреймворка можно улучшить и обобщить, сделать приятнее в использовании.
  • Проиграли в производительности? А что за решение у лидера? А, хм, занятно, попробуем сделать нечто похожее, но вот тут ещё подускорим...
  • Всё хорошо, но сложно подобрать оптимальную конфигурацию? А ведь и не в бенчмарках люди с этим сталкиваются! Давайте делать автотюнинг параметров, чтобы конфигурировать намного меньше вещей.

Бенчмарки — это бесполезно


О, раз бенчмарки такие полезные, может фреймворк прям по ним и выбирать? Вот, например, нам в компании понадобился фреймворк на Go/Kotlin/NodeJS/… Давайте возьмём топовый из бенчмарков!

Идея интересная, но на практике не работает:

  • Во многих фреймворках из топа есть уязвимости, и авторы не особо торопятся их исправлять, потому что починка ударит по производительности и результатам в бенчмарке.
  • Все без исключения фреймворки в бенчмарках работают иначе, чем в проде. Например, во всех фреймворках отключается логирование, а оно весьма прожорливо на проде и крайне сильно влияет на времена ответов, latency и jitter.
  • Многие фреймворки обладают минимальной функциональностью, только тем что необходимо для бенчмарка. Хотите поработать с другой базой данных, записать метрики или воспользоваться многопоточностью — не получится.

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



Документация


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

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

При этом все люди разные, и материалы желательно преподносить и в разных формах, например, как видео-лекции и как текст.

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

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

Взаимовыгодное обучение


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

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

Мы подключились к части инициатив с предложением: «А давайте выпускным проектом будет написание реального кода для userver». В итоге, если хорошо поработал, точно будет чем похвастаться и что показать.

Правда, тут возникли заминки: нас завалило кодом, и мы до сих пор занимаемся его подмерживанием в userver.

Кстати, оказалось весьма полезным разметить feature requests на GitHub как «Хорошая задача для начинающих» и отдельно разметить «Большая фича для продвинутых». Мы сразу получаем набор задач внешних активностей на 2—4 дня и набор проектов для больших многомесячных курсов, например, как «Код для всех».

Так зачем же open-source?


Вопрос: «А зачем вы выложили в open-source?» не даёт покоя многим людям в чатиках и на форумах. Ну что ж, давайте честно на всё ответим и разберём все мифы.

Миф 1: чтобы люди разрабатывали фреймворк за нас


Увы, это так не работает. Подавляющее большинство коммитов у нас идёт от внутренних разработчиков. Я, конечно, втайне надеюсь, что это изменится. Но, как показывает опыт с Boost C++ Libraries, даже очень популярные открытые проекты очень долго выходят на подобную модель развития и очень мало у кого получается.

При этом PR от стороннего пользователя — это маленький праздник! Ведь значит ещё кому-то проект стал интересен и полезен.

Миф 2: чтобы люди тестировали фреймворк за нас


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

Если вдруг у вас небольшой проект с достаточно узкой функциональностью (например, небольшая библиотека), то open-source вам явно поможет лучше тестироваться. Для больших фреймворков всё несколько сложнее.

Для чего же userver выложили в open-source на самом деле


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

Для больших компаний open-source — это ещё и развитие технологического бренда компании. Так можно показать людям интересные и полезные решения, которые мы пишем в рабочее время. Ну и при найме это полезно: если вы вдруг выбираете между разными отделами Яндекса, у вас есть возможность заранее увидеть технологии, с которыми вы будете работать, и выбрать себе код по вкусу.

А ещё open-source даёт возможность использовать привычный набор инструментов в партнёрских проектах: например, теперь есть шанс воспользоваться userver при коллаборации с CERN, или при автоматизации сталелитейных заводов.

Ближайшие планы


Мы готовимся к первому релизу фреймворка в этом году. А пока релиз ещё в работе, мы с радостью готовы рассказать о фреймворке (и не только) на конференциях Saint HighLoad++ и HighLoad++ Serbia.

А если вам самим есть о чём рассказать, приходите к нам на C++ Zero Cost Conf с идеей доклада. У нас тепло, весело и международно! В этом году конференция пройдёт в двух странах — в России и в Сербии. Ждём ваши заявки!

P.S.


Спасибо всем, кто контрибьютил и багрепортил в userver. Вы лучшие!

Комментарии (26)


  1. rotor
    24.05.2023 16:38
    +10

    Спасибо, что продолжаете делиться своими наработками.
    Вы абсолютно правы, смысл опенсорса не в том, что вам будут присылать багрепорты или писать код за вас. Хотя и в этом тоже. Эти поводы легко объяснить далёким от IT менеджерам, но они не главные.
    Смысл опенсрса -- счастье команды.
    И это вполне разумный аргумент.
    Высшее счастье инженера -- видеть как результатами его труда пользуются и они приносит пользу другим людям, а высшее несчастье -- работа в стол.
    И если у вас команда профессионалов, то выкладка кода в открытый доступ безусловно принесёт удовлетворение, мотивирует работать лучше.
    Кроме того, чего греха таить, когда мы знаем что наш код попадёт в опенсорс, мы прикладываем больше усилий, что бы код был максимально качественным.
    А вот утаивание кода приносит меньше профитов, чем принято думать.
    Ну и конечно, опенсорс повышает престиж компании. Ведь мы судим о компании в том числе по её коду.
    Рад, что ответственные люди в Яндексе на стороне прогресса. И надеюсь, что эта практика понемногу станет нормой повсеместной.


    1. DmitryKoterov
      24.05.2023 16:38

      +100

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


      1. slonopotamus
        24.05.2023 16:38
        +2

        Ну зачем так категорично. Человеки вполне имеют право в течение жизни шагать вверх по пирамидке товарища Маслоу.


    1. k-morozov
      24.05.2023 16:38
      +1

      Откуда такая щенячья наивность, что корпорации думают про счастье какого-то винтика, а не про деньги, которые можно делать из выкладки в open source, прямо или косвенно?


      1. Clock_Source
        24.05.2023 16:38
        +7

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


  1. sashagil
    24.05.2023 16:38
    +1

    Антон, спасибо - вопрос: используется ли в этом проекте идиома / утилита fast pimpl (вы рассказывали о ней в презентации "C++ трюки из Такси" 2.5 лет назад)? Я заглянул в пару-тройку хедеров и не наткнулся на использование (пока). Предполагаю, что не используется - т.е. C++ утилита / приём весьма общего назначения, полезная в одном крупном C++ проекте, с которым вы работали, в другом крупном C++ проекте (в той же фирме) оказалась не так уж полезна?


    1. antoshkka Автор
      24.05.2023 16:38

      Да, мы много где её используем

      Весьма полезная штука)


      1. sashagil
        24.05.2023 16:38
        +1

        Отлично, спасибо! Я себе сделал попроще, по мотивам той презентации, буду иметь в виду, если понадобится улучшить.


  1. Videoman
    24.05.2023 16:38
    +1

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


    1. MiraclePtr
      24.05.2023 16:38
      +4

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


  1. Tuxman
    24.05.2023 16:38
    +3

    Гадаю по фотографии, делаю кодревью, дорого. Один файл, и только сегодня, бесплатно. Рандом сказал read.cpp.

    • Макросы - зло, USERVER_NAMESPACE_BEGIN, UASSERT. У Вас современный C++, есть и static_assert, и if costexpr.

    • boost::filesystem::path - уже в C++17 появился , пожалуйста не тащите буст, когда можно без него.

    • Первая функция принимает const boost::filesystem::path& path, вторая std::string_view path - пожалуйста, определитесь, то у Вас path, а иначе c++ implicit conversion это зло.

    • Nit: не будем тратить Ваше время~


    1. antoshkka Автор
      24.05.2023 16:38
      +1

      1) Согласен что зло. Однако единственный способ отобразить произвольное выражение в виде массива символов - макросы вида `#define STRINGIZE(X) #X`

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

      2) Мы и не используем Boost когда можно без него. В данном случае он необходим, так как на многих платформах где собирается userver авторы стандартных библиотек C++ помечают реализацию std::filesystem как experimental и неготовую к промышленному использованию

      3) И правда некрасивенько. Можно будет поправить как-нибудь

      4) Вы пропустили большую проблему в данном коде, сосредоточившись в ревью не на логике/архитектуре. Первый кто найдёт проблему до того как мы закомитим фикс, получит от нас маленький презент


      1. mobi
        24.05.2023 16:38
        +1

        Симлинки специально пропускаете?


        1. antoshkka Автор
          24.05.2023 16:38

          Специально, в этом месте ОК


          1. mobi
            24.05.2023 16:38

            И то, что GetRelative не проверяет, что path действительно начинается c dir, тоже ок? (хотя, скорее всего за пределами он не используется)


            1. antoshkka Автор
              24.05.2023 16:38

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


              1. mobi
                24.05.2023 16:38
                +1

                И runtime_error при ошибке чтения (например, нет прав) тоже можно не обратывать?
                Да boost в некоторых случаях может filesystem_error выбросить.


                1. antoshkka Автор
                  24.05.2023 16:38

                  Такие ошибки обрабатываютя вызывающим кодом, исключения тут как раз кстати


                  1. mobi
                    24.05.2023 16:38

                    -


      1. Readme
        24.05.2023 16:38
        +1

        GetRelative(f.path().string(), path)

        — не оторвётся ли случайно (или скорее наоборот останется) какой-нибудь слэш / в relative-пути, если передать path без завершающего слэша? Зависит, конечно, от того, как именно path доходит до сюда.


        UPD: ну и в принципе смешивание std::string и fs::path для навигации звучит довольно взрывоопасно, вроде API fs должно хватать для всех GetRelative и т.д., но он ещё и нормализует пути.


        1. antoshkka Автор
          24.05.2023 16:38

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

          Но большая проблема остаётся не разгаданной, есть шанс получить ещё приз


          1. Kelbon
            24.05.2023 16:38
            +2

                FileInfoWithData info{};
                info.size = boost::filesystem::file_size(f.path());
               ...
                info.data = ReadFileContents(async_tp, f.path().string());

            А это не гонка? Сначала узнавать размер, а потом читать данные и размер может быть уже другой


            1. antoshkka Автор
              24.05.2023 16:38
              +1

              Ага, гонка. Вам полагается подарок! Напишите в личку адрес доставки


              1. Kelbon
                24.05.2023 16:38
                +2

                Сербия, Хаб яндекса...


      1. Tuxman
        24.05.2023 16:38

        Там как-то странно, IsHiddenFile() реагирует не только на ".", но и на "..", вроде как это надо было в другом месте отфильтровать бы.


    1. Playa
      24.05.2023 16:38
      +1

      Макросы — зло, USERVER_NAMESPACE_BEGIN, UASSERT. У Вас современный C++, есть и static_assert, и if costexpr.

      И как по-вашему современный C++ избавит нас от этих макросов?