Почему уходят из 1С?

в 22:31, , рубрики: , 1с не звали, Карьера в IT-индустрии, Программирование, свитчер, управление разработкой

Всем привет. Я – бывший разработчик 1С. Я устал от 1С и его ограничений, свой "каминг-аут" я совершил в середине 2021 года.

Периодически меня мучают "фантомные боли", и я захожу на сайты 1С-ной тематики в надежде, что в очередном релизе платформы 1С (по сути, это стековая виртуальная машина, как, например, JVM) наконец-то "смогли". Да, но нет.

Взять хотя бы реализацию регулярных выражений в платформе – в других ЯП процессор регулярок представляет из себя отдельный класс, в котором определены методы для обработки строк. Видимо, 1С-программисты не достойны ничего, кроме трех куцых функций.

Или недавно прочитал, что при ТиИ (процесс тестирования и исправления базы данных) данные копируются на клиентский компьютер для анализа.

Такие находки отрезвляют меня и возвращают к реальности.

Недавно я наткнулся на статью Андрея Овсянкина, где он вкратце сказал, что 1С-программисты – мушкетеры, а программисты из других стеков – слепые котята.

Я решил написать "ответочку", поскольку у меня есть обширный опыт в IT.

Я программирую уже более 20 лет, а самое главное – я видел программистов из обоих миров.

Про взаимоотношения бизнеса и IT-специалистов

В начале статьи Андрей представляет бизнесменов как недальновидных людей, которые ничего не хотят понимать, и им приходится "терпеть" чересчур заумных IT-шников. Почему именно программисты? То же самое можно сказать про отношение к любым высококвалифицированным специалистам. Обычно такое поведение присуще ларечникам, которым IT не нужен, или когда автоматизация делается ради галочки, без реальной необходимости.

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

Еще одна причина, по которой бизнес недолюбливает программистов – срыв планируемых сроков, недопонимание аналитиками требований и того, что напрограммировали в итоге.
В таких ситуациях виновата вся цепочка: руководители отделов – в том, что выстроили методологию разработки некорректно, например, спринты слишком длинные; бизнес-аналитики – в том, что некорректно поняли функциональные требования заказчика; программисты – в том, что бездумно кодили по ТЗ и не сообщили руководству о явных нестыковках.

Если же требования собраны корректно и на предприятии работают профессионалы, обычно сроки соблюдаются и пишется то, что ожидалось.

В статье Андрея однобокий взгляд на вещи, что-то из 90-х – вокруг ларечники, и программист всегда виноват.

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

Как я вкатился в 1С

Кратко расскажу про свой путь в 1С-болоте. В далеком 2009-м я вкатился в 1С, в провинции просто не было другого способа попасть в IT. Я решал типовые задачи на БП, УТ, ЗУП в местном франчайзи (самая натуральная 1С-галера, много заказчиков, нужно быстро решать задачи, прокачиваешься в скорости, но не в качестве кода). Через полтора года я ушел на фриланс. Проработал так около 8 лет. Дорабатывал, в основном, УТ 10.3 (решение 1С для управления оптовой торговлей), создал множество самописных конфигураций (то есть решений с нуля) на основе БСП (платформенный фреймворк от 1С).

Через пару лет, помимо фриланса, я взял на постоянную поддержку предприятие, где генеральный директор сходил на сеанс гипноза в местный франчайзи и ему там внушили, что срочно нужно переходить с УТ 10.3 на УТ 11 (которая внутри совершенно другая). Непонятно зачем, но надо.

Переубедить я его не смог, да и сам процесс был запущен, предыдущий программист как раз уходил оттуда. Видимо, по причине того, что не справлялся. Там я впервые столкнулся с кондовым отделом бухгалтерии, с тетеньками 50+, у которых программист всегда виноват и в апреле (время сдачи налоговой отчетности) всегда аврал.

Через год УТ 11 успешно была внедрена. На тот момент я решил, что хватит с меня типовых, от задач в УПП/ERP (самое главное решение от 1С) и ее компонентах (УТ, БП, ЗУП, КА) уже подташнивало.

И что бы мне ни говорили 1С-программисты, большая часть их задач лежит в этом заколдованном круге кусочков большой конфигурации. Это либо отчеты, призванные показать руководителю все в одном месте, либо обработки, призванные упростить какую-то хозяйственную операцию, либо отдельная подсистема, чтобы автоматизировать "уникальный бизнес-процесс", либо просто корректировка бизнес-процессов предприятия так, чтобы они ложились в типовую конфигурацию. Как это может не надоесть?

Что можно, а что нельзя на 1С

Как мы знаем, язык 1С компилируется в байт-код подобно другим стековым виртуальным машинам вроде Java, .NET. Кстати, выражаю респект Андрею Овсянкину за его OneScript. Я бы такое не написал.

На 1С не сделать исполняемый файл без зависимостей от вендора. Если та же условная Java дает на выбор целую кучу реализаций JVM, даже GraalVM Native Image, то 1С не дает ничего. Никак не сделать что-то по-настоящему низкоуровневое. Не подключиться к системе, работающей на транспортном уровне TCP/IP без внешних компонент.

При этом писать мультиплатформенные внешние компоненты – дело неблагодарное. Куда чаще в коде конфигураций встречаются COM-объекты, что загоняет решение в определенные рамки одной ОС.

gRPC поддерживается уже в 1С? Что-то мне подсказывает, что нет.

Развернуть 1С в docker-контейнере? А что там с лицензиями? В 2018-м наблюдал, как пару дней коллега пытался завести 1С в docker. Больше всего проблем возникло именно с подключением лицензий из bash.

