Использование UML и ОСРВ при смене парадигмы программирования встроенных систем от процедурного к объектно-ориентированномуИсточник: кпда
Мы стоим на пороге перехода парадигмы с процедурного на объектно-ориентированное программирование (ООП). Все больше и больше разработчиков программного обеспечения начинает осознавать, что уже давно следовало изменить процесс разработки и повысить его продуктивность, и что ОПП - верный шаг в этом направлении. В этом отношении мы (разработчики встроенных решений) зачастую на годы отстаем от наших коллег (разработчиков платформенных решений). С одной стороны, у этого есть преимущество в том, что мы можем ориентироваться на методы, уже апробированные и испытанные нашими коллегами. С другой стороны, есть некоторые недостатки из-за того, что невозможно целиком экстраполировать один к одному весь опыт с платформенной разработки на встраиваемую. Для адаптации ОО платформенных решений к требованиям встраиваемых некоторый опыт мы должны получить сами. Эта статья сфокусирована на том, как подойти к ОО разработке ПО и почему нам следует использовать этот мощный подход. Зачем менять парадигму? Для ответа на этот вопрос необходимо видеть историческую перспективу. Нам следует рассмотреть, что привело нас в эту точку и где, с точки зрения разработки встраиваемых систем, мы сегодня находимся. На сегодняшний день мы располагаем двумя характеризующими критериями для такого рассмотрения: объем ПО, измеряемый в строках кода (LOC) и сложность ПО. Давайте рассмотрим историю разработки. Первые микроконтроллеры переместились в мир электронного управления около 15 лет назад. В это время доминирующей платформой были маленькие 8-разрядные контроллеры. Спустя 5-7 лет требования приложений выросли так существенно, что большинство из этих микроконтроллеров было заменено более производительными 16-разрядными контроллерами, а спустя еще 5-7 лет для удовлетворения устойчиво растущим требованиям функциональности - 32-разрядными контроллерами. Если мы посмотрим на средний размер ПО, написанного в этих проектах, и измерим его в LOC, то увидим следующие результаты: в проектах, использующих 8-разрядные контроллеры обычно писалось 8 000 строк кода; в проектах с 16-разрядными контроллерами мы находим около 80 000 написанных строк; и в 32-разраядных контроллерах мы видим около 1 000 000 строк кода. Этот феномен роста LOC наблюдается часто и почти во всех приложениях. Из этих наблюдений мы можем заключить, что размер кода, подлежащего разработке, увеличивается примерно в 10 раз каждые 5-7 лет. Этот поразительный рост на самом деле происходит еще быстрее, потому что один только размер приложения в действительности не является правильной иллюстрацией влияния указанного роста на усилия по программированию. Гораздо лучшим показателем является сложность приложения. Если мы измерим сложность кода, то придем к выводу, что рост сложности происходит экспоненциально относительно роста LOC. Эта величина роста превышает нашу способность понять все последствия, к которым он ведет. Почему? Потому что для сравнения роста проектов есть весьма немного параметров и это помогает ответить на вопрос, почему рост проектов разработки ПО в принципе нельзя полностью оценить. Вот, наиболее яркий момент: количество разработчиков в вашем отделе вероятно не растет с такой же невероятной скоростью, верно? Бюджет для новых методов и инструментов разработки так же растет медленнее, а ваша зарплата, вероятно, не растет вообще. Разве не было бы логичнее, если бы все эти ресурсы росли так же, как объемы кодов? Разумеется, существует простая причина того, почему это не так: стоимость конечного продукта, в котором используется встраиваемое ПО, так же не растет значительно. Итак, что мы должны сделать по отношению к этой проблеме, так это повысить свою эффективность, и путем к этому является смена парадигмы. Как выглядит необходимая смена парадигмы? Как выглядит эта смена парадигмы? Последняя смена была переходом от неструктурированного программирования к структурному. Этот шаг был сделан около 8-15 лет назад путем перехода с программирования на ассемблере к программированию на высокоуровневом языке наподобие "С". Итак, согласно нашему графику изменений, новая замена парадигмы значительно запоздала. Существует старинная стратегия, которая сегодня сохраняет эффективность и в дальнейшем продемонстрирует, почему изменение парадигмы будет успешным. Стратегия, о которой мы говорим, была названа "разделяй и властвуй" Юлием Цезарем, "конечные элементы" - нашими коллегами инженерами-механиками, и ООП (объектно-ориентированное программирование) инженерами по ПО. С помощью этой стратегии можно снизить рост сложности. Это - простой секрет ООП. Сейчас есть возможность делить запутанную часть ПО на несколько частей так, что каждой части позволяется воздействовать на каждую другую только посредством определенного интерфейса. После этого различные разработчики могут рассматривать отдельно каждую часть относительно этого интерфейса. Это невероятно сокращает сложность кода. Существует два дополнительных преимущества: это - основа для командного подхода при разработке встраиваемого ПО и для повышенной пригодности сложного ПО к тестированию. Многое читатели немедленно предположат, что обсуждая ООП мы подразумеваем программирование на С++. Однако это не так. Одно программирование на С++ не очень подходит для применения ООП. К сожалению, очень часто неизвестно, что ООП требует больше элементов в дополнение к С++. В платформенном программировании, например, используются MFC (Microsoft Foundation Classes). Один из аспектов этого подхода заключается в том, что адрес MFC является интерфейсом к операционной системе. Эта операционная система определяет отклик программы в ходе ее выполнения. Так вот, в С++ упущено нечто существенное: элементы для описания времени реакции при исполнении программы. Однако это - фундаментальная необходимость в ориентированных на период исполнения встроенных приложениях реального времени. Почему? Разработка многоуровневых приложений с жесткими требованиями ко времени реакции При разработке многоуровневого ПО необходимо принимать во внимание следующие четыре плоскости: · уровень поведения · уровень времени · уровень потока данных · уровень приоритетов И теперь мы добрались до самой сути изменения парадигмы. В большинстве нынешних проектов встроенных систем реального времени интерфейсы связывают только один уровень одиночных устройств, и имеются зависимости, скрытые на другом уровне. То есть, отдельные части в реальности неразделимы, и большая часть наших трудностей является следствием этого факта. Подход "разделяй и властвуй" на самом деле означает полное исключение скрытых зависимостей, потому что только при этих условиях сложностью можно управлять. Давайте рассмотрим, как реагирует приложение, не имеющее объектно-ориентированной архитектуры. Представим, что один разработчик модифицирует и тестирует свой модуль. Модификация, однако, оказывает влияние на отклик всей системы во время ее функционирования, и в результате она может повлиять на совершенно иные части приложения. Разработчик увидит проявление этого только в результатах тестирования всей системы, что является трудоемким и дорогостоящим подходом к разработке. Итак, используя типичный подход к программированию, разработчик меняет что-либо на уровне поведения (например, расширяет ПО инструкциями, при этом воздействуя в плане выполнения на всю систему, приводя, таким образом, к новой проблеме в совершенно иной части приложения). При этом возникает вопрос: какая языковая конструкция имеется в С++ для обеспечения особого поведения с одной из частей приложения? В С++ не существует таких конструкций, но есть кое-что иное: MFC (Microsoft Foundation Classes). MFC содержат конструкции, которые формируют интерфейс к операционной системе. С помощью этих конструкций можно задавать особое поведение на этапе выполнения как часть приложения. Тогда операционная система заботится о том, что бы на этапе выполнения обеспечивалась возможность этого отклика. Существует много иных сервисов, которые предоставляет ОСРВ для создания ОО интерфейсов как неотъемлемую часть приложения (например, функции асинхронного взаимодействия). Конечно, в рамках этой статьи мы не можем привести примеры всех видоизменений этой проблемы, но, надеемся, основной замысел ясен. Встраиваемые системы реального времени гораздо более ориентированы на период выполнения, нежели платформенные системы, но ни С, ни С++ не предлагают хорошего механизма для описания отклика периода выполнения, требуемого при проектировании. Для достижения этого требуются системы времени исполнения. В коммерческих системах наподобие CMX-RTX разработки CMX Systems доступна функциональность, именуемая ОСРВ (Операционная Система Реального Времени). Сервисы ОСРВ являются основой линейки интерфейсов, которые реально способны только связывать один уровень кода и не могут передавать на другой уровень. На этот случай ОСРВ предлагает ряд конструктивных решений. Простейшими решениями являются механизм диспетчеризации и механизм асинхронного взаимодействия. Два этих общих решения позволяют разработчикам проектировать целевую архитектуру с использованием ОО интерфейсов. Таким подходом достигается настоящая инкапсуляция и это должно быть первым шагом в каждом проекте с применением ООП. Это повышает понятность и модифицируемость, но существует еще одно, более крупное, достоинство, которое будет использовать реальный потенциал эффективности: улучшение условий для переиспользования кода. Основная выгода от повышения эффективности путем переиспользования кода В приложениях объемом свыше 50 000 LOC уже больше нет возможности выбросить старый исходный код и начать новый проект "с нуля" (даже если некоторые разработчики будут предлагать такое решение). Только используя повторно столько кода, сколь возможно мы можем выдерживать сроки выполнения проектов, которые становятся все короче и короче. Объектно-ориентированные интерфейсы являются наиболее элементарными предпосылками и они предоставляются нам целевыми системами. К сожалению, есть некоторый недостаток в использовании ОСРВ. Успешное переиспользование кода реально означает, что затраты на адаптацию существующего ПО должны быть настолько минимальными, насколько возможно. По этой причине интерфейсы целевых систем по возможности всегда должны оставаться неизменными. Однако, если для новой задачи нужно модифицировать коммерческую ОСРВ, то "утилизировать" интерфейс будет трудно. Это было признано автомобильной индустрией, и был создан стандарт, который называется стандартом OSEK для ОСРВ. Этот стандарт подходит для многих приложений и является сильно запоздавшим шагом в верном направлении. Но параллельно с OSEK был разработан другой, более мощный, стандарт. Этот новый стандарт называется нотацией UML (Unified Modeling Language), стандартизованной OMG (Object Management Group). UML обеспечивает колоссальный потенциал для повышения эффективности, потому что дает возможность соединять между собой достоинства различных техник программирования. UML располагает законченными конструкциями для описания реакции периода исполнения, отсутствующие в С++, и предлагает стандарт, которого не имеют коммерческие ОСРВ. UML гораздо лучший внешний интерфейс (интерфейс к приложению) для целевых систем, чем OSEK, потому что OSEK не имеет ОО конструкций. Эти элементы (UML вместе с ОСРВ) облегчают разработку целевых ОО архитектур. Выводы Переход от процедурного программирования к ООП решит большую часть сегодняшних проблем и содержит огромный потенциал повышения эффективности, крайне необходимой нам при разработке встроенных систем. Основа этого перехода - это не С++, как часто предполагают, а использование проектирования периода исполнения. Поэтому использование ОСРВ играет центральную роль в этом переходе. Совместно с использованием таких ОО нотаций, как С++ или, лучше, UML, эта эффективность может быть умножена чрезвычайно. Проверенным решением, применяемом на рынке в течение более, чем 3 лет, является комбинация ОСРВ CMX-RTX и Rhapsody с С/С++. Код, генерируемый Rhapsody, оптимизирован для приложений, занимающих мало места в памяти, и использование CMX-RTX. При таком подходе типичное приложение, включая CMX RTX, требует около 18 Kбайт ПЗУ и 300 байт ОЗУ. По быстрому росту запросов на ОО методы и инструменты в течение последних нескольких лет видно, что все больше и больше разработчиков признают ценность этого подхода. Больше не стоит вопроса: полезно ли ООП разработчикам встроенных систем и будет ли оно приносить прибыль в будущем? Вместо этого стоит вопрос: как долго мы сможем обходиться без ОО архитектуры периода исполнения и когда достоинства ООП будут замечены как важный фактор конкурентоспособности? Вы уже здесь? Willert Software Tools GmbH |