суббота, 6 марта 2010 г.

[life.sport.photo] Фотографии с прошедшей Олимпиады 2010 в Ванкувере

Первая подборка из 45 снимков:

И вторая (так же из 45 фотографий):

[work] Впечатления после первого раунда собеседований

Читатели моего блога могли заметить, что описание вакансий и требования к соискателям изменились. Сделано это было под впечатлениями от первой волны собеседований. Точнее, от одного самого сильного впечатления – хорошие программисты работу не ищут. Поскольку прособеседованные мной соискатели хорошими программистами, к сожалению, не были. Это нормальные ребята, вполне вменяемые, но кому-то не хватало опыта, кому-то способностей. И всем сильно не хватало знаний C++.

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

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

Низкое качество тестовых решений отражается и в низком качестве самого кода программ. Все(!) решения страдали одними и теми же проблемами:

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

Временами мне казалось, что если бы разработчик просто внимательно посмотрел на распечатку своей программы, он бы мог объединить 4-5 одинаковых фрагментов в одну функцию и сократил бы тем самым объем программы, как минимум, вдвое.

Может я слишком сурово отношусь к соискателям, но я убежден, что все вышеупомянутые проблемы – это как раз признаки плохого программиста и даже больше – признаки отсутствия способностей к программированию. Особенностям и тонкостям языка C++ можно научить, в конце-концов, это всего лишь обычный процесс набивания шишек. Но вот научить распознавать повторяющиеся фрагменты кода, имхо, невозможно. Человек либо их видит, либо нет.

Еще один критерий – может ли человек объяснить почему он написал именно так или не может. Даже объяснение “я не смог придумать ничего другого” гораздо лучше характеризует разработчика, чем “ну я не знаю” или “мне так захотелось”. Программирование – это такая профессия, которая требует от человека составления детального и подробного плана выполнения поставленной перед ним задачи (чем и является код программы). И если программист не может объяснить, почему в этом плане оказались те или иные пункты, то это опасный сигнал.

Какие еще впечатления? Вот, коротко:

  • тестовое задание перед собеседованием – это must have. Я много читал на форумах высказываний “Мол, почему я за бесплатно буду что-то кому-то писать” и боялся столкнуться с такими заявлениями. Теперь людей с такими заявлениями я буду посылать фтопку сразу. Когда цирк нанимает жонглера, вполне нормально, если жонглер покажет свое умение до первого представления. Вот так и здесь – покажи, что ты умеешь до того, как писать код для реальных систем;
  • активно общаясь на форумах я привык к тому, что большинство разработчиков находятся в русле современных тенденций (проникновение функциональщины в мейнстрим, начало many/multicore эры и т.д.). Ёптыть, как же это все далеко от реальности!

Такие дела в нашей центрально-европейской провинции. Надеюсь, что в крупных городах (Киев, Минск, Питер, Москва, Новосибирск и т.д.) получше.

пятница, 5 марта 2010 г.

[work; prog.c++] Ищу людей в свою команду (С++ программистов, в Гомеле)

Я рад сообщить, что в моей команде появилась открытые вакансии. Хотим взять нескольких толковых C++ разработчиков. Вот более формальное описание:

Работодатель

ЗАО Интервэйл – поставщик решений для электронной коммерции (например, системы “Мобильный Банк”). Занимается разработкой и внедрением собственных систем. Головной офис компании находится в Москве. Разработкой ПО занимается филиал в Гомеле, где и открыта вакансия.

Позиция

Ведущий C++ программист

Обязанности

Разработка ПО для телекоммуникационных задач и для задач, связанных с электронными платежами.

Занятость

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

Требования

Высшее профильное образование.
Хорошее знания языка C++ (уверенное использование исключений, шаблонов, STL).
Умение писать простой и хорошо документированный код.
Умение работать с Subversion (или аналогичной системой контроля версий).
Опыт разработки кроссплатформенных приложений.
Опыт работы с реляционными СУБД.

Дополнительные плюсы:

  • опыт написания 24x7 приложений на C++;
  • опыт работы с библиотеками типа ACE, POCO, Qt;
  • опыт работы с динамическими языками вроде Ruby и Python.

Размер оплаты

Устанавливается по результатам испытательного срока. От 1000у.е. и выше, в зависимости от способностей, ответственности и самостоятельности.

Испытательный срок

