Заметки

Позднее Ctrl + ↑

The Cursed Forest

Ничего не ждал от игры, но она, внезапно, удалась. Выглядит бодро; чувствуется внимание к деталям, да и в сумме — совсем неплохо. А ближе к концу — ещё и трогательно.

Садитесь играть по всем правилам — гасите свет, надевайте наушники и, конечно, выключайте душнилу.

6 марта 2019 видеоигры

Повторяющийся ключ

На Инфостарте вышла любопытная статья про ошибку СУБД «cannot insert duplicate key». Одна из возможных причин сбоя — использование уникального идентификатора объекта для сопоставления при обмене с другими информационными базами (то есть, без служебного регистра, сопоставляющего объекты базы данных с идентификаторами объектов внешней базы).

Такой жести, чтобы уникальные идентификаторы совпали в разных базах для одной и той же таблицы, у меня в практике пока не было. Однако от подхода «единого идентификатора» я отрекся окончательно после того, как делал обмен между FirstBIT ERP и GROTEM / Agent.

Архитектура пилотного решения была такая: данные из FirstBIT ERP выгружались сперва в служебную ИБ 1С, написанную разработчиками GROTEM'а, а уже оттуда — в основную базу данных сервера мобильных приложений.

Сопоставление было сделано очень просто — через идентификаторы объектов. Например, один и тот же документ в обеих базах имел один и тот же идентфикатор. Но были и более сложные схемы: например, контрагент FirstBIT ERP на стороне GROTEM'а превращался в три объекта: собственно контрагента, торговую точку и документ взаиморасчетов.

WAIT WHAT

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

Однако обмен работать отказался.

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

В итоге выяснилось, что:

  1. В этой самой базе есть таблица, где хранятся все интересующие нас объекты. Документы, элементы справочников, вот это всё.
  2. Эта таблица имеет уникальный индекс по GUID объекта.

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

I will not use GUIDs to map objects!

1 марта 2019 готово работа

Одиночество

Хороший ролик про одиночество, его причины и последствия (спойлер: все серьёзно, вплоть до биологического уровня). Рассказывают на английском, но если нужно — там есть русские субтитры.

(емкий твит о том же)

(а также я, походу, достаточно много наиграл в Starcraft II, чтобы название ролика у меня в голове произносилось исключительно голосом Зератула и под музыку из Alone)

1 марта 2019 тем временем видеоигры

Неудачная охота

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

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

И вот, наконец, ты смотришь на проблему под правильным углом, а она — обычный жук. Возможно, полосатый или в крапинку, но жук как жук — сидит себе, шевелит усами. И ты такой: блин, это что — и есть моя добыча? :-)

21 февраля 2019 готово работа

Большие таблицы значений

Пока писал про поиск строк на клиенте, вспомнил ещё один нюанс, связанный с данными на управляемых формах — тоже про передачу между клиентом и сервером.

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

Но когда платформа решит передать такую таблицу на сервер, начнутся проблемы. Дело в том, что передавать она будет не простой и компактный объект ТаблицаЗначений, а весьма насыщенный ДанныеФормыКоллекция. Разница колоссальна — на одном из наших проектов траты на такой обмен данными составляли порядка 40% от всего времени работы ключевой операции.

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

17 февраля 2019

Эволюция

Говоря о развитии чего-либо (продукта, языка общения, языка программирования и так далее), люди иногда называют это «эволюцией». Мол, процессы похожи — неудачные решения точно так же постепенно вымываются, а удачные — остаются и усиляют сущность, к которой принадлежат. Так-то оно так, но я сейчас вспомнил не про позитивную сторону — фигня в том, что в ходе эволюции потомки, кроме полезных ништяков, получают все хреново выстроенные и зачастую бессмысленные механизмы, которые не смогли прикончить предка.

В итоге мы задерживаем дыхание, когда глотаем, путаемся между dissatisfied и unsatisfactory, а ещё программируем на чудесном языке JavaScript — который, при всём своем удобстве и распостраненности, вобрал в себя все мыслимые и немыслимые недостатки скриптовых языков.

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

Зная всё это, мне чуть-чуть проще смотреть на то, во что иногда превращается мой код на очередном цикле разработки. Ну и что, что у этого хомячка отрос драконий хвост? Эволюционно, например, такой хвост очень полезен. Кто я такой, чтобы спорить с Дарвином?

Твит

16 февраля 2019 английский работа JavaScript

Найти строки на клиенте

