При разработке конфигураций на платформе 1С:Предприятие 8 крайне важно соблюдать стандарты оформления кода, особенно в части структуры программных модулей. Часто у разработчиков возникает вопрос: почему экспортные методы встречаются как в разделе СлужебныйПрограммныйИнтерфейс, так и в разделе СлужебныеПроцедурыИФункции? Кажется, что границы между ними размыты, но на самом деле существует четкая архитектурная логика. В этой статье мы подробно разберем критерии разделения методов, определим границы библиотек и выясним, как автоматизировать проверку структуры кода.
Согласно стандартам разработки, объемные модули (особенно общие модули) рекомендуется разбивать на подразделы по функциональному признаку, используя готовые шаблоны для применения стандартов. Рассмотрим стандартную иерархию областей:
Рассмотрим подробнее каждый из служебных разделов, чтобы понять логику размещения кода.
Этот раздел предназначен для модулей, являющихся частью крупной функциональной подсистемы или библиотеки (например, Библиотека Стандартных Подсистем — БСП). Проанализируем ситуацию: представим, что у нас есть библиотека "Интеграция", состоящая из подсистем ОбменДанными и РаботаСВнешнимиСервисами.
Если методу из модуля подсистемы ОбменДанными нужно вызвать функционал из модуля РаботаСВнешнимиСервисами, но при этом данный функционал не должен быть доступен конечному прикладному программисту, мы помещаем его в СлужебныйПрограммныйИнтерфейс (это часто применяется при реализации паттерна Стратегия).
Ключевой критерий: метод доступен "своим" (разработчикам этой же библиотеки), но закрыт для "чужих".
Этот раздел традиционно считается местом для приватных методов модуля (без ключевого слова Экспорт). Однако стандарт допускает наличие экспортных методов и здесь. Разберем, в каких случаях это необходимо:
Экспорт, но остается в разделе СлужебныеПроцедурыИФункции.Выполнить(), в фоновом задании или как обработчик оповещения, но он не является интерфейсным решением.Чтобы понять, относится ли вызов к "внутреннему" или "внешнему", нужно четко определить состав библиотеки. В современных конфигурациях 1С библиотека — это программная сущность, регистрирующая себя в системе. Выясним, как найти эти границы программно:
Проанализируем состав регистра сведений ВерсииПодсистем в режиме "1С:Предприятие". В колонке "Имя подсистемы" перечислены все зарегистрированные библиотеки (БСП, БИП, БПО и сама конфигурация). Чтобы увидеть это в коде, найдем общий модуль ПодсистемыКонфигурацииПереопределяемый. В нем расположена процедура ПриДобавленииПодсистем:
Процедура ПриДобавленииПодсистем(СписокПодсистем) Экспорт
СписокПодсистем.Добавить("СтандартныеПодсистемы");
СписокПодсистем.Добавить("БиблиотекаИнтеграцииГосСистем");
КонецПроцедуры
Каждая из этих строк определяет корень "дерева", которое считается одной библиотекой. Все общие модули, входящие в эти ветки метаданных, подчиняются правилам СлужебногоПрограммногоИнтерфейса этой библиотеки.
Разница между разделами также заключается в уровне обязательств разработчика перед пользователями кода. Рассмотрим эту иерархию стабильности:
Для соблюдения этих правил рекомендуется использовать инструменты статического анализа, такие как 1С:Автоматизированная проверка конфигураций (АПК) или 1C:Enterprise Development Tools (EDT). Эти инструменты анализируют названия областей (#Область) и проверяют:
СлужебныйПрограммныйИнтерфейс, система выдаст предупреждение.СлужебныеПроцедурыИФункции вызывается за пределами своей подсистемы, это считается архитектурной ошибкой.Таким образом, использование правильных имен областей — это не просто украшение кода, а способ управления видимостью и надежностью вашей системы. Выясним практическое правило: если вы сомневаетесь, куда поместить экспортный метод, ответьте на вопрос: "Кто будет его вызывать?". Если только объекты вашей маленькой подсистемы — это СлужебныеПроцедурыИФункции. Если коллеги, разрабатывающие другие части вашей библиотеки — это СлужебныйПрограммныйИнтерфейс. Если весь мир — это ПрограммныйИнтерфейс.
Рассмотрим, как это выглядит в коде правильно структурированного модуля:
#Область ПрограммныйИнтерфейс
// Безопасно для использования везде.
Процедура РассчитатьНалог(Данные) Экспорт
// ...
КонецПроцедуры
#КонецОбласти
#Область СлужебныйПрограммныйИнтерфейс
// Только для вызова из других модулей этой же библиотеки.
// Например, из подсистемы "Зарплата" в подсистему "УчетЗатрат".
Процедура ЗарегистрироватьИзменениеВРегистре(Параметры) Экспорт
// ...
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
// Экспортный, потому что нужен для формы документа этой подсистемы.
// Но другие подсистемы его вызывать не должны.
Процедура ЗаполнитьРеквизитыПриИзменении(Форма) Экспорт
ЗаполнитьВнутренниеПараметры(Форма);
КонецПроцедуры
// Чисто внутренняя логика модуля.
Процедура ЗаполнитьВнутренниеПараметры(Форма)
// ...
КонецПроцедуры
#КонецОбласти
Соблюдение такой структуры позволяет поддерживать чистоту архитектуры, упрощает обновление конфигураций и позволяет инструментам анализа кода вовремя предупреждать вас о потенциальных проблемах с инкапсуляцией данных.