Rational Rose для разработчиков и ради разработчиков

         

Анонс


В следующей части статьи мы рассмотрим

Взаимодействие Rose и ClearCase Взаимодействие Rose и Requisite Pro Вопрос интеграции Rose с MS Developer Studio

См. также:






Аспекты совместной работы с Oracle


Новая версия Rose - 2000e - поддерживает полноценное проектирование баз данных. Раньше использование Rose ограничивалось только высокоуровневым проектированием, а доводкой занимались в ERwin, для чего был создан специальный мост ERwin RoseLink сторонней компанией, что создавало определенные неудобства в работе. Теперь же Rose получила достаточно выразительные средства для лучшего проектирования баз данных, а мост с ERwin включен в стандартную поставку, что позволит более не опасаться за надежность передаваемых моделей.

Подобная интеграция не может не вызывать восхищения. Наконец-то можно полностью проектировать все в Rose! По словам Роджера Оберга (Roger Oberg), вице-президента Rational: "Rational Rose стала стандартом при разработке приложений и бизнес-моделировании. Теперь, вместе с Rational Rose, проектировщики БД могут воспользоваться преимуществами UML и присоединиться к остальным разработчикам".

Использование UML для моделирования и дизайна баз данных не только облегчает коммуникацию и убирает преграды между разработчиками, но и дает им более выгодную среду для моделирования. С моделью базы данных на языке UML проектировщик БД может получать такую информацию, как ограничения (constraints), триггеры и индексы прямо на диаграмме. Когда эта информация смоделирована, пользователям становится проще обеспечивать коммуникацию с моделью базы данных в целом.

В дополнение к преимуществам от использования UML для моделирования баз данных Rational Rose дает следующие возможности:

Соответствие между объектно-ориентированной структурой и моделью данных (object-relational mapping) позволяет отслеживать преобразования модели объекта в модель базы данных. Эта форма соответствия позволяет проанализировать ссылки между приложением и базой данных и обновлять их на основе изменений, сделанных в процессе разработки. Прямое и обратное проектирование базы данных (database round trip engineering). Прямое и обратное проектирование модели данных и базы данных позволяет создать модель данных, основанную на структуре БД через прямое или обратное проектирование. Схема может быть сгенерирована прямо напротив базы данных или сохранена как скрипт для дальнейшего применения. Она будет включать таблицы, колонки, ограничения, индексы, триггеры и т.д. Ссылочная целостность (referential integrity) сохраняет целостность базы данных благодаря автоматическому переносу первичных ключей главной таблицы (parent table), как внешних, в зависимую таблицу (child table). Когда ссылка создана, пользователи могут выбрать, как обеспечить ссылочную целостность: либо через триггер, либо через декларативную целостность.

Продолжение следует:

В следующей части статьи будет рассмотрено: Обратное проектирование на С++ Анализ существующей базы данных на Oracle Что такое Rational Rose RealTime



Ассоциации с ограниченной множественностью




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

Рис.5

Код получается следующим:

ФАЙЛ STRING.h

//## begin module%1.3%.codegen_version preserve=yes // Read the documentation to learn more about C++ code generator // versioning. //## end module%1.3%.codegen_version

//## begin module%39FD295103B9.cm preserve=no // %X% %Q% %Z% %W% //## end module%39FD295103B9.cm

//## begin module%39FD295103B9.cp preserve=no //## end module%39FD295103B9.cp

//## Module: String%39FD295103B9; Pseudo Package specification //## Source file: C:\Program Files\Rational2\Rose\C++\source\String.h

#ifndef String_h #define String_h 1

//## begin module%39FD295103B9.additionalIncludes preserve=no //## end module%39FD295103B9.additionalIncludes

//## begin module%39FD295103B9.includes preserve=yes //## end module%39FD295103B9.includes

// NewString #include "NewString.h" //## begin module%39FD295103B9.additionalDeclarations preserve=yes //## end module%39FD295103B9.additionalDeclarations

//## begin String%39FD295103B9.preface preserve=yes //## end String%39FD295103B9.preface //## Class: String%39FD295103B9 //## Category: <Top Level> //## Persistence: Transient //## Cardinality/Multiplicity: 1

