Глава 5. Принципы разработки

Подходы, методологии, языки

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

На одном конце этого спектра расположены продукты COTS (Commertial Off The Shelf - Коммерческие, взятые с полки). Загрузи его, запусти его, работа сделана. На другом -- набор команд процессора, который позволяет нам выжать из железа все, на что оно физически способно. Между этими крайностями располагаются различные промежуточные семантики, которые упрощают поиск взаимосвязей ограничивая семантику.

В этих терминах, язык -- это произвольный набор (ящик инструментов -- kitbag) семантик. Cи - язык, но также и Excel -- язык, как и средства создания интерфейса пользователя (GUI builders). Эти наборы лежат, но не дают никакого намека, как использовать их содержимое. Языки специализируют по проблемным областям, чтобы достигнуть большой вероятности получения более простых взаимосвязей для любой проблемы из выбранной области. Чтобы решить, какую из двух семантик (языков) выбрать, обычно нужно спросить, какая из них требует более простых взаимосвязей (более простой программы), чтобы выполнить работу. За исключением самых тривиальных случаев, это требует знакомства с обоими наборами семантик на практике.

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

Подход заключается в совете, даваемом одним опытным картостроителем другому, о том, как лучше всего решать проблему какого-то типа. Это приглашение посмотреть на мир определенным образом, даже если это выражено как процедурный рецепт. Предписание "Получи диаграмму (Data Flow Diagram) изменения начислений по неделям" в книге "Как построить систему печати платежной ведомости" (How To Build A Payroll System) на самом деле выглядит так "Ограничь рассмотрение до систем с понедельным начислением, и выведи перечень этих начислений".

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

Имеются языки, которые специализируются на определенном подходе. Smalltalk требует от пользователя рассматривать мир в виде объектов. Lisp требует применения неудобоваримых манипуляций с лямбда исчислением, которые приводят к появлению "собаки еды" (dog of food), вместо накормленной собаки.

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

Интересные методологии состоят частично из подхода, частично из языка. Структурный дизайн Джексона (Jackson Structured Design -- JSD) ограничивает свою область применения проблемами с ясно идентифицируемыми чертами (свойствами) и поэтому в состоянии предложить очень детальную инструкцию, как решать проблемы такого типа. Держите глаза открытыми, и JSD хорошо послужит в своей области. Однако за пределами этой области он может вызвать проблемы, поскольку если у задач нет нужных Джексону черт, то бесконечное латание дыр (kludging) будет делать хорошую систему из плохого понимания. Это не ошибка Джексона, поскольку он никогда не говорил, что JSD -- это ритуализованная панацея для решения всех компьютерных проблем.

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

То же самое справедливо для подходов и языков Буча (Booch), Румбаха (Rumbaugh) и UML (Unified Modelling Language). В действительности, для каждой интересной методологии. В ранних публикациях Буча и Румбаха они не пропускали диаграммы через генераторы кода, но показали, что трансляция большинства диаграмм в большой степени механична. Не переживайте слишком сильно о реализации этих методов вручную -- в целом это несложно!

Создание языка и подхода, более или менее специализированного к какой-то предметной области -- крупное достижение. Поступая таким образом, авторы должны долгое время продумывать, как лучше всего управляться с проблемами, разделять их, исследовать их, смотреть на них с разных точек зрения и в соответствии с этим разрабатывать свой подход или язык. Но многое оказывается запутанным из-за пресловутого языкового барьера картостроитель/паковщик, и приходится отказываться от акцента на творческое мышление, необходимое для построения карты между проблемой и ее языком. Вместо того, чтобы представлять свой подход как структуру и предлагать некоторые эвристики для рассмотрения проблемы в терминах этой структуры, они вынуждены использовать процедурный язык и описывать действия, которые необходимо предпринять, императивно [строгим командным голосом - С.К.]. Если кто-то не обладает даром думать творчески, то есть конструировать мысленную карту своей проблемы посредством размышления и затем исследовать ее, то им не остается выбора, кроме как следовать этим (вероятно, некорректным) указаниям, а их результаты будут существенно зависеть от везения. Джексон тут хорош. Он специфически ограничивает свою область и говорит читателю, какие свойства искать. Читатель начинает с обследования проблемы в поисках (ключевых) признаков. Буч включает интересный раздел, посвященный поиску объектов, которого, если бы только он был выполнен глубоко и широко, достаточно, чтобы сделать путь императивов ненужным, поскольку он опирается на сугубо картостроительные моменты. Наконец, то, как книга Страуструпа (Stroustrup) описывает объектный подход и язык C++ -- праздник стиля, интуиции, структуры, глубины и творчества. Это тяжелая книга, описывающая сложный язык программирования, но она написана великим картостроителем в действии, у которого нет внутренней неразберихи относительно предмета.

Как писать документы

