- 11 файлов разобраны на нумерованные правила: 220 правил в каноне, у каждого модальность и обязательный блок «Почему» - классифицирующие места оформлены таблицами, файловый статус снят отовсюду, локальные регионы сохранены под прежними именами
155 lines
12 KiB
Markdown
155 lines
12 KiB
Markdown
# Категории директорий приложения
|
|
|
|
Всё, что приложение пишет на диск, делится на три категории по принципу
|
|
создания и ценности содержимого: конфигурация, данные, кеш. Категория сразу
|
|
отвечает на два вопроса, которые иначе выясняются чтением кода приложения:
|
|
**кто создаёт** содержимое и **что будет, если его потерять**. Из категорий
|
|
механически выводится состав бэкапа. Форма записи — `common/language.md`.
|
|
|
|
## Область действия
|
|
|
|
Раскладка меняется вместе с миграцией данных, поэтому правила
|
|
распространяются на **новые приложения**; существующие переезжают по мере
|
|
касания, отдельной кампанией не переписываются. Разделять данные и кеш
|
|
задним числом имеет смысл тогда, когда кеш заметен по объёму в бэкапе, а не
|
|
ради самой схемы.
|
|
|
|
## Правила
|
|
|
|
### R1. Записываемые пути разложены по трём категориям
|
|
|
|
**ДОЛЖЕН.** Каждая директория, в которую пишет приложение или деплой,
|
|
относится к одной из трёх категорий:
|
|
|
|
| № | Категория | Директория | Создаёт | Потеря содержимого | В бэкапе |
|
|
|---|---|---|---|---|---|
|
|
| R1.1 | конфигурация | `config/` | деплой | восстанавливается прогоном деплоя | нет |
|
|
| R1.2 | данные | `data/` | приложение | невосполнима | да |
|
|
| R1.3 | кеш | `cache/` | приложение | приложение перегенерирует | нет |
|
|
|
|
Имена в таблице — умолчание для случая «одна директория на категорию».
|
|
|
|
**Почему.** Все дальнейшие решения — что попадает в бэкап (R4), что можно
|
|
снести при нехватке места, что переживает переезд на другой диск —
|
|
читаются из категории, а не выясняются по коду приложения. Без единой
|
|
классификации каждое такое решение принимается заново и каждый раз чуть
|
|
по-другому, а цена ошибки несимметрична: лишний кеш в снапшоте стоит места,
|
|
потерянные данные не стоят ничего, потому что их больше нет.
|
|
|
|
### R2. Категория может состоять из нескольких директорий
|
|
|
|
**ДОПУСКАЕТСЯ.** Директорий в категории столько, сколько нужно раскладке;
|
|
принадлежность к категории задаётся не именем, а участием в списке бэкапа.
|
|
|
|
**Почему.** Явное разрешение снимает вопрос, не читается ли R1 как «ровно
|
|
три директории». Крупные файлы отделяют от базы, чтобы двигать их между
|
|
дисками независимо (`media/`, `uploads/` — та же категория «данные», что и
|
|
`data/`); запрет на такое деление вынуждал бы либо держать всё на одном
|
|
диске, либо выводить директорию из-под категорий вовсе. Категорию нельзя
|
|
задавать именем ровно поэтому: имён в категории несколько, и выбираются они
|
|
по содержимому.
|
|
|
|
### R3. Данные и кеш разделяются по тесту на пересоздание
|
|
|
|
**ДОЛЖЕН.** Записываемый путь относят к данным или к кешу по содержимому:
|
|
|
|
| № | Что лежит | Категория |
|
|
|---|---|---|
|
|
| R3.1 | база, загруженные файлы, сгенерированные артефакты | данные |
|
|
| R3.2 | миниатюры, распакованные ассеты, кеш внешних ответов, перестраиваемые индексы | кеш |
|
|
| R3.3 | спорный случай | `rm -rf` и запуск приложения заново: поднялось и наверстало само — кеш; не поднялось или поднялось пустым — данные |
|
|
|
|
**Почему.** Без внешнего теста граница проводится по ощущению «жалко
|
|
потерять», а оно смещено в одну сторону: дорогой в пересборке кеш
|
|
переезжает в данные и раздувает каждый снапшот. Дорого ≠ невосполнимо, и
|
|
разделяет эти два свойства именно способность приложения пересоздать
|
|
содержимое. Обратная ошибка — данные, названные кешем, — тестом
|
|
обнаруживается в тот же момент, но дёшево: при попытке пересоздать, а не
|
|
при попытке восстановить.
|
|
|
|
### R4. В бэкап идут данные, и только они
|
|
|
|
**ДОЛЖЕН.** Директории категории «данные» — в списке бэкапа; конфигурация и
|
|
кеш — нет.
|
|
|
|
**Почему.** Кеш раздувает снапшот содержимым, которое приложение
|
|
восстановит само. Конфигурацию бэкапить не только незачем, но и вредно: там
|
|
лежат секреты, а бэкапы уезжают в облако — источник истины для
|
|
конфигурации остаётся в репозитории и хранилище секретов, а не в снапшоте.
|
|
Ошибка в другую сторону дороже: директория данных, не попавшая в список,
|
|
обнаруживается в единственный момент, когда исправить её уже нечем.
|
|
|
|
### R5. Список бэкапа ссылается на те же пути, что и создание директорий
|
|
|
|
**ДОЛЖЕН.** Список выводится из категорий по R4 и ссылается на те же
|
|
объявления путей, по которым директории создаются, а не набирается
|
|
независимо.
|
|
|
|
**Почему.** Правило вывода механическое, но применяет его человек или
|
|
шаблон — то есть ошибиться можно. Общая ссылка делает целый класс ошибок
|
|
невозможным: переименование директории отражается в обоих местах сразу.
|
|
Независимо набранный список расходится тихо — ни деплой, ни прогон бэкапа
|
|
на это не жалуются, — и расхождение между тем, что бэкапится, и тем, что
|
|
нужно, проявляется при восстановлении.
|
|
|
|
### R6. Способ попадания данных в бэкап зависит от того, кто отвечает за консистентность
|
|
|
|
**ДОЛЖЕН.** Способ выбирается по тому, самодостаточны ли файлы на диске:
|
|
|
|
| № | Данные | В бэкап |
|
|
|---|---|---|
|
|
| R6.1 | файлы самодостаточны на любой момент времени | копированием |
|
|
| R6.2 | консистентность обеспечивает только сама СУБД | дампом: бэкапится директория дампов, сырой каталог базы — нет |
|
|
|
|
**Почему.** Файловый снапшот работающей СУБД не гарантирует
|
|
консистентности: скопированный каталог может не восстановиться, и узнают
|
|
об этом при восстановлении. Директория дампов — тоже данные, просто
|
|
производные, поэтому R4 покрывает её без оговорок. Сырой каталог базы из
|
|
списка при этом исключается: он удваивает объём снапшота и добавляет к
|
|
надёжной копии заведомо ненадёжную.
|
|
|
|
### R7. Способ выбирается при заведении приложения
|
|
|
|
**ДОЛЖЕН.** Решение «копировать или дампить» (R6) принимается, когда
|
|
приложение заводят.
|
|
|
|
**Почему.** Неверный выбор ничем себя не проявляет, пока бэкап не
|
|
понадобился: прогоны копирования проходят успешно и накапливают снапшоты, из
|
|
которых база не поднимется. Отложить решение — значит принять его по факту
|
|
первой неудачной попытки восстановления, то есть тогда, когда данных уже
|
|
нет.
|
|
|
|
### R8. Приложение разводит записываемые пути по категориям
|
|
|
|
**ДОЛЖЕН.** Конфигурация приложения задаёт отдельные пути для данных и для
|
|
кеша, а не один каталог на всё.
|
|
|
|
**Почему.** Снаружи категория определяется только тогда, когда разным
|
|
категориям соответствуют разные директории. Всё, сложенное в один каталог,
|
|
заставляет составлять список бэкапа вручную, читая код приложения, — и
|
|
пересматривать его при каждом обновлении, потому что новый подкаталог
|
|
появляется молча. Приложение, которое не умеет разделять, тем самым
|
|
дефектно; раскладка под этот дефект не подстраивается.
|
|
|
|
### R9. Приложение не пишет в директорию конфигурации
|
|
|
|
**НЕ ДОЛЖЕН.** Записываемые пути приложения не указывают внутрь
|
|
конфигурации.
|
|
|
|
**Почему.** Конфигурация восстанавливается прогоном деплоя (R1.1), поэтому
|
|
всё, что приложение туда записало, следующий деплой затирает без
|
|
предупреждения. Вдобавок директория конфигурации может быть подключена
|
|
только на чтение — тогда запись отказывает в рантайме. Ни то ни другое не
|
|
видно в момент, когда приложение настраивают.
|
|
|
|
<!-- local:отступления -->
|
|
<!-- /local -->
|
|
|
|
## Связано
|
|
|
|
<!-- local:эталон -->
|
|
<!-- /local -->
|
|
|
|
<!-- local:связано -->
|
|
<!-- /local -->
|