class String { //## begin String%39FD295103B9.initialDeclarations preserve=yes //## end String%39FD295103B9.initialDeclarations

public: //## Constructors (generated) String();

String(const String &right);

//## Destructor (generated) ~String();

//## Assignment Operation (generated) String & operator=(const String &right);

//## Equality Operations (generated) int operator==(const String &right) const;

int operator!=(const String &right) const;

//## Get and Set Operations for Associations (generated)

//## Association: <unnamed>%39FD300C00A9 //## Role: String::<the_NewString>%39FD300C033E const NewString * get_the_NewString () const; void set_the_NewString (NewString * value);


#ifndef NewString_h #define NewString_h 1

//## begin module%39FD296801A9.additionalIncludes preserve=no //## end module%39FD296801A9.additionalIncludes

//## begin module%39FD296801A9.includes preserve=yes //## end module%39FD296801A9.includes

// String #include "String.h" //## begin module%39FD296801A9.additionalDeclarations preserve=yes //## end module%39FD296801A9.additionalDeclarations

//## begin NewString%39FD296801A9.preface preserve=yes //## end NewString%39FD296801A9.preface

//## Class: NewString%39FD296801A9 //## Category: <Top Level> //## Persistence: Transient //## Cardinality/Multiplicity: n

class NewString { //## begin NewString%39FD296801A9.initialDeclarations preserve=yes //## end NewString%39FD296801A9.initialDeclarations

public: //## Constructors (generated) NewString();

NewString(const NewString &right);

//## Destructor (generated) ~NewString();

//## Assignment Operation (generated) NewString & operator=(const NewString &right);

//## Equality Operations (generated) int operator==(const NewString &right) const;

int operator!=(const NewString &right) const;

//## Get and Set Operations for Associations (generated)

//## Association: <unnamed>%39FD300C00A9 //## Role: NewString::<the_String>%39FD300C0348 const UnboundedSetByReference<String> get_the_String () const; void set_the_String (UnboundedSetByReference<String> value);

// Additional Public Declarations //## begin NewString%39FD296801A9.public preserve=yes //## end NewString%39FD296801A9.public

protected: // Additional Protected Declarations //## begin NewString%39FD296801A9.protected preserve=yes //## end NewString%39FD296801A9.protected

private: // Additional Private Declarations //## begin NewString%39FD296801A9.private preserve=yes //## end NewString%39FD296801A9.private

private: //## implementation // Data Members for Associations //## Association: <unnamed>%39FD300C00A9 //## begin NewString::<the_String>%39FD300C0348.role preserve=no public: String {1 -> nRHN} UnboundedSetByReference<String> the_String; //## end NewString::<the_String>%39FD300C0348.role



// Additional Implementation Declarations //## begin NewString%39FD296801A9.implementation preserve=yes //## end NewString%39FD296801A9.implementation };

//## begin NewString%39FD296801A9.postscript preserve=yes //## end NewString%39FD296801A9.postscript

// Class NewString

//## Get and Set Operations for Associations (inline)

inline const UnboundedSetByReference<String> New-String::get_the_String () const { //## begin NewString::get_the_String%39FD300C0348.get preserve=no return the_String; //## end NewString::get_the_String%39FD300C0348.get }

inline void NewString::set_the_String (UnboundedSetByReference<String> value) { //## begin NewString::set_the_String%39FD300C0348.set preserve=no the_String = value; //## end NewString::set_the_String%39FD300C0348.set }

//## begin module%39FD296801A9.epilog preserve=yes //## end module%39FD296801A9.epilog

#endif

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

Лаконичным завершение данного вида связи можно считать связь один к:. В нашем случае 1 к 6



Рис.6

При этом код будет выглядеть следующим образом

ФАЙЛ NEWSTRING.h

* * *

private: //## implementation // Data Members for Associations

//## Association: <unnamed>%39FD4614028A //## begin NewString::<the_String>%39FD461502A0.role preserve=no public: String {1 -> 6RHN} String *the_String[6];

//## end NewString::<the_String>%39FD461502A0.role

// Additional Implementation Declarations //## begin NewString%39FD296801A9.implementation preserve=yes //## end NewString%39FD296801A9.implementation

* * *

Таким же образом можно сгенерировать любой вид связи. Скажем, разработчику ничего не мешает определить связь 6 к 6 или 10 к 10. Код, сгенерированный системой, при этом будет выглядеть как "положено":


Ассоциация "один ко многим"


Данный вид ассоциаций также представляет особую ценность при проектировании классов. Множественность ассоциации задается в свойствах связи (пункты Role A Detail и Role B Detail. Где помимо ролей можно задать и специфические атрибуты конкретной ассоциациии, ну, скажем, дать ей название. Рис. 3 показывает скриншот данного окна). Рисунок 4, в свою очередь, демонстрирует внешний вид данной ассоциации.

Рис.3

Рис.4

ФАЙЛ STRING.h

* * *

private: //## implementation // Data Members for Associations

//## Association: <unnamed>%39FD300C00A9 //## begin String::<the_NewString>%39FD300C033E.role preserve=no public: NewString {n -> 1RHN} NewString *the_NewString; //## end String::<the_NewString>%39FD300C033E.role

// Additional Implementation Declarations //## begin String%39FD295103B9.implementation preserve=yes //## end String%39FD295103B9.implementation * * *

ФАЙЛ NEWSTRING.h

* * *

private: //## implementation // Data Members for Associations

//## Association: <unnamed>%39FD300C00A9 //## begin NewString::<the_String>%39FD300C0348.role preserve=no public: String {1 -> nRHN} UnboundedSetByReference<String> the_String; //## end NewString::<the_String>%39FD300C0348.role

// Additional Implementation Declarations //## begin NewString%39FD296801A9.implementation preserve=yes //## end NewString%39FD296801A9.implementation * * *

Как видно из фрагментов кода, мы получили, как и впредыдущих случаях, ссылку на класс, в то то время, как для другого класса был использован контейнер. По умолчанию Rational Rose не предоставляет реализацию контейнерного класса. Вместо него генерируется код с UnboundedSetByReference в качестве контейнерного. Указание же конкретного контейнерного класса - дело самого разработчика.



Одно из неоспоримых преимуществ Rational


Одно из неоспоримых преимуществ Rational Rose - обратное проектирование, поскольку разработчику и проектировщику важно увидеть перед изменениями уже работающую систему в нормальном графическом представлении. Как правило визуально-графический ряд оказывает куда большее воздействие нежели пролистывание технических заданий и программных текстов. Тем более что, проект, подвергшийся обратному проектированию может быть доработан и вновь сгенерирован (а впоследствии и скомпилирован). Rational Rose предоставляет для этого все необходимые средства.

Для осуществления обратного проектирования, в Rational Rose предусмотрен мощный модуль - Analyzer, чье основное предназначение, вытекающее из названия, анализ программ, написанных на С и С++. Данный модуль способен проанализировать имеющийся файл на одном из вышеупомянутых языков, и преобразовать его в визуальную модель, присвоив выходному файлу расширение mdl. Далее файл можно спокойно открыть для модификации из Rational Rose уже в визуальном режиме.

Analyzer представляет собой отдельный программный файл, вызываемый как из самой Rose, так и обычным способом. Модуль входит не во все поставки Rational Rose, а только в Enterprise, Professional и RealTime. В поставку Data Modeler данный модуль не входит, поскольку специфика поставки не предусматривает генерации кода и обратного проектирования.

Дальнейшая часть статьи будет посвящена как раз обратному проектированию, мы рассмотрим на конкретных прмерах, что разработчик получит от Rational Rose, применяя ее в качестве инструмента визуального ОО-проектирования.

Примеры будут содержать различные конструкции на языке С++ и результат их преобразования в модель. Также постараемся уделить достаточное время деталям трансляции кода программы в модель.

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



Рис.1

На рисунке 1 показан внешний вид программы в стандартных настройках и с не загроможденным экраном.

Основные поля, подлежащие обязательному заполнению (на первом этапе) это:
Caption.Имя проекта. В последствии имя модели будет определено по имени проекта.
Directories.Путь к исходящей директории. По умолчанию, Rose использует для хранения исходящих модельных файлов директорию С++\Source из домашней директории, что в некоторых случаях может приносить некоторые неудобства.
Extensions.Типы используемых расширений. Здесь можно настроить систему так, чтобы она распознавала только опредделенные виды расширений.
Bases.Место сохранения текущего проекта.
Files.Списсок из файлов, подлежащих генерации.
<
Для проведения правильного реинжениринга необходимо заполнить вышеописанные поля. Все файлы, подлежащие реинженирингу указываются в поле "Files". Следует учитывать, что при реинжениринге вы получаете визуальную модель взаимодействия классов и структур, стало быть не идет ни какой речи о том, чтобы на визуальной модели отразился существующий код системы. Далее: все нестандартные конструкции не будут выведены в модель (анализатор их просто проигнорирует), это значит, что любое отклонение от заранее известных конструкций приводит к тому, что в изначальном варианте Rose не сможет правильно проанализировать код. Этот факт не является недостатком, поскольку в арсенале Analyser'а есть инструменты тонкой настройки, позволяющие настроить все таким образом, чтобы специфика конкретного проекты была бы полностью учтена.

Процесс реинжениринга делится на два этапа: анализ и генерация модели.

На первом этапе производятся все подготовительные операции по анализу текста программы на отсутствие синтаксических ошибок. Второй этап - это преобразование кода в модель.

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

Соответственно, при отсутствии ошибок в файле можно приступить к генерации модели. В целях оптимизации времени генерации в Rose предусмотрено три способа проведения реинжениринга, каждый из которых может охватить и превосходно выполнить определенный сегмент работ. Если пользователю по каким либо причинам не подходит не один из трех предустановленных способов, то Rose допускает создание собственного реверсинжениринга.

Поговорим подробнее о трех стандартных способах :
FirstLook.Приближенная пробежка по телу программы
DetailedAnalysis.Детальный анализ проекта.
RoundTrip.Комбинация двух вышеперечисленных способов. Позволяет безболезненно строить и перестраивать разрабатываемые приложения по принципу круговой разработки.
Все настройки могут быть изменены пользователем по усмотрению.


При сохранении изменений возможно указать новое имя шаблона или перезаписать уже существующее, что позволит при частом использовании обратного проектирования не терять времени на установку нужного пункта. Как и все под этим небом, выбор соответствующего пункта обязательно сказывается на скорости анализа, чем больше - тем дольше. Еще хочется отметить такую особенность модуля Analyzer: после анализа создается не только модель но и лог файл с сообщениями, возникшими в результате сканирования программы. Лог может содержать как предупреждения так и ошибки. А особенность генерации модели состоит в том, что она состоится несмотря ни на что, то есть, невзирая на ошибки в тексте программы. Естественно никакой речи нет о какой-либо правильной модели! Эту особенность следует учитывать и внимательно анализировать файл отчета после генерации модели.

Еще одна немаловажная ремарка. Как правило обратному проектированию подвергается полноценный проектный файл, содержащий в себе и директивы #INCLUDE для определений, и комментарии... а также прочие сопроводительные инструкции. И естественно разработчику хочется иметь такой инструмент, который адекватно будет реагировать на все составляющие. Спешу обрадовать: модуль Analyzer в режиме (DetailedAnalysis) обеспечивает следующее:

Анализ и преобразование в визуальную модель классов и структур Генерацию связей в модели (между классами или структурами) Нахождение в исходном тексте комментариев и перенос их в качестве атрибутов компонентов модели. То есть если исходный текст снабжен комментариями, то они все перейдут в виде атрибутов, соответствующему элементу (переменной, массиву... итд). Способен закачать в проект все заголовочные файлы (по цепочке один за другим)

Теперь от общих фраз перейдем к практике (как говаривал незабвенный сын турцкоподданого: "ближе к телу... сведения будут оплачены..."). Для начала попытаемся проделать обратное проектирование с языка С без использования объектов. Нашей целью будет получение графической модели из структуры на языке программирования.


Почему структуры? Данный тип данных все еще широко используется программистами на языке С, сбрасывать со счетов, который несколько преждевременно!

Итак проект для реверсинжениринга представляет собой только заголовочный файл с объявлением следующей структуры:

//It's main structure struct struct_main{ char *string; //Structure's pointer int buffer[100]; //Temporary buffer char name[10]={"Massiv"};//Name of data int a; //Integer int b; //Integer };

Как видите структура достаточно тривиальна. Без излишеств. Особо хочется еще раз обратить внимание на комментарии. Каждая строка снабжена комментарием, который несет некую смысловую нагрузку. Смысл любого реверсинжениринга состоит не только в том, чтобы корректно нарисовать модель, но и для правильного описания спецификации каждой составляющей класса/структуры.

После проведения всех стандартных манипуляций по созданию проекта и его анализу получается вот такая модель в розе (рис 2):



Рис. 2



Рис. 3



Рис.4

Рисунки 2, 3 и 4 показывают отдельные спецификации.

2 - модель структуры, полученной в результате обратного проектирования

3 - список атрибутов класса/структуры. Здесь перечислены все переменные структуры.

4 - генеральная информация о структуре. Как видно из рисунка, комментарий без каких бы то ни было ограничений перешел в разряд документации, что позволит использовать его на дальнейшем этапе дополнения атрибутов, документирования и создания отчетов

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

И еще... в качестве частного случая рассмотрим объявление подструктуры в соответствии с нижеприведенным листингом:

//It's main structure struct struct_main{ char *string; //Structure's pointer int buffer[100]; //Temporary buffer char name[10]={"Massiv"};//Name of data int a; //Integer int b; //Integer struct struct_in{ int m,st; }; };



На этот раз без комментариев и занудства. На выходе получим (стр 5) следующую модель:



Рис.5

Как видим все ясно и понятно. Скромно, но очень информативно. К сожалению, если дело касается структур, то никакие связи в модели не генерятся!

Теперь перейдем к более тяжелым материям в виде классов С++. Хотя язык С и остается достаточно мощным структурным языком, все же его "изобразительных" средств в плане построения крупных информационных систем явно недостаточно. Мы не будем углубляться в полемику о том почему на больших проектах С++ смотрится выигрышней, также не будем мы затрагивать самой концепции ООП - все это тема отдельной статьи (может и не одной) или книги... хотя вряд ли стоит ее писать... подобных трудов да от именитых авторов бессчетное множество. Нас интересует достаточно приземленная проблема: как классы из чистого текста можно преобразовать в наглядную модель с обеспечением всех графических связей...

Как и ранее, попробуем проделать реверсинжениринг используя простой класс. За основу программы перепишем (подстроим) структуру под класс. Получим в итоге нечто похожее на следующий листинг:

//It's main class class string{ public: char *string; //Structure's pointer int buffer[100]; //Temporary buffer char name[10]={"Massiv"}; //Name of data int a; //Integer int b; //Integer void string(void); //constructor void ~string(void); //destructor char StringCopy(char *, //Buffer char *, //source1 char *); //source2 private: int tmp_a; int tmp_b; };

Результат обратного проектирования:



Рис.6



Рис.7

Рисунок 6 показывает модель класса "string". А на рисунке 7 отображается вкладка, описывающая функции класса. Как и в случае с переменными имена функций отображаются на экране. Также доступен вход в спецификации конкретной функции. Если еще раз вернуться к листингу, то можно обратить внимание на декларацию функции "StringCopy", в которой входные параметры дотошно документированы. Так вот, если был применен подобный подход к документированию, то комментарий каждого параметра перенесется в качестве описательного комментария в соответствующую часть атрибута модели класса.


То есть, получается, очень выгодно подвергать обработке исходные тексты написанные по всем правилам программирования.

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

//It's main class class string{ public: char *string; //Structure's pointer int buffer[100]; //Temporary buffer char name[10]={"Massiv"}; //Name of data int a; //Integer int b; //Integer void string(void); //constructor void ~string(void); //destructor char StringCopy(char *, //Buffer char *, //source1 char *); //source2 private: int tmp_a; int tmp_b; }; //It's my string class MyString: public string{ public: int s,m,r; private: char ms, mss; }; //Super string class NewString: public string, MyString { public: int z; };



Рис.9

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

Вашему вниманию было предложено несколько примеров по использованию функций обратного проектирования. Можно предположить, что Rational Rose придется по душе не только аналитикам, но и проектировщика и разработчикам, поскольку ее выразительные средства визуального проектирования и анализа делают ее незаменим инструментом при создании крупных информационных систем. Особенно полно Rose раскрывает свои возможности при анализе эффективности не новой системы, а уже существующей. Вышеуказанные примеры дают представление о том, что даст инструмент при анализе проекта с целью повышение его эффективности. Данная проблема не является надуманной, поскольку подобный анализ очень нужен компаниям переводящим, например, старое программное обеспечение на новые платформы и новые технологии.


Двунаправленные ассоциации


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

Рис.2

Ниже показаны только фрагменты двух классов, с упором на сгенерированную ассоциацию.

ФАЙЛ STRING.h

* * * private: //## implementation // Data Members for Associations

//## Association: <unnamed>%39FD2E8E00AA //## begin String::<the_NewString>%39FD2E8E0399.role preserve=no public: NewString { -> RHN} NewString *the_NewString; //## end String::<the_NewString>%39FD2E8E0399.role

// Additional Implementation Declarations //## begin String%39FD295103B9.implementation preserve=yes //## end String%39FD295103B9.implementation * * *

ФАЙЛ NEWSTRING.h

* * *

private: //## implementation // Data Members for Associations

//## Association: <unnamed>%39FD2E8E00AA //## begin NewString::<the_String>%39FD2E8E03A3.role preserve=no public: String { -> RHN} String *the_String; //## end NewString::<the_String>%39FD2E8E03A3.role

// Additional Implementation Declarations //## begin NewString%39FD296801A9.implementation preserve=yes //## end NewString%39FD296801A9.implementation * * *



На чем основана работа программы


Итак, от общих тем перейдем непосредственно к тому, что умеет делать CASE Rational Rose. Являясь объектно-ориентированным инструментом моделирования, Rose базируется на UML (Universal Modeling Language) - универсальном языке моделирования, который был разработан компанией Rational именно с целью создания наиболее оптимального и универсального языка для описания как предметной области, так и конкретной задачи в программировании. Любая задача программируется при помощи определенных диаграмм. UML поддерживает построение следующих диаграмм:

Activity diagram (диаграммы описаний технологий, процессов, функций). Use case diagram (диаграммы функций). Class diagram (диаграммы классов). State diagram (диаграммы состояний); Sequence diagram (диаграммы последовательностей действий); Collaboration diagram (диаграммы взаимодействий Component diagram (диаграммы компонент); Deployment diagram (диаграммы топологии).

Соответственно, Rational Rose 2000 является инструментом, который позволяет строить указанные диаграммы при проектировании программных систем. К сожалению, объем статьи не позволяет описать назначение всех диаграмм и спецификаций! Но мы попробуем разобраться в инструменте с точки зрения разработчика, для простоты используя только один тип диаграмм - Class Diagramm.

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

На нижеследующем примере я продемонстрирую:

Как можно спроектировать класс в Rational Rose 2000 Как можно расписать спецификации отдельных компонентов класса Как получить код (c примером) Как получить детальный отчет о классе (также с примером)

Для демонстрационных целей достаточно спроектировать только один класс. Назовем его "String". В его обязанности должны входить основные операции над массивами (печать, копирование, сравнение, получение размера). В качестве идеального примера опишем сначала данный класс на чистейшем С++:

Class String{ Private: Int Counter; Int Stat; Public: Char *TmpString; Int GetStringSize(Char *); Int PrintString(Char *); IntCmpString(Char *, Char *); Int CpyString(Char *, Char *); };

Теперь средствами Rose все спроектируем в графическом виде.

Для отображения классов в Rose используется диаграмма классов. В качестве имени задаем "MyString". Далее, войдя в саму диаграмму, необходимо расписать спецификации: атрибуты (типы переменных) и операции (функции класса с формальным описанием всех параметров на входе и на выходе).



Каждый атрибут задается отдельно, ему дается комментарий, и расписывается тип (public, protected, private). На рис. 1 показан разворот спецификации для TmpString. Подобным образом расписываются все переменные.

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



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



Следующий шаг в работе - получение кода на С++. Здесь хочется развеять существующий миф о 100% генерации кода. Rational Rose 2000e Enterprise в принципе не может дать готового кода, она способна лишь спроектировать класс и расписать спецификацию каждого элемента, подставить шаблоны членов класса для дальнейшего заполнения кодом. А вот для 100% генерации рабочего кода на С++ используется Rational Rose 2000 RealTime, которую в данном случае мы не рассматриваем.

Итак, вернемся к кодогенерации (точнее сказать, к классо-генерации). Через систему меню (Tools) выбираем поддерживаемый язык для описания спроектированного класса (в данном случае это С++), вызываем "Code Generationаl". Результатом работы будет появление двух файлов: MyString.h и MyString.cpp. В первом расписывается сам класс, а второй является шаблоном для дальнейшего заполнения соответствующим кодом.

Ниже приводятся распечатки обоих файлов, для того чтобы вы имели представление о том, какой код вы получите, применяя Rational Rose:

Весь приведенный материал получен без изменения настроек и без дополнительной правки.

Имея подобный шаблон, становится не важно, какой именно разработчик начал работать над кодированием логики класса.

Для получения же подробного отчета по классу или технического задания можно воспользоваться инструментом Rational SoDA. Отчет также приведен в конце статьи.

Следующая задача, с которой поможет справиться Rational Rose - анализ существующей системы. Зачем переписывать и документировать крупные системы заново, если можно воспользоваться функцией обратного проектирования, что позволит из имеющегося кода построить визуальную модель и уже визуально дописать необходимые свойства и атрибуты, дописать новые классы. А под конец сгенерировать весь спектр файлов, необходимых для дальнейшей работы программистов.Данный подход называется Round-Trip и полностью поддерживается в RationalRose.


Немного о других языках программирования.


Казалось, что можно придумать еще в дополнение к сказанному. Что еще может содержать и без того мощный инструмент... Ан нет! Про Rose можно еще говорить и говорить. Rational Rose имеет в своем арсенале возможность прямого и обратного проектирования на: ADA, Java, C++, COM, DDL, Basic, XML, схемы Oracle и Sql srv... Но как быть тем, кто использует языки отсутствующие в списке поддержки? К сожалению компания Ratoinl не стремится расширять список поддерживаемых языков за свой счет, отдав на откуп третьим фирмам возможность заполнения языковых ниш. Это возможно по той простой причине, что Rose имеет открытое, хорошо документированное API, позволяющее любому человеку создать дополнительный модуль (мост) для любого языка! Подчеркиваю: ДЛЯ ЛЮБОГО. Естественно, при этом человек должен досканально знать UML и синтаксис языка-источника и какое-то время на данную реализацию. Пока на сегодняшний день Rose уникальный продукт в плане открытости архитектуры.

На данный момент существуют несколько компаний, например, EnsembleSystems (), занимающихся написанием подобных линков. Уже есть линки к Delphi, ErWin, Jbuilder, VisualCafe, Jdeveloper, VisualAge SmallTalk...

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

Продолжение следует...



Общее


В прошлых частях мы достаточно много времени уделили такому мощному инструменту, как Rational Rose, причем старались разглядеть данный продукт глазами разработчика (постановщика). Достаточно подробно рассмотрели процесс проектирования как прямого, так и обратного на языке С++. Естественно, что не удалось покрыть полностью все возможности пакета, так как в этом случае пришлось бы писать целую книгу. К сожалению, во время написания третьей части данной статьи (такой же описательной как и все предыдущие) вышла в свет на русском языке великолепная книга по проектированию и кодогенерации ("UML и Rational Rose". У. Боггс, М. Боггс.). Стало быть 3 часть будет последней описательной частью:

Остальные части планируются уже не в описательном формате, а в проблематичном каждая статья берет за основу конкретную проблему проектирования или анализа, а также взаимодействия Rational Rose с другими продуктами компании Rational. Например, в одной из ближайших частей мы затронем интеграцию Rose с ClearCase и Requisite Pro. Также ждет своего череда статья по интеграции с Visual Studio.



Общее введение


Компания Rational Software является лидирующей в области создания методологий и программных решений, ориентированных на программистов, аналитиков, тестировщиков. Спектр выпускаемого программного обеспечения целиком покрывает потребность всех участников проекта: от аналитиков до разработчиков и внедренцев. Все программно-методологические решения - плод многолетнего труда аналитиков и разработчиков как самой Rational, так и ее партнеров. В итоге все решения были собраны воедино. Так появился RUP - Rational Unified Process - методологическая энциклопедия, в которой описаны все шаги, необходимые для создания качественного программного продукта. Пользуясь подобной энциклопедией и применяя соответствующие инструменты, рекомендуемые Rational, команда будет создавать обеспечение качественно и в срок. "Строй быстрей и качественней!" - вот лозунг, выдвигаемый Rational.

Особое место в RUP занимают проектирование и конфигурационное управление. Особо выделяются они потому, что те два инструмента, которые поддерживаются на данных этапах (Rational Rose и Rational ClearCase), используются на протяжении всего жизненного цикла разработки программного обеспечения. Если Rose со своей стороны используют и проектировщики, и разработчики, и аналитики (практически добрая половина коллектива), то ClearCase используют все, поскольку результатом любой деятельности в мире информационных технологий является файл, который где-то необходимо хранить и не просто хранить, а знать все изменения, которые были в него внесены на каждом этапе разработки информационной системы.

Rational Rose, являясь объектно-ориентированым средством проектирования, способна моделировать ситуации любой сложности: от проектирования банковской системы до разработки кода на С++. В умелых руках Rose неоценимый инструмент!



Однонаправленные ассоциации


Для создания подобной связи Rose генерирует специальные атрибуты. Естественно, что при подобной ассоциации связь генерируется только для одного класса. При этом Rose генерирует закрытый атрибут (Private). В остальном генерация происходит так же как и в наследовании (связь показывается стрелкой Unidirectional Association). Ниже показана картинка отношения и код, сгенерированный Rose (далее в статье также будет использоваться такой же подход: описание связи, рисунок связи, сгенерированный файл заголовка).

Рис.1

ФАЙЛ NEWSTRING.H

//## begin module%1.3%.codegen_version preserve=yes // Read the documentation to learn more about C++ code generator // versioning. //## end module%1.3%.codegen_version

//## begin module%39FD296801A9.cm preserve=no // %X% %Q% %Z% %W% //## end module%39FD296801A9.cm

//## begin module%39FD296801A9.cp preserve=no //## end module%39FD296801A9.cp

//## Module: NewString%39FD296801A9; Pseudo Package specification //## Source file: C:\Program Files\Rational2\Rose\C++\source\NewString.h

#ifndef NewString_h #define NewString_h 1

//## begin module%39FD296801A9.additionalIncludes preserve=no //## end module%39FD296801A9.additionalIncludes

//## begin module%39FD296801A9.includes preserve=yes //## end module%39FD296801A9.includes

// String #include "String.h" //## begin module%39FD296801A9.additionalDeclarations preserve=yes //## end module%39FD296801A9.additionalDeclarations

//## begin NewString%39FD296801A9.preface preserve=yes //## end NewString%39FD296801A9.preface

//## Class: NewString%39FD296801A9 //## Category: <Top Level> //## Persistence: Transient //## Cardinality/Multiplicity: n

class NewString { //## begin NewString%39FD296801A9.initialDeclarations preserve=yes //## end NewString%39FD296801A9.initialDeclarations

public: //## Constructors (generated) NewString();

NewString(const NewString &right);

//## Destructor (generated) ~NewString();

//## Assignment Operation (generated) NewString & operator=(const NewString &right);


//## Equality Operations (generated) int operator==(const NewString &right) const;

int operator!=(const NewString &right) const;

//## Get and Set Operations for Associations (generated)

//## Association: <unnamed>%39FD2A2602A7 //## Role: NewString::<the_String>%39FD2A270212 const String * get_the_String () const; void set_the_String (String * value);

// Additional Public Declarations //## begin NewString%39FD296801A9.public preserve=yes //## end NewString%39FD296801A9.public

protected: // Additional Protected Declarations //## begin NewString%39FD296801A9.protected preserve=yes //## end NewString%39FD296801A9.protected

private: // Additional Private Declarations //## begin NewString%39FD296801A9.private preserve=yes //## end NewString%39FD296801A9.private

private: //## implementation // Data Members for Associations

//## Association: <unnamed>%39FD2A2602A7 //## begin NewString::<the_String>%39FD2A270212.role preserve=no public: String { -> RHN} String *the_String; //## end NewString::<the_String>%39FD2A270212.role

// Additional Implementation Declarations //## begin NewString%39FD296801A9.implementation preserve=yes //## end NewString%39FD296801A9.implementation };

//## begin NewString%39FD296801A9.postscript preserve=yes //## end NewString%39FD296801A9.postscript

// Class NewString

//## Get and Set Operations for Associations (inline)

inline const String * NewString::get_the_String () const { //## begin NewString::get_the_String%39FD2A270212.get preserve=no return the_String; //## end NewString::get_the_String%39FD2A270212.get } inline void NewString::set_the_String (String * value) { //## begin NewString::set_the_String%39FD2A270212.set preserve=no the_String = value; //## end NewString::set_the_String%39FD2A270212.set } //## begin module%39FD296801A9.epilog preserve=yes //## end module%39FD296801A9.epilog

#endif


Описание возможностей


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

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

Проектировщикам. В большинстве случаев подрядчик не может написать качественное программное обеспечение в установленный срок, поскольку заранее не были оговорены с заказчиком наиболее важные моменты в системе. Например, заказчик забыл рассказать об очень важной составляющей своей системы, а вспомнил об этом, когда увидел (запустил) предложенную готовую программу. Соответственно, проблема на данном этапе - взаимопонимание двух сторон. Значит, если проектировщик с заказчиком посредством моделирования предметной области в Rational Rose четко и скрупулезно описали каждую деталь и увидели ее в виде понятных диаграмм, то проблему взаимопонимания можно отбросить. Таким образом, при разработке современных информационных систем много времени уделяется проектированию (моделированию предметной области), поскольку необходимо изначально договориться с заказчиком обо всех нюансах, а не вносить в режиме "пожарной команды" изменения на более поздних этапах. То есть Rational Rose поможет на концептуальном уровне разобраться с генеральным планом автоматизации. Для улучшения взаимопонимания обеих сторон совместно с Rose применяют инструмент SoDA, позволяющий на основе построенной модели дать полный отчет по ее состоянию, соответствующий всем общепризнанным мировым стандартам (в частности ISO 9000). Как видим, внедрение Rose на предприятии позволяет, в дополнение к вышеописанному, структурировать сопроводительную документацию, привести ее к необходимому стандарту с минимальными девиациями.


Разработчикам. Не меньше возможностей Rose дает и разработчикам. Давайте снова повторим очевидную вещь: информационные системы конца 90 гг. вышли на такой уровень сложности, что справиться с ними уже под силу только крупным компаниям с большим количеством узкоспециализированных разработчиков. Времена программистов-одиночек ушли в небытие. В современных условиях механизм "сам все сделаю" дает явный сбой. В качестве второй проблемы можно отметить некоторую текучесть кадров на отдельно взятом предприятии. Каждый раз, при включении нового сотрудника в проект, необходимо посвящать его во все детали проекта, на что уходит драгоценное время коллег, отрываемых от основной работы. При наличии же Rose достаточно показать все диаграммы проекта и предоставить проектную документацию, сгенерированную на основе полученной модели, как все станет на свои места. Разработчик увидит как весь проект в целом, так и свою часть. Конкретно же в плане разработки Rose поддерживает проектирование, основанное на двух способах: прямом и обратном. В режиме прямого проектирования разработчик рисует определенным образом диаграммы классов и их взаимодействия, а на выходе получает сгенерированный код на определенном языке программирования. В режиме же обратного проектирования возможно построение модели на базе имеющегося исходного кода. Из этого следует самая главная возможность для разработчиков: повторное проектирование (Round-trip), когда разработчик описывает классы в Rose, генерирует код, дописывает необходимую полнофункциональную часть и снова закачивает в Rose, для представления того, что же система получила в результате его действий.
Важнейшим свойством Rational Rose принято считать открытость архитектуры, что позволяет дополнять имеющийся в ней инструментарий новыми функциями. Например, в стандартном варианте Rose не поддерживает кодогенерацию на Ассемблере: Путем написания дополнительного модуля подобную проблему можно решить. Спешу обрадовать, на Западе достаточно компаний, выпускающих подобные модули расширения для различных языков программирования, правда, на Ассемблере еще нет, но мы будем надеяться!


Вот список включенных стандартных модулей: С++, ADA, CORBA, Visual Basic, XML, COM, Oracle). То есть Rational Rose способна проводить прямое и обратное проектирование в данных системах.
Подведем первые итоги того, что может делать Rational Rose
Проектировать системы любой сложности Давать развернутое представление о проекте в сочетании со средствами документирования (SoDA) Проводить кодогенерацию Проводить обратное проектирование имеющихся систем Имеет открытый для дополнений интерфейс Интегрируется со средствами разработки (Visual Studio) Поддержка языка UML Наличие средств автоматического контроля, в том числе проверки соответствия двух моделей Удобный для пользователя графический интерфейс Многоплатформенность Интегрируемость с другими инструментальными средствами, поддерживающими жизненный цикл программных систем, в том числе со средством управления требованиями (Requisite Pro), со средствами тестирования (SQA Suite, Performance Studio), со средствами конфигурационного управления (ClearCase, PVCS).

Данной статьей мне хочется открыть


"Долго запрягается, но быстро едет..." -

стиль жизни отечественного разработчика...
Данной статьей мне хочется открыть ретроспективу материалов по Rational Rose. Долгое время у меня вызывало сомнение необходимость подобного эссе, поскольку про Розу сказано достаточно много во всех периодических изданиях. Аналитики и проектировщики имеют представление о данном продукте и приблизительно знают, к чему его применить. Проблема только в разработчиках, которые либо не до конца представляют возможности пакета, либо имеют неправильную установку. Сия установка (комплекс) получается в результате того, что сам инструмент Rational Rose - широкопрофильный, покрывающий все большую часть аналитиков, проектировщиков и все тех же разработчиков. А по традиции его используют активно только первые две категории работников, поскольку для них очевидна необходимость применения CASE средств для описания как модели предприятия, так и бизнес-процессов и пр:
То, что может дать разработчикам собственно сама Роза, мы поговорим на страницах статьи, сейчас же необходимо отметить, что основное ее предназначение - это проектирование классов и реинжениринг уже существующих:
Вот мы плавно и подошли к камню преткновения: Ни для кого не секрет, что разработчик, профессионально владеющий инструментом (языком программирования, оболочкой, и пр.), очень неохотно использует новые инструменты, не говоря о методологиях. В этом случае пушистый котеночек превращается в ежа с большим количеством острых иголок, направленных на отстаивание собственной позиции (по иголке на каждую!). В первую очередь, поэтому все новое так трудно приживается на нашей российской ниве.
Вернемся от общих размышлений к продукту. В разработческих кругах основательно засело мнение о том, что: 1) генерация программ невозможна в принципе (по слухам-то, Роза как раз и генерирует программы), 2) генераторы никогда не смогут генерировать эффективный код!!! Ну что можно сказать по такому поводу?! Конечно же, часть возражений можно принять в расчет, но в основном это не так!


Начнем развеивать мифы:
Rational Rose не собирается за вас генерировать 100% исполняемый код! Ее задача состоит в генерации расписанных (разрисованных) классов на определенном языке программирования. По поводу кода: а это как посмотреть! В свое время тоже не верилось в трансляцию с высокоуровневого языка в машинные коды! А сейчас ведь есть уже ни один набор оптимизирующих компиляторов! Это разве не прогресс??? Скорее всего, Rose в недалеком будущем научится создавать гарантированно высококачественный код.
Еще раз хочу отметить, что Rose позволит упростить разработку сложных классов посредством выразительных возможностей по графическому представлению классов и их взаимоотношений.
Данная статья является моей попыткой продемонстрировать Rational Rose именно с точки зрения разработчика. Подобная попытка уже была предпринята мною несколько ранее в статьях по конфигурационному управлению (Clear Case), по средствам тестирования (Rational Purify, Quantify, PureCoverage). Подобная очередность не случайна, поскольку их назначение для меня, как для разработчика, очевидно и не требует дополнительного пояснения, чего не скажешь про Rational Rose. Здесь кавалерийский наскок не получился! Пришлось разбираться продукте и вникать во все детали. Плодом разбирательств и является данная статья. В ней я попытаюсь объяснить, зачем Rose нужен разработчикам.
По своей структуре статья - это "ужастик" с продолжением!!! Сейчас мне трудно сказать, сколько будет в ней частей: но никак не меньше 3. А вообще, я призываю всех разработчиков, прочитавших первую часть, высказать свое мнение о ней и дать рекомендации по дальнейшему "продвижению"!!! Данная информация от Вас мне очень и очень важна, просто не хочется писать о том, что не вызывает интереса!!!
Итак, ниже вам предложена первая, очень общая статья в стиле доклада. В ней приводятся только общие моменты с конкретными примерами на С++.
Приятного чтения!

Read the documentation to learn


Пример кодогенерации.

Файл MyString.h
//## begin module%1.3%.codegen_version preserve=yes // Read the documentation to learn more about C++ code generator // versioning. //## end module%1.3%.codegen_version
//## begin module%395AF70D0321.cm preserve=no // %X% %Q% %Z% %W% //## end module%395AF70D0321.cm
//## begin module%395AF70D0321.cp preserve=no //## end module%395AF70D0321.cp
//## Module: MyString%395AF70D0321; Pseudo Package specification //## Source file: C:\Program Files\Rational\Rose\C++\source\MyString.h #ifndef MyString_h #define MyString_h 1
//## begin module%395AF70D0321.additionalIncludes preserve=no //## end module%395AF70D0321.additionalIncludes
//## begin module%395AF70D0321.includes preserve=yes //## end module%395AF70D0321.includes
//## begin module%395AF70D0321.additionalDeclarations preserve=yes //## end module%395AF70D0321.additionalDeclarations
//## begin MyString%395AF70D0321.preface preserve=yes //## end MyString%395AF70D0321.preface
//## Class: MyString%395AF70D0321 // Данный класс позволяет проводить различные операции над // массивами символов. //## Category: <Top Level> //## Persistence: Transient //## Cardinality/Multiplicity: n
class MyString { //## begin MyString%395AF70D0321.initialDeclarations preserve=yes //## end MyString%395AF70D0321.initialDeclarations
public: //## Constructors (generated) MyString();
//## Destructor (generated) ~MyString();
//## Assignment Operation (generated) MyString & operator=(const MyString &right);
//## Equality Operations (generated) int operator==(const MyString &right) const; int operator!=(const MyString &right) const;
//## Other Operations (specified) //## Operation: GetStringSize%395AF87900E9 // Подсчитывает количество символов в переданном массиве Int GetStringSize (Char *massiv // Указатель на массив );
//## Operation: PrintString%395AF88800B9 // Печатает на экране переданный массив Int PrintString (Char *Massiv // Указатель на массив );
//## Operation: CmpString%395AF892013F // Сравнивает два массива.
Int CmpString (Char *Str1, // Указатель на первый массив Char *Str2 // Указатель на второй массив );
//## Operation: CpyString%395AF89C00D5 // Копирует один массив в другой Int CpyString (Char *Dest, // Назначение Char *Source // Источник );
//## Get and Set Operations for Class Attributes (generated)
//## Attribute: Stat%395AF8BB0289 // Общедоступная переменная числа обращений к PrintString const Int get_Stat () const; void set_Stat (Int value);
//## Attribute: Count%395AF8C20148 // Определяет статус определенного объекта const Int get_Count () const; void set_Count (Int value);
// Additional Public Declarations //## begin MyString%395AF70D0321.public preserve=yes //## end MyString%395AF70D0321.public
protected: // Additional Protected Declarations //## begin MyString%395AF70D0321.protected preserve=yes //## end MyString%395AF70D0321.protected
private: //## Get and Set Operations for Class Attributes (generated) //## Attribute: TmpString%395AF8B201E5 // Временный указатель на строковый массив. Можно // использовать в качестве буфера const Char * get_TmpString () const; void set_TmpString (Char * value);
// Additional Private Declarations //## begin MyString%395AF70D0321.private preserve=yes //## end MyString%395AF70D0321.private
private: //## implementation // Data Members for Class Attributes
//## begin MyString::TmpString%395AF8B201E5.attr preserve=no private: Char * {U} Char *TmpString; //## end MyString::TmpString%395AF8B201E5.attr
//## begin MyString::Stat%395AF8BB0289.attr preserve=no public: Int {U} Int Stat; //## end MyString::Stat%395AF8BB0289.attr
//## begin MyString::Count%395AF8C20148.attr preserve=no public: Int {U} Int Count; //## end MyString::Count%395AF8C20148.attr
// Additional Implementation Declarations //## begin MyString%395AF70D0321.implementation preserve=yes //## end MyString%395AF70D0321.implementation }; //## begin MyString%395AF70D0321.postscript preserve=yes //## end MyString%395AF70D0321.postscript
// Class MyString
//## Get and Set Operations for Class Attributes (inline)


inline const Char * MyString::get_TmpString () const { //## begin MyString::get_TmpString%395AF8B201E5.get preserve=no return TmpString; //## end MyString::get_TmpString%395AF8B201E5.get }
inline void MyString::set_TmpString (Char * value) { //## begin MyString::set_TmpString%395AF8B201E5.set preserve=no TmpString = value; //## end MyString::set_TmpString%395AF8B201E5.set }
inline const Int MyString::get_Stat () const { //## begin MyString::get_Stat%395AF8BB0289.get preserve=no return Stat; //## end MyString::get_Stat%395AF8BB0289.get }
inline void MyString::set_Stat (Int value) { //## begin MyString::set_Stat%395AF8BB0289.set preserve=no Stat = value; //## end MyString::set_Stat%395AF8BB0289.set }
inline const Int MyString::get_Count () const { //## begin MyString::get_Count%395AF8C20148.get preserve=no return Count; //## end MyString::get_Count%395AF8C20148.get }
inline void MyString::set_Count (Int value) { //## begin MyString::set_Count%395AF8C20148.set preserve=no Count = value; //## end MyString::set_Count%395AF8C20148.set }
//## begin module%395AF70D0321.epilog preserve=yes //## end module%395AF70D0321.epilog
#endif

Read the documentation to learn


Пример кодогенерации.

Файл MyString.cpp
//## begin module%1.3%.codegen_version preserve=yes // Read the documentation to learn more about C++ code generator // versioning. //## end module%1.3%.codegen_version
//## begin module%395AF70D0321.cm preserve=no // %X% %Q% %Z% %W% //## end module%395AF70D0321.cm
//## begin module%395AF70D0321.cp preserve=no //## end module%395AF70D0321.cp
//## Module: MyString%395AF70D0321; Pseudo Package body //## Source file: C:\Program Files\Rational\Rose\C++\source\MyString.cpp
//## begin module%395AF70D0321.additionalIncludes preserve=no //## end module%395AF70D0321.additionalIncludes
//## begin module%395AF70D0321.includes preserve=yes //## end module%395AF70D0321.includes
// MyString #include "MyString.h" //## begin module%395AF70D0321.additionalDeclarations preserve=yes //## end module%395AF70D0321.additionalDeclarations
// Class MyString
MyString::MyString() //## begin MyString::MyString%395AF70D0321_const.hasinit preserve=no //## end MyString::MyString%395AF70D0321_const.hasinit //## begin MyString::MyString%395AF70D0321_const.initialization preserve=yes //## end MyString::MyString%395AF70D0321_const.initialization { //## begin MyString::MyString%395AF70D0321_const.body preserve=yes //## end MyString::MyString%395AF70D0321_const.body }
MyString::~MyString() { //## begin MyString::~MyString%395AF70D0321_dest.body preserve=yes //## end MyString::~MyString%395AF70D0321_dest.body }
MyString & MyString::operator=(const MyString &right) { //## begin MyString::operator=%395AF70D0321_assign.body preserve=yes //## end MyString::operator=%395AF70D0321_assign.body }
int MyString::operator==(const MyString &right) const { //## begin MyString::operator==%395AF70D0321_eq.body preserve=yes //## end MyString::operator==%395AF70D0321_eq.body }
int MyString::operator!=(const MyString &right) const { //## begin MyString::operator!=%395AF70D0321_neq.body preserve=yes //## end MyString::operator!=%395AF70D0321_neq.body }
//## Other Operations (implementation)
Int MyString::GetStringSize (Char *massiv) { //## begin MyString::GetStringSize%395AF87900E9.body preserve=yes //## end MyString::GetStringSize%395AF87900E9.body }
Int MyString::PrintString (Char *Massiv) { //## begin MyString::PrintString%395AF88800B9.body preserve=yes //## end MyString::PrintString%395AF88800B9.body }
Int MyString::CmpString (Char *Str1, Char *Str2) { //## begin MyString::CmpString%395AF892013F.body preserve=yes //## end MyString::CmpString%395AF892013F.body }
Int MyString::CpyString (Char *Dest, Char *Source) { //## begin MyString::CpyString%395AF89C00D5.body preserve=yes //## end MyString::CpyString%395AF89C00D5.body }
// Additional Declarations //## begin MyString%395AF70D0321.declarations preserve=yes //## end MyString%395AF70D0321.declarations
//## begin module%395AF70D0321.epilog preserve=yes //## end module%395AF70D0321.epilog

Brief Description Данный класс позволяет


Пример отчета в SoDA
Class
MyString
Report

Issue <1.0>

Revision History
DateIssueDescriptionAuthor
<dd/mmm/yy><x.x><details><name>
    
    
    

Table of Contents
1Brief Description18
2.Responsibilities18
3.Operations18
4.Attributes18
5.Relationships19
5.1Associations19
5.2Aggregations19
5.3Generalizations19
6.State Diagram19


Class
MyString
Report

Brief Description Данный класс позволяет проводить различные операции над массивами символов. Responsibilities No operations of stereotype <<responsibility>> have been defined. Operations CmpString (Str1: Char *, Str2: Char *): Int Documentation: Сравнивает два массива. CpyString (Dest: Char *, Source: Char *): Int Documentation: Копирует один массив в другой GetStringSize (massiv: Char *) : Int Documentation: Подсчитывает количество символов в переданном массиве PrintString (Massiv: Char *): Int Documentation: Печатает на экране переданный массив Attributes TmpString: Char * Documentation: Временный указатель на строковый массив. Можно использовать в качестве буфера Stat: Int Documentation: Общедоступная переменная числа обращений к PrintString Count: Int Documentation: Определяет статус определенного объекта Relationships 1.1 Associations No associations have been defined. 1.2 Aggregations No aggregations have been defined. 1.3 Generalizations No generalizations have been defined. State Diagram There is no state diagram defined for class MyString.
См. также:

Семь раз исправь,


© Новичков А.Н.
, 2000

" Семь раз исправь, - десять отладь:" -

любимое занятие разработчика:



© Новичков А.Н.
, 2000

"С кем подружился... так тебе и надо...",

- способы внедрения CASE технологий....

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

Теперь вашему вниманию предлагается следующая часть статьи по Rational Rose, которая, как и прежде, целиком ориентированна на разработчиков, использующих в своей повседневной жизни язык С++. Дабы сильно не затягивать вступление расскажу о чем пойдет речь на этот раз.

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

Так первую часть мы целиком посвещаем обратному проектированию.


Сложные материи.


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

Давайте для начала вкратце проанализируем возможности Rational Rose в генерации и визуализации различных ассоциаций, связей и классов.

Одно и двунаправленные ассоциации Ассоциации "один ко многим" и "многие ко многим" Ассоциации с ограниченной множественностью



Связь "многие ко многим"


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



При кодогенерации следует учитывать одно


При кодогенерации следует учитывать одно "но". Все что происходит по умолчанию не всегда может устроить конкретного раработчика. Даже учитывая то, что инструмент изначально настроен на генерацию правильного и качественного кода, все равно Rose требует дополнительной подстройки под конкретный проект (релиз.. и пр.)
Мощные выразительные свойства в Rational Rose сочетаются с гибкой системой подсказок и настроек. Так, например, Rose позволяет проводить не только простую настройку инструментальной панели (Это возможность стала давно тривиальной, и рассматривать ее как нечто выдающееся нет необходимости), но и что очень важно - настраивать по своему усмотрению внешний вид диаграмм, для которых отсутствует картинка.
Внутренне устроение Rose позволяет менять системный файл "defaultstereotypes.ini", в котором содержатся наименования предопределенных стереотипов со ссылками на соответствующие картинки. Так если пользователя не устраивает картинка, то он спокойно может заме-нить ссылку на свой графический файла. Правда при этом следует учитывать, что все рисунки должны храниться только в формате WMF, и иметь длину не более 512 байт.