Лекция № 4. Быстрая разработка приложений. Технологичность программного обеспечения
Содержание лекции: технология быстрой разработки приложений; оценка качества процессов создания программного обеспечения; технологичность ПО.
Цель лекции:рассмотреть использование RAD-технологии и существующие методы оценки качества процессов создания программного обеспечения; а также приемы обеспечения эффективности и технологичности программного обеспечения.
Современная технология проектирования, разработки и сопровождения программного обеспечения, должна отвечать следующим требованиям [1]:
а) поддержка полного жизненного цикла программного обеспечения;
б) гарантированное достижение целей разработки с заданным качеством
и в установленное время;
в) координация ведения проекта с возможностью выполнения крупных проектов в виде подсистем, разрабатываемых группами исполнителей ограниченной численности, с последующей интеграцией составных частей;
г) минимальное время получения работоспособной системы;
д) возможность управления конфигурацией проекта, ведения версий и автоматического выпуска проектной документации по каждой версии;
е) независимость проектных решений от средств реализации;
ж) поддержка комплексом CASE-средств, обеспечивающих автоматиза-цию процессов, выполняемых на всех стадиях жизненного цикла.
Этим требованиям отвечает технология RAD(Rapid Application Development - Быстрая разработка приложений), ориентирована на максимально быстрое получение первых версий разрабатываемого программного обеспечения и предусматривающая выполнение следующих условий [3]:
а) ведение разработки небольшими группами исполнителей (3-7 человек), каждая из которых проектирует и реализует отдельные подсистемы проекта, что позволяет улучшить управляемость проекта;
б) использование итерационного подхода, способствующего уменьшению времени получения работоспособного прототипа;
в) наличие четко проработанного графика цикла, рассчитанного не более
чем на три месяца, что существенно увеличивает эффективность работы.
Процесс разработки делится на этапы анализа и планирования требований пользователей, проектирования, реализации, внедрения.
На этапе анализа и планирования требований формулируют наиболее приоритетные требования, что ограничивает масштаб проекта.
На этапе проектирования, используя имеющиеся CASE-средства, детально описывают процессы системы, устанавливают требования разграничения доступа к данным и определяют состав необходимой документации. При этом для наиболее сложных процессов создают частичный прототип: разрабатывают экранную форму и диалог. По результатам анализа процессов определяют количество так называемых функциональных точек и принимают решение о количестве подсистем и, соответственно, команд, участвующих в разработке. Под функциональной точкойв технологии RAD понимают любой из функциональных элементов разрабатываемой системы: входной элемент приложения; выходной элемент приложения; запрос; логический файл; интерфейс приложения. В соответствии с нормами, рассчитанными исходя из экспертных оценок, разрабатываемую систему делят на подсистемы, слабо связанные по данным и функциям, и точно определяют интерфейсы между различными частями. Использование CASE-средств позволяет избежать неконтролируемого искажения данных при передаче информации о проекте со стадии на стадию. Далее разработка ведется группами разработчиков, которые продолжают прорабатывать свои части системы, при этом их должны быть хорошо скоординированы.
На этапе реализации выполняют итеративное построение реальной системы, причем для контроля над выполнением требований к создаваемой системе привлекаются будущие пользователи. Части постепенно интегрируют в систему, при подключении каждой части выполняют тестирование. Определяют необходимость создания соответствующих баз данных, подключаемых к системе, формулируют требования к аппаратным средствам, устанавливают способы увеличения производительности и завершают подготовку документации по проекту.
На этапе внедрения проводят обучение пользователей и осуществляют постепенный переход на новую систему, причем эксплуатация старой версии продолжается до полного внедрения новой системы.
Технология RAD хорошо зарекомендовала себя для небольших проектов, разрабатываемых для конкретного заказчика. Такие системы не требуют высокого уровня планирования и жесткой дисциплины проектирования. Однако эта технология неприменима для построения сложных расчетных программ, операционных систем или программ управления сложными объектами в реальном масштабе времени, т. е. программ с большим процентом уникального кода. Ее использование полностью исключается в случае создания приложений, от которых зависит безопасность людей, так как технология RAD предполагает, что первые версии не будут полностью работоспособны.
Текущий период на рынке программного обеспечения характеризуется переходом от штучного ремесленного производства программных продуктов к их промышленному созданию. Существенно возросли требования к качеству разрабатываемого программного обеспечения, что требует совершенствования процессов их разработки. К наиболее известным стандартам, связанным с оценкой качества этих процессов относят [4]:
а) международные стандарты серии ISO 9000 (ISO 9000 - ISO 9004), где сформулированы необходимые условия для достижения некоторого минимального уровня организации процесса, но не дается никаких рекомендаций по дальнейшему совершенствованию процессов;
б) СММ - Capability Maturity Model - модель зрелости (совершенствования) процессов создания программного обеспечения, предложенная SEI (Software Engineering Institute - институт программирования при университете Карнеги-Меллон), которая представляет собой совокупность критериев оценки зрелости организации-разработчика и рецептов улучшения существующих процессов. СММ определяет пять уровней зрелости организаций-разработчиков, причем каждый последующий уровень включает в себя все ключевые характеристики предыдущих: 1 - начальный уровень(initial level); 2 - повторяемый уровень(repeatable level); 3 - определенный уровень(defined level); 4 - управляемый уровень(managed level); 5 - оптимизирующий уровень(optimizing level). При этом сертификационная оценка соответствия ключевых областей проводится по 10-балльной шкале. Оценкаключевой областивыполняется по следующим показателям: заинтересованность руководства в данной области; насколько широко область применяется в организации; успешность использования данной области на практике. Допускается сертификация одного процесса или подразделения организации;
в) рабочая версия международного стандартаISO/IEC 15504: Information Technology - Software Process Assessment, более известная под названием SPICE - (Software Process Improvement and Capability Determination - определение возможностей и улучшение процесса создания программного обеспечения), унаследовавшая многие черты более ранних стандартов, в том числе ISO 9001 и СММ. Так же, как и в СММ, основной задачей является постоянное улучшение процесса разработки программного обеспечения, кроме того, в SPICE тоже используется схема с различными уровнями возможностей (в SPICE определено 6 различных уровней). В основу стандарта положена оценка процессов, которая выполняется путем сравнения процесса разработки программного обеспечения, существующего в данной организации, с описанной в стандарте моделью. Анализ результатов помогает определить сильные и слабые стороны процесса, а также внутренние риски, присущие данному процессу, что позволяет оценить эффективность процессов, определить причины ухудшения качества и связанные с этим издержки во времени или стоимости.
Таким образом, создание программных продуктов по-прежнему предъявляет повышенные требования к квалификации проектировщиков и программистов. Качество проекта программного продукта, от которого зависят трудовые и материальные затраты на его реализацию и последующие модификации, называют технологичностью. Хороший проект быстро и легко кодируется, тестируется, отлаживается и модифицируется. Технологичность программного обеспечения определяется проработанностью его моделей, уровнем независимости модулей, стилем программирования и степенью повторного использования кодов.Высокая технологичность проекта особенно важна, если необходимо обеспечить повышенные требования к его качеству или разрабатывается программный продукт, рассчитанный на многолетнее интенсивное использование.
Традиционно эффективными считаются программы, требующие минимального времени выполнения и/или минимального объема оперативной памяти. Особые требования к эффективности программного обеспечения предъявляются при наличии ограничений (на объем оперативной памяти, время реакции системы). Разумный подход к обеспечению эффективности программного обеспечения состоит в том, чтобы в первую очередь оптимизировать те фрагменты программы, которые существенно влияют на характеристики эффективности. Однако многие способы снижения временных затрат приводят к увеличению емкостных и, наоборот, уменьшение объема памяти может потребовать дополнительного времени на обработку. Частично проблему эффективности программ решают за программиста компиляторы. Используемые ими средства оптимизации делятся на машинно-зависимые и машинно-независимые.Конечно, нельзя вмешаться в работу компилятора, но существуют возможности оптимизации на уровне команд.
Принятие мер по экономии памяти предполагает, что в каких-то случаях эта память неэкономно использовалась. Имеет смысл анализировать только операции размещения данных, существенновлияющие на характеристику эффективности (например, выделение памяти под данные структурных типов: массивов, записей, объектов). Следует выбирать алгоритмы обработки, не требующие дублирования исходных данных структурных типов в процессе обработки.Если в программе имеются большие массивы, используемые ограниченное время, их можно размещать в динамической памяти и удалять при завершении обработки. При передаче структурных данных в подпрограмму «по значению», копии этих данных размещаются в стеке. Избежать копирования иногда удается, если передавать данные «по ссылке», но как неизменяемые const (в стеке размещается только адрес данных).
Для уменьшения времени выполнения в первую очередь необходимо анализировать циклические участки программы с большим количеством повторений: по возможности следует выносить вычисление константных выражений из циклов, избегать «длинных» операций умножения и деления, заменяя их сложением, вычитанием и сдвигами, минимизировать преобразования типов в выражениях, исключать лишние проверки при записи условных выражений и многократные обращения к элементам массивов по индексам, избегать использования различных типов в выражении.
За увеличение эффективности не следует «платить» снижением технологичности разрабатываемого программного обеспечения. Исключения возможны лишь при очень жестких требованиях и наличии соответствующего контроля за качеством.
Дополнительную информацию по теме можно получить в [1, 3, 4, 7, 8].
5 Лекция № 5. Приемы обеспечения технологичности программных продуктов
Содержание лекции: модули и их свойства; нисходящая и восходящая разработка ПО.
Цель лекции: рассмотреть существующие способы декомпозиции ПО, методы разработки программного обеспечения.
При проектировании достаточно сложного ПО используют два способа декомпозиции разрабатываемого программного обеспечения, связанные с соответствующим подходом: процедурный (структурный) и объектный.
Результатом процедурной декомпозицииявляется иерархия подпрограмм (процедур), где функции принятия решения реализуются подпрограммами верхних уровней, а обработка - подпрограммами нижних уровней. Это согласуется с принципом вертикального управления,который был сформулирован вместе с другими рекомендациями структурного подхода к программированию и ограничивает возможные варианты передачи управления, требуя, чтобы любая процедура возвращала управление той подпрограмме, которая ее вызвала. Результатом объектной декомпозиции является совокупность объектов, которые реализуются как переменные некоторых специально разрабатываемых типов.
При любом способе декомпозиции получают набор связанных с соответствующими данными подпрограмм, которые в процессе реализации организуют в модули- автономно компилируемыепрограммные единицы. Первоначально, когда размер программ был невелик, и подпрограммы компилировались отдельно, под модулем понималась последовательность связанных фрагментов программы, обращение к которой выполняется по имени.Со временем, когда размер программ значительно вырос, и появилась возможность создавать библиотеки ресурсов, под модулем стали понимать автономно компилируемый набор программных ресурсов. Данные модуль получает и/или возвращает через общие области памяти или параметры. Чем выше степень независимости модулей, тем легче разобраться в отдельном модуле и всей программе, тестировать, отлаживать и модифицировать ее; меньше вероятность появления новых ошибок приисправлении старых или внесении изменений в программу; проще организовать разработку программы группой программистов и легче ее сопровождать. Уменьшение зависимости модулей улучшает технологичность проекта. Степень независимости модулей оценивается двумя критериями: сцеплениемисвязностью.
Сцепление - это мера взаимозависимости модулей, определяющая насколько хорошо модули отделены друг от друга. Модули независимы, если каждый из них не содержит никакой информации о другом модуле. Различают пять типов сцепления модулей:
а) сцепление по данным - модули обмениваются данными в скалярных значениях. При небольшом количестве передаваемых параметров этот тип обеспечивает наилучшие технологические характеристики ПО;
б) сцепление по образцу - модули обмениваются данными, объединен-ными в структуры. Однако, уменьшается «прозрачность» связи между модулями, так как передаваемые данные «спрятаны» в структуры, а при изменении структуры необходимо модифицировать все использующие ее модули. Дает неплохие характеристики, но хуже, чем у предыдущего типа;
в) сцепление по управлению - один модуль посылает другому некоторый информационный объект (флаг), предназначенный для управления внутренней логикой модуля. Такие настройки снижают наглядность взаимодействия модулей и обеспечивают худшие характеристики технологичности программ по сравнению с предыдущими типами;
г) сцепление по общей области данных - модули работают с общей областью данных. Считается недопустимым, поскольку программы, использующие данный тип сцепления, сложны для понимания при сопровождении ПО; ошибка одного модуля, приводящая к изменению общих данных, может проявиться при выполнении другого модуля; при ссылке к данным в общей области модули используют конкретные имена, что уменьшает гибкость разрабатываемого ПО;
д) сцепление по содержимому - один модуль содержит обращения к внутренним компонентам другого (передает управление внутрь, читает и/или изменяет внутренние данные или сами коды), что полностью противоречит блочно-иерархическому подходу. Отдельный модуль в этом случае уже не является блоком («черным ящиком»): его содержимое должно учитываться в процессе разработки другого модуля. Такой вид сцепления остается возможным для языков низкого уровня, например, Ассемблера.
Допустимыми считают первые три типа сцепления, использование остальных приводит к резкому ухудшению технологичности программ. Как правило, модули сцепляются между собой несколькими способами. Учитывая это, качество принято определять по типу сцепления с худшими характеристиками. Например, при использовании сцепления по данным и сцепления по управлению, определяющим считают сцепление по управлению.
Связность- мера прочности соединения функциональных и информационных объектов внутри одного модуля, т.е. степень взаимосвязи элементов, реализуемых одним модулем. Размещение сильно связанных элементов в одном модуле уменьшает межмодульные связи и взаимовлияние модулей. В то же время размещение сильно связанных элементов в разных модулях не только усиливает межмодульные связи, но и усложняет понимание их взаимодействия. Объединение слабо связанных элементов также уменьшает технологичность модулей, так как такими элементами сложнее мысленно манипулировать. Различают следующие виды связности:
а) функциональная - все объекты модуля предназначены для выполнения одной функции;
б) последовательная - выход одной функции служит исходными данными для другой функции;
в) информационная - функции, обрабатывающие одни и те же данные;
г) процедурная - функции или данные, которые являются частями одного процесса;
д) временная - функции выполняются параллельно или в течение некоторого периода времени;
е) логическая - базируется на объединении данных или функций в одну логическую группу;
ж) случайная - связь между элементами мала или отсутствует.
Целесообразно использовать функциональную, последовательную и информационную связности.
При рассмотрении модуля как библиотеки ресурсоввыделяют библиотеки подпрограмм, реализующие функции, близкие по назначению, и библиотеки классов, реализующие близкие по назначению классы. В качестве средства улучшения технологических характеристик библиотек ресурсов используют разделение тела модуля на интерфейсную частьиобласть реализации (в Паскале –Interface и Implementation, в C++ - h и cpp-файлы). Интерфейсная частьсодержит совокупность объявлений ресурсов (заголовков функций, имен переменных, типов, классов), предоставляемых другим модулям. Необъявленные ресурсы извне не доступны. Область реализации содержит тела подпрограмм и внутренние ресурсы (подпрограммы, переменные, типы), используемые этими подпрограммами. При такой организации любые изменения реализации библиотеки, не затрагивающие ее интерфейс, не требуют пересмотра модулей, связанных с библиотекой, что улучшает технологичность модулей-библиотек.
При проектировании, реализации и тестировании компонентов структурной иерархии применяют два подхода: восходящий и нисходящий [8].
При использовании восходящего подхода сначала проектируют и реализуют компоненты нижнего уровня, затем предыдущего и т.д. По мере завершения тестирования и отладки компонентов осуществляется их сборка, причем компоненты нижнего уровня помещают в библиотеки компонентов. Для тестирования и отладки разрабатывают специальные тестирующие программы. Недостатки: увеличивается вероятность несогласованности компонентов из-за неполноты спецификаций; издержки на проектирование и реализацию тестирующих программ, которые не преобразуют в компоненты; позднее проектирование интерфейса, невозможность продемонстрировать его заказчику для уточнения спецификаций. При промышленном изготовлении ПО восходящий подход практически не используют.
Нисходящий подход предполагает, что проектирование и последующая реализация компонентов выполняется «сверху-вниз»: вначале проектируют компоненты верхних уровней иерархии, затем следующих и так далее до самых нижних уровней. В той же последовательности выполняют и реализацию компонентов. При программировании компоненты нижних не реализованных уровней заменяют специально разработанными отладочными модулями - «заглушками», что позволяет тестировать и отлаживать уже реализованную часть. При использовании нисходящего подхода применяют иерархический, операционный и комбинированный методы определенияпоследовательности проектирования и реализации компонентов.
Иерархический методпредполагает выполнение разработки строго по уровням. Исключения допускаются при наличии зависимости по данным (если обнаруживается, что некоторый модуль использует результаты другого, то его программируют после этого модуля). Недостаток метода: большое количество достаточно сложных заглушек, а при использовании данного метода основная масса модулей разрабатывается и реализуется в конце работы над проектом, что затрудняет распределение человеческих ресурсов.
Операционный методсвязывает последовательность разработки модулей с порядком их выполнения при запуске программы. Применение метода усложняется тем, что порядок выполнения модулей может зависеть от данных, а модули вывода результатов должны разрабатываться одними из первых, чтобы не проектировать сложную заглушку, обеспечивающую вывод результатов при тестировании. С точки зрения распределения человеческих ресурсов сложным является начало работ, пока не закончены все модули, находящиеся на так называемом критическом пути.
Комбинированный методучитывает все факторы, влияющие на последовательность разработки: достижимость модуля (наличие всех модулей в цепочке вызова данного модуля); зависимость по данным (модули, формирующие некоторые данные, должны создаваться раньше обрабатывающих); обеспечение возможности выдачи результатов (модули вывода результатов должны создаваться раньше обрабатывающих); готовность вспомогательных модулей (вспомогательные модули, например, модули закрытия файлов, завершения программы, должны создаваться раньше обрабатывающих); наличие необходимых ресурсов. Кроме того, при прочих равных условиях сложные модули должны разрабатываться прежде простых, так как при их проектировании могут выявиться неточности в спецификациях, а чем раньше это произойдет, тем лучше.
Нисходящий подход допускает нарушение нисходящей последовательности разработки компонентов в специально оговоренных случаях. Его используют и при объектно-ориентированном программировании: вначале проектируют и реализуют пользовательский интерфейс ПО, затем разрабатывают классы базовых объектов предметной области, а уже потом, используя эти объекты, проектируют и реализуют остальные компоненты. Нисходящий подход обеспечивает максимально полное определение спецификаций проектируемого компонента и согласованность компонентов между собой, раннее определение интерфейса пользователя, демонстрация которого позволяет уточнить требования заказчика к создаваемому ПО, возможность нисходящего тестирования и комплексной отладки.
Дополнительную информацию по теме можно получить в [1, 4, 7, 8, 9].