Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Основы проектирования программы. Этапы создания программного обеспечения

Содержание:

Введение

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

Говоря короче, программирование из чего-то элитарного, и доступного лишь избранным стало ремеслом, делом, поставленным на поток, превратилось в некое подобие конвейера. Как Генри Форд в свое время изложил основные принципы конвейерной разработки, что привело к огромному увеличению его скорости, так и в программировании, люди попытались описать необходимые этапы разработки программного обеспечения, и некоторые «практики», которые можно применять на каждом из этих этапов.

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

Например, сюда можно отнести следующие этапы создания программы: этап ее проектирования, этап отладки, этап тестирования, этап использования, и много какие еще.

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

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

1. Необходимость разработки моделей жизненного цикла

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

1.1 Увеличение числа разработчиков

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

Возьмем какую-нибудь самую простейшую программу, например игру в «крестики-нолики». Если когда-то можно было изобразить крестики и нолики в виде нескольких отрезков и окружностей (а то и вовсе в виде текста), то сейчас очевидно, что придется рисовать их в графическом редакторе, возможно даже в трехмерном, с тенями (а следовательно, нужен будет художник). Однако потом встанет проблема их вывода на экран. Если программист один (и он не пользуется результатами труда других программистов), ему придется разработать свой формат графических файлов. Если же он возьмет стандартный формат, например, PNG, то ему нужно будет реализовывать довольно сложную библиотеку для вывода таких изображений на экран (а ведь внутри формата PNG применяются и другие технологии, например, формат сжатия ZLIB, который тоже придется реализовать). Чтобы вывести текст (например, «выиграли крестики») в таком случае потребуется реализовывать поддержку формата TTF (TrueType Fonts), в котором определена целая виртуальная машина, а также библиотеку для работы с форматом кодирования символов UTF-8.

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

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

Исходя из этого понятно, что требуется какой-то механизм, который позволил бы разработчикам «синхронизировать» свои усилия, не мешая друг другу. Например, данный инструмент должен позволить программисту №2 сохранить свои наработки, а затем, когда программист №5 отправит свои итоговые изменения, он должен объединить два программных кода, создав итоговый.

Такие программные продукты называются «Системами контроля версий», (Version Control Systems, VCS), некоторыми представителями которых являются Git, Mercurial и SVN.

1.2 Уменьшение времени тестирования и сборки

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

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

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

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

На самом деле, процесс тестирования и сборки также поддается автоматизации. Для этого существует такой класс программ, который в разных версиях называется «Постоянная интеграция» или «Постоянная доставка» (Continuous Integration/Continuous Delivery, CI/CD). Данные программы позволяют после каждого, даже самого малого изменения автоматически провести тестирование программы (по заранее созданным тестам), а также собрать ее, и (возможно) сразу же выложить на сервер для заказчика.

Примерами таких программ являются Jenkins и TeamCity. Их использование существенно ускоряет процесс создания и изменения программ, а также доставку этих изменений до заказчика.

1.3 Увеличение сложности приложений

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

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

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

Однако со временем такого деления на функции и модули стало не хватать. Тогда был разработана технология объектно-ориентированного подхода. Сам этот подход можно описать несколькими положениями:

  • Каждый модуль (то есть, набор функций, и относящихся к ним данных) называется классом. Функции класса называются «методы», данные класса – «поля»;
  • Любой класс можно «инстанцировать», то есть, «получить экземпляр класса» - копию его методов и полей. Такой «инстанцированный» класс называется «объект». Класс можно инстанцировать сколько угодно раз, каждый раз получая объекты со своими полями;
  • Методы любого объекта могут вызывать методы любого другого объекта, но только те, которые им разрешено (в каждом объекте указываются правила доступа к его полям и методам);
  • Разрешено создавать класс, опираясь на другой класс (наследоваться от него). При этом все поля и методы старого класса сохраняются, но в классе-потомке можно добавить новые.

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

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

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

И, наконец, третья проблема состоит в «плохой масштабируемости» данного решения. Допустим, мы решили работать с точками не на плоскости, а в пространстве. Наш модуль совершенно для этого не приспособлен, и нам придется писать новый. При этом, два этих модуля (на плоскости и в пространстве) окажутся никак не связанными, и, если в дальнейшем будут вноситься изменения в какой-то один из них, то другой их не получит, даже если эти изменения одинаковы для точек на плоскости и в пространстве.

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

