Также следует отметить, что стоящий человек более интенсивно использует жестикуляцию и мимику. Если вы общаетесь с группой из 10 и более человек, вставание поможет установить зрительный контакт со всей аудиторией. Зрительный контакт, жестикуляция, мимика и другие визуальные элементы играют важную роль в общении. Кроме того, положение стоя изменяет тональность и громкость голоса, а также темп речи: вы начинаете говорить так, чтобы вас было слышно в большом помещении, делая паузы для выделения важных моментов. Все эти элементы вносят существенный вклад в эффективность общения.
Хотите повысить эффективность передачи своих идей в процессе общения более чем вдвое? Это очень просто: встаньте.
Сбои неизбежны
Оборудование подвержено сбоям, поэтому мы вводим в наши системы избыточность. Она позволяет пережить отдельные сбои оборудования, но повышает вероятность того, что в любой момент времени в системе будет присутствовать хотя бы одна неисправность.
Программный код тоже подвержен сбоям. Наши приложения строятся на основе программного кода, а значит, они тоже уязвимы. Мы реализуем средства мониторинга, сообщающие о сбоях приложения, однако в основе этих средств тоже лежит программный код, а значит, они сами подвержены сбоям. Люди тоже совершают ошибки, поэтому мы стараемся автоматизировать наши действия, диагностику и рабочие процессы. Автоматизация снижает вероятность ошибок, обусловленных нарушениями правил, но повышает вероятность ошибок, возникающих из-за отсутствия правил. Ни одна автоматизированная система не способна реагировать на такой спектр ситуаций, как человек.
Поэтому мы добавляем к средствам автоматизации механизмы мониторинга. Новое программное обеспечение, новые возможности для ошибок.
Сети строятся из оборудования, программного обеспечения и очень длинных линий связи. А значит, и сети подвержены сбоям. Даже если сеть работает нормально, ее поведение формально не прогнозируемо, потому что пространство состояний большой сети с практической точки зрения бесконечно. Отдельные компоненты могут обладать детерминированным поведением, но поведение их совокупности по сути своей хаотично.
Любой механизм безопасности, который мы применяем для устранения некоторой разновидности ошибок, вводит новые виды сбоев. Мы организуем кластеризацию, чтобы приложение автоматически переходило со сбойного сервера на рабочий, но теперь при капризах кластерной сети возникает риск «расщепления мощностей».[5]
Стоит напомнить, что авария на Тримайл-Айленд[6] произошла в основном из-за клапана сброса давления — механизма безопасности, который должен был предотвращать некоторые виды сбоев, связанных с избыточным давлением.
Стало быть, сбои в системах в любом случае неизбежны. Так что же нам делать?
Осознайте один факт: независимо ни от чего в вашей системе будут происходить различные сбои. Отрицая их неизбежность, вы утрачиваете возможность контроля и изоляции этих сбоев. Но, приняв этот факт, вы сможете спроектировать реакцию своей системы на конкретные сбои. По аналогии с тем, как конструкторы автомобилей создают зоны деформации (области, деформирующиеся в первую очередь и гасящие энергию столкновения для пассивной защиты пассажиров), вы можете спроектировать защитные режимы сбоев, которые будут изолировать повреждения и защищать остальные компоненты системы.
Если этого не сделать, вам придется иметь дело со всеми непредсказуемыми — и обычно опасными — сбоями, возникающими в ходе работы системы.
Вы ведете переговоры чаще, чем вам кажется
Все мы попадали в «бюджетектурные» переделки, когда разумные технологические решения «хоронятся» ради экономии. Разговор проходит примерно так:
«Нам действительно так необходимы X?» — спрашивает спонсор проекта.
На место X можно подставить практически всё жизненно необходимое для работы системы: лицензии на программные продукты, избыточные серверы, внешние резервные копии или источники питания. Вопрос всегда задается отеческим тоном, словно вы спускаете все карманные деньги на комиксы и жвачку, тогда как серьезным взрослым людям нужно думать о покупке новых ведер, в которых они будут таскать свою будущую прибыль.
Правильный ответ на этот вопрос звучит так: «Да. Абсолютно необходимы». Но
В конце концов, у нас техническое образование, а любая техническая дисциплина — это искусство компромисса. Понятно, что экзотика вроде источников питания никому не будет нужна, если поставить в центре обработки данных несколько беличьих колес и запустить в них практикантов. И вместо того чтобы сказать «Да, абсолютно необходимы», мы говорим что-то вроде: «Вообще-то без второго сервера можно обойтись, если вы согласны смириться с простоями из-за профилактики и при каждом сбое памяти. Хотя если мы купим память с автоматическим контролем четности, то и эту проблему можно обойти. Так что остаются только сбои операционной системы в среднем через каждые 3,9 дня, а значит, по ночам сервер придется перезагружать, но это вполне могут делать практиканты, когда устанут крутить колеса».
И все это может быть совершенно справедливо, но говорить так ни в коем случае не следует. Спонсор перестает вас слушать уже после слов «вообще-то».
Проблема в том, что вы рассматриваете происходящее с технической точки зрения, а ваш спонсор четко понимает, что он ведет переговоры. Вы занимаетесь совместным поиском решения, тогда как он проводит тактический маневр типа «выйдет/не выйдет». А в любых переговорах ни в коем случае не следует делать уступки по первому требованию. Правильный ответ на вопрос «Нам действительно так необходимы X?» звучит примерно так:
«Без второго сервера вся система будет „падать“ примерно три раза в день, особенно в периоды максимальной нагрузки и при демонстрации на собрании совета директоров. На самом деле нам нужно четыре сервера, чтобы одна независимая пара обеспечивала сохранение 100-процентной работоспособности, даже если другая пара неожиданно перестанет работать».
Конечно, вы прекрасно знаете, что третий и четвертый серверы на самом деле не нужны. Это тактический гамбит, который заставит вашего спонсора перевести разговор на другую тему. Вы повышаете ставку и показываете, что система и так работает на минимальной, рискованной конфигурации. Кроме того, если вам каким-то чудом удастся получить дополнительные серверы, вы всегда можете передать один под тестирование (чтобы среда тестирования полностью соответствовала рабочей среде), а из другого получится отличная машина для сборки.
Используйте количественные критерии
«Быстрый» не может быть требованием. Как и «обладающий хорошим временем отклика». Или, скажем, «расширяемый». Главная причина заключается в отсутствии объективных критериев выполнения таких требований. Но пользователям эти характеристики все равно нужны. Задача архитектора — позаботиться о том, чтобы система обладала необходимыми качествами, а также сбалансировать неизбежные противоречия, возникающие между ними. Без объективных критериев архитектор зависит от капризов заказчика («Нет, я не могу принять программу — она работает недостаточно быстро») и разработчиков, одержимых навязчивыми идеями («Нет, программа еще не готова — она работает недостаточно быстро»).
Обычно мы стараемся записать все подобные пожелания, как и любые другие требования. Но эта запись очень часто выглядит как набор туманных эпитетов: «гибкий», «удобный в сопровождении» и так далее. Однако все критерии такого рода (при достаточном усердии даже «удобство использования») могут измеряться в числовых величинах, для которых можно установить пороговые значения. Если этого не сделать, пользователи лишатся объективных оснований для принятия системы, разработчики потеряют полезные ориентиры, которыми они могут руководствоваться во время работы, а представление архитекторов о системе утратит четкость.
Задайте простые вопросы: сколько? в течение какого времени? как часто? как скоро? увеличивается или уменьшается? с какой скоростью? Если у вас нет ответов, значит, вы не понимаете, что нужно заказчику. Ответы должны находиться в экономической модели системы, и если их там нет, то вам предстоит основательно подумать. Если вы работаете над архитектурой системы, а заказчик не дал (или не дает) вам эти цифры, спросите себя, почему. А потом получите их. Когда в следующий раз вам кто-нибудь скажет, что система должна быть «масштабируемой», спросите его, откуда возьмутся новые пользователи и почему. Спросите, сколько их будет и когда это произойдет. Не удовлетворяйтесь ответами «много» и «скоро».
Нечеткие количественные критерии должны задаваться в виде диапазона: минимум, норма, максимум. Если задать такой интервал невозможно, значит, непонятно, какое поведение требуется от системы. В ходе работы над архитектурой можно проверять систему на соответствие этим критериям, чтобы узнать, находится ли она (все еще) в пределах допустимых отклонений. Отклонения в степени соответствия некоторым критериям, происходящие с течением времени, дают полезную обратную связь. Определение этих интервалов и проверка системы на соответствие — дело трудоемкое и дорогостоящее. Если никто не беспокоится о
«Система должна реагировать на входные данные пользователя не более чем за 1500 мс. При стандартной нагрузке (определяемой как…) среднее время отклика должно лежать в интервале от 750 до 1250 мс. Время отклика менее 500 мс не воспринимается пользователями, поэтому его падение ниже этого порога оплачиваться не будет.»
Одна строка рабочего кода стоит 500 строк спецификации
Проектирование — красивая штука. Систематическое, детальное представление пространства задачи и ее решения обнажает ошибки и выявляет возможности для совершенствования, причем иногда весьма радикальным образом. Спецификации играют в этом важную роль, поскольку они определяют шаблон для построения системы. Очень важно неспешно продумать всю архитектуру — как на макроуровне, рассматривая взаимодействие между компонентами, так и на микроуровне, вникая в поведение самих компонентов.
К сожалению, архитекторы часто увлекаются процессом проектирования, попадая под очарование архитектурных абстракций. Однако сами по себе спецификации не обладают никакой ценностью. Конечной целью программного проекта является реально работающая система. Архитектор всегда должен держать в поле зрения эту цель и помнить, что проектирование — всего лишь средство, а не конечный результат. Архитектор небоскреба, пренебрегающий законами физики ради изящества здания, обречен вскоре пожалеть об этом. Стоит упустить из вида конечную цель — рабочий код, — и у проекта начинаются серьезные неприятности.
Уважайте коллег, работающих над реализацией вашего видения системы. Прислушивайтесь к ним. Если у них возникают проблемы с вашим дизайном, вполне возможно, что они правы, а дизайн ошибочен или, по крайней мере, невнятен. В таких случаях привести дизайн в соответствие практическим требованиям — ваша непосредственная задача, и решить ее вы можете, общаясь с членами вашей команды, которые помогут вам определить, что работает, а что нет. Ни один дизайн не бывает идеальным с самого начала; любой дизайн подвержен изменениям по мере реализации.
Если вы участвуете в проекте и в качестве разработчика, научитесь ценить время, потраченное на написание кода, и не верьте тем, кто говорит, что это лишь отнимает время от работы по созданию архитектуры. Вы обретете гораздо более точное видение проекта на макро- и микроуровнях, после того как сами попробуете вдохнуть жизнь в свое творение.
Решений на все случаи жизни не существует
Архитектор должен непрерывно развивать и совершенствовать свое «контекстное чутье», поскольку единственного универсального решения для широкого круга разнородных проблем не существует.
Броское выражение «контекстное чутье» впервые использовал (с содержательным описанием его смысла) Эберхардт Рехтин (Eberhardt Rechtin) в своей книге «Systems Architecting: Creating & Building Complex Systems» (Системная архитектура: создание и построение сложных систем) (Prentice Hall, 1991):
«Чтобы узнать основные принципы „эвристического подхода“ к проектированию сложных систем, спросите опытного архитектора, что он делает, когда сталкивается с особенно сложной задачей. Его ответ, скорее всего, будет таким: „Просто использую здравый смысл“. <…> Вместо термина „здравый смысл“ лучше было бы использовать выражение „контекстное чутье“[7] — знание о том, что является разумным в данном контексте. Образование, полученный опыт и изучение примеров позволяют архитектору-практику набрать значительную мощь контекстного чутья к тому моменту, когда ему доверяется решение проблемы системного уровня, — обычно на это уходит
Одна из серьезных проблем в индустрии разработки ПО, как мне кажется, состоит в том, что решение задач часто поручается людям, не успевшим развить достаточное контекстное чутье. Возможно, это связано с тем, что отрасль насчитывает всего два поколения и сейчас переживает стадию взрывного роста; не исключено, что исчезновение этой проблемы можно будет считать признаком зрелости отрасли.
Я часто сталкиваюсь с проявлениями этой проблемы в своей работе консультанта. Вот характерные примеры: отказ от проектирования на основе предметной области (domain-driven design)[8] там, где оно было бы уместным; утрата прагматического взгляда на вещи и чрезмерное увлечение проектированием программного решения, когда речь идет о задаче, не терпящей отлагательств; необоснованные или не имеющие отношения к делу предложения в тот момент, когда работы по оптимизации быстродействия системы заходят в тупик.
Самое важное, что необходимо знать о программных шаблонах, — то, когда их следует и когда не следует применять. То же самое верно в отношении гипотез о глубинных причинах проблемы и соответствующих корректирующих действий. В обеих ситуациях — при создании архитектуры системы и при анализе проблемы — универсального решения «на все случаи жизни» не существует по определению; архитектор должен развивать и тренировать свое контекстное чутье, формулируя архитектурные решения, а также выявляя и устраняя их недостатки.
Думать о производительности никогда не рано
Потребности пользователей бизнес-приложений проявляются прежде всего в функциональных требованиях. Нефункциональные аспекты системы (такие как производительность, гибкость, время безотказной работы, потребности службы поддержки и т. д.) находятся в ведении архитектора. При этом предварительное тестирование нефункциональных требований зачастую откладывается до очень поздней стадии цикла разработки, а иногда полностью делегируется команде, обслуживающей систему.
Эта ошибка встречается намного чаще, чем следовало бы. В ее основе могут лежать различные причины. Забота о быстроте и гибкости программы, которая еще толком не выполняет требуемую функцию, может показаться лишенной смысла. Тестовые среды и сами тесты достаточно сложны. Возможно, ранние рабочие версии системы не подвергнутся реалистичной нагрузке в силу недостаточно интенсивного использования.
Однако, выпуская производительность из поля зрения до поздних стадий жизненного цикла проекта, вы теряете огромное количество информации о том, когда произошли изменения в производительности. Если производительность входит в число важных критериев, по которым будут оцениваться архитектура и дизайн системы, то тестирование производительности необходимо начать как можно раньше. Если вы используете методологию гибкой разработки с двухнедельными итерациями, то тестирование производительности, на мой взгляд, следует включить в процесс не позднее третьей итерации.
Почему это так важно? Прежде всего, вы как минимум будете знать о том, какие именно изменения привели к резкому падению производительности. Если в системе возникнут проблемы с производительностью, вам не придется анализировать всю архитектуру целиком — достаточно будет сосредоточиться на тех моментах, которые менялись недавно. Рано приступив к тестированию производительности и часто его выполняя, вы сузите круг изменений, которые следует подвергать анализу.
Даже если в ходе раннего тестирования вы не будете пытаться диагностировать производительность, вы по крайней мере получите набор базовых показателей, от которых сможете отталкиваться в дальнейшей работе. Впоследствии эта информация сыграет очень важную роль при поиске источника проблем с производительностью и их устранении.
Этот подход позволяет также проверять решения, принятые в ходе проектирования и работы над архитектурой системы, в контексте реальных требований к производительности. Если к системе предъявляются жесткие требования, такая ранняя проверка особенно важна для своевременной поставки готовой системы.
Хорошо известно, что организовать техническое тестирование — непростая задача. Настройка окружения, генерация наборов данных, определение необходимых тестовых сценариев (test case) — все это занимает много времени. Раннее тестирование производительности способствует поэтапному формированию тестовой среды, избавляя вас от существенно больших затрат времени и усилий при обнаружении проблем с производительностью на более поздней стадии.
Создание архитектуры как искусство баланса
Соотнесите интересы сторон с техническими требованиями
Когда речь заходит о разработке архитектуры программного обеспечения, в первую очередь мы представляем себе классические технические операции: разбиение системы на модули, определение интерфейсов, распределение ответственности, применение шаблонов и оптимизация производительности. Кроме этого архитектор должен учитывать ряд других аспектов, в том числе вопросы безопасности, удобства использования, простоты сопровождения, управления выпуском, выбора параметров развертывания и т. д. Но все перечисленные технические и процедурные аспекты должны быть соотнесены с потребностями заинтересованных сторон. Принять во внимание эти интересы при анализе требований — отличный способ обеспечить полноту спецификаций требований для разрабатываемого продукта.
У всех вовлеченных в проект сторон есть интересы, затрагивающие как процесс разработки программного обеспечения, принятый в организации, так и организацию в целом. Именно анализ этих интересов формирует итоговый набор приоритетов для архитектора. Можно сказать, что создание архитектуры — это процесс балансировки приоритетов в краткосрочной и долгосрочной перспективах в рамках имеющегося контекста.
Для примера возьмем инженерно-технический отдел организации, предоставляющей услуги по разработке программного обеспечения. Скорее всего, у этой организации существуют определенные приоритеты: соблюдение контрактных обязательств, получение дохода, поддержание хорошей репутации среди клиентов, снижение затрат и создание ценных технических активов. Эти бизнес-приоритеты преобразуются в приоритеты отдела: обеспечить функциональность, корректность и «атрибуты качества» разрабатываемого продукта, а также продуктивность команды разработки, устойчивость процесса разработки, возможность его аудита, адаптируемость и долговечность программных продуктов.
Работа архитектора состоит не в том, чтобы просто создать функциональный, качественный программный продукт для пользователей, а в том, чтобы сделать это с соблюдением баланса интересов других сторон — руководства компании (сокращение затрат), персонала, обслуживающего продукт (простота администрирования), будущих членов команды программистов (простота изучения и сопровождения), а также с учетом опыта, накопленного профессиональным сообществом архитекторов.
Архитектор может на короткое время сознательно сместить баланс в пользу одного из приоритетов, но в долгосрочной перспективе, чтобы работа была выполнена действительно хорошо, следует избегать каких-либо перекосов. При этом поддерживаемый баланс должен отвечать имеющемуся контексту с учетом таких факторов, как предполагаемая продолжительность жизненного цикла программного продукта, критичность продукта для организации, техническая и финансовая культура компании.
Говоря коротко, создание архитектуры программного продукта не ограничивается одними лишь техническими аспектами; в процессе работы необходимо также найти правильное соотношение технических требований и бизнес-требований всех заинтересованных сторон.
Сделать наспех и сбежать — преступление
Время близится к вечеру. Команда дружно корпит над новой функциональностью, запланированной для текущей итерации; кажется, даже воздух в комнате пульсирует в рабочем ритме. Однако Джон немного спешит: его ждет свидание. Впрочем, он успевает дописать свою часть кода, компилирует ее, регистрирует в системе управления исходным кодом — и поспешно уходит. Несколько минут спустя загорается «красный свет»: сборка приложения нарушена. У Джона не было времени на автоматизированные тесты, поэтому он поступил по принципу «сделать наспех и сбежать», из-за чего застопорилась работа всей команды.
Ситуация изменилась — рабочий ритм сбился. Теперь все знают, что при обновлении кода из системы контроля версий неработоспособный код окажется и на их локальных компьютерах, а поскольку для подготовки к предстоящей демонстрации команде предстоит интегрировать много кода, это становится серьезным препятствием. По сути дела, Джон поставил команде подножку — ведь интеграция станет возможна только после того, как кто-то потратит свое время на отмену его изменений.
Такая ситуация возникает до обидного часто. Сделать наспех и сбежать — преступление, поскольку в результате нарушается нормальный ход работы. Это печально распространенный среди разработчиков способ сэкономить немного времени лично для себя, в итоге потратив впустую чужое время, что служит проявлением прямого неуважения к другим людям. И все же это происходит повсеместно. Почему? Обычно потому, что полноценная сборка системы или проведение тестов занимает слишком много времени.
Здесь в игру вступаете вы — архитектор. Вы тратите массу усилий на создание гибкой архитектуры, обучаете разработчиков гибким методам разработки (таким как разработка через тестирование) и обеспечиваете наличие сервера для непрерывной интеграции. Кроме того, вам необходимо сформировать культуру, правила которой запрещают понапрасну расходовать чужое рабочее время. Для этого помимо прочего нужно позаботиться о создании качественной инфраструктуры автоматизированного тестирования, поскольку она способна изменить поведение разработчиков. Если тесты выполняются быстро, разработчики будут проводить их чаще, что уже само по себе хорошо, но кроме этого они не будут оставлять своим коллегам нерабочий код. Если тесты зависят от внешних систем или для их выполнения необходимы обращения к базе данных, измените их так, чтобы они могли выполняться локально с заглушками (или хотя бы с базой данных, хранящейся в памяти), и пусть на сборочном сервере эти тесты выполняются медленно. Не заставляйте людей дожидаться, пока компьютер выполнит свою работу, иначе они начинают искать лазейки, которые в результате создают проблемы для всех остальных.
Не жалейте времени на то, чтобы обеспечить быструю работу с системой. Это повышает эффективность труда, устраняет поводы для уклонения сотрудников от работы и в конечном итоге способствует ускорению процесса разработки. Создавайте суррогаты и симуляторы, устраняйте зависимости, делите систему на меньшие модули — делайте что угодно, чтобы у ваших коллег не было даже тени искушения последовать принципу «сделать наспех и сбежать».
Решений может быть несколько
Одна модель данных, один формат сообщений, один транспортный механизм (и вообще ровно один основной архитектурный компонент, политика, принцип и т. п.) не может одинаково хорошо обслуживать все аспекты деятельности коммерческой организации. Похоже, этот факт является бесконечным источником удивления и огорчения для создателей систем. В то же время это совершенно естественно: раз уж организация (слово «организация» здесь подчеркнуто жирной красной линией) достаточно велика, чтобы волноваться о том, как несколько различных таблиц счетов повлияют на систему в следующем десятилетии, она наверняка слишком велика и неоднородна, чтобы можно было обойтись одной таблицей счетов.
В технической области единообразие можно ввести принудительно. И для нас это весьма удобно. Однако в сфере бизнеса в игру врывается противоречивый, многогранный, неформальный, хлопотный реальный мир. Что еще хуже, бизнесу приходится иметь дело даже не с реальным миром, а с мнениями людей о тех или иных аспектах ситуаций в тех или иных частях этого мира. Можно, конечно, попытаться отнестись к этой сфере как к технической и внедрить единое решение в приказном порядке. Однако реальность неформально определяется как «то, что не исчезает, когда в него перестаешь верить» (Филип К. Дик), и по мере развития бизнеса проблемы всегда возвращаются. Так возникают команды, занимающиеся корпоративными данными и тому подобным, которые тратят все свое (очень дорогое) время на обуздание экзистенциального ужаса посредством жонглирования DTD.[9]
Время отклика подобных систем обычно оказывается неудовлетворительным с точки зрения заказчика.
Почему бы не принять реальность непоследовательного мира и не допустить существование нескольких несогласованных, перекрывающихся представлений, служб, решений? Да, технический специалист в каждом из нас, услышав такое предложение, съеживается от ужаса. Мы сразу представляем себе кошмарные сценарии: несогласованные обновления, лишние затраты на сопровождение, клубки зависимостей, которыми приходится управлять… Но давайте позаимствуем полезный опыт из мира хранения данных. Витрины данных (data marts) часто денормализуются (в реляционном смысле), в них произвольно смешиваются импортированные и вычисленные значения, а представления данных сильно отличаются от представлений данных в исходных базах данных. И при этом от наличия у витрины данных нефункциональных свойств никакой катастрофы не происходит. На границе двух совершенно разных миров — как правило, операций с данными и аналитической обработки с характерными для них различиями в частоте обновления и выборки, в пропускной способности, в периодичности изменений структуры и, возможно, даже в объемах — находится ETL-процесс.[10] В этом ключ к задаче: достаточно сильные различия в нефункциональных свойствах системы формируют границу, через которую удается организовать практическое управление несогласованными представлениями.
Конечно, не стоит дублировать представления или создавать альтернативные транспортные механизмы просто ради развлечения. Но вы всегда должны иметь в виду то, что декомпозиция системы по нефункциональным параметрам способна открыть благоприятные возможности для создания разнородных решений в интересах ваших клиентов.
Всем заправляет бизнес
В контексте разработки корпоративных программных приложений архитектор должен стать в компании своего рода «мостом» между деловым и техническим сообществами, представляя и защищая интересы обеих сторон и часто выступая в роли посредника между ними, но при этом позволяя бизнесу заправлять делами. Принимая решения в области технологий, архитектор должен руководствоваться бизнес-целями компании и окружающими ее реалиями.