вторник, 1 января 2030 г.

О блоге

Более двадцати лет я занимался разработкой ПО, в основном как программист и тим-лид, а в 2012-2014гг как руководитель департамента разработки и внедрения ПО в компании Интервэйл (подробнее на LinkedIn). В настоящее время занимаюсь развитием компании по разработке ПО stiffstream, в которой являюсь одним из соучредителей. Поэтому в моем блоге много заметок о работе, в частности о программировании и компьютерах, а так же об управлении.

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

понедельник, 31 декабря 2029 г.

[life.photo] Характерный портрет: вы и ваш мир моими глазами. Безвозмездно :)

Вы художник? Бармен или музыкант? Или, может быть, коллекционер? Плотник или столяр? Кузнец или слесарь? Владеете маленьким магазинчиком или управляете большим производством? Реставрируете старинные часы или просто починяете примус? Всю жизнь занимаетесь своим любимым делом и хотели бы иметь фото на память?

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

пятница, 17 ноября 2017 г.

[prog.c++.thoughts] Какой вклад в сложность C++ вносит борьба с самой сложностью C++?

Давеча один из интересующихся SObjectizer-ом пользователей задал вопрос: а можно ли использовать в SO-5 в качестве обработчиков сообщений const-методы? Вопрос оказался, что называется, внезапным. Мы используем SO-5 в разработке софта уже лет семь (как раз где-то в конце 2010 первые стабильные версии SO-5 пошли в дело, если мне не изменяет склероз). Но ни разу нам не пришлось столкнуться с тем, чтобы обработчик сообщения следовало бы пометить модификатором const. Видимо, это потому, что обработчики сообщений в подавляющем большинстве случаев меняют состояние агента, поэтому не было смысла использовать const-методы в качестве обработчиков. А тут новый человек, другие задачи, другой взгляд на решение этих задач. И const-методы оказались нужны.

Ну, OK. Какие проблемы, будем делать.

Только вот как это сделать так, чтобы трудоемкость и сопровождаемость получившегося решения не зашкалила? Речь идет о том, чтобы преобразовать 6-7 методов вот такого формата:

templateclass RESULT, class ARG, class AGENT >
subscription_bind_t &
event(
   RESULT (AGENT::*pfn)( ARG ),
   thread_safety_t thread_safety = not_thread_safe );

которые живут в SO-5 давно, и используются повсеместно.

Нужно было получить методы, которые бы могли принять как RESULT(AGENT::*pfn)(ARG), так и RESULT(AGENT::*pfn)(ARG) const.

Простейший вариант, который приходит в голову -- это тупое дублирование:

четверг, 16 ноября 2017 г.

[prog.c++] Наткнулся на странное в VC++12

Разбавляя код SObjectizer-а шаблонной магией наткнулся на странную штуку в VC++12 (который из VS2013). Такое ощущение, что когда вложенность лямбд оказывается достаточно большой и очередная лямбда не захватывает контекст (т.е. может быть конвертирована в обычную функцию), то VC++ в качестве типа лямбды начинает использовать не анонимный класс с operator(), а указатель на функцию с соответствующей сигнатурой. Т.е. тупо конвертирует лямбду в функцию и дальше использует тип этой функции в качестве типа лямбды. Проявилось это вот на такой строчке. Там реально лямбда на лямбде и лямбдой погоняет :)

К счастью, в более новых версиях VC++ уже такого нет, там лямбда остается лямбдой. Надо бы закругляться с поддержкой VC++12.0. Видимо, в 2018 мы перестанем поддерживать этот компилятор в SO-5.

Еще захотелось, чтобы в C++ таки концепты завезли. Ибо набирать такое, наверное, прикольно, но уж больно муторно:

templatetypename Method_Pointer >
typename std::enable_if<
      details::is_agent_method_pointer<Method_Pointer>::value,
      subscription_bind_t & >::type
event(
   Method_Pointer pfn,
   thread_safety_t thread_safety = not_thread_safe );

Хотелось бы один раз определить концепт MethodAsHandler, а потом указывать этот концепт в декларации метода:

subscription_bind_t &
event(
   MethodAsPointer pfn,
   thread_safety_t thread_safety = not_thread_safe );

Осталось каких-то три годика подождать... :)

понедельник, 13 ноября 2017 г.

[prog.c++] Полку парсеров аргументов командной строки для современного C++ прибыло

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

Итак, первая библиотека -- Clara от автора отличного инструмента для TDD и BDD в C++, Catch/Catch2 (с недавних пор библиотека называется именно Catch2). Clara изначально развивалась внутри Catch, но при подготовке Catch2 ее выделили в отдельный проект. Получается, что Clara является более-менее проверенной библиотекой, все-таки Catch2 используется весьма активно. Плюс работает на разных платформах и с разными компиляторами. Но, с другой стороны, документация пока оставляет желать много лучшего.

