Я хочу поделиться своим опытом – рассказать о том, как я создавал общий модуль с универсальными процедурами, какие ошибки допустил и как их преодолел. Этот модуль позволил мне быстро организовывать множество других HTTP-сервисов и значительно повысил эффективность дальнейшей работы.
У меня более 10 лет опыта в бухгалтерском учете, моя основная профессия – бухгалтер. В то же время я уже более 18 лет занимаюсь программированием на 1С. В моей биографии есть и еще один интересный факт – я был преподавателем в вузе.
Сейчас я работаю в подразделении компании «Самокат», которое отвечает за подготовку и сбор отчетности. Хочу подчеркнуть: эта статья не касается каких-то внутренних секретов фирмы. Это рассказ о личном опыте, о задачах, с которыми я столкнулся, и о том, как я их решил.
Статья ориентирована на практиков, но в то же время может быть полезна и начинающим программистам – я покажу, какие ошибки можно избежать и как выстроить более эффективный стиль работы. Практикующим разработчикам она даст возможность сравнить подходы и увидеть, как результаты своего труда можно превратить в дополнительные преимущества и применить их в будущем.
Руководителям же, возможно, будет интересно задуматься о том, как можно повысить эффективность и продуктивность команды с помощью определенных методов разработки. Возможно, какие-то из них уже применяются у вас, а какие-то – станут поводом к размышлению.
Для начала я хочу задать вопрос, к которому мы вернемся в конце статьи: что является результатом работы программиста?
Когда я решал задачи, исправлял ошибки, дорабатывал функционал, этот вопрос всегда был для меня актуален.
Главное – начать: создание первого сервиса
Более пяти лет назад компании понадобился HTTP-сервис. На тот момент я был разработчиком среднего уровня и почти ничего не знал об этой технологии. Я лишь понимал, что такая возможность существует в конфигурации 1С. Передо мной поставили задачу попробовать разработать HTTP-сервис.
У нас была база 1С с определенными данными, и эти данные нужно было передавать сотрудникам – либо в мобильные приложения, либо на сайт. Это позволило бы сократить время на передачу информации и повысить эффективность работы: сотрудники мгновенно узнавали о предстоящих планах и задачах.
Сначала мне поручили разработать всего один метод. Он должен был предоставлять информацию о планах выпуска продукции для каждой торговой точки. В результате каждый продавец через сайт или мобильное приложение мог увидеть свой план.
Это сразу дало ощутимый эффект: информация доходила до сотрудников напрямую, без посредников и звонков. Все знали, какие планы на сегодня и какие задачи нужно выполнить.
Рост и хаос: расширение функциональности без архитектуры
Дальше история развивалась так: сервис понравился бизнесу, и появились новые запросы: «Давайте добавим еще пару методов: получение списка пекарен и торговых точек, информацию по сотруднику, данные о заработной плате и так далее».
В итоге за три месяца выросла довольно объемная система, которая, мягко говоря, «режет глаз» любому опытному разработчику – особенно тому, которому потом предстояло ее сопровождать.
Представьте: десятки методов с похожими названиями, не всегда отражающими суть, и поддерживать все это становилось все сложнее. Это был довольно неприятный момент: расширять систему стало тяжело.
Задача ставилась по принципу: «Сделай, а мы потом как-нибудь оптимизируем». В результате внутри каждого метода оказывалась огромная «портянка» кода: проверка параметров, их преобразование, запросы к базе, обработка данных, формирование результата и еще куча дополнительных процедур.
Пока методов было пять – жить было можно. Но когда их стало за 30, потом за 50, поддержка превратилась в реальную проблему. На 60-м методе система буквально «захлебнулась». Бизнес получал выгоду от HTTP-сервиса и требовал его развития. Но для разработчиков ситуация становилась все тяжелее: средняя оценка на реализацию одного метода доходила до пяти часов, а для сложных случаев – значительно больше.
Возникла серьезная проблема: мы сделали API, но оказалось, что при развитии API в каждом методе требуются дополнительные проверки.
Например, нужно было проверять версию приложения и отклонять устаревшие запросы. Логично было бы вынести эту проверку в одно место, но по факту ее приходилось прописывать в каждом методе вручную. А если появлялись новые обязательные требования, доработка превращалась в трудоемкий процесс, который отнимал много времени и сил. При этом конфигурация постоянно развивалась: появлялись новые реквизиты, которые нужно было включать в ответы. Чтобы обновить метод, приходилось лезть в его огромный код, разбираться в параметрах и переписывать логику.
В итоге поддержка стала занимать все больше времени. Система превратилась в «чемодан без ручки»: передать ее стороннему разработчику было почти невозможно, а поддерживать самим становилось все тяжелее.
Но, как говорится, голова у нас есть – и решение мы все-таки нашли.
Анализ затрат времени: что именно отнимало ресурсы
Я не зря упоминал свой опыт преподавания и анализа хозяйственной деятельности. Он помог мне взглянуть на процесс со стороны и задать себе вопрос: а на что именно мы тратим время при разработке каждого метода API?
Во-первых, на добавление нового метода http. Нужно было прописать метод, выбрать тип метода GET/POST, назначить для него процедуру, а также обязательно добавить общие процедуры в начале и в конце. Если что-то забывалось, приходилось возвращаться и переделывать. В среднем это занимало 1–2 часа. Сразу уточню: часы условные, где-то уходило меньше, где-то больше, в зависимости от ситуации.
Во-вторых, на проверку обязательных параметров. Нужно было убедиться, что все необходимые параметры переданы и корректны. Это отнимало примерно час, потому что код представлял собой «портянку» с проверками: есть ли параметр и соответствует ли он требованиям.
В-третьих, на преобразование параметров, проверку на их существование. Все параметры, которые поступали в базу, нужно было проверять и преобразовывать. Если формат не подходил или данных просто не существовало в системе, необходимо было вернуть корректное сообщение. Например, если прислали неверный УИД, об этом нужно уведомить получателя. На этом этапе я еще подробнее остановлюсь позже.
В-четвертых, на проверку на правильный регистр принимаемых значений. Особенно эта проблема проявлялась при работе со сторонними компаниями и мобильными разработчиками. Важно было заранее договориться, в каком регистре приходят параметры, потому что для 1С регистр символов критичен. Если хотя бы одна буква оказывалась в верхнем регистре, метод уже не работал. Это была настоящая боль: если разработчик мобильного приложения забыл про договоренность или включил автоматическое форматирование к нижнему регистру, то все ломалось. На отладку таких ошибок уходило немало времени.
И, в-пятых, на самое трудоемкое – на выдачу результата. После того как параметры проверены, нужно было подготовить запрос, затем упаковать его в структуру или массив структур и только потом отправить на сериализацию. Именно на этом этапе тратилось больше всего времени. Причем ошибка могла скрыться в мелочи: вы доработали запрос, но не поправили выдачу, и нужный параметр не вернулся получателю. Приходилось снова проверять и перепроверять все, что отправлялось наружу.
Первые улучшения: универсальные функции и роутер
Я решил эту проблему с помощью нескольких подходов.
1. Унификация повторяющихся действий. Я понял, что все шаги при создании метода API однотипные и универсальные. Их нужно было вынести в одно место: передавать параметры в функцию, а она уже возвращала готовый результат.
Первая большая проблема заключалась в огромном списке методов API. Это все я отправил в роутер. В 1С есть есть такая функция, как шаблон, и мы сделали два варианта: с одним параметром и с двумя. Он уходил в функцию, которая осталась в модуле HTTP-сервиса. Там выполнялись проверки входящих данных и добавлялись необходимые завершающие процедуры. Основная логика при этом перенаправлялась в общий модуль, который отвечал за работу этого HTTP-сервиса.
Таким образом, при добавлении нового метода мне больше не нужно было менять код роутера. Достаточно было задать название метода, его параметры и команду, а также добавить функцию в общий модуль. Это значительно сократило время разработки.
2. Проверка обязательных параметров. Для каждого метода нужно было убедиться, какие параметры и в каком формате пришли. В большом массиве значений легко потерять опечатку, а код зачастую писался копипастой – самый рискованный подход: где-то не поправил имя параметра, и весь метод перестает работать, время уходит на отладку.
Что я сделал? Написал универсальную функцию для проверки обязательных параметров. Я приводил имена параметров к нижнему регистру и передавал в функцию список обязательных полей. В зависимости от типа запроса (GET или POST) функция смотрела либо в строку запроса, либо в тело и возвращала результат: все ли параметры есть и корректны ли они.
Если проверка не проходила, функция сразу возвращала список недостающих параметров. Раньше, когда проверки были «вшиты» индивидуально, метод спотыкался о первый отсутствующий параметр, мы его добавляли – и только потом выяснялось, что не хватает еще одного. Теперь же сразу приходил полный перечень того, что нужно добавить. Это оказалось гораздо удобнее: мобильный разработчик сразу видел, какие данные он не передал.
3. Преобразование параметров. Большинство запросов содержали одинаковые параметры: дата начала, дата конца, номер торговой точки, код торговой точки, УИД и т.д. Поэтому я создал функцию, которая брала эти параметры после проверки и преобразовывала их в нужный формат.
Если преобразование было невозможно (например, неверный УИД документа или отсутствующая запись), функция возвращала ошибку, и я передавал ее пользователю.
Эта оптимизация сильно сократила время работы: написание преобразования занимало около 10 минут. Единственным исключением было появление новых параметров – тогда нужно было зайти в функцию и добавить логику. Но это была уже точечная доработка.
Еще один скрытый плюс этой функции – стандартизация параметров для взаимодействия с мобильными разработчиками. Раньше, например, один и тот же параметр мог называться по-разному. Из-за этого приходилось постоянно проверять, какой именно параметр и куда передавать. Теперь же установились единые названия, что значительно упростило работу и уменьшило количество ошибок.
Оптимизация выдачи результата и обработка регистра
Как я уже говорил, самым трудоемким этапом была подготовка запроса в готовый результат. Прошу не кидаться помидорами, если заметите ошибки в коде – так оно было на самом деле, и я объясню почему.
У нас уже были готовые параметры, они были проверены и преобразованы. Теперь нужно было сформировать запрос к базе, получить выборку и упаковать ее в массив для выдачи через API. В начале этот процесс делался «точечно»: каждая структура формировалась через цепочку точек. Почему так получилось? Первоначально это был тестовый вариант: «Давай сделаем, проверим, работает ли, а потом отрефакторим». Через точку было самым простым решением. Я взял из конфигурации код трехлетней давности и он до сих пор такой. Сами понимаете, что эффективность и скорость работы при большой нагрузке, при большом количестве запросов API падала за счет такой структуры.
Я сделал универсальную функцию, которая обрабатывала результат запроса, который приходил из 1С.
-
По каждому полю назначались названия ячеек,
-
Если была вложенная выборка, она автоматически формировалась в массив структур,
-
Все названия полей теперь соответствовали структуре API.
Теперь, чтобы изменить API, не нужно было менять выдачу вручную: достаточно было добавить поле в запрос, и функция сама преобразовывала его в готовый результат. Благодаря этому время на подготовку нового метода сократилось до одного часа.
Еще одна встроенная функция, которая была вложена во все функции, работавшие с этим сервисом, переводила ключи параметров в нижний регистр. Раньше проблемы возникали, если мобильный разработчик присылал параметры с заглавной буквы. Теперь таких ошибок не было – это ускоряло работу и исключало лишние проблемы.
Для удобства я сделал фиксированную структуру ответов. Каждый ответ содержал описание ошибки или результат, готовый к отправке клиенту через API. Это также существенно сократило время разработки новых методов.
Как видите, новая функция API уже была достаточно простая. Я добавлял обязательные параметры, проверял их, затем преобразовывал, далее делал с ними какие-то манипуляции, например, если параметрам нужно было получить какой-то документ. Далее я делал запрос, который мог сразу редактировать в том виде, в котором его нужно выдавать пользователю, и возвращал. То есть дорабатывать такие структуры стало проще.
И тут мне пришло озарение, что это очень удобно, когда мы делаем какие-то универсальные процедуры, универсальные функции, которыми мы можем пользоваться в дальнейшем.
Создание общего модуля и его повторное использование
Всю эту функциональность я объединил в единый крупный модуль, в котором были собраны все необходимые компоненты. Однако бизнес постоянно развивается и требует новых решений. В какой-то момент возникла задача создать новый микросервис на платформе 1С. При этом существующий сервис работал стабильно – мы его практически не трогали, лишь изредка добавляя небольшие функции. Учитывая накопленный опыт, я решил действовать максимально просто: я скопировал готовый модуль в новую конфигурацию.
Что это дало? Когда у тебя есть наработки и понимание системы, все кажется проще. Первоначальная оценка сроков на создание базового HTTP-сервиса составляла около 40 часов. Мы реализовали его буквально за два дня – уже через два рабочих дня сервис был в рабочем состоянии. Таким образом, мы сократили время разработки в разы.
Однако вскоре столкнулись с новой проблемой. Новая база была создана с нуля и изначально предполагалась как простое хранилище данных – информационная система для пользователей. Ее настройкой и наполнением занимался, по сути, джун-разработчик: добавлял реквизиты, табличные части, немного правил формы. Сложной разработки не требовалось.
Однако со временем в эту базу начали активно вводить данные, которые оказались критически важны для пользователей по всей России. Речь шла о базе рецептур: сначала появились ингредиенты, затем технологические процессы, аналоги, сырье, параметры качества и т.д. База начала активно разрастаться.
Возникла потребность в том, чтобы данные из этой базы оперативно и автоматически попадали в другие системы – без постоянного вмешательства middle-разработчиков, согласований API и ручных правок. Ведь каждый запрос на обновление интерфейса требовал времени и ресурсов.
Используя опыт разработки стандартных процедур, я пришел к выводу: все можно сделать гораздо проще. Я реализовал механизм, при котором объект из 1С самостоятельно «разбирается» и преобразуется в структуру, готовую к передаче через API.
Если в объекте появляется новый реквизит – он автоматически включается в ответ. У нас уже были функции формирования ответа, и я просто научил их динамически обрабатывать структуру объекта.
Например, у нас есть универсальная функция «ПолучитьСтруктуруОбъекта». Она анализирует тип данных и в зависимости от этого определяет, как его обрабатывать:
-
Если это простые типы – возвращает их напрямую,
-
Если это документ – рекурсивно извлекает все нужные реквизиты,
-
Если это справочник – на основе метаданных формирует соответствующую структуру.
Эта функция универсальна и не зависит от конкретной конфигурации. Она работает одинаково, независимо от того, какие изменения происходят в базе.
Такой подход позволил нам отказаться от постоянных согласований и ручного обновления API. Теперь данные всегда актуальны, а интеграция – гибкая и масштабируемая.
Применение модуля в других задачах и его ценность
В результате всех этих действий у меня появился общий модуль, который решал множество задач.
И оказалось, что его можно использовать и в других ситуациях. Например, при разработке других сервисов. В таких случаях мне достаточно было просто скопировать общий модуль, передать туда необходимые данные и получить готовый результат.
Фактически, работа с запросами и обработка ответов уже была автоматизирована: модуль собирал данные, обрабатывал их и выдавал результат. Благодаря этому разработка новых сервисов стала очень быстрой: сервисы с двумя-тремя API создавались буквально за неделю.
Далее возникла ситуация с отраслевым решением, где требовалось наладить выгрузку данных. И снова очень помог наш общий модуль.
Я просто взял содержимое объектов по списку запросов и выгрузил их в формате JSON. Этого было достаточно, чтобы на принимающей стороне обработать данные и загрузить их в другую конфигурацию именно в нужном формате.
Таким образом, за короткий период удалось создать универсальные и эффективные обработки, которые решали задачу быстро и надежно.
Результат работы программиста: что остается после нас
Теперь вернемся к вопросу: что является результатом работы программиста? Что мы оставляем после себя?
Когда я несколько раз реализовывал свою работу и делился результатами, я понял, что модуль, который я создал и использовал несколько раз, является моим результатом. Программисты, которым я передал этот модуль, тоже экономили время разработки. То есть результат работы программиста – это код, который могут использовать другие члены сообщества.
Когда я сам использовал этот модуль, я думал: «Если бы он у меня был раньше, сколько времени можно было бы сэкономить!»
Здесь хочу провести метафоричную аналогию со строительством пирамиды Хеопса. Когда у меня появился модуль, я подумал: возможно, другие разработчики тоже создают такие инструменты. Если каждый из нас будет создавать модуль и делиться им с сообществом, я думаю, что это может привести к позитивным результатам, так как мы сможем создавать более крупные объекты, а не маленькие пирамиды. Сложив результаты труда нескольких программистов, мы сможем решать новые задачи и делать такие проекты, которые удивят весь мир.
Из вложения к этой публикации можно скачать мой модуль и использовать его в своей работе. Там находятся все функции, о которых я рассказывал. Сейчас модуль требует наличия БСП, но в будущем я планирую сделать так, чтобы его можно было использовать с нуля.
*************
Статья написана по итогам доклада (видео), прочитанного на конференции INFOSTART TECH EVENT.
Вступайте в нашу телеграмм-группу Инфостарт