-
Don't be a meat proxy
Коротенькая заметка о ребятах, которые на все отвечают выхлопом нейросети: Don’t be a meat proxy. Хороша тем, что метко вводит новый термин: meat proxy. Мясной посредник между человеком и нейросетью.
Замечаю, что все больше людей скатываются к роли посредника. Задаешь коллеге вопрос – он подвисает на пять минут и кидает md-выхлоп. Разумеется, он его не читал: тебе надо – ты и разбирайся.
Попадаются ребята, которые открыто пишут: Иван, я передал твои замечания по ревью нейросети, и вот что она сказала… Далее идет md-выхлоп, который, конечно же, заботливый коллега даже не читал.
Некоторое время я не знал, что делать с такими людьми – под каким углом смотреть и как взаимодействовать. На мой взгляд, человек, который проксирует каждое обращение к нейросети – словно проблемный родственник. Лучше его не провоцировать и не подкидывать горячих тем, и тогда, может быть, все обойдется.
Со временем я понял, что, похоже, некоторые люди плохо улавливают этикет. Каждая технология требует своего этикета, но не все это понимают – в инструкции не написано. Скажем, когда появились мобильные телефоны, считалось нормальным обсуждать бытовые дела на всю маршрутку. Когда появились планшеты и мобильный интернет, каждый решил, что можно включить сериал или игру без наушников. Сейчас так поступают разве что дети и пенсионеры.
С нейросетями та же история. Есть те, кто по какой-то причине не понимает: людям нравится нормальное, живое общение. Взаимодействие с машиной – это один протокол, с человеком – другой. Если коллега отвечает макрдаун-выхлопом, то тем самым нарушает негласные договоренности. С ним просто не хочется общаться – каким бы лапочкой и хорошим человеком он ни был.
Верю, что когда-то это поймут. Я подожду.
-
О Конфуции
Читаю Конфуция. Вот какой случай напомнил о нем.
Жил в Америке ультра-патриот. Трамп, МАГА, все дела. Потом женился на русской эмигрантке, и пара поехала в отпуск. Супруга как раз продлевала визу, и оказалось, что старый документ уже недействителен, а новый еще не выдали.
В аэропорту к паре подошли представители ICE – Immigration and Customs Enforcement (иммиграционная и таможенная служба США). Тут важно понимать контекст. Формально ICE борется с незаконной миграций, однако при Трампе штат расширили на порядок, чтобы проводить облавы. На работу в ICE устраивается отребье вроде бывших военных, таксистов и охранников. Мало того, что эти люди озлоблены на всех; так еще государство дает им в руки летальное оружие, чтобы задерживать мигрантов.
То, что подобные облавы проходят со всеми возможными нарушениями, нет смысла и говорить. Достаточно не той одежды, головного убора, цвета кожи, чтобы оказаться в приемнике на месяцы. Семьи разделяют. Иногда при задержании гибнут люди.
Представителям ICE не понравилось, что у супруги виза еще не выдана. Ее отправили в приемник, и там она провела несколько недель. Ситуация в приемнике ICE местами хуже, чем в тюрьме. Например, свет никогда не выключают, а охранники нарочно громко говорят по рации. Неделя – и от недосыпания едет крыша. Никаких медикаментов достать нельзя, правозащитников не пускают. За грубое слово изобьют и скажут родственникам, что поскользнулся на банановой кожуре.
Все это время муж пытался вызволить супругу. Навещал ее трижды в неделю, видел все своими глазам. В итоге женщину отпустили под залог с надетым на ногу браслетом. В обращении к прессе мага-патриот сказал, что разочарован в Трампе и ситуации с преследованием людей.
История пары на этом не кончилась: им еще ходить по инстанциям в браслете и доказывать правоту. Однако оставим их и подумаем над другим вопросом: при чем же тут Конфуций?
При том, что примерно в 680 году ДО нашей эры (то есть 2700 лет назад) Конфуций вывел формулу человеколюбия: не делай другим того, чего не желаешь себе. Разумеется, и до Конфуция эту мысль высказывали в том или ином виде, но он возвел ее в абсолют. На человеколюбии держится все учение Конфуция.
Условный мага-патриот уверен: можно устраивать облавы на мигрантов ради высшего блага. Ведь это мигранты: они цветные, глупые, что с них взять. Подумаешь, в приемнике тяжело спать и нет медикаментов? Это ложь правозащитников.
Но когда в жернова попадает близкий человек, все меняется. Товарищ
СталинТрамп, произошла чудовищная ошибка…Если бы у мага-патриота был хоть грамм мозгов, он бы понял, насколько верна формула Конфуция. Не желай другим гнить в приемнике, если не хочешь, чтобы то же самое случилось с тобой – или близким, что отнюдь не лучше.
За последние 2700 лет люди не придумали ничего лучше этой формулы. Остальные религии и учения – просто ее повторы. Например, формула целиком вмещает десять христианских заповедей: почитай родителей, не укради, не убий… В самом деле: хочешь, чтобы дети тебя уважали? Уважай своих родителей. Не хочешь, чтобы у тебя крали? Не кради сам. Не хочешь быть убитым? Не убий.
И так далее.
Глядя на историю людей, иной раз поражаешься. Мысль высказали 2700 лет назад и с тех пор повторяют во всех вариациях. Понять ее – это ведь не вырастить плавник или третью руку: тут не нужны тысячелетия. Но судя по текущей обстановке, до понимания формулы осталось еще очень и очень долго.
-
Чинить или отказаться
Когда что-то не работает, очевидное решение в том, чтобы починить. Второе неочевидное – отказаться. Чем старше становлюсь, тем чаще отказываюсь от того, что ломается. Разумеется, тезис слишком абстрактный и решается по ситуации. Но часто отказ не рассматривают в принципе и чинят одно и то же годами. Не надо так: отказ и пересмотр очень важны.
-
Повторный рендер
Почти на всех сайтах я замечаю повторный рендер. Это когда контент нарисовался, а потом Реакт решил, что виртуальное дерево устарело. Поэтому вжух – и контент рисуется еще раз.
То же самое во многих мобильных и настольных приложениях вроде Slack или Teams — которые только называются “приложениями”, а на самом деле оболочка Хрома или WebView.
Никто не считает это проблемой. Подумаешь, мигнул контент! В нулевые скорость была низкая, верстали таблицами, и сайт собирался по 30 секунд. Бывало, уже давно читаешь текст, и раз – что-то подгрузилось, подпрыгнуло, перестроилось. А тут – всего-то мигнуло.
Забавно, что современный фронтенд по-прежнему в ситуации эпохи нулевых – не может победить технические трудности. Должен быть улучшенный алгоритм рендера, который бы не срабатывал дважды. Еще лучше – дать над этим контроль разработчику.
Ну и фронтендеры хороши: никого не парит, что экран мерцает. Я вот заметил недавно, что на каждый клик огромная таблица повторно рендерится. А мне отвечают – не приоритетная задача. Спасибо, починим через никогда.
Давайте договоримся: не важно что у вас под капотом, Реакт-Вуй или что угодно. Контент не должен перерисовываться только потому, что ему так показалось. А если эти ваши Реакты-Вуи не починить, то верстайте так, чтобы не провоцировать повторный рендер.
-
Confirmation