Пример того, как может выглядеть работа с Clara я выдрал из unit-тестов для нее:

using namespace clara;
struct TestOpt {
    std::string processName;
    std::string fileName;
    int number = 0;
    int index = 0;
    bool flag = false;
    std::string firstPos;
    std::string secondPos;
    std::vector<std::string> unpositional;

    auto makeCli() -> Parser {
        return ExeName( processName )
          | Opt( fileName, "filename" )
              ["-o"]["--output"]
              ( "specifies output file" )
          | Opt( number, "an integral value" )
              ["-n"]
          | Opt( [&]( int i ) {
                    if (i < 0 || i > 10)
                        return ParserResult::runtimeError("index must be between 0 and 10");
                    else {
                        index = i;
                        return ParserResult::ok( ParseResultType::Matched );
                    }
                }, "index" )
              ["-i"]
              ( "An index, which is an integer between 0 and 10, inclusive" )
          | Opt( flag )
              ["-f"]
              ( "A flag" )
          | Arg( firstPos, "first arg" )
              ( "First position" )
          | Arg( secondPos, "second arg" )
              ( "Second position" );
    }
};

Здесь метод TestOpt::makeCli как раз и создает парсер аргументов командной строки, который сохраняет разобранные значения внутри экземпляра структуры TestOpt.

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


Второй инструмент -- это clipp. Так же header-only, так же ему достаточно только стандартной библиотеки современного C++. Средства описания аргументов командной строки похожи на таковые в Clara, но, как мне показалось, здесь все более продвинуто:

#include <iostream>

#include "clipp.h"

using namespace clipp;
using std::cout;
using std::string;

int main(int argc, char* argv[]) { 
    bool rec = false, utf16 = false;
    string infile = "", fmt = "csv";

    auto cli = (
        value("input file", infile),
        option("-r""--recursive").set(rec).doc("convert files recursively"),
        option("-o") & value("output format", fmt),
        option("-utf16").set(utf16).doc("use UTF-16 encoding")
    );

    if(!parse(argc, argv, cli)) cout << make_man_page(cli, argv[0]);
    // ...
}

Если с аргументами что-то не так, то можно автоматически сгенерировать вот такой текст:

SYNOPSIS
    convert <input file> [-r] [-o <output format>] [-utf16]

OPTIONS
    -r, --recursive  convert files recursively
    -utf16           use UTF-16 encoding

Библиотека использует перегрузку операторов, что позволяет записывать вот такие-вот DSL-и:

auto cli = ( 
    option("-b")          % "activates b"   >> b,             
    option("-c""--noc") % "deactivates c" >> set(c,false),
    option("--hi")        % "says hi"       >> []{cout << "hi!\n";} );

Вообще, документация оставляет самые приятные впечатления. А вот по поводу кода на Reddit-е высказали замечания. С которыми автор библиотеки согласился и пояснил, что разработка еще не завершена и, например, под MSVC он пока особо ничего не проверял. Так что дока хорошая, а вот либа еще сырая. Хотя желание попробовать вызывает.

суббота, 11 ноября 2017 г.

[life.books] Коротко о четырех книгах, которые я пытался прочитать в последнее время

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

Первая книга -- "Просто гениально" за авторством Уильяма Тейлора.

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

В общем, процент полезного сухого остатка какой-то совсем мизерный. Единственный момент, который отложился в памяти -- это пример компании, в которой настолько серьезно относятся к обучению, что у всех не рядовых сотрудников, включая ТОП-менеджеров, есть обязательства по обучению сотрудников на нижестоящих ступеньках иерархии.

Вторая книга -- "Покер лжецов" Майкла Льюиса.

Просто оказалась не моя тема. В книге рассказывается о том, что происходило на Уолл-стрит с конца 1970-х и начала 1980-х. Рассказывается, в основном, о людях, но с сильной привязкой к финансовым механизмам, которые работали в то время. Но, поскольку в торговле ценными бумагами я вообще ничего не понимаю, то не понимаю и контекста, внутри которого происходят описываемые автором события. Без такого понимания читать просто не интересно. Но вообще книга написана живым, может быть местами грубоватым, языком. Так что если кто-то знаком с рынком облигаций, то ему книга может быть покажется интересной. Я же не дочитал и до половины.

Третья книга -- "«Do not disturb». Записки отельера". Автор Юнис Теймурханлы.

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

Наконец, четвертая книга -- "Ген директора" Владимира Моженкова.

