суббота, 20 декабря 2003 г.

Вверх и вниз

* * *

"В иерархии каждый индивидуум достигает

предела своей некомпетентности."

(принцип Питера)


Эта заметка для программистов. Для тех программистов, которые силой "логики жизни" (или закона Мэрфи), оказались в роли "постановщиков задач", "руководителей проектов" и тому подобных странных ролях. А также для тех программистов, которых ветром странствий занесло в фирмы, где "техзадания" пишут сами программисты. Короче - эта заметка о написании техзаданий (ТЗ)...

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

Да потому, что у программистов редко получается написать это самое ТЗ в нормальном виде (или в разумные сроки). Гуру от менеджмента говорят о "нисходящем" и "восходящем" проектировании, о том, что у большинства программистов другие стратегии мышления и что пусть уж ТЗ пишут другие люди, мыслящие другими масштабами обобщений... Но если вдуматься в этот тезис, он предстает абсурдом. Поскольку у "программиста" не может быть только одной стратегии мышления. Кроме того, что он программист, он еще и человек... и как человек, ловит рыбу или выбирает продукты в магазине ничуть не хуже того самого менеджера. И только на работе, садясь за клавиатуру, они включают разные стратегии. Ну так это, на мой взгляд, дело поправимое. О чем собственно и пойдет речь - о стратегиях...


* * *

"Все, что мы можем помыслить -

существует. Оно реально именно

в силу нашего представления."


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

Сядьте спокойно и возьмите лист бумаги и карандаш (или откройте пустое окошко графического редактора). А теперь подумайте, с чего вы бы начали писать код. Вот прямо сейчас. Что есть то, что вы бы написали в первую очередь? Рисуем на листе (на экране) квадратик и пишем название. Не важно что это (класс, структура, функция или библиотека), оно есть "сущность" уже потому, что мы его назвали. И как всякая сущность может быть описана "модулем" (хотя бы теоретически).

То, что я сказал здесь, часть общего метода: когда мы хватаем кота за хвост, мы не морочим себе голову, на тему того, что хвост непрерывно переходит в кота. Просто есть то, за что можно схватить - (ручка кота) хвост. Значит, можно считать "это" сущностью, частью, модулем, имеющим имя (гм... модульный кот поднял голову и недовольно посмотрел. "А ведь модулями я буду гораздо более емким" ) В дальнейшем я буду говорить "модуль". Надеюсь, теперь будет понятно, что я имею в виду.

Итак, у вас перед глазами один квадратик. А теперь представьте, что это модуль у вас УЖЕ НАПИСАН. Можете прежставить дискету в руках, файл на диске или открытый исходник в редакторе. Так или наче, но он у вас есть. Что вы с ним будете делать дальше? Тестировать, записывать в архив, может быть, еще что-нибудь... Представьте, КАК вы делаете это... Обведите ваш квадратик еще одной жирной рамочкой - пока закончено.

А теперь, _имея этот модуль уже законченным_, что вы станете писать дальше? Что есть то следующее, что вы стали бы кодировать? Руки на клавиатуре, представьте перед собой открытый редактор, о чем будет следующая строчка вашего кода? Как это "нечто" мы назовем? Рисуем следующий квадратик...

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

Есть ли что-то такое, что мы упустили в первом модуле, и вспомнили только занявшись вторым? Что-то такое, что при кодировании потребовало бы от вас правок в первом модуле? Если есть, "правим" сразу, пока не ушли далеко... Например, можно почеркаться на стороне квадратика первого модуля (или заштриховать уголок) - это ваши правки. Модуль стал менее опрятным... ну что ж - дойдет время и до рефакторинга.

Ну вот, теперь у вас уже два модуля. Правки внесены, связи использованы... Что пишем двальше? Рисуем третий квадратик... И снова - хорошо представить, как вы будете чувствовать себя, что видеть и слышать, когда третий модуль будет написан. Остановитесь и вчувствуйтесь в этот момент, в это время, в это состояние... Каковы связи между всеми тремя модулями? Какие правки потребуются в первом и втором. Линии связей, почеркушки правок... и идем дальше.

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

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


