Введение в ADR (Architecture Decision Record) — минимальный способ сохранить «почему мы спроектировали именно так» в небольшой команде

· · Проектирование, Обзор проектирования, Документация, ADR, Техническая консультация, Обслуживание, Контрактная разработка, Разработка Windows

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

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

В этом блоге мы уже разбирали, как вести заказную разработку, в статье «Что нужно продумать перед заказом разработки Windows-приложения», а структуру договора — в статье «Выбор между квазидоверительным договором и договором подряда — уроки из „Модельной сделки и договора“ IPA». Эта статья продолжает эту тему и посвящена тому, что нужно, чтобы система работала годами после того, как её построили. Разберём ADR (Architecture Decision Record) — механизм сохранения обоснования проектного решения с минимальными усилиями, в контексте небольшой заказной или внутренней разработки.

1. Сначала вывод

  • Прежде исчерпывающего проектного документа нужно сохранять запись решений. Настоящую проблему при сопровождении создаёт не незнание того, что делает код, а незнание того, почему это было сделано именно так.
  • ADR — это лёгкий формат, который фиксирует одно решение в одном файле по шаблону заголовок / статус / контекст / решение / последствия. Майкл Найгард предложил его в 2011 году, и правило — не более одной-двух страниц на решение.1
  • Место хранения — тот же репозиторий, что и код (например, docs/adr/0001-title.md) — под контролем версий вместе с кодом, рассматривается вместе с код-ревью, а не в вики или общей папке.12
  • Решение никогда не перезаписывается. При смене курса добавляется новый ADR, а статус старого меняется на Superseded с перекрёстной ссылкой между ними. Журнал ADR — это журнал только для добавления записей.2
  • Вместо того чтобы фиксировать всё подряд, пишите только решения, которые трудно изменить впоследствии, имели несколько равноценных альтернатив или были определены ограничением. Правила именования и настройки форматтера — вне области ADR.2
  • По личному опыту, удержание каждой записи в пределах 15–30 минут — это то, что позволяет практике прижиться. Тяжеловесный шаблон умирает после первых трёх записей.
  • В заказной разработке ADR становится результатом, которым можно поделиться с заказчиком. Он работает как есть в качестве материала для объяснения на приёмке и как документ передачи дел при смене персонала или подрядчика.

2. Проблема «почему это устроено именно так»

2.1 Код рассказывает, что делает, но никогда — почему

Прочитав код, при должном терпении можно понять, что он делает. Чего понять нельзя — так это «почему» в вопросах вроде следующих.

  • Почему база данных — SQLite, а не SQL Server?
  • Почему интеграция с другой системой построена на передаче CSV-файлов, а не через веб-API?
  • Почему только этот отчёт запускает Excel для печати?
  • Почему всё ещё .NET Framework, а не обновлено до актуального .NET?

За такими решениями всегда стоит причина, лежащая вне самого кода — бюджет и срок на тот момент, ограничения на стороне клиента, компромисс с существующими активами. Это слишком объёмно для комментария, а «история о том, как мы пришли к этому решению» неудобно ложится и в проектный документ. В итоге причина не сохраняется нигде.

2.2 Любое место, где обычно хранится решение, исчезает за несколько лет

Так где же сегодня на самом деле живёт обоснование проектного решения? Сравним обычные места.

Где хранится Сохранится ли через несколько лет Расстояние до кода Найдёт ли преемник
Устная договорённость на встрече Не сохранится Невозможно
Чат (Teams/Slack) Утекает и фактически исчезает Далеко Почти невозможно
Электронная почта Погребено в чьём-то личном ящике Далеко Исчезает при увольнении
Протокол встречи (общая папка) Сохраняется, но вперемешку Далеко Непонятно, в протоколе какой встречи искать
Вики / проектный документ Обновления останавливаются, расходится с реальностью Далеко Найти можно, доверять — нет
ADR (в репозитории) Сохраняется вместе с кодом Тот же репозиторий Достаточно открыть docs/adr/