Обязательный испытательный срок до одного месяца. Размер оплаты на время испытательного срока определяется по результатам собеседования.

Порядок прохождения собеседования

Присылаете свое резюме на адрес eao197 собака intervale точка ru (и копию на eao197 собака gmail точка com). Вам высылается тестовое задание, которое вы должны выполнить за два дня. Если тестовое задание выполнено, то вам назначается собеседование.

Условия работы

Гибкий рабочий график.
Офис в центре Гомеля.
Занятия английским языком для желающих.
Бассейн для желающих за счёт фирмы.
Ежегодные выезды на природу ("день здоровья"), корпоративы за счёт фирмы.
Дружный молодой коллектив.
Ежегодные походы на байдарках для желающих (это за свой счёт).
Турник и брусья в офисе.

Контактная информация

Евгений Охотников, eao197 собака intervale точка ru

Теперь менее формально. Указанная в официальном объявлении зарплата – это базовый уровень для нормального C++ника. Для опытных и самосоятельных разработчиков размер оклада будет обсуждаться в более широком диапазоне :)

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

Под катом небольшие рекомендации по составлению резюме ;)

[prog] ACE обновилась до версии 5.7.7

Вышла новая версия библиотеки ACE – 5.7.7. Из основных изменений:

  • добавлена поддержка atomic-инструкций GCC (версий старше 4.1) для платформ PPC32/PPC64/IA64;
  • добавлена поддержка флагов –mcpu и –mtune, что может существенно улучшить производительность на процессорах IBM Cell;
  • улучшена производительность для таймера при работе с малыми временными интервалами;
  • для ACE_Time_Value добавлен оператор сдвига в C++ stream-ы.

Плюс еще несколько улучшений и багфиксов.

Соответственно, до версий *.7.7 обновились TAO и CIAO.

Скачать можно отсюда: http://download.dre.vanderbilt.edu/

Disclaimer: мопед не мой, я только дал объяву.

[life.humour] Подборка юмористических рекламных фотографий

Вот здесь: http://freshpics.blogspot.com/2010/03/hilarious-print-advertisements.html

Для затравки:

[life.photo] Заложница с ножом у горла

Китаец взял свою сводную сестру в заложницы на улице города Вуксю (Wuxi):

Она была освобождена (даже без ранений), а он взят под стражу.

Снимок найден в очередном выпуске WSJ’s Pictures of the Day.

А вот как освобождение заложницы происходило:

Продолжение найдено почти там же.

четверг, 4 марта 2010 г.

[prog] О скорости упаковки/распаковки XML

Многие знают, а некоторые еще только догадываются, что использование XML для передачи данных – штука недешевая. Скорость упаковки/распаковки XML в несколько раз меньше различных форм бинарной сериализации. Но вот во сколько раз?

По работе пришлось заняться этим вопросом и вот что удалось с ходу найти в Интернете:

An XML Alternative for Performance and Security: ASN.1 – небольшая статья от 2004 года, в которой сравниваются скорости работы ASN.1 и XML. В некоторых случаях скорость декодирования XML на 1000% медленнее скорости декодирования ASN.1 (речь, насколько я понял, идет о подписанных сообщениях).

Use of ASN.1 Encoding Rules for Binary XML – 37-ми страничная презентация от Objective Systems Inc., в которой приводятся результаты нескольких замеров производительности. Впечатлил такой результат: на сериализацию 10000 сообщений (объем в ASN.1 BER – 125 байт, объем в XML – 868 байт) потребовалось: для ASN.1 BER – 53 миллисекунды, для XML – 139 миллисекунд. А для десериализации: ASN.1 BER – 58 миллисекунд, тогда как для XML – 1228 миллисекунд.

Investigating Performance of XML Web Services in Real-Time Business Systems – практически совсем свежая статья о том, какие существенные накладные расходы привносит XML-формат в SOA и как можно с этим бороться.

Сам я сегодня провел маленький эксперимент по моделированию своей задачи: некий узел должен принимать несколько тысяч сообщений типа A и формировать несколько тысяч сообщений типа B. Так вот у меня для двоичного формата (по принципам TLV из ASN.1 BER) получалось время ~40 миллисекунд. А для XML-формата – ~250 миллисекунд (в качестве XML движка использовалась библиотека POCO, не исключено, что с libxml2 время было бы меньше). Что интересно, в моем случае сериализация XML потребляла больше времени, чем десериализация (возможно, из-за слишком тривиальной реализации теста).

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

