From Novosibirsk, Russia? Our tiny company is looking for current or future rock-star developers.

October 28, 2006

Declarative does not mean XML

«Декларативный» часто означает «описанный в XML». (Сам XML здесь не принципиален, вместо него можно подставить YAML, ini или любой другой приходящий в голову формат.) Многие люди стали считать, что это обязательное условие, но при этом они упускают из вида феномен под названием DSL.

Декларативность — это стиль описания, а не его формат. Вы можете вызывать набор методов из функции на Java и называть это декларативным описанием. Фактически, многие использования паттерна Builder подходят под это название.

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

October 20, 2006

Just-buzz

Интересно, сколько всё-таки людей читают мой блог? Если вы прочли эту запись, пожалуйста, отправьте мне по почте письмо или сообщите каким-либо другим способом. Через пару неделек подведём итоги.

Я определился с тем, что функция комментирования в моём блоге излишня (в силу разных причин — главным образом, интересная информация в комментариях до читателей всё равно не доходит, зато бесполезная плодится). Помимо прочего, по крайней мере некоторые люди любят оставлять комментарии, вообще никак не подписываясь, что я не считаю признаком особо хорошего тона. Так или иначе, комментарии отключены. Рад буду услышать ваше мнение и обсудить любые мои публикации по электронной почте: andreyvit@gmail.com. (В обмен обязуюсь не сохранять ваш адрес электронной почты в каких-либо адресных книгах, куда могут добраться вирусы и прочая гадость.) Об интересных дискуссиях я, конечно, тоже расскажу на страницах этого блога.

Из новостей: вчера посмотрел фильм Забриски Пойнт, который давно искал. Ура! Теперь хочу все остальные фильмы того же режиссёра.

Наконец, заголовки постов написаны по-английски, ибо это единственный способ получить здесь красивые URL. Увы.

October 17, 2006

Less time than none

Ко мне приезжали родители на пару недель. Безусловно, было очень приятно. Но (свободного от крайне срочных дел) времени даже не то, чтобы не было, его как будто бы было отрицательное количество. Сейчас вспоминал, какое же длинное-длинное сумасшествие (с кульминацией в виде написания графики на протяжении двух ночей) недавно закончилось, и понял, что его положено описать фразой «а у меня были в гостях родители».

Но всё равно здорово, пусть приезжают ещё. :)

October 13, 2006

October's blog of the month

В качестве нового начинания, которое, надеюсь, приживётся, предлагается «блог месяца».

Итак. Если вы ещё не читаете блог Реймонда Чена, но при этом интересуетесь программированием, обязательно подписывайтесь. Сейчас Рэймонд работает в Microsoft, но:

Before his career at Microsoft and lasting even into 1995, Raymond Chen identified himself as "just another Linux hacker" in his Usenet sig. He is listed in the Linux kernel CREDITS file as "Author of Configure script".

Сейчас блог посвящен красивым воспоминаниям про то, почему некоторые части Windows были (и есть) реализованы именно так.

В качестве featured article я рекомендую эту, эту и вот эту.

October 12, 2006

When to throw exceptions?

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

Зачем создана обработка исключений?

1. Чтобы каждая функция не занималась обработкой ошибок. Дело в том, что бо́льшая часть кода успешно работает, когда всё идет хорошо, но не знает, что делать, если произошла ошибка. Исключения позволяют сконцентрировать обработку ошибок в одном месте минимальными усилиями программиста. Помимо прочего, это делает код функций более коротким и понятным, т. к. в них описан только успешный сценарий.

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

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

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

Во-вторых, умные люди не видят в исключениях никакой магии. В Python исключения используются для выхода из циклов. В Ruby есть два вида исключений, один из которых специально упрощен для выхода из вложенных подпрограмм. Авторы JRuby (на Java) пытались использовать исключения для эмуляции параллельного исполнения в стиле Ruby.

