Сложность комплексов программ

Адаптивные процессы

В настоящее время все большее распространение получают адаптивные или облегченные, «живые» (agile) процессы разработки

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

Адаптивные процессы делают упор на использовании хороших разработчиков, а не хорошо отлаженных процессов разработки

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

Принципы «живой» разработки

Основные принципы «живой» разработки ПО зафиксированы в манифесте, появившемся в 2000 году:

1.Люди, участвующие в проекте, и их общение более важны, чем процессы и инструменты

2.Работающая программа более важна, чем исчерпывающая документация

3.Сотрудничество с заказчиком более важно, чем обсуждение деталей контракта

4.Отработка изменений более важна, чем следование планам

Экстремальное программированиe

Extreme Programming, XP — авторы методологии — Кент Бек, Уорд Каннингем, Мартин Фаулер и другие.

Основные приёмы XP

  • Короткий цикл обратной связи (Fine scale feedback)

o Разработка через тестирование (Test driven development)

o Игра в планирование (Planning game)

Заказчик всегда рядом (Whole team, Onsite customer)

o Парное программирование (Pair programming)

• Непрерывный, а не пакетный процесс

o Непрерывная интеграция (Continuous Integration)

o Рефакторинг (Design Improvement, Refactor)

o Частые небольшие релизы (Small Releases)

• Понимание, разделяемое всеми

o Простота (Simple design)

o Метафора системы (System metaphor)

o Коллективное владение кодом (Collective code ownership) или выбранными шаблонами проектирования (Collective patterns ownership)

o Стандарт кодирования (Coding standard or Coding conventions)

• Социальная защищенность программиста (Programmer welfare):

o 40-часовая рабочая неделя (Sustainable pace, Forty hour week)

Тестирование

В XP особое внимание уделяется двум разновидностям тестирования:

• тестирование модулей (unit testing);

• приемочное тестирование (acceptance testing).

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

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

Для XP более приоритетным является подход, называемый TDD (Test Driven Development) — сначала пишется тест, который не проходит, затем пишется код, чтобы тест прошел, а уже после делается рефакторинг кода.

Игра в планирование

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

Заказчик всегда рядом

«Заказчик» в XP — это не тот, кто оплачивает счета, а тот, кто на самом деле использует систему. XP утверждает, что заказчик должен быть всё время на связи и доступен для вопросов.

Парное программирование

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

Непрерывная интеграция

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

Рефакторинг

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

Частые небольшие релизы

Версии (releases) продукта должны поступать в эксплуатацию как можно чаще. Работа над каждой версией должна занимать как можно меньше времени. При этом каждая версия должна быть достаточно осмысленной с точки зрения полезности для бизнеса.

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

Простота дизайна

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

Метафора системы

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

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

Подобрав хорошую метафору, вы облегчаете команде понимание того, каким образом устроена ваша система. Иногда сделать это не просто.

Стандарты кодирования

Все члены команды в ходе работы должны соблюдать требования общих стандартов кодирования. Благодаря этому:

• члены команды не тратят время на глупые споры о вещах, которые фактически никак не влияют на скорость работы над проектом;

• обеспечивается эффективное выполнение остальных практик.

Если в команде не используются единые стандарты кодирования, разработчикам становится сложнее выполнять рефакторинг; при смене партнеров в парах возникает больше затруднений; в общем и целом, продвижение проекта затрудняется. В рамках XP необходимо добиться того, чтобы было сложно понять, кто является автором того или иного участка кода, — вся команда работает унифицированно, как один человек. Команда должна сформировать набор правил, а затем каждый член команды должен следовать этим правилам в процессе кодирования. Перечень правил не должен быть исчерпывающим или слишком объемным. Задача состоит в том, чтобы сформулировать общие указания, благодаря которым код станет понятным для каждого из членов команды. Стандарт кодирования поначалу должен быть простым, затем он будет эволюционировать по мере того, как команда обретает опыт. Вы не должны тратить на предварительную разработку стандарта слишком много времени.

Коллективное владение

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

