Каталог статей.


Гибкое проектирование программного обеспечения.

источник статьи

В 1992 году Джек Ривз опубликовал концептуальную статью «What Is Software Design?» в журнале C++ Journal. В ней Ривз доказывал, что дизайн программной системы документирован главным образом ее исходным кодом, что диаграммы, описывающие исходный код, - это дополнение к дизайну, а не сам дизайн. Как оказалось, статья Джека стала предвестником технологий гибкой разработки.

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


Ароматы дизайна


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


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


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


Ароматы портящегося софта

О том, что программа начинает загнивать, можно узнать по появлению следующих ароматов:

• Жесткость

• Хрупкость

• Косность

• Вязкость

• Ненужная сложность

• Ненужные повторения

• Непрозрачность


Жесткость


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


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


Хрупкость


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


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


Косность


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


Вязкость


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


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


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


Ненужная сложность


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


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


Ненужные повторения


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


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


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


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


Непрозрачность


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


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


Почему программы загнивают


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


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


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

источник статьи