Как стать автором
Обновить

Проработка нефункциональных требований? Нет, проработка аспектов обеспечения качества

Уровень сложностиСредний
Время на прочтение22 мин
Количество просмотров5.9K

Аннотация

“Надежность/доступность системы должна быть 99.5%”. В этой формулировке есть проблемы:

  1. А почему 99.5%, а не 99.6% ? Почему именно 99.5%?

  2. Вся система должна быть одинаково надежная? Точно?

  3. Как проверять будем? Особенно на стадии дизайна или тестирования?

  4. И самое главное - если никто не продумал “Как будет это обеспечено”, тогда почему мы считаете, что это будет обеспечено?

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

  1. Надежность/доступность (availability),

  2. Время отклика, 

  3. Производительность.

Автор статьи не претендует на полноту предлагаемых тактик/полноту моделей ИТ системы. 

Автор не претендует на изобретение методики, по существу, это сочетание материалов работ А. Левенчука, книги “Архитектура программного обеспечения на практике” Л.Басс, П.Клементс, Р.Кацман и статьи автора https://habr.com/ru/articles/706956/.

Статья сделана на опыте разработки ИТ систем для ритейла. 

К похожей методике пришли и авторы Attribute-Driven Design, но при этом некоторые шаги в данной статье расписаны более детально.

Вводная

Отсутствие логики принятия решения

99.5% потому что “что” ? 

Любому бизнесу нужна: 

  1. надежность (здесь и далее имеется в виду availability) 100% 

  2. стоимость проекта = 0 руб, 

  3. время проекта = 0 секунд, 

  4. время отклика = 0 мс и т.п.

Ухудшение любого из этих параметров ведет к прямым/косвенным потерям денег. 

Обеспечить такую надежность (стоимость, время и т.п.) невозможно. Большая надежность требует больших усилий = денег.

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

Чтобы достичь баланса нужно понять:

  1. Сколько бизнес теряет в зависимости от времени отказа,

  2. Сколько денег нужно потратить на разные варианты обеспечения работоспособности.

Где-то на пересечении графиков должен быть достигнут баланс. Грубо говоря, баланс достигается на пересечении двух графиков (ось Х - минуты простоя, ось Y - потери бизнеса в деньгах).

Картинка неточная, но дает первое представление о нужном результате проектирования.

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

Ошибка универсализации

Рассмотрим сайт интернет-магазина с точки зрения разного функционала.

Бизнес-потери от отказа работы верхнего баннера такие же, как от отказа работы корзины? 

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

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

Разница между верхней и нижней точкой на картинке 7 раз (в реальности 5-20 раз). То есть ночью сайт может быть менее надежна, чем днем; баланс обеспечения может достигаться в разное время разным способом.

Измеримость/проверяемость

Как измерить и проверить выполнимость требования надежности “99.5%” на тестовых или разработческих стендах? Имитировать падения отказа по всем возможным причинам? А как тестировать надежность по причине ошибки в коде (которую не ловит компилятор)? (На самом деле методики есть, но они требуют рассмотрения системы как набора взаимодействующих частей с перечнем причин отказа - ровно то, что делается при проработке моделей обеспечения качества).

Еще хуже с формулировкой быстродействия: “Страницы сайта должны открываться за 3 секунды”. Но скорость загрузки зависит от

  1. Пропускной способности/задержке сети,

  2. Скорости исполнения сторонних js,

  3. Объема картинок и другой статики,

  4. Способа измерения (TTFB / full load при измерении в Chrome консоли значительно больше, чем если вы будете измерять секундомером), 

  5. Первого/не первого открытия страницы (что загружено в локальный кеш/базу данных), “прогрева” сервера (что попало в серверный кеш/базу данных в памяти).

Если мы попробуем сформулировать требование в виде результата проведения эксперимента “При включенном тортлинге (замедлении скорости сети) до Х, при измерении через Google консоль, скорость полной загрузки страницы с включенными внешними js составляет 20 секунд”, то бизнес не поймет это требование (а где мои 3 секунды ?). Так зачем же так делать?

