воскресенье, 6 июня 2010 г.

Что такое хорошо, а что такое плохо

Кроха сын к отцу пришел и спросила кроха: чем же мой код так хорош, ну а что в нем плохо?

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


Что такое плохо.

Характеристики системы, которыми она обладать не должна, принято называть «symptoms of poor design». При разработке системы важно обращать на них внимание и следить за тем, что бы они проявляли себя как можно реже. И так, вот они:

• Жесткость (Rigidity) – сложно вносить изменения с систему; небольшие изменения требуют серьезных модификаций. «Мне нужно всего лишь добавить новое сообщение на страницу, а я должен переписать пол приложения» - так негодуют разработчики, кому приходится модифицировать «жесткую» систему.
• Хрупкость (Fragility) – даже незначительные изменения, внесенные в систему, могут повлечь за собой непредсказуемые последствия. Обычно такое случается, если код программы не покрыт юнит тестами. В этом случае регрессионное тестирование становится настоящим кошмаром, как для тестеров, так и для разработчиков.
• Неподвижность (Immobility) – тяжело выделить отдельные компоненты для их дальнейшего переиспользования в других системах (компоненты слишком сильно зависят друг от друга). Низкое зацепление и высокое связывание являются тому причиной.
• Вязкость (Viscosity) – делать что-либо правильно сложнее, чем делать неправильно. Типичным примером может быть необходимость «копипастить» вместо наследования или модификация тех же скопированных кусков кода в нескольких местах, вместо внесения одного изменения в общую часть.
• Избыточная сложность (Needless Complexity) – система содержит инфраструктуру без явных преимуществ. Примером может быть создание дополнительных слоев, различных оберток объектов для передачи между этими слоями, хотя можно передавать их напрямую и т.д. Про некоторые решения, которые влекут за собой избыточную сложность, часто говорят: «Стрелять из пушки по воробьям».
• Избыточное повторение (Needless Repetition) – повторяющиеся структуры, которые лучше вынести в общие абстракции. То, что техника «скопировал-вставил» является дурным тоном, известно многим, но, не смотря на это, она применяет достаточно. Как результат система становится хрупкой и вязкой.
• Непрозрачность (Opacity) – тяжело понять что делает код. Чрезмерное использование различных трюков, плюс избыточная сложность, несомненно, приведет к тому, что код станет тяжелым для понимания. Возможно, в трюках и бывает необходимость, но такие участки кода должны быть хорошо документированы. Кроме того, отсутствие корпоративного стандарта по форматированию кода, так же ведет к его непрозрачности.


Что такое хорошо.

Обратно характеристикам «бедного дизайна», можно привести те, которые обычно сопровождают дизайн высокого качества:

• Минимальная сложность (Minimal complexity) – отсутствие слишком «умного» дизайна. Его всегда сложнее понимать и поддерживать. «Keep it simple» - один из известных принципов Agile разработки.
• Легкость поддержки (Ease of maintenance) – систему легко поддерживать, т.е. легко понять, как она работает и легко модифицировать её логику.
• Низкое связывание (Loose coupling) – система обладает минимальной зависимостью между её компонентами.
• Склонность к расширению (Extensibility) – вы можете легко расширить функционал системы без внесения изменений в существующий код.
• Склонность к повторному использованию (Reusability) – отсутствие повторяющихся кусков кода, высокое зацепление и низкое связывание её компонентов располагает к их легкому повторному использованию в других программах.
• Высокий уровень входящих связей (High fan-in) – один класс часто используется другими классами – следствие системы обладающей высоким повторным использованием своих компонентов.
• Низкий уровень исходящих связей (Low-to-medium fan-out) – классы должны зависеть от наименьшего количества других классов. Высокий «fan-out» (более 7) означает, что класс слишком зависим от других классов, что зачастую является следствием его чрезмерной сложности.
• Переносимость (Portability) – программа не испытывает проблем с запуском на других машинах, и при этом, не требует сложной предварительной настройки.
• Худоба (Leanness) – отсутствие неиспользуемых классов и модулей сделает систему более легкой в понимании и поддержке. YAGNI – «you ain’t gonna need it», еще один из принципов Agile разработки.
• Расслоение (Stratification) – система, спроектированная по принципу расслоения, легко оценить на каждом уровне без затрат на понимание остальных. Такая фокусировка положительно сказывается как на поиске проблем, так и на способности системы повторному использованию.
• Стандартные подход (Standard techniques) – система полностью написана с использованием единого подхода, таким образом, любой разработчик не испытывает трудностей в понимании частей системы, которые были написаны его коллегами.


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