Обратная связь, атомарность и масштабируемость

10.09.24

Разработка - Рефакторинг и качество кода

В статье рассматривается отказ от использования процедур и унификация формата ответа функций. Способ описывается на примере развития абстрактной информационной системы, работающей с PDF файлами.

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

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

Следует понимать, что абстрактный пример для статьи максимально упрощен, при этом применение паттерна гипертрофировано. В реальной практике количество кода, узлов и условий намного больше, а использование любых паттернов, включая этот - взвешено и при необходимости.

 

Вводные

Нам поставлена задача - по содержимому файлов PDF создавать данные в информационной базе. Операция несложная, состоит из трех этапов - распознать содержимое документа PDF, создать по содержимому стандартизированные таблицы с данными, а затем реализовать бизнес-логику в учетной системе по этим данным.

 

 

Программный код, который это реализует, будет выглядеть примерно так:

 
 Внутренняя реализация - простейший способ

 

Такой способ реализации прост, последователен, логичен, удобочитаем. Но все это начнет исчезать, когда система поработает некоторое время. Выяснится, что некоторые файлы не обрабатываются. Разработчик заменит процедуру на функцию для возвращения признака успешного выполнения. Затем потребуется видеть, на каких этапах операции возникают ошибки обработки. В коде начнут появляться вставки с выводом сообщений, находиться вставки будут в различных местах кода, на различных слоях.
И даже при таком расширении функциональности (с уже потерянной элегантностью кода) проблемы не решатся - выясниться, к примеру, что вызов производится в некоторых случаях не пользователем, а автоматически, и сообщения некому читать.

 

Обратная связь обработчиков

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

  • Удалось ли выполнить операцию так, как от него это ожидалось?

  • Информационные сообщения, появившиеся в процессе работы;

  • Непосредственно сам результат обработчика (если требуется);

  • Прочая дополнительная информация, требуемая в контексте функциональности (если требуется).

Удобно для этого использовать ответ в виде структуры со следующими ключами:

Ответ = Новый Структура;
Ответ.Вставить("ВыполненоУспешно", Ложь);  // Односложный ответ, всегда булево
Ответ.Вставить("МассивСообщений", Новый Массив); // Всегда массив, может быть пустым
Ответ.Вставить("Результат", Неопределено); // То, что ожидается от функции. При неудаче - Неопределено

Система с таким паттерном информативна, удобна для отладки во всех слоях, замена обработчиков, возможно введение обработчиков возникающих проблем, сбор появившихся сообщений и их сортировка (мы ведь не собираемся выводить пользователю сообщения со всех слоев системы).

Реализация такого подхода:

 

 

 
 Внутренняя реализация с обратной связью

 

Взглянув на программный код выше, возникает разумный вопрос - не избыточна ли такая функциональность?

 - Нет.

Атомарность

Увеличив количество строк кода более, чем в 4 раза, мы создали функцию, которая теперь не только поддерживает масштабируемость собственной внутренней реализации, но так-же может быть легко встроена в часть другой системы, использующей описываемый паттерн. Унифицированный формат ответа исключает различные виды связей процедур и функций, определенных разработчиком локально, и неприменимых в других местах. В некоторых случаях процедуры и функции настолько тесно сплетены, что превращаются в монолит, полностью исключающий их атомарность.

При правильном использовании паттерна напротив, система состоит из автономных обработчиков, которые получают некоторые данные в виде параметров, и всегда возвращают данные в едином формате.

 

Рассмотрим это на примере нашей системы:

Наша разработка по работе с файлами PDF нашла признание в глазах заказчика, и он расширяет ее применение. Поступают новые требования:

1. Файлов теперь будет очень много, система должна справляться с нагрузкой;

2. Поддержка файлов PDF с новым типом таблиц, разделенных табуляцией (TSV);

3. Полноценное использование модуля из внешних систем, в т.ч. с Интернет-сайта заказчика;

4. Просмотр состояния выполнения обработки каждого файла в интерактивном режиме.

 

Масштабируемость