Формулировка в виде “гугло-попугаев”: “Производительность должна быть 90 баллов”, “FCP должно быть 1.5 секунды” обладает следующими проблемами:

  1. Далеко не у всех лидеров интернет-торговли это 90 баллов, зачем же это требовать?

  2. Время отклика какой страницы мы меряем (да, мерять нужно не только главную страницу сайта)?  Вот пример товарной плитки с примененными какими-то фильтрами 

  3. И, как следствие, как проверять будем ? Вариантов товарной выкладки миллионы/миллиарды (посчитайте количество ваиантов применения фасетных фильтров). Делать миллион/миллиард проверок требований?

  4. Автору не известно никакой статистики, как влияет улучшение на 1 “гугло-попугай” улучшит продажи. Сколько денег имеет смысл потратить, неясно. Так как достигать баланса обеспечения качества? *

  5. Самое главное. Разработчики чаще всего, глядя на это требование, пожимают плечами и делают так как делали раньше. Требование есть, результата - нет.

P.S. По опыту автора, ни один из бизнес-заказчиков не согласился провести А/Б тестирование с замедленной версией сайта. Статьи в интернете, которые видел автор, опираются на корреляции объема продаж / скорости разных интернет-магазинов, что не доказывает наличие причинно-следственной связи. 

Требование есть, а результата - нет

Женщине пришлось делать искусственное оплодотворение. Она пришла в клинику к врачу и говорит: 

— Я бы хотела родить ребенка. Мальчика, высокого блондина, похожего на Тома Круза»

Врач расстегивая штаны : 

— «Том Круз, Том Круз... каким получится, таким и будет».

Если не создана модель того, как будет обеспечено требование, то высок риск того, что обеспечено это не будет.

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

Собственно, для достижения баланса обеспечения качества, нужны модели обеспечения этого самого качества, как это качество будет достигаться, будем фокусироваться на них.

Надежность

Чтобы проработать модели ИТ системы с точки зрения надежности, нужно представить ее в виде набора взаимодействующих частей (блоков), каждая из которых: 

  1. Обладает разными причинами отказа,

  2. Причины устраняются разными методами.

Например, для сайта интернет-магазина, это может быть такая схема:

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

Далее мы: 

  1. рассматриваем или блок или взаимодействие блоков и задаем вопрос: “Что может отказать?”,

  2. думаем “как может быть устранена причина отказа”,

  3. применяем тактики/паттерны проектирования,

  4. получаем конечное количество вариантов решения, между которыми и производим выбор,

  5. проектируем тестирование выбранного варианта.

Будем разбирать эту методику на примерах.

Пример 1. Отказ сервера СУБД

Например, рассмотрим блок “Серверный СУБД”.

Мы обнаруживаем риски отказа (их может быть и больше, за полноту не ручаюсь):

  1. Отказ/критический сбой оборудования, 

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

  3. Переполнение жесткого диска.

Далее нам нужно устранить риск отказа: предотвратить его или устранить последствия. Можно воспользоваться известными тактиками (а можно и придумать новые, пополнив каталог тактик):

  1. Мониторинга оборудования и организации процесса перенастройки позволяет предотвратить отказ,

  2. Виртуализация позволяет уменьшить вероятность отказа, а также ускорить восстановление после отказа (восстановлением из образа),

  3. Резервирование позволяет уменьшить время восстановления и вероятность отказа 

  4. И т.п.

Подитог: Различные точки отказа имеют различные причины отказа и различные конкретные тактики повышения надежности. 

Пример 1. Тактика резервирования для сервера СУБД

Например, резервирование можно обеспечить разными способами:

  1. Только бэкап, в случае отказа закупка и восстановление из бакапа,

  2. Холодный резерв, включающий бэкап и закупленный не настроенный сервер,

  3. Горячий резерв, включающий закупленный сервер, поддерживающий копию СУБД с небольшим отставанием,

  4. Мастер-мастер конфигурация в разных ЦОД, предполагающая минимум два сервера, одновременно предоставляющих информацию (возможно местами с задержкой актуальности).

