28 октября 2008 г.

S?XBuilder

Today I've seen quite amazing exception: java.net.ConnectException: Connection timed out: connect at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195) ... ... ... at org.jdom.input.SAXBuilder.build(SAXBuilder.java:489) at org.jdom.input.SAXBuilder.build(SAXBuilder.java:888) at asg.newsbook.XHtmlToolkit.createDocument(XHtmlToolkit.java:61) ... ... ... (deep from Jasper engine) I've simply called org.jdom.input.SAXBuilder.build(String). I expected this thing to simply parse the damn string into Document, I could expect that it'll throw an exception about invalidity of the document, whatever. No. Software gets so complicated. SAXBuilder decided for whatever reason (here I'm guilty, of course), that it must connect with W3C and download the XSD, or DTD, whatever it needed. And for my each document it sent a web request. Thus slowing down the application a factor of hundreds, accidentally throwing exceptions like the one above, when W3C was too busy. Soo.. Decide for yourself, is this behavior sexy. I think it is. Today I've had enough sex debugging that application. Easy as it was to believe that SAXParser really sux, I'm full of respect of this quite intelligent thing.

12 августа 2008 г.

Usability match: Nokia vs. Sony Ericsson

Кое-что на эту тему я уже писал.

Попробую вообразить, что я Лебедев (или Joel Spolsky; ум, эхм, лучше уж Лебедев :-) и написать, что я ненавижу.
Я ненавижу пользовательский интерфейс „умных“ мобильных телефонов Nokia. (и еще компьютерные мыши).
Но, кажется, я еще „немного“ не дорос до великих гуру юзабилити, так что — остаюсь AnSGri и попытаюсь сравнить интерфейсы мобильных устройств от крупнейших производителей со всем цинизмом и объективизмом.

Прежде всего, условимся, что речь идет о многофункциональных мобильных устройствах, а не просто о телефонах (предпочту не употреблять слово «смартфон», так как SE K700i обычно смартфоном не считают, а именно про аппараты такого класса пойдет речь).

Придумаем «летчика-испытателя», за которым мы будем наблюдать и из неудач которого будем делать выводы об ошибках дизайнера. Говорят, что по себе людей не судят, но ввиду отсутствия под рукой настолько же хорошо известного человеческого организма нарушим это правило. Только будем вести себя немного (намного?) глупее, чем обычно: в таких случаях это полезно.
Итак, перед нами обычный студент, неплохо разбирающийся в компьютерах, не боящийся техники и посвященный в то, что лучший пользовательский интерфейс незаметен. Ну и как любой нормальный человек, он терпеть не может дурацких вопросов.

Первый раунд. Пользователь впервые в жизни видит устройство. Коробка распакована, SIM установлен, нажата кнопка включения. Nokia просто включается. Он набирает номер, и — замечает кнопку с изображением зеленой телефонной трубки. Очевидно, «позвонить». И правда, работает. Точно так же, как и кнопка с красной перечеркнутой трубкой успешно завершает вызов. Sony Ericsson включается, запуская Мастер настройки, который позволяет настроить язык, время и даже, может быть, запросить настройки интернета у оператора. Замечательно! Но тут появляется странная страница, на которой нас, по всей видимости пытаются чему-то научить. «Как так! Какое-то устройство вздумало меня учить!» Но возмущение вскоре спадает: там изображена кнопка «назад», и пользователь запоминает, что у устройства есть такая клавиша. Настройка завершена, он набирает номер — и видит, что над левой софт-клавишей написано «вызвать». Тут все гладко. Во время вызова над правой софт-клавишей загорается сначала «отмена», затем «отбой». Тут тоже все ясно, и не перепутаешь. Первый раунд окончен со счетом 1:1.

