Некоторое время назад на Хабре в комментариях к статье Сказка про собес наоборот пытался донести мысль о том, что есть люди, которые не умеют "думать вслух". Т.е. если им на собеседовании задать какую-то задачку с целью "посмотреть как человек рассуждает", то они будут выглядеть как впавшие в ступор и производить, мягко говоря, странные впечатления.
Дабы не повторяться, процитирую себя самого:
Есть люди (вроде меня), которые получив какую-то задачу на первое время впадают в состояние абсолютного тумана в голове. Нет никаких внятных мыслей, в голове роятся разрозненные отрывки из обрывков. Вроде "так, если здесь вот это, то..." и потом обрывается, а вместо этого приходит "а вот если здесь вот так, то..." и потом опять обрывается, чтобы смениться следующим обрывком совсем другой мысли. И так длится какое-то время (в зависимости от задачи от десятка минут до нескольких дней, а то и недель). Чтобы потом внезапно (действительно внезапно, это не фигура речи) туман вдруг отступил и проявились очертания вполне себе четкого решения и вот уже дальше все идет "как по писаному".
Так вот проблема в том, что если в момент "тумана в голове" у меня кто-то будет выпытывать логические построения, то выглядеть я буду, мягко говоря, идиотом. Пык-мык и "не знаю", "не думаю", "не представляю" + рисование ничего не значащих каракулей на бумаге.
К сожалению, мой собеседник меня не понял (так уж показалось) и в итоге выдал вот такой пассаж:
Я давно живу и много чего видел. В том числе, умных и талантливых людей (реально умных и реально талантливых), но совершенно не способных к коммерческой разработке. В академической среде они показывали себя с наилучшей стороны. Но когда нужно сделать задачу в заданном объеме и в заданный срок - все... "Озарение не снизошло" вовремя и сроки все сорваны. Остальным приходится все бросать и разгребать.
А вчера я столкнулся с ситуацией, которая отлично иллюстрирует момент с "рисованием ничего не значащих каракулей на бумаге". Что и подтолкнуло к написанию этого поста.
Волею судьбы выдалась возможность поработать над RESTinio (ага, три года проект был на паузе, но сейчас есть ресурсы чтобы его обновить). К сожалению, ничего принципиально важного и нового в релиз 0.7 добавить не получится. Но вот одна конкретная фича остается для меня незакрытым гештальтом и хочется что-то сделать в этом направлении.
Суть в том, что в свое время в RESTinio был добавлен механизм объединения обработчиков запросов в цепочки. Это что-то a la middleware из Express.JS (но именно что a la, т.е. по мотивам, но не один-в-один).
Проблема с текущей реализацией цепочек в том, что это должны быть только синхронные обработчики. Т.е., RESTinio принимает очередной входящий HTTP-запрос, отдает его первому обработчику в цепочке, затем второму, затем третьему и т.д. Т.е. очередной обработчик должен выполнить все свои действия вот прямо здесь и сейчас, и пока он не завершится RESTinio не сможет принимать другие HTTP-запросы на этой рабочей нити.
Что неудобно, например, если какому-то обработчику нужно выполнить длительную асинхронную операцию. Скажем, сходить в БД или обратиться к стороннему компоненту дабы аутентифицировать пользователя.
Поэтому сразу встал вопрос "цепочки синхронных обработчиков -- это лучше, чем ничего, но можно ли сделать их асинхронными?"
Три года назад ресурсов на решение этого вопроса не хватило.
А вот сейчас возможность представилась. Поэтому пытаюсь подступиться к этой задаче вновь.
Но вот проблема: я не знаю как ее решить. На данный момент от слова совсем. Получается что есть и "заданный объем", и "заданный срок", а вот как сделать решительно непонятно.
Да, тот самый туман в голове с обрывками из отрывков разрозненных мыслей. Ну и каракули на бумаге, куда же без этого.
Есть ли у меня уверенность в том, что задача будет решена за неделю (а больше времени может и не быть)?
Нет, конечно.
Хочу ли я сделать первое, что придет в голову просто ради того, чтобы поставить галочку в списке фич RESTinio?
Нет. Лучше уж у нас фич будет меньше, но те, что есть, пусть будут сделаны хорошо. Это гораздо дешевле в средне- и долгосрочной перспективе.
И что же получается?
А получается то самое: нужно ждать озарения, которое, если придет, то даст новую важную фичу нашему программному продукту. А если не придет... Ну и не придет 🙁 Не будет этой фичи, продукт будет беднее и, в чем-то, ущербнее. Причем, я-то как раз знаю, сколько эта затея будет нам стоить (ага, тупо в деньгах). И, соответственно, буду знать сколько придется списать в убыток (собственных денег), если ничего не получится.
И, что характерно, другого выбора нет. Либо решение будет найдено (то самое "озарение") и, возможно, это принесет нам какие-то дивиденды. Либо не будет (что более чем вероятно) и тогда придется смирится с потерей ресурсов, которые могли бы быть потрачены на что-то другое. Или-или, других вариантов просто нет.
Но, если результат вовсе не гарантирован, то что же толкает на поиск решения?
Во-первых, "есть такое слово: надо!" 😂 Поскольку продукт жив, то он должен пополняться новыми фичами. Пусть даже какие-то из них (пока) непонятно как сделать.
Во-вторых, некий багаж изобретательства в прошлом есть. Это вселяет надежду на то, что и в этот раз из рисования каракулей что-то, да появится.
Дабы не быть голословным по поводу изобретательства. Перечитываю сейчас куски документации по RESTinio, дабы восстановить в памяти что и как у нас уже сделано. Дошел до раздела про экспериментальный easy_parser router (на русском языке про него есть статья на Хабре). И вот перечитываю, а у самого остатки волос шевелятся от увиденного: сложно поверить, что все это мы сами придумали и сделали 😎
Особенно, почему-то доставил вот этот фрагмент из раздела про easy_parser:
// A parser for grammar:
//
// communicator = "port=" ("default" | port_params)
// port_params = '(' NUMBER ':' NUMBER ',' NUMBER ')'
//
struct port_params {
unsigned short port_index_;
unsigned int in_speed_;
unsigned int out_speed_;
};
auto parser = epr::produce<port_params>(
epr::exact("port="),
epr::alternatives(
epr::exact("default")
>> epr::just(port_params{10u, 4096u, 4096u})
>> epr::as_result(),
epr::produce<port_params>(
epr::symbol('('),
epr::non_negative_decimal_number_p<unsigned short>()
>> &port_params::port_index_,
epr::symbol(':'),
epr::non_negative_decimal_number_p<unsigned int>()
>> &port_params::in_speed_,
epr::non_negative_decimal_number_p<unsigned int>()
>> &port_params::out_speed_,
epr::symbol(')')
) >> epr::as_result()
)
);
Вот не знаю почему. Вроде бы там есть и более сложные, и более выразительные фрагменты. Но доставил почему-то этот.
Кстати говоря, это стандартный C++14. Я знаю, что многим C++ категорически не нравится и многие убеждены, что C++ принципиально не подходит под написание eDSL. Но мне нравится то, что получилось.
Не буду скромным и в очередной раз прорекламирую самого себя: (пере)изобретаю велосипеды для себя, могу делать тоже самое для вас.