Давайте сравним ущерб и расходы на обеспечение.

  1. Можно не делать ничего. Если повезет, можно что-то, когда-то восстановить.

  2. Бакапирование. Система стоит, пока система не восстановлена. Также мы теряем данные, введенные/измененные с момента последнего бакапа. Мы сталкиваемся с необходимостью найти еще один баланс, так как:

    1. Во время бакапа система заблокирована на запись (обычно) - для клиента это частичный отказ системы,

    2. При отказе мы теряем данных с момента последнего бакапа.

  3. Холодный резерв. Система стоит, пока мы устанавливаем систему и развертываем данные из бакапа. Сколько идет развертывание данных из бакапа ? Зависит от объема данных.

    1. У нас появился новый вопрос для исследования: Оценка объема данных. Чтобы ответить на него, нужно: 

      1. выделить в физической модели данных наиболее объемные таблицы (вопрос к надсистеме - как много экземпляров сущностей), 

      2. для строковых/байтовых полей оценить среднюю длину (вопрос к надсистеме, например, среднее количество букв в имени клиента), 

      3. понять какие будут индексы (вопрос к использующей системе - программному коду), 

      4. и по таблицам определения места оценить объем.

    2. Расходы - доп. сервер, но он может использоваться как резерв любой вашей системы.

  4. Горячий резерв. Система стоит, пока происходит докатка логов изменений на slave и переключение на эту базу.  

    1. Расходы - доп серверу на систему, настройка сервера и СУБД.

  5. Master-master в двух ЦОД с выбранным вариантов подтвержденной записи только в одну ноду.

    1. Расходы - доп серверу на систему, настройка сервера и СУБД, дополнительная аренда на ЦОД, разработка механизмов синхронизации нод и устранения противоречий данных.

Итого, получится подобная матрица (только с цифрами):

Выбираем между вариантами вместе с бизнесом (достигая баланса обеспечения качества в конкретном случае). Опыт показывает, что говорить с бизнесом проще именно про эти варианты, нежели про выбор “99.5% или 99.9%”. Варианты конкретны и понятны вам и бизнесу. 

Для выбранного варианта проектируем тестирование на тестовом окружении, например:

  1. Холодное резервирование можно проверить путем испытания - установки и развертывания системы из бакапа,

  2. Горячее резервирование путем: 

    1. Проверки “а идут ли изменения”, производим какое-то изменение данных на master ноде, через некоторое время проверяем эти данные на slave,

    2. Отключения master сервера, докатки логов изменений и включения его как основного.

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

Пример 2. Тактика архивирования

Рассмотрим тот же блок “Серверный СУБД”.

Защитится от переполнения жесткого диска для СУБД можно путем реализации функционала архивирования, при котором старые данные, не нужные для оперативной работы, “отсаживаются” в другое место или удаляются. 

Есть разные способы реализации

  1. Партицирование, при котором партиция “архив” хранится на более дешевых, но медленных дисках,

  2. Перемещение в архивную СУБД,

  3. Удаление.

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

  1. Какие документы востребованы в оперативной работе,

  2. Что делать с вычислимыми атрибутами, сущностями при удалении документов (например, с остатками на складе), как будет достигаться целостность  (например, появится операция установки входящих остатков на период),

  3. Какие справочные данные архивировать и как (будут ли востребованы в будущем?).

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

Для ответа на эти вопросы нужно разбираться в бизнес-целях и задачах использования данных - это делает роль ИТ-аналитика.

Подитог: При применении тактики могут появится задачи проектирования для ИТ-аналитика.

Пример 3. Автономность

Допустим, мы развиваем мобильное приложение. Одна из точек отказа - внешний интернет (надежность которого мы не можем обеспечить), что ведет к невозможности обслуживания клиента, снижая прибыль/LTV компании.

Одна из тактик - обеспечение автономной работы приложения.

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

 

Кроме того, нужно продумывать как реализовывать:

  1. Синхронизацию изменений и разрешение конфликтов изменений, если они происходят одновременно на беке и на фронте,

  2. Задумываться о необходимой для консистентной и безопасной работы актуальности данных на фронте, 

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