Архитектурные рекомендации Microsoft прямо указывают на то же самое: незадокументированное решение забывается, провоцируя повторение того же спора и изменения, идущие вразрез с исходным замыслом.2

2.3 В заказной разработке граница договора становится границей памяти

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

С точки зрения договора тоже совершенно нормально, что разработка и сопровождение — это отдельные договоры и отдельные этапы (эту структуру мы разбирали в нашем разборе «Модельной сделки и договора» IPA). И при квазидоверительном договоре именно потому, что подрядчик выполняет работу автономно, запись, которую можно показать заказчику — что было решено и как, — становится подтверждением этого доверия. ADR помогает и в том, и в другом.

3. Что такое ADR

3.1 Предложение Найгарда — пять элементов и ограничение в две страницы

ADR — это формат, который Майкл Найгард предложил в своей записи в блоге 2011 года «Documenting Architecture Decisions».1 Ключевые моменты таковы.

  • Один файл на одно решение. Файлы нумеруются по порядку, номер никогда не используется повторно
  • Файл хранится в лёгком формате вроде Markdown, внутри репозитория проекта
  • Структура строится вокруг пяти элементов: заголовок / статус / контекст / решение / последствия
  • Статус проходит путь от предложенного (proposed) к принятому (accepted), а при отмене переходит в устаревшее (deprecated) или заменённое (superseded). Старую запись никогда не удаляют
  • Весь документ укладывается в одну-две страницы, написан связной прозой, которую будущий разработчик сможет прочитать как беседу

Несмотря на слово «архитектура» в названии, это не техника, зарезервированная для крупных систем. Наоборот, этот минимальный фиксированный формат лучше всего работает именно в небольших командах без выделенного архитектора и без человека, отвечающего за документацию. Шаблоны и инструменты ADR также систематически собраны на сайте сообщества (adr.github.io) — хорошая точка входа для идеи «фиксировать архитектурно значимое решение вместе с его обоснованием и компромиссами».3

3.2 Шаблон на Markdown

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

# ADR-NNNN: (Сформулируйте решение одной короткой фразой)

## Статус

Предложено | Принято | Устарело | Заменено (-> ADR-MMMM)

## Контекст

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

## Решение

Сформулируйте прямо, в действительном залоге: «Мы сделаем то-то».
От одного до трёх предложений.

## Последствия

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

Ключевой момент — писать в разделе «Последствия» и о минусах тоже. Решение без компромиссов почти не стоит того, чтобы его фиксировать. Рекомендации Microsoft также подчёркивают, что не следует скрывать последствия решения — ни намеренно, ни случайно, — и что запись без обоснования со временем теряет ценность.2

4. Что писать в ADR, а что — нет

Главная причина, по которой практика ADR не приживается, — попытка фиксировать всё подряд. Рекомендации Microsoft советуют ограничивать записи тем, что влияет на структуру системы или важную характеристику качества и что трудно отменить впоследствии.2 Переведя это в повседневное правило, получаем следующую таблицу.

Вид решения Пример Писать ADR? Почему
Технологический выбор, который трудно изменить впоследствии Сделать базу данных SQLite, использовать передачу файлов для интеграции Да Изменение обходится дорого, а трогать без понимания причины — рискованно
Выбор из нескольких равноценных вариантов Генерировать отчёт библиотекой вместо COM-автоматизации Да Знание, почему отброшен другой вариант, избавляет преемника от повторного анализа
Ограничение стало решающим фактором Отказ от автообновления, потому что окружение клиента офлайн Да Решение можно пересмотреть, когда ограничение исчезнет (при обновлении окружения)
Договорённость с внешней стороной Кодировка и формат CSV подогнаны под спецификацию контрагента Да Явно показывает границу, которую нельзя изменить в одностороннем порядке
Унификация соглашения или стиля Правила именования, настройки форматтера, порядок using-директив Нет Достаточно конфигурационного файла вроде .editorconfig плюс автоматизации
Деталь реализации, которую можно менять в любой момент Как разбиты внутренние классы, как организованы приватные методы Нет Достаточно кода и код-ревью
Рутинная эксплуатационная работа Обновление патч-версии библиотеки Нет Достаточно истории изменений (журнала коммитов)

