суббота, 12 октября 2019 г.

[work;life] СтифСтриму три года. Наполовину реклама, наполовину рефлексия на эту тему

Намедни нашей небольшой компании исполнилось три года. Поэтому поводу тост^W пост.

Было очень непросто. Временами возникали сомнения в том, а выживем ли вообще. Непросто и сейчас. В обозримом будущем просто тоже не будет. Но не зря мы себя назвали "Упрямый поток", упертости в желании двигаться вперед нам не занимать. Так что мы все еще здесь.

Кому и что мы можем предложить

Постепенно мы сосредоточились на двух вещах:

  • во-первых, наши собственные открытые продукты и связанные с ними сервисные услуги. Так что если кому-то нужна поддержка или консультация по SObjectizer и/или RESTinio, или доработка наших продуктов под ваши специфические нужды, то смело обращайтесь. Без помощи не оставим;
  • во-вторых, работа с небольшими клиентами/заказчиками, которые остались один на один с каким-то (не очень) старым софтом, без которого не обойтись, но который некому фиксить/сопровождать/развивать. На рынке не так уже много спецов по C++, маленькие компании не всегда могут себе позволить держать такого в штате или обратиться к крупному аутсорсеру. В таких случаях обращаются к нам и мы разбираемся в чужом говнокоде, заставляем это "наследие" работать. Высказываем свои соображения, в том числе и по целесообразности продолжения "жрать кактус".

Мы хоть и специализируемся на C++ и, по мере надобности, приводим в рабочее состояние копролиты на чистом С, но не имеем цели всеми средствами удержать клиента в рамках C/C++. Если проблему клиента выгоднее решить на Go, C# или Java, мы именно это и порекомендуем сделать. Лучше пусть клиент возьмет других исполнителей, нежели со временем обнаружит что мы его, мягко говоря, накололи.

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

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

Работаем более-менее качественно. Дефекты время от времени проявляются, куда же без этого. Заказчиков без помощи не оставляем, всегда стараемся исправить найденные косяки как можно быстрее.

Любой желающий может заглянуть в потроха наших разработок (SObjectizer и so5extra, RESTinio, json_dto). Если вас такое качество устраивает, то обращайтесь, пообщаемся.

Рекордов по срокам не ставим и жопу на британский флаг не рвем. Тут уж извините, быстро только кошки родятся, а наспех написать надежно работающий код на C++ (и тем более на C) нельзя. Если вы знаете кого-то, кто умеет, то вам повезло, держитесь за этого исполнителя обеими руками. Однако, что такое "нужно было вчера" понимаем. Например, если сбоит то, что должно работать в режиме 24x7, то стараемся войти в положение.

Наш стандартный рейт для краткосрочных заказов 35USD в час. Основная часть клиентов у нас пока из exUSSR и мы понимаем, что этот ценник для многих слишком высокий, но дешевле не можем, извините. Более низкую стоимость мы выставляем для долгосрочных работ или если дело касается открытых доработок наших OpenSource решений.

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

Стоило ли оно того и некоторые выводы/соображения?

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

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

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

Можно выделить несколько вещей о которых я, в принципе, знал, но объем и значимость которых не осознавал в полной мере:

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

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

Ваши проблемы будут с вами 24x7x365. Если не понятно почему, то см. выше про "Никто кроме вас".

Скорее всего вы никто и звать вас никак. Особенно актуально для тех, кто добился более-менее высоких должностей в крупных компаниях с уже сложившейся репутацией. Грубо говоря, когда вы предлагаете покупателю продукт/сервис от HP или IBM, то это одно, но когда вы не имеете за спиной поддержки громкого бренда и продвигаете новый продукт от никому не известной компании "Рога и Копыта", то вы никто и звать вас никак. Очень хорошо, если для старта вы можете воспользоваться старыми связями и покупку вашего продукта/сервиса могут пролобировать те, кто вас уже знает и/или имеет какой-то свой интерес в этом. Но за пределами этого не очень широкого круга старых связей вы никто и звать вас никак. Имя и репутацию нужно строить с нуля.

Воронка продаж. Она существует.

Время -- деньги или "time to market really matters". Ваше отношение ко времени и деньгам изменится. Одним из основных вопросов станет "когда продукт станет доступен на рынке?", а каждый день просрочки вы в прямом смысле начнете ощущать собственным кошельком. Соответственно, качество вашего продукта станет всего лишь одним из свойств продукта. Именно поэтому выше я и говорил, что мы работаем "более-менее качественно": качество стоит очень дорого, мало кто готов за это платить, т.к. платить приходится не только и не столько деньгами, сколько временем, которое не купить и которым никто не располагает в достаточной мере. Ну кроме наемных работников, само собой ;)

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

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

Ничто не вернет времени, которое вы потратили на бизнес, а не на семью. Ничто.

Ну с большего как-то все. Надеюсь, что никого сильно не напугал ;)

Благодарности

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

Приносим извинения тем, с кем не смогли поработать в силу своей загруженности и каких-то других обстоятельств. Разорваться не можем, увы. Да и shit happens, ничего не поделать.

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

Найти нас можно здесь: stiffstream.com.

среда, 9 октября 2019 г.

[prog.c++] Первые результаты второго подхода к удобному парсеру HTTP-полей в RESTinio

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

Поэтому когда представилось время вернуться к доработке RESTinio, то была предпринята следующая попытка. И вот сегодня были получены первые результаты. Кому интересно милости прошу под кат:

[prog.c++] Что-то я неслабо затупил из-за отсутствия fold expression в C++14

Столкнулся со следующей задачей: есть экземпляр std::tuple, который содержит объекты-парсеры. Нужно пробежаться от первого элемента тупла к последнему и для каждого парсера вызвать метод try_parse с определенными параметрами. Но! Нужно прервать эту итерацию как только очередной try_parse вернет false.

В C++17 это элементарно записывается посредством fold expression:

templatetypename Tuple, std::size_t... Indexes >
bool try_parse_impl(
   const std::string & source,
   Tuple & t, 
   std::index_sequence<Indexes...>)
{
   return (... && std::get<Indexes>(t).try_parse(source));
}

templatetypename... F >
bool try_parse(const std::string & source, std::tuple<F...> & parsers)
{
   return try_parse_impl(source, parsers, std::index_sequence_for<F...>());
}

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

А вот как сделать тоже самое, но в C++14, где fold expression нет?

Единственное, что у меня пока вышло -- это вот такое:

templatebool valid_index, std::size_t I >
struct try_parse_impl
{
   templatetypename... Parsers >
   static bool apply(const std::string & source, std::tuple<Parsers...> & t)
   {
      if( std::get<I>(t).try_parse(source) )
         return try_parse_impl< (I+1 < sizeof...(Parsers)), I+1 >::apply(source, t);
      else
         return false;
   }
};

template< std::size_t I >
struct try_parse_impl< false, I >
{
   templatetypename... Parsers >
   static bool apply(const std::string &, std::tuple<Parsers...> &)
   {
      return true;
   }
};

templatetypename... F >
bool try_parse(const std::string & source, std::tuple<F...> & parsers)
{
   return try_parse_impl< (0 < sizeof...(F)), 0 >::apply(source, parsers);
}

Возможно, вместо всего этого как-то можно было бы обойтись более прямой работой с std::index_sequence. Но что-то для этого моего понимания механизма распаковки параметров в variadic templates не хватает. И примеры, которые я находил в Интернетах не очень помогают, т.к. там идет итерация по всем элементам тупла, без анализа результата на очередной итерации и прерывания цикла.

Поиграться с полным примером можно здесь.

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