В стандартной библиотеки C++ исключения кидаются, например, когда не получается открыть файл. Если задуматься, это нормальная ситуация — в 99% случаях вы получаете имя файла от пользователя, окружаете вызов open обработкой исключений и в catch сообщаете пользователю, что имя файла неверно. Если пользоваться логикой «исключения только для случаев, которые не ожидает программа», open должна была бы возвращать bool, а не кидать исключения.

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

Случаев, когда исключения использовать не стоит, я вижу три:

1. Ошибка в процедуре, исполняющейся очень большое число раз. Скажем, функция Win32 API TryEnterCriticalSection создана ровно для того, чтобы очень часто вызываться в цикле, а механизм Critical Sections в принципе сделан для ускорения работы программы. Поэтому этой функции стоит возвращает bool (точнее, BOOL), а не кидать исключения. (Разумеется, это если бы функции Win32 API вообще могли бы кидать исключения в стиле C++.)

2. Особая ситуация, которая всегда обрабатывается там же и так же, как и нормальная ситуация. TryEnterCriticalSection могла бы быть подходящим примером, но еще более подходящий вариант — вызов fork() в Unix.

У fork есть три типа возврата: (1) не удалось создать процесс, (2) всё нормально и это родитель, (3) всё нормально и это ребёнок. В случае (2) функия возвращает PID (идентификатор процесса) созданного ребёнка. Можно было бы считать это основным результатом функции, а в случаях (1) и (3) кидать исключения. Однако случай (3) концептуально равноправен со случаем (2) и его обработкой точно занимается тот же самый код, который вызывает fork. Поэтому в третьем случае не стоит кидать исключения, тогда как в первом — стоит.

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

3. Если вызвавшая сторона может быть написана на другом языке или не может ловить исключения по другим причинам. Например, функция обработки сообщений в Win32 или обработчик сигналов в Unix не должен кидать исключения, потому что его вызывает операционная система.

October 10, 2006

Opinions are welcome

В комментариях к предыдущему посту развернулась дискуссия о Питоне, Руби и их развитии (а также о C++). Всех желающих приглашаю прочесть её и/или высказать своё мнение.

Может (а вдруг) среди читателей также есть любители еще каких-нибудь языков? Например, про groovy я вообще мало что знаю. Или, вот, мы в разговоре мало упоминаем JavaScript, тогда как это полноценный язык, который отлично используется в функциональном стиле. И, да, он лучше PHP. Пусть там не развито метапрограммирование — сейчас — но prototype-based OOP тоже достойно внимания и анализа.

Готов сделать предсказание: скоро JavaScript обретёт свои наработки в метапрограммировании. Конечно, оно там будет в стиле Питона и потребует понимания механизма прототипов, но зато получится очень просто и красиво.

October 09, 2006

PHP5 vs. Python/Ruby

Встретил человека, которого удовлетворяет PHP5. Мне кажется, ему легко живется в этом мире.

Языки с динамической vs. со статической типизацией — это, безусловно, предмет длительного спора. У каждого из них есть свои положительные и отрицательные стороны.

Статическая типизация даёт программисту больше уверенности в коде (иногда ложной).

Динамические языки, во-первых, позволяют выражать мысли естественно (окружающий мир тоже живет по принципам duck typing, а не строгой типизации), во-вторых, уникальной сильной стороной динамических языков является метапрограммирование.

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

Главное преимущество языков с динамической типизацией — применение метапрограммирования и функций высших порядков как основного способа программирования. Динамическая типизация просто делает это возможным.

Что же мы видим в PHP5? Метапрограммирование отсутствует напрочь. Авторы очень старались сделать всё, как у нормальных людей, но так и не поняли самого главного. Более того, они пытаются сделать язык похожим на Java, но только без строгой типизации (что суммирует недостатки обоих подходов в одном языке).