Про то, что метод НайтиСтроки() для коллекций данных формы горазд под шумок наделать серверных вызовов, я узнал довольно давно, столкнувшись с неадекватно долгой прогрузкой формы (там он вызывался прямо в обработчике открытия, да ещё и в цикле). Так делать, конечно, не нужно, на что мягко намекает справка: calling the method executes a server call.

Однако сегодня писал код для задачи с похожей механикой и заметил, что серверных вызовов по факту нет. Удивился, полез на ИТС и, в общем, дело в следующем: при вызове НайтиСтроки() на клиенте поиск на нём и происходит, однако платформа не держит все данные больших коллекций на клиенте. Они передаются с сервера, и запрос этих данных с клиента — тот самый серверный вызов, на который ссылается справка.

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

12 февраля 2019

Ай ду май бэст

Что здорово облегчает работу над английским языком — так это практика, которая буквально сама лезет в руки. Причем порой она полезнее каких-нибудь примеров с условного Cambridge Dictionary — просто потому, что лучше запоминается.

Например, вчера проходили на занятиях гипотетические формулировки и запоминали, как правильно понимать wish и if only; сегодня первое, что попалось в ленте — вот этот твит. Куда уж доходчивее :-)

Твит

Или, скажем, недавно освежали в памяти разницу между try и trying — а я её запомнил давным-давно по вымученному «I do my best» Фелисити из Borderlands: The Pre-Sequel. Ситуация там была довольно яркая, и этот оттенок невозможности выполнить задачу здорово въелся в память.

12 февраля 2019 английский видеоигры

Из чего сделаны наши девчонки?

На фоне скандальной рекламы «Reebok» (я в этой теме полный мимокрокодил, но взрывная волна даже до меня докатилась) на ютубе попался классный ролик их конкурентов. Ему уже пара лет, но он ровно про то же и, блин! Реклама здорового человека — не знаю, как лучше выразиться.

Показал мелкой — смотрела глазами по пять копеек. Покажу ещё раз, когда опять будет батониться вместо тренировки :-)

9 февраля 2019 семья тем временем

Внезапный барабанщик

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

Оттакота!

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

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

Может, мне нужно было стать басистом, а не вот это всё.

9 февраля 2019

Удаление временных таблиц

Любопытная деталь: при закрытии менеджера временных таблиц не происходит удаления этих таблиц из tempdb. Актуально и для прямого вызова метода Закрыть() объекта менеджера, и для неявного варианта (когда объект менеджера уничтожается при завершении метода, в котором он был создан). На деле в обеих случаях выполняется только TRUNCATE, который удаляет данные таблицы; сама же таблица остаётся на случай, если пользователь снова выполнит запрос с таким же составом полей (это выгоднее, чем заново её создавать).

То же самое (удаление данных, но не самой таблицы) происходит при прямом вызове УНИЧТОЖИТЬ из текста запроса. К слову, эта команда вообще редко бывает осмыслена — разве что если объект менеджера живет сравнительно долго, а во временную таблицу помещён большой объем данных, от которого хочется побыстрее избавиться.

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

7 февраля 2019

Конкатенация строк

Как и многие другие компании, мы даем соискателям тестовое задание. Оно намеренно несложное и нужно больше для того, чтобы посмотреть — насколько кандидат понимает платформу? Как аккуратно работает с объектами конфигурации и её кодом?

Одна из множества мелких штук, которые там проверяются — это формирование длинного сообщения для пользователя, включающее множество параметров. Разработчик может делать это через СтрШаблон() или СтрСоединить(), а может — через простую конкатенацию (соединение) строк. Если кандидат использует последний вариант — это считается небольшим минусом: для пользователя результат будет тот же, но вот понять из кода, как он будет примерно выглядеть — заметно сложнее.

Однако тут есть другой аспект. В первой половине прошлого года «Рарус» опубликовал отчет о работах, проделанных для «Билайна». Там много любопытного, но среди прочего есть совершенно оглушительный пункт: за счет отказа от соединения строк разработчики добились 40% снижения нагрузки на процессоры! От двух дополнительных серверов после этих изменений вообще отказались, так как они стали не нужны.

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

27 января 2019 работа

Не скомпилированный код

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

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

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

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

27 января 2019

Поездка на Кок-Коль

Летом катался с друзьями на границу с Монголией (на машинах доехали до Ташанты, а оттуда — на велосипедах до Кок-Коля). Вымотались как проклятые, однако это того определенно стоило — виды с гор невероятно крутые! Одно жаль, животные попадались нечасто — даже чумных сусликов не встретили, хотя их нам каждый встречный анонсировал, включая погранцев :-)