Когда сомневаетесь, есть единственный тест: захочет ли тот, кто посмотрит на этот код через год, — включая будущего вас, — спросить «почему»? Если да — пишите; если это самоочевидно из кода или настроек — не пишите.

Ещё одна ловушка — размышлять о нужной степени детализации в терминах «какой это тип документа». Заранее определив разделение ролей, как показано ниже, вы избавляете себя от сомнений.

Информация, которую хочется сохранить Куда она относится Связь с ADR
Почему выбран этот подход ADR Основное содержание
Текущая архитектурная схема / поток данных Проектный документ (тонкий) Ссылка из ADR
Содержание отдельного изменения Сообщение коммита / PR Связывается указанием номера ADR
Инструкция по эксплуатации Руководство по эксплуатации Совсем другое (другая аудитория). О том, как его писать, см. «Основы написания руководства в Word»
Запись о реагировании на инцидент Заявка / issue об инциденте Если по итогам реагирования меняется подход — заводится новый ADR

5. Ведение ADR в небольшой заказной разработке

5.1 Каталог и имена файлов

Заведите docs/adr/ прямо в корне репозитория и размещайте файлы с порядковым номером и коротким слагом.

docs/
  adr/
    0001-record-architecture-decisions.md
    0002-use-sqlite-for-local-storage.md
    0003-excel-report-via-com-automation.md
    0007-excel-report-via-openxml-library.md

Стандартный ход — сделать самой первой записью ADR о самом решении использовать ADR. Тогда преемнику достаточно открыть docs/adr/, чтобы понять весь порядок работы целиком.

5.2 Когда писать и кто рецензирует

  • Пишите сразу, как только решение принято. В качестве завершающего шага обсуждения проектного решения превращайте итог встречи в ADR в тот же день. Как будет показано ниже, откладывание записи «на потом» обречено на провал.
  • Включайте ADR в код-ревью. Всё, что нужно проверять, — включает ли pull request, затрагивающий архитектурный подход, добавление или обновление ADR. Отдельное совещание для утверждения ADR не нужно — включение в существующий процесс ревью и есть реалистичный ответ для небольшой команды. Ведение ADR под контролем версий также рекомендуют и Microsoft.2
  • Чтобы отменить решение, напишите новый ADR и измените статус старого на Superseded, связав их перекрёстной ссылкой. Никогда не переписывайте текст. Не редактировать утверждённую запись и сохранять историю через цепочку замещений — вот что значит относиться к ADR как к журналу только для добавления записей.2

5.3 ADR как результат, которым делятся с заказчиком

В заказной разработке рекомендуется делиться ADR с заказчиком как частью результатов работы. Здесь есть три выгоды.

  1. Материал для приёмки и объяснений. Вместо устного объяснения, почему система устроена именно так, достаточно показать ADR. Поскольку заказчик сам является стороной ограничений — бюджета, срока, окружения, — определивших решение, наличие записи предотвращает последующее расхождение в понимании.
  2. Страховка на случай смены подрядчика. С точки зрения заказчика наличие «истории решений», которую можно передать следующему подрядчику, сильно меняет стоимость и риск передачи дел. О том, как всё продумать до заказа, мы писали в «Что нужно продумать перед заказом разработки Windows-приложения», но при решении на этапе договора, какую документацию получить на будущее после сдачи проекта, ADR — один из вариантов с самым высоким соотношением ценности и затрат.
  3. Хорошо сочетается с отчётностью по квазидоверительному договору. Квазидоверительный договор требует отчёта о ходе выполнения работы, и ADR можно использовать напрямую как отчёт по проектному этапу.