Второй раунд. SMS. Подопытный, пользуясь подсказками над софт-клавишами, добрался по меню до пункта «Новое сообщение», и тут начинается другой вид деятельности — набор текста. Пользователь имеет общие представления и о T9, и о посимвольном наборе, но ранее не очень много ими пользовался, чаще имея дело с полноразмерной клавиатурой своего ПК. Допустим, он хочет набрать «Привет! Я себе мобилу Nokiaкупил». В этом простеньком сообщении аж целых две «коряги» — восклицательный знак и смена языка. Потыкав всякие кнопочки, можно найти, что под «звездочкой» скрывается меню ввода символов, которое решает задачу. А вот со сменой языка проблема. Если и можно догадаться, что удерживание решетки переключает способ ввода, то можно предположить, что переключение языка скрыто там же. Ан нет! И пользователь, уже изрядно наматерившись, прибегает к последнему средству — инструкции. И знаете что? Он не находит ответа на свой вопрос. Настроение испорчено, и в отправленном сообщении говорится «Ну и г*о же эта Нокия!». Тогда как второй экземпляр пользователя успешно пишет «Sony как всегда сделала отличное устройство!», потому что над правой софт-клавишей написано «Функции», и при ее нажатии вылезает столь привычное контекстное меню, в котором есть и вставка символа, и смена языка, и все что угодно. А все потому, что кнопка «Назад» уже есть, и не занимает драгоценную софт-клавишу. Ах да, я совсем забыл про третью «корягу» — исправление опечаток. У Nokia для этого как раз служит правая софт-клавиша. У SE по-другому — для удаления служит кнопка «C». С логичностью такого решения можно поспорить, но лично я с первого взгляда понял, что она обозначает «Clear», то есть — удалить. 2:1 в пользу SE, а точнее, против Nokia. Хотя, мне кажется, кто-то сочтет это нокаутирующим ударом.

Третий раунд. Power Usage. Итак, с двумя основными функциями разобрались, но не за них мы платим большую часть стоимости, а за поддержку приложений, наличие камеры, органайзера, медиаплеера и прочее. Честно скажу, не слишком много с нокиевскими устройствами общался, однако первые впечатления не лучшие. Задам вам лишь один вопрос, на который, однако, нормальный человек редко ответить в состоянии: что делает кнопка с изображением телефонной трубки в режиме фотокамеры? Я не знаю, но кажется, что на самом деле она ничего не делает. Что ж, хотя бы ничего плохого... Как сказать. У Sony Ericsson, как можно догадаться из предыдущего раунда, управление подобно управлению компьютером с помощью двухкнопочной мыши. Левая софт-клавиша или щелчок джойстика — действие по умолчанию, типа «Открыть», «Сохранить», «Позвонить». Правая же в большинстве случаев открывает самое настоящее контекстное меню. При этом кнопка «Назад» возвращает нас ровно на один шаг назад, всегда и везде, а кнопка «C» обозначает удаление объекта под курсором, если это возможно. Я уж не говорю про кнопку «Alt-Tab», переключающую приложения или открывающую подобие меню «Пуск», появляющуюся на последних моделях. 3:1, хотя по мне так и нокаут.

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

9 августа 2008 г.

ООП как создание предприятия

Недавно я писал об опасности излишней "объектаризации" (или объективизации?..) и провел аналогию между написанием программы и управлением предприятием. Сейчас давайте рассмотрим эту аналогию поподробнее.

Прежде всего, условимся считать объектом рабочего либо механизм. В большинстве случаев особой разницы нет, потому что в современном производстве мало задач, с которыми бы не справился робот конечной сложности. Какую-нибудь узкоспециализированную утилиту, типа юниксовой ls можно считать монолитным инструментом, упрощающим отдельную задачу. И когда мы пишем "ls | sort", мы просто последовательно применяем два разных инструмента, как последовательно применяем зубило и напильник при обработке куска металла.
Пока мы можем без труда справиться с некоторой задачей в одиночку, не имеет смысла разделять эту задачу на объекты. Так, можно без посторонней помощи, последовательным применением пилы, рубанка, наждачной шкурки и молотка с гвоздями можно смастерить, скажем, табуретку. Но мы хотим не просто табуретку, мы хотим красивую табуретку, которая не будет портить наш интерьер своей угловатостью, а напротив, будет радовать глаз. И появляется идея пригласить резчика и художника, чтобы они украсили наше произведение. (И что-то мне это уже напоминает: табуретка с двумя декораторами...)

