Заметки

Позднее Ctrl + ↑

Бытовой героизм

Поднимал какое-то время назад Swagger для внутренней API-шки. Пока возился — стало понятно, что часть функционала в документацию включать не нужно. Поискал способ, как это сделать без костылей — наткнулся на забавный вопрос на GitHub'е.

Чем забавный? Ну, невольно вспомнил про Мисту. В среде 1С-разработчиков это синоним слова "токсичность": мол, спросишь там что-нибудь — получишь ушат помоев за шиворот вместо ответа. Здесь, конечно, не так всё запущено, но ребята, с завидным упорством ссылающиеся на 14-и страничный мануал, здорово рассмешили.

Одно радует: к концу треда всё же нашёлся отважный повстанец, который просто взял и запостил нужный параметр для декоратора.

Не все герои носят плащи, ей-богу.

24 сентября 2023 работа Swagger

Румынская фича

Делаю для нашего клиентского портала функцию восстановления пароля через SMS. Добрался до документации Twilio о поддержке буквенно-цифрового ID отправителя в разных странах; эта фича позволяет отправлять сообщения так, чтобы получатель видел не номер отправителя, а что-то осмысленное (название компании, например).

При этом фича везде зарегулирована по-своему: где-то просто работает, где-то нужна регистрация.

Читаю:

Скрин

🤔

  • Португалия: да
  • Пуэрто-Рико: нет
  • Катар: да (с регистрацией)
  • Реюньон: да
  • Румыния: да (с регистрацией) (но бойтесь Дракулы)

Не знаю, как ещё объяснить это кладбище.

UPD: Нашёл разгадку. Могильные кресты означают, что за регистрацию нужно заплатить 700 баксов.

Объяснение про Дракулу мне нравилось больше.

30 августа 2023 тем временем работа

Новый Фастаймер

Выпустил новую версию своего консольного таймера для интервального голодания. Сам таймер я написал где-то год назад, когда меня в очередной раз расстроило приложение Zero для Android: в нём не работала какая-то совсем примитивная функция вроде просмотра конкретного интервала.

Основное отличие 1.3.1 от 1.2.3 — выпилил к черту консольное меню в пользу старых-добрых аргументов и опций. Концепция меню выглядит удобной, пока фич у приложения мало, но как только их число растёт — необходимость протыкивать каждое действие начинает напрягать.

23 августа 2023 готово Python

Таков путь

Немного экзистенциальной безысходности от СП (на случай, если вам её почему-то не хватало):

Исключение генерируется

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

Но все равно, забавно смотрится. Напомнило старый мем:

Исключение генерируется

17 июля 2023

Ду ю спик инглиш?

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

Диалог входа

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

Может, их и вовсе нет.

14 мая 2023

Опочтовиться

Пополнял словарь в попытках описать англоговорящему приятелю свои последние приключения и вычитал про красочную идиому «to go postal». Означает что-то вроде «рехнуться от злости»; появилась где-то между 80-и и 90-и годами в Штатах после серии довольно безумных инцидентов, в которых работники почты ехали крышей и нападали на всех подряд, включая коллег и посетителей.

В общем, выражение на первый взгляд звучит забавно, но уж больно мрачная история за кулисами. Думаю, продолжу применять старое-доброе «to go ballistic». Буквально «разозлиться так, что стать похожим на ракету, потерявшей управление», «взорваться от гнева».

В русском языке, кстати, есть похожие «ракетные» коннотации, но они почему-то про более управляемую или полезную, что ли, историю. Типа, пожар в заднице был настолько силён, что бедняга покинул Землю и успешно приземлился на Марсе (а не просто взорвался) :-)

8 мая 2023 английский

Пауза()

Важная особенность: метод ВызватьПаузу недоступен в клиент-серверном вызове; при вызове с клиента серверного метода, в котором вызывается ВызватьПаузу, будет сгенерировано исключение «Нельзя вызвать метод ВызватьПаузу в клиент-серверном вызове».

Метод ВызватьПаузу

Странное ограничение, если честно. С одной стороны, адекватный разработчик и так не будет в клиент-серверном вызове делать искусственную паузу, с другой — кому чешется, всё равно её там сделает (через проверку времени в цикле, например). Стоило ради security by obscurity огород городить?

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

30 апреля 2023

Сделай это педантично

Ежедневная пальма первенства в номинации «самый философский код» уходит автору этого элегантного способа проверить, что две булевые переменные не равны друг другу:

