Опубликован: 23.10.2005 | Доступ: свободный | Студентов: 4086 / 201 | Оценка: 4.44 / 4.19 | Длительность: 33:04:00
Специальности: Программист
Лекция 18:

Объектно-ориентированная среда

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

Завершенная схема среды будет приведена позже (рис. 18.2). Некоторые ее важнейшие компоненты помещены на CD, прилагаемом к книге. Цель этого представления состоит в том, чтобы показать, как поддержка среды может сделать ОО-концепции удобными для практического использования. Предостережение: обсуждаемая среда никоим образом не является совершенной (фактически она все еще развивается). Это просто пример современной OO-среды. Другие, упомянем, например, Borland Delphi, завоевали широкий и заслуженный успех. Но мы должны изучить одну среду более глубоко, чтобы понять связь между принципами ОО-метода и их ежедневным применением разработчиком у терминала. Автор надеется, что многие концепции будут полезны и для читателей, использующих другие инструментальные средства.

Компоненты среды

Среда1При чтении этой лекции следует учитывать, что за годы, прошедшие после написания этого текста, сама среда (но не язык) существенно изменилась. На диске, прилагаемом к книге, представлена одна из ее последних версий Envision, позволяющая работать на Eiffel в среде Visual Studio.Net. Хотя данный текст описывает устаревшую версию, но общие идеи проектирования подобной среды сохранили свое значение. В предисловии редактора и автора даются ссылки на сайт, позволяющий познакомиться с последними достижениями в этой области. объединяет следующие элементы:

  • лежащий в основе метод: ОО-метод, описанный в этой книге;
  • язык - нотацию, представленную в этой книге и используемую на этапах анализа, проектирования и реализации;
  • набор инструментальных средств, необходимых для использования метода и языка: средства компиляции, просмотра, документирования, проектирования;
  • библиотеки программных компонент повторного использования.

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

Язык

Язык - это нотация, введенная в лекциях 7-18 курса "Основы объектно-ориентированного программирования" и применяемая в ней. Мы по существу полностью ее рассмотрели за исключением нескольких технических деталей, таких как представление специальных символов.

Развитие

Первая реализация языка выпущена в конце 1986 г. Единственный существенный пересмотр (1990 г.) не затронул никаких фундаментальных концепций, но упростил выражение некоторых из них. С тех пор ведется постоянная работа по уточнению и упрощению, затрагивающая только детали. Два недавних расширения связаны с механизмом параллелизма (рассмотренным в "Параллельность, распределенность, клиент-сервер и Интернет" , где добавлено единственное ключевое слово separate ) и конструкцией Precursor для облегчения переопределения. Стабильность языка, редкое явление в этой области, была для пользователей среды одним из важных преимуществ.

Открытость

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

Особый интерес представляют интерфейсы с языками C и C++. Для C++ доступно средство под названием Legacy++, позволяющее на основе существующего класса C++ создать обертывающий класс (wrapper class), автоматически инкапсулирующий все экспортируемые компоненты оригинала. Это особенно полезно для организаций, которые использовали C++ как первую остановку на пути к ОО и теперь хотят без потерь инвестиций перейти к законченной и систематической форме объектной технологии. Инструментарий Legacy++ сглаживает такой переход.

Технология компиляции

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

Требования к компиляции

Технология компиляции разрабатывалась и совершенствовалась многие годы для решения следующих задач:

  • C1 Эффективность сгенерированного кода должна быть сопоставимой с эффективностью, достигаемой при использовании классического языка типа C. Нет никаких причин платить за OO-методы снижением производительности.
  • C2 Время перекомпиляции после внесения изменений должно быть коротким. Точнее, оно должно быть пропорционально объему изменений, а не размеру полной системы. Важнейшим требованием для разработчиков, создающих большие системы, является возможность немедленно увидеть результаты сразу после внесения изменений.
  • C3 Третье требование появилось позже, но становится важным для пользователей: поддержка быстрой доставки приложений через Internet для непосредственного выполнения.

