AZ-структурирование файлов исходного кода
Дата публикации: 2022-11-16AZ-структурирование — мой способ организовать исходные файлы в проектах, где код хранится в файловой системе: Java, PHP, JavaScript/Node.js. Его цель — сделать рефакторинг предсказуемее.
Почему это нужно
Код чаще меняют, чем пишут с нуля. В веб-разработке требования уточняются по ходу дела: мы видим направление, но не все детали. Поэтому на каждой итерации добавляем, удаляем и меняем код. Это не недостаток, а нормальный режим работы.
Главная сложность рефакторинга — понять границы распространения изменений. Инкапсуляция в ООП решает именно эту задачу.
Обычные границы
Большой проект состоит из пакетов и файлов. В ES-модуле код без export можно менять свободно внутри файла. Экспортируемый код потенциально используют где угодно в проекте. У npm-пакета публичную поверхность задают main или exports; всё остальное — внутреннее дело пакета.
Но иногда границы нужны меньше пакета. Исходники обычно раскладывают по роли или по предметной области. Я сочетаю оба подхода: сначала роль, затем функция.
src/
Back/Mod/RDb/
Front/Mod/Store/Ui/
Lib/Route/Home.mjs
Shared/Dto/
Первый уровень устойчивее и зависит от фреймворка; второй меняется вместе с бизнес-задачами. У файла могут быть глобальные границы — его используют во всём пакете, или локальные — изменения не затрагивают другие файлы.
A-структура
Сложность побеждают декомпозицией. Предположим, крупная модель лежит в Mod/Settings.mjs. Её части логично вынести рядом:
Mod/
Settings/
Payments.mjs
Profile.mjs
Security.mjs
Settings.mjs
Пара папки Settings/ и файла Settings.mjs уже подсказывает, что это одна модель с деталями. Но если структура и так занята несколькими моделями, я помечаю приватные фрагменты подкаталогом A/:
Mod/
Settings/
A/
Snippet1.mjs
Snippet2.mjs
Payments.mjs
Profile.mjs
Settings.mjs
Файлы из Settings/A/ — части Settings.mjs. Корневой файл можно импортировать в пакете, а содержимое A/ предназначено только для него. Так уровень файлов получает собственную private-область, а границы изменений становятся очевиднее. A-структура может вкладываться: Route/Settings/A/Profile/A/Password/Change/A/Evt/Change.mjs.
Z-структура
Иногда вспомогательный код относится не к одному файлу, а к группе файлов — это «библиотека для группы». Для неё я использую каталог Z/:
Cli/
Data/
Z/ListTables.mjs
Export.mjs
Import.mjs
Init.mjs
Изменения в Cli/Data/Z/ListTables.mjs не должны выходить за границы Cli/Data/.
Вывод
Если обозначать private-области прямо структурой файлов, легче видеть, куда распространяется изменение. A/ означает детали одного корневого файла, Z/ — общие детали небольшой группы. Это не правило языка и не замена хорошему API, а договорённость команды, заметно помогающая при рефакторинге больших проектов.