* * *

"Не умножайте сущностей

сверх необходимого."

("бритва Оккама")

"Любая классификация содержит

от трех до шести категорий"

(из законов Мэрфи)


У нас получилась схемка. Аккуратненькая и даже (возможно) красивая. Но та ли это программа, которая нам нужна? Возможно, еще нет... Могу вам сказать, что если на вашей схеме больше 5-6 модулей, то это модули разных уровней. Некоторые из них отражают действительно существенные блоки и функции, а некоторые - частные переходики, связки и функции, про которые в какой-то момент забыли, а потом вспомнили (или наоборот: нарисовали раньше, потому что было понятнее, как их писать). Берем третий лист и перерисовываем схему, объединяя более мелкие и частные кусочки с теми модулями, к которым они собственно и относятся. У вас должно получиться от 4 до 6 модулей.


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

И остается только пройти этот путь шаг за шагом. Если так, то стоит вернуться назад, ко второму листу и еще раз рассмотреть эти крупные модули, задавая себе все тот же вопрос: "с чего именно я начну писать эту штуку?" При этом крупный модуль распадется на несколько более мелких. После этого можно будет вернуться к сборке схемы на один уровень крупности. Замечу попутно, что все вновь полученные модули должны иметь свои собственные имена, как всякие вещи, вновь рожденные нашим воображением (и Адам начал работу по именованию всех тварей земных...), ибо то, чего мы не можем помыслить, не существует.


* * *

"Бутерброд всегда падает маслом вниз"

(первое следствие закона Мерфи)


Берем следующий лист, рисуем нашу схемку в центре листа и обводим все одним большим квадратиком. Система закончена. Что дальше? Как это будет, когда вы допишете все? Начнется большое тестирование? Что ж, пусть так... Представим, как это будет. Вот пришли пользователи (рисуем их рядом с нашим квадратиком, рисуем линии взаимодействия пользователей с нашими модулями внутри квадратика)... И вместо того, чтобы ввести свои данные, зацепили кнопку питания... Вот наладчики потащили шнур к серверу (наладчиков на схему!) и воткнули его не в тот компьютер...


В общем, представляем мир в стиле Кэрроловской "Алисы". Квадратик вашей программы - единственный элемент стабильности и логичности в этом мире. Возможно, она не во всех случаях работает, но ее действия всегда предсказуемы. Это так? Или нужно внести еще какие-нибудь исправления? Тогда опять черкаемся на схеме, помечая места исправлений. А потом делаем итоговый вариант, с вашей программой в центре листа и существенными взаимодействиями извне...


Ну вот, теперь можно писать... нет, нет, не код. Техническое задание.


* * *

"... все уже было."

Положите перед собой ваши листочки. Если вы возвращались к переразбивке модулей, то оставьте толко "основную ветвь" (тупиковую можно отложить в сторону). Кстати, листочков у вас окажется тоже 4 - 6, как и модулей... ("Части кота, - подумал кот. - Усы... лапы...")

И начинаем описывать существенные взаимодействия, следуя по листочкам в обратном порядке. Сперва - взаимодействия вашей программы с внешним миром. Здесь можно использовать куски текста из "общей постановки задачи", которая была вам дана (устно или письменно), и обязательно должны присутсвовать те ограничения, которые заставили вас внести почеркушки-"правки" на последнем этапе. Это те самые моменты внешнего мира, про которые забыли и начальство и заказчики. И одновременно - основная тема для согласований. Дальше возвращаемся к первому-второму листочку, какие правки отмечены там? Что требовалось бы сказать вам, чтобы вы сразу выбрали чистовой вариант?

Ну вот, собственно и почти все с ТЗ, остальное - нюансы оформления, которые в каждой фирме свои.

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

20.12.2003