Потом мы вдруг осознаем, что на наши резные-расписные табуретки есть спрос - и вместе с теми же резчиком и художником открываем фирму по производству табуреток. И дела идут хорошо, так что мы решаем расширить ассортимент продукции и в дополнение к табуреткам производить резные-расписные столики. Но у главного и единственного нашего плотника почему-то не выходит производство столов, хотя стол с виду и похож на табуретку. Так что мы нанимаем человека, умеющего делать столы - экземпляры другого подкласса класса мебель. И вот у нас уже полноценная мебельная мануфактура (коли уж производство нисколько не автоматизировано, но разделение труда налицо). Долго ли, коротко ли, но вот мы уже владеем небольшим заводом по производству резной да расписной мебели. Завод состоит из трех цехов - сборочного, художественного и цеха художественной резьбы.
Но мы кое-что забыли - транспортный отдел. Ведь завод производит много продукции, а значит требует поставок больших объемов сырья. И поэтому мы заключили контракт с транспортной фирмой, которая раз в неделю на больших грузовиках будет привозить нам доски и краску. А также арендуем склад, чтобы сохранять готовую продукцию до приезда заказчика. А поскольку дела идут хорошо, появляются деньги на механизацию производства - как минимум ручные рубанки заменить электрическими. И вот у нас уже фабрика: рабочих немало, да и труд не только ручной.

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

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

6 августа 2008 г.

ООП навязывает управленческий образ мышления

... причем в худшем его проявлении - в стремлении переложить всю работу на подчиненных и нежелании делать ничего самому. Беда в том, что в результате самому работать приходится еще больше.
Например, недавно мне пришлось писать модуль вычисления выражений (короче, калькулятор, считающий "a + 2px * sqrt(2) - 3.0em") на C#. В этом языке нет ничего, кроме объектов. Поэтому я, недолго думая, создал классы Лексема, Выражение, Оператор и т. п. И оказался в глубокой задумчивости: а какие же "приказы" им раздать, чтобы они сами все сделали?
Здесь полезно обратиться к аналогии между ООП и управлением предприятием, где каждый объект - это работник, а программист (ну или разработчик) олицетворяет высшее руководство. (Можно еще добавить, что операционная система - это государство, а аппаратура - это сама природа).

Итак, как же мы бы организовали вычисление выражения на предприятии? В нашем изначальном "объектном" варианте задействована толпа служащих - числа, операторы, функции, единицы измерения и т. д. И я не завидую тому менеджеру, которому предстоит давать указания всем этим людям (читай - написать программу взаимодействия всем этим объектам). А как бы вы поступили на месте этого несчастного менеджера? Моим ответом было "написать значение на лбу у каждого, выстроить в ряд и посчитать все самому". Потому что это несравненно проще, чем объяснять каждому правила поведения в нашем выдуманном мире. Так зачем же нам живые люди (объекты)? Нам и мертвые сгодятся! (пассивные структуры). Или, еще лучше, собрать механизм, который, в отличие от мертвых людей, не разлагается. (Написать единый модуль в структурном стиле). Ну или нанять квалифицированного специалиста (купить готовую библиотеку, решающую нашу задачу).

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

1 августа 2008 г.

Проект: SmartEdit Control

Недавно мне пришлось работать с замечательным графическим редактором CorelDraw. Это не просто чрезвычайно мощный инструмент для работы с векторной графикой, в том числе и инженерной, но и просто очень качественно выполненный программный продукт. Об этом говорит следующая маленькая и, я подозреваю, мало кому известная деталь: почти все текстовые поля для ввода чисел (длина, координаты, ...) понимают арифметические выражения и единицы измерения. То есть, если вы хотите сдвинуть объект на 5 мм, вы щелкаете по полю и дописываете "+ 5mm". И все работает! Несмотря на то, что исходное значение дано в дюймах. В Photoshop, насколько я знаю, тоже нечто подобное реализовано.
А вот в Microsoft Office Word, когда нужно сделать ровно двадцатимиллиметровый текст, приходится отвлекаться от работы и вычислять "20.0 / 25.4 * 72". Мелочь, конечно, а неприятно. Именно из таких маленьких разочарований и складывается плохое настроение. Компьютеры давно уже существенно более мощные, чем необходимо, но почему-то калькулятор под рукой держать все еще приходится ("покажите мне удобную программу-калькулятор!").

Это я к тому, что подобная функциональность нужна везде, где от пользователя требуется ввод чисел, особенно имеющих размерность. Так же как и каждый второй список нуждается в естественной, а не алфавитной, сортировке.
Так что сделаю-ка я .NET-компонент, совмещающий удобство TextField-а для программиста с удобством для пользователя.