5.4 Реалистичное представление о затратах времени

По моему опыту, написание одной записи по шаблону занимает 15–30 минут. На небольшом проекте решения возникают, может быть, несколько раз в месяц, так что инвестиция в один-два часа в месяц сохраняет всё «почему» целиком. По сравнению со временем, которое теряется на расследование, повторный анализ и передачу дел через несколько лет, вряд ли найдётся проект, где это не окупается.

6. Типичные ошибки

Паттерн ошибки Симптом Противодействие
Пишут слишком много ADR заводят даже на мелкие решения, и запал заканчивается через три недели Сузить область по таблице из главы 4. Несколько в месяц — норма
Тяжеловесный шаблон Форма с полями согласования, анализа влияния и оценки риска, которую никто не заполняет Вернуться к пяти элементам Найгарда. Ограничение в одну-две страницы1
Пишут в вики Обновления останавливаются в месте, отдельном от кода, расходятся с реальностью и теряют доверие Хранить в репозитории и рецензировать вместе с PR
Пишут задним числом, всё сразу «Напишу, когда станет спокойнее» -> память уже стёрлась, и написать не получается Писать сразу после решения. Если не получается — писать прямо во время принятия решения, с демонстрацией экрана
Переписывают прошлый ADR История исчезает, и становится непонятно, когда изменился курс Заменять через Superseded, текст оставлять неизменным2
Не пишут последствия (минусы) Получается просто уведомление о решении, бесполезное для повторного рассмотрения Обязательно писать компромиссы и условия для пересмотра

Особенно легко попасться на «пишут задним числом, всё сразу», когда ADR внедряют в существующую систему не с самого начала. Вместо попытки восстановить все прошлые решения реалистичнее вернуться назад и записать лишь несколько главных решений, которые ещё помнятся, а дальше наращивать записи начиная с сегодняшних решений. Даже для существующей (унаследованной) системы стоит вернуться назад и зафиксировать те прошлые решения, которые ещё удаётся восстановить.2

7. Разобранные примеры ADR

Приведём два полных ADR на темы, которые часто встречаются в небольших Windows-приложениях для бизнеса (содержание — обобщённый пример).

Первый — классическое технологическое решение: база данных.

# ADR-0002: Хранить бизнес-данные в SQLite

## Статус

Принято (2026-07-17)

## Контекст

Эта система — настольное приложение управления складом для одной
торговой точки. Пользователей 2-3 человека, но на практике оно
установлено на одном общем ПК в офисе и используется по очереди
(одновременно работает только один человек). У клиента нет персонала,
способного эксплуатировать сервер БД на месте, и нет бюджета на
серверное оборудование. Ожидаемый объём данных даже через 10 лет
эксплуатации останется в пределах нескольких сотен мегабайт.
Рассмотрели варианты SQL Server Express, SQLite и файл Access
(.accdb). SQL Server Express отклонили, поскольку у клиента нет
постоянной возможности разворачивать и проверять работу сервера
после выполнения Windows Update. Access отклонили из-за риска
повреждения при параллельной записи и плохих перспектив миграции
в будущем.

## Решение

Для хранения данных будет использоваться SQLite. Файл базы данных
не будет лежать в общей папке; он будет находиться локально на
основном ПК. Резервные копии создаются ежедневно как снимок через
VACUUM INTO и сохраняются на NAS (копирование живого файла во время
работы приложения не вариант, поскольку это грозит повреждённой
резервной копией из-за пропущенного WAL-файла или гонки записи).

## Последствия

