MODX платит огромную постоянную архитектурную цену за функциональность, которой большинство проектов почти не пользуется
Это не моральная оценка и не попытка объявить сложность чем-то плохим сама по себе. Речь о вполне конкретной инженерной проблеме: насколько оправдана стоимость архитектурной возможности относительно того, как часто и насколько глубоко ей реально пользуются.
В MODX эта проблема особенно хорошо видна на системе контекстов и политик доступа.
Идея была рациональной
Contexts в MODX задумывались как способ разделять приложение на независимые области: web, mgr, дополнительные сайты, языковые версии, закрытые разделы. У каждого контекста могли быть свои настройки, политики, пользователи, права, resource map и runtime-состояние.
Одновременно MODX строил универсальную ACL-модель. Права можно было задавать не только на ресурсы, но и на категории элементов, сами элементы, TV, Media Sources, namespaces, меню и другие системные сущности.
Для этого в ядре существовал и частично до сих пор существует большой набор специализированных моделей и таблиц:
modx_access_contextmodx_access_resourcesmodx_access_resource_groupsmodx_access_categorymodx_access_elementsmodx_access_templatevarsmodx_access_media_sourcemodx_access_namespacemodx_access_menus- исторически —
modx_access_actions,modx_access_actiondomи другие связанные сущности.
С инженерной точки зрения это мощная идея: один общий security framework можно применять к очень разным объектам.
Но универсальность ушла слишком глубоко в ядро
Проблема начинается в тот момент, когда эта гибкость перестаёт быть опциональной надстройкой и становится фундаментальной частью runtime-модели.
Доступ к объектам MODX связан с policies, user groups, roles, authority, target objects и конкретным context. Любой сложный security scenario быстро превращается в многомерную схему:
User
× User Group
× Role / authority
× Context
× Policy
× Resource Group
× Element Category
× Media Source
× target object
Сам по себе такой граф ещё можно оправдать, если он широко используется. Но на практике подавляющее большинство проектов живёт гораздо проще: один web, один mgr, один администратор, несколько редакторов, иногда Resource Groups и почти никогда — вся полнота object-level ACL по всем типам сущностей.
При этом ядро всё равно обязано поддерживать всю эту модель постоянно.
Контекст оказался слишком "толстой" абстракцией
Контекст в MODX — это не просто идентификатор сайта или набор настроек. В него завязаны:
- settings;
- policies;
- resource maps;
- aliases;
- plugins;
- security state;
- authentication state;
- cache;
- context-specific runtime.
Даже пользовательская идентичность внутри одной PHP-сессии может быть разной в разных context:
{
"modx.user.contextTokens": {
"mgr": 1,
"web": 642
}
}
То есть одна физическая сессия допускает ситуацию, когда в Manager пользователь один, а на frontend — другой.
Технически это гибко. Практически — это добавляет ещё один слой логики, который большинство разработчиков никогда не использует осознанно, но который остаётся частью core semantics.
Почему всё это пришлось агрессивно кешировать
Полный пересчёт effective permissions на каждом обращении к объекту был бы слишком дорогим. Поэтому MODX вынужден кешировать вычисленное security state на нескольких уровнях.
Jason Coward, главный архитектор MODX Revolution, прямо объяснял, что access policies кешируются "for obvious performance reasons" как на стороне target objects, так и в пользовательской session.
Отсюда в сессии появляются структуры вроде:
modx.user.*.attributes
modx.user.*.resourceGroups
modx.user.contextTokens
Контексты, в свою очередь, имеют собственный cache, куда попадают settings, policies и другие context-specific данные. Объекты могут иметь собственный policy cache.
Получается закономерная цепочка:
богатая ACL-модель
→ дорогой permission resolution
→ кеширование effective state
→ session cache + context cache + object cache
→ распределённое security state
→ сложная invalidation
То есть кеширование здесь не опровержение тяжести системы, а прямое следствие этой тяжести.
Цена производительности превращается в цену сопровождения
Когда effective permissions оказываются размазаны между базой, пользовательской session, context cache и object cache, изменение прав становится уже не просто изменением записи в ACL.
Отсюда исторически знакомые MODX-процедуры:
Flush Permissions
Flush Sessions
очистить cache
перелогиниться
Это не случайная UX-особенность. Это следствие того, что security state пришлось денормализовать ради производительности.
Редко используемые таблицы всё равно остаются частью системы
Многие modx_access_* таблицы в типичных проектах пустые или почти пустые, потому что конечные разработчики просто не используют соответствующие возможности.
Но пустая таблица не означает нулевую архитектурную стоимость.
Пока соответствующая feature существует в core, нужно поддерживать:
- модель;
- schema;
- связи;
- loaders;
- processors;
- permission resolution;
- cache semantics;
- backward compatibility;
- миграции;
- тестирование;
- диагностику edge cases.
То есть стоимость платится не количеством строк в таблице, а самим фактом существования subsystem.
Цена компетенции
Есть ещё одна цена, которую часто недооценивают: требования к человеку, который способен безопасно менять ядро.
Чтобы разобраться в проблеме auth, ACL или cache в MODX, недостаточно знать PHP и даже недостаточно хорошо знать публичный API MODX.
Нужно понимать:
- contexts;
- user sessions;
- contextTokens;
- policies;
- policy templates;
- roles и authority;
- User Groups;
- Resource Groups;
- Element Category ACL;
- Media Source ACL;
- object lifecycle;
- processors;
- xPDO hydration;
- context cache;
- object cache;
- permission invalidation;
- backward compatibility старых Extras.
И чем больше редко используемых возможностей остаётся в ядре, тем выше минимальный уровень компетенции нужен для человека, который способен принять или отклонить изменение в core.
Это напрямую влияет уже не только на код, но и на развитие проекта: тикеты и pull requests копятся быстрее, чем небольшая группа людей, реально понимающих все последствия изменений, успевает их разбирать.
Сильная идея не обязана жить вечно
Важно не перепутать критику результата с отрицанием исходной идеи.
Универсальная ACL-модель MODX была амбициозной и во многих сценариях действительно мощной. Возможность тонко разграничивать доступ к ресурсам, элементам, файловым источникам и разным context — реальная функциональность, а не фикция.
Но архитектурная возможность должна периодически проходить повторную проверку на ценность.
Здоровая эволюция платформы выглядит примерно так:
идея
→ реализация
→ использование
→ оценка реального спроса
→ укрепление удачного
→ упрощение или удаление невостребованного
Если система умеет только добавлять возможности, но почти не умеет от них отказываться, она начинает накапливать не просто старый код, а постоянные обязательства по поддержке старых архитектурных гипотез.
Именно здесь появляется legacy не как возраст, а как неспособность системы забывать.
Почему это важно обсуждать по фактам
Разговоры о legacy часто быстро превращаются в спор о репутации технологий, команд и отдельных людей. Это почти всегда ухудшает качество анализа.
Общий принцип я отдельно разбираю в концепте AI as reputation arbiter: оценивать стоит наблюдаемые механизмы, последствия и проверяемые факты, а не пытаться автоматически назначать кому-то статус "правильного" или "неправильного" участника дискуссии.
В случае MODX вопрос можно сформулировать без морализации:
Оправдана ли постоянная архитектурная стоимость сложной multicontext ACL-системы частотой и глубиной её реального использования?
Мой вывод — во многих практических сценариях уже давно нет.
Именно поэтому MODX сегодня платит огромную постоянную архитектурную цену за функциональность, которой большинство проектов почти не пользуется.