А пока я ухожу в гугл. Вдруг есть уже такое в этом мире?

24 июля 2008 г.

История одного проекта 3

Внимание!
Не пытайтесь повторить это самостоятельно!

...потому что лучше пару раз почесать затылок, склонившись над листом бумаги, и сразу увидеть Корень Зла. Иначе он обовьет ваше несчастное тело быстрее, чем вы что-то сможете сделать. И вам придется долго и упорно грызть это корневище, чтобы, наконец, выбратся из этого персонального ада.
А корень этот на вкус напоминает кусок гнилого кода.. Чем, собственно, он и является.

Хотя мне, наверное, следовало бы предупредить вас в самом начале, потому что сейчас речь пойдет о банальнейших проблемах производительности.
Итак, в прошлый раз мы построили интерфейс, представляющий текстовое поле в виде бесконечного прямоугольного массива символов. Так что можно идти переопределять процедуру прорисовки окна. Так, а раз достаточно просто перерисовать каждый отдельный символ, то почему бы при перерисовке просто не вызвать m*n раз процедуру, рисующую один-единственный символ? А теперь объявим эту процедуру абстрактной. Отлично, теперь мы имеем довольно общий шаблон редактора, который всего лишь надо параметризовать процедурой прорисовки. То есть теперь, в принципе, есть на что посмотреть! Да, мерзко писать код, не имея возможности запустить его и посмотреть, что получится. И мы порождаем подкласс, назовем его ColorApxEd, который просто рисует цветные буковки на цветном фоне:
Отлично, все работает! Но так не бывает. Этот скриншот был сделан намного позже. Вначале, конечно же, ничего не работало. Но мало-помалу смертельные баги были раздавлены, и на свет явился очень мерзкий и живучий таракан.

Дело в том, что (1) при нажатии любой клавиши перерисовывалось все окно, и (2) при перерисовке текст мелькал. "Приехали".
Что ж, лучше поздно, чем никогда, наконец, взяться за ум. Тут-то я и узнал, что же такое двойная буферизация. А также понял, что прорисовку необходимо выполнять с умом - ровно то, что нужно, и ничего более. Еще одна неделя работы. Двойную буферизацию я прикрутил быстро, и все потихоньку начало работать.
И можно было, наконец, писать градиентную подсветку.

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

Но через два года, этим летом, я решил покопаться в старых наработках. И наткнулся на APXN. И ужасно удивился, что "почти всё почти работает". К тому же, на новом компьютере скорость перерисовки была вполне приемлемой. Кстати, новый компьютер с первого взгляда и помедленнее должен быть - 1600 MHz против старых 2400. Вот что значит Intel Core Duo, даже и не "2", да и программа многопоточность не использует.
И я просто занялся шлифовкой того, что было. Решил сделать "конфетку" из "будто бы и непригодного материала". И если раньше я пытался в нем что-то написать, и инстинктивно пытался Ctrl+прыгать по тексту, а также тыкать Ctrl+Del, и оно не работало, и я тут же проклинал эту гадость и возвращался к Notepad++, то после того, как я реализовал полный спектр клавиатурных команд, стало можно с ним работать! Вроде мелочь, а ведь именно из мелочей складывается настроение. А еще я поленился прикручивать поддержку одновременного открытия нескольких файлов, но заменил это кое-чем, не встречающимся в большинстве "блокнотов" - программа запоминает состояние (позицию прокрутки, каретку, закладки...) для каждого файла. Заодно вынуждает почаще сохраняться (в пику проклятому n++, не раз терявшему бесценные байты при неожиданной смерти системы :)
Теперь я уверовал в истинную силу юзабилити, когда пара строк кода просто делает работу возможной. А еще пара строк - приятной.


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

21 июля 2008 г.

История одного проекта 2