Так есть ли в этом смысл?

Рассмотрим разные сценарии использования мобильного приложения магазина:

  1. Сканирование штрих-кода клубной карты на кассе,

  2. Просмотр новых акций в приложении,

  3. Выбор товаров для покупки.

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

Почему важно это решить заранее? Переделка потребует переделки архитектуры, что потребует значимых трудозатрат. 

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

Пример 4. Канареечное тестирование

Одна из тактик уменьшения влияния отказа из-за ошибочного кода - это канареечное тестирование

.

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

Представим себе задачу: “У нас была регистрация/логин по email, хотим переделать на регистрацию/логину по телефону”.

Для организации канареечного тестирования нужно ответить на вопросы

  1. Кто выбирает клиентов, на которых тестировать ? Можно принудительно каких-то клиентов “загнать” на новую версию или мы даем клиенту выбор?

  2. Мы даем клиенту возможность отката на прошлую версию ? Да/Нет?

Эти вопросы следует проработать, достигнув баланса цена/качество.

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

Разумеется проблема в том, что в старой версии телефон не обязателен и не уникален, а в новой версии email не обязателен и не уникален.

Нам нужно спроектировать:

  1. Как логинить клиентов, у которых: 

    1. номер телефона не уникален в новой версии?,

    2. номер телефона стал не уникален после того, как какой то другой клиент ввел в старой регистрации аккаунт с таким же номером (старая форма не проверяет уникальность),

    3. номер телефона отсутствует ?

    4. нужно делать отдельную форму и логику для уникализации/восстановления аккаунта?

  2. Как зарегистрировать клиента в новой форме, если

    1. Новая форма не проверяет уникальность/обязательности email. Как сделать логин клиентов на старой версии, если их email стал не уникален ?

      1. Особенно с учетом того, что старую версию мы не трогаем (мы же проверяем новый код на ошибки, предполагая что не вносятся новые ошибки при изменении старой версии),

  3. Как обеспечить откат клиентов, если в новой форме не проверяется уникальность/обязательность email для клиентов ?  Эти клиенты и клиенты с такими-же email могут быть потеряны для бизнеса?

    1. Нужно делать новую форму для возможности отката ?

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

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

Подитог

Проработать надежность можно таким способом:

  1. Узнать какая будет проблема, если система не работает час/день/неделю, если проблема значима (выше 100 к.руб, грубо говоря), то нужно проектировать как обеспечить надежность.

  2. Представить систему в виде модели взаимосвязанных блоков - точек отказа.

  3. По блокам или их взаимодействиям выявляем причины отказа, 

  4. К причинам применяем тактики повышения надежности, создаем варианты решений. 

  5. Проработка варианта решения может создать новые задачи на анализ и проектирование (в примерах - объем хранимых данных или вариант проведения канареечного тестирования).

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

  7. Имея проработанные варианты, вместе с бизнесом можно принять взвешенное решение в пользу одного из вариантов.

Время отклика 

Не путаем скорость (время отклика) и производительность

Рассмотрим пример: сохранение данных по клиентам в СУБД при интеграции:

  1. Можно сохранять по одному клиенту (в один поток). 

    1. Время на сохранение одного клиента - 0.02 сек.

    2. Производительность 50 клиентов/сек.

  2. Можно сохранять пачкой по 1000 клиентов.

    1. Время на сохранение пачки - 1 сек

    2. Производительность 1000 клиентов/сек.

Первый вариант сохраняет клиентов быстрее в 50 раз второго, но в 20 раз менее производительно.

Преобразование модели системы

Время отклика - это время проведения какой-то последовательности операций.

Для этого нам нужно преобразовать модель операций

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

После этого к каждому блоку или к модели их взаимодействия мы можем применить тактики ускорения 

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

Разберем тактики, требующие дополнительного проектирования ИТ аналитиком, на примерах.

Пример 5. Предварительное выполнение

Допустим, мы спроектировали ответ на запрос “Открыть корзину на сайте интернет-магазина”, как последовательное выполнение операций:

Преобразовав эту модель, под аспект быстродействия, мы получим такую модель

Можно применить тактику предварительного выполнения к блоку “Получить корзину из БД”. Давайте заранее получим корзину из БД и сложим ее в RAM (“кеширование”).

Но просто “кеширование” - не ответ. Нужно понять насколько это тактика ускоряет обработку, а это упирается в баланс количества случаев “угадывания” и расходов на объем RAM

Сколько нужно выделить RAM ? Чем больше выделим RAM тем больше клиентов увидят свою корзину быстрее, но тем больше нужно потратить денег (это очередной баланс обеспечения качества). 

Как принимать решение? Есть два варианта:

  1. Предусмотреть возможность кэширования и далее управлять объемом кэша, получая данные о “попадании в кэш” на боевой базе. Минус варианта - серверные возможности расширения RAM не безграничны. Нужно ли сразу делать более дорогостоящее шардирование, сколько нод понадобится - неясно. 

  2. Спрогнозировать заранее сколько клиентов, сколько имея не пустую корзину, заходит в нее через какое время и заранее спроектировать модель решения.

Прогнозировать можно простым грубым способом - перенести статистику, посмотреть процентили: 

  1. 80% клиентов, имеющие корзину, открывают ее через 15 дней,

  2. 90% клиентов, имеющие корзину, открывают ее через 45 дней,

  3. 95% клиентов, имеющие корзину, открывают ее через 90 дней.

Зная количество дней хранения и статистику посещений, можно вычислить объем RAM на хранение. Мы получим с одной стороны процент “ускоренных” клиентов, с другой стороны стоимость. По этой таблице можно принять какое-то решение, даже если нет данных о потерях бизнеса от “более медленной” открытия корзины. 

А нельзя ли и остальные расчеты предвычислить?

Почему бы не рассчитывать по хранимым корзинам промоакции и сроки доставки раньше, чем это понадобится клиенту ?

Если мы будем так делать, то мы увеличим нагрузку на сервер (увеличивается объем вычислений), так как будут расчеты “впустую” для клиентов, которые не откроют корзину.

С другой стороны, мы уменьшаем время отклика. 

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

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

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

  1. Клиент кладет товар в корзину (без перехода в корзину),

  2. Клиент с корзиной попадает на высококонверсионную страницу,

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

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

Пример 6. Минимизация лишних вычислений

Тактика предполагает нахождение случаев лишних вычислений и перепостроение алгоритма для отказа от них для суммарного ускорения.

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

Например, нужен ли новый расчет срока доставки? Далеко не всегда. Если 

  1. объемный вес корзины менее 30 кг (граничное условие основного тарифа нашей курьерской компании, которое мы можем, к примеру, упрощенно заменить на 30 штук товара в корзин), 

  2. город доставки не изменяется, 

  3. текущее время не перешло за cutoff доставки (отсечка, до которой склад производит сборку для текущего временного периода),

то время доставки не изменится относительно прошлого расчета.

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

Плюсы решения - мы повышаем скорость работы в случае добавления второго и следующего товара в корзину в большинстве случаев и изменения количества/удаления в корзине.

Минусы решения - мы усложняем логику расчета, добавляем кеширование (расход памяти).

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

Подитог. Применение тактики ведет к необходимости проектировать более сложную модель реализации.

 

Пример 7. Распараллеливание

Широко применяемая на практике тактика.

В данном случае, мы потенциально можем распараллелить:

  1. Расчет промоакций по корзине.

  2. Расчет срока и стоимости доставки по корзине. Но это возможно, если стоимость доставки не зависит от суммы корзины. А возможно, что в некоторых регионах … Применение распараллеливания требует построения модели зависимости одних блоков от других. 

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

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

Пример 8. Ограничение времени выполнения

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

Если рассматривать первый отображаемый экран (который должен быть отрисован наиболее быстро), то, имея заданную пропускную способность (например 10МБ/сек) и “требование” загрузки за 3 секунды, можно посчитать, что объем первого экрана страницы не может быть более 3.5Мб (3 секунды минус 200 мс на передачу запроса и формирование html на сервере, умножить на 10 МБ/сек).

