Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Внутренние факторы качества




 

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

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

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

 

Единство дизайна

 

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

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

 

Качество кода

 

Внутреннее качество начинается с качества исходного кода программы. Основным фактором качества исходного кода программы является его читаемость и понятность.

Код должен быть читаем любым членом команды с любой целью:

·   посмотреть, каким же образом программисту удалось написать так плохо работающую функцию,

·   выяснить, почему снаружи все так криво выглядит,

·   понять, реализовал ли один программист то, что может пригодиться другому.

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

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

 


Документация

 

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

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

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

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

Метафоры

 

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

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

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

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

 

Растущие сложные системы

 

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

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

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

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

Такой внешний фактор качества ПО, как функциональность, трудно определить однозначно. Здесь в силу вступает так называемый закон 80/20: «80% пользователей используют только 20% функций системы». Почему бы не оставить только 20% и не выкинуть остальные 80%? Дело в том, что для каждого пользователя эти 20% могут состоять из разной функциональности.

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

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

 

Метрики

 

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

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

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

·   Средняя (или максимальная) длина метода в строках. Надо стремиться к уменьшению этой величины.

·   Количество доступных клиентам элементов класса. Тоже стоит уменьшать, поскольку с чересчур большим API трудно работать.

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

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

 

Модульность

 

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

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

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

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

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

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

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

 

Повторное использование

 

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

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

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

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

ООП очень помогает при повторном использовании кода: наследование и полиморфизм - это очень эффективные инструменты для решения таких задач.

Инкапсуляция

 

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

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

Есть идея: чем меньше API, тем проще его защитить. Давайте спрячем от посторонних глаз все, что можно спрятать. Жаль, но спрятать все не получится: надо дать возможность пользоваться модулем. Отсюда следует важный принцип: «Все, что не является необходимым для пользователя, должно быть скрыто».

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

Принцип сокрытия всех деталей реализации называется инкапсуляцией. Его можно сформулировать и так: «Мой модуль делает это. Вам не нужно знать, как».

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

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

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...