Давая каждому программисту право изменять код, мы получаем риск появления ошибок, вносимых программистами, которые считают что знают что делают, но не рассматривают некоторые зависимости. Хорошо определённые UNIT-тесты решают эту проблему: если нерассмотренные зависимости порождают ошибки, то следующий запуск UNIT-тестов будет неудачным SCRUM

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

Главные действующие роли в Scrum:

ScrumMaster — тот, кто ведёт Scrum митинги и следит, чтобы при этом соблюдались все принципы Scrum (роль не предполагает ничего кроме корректного ведения самого Scrum-а, руководитель проекта скорее относится к Product Owner и не должен являться ScrumMaster);

Владелец Продукта (Product Owner) — человек, который представляет интересы конечных пользователей и других заинтересованных в продукте сторон; и кросс-функциональная Команда (Scrum Team), состоящая как из разработчиков, так и из тестировщиков, архитекторов, аналитиков и т. д. (при этом размер команды в идеале составляет 7±2 человека). Команда является единственным полностью вовлечённым участником разработки, и отвечает за результат как единое целое. Никто кроме команды не может вмешиваться в процесс разработки на протяжении спринта.

На протяжении каждого спринта создаётся функциональный рост программного обеспечения. Набор возможностей, которые реализуются в каждом спринте, происходят из этапа, называемого product backlog (документация запросов на выполнение работ), обладающего наивысшим приоритетом по уровню требований к работе, который должен быть выполнен. Запросы на выполнение работ (backlog items), определенных на протяжении совета по планированию спринта (sprint planning meeting), перемещаются в этап спринта. На протяжении этого собрания Владелец Продукта информирует о заданиях, которые должны быть выполнены. Тогда Команда определяет, сколько из желаемого они могут выполнить, чтобы завершить необходимые части на протяжении следующего спринта. Во время спринта команда выполняет определенный фиксированный список заданий (т. н. sprint backlog). На протяжении этого периода никто не имеет права менять список требований к работе, что следует понимать как заморозку требований (requirements) во время спринта.

20. Понятие качества программы. Стандарт ISO 9126.

Качество определяется в стандарте ISO 9126 как вся совокупность его характеристик, относящихся к возможности удовлетворять высказанные или подразумеваемые потребности всех заинтересованных лиц.

Основными критериями качества ПО (criteria of software quality) являются:

1. функциональность – способность ПО выполнять набор функций (действий), удовлетворяющих заданным или подразумеваемым потребностям пользователей. Набор указанных функций определяется во внешнем описании ПО;

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

3. эффективность – соотношение уровня услуг, предоставляемых ПО пользователю при заданных условиях, и объема используемых для этого ресурсов. К числу таких ресурсов могут относиться требуемые аппаратные средства, время выполнения программ, затраты на подготовку данных и интерпретацию результатов;

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

5. модифицируемость – характеристики ПО, которые позволяют минимизировать усилия по внесению изменений для устранения ошибок и по его модификации в соответствии с изменяющимися потребностями пользователей. Модифицируемость ПО существенно зависит от степени и качества его документированности;

6. мобильность – способность ПО быть перенесенным из одной среды (окружения) в другую, в частности, с одной аппаратной платформы на другую.

Оценочные характеристики качества:

Оценочные характеристики качества:

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

•Путем непосредственного измерения определяются опорные свойства.

•Остальные свойства оцениваются путем вычисления функций от опорных значений. Такие функции называются метриками.

21. Критерии сложности, корректности и другие показатели качества программ для основных этапов их жизненного цикла.

Статическая сложность моделей:граф-модель (узлы – точки перехода, рёбра – линейные участки).

Иерархия сложности: линейный код, код с простым ветвлением (условия), с циклами.

Цикломатическое число – «густота рёбер» в графе; (Cyclomatic number, circuit rank) — для неориентированного графа число , равное мощности множества фундаментальных циклов или, что то же, числу хорд относительно каркаса графа ; для орграфа цикломатическое число неориентированного графа, получающегося заменой дуг ребрами.

Ц. число = (кол-во рёбер) – (кол-во узлов) + (кол-во связных подграфов).

