Наверное, самый скверный способ оценить сделанную работу, каким может воспользоваться управляющий, - сосчитать количество написанных строк текста программы. Число строк, попавших во фрагмент кода, абсолютно никак не связано с его завершенностью и сложностью. В дополнение к другим недостаткам этого неандертальского подхода, в нем слишком просто играть с цифрами, что приводит к оценкам производительности, отличающимся друг от друга более, чем на два порядка. Например, что такое строка программы (особенно на Smalltalk)? Считаются ли физические строки или точки с запятой? Как учесть несколько операторов на одной строке и операторы, которые занимают более одной строки? А как измерить количество затраченного труда? Считать код работой всего персонала или, может быть, только программистов, написавших реализацию? Рабочий день должен считаться восьмичасовым или время, проведенное за утренней раскачкой, тоже должно учитываться? Традиционные меры сложности более подходят для первых поколений языков программирования, они не являются показателями завершенности и сложности объектно-ориентированной системы.
Например, цикломатическая метрика МакКэйба не будет сколько-нибудь полезной мерой сложности, если ее применить к объектно-ориентированной системе в целом, потому что она слепа к структуре классов системы и механизмам. Однако, мы находим полезным применять цикломатическую метрику к отдельным классам, - она дает некоторое представление об их сложности и может быть использована для определения наиболее подозрительных классов, которые, вероятно, содержат больше всего ошибок.
Мы склонны измерять прогресс разработки числом готовых и работающих классов (логический аспект), или количеством функционирующих модулей (физический аспект). Как говорилось в предыдущей главе, другой мерой прогресса является стабильность ключевых интерфейсов (то есть насколько часто они подвергаются изменениям). Сначала интерфейсы всех ключевых абстракций изменяются ежедневно, если не ежечасно. Через некоторое время стабилизируются наиболее важные из ключевых интерфейсов, следом - вторые по важности и т.д. К концу жизненного цикла разработки только несколько несущественных интерфейсов нуждаются в доработке, так как основной упор делается на то, чтобы заставить готовые классы и модули работать вместе. Иногда в ключевые интерфейсы требуется внести некоторые изменения, но они обычно остаются совместимыми снизу вверх. Причем, эти изменения производятся только после того, как будет тщательно продумано их влияние. Эти изменения могут быть внесены в разрабатываемую систему при подготовке нового релиза.
Чидамбер и Кемерер предлагают несколько мер, которые непосредственно применимы к объектно-ориентированным системам [15]:
• взвешенная насыщенность класса методами;
• глубина дерева наследования;
• число потомков;
• зацепление объектов;
• отклик на класс;
• недостаток связности в методах.
Взвешенная насыщенность класса дает относительную меру его сложности; если считать, что все методы имеют одинаковую сложность, то это будет просто число методов в классе. Вообще, класс, который имеет большее количество методов среди классов одного с ним уровня, является более сложным; скорее всего, он специфичен для данного приложения и содержит наибольшее количество ошибок.
Глубина дерева наследования и число потомков - количественные характеристики формы и размера структуры классов. Как обсуждалось в главе 3, хорошо структурированная объектно-ориентированная система чаще бывает организована как лес классов, чем как одно высоченное дерево. Мы советуем строить сбалансированные по глубине и ширине структуры наследования: обычно - не глубже, чем 7╠2 уровня, и не шире, чем 7╠2 ветви.
Зацепление объектов - мера их взаимозависимости. Так же, как и при традиционном программировании, мы стремимся спроектировать незацепленные (то есть слабо связанные) объекты, поскольку они имеют больше шансов на повторное использование.
Отклик на класс - количество методов, которые могут вызываться экземплярами класса. Связность методов - мера насыщенности абстракции. Класс, который может вызывать существенно больше методов, чем равные ему по уровню классы, является более сложным. У класса с низкой связностью можно подозревать случайную или неподходящую абстракцию: такой класс должен, вообще говоря, быть переабстрагирован в несколько классов или его обязанности должны быть переданы другим существующим классам.
7.6. Документация
Наследие разработки