- Плюс: не нужно разворачивать и обслуживать сервер БД. Резервное копирование сводится к одной SQL-команде
- Плюс: среду выполнения можно поставлять вместе с приложением, установка остаётся простой
- Минус: запись блокируется на уровне базы данных целиком, поэтому масштабировать на несколько точек или множество одновременных пользователей не получится
- Минус: перенос на серверную БД в будущем потребует миграции данных и переработки слоя подключения
- Пересмотреть это решение сразу, как только понадобится одновременная работа с нескольких ПК (в этом случае — переход на серверную БД или архитектуру на основе API)

Второй — пример отмены уже принятого решения. Обратите внимание и на использование статуса Superseded.

# ADR-0007: Формировать Excel-отчёты библиотекой вместо COM-автоматизации

## Статус

Принято (2026-07-17) -- заменяет ADR-0003 (переход на COM-автоматизацию)

## Контекст

Есть требование выгружать накладные и месячные сводки в файлы Excel.
Изначально это было реализовано через COM-автоматизацию Excel
согласно ADR-0003, но в необслуживаемом ночном пакетном задании
процессы Excel регулярно зависали и останавливали обработку, а
требование к лицензии Office на машине выполнения становилось
повторяющейся проблемой при каждом обновлении оборудования.
Рассмотрели продолжение работы с COM-автоматизацией (с добавлением
мониторинга процессов), переход на библиотеку, генерирующую формат
Open XML напрямую, и перевод отчётов в PDF (изменение требований).
PDF отклонили, поскольку клиент полагается на возможность вносить
пометки прямо в Excel.

## Решение

Отчёты будут переведены на прямую генерацию .xlsx библиотекой, без
зависимости от самого Excel. Оформление хранится как файл-шаблон
.xlsx в репозитории, генерация выполняется заполнением ячеек.

## Последствия

- Плюс: Excel больше не требуется в среде выполнения, необслуживаемые запуски становятся стабильными
- Плюс: проблема зависающих процессов устраняется структурно
- Минус: доступны не все возможности Excel, поэтому часть оформления существующих отчётов придётся упростить
- Минус: перевод существующих отчётов в шаблоны потребует затрат на доработку
- ADR-0003 помечен как Superseded, со ссылкой на этот ADR

Прочитав только эти две записи, легко убедиться, что они отвечают на вопросы, которые неизбежно возникают при передаче дел: «почему в этой системе нет серверной БД?» и «почему в коде отчётов остались следы запуска Excel?». Вместе они занимают около 1500 символов и пишутся меньше чем за час.

8. Итог

  • То, что теряется при сопровождении и передаче дел и создаёт проблемы, — не What, а Why. Незадокументированное решение забывается, провоцируя повторение споров и изменения, идущие вразрез с исходным замыслом.2
  • ADR — это лёгкий формат записи: одно решение на файл, пять элементов, не более одной-двух страниц. Оригинальная форма Найгарда работает как есть и для небольшой разработки.1
  • Фиксируйте только решения, которые трудно изменить, у которых были реальные альтернативы, или которые определило ограничение. Соглашения и форматирование оставьте автоматизации — они вне области ADR.2
  • Храните в docs/adr/, рецензируйте вместе с pull request. Никогда не перезаписывайте решение — заменяйте через Superseded и сохраняйте историю неизменной.12
  • В заказной разработке ADR становится результатом, ценным и для заказчика, — как документ для объяснения на приёмке и как документ передачи дел при смене подрядчика.
  • 15-30 минут на запись. Начните с того, что напишете один ADR для следующего же проектного решения, а для существующей системы — с того, что вернётесь назад и зафиксируете лишь несколько главных решений, которые ещё помните.

Похожие статьи

Смежные направления консультаций

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

Источники

  1. Michael Nygard, Documenting Architecture Decisions. Первоисточник ADR (2011 год). О пяти элементах — заголовок/контекст/решение/статус/последствия, о переходе статуса от предложенного к принятому и далее к устаревшему/заменённому, об объёме в одну-две страницы, о хранении в виде последовательно пронумерованных файлов в репозитории и о сохранении старых решений через Superseded вместо удаления.  2 3 4 5 6

  2. Microsoft Learn, Maintain an architecture decision record (ADR). Рекомендации из Azure Well-Architected Framework. О том, что журнал ADR следует вести только на добавление записей и не редактировать утверждённую запись, что при изменении решение заменяется новой записью с перекрёстной ссылкой, что область применения ограничивается решениями, влияющими на структуру системы или важную характеристику качества и трудными для отмены, что запись должна включать контекст, обоснование, компромиссы и статус (Proposed/Accepted/Superseded), что незадокументированные решения забываются и провоцируют повторение споров или изменения вразрез с исходным замыслом, и что даже для существующей нагрузки стоит фиксировать прошлые решения задним числом.  2 3 4 5 6 7 8 9 10 11 12 13

  3. adr.github.io, Architectural Decision Records. Сайт сообщества ADR. Об определениях архитектурного решения (AD) и архитектурно значимого требования (ASR), о том, что ADR фиксирует одно решение вместе с его обоснованием, компромиссами и последствиями, а также о подборке шаблонов и инструментов. 

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

Реагирование на инциденты не заканчивается восстановлением — шаблон постмортема (предотвращения повторения) для небольших команд разработки

Считать инцидент закрытым сразу после исправления и извинений — гарантированный способ повторить его снова. Адаптируем blameless-постморт...

Чтобы не забыть решить, «за сколько секунд это должно работать» — упорядочиваем нефункциональные требования с помощью «Градации нефункциональных требований» IPA

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

Если вам досталась система без исходного кода и без документации — практический план, как сопровождать её, не останавливая работу

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

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Частые вопросы

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

Что такое ADR (Architecture Decision Record)?
Это документ, который фиксирует одно решение, затрагивающее структуру программной системы, в одном файле по короткому фиксированному формату: заголовок / статус / контекст / решение / последствия. Майкл Найгард предложил этот лёгкий формат в 2011 году; базовое правило — не более одной-двух страниц на решение и коммит в формате Markdown в том же репозитории, что и код. В отличие от исчерпывающего проектного документа, ADR специализируется на сохранении того, почему был сделан именно этот выбор и какие альтернативы были отброшены.
Что стоит писать в ADR, а что можно опустить?
Стоит фиксировать: решения, которые трудно изменить впоследствии (выбор базы данных или способа обмена данными, формат внешней интеграции и т. п.), решения, сделанные между несколькими равноценными вариантами, и решения, определённые ограничением — бюджетом, сроком, существующими активами. И наоборот, то, что механически обеспечивается инструментом или соглашением, например правила именования или настройки форматтера, а также то, что легко изменить и что самоочевидно из кода, отдельного ADR не требует. Если сомневаетесь, используйте проверку: «захочу ли я через год спросить, почему сделано именно так».
Если хочется изменить прошлое решение, можно ли переписать старый ADR?
Нет — не переписывайте его, а добавьте новый ADR, который его заменяет. Измените статус старого ADR на Superseded (заменён), добавьте ссылку на новый ADR и оставьте его текст без изменений. Рекомендации Microsoft также советуют относиться к журналу ADR как к журналу только для добавления записей и никогда не редактировать утверждённую запись задним числом. Так сама история — когда и почему изменился курс — становится самостоятельным документом для передачи дел.
Если у нас уже есть проектная документация, не избыточен ли ADR?
Они играют разные роли. Проектный документ показывает, какова структура сейчас, но обычно не сохраняет, почему была выбрана именно эта структура и что было отброшено. Исчерпывающий проектный документ также имеет свойство переставать обновляться и через несколько лет расходиться с кодом. ADR требует лишь добавления нескольких сотен символов на каждое решение, поэтому гораздо меньше подвержен устареванию — даже когда проектный документ устаревает, обоснование каждого решения продолжает жить само по себе. Для небольшой разработки реалистичная схема — держать подробный проектный документ тонким и дополнять его ADR.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог