<<<предыдущий список следующий>>>

Это - копия документа, находившегося на http://dz.ru. Авторские права, если не указано иначе, принадлежат Дмитрию Завалишину и/или Евгении Завалишиной. Все изменения, внесенные мной, находятся в этой рамочке.Пожалуйста, прочитайте disclaimer.


29 декабря 1998 года

Апгрейд модемов - старинная русская забава. Берется модем, содержимое его ПЗУ ретранслируется в ассемблер и затем доводится напильником в соответствии с местными потребностями. В их число входит все, на что у апгрейдера хватит сил и интеллекта - от улучшения распознавания сигнала "занято", который русские АТС подают самыми нетривиальными способами, до "приделывания" новых протоколов и методов модуляции. Самая простая и доходная методика, надо сказать, заключалась в том, чтобы включать обратно отключенные разработчиком функции. Не секрет, что USR Sportster был сделан из USR Courier методом отрубания некоторых возможностей и изменения внешнего вида. При этом аппаратная часть модема содержала все необходимое, и даже поддержка отключенных возможностей присутствовала в ПЗУ. Фирменная программа модема просто определяла, на чем она работает - на курьере или на спортстере, и если второе - отказывалась поддерживать фирменные "курьерские" функции и протоколы. Все, что нужно было сделать - убедить ее, что она на курьере. Функции волшебным образом появлялись.

С этого фокуса все началось. То есть у них там, на Западе, на нем все и кончилось, как мне видится. А вот у нас расцвело пышным цветом. Идея влезть в модем и там покуролесить для русского человека означала нечто большее, нежели возможность переставить джампер или забить NOP-ом пару команд в ПЗУ.

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

К чему я это все?

На сервере Infused Bytes - интервью с человеком, который стоял за этим делом, с автором русского курьера - Михаилом Лихачевым. Интересное. Почитай, еще одна success story русской электронной промышленности.

Вопросы читателей и наши ответы.

Q: "Хочется, понимаете ли, аналог фотошопа под Linux."

A: Зайдите на www.gimp.org, попробуйте GIMP. Одни говорят, что это никак не тянет на фотошоп, другие - что это гораздо круче, но, мне кажется, пока сам не попробуешь - все равно не узнаешь, кто был прав. Собственно, правда есть и в том, и в том утверждении. Конечно, к GIMP-у не привинтишь дополнительные модули, сделанные под фотошоп. Зато у него есть скриптинг, которому под фотошоп же вряд ли есть аналог. Да и задачи у всех разные, для одних GIMP лучше, для других - хуже. Смотрите сами.

Q: "Не подскажете ли Вы, где можно найти информацию (неважно, по-русски или по-английски) о 1394 aka FireWire?"

A: Подскажем, почему нет. Искать имеет смысл от сайтов www.1394.org (устройства под 1394), www.ti.com/sc/docs/msp/1394/1394.htm (документация, контроллеры, инфо), http://developer.apple.com/hardware/FireWire/ (инфо для разработчиков, ссылки), http://www.dvcentral.org/ (цифровое видео, новости 1394).

Как убедиться в том, что жена вам изменяет? Взять у нее из кармана метрошную карточку на несколько поездок, посмотреть на ней номера станций и декодировать ее, используя этот ресурс на www.metro.ru. Как убедиться в том, что жена вам не изменяет? Никак. :-)

"Разбирательство по делу Микрософта разворачивается в направлении все менее и менее приятном для подсудимого. Сегодня если издание хочет помочь Микрософту, оно просто не пишет об этом."

Честно сказать, по мне - издание должно помогать исключительно читателю, но писать о суде над Микрософтом я пока воздерживаюсь ибо надоело немного. Наверное, через недельку-другую напишу, если он к тому времени не кончится. :-)

Я писал как-то о Lego-вском процессоре - "кирпиче", который умеет получать информацию с трех сенсоров и управлять тремя моторами в соответствии с прошитой пользователем программой. Так вот - его уже всхакали до самых корней, как водится. Здесь находится результат, если кому интересно.

Те, кому FreeBSD интересно, а английский - не под силу, могут посетить http://www.freebsd.org.ru/ - там все по-русски. Увы, сайт этот несколько портит впечатление тем, что начинается с антимикрософтовских лозунгов. Сама FreeBSD стоит на позициях явно позитивных, а не на "весь мир насилья мы разрушим до основанья, а затем". Нельзя "затем", можно только "перед тем", и обязательно - "лучше того". А это не делается из религиозных соображений.

Соловьев оформил сайт Ирины Богушевской, и результат получился, surprise, surprise, в Соловьевском стиле. :-) То есть нетривиально и вкусно.

На www.providers.ru открылся форум. Желающих потрепаться приглашают начинать. :-)

hmm2_record.jpg (35768 bytes)Кто играл в Heroes of Might and Magic II, тот скриншот справа заценит. А тот, кто не играл - пусть же уже ж поиграет, и заценит саму игру! :-)

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

Что-то в этом, конечно, есть, но... мне вот нравятся оба типа игр. Более того, real-time стратегии меня напрягают, а походовая игра от первого лица наверняка занудила бы до смерти, если бы кто ее создал. :-) Не знаю, чем это объяснить и чем принципиально отличается realtime от первого лица и он же при взгляде на карту сверху. Числом объектов, о которых нужно думать? Менее лаконичным интерфейсом? Трудно сказать.