Просто отличная книга. Все четко, по делу, без воды, хождения по кругу и лишних соплей. Тем, кто собирается открывать свое дело или же пытается чем-то управлять, имеет смысл прочесть. Какие-то моменты могут конкретно зацепить. Например, меня зацепил момент, связанный как раз с чтением книг. Автор рассказывал, как он прививал в своей компании привычку к чтению. И как затем начал спрашивать "Ну вот ты прочитал, а что применил? Ничего? Так зачем читал?". Я вроде как чего-то по менеджменту читал. Но не скажу, что применял. Скорее читал для того, чтобы лучше понимать происходящее и расширить свой кругозор. Поэтому такой вопрос "в лоб" меня самого застал врасплох :)

пятница, 10 ноября 2017 г.

[prog.c++] Пересмотр приоритетов для SO-5.5.20

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

Первоначально планировалось начать с того, чтобы дать возможность пользователю параметризовать диспетчеры собственным типом thread. Т.е. если кому-то не хочется использовать std::thread, а хочется подсунуть что-то свое, на базе, скажем pthreads (с надобностью задавать специфические параметры для новых нитей), тот мог бы указать свой тип вместо std::thread.

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

Если же кому-то возможность использовать собственные нити вместо std::thread нужна уже сейчас или в обозримом будущем, то дайте нам знать. Если это реально кому-то нужно, то приоритет мы поднимем и такую функциональность реализуем. Но хочу, чтобы было понятно: в SO-5 сейчас и так уже достаточно фич. Просто так добавлять туда очередную фичу просто "шоб было" a) не интересно и b) не выгодно. Все-таки мы делаем SO-5 за свои и тратить свои ресурсы на то, что останется лежать мертвым грузом -- это сомнительная идея.

Так что если вам что-то нужно в SO-5, то найдите способ сказать нам об этом (например, в комментариях к этой заметке, а еще лучше по email: info at stiffstream dot com или eao197 at stiffstream dot com, или на мой gmail-овый ящик). То, что нужно реальным или потенциальным пользователям, мы будем добавлять в SO-5.

Пока же в работах над версией 5.5.20 мы попробуем сосредоточиться на том, что может [не]существенно изменить подходы к использованию SO-5 и агентов. В частности это может быть:

  • более простая и тесная интеграция mchain-ов и агентов. Суть в том, чтобы сообщение, которое кто-то отсылает в mchain, могло поступать напрямую конкретному агенту. Тем самым mchain работал бы как естественный механизм overload control. Подробнее это описано здесь;
    • эта фича сейчас под вопросом до тех пор, пока не появятся какие-то дополнительные типы mchain-ов (например, в рамках so_5_extra). Когда будут разные типы mchain-ов, с разной логикой поведения, тогда будет лучше понятно, можно ли сделать универсальную интеграцию агента с разнотипными mchain-ами.
  • возможность каскадировать mbox-ы. Это выглядит актуальным в связи с появлением новых типов mbox-ов в so_5_extra. Например, может быть MPMC-mbox, одним из подписчиков которого будет collecting_mbox, а подписчиком collecting_mbox-а может быть round-robin mbox, подписчиком которого могут быть mchain-ы. Сейчас подписчиком mbox-а можно сделать только агента и это не позволяет выстраивать подобные цепочки без использования промежуточных агентов. Может быть такая возможность каскадирования mbox-ов поможет, например, в реализации реактивного программирования поверх SO-5;
    • разбирательство с текущим механизмом доставки сообщений показало, что эту функциональность сложно сделать без слома API. Делать такой слом в ветке 5.5 неразумно (следует сохранять совместимость в рамках релизов 5.5.*). А выделять версию 5.6 только ради одной фичи -- это преждевременно;
  • какое-то приближение к идее сессионных типов. Это когда сценарий взаимодействия между агентами описывается на уровне типов: сперва в одну сторону может пойти сообщение request, а обратно может прийти либо response, либо timeout, а затем может пойти только finish, но не request. Либо же это может быть какое-то приближение к типизированным mbox-ам и/или агентам. Опять же, прямо на уровне типов описывается, какие воздействия воспринимаются mbox-ом/агентом. Данная тема поднималась ранее;
  • какие-то инструменты для упрощения тестирования агентов. Этот вопрос задавали на последней C++ CoreHard. И он действительно актуален, т.к. тестирование агентов, которые общаются с внешним миром через асинхронные сообщения -- это не просто. Но в данной теме еще и конь не валялся.

В общем, пока вот такие приоритеты. Опять же повторюсь, если будут какие-то конкретные предложения (вроде идеи с мутабельными сообщениями или возможности проверить существование подписки), то мы их внимательно рассмотрим. И, с большой вероятностью, реализуем. Так что есть более чем реальная возможность повлиять на развитие SO-5.