Итак, ранее я познакомил вас со своей дурной идеей, пришло время перейти к тому, как все это было реализовано.
Как я уже говорил, раз уж я решил ограничится моноширинными шрифтами, то вся рабочая область редактора может быть представлена прямоугольным двумерным массивом символов. Такой взгляд на текст чрезвычайно удобен с точки зрения прорисовки. Действительно, определили, какая часть этого прямоугольника видна на экране - и перерисовываем подряд все клетки. С другой стороны, мы имеем дело с текстом, а при работе с текстом крайне удобно иметь, кроме адресации "строка-столбец", еще и последовательную адресацию. К тому же, хранить текст в прямоугольном массиве крайне нерационально.
Поскольку все мои мысли были заняты именно графикой, то я решил хранить текст в виде списка строк. На языке Си это можно представить так:

struct ApxString {
    char *chars; // строка символов
    short *styles; // строка стилей символов
    size_t size; // выделенная длина строк
    size_t length; // длина текста в строке
} buffer[]; // сам буфер в виде масива строк
size_t bufsize; // размер буфера
Возможно, именно в этом заключалась моя главная ошибка. Ведь для работы с этой структурой совершенно невозможно было использовать никакие библиотечные функции, хотя бы потому, что необходимо было параллельно каждой манипуляции со строкой символов делать то же со строкой стилей (которые еще short по давно забытой причине, хотя char'а бы вполне хватило).
Первым делом я решил абстрагироваться от тонкостей управления памятью. Это было достигнуто введением свойств CharAt[Row, Col], StyleAt[Row, Col] и RowLengths[Row, Col]>, которые, соответственно, позволяют прочитать или установить символ, стиль или использованную длину строки. Причем эти свойства ведут себя корректно при любых значениях параметров, автоматически перераспределяя память, если необходимо, и игнорируя отрицательные значения. Если символ не определен, то возвращается #0, если стиль не определен - возвращается стиль конца строки. Полная иллюзия бесконечного прямоугольного массива символов и стилей. Конечно, во всякой нетривиальной абстракции есть дыры. В данном случае дыра - это ограниченность памяти. Но я решил пренебречь этим ограничением, поскольку мегабайт текста в этой структуре будет занимать порядка 10MB: по 3 байта на символ, плюс 8 байт на длины, плюс запас на округление длины каждой строки вверх, скажем, до 20 символов. Так что все действительно не так уж страшно.
Осталось построить интерфейс для доступа тексту как к одной строке. Для этого я просто написал функции преобразования индексов - из двумерных в одномерный и обратно. Теперь для доступа к n-му символу нужно написать что-то вроде CharAt[IndexToPos(n)].

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

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

Теперь, когда появились высокоуровневые средства манипуляции текстом, можно строить слой обработки действий пользователя. Фактически вся работа делается в обработчиках KeyDown и KeyPress, первый из которых вызывается для всех клавиш, а второй - для символьных и некоторых командных (например, я очень удивился, когда узнал, что Ctrl+A - на самом деле символ с кодом 1).
Вот тут писать пришлось много. Вот лишь неполный список того, на что должно реагировать уважающее себя текстовое поле:

  • символьные клавиши
  • Enter
  • Delete и Backspace
  • PageUp/PageDown
  • Стрелки
  • Ctrl+Delete и Ctrl+Backspace
  • Ctrl+Стрелки
Некоторые из этих команд настолько естественны, что их наличие даже не осознаешь. Например, Ctrl+Backspace. Естественно, когда я начал пользоваться собственным редактором, тут же выявил кучу недоделок. Eat your own dog food!.

А как же градиентная прорисовка, из-за которой, собственно, все и затевалось? Об этом чуть позже.

19 июля 2008 г.

История одного проекта 1

Хочу поделиться с вами частью своего небольшого опыта разработки ПО. А именно, расскажу вам историю реализации одной бредовой идеи, посетившей меня в конце 11 класса, когда я еще не осознавал, насколько это сложно - создавать законченный программный продукт.
(Сам "продукт" в скором времени будет доступен в открытых исходниках).
В то время я немного увлекался компьютерной графикой, а также потихоньку делал программку для защиты на экзамене по информатике (тогда я и начал понимать, что такое законченный программный продукт). Программка та не представляет никакого интереса даже для меня, важны те условия, в которых я ее создавал - Borland Delphi 7 с ее весьма своеобразным редактором кода. Я очень долго ковырялся в цветах подсветки синтаксиса и как-то раз мне в голову пришла идея.
"А почему бы не сделать такую подсветку, где цвет фона текста меняется не резко, а плавно? Ведь на это же, наверное, намного приятней смотреть!"
И я решил сделать компонент, который предоставлял бы такую подсветку.

И тут же возникла первая проблема. Готового текстового редактора, который позволил бы управлять прорисовкой своего фона, у меня не было. Как присобачить подсветку синтаксиса к обычному текстовому полю, я тогда еще не знал (впрочем, и сейчас я знаю, что это нехорошо). А в интернете поискать не догадался, верите ли.
Так что я принял решение написать редактор с нуля. С абсолютного делфионского нуля, точнее, с TCustomControl'а, который всего лишь предоставляет окно и поверхность для рисования. Естественно, образцом для подражания был пресловутый делфионский редактор.
Что ж, дурному коту, как и бешеной собаке, семь верст не крюк - я принялся за работу.

Задумывались ли вы когда-нибудь, как устроено обыкновенное текстовое поле, такое как в Блокноте? Скорее всего да, поскольку если вас не отпугнуло начало моего рассказа, то, наверное, вы знакомы с компьютером если не на уровне "физиолога", то на уровне "терапевта" уж точно. И я рад за вас, если этот "простенький механизм" для вас действительно простенький. Мне он таковым не кажется до сих пор.
А мне предстояло реализовать нечто подобное самому, от начала и до конца. Странно, но я не испугался. "Меньше знаешь - крепче спишь". Ведь и Линус Торвальдс, как он пишет в своей книге "Just For Fun", признается, что если бы он заранее знал, сколько работы ему предстоит проделать, врядли бы взялся за свой проект. Впрочем, у незнания всегда есть и негативные последствия, причем, к сожалению, они обычно преобладают.

Но вернемся к нашим баранам.
Целью было создание VCL-компонента, аналогичного делфионскому редактору кода, с подсветкой синтаксиса, свободной кареткой и т.д., отличающегося "революционным" графическим дизайном. А также, разумеется, создание простенького редактора на основе этого компонента. Целью не являлось создание редактора общего назначения, а лишь редактора кода. Целевая аудитория - все, кому надоело писать ad hoc программки в "блокноте", и кто, к тому же, любит вещицы с переподвыпердовертом. (Такие как я :)
Раз уж я делаю редактор кода, то можно ограничиться моноширинными шрифтами. А следовательно - просто разбить компонент на прямоугольные ячейки одинакового размера. Это во много раз упрощает задачу.
Остается лишь реализовать "текстовый" интерфейс к этой прямоугольной решетке и должным образом редактировать решетку при нажатии клавиш. Всё!

А вот о том, что же я сделал, и почему это неправильно, я напишу завтра.

15 июля 2008 г.

Два подхода к разрешению неоднозначностей

Сегодня меня попросили разобраться с весьма странной проблемой: мобильный телефон при входящем вызове напрочь отказывался показывать имя, соответствующее номеру в телефонной книжке. Совершенно непонятно было, чем такое может быть вызвано. Оказалось, что проблемы возникли из-за повторяющихся номеров в книжке - когда поступал вызов, телефон отказывался решать, какое же из имен показывать, и не показывал имени вообще. Назовем подобное поведение "политикой Nokia". А "политикой Sony Ericsson" назовем выбор первого попавшегося имени.

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

АспектNokiaSony Ericsson
Мотивация Пользователь умнее машины, и только ему должно принадлежать право принимать окончательное решение. У машины достаточно данных, чтобы избавить пользователя от лишней головной боли.
Что делаем? Либо отказываемся выполнять противоречивое указание, требуя более корректной команды, либо запрашиваем уточнение. Разрешаем противоречие, используя имеющиеся данные и немного машинного здравого смысла ;)
Достоинства У пользователя есть возможность исправить команду и получить корректный результат. Система ведет себя предсказуемо, и пользователь не испытывает дискомфорта из-за того, что кто-то пытается его перехитрить. Пользователь экономит кучу времени на ответах на тривиальные или, того хуже, несущественные, вопросы.
Недостатки Пользователя порой отвлекают по пустякам, что не может не раздражать. Одна секунда, потраченная на ответ на возникший из ниоткуда дурацкий вопрос, типа "Установить критические обновления?" может стоить 15 минут рабочего времени из-за потери концентрации. Автоматика может натворить чего-нибудь нехорошее (например, повесить систему в ходе фоновой установки этих самых критических обновлений). Кроме того, многим может не понравиться, что компьютер вообразил себя умнее них.