Теория Холстеда

Уровень языка

Сложность комплексов программ

Сложность эксплуатации

NP-полные задачи – сводимость за биномиальное время.

(!) Сложность = (кол-во шагов) / (объём данных); ни в коем случае не время!

22. Принципы и инструменты тестирования программных продуктов.

Принципы тестирования

Хорош тот тест, для которого высока вероятность обнаружить ошибку. Эта аксиома является фундаментальным принципом тестирования. Поскольку невозможно показать, что программа не имеет ошибок и, значит, все такие попытки бесплодны, процесс тестирования должен представлять собой попытки обнаружить в программе прежде не найденные ошибки.

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

Не нужно тестировать свою собственную программу. Ни один программист не должен пытаться тестировать свою собственную программу. Это относится ко всем формам тестирования — как к тестированию системы, так и к тестированию внешних функций и даже отдельных модулей. Тестирование должно быть в высшей степени разрушительным процессом, но имеются глубокие психологические причины, по которым программист не может относиться к своей собственной программе как разрушитель. Дополнительное давление (например, жесткий график) на отдельного программиста или весь коллектив разработчиков проекта часто мешает программисту или всему коллективу выполнить адекватное тестирование. Если модуль содержит дефекты вследствие каких-то ошибок перевода, довольно высока вероятность того, что программист допустит ту же ошибку перевода (например, неправильно интерпретирует спецификации) и при подготовке тестов. Все ошибки в его понимании других модулей и их сопряжении также отразятся на тестах.

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

Отсюда вовсе не следует, что программист не может тестировать свою программу.Многие программисты с этим вполне успешно справляются. Здесь лишь делается вывод о том, что тестирование является более эффективным, если оно выполняется кем-либо другим. Заметим, что все наши рассуждения не относятся к отладке, т. е. к исправлению уже известных ошибок. Эта работа эффективнее выполняется самим автором программы.

Необходимая часть всякого теста — описание ожидаемых выходных данных или результатов. Одна из самых распространенных ошибок при тестировании состоит в том, что результаты каждого теста не прогнозируются до его выполнения. Ожидаемые результаты нужно определять заранее, чтобы не возникла ситуация, когда «глаз видит то, что хочет увидеть». Чтобы совсем исключить такую возможность, лучше разрабатывать самопроверяющиеся тесты либо пользоваться инструментами тестирования, способными автоматически сверять ожидаемые и фактические результаты.

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

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

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

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

Детально изучите результаты каждого теста. По всей вероятности, это наиболее очевидный принцип, но и ему часто не уделяется должного внимания. Самые изощренные тесты ничего не стоят, если их результаты удостаиваются лишь беглого взгляда. Тестирование программы означает большее, нежели выполнение достаточного количества тестов; оно также предполагает изучение результатов каждого теста. «Да, я уже проверял такую ситуацию, но такого как-то не заметил в выдаче», — довольно распространенная реакция программиста на обнаруженную новую ошибку.

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

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

Считайте тестируемость ключевой задачей вашей разработки.

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

Никогда не изменяйте программу, чтобы облегчить ее тестирование. Часто возникает соблазн изменить программу, чтобы было легче ее тестировать. Например, программист, тестируя модуль, содержащий цикл, который должен повторяться 100 раз, меняет его так, чтобы цикл повторялся только 10 раз. Может быть, этот программист и занимается тестированием, но только другой программы.

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

Приведем еще раз три наиболее важных принципа тестирования:

1. Тестирование — это процесс выполнения программ с целью обнаружения ошибок.

2. Хорошим считается тест, который имеет высокую вероятность обнаружения еще не выявленной ошибки.

3. Удачным считается тест, который обнаруживает еще не выявленную ошибку.

УНИВЕР: К ЧЕМУ ГОТОВИТЬСЯ, ПЕРВЫЕ СЛОЖНОСТИ, КОМПЛЕКСЫ В ТВОРЧЕСТВЕ | Обсудим с Аней


Похожие статьи.

Понравилась статья? Поделиться с друзьями: