Границы системы: как выбор границы меняет вывод
«Отдельных систем не существует. Мир — континуум. Где провести границу вокруг системы, зависит от цели разговора». — Донелла Медоуз, «Thinking in Systems» (2008)
Фраза звучит как разрешение делать что угодно. Означает она противоположное: раз граница выбирается, за неё отвечает тот, кто выбрал. В прошлой главе мы договорились, что система — это элементы, связи и назначение. Но чтобы перечислить элементы, надо знать, где остановиться: граница логически первична.
Сцена: два честных отчёта об одном инциденте
Пятница, 14:20. Оформление заказов деградировало на 40 минут. Через неделю — два постмортема.
Команда платежей. «Сервис отработал штатно: p99 обработки 38 мс при SLO 120 мс, ошибок 0.02%, деплоев не было. Причина вне нашей зоны — всплеск входящего трафика в 2.4 раза. Действие: попросить смежников предупреждать о нагрузочных тестах».
Команда заказов. «В 14:18 выкатили батчинг записи с окном 100 мс. Наш p99 вырос с 31 до 106 мс — в пределах SLO 150 мс. Причина вне нашей зоны: платежи начали таймаутиться. Действие: попросить платежи поднять лимиты».
Оба отчёта фактически верны, каждая метрика измерена правильно, и оба вывода бесполезны. События «всплеск трафика в 2.4 раза» не было: клиент с таймаутом 100 мс начал ретраить запросы, задержавшиеся из-за нового окна батчинга; ретраи подняли нагрузку; нагрузка подняла задержку; петля замкнулась. Причина лежит на стыке, а стык не попал ни в одну из двух границ. Это не история про плохие команды, а структурное свойство: когда граница режет петлю обратной связи пополам, каждая половина выглядит как внешнее возмущение.
Что такое граница: не два круга, а три
Бытовое представление — «есть система и есть внешний мир». Рабочее требует трёх зон.
Эндогенное — переменные, чьё поведение модель объясняет: у них есть причины внутри. Экзогенное — входы: модель их использует, но не объясняет. Исключённое — то, чего в модели нет вообще; самая опасная зона, потому что у неё нет ни строки в дашборде, ни узла на схеме, и её отсутствие не замечают.
Ключевой приём системной динамики Джея Форрестера — эндогенная точка зрения: интересующее поведение должно порождаться структурой внутри границы, а не подаваться снаружи как последовательность шоков. Отсюда критерий из «Industrial Dynamics» (1961): если для объяснения происходящего приходится каждый раз добавлять новое внешнее событие — граница проведена слишком узко. Посмотрите на пунктирные стрелки: в сцене выше «всплеск трафика» был экзогенным входом для обеих команд, а стоит перевести RPS в эндогенные — сделать его функцией собственной задержки — и модель воспроизводит инцидент без внешних шоков. Вывод переворачивается: не «смежники нас залили», а «мы сами замкнули петлю».
Граница — это решение, и у него есть критерий
Свобода выбора границы часто читается как «любая граница годится». Неверно: граница оценивается по одному признаку — воспроизводит ли модель внутри неё то поведение, которое вас интересует. Отсюда порядок работы, обратный интуитивному.
- Сначала режим поведения (reference mode) — не схема, а график во времени: «очередь растёт с 09:00 до 18:00 и не рассасывается за ночь», «после каждого крупного релиза MTTR растёт три недели, потом возвращается». Без графика границу нечем оценивать.
- Потом горизонт времени. Он входит в границу наравне со списком элементов и должен быть длиннее задержки между действием и последствием, иначе последствие окажется за пределами модели (см. задержки).
- И только потом список элементов. Элемент попадает внутрь, если без него режим поведения не воспроизводится.
Тест на «слишком узко». Приходится ли объяснять поведение чередой внешних событий? «В понедельник всплеск, в среду релиз смежников, в пятницу упала сеть» — и так каждый месяц с новым списком. Регулярность событий, которые вы считаете случайными, — сильный признак, что их источник внутри контура, просто снаружи вашей границы.
Тест на «слишком широко». Появились ли переменные, которые нельзя измерить, нельзя изменить, и при изменении которых на порядок вывод не меняется? Каждая такая — чистый минус: степеней свободы больше, предсказаний столько же. Итого: граница правильна не тогда, когда она полна, а тогда, когда её ошибочность можно обнаружить.
Шесть границ, которые обычно не совпадают
Слово «граница» означает минимум шесть разных вещей, и половина организационных патологий — следствие того, что их считают одной.
| граница | вопрос, на который она отвечает | где обычно записана |
|---|---|---|
| физическая | что за процесс, контейнер, VPC | схема деплоя |
| ответственности | кого будят ночью, кто владеет SLO | расписание дежурств |
| измерения | где стартует таймер, где стоит счётчик | конфиг метрик |
| управления | что можно изменить без согласования | нигде |
| учёта | чей бюджет платит, чья квота расходуется | биллинг |
| времени | горизонт квартала или трёх лет | нигде |
Обратите внимание на две строки «нигде»: именно незаписанные границы расходятся с остальными незаметно. Патологии живут не внутри зон, а в зазорах между ними.
- Ответственность есть, управления нет. Дежурного будят за общую базу, конфигурацию которой он менять не может. Доступна одна реакция — обходной путь; со временем обходные пути становятся архитектурой.
- Управление есть, измерения нет. Команда владеет воркером, но SLO меряется на ответе API: отставание очереди растёт часами при зелёном дашборде.
- Измерение есть, ответственности нет. Метрику снимают, но реагировать никто не обязан. Такие метрики деградируют предсказуемо: сначала на них перестают смотреть, потом ломается сбор.
- Учёт уже управления. Команда платит за свои поды, но не за нагрузку на общий кластер БД — готовая конструкция для трагедии общего ресурса, разберём ниже.
Приём: возьмите один компонент и честно ответьте по каждой из шести границ, внутри он или снаружи. Компоненты с расходящимися ответами — ваш список на разбор; обычно их два-три, и они же фигурируют в половине инцидентов. Отдельно стоит развести системную границу и ограниченный контекст из DDD (bounded context): первый — граница объяснения поведения во времени, второй — граница языка предметной области, внутри которой «заказ» значит ровно одно. Они часто не совпадают, и это нормально: критерии качества у них разные.
Граница измерения: где включается таймер
Самая коварная из шести, потому что выглядит объективным фактом, а является конструкторским решением.
Между T0 и T4 — четыре разных «времени ответа», и каждое кто-то называет латентностью. Серверный SLO меряет T2–T3 и умалчивает про три четверти ожидания. Это не подтасовка: команда добросовестно меряет то, чем управляет, — но выводы из отрезка T2–T3 нельзя переносить на впечатление пользователя. Есть и частный случай, где граница измерения искажает результат на два порядка: нагрузочный генератор шлёт запрос, ждёт ответа, шлёт следующий, и если сервис на 200 мс встал, за эти 200 мс он отправил один запрос вместо двухсот — медленные замеры просто не попали в выборку. Гил Тене назвал это coordinated omission: измеритель «согласованно» замолкает вместе с системой (How NOT to Measure Latency).
"""Одна и та же деградация, две границы измерения."""
import math
N, STALL_AT, STALL_MS = 10_000, 5_000, 200
def quantile(xs: list[float], p: float) -> float:
s = sorted(xs) # O(n log n) по времени, O(n) по памяти
return s[min(len(s) - 1, math.ceil(p * len(s)) - 1)]
# «Внутри клиента»: меряем только отправленные запросы — во время затыка отправлен ровно один.
naive = [1.0] * (N - 1) + [float(STALL_MS)]
# «По расписанию»: запрос должен был уйти в момент i, а ушёл после затыка.
corrected = [float(STALL_AT + STALL_MS - i) if STALL_AT <= i < STALL_AT + STALL_MS else 1.0
for i in range(N)]
for name, data in (("внутри клиента", naive), ("по расписанию", corrected)):
print(f"{name:>16}: p50={quantile(data, .5):6.1f} "
f"p99={quantile(data, .99):6.1f} p99.9={quantile(data, .999):6.1f}")
# внутри клиента: p50= 1.0 p99= 1.0 p99.9= 1.0
# по расписанию: p50= 1.0 p99= 100.0 p99.9= 190.0
Обе цифры получены из одного и того же поведения системы, ошибки в коде нет ни в одном варианте, а p99 отличается в сто раз исключительно из-за границы измерения. Следствие: утверждение «p99 = 40 мс» неполно без указания границы. Техника — в «Измерение производительности» и «Наблюдаемость».
Разбор: батчинг, который «сэкономил» CPU
Вернёмся к сцене и посчитаем. Модель намеренно грубая: важен не абсолютный результат, а то, что меняется
от переноса одной переменной через границу. Допущения (все проверяемы и все могут оказаться неверными):
поток пуассоновский, обслуживание экспоненциальное — приближение M/M/1 со средним ожиданием 1/(C − λ);
окно батчинга даёт равномерную задержку от 0 до B мс поверх очереди; клиент ретраит по таймауту T
не более двух раз; ретраи неотличимы от новых запросов.
"""Ёмкость сервиса при экзогенной и эндогенной нагрузке."""
from math import exp
def p_timeout(lam: float, C: float, B_ms: float, T_ms: float) -> float:
"""Доля запросов, чьё полное время превысило таймаут клиента."""
if lam >= C:
return 1.0
W = 1000.0 / (C - lam) # ожидание в очереди, мс
if B_ms == 0:
return exp(-T_ms / W)
return (W / B_ms) * (exp(-(T_ms - B_ms) / W) - exp(-T_ms / W)) # усреднение по окну батчинга
def fixpoint(lam0: float, C: float, B_ms: float, T_ms: float, retries: int = 2):
"""Неподвижная точка потока с учётом ретраев; None — устойчивой точки нет. O(k), k ~ 5-20."""
lam = lam0
for _ in range(500):
p = p_timeout(lam, C, B_ms, T_ms)
new = lam0 * sum(p ** k for k in range(retries + 1))
if new >= C:
return None, p # поток превысил ёмкость: коллапс
if abs(new - lam) < 1e-6:
return new, p
lam = new
return lam, p
CONF = {"без батчинга": (1900, 0, 1.00), "с батчингом": (2600, 100, 0.62)} # ёмкость, окно, CPU/запрос
for lam0 in (1200, 1750):
for name, (C, B, cpu) in CONF.items():
lam, p = fixpoint(lam0, C, B, T_ms=100.0)
print(f"{lam0} rps / {name:>13}: поток={lam:7.1f} (+{100*(lam/lam0-1):.2f}%) "
f"таймауты={100*p:5.2f}% p99={B + 4.605*1000/(C-lam):6.1f} мс CPU={cpu*lam:6.0f}")
1200 rps / без батчинга: поток= 1200.0 (+0.00%) таймауты= 0.00% p99= 6.6 мс CPU= 1200
1200 rps / с батчингом: поток= 1208.7 (+0.72%) таймауты= 0.72% p99= 103.3 мс CPU= 749
1750 rps / без батчинга: поток= 1750.0 (+0.00%) таймауты= 0.00% p99= 30.7 мс CPU= 1750
1750 rps / с батчингом: поток= 1771.4 (+1.22%) таймауты= 1.21% p99= 105.6 мс CPU= 1098
Внутри границы команды заказов батчинг — однозначная победа: CPU на 37% меньше, p99 внутри своего SLO.
Это правда, и её надо признать: локальная оптимизация здесь не выдумана. Расширим границу на клиента.
Бинарный поиск по максимальному λ0, при котором неподвижная точка ещё существует, даёт настоящий потолок:
| конфигурация | потолок при экзогенной нагрузке | потолок при эндогенной | завышение |
|---|---|---|---|
| без батчинга | 1900 rps | 1838 rps | 3.3% |
| с батчингом | 2600 rps | 2288 rps | 12.0% |
Батчинг поднял ёмкость с 1900 до 2600 rps, но реальный потолок вырос только до 2288. Важнее другое: ошибка планирования выросла вчетверо — раньше расчёт по экзогенной нагрузке врал на 3%, теперь на 12%. Изменение перевело систему в режим, где ретраи стали значимой эндогенной переменной. За потолком 2288 неподвижной точки нет вообще: поток растёт до ёмкости и держится там, пока кто-нибудь не выключит ретраи — механика метастабильных отказов из Metastable Failures in Distributed Systems.
Знаки читаются так: + — растёт причина, растёт следствие; − — растёт причина, падает следствие. Цикл
L → TO → R → Q → U → L состоит из одних плюсов, значит он усиливающий: любое отклонение он раздувает.
Путь B → CPU → U — с минусом, уравновешивающий, и работает мгновенно. Поэтому решение и выглядит
выигрышным: уравновешивающий эффект виден сразу, усиливающий — только под нагрузкой (разбор таких
конструкций — в следующей главе).
Проверяемое предсказание. Гипотеза «нагрузка экзогенна» фальсифицируема: если она верна, рост нашего p99 на 70 мс не должен менять входящий RPS. Ставим окно батчинга под фиче-флагом, включаем на 10% трафика при стабильном спросе, сравниваем входящий RPS в контрольной и тестовой группах: разница за пределами шума опровергает гипотезу, и клиента надо втягивать внутрь границы.
Разбор: кэш внутри границы или снаружи
Типичная строчка в расчёте ёмкости: «hit rate кэша 92%, значит на базу пойдёт 8% трафика». Здесь hit rate — экзогенный параметр, и модель говорит: база выдержит, реплики не нужны. Если перенести кэш внутрь границы, у hit rate появляются причины: рабочее множество зависит от профиля трафика, а профиль меняется при деградации; вытеснение зависит от объёма; при росте задержки базы растёт время заполнения кэша, значит растёт доля промахов; промахи повышают нагрузку на базу — снова усиливающая петля.
Различие наблюдаемо и потому разрешаемо экспериментом: если hit rate экзогенен, он не должен зависеть от задержки базы. Внесите задержку 50 мс на 5% запросов к базе (простейший fault injection): не сдвинулся — экзогенность подтверждена для этого диапазона, поплыл — параметр переводим в эндогенные и пересчитываем ёмкость. Мы не спорим, «правильно» ли считать кэш частью системы, а формулируем, чем варианты различаются наблюдаемо, и меряем: спор о границе, который нельзя свести к наблюдению, — это спор о вкусах. Дальше: «Кэширование», «Паттерны устойчивости».
Разбор: найм — граница команды против границы организации
Внутри границы команды всё просто: наняли двух инженеров, расчётная мощность выросла на 40%, мощность есть сумма людей на производительность. Внутри границы организации онбординг потребляет время сеньора — того самого, который единственный держит ключевой сервис; мощность в первые месяцы падает, а координационная нагрузка растёт квадратично по числу пар. Это закон Брукса из «Мифического человеко-месяца» (Fred Brooks, 1975): «добавление рабочей силы к запаздывающему проекту задерживает его ещё больше».
Честно про доказательность: закон Брукса — обобщение опыта разработки OS/360, а не измеренная закономерность. Падение производительности при быстром росте воспроизводилось в исследованиях по ramp-up, но эффект сильно зависит от структуры работы: там, где задачи слабо связаны, он мал. Считайте это хорошо мотивированной гипотезой с ограниченной областью применимости; проверить у себя просто — постройте lead time по неделям вокруг прошлых расширений команды. Практика — в треке «Тимлид»: онбординг и топологии команд.
Разбор: техдолг — граница по времени
Здесь граница проходит не по элементам, а по горизонту. При горизонте в квартал техдолг вообще не переменная: он не успевает проявиться, и модель честно показывает, что торопиться выгодно. При горизонте в два года это запас с входящим потоком (скорость накопления при спешке), исходящим (скорость выплаты) и эффектом процента: чем больше запас, тем медленнее любое изменение, тем выше соблазн опять сделать быстро и грязно (запасы и потоки).
Следствие: спор «надо ли чинить техдолг» почти никогда не является спором о фактах. Это спор о горизонте, замаскированный под спор о приоритетах, и пока горизонт не назван вслух, обе стороны правы внутри своих границ. Первый ход — не аргументы, а вопрос: «на каком горизонте мы оцениваем это решение?». Прикладная сторона — в «Техдолг».
Разбор: общий ресурс — граница учёта
Общий кластер БД, общие раннеры CI, общий Kafka. Каждая команда оптимизирует своё время сборки, добавляя параллельных джоб; суммарная очередь растёт; сборки замедляются у всех; в ответ каждая команда добавляет ещё джоб. Трагедия общего ресурса в чистом виде — механизм описан у Хардина (Science, 1968). Причина не в жадности, а в конфигурации границ: выигрыш попадает внутрь границы команды, издержка — за неё.
Важная поправка, которую часто опускают: Элинор Остром показала на большом корпусе полевых исследований, что общие ресурсы регулярно управляются устойчиво без приватизации и без внешнего принуждения — при наличии наблюдаемости расхода, понятных правил и механизма разрешения споров («Governing the Commons», 1990, нобелевская лекция). В инженерном переводе это три вещи: видимость расхода по потребителям (дашборд «минуты раннеров по командам», а не общая цифра), квоты или ценник (перенос издержки внутрь границы того, кто её создаёт) и механизм исключений (иначе правила начнут обходить и вы получите теневую инфраструктуру). Все три — операции над границами, а не над поведением людей; это общий признак хорошего системного вмешательства, подробнее в главе «Точки воздействия».
Как записывать границу, чтобы к ней можно было вернуться
Граница, оставшаяся в голове автора, через месяц становится неотличимой от «объективной картины мира». Записывайте её явно — в ADR, дизайн-док или шапку постмортема; формат любой, смысл в том, чтобы каждая строка была опровержима.
# приложение к ADR-042 «Батчинг записи в сервисе заказов»
behavior_of_interest: "p99 оформления заказа и доля успешных оформлений"
reference_mode: "p99 стабилен 30 мс, при пиках скачки до 400 мс раз в 2-3 недели"
time_horizon: "90 дней — две недели на разгон плюс два пиковых цикла"
endogenous: # объясняем внутри модели
- name: "длина очереди на запись; задержка API; доля запросов сверх таймаута клиента"
- name: "входящий поток с учётом ретраев"
note: "перенесено из exogenous после инцидента 14 марта"
exogenous: # берём как вход, сценарии заданы явно
- name: "внешний спрос, rps"
scenarios: [1200, 1750, 2100]
source: "квантили за 90 дней из метрик балансировщика"
- name: "ёмкость кластера БД"
note: "фиксирована на горизонте, изменение требует отдельного ADR"
excluded: # сознательно не рассматриваем
- name: "hit rate кэша"
assumption: "не зависит от задержки БД в диапазоне до 150 мс"
falsifier: "fault injection 50 мс на 5% запросов; сдвиг hit rate > 2 п.п. опровергает"
- name: "мотивация команды"
assumption: "влияет медленнее горизонта модели"
falsifier: "нет дешёвого — помечено как непроверенная гипотеза"
review_trigger: "любой инцидент, объяснённый внешним всплеском трафика"
Рабочим, а не декоративным документ делает поле falsifier — наблюдение, которое опровергнет допущение.
Если его нельзя придумать, честнее написать «непроверенная гипотеза», чем изобретать наукообразие;
review_trigger при этом задаёт условие пересмотра — прямое следствие теста на «слишком узко».
Пределы метода: где граница перестаёт быть проверяемой
Теперь честная часть. Работа с границами легко вырождается в производство красивых схем, которые ничего не предсказывают. Признаки вырождения конкретны. Схема без режима поведения: если нельзя назвать график во времени, который модель должна воспроизвести, это не модель, а иллюстрация — её невозможно опровергнуть, а значит и подтвердить.
Граница, растущая после каждого возражения. На любое «а как же X?» автор добавляет X внутрь. Через три итерации внутри границы вся организация и рынок, модель объясняет всё постфактум и не запрещает ничего. Природа ошибки та же, что у нефальсифицируемых объяснений в «Причинные и статистические ошибки».
Стрелки без знаков и без данных. Причинная стрелка утверждает направление и знак; если ни то, ни другое не подкреплено измерением или явно названным допущением, она не несёт информации. Диаграмма из двадцати таких стрелок не становится информативнее — она становится убедительнее, а это хуже. Стрелка «нагрузка → ошибки» выглядит как причинное утверждение, но получена обычно из совпадения графиков: схема сама по себе причинности не даёт, причинность приходит из вмешательства («Научная и инженерная аргументация»).
Чего метод не даёт в принципе. Граница не определяет параметры: даже идеально проведённая, она не скажет, чему равна ёмкость. Без данных нет количественного прогноза — структура без измерений даёт класс поведения (растёт / колеблется / насыщается), а не числа. И она не разрешает ценностные конфликты: вопрос «чьи издержки считать» не технический. Им явно занимается Critical Systems Heuristics Вернера Ульриха (wulrich.com) — набор вопросов вида «кто бенефициар, кто принимает решения, кто затронут, но не имеет голоса»; его доказательная база это разборы случаев, а не эксперименты, поэтому он полезен как чек-лист и бесполезен как доказательство. Резюме: системное мышление хорошо объясняет форму поведения и плохо даёт числа — требуйте от модели ровно того, что она может дать (подробнее в главе «Моделирование и его пределы»).
Честно про доказательную базу
Метод не появился в вакууме, и его история — в основном история споров о границах.
Urban Dynamics (1969). Книга Форрестера выдавала контринтуитивные выводы о городской политике — например, что строительство дешёвого жилья ухудшает положение бедных районов. Критика начала 1970-х показала: выводы чувствительны к неизмерявшимся параметрам и к границе, проведённой так, что миграция между городом и остальной страной оказалась вне модели. Это ровно наш случай — границей был предопределён вывод. Урок не «системная динамика не работает», а «границу предъявляют вместе с выводом и проверяют устойчивость вывода к её сдвигу».
«Пределы роста» и World3 (1972). Модель агрегировала мир до нескольких переменных, не содержала цен и рынков, а результаты подавались как сценарии, но читались как прогнозы. Уильям Нордхаус в «World Dynamics: Measurement Without Data» (The Economic Journal, 1973) предъявил главную претензию: структура задана априори, параметры подобраны без данных. Позже Грэм Тёрнер сопоставил стандартный сценарий с данными за 30 лет и нашёл согласие по агрегатам (Global Environmental Change, 2008) — эту работу тоже критиковали, поскольку согласие агрегатов не подтверждает механизм. Взвешенная позиция: World3 — не подтверждённый и не опровергнутый прогноз, а структурная гипотеза с обсуждаемыми границами; трек на неё не опирается. Знаменитый список из двенадцати точек воздействия в «Leverage Points» Медоуз (1999) — тоже эссе с небесспорным, по признанию автора, порядком пунктов: эвристика для разговора, не измеренная иерархия (оригинал).
Что действительно измерено. Самая твёрдая часть доказательной базы — не модели, а эксперименты о том, как люди рассуждают о системах. Стерман и коллеги показали воспроизводимый эффект: люди систематически ошибаются в задачах на накопление — не могут построить график запаса по графику притока и оттока, даже имея техническое образование (bathtub dynamics, System Dynamics Review, 2000). То же даёт «пивная игра»: участники устойчиво порождают колебания в цепочке поставок из-за задержек, даже зная о них. Вывод скромный, но полезный: интуиция про накопление и задержки систематически подводит, поэтому запасы стоит считать, а не оценивать на глаз.
Безопасность как отдельная линия. Йенс Расмуссен (Safety Science, 1997) и Нэнси Левесон (STAMP, «Engineering a Safer World», полный текст) пришли к тому же выводу с другой стороны: авария редко имеет «корневую причину» внутри одного компонента, она возникает из структуры контроля, и граница расследования предопределяет, что будет названо причиной. Это позиция о том, как строить объяснение, а не предсказательная теория аварий. Общий итог: границы и петли хорошо работают как язык описания и генератор гипотез; количественные предсказания получаются только там, где есть измерения, а всё выходящее за рамки посчитанных примеров читайте как гипотезу для проверки на ваших данных.
Типичные ошибки
- Граница выбрана по оргструктуре. Дефолт «система = то, что мы катим». Оргструктура коррелирует с архитектурой (закон Конвея, melconway.com), но отражает историю найма, а не структуру поведения.
- Экзогенная нагрузка по умолчанию. «RPS задан извне» верно ровно до появления ретраев, автоскейлинга, фоновой синхронизации и повторных заходов раздражённого пользователя.
- Горизонт по циклу планирования. Квартал выбран не потому, что соответствует динамике системы. Если задержка эффекта больше горизонта, модель систематически рекомендует брать в долг.
- Смешение границы модели и границы ответственности. «Это не наша зона» — корректное утверждение об ответственности и некорректное о причинности. Симметричная ошибка — «это системная проблема» как способ ничего не делать: без проверки и следующего шага внутри вашей зоны управления это пустая фраза.
- Молчаливое расширение границы в середине спора. Полдиалога обсуждали сервис, потом незаметно перешли к организации: оба правы, согласия нет. Лечится вопросом «мы сейчас про какую границу?». И наоборот, одна граница на все вопросы не работает — для ёмкости, постмортема и найма нужны разные; универсальной «карты системы» не бывает, бывает карта под вопрос.
Мини-итог
- Граница отделяет три зоны, а не две: эндогенное, экзогенное и исключённое. Опаснее всего третья.
- Критерий хорошей границы — воспроизведение заранее названного режима поведения, а не полнота. Сначала график во времени, потом горизонт, потом список элементов. Тест на узость: поведение объясняется чередой внешних шоков. Тест на широту: появились переменные, которые нельзя ни измерить, ни изменить.
- Границы деплоя, ответственности, измерения, управления, учёта и времени не совпадают; патологии живут в зазорах между ними. Перенос одной переменной через границу переворачивает вывод: в примере расчёт завышал потолок на 12% только потому, что ретраи клиента считались внешними. Поэтому границу записывают явно и фальсифицируемо: допущение без опровергающего наблюдения — гипотеза, и называть её надо гипотезой.
Что дальше
Мы дважды упёрлись в одно и то же: как только петля обратной связи пересекает границу, поведение перестаёт быть объяснимым изнутри. Пора разобрать сами петли — чем усиливающий контур отличается от уравновешивающего, как читать знаки на стрелках, почему усиливающие дают экспоненту, а уравновешивающие — колебания.
Петли обратной связи: усиливающие и уравновешивающие
Источники
- Donella H. Meadows. Thinking in Systems, 2008; «Leverage Points», 1999.
- Jay W. Forrester. Industrial Dynamics, 1961; Urban Dynamics, 1969 — и критика последней в 1972–1974.
- William D. Nordhaus. «World Dynamics: Measurement Without Data». The Economic Journal, 83(332), 1973; Graham Turner. «A comparison of The Limits to Growth with 30 years of reality», Global Environmental Change, 2008, https://doi.org/10.1016/j.gloenvcha.2008.05.001
- John D. Sterman. Business Dynamics, 2000; Booth Sweeney & Sterman. «Bathtub dynamics». System Dynamics Review, 16(4), 2000.
- Garrett Hardin. «The Tragedy of the Commons». Science, 162(3859), 1968; Elinor Ostrom. Governing the Commons, 1990, https://www.nobelprize.org/prizes/economic-sciences/2009/ostrom/lecture/
- Jens Rasmussen. «Risk management in a dynamic society». Safety Science, 27(2-3), 1997; Nancy G. Leveson. Engineering a Safer World, 2011, http://sunnyday.mit.edu/safer-world.pdf
- Инженерные ссылки по тексту: Bronson et al. «Metastable Failures in Distributed Systems» (HotOS ‘21), Gil Tene «How NOT to Measure Latency», Werner Ulrich «Critical Systems Heuristics», Google SRE Book.