Как долго ждать нормальной асинхронности (то, что в go называется горутинами, green threads на Java, корутинами в C#) на клиенте?

С веб-сокетами из 1С уже можно работать без внешних компонент?

Как сильно кастомизировать внешний вид UI чисто на 1С? Если нужен свой веб-клиент, его придется писать на Javascript.

Парсер HTML с поддержкой динамических страниц? А как завести Chromedriver или Selenium из 1С?

Нейронные сети, ML и это вот все. PyTorch, Keras из коробки уже завезли?

Возможно, часть из этого можно сделать на 1С, просто у меня не хватает знаний. Если так, то прошу меня поправить в комментариях.

1С – это CRUD для малого и среднего бизнеса, где обычно много табличек. Если нужны таблички с красивой визуализацией, то фреймворк 1С очень круто справляется с этой задачей, но как только нужно отойти немного в сторону, начинаются костыли. Возьмем, к примеру, систему компоновки данных или СКД. СКД – некий построитель отчетов, а ля Jasper Reports, только урезанный и встроенный в ВМ 1С.

В ней можно задать несколько выборок (результирующих таблиц), либо в виде read-only SQL запроса или из объектов в памяти, указать связи между ними по полям одного типа, псевдонимы и заголовки этих полей в результирующем отчете, параметры группировки полей, добавить какие-то дополнительно вычисляемые поля из тех, что заданы в дата-сете, указать параметры форматирования этого дела и вывести на экран в виде таблиц, графиков. Очень удобно, согласен.

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

Поскольку отбор зачастую не ограничивается при разработке, пользователь может запросто повесить базу отчетом с бесконечным периодом в отборе. Но это еще полбеды, программист может вмешаться не во все этапы формирования отчета, и иногда при формировании SQL запроса вылезают забавные глюки, например, когда платформа 1С "подумала" за нас и убрала скобки в операторе WHERE, что привело к некорректной работе этого условия. Не знаю, поправили ли этот баг, скорее всего, нет.

Кстати о настройках – есть 3 варианта настроек: дефолтные, фиксированные и заданные пользователем. Иногда при пересечении фиксированных и сохраненных ранее пользователем настроек выдается сообщение об ошибке, что 1С не знает, что с этим делать. Для пользователя это совершенно не понятная информация, он пытается понять, что это за «фиксированные» настройки и что пошло не так, причем пользоваться отчетом при этом нельзя – нужно сбрасывать настройки на дефолтные.

Еще знатно приседать приходится, когда нужно отобразить не обычную таблицу, а «как в Excel документе». Такие таблички очень любят всякие эффективные менеджеры.

И это только один из примеров универсальной технологии от 1С. В плане велосипедостроения вендор иногда все же идет по более легкому пути и делает обертку над технологиями из большого IT. И похоже, что это делается, чтобы посильнее привязать специалиста 1С к этой экосистеме. Других объяснений я не нахожу.

Что там с IDE?

В мире 1С существует 2 IDE. Первая – православный, непоколебимый конфигуратор. Тут все в духе 1С: возможности, как у IDE из 90-х, очень долгий поиск по модулям (сущности с кодом), нет поиска с учетом регулярных выражений. Вечно приходится ждать, теряя самый драгоценный ресурс в жизни человека, даже на небольших проектах. Заходишь в конфигуратор и ждешь, запускаешь режим 1С Предприятия (то есть режим, в котором виртуальная машина 1С исполняет написанный код) и ждешь. А иногда и не заходишь даже, получаешь какие-то непонятные ошибки, для исправления которых приходится лезть в ТЖ (технологический журнал – технический лог виртуальной машины 1С). Это нормально? Открываешь журнал регистрации (технический лог транзакций внутренней ORM 1С) и происходит что-то необычное? Да нет, все так же ждешь. Как я мог не вспомнить про этот шикарный поиск по журналу регистрации! За время ожидания можно сходить "туда и обратно". Прошу заметить, что на том же оборудовании VS Code и Golang летают.

А что насчет "обновлений нетиповой конфигурации" (то есть тиражного решения с доработками других программистов)? Поскольку в git коммит – это атомарная транзакция, а не целый текст модуля, это позволяет определить изменения точечно, а уж про cherry-picking не стоит говорить, в конфигураторе без костылей такое невозможно.

Может быть, я зря нагнетаю, но в каком-нибудь настоящем ЯП вы видели, чтобы костыли, которые улучшают IDE, продавали за деньги? Это я про Турбоконф и Снегопат (костыли для IDE от сторонних разработчиков). Причем Александр Орефков (автор Снегопата) рассказывал, что вендор предлагал ему работу. То есть 1С знает о происходящем, но ничего не меняет. Еще один плевок в лицо сторонников платформы 1С. Ничего, им не привыкать, они утрутся.

А что по совместной разработке? Думаете, они просто взяли и стали использовать git? Ахаха, как бы не так!

Очередная многоходовочка от разработчиков платформы – они создали собственную self-hosted VCS, которую назвали «хранилище конфигураций».

Все это очень похоже на SVN. В данном творении минимальной блокируемой единицей является общий модуль 1С, который представляет из себя кусок кода, инкапсулированный в один текстовый файл с уникальным именем, например, «ОбщегоНазначения». Из-за невозможности создания собственных классов в 1С в таких модулях может храниться довольно разнообразный функционал. Подход с блокировкой большого куска кода выливается в невозможности нескольких разработчиков работать над одним модулем, что вынуждает программистов, которым не повезло редактировать одно и тоже место, поочередно выпрашивать разблокировать редактируемый модуль.

В апреле 2015 года 1С сама же уткнулась в устаревшую IDE и решила сделать все правильно. Они придумали новую IDE на основе Eclipse и назвали ее EDT. Сделано в лучших традициях вендора – все для богатых, высокие системные требования, но все равно довольно низкая скорость интерфейса.

Последний раз, когда я в ней работал, EDT из-под себя вызывала конфигуратор.
Разработка идет до сих пор. И да, там все-таки завезли git.

Эх, если бы дело было только в git’е.

Как ушел из 1С

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

С ребятами из других стеков мы делали решение для сбора и анализа данных на одном из перспективных рынков.

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

Кроме того, нетиповые составляют очень маленький процент рынка труда. Мне пришлось искать работу летом 2020-го года. На одном известном сайте было всего 6 вакансий, где требовалась разработка нетиповых. Ограничения фреймворка 1С и "огромное" количество вакансий еще больше оттолкнуло меня от этой экосистемы.

Я начал учить Java, написал на ней пару пет-проектов, а потом еще и на Golang, который мне очень понравился. После написания очередного пет-проекта я составил резюме на Golang, прошел собеседование и получил хороший оффер на позицию Middle Golang разработчика. Мне дали +25% к тому, что я уже зарабатывал на 1С.

По прошествии полутора лет могу перечислить, что же изменилось:

  • Мне не нужно разбираться, почему в бухгалтерии очередная цифра не так считается.

  • Мне не нужно разбирать ошибки после очередного кривого обновления платформы или конфигурации, и да, делать это "вчера" не нужно.

  • Мне не нужно знать 100500 противоречащих друг другу законов, которые успел напечатать бешеный принтер.

  • Мне не нужно знать, чего же там еще накрутили в платформе, почему я не могу обойти ее недоработки.

  • Мне не нужно очищать кэш пользователей или свой кэш, или еще какой-то кэш!

  • Мне не нужно перезапускать сервер предприятия 1С.

  • Рабочий день состоит на 30% из общения с PM'ами, 20% code review и 50% чистого программирования.

Если попробовать обобщить – это свобода от 1С, костылей, которыми она обросла, и "болота" типовых конфигураций.

Соглашусь, что многое зависит от работодателя, но работать стало легче при всех прочих равных.

К 1С-нику зачастую отношение как к обслуживающему персоналу, и не надо мне тут про "как себя поставишь". Даже если всех "приструнить", осадочек останется. Я знаю, я делал это.

В настоящем программировании меньше общения с пользователями твоего творения, на текущем месте работы его нет. В моем случае тезис Андрея про "ваши заказчики всегда будут вас раздражать" явно не к месту.

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

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

Все это разнится с картиной мира Андрея, там у среднего программиста постоянная депрессия, он всегда уставший, злой и неудовлетворенный.

Кто тут самый умный

Умнее/глупее – примитивное сравнение. За неимением статистики попробую сравнить себя с коллегами.

Тимлид моей команды, как раз "настоящий backend программист", у которого 10+ лет опыта. Он знает пару ЯП для backend разработки, знает про шаблоны проектирования, разбирается в тонкостях работы различных СУБД (в том числе нереляционных), знает про балансировку нагрузок, умеет пользоваться bash, git, CI/CD, Kubernetes и может сделать что-то простенькое на JS, React или Vue. Кроме того, у такого специалиста может быть более разносторонний опыт в архитектурном плане, а не только написание CRUD приложений для бизнеса.

Все ли из вышеперечисленного умеет средний 1С-программист с опытом 10+ лет? Может, кто-то и может, я – нет.

Очень жаль своего времени, потраченного на vendor-lock'нутый CRUD-фреймворк, жутко разросшийся с годами.

"Настоящие программисты" заморачиваются с SOLID? Как написано в книжке "Совершенный код" Стива Макконнелла, "Самые дорогостоящие ошибки – это ошибки проектирования". Мой опыт в программировании подтверждает этот тезис. Если другой ЯП дает возможность грамотно спроектировать иерархию классов / структур / зависимостей, почему бы этого не сделать сразу, чтобы потом не было мучительно больно?

А что дает 1С для структуризации кода? Общие модули? Смешно, ей-богу. Это то, что в Java и Golang называется пакет, но код нужно держать в одном файле, т. е. очередная насмешка над 1С-программистами со стороны вендора.

"Настоящие программисты" заморачиваются со сложностью алгоритмов? И правильно делают. Сложность алгоритма явнее видна на больших объемах. Если не думать об алгоритмической сложности или подкапотной работе с типами, например, можно на конкатенации большого объема строк ждать 8 часов (вместо 20 минут после оптимизации). Однажды я словил такую неприятную особенность 1С на продуктиве. Это было больно.

И если взять 1С – что плохого в использовании даже тех малых возможностей по выбору структур данных, которые предоставляет фреймворк 1С? Иногда лучше использовать соответствия (хеш-таблицы) вместо массивов (динамические массивы).

Не вижу ничего плохого в том, чтобы заблаговременно обойти острые углы. Это называется планирование.

Ограничения 1С работают во благо

"Настоящие программисты" много думают про техническую реализацию? Думаю, это потому, что их предыдущий опыт подсказывает, что и где может сломаться. Что плохого в том, чтобы проанализировать время добавления в список? Это влияет на UI и UX от конечного продукта.

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

Поэтому даже на SSD-дисках и многоядерных процессорах формы списков в типовых конфигурациях открываются по 5 секунд, и ничем это не исправить, так как у 1С-программиста таких средств просто нет, и жадный вендор не планирует менять положения вещей.

Легче ведь сказать, что "ограничения платформы во благо".

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

"Настоящие программисты реально не понимают, что нужны не код и не программа, а достижение цели"? Градус безумия повышается, сложно комментировать такие "заказные" суждения.

Могу рассказать, как разработка ведется на моей работе.

  • Сначала бизнес-аналитики снимают требования с бизнеса, хотя это можно сделать самому. Будучи 1С-программистом, когда мне приходилось писать собственные решения, я сам ходил по отделам и собирал требования. Ничего сложного в этом не вижу.

  • Почему я мог это без труда сделать, а "настоящий программист" не может?
    На основании первичных требований создаются "истории" в Jira. После изучения этих "историй" на коллективные встречи собираются аналитики, дизайнеры и руководители подгрупп разработки, обычно это ведущие программисты. Подгруппы формируются по какой-то доменной области в приложении.

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

  • На основании встреч аналитики пишут/дорабатывают спецификации. И так несколько итераций до достижения ясности того, как функционал должен работать и выглядеть.

  • После чего ставятся задачи на доработку программистам. Если ясности нет, ставится задача на "изучение проблемы".

Я согласен с таким подходом. Я не пишу код, если не понимаю, чего нужно достичь в итоге. Мой опыт говорит, что когда автоматизируешь хаос, получаешь автоматизированный хаос.

Как можно автоматизировать то, чего до конца не понимаешь? Кто в понимании Андрея "настоящий программист"? Сферическая макака в вакууме?

Даже не знаю, чем провинились именно Java, .NET и PHP-программисты, что их выбрали в качестве козла отпущения в оригинальной статье.

Автор каким-то образом даже подсчитал, что именно 80% из них не думают, когда программируют. Наверное, у него есть какая-то статистика, которую он вручную собирал.

А чего тогда не сразу 140% всех программистов, кроме 1С-программистов? Если уж "топить", то до талого.

При запуске модули не стыкуются, пересылается не то, и в целом происходит караул? Так скорее пишутся типовые конфигурации, иначе как объяснить ошибку, которую я нашел в коде УТ 11 после очередного обновления от вендора.

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

А почему? Потому что строка в "Иначе" "уехала" за видимую область экрана в конфигураторе.

И это, на минуточку, в тиражном решении, купленном за деньги. Ленивые и жадные. Да, это про 1С.

В ЯП, которые компилируются в машинный код, такая ошибка просто не пережила бы сборку проекта.

В других "настоящих" ЯП для защиты от подобных ошибок есть модульные и интеграционные тесты, которые упадут в CI/CD pipeline при коммите.

Да, в 1С есть автоматизированное тестирование, Vanessa и другие инструменты. Но почему даже вендор не использует их? Почему тестирование остается уделом небольшой части энтузиастов?

Фреймворк 1С помогает в мелочах, о которых 1C-ники даже не задумываются? Все это действительно так, пока пишешь небольшую конфигурацию для знакомого из соседнего подъезда, там, где нет особых пожеланий по скорости или масштабируемости решения.
А когда бизнес усложняется, почему-то формула 1С перестает работать. Недавно жадный вендор все-таки придумал кое-что для масштабирования – Дата акселератор. Правда, это было сделано в свойственной 1С манере, разделив функциональность на ПРОФ и КОРП лицензии. Двух зайцев сразу – придумали костыль и заодно потоптали людей, симпатизирующих платформе.

Нельзя же просто взять и сделать в платформе библиотеки для низкоуровневого взаимодействия на уровне TCP/IP с каким-нибудь существующим во взрослом программировании решением.

Это не 1C way, 1С way – как у афроамериканских реперов – деньги превыше всего, даже здравого смысла. А иначе зачем 1С придумывать свою шину обмена сообщениями, свою in-memory БД + OLAP в виде Дата акселератора, свой Skype в виде "Системы взаимодействия". Что дальше? Социальная сеть 1С? Каждый раз удивляюсь находчивости вендора – а как это нельзя, если на самом деле можно?

Насколько убого сделано распараллеливание, даже говорить не стоит. Это оскорбление IT-инженеров, какой-то костыль в виде чтения сообщений из другого сеанса, порождающий решения в виде сбора сериализованных данных оттуда. Это еще ничего.
Самое смешное, что на каждый недопоток или "фоновое задание" требуется лицензия. Шах и мат, 1С-ники! Многие предприятия просто ставят взломанный сервер 1С предприятия, то есть фактически нарушают закон. Так вендор заботится о людях, которые покупают их продукты? Вкусно и точка! Кушайте, не обляпайтесь.

Если мне не изменяет память, при одновременной работе более 1000 фоновых заданий, метод "ПолучитьФоновыеЗадания" отдает только первые 1000 из них. А зачем вам больше? Вы что там, биткоины майните? Хотя что это я нагнетаю. Вон, в 22-м релизе 1С завезли community edition, а также функции замены строк и логарифмы в запросах. Так можно и с колен подняться. Остановитесь!

ORM в 1С – самый лучший

Вернемся к тезисам про "благие ограничения платформы 1С". В оригинальной статье указано, что когда в 1С одна база данных – это хорошо. Я, кажется, понял: 1С – это российский Apple, ведь если Ваш автомобиль не поворачивает, Вам этого не нужно. 
Поэтому в 1С мы пилим "монолитного монстра", которого пересаживаем на Дата Акселератор, и платим за КОРП лицензию, когда он станет слишком неповоротливым из-за огромных размеров.

В одной из высоконагруженных самописных конфигураций, с которой я имел дело, один из разработчиков, работавший ранее в одном из операторов связи, пришел к прямому чтению данных 1С из MS SQL. И это работало быстрее, чем платформенный ORM. Представляете, что за безумие творится под капотом 1С? Ограничения во благо. Повторяем, даже если звучит убого.

Еще в 1С нет соблазна налепить интеграцию "прочитаем из базы соседей"? Где, а главное – в окружении кого работал Андрей? Если обратиться к замечательной книжке про переход от монолита к микросервисам, там на первых же страницах написано: "Не давайте прямого доступа к внутренностям вашего сервиса и проектируйте ваш API, исходя из потребностей пользователей, а не ваших догадок. Контракты API должны содержать только те данные, без которых не обойтись".

Этот подход позволяет избежать ситуаций, когда "другая команда удалила или переименовала какую-нибудь колонку в своей базе, и у вас все отвалилось".

Но, видимо, в мире, где "такие интеграции в порядке вещей", подобные и очевидные архитектурные приемы еще предстоит открыть. И, разумеется, "они не будут вас уведомлять об изменениях". Разумеется, вокруг враги, а еще все врут.

На моем предприятии ни у одного из более 2000 микросервисов нет прямого доступа к БД. Даже там, где нужно что-то прочитать из одной известной СУБД, сверху прикручен API, который ставит запросы в очередь. 

Так что ходить в базу другого сервиса – это норма жизни разве что для распределенного монолитного приложения, в микросервисной же архитектуре это жуткий антипаттерн. Этот тезис даже закреплен в общем положении по микросервисам для IT-подразделения о том, как делать "хорошо", чтобы не было "плохо".

Поговорим про ORM. По мнению Андрея, в 1С ORM работает близко к идеалу. Это не совсем так. Данные мы читаем через read-only SQL образца прошлого века, а пишем исключительно через методы-обертки. Кстати, надеюсь, 1С через пару десятков лет разрешит добавлять произвольный отбор в набор записей (таблица с данными для СУБД) регистра сведений (один из классов-оберток встроенной ORM) с несколькими измерениями (индексированные поля в этом классе). Было бы неплохо, имея разнородный набор данных, не прибегать к построчной записи через менеджер (в других ЯП это называется record, "upsert" размером с одну строку).

Судя по тому, что я видел в технологическом журнале – при сохранении набора записей сначала вызывается DELETE * FROM TABLE WHERE с условием отбора по измерениям. Потом делается INSERT в таблицу БД. 

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

В 1С ORM фреймворк самый лучший, потому что единственно доступный. Для той же условной Java есть Hibernate, MyBatis, Sql2o. В Golang есть Beego, GORM. Каждый фреймворк можно подобрать для конкретной задачи. Если очень надо, то можно отказаться от ORM или писать Native SQL-запросы в том же Hibernate. А в 1С можно написать SQL-запрос для создания или изменения сущности? Конечно, нельзя, иначе неопытные однорукие программисты 1С сломают гениальные абстракции над табличками в виде регистров накопления, бухгалтерии, расчетов.

В 1С все стабильно, розовые пони скачут по облакам 1C Fresh – "мы пользуемся объектной моделью и даже не задумываемся о том, как эти данные забираются из базы". Если никто не задумывается, то что же заставило в недрах БСП появиться функции "ОбщегоНазначения.ПолучитьЗначениеРеквизита"?

1С не пытается замести под ковер язык SQL? Из того, что я вижу на форумах, 1С-программисты пару десятков лет просят вендора добавить функциональности, которая давно существует в обычном SQL. Так что вендор, скорее, боится разработчиков 1С, поэтому осторожно разрешает read-only операции, а то вдруг эти люди поверят в себя и попросят еще больше. Согласен, не надо так.

С самых первых курсов, с младых ногтей всех 1С-ников натаскивают на производительность запросов и их оптимизацию? Именно поэтому, придя в одну из обслуживаемых мною далее фирм, я увидел SQL запрос с 60 временными таблицами, который написал уволившийся 1С-программист. Хранить вспомогательные данные не нужно. Это усложняет систему.

Разработчики ORM пытаются совсем спрятать от программиста язык SQL? Да, эти негодяи, придумавшие Hibernate, спрятали его аж в двух местах! Ясно же, решили запутать следы. Сначала сделали анотацию @NamedNativeQuery, а потом еще и в EntityManager сделали метод createNativeQuery. Я до сих пор не знаю, какой из способов использовать. Знаете ли, это работа для IT-специалистов уровня Senior.

Мало того, что спрятали SQL, так еще и "генерируют миллион запросов в цикле, о которых программист даже не подозревает". Да, но все-таки в Hibernate не до конца последовали зловещему плану, потому что забыли запретить настраивать уровень логирования запросов к БД. Ведь кто-то догадается и увидит запросы в логах. Но, как мы знаем, в описываемом Андреем мире у программиста прокачан навык телепатии, логи ему не нужны.

Для 1С наименование ссылки – это примитивная вещь? Да, поэтому в БСП ее достают через функцию с анализом метаданных, читай рефлексией, ненапряжно совсем. Все так делают.

Другие программисты не умеют строить модели данных и очень плохо проводят границы между доменами? Фи, а чего еще ожидать от 80% Java, .NET и PHP-программистов? Они без ТЗ, свитшота и смузи кринжуют, падают с моноколес, какое там IDE открыть. Остановите это безумие!

"Настоящие программисты" не умеют разделять бизнес-процессы на домены? Ладно, мы уже поняли, что 1С-ник – человек-швейцарский нож, а остальные – пыль. Мне понравился класс, приведенный Андреем на слайде:

// Заказчик
public class Customer
{
	// Ссылка
	int Id { get; set; }

	// Наименование
	int Name { get; set; }

	// ИНН, КПП, ОГРН и пр.
	// Встроить этот класс в ту же таблицу - геморрой.
	LegalAttributes LegalAttributes { get; set; }

	// Ссылка на банк (чтоб легло в базу)
	int BankId { get; set; }

	// Банк-объект со всеми реквизитами (чтобы в коде работать)
	Bank Bank { get; set; }

	// Все заказы клиента
	// да, прямо в клиенте, а чо, легко же сделать
	// да, будут считаны все сразу из базы, если не предпринимать действий.
	List<CustomerOrder> Orders { get; set; }
}

При беглом осмотре сразу возникает вопрос к наименованиям. Так заказчик или клиент? Попробую предположить, что, скорее всего, второе, ведь customer'ами кличут клиента системы. В уже упомянутой книжке Макконнелла целая глава посвящена внятным именам сущностей в коде. А то и не одна.

Идем дальше. А для какого уровня в приложении этот класс?

Если это транспортный уровень (transport в backend) или тот же слой представления (view во frontend), то зачем хранить BankId отдельно от сущности Bank?

Нужна ли информация о банке клиенту API или для отрисовки? Если в API или просто на frontend отдаются заказы, то почему нет атрибутов пагинации вроде ID последнего заказа из запроса и количества запрашиваемых заказов? Зачем в принципе отдавать заказы клиента вместе с информацией о нем?

Почему нельзя дать потребителю выбрать, когда он хочет забрать эти данные?

Если это уровень сервиса, то зачем хранить заказы внутри сущности клиента? Если бы у меня стояла такая задача, я бы вытаскивал заказы клиента по кусочкам только тогда, когда они мне реально нужны. Ведь если вытащить сразу все, мне прилетит предупреждение о том, что я израсходовал 100500 GB памяти на сервере. В текущей компании сначала меня пожурят, а затем попросят поискать другое место работы.

Без особой необходимости не нужно ничего оптимизировать. Нужное количество заказов можно вытащить, когда они понадобятся, и обработать их. Необходимо как можно меньше выделять память, тогда будет меньше вызовов сборщика мусора, меньше запросов к БД, меньше сетевого траффика. Это же так очевидно.

Даже если мне внезапно захотелось вытащить все заказы клиента из базы, почему бы не попросить Hibernate делать это, когда есть обращение к getter'у поля Orders с помощью параметра анотации @ManyToOne(fetch = FetchType.LAZY)?

Если это уровень репозитория, то почему так много полей из разных таблиц БД в одном классе?

Ответ на мои вопросы кроется в оригинальной статье, в утверждении "Они не умеют проектировать модель данных". А, понял, все не умеют. Или все же "кто-то умеет, но в среднем – нет"? Да, но нет?

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

Про индексы и DBA

Клиент-серверное взаимодействие в 1С. Это мое любимое.

Еще в бытность 1С-ником я оптимизировал UI в рабочем месте сборщика заказов в УТ 11, потом в самописной конфигурации нужно было рисовать карты в поле HTML-документа. Мне пришлось погрузиться с головой в работу веб-клиента.

В статье или "оде" 1С – очередные жалобы на недокоммуникацию между frontend и backend разработчиками. Я уже сбился считать тревожные звоночки. Разработка представляется паноптикумом – backend'еры не умеют анализировать и общаться с БД и разделять бизнес-логику по доменам, PM'ы постоянно бегают под ногами со своими сроками, DBA молча добавляют индексы в БД, frontend'еры "просто хотят рисовать кнопочки", а сверху сидит ларечник, который никому не хочет платить.

Оказывается, чтобы добавить галочку в этой обстановке, "нужно будет составить ТЗ, проверить результаты работы фронтендеров, провести интеграционное тестирование". На текущем месте работы вот как мы это делаем. У нас еще хуже, чем frontend на Javascript. У нас мобильное приложение, которое так просто, как веб-страницу, не обновишь.

С аналитиками, мобильными разработчиками и дизайнерами на общем совещании мы обсуждаем функционал. Все участвующие задают интересующие вопросы. По результатам совещания создается "История" в Jira, которая обрастает задачами на доработку нужных компонентов. Для галочки такой процесс занимает от силы 2 дня.

Я добавляю флажок в конечную точку API, если нужно, поднимаю версию этой конечной точки.

Мобильные разработчики рисуют галочку в очередном релизе. Дизайнер это утверждает, а QA-инженер тестирует. Ничего архисложного в этом нет, если процесс разработки адекватно поставлен.

И да, в 2022-м люди договариваются, а не сходу требуют ТЗ.

Андрей напишет сервис ради галочки? Стоп. А зачем столько приседаний ради галочки в договоре? Или команда пишет целый сервис для хранения данных договора? Если так, то почему такая непоследовательность? Значит, в сущность клиента/заказчика сразу выведены его 100500 заказов, а тут целый сервис ради галочки или договора.

Выставите и задокументируете API? Автогенерация спецификации swagger из аннотаций в коде, видимо, перестала работать в этом нашем настоящем программировании, да.
Фронтендерам надо рисовать кнопки и чтобы от них отстали? Да, совсем забыл про удивительных мир «настоящего программирования».

Неделя – на выключение поля при установленном флажке! Я не удивлен, учитывая качество человеческого материала, описанного в оригинальной статье. Мне было бы интересно познакомиться с HR, который подбирал такие замечательные кадры. Интересно, в мире HR существует аналог "Золотой малины"?

И да, мне как серверному программисту нужно десериализовать JSON. Опять этот ретроградный Меркурий все испортил и отменил в Spring Jackson ObjectMapper по умолчанию. Сижу и завидую 1С-программистам, им ведь в REST-сервисах не нужно десериализовывать тело запроса. Вернуться что ли обратно в 1С, как считаете?
Продолжаем страдать, дальше мне нужно превратить DTO в то, что ляжет в базу данных по одному полю. А что, переложить данные стало так сложно? При строгой типизации IDE знает о совпадающих полях и сама заполняет их, а я просто получаю удовольствие.
Как это нет функции "ЗаполнитьЗначенияСвойств"?! Хватит с меня этого вашего "настоящего программирования". Если говорить серьезно, то в Java, Golang и, скорее всего, в C# заполнение экземпляров типов с одинаковыми именами полей решается рефлексией. Но думаю, что это избыточная сложность – достаточно переложить одни поля в другие через горячую клавишу в IDE. Конечно, имеется в виду нормальная IDE, а не конфигуратор 1С.

Кстати, на github.com даже кто-то написал эту функцию https://github.com/jinzhu/copier.

Насчет "не забыть про логирование, про права доступа, технический журнал, телеметрию". Логирование в 1С делается очень легко? Решили мы как-то на высоконагруженной самописной конфигурации писать логи, как ребята из соседних команд, в специальный топик в Apache Kafka. Сначала взяли Confluence REST API, он работал нормально, а потом перестал, были фризы при записи на 30 секунд. Затем пробовали внешнюю компоненту от Серебрянной Пули, тоже на удивление медленно. Возможно наши Python-разработчики просто не умели готовить Apache Kafka. Но, в основном, все, что может 1С – это работать не ниже протоколов прикладного уровня, и чаще всего это HTTP-протокол.

Интересный факт – знакомый 1С-программист обнаружил, что полностью аналогичные некеширующиеся HTTP-запросы из 1C и Python к тому же ресурсу API на последнем выполняются в несколько раз быстрее. Почему? Как? Зачем? Это еще с учетом того, что Python имеет славу медленного ЯП.

Чем все закончилось с логированием? При большой нагрузке запись логов работала дольше бизнес-логики, и это со всеми оптимизациями! Какой это по счету шах и мат 1С-программистам? В общем, да, стали записывать в текстовые файлики на сервере! Ограничения во благо же.

Про права

У нас на работе права доступа регулируются отдельным сервисом, который инкапсулирует в себе нужный ограничивающий функционал. И работает он ожидаемо, а не как RLS. Если бы все работало как часы, на всем известном в сообществе 1С-форуме не появлялись бы темы про RLS с таким завидным постоянством.

Телеметрия и технический журнал реализуются в отдельном сервисе.

Не могу не прокомментировать про слишком "много писать, получается спагетти-код, они не умеют пользоваться библиотеками". А кодогенерацию отменили уже? Судя по словам Андрея, в транспортный слой запихивается половина, т. е. 50% кода, который обрабатывает бизнес-логику. А как это пропустили на code review? Что-то не очень с компетенциями в команде мечты.

Да, писать кода приходится много, но зато поведение решения будет ожидаемым. Я могу посмотреть запросы в Chrome DevTools, могу их оптимизировать. Я занимался как-то самописной конфигурацией, в которой был красивый интерфейс – карты рисовались через Leaflet + OpenStreetMap в поле HTML документа (control для webview в 1С), по факту на 1С Webkit. UI часто падал в неожиданных местах, но хотя бы работал со сносной скоростью, я постарался минимизировать количество вызовов сервера. Анализ ошибок был делом мучительным и неопределенным.

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

Могу ли я залезть под капот 1С? Нет, ограничения же во благо. Как я это исправлял? Чисто эвристическим методом находил забавные места, вроде установки "Неопределено" в поле на форме или дробных значений в конструкторе объекта Цвет. Нормально, да?
"Неблагодарный труд" - то, чем вынужден заниматься 1С-программист, попытайся он сделать что-то необычные на этом фреймворке.

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

Так что про то, что права не проектируют – Андрею просто не повезло с коллегами.

Про PDF в взрослом программировании

В настоящих ЯП нет бесплатной и хорошей библиотеки для конвертации PDF? Есть хорошие платные библиотеки, причем чем лучше библиотека, тем жаднее ее авторы. Думаю, что это Андрей про 1С пишет. По поводу бесплатных – для Java на первой же странице поисковой выдачи находятся OpenPDF и Apache PDFBox.

Я видел в исходниках одного государственного сервиса, что они используют OpenPDF для генерации отчетных документов. Для конвертации XLS в PDF есть Spire.XLS. Про конвертацию поговорили. Если стоит задача извлечь текст из PDF с сохранением его порядка, особенно если текст в таблице? Великая и неповторимая 1С не смогла. А в Java получилось с помощью все той же Apache PDFBox.

Даже если что-то не устраивает, я могу это дописать, ведь я могу расширять классы и переопределять методы. Как я могу вмешаться в генерацию PDF в 1С или генерацию кода веб-клиента? Есть 2 варианта – устроиться в 1С и дописать платформу или наделать внешних компонент, но ведь тогда это не чистый 1С, а некого рода читерство. Так что остается первый вариант.

Настоящим программистам приходится плакать, колоться и запускать приложение html2pdf.exe. Хахаха, жалкие неудачники! Другое дело – в 1С: никаких приложений, COM-объектов, внешних компонентов запускать не приходится. Никогда. Вот как много значит безоговорочная вера в непогрешимость вендора.

1С-ники – очень хорошие аналитики

А разве в других стеках программирования очень плохие аналитики? В описываемом Андреем мире программисты на других языках не задают вопросов о задаче. Ведь это те самые недееспособные ребята, которые в слове Class делают 5 ошибок. Не считаю умение анализировать требования чем-то сверхсложным.

Если мне дали непонятные требования, мои действия следующие: я надеваю повязку на лоб, включаю эпичную музыку фоном и начинаю узнавать у всех причастных, чего же они действительно хотели от моего скромного сервиса. Зачем что-то кодить, если придется выбрасывать после уточнения требований?

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

Действительно, только такой человек может встретить нервного менеджера, который еще посмел ругаться с гуру программирования 1С. Программисты из других стеков просто не справятся.

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

Вот почему 1С-ники такие красавчики?

Может быть Agile?

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

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

Но даже с Agile нет гарантии, что не попадешь на некомпетентных руководителей.

Однажды на одном из бывших мест работы IT-директор добавил к нам, программистам, на созвон, PM'ов, они своего не упустили и через каждые 5 минут спрашивали про сроки. В общем, эмоций было немного, но они были яркими.

Стоит ли переходить из 1С на другие ЯП?

В оригинальной статье очень предвзятый и категоричный взгляд на вещи. Есть ощущение, что статья "заказная".

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

В жизни все происходит в свое время. Пока человеку комфортно в 1С, он найдет миллион отговорок про настоящие ЯП, что ничего не поменяется. Как только Вы реально устанете от бесконечных "да, но нет" платформы, решение и алгоритм действий появятся сами собой. У меня случилось именно так.

Я не планировал уходить из 1С, иначе бы действовал гораздо более решительно. Сначала просто хотелось подучить Java, попробовать на вкус это ваше "взрослое IT". Меня зацепило и не отпускает до сих пор. Можно ли сказать, что в 1С я выгорел? Не думаю, я мог бы с тем же успехом дальше писать нетиповые.

В токсичной экосистеме 1С Вы никогда не напишете что-либо выходящее за рамки СНГ. Вендор не хочет выходить на международные рынки, как Microsoft или Oracle. Представитель 1C International, который занимается распространением 1С за пределы родины, в 2020-м мне сказал, что это не 1C way. Они хотят найти разработчика, который уже живет в стране X, знает потребности местного рынка и уже пишет решение, которое как минимум поработит страну пребывания и решит все проблемы человечества разом.
Зачем 1С такому разработчику, когда он уже достиг успеха?

Кроме того, судя по скорости реализации пожеланий от сообщества 1С-программистов в платформе, новых технологий ждать придется не один десяток лет, старые бы подвезли до конца.

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

Рынок 1С – CRUD-приложения для мелкого и среднего бизнеса с визуализацией табличек и обслуживание бешеного принтера.

Да, в настоящем программировании все придется пилить самому, зато можно сделать ровно то, что хочет бизнес. Можно выучить универсальные технологии, применимые не только в 1С, а во взрослом IT, где векторов развития гораздо больше, чем в 1С. Можно работать со всем миром. Поскольку вовлечен весь мир, взрослые ЯП и их экосистемы развиваются гораздо быстрее и динамичнее, чем 1С. Я думаю, это очевидно.

Будете ли вы в итоге скучать по 1С? Я не скучаю, иногда жалею, что не нашел в себе мотивации уйти раньше. Теперь приходится в авральном режиме изучать некоторые технологии из-за того, что в экосистеме 1С все свое.

Разработчики платформы 1С видят, что приток молодых специалистов уменьшился, и это неспроста. Всегда поражался политике 1С. Как можно сделать платным форум со специалистами и платформу?

Вон Embarcadero тоже хочет 5000 USD за лицензию разработчика на Delphi. Только где теперь Delphi? Лично знаю двоих бывших delphi'стов, которые в конечном итоге переметнулись в Java.

По поводу отзывчивости сообщества – пойдите спросите что-нибудь на одном из первых форумов в поисковой выдаче про 1С. На какой странице будет робкая попытка помочь? На 2-й? Сравните с тем, как помогают на stackoverflow.com или forum.golangbridge.org. А эти всезнающие индусы и арабы с их мануалами на YouTube! Вы все сами прекрасно понимаете. Вернуться никогда не поздно.

А что там по деньгам?

"Я встречал Java-программистов, которые приходят на 100 тысяч рублей"? Насколько я знаю, это потолок для Junior-специалиста в Москве на середину прошлого года. Я также встречал 1С-программистов, которые приходят на 200 тысяч рублей, даже одного такого видел в зеркале. Разброс зарплат зависит от средней по рынку и стоимости специалиста. Поэтому готовьте классное резюме и меняйте стек.

Моему знакомому Middle Java разработчику предлагали на руки 270 тысяч рублей в июле прошлого года.

Многие толковые 1С-ники, которым уже за 30+, боятся уйти из 1С из-за проседания по доходам, у многих кредиты, семьи, да и время сейчас неспокойное. Думаю, что важно иметь хорошее резюме, побольше опыта, пусть даже и в GitHub – и все приложится.
У меня получилось не просесть по доходам, даже выторговать больше.

Могу как-нибудь написать мануал по свитчерству.

Заключение

Я постарался описать все утверждения, с которыми не согласен. Это моя первая статья, и надеюсь, что читателю удалось дотерпеть до конца. Прошу прощения за повторения, и если я кого-то задел своими словами. Ребята, вы – лучшие, я бы не осилил дочитать такую длинную статью.

Несмотря на критику оригинальной статьи и фреймворка 1С в целом, я хотел бы сказать спасибо его создателям. Именно с помощью 1С простой парень из провинции начал зарабатывать себе на жизнь любимым делом – программированием.

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

Мое отношение к 1С-программистам положительное, как и раньше. Я им сочувствую, т. к. им приходится вести неблагодарную fullstack-разработку и решать задачи сразу нескольких "настоящих программистов". И все это при наплевательском отношении со стороны вендора.

Знакомый коллега наблюдал как fullstack-разработчика (Javascript + PHP) посадили писать на 1С. "Настоящий программист" не мог понять, почему столько ограничений, ведь "это легко делается на Javascript". После недели, потраченной на доработку подсистемы, он перестал посмеиваться над 1С-никами.

Те, кто попал в 1С в то же время, что и я, помните, как круто было вначале, когда такой коммерциализации сообщества 1С еще не было? Разработки были бесплатными, а ребята на вышеупомянутом форуме казались такими умными. Критикуемые мною решения в 1С – хороший отрицательный пример, и где-то я даже поучился у 1С, как лучше не делать.
Если резюмировать, я согласен с автором, что для быстрого прототипирования CRUD-приложений без высокой нагрузки лучше 1С нет. Задумка фреймворка 1С изначально была хорошая, но для своего времени, когда царили монолитные приложения. Проблемы 1С начинаются там, где требуется разработать что-то необычное и интересное. А этого по прошествии 10 лет на 1С очень хотелось.

Может быть, с учетом последних событий и изоляции страны все-таки придется вернуться в 1С. Это будет очень иронично.

Автор:
rabid_otter

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js