Лично я предпочитаю Ruby, потому что в нем красивее выглядит и метапрограммирование, и применение higher-order functions (благодаря SmallTalk'овским корням). Впрочем, это уже дело вкуса. Пусть метапрограммирование в Питоне выглядит более странно, но оно не менее мощное.

P.S. Помнится, раньше были споры про строгую типизацию, а не про статическую. А вот сегодня я, не морщась, употребляю эти термины почти как синонимы. Десять лет назад меня бы за такое линчевали.

P.P.S. Да, забыл, но впрочем это естественно, зачем говорить о том, чего нет. Функции высших порядков в PHP тоже имеют рудиментарный вид (ну то есть отсутствуют).

October 05, 2006

To whom it may concern: happy new winter!

Вчера выпал первый снег! (Полагаю, правда, что для многих, читающих мой блог, это не новость.) На улице очень оптимистичный и праздничный вид. По ощущениям — как будто скоро Новый Год. Сегодня съездил в город, получилось что-то вроде выходного (на половину дня).

Очень красивые виды наблюдались в лесу. Извиняюсь за банальность, как в сказке: все деревья еще с листьями и в снегу. Шел с работы до универа и много-много раз пожалел, что с собой нет фотоаппарата. На обратном пути встретил человека с очень довольным лицом и фотоаппаратом на шее. Я его понимаю. …Впрочем, во всём Академгородке сейчас красиво.

У коворкера сегодня был день рождения. Хорошо посидели. На всех было 2 совершенно одинаковых фотоаппарата — Canon EOS (подробнее назвать модель не могу, но это довольно навороченная цифровая зеркалка). Фотоаппарат, конечно, хороший, но через видоискатель снимать жутко неудобно. Да и 20 штук за фотик я отдавать пока не готов.

Игра «русская рулетка» от xored: каждый сотрудник по-очереди отвечает на просьбы заказчиков что-то типа «подождите еще», «мы работаем над этим», «с вами скоро свяжется …»; тот, на ком заказчики обидятся и разорвут контракт, выплачивает всю его стоимость.

October 04, 2006

О глубоком сне, изогнутых клавиатурах и leap'ах

От постоянного использования клавиатуры на работе в запястье левой руки стали возникать неприятные ощущения. Пересел на Microsoft Natural Keyboard, и ощущения сразу исчезли. Так что изогнутые клавиатуры действительно делают своё дело, что бы там ни говорили.

Заодно научился работать на клавиатуре с нетрадиционным блоком дополнительных клавиш (которые посередине между основной частью и цифровой клавиатурой). Достаточно приучиться использовать Ctrl-C, Ctrl-V и Ctrl-X вместо Ctrl-Insert, Shift-Insert и Shift-Delete (что я и так уже сделал, ибо на маке применяются Command-C, Command-V и Command-X).

Кстати о Mac. Самым загадочным в его поведении был мгновенный выход из состояния hibernate (или его еще называют «suspend to disk»). (Как я уже говорил, обычного sleep, то есть suspend to memory, у него нет, видимо потому, что hibernate работает быстро.) Честное слово, если я бы не прочел Джефа Раскина и его описание загрузки Canon Cat, я бы не догадался.

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

Так вот, в MacOS применяется хак имени Раскина. После открытия крышки изображение появляется мгновенно, но курсор еще секунды 2 не двигается.

А пользовательский интерфейс Canon Cat ныне существует в виде проекта The Raskin Center for Humane Interfaces по имени Archy (см. также описание Archy на Wikipedia). Archy представляет все данные, с которыми работает компьютер, в виде большого текстового документа. Основным способом навигации (перемещения курсора по нему) предлагается поиск, именуемый Leap. Вместо использования стрелочек или мыши вы нажимаете на клавишу поиска (Leap Forward или Leap Backward) и набираете текст.

Мораль: когда-то я попробовал Archy и решил, что его Leap слишком непривычно использовать. Но недавно я стал пробовать использовать Incremental Search в Eclipse для перемещения по файлу, и это действительно очень удобно и быстро. Неприятно только нажимать Ctrl-J и Ctrl-Shift-J (Archy использует левый и правый Alt, и это на порядок удобнее).