Так же я разыскиваю замеры производительности (в особенности сравнения производительности) различных message-oriented middleware продуктов (вроде IBM WebSphere MQ, SonicMQ, FUSE Message Broker, TIBCO Rendezvous, FioranoMQ и т.д.) Был бы признателен за помощь в поиске публично доступных материалов на эту тему.

среда, 3 марта 2010 г.

[prog.c++] Пустой массив в структуре

Когда-то давным-давно, изучая программирование под Windows, встречал иногда вот такой фокус:

struct some_struct_t
   {
      int field_1;
      ...
      int field_N;
      char last_field[];
   };

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

char raw_data[ SOME_LIMIT ];
read_data( raw_data, sizeof( raw_data ) );
const some_struct_t * data =
      reinterpret_cast< const some_struct_t * >( raw_data );
for( size_t i = 0; i != data->field_K; ++i )
   if( XXX == data->last_field[ i ] )
      ...

Такой хак использовался когда-то в C, а потом достался в наследство C++. Ну и ладно бы, никогда к нему не прибегал. А на днях пришлось объяснять человеку, что когда он пишет вот так:

struct info_t
   {
      char * name[];
   };
info_t info;
for( size_t i = 0; i != ...; ++i )
   info.name[ i ] = new char[...];

то это, мягко говоря, не совсем правильно. Поскольку память под name никто не выделял, но наглым образом использует.

При этом я открыл для себя интересную штуку: оказывается, C++ компилятор под поле info_t::name вообще не выделяет места! Т.е. я думал, что при такой записи в info_t под поле name будет отведено место на один char*. Но нет! В Visual C++ 2003-2008 размер всей структуры info_t – всего один(!) байт (что и понятно, поскольку объектов с нулевым размером быть не должно). А вот в GCC 4.3.2 из cygwin-а размер info_t все-таки нулевой.

Вот такие дела. Век живи – век учись, дураком помрешь ;)

[comp.modem] Мой Acorp W422G приказал таки долго жить

Не смотря на недавно проведенный ремонт, мой ADSL модем Acorp W422G все-таки перестал нормально работать. Не знаю, что точно произошло (был на работе), но в один прекрасный момент модем перестал обнаруживать DSL-линию. Как через ASDL-сплиттер, так и без оного. После обращения в БелТелеКом линия обнаруживаться начала, но скорость была крайне низкой и связь была ненадежной. Разбирательство со специалистами БелТелеКома показало, что у нас очень низкий уровень сигнала. И было не понятно, по чьей именно вине.

В конце-концов, мы взяли ADSL-модем с WiFi-ем в самом БелТелеКоме (благо бесплатно и сейчас у них такие модемы есть), с ним все заработало. Новый модем быстро нашел DSL-линию и связь держит стабильно. А старый Acorp мигает-мигает огоньками, но без толку.

Видимо, опять возникли какие-то неполадки в модеме, на этот раз в модуле ADSL. Но чинить его уже желания нет :)

Так что Acorp W422G был вполне себе хорошим, неприхотливым девайсом с хорошими возможностями. Но проработать смог всего год. Что мало, я считаю. Поэтому никому сию модель рекомендовать не буду.

Кстати, рекомендация для тех, кто сам будет настраивать модем “Промсвязь M-200 A” (в девичестве ZTE) в режиме router-а: имя сервиса (которое предшествует имени пользователя и пароля в диалоге настроек) нужно оставлять пустым. Я изначально задал его и долго курил, почему же меня не пускает в Интернет :)

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

вторник, 2 марта 2010 г.

[prog.c++.bicycle] Еще один трюк в отсутствии rvalue references

В C++0x планируется добавление интересной штуки под названием rvalue references, которая должна убрать изрядную часть накладных расходов в C++ программах. Но пока C++0x не принят, приходится жить без rvalue references и изобретать разные вспомогательные велосипедики.

Первый, под названием temporary_object_ref, я начал использовать года полтора назад. Штука тривиальная и, временами, полезная. Но не всегда. Представим себе, что у нас есть объект, конструктор которого получает три сложных аргумента:

class demo_t
   {
   private :
      std::string m_destination;
      std::string m_source;
      std::list< std::string > m_hints;

   public :
      demo_t(
         const std::string & destination,
         const std::string & source,
         const std::list< std::string > & hints )
         :  m_destination( destination )
         ,  m_source( source )
         ,  m_hints( hints )
         {}
   ...
};

Если мы используем только этот конструктор, то мы всегда вынуждаем объект demo_t копировать значения аргументов. Даже в случаях, когда аргументами являются временные объекты:

std::string destination = domain + "/" + subject + "/" + timestamp;
std::list< std::string > hints;
hints.push_back( "lifetime: default" );
hints.push_back( "priority: default" );

demo_t demo( destination, source, hints );

В этом случае временные объекты destination и hints после объявления demo не нужны. И было бы хорошо, если бы при инициализации demo их значения перешли бы объекту demo (та самая move semantic из C++0x).

Этого можно было бы достичь с помощью temporary_object_ref, если добавить в demo_t еще один конструктор:

class demo_t
   {
   ...
   public :
      ... // Остальные конструкторы.
      demo_t(
         temporary_object_ref_t< std::string > destination,
         const std::string & source,
         temporary_object_ref_t< std::list< std::string > > hints )
         :  m_source( source )
         {
            destination.writeable().swap( m_destination );
            hints.writeable().swap( m_hints );
         }
   ...
};

...

demo_t demo(
      make_temporary_object_ref( destination ),
      source,
      make_temporary_object_ref( hints ) );

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

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

class demo_t
   {
   ...
   public :
      demo_t(
         const_or_swappable_t< std::string > destination,
         const_or_swappable_t< std::string > source,
         const_or_swappable_t< std::list< std::string > > hints )
         {
            destination.apply_value( m_destination );
            source.apply_value( m_source );
            hints.apply_value( m_hints );
         }
   ...
};

...

demo_t demo(
      swappable_object( destination ),
      const_object( source ),
      swappable_object( hints ) );

Весь фокус в простом шаблоне const_or_swappable_t (код которого будет приведен ниже). Если объекту const_or_swappable_t передается константный аргумент, то в своем методе apply_value он выполняет его копирование. Если же аргументом является временный объект – то в apply_value вызывается swap. Тип аргумента (константный или временный) указывает программист посредством вспомогательных функций const_object и swappable_object.

Disclaimer. Пока это решение на практике я еще ни разу не применил. Самым явным его недостатком является то, что при его использовании сначала вызываются конструкторы по умолчанию для атрибутов класса, а только затем отрабатывают apply_value. Это так же лишние накладные расходы. А так же нельзя инициализировать подобным образом атрибуты-константы.

А вот код const_or_swappable_t с необходимыми вспомогательными функциями:

struct constant_object_tag {};
struct swappable_object_tag {};

template< class T >
class const_or_swappable_t
   {
      union {
         const T * const_ptr;
         T * swappable_ptr;
      } m_ptr;
      bool m_is_const;
   public :
      const_or_swappable_t( constant_object_tag, const T & o )
         :  m_is_const( true )
         {
            m_ptr.const_ptr = &o;
         }
      const_or_swappable_t( swappable_object_tag, T & o )
         :  m_is_const( false )
         {
            m_ptr.swappable_ptr = &o;
         }

      void apply_value( T & to ) const
         {
            if( m_is_const )
               to = *(m_ptr.const_ptr);
            else
               m_ptr.swappable_ptr->swap(to);
         }
   };

template< class T >
const_or_swappable_t< T > const_object( const T & o )
   {
      return const_or_swappable_t< T >( constant_object_tag(), o );
   }

template< class T >
const_or_swappable_t< T > swappable_object( T & o )
   {
      return const_or_swappable_t< T >( swappable_object_tag(), o );
   }

понедельник, 1 марта 2010 г.

[work] Советы соискателям

Казалось бы, столько кругом говорят о том, как правильно писать резюме… Ан нет, видимо, мало. Поэтому я позволю себе дать несколько советов соискателям (на должность программистов, по крайней мере).

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

Как вы увеличиваете объем работы своего потенциального начальника? А вот так:

1. Присылаете свои резюме с таких e-mail-ов, по которым невозможно понять ни имя, ни фамилию. Когда я вижу письмо от “Бубль-гум <dodik@gmail.com>” я не могу вспомнить, кто это и зачем он мне пишет. Накануне я запомнил, что мне присылал резюме Иван Иванов и я задал ему несколько вопросов. И жду ответов от Ивана Иванова, а не от Бубль-гума. Вспомнить тождество между Ивановым и Бубль-гумом – это лишняя работа, которую я делать не хочу.

2. Расставляете какие-то условные баллы самому себе для указания степени владения инструментами. Вроде такого:

Владение инструментами (1 – начальный уровень, 2 – средний уровень, 3 – хороший уровень, 4 – отличный уровень):

MS SQL Server: 2
Visual C++: 3
MFC: 4
… (и далее перечень из десятка-другого названий)

Тут сразу несколько проколов.

Во-первых, я вынужден делать лишнюю работу по переводу циферок в какую-то качественную оценку. Вот вижу я тройку в графе Visual C++ и что? Это по 5-ти балльной шкале или 10-балльной? Или это годы использования? Еще круче, когда такие записи оформляются в виде таблички с несколькими столбцами – баллы за уровень знания, годы использования, количество проектов и т.д. При этом список технологий не маленький, и шапка таблицы оказывается где-то на предыдущей странице, поэтому с ходу не поймешь, что обозначают последовательности вида “3 4 5”. Чтобы разобраться с этим, мне приходится делать лишнюю работу, которую делать я, естественно, не хочу.

Во-вторых, ваши собственные баллы мне ничего не говорят. Я сам себя временами оцениваю как хорошо знающего C++. До тех пор пока не встречаю на форумах или у своих коллеги простые вопросы, на которые не могу сразу ответить. Поэтому, когда я вижу оценку от соискателя в 4 или 3 балла, мне приходится напрягаться, чтобы сделать какие-то “поправки на ветер” – мол, если человек работает на C++ три года и выставил себе оценку в 4 балла, то… Это лишняя работа, я не хочу ее делать. Поэтому пишите просто опыт в годах. Ну или давайте какие-то объективные оценки, вроде результатов BrainBench-а, если таковые у вас есть (хотя лично мне на такие пенисомерки оценки наплевать).

3. Перечисляете в своем резюме такие технологии, которые не имеют отношения к требованиям вакансии. Если вакансия для “С++ разработчика” без требований знания .NET-а, то не нужно вписывать в резюме C# и LINQ – мне это пофигу и я вынужден тратить время на выискивание нужных мне технологий в вашем непозволительно длинном перечне. Сюда же идут пассажи по поводу наличия водительских прав, желания ездить в командировки и порода любимой собачки т.п.

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

PS. Еще лично у меня есть предубеждение по поводу красочно оформленных Word-овских документов, которые присылают в качестве резюме. Лично мне это не нравится (особенно когда все это сочетается с тремя вышеизложенными недостатками), хотя объективных возражений против Word-а я придумать не могу.

Короче – будьте проще.

[life.cinema] Очередной кинообзор

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

Я. Какой-то укуренный фильм про каких-то укурок.

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

Жена путешественника во времени. Добротно сделанная мелодрама с оригинальным фантастическим сюжетом. Сам я поклонником мелодрам не являюсь, но жене фильм понравился.

Возмездие. Качественно сделанный фильм. Отличная игра Мэла Гибсона. Но мне показался слишком затянутым и, местами, черезчур запутанным.

Наша Раша: Яйца судьбы. Вполне нормальная попытка сотворить из юмористического шоу "Наша Раша" комедию. Местами смешно, местами нет, чаще нет. Фраза "А я наказываю, жестоко наказываю", похоже, войдет в мой словарь так же плотно, как и "Да ты успокойся!" Впечатления о фильме были бы гораздо хуже, если бы не комментарии Сергея Юрьевича Теплакова под финальные титры ;)

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

Легион. Ерунда – нет ни серьезного сюжета, ни нормального экшена, ни спецэффектов, ни актерской игры.

Формула любви для узников брака. За исключением последних 20 минут (очень предсказуемых и слащаво-приторных) вполе нормальная коммедия.

Пила 6. Как всегда качественно снятое мочилово и расчлененка. Сюжет абсолютно вторичный или даже третичный. Но в конце достойно сделан задел для Пилы 7.

Посылка. Очень даже ничего. Посмотрел с удовольствием. Хотя чего-то мне в фильме не хватило, что-то там не срастается (но что не знаю), так что не шедевр, к сожалению.

Наперегонки со смертью. На удивление неплохой фильм оказался. Простенько и со вкусом. Далеко не "Карты, деньги и два ствола", но я посмотрел с удовольствием.

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