---
title: "AZ-структурирование файлов исходного кода"
description: "Подход к структуре файлов, который отмечает частные части кода и делает границы рефакторинга заметнее."
date: 2022-11-16
---

AZ-структурирование — мой способ организовать исходные файлы в проектах,
где код хранится в файловой системе: Java, PHP, JavaScript/Node.js. Его
цель — сделать рефакторинг предсказуемее.

## Почему это нужно

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

<zoom-img src="/medium/img/8ae5844696ea/image-01.png" alt="Каскадная модель разработки" width="100%"></zoom-img>

<zoom-img src="/medium/img/8ae5844696ea/image-02.png" alt="Спиральная модель разработки" width="100%"></zoom-img>

Главная сложность рефакторинга — понять границы распространения
изменений. Инкапсуляция в ООП решает именно эту задачу.

## Обычные границы

Большой проект состоит из пакетов и файлов. В ES-модуле код без `export`
можно менять свободно внутри файла. Экспортируемый код потенциально
используют где угодно в проекте. У npm-пакета публичную поверхность
задают `main` или `exports`; всё остальное — внутреннее дело пакета.

<zoom-img src="/medium/img/8ae5844696ea/image-03.jpg" alt="Границы распространения изменений в коде" width="100%"></zoom-img>

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

    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, а договорённость команды, заметно помогающая при
рефакторинге больших проектов.