Для системы, не поддерживающей расширение функциональности, пункты 3 и 4 означали бы полное перестроение архитектуры, в некоторых случаях - написание программы с нуля. В нашем же случае атомарность всех обработчиков позволяет разрывать их цепь в любом месте на разные потоки.

 

Пример реализации, когда обработка файла разорвана на отдельные последовательности операций:

  • Получение файла и создание задания на отложенную обработку файла (API - POST);

  • Преобразование данных файла в таблицы значений и сохранение их (регламентное задание 1);

  • Запись данных таблиц значений в информационную базу (регламентное задание 2);

  • Запрос подробного состояния обработки файла и формирование отчета о выполнении (API - GET).
 

 

 
 Создание задания на обработку регламентными заданиями
 
 Преобразование файлов в данные
 
 Формирование отчета о выполнении задания

 

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

Если проанализировать код, видно, что он весь пронизан таким способом построения кода. Код стал шаблонным, однообразным, и как следствие, удобочитаем.

 

Заключение

Описываемый способ особенно актуален при работе с внешними сервисами и/или в многослойной архитектуре приложения. Однако использование его в тех местах, где это не требуется, может привести к определенным проблемам. Разработчик определяет, опираясь на систему сдержек и противовесов, собственного опыта и правил разработки, как паттерны использовать.

разработка программирование чистая архитектура паттерн обратная связь атомарность масштабируемость расширяемость

См. также

Рефакторинг и качество кода Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В последнее время термин «чистый код» стал очень популярным. Появились даже курсы по данной тематике. Так что же это такое?

16.09.2024    13211    markbraer    64    

38

Рефакторинг и качество кода Бесплатно (free)

Для быстродействия большой базы данных важно не только оптимизировать запросы, но и соблюдать стандарты при разработке подписок на события, обработок для массового изменения данных, в реализации обработчиков обновления, расширений, регламентных заданий и в архитектуре СКД-отчетов. Расскажем о нюансах разработки компонентов большой системы.

28.08.2024    1086    Chernazem    3    

6

Рефакторинг и качество кода Программист Бесплатно (free)

SOLID – принципы проектирования программных структур (модулей). Акроним S.O.L.I.D. образован из первой буквы пяти принципов. Эти принципы делают код более гибким, упрощают разработку. Принято считать, что принципы SOLID применимы только в объектно-ориентированном программировании. Но их можно успешно использовать и в 1С. Расскажем о том, как разобраться в принципах SOLID и начать применять их при работе в 1С.

22.08.2024    9713    alex_sayan    41    

49

Рефакторинг и качество кода Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Рассмотрим основные принципы шаблона проектирования "Стратегия" на простом примере.

25.06.2024    4024    MadRave    34    

27

Рефакторинг и качество кода Программист Платформа 1С v8.3 Абонемент ($m)

В статье расскажу и покажу процесс проведения Code-review на примере обработки с GitHub.

1 стартмани

04.06.2024    6150    mrXoxot    55    

42

Рефакторинг и качество кода Платформа 1С v8.3 Бесплатно (free)

Поделюсь своим опытом аудита кода авторских продуктов с Infostart.ru как одним из элементов применения DevOps-практик внутри Инфостарт. Будет настоящий код, боевые скриншоты, внутренние мемы от команды ИТ-лаборатории Инфостарт и прочее мясо – все, что любят разработчики.

10.04.2024    13073    artbear    85    

108

Рефакторинг и качество кода Программист Платформа 1С v8.3 Россия Бесплатно (free)

Предлагаю вашему вниманию советы мастеров древности. Программисты прошлого использовали их, чтобы заострить разум тех, кто после них будет поддерживать код. Гуру разработки при найме старательно ищут их применение в тестовых заданиях. Новички иногда используют их ещё лучше, чем матёрые ниндзя. Прочитайте их и решите, кто вы: ниндзя, новичок или, может быть, гуру? (Адаптация статьи "Ниндзя-код" из учебника JavaScript)

01.04.2024    4121    DrAku1a    15    

39

Рефакторинг и качество кода Программист Бесплатно (free)

