Результатом фазы оценки осуществимости являются детальная спецификация, план работы и оценка стоимости. Наиболее традиционной формой плана можно считать сетевой график, который представляется в виде ориентированного графа с двумя
Сетевой график – очень удобный инструмент: во-первых, на нем четко видна зависимость работ друг от друга, во-вторых, на основе сетевого графика можно вычислить длительность всей работы, в-третьих, пользуясь результатами этих расчетов, можно попытаться оптимизировать длительность и затраты на работу.
Длительность вычисляется следующим образом. Суммируем длительности работ по всем возможным путям в графе. Тот путь от начала к концу, который является самым длинным, объявляется критическим, потому что задержка любой работы, лежащей на этом пути, приводит к задержке всей работы в целом. Понятно, что критических путей (с одинаковой длительностью) может быть несколько.
Рассмотрим пример.
Здесь приводится классическая задача планирования: нормально работающая, полностью загруженная компания получила заказ, от которого по разным причинам невозможно отказаться. Перечислим названия событий, т.е. узлов в графе:

Под каждым ребром графа записана планируемая длительность соответствующей работы (в неделях). Еще раз повторю, что это только пример, прошу не придираться к техническим деталям, в частности, разумеется, каждая передача (3-7, 3-10 и т.д.) не может длиться более одного-двух дней, но не хотелось возиться с дробями.
Критическими путями являются пути 1-6-2-3-4-5-9-13-14-15 и 1-6-2-3-4-5-12-13-14-15, т.е. вся работа не может быть выполнена быстрее, чем за двадцать одну неделю. Понятно, что с точки зрения оптимальной загрузки коллектива было бы лучше, чтобы все пути в графе от начала к концу имели примерно одинаковую длительность с тем чтобы как-то уменьшить длину критического пути. Например, есть соблазн заставить группу QA проводить даже начальное тестирование, уменьшив нагрузку на программистов, работа которых находится на критическом пути. Но тогда очень трудно определить границы ответственности, программисты начинают выдавать откровенную халтуру и в результате сроки даже удлиняются. В реальных проектах, где работ очень много, все-таки удается путем перераспределения работ улучшать сетевой график, по крайней мере, к этому стремятся все руководители.
Еще несколько замечаний по данному примеру. Явно неудачно спланированы работы между событиями 1, 2, 6. Коллектив сформирован за одну неделю, а рабочие места еще не готовы. Группа технических писателей начинает работать на шесть недель позже проектировщиков, а группа QA имеет трехнедельный перерыв перед завершением проектирования и т.д.
Эти проблемы действительно трудны, каждая компания решает их по-своему, например, очевидным решением является использование одной и той же группы QA или технических писателей для нескольких групп разработчиков.
Еще одной популярной формой графического представления плана работ является диаграмма Ганта (Gantt). Диаграмма Ганта представляет собой прямоугольник: слева направо равномерно отсчитываются периоды времени (недели, месяцы), сверху вниз перечисляются работы, причем каждая работа представляется в виде отрезка, начало и конец которого размещаются в соответствующем периоде.
Для сравнения с сетевым графиком нарисуем диаграмму Ганта для того же примера:

Если в сетевом графике особенно наглядно видны зависимости работ друг от друга, (например, работа 12-13 может начаться только после завершения работ 5-12 и 11-12), то в диаграмме Ганта основной упор делается на то, что происходит в каждую конкретную неделю, например, видно, что группа QA имеет перерыв в работе в 2 недели между работами 11-12 (автономное тестирование) и 12-13 (комплексное тестирование). Именно поэтому "большие начальники" предпочитают диаграммы Ганта: в конце каждой недели проводишь вертикальную линию и сразу видишь, какие работы велись, что должно кончиться, а что начаться. Должен признаться, что я и сам нашел пару ошибок в расчетах по сетевому графику, пока строил диаграмму Ганта для этого примера. Тем самым я еще раз убедился, что диаграмма Ганта нагляднее сетевого графика, или в том, что я уже большой начальник, а не технический специалист. Технические менеджеры предпочитают сетевые графики, так как им важнее информация о том, что от чего зависит, да и пересчитывать критические пути им приходится практически каждую неделю.
На диаграмме Ганта принято над каждым отрезком работы указывать, сколько сотрудников принимает участие в этой работе (в сетевом графике это возможно, но не очень удобно, поскольку надо указывать еще и длительность работы). Опять-таки, начальники любят смотреть, сколько сотрудников занято в каждой неделе, что легко увидеть как раз на диаграмме Ганта.
На самом деле управление[8] почти неотделимо от планирования. Вы спланировали работу, приступили к ее исполнению. Каждую неделю Вы собираете еженедельные отчеты от руководителей групп и оцениваете состояние каждой работы по сравнению с сетевым графиком. Если все в порядке – можно плевать в потолок и ждать конца следующей недели. К сожалению, так бывает очень редко. Допустим, какая-то работа затянулась. Если она не на критическом пути – ничего страшного. Нужно провести воспитательную работу, дать дополнительный срок (причем надо следить, чтобы от этого увеличения не возник новый критический путь!), продумать какие-то меры, чтобы не допустить повторения подобных ситуаций. Если же проваленная работа лежит на критическом пути, необходимо перепланирование, причем основной проблемой является невозможность (чаще всего) сдвига сроков завершения. Мы только что (при планировании) занимались оптимизацией сетевого графика, прошло всего несколько недель — и вот мы снова занимаемся тем же самым.
Даже сама по себе задача определения задержки выполнения какой-то работы является весьма нетривиальной. Люди имеют обыкновение выдавать желаемое за действительное, а уж менеджеры – и подавно. Каждый думает, что возникшую небольшую задержку он обязательно ликвидирует в ближайшие дни, поэтому можно и не сообщать о ней начальнику. Кроме того, хотя при составлении плана делалось все возможное, чтобы сформулировать все события максимально точным образом, всегда есть лазейка, чтобы представить недоделанную работу завершенной. Тут многое зависит от психологического климата в коллективе, от уровня доверия, установившегося между руководителями и подчиненными.
Не меньшее значение имеет и уровень технической оснащенности: одно дело, когда решение принимается только на основании устного сообщения, и совсем другое – когда все результаты работы (не только программы, но и схемы, алгоритмы, описания и т.д.) собираются в едином репозитории, когда имеется возможность выполнения различных формальных проверок, когда руководитель может просмотреть результаты в их развитии, оценить работу не только группы в целом, но и каждого ее участника.
Графически проблему управления можно представить в виде треугольника:

