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

Live and learn

Недавно узнал, что в Google Books появились все номера журнала Popular Science 112за более, чем 100 лет. Обнаружив, что журналы и книги нельзя скачивать к себе в формате PDF или другом, решил написать за вечер (и написал) качалку книг с Google Books. Пока что она в альфа-версии, типичный linux way (работает из консоли), но уже умеет качать. :) Скачал номер за 1870 год, в котором наткнулся на статью “Man as an object of scientific study”.

Невольно заулыбался, начав читать (на картинке начало статьи). Сразу вспомнился Лем с его “Суммой технологий”, в которой он сетовал на нехватку ресурсов для постижения всех научных знаний… Только он писал на 100 лет позже автора этой статьи.

Кстати, все номера Popular Science доступны здесь.

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

Pirates of Silicon Valley

Только что посмотрел этот фильм. Мне он показался немного неправдоподобным — очень уж упрямо из Билла Гейтса делают говнюка, а из Стива Джобса гения, хотя некоторая критика в адрес отсутствия вкуса у Microsoft мне показалась справедливой. Вызвали эмоции сцены с работниками компании IBM, закостенелыми дяденьками в костюмах, которым противопоставляется бунтарь Джобс: мне почему-то сильно они напомнили нашу российскую современность… Именно сейчас в нашей стране в IT наиболее компетентны люди примерно до 40 лет (чем дальше от крупных городов, тем ниже возрастная планка). На мой взгляд, поколению Джобса и Гейтса у нас сейчас примерно соответствует поколение, к которому принадлежу я — поколение гиков, которым в детстве копание в ZX Spectrum’е и БК-0010 было интереснее играния в футбол во дворе.

вторник, 23 февраля 2010 г.

Баг в компиляторе?

Сегодня продолжил свой небольшой challenging, посвящённый C++/CLI и вообще C++. Давно было интересно, как получить отдельные элементы из параметров для макросов __VA_ARGS__ (я использовал их вместе с template’ами, очень выразительная штука получается). Загуглил, наткнулся на это обсуждение: http://www.codeguru.com/forum/showthread.php?t=468033

Мужик очень красиво придумал, но создатели стандарта C++ залажали, и его идея не работала до конца. Я решил проверить, как обстоят дела с этой проблемой в C++/CLI, выяснилось, что всё точно так же. Объявляем хитрые макросы, которые (теоретически) помогут нам работать со списком параметров как со списком в Лиспе или любом другом функциональном языке (они позволят нам обращаться к “голове” и “хвосту” любого подсписка списка рекурсивно):

  1. #define EXPAND(a) a
  2. #define H(a, ...) a
  3. #define B(a, ...) __VA_ARGS__
  4. #define FOO(...) H(EXPAND(__VA_ARGS__))
  5. #define BAR(...) B(EXPAND(__VA_ARGS__))

А теперь попробуем использовать:

  1. int fst = FOO(10, 20, 30); // OK, fst == 10.
  2. int sec = FOO(BAR(10, 20, 30)); // Compilation error.
  3. int arr[2] = { BAR(10, 20, 30) }; // Expected arr[0] == 20, arr[1] == 30, but both are null.

Как видим, первый элемент списка возвращается корректно, а вот второй элемент, так же как и “хвост” списка, возвращается некорректно. Такие дела.

понедельник, 22 февраля 2010 г.

Мой первый эксперимент с C++/CLI

Сегодня неважно себя чувствовал, и решил из-за этого вместо активной работы спокойно покопаться со связкой .NET и native C++. Первой мыслью было придумать лайфхак для возможности за день-два полностью перенести имеющийся код из текущего проекта по работе, который пишется на C++/Qt с C-шным фронтендом для олдскульных программистов. :)

Запала в голову сначала мысль сгенерировать в полуавтоматическом режиме какую-нибудь обёртку для кода на C++ (сразу вспомнился SWIG), но потом всё-таки решил, что это будет невозможно из-за того, что взаимодействие должно быть не в одну сторону (.NET использует C++), а в обе — .NET видит и использует код на C++, а C++ видит код из .NET, причём он должен видеть его именно как код на C++. Второе условие и кажется мне невыполнимым без ручного написания враппера. Потому остановился на том, что надо писать .NET-обёртку над C-шным фронтендом, благо, он в будущем планируется настолько полным, чтобы покрывать функциональность API из C++, ну и возможно придумать со стороны C++ некий тип, который выглядел бы как Qt-шный класс с массивом полей-функций, представляющих методы класса из .NET (для проекта по работе я написал некоторый type-safe аналог делегатам, базирующийся на динамике из Qt и template’ах, напишу о нём как-нибудь позже). Этот тип единственный из всего кода на C++ знал бы о существовании какого-то объекта в .NET, и делегировал ему все “сигналы” (“события” в терминах .NET) и вызовы методов из C++. Ну что ж, звучит красиво! Приступим!

Зная по опыту, что есть возможность писать на C++, используя одновременно платформу .NET и нативный код на C++, я решил сделать прототип, воплощающий мою идею. Основная идея сейчас это вызвать нативный код и вернуть результат в managed-код. Итак, в прототип входит:

  • Библиотека, написанная на чистом C++ с использованием Qt и скомпилированная в *.lib с помощью майкрософтовского компилятора (типа, наш “неприкасаемый” код C++, который ничего не знает об этих ваших .NET-ах).
  • Обёртка, склеивающая библиотеку с managed-кодом из .NET. Является проектом для C++/CLI, самая интересная часть. Видна со стороны .NET как обычная .NET-сборка, но может на полную мощность использовать нативный C++ и линковаться с нативными библиотеками.
  • “Клиент” на чистом .NET (я написал на C#), который референсит обёртку, и вызывает с помощью неё код из библиотеки.

Пишем код нашей C++-библиотеки, файл QtLibrary.h:

  1. class QTLIBRARY_EXPORT QtLibrary : public QObject
  2. {
  3.     Q_OBJECT
  4. public:
  5.     QtLibrary() { }
  6.     ~QtLibrary() { }
  7.  
  8.     int Sum(int arg1, int arg2);
  9. };

Файл QtLibrary.cpp:

  1. #include "QtLibrary.h"
  2.  
  3. int QtLibrary::Sum( int arg1, int arg2 )
  4. {
  5.     return arg1 + arg2;
  6. }

При этом не забываем пометить класс как экспортируемый, объявив в другом файле через макрос QTLIBRARY_EXPORT ключевое слово __declspec(dllexprort):

  1. #include <Qt/qglobal.h>
  2.  
  3. #ifdef QTLIBRARY_LIB
  4. # define QTLIBRARY_EXPORT __declspec(dllexport)
  5. #else
  6. # define QTLIBRARY_EXPORT __declspec(dllimport)
  7. #endif

Далее идём в свойства проекта и добавляем объявление QTLIBRARY_LIB (Properties - C/C++ – Preprocessor – Preprocessor Definitions). Этого не нужно делать, если библиотека импортирует класс, помеченный макросом QTLIBRARY_LIB, чтобы тот же самый хедер был обработан компилятором для получения __declspec(dllimport).

Также я поместил файл QtLibrary.h в отдельную папку /include, которая будет источником всех объявлений классов, которые являются “общими” для разных библиотек. Не забываем указать линкеру, куда складывать *.lib файлы: создаём папку /lib в корне папки проекта и указываем её (Properties – Linker – Advanced – Import Library). (Это классический способ “расшаривания” классов между библиотеками, и любой программист на C++ знает об этом, но я всё-таки написал подробно. :))

Приступаем к самому интересному — обёртке. Создаём проект на Visual C++, тип CLR/Class Library. Это означает, что проект будет виден как обычная .NET-сборка и может использовать как .NET, так и нативный C++. Файл Wrapper.h:

  1. using namespace System;
  2. class QtLibrary;
  3.  
  4. namespace CppCode
  5. {
  6.     public ref class CppWrapper
  7.     {
  8.     private:
  9.         QtLibrary* _cppClass;
  10.     public:
  11.         CppWrapper();
  12.         int SumFromCpp(int ar1, int ar2);
  13.     };
  14. }

