Структуры проблемы

Можете себе вообразить Марго Фонтейн (Margot Fonteyn) с ногами и руками в гипсе и парой кандалов на лодыжках? Очень не грациозно.

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

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

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

Это не преступление -- быть умелым и квалифицированным.

Разбор полетов

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

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

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

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

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

На самом деле, источники проблем можно классифицировать с точки зрения вовлеченности в процесс как:

Несвязанные

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

Операционные

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

Эргономические

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

Процедурные

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

Уменьшение сложности и последовательное ужимание

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

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

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

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

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

Бесконечная деградация "программных архитектур"

Была команда, которую заказчик попросил создать среду реального времени, которая могла бы поддерживать небольшие процессы, стыкуемые через средства ввода/вывода, что-то типа графической оболочки для управления сложной системой трубопроводов. Если классифицировать эту задачу, это работа по системному программированию. Эта команда решила быть Профессиональной, и стала использовать Надлежащие Методы. Поэтому они пошли и сделали объектно-ориентированную модель этих вещей из Требований Пользователя используя инструменты, автоматизирующие подход Шлера-Меллора (Shlear-Mellor). Но была небольшая трудность, поскольку проблема была из другой области, зато они подогнали ее под Надлежащую Методологию. Они ведь могли использовать генератор кода! Они нажали кнопку и получили целую кучу склеенных классов. Каждый из них просто вызывал процедуру из API из "Программной Архитектуры", слоя, который требовался в подходе, что позволяло приложению работать на определенном типе компьютерной системы. В этом случае Программная Архитектура стала бы системным средством предоставления графического интерфейса для оболочки, работающей со сложной системой трубопроводов!

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

По мере того, как все становилось все более абсурдным, росло напряжение и команда все настойчивее обороняла свой Профессионализм. Один раз на встрече некто, ожидая хотя бы немного прагматизма, представился как "программист компьютеров" (computer programmer). Результат был замечательный. Вся команда глядя в пол бубнила под нос "Программный Инженер... Компьютерный Ученый..." (Software Engineer... Computer Scientist...), как будто тот совершил значительную социальную ошибку. Два члена команды позднее объясняли, что они не нашли создание "просто кода" интересным, и их Профессиональный Интерес заключался в Применении Процесса.

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

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

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

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

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