Согласовать два первых требования очень трудно. Требование C1 обычно обеспечивается путем экстенсивной оптимизации, в результате приводящей к замедлению перекомпиляции и компоновки. Интерпретирующие среды хорошо соответствуют C2, выполняя ПО "на лету" после минимальной обработки, но приносят в жертву производительность (C1) и статический контроль типов.

Технология тающего льда

Для решения указанных проблем технология компиляции, известная как Технология тающего льда (Melting Ice Technology), использует сочетание дополняющих друг друга методов. Откомпилированную систему называют замороженной, уподобляя ее куску льда в морозильной камере. Образно говоря, чтобы начать работу над системой, ее нужно достать из холодильника и немного подогреть. Растаявшие элементы представляют собой изменения. Эти элементы не станут причиной цикла "перекомпиляция - сборка" для удовлетворения требования C2. Вместо этого "растаявший" код будет непосредственно обрабатываться исполняющей машиной, встроенной в окружение.

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

  • Быстрая перекомпиляция. Типичное время ожидания - несколько секунд.
    "Замороженная" и "растаявшая" части системы

    Рис. 18.1. "Замороженная" и "растаявшая" части системы
  • Это по-прежнему компиляционный подход: при любой перекомпиляции выполняется полный контроль типов (без чрезмерных временных потерь, потому что проверка, подобно компиляции, является возрастающей - проверке подлежат только изменяемые части кода).
  • Скорость выполнения остается приемлемой, потому что для нетривиальной системы типичная модификация затронет лишь небольшую часть кода, которая и будет запускаться на машине выполнения, а все остальное будет выполняться в его откомпилированной форме. (Для максимальной эффективности используется рассмотренная ниже форма компиляции - finalization.)

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

Анализ зависимостей

Как это и должно быть в любой современной среде разработки, процесс перекомпиляции является автоматическим. Вы просто нажимаете кнопку Melt в инструментарии Project Tool, описанном ниже, и механизмы тихо определят набор элементов, подлежащих перетрансляции. Нет никакой потребности в файлах Make, а нотация не содержит понятия "include file".

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

Для снижения времени в качестве единицы перекомпиляции выбирается не класс, а отдельная подпрограмма.

Заметим, что если добавлен внешний элемент, например функция C, то потребуется замораживание. Необходимость этого определяется автоматически.

Предкомпиляция

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

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

В новую систему можно включить неограниченное число откомпилированных библиотек. Механизм объединения таких библиотек поддерживает совместное использование. Если две откомпилированные библиотеки B и C ссылаются на A (например, графическая библиотека Vision и клиент-серверная библиотека Net, обсуждаемые далее, обе используют библиотеку структур данных и фундаментальных алгоритмов Base), то только одна копия A включается в систему.

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

Удаленное выполнение

Интерпретируемый код, сгенерированный после таяния, традиционно известный как байт-код, является независимым от платформы. Для выполнения байт-кода достаточно иметь копию Исполняющей Машины (Execution Engine), известной как 3E и свободно загружаемой через Интернет.

Установка 3E в качестве дополнительного модуля (plug-in) Web-браузера дает возможность непосредственного выполнения кода. 3E автоматически выполнит соответствующий код при активизации пользователем гиперссылки, соответствующей байт-коду. Этот механизм удаленного выполнения стал популярен благодаря Java.

Существует два варианта 3E, отличающиеся набором библиотек. Первый предназначен для использования в Интернете и отличается повышенной безопасностью, он допускает только терминальный ввод-вывод. Второй, предназначенный для Интранет (корпоративных сетей), обеспечивает полноценную поддержку ввода-вывода и ряд других возможностей.

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

Оптимизация

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

  • Удаление мертвого кода, то есть любых подпрограмм, которые никогда не вызываются, прямо или косвенно, из корневой процедуры создания системы. Это особенно важно, если использовано много предкомпилированных библиотек. Выигрыш в размере системы нередко составляет около 50%.
  • Статическое связывание, автоматически выполняемое компилятором для компонентов, не являющихся полиморфными или не переопределяемых потомками.
  • Подстановка кода подпрограмм.

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

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

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