Проектирование через тестирование и запутанные верёвки

Андрей Шариро

Андрей Шапиро, арт-директор и партнер в Byndyusoft, рассказал о методе test-driven design, который помогает шаг за шагом выстроить процесс проектирования, подружить между собой все требования и не упустить важные детали. 

В поисках алгоритма для проектирования

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

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

Суть всех вышеперечисленных подходов в том, что у нас есть одно или несколько условий, которые должны быть удовлетворены, чтобы мы остановились в своих поисках. В случае с распутыванием всё просто — нам надо освободить все веревки, а в случае с лабиринтом — освободить человека, то есть сделать так, чтобы его больше не ограничивали стены. 

Лучшая метафора неопределенности — лабиринт. Работа с неопределенностью как поиск выхода из лабиринта. Есть здесь и цикличность (итерации)
Лучшая метафора неопределенности — лабиринт. Работа с неопределенностью как поиск выхода из лабиринта. Есть здесь и цикличность (итерации). Фотография — Universal Eye

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

В проектировании аналогом «распутывания веревок» является метод TDD (test-driven design/development). Его и мы и рассмотрим в статье, а еще поговорим о двух полезных «аддонах» к нему — приеме «Штука» и инвентаризации агрегатов.

Мы пишем о менеджменте продуктов и развитии в телеграм-каналах make sense и Продуктовое мышление.

Приём «Штука»

Артём Горбунов как-то поделился приёмом «Штука». Во время работы в Студии Лебедева он наблюдал за Ромой Воронежским, а тот в процессе создания дизайна любил приговаривать: «нам нужна такая штука». Артём интуитивно вынес из этого свой приём. По его словам, ему было важно само ощущение, что «штука» эта волшебная — то есть она сказочным образом решает все проблемы и при этом может принять любую форму. Это похоже на оператор «идеального конечного результата» в ТРИЗ и даёт свободу гиперболизировать любые необходимые функции в пределах нашего воображения.

Но мне здесь важно другое. На ранних этапах «Штука» — это абстрактная сущность, которой пока нет. Её ещё предстоит создать. Мы не знаем, как она называется, как будет выглядеть и из чего будет состоять — зато можем точно сформулировать, зачем она нужна и что именно должна делать. Держа это в голове как набор целевых установок, мы добавляем что-то в решение или убираем лишнее — и так постепенно приближаемся к окончанию поиска. Этот метод похож на выращивание объекта, решающего задачу.

В общем случае любая «интерфейсная штука» делает всего две вещи:

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

Применим приём «Штука» для создания интерфейса настройки оплаты по двум моделям: подписочная модель и немедленная разовая оплата. Для начала нужно сформулировать, что эта «штука» для оплаты должна показывать и какие действия она позволит совершать. У меня вышел такой список:

  1. Какие тарифы есть вообще?
  2. Какой тариф выбран сейчас, как его сменить?
  3. Какой способ оплаты выбран: разовая оплата или оплата по подписке?
  4. Текущее состояние: оплачен ли последний месяц, когда будет следующее автоматическое списание, если включена подписка.
  5. Как внести немедленную оплату?
  6. Как отписаться от продукта?

Сформулировав этот набор, мы можем приняться за «выращивание». Для примера возьмем последнее, шестое требование из списка. Скомпонуем первый вариант формы. Я буду делать это в текстовом формате (я писал о такой технике проектирования UI в англоязычной статье).

Прием проектирования «Штука» — первая итерация

Что здесь произошло. Я ввёл сущность «Подписка», описал её состояние и прикрепил к ней манипулятор — кнопка «Отписаться». При этом пришлось выйти за рамки шестого требования и удовлетворить четвертому — описать последнюю операцию и рассказать, какой режим оплаты выбран. Я решил, что вся история платежей будет полезна — но разместить её лучше на отдельной странице (сейчас туда ведёт ссылка «История платежей»).

Попробуем добавить сюда пятый пункт требований — «какой тариф выбран сейчас и как его сменить». Для начала просто помещаем информацию о тарифе и о том, как его сменить, в текстовый макет.

Прием проектирования «Штука» — вторая итерация

Форма обогатилась, но теперь не нравится, что она стала слишком сложной: кнопка смены тарифа затесалась в длинную «колбасу» с заголовком. Кроме того, перед глазами нет структуры тарифов, а многоточие на кнопке «Сменить» говорит о том, что надо проектировать какое-то другое место — всплывающее окно или экран — в котором будет происходить смена тарифа. Слишком сложно. Поэтому я попробую пересобрать макет.

Прием проектирования «Штука» — третья итерация

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

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

Это и есть итеративный процесс в действии. Далее предстоит проделать то же самое с остальными пунктами списка требований. Причем новые блоки наверняка придётся пересматривать и менять, какие-то — объединять, чтобы избавиться от дублирования, а некоторые наоборот — дробить, чтобы выполнялись новые требования.

TDD или test-driven design/development

Подход «сначала тесты», когда тестирование идёт не в конце, а до написания программы, был впервые предложен в концепции экстремального программирования в конце девяностых. Суть его в том, что мы сначала пишем приёмочный тест — например, что сложение двух конкретных чисел 2 и 3 даёт на выходе 5, и только после этого — код, реализующий этот алгоритм. На следующей итерации добавляем новый тест, например, для −2 и 3, чтобы наш метод умел работать с отрицательными числами, и модифицируем код так, чтобы он удовлетворял обоим тестам. И так далее. Добавление каких-то тестов сделает код нерабочим и это штатная ситуация — значит, пришло время модифицировать программу.

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

Разберём на примере. Допустим, мы проектируем механизм, который позволит сотрудникам отдела обрабатывать стопку задач. Мы знаем, что человечество уже изобрело очередь — и даже её электронную версию — но пока мы не знаем в деталях, как она должна быть организована в нашем случае. Именно это «не знаем в деталях» и должно быть спроектировано.

Метод TDD

Ниже я записываю критерии готовности для будущего дизайна. Обратите внимание на их формулировки: на каждый вопрос можно быстро дать бинарный ответ — удовлетворили мы текущим решением конкретному критерию или нет.

Список критериев готовности механизма распределения задач по сотрудникам:

  • Весь объём работ распределен между сотрудниками на смене. Задачи не назначаются тем, кто сейчас не работает с системой.
  • Обеспечена одновременная работа с очередью старых и новых входящих заявок. Работа с очередью не блокирует другую работу с таблицей документов.
  • Виден объём отдельных очередей по типам задач и общей очереди.
  • Определён непротиворечивый принцип приоритезации задач.
  • Приоритетные задачи берутся раньше менее приоритетных.
  • Задача изымается из очереди, если по ней проведены ключевые изменения.
  • Отложенные задачи возвращаются прежнему исполнителю через некоторое время.
  • У сотрудника есть возможность вернуться к отложенным им задачам.
  • Есть отказ от задачи из-за отсутствия компетенций.
  • Есть способ перейти ко всем задачам одного контрагента.
  • Очередь прощает ошибки при ложном сообщении сотрудника о готовности по заявке.

Теперь можно начать циклично «выращивать» конструкцию интерфейса по аналогии с тем, как мы выше действовали в приёме «штука».

Микрокурс «Создание и тестирование прототипов. MVP» — Владимир Баяндин, Стас Пятикоп

Инвентаризация агрегатов

Когда у нас зафиксирован набор критериев готовности или есть набор пользовательских историй, собранных методом User Story Mapping, полезным бывает предварительно провести инвентаризацию. Такой процесс помогает заранее сообразить, из чего будет состоять конструкция, верхнеуровнево осмотреть её мысленным взором.

Для инвентаризации мы просматриваем список критериев или историй и вычленяем оттуда будущие агрегаты интерфейса. Причём именно агрегаты, а не элементы. Примеры агрегатов: обработчики очереди, «шапка», «подвал», мультизагрузчик файлов, насыщенная фильтрами таблица — то есть крупные смысловые узлы конструкции интерфейса. Агрегаты всегда крупнее отдельных элементов интерфейса — таких, как поле ввода, кнопка или подпись. Размышлять на уровне агрегатов на этапе предварительного конструирования удобнее, чем на уровне элементов-атомов.

Пробежимся по списку критериев нашего механизма распределения задач и вычленим будущие агрегаты. Что нам точно понадобится:

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

Порой инвентаризация задевает не только интерфейсные агрегаты, но и внутренние механики или логику, которая в итоге спрячется под капотом системы. Всё это хорошие претенденты для размещения в тексте проектной документации.

Пример инвентаризации набора пользовательских историй. Красный текст — результат фазы инвентаризации
Пример инвентаризации набора пользовательских историй. Красный текст — результат фазы инвентаризации

Плюсы и минусы проектирования через тестирование

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

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

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

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

Плюсы

  • Легко сверить курс с другими людьми — командой, заказчиком, стейкхолдерами.
  • Не требует представления о форме решения.
  • Подходит для работы в квадрантах Complex и Complicated фреймворка Cynefin.
  • Проще флексить.
  • Проще проверять решение на полноту.

Минусы

  • Требует проверки на адекватность приёмочных критериев, но при этом не даёт для этого своих практик и инструментов — придётся применять другие.

Материалы