{}const=>[]async()letfn</>var

Процедуры и функции в 1С: как писать код, который не стыдно поддерживать

Разбираемся, как правильно писать процедуры и функции в 1С: именование, параметры, обработка ошибок, принцип единственной ответственности. Практические примеры кода, который легко читать и поддерживать.

К

Kodik

著者

calendar_today
schedule5分で読める

Каждый, кто работал с чужим кодом в 1С, хотя бы раз испытывал то самое чувство: открываешь модуль, а там процедура на 800 строк с названием «ОбработатьДанные». Без комментариев. С переменными «а», «б» и «Врем». И ты понимаешь — через полгода твой собственный код может вызвать у кого-то точно такие же эмоции.

Давайте разберёмся, как писать процедуры и функции в 1С так, чтобы код оставался читаемым, предсказуемым и удобным для поддержки — даже спустя годы.

Процедура vs функция: в чём принципиальная разница

На первый взгляд всё просто: функция возвращает значение, процедура — нет. Но за этой простотой скрывается важный принцип проектирования.

Функция — это вопрос. Ты спрашиваешь систему о чём-то и получаешь ответ. Она не должна менять состояние базы данных, не должна выводить сообщения пользователю. Она просто считает и возвращает результат.

Функция РассчитатьСуммуСоСкидкой(Сумма, ПроцентСкидки)
    Возврат Сумма - Сумма * ПроцентСкидки / 100;
КонецФункции

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

Процедура ЗаполнитьЦеныВТабличнойЧасти(ТабличнаяЧасть, ТипЦен)
    Для Каждого Строка Из ТабличнаяЧасть Цикл
        Строка.Цена = ПолучитьЦенуНоменклатуры(Строка.Номенклатура, ТипЦен);
        Строка.Сумма = Строка.Количество * Строка.Цена;
    КонецЦикла;
КонецПроцедуры

Если вы ловите себя на том, что функция и записывает данные, и возвращает результат — это сигнал, что стоит разделить логику на две части.

🔥 10万人以上の学生が参加中

理論を読むのに疲れた?
コーディングの時間だ!

Kodik — 実践でプログラミングを学ぶアプリ。AIメンター、インタラクティブなレッスン、実際のプロジェクト。

🤖 AI 24時間
🎓 修了証
💰 無料
🚀 始める
今日参加

Именование: ваш код читают люди, а не компилятор

Имя процедуры или функции — это контракт с тем, кто будет читать код после вас. Хорошее имя делает комментарий ненужным.

Плохие имена — это имена, которые ничего не говорят о назначении:

// Что обрабатывает? Какие данные? Зачем?
Процедура ОбработатьДанные()

// Что именно проверяет? Какой документ?
Функция Проверка(Док)

// "Выполнить" — самое бесполезное слово в названии
Процедура ВыполнитьОперацию()

Хорошие имена содержат глагол и описывают конкретное действие:

Процедура РассчитатьСебестоимостьПоПартиям(ДокументОбъект)

Функция ПолучитьОстатокНоменклатурыНаСкладе(Номенклатура, Склад, Дата)

Функция ЕстьПравоНаСкидку(Контрагент, СуммаЗаказа)

Несколько правил, которые реально работают:

  • Функции-вопросы начинайте со слов «Получить», «Рассчитать», «Найти», «Есть» (для булевых значений).

  • Процедуры-команды начинайте со слов «Заполнить», «Записать», «Отправить», «Удалить», «Установить».

  • Не бойтесь длинных имён. «ПолучитьСуммуОплатыЗаПериодПоКонтрагенту» — это понятнее, чем «ПолучитьСумму».

Параметры: меньше — лучше

Если у вашей процедуры больше пяти параметров — что-то пошло не так. Это не просто вопрос эстетики: большое количество параметров означает, что процедура делает слишком много или что данные плохо структурированы.

Проблема:

Процедура СоздатьЗаказ(Контрагент, Склад, Менеджер, ДатаОтгрузки, 
    ТипЦен, ВалютаДокумента, Организация, Комментарий, Приоритет)
    // ...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 разработчиков, где всегда можно задать вопрос, получить поддержку и найти единомышленников. Присоединяйтесь — вместе расти в профессии гораздо проще!

🎯先延ばしをやめよう

記事は気に入った?
実践の時間だ!

Kodikでは読むだけでなく、すぐにコードを書く。理論 + 実践 = 本当のスキル。

即座に実践
🧠AIがコードを説明
🏆修了証

登録不要 • カード不要