6 января 2019 спорт

Знак амперсанда в 1С

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

Пример ниже выведется как «Project Costing». Символ «P» в ней будет подчеркнут и станет горячей клавишей; если это, например, заголовок команды, то её можно будет вызвать, нажав Alt + P.

ТекстНадписи = "&Project Costing";

Единственное неудобство — если нужно вывести амперсанд прямо в надпись. В этом случае символ следует удвоить: так, пример ниже будет выглядеть как «Project P&L». Никаких горячих клавиш в таком случае создано не будет.

ТекстНадписи = "Project P&&L";

27 декабря 2018

Как Valve в посудной лавке

Ребята из Valve продолжают заигрывать с поклонниками своих игр — то ли по привычке, то ли там и правда кто-то считает, что это отличный способ напоминать о себе.

Конечно, с этой компанией как разработчиком игр всё в целом понятно. Мало кто всерьёз ждет третий Half-Life или, скажем, продолжение Portal. Но меня каждый раз умиляет это непринужденное изящество слона в посудной лавке, с которым Valve работает со своей аудиторией.

Твит

10 декабря 2018 видеоигры

Эффект сноуборда

Стою! Сижу!

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

Я уже говорил тебе, что такое безумие, а? Безумие — это точное повторение одного и того же действия. Раз за разом, в надежде на изменение. Это есть безумие.

― Ваас Монтенегро, Far Cry 3

Но вниз все равно приезжаешь невероятно довольный.

Магия какая-то.

1 декабря 2018 спорт

Ссылка нового объекта

Уникальный идентификатор — удобный критерий при сопоставлении объектов в разных конфигурациях. Например, когда нужно передавать инвойсы из одной базы в другую. Как второй базе понять, загружался полученный инвойс или нет? Первое, что приходит в голову — просто выполнить поиск объекта по его UUID:

ИнвойсЗагружен = Документы.Инвойс.ПолучитьСсылку(UUID).Пустая();

Однако иногда уникальный идентификатор используют для связи объектов в одной конфигурации. Например, если условия задачи мешают добавить обычный ссылочный реквизит и мы не можем в документе А прямо сослаться на документ Б. Или, скажем, если мы создаем элемент справочника на основании документа и хотим иметь между ними прямую связь — присваивая элементу справочника ссылку, полученную по уникальному идентификатору документа. Платформа гарантирует уникальность идентификатора в пределах таблицы, так что такие трюки вполне безопасны.

Я это к чему. Метод УстановитьСсылкуНового() в коде нужно использовать с осторожностью! Проверяйте, что ссылка ещё не установлена до выполнения вашего кода:

СсылкаЗадана = ПолучитьСсылкуНового().Пустая();

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

Ну и, конечно, эта штука работает в обе стороны — я имею в виду, что установленную вами ссылку тоже может потереть какой-нибудь посторонний код (например, обработчик события объекта или подписка на него). Это надежно решается только тестированием.

29 ноября 2018

Распределенный дизайн

Дизайнер из «Stack Overflow» написал о том, как они организуют удаленную работу. Понравилась структура текста — не просто «как мы это делаем», а прямо парами: проблема + решение.

У нас в компании почти вся разработка — удаленная и сам я — тоже удаленщик. Мне очень нравится так работать; главное тут — помнить, как легко нахватать самых неожиданных проблем, когда твое рабочее место и твой дом — одно и то же место. Советы из статьи пить воду и вылезать под солнце вполне себе актуальны, например — в ходе какого-нибудь кранча про это и правда легко забыть.

20 октября 2018 работа

Идеальное произношение

Твит

Примерно то же самое я услышал несколько лет назад от инженера Bloomberg'а — мы тогда писали для заказчика программу, автоматически следящую за курсами акций, и столкнулись с кучей проблем (для работы с финансовыми инструментами Bloomberg дает мощный, но довольно сложный API).

В конце концов дело дошло до диалога с техподдержкой, и после обмена несколькими сообщениями коллега предложил пообщаться голосом. Я здорово смутился и заметил, что, мол, так-то можно, но my English isn't fluent enough. На это собеседник лишь пожал плечами: мол, мы привыкли — английский используется повсеместно, и обратная сторона медали в том, что его везде крутят на свой лад. Так что правильное ударение — последнее, что его будет волновать, лишь бы была понятна мысль.

15 октября 2018 английский

Ранее Ctrl + ↓