четверг, 23 января 2020 г.

[prog.c++] Стали доступны SObjectizer-5.7.0 и so5extra-1.4.0

Главное нововведение в SObjectizer-5.7.0 -- это поддержка send_case в функции select(). Т.е. теперь select() может не только читать сообщения из нескольких каналов, но и отправлять сообщения в каналы как только целевой канал оказывается готов для приема нового сообщения. Увидеть это можно в новом примере mchain_fibonacci, сделанного по мотивам аналогичного кода из A Tour of Go.

Фичу эту хотелось добавить в SObjectizer уже давно. Но вот только сейчас сошлись звезды. И по этому поводу я даже решился пойти на то, чтобы поломать совместимость с не так давно выпущенной версией 5.6. Поломка, правда, не такая уж и серьезная, старая функция case_, которая ранее использовалась для чтения входящих сообщений из канала в select(), теперь называется receive_case. Так что перейти с SO-5.6 на SO-5.7 можно посредсвом банального Search-and-Replace. Но формально совместимость сломали, да.

А в so5extra-1.4.0 самое важное -- это смена лицензии. Если предыдущие версии распространялись под двойной лицензией и для использования в закрытом коммерческом ПО нужно было покупать лицензию, то теперь so5extra распространяется под BSD-3-CLAUSE лицензией и может использоваться бесплатно.

Полный список изменений для SO-5.7.0 можно увидеть здесь, для so5extra-1.4.0 -- здесь.

Думаю, что нужно специально подчеркнуть то, что разработка SO-5 и so5extra окончательно перехала на GitHub. Вскоре на BitBucket поудаляют Mercurial-репозитории, так что жить приходится с git-ом на GitHub-е. Я, хоть и плююсь постоянно от git-а и отдыхаю душой и телом, когда представляется случай воспользоваться Hg, но вынужден смирится :(

Отдельно пару слов о будущем SObjectizer-а.

Проект живет. Если кто-то столкнется с какими-то проблемами, то дайте нам знать, обязательно постараемся помочь. Если кому-то нужна помощь с SObjectizer-ом, то смело обращайтесь. Собственно, это наша работа, так что без поддержки не оставим. В том числе расскажем нужен ли вам SObjectizer или нет. Поскольку мы клиентов не накалываем, то можно быть уверенным в том, что продавать слона мы вам не будем. Если SObjectizer вам не подойдет или вообще C++ не нужен в вашей задаче, то так и скажем. Благо такое уже случалось.

А вот вопрос о том, когда будут выходить новые версии SObjectizer-а является открытым. Большие фичи, которые хотелось сделать в SO-5 лично мне, уже сделаны. Поэтому больших релизов на горизонте не предвидится. Мелкие корректирующие релизы будут выходить по мере надобности.

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

В завершении скажу немного про свои ощущения от применимости SObjectizer-а.

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

Так что не на правах рекламы, а просто в порядке "поделится опытом": если у вас есть необходимость работать с многопоточностью в C++, то возьмите что-нибудь типа SObjectizer-а. Не обязательно SObjectizer. QP/C++, CAF, Boost.fibers, да что угодно, что может дать вам акторов и/или CSP-шные каналы... Но лучше, конечно же, SObjectizer ;)

среда, 22 января 2020 г.

[prog.c++] Шаблоны, но уже не против копипасты.

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

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

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

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

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

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

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

struct testing_traits_t {
   using client_type = testing_client_info_t;

   static first_property_type get_first_property(const client_type * cln) {...}
   static second_property_type get_second_property(const client_type * cln) {...}
   ...
};

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

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

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

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

PS. Желающим поговорить про то, почему все это неправильно и что правильнее было бы разделить приложение на отдельные модули со строго определенными интерфейсами, что позволило бы использовать mocking при тестировании и пр. правильные вещи, могу сказать одно: добро пожаловать в реальный мир.

PPS. Если вы сами владеете старым C++ным или C-шным проектом и испытываете сложности с его поддержкой/развитием, то вам сюда. Возможно, мы сможем помочь ;)

понедельник, 20 января 2020 г.

[prog.rust.flame] "Говорил я вам. Не прислушались. Так и получилось. Как говорил я вам..."

На выходных, лениво пожевывая попкорн почитывал срачик на Habr-е, в котором светлые рыцари ордена safe Rust-а громко доказывали, что писать код так, как сделал автор Actix-Web, ни в коем случае нельзя. Занимательное чтиво, аж душа пела.

Пела потому, что когда лет 5-6 назад первые упоротые в своей воинственности Rust-оманы начали бегать по профильным форумам и убеждать всех тех, кому Rust вообще не был интересен, что Rust -- это самое лучше, что произошло с софтостроением после изобретения перфокарт, некоторые скептически настроенные старпёры сердито ворчали: "Ну подождите пару-тройку лет, в этот ваш Rust обязательно придут люди, которые начнут использовать unsafe, скажем так, весьма творчески. Вот тогда и посмотрим, насколько Rust окажется safe в реальной-то жизни".

Ну вот и дождались.

Вполне ожидаемо оказалось, что это во влажных мечтах оторванных от реальности фанатов в боевом коде на Rust-е unsafe либо не будет вообще, либо он будет локализован, тщательно оттестирован и аналь огорожен.

Просто одно дело, когда ты в свободное время пишешь pet project на своем любимом языке для души. Совсем другое -- когда у тебя есть жесткие цели, сроки, бюджеты, конкретные люди со своими проблемами и куча других факторов, которые и отличают настоящую разработку от экспериментов с перспективной технологией. Вот автор Actix-Web-а столкнулся с задачей выжать из своего Web-сервера максимум производительсти и был вынужден прибегнуть к unsafe. И это еще был весьма квалифицированный и мотивированный разработчик. Что уж говорить об писателях индусокода (всех национальностей), которые неизбежно будут пихать unsafe в код, потому что дедлайн, а времени ублажать компилятор нету.

PS. А для всех свято верующих в то, что в реальной жизни unsafe в Rust будут использовать исключительно правильно, а прецидент Actix-Web-а -- это досадное исключение, ВИА "Громыка" исполняет свой незабвенный шлягер, строчка из которого была вынесена в заголовок заметки.