Искусство программирования для Unix
Шрифт:
Фактически опыт работы со статистическими фильтрами показывает, что отдельный используемый самообучающийся алгоритм гораздо менее важен, чем качество наборов данных спам/неспам, на основе которых алгоритм вычисляет весовые коэффициенты. Поэтому результаты статистических фильтров действительно больше определяются моделью данных, чем алгоритмом.
Статья "A Plan for Spam" была ошеломляющей новостью, поскольку ее автор убедительно доказал, что простой, даже грубый статистический подход дает меньшее количество принятых за спам и не являющихся таковыми сообщений, чем могли бы предоставить любые сложные методики на основе сличения с образцом или человек, просматривающий письма. Unix-программистам проще избежать соблазна искусных методик сличения с образом, чем их коллегам в других культурах программирования,
9.1.3. Учебный пример: программирование метаклассов в fetchmail
Утилита fetchmailconf(1), конфигуратор файлов профилей, поставляемая с программой fetchmail(1), содержит полезный пример передовой программы, управляемой данными, написанной в объектно-ориентированном языке очень высокого уровня.
В октябре 1997 года серия вопросов в списке рассылки пользователей fetchmail продемонстрировала тот факт, что конечные пользователи сталкивались с возрастающими проблемами при создании конфигурационных файлов для fetchmail. В файле используется простой классический для Unix свободный формат синтаксиса. Однако данный файл может оказаться неприступно сложным, когда пользователь имеет учетные записи POP3 и IMAP на нескольких узлах. Несколько упрощенная версия конфигурационного файла fetchmail приведена в примере 9.1.
Цель создания fetchmaikonf заключалась в том, чтобы полностью скрыть синтаксис управляющего файла за стильным, эргономичным GUI-интерфейсом с кнопками выбора, бегунками и формами для заполнения. Однако в бета-версии была проблема: программа могла легко создавать конфигурационные файлы, исходя из действий, предпринятых пользователем в GUI, но не могла считывать и редактировать уже существующие файлы.
Анализатор для синтаксиса конфигурационного файла fetchmail является довольно сложным. Фактически он написан с использованием программ yacc и lex, двух классических инструментов Unix для создания кода синтаксического анализатора на языке С. Вначале разработчикам показалось, что для того чтобы с помощью fetchmailconf можно было редактировать существующие конфигурационные файлы, понадобится воспроизвести тот же сложный синтаксический анализатор в языке реализации fetchmailconf — Python.
Такая тактика выглядела бесперспективной. Даже если не принимать во внимание объем необходимой дублирующей работы, очень трудно быть уверенным в том, что два синтаксических анализатора, написанных на двух различных языках, допускают использование одной и той же грамматики. Обеспечить в дальнейшем их синхронизацию по мере развития конфигурационного языка будет чрезвычайно сложно. Данный подход нарушал бы правило SPOT, описанное в главе 4.
На какое-то время автор был поставлен в тупик данной проблемой. Разрешило ее интуитивное понимание того, что программа fetchmailconf может использовать собственный синтаксический анализатор fetchmail в качестве фильтра. В результате в fetchmail был добавлен параметр
Основное препятствие было преодолено. Интерпретатор Python мог затем оценить вывод fetchmail
Однако описанное препятствие было не последним. Было действительно необходимо не только предоставить fetchmail существующую конфигурацию, но превратить ее в связанное дерево действующих объектов. В данном дереве было бы 3 вида объектов: Configuration (объект верхнего уровня, представляющий всю конфигурацию), Site (представляющий один из серверов для опроса) и User (представляющий пользовательские данные, связанные с узлом). Файл в примере описывает 3 объекта Site, каждый из которых связан с одним пользовательским объектом.
Данные 3 класса объектов уже существовали в fetchmailconf. Каждый из них имел метод, который заставлял его выводить на экран GUI-панель редактирования для модификации своего экземпляра данных. Последняя проблема сводилась к некоторому преобразованию статических данных в Python-инициализаторе в действующие объекты.