Брутально и бессердечно о программировании и проектировании
ГлавнаяФорумПаттерныАнтипаттерныТест-драйвЗаметкиВопрос-ответКнигорецензииСправочная

43. Скриптовый интерфейс CAD-систем

Как есть
Большинство современных программ, так или иначе подпадающих под определение «CAD-система», предоставляют скриптовый интерфейс. И это не случайно: пользовательский интерфейс не способен покрыть всех нужд пользователя, особенно когда речь идет об автоматизации обработки данных.
К сожалению, мало где можно встретить CAD-систему с человеческим скриптовым интерфейсом. Чаще всего скриптовый интерфейс делается для галочки, просто чтобы был. В один прекрасный день у одного из менеджеров вдруг начинает свербить в одном месте, мол срочно нужно сделать в продукте поддержку скриптинга.
Примером всестороннего говна может служить скриптовая система продуктов компании Adobe, например Photoshop или Illustrator. «Всестороннего» — это значит «говно, с какой стороны ни посмотри». Скриптовая система продуктов Adobe ужасна во всем, от документации до архитектуры объектной модели.
Если человек не проникнут любовью к своему делу, то существует всего один способ заставить его сделать что-то более менее человеческое, который заключается в том, чтобы заставить его самого ежедневно использовать собственное творение. Автору не известно, насколько сильно программисты Microsoft проникнуты любовью к своему делу, однако можно сказать с уверенностью, что MSDN такой удобный в использовании хотя бы потому, что сами программисты Microsoft ежедневно им пользуются. Программистам же из Adobe этот скриптовый интерфейс не нужен. Никто в Adobe использует его ежедневно в своей повседневной работе, никто ежедневно не роется в его документации. Именно по этой причине документация по скриптам хранится в формате PDF. Совершенно очевидно, что оформлять документацию по API в PDF могут только последние мудаки и дегенераты.
 
Как должно быть
Требования, которые предъявляются к любой скриптовой системе, очевидны. Скриптинг должен позволять легко и удобно выполнить некоторую автоматизацию действий пользователя. Этого можно добиться, поставив при разработке скриптовой системы следующие условия.
Во-первых, все действия, которые можно выполнить через UI приложения, должны быть доступны через скриптовый интерфейс. Половина CAD-систем кладет на это, и кладет с прибором.
Во-вторых, композиция объектной модели скриптовой системы должна быть интуитивно понятна и должна естественным образом вытекать из иерархии сущностей приложения, с которыми работает пользователь. Программа должна предоставлять так называемый script listener, который, в свою очередь, должен выдавать сценарии с человеческой структурой и именами. В некоторых CAD-системах, выполнив определенные действия и открыв script listener можно увидеть нечто вроде следующей бесполезной портянки:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
command cmd0 = new command;
cmd0.proc_id = 0x8f2f1103;
cmd0.params[0] = 2;
cmd0.params[1] = 3857;
cmd0.params[2] = 34;
app.generic_action(cmd0);

command cmd1 = new command;
cmd1.proc_id = 0x8f2f1144;
cmd1.params[0] = 543;
cmd1.params[1] = 85;
app.generic_action(cmd1);

command cmd2 = new command;
cmd2.proc_id = 0x8f2f14da;
cmd2.params[0] = 0
cmd2.params[1] = 0
cmd2.params[2] = 4.466;
cmd2.params[3] = 9.212;
app.generic_action(cmd2);

command cmd3 = new command;
cmd3.proc_id = 0x8f2f1f2d;
cmd3.params[0] = "set10.xml";
app.generic_action(cmd3);

// И так далее
Естественно, такой script listener совершенно бесполезен.
Существует предельно простая и лаконичная архитектура, позволяющая получить нужные качества скриптовой системы. И программист, и пользовательский интерфейс, должны взаимодействовать с логикой приложения через единый скриптовый шлюз. С одной стороны это позволит выполнять на скрипте любые действия, доступные из UI. С другой — заставит разработчиков программы ежедневно работать с собственной скриптовой системой.
Если архитектура приложения изначально не предусматривала реализацию скриптового интерфейса, то любые попытки по-быстрому «прикрутить» скриптовую систему закончатся появлением на свет самого бесполезного модуля приложения.
 