Зато легко сказать, за что я люблю Heroes. За уравновешенность характеристик всего и вся, за удивительную сказочно-игрушечную красоту без тени затасканности, за богатство возможностей без необходимости вызубривать сотни тонкостей в первый день игры. На последнем остановлюсь особо. Как правило, игры либо примитивны, либо зануживают необходимостью вникать в детали, количеством своим повергающие в уныние даже опытного члена династии библиотекарей. Детализация в HMM прекрасна тем, что на нее можно легко забить и быть при этом вполне в состоянии играть и выигрывать. Да и детали таковы, что, раз узнав, их уже не забудешь. Трудно ли запомнить, что Fire elemental очень боится заклинания "холодный луч", а Water elemental - молнии? Очевидно, не правда ли? Но знать необязательно. Не так быстро, но, heroes_3.jpg (9407 bytes)скорее всего, победишь все равно. А не так быстро - значит меньше очков. В HMM есть лишь одна оценка - время, за которое ты победил. Чем меньше ходов потребовалось - тем выше рейтинг.

Интересно также, что HMM II, что случается нечасто, оказался чертовски удачным развитием первых "геройцев". Игра не потеряла сочности и обрела массу новых деталей. Более того, вслед за HMM II вышла версия Gold (Price of Loyality), которая основана на том же движке но содержит новые дополнения. И снова весьма интересные и удачные! А в феврале должны выйти Heroes of Might and Magic III, и есть все основания полагать, что развитие будет достойным.

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

Моя фраза "exceptions, только exceptions", конечно, вызвала кучу эмоций. Разной степени обоснованности. :-) По мере возможности и желания не перегружать online программистской проблематикой буду отвечать на письма по этому поводу. Сегодня - первое.

   
From: Victor Poznyak
Subject: Цитата от 22-Dec-98: "Exceptions, только exceptions"

Привет, Дмитрий!

Не все так однозначно. Вот например нужна функция выбора элемента из массива. Пишем: x = array[i]; Здесь конечно "Exceptions, только exceptions". Но вот иногда надо проверять - а есть ли такой элемент, и тогда код возврата гораздо удобнее. Что-то не нравиться мне конструкция типа:

found = true;
try {
	x = array[i];
} catch(...) {
	found = false;
}
if( found) printf( "Yes, we did it!\n" );

вместо одной строчки:

if( isEmpty(x = array[i]) ) printf( "OOP - suxx! GOTO - rulezz\n" );

или вот недавно, вставляю строчки в базу оракловскую:

for( первый элемент списка; есть еще элементы; взять слудующий )
{
if( вставить_в_базу( элемент_списка ) == error )
printf("описание ошибок в данных: жопа стряслась\n" );
}

ну и как сюда вставить "Exceptions, только exceptions"? Все остальные вызовы оракловские (логин, создание курсора и т.п.) хорошо обернуть exceptions, это да. А вот этот - нет.

Если ловить различные классы exceptions, то что делать после ошибки вставки? продолжать цикл? Но тогда получается, что управление скакнуло туда-сюда в рамках одной процедуры. Чем не гоуто и спагетти-программ.

Всегда с интересом читающий DZ-online (начиная с фидошных выпусков),
Виктор Позняк.

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

Начну с "обернуть". Вообще как только что-то требуется оборачивать для совместимости с ОО, начинается нервотрепка и геморрой. Потому я так и радуюсь поползновениям типа BeOS-овского ОО-интерфейса, что они избавляют от оборачивания, в меру возможности. У них есть минусы, безусловно, но ОО должно быть именно таким - повсеместным. Когда нижний уровень - плоский, строить на нем ОО-программу бывает настолько неприятно, что иногда кажется, что чёрт бы с этим ОО, не до жиру.

Это все известно, и когда я говорю "Exceptions, только exceptions", я имею в виду именно это - только exceptions, от самой первой строки до самой последней. Никаких плоских API и старого процедурного хлама. Тогда все будет чистенько и, по крайней мере, дурацких проблем нестыковки концепций не будет. Будут другие :-), но это уже и другой уровень, один только переход на который кой-чем окупается. Как правило. :-)

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

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

Самый смешной известный мне результат неследования этому принципу - технология ФИДО, где обратный адрес письма берут из поля MSGID (которое предназначено для хранения уникального идентификатора письма), а уникальность письма вычисляется по полю FROM (котоое, по идее, для обратного адреса). Результат - ненадежность результата обоих действий.

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

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

Таким образом фраза "код возврата гораздо удобнее исключения" просто неправомерна. Это все равно, что "сказать человеку "Вася тут не живет" - гораздо удобнее, чем выкинуть его в окно, повесив на задницу записку "Вася тут не живет". Не удобнее, а единственно возможно! Если он, конечно, не в восьмой раз с тем же самым вопросом приходит. :-)

try {
    if( array.element_exist(i) )
        {
	x = array[i];
        printf("We did it!\n");
        }
} catch(...) {
    printf("Something wrong with array - can't access it!\n");
}

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

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

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

Главный принцип проверки удачности модели исключений - после перехода на них кода должно стать меньше, он должен стать понятнее и сами исключения (кидалки и ловушки) не должны составлять даже процента кода.

В проектах размером порядка 50000 строк достижимость я проверил практически, больше не пробовал - по приколу, для проверки идеи больше 50К накатать - я не маньяк. :-)