Файл Wrapper.cpp:

  1. #include "stdafx.h"
  2. #include "Wrapper.h"
  3. #include <QtLibrary.h>
  4.  
  5. int CppCode::CppWrapper::SumFromCpp(int arg1, int arg2)
  6. {
  7.     return _cppClass->Sum(arg1, arg2);
  8. }
  9.  
  10. CppCode::CppWrapper::CppWrapper()
  11. {
  12.     _cppClass = new QtLibrary();
  13. }

Обратите внимание на #include <QtLibrary.h>: для того, чтобы этот файл указывать без лишних запутанных слешей, в свойствах проекта обёртки указываем созданную директорию /include как место, где надо искать хедеры (Properties – C/C++ – General – Additional Include Directories). В свойствах линкера указываем, откуда нам брать *.lib файлы для линковки с QtLibrary (Properties - Linker – General – Additional Library Directories). QTLIBRARY_LIB не объявляем нигде (ни в коде, ни в свойствах проекта), чтобы макрос QTLIBRARY_EXPORT работал в проекте обёртки как __declspec(dllimport).

Ну а теперь наконец-то клиент! Делаем обычную сборку под .NET (либо исполняемый файл, либо библиотеку). Я сделал консольное приложение, с ним меньше всего возни. Файл Program.cs:

  1. using System;
  2. using CppCode;
  3.  
  4. namespace NETApp
  5. {
  6.     class Program
  7.     {
  8.         static void Main(string[] args)
  9.         {
  10.             CppCode.CppWrapper wrapper = new CppCode.CppWrapper();
  11.             int result = wrapper.SumFromCpp(10, 20);
  12.             Console.WriteLine(result);
  13.         }
  14.     }
  15. }

В референсы добавляем сборку с обёрткой. Кстати, для простоты я указал для трёх сборок в качестве output-директории одну и ту же папку /out, лежащую в корне проекта.

Вот и всё! Результатом работы будет сумма 10 + 20 = 30. Как можно догадаться, таким же образом можно сделать .NET-обёртки для CUDA или других интересностей. Основной цели я добился, код вызвал, а это значит, что обёртку для C-шного front-endа можно сделать! Пойду думать, реализовать мою вторую идею насчёт класса-менеджера для связки Qt - .NET. :)

среда, 17 февраля 2010 г.

Мнение об Agile

В Google Reader у меня есть пара иностранных блогов, посвящённых Agile и вообще тестированию, а также я читаю Хабрахабр, на котором тоже есть твоё “коммьюнити”, посвящённое тестированию. Давно заметил любопытную вещь — в этих блогах какие-то очень длинные посты, простыни по несколько параграфов. И о чём там только не пишут — ощущение, что читаешь какой-то журнал в стиле “женских”, в котором пишут обо всём, включая психологию программиста и влияние тестирования на его жизнь. Пишут о том, как правильно обсуждать совершённые ошибки в команде, как правильно работать — например, в XP рекомендуют “парное” программирование, и много статей посвящено тому, как правильно выбирать себе “партнёра” по клавиатуре, и т.д. Возникает вопрос — а зачем так много букв?

У меня складывается ощущение, что Agile это какой-то аналог правил для пионеров в пионерском лагере: в 8 утра зарядка, с 14 до 15 “тихий час”… Вроде бы и не подкопаешься, правила эти нужны, но они для пионеров, а не для взрослых людей. Я плохо себе представляю Линуса Торвальдса, который пишет ядро системы, используя “парное” программирование в духе XP, посещая семинары по Agile, не отклоняясь ни на шаг от TDD… Он просто делает что-то, и делает хорошо, ему не нужны все эти пионерские правила. К профессионалам эти правила неприменимы.

ИМХО, успех любого проекта зависит только от ума людей, которые его делают. Не от методологий, не от выбранной платформы, а от людей — их ума и их опыта.

понедельник, 8 февраля 2010 г.

Добро пожаловать

Приветствую всех в моём блоге. В этом блоге я собираюсь публиковать свои мысли на тему IT, какие-то полезные tips and tricks, которые я нахожу в процессе работы, рассуждения о технологиях, и так далее. Я также веду и личный блог, но в последнее время мне начал надоедать формат “лытдыбра”. Буду рад общаться тут с вами о том, что действительно интересно и познавательно!