Подтверждать или нет?
Кстати, лютейше бесят ребята, которые делают кнопку подтверждения слева. Это неправильно. Продолжение действия должно быть справа, а слева — возврат или отмена. Разумеется, к тем ребятам, которые не могут показать текст, это не относится — у них еще все впереди.
-
Кложурный тулинг
Если я правильно понимаю ты писал (пишешь?) на питоне в том числе. Просто я немного поглядываю что происходит в мире clоjure и вижу, люди как-то справляются без linter-ов, typechecker-ов и без такого инструмента, как uv (это менеджер интерпретатора, зависимостей проекта и виртуального окружения) в мире python. Когда работаешь с чужим кодом и погружаешься в него, то такие вещи очень сильно помогают. Возможно, в мире clоjure как-то можно обойтись без них, но тогда мне интересно как?
До прихода в Кложу я много писал на Питоне. Сейчас, хоть и меньше, тоже приходится: на работе есть Python-лямбды и скрипты. Питон — популярный язык, и я прибегаю к нему в случаях, если нужно что-то продемонстрировать для широкой аудитории.
Если отвечать на вопросы буквально, то да: тулинг Кложи не дотягивает до Питона. Для него созданы десятки линтеров и чекеров, а к каждому — еще столько же плагинов. Есть Jetbrains с Pycharm, которая выводит типы и предлагает автокомплит на любой чих. Программирование на Питоне в Pycharm стало как в Джаве — все типы подхватываются, и возникает ощущение, что в языке строгая типизация. Что касается uv и uvx, то я не застал их, но знаю, что это мощные средства.
До этого изобилия Кложе далеко как до Луны. IDE нет, есть только плагины к редакторам. Я пользуюсь связкой Emacs + Cider, но понимаю, что освоить ее новичку трудно. Автокомплит каждый настраивает как может. Проверку синтаксиса в полете и прочие удобства — тоже. Централизованным решением вроде Jetbrains даже не пахнет, и вряд ли оно когда-либо появится.
Не все так плохо с линтерами. Есть весьма развитый clj-kondo, который отлавливает много ошибок, например неверное число аргументов, необъявленные переменные и так далее. Суммарно кложурных линтеров наберется с десяток, и если использовать хотя бы пару из них, это решит некоторое число проблем. Также есть форматтеры кода по определенным правилам.
Существует кложурный LSP сервер (Language Server Protocol). Во многих редакторах LSP-клиент идет из коробки (VS Code, Emacs), так что здесь наблюдается развитие. С LSP у вас будет автокомплит, переход по коду и остальные базовые вещи.
В Кложе есть REPL, который закрывает много проблем. REPL основан на том положении, что единственный способ доказать, что код работает – это запустить его. Бывает, что код на Джаве выглядит корректно, но не работает. Непойманное исключение, ошибка индекса в массиве, NPE и так далее. Все это проверяется на практике, компилятор не поможет. Будет глупо оправдываться тем, что компиляция прошла: какая разница, если прод падает?
Зато REPL позволяет выполнить код в редакторе и отловить подобные случаи. Кстати, замечаю вот что: все больше джавистов топят за TDD – разработку от тестов. Парни не понимают, что TDD – это прокисший REPL, своего рода костыль, чтобы поскорее запустить код. В Джаве нет репла, но есть зеленая кнопочка Run, которая появляется в Main- и Test-классах. Нажатие этой кнопочки – просто убогий способ запустить код и ничего больше.
REPL не отменяет тестов, их пишут – юнит-, интеграционные и так далее.
Если переходить на Кложу с языков вроде Питона или Джавы, будет неудобно. Там у вас уютный Jetbrains, который по одной клавише угадывает экран кода. Здесь — самосбор: плагины к редактору, запуск линтера из командной строки. Зачем все это?
Затем, чтобы выйти из зоны комфорта, увидеть разнообразие, попробовать себя в чем-то другом. IDE и тулинг на все случаи жизни — это здорово, но нельзя на них замыкаться. Не вся работа делается в IDE по подписке. Когда Рич и Кен делали Unix и Си, разве были у них средства, аналогичные нашим? Они сами написали линтеры, парсеры, чекеры и прочие обвязки. А как написали IDE без IDE?
Удобства – это хорошо, но плохо, когда зависишь от них. Если точнее, плохо, когда кругозор сужается до той степени, когда жизнь без удобств становится немыслимой. Речь не о том, чтобы полностью от них отказаться. Но полезно быть в состоянии что-то сделать без привлечения мощных средств.
Когда вы увозите ребенка к бабушке в деревню, скорее всего там нет микроволновой печи, кондиционера, интернет-канала на 4К и других полезных вещей. Но никто не сомневается, что ребенку в деревне полезно: речка, солнце, животные. Отдохнет от гаджетов, помоется в дачном душе и вообще – не развалится.
Так и здесь. Да, чего-то не хватает, но не развалитесь. Можно и на Кложе писать хороший софт, зарабатывать и получать удовольствие. Да и не только на Кложе: я бы с удовольствием взялся за коммерческий проект на Common Lisp или Cobol — да на чем угодно! Нет тулинга? Не беда: либо обойдусь, либо напишу свой.
С таким настроем легко жить и смотреть в будущее.
-
On cowardness in Clojure code
Imagine you have a function accepting a value and doing something with it:
(defn double-number [x] (when x (* x 2))) ;; or (defn get-user [id] (when id (jdbc/execute! *db* ["select..." id])))A common pattern which comes all the time is to wrap the entire body with a
(when id ...)form. You don’t want to process nil values so it’s safer to protect yourself against NPEs. Without(when ...), a nil value can ruin the entire pipeline, cause a null pointer error, trigger DB queries in vain and so on. These all sound reasonable, yet I’ve got my own term to describe such a kind of code: “coward style”.A person who is wrapping the whole function with
(when)isn’t getting one thing. If a function had been given nil, it should have never been called instead. Clojure provides a number of macros to call a function conditionally depending on arguments, for example:(some-> (get-user-id) (get-user))Should
(get-user-id)return nil, the(get-user nil)form never gets called. The same applies to(cond->)and other macros that build an execution form conditionally.In other words: a function must not check its input parameters for nils. But those people who call this function must.
Now let me explain the “coward style” I mentioned before. It’s when people write like this:
(defn double-number [x] (when x (* x 2)))I don’t know what this code tells you, but to me, it’s clearly this: “Guys, I don’t want any problems. I don’t want any exceptions to be raised. If you supply me with a number, I’ll double it but won’t do anything if you pass nil. I cannot process it but won’t argue on you. Let’s keep it all quiet. Deal?”
This is a speech of a typical coward: I don’t want problems. I don’t want stack traces. I don’t want alerts and investigations. Let’s be quiet. The job is half-way done in fact as the function works partially. It won’t tell you when something is not quite right.
I’ve seen plenty of computation chains like this:
(-> some-param (parse-param) (pre-process-param) (get-use-id) (get-user-by-id) (send-user-somewhere))Now imagine that every function starts with
(when ...), and the final function crashes with NPE. It will be quite challenging to find who is guilty. These functions are real cowards: nobody wants to take blame. “I got nil → I returned nil. Not my business. I washed my hands”.Thus, stop writing functions starting with
(when ...). If a function silently swallows a nil value doing nothing, sooner or later you’ll pay for that. Or your teammates will.There is still a way though to protect yourself against nils which I like a lot. Use built-in pre- and post conditions:
(defn double-number [x] {:pre [(number? x)]} (* x 2))Now if you pass nil, you’ll get a clear error
(double-number nil) ;; Execution error (AssertionError) at … (REPL:211). ;; Assert failed: (number? x)Preconditions help a lot with guessing types. Above, they clearly say
xmust be a number and nothing else. In addition to:preand:postforms, the standard(assert ...)form might help in the middle of a function to interrupt execution when you know it makes no sense to go on with a weird value.Keen mind that
:pre,:post, andassertforms rely on the global*assert*variable. It’s a good practice to rely on assertions a lot but wipe them off on production as they slow down the code. When baking an uberjar, setclojure.core/*assert*to false. If it’s ClojureScript with a shadow compiler, pass{:elide-asserts true}into the:compiler-optionsmap for a production release.I agree that pre/post and assertions take lines of code, and sometimes they make code a bit noisy. But they will save you hours of debugging. Don’t be a coward whose main goal is to avoid exceptions. Don’t hide weird things. Be simple and explicit, and let your code express these two qualities.
-
Глава 10. Релевантный поиск
Главы
- Введение в документы
- Базовые возможности JSON
- JSON в таблицах
- Индексирование JSON
- Ограничения в документах
- Язык путей JSONPath
- Отчеты, функции, расписание
- Функции на языке Python
- Версии и патчи
- Релевантный поиск
Содержание
- Главы
- Поиск в конкатенации полей
- Слоеный поиск
- Замечания к UNION
- Последующая обработка
- Замена UNION на FULL JOIN
- Коротко о MapReduce
- Поиск в исторической таблице
- О быстродействии
- Дальнейшие улучшения
- Страничная навигация
- Полнотекстовый поиск
- Объект запроса
- Определение и хранение языка
- Полнотекстовый слой в UNION
- Оптимизации и доработки
- Заключение
В последней главе речь пойдет о релевантном поиске документов. При таком поиске документу назначено число, которое означает, насколько точно он подходит запросу. Мы узнаем, как выбирать документы по разным критериям, ранжировать и объединять их двумя способами. В числе прочего мы рассмотрим полнотекстовый поиск силами
tsvectorиtsquery.В главе про индексы мы упомянули поиск документов. Поиск необходим любой системе, неважно стартап ли это или крупный банк. В основе поиска лежат правильные индексы, но их одних недостаточно: понадобятся и другие техники.
-
Глава 9. Версии и патчи
Главы
- Введение в документы
- Базовые возможности JSON
- JSON в таблицах
- Индексирование JSON
- Ограничения в документах
- Язык путей JSONPath
- Отчеты, функции, расписание
- Функции на языке Python
- Версии и патчи
- Релевантный поиск
Содержание
- Главы
- Историческая таблица
- Демонстрация
- Создание версий
- Версии на триггерах
- Доводы против триггеров
- Версии в приложении
- Версии в Postgres
- Ограничение по времени
- Восстановление версии
- Архивация версий
- Стандарт JSON Patch
- Патчи в приложении
- Патчи в базе данных
- Версии с патчами
- Прием патчей от клиента
- Коротко об event-sourcing
- Сбор агрегатов из событий
- Махинации с патчами
- Бесконфликтное редактирование
- Решение конфликтов
- Технические детали
В этой главе мы поговорим о том, как хранить разные версии одного документа. Обсудим, как организовать историческую таблицу, перемещать в нее документы и восстанавливать их. Также мы затронем тему разности JSON и познакомимся со стандартом JSON Patch (не путать с JSON Path).
Как мы упоминали, документ – это большая структура данных. Некоторые документы содержат сотни полей, и они часто меняются. При этом изменения фиксируют: создают резервные копии документов. Эти копии открывают полезные возможности, например:
- откатить ошибочную операцию, что важно в финансах и банковском секторе.
- Пересчитать какие-то показатели, если в прошлом это сделали неверно.
- Вести аналитику: смотреть как менялись сущности во времени, строить графики, отслеживать рост и падение показателей.
Некоторые разработчики уверены, что ответ на все перечисленное – бекапы. Чтобы получить документ во вчерашнем состоянии, нужно восстановить бекап на тестовую базу и прочитать его оттуда. Этот подход справедлив лишь отчасти, потому что восстановление бекапа – дорогая операция. Выполнять ее ради одного документа неэффективно. Иногда один и тот же документ нужен в нескольких срезах, и приложение не может ждать, пока восстановятся все бекапы.
-
Русская речь в фильмах
Иногда русская озвучка бывает, мягко говоря, спорной. Актеры кричат в тех местах, где персонаж шепчет; интонация странная, пропадают акценты, идиомы, игра слов. Так что если вам позволяют условия (знаете язык, партнер(ша) не возражает), потребляйте фильмы и игры в оригинале (или хотя бы ключевые сцены). У этого правила, однако, есть исключение: иногда в оригинале звучит русская речь. В таком исполнении, что хочется не слышать ее ни за какие деньги.
Имеем американского персонажа. Всем он хорош: и силен, и умен, и женщину спас. Одна беда – русского происхождения. И вот на середине фильма всплывает русская мафия, дядюшка или бывшая, с которыми герой изъясняется по-русски. То есть как по-русски: в Гугл-транслейт набивается текст на английском, тот выдает русский транслит. Актер учит его наизусть как абракадабру: “Татиана, как дафно ти юже десь?” Татьяна: “Пивет Джон, две ньидели ка пиехаля”.
Разумеется, у меня нет претензий к американскому зрителю. Им без разницы – русский, бурятский, венгерский – все это наречия каких-то варваров. Но куда смотрят создатели фильма? Разные факт-чекеры и консультанты, которые отвечают за реалистичность сцен. Неужели нельзя найти русскоговорящего актера с похожим голосом и озвучить пару фраз? В чем сложность?
Когда русский бандит обращается к американцам, проблемы не возникает. Тут даже переигрывают: “лэт мы спык ынглиш фр-р-ром май хар-р-рт”. Плохой персонаж всегда будет с рокочущим “р”. Как обезьянничать, так все мастера. А как насчет нормальной речи?
Много лет назад со мной был случай. Я играл в одну игру, и там на хороших парней (американцев) напали плохие (конечно, русские). Атаку отбили, и одного молодого бандита взяли в плен. А он оплакивает убитую шальной пулей сестру: Наташа, очнись, солнышко, пойдем… и все это – на чистом русском. Ощущение, словно за спиной кто-то говорит. Я аж подскочил на стуле.
Из Википедии и всяких ссылок я узнал, что этот фрагмент – инициатива русскоязычного сотрудника студии. Изначально дорожку записали как есть – транслитом. Вообразите, как звучали слова скорби из уст человека, который не знает языка? Картавые “встаувай, Натащья, ти живуа? Нье умиай!” Все это – в момент смерти? Это даже не кринж, а пиздец, и так делать нельзя.
Разработчик прекрасно это понимал и сделал вот что. Когда все ушли, он записал дорожку на нормальном русском и подменил в ассетах. Никто не заметил, и русская речь ушла в релиз. Позже игру хвалили в том числе и за это: впервые за вечность в игре адекватная речь, а не транслит.
Выходит, что инди-студия смогла, а Голливуд не может? Слабо верится.
Интересно, что в локализации фильмов мы не сталкиваемся с подобным кринжем: герой говорит с родными на нормальном языке, в то время как в оригинале звучит тарабарщина. Оригинал, увы, нет-нет да подкинет подобный сюрприз. Длятся подобные сцены недолго, но даже их хватает, чтобы свалится на пол от отчаяния и стыда.