пятница, 4 февраля 2011 г.
Стереть и переписать все нафиг!
Это здоровая реакция нормального разработчика, бесконечно стремящегося к совершенству кода.
Но, увы, в больших системах, которые разрабатывались годами или даже десятилетиями нельзя просто так взять и все переписать. Бизнес не даст этого сделать.
Вот и возникает волшебное слово «legacy» код.
Лично на своем опыте я убедился, что работы со «старым» - это умение, и умение очень полезное. Парадокс, но порой выгоднее взять старый код, работающий годами, и просто обернуть его красивый интерфейс текущего «правильного» языка, чем тратить титанические усилия на полностью новую разработку.
Ну и что, что Фортран с common-переменными повсюду или С, ну что, что там код 80-х годов с функциями на десятки экранов без каких-либо зачатков unit-тестирования, и потрогать этот код просто страшно. Но трогать его не надо, а надо понять интерфейс и изолировать его.
Лично у меня подобное «прозрение» случилось только недавно, примерно аналогично как с unit-тестированием. Слово «legacy» код не должно синонимом «стереть и переписать все нафиг!», а должно быть знаком того, что надо сделать взвешенную оценку поддержки старого «тлеющего» кода против новой разработки. Любой код начинает тлеть сразу поле релиза, но когда он вам уже достался тлеющим – это другая история.
А корень парадокса в том, что пользователи не хотят вашу новую версию, переписанную с нуля на модном языке Х, они хотят проверенную версию, что далеко не всегда означает одно и то же.
Как пример, банки – это одни из консервативнейших потребителей программных продуктов. И их можно понять – фаза тестирования перед внедрением на боевую обычно длится месяцами и стоит приличных денег, а уж после того, как системы запущена, никто не будет ничего менять без веской причины. А слова «мы тут все переписали заново, пожалуйста, поставьте…» обычно игнорируются на слове «все».
В общем, если хотите рассматривать создание программных продуктов не просто как написание «идеального кода», а как бизнес, работа со старым кодом – это один из навыков, который придется освоить.
среда, 26 января 2011 г.
Fossil - контроль версий, баг-трекер и wiki в одном флаконе
Есть множество бесплатных хостингов для проектов с открытым кодом. Также есть места, где можно держать и закрытые проекты, но такие хостинги часто платные. Да и в целом, если уж есть какой-то закрытый проект, и есть причины его закрытости, то выкладывать его на хостинг третьих лиц было как-то нелогично.
Лично я люблю git для UNIX и mercurial для Windows. Каждая система имеет пачку удобных хостингов, как говорится, выбирай на вкус.
И вот у меня образовался закрытый проект, который мало того, что активно развивается, так еще и накапливает баг-репорты, приправленные файлами отчетов и картинками, и требует ведения документации.
Начал я его вести в mercurial, но когда начал утопать в письмах и документации, то осознал необходимость баг-трекера и wiki. Настраивать все это локально (на публичные готовые хостинги выложить не могу) как-то лень. И тут я вспомнил по fossil.
Fossil - это распределенный контроль версий, баг-трекер и wiki в одном флаконе. Более того, его автор -- ни кто иной, как автор SQLite, борец за минимализм, простоту и надежность. Как и в случае с небезызвестной базой данных, которую кто уже только не использует, все, что вам нужно - это один единственный файл -- fossil[.exe].
Для командной строки - это просто SCM, а будучи запущенной с параметром "ui", превращается в локальный веб-сервер, в котором есть "морда" для просмотра репозитория, баг-трекера и wiki. Более того, все данные живут также в одном единственном файле-репозитории, который по сути является SQLite-базой. Для переноса его в другое место, другую операционную систему или резервного копирования, нужно просто скопировать один файл.
fossil умеет импортировать и экспортировать в git, поэтому я сначала перегнал существующий репозиторий из mercurial в git, а потом импортировал из git в fossil.
В целом, fossil хорош. Вылизанный и минималистичный. Говорят, что из-за использования SQLite в качестве хранилища, с одной стороны получаешь надежность и транзакционность любых изменений (понятно, что хоть остальные системы работают просто с файлами, у них с целостностью тоже все в порядке), но с другой стороны, по скорости может радикально проигрывать git или mercurial на больших проектах. Но для небольших "домашних", но секретных проектов - сложно представить удобнее утилиты.
Даже в рамках компании, можно личный проект в два счета превратить в общий, просто запустив fossil в режиме сервера и дав коллегам его адрес. Домашняя страничка fossil по сути является сервером, работающим на fossil (там можно увидеть живой трекер и wiki). Не самое плохое доказательство уверенности автора fossil'а в своем детище.
Да, лицензия у fossil, конечно, BSD.
Итак, для дома для семьи -- очень удобно.
вторник, 25 января 2011 г.
Баг в компиляторе LCC
Благополучно нарвался на баг в компиляторе LCC.
c:\lcc\bin\lcc -v
Logiciels/Informatique lcc-win32 version 3.8. Compilation date: Dec 4 2010 13:14:58
Файл: t.c
1 2 3 4 | int main() {
char* p;
char* s[1] = { p };
}
|
c:\lcc\bin\lcc t.c
Error t.c 3 Compiler error (trap). Stopping compilation
Обычно ж как бывает, начинает проявляется "баг компилятора" -- программа ведется себя странно, исключения почему-то не ловятся, наблюдаются неожиданные падения программы и т.д. В подавляющим случаев, увы, все кончается просто ошибками работы с памятью. Ничего сверхестественного.
Баги же типа этого, проявляющиеся на тривиальном примере - это всегда событие.
Из недавнего:
четверг, 20 января 2011 г.
Вопросы на интервью, на которые нельзя не знать ответы
Так сложилось, что за последние полгода, я активно участвовал в процессе интервьирования программистов в компании Bloomberg.
Также на многократном личном опыте знаю, что когда тебе оказывают – это всегда обидно и досадно, какой бы причина там ни была. Но это случается почти со всеми.
К сожалению, отказывать приходится порой из-за радикально тривиальных вещей, незнание которых просто несовместимо с профессией.
У меня накопилось несколько вопросов, незнание ответа на которые является почти стопроцентной причиной, когда я в своем отчете писал отказ.
Интервьюирование было на позицию "Senior C/C++ developer”.
Ответы приведу тут же, так как они очевидны.
- Сколько примерно будет 2^32? (обычно задается по телефону)
Ответ "Около четырех миллиардов" является исчерпывающим.
Я вообще и не могу понять, как человек, в названии профессии которого есть слово "программист" может этого не знать. Увы, это далеко не единичные случаи.
- Как сравнить две переменные типа double или float на равенство? (обычно задается по телефону)
Ответ "Вычесть одно из другого и сравнить результат на больше/меньше с каким-то малым числом, например 10E-6" является исчерпывающим. Конечно, много зависит от используемой библиотеки работы с числами с плавающей точкой, но смысл, в целом, одинаков.
Увы, количество неотвечающих тоже весьма значительно.
- (Хит!) Что распечатает данная программа? (не забываем, что собеседование на позицию разработчика на C/C++). В принципе, его тоже можно задать по телефону.
char* f() {
char buf[100];
strcpy(buf, "TEST”);
return buf;
}
int main() {
char* s = f();
/* (1) */
printf("%s\n", s);
}
Ответ: "Нельзя сказать с уверенностью, скорее всего мусор, но в целом это неопределенное поведение, так как локальный буфер формально прекращает существование после выхода из функции f()" является почти исчерпывающим.
Почему "почти"? Потому что обычно за ним дополнительный вопрос: "Что именно может с высокой вероятностью затирать заветное слово TEST и приводить к выводу мусора? Для конкретности: платформа x86, 32-bit, компилятор Visual Studio. Если остановить программу отладчиком в точке (1) и посмотреть, на что указывает указатель "s", то очень высока вероятность, что там будет таки "TEST", а вот printf() таки с высокой вероятностью распечатает мусор. Почему?".
Более половины собеседований, в которых я участвовал, заканчивались со знаком "минус", так как человек даже не делал попытку сказать что-то типа "В данных условиях скорее всегда слово TEST будет перезатерто параметрами функции printf(), которые передаются через стек и ложатся на то место, где был раньше размещен буфер "buf". Конечно, многое зависит от режимов оптимизации, так как аргументы могут быть переданы через регистры."
Фактически, произнесенные слова "стек" и "параметры функции" являются достаточным ответом на вопрос.
Повторюсь, я лично считаю, что на собеседовании задача интервьюера не показать, на сколько он сам умен (читать задачи по бумажке может каждый), а попытаться разглядеть в собеседнике те качества, которые требуются для данной позиции. И просто отказывать человеку из-за того, что он не ответил, как тебе кажется, на один элементарный вопрос, также глупо, как и делать из этого вывод о прочих знаниях кандидата.
Но все же есть такая черта, ниже которой уже нельзя.
А у вас есть вопросы, "неответы" на которые вы лично можете считать поводом для практически однозначного отказа?
Самые глупые ответы на интервью, что я когда-либо давал
Решил я вспомнить, какие самые невозможно глупые ответы я когда-либо давал на интервью, за которые мне до сих пор даже перед самим собой стыдно неимоверно.
- Как-то яростно пытался доказать, что тип int является за 100% атомарным без каких-либо гвоздей на платформе x86. Не доказал (и вот почему).
- Вопрос: «При множественном виртуальном наследовании в С++, кто и как должен заботиться о правильном однократном вызове конструктора базового класса (подразумевается, что у этого конструктора есть параметр)?». Я сказал, что это компилятор, и вдобавок еще не смог объяснить почему.
- Ну и лидер нашего хит-парада. Вопрос: «В С++ таблица виртуальных функций принадлежит классу или экземпляру класса?» Барабанная дробь: я сказал, что каждый экземпляр одного класса имеет собственную копию таблицу. Почему я так сказал, я до сих пор не знаю.
Все это еще раз подтверждает факт того, что на нервах можно сморозить такое, что потом сам будешь думать о причинах сказанного.
вторник, 18 января 2011 г.
Алгоритмы на C++ и Java
Не побоюсь повториться -- две совершенно волшебные, на мой взгяд, ссылки на реализации множества алгоритмов на C++ и Java.
- http://e-maxx.ru/algo/ - алгоримты на С++ с минимумом теории
- http://sites.google.com/site/indy256/ - алгоритмы на Java и С++
Если у вас есть в заначке ссылка на ресурс подобного качества, поделитесь пожалуйста.
Компилятор языка С: LCC-WIN32
Потребовалось мне тут прикрутить к замечательной программе putty подсветку синтаксиса на лету в терминальной сессии. И так вышло, что на новом рабочем ноутбуке я пока еще не успел поставить Студию. У putty есть makefile’ы для Visual Studio, Borland’а, Cygwin’а и LCC. Первых двух у меня не было, и взять их было негде, Cygwin недолюбливаю из-за необходимости таскать с собой потом dll’ки, и чудом выбор пал на LCC. До этого я никогда этот компилятор не использовал.
И я был приятно удивлен практически всему увиденному. Во всего шести мегабайтах дистрибутива вы получаете быстрый компилятор С99 с поддержкой современных процессоров, линковщик, ассемблер, компилятор ресурсов и внушительную библиотеку.
Про библиотеку хочу сказать отдельно. Помимо стандартного набора libc и Win32 API, там полно всего остального. Лично я был несказанно удивлен простой, и порой столь нужной функцией ping() (и не надо больше вызывать ping.exe в скрытом окне).
В общем, с помощью также идущих в комплекте регулярных выражений, я быстро подхачил putty как мне было нужно. Попутно проронил ностальгическую слезу от программирования оконного интерфейса на чистом Win32 API и ощутил некоторые приятности С99. Например, объявление переменных не в начале блока, а где удобно, и размер автоматических массивов задавать не статически, а из переменной. C99 однозначно стоит внимательного изучения.
Приведу небольшую выжимку из идущих в комплекте библиотек (кроме стандартных libc и Windows API, конечно). Думаю, названия говорят сами за себя.
| gl.h | OpenGL |
| sqlite.h | |
| bignums.h | Работа с числами произвольной точности |
| bitstring.h | |
| bluetoothapis.h | |
| d3d.h | |
| d3dx.h | |
| dynloader.h | Работа с DLL’ками |
| gc.h | Сборщик мусора (требует запуска, конечно) |
| getopt.h | |
| icmpapi.h | |
| int128.h | |
| matrix.h | Работа с векторами и матрицами |
| mq.h | IBM MQ |
| msi.h | |
| netmon.h | |
| netsh.h | |
| pcre.h | Регулярные выражения в стиле Perl |
| ping.h | PING! |
| ras.h | |
| regexp.h | Простой API для регулярных выражений (regcomp() и regexec()) |
| snmp.h | |
| sqlite3.h | |
| str.h | Работа со строками в стиле C99 |
| tapi.h |
Итак, если вам быстро нужен небольшой компилятор (дистрибутив всего шесть мегабайт), для написания программы на С99 под Windows (для графического интерфейса придется все делать на чистом Win32 API), имеющий в комплекте в дополнение к libc и Win32 API приличный набор разнообразных библиотек, то LCC – это очень сильный кандидат.
Кстати, отдельно можно скачать и 64-битную версию компилятора.
Единственное, чего я не пробовал – это линковать объектники LCC с другими компиляторами. Кто имеет опыт – поделитесь.