Нам нужно распределить общий объем на разные части страницы, разделенные по типу и ответственным.

Есть “мелкие” данные (например css или тело html, сторонние js), которые можно отбросить для этой модели. 

Мы принимаем решения о “крупных” данных: 

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

  2. Используемых js библиотеках, это ограничивает дизайнера в визуальных эффектах,

  3. Картинках верстки, это ограничивает дизайнера в качестве используемых картинок,

  4. Картинках на баннерах и превью видео, загружаемые контент-менеджером в админку.

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

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

Пример 9. Приоритизация

В случае если потребителю результата ценно получать этот результат по частям, имеет смысл приоритизировать этот результат.

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

Приоритезация позволит принято решения о разделении частей страницы и способе организации приоритетов загрузки разработчику.

Подитог. Требования быстродействия могут в части случаев трансформироваться при этой тактике в “неколичественные” решения о приоритетах.

Производительность

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

Например, алгоритм открытия корзины клиента

преобразуется в модель

При этом у нас открывается не одна корзина, не одна страница и есть и другие операции, которые выполняются этими серверами.

Применяя тактики, мы отталкиваемся от нагрузки на серверы, создаваемые операциями. Для увеличения производительности мы применяем тактики:

Возможны тактики, нацеленные на увеличение производительности сервера:

  1. аппаратное ускорение (масштабирование, распределение разного вида вычислений на разные сервера и другие),

  2. графики использования мощностей разными сценариями,

  3. и пр.

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

Заметим, что любые тактики имеет смысл задумываться применять, если планируется значимая нагрузка:

  1. большой объем операций, более 1-10к,

  2. большой объем данных, более 10-100к.

Пример 10. Минимизация операций.

Группа тактик, нацеленных на оптимизацию алгоритмов преобразования данных.

Допустим, мы решаем задачу передачи данных из одного сервера в другой. Если решается задача синхронизации данных и данных достаточно много (более 10-100к), то имеет смысл передавать не все данные, а только изменения этих данных.

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

Например, мы передаем клиентом из MDM по клиентам во внешнюю систему рассылок. Во внешней системе рассылок email должен быть уникальным полем (ограничение системы). Правильным решением было бы добится уникальности email в MDM, но это возможно не всегда:

  1. уникализация требует переработки сценариев регистрации и изменения данных во всех системах, а это может быть слишком долго / дорого,

  2. сама система MDM может быть неизменяема.

В этих случаях нужно определить какое-то правило уникализации. Допустим, бизнес выработал такое правило “в случае неуникальности, email принадлежит клиенту с наиболее поздней продажей”. У нас возникает алгоритм уникализации:

 

Алгоритм, обрабатывающий все данные целиком, достаточно прост:

  1. берем клиента с email,

  2. стираем email, если есть другой клиент с таким-же email с более поздней продажей.

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

(Кому интересно, может взять время решить задачу самостоятельно).

Решением может быть такой алгоритм:

Будем называть winner клиента, который сохранил email после уникализации.

Анализируем изменения клиента, разбираем какие могут быть для нас важные случаи: 

  1. Появился новый клиент с заполненным email, определяем winner для этого email,

  2. Удалился клиент или у клиента удален email, при этом этот клиент ранее был winner, определяем нового winner для этого email,

  3. Изменился email у клиента,

    1. Ищем нового winner для старого email, если ранее этот клиент был winner,

    2. Изем winner для нового email,

  4. Остальные изменения незначимы.

Анализируем изменения продаж, выделяем случаи:

  1. Появилась новая продажа, ищем нового winner для email, если клиент этой продажи имеет email и он не winner,

  2. Отменилась продажа, ищем нового winner для email, если клиент имел email и ранее был winner,

  3. В продаже изменился клиент. В этом случае ищем winner для email старого клиента и нового клиента (поскольку таких случаев мало, то можно не прорабатывать вариант является ли старый/новый клиент winner для своего email, совпадения или отсутствия email у старого/нового клиента)

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