Отсюда сразу видны приблизительные границы применимости этих подходов. Ясное дело, если от принятого решения зависит что-то "материальное" (например возможность перевести деньги не на тот счет), лагерь Nokia имеет право бесконечно долго пытать пользователя, заставляя убрать весь "мусор" из окна ввода номера счета, вроде лишних букв; тогда как решение об отображении хоть какой-нибудь подсказки о том, кто вам звонит посреди ночи, в любом случае лучше, чем не сказать ничего кроме номера (особенно если вы, так же как и я, не помните ни одного телефонного номера).
Что же касается вышеупомянутой установки критических обновлений - я вполне согласен с наличием закопанной в настройках опции "автоматически устанавливать". Тут скорее дело вкуса.


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

14 июля 2008 г.

Антистандартизация: еще один болт

Сколько видов шлицев на болтах вы знаете? Всякий, кто брал в руки отвертку, скажет, что они бывают плоские и крестовые. И на протяжении десятилетий, имея небольшой наборчик из десятка отверток, можно было завинтить любой болт! Но все в мире меняется...
Немного покопавшись в Сети, легко находим следующую информацию (источник; кстати, на том же сайте рассказывается о происхождении крестообразного шлица):

Сегодня в практике наиболее широко встречаются следующие виды шлицев: Прямой; Крестообразный типа Phillips (согласно стандартам DIN - крестообразный типа Н); Крестообразный типа Pozidriv (согласно стандартам DIN - крестообразный типа Z); Комбинированный типа Pozidriv + прямой; Шестиконечная звезда типа Тоrх; Внутренний шестигранник; Шестигранный.

И только за последние 3 дня я повидал 5 видов шлицев, двух из которых в этом списке нет, а именно, фирменный "трехгранный" Nokia и, о ужас, подобие ставшей уже обычной шестиконечной звезды, но со штырем внутри, так что нужна полая отвертка. Которой, ясное дело, ни у кого нет. Я было хотел нарисовать чертеж этого творения Ада, но прокопавшись по 20 минут с Expression Design и Inkscape, понял, что лучше мне этого не делать :-[

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

  1. Новая форма шлица ускоряет производство;
  2. Новая форма шлица затрудняет разбор не предназначенного для того изделия "криворуким пользователем" (своего рода обфускация)
У креста есть некоторые преимущества перед плоским шлицем, равно как и у звездочки и шестигранника - перед крестом (существенно труднее сорвать шлиц). При этом пока еще не у каждого дома лежит набор "звездочек". Так что заодно "защищаемся от дурака". Тогда как ужасная "звезда-со-штырем" явно не дает технологического преимущества, зато... впрочем, истинного "энтузиаста" ничто не способно защитить от удара током.
А самое смешное, что вышеупомянутый болт был применен на элементарнейшем устройстве - нагревателе для детского питания, который любой мужик без труда отремонтирует. Если бы не этот корень зла.
Так что налицо признание безрукости пользователей во всех областях.
И это весьма печально.

Beginning of The Construction

Приветствую всех на этой пустынной странице! Я наконец-то собрался с силами (к сожалению, не с мыслями) и, следуя совету Джефа Этвуда (Jeff Atwood), завел блог. Захотелось потренироваться в написании статей, потому что хороший разработчик должен уметь писать. Посему любая критика "категорически приветствуется". Придирайтесь на здоровье!
Чтобы вам не было совсем скучно, я заготовил несколько ссылок, чтобы вы легко могли сбежать отсюда куда-нибудь поинтереснее :) Joel on Software - Joel Spolsky пишет о всех аспектах разработки ПО (типа shrinkwrap). Coding Horror - Programming and human factors by Jeff Atwood The Old New Thing - Известнейший разработчик Microsoft Реймонд Чен (Raymond Chen) об истории развития Windows API, а также о многом другом, например, о вьетнамских сэндвичах. Ну все, хватит о разработке ПО. Кстати, похоже, что это будет основной темой блога... Сайт Кори Доктороу, того самого писателя-фантаста, который написал Землю Сисадминов.
Ах да, я забыл представиться. Антон Григорьев, студент МФТИ, mailto: ansgri at gmail dot com See ya!