С точки зрения многих инженеров-программистов, большая часть их жизни состоит в написании документов. С точки зрения настоящей работы, мы предпочли бы сказать, что их жизнь состоит в выполнении работы по повышению понимания, которое будет донесено до их коллег в соответствии с протоколом, определенным в их процессе. Следовательно, мы подразумеваем, что работа -- это всегда понимание, а процесс говорит, какое понимание нам нужно передать коллегам. Это определяет приемлемый для каждого документа язык. Эти соображения помогут сформировать описание реальной работы, которую требуется выполнить при работе над каждым из создаваемых инженером документов, как то: Требования Пользователя, Требования к Программному Обеспечению, Архитектурный Проект, Детальный Проект и Спецификация Тестирования (User Requirement, Software Requirement, Architectural Design, Detailed Design and Test Specification).

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

Второй момент касается формата. На любой стадии процесса программирования люди используют понимание, чтобы находить и предлагать паттерны. Если бы они знали, что они собираются найти, у них не было бы работы, поскольку их мог бы заменить настроенный кем-нибудь коммерческий (COTS) продукт. Раз мы не знаем наверняка, что работнику нужно представить, то как мы можем сказать ему, как он это должен представить? Стандартные форматы в процессах не должны восприниматься как догмы. Все приличные процессы в ISO 9001 содержат стандарты размещения необходимых разделов. Используй их соответственно, и если во время написания возникает структура документа, можно сделать вставку в План Управления Проектом, чтобы описать выбранный формат. Вот и вся суть ISO 9001.

Требования пользователя