Как поступить
Скриптовый интерфейс — прекрасное дополнение к любой CAD-системе, и к его проектированию следует подходить с высокой мерой ответственности.
О внедрении скриптовой системы следует подумать еще в самом начале проектирования всего приложения. Скриптовая система должна естественным образом вписываться в основную архитектуру приложения, или даже быть ее неотъемлемой частью. Простое прикручивание скриптинга сбоку готового приложения никогда не даст качественного результата.
Интерфейс и объектная модель скриптовой системы должны быть максимально удобны для человека. Вообще говоря, скрипт — это самый высокий уровень программирования, решение любой задачи на нем должно быть максимально просто и понятно. В идеале скрипт должен быть простым формализованным перечислением действий над сущностями уровня пользователя программы.
Не следует использовать костыли вроде приведенных выше generic actions — это противоречит самому смыслу скриптинга.
Также не следует отображать какое-либо существующее API в скрипт. Например, в некоторых скриптовых системах можно встретить набор функций для работы с файлами, аналогичный набору функций языка C, а именно — fopen, fclose, fread, fwrite, и так делее. Это неверный подход. Подобное API является слишком низкоуровневым чтобы использовать его в скрипте. Такая простая операция как запись в файл, в скприте должна укладываться в одну грамматическую конструкцию.
Не следует использовать политику двойных стандартов. Любой внешний модуль должен получать доступ к внутренней логике программы через один и тот же скриптовый шлюз, будь то UI, планировщик задач или скриптовый программист.
Отдельного внимания заслуживает механизм оповещения об ошибках. Исключения, как способ оповещения об ошибках, несомненно, имеют преимущества перед возвращаемым значением и глобальным кодом ошибки, однако, в скриптовых системах это не самый популярный механизм. Причина этого, скорее всего, состоит в повышенной сложности реализации механизма исключений. Если все-таки возможность воспользоваться исключениями имеется, то лучше это сделать. Если же существует такой скрипт, у которого транзакционность заложена в самой грамматике, то автор будет благодарен читателю, который об этом скрипте расскажет.
Довольно удобно, когда скриптовая система позволяет создавать диалоговые окна и получать из них параметры для скрипта. Такая возможность (хотя и в никудышном исполнении) есть, например, в Autodesk 3ds Max. В идеале, организация основного UI не должна ничем отличаться от пользовательских скриптовых модулей с диалоговыми окнами. Такой подход заставит использовать интеграцию UI и скрипта в повседневной жизни, а следовательно она будет выполнена особенно качественно. Именно поэтому интеграция UI и скрипта в Autodesk 3ds Max — никудышное говно.
 
План действий
Итак, если вы решили реализовать скриптинг в своей CAD-системе, то вооружитесь следующим планом действий.
  1. Выберете языковую грамматику. На каком языке будет построен ваш скриптинг, на уже существующем или изобретенном лично вами — решать вам. У обоих путей существуем как масса достоинств, так и масса недостатков, кроме того — речь сейчас не об этом. Поэтому, просто определитесь с языком.
  2. Разработайте объектную модель, композицию сущностей и понятий. Сосредоточьтесь на «человеческом факторе» — модель должна быть проста и интуитивно понятна.
  3. Разработайте механизм интеграции UI и скриптовой системы. Разработайте удобный редактор диалогов, меню и прочих UI-элементов. Этим редактором будут пользоваться все — и вы, и сторонние программисты скриптов. Позаботьтесь о том, чтобы описание диалогов имело «friendly human-readable» формат (например, XML) и было доступно для редактирования наравне с визуальным редактором.
  4. Разработайте основной UI. В случае необходимости скорректируйте объектную модель скрипта. Подгоняйте модель скрипта к тем, кто его использует, а не наоборот. Помните — скрипт это прежде всего действия пользователя, а не набор машинных инструкций, которые за ним стоят.
  5. Следите за тем, чтобы все пользователи скрипта работали через единый шлюз, а весь пользовательский интерфейс строился на общих правилах в одном и том же редакторе.
  6. Отдельное внимание уделите документации. Хороший способ держать документацию в актуальном состоянии — заставить всех разработчиков ежедневной ей пользоваться. Хороший способ оформления — онлайн документация в HTML-формате.
Помните — скриптовая система это не дополнительный модуль, а неотъемлемая часть архитектуры всего приложения. Не пытайтесь пойти по пути «сегодня мы сделаем приложение, а завтра добавим скриптинг». Также не забывайте, что скриптинг и пользовательский интерфейс тесно связаны между собой. Следите за тем, чтобы их взаимодействие было в первую очередь удобно для человека.
 
Напоследок
Вот, в общем-то и все, о чем хотелось сказать в общих чертах о скриптинге в CAD-системах. Напоследок, пример хорошего (по мнению автора) вымышленного скриптового модуля в вымышленной грамматике.
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<dialog caption="Удаление объектов по размеру">
    <editbox
        name="from"
        x="10"
        y="10"
        type="float"
        value="0"
        caption="Линейные размеры, от"
    />
    <editbox
        name="to"
        x="10"
        y="20"
        type="float"
        value="100"
        caption="Линейные размеры, до"
    />
    <checkbox
        name="invisible"
        x="10"
        y="30"
        value="checked"
        caption="Включая невидимые"
    />
    <button
        x="center"
        y="40"
        type="okcancel"
        on_ok="apply"
    />
</dialog>

function apply(dialog& dlg)
{
    document doc = application.documents.current();

    foreach obj as geomobject in doc.objects
    {
        if(obj.size < dlg.from || obj.size > dlg.to)
        {
            continue;
        }

        if(!obj.visible && !dlg.invisible)
        {
            continue;
        }

        application.objects.remove(obj);
    }
}

Оглавление
Статистика
© 2007—2009 Inside C++ Коммерческие услугиКонтактная информация