Мы создаем специальный класс «Точка», в котором опишем несколько полей (в данном случае, скорее всего, два – координата X и координата Y), доступ к которым, однако, запрещаем, чтобы никто из других классов не смог их прочитать (если же подобное чтение необходимо, то можно создать два специальных метода, возвращающих эти координаты, они называются геттеры). Теперь, любой программист может средствами языка, поддерживающего объектно-ориентированное программирование, сколько угодно раз «инстанцировать» наш класс – создать объект класса «точка». При этом автоматически будет выделена новая область памяти для данных класса. При создании объекта программист передаст классу некоторые параметры (скорее всего, координаты точки), и они будут запомнены для дальнейшего использования. Таким образом мы решаем первую проблему – нам не нужно работать с памятью, все происходит за нас автоматически.

Вторая проблема решается правильной настройкой прав доступа. Так как мы запретили прямой доступ к полям (координатам точки) из других классов, то ни один программист не сможет изменить координаты после их создания (равно как и не сможет создать объект каким-либо иным способом, кроме как инстанцировав класс). Все методы, которые используются в классе, однако не должны вызываться извне также можно запретить. Следовательно, в данном случае вторая проблем полностью решена – новый программист не сможет «сломать» наш класс, даже если захочет специально. Если же ему просто не хватает знаний, то он получит ошибку, и попросит совета у более опытных коллег, которые объяснят ему порядок работы с данным классом.

Третья проблема масштабируемости решается в объектно-ориентированном программировании с помощью создания классов, основанных на других классах. Например, мы можем создать класс «Трехмерная точка», основываясь на уже созданном классе «Точка». При этом мы автоматически получим в новом классе два поля с координатами, и нам придется добавить лишь одно – «Координата Z». Некоторые методы (например, определить, в какой координатной четверти находится точка) не потребуется менять вовсе, так как они будут зависеть лишь от «старых» координат X и Y. Однако некоторые методы (например, посчитать расстояние от начала координат) придется переделать. Однако их число будет меньше, а следовательно, сделать это будет проще.

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

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

1.4 Проблема эмоционального выгорания

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

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

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

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

Для того, чтобы повысить моральный дух команды был разработан процесс «геймификации» (от англ. game – игра). Данный процесс состоит в том, что процесс разработки рассматривается как игра типа RPG (Role Playing Game), в которой каждый игрок должен выполнять квесты
(от англ. quest – задание) и получать за это ачивки (от англ. achievement – достижение).

Например, у каждого человека может быть некоторое число «очков» в разработке, которые можно получить, выполняя различные задания. Например, «+1 очко за изменение, которое ничего не поломало в программе», «+5 очков за реализацию нужной функции», и так далее.

Некоторые команды идут еще дальше, и вводят специальные значки или жетоны, которые выдаются программистам по достижении конкретных целей, например «Создать 10 точек останова в отладчике» или «Написать 1000 строк кода». Это приводит к тому, что программисты начинают соревноваться за получение таких значков и коллекционировать их.

Примерами подобных значков могут быть такие:

Некоторые идут еще дальше, и каждому разработчику ставят в соответствие вымышленного персонажа, которого необходимо развивать, как и в обычной игре, со своими параметрами «сила», «отвага», и так далее, собранными предметами и полученными наградами. Иногда для этого создается свой внутрикорпоративный сайт, например такой:

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

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

2. Часто используемые модели жизненного цикла программ

Хотя моделей жизненного цикла существует чрезвычайно много (из нерассмотренных в данной работе можно назвать, например модели Scrum или Kanban), тем не менее, среди них можно выделить основные. Ниже будут разобраны несколько моделей жизненного цикла при создании программ, и отмечены этапы, через которые нужно пройти, чтобы разработать программу в рамках данной модели.

2.1 Модель водопада

Модель жизненного цикла под названием «водопад» (англ. Waterfall) определяет, что любое программное обеспечение проходит в своем развитии через две фазы:

  1. Разработка;
  2. Сопровождение.

Однако, так как данные фазы являются довольно крупными, они дополнительно подразделяются на ряд этапов. Например, разработка состоит из пяти этапов:

  1. Определение требований – сюда включается описание общего контекста задачи, ожидаемых функций системы и ее ограничений. На данном этапе заказчик совместно с разработчиками принимает решение о том, что систему необходимо создать;
  2. Спецификация системы – разработчики системы пытаются осмыслить выдвигаемые заказчиком требования и зафиксировать в виде спецификаций системы. Важно отметить, что в спецификациях описывается только внешнее поведение системы, то есть «что она будет делать», в то время как внутренняя реализация (то есть, «как система будет это делать») сюда не включается. Прежде чем приступать к работе над проектом согласно спецификации, они должны быть проверены на соответствие исходным целям, полноту, непротиворечивость и однозначность;
  3. Проектирование – на данном этапе выполняется проектирование системы таким образом, чтобы она могла удовлетворять определенным на этапе 1 и 2 требованиям. Чаще всего на данном этапе выполняют последовательную декомпозицию системы до уровня очевидных процедур и функций (а также модулей или классов);
  4. Реализация – на данном этапе каждый из спроектированных на предыдущем шаге модулей непосредственно кодируется на наиболее подходящем для данного приложения языке;
  5. Тестирование – созданный программный продукт подвергается комплексному тестированию, чтобы удостовериться, что он соответствует спецификации и выполняет поставленные задачи.

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

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

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