Оцените насколько усложнился алгоритм. Стоит ли реализовывать этот более сложный алгоритм ? 

  1. Нет, если данных по клиентам менее 10-50к (обычно обработка таких данных укладывается в час, что достаточно для обновления данных, если не требуются рассылки новым клиентам сразу после регистрации) 

  2. Да, если данных по клиентам более 100-500к или требуются рассылки сразу после регистрации.  

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

Пример 11. Тактика перехода на пачки

Еще одной тактикой увеличение производительности является переход на обработку пачками. 

Для этого берем спроектированное решение и думаем, какие операции/часть операций можно выполнять пачкой. Начинать лучше с большого объёма операций.

Например, рассматривая модель алгоритма прошлого примера, можно выделить такую операцию, как поиск нового winner для случаев, когда для одного email есть ровно один клиент.

Выделить таких клиентов из всей массы можно одним SQL запросом, обработать также небольшим количеством SQL запросов (случай когда много клиентов для одного email тоже можно обработать более сложной последовательностью SQL, если принято решение о такой архитектуре реализации. Но нужно ли это делать, если таких случаев 5% ?).

Применение обработки/передачи информации пачками как правило замедляет время отклика, но увеличивает производительность.

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

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

Итого

Если обобщить, получается следующая методика проработки аспектов качества системы:

  1. Выбирается аспект проектирования (какие и в каком порядке в каком случае их брать остается открытым вопросом).

  2. Выясняется, а есть ли потенциальная проблема. Для каждого аспекта есть “пороги значений” когда нужно или не нужно идти дальше в проектирование. Например,  

    1. Надежность: сколько бизнес потеряет от простоя системы (минута, 10 минут, час, 6 часов, сутки).

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

    3. Производительность: какие объемы операций нужно обрабатывать.

  3. Спроектированные ранее модели системы (начиная с функциональных моделей) преобразуются с точки зрения аспекта в новую модель. При этом возможно:

    1. Объединение моделей каких-то частей системы, если они неразличимы для аспекта,

    2. Разделение модели какой-то части системы, если разные части различимы для аспекта,

  4. Выбор наиболее значимой части системы или взаимодействия частей системы для изменения. Выбор наиболее подходящей тактики изменения.

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

  5. Применение тактики, проектирование вариантов решений в виде моделей

    1. Вариант решения должен быть как-то оценен (в идеале в сроках/деньгах, но часто достаточно черновых прикидок), мы узнаем “какие нужны расходы на обеспечение качества”,

    2. При проектировании может оказаться, что нам требуется больше информации из надсистем (из моделей использования системы),  контекста для принятия решений, для понимания “сколько это принесет денег/какие будут издержки отсутствия нужного качества” (в соответствии с https://habr.com/ru/articles/706956/),

    3. При проектировании может оказаться, что нужны дополнительные знания, для получения которых нужно создать дополнительные модели системы,

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

    5. Проектирование новой модели может показать необходимость перепроектирования ранее спроектированных моделей решения (даже спроектированных ранее функциональных моделей системы),

    6. Спроектированные модели решения создают новые вводные для других моделей решения (возможно уже ранее спроектированных),

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

    8. Иногда лучшим решением будет “ничего не делать, все и так нормально”, но заранее это сказать не всегда возможно.

  6. Принимается решение с учетом баланса обеспечения качества,

    1. Предлагаемые варианты понятны для бизнеса и ИТ, в отличии от “99.5%”, решение принимается более адекватно/рационально,

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

  8. Проверяем достаточность решения (сохранилась ли проблема). Применяем следующую тактику.

В виде схемы:

P.S. Подход удобен еще в случаях, когда бизнес-потери бизнес не может оценить. Например, ИТ системы автоматизации бухгалтерии или BI (BI не работает 1 час. Сколько теряет бизнес?). В таких случаях, говорить по баланс обеспечения качества на уровне всей системы не получается. Но глядя на конкретные варианты обеспечения конкретного блока (например, делаем горячее или холодное резервирование BI или нет), бизнес готов вместе принимать осознанные решения. 

Теги:
Хабы:
Всего голосов 9: ↑8 и ↓1+7
Комментарии1

Публикации

Истории

Работа

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань