#Область ВНЕШНИЕ_ВЫЗОВЫ или MVC в 1С, библиотечность и упрощение интеграции кода




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

58 Comments

  1. kiruha

    А если будет

    ОбщегоНазначения.ЗначениеРеквизитаОбъекта

    и

    ОбщегоНазначенияКлиентСервер.ЗначениеРеквизитаОбъекта

    в одном модуле ?

    или даже в разных, но таким образом имеющие разное исполнение

    Программист увидит Внешний_ЗначениеРеквизитаОбъекта и не заметит что это разное исполнение в 2 случаях,

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

    И вообще общие модули это не просто бессмысленное нагромождение процедур и функций,

    это по задумке аналоги классов со своими методами, которые должны облегчать чтение кода

    Reply
  2. for_sale

    (1) Тут сразу несколько вопросов — а для чего в разных модулях делать функции с одинаковым названием и разным исполнением? Различия функций в разных версиях ещё понятно, но одинаковые функции с разным функционалом в разных модулях — это, по-моему, даже для 1С слишком:) И даже если они есть — для чего их вызывать из своего модуля вместо одной из них?

    Но в принципе, по-моему, ответ на ваш вопрос очевиден — назвать их по-разному. Вам сама 1С не даст назвать две функции в модуле Внешний_ЗначениеРеквизитаОбъекта. Вторую просто назовёте по-другому, Внешний_ЗначениеРеквизитаОбъекта_КотораяБылаСозданаЗачемТоЕщ­ёИПочемуТоЕщёИИспользуется, например.

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

    И вообще общие модули это не просто бессмысленное нагромождение процедур и функций,

    это по задумке аналоги классов со своими методами, которые должны облегчать чтение кода

    Так я ж и не говорил, что бессмысленное. Вы, мне кажется, невнимательно прочли пост. Смысл в том, чтобы все эти вызовы поместить в одно место и легко (легче, чем было) их контролировать. Ни в коем случае я не пытался оспаривать нужность самого существования таких вызовов. Просто призвал не размазывать их по всему коду.

    Reply
  3. herfis

    Если проводить аналогии, то это скорее интерфейсы, адаптеры и иже с ними.

    Но так — идея норм. В собственных подсистемах/обработках, внедряемых в типовые, тем более тиражируемых, имеет смысл.

    Reply
  4. herfis

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

    Reply
  5. herfis

    (5) Чел просто предлагает все внешние зависимости «своего» куска функционала, собирать в одном месте и вызывать через функции-адаптеры.

    Если это просто одна обработка — будет просто вынос в отдельные секции программных модулей этой обработки. Если целая подсистема — то да, полный набор модулей по их видам. Список процедур составляется «от обратного». Что используется, то и выносится.

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

    Ну, это как я понял исходный посыл.

    Reply
  6. pm74

    (0) а медный кабель зачем ?

    Reply
  7. CyberCerber

    Хорошая практика.

    Когда писал универсальную обработку, которая должна работать на разных версиях БСП, приходилось создавать такие «тупые» методы:

    &НаКлиенте
    Функция ОбластьМакета(Макет, Секция)
    
    Попытка
    Возврат УправлениеПечатьюКлиент.ОбластьМакета(Макет, Секция);
    Исключение
    Возврат УправлениеПечатьюКлиент.ПолучитьОбласть(Макет, Секция);
    КонецПопытки;
    
    КонецФункции

    Показать

    И таких функций у меня в обработке в 1000 строк штуки 4 — 5.

    А вынести все вызовы внешних модулей, даже если пока в них нет различий, идея хорошая.

    А разработчикам БСП можно сказать только одно: Пожалуйста, не делайте такое с методами, которые могут использовать сотни программистов. Это же просто кощунство!

    Reply
  8. kiruha

    (2)

    1)В типовых встречается одинаковые.

    2) Предположим у меня есть общий модуль ОбменЦБанк

    И в коде используются

    ОбменЦБанк.ОтправитьСообщение()
    ОбменЦБанк.ОтправитьПакет()
    ОбменЦБанк.ПринятьПакет()
    ОбменЦБанк.ПолучитьПрофильДоступа()
    ОбменЦБанк.Верификация()

    …..

    Зачем мне все это заменять на

    ВнешняяФункция_ОтправитьСообщение() 

    и т.п.

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

    а если изменю раз в год, то и код поправлю ?

    Или это только для типовых ?

    Reply
  9. TODD22

    Пару раз наступив на изменение процедур в БСП, стал просто все необходимые процедуры копировать из БСП в свои модули. Если конечно за ними ещё много всего не потянется.

    Reply
  10. whitegh0st

    (7)тут скорее всего mvvm потому как внесение части функций в отдельный модуль тяжело назвать контроллером. Да и вообще странно использовать эти термины в отношении 1С, потому как мы не можем, например, взять и использовать другой компонент для представления не меня при этом модели

    Reply
  11. for_sale

    (15)

    внесение части функций в отдельный модуль

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

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

    странно использовать эти термины в отношении 1С

    Странно, потому что в 1С вообще очень слабо со всякими терминами, принятыми в других языках. И не потому, что их тут нельзя применить, а потому, что никто таким применением не занимается. Иногда кажется, что слово «оптимизация» неприлично употреблять в «приличном» 1Совском обществе 🙂

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

    Почему не можем? Классический пример из википедии — представление данных в виде графика, диаграммы или таблицы. Мы точно также можем сделать (и зачастую делаем) несколько отчётов с одними и теми же данными, но в разной форме и разном сочетании. MVC аз из — есть база, есть интерфейс и есть контроллер в виде СКД, который их связывает. Другое дело, что в 1С вообще тяжело найти другие достойные примеры. Как было всё в кучу, так и есть, поэтому зачастую так и получается, как вы написали — нельзя поменять представление, не меняя модель. Но нельзя не потому, что невозможно, а потому что так написано, что проще застрелиться, чем поменять.

    Reply
  12. Артано

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

    Reply
  13. nomadon

    (11) во-первых просто красиво, во-вторых демонстрация положения дел «после», ну и в тексе что то написано про провода)))

    Reply
  14. nomadon

    (12) в бсп есть функции получения версии бсп, можно без попытки обойтись

    Reply
  15. for_sale

    (13) Есть такое понятие — хороший код. Это когда всё однотипно, всё понятно, нет завязки на программиста, легко поддерживается и легко читается. Я не претендую вот эту практику из поста ввести в хороший код, но могу точно сказать, когда начинаются вот такие вопросы — а зачем мне, я же раз в год или вообще никогда — в результате получается yet another 1C project, то, что мы видим постоянно, Г-код.

    Потому что невозможно писать одному человеку в разных стилях — вот тут я напишу тяп-ляп, а завтра, когда нужна будет масштабируемость, напишу красиво. Человек, который пишет так, как будто никто за ним никогда не будет доделывать и пишет «на века», мол, это всё равно никто не будет изменять — он и будет так писать, всегда. Проще говоря, Г-код вызывает привыкание 🙂

    У вас ключевое слово — Я. Вы считаете, что никто никогда не будет после вас поддерживать этот код, а вы и так знаете, что там где. И так все думают.

    Поэтому ответ на ваш вопрос — да не зачем. Нет никакой жизненной необходимости в этом. Как нет никакой необходимости ставить пробелы между словами и операторами, называть переменные осмысленно и писать каждое действие с новой строки.

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

    Reply
  16. pm74

    (18) что то вроде «маленькой собачки Фаворского»?

    Reply
  17. mxs89

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

    Reply
  18. Сурикат

    Соглашусь с предыдущим высказыванием

    Автор еще и неправильно назвал шаблон. Это не MVC, это обычный фасад.

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

    Наверняка, все согласятся, что такое следует использовать только в крайних случаях при жестких требованиях к интерфейсу

    Reply
  19. the1

    А клиентские и серверные методы тоже в один модуль выносишь?

    Reply
  20. shmalevoz

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

    Reply
  21. Darklight

    Увы. решение не полное. Так как помогает (и даже не автоматизирует, оставляя кучу ручных действий) убрать только один самый верхний уровень проводов. Да, он большой, но, всё же, лишь менее четверти всех проводов глубже никуда не пойдут. А остальные дальше всё равно уйдут в недра БСП и выдирать всё равно придётся вручную.

    Да и замораичитваться с такими областями придётся постоянно — в разных модулях — дублируя их части многократно и хаотично.

    Лично я давно, в своих разработках, пытаюсь освоить практику создания отдельного набора из нескольких общих модулей, который будет посредником для осуществления вызовов функций БСП из основного кода. Во-первых — не нужно многократно дублировать такую прослойку в местах применения, во-вторых в одном месте видно всё то, что используется из БСП, в-третьих — в этом же одном месте можно организовать ветвление поддерджки разных версий БСП и платформы. А в пятых…. об этом ниже.

    В пятых — этого не достаточно. Нужна ещё и автоматизация.

    В принципе это не так сложно (но лично я ещё этого не сделал) написать простую обработку текстовых модулей на предмет рекурсивного поиска вложенных вызовов методов модулей, автоматического выдергивания их и переноса в результирующую сборку — т.е. трассировка проводов от клемы до клемы и полный перенос используемой схемы.

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

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

    Можно сделать настройки какие методы вообще не переносить — и ремить их вызовы или заменять на другие вызовы — например на свои методы, а какие наоборот — всегда переносить (даже если на них нет вызовов).

    Вот это было бы хорошее решение.

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

    Reply
  22. Darklight

    А по поводу применимости паттерна MVC в 1С — в принципе вполне возможно было бы, хоть и есть некоторые трудности и непривычности. Главное это то, что 1С Предприятие 8 не поддерживает создание произвольного количества модулей внутри прикладных объектов. Конечно, с появлением модуля менеджера ещё можно как-то выкручиваться, но…. тут вторая дилемма, из двух проблем:

    — Либо (когда строго примененяется) паттерн MVC в большинстве прикладных объектов попросту не нужен — иначе это попросту приведёт к излишнему усложнению

    — Либо (когда действительно у объекта есть несколько форм представления) попросту будет сильно перегружать модуль менеджера дополнительным кодом

    Эти проблемы, конечно, можно считать надуманными и в целом MVC вполне можно применить в 1С как в УФ, так и в управляемых формах, только, вот моды, нет, были бы хотя бы некоторые популярные типовые решения построены по MVC — так и развитие быстро бы начало набирать обороты. Но, компания 1С, видимо не видит в этом смысла. А жаль… Удобно было бы верстать УФ как текстовые макеты, переключаясь в визуальный редактор, отдельно от кода, который был бы размещён в отдельных модулях, с минимальными повторениями функционала.

    Вот бы ещё и поддержку фреймов — чтобы и визуальную часть не приходилось бы многократно дублировать при разработки разных форм-представлений одного и даже различных объектов (ведь, например, у многих типовых документов очень много крупных схожих визуальных блоков, лишь точечно отличающихся в реализации обработчиков) — вообще была бы песня!

    Эх…. ждём 1С: Предприятие 9, авось…

    Reply
  23. spetzpozh

    Насчет версий БСП. БИТ в их БИТ:Финансе пошел дальше и внедрил в типовое решение ЕЩЕ одну БСП со своими префиксами бит_. С одной стороны много сил на копирование, с другой — тебя не парит, что происходит со встроенной БСП. Речь про БИТ Финанс для БП 2.0.

    Возможно, в 3.0 они это убрали.

    Reply
  24. IvanovAV

    Иногда, проще свой простенький код и запрос написать, чем завязываться на общие модули типовой конфы и БСП. Она сама по себе, а мы сами по себе. Самое обидное когда начинают бестолково Имена объектов и реквизитов переименовывать, в частности УТ 11. Вопрос: для чего им синонимы?

    Reply
  25. CSiER

    (16), упоминание MVC в статье лишнее. Там другая цель — разделить сущности. На примере того же механизма СКД — он «сам себе MVC» 🙂 model -схема компоновки (сам запрос, параметры и т.п.), view — настройки пользователя конкретного варианты отчета и т.д., а controller — «черный ящик с кнопкой сформировать», с помощью которого получается макет компоновки и затем уже результат компоновки отображается пользователю. СКД позволяет менять интерфейс без изменения модели (одни и те же данные можно представить в виде таблицы и, например, диаграммы).

    Описанное решение — скорее паттерн прокси из банды четырех (очень отдаленно). Все описанное IMHO.

    Reply
  26. for_sale

    (22) Любая библиотека, вызов, обёртка потребует доработки, если вызываемое изменится, не думаю, что это — минус именно данного подхода. Данный подход призван как раз собрать наиболее рисковые на замену места в одном месте, чтобы было ясно, что и где менять в случае чего. Более того, в случае, указанном в посте, когда функция

    УправлениеКонтактнойИнформациейКлиент.ОткрытьФормуКонтактнойИнформации

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

    Reply
  27. for_sale

    (23)

    Ну я же специально вставил ссылку на википедию — почитайте вначале, что есть MVC, погуглите, а потом приходите авторитетно пинать автора.

    То, что вы описали — это что-то вроде суеверия — «бабушка рассказывала, что MVC нужен только для форм, где много данных разных документов!».

    На деле любая форма документа, отчёта, справочника должна писаться с мыслью об MVC. Чтобы, меняя интерфейс, не лезть в базу, и чтобы меняя базу. не лезть в интерфейс. И всё, никакой магии.

    Пример 1:

    #Форма
    Процедура ОбработчикНажатияНаКнопкуПодборНоменклатуры()
    
    Запрос = Новый Запрос;
    // запросом выбираем остатки номенклатуры,
    // пришиваем к ним штрихкод из регистра
    
    Цикл…
    // обходим номенлатуру, чистим то, что уже было добавлено или ещё какие проверки
    
    КонецПроцедуры
    

    Показать

    Пример 2:

    #Форма
    Процедура ОбработчикНажатияНаКнопкуПодборНоменклатуры()
    
    ТоЧтоНужно = ПолучитьНоменклатуруСОстаткамиИШтрихкодомИАртикулом();
    
    ОчиститьДубли(ТоЧтоНужно);
    
    КонецПроцедуры
    
    #Какой-то общий модуль или модуль менеджера
    Функция ПолучитьНоменклатуруСОстаткамиИШтрихкодомИАртикулом()
    …
    

    Показать

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

    Второй пример — MVC. Есть интерфейс, который знает, что где-то есть номенклатура с остатками и штрихкодом, и работает с этими данными. Как эти данные получены — интерфейсу наплевать. Когда штрихкод начнут хранить не в регистре, а в справочнике Номенклатура, а остатки получать из текстового файлика где-то на хостинге, а не из базы — интерфейс будет спокойно работать в штатном режиме.

    При чём тут строгие требования к интерфейсу? Я за критику, но конструктивную. Критика ради критики, даже не разобравшись в терминах — это уже деструкция и описанное выше ЧСВ, извините за резкость.

    Reply
  28. for_sale

    (26)

    В принципе согласен с вами. На полноту и не претендовал, в 1С только нырни — всю жизнь оптимизировать можно:)

    По вашему решению — если напишите развёрнутый пост, почитаю с интересом, если какие-то готовые идеи есть с примерами. За конструктивную критику — спасибо с плюсом.

    Reply
  29. for_sale

    (29) Если 1С перестанет что-то постоянно бестолково делать, оно потеряет свою самобытность 🙂

    Reply
  30. for_sale

    (21)

    маленькой собачки Фаворского

    Когда работаю в коде 1С, перед глазами часто всплывает картина — комната, полностью увешанная оголёнными проводами, которые тянутся отовсюду везде. И когда нужно что-то своё вставить в сеть, приходится лазить по проводам с риском быть убитым и искать нужные, с нужным напряжением и силой тока, а потом прикручивать свои провода к этим 🙂 А хотелось бы просто взять вилку и вставить в розетку. И чтобы все провода были изолированы, связаны в пучок и всё было легко найти.

    Reply
  31. for_sale

    (25) Надо писать об этом посты и просвещать народ.

    Reply
  32. pm74

    (35) ну извините просто не понял вашей ассоциации

    Reply
  33. kote

    (27)

    .. помню, еще в 2010 году как https://infostart.ru/public/74872/

    Короче, все эти паттерны в мире 1С — это как метание биссера.

    А на счёт зависимостей от функций в БСП выход простой.. берите и копируйте себе в обработку нужную функцию.

    А лучше — напишите свою. Окупится в течении 1 года поддержки.

    Кто там про вечную альфу сказал — хлопаю стоя. Но всё это от того, что язык не развивается.. а ведь есть куда и как.

    Вот, например, люди чудят — и ведь работает — https://github.com/covrom/gonec/issues/5#issuecomment-335707925

    А 1С — рано или поздно сойдёт на нет.. потому, как глупое заявление на конференции топа 1С, что «в ERP 5 млн. строк кода» когда то будет встречено заявлением «а в нашем — всего 50 тыс. — но делает все то же самое»..

    Reply
  34. kote

    (26)

    Посмотрите на https://infostart.ru/public/591496/ — с точки зрения организации кода в объекты с относительно-нормальными интерфейсами в 1С.

    В принципе то, что там сделано — с помощью процедурно-1С-стиля сделать невозможно. Т.е. такой способ даёт некоторые доп. возможности не только в организации кода, но бонусы в построении объектных ээ… пусть будет — абстракции.

    Reply
  35. Сурикат

    (32)

    Возможно я резко выразился, за что приношу извинения.

    Про то что у вас MVС или не MVC вопрос спорный. Чем MVC отличается от адаптера? Я считал, что MVC должен перенаправлять вызовы к разным моделям, в зависимости от параметра клиента. Если так, то MVC у вас только в случае с изменением семантики метода. Все остальное адаптер.

    Сильное изменение параметров метода = ошибка компиляции, сами же об этом писали. Следовательно у вас нет вызова разных моделей, а вы заменяете один метод на другой, пусть и завернутый в стандартизованный интерфейс => адаптер.

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

    Контроллер — своеобразная фабрика для моделей со стандартизованными действиями (как я его представляю). Отличается от фабрики тем, что возможна различные интерфейсы.

    Почему MVС применять не стоит — потому что в 1С нет разных моделей. Вид настолько зависит от модели, что в использовании MVС нет никакого профита. Очень редки случаи переиспользования вида.

    Некоторые и модель не пишут, получая проблемы второго вашего примера (из комментария). Там вы как раз описываете случай изменения БД, которые не влияют на остальное приложение, т.к. у нас есть модель!

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

    Reply
  36. IvanovAV

    (38) По заявлению топа, стало понятно: Что если качество продукта они оценивают количеством строк кода, следовательно зарплату в 1С за это и платят. Теперь понятно почему в новых типовых конфигурациях куча промежуточных процедур состоящих из одной строчки перебрасывающей в другую процедуру.

    Интересно какая взаимосвязь между количеством критических ошибок и строк кода? Даже страшно представить сколько их в 5 млн строк кода.

    Reply
  37. Brawler

    (41) Без разницы какое число кода у них там, все упирается на самом деле в качество этого кода.

    Я вон вчера ковырялся в коде КА 2.4.1.215, разбирался как цена в документе рассчитывается и набрел на кусок кода, где определяется есть ли колонка в таблице или нет с определенным именем.

    Переменная «ТабличнаяЧасть», тип значения «ДанныеФормыКоллекция».

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

    Как-то так упрощенно

    ….
    ЕстьКоличествоУпаковок = ТабличнаяЧасть.Выгрузить().Колонки.Найти(«КоличествоУпаковок») <> Неопределено;
    ….
    ….
    ЕстьКодСтроки = ТабличнаяЧасть.Выгрузить().Колонки.Найти(«КодСтроки») <> Неопределено;
    ….
    

    Что происходит?

    Так как у объекта типа «ДанныеФормыКоллекция» нет возможности узнать какие колонки в таблице есть, то 1С пользуется возможностью и выгружает таблицу посредством «Выгрузить()» в ТаблицуЗначений, а там уже есть возможность получить доступ к колонкам, чем они и пользуются «Колонки.Найти…», однако при таком использовании «Выгрузить()» делается полная копия таблицы как я понимаю, идет жор памяти + ресурсов ЦП. Да в основном незначительно, на мелких документах, но на больших это уже будет хуже, а при большом числе юзеров так вообще…

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

    ….
    ЕстьКоличествоУпаковок = ТабличнаяЧасть.Выгрузить(Новый Массив()).Колонки.Найти(«КоличествоУпаковок») <> Неопределено;
    ….
    ….
    ЕстьКодСтроки = ТабличнаяЧасть.Выгрузить(Новый Массив()).Колонки.Найти(«КодСтроки») <> Неопределено;
    ….
    

    Кто глазастый заметил уже «Выгрузить(Новый Массив())», просто получить структуру таблицы без строк данных. Жора памяти нет, ЦП тоже радуется.

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

    Reply
  38. kote

    (42) RE «(41) Без разницы какое число кода у них там..»

    Это заблуждение. Разница есть. Примерно в 100 раз.. (5 000 000/50 000)

    И думаю, что «плотность» ошибок в 5 млн. будет выше (и сохраняться они дольше) — хотя бы в силу того, что отрабатывать каждый участок будет в среднем в 100 раз реже..

    Reply
  39. Brawler

    (43) сейчас у вас 50 000 взяты с потолка и никогда эти 50 000 не сравнятся и близко даже с 1 000 000 строк кода

    Дурные варианты сравнения, где весь модуль записан в одну строку не рассматриваем.

    Reply
  40. kote

    (44) Попробуйте python и его стандартную библиотеку. Разница будет в 200 раз.

    Reply
  41. json

    Я тоже давно использую мвц в 1с при написании обработок. Я этот принцип понимаю, как отделение интерфейса от бизнес логики (представления от модели). Поэтому я все процедуры, которые обращаются к базе описываю в модуле обработки, а все процедуры, которые работают с интерфейсом — в форме. В качестве контроллера использую короткие серверные процедуры (тоже в форме). Получается что-то типа того:

    &НаСервере
    Процедура ОбновитьЦеныНаФорме() // контроллер
    
    АктуальныеЦены = РеквизитФормыВЗначение(«Объект»).ПолучитьАктуальныеЦены(Параметры); // модель
    
    ВывестиТаблицуЦенВТаблицуНаФорме(АктуальныеЦены); // представление
    
    КонецПроцедуры

    Также хорошо подходит при печати. Например, так:

    Процедура ПечатьЗаказа(Заказ) // контроллер
    
    ДанныеДляПечати = ПолучитьДанныеЗаказаДляПечатиЗапросом(Заказ); // модель
    
    СформироватьПечатнуюФормуЗаказа(ДанныеДляПечати); // представление
    
    КонецПроцедуры

    Примеры придумал на ходу, но принцип использую такой

    Reply
  42. Brawler

    (45) не то сравниваете, вы уже на уровень платформ спустились грубо говоря.

    python и его стандартную библиотеку

    1С и его стандартную библиотеку (платформа)!

    C# и его стандартную библиотеку

    И чего их сравнивать?

    Нужно готовые решения созданные на их базе сравнивать!!!

    Reply
  43. for_sale

    (46)

    РеквизитФормыВЗначение(«Объект»)

    Вообще хорошо, только РеквизитФормыВЗначение(«Объект») — вариант так себе, оно его каждый раз будет заново получать, а если что-то инициализируется в модуле, то ещё хуже, каждый раз по-новой. Лучше использовать модуль менеджера.

    Reply
  44. Darklight
    Reply
  45. Darklight

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

    Кстати, если в общих модулях конфигурации реализовать механизм кеширования — то этот значение объекта можно было бы закешировать где-нибудь (на время сеанса / ~20 мин) — и получать его от-туда по кеш-ключу) — но это тоже не без недостатков.

    Но я бы, всё же, использовал тут не модуль объекта, а модуль менеджера. Одна беда — у внешних обработок/отчётов его нет (тут дальше следуют много заценгзуренного мата в сторону разработчиков 1С 8 из компании 1С). К модулю менеджера в серверном контексте можно просто обращаться по прямому пути (Документ.Такойто.КакаяТоФункция(ЭтаФорма)). Ну, при желании можно и более универсально (Выполнить(Метаданные().ПолноеИмя()+».»+»КакаяТоФункция(ЭтаФорма)»)).

    А вообще применение MVC в 1С УФ усложняется как раз раз тем, что в управляемых формах есть разделение контекста на «Серверный» и «Клиентский». Причём и тот и другой ещё делиться на «Без контекста формы» и «С контекстом формы». И именно в этом контексте формы вся сложность — т.к. он доступен только в модуле самой формы — но, это тоже решаемо — обычно вполне достаточно в него на форме войти и передать уже внешней функции в качестве переменной ЭтаФорма (что компания 1С и очень часто делает в своих прикладных решениях — т.е. уже отчасти применяет MVC — жаль только, что отчасти).

    С разделением контекста на «Серверный» и «Клиентский» тоже есть проблема — увы, но в клиентском контексте не доступны ни модуль объекта (включая внешние и встроенные обработки), ни модуль менеджера. То есть — чтобы вынести клиентские реализации обработчиков из формы — нужно создавать встроенный в конфигурацию отдельный ОбщийМодуль с доступным клиентским контекстом выполнения. Что отделяет реализацию от принадлежности к самому объекту приложения, и требует размещения в составе конфигурации. Некрасиво и неудобно получается. И поддержку сильно усложняет.

    Reply
  46. json

    (48)

    (50) Да, именно потому и использую модуль объекта, чтобы можно было отлаживать в том числе и в виде внешней обработки. Пускай не очень красиво, но зато практично. Более удобного варианта я не нашел.

    Когда-то делал замеры того, сколько выполняется РеквизитФормыВЗначение(«Объект»). Создал обработку с табличной частью 10 колонок на 1000 строк и выполнял эту процедуру в цикле. Получалось около 10 циклов в секунду, т.е. накладные расходы около 0.1 сек. Замеры выполнял на файловой базе. Но на серверной должен наверное быть похожий результат, т.к. действие уже выполняется на сервере и обращения между клиентом и сервером при этом не происходит. Тем более, что на практике в цикле эту операцию выполнять нет необходимости, обычно достаточно один раз получить объект из реквизита формы. Такую задержку пользователь не ощущает, а удобство доработки заметно возрастает.

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

    Reply
  47. kote

    (49)

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

    Все проблемы с БСП растут отсюда.

    .. а так было бы:

    
    БСП_23 = Подключить(«БСП.v.2.3»);
    БСП_24 = Подключить(«БСП.v.2.4»);
    
    _стр = БСП_23.СтроковыеФункции;
    _хмл= БСП_24.РаботаСXML;
    
    мМассив = _стр.МассивВСтроку(вхМассив);
    
    мХМЛ = _хмл.СериализоватьСсылку(вхДокументСсылка);
    
    

    Показать

    .. код бы не ломался, когда появляется новая БСП, но нужны оттуда новые фукнции

    Reply
  48. Darklight

    (52)Да. Лишь по вашему примеру примечание: у Вас там описано динамическое связывание — вещь безусловно хорошая, но статическое связывание применяется чаще (как и то, что решение редко применяет разные версии БСП), примерно как сделано в 1Script

    //Где то в настройка дерева конфигурации, в группе «Общие.Библиотеки» создана ветвь-узел: БСП, в ней ветвь-лист  «Ядро», где статически подключена некоторая  реализация БСП.Ядро
    //Причём либо одна конкретная версия (которая будет связана с именем «БСП.Ядро», либо набор версий, где лишь одна будет назначена основной — на использование по имени без указания версий (по умолчанию)
    
    //Вариант1
    #Использовать Библиотеки.БСП.Ядро;
    //Для набора версий можно уточнить версию
    //#Использовать Библиотеки.БСП.Ядро(«2.4.*.*»);
    //Такая конструкция подключит БСП определённой версии ко всему модулю (но только в его границах)
    
    //Вариант2
    //А такая конструкция сделает библиотеку доступной только в определённой области; причём, версия библиотеки будет выбрана не ниже заданной версии: 2.3.8.0 но ниже, чем 2.4, с выбором максимальной доступной версии БСП: так <2.3.8<.* с выбором минимальной доступной)
    #Использование Библиотеки.БСП.Ядро(«>2.3.8<.*»)
    
    _стр = СтроковыеФункции; //редакции 2.3: получение общего модуля из библиотеки БСП.Ядро(«>2.3.8<.*»)
    
    //Вариант3
    _хмл= Библиотеки.БСП.Ядро(«2.4.3.0<«).РаботаСXML; //Прямое обращение  к общему модулю библиотеки БСП.Ядро нужной версии 2.4.3.0<
    
    мМассив = _стр.МассивВСтроку(вхМассив);
    
    #КонецИспользования //Библиотеки.БСП.Ядро(«>2.3.8<.*»)
    
    //здесь _стр уже не доступно
    //здесь _хмл продолжает быть доступным
    
    мХМЛ = _хмл.СериализоватьСсылку(вхДокументСсылка);
    

    Показать

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

    Reply
  49. tindir

    (27) Частияно Шастье наступит с приходом EDT(верстка текстом). А вот о формировани «Шапки» документа одинаково для всех тоже давно мечтается. Как у C#MVC header.cs в котором описан основной шаблон для нужных тебе объектов. Но есть всегда НО.

    Reply
  50. whitegh0st

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

    Reply
  51. CSiER
    На самом деле MVC я здесь задел «по касательной», как одно из воплощений идеи о том, что для упрощения поддержки и интеграции внешнее взаимодействие лучше вынести в ту самую прослойку — Контроллер.

    Посыл изучать паттерны (шаблоны) — отличный. Все мы рано или поздно приходим к некоторым решениям, а потом оказывается, что они уже давно существуют в виде известных паттернов/антипаттернов. В контексте 1С не хватает хороший статей по best practice применения шаблонов проектирования (если знаете — просьба оставить в комментарии или в личку). Может быть когда-нибудь и появится адаптированная версия GOF для 1С 🙂

    Reply
  52. herfis

    (56) Да ну, я вас умоляю. Большинство паттернов банды четырех заточены под ООП и строгую типизацию. Как мол в этих рамках красиво решать типовые задачи. А те из них, которые имеют более широкое применение — и так интуитивно понятны.

    Reply
  53. CSiER

    (57), отчасти согласен. Конкретно по шаблонам GOF («те из них, которые имеют более широкое применение») — как раз не хватает структурированного описания практик применения в контексте 1С. С другой стороны, сообщество 1С растёт — думаю со временем появятся свои паттерны )

    Reply
  54. Darklight

    (58)Пора Инфостарту объявить конкурс на лучшие паттерны программирования в среде 1С

    Reply
  55. vec435

    Нужно сделать некий «сборщик проекта» — который вытянет все !!! функции

    Reply
  56. pfihr

    (38) Рекомендую ознакомиться в целом с этим проектом, https://github.com/covrom/gonec

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

    Reply
  57. kote

    (61) Давно слежу за Вашим проектом, Роман 🙂 чешу руки попробовать.. но никак не доходит очередь.

    PS Для чистоты сравнения стоит в сравнение производительности включить других участников — OneScript был бы к месту.. и только перебор цикла — это не тест, нужно показать работу со сложными структурами данных, подобных 1Сским — Структура, Соответствие, ТЗ, Массив.. запись/чтение/удаление — что-то подобное.

    Reply
  58. pfihr

    (62) Цель Гонца — тесная интеграция с 1С, на 1С жирные решения, на Гонце — легкие микросервисы, встраиваемые в классическую инфраструктуру микросервисов, например, на docker/kubernetes. 1С и Гонец дружат посредством HTTP и JSON. Намеренно делаю сравнение производительности с 1С и python, чтобы получить понимание производительности относительно 1С и возможности работы в качестве целевого назначения, и этого достаточно. Сравнивать с OneScript совершенно не вижу смысла.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *