Что общего между велосипедом и вечным двигателем?
Wednesday, 12 Dec 2001
Размножение сущностей
Как все недоучки, я учился программировать непосредственно на первом заказе. Не могу с уверенностью сказать, что я чему-то научился; тем не менее, путь наименьшего сопротивления прельстил меня полностью. Разумеется, я выбрал Borland Delphi в качестве инструмента разработки. Алгоритмизацией я баловался с пятого класса средней школы, алгоритм Эвклида на фортране был написан и даже — успешно отлажен на EC-1080. Если я ничего не путаю. Перфокарты с итоговым вариантом я бережно храню до сих пор. Впрочем, я отвлекся.
Пугало меня создание пользовательского интерфейса. Формочки, кнопочки, менюшки, тулбарчики. Я совершенно не представлял себе, с какой стороны можно ко всему этому подойти. Поэтому я выбрал — Delphi. Втуне надеясь, что грамотный RAD решит за меня все проблемы, связанные с созданием окошечек и прочих мулечек. Это была, если не ошибаюсь, вторая версия.
Достаточно быстро справившись с алгоритмизацией, я занялся проектированием интерфейса. Потырил нехитрым способом (Alt+PrintScreen) иконки из какого-то Microsoft’овского монстра и открыл редактор форм. Я собирался следовать рекомендациям профессионалов, поэтому потратил некоторое время на тщательное дублирование пунктов меню — кнопками в тулбаре. Многие помнят, как в первых версиях Delphi был реализован интерфейс добавления событий. Выбираешь кнопочку, либо пункт меню, щелкаешь по ней дважды — и кусочек кода обработчика события нажатия кнопки готов. По неопытности (ну да, вообще-то — поглупости) я старался вносить минимальные исправления в сгенерированный код. Одним из наиболее свежих моих воспоминаний на тот момент была попытка реанимации редактора форм в MS Visual Studio после ручной правки нагенерированного мастером шаблонов мусора. И я старательно эксплуатировал великую технологию — написав код обработчика нажатия кнопки, я копировал его в обработчик соответствующего пункта меню. Я надеюсь, не нужно объяснять,чем чреват такой подход.
Я, очевидно, был не единственный в когорте недоумков, плодивших сущности такого толка. Иначе сложно объяснить появление эзотерических объектов типа в последующих версиях Delphi. Разработчики ввели лишнюю, по сути, сущность — намеренно создав узкое место для нерадивых программистов. Допустить ошибку рассинхронизации кода обработки кнопок и меню стало гораздо сложнее.
Один на один!
Вообще говоря, тема корректного позиционирования событий относительно оси действий пользователя — очень больной вопрос для многих программистов. Самый, пожалуй, яркий пример здесь — элемент управления типа CheckBox, отражающий состояния бинарного типа (да/нет). Я сделал десятки глупейших ошибок в коде, заводя дополнительную переменную для хранения самого значения. Ведь контент должен быть отделен от оформления, не так ли? Так, да не совсем. Стандартными средствами языков Pascal и C++, к великому сожалению, не обеспечить безопасное разделение. Заведите переменную, отдельно от флажка на форме — и через неделю показания флажка и значения переменной рассинхронизуются в какой-нибудь экзотической ситуации.
Хорошая новость: средствами Java — обеспечить механизм разделения можно. Я часто говорю, что одним из основных преимуществ этого языка я считаю модель Listener’ов. Все до безобразия просто — нажатие мышкой на флажок напрямую меняет значение внутренней переменной; сам флажок — регистрируется «слушателем» и получает извещения обо всех изменениях, происходящих с переменной, будь то скрытая установка значения из кода, чтение из файла, или даже щелчок по другому связанному с переменной флажку в соседнем окне.
Сплошное торжество здравого смысла — теперь у нас есть одна переменная, сколько угодно ее визуальных представлений; вдобавок мы практически застрахованы от рассинхронизации. Можно провозгласить какой-нибудь лозунг и со спокойной совестью отправиться на обед.
Сущность описывающая живущий во времени объект — это Persistent-класс, подключающий Listener’ы. Сущность описывающая моментальное действие — это Listener-класс, как правило — имеющий визуализатор.
Разумеется, оба класса должны уметь каскадно встраиваться друг в друга (объекты обоих типов могут содержать объекты первого типа в соотношении«one-to-many», при этом первый тип должен уметь вызывать соответствующие Listener’ы на сыновьях, а второй — при случае корректно отрисовать не только себя, но и всех дочерей).
Великие изобретатели.
Именно из вышеизложенных соображений я всегда предпочитаю воспользоваться третьесторонней библиотекой, а не писать свою. При условии, что мне знакомо имя производителя этой библиотеки, проект развивается и есть возможность его протестировать. Даже, если эта библиотека не охватывает всех моих нужд. Причина проста: я буду выступать Listener’ом у той компании, я буду просто немного адаптировать свой код в соответствии с развитием библиотеки. Если сейчас кажется, что переписать эту хрень — дело двух рабочих дней, то завтра ситуация неизбежно изменится. И я столкнусь с необходимостью поддерживать свою программу и библиотеку. Помните, раньше каждый считал своим долгом написать собственную программу инсталляции? Тех, кто поддался этому соблазну и не пошел «на поводу» у славных ребят из Wise и/или InstallShield — с выходом каждой очередной версии Windows — ждут бессонные ночи и расшатанные нервы.
Поэтому я, скрепя сердце, пользуюсь стандартными элементами управления, стандартными средствами визуализации, стандартной формой окон и стандартной маркой сигарет. По крайней мере, при таком раскладе мне не придется рвать наголове волосы, когда разработчики Longhorn’а скажут: «с сегодняшнегодня все окна нужно делать круглыми».
NB! Следующий абзац на данный момент устарел :-( Последний пример, который мне хочется привести — касается поиска по сайту.Я его недавно прикручивал. И понял вот что: не нужно поддаваться соблазну и,например, парсить ответ Google, чтобы показать результаты в том же стиле, вкотором оформлен сайт. Я не хочу оказаться у разбитого корыта, и даже не узнатьоб этом (а я — ага, — достаточно редко хожу к себе на сайт), когда разработчики этой прекрасной во всех отношениях поисковой машины по ту сторону океана решат оснастить страницу дополнительным тегом. Кроме того, я не хочу скрывать, что поиск по моему сайту за меня выполняет Google. Я им признателен и вообще. Поэтому я сделал вот как:
form name="googlesearch" method="get"
action="http://www.google.com/search"
onSubmit="if (q.value == '') return false;
q.value = q.value + ' site:www.matiouchkine.de';
return true;"
Потратив на это две минуты и будучи абсолютно уверенным, что меня не ждут неприятные неожиданности в будущем.
И да, я знаю про Google APIs. Только вот нужна ли мне эта пушка для стрельбы по редкозалетающим воробьям? Мне кажется, нет.
А сэкономленное таким нехитрым способом время я потратил на написание этой статейки.
Все стремятся изобрести велосипед и вечный двигатель.