В этом треугольнике каждая вершина зависит от двух других. Например, если работы не укладываются в сроки, можно попытаться договориться с заказчиком об их удлинении (очевидно, что стоимость работ также возрастет). Если сроки сдвинуть нельзя, необходимо договариваться с заказчиками об уменьшении объема работ (т.е. выкинуть какие-то функции из спецификации), либо привлекать дополнительные ресурсы. Кто-то из классиков сказал: "Добавлять людей в горящий коллектив – это все равно что заливать пожар керосином" – ведь новых людей нужно ввести в курс дела, отвлекая на это основных разработчиков, но даже после этого вряд ли удастся ускорить работу, так как увеличивается количество интерфейсов и согласований между участниками. В тех случаях, когда сроки сорваны, ресурсы исчерпаны, а важная работа не выполнена, легче эту работу заново спланировать и поручить другому коллективу.
Опытные руководители проектов отчетливо понимают эти проблемы и решают их, в первую очередь, за счет квалифицированного проектирования, учета возможных рисков, обеспечения возможности регулярного общения между разработчиками, выделения максимально независимых компонентов (которые могут быть переданы дополнительным разработчикам), за счет скрытых ресурсов, о которых разработчики даже не подозревают. Например, широко распространена практика, когда руководитель договаривается с заказчиком об одних сроках, а разработчикам сообщает другие, более сжатые сроки.
Неплохо иметь "пожарную команду" из двух-трех высококлассных специалистов, которые в промежутках между "пожарами" занимаются исследованиями или развитием инструментальных средств.
Некоторые авторы предлагают в случае выхода из графика применять "метод пряника", т.е. предлагать разработчикам дополнительные деньги за сверхурочную работу, но, может быть, это не очень верно. Т.е. такая мера может сработать раз или два, но потом разработчики интуитивно (а, может быть, и не совсем интуитивно) начинают затягивать работы, ожидая дополнительных подачек. Сидит такой имитатор деятельности, месяц бьет баклуши, но за два-три дня до сдачи начинает работать ночами и утром в день сдачи с воспаленными глазами сдает руководителю действующую программу, но не прошедшую через регулярную процедуру QA, не проверенную в комплексе с другими программами и т.д.
Жертвенность на работе – это, в первую очередь, признак непрофессионализма.
Так как же все-таки управлять программистским коллективом? Добавлять людей нельзя, сулить премии нельзя, давить своим авторитетом на подчиненных нельзя, а что же можно? Хотелось бы получить ответ от каких-то известных в этой области специалистов, причем не на уровне общих рассуждений, а в виде конкретных рекомендаций и методик, иначе и вправду системное программирование сильно смахивает на искусство, а не на промышленную дисциплину.
Многие годы для нас таким авторитетом является Ф. Брукс, который руководил отделением программирования IBM (несколько тысяч человек) в шестидесятые годы, как раз тогда, когда создавалась знаменитая серия IBM/360. Покинув IBМ, Ф. Брукс стал профессором университета Чапел-Хилл в Северной Каролине и написал ставшую бестселлером книгу "Как проектируются и создаются программные комплексы. Мифический человеко-месяц. Очерки по системному программированию". Эта книга в 1979 году была переведена на русский язык и издана в издательстве "Мир". За несколько лет до этого по СССР ходил "левый" перевод этой же книги, выполненный (и, кстати, гораздо лучше, чем официальный) академиком А.П. Ершовым. Через 20 лет вышло юбилейное переиздание книги[5], дополненное поздними статьями Ф. Брукса и подробным анализом, какие идеи, высказанные 20 лет назад, сохранили свою силу, а какие оказались ошибочными. Кроме несомненного дара системного программиста и огромного опыта руководства большими коллективами Ф. Брукс обладает ярким литературным талантом – многие фразы из книги стали общеизвестными лозунгами программистов. В декабре 2000 года мне удалось побеседовать с ним прямо на его рабочем месте, и личная встреча только усилила мои впечатления об этом замечательном ученом.
Так вот, читая эту книгу, можно обнаружить массу полезных и красиво изложенных советов, как организовать коллектив, какие бывают варианты жизненного цикла ПО, какую документацию и насколько подробно надо готовить, и еще множество интересных вещей. Но конкретных советов, что делать, когда гром уже грянул, когда работа, лежащая на критическом пути, не выполнена в срок, вы не найдете.
Основная идея состоит в том, что при правильной организации, с хорошо подготовленным коллективом можно уменьшить вероятность срывов, предугадать их на возможно более
Но ведь люди работают, сроки горят, значит, какие-то выходы из этой ситуации есть. Я спросил Лена Эрлиха, нашего американского заказчика, как поступают американские менеджеры в ситуации, когда заваливается критически важная работа. Ответ был прост, как выстрел. Подключаются 1-2 мощных специалиста, проводятся совещания по ходу работ – каждый день, а если мало, то дважды в день, обязательно в присутствии высшего руководства. Те функции, ошибки в которых исправить трудно, безжалостно выкидываются. Главное, чтобы в срок заработала основная масса функций – тогда есть шансы договориться с заказчиком о дополнительном времени для завершения работы, если же к нужному времени показать нечего, скандал неминуем.
В общем-то, ситуация классическая: ученые говорят, что "добавлять людей в горящий коллектив — это все равно что заливать пожар керосином", а практики добавляют, ужесточают контроль и часто побеждают. "Ученый думает, что знает, но у него не совпадает, у практика все совпадает, но почему – никто не знает".
Чтобы не завершать параграф на такой грустной ноте, приведу перечень возможных корректирующих действий менеджера из внутренних правил одной крупной западной фирмы:
Как видите, все на уровне здравого смысла, никакой "серебряной пули", но здесь следует привести мою любимую фразу: "На свете есть множество общеизвестных, но не общепринятых истин". Если не получается руководить программным проектом, то почему бы не попробовать работать по правилам?
Для начала вспомним три аксиомы одного из самых первых советских программистов с несколько необычной фамилией Шура-Бура.
Аксиома 1. В каждой программе есть ошибка.
Аксиома 2. Если в программе нет ошибок, значит, в исходном алгоритме есть ошибка.
Аксиома 3. Если ни в программе, ни в алгоритме ошибок нет, то такая программа никому не нужна.
При всей шутливости этих аксиом в них отражена суровая правда жизни.
Исходные идеи тестирования абсолютно понятны [9].
Вы написали программу, хотите убедиться в правильности ее работы, поэтому пропускаете один или несколько тестов и смотрите, что получилось. Понятно, что тесты должны быть простыми настолько, чтобы можно было предсказать правильный ответ, иначе как вы определите, правильно ли программа сработала?
А что делать со сложными тестами и, вообще, сколько тестов нужно пропустить? Ответ очевиден – бесконечно много, поэтому с помощью теста можно доказать наличие ошибок (если тест был достаточно "зубастым"), но нельзя доказать их отсутствие.
Бесконечность тестов определяется наличием циклов, рекурсии, разнообразием значений данных. Ситуация обычна для нашей специальности. Теоретическая невозможность не снимает с нас ответственности за поиск практических способов проверки – пусть не полных, но дающих какую-то степень уверенности. Итак, что же можно сделать?
Еще 30 лет назад был популярен критерий полноты тестирования, при котором набор тестов гарантировал, что по каждому ребру графа управления программы исполнение программы хотя бы один раз пройдет. Такой набор тестов можно создать, часто даже автоматически.
Чтобы проверить цикл, нужно создать тест, гарантирующий прохождение цикла 0, 1 и 2 раза. 0 – вдруг условие входа в цикл сразу было ложным, 1 – нормальное прохождение, 2 – не столь очевидно. Возможно, в конце цикла есть присваивание переменной, которая в начале цикла только читается. Понятно, что однократный проход по циклу не даст возможности проверки важного и весьма вероятного варианта.
Изложенные критерии носят только эвристический характер, но весьма полезны. Таким образом, мы видим, что программирование и тестирование – совершенно разные типы деятельности, требующие разных исполнителей.
Программирование – это конструктивный созидательный процесс, который требует высокой квалификации и определенного оптимизма (cм. аксиомы Шуры-Буры).
Тестирование – деструктивный процесс, который требует высокой дотошности, подозрительности, пессимистичности, но, вообще говоря, не требует высокой квалификации. Пусть не обижаются на меня настоящие системные программисты, которые создают инструментальные средства автоматизации тестирования, я говорю об обычных тестерах. В каждом коллективе есть люди с неуживчивым характером, любящие покритиковать коллег по работе. Цены им не будет в группе тестирования.
Еще раз повторим, что тестирование нужно вовсе не для того, чтобы показать, что программа работает правильно – это невозможно. Тестирование – это процесс исполнения программы с целью нахождения ошибок. Хороший тест – это тест, на котором с большой вероятностью ошибка найдется.
Теперь приведем несколько организационных и технологических соображений относительно тестирования.
Тестирование (не считая начальных отладочных тестов) не должно проводиться самими авторами программы. Наблюдается определенная "замыленность" взгляда автора на программу, поэтому он и тесты будет готовить на те варианты, которые предусмотрел в программе.
Должна быть конкуренция между программистами и тестировщиками, нужен дух соревнования: "Я все равно тебя поймаю" против "Врешь, не поймаешь".
Необходимо уметь оценивать вероятность и примерное количество оставшихся ошибок. Например, известен метод оценки количества рыб в пруду. Ловят, скажем, 100 рыбок, помечают их и выпускают обратно в пруд. Затем снова ловят 100 рыбок. Если почти все они мечены, значит, в пруду примерно 100 рыбок и есть, если же меченых попалось мало, то рыб, скорее всего, больше, причем в той же пропорции, какова доля непомеченных из 100 вновь пойманных. Во многих фирмах применяют тот же прием: специальные люди вставляют некоторое количество разнообразных ошибок в программы и возвращают их на доработку авторам с требованием обнаружить ровно столько же ошибок. По тому, какая часть найденных ошибок относится к специально вставленным, а какая – к вновь найденным ошибкам, можно судить о числе оставшихся ошибок. Еще проще – поручить тестирование одной и той же программы двум группам тестировщиков и оценить процент ошибок, найденных обеими группами.
Должно проверяться не только нормальное поведение программы, но и поведение в случае неправильных входных данных и других ошибочных ситуаций на предмет устойчивости программы, осмысленности сообщений об ошибках и т.д.
Всегда должен быть четко оговорен конечный результат тестирования. В идеале еще до начала работ или на одной из ранних стадий (работа 2-10 из нашего примера) должен быть создан и согласован с заказчиком набор тестов, успешный пропуск которых свидетельствует об успешном окончании работы в целом. К сожалению, на практике такое встречается редко, поэтому сдача проекта – это всегда, скажем так, шумный процесс.
Различают тестирование по типам:
и по объему:
Особого упоминания заслуживают тестирование граничных значений входных данных, тесты на максимальный объем счета, проверка предположений об ошибках ("Я бы сделал ошибку здесь").
Иногда применяется перекрестное чтение особо ответственных участков программы, когда одна группа разработчиков читает программы другой группы (insрection
В зрелых программистских компаниях для каждого проекта ведется своя база данных ошибок, в которую вносится:
Особенно заметна ценность базы данных ошибок для больших и длительных проектов. Если идентификатор одной ошибки встречается десятки раз в различных письмах, недельных отчетах – это верный признак того, что требуется вмешательство руководства. Все руководители разных рангов знают на память записи из этой базы данных о текущих ошибках с высшей важностью и приоритетом. По завершении каждого проекта база данных ошибок внимательно анализируется. Интересно распределение ошибок по тому, кто их совершил, по времени исправления, кто чаще ошибки находит и т.д. Если в одну неделю разработчик 1 сделал 10 ошибок, а разработчик 2 – только 2, это еще ни о чем не говорит. Но если же за весь период разработки разработчик 1 сделал 100 ошибок, а разработчик 2 – только 10, то по этим цифрам можно уже судить об их квалификации. Можно также оценивать целые группы или, скажем, качество проектирования, а можно сделать какие-то выводы по мощности и надежности используемых инструментальных средств.
На основе изучения записей в базе данных ошибок руководство проектом принимает решение о возможности выпуска продукта, например, продукт нельзя выпускать, если есть хотя бы одна ошибка с важностью "crash" или с приоритетом "highest/high". Возможна и такая стратегия, когда продукт выпустить обязательно надо, но времени на исправление основных ошибок нет (нужно помнить, что даже небольшие исправления могут повлечь за собой новые ошибки), тогда из продукта просто удаляют часть функций, в которых есть ошибки.
Мы говорили о тестировании, только отдавая дань многолетней традиции. На самом деле, любая зрелая программистская компания имеет большую независимую группу оценки качества ПО (
QA должна играть роль придирчивого пользователя, но внутри компании. В США разработчики и QA сидят в разных концах коридора, не поощряется даже неформальное общение. В западных компаниях довольно существенную часть зарплаты (примерно 20-30%) составляет бонус, выплачиваемый в конце проекта и только в случае его успешного завершения. Так вот, если QA найдет слишком много ошибок разработчиков, те остаются без бонуса, но если QA принял разработку, а затем пользователи начнут жаловаться, то QA остается без бонуса, хотя жалобы связаны с ошибками разработчиков. Таким искусственным разделением ответственности и непоощрением дружеских отношений между разработчиками и QA владельцы компаний пытаются застраховаться от неудачи на рынке. В США говорят, что каждому продукту дается только одна попытка выхода на рынок. Если пользователям по разным причинам продукт не понравился, репутация теряется навсегда. Поэтому ошибки так дорого стоят.
Результатом фазы оценки осуществимости являются детальная спецификация, план работы и оценка стоимости. Наиболее традиционной формой плана можно считать сетевой график, который представляется в виде ориентированного графа с двумя
Сетевой график – очень удобный инструмент: во-первых, на нем четко видна зависимость работ друг от друга, во-вторых, на основе сетевого графика можно вычислить длительность всей работы, в-третьих, пользуясь результатами этих расчетов, можно попытаться оптимизировать длительность и затраты на работу.
Длительность вычисляется следующим образом. Суммируем длительности работ по всем возможным путям в графе. Тот путь от начала к концу, который является самым длинным, объявляется критическим, потому что задержка любой работы, лежащей на этом пути, приводит к задержке всей работы в целом. Понятно, что критических путей (с одинаковой длительностью) может быть несколько.
Рассмотрим пример.
Здесь приводится классическая задача планирования: нормально работающая, полностью загруженная компания получила заказ, от которого по разным причинам невозможно отказаться. Перечислим названия событий, т.е. узлов в графе:

Под каждым ребром графа записана планируемая длительность соответствующей работы (в неделях). Еще раз повторю, что это только пример, прошу не придираться к техническим деталям, в частности, разумеется, каждая передача (3-7, 3-10 и т.д.) не может длиться более одного-двух дней, но не хотелось возиться с дробями.
Критическими путями являются пути 1-6-2-3-4-5-9-13-14-15 и 1-6-2-3-4-5-12-13-14-15, т.е. вся работа не может быть выполнена быстрее, чем за двадцать одну неделю. Понятно, что с точки зрения оптимальной загрузки коллектива было бы лучше, чтобы все пути в графе от начала к концу имели примерно одинаковую длительность с тем чтобы как-то уменьшить длину критического пути. Например, есть соблазн заставить группу QA проводить даже начальное тестирование, уменьшив нагрузку на программистов, работа которых находится на критическом пути. Но тогда очень трудно определить границы ответственности, программисты начинают выдавать откровенную халтуру и в результате сроки даже удлиняются. В реальных проектах, где работ очень много, все-таки удается путем перераспределения работ улучшать сетевой график, по крайней мере, к этому стремятся все руководители.
Еще несколько замечаний по данному примеру. Явно неудачно спланированы работы между событиями 1, 2, 6. Коллектив сформирован за одну неделю, а рабочие места еще не готовы. Группа технических писателей начинает работать на шесть недель позже проектировщиков, а группа QA имеет трехнедельный перерыв перед завершением проектирования и т.д.
Эти проблемы действительно трудны, каждая компания решает их по-своему, например, очевидным решением является использование одной и той же группы QA или технических писателей для нескольких групп разработчиков.
Еще одной популярной формой графического представления плана работ является диаграмма Ганта (Gantt). Диаграмма Ганта представляет собой прямоугольник: слева направо равномерно отсчитываются периоды времени (недели, месяцы), сверху вниз перечисляются работы, причем каждая работа представляется в виде отрезка, начало и конец которого размещаются в соответствующем периоде.
Для сравнения с сетевым графиком нарисуем диаграмму Ганта для того же примера:

Если в сетевом графике особенно наглядно видны зависимости работ друг от друга, (например, работа 12-13 может начаться только после завершения работ 5-12 и 11-12), то в диаграмме Ганта основной упор делается на то, что происходит в каждую конкретную неделю, например, видно, что группа QA имеет перерыв в работе в 2 недели между работами 11-12 (автономное тестирование) и 12-13 (комплексное тестирование). Именно поэтому "большие начальники" предпочитают диаграммы Ганта: в конце каждой недели проводишь вертикальную линию и сразу видишь, какие работы велись, что должно кончиться, а что начаться. Должен признаться, что я и сам нашел пару ошибок в расчетах по сетевому графику, пока строил диаграмму Ганта для этого примера. Тем самым я еще раз убедился, что диаграмма Ганта нагляднее сетевого графика, или в том, что я уже большой начальник, а не технический специалист. Технические менеджеры предпочитают сетевые графики, так как им важнее информация о том, что от чего зависит, да и пересчитывать критические пути им приходится практически каждую неделю.
На диаграмме Ганта принято над каждым отрезком работы указывать, сколько сотрудников принимает участие в этой работе (в сетевом графике это возможно, но не очень удобно, поскольку надо указывать еще и длительность работы). Опять-таки, начальники любят смотреть, сколько сотрудников занято в каждой неделе, что легко увидеть как раз на диаграмме Ганта.
На самом деле управление[8] почти неотделимо от планирования. Вы спланировали работу, приступили к ее исполнению. Каждую неделю Вы собираете еженедельные отчеты от руководителей групп и оцениваете состояние каждой работы по сравнению с сетевым графиком. Если все в порядке – можно плевать в потолок и ждать конца следующей недели. К сожалению, так бывает очень редко. Допустим, какая-то работа затянулась. Если она не на критическом пути – ничего страшного. Нужно провести воспитательную работу, дать дополнительный срок (причем надо следить, чтобы от этого увеличения не возник новый критический путь!), продумать какие-то меры, чтобы не допустить повторения подобных ситуаций. Если же проваленная работа лежит на критическом пути, необходимо перепланирование, причем основной проблемой является невозможность (чаще всего) сдвига сроков завершения. Мы только что (при планировании) занимались оптимизацией сетевого графика, прошло всего несколько недель — и вот мы снова занимаемся тем же самым.
Даже сама по себе задача определения задержки выполнения какой-то работы является весьма нетривиальной. Люди имеют обыкновение выдавать желаемое за действительное, а уж менеджеры – и подавно. Каждый думает, что возникшую небольшую задержку он обязательно ликвидирует в ближайшие дни, поэтому можно и не сообщать о ней начальнику. Кроме того, хотя при составлении плана делалось все возможное, чтобы сформулировать все события максимально точным образом, всегда есть лазейка, чтобы представить недоделанную работу завершенной. Тут многое зависит от психологического климата в коллективе, от уровня доверия, установившегося между руководителями и подчиненными.
Не меньшее значение имеет и уровень технической оснащенности: одно дело, когда решение принимается только на основании устного сообщения, и совсем другое – когда все результаты работы (не только программы, но и схемы, алгоритмы, описания и т.д.) собираются в едином репозитории, когда имеется возможность выполнения различных формальных проверок, когда руководитель может просмотреть результаты в их развитии, оценить работу не только группы в целом, но и каждого ее участника.
Графически проблему управления можно представить в виде треугольника:

В этом треугольнике каждая вершина зависит от двух других. Например, если работы не укладываются в сроки, можно попытаться договориться с заказчиком об их удлинении (очевидно, что стоимость работ также возрастет). Если сроки сдвинуть нельзя, необходимо договариваться с заказчиками об уменьшении объема работ (т.е. выкинуть какие-то функции из спецификации), либо привлекать дополнительные ресурсы. Кто-то из классиков сказал: "Добавлять людей в горящий коллектив – это все равно что заливать пожар керосином" – ведь новых людей нужно ввести в курс дела, отвлекая на это основных разработчиков, но даже после этого вряд ли удастся ускорить работу, так как увеличивается количество интерфейсов и согласований между участниками. В тех случаях, когда сроки сорваны, ресурсы исчерпаны, а важная работа не выполнена, легче эту работу заново спланировать и поручить другому коллективу.
Опытные руководители проектов отчетливо понимают эти проблемы и решают их, в первую очередь, за счет квалифицированного проектирования, учета возможных рисков, обеспечения возможности регулярного общения между разработчиками, выделения максимально независимых компонентов (которые могут быть переданы дополнительным разработчикам), за счет скрытых ресурсов, о которых разработчики даже не подозревают. Например, широко распространена практика, когда руководитель договаривается с заказчиком об одних сроках, а разработчикам сообщает другие, более сжатые сроки.
Неплохо иметь "пожарную команду" из двух-трех высококлассных специалистов, которые в промежутках между "пожарами" занимаются исследованиями или развитием инструментальных средств.
Некоторые авторы предлагают в случае выхода из графика применять "метод пряника", т.е. предлагать разработчикам дополнительные деньги за сверхурочную работу, но, может быть, это не очень верно. Т.е. такая мера может сработать раз или два, но потом разработчики интуитивно (а, может быть, и не совсем интуитивно) начинают затягивать работы, ожидая дополнительных подачек. Сидит такой имитатор деятельности, месяц бьет баклуши, но за два-три дня до сдачи начинает работать ночами и утром в день сдачи с воспаленными глазами сдает руководителю действующую программу, но не прошедшую через регулярную процедуру QA, не проверенную в комплексе с другими программами и т.д.
Жертвенность на работе – это, в первую очередь, признак непрофессионализма.
Так как же все-таки управлять программистским коллективом? Добавлять людей нельзя, сулить премии нельзя, давить своим авторитетом на подчиненных нельзя, а что же можно? Хотелось бы получить ответ от каких-то известных в этой области специалистов, причем не на уровне общих рассуждений, а в виде конкретных рекомендаций и методик, иначе и вправду системное программирование сильно смахивает на искусство, а не на промышленную дисциплину.
Многие годы для нас таким авторитетом является Ф. Брукс, который руководил отделением программирования IBM (несколько тысяч человек) в шестидесятые годы, как раз тогда, когда создавалась знаменитая серия IBM/360. Покинув IBМ, Ф. Брукс стал профессором университета Чапел-Хилл в Северной Каролине и написал ставшую бестселлером книгу "Как проектируются и создаются программные комплексы. Мифический человеко-месяц. Очерки по системному программированию". Эта книга в 1979 году была переведена на русский язык и издана в издательстве "Мир". За несколько лет до этого по СССР ходил "левый" перевод этой же книги, выполненный (и, кстати, гораздо лучше, чем официальный) академиком А.П. Ершовым. Через 20 лет вышло юбилейное переиздание книги[5], дополненное поздними статьями Ф. Брукса и подробным анализом, какие идеи, высказанные 20 лет назад, сохранили свою силу, а какие оказались ошибочными. Кроме несомненного дара системного программиста и огромного опыта руководства большими коллективами Ф. Брукс обладает ярким литературным талантом – многие фразы из книги стали общеизвестными лозунгами программистов. В декабре 2000 года мне удалось побеседовать с ним прямо на его рабочем месте, и личная встреча только усилила мои впечатления об этом замечательном ученом.
Так вот, читая эту книгу, можно обнаружить массу полезных и красиво изложенных советов, как организовать коллектив, какие бывают варианты жизненного цикла ПО, какую документацию и насколько подробно надо готовить, и еще множество интересных вещей. Но конкретных советов, что делать, когда гром уже грянул, когда работа, лежащая на критическом пути, не выполнена в срок, вы не найдете.
Основная идея состоит в том, что при правильной организации, с хорошо подготовленным коллективом можно уменьшить вероятность срывов, предугадать их на возможно более
Но ведь люди работают, сроки горят, значит, какие-то выходы из этой ситуации есть. Я спросил Лена Эрлиха, нашего американского заказчика, как поступают американские менеджеры в ситуации, когда заваливается критически важная работа. Ответ был прост, как выстрел. Подключаются 1-2 мощных специалиста, проводятся совещания по ходу работ – каждый день, а если мало, то дважды в день, обязательно в присутствии высшего руководства. Те функции, ошибки в которых исправить трудно, безжалостно выкидываются. Главное, чтобы в срок заработала основная масса функций – тогда есть шансы договориться с заказчиком о дополнительном времени для завершения работы, если же к нужному времени показать нечего, скандал неминуем.
В общем-то, ситуация классическая: ученые говорят, что "добавлять людей в горящий коллектив — это все равно что заливать пожар керосином", а практики добавляют, ужесточают контроль и часто побеждают. "Ученый думает, что знает, но у него не совпадает, у практика все совпадает, но почему – никто не знает".
Чтобы не завершать параграф на такой грустной ноте, приведу перечень возможных корректирующих действий менеджера из внутренних правил одной крупной западной фирмы:
Как видите, все на уровне здравого смысла, никакой "серебряной пули", но здесь следует привести мою любимую фразу: "На свете есть множество общеизвестных, но не общепринятых истин". Если не получается руководить программным проектом, то почему бы не попробовать работать по правилам?
Для начала вспомним три аксиомы одного из самых первых советских программистов с несколько необычной фамилией Шура-Бура.
Аксиома 1. В каждой программе есть ошибка.
Аксиома 2. Если в программе нет ошибок, значит, в исходном алгоритме есть ошибка.
Аксиома 3. Если ни в программе, ни в алгоритме ошибок нет, то такая программа никому не нужна.
При всей шутливости этих аксиом в них отражена суровая правда жизни.
Исходные идеи тестирования абсолютно понятны [9].
Вы написали программу, хотите убедиться в правильности ее работы, поэтому пропускаете один или несколько тестов и смотрите, что получилось. Понятно, что тесты должны быть простыми настолько, чтобы можно было предсказать правильный ответ, иначе как вы определите, правильно ли программа сработала?
А что делать со сложными тестами и, вообще, сколько тестов нужно пропустить? Ответ очевиден – бесконечно много, поэтому с помощью теста можно доказать наличие ошибок (если тест был достаточно "зубастым"), но нельзя доказать их отсутствие.
Бесконечность тестов определяется наличием циклов, рекурсии, разнообразием значений данных. Ситуация обычна для нашей специальности. Теоретическая невозможность не снимает с нас ответственности за поиск практических способов проверки – пусть не полных, но дающих какую-то степень уверенности. Итак, что же можно сделать?
Еще 30 лет назад был популярен критерий полноты тестирования, при котором набор тестов гарантировал, что по каждому ребру графа управления программы исполнение программы хотя бы один раз пройдет. Такой набор тестов можно создать, часто даже автоматически.
Чтобы проверить цикл, нужно создать тест, гарантирующий прохождение цикла 0, 1 и 2 раза. 0 – вдруг условие входа в цикл сразу было ложным, 1 – нормальное прохождение, 2 – не столь очевидно. Возможно, в конце цикла есть присваивание переменной, которая в начале цикла только читается. Понятно, что однократный проход по циклу не даст возможности проверки важного и весьма вероятного варианта.
Изложенные критерии носят только эвристический характер, но весьма полезны. Таким образом, мы видим, что программирование и тестирование – совершенно разные типы деятельности, требующие разных исполнителей.
Программирование – это конструктивный созидательный процесс, который требует высокой квалификации и определенного оптимизма (cм. аксиомы Шуры-Буры).
Тестирование – деструктивный процесс, который требует высокой дотошности, подозрительности, пессимистичности, но, вообще говоря, не требует высокой квалификации. Пусть не обижаются на меня настоящие системные программисты, которые создают инструментальные средства автоматизации тестирования, я говорю об обычных тестерах. В каждом коллективе есть люди с неуживчивым характером, любящие покритиковать коллег по работе. Цены им не будет в группе тестирования.
Еще раз повторим, что тестирование нужно вовсе не для того, чтобы показать, что программа работает правильно – это невозможно. Тестирование – это процесс исполнения программы с целью нахождения ошибок. Хороший тест – это тест, на котором с большой вероятностью ошибка найдется.
Теперь приведем несколько организационных и технологических соображений относительно тестирования.
Тестирование (не считая начальных отладочных тестов) не должно проводиться самими авторами программы. Наблюдается определенная "замыленность" взгляда автора на программу, поэтому он и тесты будет готовить на те варианты, которые предусмотрел в программе.
Должна быть конкуренция между программистами и тестировщиками, нужен дух соревнования: "Я все равно тебя поймаю" против "Врешь, не поймаешь".
Необходимо уметь оценивать вероятность и примерное количество оставшихся ошибок. Например, известен метод оценки количества рыб в пруду. Ловят, скажем, 100 рыбок, помечают их и выпускают обратно в пруд. Затем снова ловят 100 рыбок. Если почти все они мечены, значит, в пруду примерно 100 рыбок и есть, если же меченых попалось мало, то рыб, скорее всего, больше, причем в той же пропорции, какова доля непомеченных из 100 вновь пойманных. Во многих фирмах применяют тот же прием: специальные люди вставляют некоторое количество разнообразных ошибок в программы и возвращают их на доработку авторам с требованием обнаружить ровно столько же ошибок. По тому, какая часть найденных ошибок относится к специально вставленным, а какая – к вновь найденным ошибкам, можно судить о числе оставшихся ошибок. Еще проще – поручить тестирование одной и той же программы двум группам тестировщиков и оценить процент ошибок, найденных обеими группами.
Должно проверяться не только нормальное поведение программы, но и поведение в случае неправильных входных данных и других ошибочных ситуаций на предмет устойчивости программы, осмысленности сообщений об ошибках и т.д.
Всегда должен быть четко оговорен конечный результат тестирования. В идеале еще до начала работ или на одной из ранних стадий (работа 2-10 из нашего примера) должен быть создан и согласован с заказчиком набор тестов, успешный пропуск которых свидетельствует об успешном окончании работы в целом. К сожалению, на практике такое встречается редко, поэтому сдача проекта – это всегда, скажем так, шумный процесс.
Различают тестирование по типам:
и по объему:
Особого упоминания заслуживают тестирование граничных значений входных данных, тесты на максимальный объем счета, проверка предположений об ошибках ("Я бы сделал ошибку здесь").
Иногда применяется перекрестное чтение особо ответственных участков программы, когда одна группа разработчиков читает программы другой группы (insрection
В зрелых программистских компаниях для каждого проекта ведется своя база данных ошибок, в которую вносится:
Особенно заметна ценность базы данных ошибок для больших и длительных проектов. Если идентификатор одной ошибки встречается десятки раз в различных письмах, недельных отчетах – это верный признак того, что требуется вмешательство руководства. Все руководители разных рангов знают на память записи из этой базы данных о текущих ошибках с высшей важностью и приоритетом. По завершении каждого проекта база данных ошибок внимательно анализируется. Интересно распределение ошибок по тому, кто их совершил, по времени исправления, кто чаще ошибки находит и т.д. Если в одну неделю разработчик 1 сделал 10 ошибок, а разработчик 2 – только 2, это еще ни о чем не говорит. Но если же за весь период разработки разработчик 1 сделал 100 ошибок, а разработчик 2 – только 10, то по этим цифрам можно уже судить об их квалификации. Можно также оценивать целые группы или, скажем, качество проектирования, а можно сделать какие-то выводы по мощности и надежности используемых инструментальных средств.
На основе изучения записей в базе данных ошибок руководство проектом принимает решение о возможности выпуска продукта, например, продукт нельзя выпускать, если есть хотя бы одна ошибка с важностью "crash" или с приоритетом "highest/high". Возможна и такая стратегия, когда продукт выпустить обязательно надо, но времени на исправление основных ошибок нет (нужно помнить, что даже небольшие исправления могут повлечь за собой новые ошибки), тогда из продукта просто удаляют часть функций, в которых есть ошибки.
Мы говорили о тестировании, только отдавая дань многолетней традиции. На самом деле, любая зрелая программистская компания имеет большую независимую группу оценки качества ПО (
QA должна играть роль придирчивого пользователя, но внутри компании. В США разработчики и QA сидят в разных концах коридора, не поощряется даже неформальное общение. В западных компаниях довольно существенную часть зарплаты (примерно 20-30%) составляет бонус, выплачиваемый в конце проекта и только в случае его успешного завершения. Так вот, если QA найдет слишком много ошибок разработчиков, те остаются без бонуса, но если QA принял разработку, а затем пользователи начнут жаловаться, то QA остается без бонуса, хотя жалобы связаны с ошибками разработчиков. Таким искусственным разделением ответственности и непоощрением дружеских отношений между разработчиками и QA владельцы компаний пытаются застраховаться от неудачи на рынке. В США говорят, что каждому продукту дается только одна попытка выхода на рынок. Если пользователям по разным причинам продукт не понравился, репутация теряется навсегда. Поэтому ошибки так дорого стоят.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.