Files
dev-conventions/conventions/arch/app-directories.md
T
av c1cb240540 темы: определение, объявление в шапке и манифест набора
- тема — набор правил об одном фокусе разработки, имя латиницей (нижний
  kebab-case рекомендуется, годится любой идентификатор, пригодный для имени
  файла); определение в LANGUAGE.md и README.md
- заведены META-28 и META-29: тема объявляется в шапке (`topic:`), стоит в
  манифесте набора и не переиспользуется; `topic:` добавлен во все 12 файлов
- prefixes.toml и topics.toml слиты в manifest.toml — манифест набора против
  манифеста подключения `.conventions.toml`, разделы topics/prefixes с live
  и retired
2026-07-26 15:27:55 +03:00

12 KiB
Raw Blame History

topic, prefix
topic prefix
app-directories DIRS

Категории директорий приложения

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

Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки ПОЧЕМУ и МЕХАНИЗИРОВАНО толкуются как описано в языке конвенций версии 1 — тогда и только тогда, когда написаны заглавными.

Область действия

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

Правила

DIRS-1. Записываемые пути разложены по трём категориям

ДОЛЖЕН. Каждая директория, в которую пишет приложение или деплой, относится к одной из трёх категорий:

Категория Директория Создаёт Потеря содержимого В бэкапе
DIRS-1.1 конфигурация config/ деплой восстанавливается прогоном деплоя нет
DIRS-1.2 данные data/ приложение невосполнима да
DIRS-1.3 кеш cache/ приложение приложение перегенерирует нет

Имена в таблице — умолчание для случая «одна директория на категорию».

ПОЧЕМУ. Все дальнейшие решения — что попадает в бэкап (DIRS-4), что можно снести при нехватке места, что переживает переезд на другой диск — читаются из категории, а не выясняются по коду приложения. Без единой классификации каждое такое решение принимается заново и каждый раз чуть по-другому, а цена ошибки несимметрична: лишний кеш в снапшоте стоит места, потерянные данные не стоят ничего, потому что их больше нет.

DIRS-2. Категория может состоять из нескольких директорий

ДОПУСКАЕТСЯ. Директорий в категории столько, сколько нужно раскладке; принадлежность к категории задаётся не именем, а участием в списке бэкапа.

ПОЧЕМУ. Явное разрешение снимает вопрос, не читается ли DIRS-1 как «ровно три директории». Крупные файлы отделяют от базы, чтобы двигать их между дисками независимо (media/, uploads/ — та же категория «данные», что и data/); запрет на такое деление вынуждал бы либо держать всё на одном диске, либо выводить директорию из-под категорий вовсе. Категорию нельзя задавать именем ровно поэтому: имён в категории несколько, и выбираются они по содержимому.

DIRS-3. Данные и кеш разделяются по тесту на пересоздание

ДОЛЖЕН. Записываемый путь относят к данным или к кешу по содержимому:

Что лежит Категория
DIRS-3.1 база, загруженные файлы, сгенерированные артефакты данные
DIRS-3.2 миниатюры, распакованные ассеты, кеш внешних ответов, перестраиваемые индексы кеш
DIRS-3.3 спорный случай rm -rf и запуск приложения заново: поднялось и наверстало само — кеш; не поднялось или поднялось пустым — данные

ПОЧЕМУ. Без внешнего теста граница проводится по ощущению «жалко потерять», а оно смещено в одну сторону: дорогой в пересборке кеш переезжает в данные и раздувает каждый снапшот. Дорого ≠ невосполнимо, и разделяет эти два свойства именно способность приложения пересоздать содержимое. Обратная ошибка — данные, названные кешем, — тестом обнаруживается в тот же момент, но дёшево: при попытке пересоздать, а не при попытке восстановить.

DIRS-4. В бэкап идут данные, и только они

ДОЛЖЕН. Директории категории «данные» — в списке бэкапа; конфигурация и кеш — нет.

ПОЧЕМУ. Кеш раздувает снапшот содержимым, которое приложение восстановит само. Конфигурацию бэкапить не только незачем, но и вредно: там лежат секреты, а бэкапы уезжают в облако — источник истины для конфигурации остаётся в репозитории и хранилище секретов, а не в снапшоте. Ошибка в другую сторону дороже: директория данных, не попавшая в список, обнаруживается в единственный момент, когда исправить её уже нечем.

DIRS-5. Список бэкапа ссылается на те же пути, что и создание директорий

ДОЛЖЕН. Список выводится из категорий по DIRS-4 и ссылается на те же объявления путей, по которым директории создаются, а не набирается независимо.

Объявление пути — то единственное место, где путь директории записан буквально: переменная деплоя, константа, поле конфигурации. Всё остальное на него ссылается.

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

DIRS-6. Способ попадания данных в бэкап зависит от того, кто отвечает за консистентность

ДОЛЖЕН. Способ выбирается по тому, самодостаточны ли файлы на диске:

Данные В бэкап
DIRS-6.1 файлы самодостаточны на любой момент времени копированием
DIRS-6.2 консистентность обеспечивает только сама СУБД дампом: бэкапится директория дампов, сырой каталог базы — нет

ПОЧЕМУ. Файловый снапшот работающей СУБД не гарантирует консистентности: скопированный каталог может не восстановиться, и узнают об этом при восстановлении. Директория дампов — тоже данные, просто производные, поэтому DIRS-4 покрывает её без оговорок. Сырой каталог базы из списка при этом исключается: он удваивает объём снапшота и добавляет к надёжной копии заведомо ненадёжную.

DIRS-7. Способ выбирается при заведении приложения

ДОЛЖЕН. Решение «копировать или дампить» (DIRS-6) принимается, когда приложение заводят.

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

DIRS-8. Приложение разводит записываемые пути по категориям

ДОЛЖЕН. Конфигурация приложения задаёт отдельные пути для данных и для кеша, а не один каталог на всё.

ПОЧЕМУ. Снаружи категория определяется только тогда, когда разным категориям соответствуют разные директории. Всё, сложенное в один каталог, заставляет составлять список бэкапа вручную, читая код приложения, — и пересматривать его при каждом обновлении, потому что новый подкаталог появляется молча. Приложение, которое не умеет разделять, тем самым дефектно; раскладка под этот дефект не подстраивается.

DIRS-9. Приложение не пишет в директорию конфигурации

НЕ ДОЛЖЕН. Записываемые пути приложения не указывают внутрь конфигурации.

ПОЧЕМУ. Конфигурация восстанавливается прогоном деплоя (DIRS-1.1), поэтому всё, что приложение туда записало, следующий деплой затирает без предупреждения. Вдобавок директория конфигурации может быть подключена только на чтение — тогда запись отказывает в рантайме. Ни то ни другое не видно в момент, когда приложение настраивают.