Шок и трепет

Android,  оказывается, не поддерживает Ad-hoc wireless networks. Причем, вовсе не потому, что эту фичу решили не реализовывать – ее, напротив, выпилили в версии 2.2

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

Ну и как дальше жыдь, я вас спрашиваю?

Теория и практика макаронолитейного дела

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

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

class MyCoolClass
{
private:
BigFatObject* m_pOtherObject;
public:
MyCoolClass(BigFatObject* _pPtr):
m_pOtherObject(_pPtr)
{
}

void DoSmth()
{
std::string sName = m_pOtherObject->GetName();
// do smth
}

void DoMoreThings()
{
std::string sName = m_pOtherObject->GetName();
// do smth
}

// and other methods. All like this.

}

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

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

Хозяйке на заметку

Первый сервис-пак для Windows 7 лучше пока не ставить. Может случиться бо-бо.

Так как же правильно взвешивать Боинг?

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

Знаете что? Единственное, что можно сказать о человеке, успешно решающем сферические головоломки в вакуууме это то, что он умеет решать сферические головоломки в вакууме.

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

Возьмем уже не очень популярную задачу о взвешивании Боинга без весов. Не очень популярную потому, что “правильные ответы” уже разве что на заборах не написаны.

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

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

Есть еще и деструктивные варианты, которые я по понятным причинам упоминать не буду.

Впрочем, правильного ответа в интернетах нет. Правильный ответ вообще сам по себе односложен и является в свою очередь вопросом:

“А зачем Вам нужно знать вес Боинга?”.

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

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

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

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

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

Would you mind getting real or why online С++ tests suck

Dear Madam/Sir,

I appreciate you going into the trouble actually visiting this page.  This post represents this blog owner’s point of view on so-called “Online C++ tests” that are used by recruitment agents to select candidates and explains why its author does not take any of these tests anymore. The sole purpose of the post is to be referred to when he is asked to sit one of these to save him the time explaining his position on this issue over and over again. By writing this post, the author did not intend to insult anyone nor pay revenge of any kind to anyone.

Almost every good software developer can find themselves discussing a new exciting career™ opportunity with the potential employer or their agent. Nine from ten, the candidate will be asked to sit a test. A very easy one, should not be too much trouble, person of such experience will not have any problems completing it in no time, they are told. And this is what is terribly wrong about it. You will have problems. No matter how good you are.

I agree that some initial screening may be required. For example, company needs a junior software developer and they need to be sure that candidates understand basic concepts of certain programming language. In this case test will help. It simply must be well prepared, 100% accurate, 100% correct, 100% meaningful and also short, if not too much trouble. The problem is that most of the tests out there don’t have any of this characteristics. The bigger problem is that they are usually put together by those who have never worked in the software development. And the killer problem is that these tests are filled with inconsistencies, discrepancies or simply full of errors (I wanted to use more colorful language here, but this post is going to be a part of my CV, so I better don’t).

About a year ago I was asked to sit an online C++ test.  I had no objections then. I also was interested in the position. The first question was quite obvious. The second had 4 answers and three of them were correct, but according to the question, only one of them was supposed to be correct. I lost all the interest momentarily. I wanted to stop it right then, but I decided to continue. I don’t regret. At least, now I have the proof how bad these tests are . That’s what question number 4 was:

(more…)

Брейнбенч головного мозга

Внезапно позвонил очередной агентег с очередной lifetime opportunity. И ссылку на тест прислал. По С++.

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

Вот теперь сочиняю ответ. Кстати, не напомните, “нах$й” пишется раздельно, или слитно?

Рабоче-крестьянские зарисовки

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

(more…)

Историческое

По старой памяти установил DevPartner на VS 2010.

Это даже не УГ, это намного хуже.

А когда-то вполне себе рулезная штуковина была.

Оптимизированные грабли

Тут на днях коллеги подложили нам свинью.

#define true false    // happy debugging!

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

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

(more…)

Паттерн “observer” на tr1::function или почти настоящие делегаты

Про C++ делегаты на основе boost::function (tr1::function) я уже писал. В отличие от стандартного варианта обсервера для C++, который подразумевает фиксированный контракт (интерфейс) для подписчиков, вариант с функциональными объектами обладает определенными весомыми преимуществами (все они перечислены в посте по ссылке).

Но за удобство приходится платить. В данном случае расплачиваться приходится невозможностью реализовать отписку. И причина тому банально проста. Вот простейший пример

class Subject
{
   public:
       typedef std::tr1::function<void (const MyData&)> typeDelegate;

       void Subscribe(typeDelegate);
       void Unsubscribe(typeDelegate);
}

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

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

Отсутствие возможности сравнивать ставит жиирный такой знак вопроса на самой возможности отписки. Конечно, можно усложнить интерфейс субъектов и обязать подписчиков передавать какой-нибудь уникальный идентификатор при подписке и отписке. Таким идентификатором, например, может быть и указатель на подписчика, совсем как в классическом обсервере.

Делать так можно. Только это кривовато сразу по нескольким статьям. Поэтому нам нужно пойти другим путем.

Вышеозначенный делегат можно создавать динамически и заворачивать в умный указатель. А умные указатели уже можно сравнивать! Значит, получим

class Subject
{
   public:
       typedef std::tr1::function<void (const MyData&)> typeDelegate;
       typedef std::tr1::shared_ptr<typeDelegate> typeDelegatePtr;

       void Subscribe(typeDelegatePtr);
       void Unsubscribe(typeDelegatePtr);
}

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

// Somewhere in subscriber's constructor, for example
Subject::typeDelegatePtr m_Delegate(
    new Subject::typeDelegate(bind(&Subscriber::Process, this, _1))
    );
//...
//   Subscribe for events on _pSubject
_pSubject->Subscribe(m_Delegate);
//
//
//   Unsubscribe from _pSubject
_pSubject->Unsubscribe(m_Delegate);

При этом реализация методов подписки и отписки субъекта становится очевидной, поэтому о них больше ни слова.

Как видно, если у объекта есть необходимость отписки, он должен сохранять оригинал делегата для этих целей. Если отписка не требуется (а такое бывает часто), локальная копия m_Delegate не нужна – временный экземпляр его можно будет создать при вызове Subscribe().

Можно еще сделать следующий финт ушами – слегка изменить интерфейсы и в субъект передавать не shared_ptr, а weak_ptr, образованный от оригинального умного указателя на делегат, который является членом класса-подписчика. При этом бесплатно решается проблема курицы и яйца: иногда требуется обеспечить, чтобы объект-подписчик автоматически отписывался при удалении, но никакой гарантии, что субъект еще жив, нет и быть не может. Достаточно лишь обеспечить, чтобы субъект проверял, не протухли ли “слабые” указатели (или делал им lock()) перед вызовом делегата, а подписчик владел оригинальным shared_ptr<typeDelegate>. При этом удаление подписчика будет вызывать инвалидацию всех инстанций weak_ptr, образованных от этого указателя, тем самым делая невозможным вызов убитого объекта через делегат, что и даст нам такую вожделенную возможность подписчика замести все свои следы даже без информации о том, на события каких объектов он подписан и живы ли они еще.

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

10 visitors online now
10 guests, 0 members
Max visitors today: 15 at 09:10 am MST
This month: 23 at 05-03-2012 08:23 am MST
This year: 29 at 01-23-2012 02:50 am MST
All time: 45 at 02-23-2011 09:11 am MST