Заметки
Позднее Ctrl + ↑
Новый Фастаймер
Выпустил новую версию своего консольного таймера для интервального голодания. Сам таймер я написал где-то год назад, когда меня в очередной раз расстроило приложение Zero для Android: в нём не работала какая-то совсем примитивная функция вроде просмотра конкретного интервала.
Основное отличие 1.3.1 от 1.2.3 — выпилил к черту консольное меню в пользу старых-добрых аргументов и опций. Концепция меню выглядит удобной, пока фич у приложения мало, но как только их число растёт — необходимость протыкивать каждое действие начинает напрягать.
Таков путь
Немного экзистенциальной безысходности от СП (на случай, если вам её почему-то не хватало):
Это справка для метода УдалитьСообщения() менеджера канала сервиса интеграции. Если серьёзно, я понимаю, что тут имеется в виду: дело в том, что все методы сервисов интеграции швыряются исключениями, если их вызвать в сеансе со включенными разделителями. Авторы документации педантично сообщают об этом в справке по любому из них, так что здесь, видимо, просто почему-то кусок отвалился. В английской документации к этому методу, например, всё нормально.
Но все равно, забавно смотрится. Напомнило старый мем:
17 июля 2023 1С
Ду ю спик инглиш?
Диалог входа в хранилище конфигурации актуальной версии платформы (8.3.22.1923, если быть точным), запущенной с английским интерфейсом:
Слышал, что развитие Конфигуратора остановилось во многом из-за чудовищного количества технического долга, тормозящего любые новые фичи. Но тут интерфейс поехал прямо на одном из первых окон приложения! Любопытно, как это пролезло через тесты.
Может, их и вовсе нет.
14 мая 2023 1С
Опочтовиться
Пополнял словарь в попытках описать англоговорящему приятелю свои последние приключения и вычитал про красочную идиому «to go postal». Означает что-то вроде «рехнуться от злости»; появилась где-то между 80-и и 90-и годами в Штатах после серии довольно безумных инцидентов, в которых работники почты ехали крышей и нападали на всех подряд, включая коллег и посетителей.
В общем, выражение на первый взгляд звучит забавно, но уж больно мрачная история за кулисами. Думаю, продолжу применять старое-доброе «to go ballistic». Буквально «разозлиться так, что стать похожим на ракету, потерявшей управление», «взорваться от гнева».
В русском языке, кстати, есть похожие «ракетные» коннотации, но они почему-то про более управляемую или полезную, что ли, историю. Типа, пожар в заднице был настолько силён, что бедняга покинул Землю и успешно приземлился на Марсе (а не просто взорвался) :-)
8 мая 2023 английский
Пауза()
Важная особенность: метод ВызватьПаузу недоступен в клиент-серверном вызове; при вызове с клиента серверного метода, в котором вызывается ВызватьПаузу, будет сгенерировано исключение «Нельзя вызвать метод ВызватьПаузу в клиент-серверном вызове».
Странное ограничение, если честно. С одной стороны, адекватный разработчик и так не будет в клиент-серверном вызове делать искусственную паузу, с другой — кому чешется, всё равно её там сделает (через проверку времени в цикле, например). Стоило ради security by obscurity огород городить?
В лучшем случае какой-нибудь джун схватит это исключение, подумает "похоже, я что-то не так делаю" и двинется в правильном направлении. Однако закладывать в платформу ограничение ради этого кейса — как из пушки по воробьям палить. Давайте ещё лимит по количеству прикрутим — мол, не больше 1000 пауз на сеанс, а то вдруг пользователи подумают, что программа работает слишком медленно :-)
30 апреля 2023 1С
Сделай это педантично
Ежедневная пальма первенства в номинации «самый философский код» уходит автору этого элегантного способа проверить, что две булевые переменные не равны друг другу:
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 1С работа код с запашком
Повествование через окружение
Люблю замечать в окружающем мире штуки, за которыми явно стоит какая-то история. В видеоиграх это называют "повествованием через окружение": напрямую тебе историю не рассказывают, но если посмотреть по сторонам — можно догадаться, какое ружье висело на стенке и кто из него пальнул.
Например, недавно отмечал с коллегами десятилетие компании в местном гольф-клубе. Шары нужно было отправлять в полет со второго этажа; перил там по понятным причинам нет, но натянута сетка на случай, если кто-то потеряет равновесие.
Рядом висят предупреждения: прыгнете в сетку своим хотением — заплатите десять тысяч дирхам. Запишете этот прыжок веры на камеру — готовьте ещё пять тысяч.
Чувствуется история за кулисами, да?
Или, скажем, летал как-то в Турцию отдыхать и решил на всякий случай полистать правила авиакомпании (что можно брать на борт, чего нельзя). Среди списка запрещенных к проносу на борт предметов нашёл пункты «стальное копье» и «стальной кистень» 😬
UPD: Ещё один отличный пример откуда-то из сети.
19 марта 2023 тем временем работа
Помедленнее, я записываю
Обычно при разработке исходишь из простой формулы: чем быстрее работает — тем лучше. Например, чем больше запросов приложение успеет выполнить за единицу времени — тем быстрее решится задача, ради которой эти запросы нужны.
Однако бывает наоборот: нужно снизить количество операций, которые программа способна выполнить. Допустим, мы дергаем внешний сервис и он банит, если делать это слишком часто. Пример — облако Битрикс24, которое требует отправлять не больше двух запросов в секунду.
Вот реализация такой замедлялки, которую я написал на прошлой неделе. Поддержки очередности в ней нет; основная решенная задача — выполнить как можно больше запросов, не выходя за лимит (с учётом того, что запросы могут делаться из разных сеансов).
Задача решена грубо — через константу, которая хранит дату текущей секунды и количество уже были отправленных запросов. Клиенты, которые утыкаются в ограничение — ждут. Для нагруженных систем такой подход не годится, а так — вполне может пригодиться.
REST-сервис для Service Manager
На этой неделе написал REST-сервис для настройки к нашему сервис-менеджеру (это такая конфигурация для управления инстансом 1cFresh). Развернуть контур разработки у нас — задача регулярная, и базу менеджера каждый раз приходилось тюнить руками: подкручивать витрину, менять адреса приложений, перезаписывать регламентные задания и так далее.
Реализация была проста. Придумай структуру JSON, напиши парсер, найди подходящий код в конфигурации, обеспечь его вызов извне и убедись, что ничего не сломал. Рутинная работа, в общем-то, но я люблю время от времени делать такие штуки: смотреть вокруг и пытаться сообразить, какая из ежедневных задач раздражает достаточно сильно.
Эта — хороший пример. Настройка сервис-менеджера не была проблемой (запустить приложение и покрутить настройки), но о ней нужно было думать и её нужно было делать. А теперь — нет:
- Есть JSON-файл со всеми настройками;
- Есть REST-сервис для его обработки;
- Есть скрипт, который засунет первый во второй;
- Есть пайплайн, который сделает всё это сам.
Короче, ботинок тёр ногу, а теперь перестал. Йаху!
Карьерные самосвалы
Коллега проворчал, что если продолжать эту логическую цепочку, то конфигуратор будет «Жигулями», а EDT — «Кама1» (это такой электрокар, который много лет пилят где-то в недрах КАМАЗа и всё никак не могут собраться с силами и, наконец, допилить).
Ну а я стараюсь смотреть на вещи с оптимизмом. Думаю, платформа и её IDE — это такие карьерные самосвалы. Никто в здравом уме на них по домашним делам не катает, но на разрезе эти звери незаменимы!
20 февраля 2023 1С
Про странный Битрикс
Чем дальше лезу в REST-интерфейс Битрикс24, тем сильнее поражаюсь тому, насколько необычно устроено мышление у его разработчиков. Проявляется это по-разному.
Взять, например, интерфейс сделок и товаров по ним. В таблице последних нет поля суммы: мол, нужна тебе сумма по строке — сам и считай. Зато сумма есть на уровне документа. Угадаете, как называется поле?
AMOUNT? DEAL_AMOUNT? DOCUMENT_AMOUNT? AMOUNT_TOTAL?
Не угадали, правильный ответ — OPPORTUNITY.
Но вернемся в строке товара. В ней есть товар, ставка НДС и единица измерения. Все три сущности вполне самостоятельны: у каждой есть отдельная таблица со вспомогательной информацией и свой собственный идентификатор. Логично предположить, что в строке товара они и хранятся: ID товара, ID ставки НДС и ID единицы измерения.
Логично-то логично, но нет, хрен там плавал. Для номенклатуры и правда хранится ID, а вот для ставки НДС — значение ставки, и для единицы измерения — код измерения по ОКЕИ ¯\_(ツ)_/¯
Нормализация базы данных? Чего? Какая еще нормализация? Отстань, мужик, работать мешаешь.
Групповая работа в Google Docs
Последний месяц переписываю типовой обмен данными между FirstBit ERP и Битриксом под клиентскую задачу. Коллеги, занимающиеся тем же на стороне Битрикса, подготовили под это дело массивный маппинг: какое поле на стороне 1С в какое поле Битрикса нужно передавать (и наоборот).
Этот маппинг они выложили в виде таблиц Google Docs, в интерфейсе которого можно видеть пользователей, пользующихся документом в этот момент — как залогиненных, так и анонимных. Последних он традиционно отображает в виде животных.
Коллеги в основном предпочитают работать анонимно. В итоге я последнее время крепко ощущаю себя диснеевской принцессой: приступаешь такой утром к работе, и отовсюду выкатываются неопознанные квокки, пингвины и шиншиллы :-)
18 сентября 2022 работа Битрикс тем временем
Слак советует
Слак, конечно, есть за что ругать. За тормоза, за баги, за оповещения. Но я просто обожаю его заглушки на случай, если новых сообщений нет.
Посмотрите, какая милота:
Зачем вообще нужны психотерапевты?
Или вот:
Боже, слак, хоть ты не начинай.
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 1С
Не так, а этак!
Про хорватский комикс 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, да и вообще... В мире и так хватает энтропии. Особенно, блин, сейчас.
Смотри не перепутай
Если вид операции — продажа товара или недвижимости, то открой общую форму AdvancesPickFormWithVAT с параметрами, описанными в структуре PickParameters. Колбеком будет метод EditPrepaymentOffsetEnd, описанный в этом же модуле; передай ему структуру AdditionalParameters. Форму нужно открыть так, чтобы она заблокировала весь интерфейс.
А вот если вид операции — возврат поставщику, то открой общую форму AdvancesPickFormWithVAT с параметрами, описанными в структуре PickParameters. Колбеком будет метод EditPrepaymentOffsetEnd, описанный в этом же модуле; передай ему структуру AdditionalParameters. Форму нужно открыть так, чтобы она заблокировала весь интерфейс.
Смотри не перепутай.
16 марта 2022 1С код с запашком
Минус Google Fonts
Год назад, блин. Ладно, всем привет! С вами Джонни Слоупок! Сегодня мы будем выпиливать из моего блога работу с Google Fonts. Я подгружал с него основной шрифт (PT Sans), но без кросс-доменного кэширования единственный смысл делать это дальше — если сервер, на котором работает сайт, слабоват и с гугла шрифты грузятся шустрее.
В моем случае блог отдают сервера гитхаба, которые на производительность не жалуются, так что теперь PT Sans загружается прямо с них. И знаете что? Разница прямо драматическая. Если раньше при обновлении страницы была явно заметна задержка между загрузкой страницы и загрузкой шрифта, то теперь её невооруженным глазом не разобрать. Если у вас свой блог и хотите попробовать — вот тут есть классный сервис, который решает задачу в несколько кликов.
Не забудьте повесить звезду на репозиторий!
Ранее Ctrl + ↓