If DataStructure.Property("AmountVATIn")
    And ((DataStructure.AmountVATIn And NOT SearchPriceIncludesVAT)
    OR (NOT DataStructure.AmountVATIn And SearchPriceIncludesVAT)) Then    
    Price = RecalculateAmountOnVATFlagsChange(Price, DataStructure.AmountVATIn, TabSectionLine.VATRate);
EndIf;

Думаю дописать сюда что-нибудь вроде «And Not (DataStructure.AmountVATIn = SearchPriceIncludesVAT)», чтобы придать происходящему тонкую нотку безумия.

21 марта 2023 работа код с запашком

Повествование через окружение

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

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

Фотка с сайта клуба, чтобы было понятнее.

Рядом висят предупреждения: прыгнете в сетку своим хотением — заплатите десять тысяч дирхам. Запишете этот прыжок веры на камеру — готовьте ещё пять тысяч.

Чувствуется история за кулисами, да?

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

UPD: Ещё один отличный пример откуда-то из сети.

19 марта 2023 тем временем работа

Помедленнее, я записываю

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

Однако бывает наоборот: нужно снизить количество операций, которые программа способна выполнить. Допустим, мы дергаем внешний сервис и он банит, если делать это слишком часто. Пример — облако Битрикс24, которое требует отправлять не больше двух запросов в секунду.

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

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

5 марта 2023 Битрикс готово

REST-сервис для Service Manager

На этой неделе написал REST-сервис для настройки к нашему сервис-менеджеру (это такая конфигурация для управления инстансом 1cFresh). Развернуть контур разработки у нас — задача регулярная, и базу менеджера каждый раз приходилось тюнить руками: подкручивать витрину, менять адреса приложений, перезаписывать регламентные задания и так далее.

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

Эта — хороший пример. Настройка сервис-менеджера не была проблемой (запустить приложение и покрутить настройки), но о ней нужно было думать и её нужно было делать. А теперь — нет:

  1. Есть JSON-файл со всеми настройками;
  2. Есть REST-сервис для его обработки;
  3. Есть скрипт, который засунет первый во второй;
  4. Есть пайплайн, который сделает всё это сам.

Короче, ботинок тёр ногу, а теперь перестал. Йаху!

25 февраля 2023 работа

Карьерные самосвалы

Автомобили

Коллега проворчал, что если продолжать эту логическую цепочку, то конфигуратор будет «Жигулями», а EDT — «Кама1» (это такой электрокар, который много лет пилят где-то в недрах КАМАЗа и всё никак не могут собраться с силами и, наконец, допилить).

Ну а я стараюсь смотреть на вещи с оптимизмом. Думаю, платформа и её IDE — это такие карьерные самосвалы. Никто в здравом уме на них по домашним делам не катает, но на разрезе эти звери незаменимы!

20 февраля 2023

Про странный Битрикс

Чем дальше лезу в REST-интерфейс Битрикс24, тем сильнее поражаюсь тому, насколько необычно устроено мышление у его разработчиков. Проявляется это по-разному.

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

AMOUNT? DEAL_AMOUNT? DOCUMENT_AMOUNT? AMOUNT_TOTAL?

Не угадали, правильный ответ — OPPORTUNITY.

Чего, блядь?

Но вернемся в строке товара. В ней есть товар, ставка НДС и единица измерения. Все три сущности вполне самостоятельны: у каждой есть отдельная таблица со вспомогательной информацией и свой собственный идентификатор. Логично предположить, что в строке товара они и хранятся: ID товара, ID ставки НДС и ID единицы измерения.

Логично-то логично, но нет, хрен там плавал. Для номенклатуры и правда хранится ID, а вот для ставки НДС — значение ставки, и для единицы измерения — код измерения по ОКЕИ ¯\_(ツ)_/¯

Нормализация базы данных? Чего? Какая еще нормализация? Отстань, мужик, работать мешаешь.

15 октября 2022 работа Битрикс

Групповая работа в Google Docs

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

Этот маппинг они выложили в виде таблиц Google Docs, в интерфейсе которого можно видеть пользователей, пользующихся документом в этот момент — как залогиненных, так и анонимных. Последних он традиционно отображает в виде животных.

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

18 сентября 2022 работа Битрикс тем временем

Слак советует

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

Посмотрите, какая милота:

All done. The future is yours.

Зачем вообще нужны психотерапевты?

You're up to date. Go forth and do great things.

Или вот:

You're all read. Here is a tractor.

Боже, слак, хоть ты не начинай.

25 августа 2022 тем временем