Недавно возник большой интерес к "Реинженирингу бизнес-процессов" (`Business Process Re-Engineering' -- BPR). Это практика изучения бизнес-процессов для определения, можно ли их улучшить, и часто это необходимо сделать просто потому, что со временем изменилась природа бизнеса организации. Иногда превозносят точку зрения, что программная инженерия всегда включает значительный компонент BPR, поскольку в противном случае потребитель обнаружит, что компьютерная система автоматизирует бизнес-процесс, не учитывающий появление компонентов, которые руководство реализовало в ответ на потребности бизнеса, и систему ожидает крах. Таким образом, первая обязанность инженера-программиста -- помочь потребителю понять природу их собственных требований. В примере простейшей программы -- это кристаллизация желания из общего ощущения дискомфорта в специфическую потребность в большей освещенности. Инженер-программист руководствуется в этой работе дисциплиной, накладываемой необходимостью писать программу для компьютера. В работающем коде невозможно скрыть неоднозначности, как это можно сделать в текстовом отчете. Полезные ТП, таким образом, составляют настолько ясное понимание потребностей пользователя, насколько это возможно в начале проекта, как это понято пользователем и инженером, на языке пользователя. ТП обязательно потребуют уточнения в дальнейшем, по мере того, как дисциплина программирования выявит неоднозначности, независимо от того, будут ли эти поправки включены в документ или нет.

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

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

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

Требования к программному обеспечению

Если ТП описывают требуемую систему на языке пользователя, то ТПО описывают ее на языке инженера. Поэтому в этом документе сначала могут оказаться расчеты размера системы. Что особенно характерно для современных объектных методологий, потребность в ТПО уменьшилась, поскольку архитектура будет состоять из прикладных классов, у которых ясные взаимосвязи с языком ТП. В этой ситуации, ТПО и АП могут быть объединены.

Говорят, скульптор думает о своей законченной работе, как о заключенной внутри глыбы камня или куска дерева, и которую нужно оттуда извлечь, отсекая лишнее. Это помогает. Точно так же, мы можем представить себя глядящими глазами пользователя на наше творение в один из дней в будущем. Если мы смотрим на него используя свойства (черты) системы, мы можем спросить себя: "Как это должно быть реализовано?" Тогда очень легко получить описание потребностей пользователя на языке инженера-программиста.

Архитектурный проект

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

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

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

Детальный проект

ДП -- это записка в бутылке. Он говорит читателю о том, как автор планировал реализацию, поэтому код можно понять. Детальность изложения должна прояснить те места, которые остались за кадром в АП, и привести читателя в точку, где уже должен быть сам код. Иногда, это объяснение может быть выражено псевдокодом, но не обязательно. Следует допускать возможность исправления ДП. Во время реализации будут возникать такие детали проекта, как организация кода в модули. Если такие детали не передать с помощью ДП нашим коллегам, то как еще это сделать? Это простое упущение вызывает в дальнейшем слишком много ненужных проблем, поскольку инженеры посчитают составляющие системы хорошо документированными, только в случае, если они знали, с чего начать! Окончательный вариант ДП должен говорить последователям, что они должны знать, чтобы понять систему и изменить ее.

План тестирования

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

Ход конем ("Вилка")

Снова и снова в этой работе мы видим эхо глубокой структуры, которую мы выявили, написав простейшую программу. У нас есть проблемная область, семантика системы и карта взаимосвязей между ними, созданная программистом при рассмотрении желания. Этот паттерн -- центральное действие программирования компьютеров. В нем самом может и не содержаться понимания, но способность это делать -- единственное доказательство, что проблема на самом деле понята в терминах заданной семантики. Если семантика строгая и проверяемая, как семантика цифрового компьютера, можно заявить о "глубоком" или "истинном" понимании, но это только предположение, поскольку кто-нибудь всегда может заглянуть за горизонт и сказать: "Посмотри на это так!"

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

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

while((c = getchar()) != EOF) putchar(f(c));

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

"Ход конем" всегда использует внутреннюю (присущую ей) глубокую структуру проблемной области. Проверка того, что эта глубокая структура реальна, а не плод воображения и случайных совпадений, очень важна. Если дизайнер использует случайные совпадения, результат будет скорее "заумным", чем "элегантным", и все будет хрупким, полагающимся на специальные меры предосторожности по всему результирующему коду системы, с потерей целостности проекта. Вайнберг (Weinberg) приводит пример программиста, пишущего на ассемблере. Тот обнаружил, что мог бы делать поиск по таблице [table lookups - например, массив адресов перехода или массив указателей на функции, когда выбор осуществляется по целому индексу - С.К.] основываясь на номере кода операции и спроектировал свою программу исходя из этого. Но разработчики аппаратуры ("железа") не считали схему нумерации кодов операций священной, и когда они произвели допустимые изменения, весь дизайн программы развалился.

Персональный послойный процесс

Дзенская притча говорит о мудром монахе, пришедшем к старому учителю. Он вошел в комнату учителя и сел перед ним. "Когда ты входил, с какой стороны двери ты оставил свой посох?" - спросил учитель. Монах не знал. "В таком случае, ты потерял свой Дзен".

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

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

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

1. Идентифицировать все файлы, которые включают функции:

ModelOpen(),

ModelRead(),

ModelWrite(),

ModelClose().

2. Отключить контроль версий этих файлов.

3. Внести изменения.

3.1. Изменить modread.c

3.1.1. Исправить ModelOpen()

3.1.2 Исправить ModelRead()

3.1.3. Исправить ModelWrite()

3.1.4. Исправить ModelClose()

3.2. Изменить appfile1.c

3.3. Изменить appfile2.c

4. Обратно включить контроль версий

5. Перекомпилировать

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

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

3.1.5. Разобраться со всеми заголовочными файлами :-(

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

Нам не нужно помнить, в какое мусорное ведро мы выбросили стаканчик из-под выпитого утром кофе, чтобы иметь полное понимание, где мы находимся в нашей организованной работе. Вместо этого мы можем проникнуться духом TQM и организовать самих себя с полным осознанием того, что мы делаем. Если мы это сделаем, проявятся все обычные преимущества от обдумывания того, что мы делаем. Мы сможем увидеть возможности автоматизации скучного набора текста с помощью скриптов и макросов, а в рамках Персонального Послойного Процесса (PLP) мы всегда можем задать вопрос: "Как бы я мог отменить это действие"; это то, что отличает от людей, которые случайно стирают свой код (удалив по ошибке файл) и которым приходится два часа ждать администратора, чтобы восстановить этот файл со сделанной ночью резервной копии.

И, в качестве последнего комментария этого раздела, скажем, что в условиях профессиональной инженерной среды часто нам нужно использовать PLP для управления сложностью даже простейшей работы. Ритуализация PLP может стать гипнотической. Чтобы выдержать пропорции, всегда спрашивайте себя, не хватит ли 30 секунд, чтобы завершить эту работу, и если ее можно просто сделать, не теряйте время на выполнение ритуалов. Всегда делайте резервную копию!

Увидеть мир в строчке кода

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

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

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

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

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

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

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

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

Посвятите некоторое время просмотру дизайна используемых вами API. Взгляните на их валюту - значения, передаваемые из/в API. Как части этого интерфейса стыкуются друг с другом? Хорошо ли они спроектированы? Какие идиомы предлагают вам использовать их разработчики? API обычно проектируют опытные разработчики, и они похожи на небольшие послания от очень ярких людей о том, как они видят мир. Стиль UNIX API Кена Томпсона (Ken Thompson) прекрасно сохранился за 30 лет. Он сам говорил, что единственное изменение, которое он бы сделал: " Я бы написал creat() c e!" В UNIX API есть что-то очень близкое к тому, как работают компьютеры.

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

Концептуальная целостность

В "Мифическом человеко-месяце" Фредерик Брукс (The Mythical Man Month by Fred Brooks) подчеркивает важность концептуальной целостности проекта. Наш глубокий взгляд на программирование предполагает некоторые практические пути достижения концептуальной целостности.

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

Во-вторых, у нас есть картина того, как программист оптимизировал последовательность проектных решений для получения минимального решения и управления сложностью. Поэтому нам нужно посмотреть на виды конструкций, из которых строятся программы, и убедиться, что они общедоступны. Такое руководство по стилю проекта указывает на согласованный набор соглашений об именовании переменных, стратегий обработки ошибок, примеров идиом использования API подсистем и даже стиль комментариев. Можно сказать, что управляя формой кирпичей, архитектор может задать форму здания, оставляя в то же время гибкость в руках конструктора. Структура такого кода, таким образом, гарантирует, что код канонических примеров предсказуем и элегантен. Поэтому примеры кода в руководстве по стилю управляют структурой, а структура управляет кодом. Здесь мы видим еще одно эхо "Хода конем" -- если мы используем правильные структуры, то мы можем ввести в игру необходимый и достаточный синтаксис и написать минимум текста. И наоборот, чем более запутанные берутся приемы, тем больше их нужно, чтобы переплести их вместе.

И, наконец, последнее преимущество концептуальной целостности, ценимое профессиональными программистами -- очень практичное. Представьте, что вы в работе. Вы увидели способ распределить функциональность, вы нашли элегантные методы обхода всех тех способов, какими ОС может сигнализировать об ошибке, и уже наполовину сделали работу по кодированию, и вам понадобилось имя для новой переменной. В вашей голове застопорилось от перегрузки тривиальностью! Экспоненциальная выгода от сосредоточенности внимания и удержании этого состояния так же велика, как экспоненциальная выгода от минимизации размера кода, поэтому стоит оградить себя от всяких глупых раздражителей, отвлекающих внимание. В местах, где каждый прекращает работу через каждые десять минут для объяснений с руководством, преимущества настоящей концентрации внимания никогда не проявятся, но там, где внешние обстоятельства тщательно отсеиваются, наличие руководства по стилю позволяет часто делать подобные штучки [например, выбор имен для переменных - С.К.] на лету и может существенно увеличить эффективность работы.

Управление настроением

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

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

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

Если коллега говорит что-то, что вы не понимаете или кажется парадоксальным или нелепым, спросите себя, а что если человек пытается рассказать о части карты, которую вы видите перед собой, с совершенно другой точки зрения. Узнайте, что это значит на языке, который вас устраивает. Начните с предположения, что у него имеется кое-что интересное в голове, и попытайтесь выяснить, что это такое. Этот стиль дискуссий, о котором много думали апологеты зететики (Zetetics), вышедшие из Общества по Исследованию Паранормальных Проявлений (Society for the Investigation of Claims of the Paranormal -- SICOP), чтобы исследовать, какими могли бы быть правила доказательства существования паранормальных явлений.

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

Если в дискуссии у членов команды разные цели, то мало чего можно достичь. Никто не сможет сконструировать разумное описание технических моментов, если его прерывают люди, которые думают, что цель заключается в максимизации приемлемости для пользователя (maximising customer acceptability).

Это не означает, что все собрания без ясно определенной цели с неизбежностью вырождаются в переход на личности -- это происходит только когда произвольно выбранные цели взаимно исключают друг друга. Но даже дискуссии со многими целями могут быть прояснены, если сначала явно сформулировать, в чем эти цели состоят. И ни в коем случае внимание группы не должно удерживаться с ритуальной одержимостью паковщиков, поскольку идея заключается в прояснении дискуссии, а не в избегании ее. Как всегда, мы должны служить цели, а не микрополиции процедуры. Если член команды видит, что что-то уводит от темы (и засоряет весь вид), он должен сказать об этом. И наоборот, если он видит обстоятельство, которое нужно обсудить, но оно не настолько критично, он может записать его на клочке бумаги и заявить о нем как о теме для обсуждения на следующих собраниях.

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

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

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

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

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

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

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

Помните, что паковщики в организации не поймут описанные выше эффекты, поскольку они не признают существование такого подхода и состояния ума, с которым мы программируем. Это проблема офиса с открытой планировкой [когда все находятся в одном помещении - С.К.]!

Моделирование ситуаций

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

Книга "Справочник рейнджера Слоана" (Sloane Ranger's Handbook) включает карту мира для рейнджеров Слоана. Около 50% всей карты занято Площадью Слоана, Шотландия соединена с Лондоном узенькой дорожкой M1, а континенты отодвинуты к краям карты. Шутка заключается в том, что у всех нас собственная искаженная карта мира, но карта рейнджеров уж очень сильно искажена по сравнению с географической. Для рейнджеров Слоана это не шутка -- это правильное представление их мира, и они утверждают, что их представление не более нереальное, чем какое бы то ни было другое. (Некоторые из них купили книгу, чтобы иметь возможность проверить правильность. Она прошла проверку.)

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

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

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

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

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

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

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