Что делать? Как делать? Чем делать? Все эти вопросы на самом деле вторичны. Искать ответы на них следует только после утвердительного «Делать!», уверенно сказанного в ответ на Вопрос Вопросов «А делать ли вообще?» Талантливый программист Йон Смерл (Jon Smirl) начал искать ответ на этот вопрос слишком поздно – когда груз добровольно взваленного им на себя проекта Xegl стал настолько непосилен, что хороший проект пришлось закрыть.
Пожалуй, начинать придется с повторения очевидного. Оценка стоимости программного продукта – не разовое действие, а процесс, сопровождающий разрабатываемый, а затем и созданный продукт на всех этапах его жизненного цикла. Именно поэтому даже принято говорить об отдельных жизненных циклах собственно продукта и оценки его стоимости. Последняя уточняется даже тогда, когда в нее вносятся необходимые коррективы, отражающие затраты, связанные с выведением продукта из употребления. Естественно, можно ограничиться макроуровнем – выделить отдельные фазы этого процесса и сконцентрироваться на них. Так, наиболее интересной является предпроектная фаза, позволяющая оценить – пусть грубо, но все-таки хоть с какой-то степенью определенности – сложность и стоимость будущего программного изделия. К сожалению, незнание практикующими программистами сравнительно простых вещей и отсутствие в обязательных курсах обучения дисциплин «программной метрологии» приводят к тому, что упорно не желающие сдаваться перед натиском индустриального подхода к разработке ПО многочисленные «частники-индивидуалисты» (создающие будь то Open Source, будь то shareware-программы) переоценивают свои силы и расходуют время на проекты заведомо нереальной сложности. А понимание напрасности израсходованных времени и сил всегда приводит к разочарованию – виновнику маленьких и больших житейских трагедий. С другой стороны, тем программистам, кто уже вырос из коротких штанишек кодирования и присматривается к управленческой работе, но все же – по специальности, очень полезно иметь представление об оценке стоимости программного продукта и проекта по его созданию.
Сразу следует предупредить читателя, в первую очередь, владеющего каким-либо языком программирования и имеющего за плечами определенную практику разработки ПО, – область, в которую мы вторгаемся, находится за пределами традиционно очерченной «дисциплины программирования». Эту область можно отнести к нечетко очерченной территории «архитектуры» (более точно было бы применить английский термин, не имеющий точного перевода и даже аналога, – architecting). Название области – пользовательские требования к функциональности (functional user requirements, в дальнейшем автор постарается все специфические термины приводить в оригинальной форме – это просто необходимо в связи с тем, что русскоязычной литературы соответствующей тематики очень мало). «Расстояние», отделяющее две области – специфичный для программиста мир программных решений и мир пользовательских требований к функциональности (ПТФ), огромно. Понятийный аппарат программистского мира предназначен для нахождения способов реализации программ, в мире же ПТФ реализация неинтересна и несущественна, здесь главное – точное нахождение всех ответов на вопрос «что программа должна делать?». Соответственно, начинать надо со знакомства с терминами, которые в мире ПТФ звучат привычно, но специфика их семантики отражает расстояние между двумя упомянутыми областями.
Всего можно выделить шесть терминов, синтаксически совпадающих в двух мирах. Начнем мы с самого распространенного. Казалось бы, что может быть необычного в слове «пользователь» (user)? Программисты (да и в целом IT-специалисты) настолько привыкли понимать под ним человека, взаимодействующего (или использующего) программу, что в более чем неплохих словарях (например, Microsoft Computer Dictionary, изд. 5-е, 2002 г.), отдельного определения для термина «user» просто нет. В мире пользовательских требований к функциональности «пользователь» уже намного менее конкретен – им может быть не только любая персона или группа/организация, влияющая на формирование требований (т. е. способная сформулировать один или несколько ответов на вопрос «что должна делать программа?»), но и вообще все, что взаимодействует в любой форме в любое время с программой. Иными словами, «пользователем» могут быть люди, группы людей, организации, приложения, а также все объекты любой природы, являющиеся источниками и потребителями данных программы. Так, для проектировщика встраиваемой микрокомпьютерной системы безопасности пользователями вполне могут быть… ночные бабочки и, простите, тараканы. Потому что и те и другие существа могут с высокой степенью вероятности вносить в работу системы помехи (влияя на распространенные типы датчиков), которые надо учитывать при формировании требований к функциональности. И точно такими же пользователями в этом случае будут контроллеры соединенных с системой безопасности удаленных точек оповещения, сотрудники охраняемого объекта и службы безопасности.
Толкование терминов «приложение» и «система» (application, system) в мире ПТФ также несколько отличается от общепринятого (табл. 1). Здесь «приложение» – это связанный в единое целое и подчиненный определенным целям набор автоматически выполняемых процедур и сопровождающих данных. «Приложение» может содержать множество компонентов, модулей, подсистем. Часто используемые синонимы для этого термина – система, прикладная система (application system), информационная система (information system). В этом определении «приложения» важен факт его независимости от типа платформы, режимов работы, способов физической организации выполнения функций. Иными словами, «приложение» в мире ПТФ совершенно лишено деталей реализации.
Термин | Принятое в IT значение | Значение в мире ПТФ |
Пользователь (user) | Физическое лицо, которое использует ПО или определяет требования к нему | Лицо, группа лиц, организация, приложение, устройство и т. д., которые в той или иной мере обусловливают требования к функциям, выполняемым ПО |
Приложение (application) | Физическая реализация программного продукта. Границы «приложения» часто четко определены сугубо на аппаратном или программном уровне | Образующий единое целое набор автоматически исполняемых процедур и необходимых данных, подчиненный строго определенному перечню целей |
Проект (project) | В зависимости от организационных особенностей может включать в себя как процесс проектирования нового изделия, так и процессы его модификации, усовершенствований и т. д. | Множество оценок функциональности и усовершенствований во всех точках жизненного цикла ПО |
Файл (file) | Набор данных, существующий на физическом уровне (обычно на уровне конкретной файловой системы, например «входной файл») | Обусловленная пользователем как связанная группа данных безотносительно их типа, представления и физической реализации |
Еще один «новый» термин – «проект». Его ПТФ-значение существенно отличается от общепринятого инженерного. Хотя бы тем, что оно основывается на дополнительном понятии – «оценка функциональности в точке» (function point count), отражающем число реализованных требований к программному продукту в данной точке его жизненного цикла. Соответственно, «проект» в ПТФ – это множество оценок функциональности во всех точках жизненного цикла ПО.
Непривычность понятия «проект» в мире ПТФ распространяется и на термин «усовершенствование в ходе проекта» (enhancement). Под ним подразумевается разница между оценками функциональности в соседних точках жизненного цикла ПО. Усовершенствования, таким образом, не обязательно могут означать появление дополнительной функциональности.
На понятии «файл» в мире ПТФ основано много определений. ПТФ-файл – это логически связанная группа данных безотносительно физической реализации данных. Что означает – ничего общего у ПТФ-файла с традиционным для IT «файлом» фактически нет. К слову, понятие «логически связанный» также имеет специфическое ПТФ-значение. Но его лучше всего пояснить так – если в литературе о ПТФ вы встретите слово «logical», забудьте о «логических моделях баз данных» или о «математической логике» и просто замените его сложным синонимом «определенный опытным пользователем как…». То есть использованное ранее сочетание «логически связанный» означает следующее: «определенный опытным пользователем как связанный».
Определение, принятое в экономике для продуктивности (товары или услуги, произведенные с единичными затратами труда и средств), долгое время фактически «не работало» в такой сфере деятельности, как программирование, из-за отсутствия четко определенных понятий «товар» и «услуга». А распространенные оценки продуктивности, основанные на количестве строк кода, на самом деле далеки не то что от идеала, а в некоторых случаях от элементарного здравого смысла. Кажущееся неожиданным, это утверждение хорошо иллюстрируется известным парадоксом оценки производительности, основанной на «стоимости строки кода». Предположим, что два коллектива разработчиков решают одну и ту же задачу с применением разных технологических средств. Первый коллектив специализируется в низкоуровневом программировании с использованием языка ассемблера целевой платформы, второй – работает на языке C. На первых проектных этапах в силу высокой квалификации обе группы идут плечо к плечу, затратив по одному месяцу на изучение требований к ПО и по два месяца на высокоуровневое проектирование. Этап кодирования, безусловно, намного более трудоемкий при применении низкоуровневого языка ассемблера, отнимает у первого коллектива девять месяцев, у второго – два. Соответственно, по той же причине этап тестирования обходится первому коллективу в четыре месяца, второму – в два. Завершающие этапы – подготовка комплекта сопроводительной документации и отработка системы поддержки ПО у обеих команд почти одинаковы – первый коллектив затрачивает на решение этих задач три месяца, второй – два. Результирующий программный продукт первой команды содержит 30 тыс. строк кода, второй – 5 тыс. И наконец, затраты первой команды составляют 150 тыс. у. е., второй – 90 тыс. А вот теперь начнется парадоксальное – если оценивать эти два проекта на основе «строк кода», то получится, что цена строки кода при программировании на ассемблере – 5 у. е. (150 000 у. е./30 000 строк), почти в три раза меньше, чем строки кода на C, которая равна 18 у. е. (90000 у.е./5000 строк). А производительность труда программистов-«ассемблерщиков», измеренная в выданных на-гора строках в месяц, выше в три раза (!), чем у их работающих на сравнительно высокоуровневом языке коллег – 30 тыс. строк за 19 месяцев против 5 тыс. за 10 месяцев, т. е. 1579 строк в месяц против 500. И пусть логика и практика подсказывают, что использование высокоуровневых средств создания ПО лучше, метрика, основанная на «строках кода», убедительно доказывает обратное. Это противоречие в конце 70-х годов прошлого века вынудило Алана Альбрехта (Allan Albrecht) из IBM создать новую метрику, пригодную для более разумной оценки как продуктивности работы программистов, так и сложности и стоимости программного проекта – оценку функциональности в баллах. Основная идея метрики Альбрехта – максимальный отказ от деталей реализации ПО и перенос оценки в область функциональности, наблюдаемой пользователем. Иначе говоря, в область ПТФ, пользовательских требований к функциональности.
Главный инструмент оценщика функциональности в баллах – простая таблица, заполняемая на основе результатов формирования перечня требований к проектируемой системе (табл. 2).
Параметр | Весовой фактор (Cj) | Оценочная функция | |||
Оцен-ка | Простой проект | Типовой проект | Сложный проект | Баллы | |
Количество входных файлов | X1 | 3 | 4 | 6 | C1X1 |
Количество выходных файлов | X2 | 4 | 5 | 7 | C2X2 |
Число пользовательских запросов | X3 | 3 | 4 | 6 | C3X3 |
Количество внутренних файлов | X4 | 7 | 10 | 15 | C4X4 |
Количество интерфейсных файлов с внешними системами | X5 | 5 | 7 | 10 | C5X5 |
Функциональность в баллах, всего | Σi CiXi |
Следует учесть, что понятийный аппарат, использованный в этой таблице, соответствует не классическим, принятым в IT, толкованиям терминов, а уже упомянутой ранее ПТФ-терминологии.
Подставив в табл. 2 оценочные цифры Xi, которые легко получить из описания системы на уровне ответа на вопрос «что система должна делать?», и выбрав класс сложности проекта (здесь нужно исходить из опыта и принципа «готовимся к худшему»), можно оценить его функциональность в баллах. К слову, точность такой эмпирической оценки может быть на ранних проектных стадиях высьма высокой и достаточной для практики – по мнению специалистов, на уровне 25%.
Но сама по себе оценка функциональности в баллах явно не подходит для того, чтобы определить сложность проекта и его стоимость. И тут на помощь «оценщику» приходит метод «отката» к… оценке сложности в строках кода (в зарубежной литературе именуемый backfiring). Это эмпирический метод, позволяющий пересчитать баллы функциональности в реализующие их строки кода на основании полученных с помощью статистического анализа множества реальных проектов коэффициентов (табл. 3).
Язык | Строк кода на балл функциональности |
Ассемблер | 320 |
Макроассемблер | 213 |
C | 150 |
Algol | 106 |
Cobol | 106 |
Fortran | 106 |
Pascal | 91 |
Modula-2 | 71 |
Ada | 71 |
Prolog | 64 |
Lisp | 64 |
Forth | 64 |
Basic | 64 |
C++ | 53 |
Java 2 | 46 |
Objective C | 26 |
Visual Basic 6 | 24 |
Smalltalk | 21 |
Delphi 5 | 18 |
Языки запросов | 16–13 |
Данные в табл. 3 интересны не только возможностью «отката» от абстрактных баллов функциональности к более ощутимым строкам кода, но и как неплохая оценка уровня языков программирования.
Итак, получив с помощью калькулятора (см. табл. 2) оценку функциональности в баллах и перемножив ее на коэффициент для выбранного языка реализации проекта из табл. 3, можно вычислить сложность проекта, измеренную в строках кода. Полученная цифра позволяет оценить не только стоимость реализации проекта (как именно это делать «вообще» в наших условиях, сказать трудно, слишком велика зависимость оценки от специфики работы компании), но и свои силы и возможность «осилить» проект. Но как быть, если получить цифры, необходимые для работы калькулятора, трудно или нереально?
В таком случае разумно воспользоваться эмпирическим способом нахождения оценки функциональности в баллах в зависимости от классификации вашего проекта. В основе этого способа лежат три классификатора – масштаба проекта, пользователей объекта проектирования и типа объекта проектирования (табл. 4).
Масштаб проекта, C1 | Пользователи объекта проектирования, C2 | Тип объекта проектирования, C3 | |||
Функция | 1 | Индивидуальное использование | 1 | Не требующий программирования (визуальная разработка и т. д.) | 1 |
Объект | 2 | Потребители shareware ПО | 2 | Скрипт | 2 |
Библиотека объектов | 4 | Академическая среда, инженерия | 3 | ПО встраиваемой одноплатной системы | 5 |
Реализация концепции | 5 | Внутрикорпоративные, локальное использование | 5 | База данных | 6 |
Прототип для последующего эволюционного развития | 6 | Внутрикорпоративные, распределенное использование | 6 | Клиент-серверное ПО | 8 |
Приложение для внутренних нужд | 8 | Контрактный проект, гражданский заказчик | 7 | Математическое ПО | 9 |
Приложение под заказ | 9 | Контрактный проект, заказчик – органы местной власти | 8 | Коммуникационное ПО | 11 |
Приложение, пригодное к расширению функциональности в ходе жизненного цикла | 10 | Коммерческий проект | 9 | ПО управления процессами | 12 |
Компонент внешней системы | 11 | Контрактный проект, государственное финансирование | 14 | ПО встраиваемой многоплатной системы | 13 |
Новая масштабная система | 12 | Военный проект | 15 | ПО для общедоступных сервисов | 15 |
Компонентная система | 13 |
Используя классификатор, вы можете получить оценочное значение сложности своего будущего проекта в баллах функциональности по незамысловатой формуле:
FP = (C1 + C2 + C3)2,35,
где FP – оценка в баллах функциональности, а Ci – соответствующие значения из таблицы. После этой процедуры воспользуйтесь методом «отката» и получите оценку сложности в строках кода.
Осталось, пожалуй, для демонстрации применить все вышесказанное «на практике». Предположим, что перед вами стоит задача разработать ПО для одноплатного компьютера, являющегося сердцем автономной системы охраны объектов. Система с вашим ПО будет выпускаться серийно и срок ее службы планируется весьма продолжительным. Последнее означает, что за период выпуска компьютера могут появиться новые типы датчиков и исполнительных устройств, и для обеспечения конкурентоспособности вашего изделия было бы неплохо обеспечить возможность дополнять ими функциональность уже произведенных изделий. Короче, масштаб вашего проекта – «приложение, пригодное к расширению функциональности в ходе жизненного цикла» (C1 = 10, табл. 4), это, очевидно, коммерческий проект (C2 = 9), объект проектирования которого – «ПО встраиваемой одноплатной системы» (C3 = 5). Сложность этого проекта в баллах функциональности:
FP = (10 + 9 + 5)2,35 = 1752.
Воспользуемся «откатом» и восстановим количество строк кода, необходимых для реализации проекта на языке C (самом распространенном при проектировании встраиваемых систем), для чего умножим значение FP на соответствующий коэффициент из табл. 3. Итак, ожидаемая сложность ПО – на уровне 262 тыс. строк. Ну а над полученным значением уже следует долго и много думать – стоит ли взваливать на себя обязательства и переходить к более детальному анализу проекта, выявлению функциональных требований и уточнению сложности с помощью калькулятора табл. 2.