Взболтать, но не смешивать

Затрем немного про организацию кода. Если вам нужно где-то описать множество объектов с общими свойствами — подумайте, не стоит ли подробить описание на отдельные методы, каждый из которых будет описывать один конкретный объект?

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

SupportedTypes["Document.SupplierPricesEntering"]   = "Prices";
SupportedTypes["Document.OpeningBalancesEntering"]  = "CustomerAccounts,VendorAccounts";
SupportedTypes["Document.Requisition"]              = "InventoryAndServices";

Вроде всё в порядке, так? Описания есть, табличные части перечислены, посплитить их по запятой — считай, бесплатно.

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

SupportedTypes["Document.SupplierPricesEntering"]   = "Prices";
SupportedTypes["Document.OpeningBalancesEntering"]  = "CustomerAccounts,VendorAccounts";
SupportedTypes["Document.Requisition"]              = "InventoryAndServices";

<...>

SupportedTypes["Document.OpeningBalancesEntering"]  = "PayrollDeductions";

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

Вывод? Ну, можно написать метод-хелпер, который будет принимать на вход тип документа и имя одной табличной части. Хелпер будет заполнять соответствие SupportedTypes и следить за тем, чтобы уже добавленные в него данные не были потеряны.

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

Procedure AddOpeningBalancesEnteringDocument(SupportedTypes)

    TabularSections = New Array;

    TabularSections.Add("CustomerAccounts");
    TabularSections.Add("VendorAccounts");
    TabularSections.Add("PayrollDeductions");

    SupportedTypes["Document.Requisition"] = StrConcat(TabularSections, ",");

EndProcedure

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

7 августа 2022

Не так, а этак!

Про хорватский комикс NOT/BUT мне кто-то рассказал в начале прошлого года, когда я всерьёз учился рисовать. Каждый стрип там — про какую-то травмирующую или просто мрачную мысль, которая приходит в голову художника во время работы. Идея в том, чтобы подтолкнуть читателя в правильном направлении и дать ему посмотреть на ситуацию, в которую он попал, с более практичной стороны.

Рисовать я бросил через год, в конце февраля: стало понятно, что времени на хобби у меня больше нет. Но комикс — совершенно универсальный; полистайте, даже если понятия не имеете, что такое клячка :-)

Да что за херня?

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

23 июля 2022 работа тем временем

Окей!

Блин. Посмотрел видео и понял, что я как раз давным-давно просто пишу OK в утренних дейликах в ответ на вопрос «how do you feel today». Мол, со мной всё в норме, жив-здоров, на работу ничто не влияет.

Что обо мне думали коллеги — боюсь предположить. Надеюсь, они тоже не знали про то, что okay в ответе на такой вопрос нифига не значит okay. :-)

22 июля 2022 английский работа

Баночка с печеньем

На днях прикручивал работу с куками к одному из своих скриптов. Пока искал оптимальное решение, наткнулся на совершенно очаровательный (при этом, кстати, 100% рабочий) совет со StackOverflow:

You can get a CookieJar object from the session with session.cookies, and use pickle to store it to a file.

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

Вот как после этого не любить пайтон, а?

P.S. Пока писал заметку, разобрало любопытство — почему всё-таки pickle, а нe serialization? Так вот, если вкратце: таков путь.

28 мая 2022 Python

Минус встроенные твиты

Не успел я выпилить из блога Google Fonts, как пришлось отправить вдогонку встроенные твиты.

Как это работало раньше? Хотел сослаться на твит — просто вставлял на него ссылку. Скрипт сборки заменял её на HTML-блок, который находил скрипт Твиттера и заменял на текст твита (и всякими полезными ссылками). Вот в этом коммите в целом видно, как это работало.

Как это работает теперь? Ну да, никак. Твиттер в России заблокирован, так что его скрипты работают только со включенным VPN.

Штош

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

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

Ничего лишнего. Чистый функционал. Ты ему — твит. Он тебе — картинку:

npx snap-tweet https://twitter.com/PossumEveryHour/status/1506148678461014016

И всё. Захотелось занести автору денег.

Подумал, не прикрутить ли snap-tweet к скрипту сборки (чтобы было, как раньше: вставляешь ссылку на твит, а дальше оно само генерит картинку и кладёт куда надо). Решил, нафиг. Грубое попирание KISS, да и вообще... В мире и так хватает энтропии. Особенно, блин, сейчас.

21 марта 2022 блог вебдев Node.js

Ранее Ctrl + ↓