2.2 Модель водопада с промежуточным контролем

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

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

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

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

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

2.3 Спиральная модель

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

  1. Этап определения требований и анализа;
  2. Этап проектирования;
  3. Этап реализации;
  4. Этап внедрения.

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

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

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

2.4 Гибкие методологии разработки

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

  1. Циклы (итерации) в данных проектах очень короткие, обычно 2-3 недели по протяженности. Хотя отдельная итерация такой длительности недостаточна для выпуска новой версии продукта, по данной методологии к концу итерации программный продут должен быть готов к выпуску (то есть, он хотя бы должен компилироваться и работать);
  2. Применяется для небольших групп, внутри которых все друг друга знают, причем упор делается на непосредственное общение лицом к лицу. Чаще всего при этом все участники группы (включая представителя заказчика) находятся в одном офисе и часто проводят встречи, где обсуждается текущее состояние дел. Считается, что люди важнее процессов и инструментов;
  3. Основной метрикой данных методологий является готовый продукт. Считается, что если продукт есть, и он работает – значит все делается верно. Считается, что работающий продукт важнее исчерпывающей документации;
  4. По данным концепциям изначальные условия, поставленные заказчиком не так важны, и могут меняться в процессе разработки, изменения просто будут включены в следующую итерацию. Команда постоянно должна быть готова к изменениям, и к взаимодействию с заказчиком.

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

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

Некоторые методологии разработки, которые можно отнести к семейству «гибких» приведены далее.

2.4.1 Разработка, основанная на тестах

Разработка, основанная на тестах (Test Driven Development, TDD) – это методология разработки, которая основывается на повторении коротких циклов разработки (в связи с чем данная методология и отнесена к «гибким»), на каждом из которых сначала пишется тест, который проверяет, работает ли желаемое изменение, затем код, который заставляет тест выполнится успешно, а затем, если необходимо и осталось время до конца текущего цикла, производится модернизация (рефакторинг) кода.

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

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

В процессе разработки, основанной на тестах, разработчики проходят через следующие стадии:

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

В данной методологии, как и во всех остальных, есть свои достоинства и недостатки. Перечислим преимущества данной методологии:

  • Разработчику с самого начала приходится обдумывать, как именно приложение будет тестироваться. Это приводит к тому, что будет достаточно качественно проработана структура программы еще до ее написания;
  • Если некоторые из тестов неожиданно перестают проходить, можно достаточно просто произвести откат к последней версии, которая проходит все тесты, и начать снова. В некоторых случаях это получается быстрее, чем использовать отладчик и искать ошибку;
  • Несмотря на то, что при разработке через тестирование обычно требуется написать больше кода, общее время, затраченное на разработку программы обычно оказывается меньше из-за того, что многократно снижается время на отладку и уменьшается количество ошибок;
  • С покрытием кода тестами можно проводить рефакторинг кода без боязни его испортить. Если после рефакторинга какая-то функциональность будет не работать, тесты сразу сообщат об этом;
  • Тесты могут работать в качестве документации. Например, можно открыть тест работы программы, и понять, какие функции необходимо вызывать для минимального сеанса работы.

Перечислим недостатки данной методологии:

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

2.4.2 Разработка, основанная на функциях

Разработка, основанная на функциях (Feature Driven Development, FDD) основана на том, что изначально мы получаем минимально работающую программу, в которую по очереди добавляем необходимые функции так, чтобы на каждой итерации мы имели работающую программу.

Процесс работы в рамках FDD состоит из пяти этапов:

  1. Разработка общей модели – производится высокоуровневый анализ исходной задачи, и строится модель конкретной предметной области;
  2. Составление списка функций – предметная область, полученная на шаге 1 разбивается на более мелкие области с точки зрения функциональности. Часто каждая такая функция соответствует
    какому-либо бизнес-процессу. Разработка каждой из таких функций должна занимать не более 2 недель (иначе ее необходимо разбить на более мелкие) – именно поэтому данный вид разработки отнесен к «гибким» методологиям;
  3. После составления списка функций происходит составление плана функций. Каждая из функций заносится в отдельный класс/классы (в случае объектно-ориентированного программирования), определяются методы и свойства класса;
  4. Реализация функции – видимая клиенту функциональность каждой функции доводится до состояния полной готовности. После тестирования и проверки кода завершенная функция включается в основной проект, и начинается работа над следующей функцией.

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

Экстремальное программирование (Extreme Programming, или, сокращенно, XP) – это одна из гибких методологий разработки программного обеспечения, которая исходит из той идеи, что при разработке необходимо применять самые последние разработанные способы и методы улучшения качества кода и сокращения сроков. Данный метод является «экстремальным» в том смысле, что он находится на «переднем крае» разработки, впитывая в себя все то новое, что разрабатывается в данной области.

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

  1. Это гибкая методология разработки, но также «экстремальная», доведенная до предела. Если в гибкой методологии предполагается готовность продукта раз в 2-3 недели, то здесь это возводится в абсолют, и считается, что продукт должен быть готов после каждого коммита разработчика. То есть, если разработчик внес какие-то изменения в основное дерево, то это должно быть что-то законченное, что может быть сразу запущено. Для проверки этого на сервере разработки ставятся программы, запускающие после каждого коммита автоматические тесты, и осуществляющие сборку проекта с сигнализацией ошибок;
  2. Используется разработка через тестирование, то есть, тесты пишутся до кода, и запускаются при каждом коммите;
  3. Принцип «Заказчик всегда рядом» - так как при каждом коммите у нас работающая система, то в нее можно пустить заказчика, который может в реальном времени в ней работать (конечно, не с реальными данными), и видеть, как система растет и улучшается;
  4. Парное программирование – принцип, когда программируют одновременно два человека за одним компьютером. Один из них пишет код, а второй просматривает глазами, и обращает внимание на ошибки и неточности при необходимости. Через некоторое время они меняются ролями. Это приводит к повышению качества кодирования, а также к тому, что разработчики могут научить друг друга новым техникам и приемам;
  5. Существует стандарт кодирования, в котором четко описано, как необходимо кодировать программу вплоть до мельчайших деталей. Например, написано, что «переменные должны описываться в CamelCase – на английском языке, без пробелов между словами, и каждое слово с большой буквы, например DoSomething или DebtPercent». Данное правило проверяется системой тестов при каждом коммите и жестко контролируется;
  6. Коллективное владение кодом – каждый разработчик несет ответственность за весь код, в том числе и тот, который писал не он. То есть, при необходимости он может поправить ошибку в любом месте программы, или дописать необходимый функционал. Нет жесткого закрепления конкретных разработчиков за конкретными функциями. Парное программирование способствует этому – каждый разработчик видит не только свой код, но и чужой, что позволяет ему понимать, как работает система в целом.

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

Заключение

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

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

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

Список использованных источников

Бумажные источники

  1. Аллен Э. Типичные ошибки проектирования. – «Питер», 2003. – 224 с.
  2. Бобровский С. Технологии Пентагона на службе российских программистов. Программная инженерия. – «Питер», 2003. – 222 с.
  3. Кент Б. Экстремальное программирование. – «Питер», 2002. – 260 с.
  4. Лайза К, Джанет Г. Гибкое тестирование: практическое руководство для тестировщиков ПО и гибких команд. – М.: «Вильямс», 2010. – 464 с.
  5. Леффингуэлл Д., Уидриг Д. Принципы работы с требованиями к программному обеспечению. Унифицированный подход. – М.: «Вильямс», 2002. – 448 с.
  6. Нейгард М. Release it! Проектирование и дизайн ПО для тех, кому не все равно. – «Питер», 2016. – 320 с.
  7. Ральф Д., Ричард Х., Джон В., Эрих Г. Приемы объектно-ориентированного проектирования. Паттерны проектирования. – «Питер», 2016 – 366 с.
  8. Роберт С. Мартин, Джеймс В. Ньюкирк, Роберт С. Косс. Быстрая разработка программ. Принципы, примеры, практика. – М.: «Вильямс», 2004. – 752 с.
  9. Субраманиам В., Хант Э. Этюды на тему быстрой разработки программного обеспечения. – М.: Лори, 2009. – 208 с.
  10. Фаулер М. Архитектура корпоративных программных приложений. –
    М.: «Вильямс», 2007 – 544 с.

Электронные источники

  1. Компания LiveTex, Геймификация в деле – [электронный ресурс] - http://habrahabr.ru/company/livetex/blog/203054/
  2. Компания Сибирикс, Геймификация студии с помощью подручных средств – [электронный ресурс] - http://habrahabr.ru/company/sibirix/blog/189112/