Каждый, кто работал с чужим кодом в 1С, хотя бы раз испытывал то самое чувство: открываешь модуль, а там процедура на 800 строк с названием «ОбработатьДанные». Без комментариев. С переменными «а», «б» и «Врем». И ты понимаешь — через полгода твой собственный код может вызвать у кого-то точно такие же эмоции.
Давайте разберёмся, как писать процедуры и функции в 1С так, чтобы код оставался читаемым, предсказуемым и удобным для поддержки — даже спустя годы.
Процедура vs функция: в чём принципиальная разница
На первый взгляд всё просто: функция возвращает значение, процедура — нет. Но за этой простотой скрывается важный принцип проектирования.
Функция — это вопрос. Ты спрашиваешь систему о чём-то и получаешь ответ. Она не должна менять состояние базы данных, не должна выводить сообщения пользователю. Она просто считает и возвращает результат.
Функция РассчитатьСуммуСоСкидкой(Сумма, ПроцентСкидки)
Возврат Сумма - Сумма * ПроцентСкидки / 100;
КонецФункцииПроцедура — это команда. Ты просишь систему что-то сделать: записать документ, отправить письмо, заполнить табличную часть. Она выполняет действие и не возвращает результат.
Процедура ЗаполнитьЦеныВТабличнойЧасти(ТабличнаяЧасть, ТипЦен)
Для Каждого Строка Из ТабличнаяЧасть Цикл
Строка.Цена = ПолучитьЦенуНоменклатуры(Строка.Номенклатура, ТипЦен);
Строка.Сумма = Строка.Количество * Строка.Цена;
КонецЦикла;
КонецПроцедурыЕсли вы ловите себя на том, что функция и записывает данные, и возвращает результат — это сигнал, что стоит разделить логику на две части.
Именование: ваш код читают люди, а не компилятор
Имя процедуры или функции — это контракт с тем, кто будет читать код после вас. Хорошее имя делает комментарий ненужным.
Плохие имена — это имена, которые ничего не говорят о назначении:
// Что обрабатывает? Какие данные? Зачем?
Процедура ОбработатьДанные()
// Что именно проверяет? Какой документ?
Функция Проверка(Док)
// "Выполнить" — самое бесполезное слово в названии
Процедура ВыполнитьОперацию()Хорошие имена содержат глагол и описывают конкретное действие:
Процедура РассчитатьСебестоимостьПоПартиям(ДокументОбъект)
Функция ПолучитьОстатокНоменклатурыНаСкладе(Номенклатура, Склад, Дата)
Функция ЕстьПравоНаСкидку(Контрагент, СуммаЗаказа)Несколько правил, которые реально работают:
Функции-вопросы начинайте со слов «Получить», «Рассчитать», «Найти», «Есть» (для булевых значений).
Процедуры-команды начинайте со слов «Заполнить», «Записать», «Отправить», «Удалить», «Установить».
Не бойтесь длинных имён. «ПолучитьСуммуОплатыЗаПериодПоКонтрагенту» — это понятнее, чем «ПолучитьСумму».
Параметры: меньше — лучше
Если у вашей процедуры больше пяти параметров — что-то пошло не так. Это не просто вопрос эстетики: большое количество параметров означает, что процедура делает слишком много или что данные плохо структурированы.
Проблема:
Процедура СоздатьЗаказ(Контрагент, Склад, Менеджер, ДатаОтгрузки,
ТипЦен, ВалютаДокумента, Организация, Комментарий, Приоритет)
// ...40 строк создания документа
КонецПроцедурыРешение — структура:
Функция НовыеПараметрыЗаказа()
Параметры = Новый Структура;
Параметры.Вставить("Контрагент");
Параметры.Вставить("Склад");
Параметры.Вставить("Менеджер");
Параметры.Вставить("ДатаОтгрузки", ТекущаяДата());
Параметры.Вставить("ТипЦен");
Параметры.Вставить("Валюта");
Параметры.Вставить("Организация");
Параметры.Вставить("Комментарий", "");
Параметры.Вставить("Приоритет", 0);
Возврат Параметры;
КонецФункции
Процедура СоздатьЗаказ(ПараметрыЗаказа)
// Чисто, понятно, расширяемо
КонецПроцедурыПаттерн «функция-конструктор параметров» — один из самых полезных приёмов в 1С. Он позволяет добавлять новые параметры, не ломая существующие вызовы.
Принцип единственной ответственности
Это, пожалуй, самый важный принцип, который нарушается в коде 1С чаще всего. Одна процедура должна делать одну вещь.
Антипаттерн — «процедура-комбайн»:
Процедура ОбработатьДокумент(ДокументОбъект)
// Проверка заполнения — 50 строк
// Расчёт сумм — 30 строк
// Формирование движений — 100 строк
// Отправка уведомления — 20 строк
// Обновление статуса контрагента — 25 строк
// Логирование — 15 строк
КонецПроцедурыЭту процедуру невозможно протестировать, сложно отладить, и когда что-то сломается — а оно сломается — вы будете перечитывать все 240 строк.
Правильный подход:
Процедура ОбработатьДокумент(ДокументОбъект)
ОшибкиЗаполнения = ПроверитьЗаполнениеДокумента(ДокументОбъект);
Если ОшибкиЗаполнения.Количество() > 0 Тогда
ВывестиОшибкиЗаполнения(ОшибкиЗаполнения);
Возврат;
КонецЕсли;
РассчитатьСуммыДокумента(ДокументОбъект);
СформироватьДвижения(ДокументОбъект);
ОтправитьУведомление(ДокументОбъект);
ОбновитьСтатусКонтрагента(ДокументОбъект.Контрагент);
КонецПроцедурыТеперь каждая операция изолирована. Если нужно изменить логику расчёта сумм — вы точно знаете, где искать. Если сломалась отправка уведомлений — не нужно перечитывать код расчёта.
Обработка ошибок: не прячьте проблемы
Одна из самых распространённых ошибок — молчаливое проглатывание исключений.
Как не надо:
Процедура ОтправитьДанныеВоВнешнююСистему(Данные)
Попытка
// ...отправка
Исключение
// Пусто. Ну не отправилось и ладно.
КонецПопытки;
КонецПроцедурыЧерез три месяца приходит бухгалтер и говорит: «Данные не уходят с прошлого лета». А в логах — тишина.
Как правильно:
Процедура ОтправитьДанныеВоВнешнююСистему(Данные)
Попытка
// ...отправка
Исключение
ТекстОшибки = ОписаниеОшибки();
ЗаписьЖурналаРегистрации("ИнтеграцияВнешняяСистема",
УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
ВызватьИсключение "Не удалось отправить данные: " + ТекстОшибки;
КонецПопытки;
КонецПроцедурыЗолотое правило: ловите только те ошибки, которые знаете как обработать. Остальные — логируйте и пробрасывайте выше.
Экспорт: не делайте всё публичным
В 1С есть соблазн поставить «Экспорт» на каждую функцию — а вдруг пригодится. Это приводит к тому, что модуль превращается в свалку, где невозможно понять, что является публичным API, а что — внутренней кухней.
Правило простое: процедура или функция получает модификатор «Экспорт» только тогда, когда она действительно нужна другим модулям. Всё остальное — приватная реализация, которую вы вольны менять как угодно.
// Это публичный API модуля — хорошо задокументировано, стабильный контракт
Функция РассчитатьСтоимостьДоставки(Параметры) Экспорт
// ...
КонецФункции
// Это внутренняя деталь реализации — без экспорта
Функция ПолучитьТарифнуюЗону(АдресДоставки)
// ...
КонецФункцииВозвращаемые значения: будьте предсказуемы
Функция должна всегда возвращать значение одного типа. Если функция может вернуть строку, число или Неопределено в зависимости от ситуации — каждый вызывающий код превращается в детектив.
Плохо:
Функция НайтиКонтрагента(ИНН)
Запрос = Новый Запрос("...");
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат Ложь; // Иногда булево
КонецЕсли;
Возврат Результат.Выгрузить()[0].Контрагент; // Иногда ссылка
КонецФункцииХорошо:
// Возвращает ВСЕГДА ссылку. Пустая ссылка = не нашли.
Функция НайтиКонтрагентаПоИНН(ИНН)
Запрос = Новый Запрос("...");
Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
Возврат Справочники.Контрагенты.ПустаяСсылка();
КонецЕсли;
Возврат Результат.Выгрузить()[0].Контрагент;
КонецФункцииКомментарии: объясняйте «зачем», а не «что»
Хороший код почти не нуждается в комментариях — он сам себя объясняет через понятные имена. Но иногда комментарии необходимы: когда нужно объяснить неочевидное бизнес-правило или причину нестандартного решения.
Бесполезный комментарий:
// Получаем дату
Дата = ТекущаяДата();Полезный комментарий:
// Используем дату начала следующего месяца, потому что тарифы
// обновляются первого числа и биллинг должен считать по новым ценам
ДатаРасчёта = НачалоМесяца(ДобавитьМесяц(ТекущаяДата(), 1));Для экспортных функций обязательно добавляйте описание параметров и возвращаемого значения. Это не формальность — это документация вашего API:
// Рассчитывает стоимость доставки с учётом зоны и веса.
//
// Параметры:
// АдресДоставки - Строка - полный адрес в формате ФИАС
// ВесГрамм - Число - вес отправления в граммах
//
// Возвращаемое значение:
// Число - стоимость доставки в рублях, 0 если доставка бесплатная
//
Функция РассчитатьСтоимостьДоставки(АдресДоставки, ВесГрамм) ЭкспортЕсли вы хотите углубить свои знания в программировании и изучить современные технологии — загляните в приложение Кодик. Это образовательная платформа с курсами по Python, JavaScript, HTML, CSS и другим языкам, где сложные вещи объясняются простым языком, а теория сразу подкрепляется практикой.
А в нашем Telegram-канале вас ждёт дружное сообщество из более чем 2000 разработчиков, где всегда можно задать вопрос, получить поддержку и найти единомышленников. Присоединяйтесь — вместе расти в профессии гораздо проще!