В новом материале мы анализируем, как в программировании баланс между быстротой разработки и тщательной проработкой кода влияет на конечный продукт. Обсуждаем, почему иногда важнее сосредоточиться на скорости выполнения проекта, и когда можно позволить себе уступить в качестве ради достижения бизнес-целей.

01.04.2024    1260    Prepod2003    6    

2
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Aitbay 13.09.24 10:36 Сейчас в теме
Хорошо описано, по идее мысль не новая, но полезная
acces969; +1 Ответить
2. SirStefan 55 18.09.24 14:32 Сейчас в теме
Тогда уж так, для масштабируемости:
Функция НовыйСтруктураОтвета()
      Возврат Новый Структура("ВыполненоУспешно, МассивСообщений", Ложь, Новый Массив);
КонецФункции
acces969; +1 Ответить
3. acces969 361 30.09.24 08:53 Сейчас в теме
(2) Да, хороший способ. Можно в глобальный модуль добавить. Делаю похожее с непериодическими регистрами сведений, если требуется периодически менять значения ключа записи. Две процедуры находятся в модуле регистра сведений и реализуют чтение/запись в него. Это позволяет исключить проблему, когда трудно найти, в каком месте в коде записываются какие-либо данные в регистр сведений.

Первая функция возвращает пустую структуру, которая затем принимается второй процедурой для непосредственной записи/обновления ключа:

Функция ИнициализацияДанныхКлюча() Экспорт
	
	ДанныеКлюча = Новый Структура;
	ДанныеКлюча.Вставить("КлючBase64", "");
	ДанныеКлюча.Вставить("ПредставлениеКлючаПодписи", "");
	ДанныеКлюча.Вставить("Пароль", "");
	ДанныеКлюча.Вставить("КлючBase64Аутентификации", "");
	ДанныеКлюча.Вставить("ПредставлениеКлючаАутентификации", "");
	ДанныеКлюча.Вставить("ПарольАутентификации", "");
	
	Возврат ДанныеКлюча;
	
КонецФункции

Процедура ОбновитьДанныеКлюча(Ключ, ДанныеКлюча, Запись = Неопределено, ЗаписыватьЗапись = Ложь) Экспорт
	
	Если Запись = Неопределено Тогда
		Запись = РегистрыСведений.ДанныеКлючей.СоздатьМенеджерЗаписи();
		Запись.Ключ = Ключ;
		Запись.ПредставлениеКлючаПодписи = ДанныеКлюча.ПредставлениеКлючаПодписи;
		Запись.ПредставлениеКлючаАутентификации = ДанныеКлюча.ПредставлениеКлючаАутентификации;
		Запись.ДанныеКлюча = Новый ХранилищеЗначения(ДанныеКлюча);	
	Иначе
		Запись.ПредставлениеКлючаПодписи = ДанныеКлюча.ПредставлениеКлючаПодписи;
		Запись.ПредставлениеКлючаАутентификации = ДанныеКлюча.ПредставлениеКлючаАутентификации;	
		Запись.ДанныеКлюча = Новый ХранилищеЗначения(ДанныеКлюча);
	КонецЕсли;
	
	Если ЗаписыватьЗапись Тогда
		Запись.Записать(Истина);   
	КонецЕсли;
	
КонецПроцедуры
Показать


В зависимости от требований и состава регистра сведений, процедура записи может отличаться. Структура инициализации в свою очередь может содержать только данные, необходимые для бизнес-логики, а не все поля записи регистра сведений.
4. SirStefan 55 30.09.24 09:44 Сейчас в теме
Тогда
Функция НовыйСтруктураОтвета()
      Возврат Новый Структура("ВыполненоУспешно, МассивСообщений, Данные", Ложь, Новый Массив, Новый Структура);
КонецФункции
...
Ответ = НовыйСтруктураОтвета();
Ответ.Данные = ИнициализацияДанныхКлюча();


И тогда Ответ.Данные можно и в ЗаполнитьЗначенияСвойств использовать. Или передавать как массив, так и таблицу значений для пакетной записи...
Оставьте свое сообщение