Куда течет интерфейс?
Разработка - Работа с интерфейсом
Текучий интрефейс (fluent interface) - это способ организации функций в классе таким образом, чтобы их можно было вызывать через точку друг от друга, т.е. использовать цепочки методов
Возможно, если вы сталкивались с автоматизированным тестированием в 1С или OneScript, вроде YaxUnit, xUnitFor1C, Vanessa-Add, Asserts и т.п., то слышали термин "текучие утверждения". Так вот это частный случай текучего интерфейса, когда с его помощью реализуются разнообразные проверки истинности утверждений - например, результатов тестирования:
Ожидаем.Что(НекийМассив.Количество()).Минимум(9);
Но данный механизм применим не только там: любой процесс, предполагающий последовательный вызов методов от одного объекта может стать с ним сильно лучше. И сегодня мы посмотрим, как этого добиться.
ООП и 1С
Как было отмечено в определении текучего интерфейса - его использование подразумевает наличие класса. 1С, как мы знаем, объектно-ориентированным языком не является и эти ваши...

...не реализует. Но выход есть - использовать модуль объекта обработки
Обработка - тоже своего рода класс на минималках. Он не может by design в наследование (создание одного класса от другого с наследованием полей и методов) и рыбополиморфизм (если проблему обработки функцией параметров разных типов вообще можно записать в существующие для языка с динамической типизацией). Но зато может в инкапсуляцию - ограничение доступа ко всякой небезопасной внутрянке благодаря экспортным/неэскпортным переменным и методам, а главное может вернуть саму себя в качестве результата функции чем мы и воспользуемся
Пишем код
Основную идею нашей дальнейшей работы можно описать так: если обычные функции принимают параметры и возвращают результат, то функции в текучем интерфейсе всегда возвращают в качестве результата объект обработки, а настоящий результат, при необходимости, можно записать в переменные.
Для наглядности создадим новую обработку. Она будет представлять из себя некоторый "текучий калькулятор", благодаря которому мы сможем выполнять математические действия одно за другим через точку. Да, очень просто, но зато понятно.
Работать мы будем только в модуле обработки. Для начала, определим переменную для числа-результата и первую функцию - установку начального значения этой переменной
Перем Значение Экспорт;
#Область ПрограммныйИнтерфейс
// Функция - Установить значение
//
// Параметры:
// ЧисловоеЗначение - Число - Начальное значение
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция УстановитьЗначение(Знач ЧисловоеЗначение) Экспорт
Значение = ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Функция ПривестиЧисло(Знач ЧисловоеЗначение) Экспорт
ОТЧ = Новый ОписаниеТипов("Число");
Возврат ОТЧ.ПривестиЗначение(ЧисловоеЗначение);
КонецФункции
#КонецОбласти
Не будем пока подробно на этом останавливаться, а сразу добавим еще две функции: пусть это будут сложение и вычитание.
// Функция - Прибавить
//
// Параметры:
// ЧисловоеЗначение - Число - Значение для прибавления
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция Прибавить(Знач ЧисловоеЗначение) Экспорт
Значение = Значение + ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
// Функция - Отнять
//
// Параметры:
// ЧисловоеЗначение - Число - Значение для вычитания
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция Отнять(Знач ЧисловоеЗначение) Экспорт
Значение = Значение - ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
Отлично - у нас есть некоторый базовый интерфейс. Рассмотрим его:
- Первое, что бросается в глаза - все функции возвращают ЭтотОбъект. Это, как мы уже обсуждали, и позволяет делать цепочки вызовов
- Второе - это переменная значение. Она служит для хранения результата между операциями и получения конечного значения
Попробуем сделать некоторые вычисления, используя нашу обработку
ТекучийКалькулятор = Обработки.ТекучийКалькулятор.Создать();
ТекучийКалькулятор.УстановитьЗначение(0)
.Прибавить(20) // 20
.Отнять(10) // 10
.Прибавить(5) // 15
.Отнять(3); // 12
Результат = ТекучийКалькулятор.Значение; // 12
Здесь я каждое действие записываю с новой строки: это не обязательно, но визуально наглядно и удобно для длинных цепочек.
Думаю, тут нет необходимости в особенных объяснениях: мы вызываем функции, которые меняют экспортную переменную Значение, а затем получаем ее содержимое. Таким образом можно реализовать множество разнообразных процессов, в том числе и сугубо 1Сных: мы используем обработку, как самый очевидный объект метаданных для подобных изысканий, но на самом деле ничего не мешает нам реализовывать подобное и в модулях объектов справочников или документов. Например, для их заполнения
Обработка ошибок
С самой базовой информацией мы разобрались. Теперь перейдем к другой немаловажной части - обработке ошибок.
Так как мы выполняем действия безостановочно, одно за другим, без возможности проверить корректность выполнения какой-либо из вызываемых функций в середине, нам необходимо реализовать обработку ошибок внутри нашего объекта.
Есть несколько вариантов организации этого процесса, я же предложу тот, который чаще всего видел и мне самому кажется наиболее удачным:
- В модуле обработки мы добавим еще одну переменную - Ошибка
- В каждую нашу функцию добавим Возврат в том случае, если Ошибка заполнена
Вот как выглядит наш обновленный модуль:
Перем Значение Экспорт;
Перем Ошибка Экспорт;
#Область ПрограммныйИнтерфейс
// Функция - Установить значение
//
// Параметры:
// ЧисловоеЗначение - Число - Начальное значение
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция УстановитьЗначение(Знач ЧисловоеЗначение) Экспорт
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Значение = ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
// Функция - Прибавить
//
// Параметры:
// ЧисловоеЗначение - Число - Значение для прибавления
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция Прибавить(Знач ЧисловоеЗначение) Экспорт
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Значение = Значение + ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
// Функция - Отнять
//
// Параметры:
// ЧисловоеЗначение - Число - Значение для вычитания
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция Отнять(Знач ЧисловоеЗначение) Экспорт
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Значение = Значение - ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Функция ПривестиЧисло(Знач ЧисловоеЗначение) Экспорт
ОТЧ = Новый ОписаниеТипов("Число");
Возврат ОТЧ.ПривестиЗначение(ЧисловоеЗначение);
КонецФункции
#КонецОбласти
Для проверки необходимо спровоцировать какое-нибудь исключение. Добавим для этого функцию деления:
// Функция - Разделить на
//
// Параметры:
// ЧисловоеЗначение - Число - Делитель
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция РазделитьНа(Знач ЧисловоеЗначение) Экспорт
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Делитель = ПривестиЧисло(ЧисловоеЗначение);
Попытка
Значение = Значение / Делитель;
Исключение
Ошибка = ОписаниеОшибки();
КонецПопытки;
Возврат ЭтотОбъект;
КонецФункции
Эта функция будет обрабатывать исключение при невозможности поделить одно число на другое, таким образом останавливая выполнение дальнейших процессов. Попробуем вклинить вызов РазделитьНа в нашу цепочку:
ТекучийКалькулятор = Обработки.ТекучийКалькулятор.Создать();
ТекучийКалькулятор.УстановитьЗначение(0)
.Прибавить(20) // 20
.Отнять(10) // 10
.Прибавить(5) // 15
.РазделитьНа(0) // Ошибка
.Отнять(3);
Ошибка = ТекучийКалькулятор.Ошибка;
Если ЗначениеЗаполнено(Ошибка) Тогда
Результат = Ошибка;
Иначе
Результат = ТекучийКалькулятор.Значение;
КонецЕсли;
// Деление на 0
Сообщить(Результат);
Таким же нехитрым образом, кроме текста ошибки, мы можем сохранить и другую информацию об исключении: например, добавить переменную для записи имени функции, которая привела к ошибке или счетчик, увеличивающийся на 1 после вызова каждой функции цепи, чтобы определить, какое "звено" было последним
Получение результата
Последний небольшой момент на сегодня - получение финального результата. Этот момент не очень важен, если вы пишите обработку для себя, но куда более важен для разработчиков универсальных решений.
Все это связано с той самой инкапсуляцией - ограничением доступа к данным извне для предотвращения манипуляции с ними теми методами и в тех местах, которые для этого не предназначены. Сейчас мы используем переменные с признаком Экспорт, что позволяет напрямую получать и менять их содержимое в любой момент и любым способом. Как правило, это не очень хорошо, так как увеличивает количество способов, которыми можно сломать нашу обработку.
Для избежания такой ситуации лучше сделать переменные не экспортными, а получение и установку значений вынести в экспортные функции. Внутри этих функций мы уже сможем контролировать данные, которые пытаются попасть в поля нашей обработки.
У нас уже есть функция для установки начального значения и там даже есть первая обработка: мы сразу приводим значение к числу, в то время как при наличии экспортных переменных там могло появиться значение любого типа. Остается лишь написать такую же функцию и для получения результата:
// Функция - Получить результат
//
// Возвращаемое значение:
// Структура - Описание результата
// * Ошибка - Булево - Признак ошибки выполнения
// * Данные - Строка,Число - Полученное значение или текст ошибки
Функция ПолучитьРезультат() Экспорт
ЭтоОшибка = ЗначениеЗаполнено(Ошибка);
Возврат Новый Структура("Ошибка,Данные"
, ЭтоОшибка
, ?(ЭтоОшибка, Ошибка, Значение));
КонецФункции
... и немного изменить вызов
ТекучийКалькулятор = Обработки.ТекучийКалькулятор.Создать();
// И никаких экспортных переменных :)
Результат = ТекучийКалькулятор.УстановитьЗначение(0)
.Прибавить(20)
.Отнять(10)
.Прибавить(5)
.РазделитьНа(0)
.Отнять(3)
.ПолучитьРезультат();
При подобном подходе, с исключением возможности напрямую влиять на данные извне, предусмотреть и обработать все возможные исключительные ситуации становится гораздо проще.
В заключение
Вот, собственно, и все. Сегодня немного познакомились с ООП в 1С и рассмотрели основанную на нем реализацию текучего интерфейса. Надеюсь, данный метод поможет вам в написании красивого и лаконичного кода. А полный текст модуля из примеров кода можно найти ниже
Перем Значение;
Перем Ошибка;
#Область ПрограммныйИнтерфейс
// Функция - Установить значение
//
// Параметры:
// ЧисловоеЗначение - Число - Начальное значение
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция УстановитьЗначение(Знач ЧисловоеЗначение) Экспорт
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Значение = ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
// Функция - Прибавить
//
// Параметры:
// ЧисловоеЗначение - Число - Значение для прибавления
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция Прибавить(Знач ЧисловоеЗначение) Экспорт
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Значение = Значение + ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
// Функция - Отнять
//
// Параметры:
// ЧисловоеЗначение - Число - Значение для вычитания
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция Отнять(Знач ЧисловоеЗначение) Экспорт
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Значение = Значение - ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
// Функция - Разделить на
//
// Параметры:
// ЧисловоеЗначение - Число - Делитель
//
// Возвращаемое значение:
// ОбработкаОбъект.ТекучийКалькулятор - Этот объект
Функция РазделитьНа(Знач ЧисловоеЗначение) Экспорт
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Делитель = ПривестиЧисло(ЧисловоеЗначение);
Попытка
Значение = Значение / Делитель;
Исключение
Ошибка = ОписаниеОшибки();
КонецПопытки;
Возврат ЭтотОбъект;
КонецФункции
// Функция - Получить результат
//
// Возвращаемое значение:
// Структура - Описание результата
// * Ошибка - Булево - Признак ошибки выполнения
// * Данные - Строка,Число - Полученное значение или текст ошибки
Функция ПолучитьРезультат() Экспорт
ЭтоОшибка = ЗначениеЗаполнено(Ошибка);
Возврат Новый Структура("Ошибка,Данные"
, ЭтоОшибка
, ?(ЭтоОшибка, Ошибка, Значение));
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Функция ПривестиЧисло(Знач ЧисловоеЗначение) Экспорт
ОТЧ = Новый ОписаниеТипов("Число");
Возврат ОТЧ.ПривестиЗначение(ЧисловоеЗначение);
КонецФункции
#КонецОбласти
Спасибо за внимание!
Другие мои статьи:
Открытый пакет интеграций для популярных API: Telegram, VK, Viber, Bitrix24 и многих других
Open-source набор библиотек интеграции с популярными сервисами: методы для 20-ти популярных API, поставка в виде расширения, OneScript-пакета и даже полноценного приложения для командной строки, подробная документация. И все это абсолютно бесплатно!
Автоматизация редактирования изображений в ImageMagick - это просто!
На что способен ImageMagick и некоторые неочевидные моменты при интеграции его в 1С.
![]()
Мой GitHub: https://gitub.com/Bayselonarrend OpenYellow: https://openyellow.notion.site Лицензия MIT: https://mit-license.org
Вступайте в нашу телеграмм-группу Инфостарт
разработка ООП fluent текучие утверждения текучий интерфейс
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
Работа с интерфейсом Анализ учета Мониторинг 1С:Предприятие 8 1С 8.3 1C:Бухгалтерия 1С:Бухгалтерия 3.0 1С:ERP Управление предприятием 2 1С:Управление холдингом 1С:Зарплата и Управление Персоналом 3.x 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Управление торговлей 11 Платные (руб)
Создайте свой функциональный интерфейс в любой конфигурации 1С с помощью расширения Infostart Dashboard. Настраивайте панели виджетов с метриками, индикаторами и показателями на начальном экране. Узнайте возможность внедрения подсистемы у себя в конфигурации с помощью бесплатной обработки "Анализ внедрения подсистемы 1С Infostart Dashboard"!
31720 руб.
27.03.2025 92191 69 44
Консолидация данных Работа с интерфейсом Разработчик Пользователь 1С:Предприятие 8 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 1C:ERP Узбекистан Беларусь Кыргызстан Россия Казахстан Платные (руб)
Знакомая ситуация? Пользователи, особенно менеджеры, уверены: отборов много не бывает. Идут пожелания добавить в форму списка еще один быстрый фильтр, еще два, еще пять... В итоге интерфейс превращается в нагромождение полей отбора, а потребность в «самом главном» отборе, который «вот прямо сейчас нужен», все равно не закрыта. Универсальное расширение, которое решает эту проблему элегантно и технологично. С его помощью в любую форму списка можно легко добавить панель настраиваемых кнопок-закладок, каждая из которых применяет сложный фильтр-запрос, а так же показывает актуальное количество элементов в реальном времени.
6088 руб.
17.10.2025 3625 3 0
Разработка Инструментарий разработчика Работа с интерфейсом Адаптация типовых решений Нейросети 1C:Бухгалтерия 1C:ERP 1С:ЗУП 1С:КА 1С:УНФ 1С:УТ 1С:Розница 1С:ДО 1С:ERP Управление предприятием 2 Платные (руб)
Разработка "Дизайнер форм 1С" реализована в виде расширения 1С и является универсальным инструментом для разработки прототипа форм с целью демонстраций, технических заданий и т.д. Без участия разработчика с возможностью экспорта в файл внешней обработки и генерации формы используя искусственный интеллект.
36600 руб.
28.08.2025 10292 2 2
Механизмы платформы 1С Разработчик 1С:Предприятие 8 Бесплатно (free)
Давайте разберемся в механизме «История данных» и поэкспериментируем для наглядности. Сравним «Версионирование объектов» и «Историю данных».
06.03.2023 75528 dsdred 105
Механизмы платформы 1С Разработчик 1С:Предприятие 8 Россия Бесплатно (free)
При знакомстве с новой механикой работы с асинхронностью (обещание, ждать и асинх) делал пометки, которыми и хочу поделиться. Ничего сверхъестественного в них нет, просто небольшие примеры и некоторые всплывшие нюансы использования.
29.07.2022 144818 zeltyr 28
Работа с интерфейсом Разработчик 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)
"MVC плохо применима в 1С" - познакомьтесь с моделью состояния и, возможно, ваше мнение поменяется! Представленное решение является эволюционным развитием идеи реализации MVC для 1С. В новой версии добавлены DSL для описания модели состояния, а также параметризация свойств параметров и элементов формы.
1 стартмани
05.07.2022 17923 kalyaka 8
Механизмы платформы 1С Системный администратор Разработчик 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)
Копнем глубже в тему "Что же такое динамическое обновление" и почему оно может привести к проблемам. И может ли?
09.05.2022 55062 Infostart 85
Инструментарий разработчика Рефакторинг и качество кода Групповая разработка (Git, хранилище) Механизмы платформы 1С Разработчик Стажер Бесплатно (free)
Стек технологий, которые могут быть полезны разработчику на 1С и около 1С. По каждой технологии постарался объяснить, зачем она нужна и с чего начать изучение, если заинтересует.
29.11.2021 83169 mrXoxot 63
Результат = 0 + 20 - 10 + 5 / 0 - 3;чем
Результат = ТекучийКалькулятор.УстановитьЗначение(0)
.Прибавить(20)
.Отнять(10)
.Прибавить(5)
.РазделитьНа(0)
.Отнять(3)
.ПолучитьРезультат();При правильном подходе, текучий интерфейс сокращает количество кода. Тут же получилось будто кода больше
1. Желательно приводить что-то реалистичное. Иначе посидели и поговорили, а практически так делать никто не будет.
2. И как раз рассмотренный пример, говорит об обратном - как сделать код более сложным и объемным. Так что надо подходить более аккуратно к примерам. Привели бы пример с тестированием, вопросов бы не возникло (наверное).
3. Мне стало интересно как вы перепишите пример со скобочками (если не сложно)? Результат = 0 + ((20 - 10)*3 + 5 / 0) - 3;
Но не любят у нас в сообществе ООП и что-то с этим связанное. Отчасти виной этому сам вендор. Как всегда разворачивается холивар, только успевай шапку подставлять
Писать код вот так - допустимо в маленькой задачке, где на чтение "чужого кода" и понимание функционала не требуется много времени.
На больших проектах сложности будут на этапе отладки - время на анализ кода возрастет.
Чтобы доработать - нет промежуточных переменных, где можно наложить условия по доп.требованиям задачи. Можно внести изменения в эти "общие методы", но опасно - придется тестировать везде, где "общий метод" применяется. Либо закомментировать всю строку целиком и написать собственную строку или создать ветки условий и код станет еще сложнее.
За 9 лет работы в 1С убедился, что чем проще код читать и дорабатывать, тем он эффективнее (качество + экономия временим на все циклы разработки).
Идея с ООП интересная, в профессионализме автора не сомневаюсь, но такой подход к написанию кода не поддерживаю.
У кого?
Те же фреймворки для автоматизированного тестирования (используемые, кстати, чаще всего на крупных проектах) используют этот подход и никого это не смущает. В любом случае, я не имел ввиду, что это абсолютно универсальная вещь, которую необходимо использовать везде и везде она будет полезна
List<EmailAddress> addresses = library.getReaders().stream()
.filter(Reader::isSubscriber)
.filter(reader -> reader.getBooks().size() > 1)
.map(Reader::getEmail).map(EmailAddress::new)
.collect(Collectors.toList());на 1с такой код будет выглядет так:
ЧитателиБиблиотеки = ВсеЧитателиБиблиотеки();
АдресаEmail = Новый Массив;
Для каждого ИнфоОЧитателе Из ЧитателиБиблиотеки Цикл
Если ИнфоОЧитателе.Подписчик И ИнфоОЧитателе.Книги.Количество() > 1 Тогда
АдресаEmail.Добавить(ПреобразоИнфоОЧитателе.Email);
КонецЕсли;
КонецЦикла;
в этом примере наверно не очевидны преимущества, но когда большая вложенность Цикл...Если...Цикл...Если, конвейерный код получается намного компактнее
ЗЫ: В турбовижине используется несколько иной подход, когда в конструктор засовывается конструктор, в который засовывается конструктор, в который ... И так "одной строкой кода" рисуется форма целиком со всеми добавленными на нее полями.
ЗЫЗЫ: Ща такое повсеместно, по крайней мере во флаттере с этим вот прям беда была - я тупо путался, после какой запятой что рисовать.
Строитель = Обработки.Веб_Строитель.НовыйСтроитель();
Строитель.ДобавитьСтили(ВебИнтерфейсКлиент.СтильДокумента(,,,Истина));
Строитель.ДобавитьСтили(ВебИнтерфейсКлиент.СтильСсылкаКакКнопкаКоманднойПанели());
Строитель.ДобавитьТег("html")
.ДобавитьТег("head")
.ВставитьСтили().ЗакрытьТег()
.ДобавитьТег("body", , Новый Структура("style", "background: #FCFAEB;"))
.ДобавитьТег("div",, Новый Структура("style", "white-space: nowrap;"))
.ДобавитьТег("img",,Новый Структура("src, style",КартинкаURL,"object-fit: contain; width:16px; height:16px; margin-right: 2px;")).ЗакрытьТег()
.ДобавитьТег("a", "В приход").ЗакрытьТег()
.ЗакрытьТег()
.ЗакрытьТег()
.ЗакрытьТег()
.ЗакрытьТег();
ДокументHTML = Строитель.ПолучитьHTML();
ЭлементыФормы.ПолеВПриход.УстановитьТекст(ДокументHTML);
Показать1. Постоянный вызов одного и того же модуля и возврат к модулю из которого происходит вызов.
2. Постоянно возвращается объект (чтоб выполнить следующий вызов), если это ещё и тяжелый объект, то избыточный расход по памяти
Это не стоит того чтоб использовать. В редких случаях использовать очень осторожно. Всегда нужно следить за ресурсами, добавится у объекта реквизит с файлом в пару Гб и всё, будешь долго попрыгаешь через точку
Объект же не создается каждый раз новый. О каком расходе памяти идет речь?
Всё высосано из пальца и какая-то экономия на спичках.
Про первый пункт вообще не понял. Что плохого в вызове другого модуля? ) Это прям что-то новенькое в области оптимизации 1С! Давайте вернемся к 7.7, где был один глобальный модуль на всё! Сразу заживем и скорости возрастут ))
Результат = "123".КонвертироватьВЧисло().Прибавить(5);Вот это было бы честной поддержкой 1С.
2. Постоянно возвращается объект (чтоб выполнить следующий вызов), если это ещё и тяжелый объект, то избыточный расход по памяти
Я не уверен, что это создает накладные расходы, если не происходит передачи с сервера на клиент, но могу ошибаться
Это было бы очень странно, если мы говорим об обработке. Думаю, в типичном сценарии это не будет отнимать каких-либо заметных ресурсов сверх того, что тратят обычные вызовы
Всего 20 лет как американская жвачка пришла в Россию, а уже и до 1С добралась))
Вопиющее извращение ООП, вытянутое из левой ноздри (если кто не знает - там, за ноздрёй - мозг, а в нём - умные мысли!) каким-то скриптинг гаем.
И все как дети - подхватывают самое плохое, а элементарную логику и необходимый порядок - игнорируют. Потому что скучно, или просто - потому что...
Впрочем, как тут и написано - в 1С нет ООП, как нет и не будет порядка и элементарной логики. Ибо об этом должны в первую очередь заботиться технические идеологи платформы, а они то ли заняты пендостанскими хрендами, то ли давно уволены, если судить по количеству костылей, используемых прикладниками чтобы оно хоть как-то работало.
Пусть будет ещё один костыль - код-то уже практически нечитаем...
Не в обиду автору - статья прикольная, и сама фишка.
Но непрактичная, как некоторые доистерические языки, в которых код состоял из одних скобок и операторов.
И да спасёт нас оператор With от подобной ереси, аминь!
Всего 20 лет как американская жвачка пришла в Россию, а уже и до 1С добралась))
Это можно было делать с тех пор, как в 1С появились обработки и я не первый это придумал
Чистое имхо + словесный фарс: тысяча и одна технология в программировании использует этот подход для сокращения и улучшения читаемости кода. Видимо все кто делал и используют LINQ, jQuery, Pandas и Spring Boot извращенцы, которые не понимают, что это на самом деле плохо и неудобно
Единственный язык с чистым ООП - это Smalltalk. Все остальные языки имеют ООП той или иной степени этой чистоты. В 1С ООП очень слабое и действительно ООП языком его нельзя назвать, но как раз пример с обработкой о том, что отдельные части парадигмы выполняются. Иначе и нельзя было бы реализовать fluent api
Про логику это вообще какой-то холостой выстрел ни о чем
Можно подумать, что если завтра в язык завезут нового сахара, то костыли закончатся. Как вообще можно связать "идеологов платформы", которые теперь делают что-то не так и "заняты пендостанскими хрендами", хотя язык уже десятилетие не меняется, и прикладников, которые лепят костыли на предметном уровне под меняющиеся процессы?
Как связаны старые языки с популярным способом организации методов в классах? Никак, очевидно, просто "непрактичная" и все
Для сокращения - это точно. Но где тут читабельность? Ну прочитал это колбасу на пару страниц вправо, и тут же представил себе результат выполнения, ага.
А ошибки вылавливать из этого вот, особенно в нетипизированных языках? Рантайм план покажет?
Из-за таких вот (в) попу лярвных "технологий" компы сейчас выполняют на 80% больше (и это не предел, млин!) инструкций, чем необходимо для реализации конкретной задачи. То есть глючат, тупят, жрут Раму и греют воздух. И с каждым годом надо больше и больше аппаратной мощности, хотя существующая хорошо если на 20% эффективно используется.
Зато имеем целый выводок языков, созданных непонятно кем и непонятно зачем, и ни одного по настоящему качественного, проработанного на научной основе, генерирующего байт-код, пригодный для дальнейшей глубокой оптимизации под любую платформу (и этих бы выводок сократить, до одной!), а не просто для максимального упрощения конечного компилятора (Жаба).
Что-то реализовано в Си, что-то в Питоне, что-то Аде, что-то в Жабе, что-то в LLVM. Это долбанные лебедь, рак и щука. Никаких стандартов, зато широчайший выбор для желающих свихнуться при выборе и высокопроизводительных авторов говнокода! Капитализма, мать...
В 1С нужно завозить не сахар, а полный пересмотр архитектуры, включая язык, который два десятилетия не меняется.
Криворуких прикладников не убавится, но те немногие, которые способны и хотят писать качественно, а не "больше всех", получат возможность реализовать что-то полезное и долгоиграющее. Например, переделают мега-костыль БСП в нормальную библиотеку классов, и сделают одно мощное модульное строго стандартизованное решение вместо выводка убогих калек, которые кое-как продаются и кое-как удовлетворяют клиентов, да и то - потому что альтернативы не наблюдается.
Тогда, возможно, приложения 1С научатся потреблять больше 1% ЦПУ и меньше 100% РАМ, и чуток экономить дисковое пространство (в текущей реализации база 1С состоит на 2/3 из ссылок, из которых половина не нужна вовсе, а вторую можно поделить на 4+, если не совать ГУИДы в каждое ссылочное поле).
А мне не придётся сидеть ночами, отлавливая чужие баги в совершенно нечитаемом коде, или по полчаса ждать пока мастер настройки обмена вычитает и в сотый раз перегрузит в таблицы всю посылку оппонента после очередного нажатия что на ОК, что на Х.
Впрочем, о чём это я? 1С - КОММЕРЧЕСКОЕ приложение. А следовательно, не стоит ждать ни соли, ни сахара. Только расходов, и не только денежных.
А ведь, "системообразующее" предприятие... За страну обидно! И за логику. Внедряем импортное потреблядство, все живут как проще, а на выходе - всеобщий гемор, который неизбежно закончится всеобщей задницей. Будет весело!
Ничего, третья мировая генофонд прочистит, и торгашам достанется. Чуток осталось - лет 10-15, если у какого-нибудь идиота палец на кнопке не дрогнет. Жаль, организаторов этого бардака не достанет, как и в прошлую ядерную...
Да, это он и есть. То, что вы это так трактуете не означает, что это так на самом деле. Или вы всерьез считаете, что проблема в слове with
Если класс реализует fluent api, то ВСЕ методы возвращают self. Проблема, которой не существует
Прекрасно представляю, потому что fluent надо использовать там, где он к месту, т.е. где последовательно выполняются манипуляции, завязанные на один объект. Как правило, речь идет о взаимодействии с какими-нибудь отдельными сторонними блоками или библиотеками
Статистические данные сами собрали?
Что-то реализовано в Си, что-то в Питоне, что-то Аде, что-то в Жабе, что-то в LLVM. Это долбанные лебедь, рак и щука. Никаких стандартов, зато широчайший выбор для желающих свихнуться при выборе и высокопроизводительных авторов говнокода! Капитализма, мать...
Это просто поток сознания. Да, вы представляете, кто угодно может создать язык и, если вы знаете его название, то это в первую очередь означает, что им пользуются люди. Иначе вы бы о нем не знали. Получается, не непонятно зачем? Язык же, о котором вы говорите, знаете почему не существует? Потому что никто не готов за такое платить. День невероятных открытий
Чтобы заявлять такие вещи, нужно как минмум иметь серьезный авторитет в этих вопросах. Иначе это просто выглядит как болезненное брюзжание. Есть языки, люди ими пользуются - что делает вас лучше их, чтобы решать?
Если даже вернуться к неоптимальности и "80%": да, мир устроен так, что кто программы платит, тот их и танцует. И если бизнес, который обычно и платит, видит, что цена ОЗУ меньше человекачаса программиста и риска простоя из-за ошибок при работе на низком уровне (для недопуска которых нужны более дорогие специалисты), то, внезапно, большая часть программистов будет писать на непроизводительных, но простых и безопасных языках. Очевидное невероятное
И это все при том, что из-за "проклятого капитализма", есть целая куча хороших языков низкого уровня на любой вкус, от Rust до Nim. Тоже недостаточно хороши для реализации вашего гения?
Вы за это заплатите? Или может заплатит бизнес, который 10 лет автоматизировал все чтобы начать с нуля? Полиграф Полиграфович плачет, читая это
Остальное - просто какие-то абстрактные рассуждения на вольную тему, не представляю, зачем вы на меня их выливаете. Пожалеть вас, что мир не такой идеальный, как вам хотелось бы?
Бардак должен закончиться, хотя бы потому что из него уже становится сложно извлекать прибыль.
Плюс методологический кризис по всем наукам, если производство коммерческого говнокода можно отнести к научным дисциплинам.
Единственный субъект в мире, который способен взяться за такую проблему - это Россия (как государство, или скорее как ИП Путин - опять у нас всё держится на одном гвозде, повторяем 20век). Потому что только у нас внедрение потреблядства идёт с большими проблемами - ещё есть шанс вывернуться самим и вывернуть наизнанку долбанный мир.
А про понятный код - вы давно заглядывали в исходники типовых?
Раньше на 1С можно было писать более или менее понятный код, теперь вместо него пишут бесконечные обработчики ожидания и пятиуровневые вызовы через модули с разными атрибутами, чтобы мимо серверного контекста не попасть.
Не было нормальной многопоточности - ладно, не так часто это нужно. Но запретить модальность, вместо того чтобы реализовать её по-человечески - это блин забота о прикладниках и пресловутой экосистеме?
И таких нюансов несколько сотен можно наскрести. Архитектура платформы просто вынуждает прибегать к извращениям и потом тратить время на отладку этого дерьма.
Сейчас задумали в четвёртый раз менять интерфейс. Опять садимся всё переписывать. Это для кого всё?
Да ни для кого - для прибыли. Качает насос бабло со всей России - мало, надо соседей подтягивать, а для этого неплохо бы мимикрировать под им привычное.
Я уже написал выше, чем заканчивается гребля под себя. И так оно и будет. В который раз уже, только памяти хватает на 2-3 поколения. Колония одноклеточных, блин.
Либо биомасса начнёт уже организовываться и координировать усилия, либо - Матрица.Перезагрузка().
Пожалуй, эти вопросы для другой песочницы. Всё никак не усвою, что в большинстве случаев лучше молчать, чем мычать...
Модальность запрещена не потому что так захотелось разработчикам платформы, а потому что она запрещена в браузерах.
Если пишите свою нетленку и не планируете использовать веб-клиент, используйте модальные окна, кто вам запретит-то? Или используйте Асинх вместо ОписаниеОповещения.
И тут Остапа понесло...
(57)
Это можно и нужно было реализовать на уровне платформы, а не заставлять прикладников заниматься онанизмом. Вслед за Гуголом, которому тоже проще было скинуть гемор на конечных потребителей фреймворка, чем реализовывать независимые многоуровневые блокировки для каждого модального элемента и связанную с этим многопоточность.
Пытаются всех и вся впихнуть в мобильник с Андроидом, в котором для нормальных окон места нет. Причём тут полноразмерные браузеры? Да при унификации - чудо-меню-Пуск Win8 - про то же.
А остальные тупо повторяют ошибку, не пытаясь хотя-бы её изолировать на своём уровне. Гуглу, понятно, пенять бесполезно, а остальные браузерокопипастеры пользуются, чем дали - халява же...
Это-то недоразумение чем лучше? Мертворождённая многопоточность, которую ещё лет 10 допиливать и выпрямлять будут. Если вообще будут, с учётом объёма необходимых изменений в платформе.
Всё зависит от точки зрения. С моей - понесло остальной мир, а Остап за что-то зацепился...
Как правильно замечал покойный Задорнов - вперёд, в пропасть. А я бы сказал вернее - в унитаз. Не достойны мы порядочной пропасти. В сотый раз уже разводят популяцию, а результат - один. Впрочем, свою задачу она выполняет, но это уже отдельная история, совсем не про 1С.
Когда-то, в допотопном СССР, людей попытались научить думать, но потом испугались результата...
Теперь модно делать, неважно что, но - быстро и много. А потом - впаривать "продукт" своей жизнедеятельности, эффективно и дорого. Вот это - конкретика!
Вот, например, "fluent interface" придуман как костыль для языка, в котором отсутствовал аналог with.
Кто-то увидел в этом "упрощение" - на кнопки же нажимать меньше! - и понеслась коза по рельсам.
Впендюрили во все языки, где надо и не надо, название вот придумали...
При этом никто не считает, насколько раздуются стеки, как возрастёт нагрузка на кеш и потребление мозгов, сколько от этого произойдёт тормозов и, блин, расхода электроэнергии и прочего жизненного ресурса.
А ведь таких "оптимизаций" многие тысячи - достаточно поотлаживать любую прогу сложнее блокнота да помониторить её обращения к ресурсам ОС. Что M$, что 1С, даже великие и непревзойдённые производители огрызков - все используют и приумножают говнокод. Что уж говорить про опенсорсников, которые держатся на энтузазизме, народных подаяниях и подачках конкурентов.
Я понимаю, что хрень в основном используется для сокращения каких-то рутинных часто повторяемых операций в узких областях, где эффективность (якобы) не нужна, а отладка не важна.
Но в любом случае - это костыль, который лечится либо With, либо макросом, либо - нормальным планированием API, в котором все рутинные операции реализованы одним вызовом, а не трехметровой колбасой.
Одни делают кривые фреймворки, другие придумывают костыли, чтобы их "почти выпрямить". Некоторые даже сами делают и сами выпрямляют! И этот бардак преподносится как общепринятый стандарт кодирования, просто потому что "все так делают"...
Даже если вы хорошо знаете, как работает система, занимайтесь не гаданием, а замерами. Полученная информация в девяти случаях из десяти покажет, что ваши предположения были ошибочными!
- Рон Джеффрис
Это же одна из 10 заповедей Говнокодинга!
Пиши как попало, а рантайм с профайлером выпрямят, когда нибудь...
Я не говорю, что профилировать не надо, но замеры показывают только то, как справляется конкретная железка с конкретной узкой задачей. На компе у пользователя тайминги, как правило, гораздо печальнее. Особенно, если смотреть не на относительный вклад, а на секунды. И профилировать не только прикладной код, но и библиотеки, а также поинтересоваться, чего и как делают интерпретаторы и компиляторы, которые умеют гадить в код не хуже прикладников.
Никакой профайлинг не заставит говнокодера понять, что та же задача могла быть выполнена втрое быстрее и с вдвое меньшим потреблением ресурсов. "А чо, у меня на компе оперативы много, и проц топовый - пускай работают. А я отдохну, пожалуй...".
Ну покажи тот же калькулятор в виде макроса или "нормального API", или одного вызова? Сидишь и написываешь всякую ерунду
Или вот: Мегакалькулятор.Мегафункция(5, 7, 10);
Или особо запущенный случай: With Мегакалькулятор do Сложить(5, Умножить(7,10));
Один длиннее и запутаннее другого, не правда ли?
Макросы стараюсь не использовать и уже забыл синтаксис - догадайтесь сами.
А это читается хуже текучего интерфейса
Если же все вызовы хаотичны - это повод пересмотреть общую архитектуру, где-то что-то не так поделили.
Как ты сам себе представляешь строгий порядок действий в том же калькуляторе?
Я бы вообще жёстко запретил известные фокусы и стилистические извращения на уровне синтаксического анализатора, чтобы их потом не оптимизировать. Оптимизировать нужно соответствие структуры байткода возможностям машинного, а выкрутасы по трансформации рекурсий и подобные сильно усложняют компилятор и иногда приводят к очень интересным, но весьма неприятным детским неожиданностям)
Если ЗначениеЗаполнено(Ошибка) Тогда Возврат ЭтотОбъект КонецЕсли;
Значение = ПривестиЧисло(ЧисловоеЗначение);
Возврат ЭтотОбъект;
КонецФункции
Возвращать объект - обработку - может пригодиться, когда объект-обработка представляет собой контейнер для хранения параметров и промежуточных данных - расчетов.
Что возвращать- объект-структуру, объект-соответствие или объект-обработку - зависит от возможностей "объекта" (какие типы умеет хранить) и самой задачи.
Многие используют внешние обработки для запуска алгоритмов - чтобы динамически обновлять и проверять алгоритмы без закрытия сеансов пользователей, чтобы скрыть алгоритмы. Поэтому способ, представленный в статье имеет место быть.
Я на обычных формах много раз использовал обработку в качестве центрального объекта для выгрузки на сайт (туда-сюда обмен), для расчета АВС-показателей.
Всем добра!
Это не совсем так, потому что есть как минимум стек вызовов.
Вообще, я уже 10 раз пояснил, что fluent это не для всего и никто не говорит, что это нужно использовать везде при работе. Fluent это про отдельный блок, выполняющий комплексную параметризированную обработку по шагам: проверка условий в Unit-тестах, http-запросы, ORM и пр.
Я сам написал порядком тестов на YaxUnit и могу сказать, что без текучих утверждений это было бы на порядок менее удобно. Разносить этот подход как непригодный для обычной повседневной доработки конфигураций - война с ветряными мельницами
По-моему, fluent interface вполне применим в 1С и никаких костылей, ну почти, не вижу.
Наоборот, даже если не знать всех этих умных слов любой junior сразу поймет как работает цепочка.
ПолучитьКурсыВалют()
.ПреобразоватьВJSON()
.ЗаписатьВЛог()
.РасчитатьКонтрольнуюСумму()
.ОтправитьПоПочте().
Что тут сложного (даже если не откидывать, как это сделал я, передачу параметров)?
Более того, интуитивно понятно, что цепочка является гибкой и может быть частично изменена или прервана досрочно, или прервана, а потом возобновлена.
Т.е. по сути имеем дело с internal DSL.
Да, без возможности использования функциональных переменных и выражений, инжекций и проксирования, возможности ограничены, но тут уж ничего не поделаешь.
"Если класс реализует fluent api, то ВСЕ методы возвращают self."
В вашем же примере, если я верно понял, ПолучитьРезультат() - возвращает структуру, непонятно зачем прерывая работу цепочки. И не позволяя продолжить вычисления. Калькулятор так работать не должен.
Как вариант обхода этого ограничения можно предложить передачу результата через аргумент.
И еще, не уверен, что это реально будет полезно, но, неплохо бы упомянуть про возможность получения не this, а immutable через возврат нового экземпляра обработки (это не я придумал, а есть такой стандартный вариант).
В примере с калькулятором это непонятно зачем, но при сложной/ресурсоемкой инициализации объекта закономерно желание его переиспользования, начиная с первоначального состояния.
ПолучитьРезультат - этакий геттер, защищающий переменную. Его действительно проблематично реализовать без прерывания, разве что ввести еще одну переменную экспортную только для этого. Но это единственное исключение без self и вызывается 1 раз в самом конце
Это интересно, но я не очень понимаю, как потом вернутся к оригинальному объекту для продолжения обработки. Может, непрвильно понял идею
Все просто - вместо возврата ЭтотОбъект в возвращаемом методе создаем новую копию обработки, инициализируем ее текущими значениями и возвращаем.
Методы цепочки при таком подходе будут "портить" результаты уже не текущей обработки, а "своей собственной"
Думаю понятно, что если у нас гигантские объемы данных и т.п, то так делать не стоит.
А вот если просто тупо теряем время на получение этих самых данных/тратим денежку за вызов API и т.п , то вполне себе вариант.
Вот пример на JavaScript, думаю будет понятно. там цепочка нарисована невнятно, но от этого более понятен принцип (ну или вместо const kitten1 = new Kitten() .setName('Salem'); рассмотрите:
const kitten1 = new Kitten().setName('Salem').setColor('black');)
class Kitten {
constructor() {
this.name = 'Garfield';
this.color = 'orange';
}
setName(name) {
const copy = new Kitten();
copy.color = this.color;
copy.name = name;
return copy;
}
setColor(color) {
const copy = new Kitten();
copy.name = this.name;
copy.color = color;
return copy;
}
// ...
}
// use it
const kitten1 = new Kitten()
.setName('Salem');
const kitten2 = kitten1
.setColor('black');
console.log(kitten1, kitten2);
Показать(41)
Да не надо вводить экспортных переменных, просто передавайте в методах цепочки внешний параметр - и там получайте промежуточные состояния.
Можно сделать и иначе, не возвращать ссылку на объект, а возвращать структуру типа "Результат, Then", где then - ЭтотОбъект.
Тогда цепочка будет выглядеть хуже, поэтому и не могу рекомендовать, но не намного.
рез = ПолучитьКурсыВалют().then
.ПреобразоватьВJSON().then
.ЗаписатьВЛог().then
.РасчитатьКонтрольнуюСумму().then
.ОтправитьПоПочте().
При этом рез.Результат - ваши текущие результаты вычисления.
А если хотите продолжить цепочку, то, например,
рез.then.ПреобразоватьВXМL()
А на копирование объекта, да ещё и инициализацию уже заполненными полями, мы время (и память) не тратим?
И я не уловил, о каком получении идёт речь? О получении объекта? А копию мы не получаем?
(81)
Тратим.
Поэтому никто не предлагает использовать этот прием, только потому, что он возможен. Не говоря уж о том, что его даже модным не назовешь - он уже известен не один десяток лет.
Более того, никто не мешает сохранить первоначальные результаты, например в вызывающем коде, и потом повторно инициализировать первоначальный, или новый объект, а не создавать классы по цепочке со всеми издержками.
Иногда удобно одно, иногда другое. It's up to you. Вот есть такие варианты - вам решать нужно ли оно вообще.
Чтобы было понятней, вот есть такой прием в том же 1С, когда вместо конкатенация строк "плюсиком", используют
СтрСоеденить или ЗаписьXML. Лично я, если надо сложить пару строк пользуюсь "плюсиком", не пытаясь сэкономить микросекунды (и даже прводить исследования, на сколько микросекунд будет разница).
По мне так читаемость кода здесь важней.
То же самое в обсуждаемой теме, если оно вам не надо, скорее-всего, она вам действительно не надо.
Насколько я понимаю:
* Сохранение в переменную, таким образом ветвим в нужных местах цепочку
* Использование стека и метод pop
тк = Обработки.ТекучийКалькулятор.Создать();
тк.УстановитьЗначение(0);
тк.Прибавить(20) ;
тк.Отнять(10) ;
тк.Прибавить(5) ;
тк.РазделитьНа(0) ;
тк.Отнять(3);
Результат = тк.ПолучитьРезультат();
Показать
Возврат ОжидаетЧто(Результат).ИмеетТип("Структура").Заполнено().НетСвойства("error")
Превратится в
Ответ = Ложь;
Если ИмеетТип(Результат, "Структура") Тогда
Если ЗначениеЗаполнено(Результат) Тогда
Ответ = НетСвойства(Результат, "error");
КонецЕсли;
КонецЕсли;
Возврат Ответ
ПоказатьОтвет = Ложь;
Если ИмеетТип(Результат, "Структура") Тогда
Если ЗначениеЗаполнено(Результат) Тогда
Ответ = НетСвойства(Результат, "error");
КонецЕсли;
КонецЕсли; ПоказатьВот так и должен выглядеть тривиальный код на 1С. Для чего вводить еще один уровень.
Что сделаете, если в рекомендуемом коде понадобится ветка Иначе с установкой каких-то переменных?
1. Да, так и должен выглядеть тривиальный 1С код - если вы вносите изменения в типовую конфигурацию, то надо писать вот так
2. Fluent не универсален: он нужен к месту вроде как здесь. Мне не нужна и никогда не будет нужна ветка иначе, потому что я использую блок с утверждениями - специальный отдельный модуль для специальной отдельной задачи определения истинности или ложности произвольного набора утверждений
3. Если я добавлю в это сборное условие еще 5 подусловий, то при использовании обычного кода это будет 5 раз вложенное Если...Тогда или 5 раз прокинутые выражения через Или. А если мне нужно будет несколько таких сборных условий, то это будет когнитивный ад. С текучеми утверждениями это будет просто еще одна строка в модуле, который будет маленьким и удобоваримым, даже если я напишу там 100 таких проверок
Fluent хорош, когда есть обособленная универсальная абстракция: вот есть обработка отвечающая за какой-то процесс, который может состоять из отдельных действий в произвольном порядке. Например, формирование http-запроса, где в него в произвольном порядке нужно просто закинуть тело, заголовки, установить URL и вызвать. Это хороший кейс для этого и, насколько я помню, такая реализация существует. Если же это типичный 1Сный сценарий правки в середине, где нудно доработать обычный код в конфе под конкретный уникальный случай (который может еще и 10 раз поменяться), то текучий интерфейс не подойдет
Да, это так) Я просто не ожидал, что будет такой холивар и прямо нужен отдельный дисклеймер что "решение не универсально, все трюки выполнены каскадерами!"
Ответ = Проверки.ИмеетТип(Результат, "Структура") И Проверки.Заполнено(Результат) И Проверки.НетСвойства(Результат, "error");
вот и код получился заметно сложнее
Ответ = Проверки.ИмеетТип(Результат, "Структура")
И Проверки.ЗначениеЗаполнено(Результат)
И Проверки.НетСвойства(Результат, "error");При этом код не потерял в читаемости и понятности.
Зато выиграл в потреблении ресурсов и производительности минимум в 3 раза.
В компиляторах разных языков присутствует выбор оптимизации "по производительности" или "по памяти". Что означает более быстрый код, но больше потребление памяти, или наоборот меньше памяти и меньше производительности.
Вы же предлагаете чуть меньше букв написанных разработчиком, и при этом производительность меньше и потребление ресурсов больше. Соотнеся то, что разработчик потратится на это один раз, а выполняться код будет миллиарды и более раз, какая-то мягко говоря сомнительная оптимизация.
ОжидаетЧто(Результат).ИмеетТип("Структура").Заполнено().НетСвойства("error")со своим.
как раз потерял
голословные заявления. Вот что про это пишут умные люди:
Даже если вы хорошо знаете, как работает система, занимайтесь не гаданием, а замерами. Полученная информация в девяти случаях из десяти покажет, что ваши предположения были ошибочными!
- Рон Джеффрис
НормальныйКалькулятор = Обработки.НормальныйКалькулятор.Создать();
// Эмуляция With начало
я = НормальныйКалькулятор;
я.УстановитьЗначение(0);
я.Прибавить(20);
я.Отнять(10);
я.Прибавить(5);
я.РазделитьНа(0);
я.Отнять(3);
я = Неопределено;
// Эмуляция With конец
Результат = НормальныйКалькулятор.ПолучитьРезультат();
Показать Счета = ПланыСчетов.Хозрасчетный;
Субконто = ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные;
ПостроительПроводок = Обработки.ПостроительПроводок.Создать();
ПостроительПроводок.НовыйНаборЗаписей(Шапка.Ссылка);
// Значения попадут в измерения каждой проводки
ПостроительПроводок.ОрганизацияПоУмолчанию(Шапка.Организация);
ПостроительПроводок.ПодразделениеПоУмолчанию(Шапка.Подразделение);
//Д т 90.02.1 - Кт 41.01
ПостроительПроводок.НоваяПроводка()
.СчетДт(Счета.СебестоимостьПродажНеЕНВД)
.СубконтоДт(Субконто.НоменклатурныеГруппы, Шапка.Группа)
.СчетКт(Счета.ТоварыНаСкладах)
.Сумма(Товары.Итог("Себестоимость")).Содержание("Отражение себестоимости товаров");
// Дт 62.01 - Кт 90.01.1
ПостроительПроводок.НоваяПроводка()
.СчетДт(Счета.РасчетыСПокупателями)
.СубконтоДт(Субконто.Контрагенты, Шапка.Контрагент).СубконтоДт(Субконто.Договоры, Шапка.Договор)
.СчетКт(Счета.ВыручкаНеЕНВД)
.СубконтоКт(Субконто.НоменклатурныеГруппы, Шапка.Группа).СубконтоКт(Субконто.СтавкиНДС, Перечисления.СтавкиНДС.НДС20);
.Сумма(Товары.Итог("Сумма")).Содержание("Отражение выручки");
// Дт 90.03 - Кт 68.02
ПостроительПроводок.НоваяПроводка()
.СчетДт(Счета.Продажи_НДС)
.СубконтоДт(Субконто.НоменклатурныеГруппы, Шапка.Группа).СубконтоДт(Субконто.СтавкиНДС, Перечисления.СтавкиНДС.НДС20);
.СчетКт(Счета.НДС)
.СубконтоКт(Субконто.ВидыПлатежейВГосБюджет, Перечисления.ВидыПлатежейВГосБюджет.Налог)
.Сумма(Товары.Итог("СуммаНДС")).Содержание("Отражение НДС");
НаборЗаписей = ПостроительПроводок.НаборЗаписей(); ПоказатьРезультат = ТекучийКалькулятор.УстановитьЗначение(0)
.Прибавить(20)
.Отнять(10)
.Прибавить(5)
.РазделитьНа(0)
.Отнять(3)
.ПолучитьРезультат();
мне нравится - 1. это оригинально 2. достаточно лаконично 3. заставило задуматься о применимости.
Можно использовать объект обработки (и не только обработки, а например объект справочника, почему нет?) - и все это будет работать на сервере. Хотим на клиенте - пожалуйста, аналогично используем для этого клиентскую форму. Не хотим связываться с созданием тяжелых объектов? Не вопрос - используем для этой цели общий модуль, а в цепочке экспортных функций в параметрах протягиваем структуру для сохранения и накопления результата.
... но зачем? Да, это необычно, оригинально, но каких-то особых преимуществ не дает ни в скорости, ни в компактности кода, ни в возможностях поддержки/отладки.
Сравните с классическим подходом и попробуйте назвать преимущества:
Перем Р;
ТК = ТекучийКалькулятор; // общий модуль
ТК.УстановитьЗначение(Р, 0);
ТК.Прибавить(Р, 20) // 20
ТК.Отнять(Р, 10) // 10
ТК.Прибавить(Р, 5) // 15
ТК.Отнять(Р, 3); // 12
Результат = Р;
ПоказатьНе надо свихиваться, кто будет тогда писать статьи?)
Fluent хорош, когда есть обособленная универсальная абстракция: вот есть обработка отвечающая за какой-то процесс, который может состоять из отдельных действий в произвольном порядке. Например, формирование http-запроса, где в него в произвольном порядке нужно просто закинуть тело, заголовки, установить URL и вызвать.
- все это ведь можно использовать в (66) или нет? Если нет, то почему? Если да, то зачем усложнять и привлекать объект обработки?
В целом, причина этого вопроса у многих в том, что я привел плохой пример в статье: я думал он будет простой, чтобы было все понятно, но в итоге он не показывает реальных приемуществ подхода
Дело не только в том, что все записывается в одну строку. Главное преимущество: возможность для разных задач комбинировать в разном порядке и количестве функции класса в цепи вызовов. Поэтому такой подход и любят во всяких готовых модулях, вроде ORM, где удобно использовать разные ВыбратьПоле("Имя").ВыбратьПоле("Фамилия").Отбор("Возраст").Больше(30).Получить()
Да
Не думаю, что это реальная проблема - можно передать финальный результат. Все равно цепочка вызовов это про обработку где-то в одном конкретном месте
Тоже не представляю зачем, даже если можно было бы. Никому же не хочется сериализовать общий модуль при обычном способе написания код
Это надо на Pentium II наверное сидеть, чтобы ощутить накладные расходы от одноразового создания обработки)
Имхо, тоже будто бы из пальца высосано
а разве я не могу комбинировать в разном порядке и количестве вызовы функции общего модуля?
Модуль.ВыбратьПоле(Контекст, "Имя");
Модуль.ВыбратьПоле(Контекст, "Фамилия")
Модуль.Отбор(Контекст, "Возраст");
Модуль.Больше(Контекст, 30);
и из Контекста получить накопленный результат? Кроме многострочности и некоторой повторности идентификаторов "Модуль" и "Контекст" разницы особой не вижу.
верно до тех пор, пока не придется в одной цепочке использовать, например данные из ИБ (например реквизит объекта) и данные клиентской формы (например текущая строка)
верно до тех пор, пока какой-нибудь деятель не превратит этот код в библиотеку (мы же против велосипедов и за переиспользование кода), а другой деятель не будет его вызывать в цикле из 10000 итераций (он же не обязан изучать содержимое такой библиотеки и просто использует ее API)
Имхо, тоже будто бы из пальца высосано
опять же, все хорошо до тех пор, пока эту функциональность не начнет использовать пользователь, которому забыли дать права на обработку. А кто из админов базы может представить, что чтобы сформировать, к примеру, по определенной процедуре текст запроса к сервису, нужно давать пользователю какие-то дополнительные права? это слишком необычная ситуация.
В целом, не подумайте, что я резко против этого подхода, я и сам что-то подобное применял. Но разработчик перед решением об использовании этого механизма должен взвесить все плюсы и минусы для данной конкретной задачи и в данной конкретной ситуации. Использовать же нестандартный механизм бездумно, просто потому что он понравился или потому что он используется в другом языке или из-за "вау-эффекта" на мой взгляд непрофессионально. В статье не хватает информации о подводных камнях и о примерах задач, в которых такой подход предпочтительнее, с обоснованием такой предпочтительности.
PS: в 1С:Исполнителе, в отличие от платформы 1С, текучий интерфейс - штатная возможность, не требующая создания промежуточных прикладных объектов. Там такой механизм не выглядит чужеродным.
Можно. Не вижу никаких приемуществ, это просто по-другому
Ну вы так пишете, будто это какой-то уникальный минус конкретно обработки. Вся 1Ска так работает, предлагая вам сразу при добавлении обработчика события создать и &НаКлиенте и &НаСервере, потому что на клиенте нельзя использовать ни запросы, ни серверные функции. Не вижу принципиального различия от того, что это был бы обычный код в серверном модуле
Проблемы индейцев шерифа не волнуют. С таким подходом можно еще отказаться от языка запросов, потому что кто-то будет выполнять запрос в цикле из 10000 итераций
Весь код такой библиотеки находится в самом объекте. И если он использует ее API, то он сначала создает объект, а потом вызвает его методы. Где здесь подводный камень, при котором не очевидно что ты создаешь обработку несколько раз в цикле? В любом случае любое действие начинается с Обработки.Обработка.Создать() и это явно видно
Не говоря о том, что сделать код, который вызывать в цикле возможно, но не стоит, можно при любом подходе
Обработки не появились в тот день, когда я написал про fluent. Их миллион в типовых и много кто их использует для разных задач, так что это будто бы камень не в тот огород
Мне кажется, это очевидно и нет такого механизма, про который нельзя было бы это сказать. Я же рассказываю о том, как он работает, а не о том, что его теперь нужно пихать везде и вообще это новый подход к написанию всего кода
Этому нестандартному механизму сто лет в обед, в том числе и в 1С. Есть пулл задач, которые он упрощает, поэтому я о нем рассказываю. Идея была в том, что каждый сам приложит это уже на свою работу
(74)
У вас какое-то странное понятие об объектах: единственное отличие 1С от других языков и исполнителя в том, что в 1С нельзя программно объявлять классы, а нужно создавать объект метаданных. В остальном обработка - это такой же ООП класс, только без наследования. Вы точно также создаете описание полей и функций в любом ООП языке, просто в том языке это буде ограничено конструкцией class Name{}, а в 1С рамками модуля объекта. И потом этот класс точно также нужно будет инициализировать (создавать объект). Если в исполнителе можно от некоторых базовых подкапотных классов сразу писать через точку, то это просто означает создание подобия объекта внутри, которое скрыто от ваших глаз
* На fluent не редко строят api. которым пользуются другие разработчики.
* Используют его для инкапсуляции внутреннего состояния
* Да можно создать метод инициализации состояния, хранить его в переменной, которую пробрасывать в вызовы
* Состояние прячут, чтобы конечный разработчик-пользователь не вмешивался и не менял внутреннее состояние, чтобы не сломать механизм.
* Зачем прятать? Чтобы упростить себе жизнь, приватные реквизиты для того и приватные, чтобы к ним не имели доступ снаружи. Таким образом ограничивается набор возможных состояний, выполняются проверки при установке свойств и обеспечивется консистентность.
* Плюс есть ситуации, когда метод fluent'а возвращает не этот же объект, а другой fluent.
Причины есть, но не всегда они актуальны особенно в 1с.
Обработка - это объект. Реквизиты и ТЧ обработки - публичные свойства обработки. Переменные модуля - приватные свойства обработки
В статье рассказано одновременно о двух принципах: 1) использование текучего интерфейса для компактной записи кода (других преимуществ не вижу) и 2) использование обработки как объекта для сокрытия промежуточных данных (других преимуществ опять же не вижу). Каждый принцип кроме достоинств имеет и недостатки, применять их надо вдумчиво, использовать их можно как вместе, так и по отдельности.
Выделите некоторые комментарии как лучшие - для акцента мыслей.
Допишите в шапке статьи - что метод не универсальный, но полезный в практике 1С, особенно для расширения кругозора - чтобы у всех сразу отпали вопросы...
Вот это красиво и читаемо.
Ожидаем.Что(НекийМассив.Количество()).Минимум(9);Вот это не красиво и не читаемо.
ТекучийКалькулятор = Обработки.ТекучийКалькулятор.Создать();
ТекучийКалькулятор.УстановитьЗначение(0)
.Прибавить(20) // 20
.Отнять(10) // 10
.Прибавить(5) // 15
.Отнять(3); // 12
Результат = ТекучийКалькулятор.Значение; // 12 ПоказатьДаже автор сам об этом пишет:
Да и к ООП то что реализовано имеет очень отдаленно отношение, потому что в 1С этого не заложено. А именно поэтому применение в реальных разработках это можно применить только ради самого применения.
Прикольно, но бесполезно.
Это еще не все.
В языках где есть поддержка ООП объект имеет одну копию и передается ссылка на него, 1С при каждом использовании возвращает весь объект целиком. О ресурсах тоже иногда полезно думать, хотя часто думают "подумаешь пару копий, у нас памяти дофига".
Действительно красивый пример применения приведен в (20)
А теперь посчитаем. В красивом коде создано 38 объектов. А если работает 100 пользователей? 3800 лишних объектов, стоит ли настолько платить за красоту. При этом наличие БСП сильно упрощает код приведенный в качестве примера изначального обходясь меньшими затратами.
И BI и мессенджеры и чуть не сайты...
Автор просто показал подход реализовав его на 1с.
Он не заставляет его использовать и про "манну небесную" он не писал.
в комментариях есть ссылки
но пример с калькулятором очень уж неудачный!
(0) Предлагаю добавить полезные ссылки на примеры текучего интерфейса в конец статьи.
-
-
Вы можете заказать платную консультацию или разработку у автора. Будет создан приватный заказ на «Бирже заказов» для автора.
№ 2295585
Создание 03.02.25 13:00
Обновление 03.02.25 13:00
Просмотры 25952
Загрузки 0
Рейтинг
68
Комментарии 127
Код открыт Да
Рубрики Механизмы платформы 1С Работа с интерфейсом
Кому
Разработчик
,
Стажер
Тип файла Нет файла
Платформа 1С:Предприятие 8
Конфигурация Универсальные
Операционная система Не имеет значения
Страна Не имеет значения
Отрасль Не имеет значения
Налоги Не имеет значения
Вид учета Не имеет значения
Доступ к файлу Бесплатно (free)



