-
Bogus: a simple GUI debugger for Clojure
(This is a copy of the readme file from the repository.)
Bogus is a small, GUI-powered, NIH-reasoned debugger for Clojure.
Installation
Lein:
[com.github.igrishaev/bogus "0.1.0"]Deps.edn
{com.github.igrishaev/bogus {:mvn/version "0.1.0"}}The best way to use Bogus is to setup it locally in your
profiles.cljfile:;; ~/.lein/profiles.clj {:user {:dependencies [[com.github.igrishaev/bogus "0.1.0"]] :injections [(require 'bogus.core)]}}Usage
Once you have the dependency added and the
bogus.corenamespace imported, place one of these two forms into your code:(bogus.core/debug) ;; or #bg/debugFor example:
(defn do-some-action [] (let [a 1 b 2 c (+ a b)] #bg/debug ;; or (bogus.core/debug) (+ a b c)))Now run the function, and you’ll see the UI:

The UI window blocks execution of the code. In the example above, you’ll hang right before executing the next
(+ a b c)form. Close the window to continue execution of the code.The UI consists from three parts: the input area, the output, and the log. Type any Clojure-friendly form in the input textarea and press “Eval”. The result will take place in the output textarea. You can copy it from there to your editor.
The input can take many Clojure forms at once. They are executed as follows:
(eval '(do (form1) (form2) ...))so you’ll get the result of the last one.
If you mark some text in the input with selection, only this fragment of code will be executed.

In the input code, you can use any local variables as they’re global ones. In the example above we’ve executed the
(+ a b c)form referencing locala,b, andcfrom theletclause.The “Locals” button pretty-prints the local variables. Bogus does it in advance when the window opens the first time. The “Inspect” button opens the standard
clojure.inspector/inspect-treewidget rendering the locals. This is quite useful when examining massive chunks of data.
The Log area tracks the history of the expressions you executed and their results. That’s useful sometimes to copy-paste it somewhere. Should you get an exception, it gets rendered with the
clojure.stacktrace/print-stack-tracefunction (which probably needs some improvements).
You can have several debug breakpoints, for example:
(defn do-some-action [] (let [a 1 b 2 c (+ a b)] #bg/debug (+ a b c) (let [d 9] #bg/debug (* a b c d))))The first debug session will take the
a,b, andclocals, whereas the second one will havea,b,c, andd. You won’t proceed to the second session until you close the first window.Bogus debugger works in tests, in nREPL, in ordinary REPL, in Manifold, in the futures as well. Here is a small demo of having two debug sessions in parallel threads:
(let [f1 (future (let [a 1] #bg/debug (+ a 1))) f2 (future (let [b 2] #bg/debug (+ b 1)))] (+ @f1 @f2))If you run this code, you’ll get the two windows each having their own locals:

The second session has the
f1local var captured from theletclause. If you try toderefit, the entire REPL will hang due to the mutual blocking, so be careful when dealing with parallel debugging.How it works
The under-hood of Bogus is simple: it captures the local vars from the
&envmapping available in a macro. Then there is a couple of functions that “globalize” the locals by injecting them into the origin namespace usingclojure.core/intern. Once the namespace is populated, theevalform treats local vars as globals. Before leaving the macros, the vars are “deglobalized” meaning all the injected vars are removed. The macros is smart enough to preserve existing global vars: it temporary assigns them another name like__OLD_my-var__.Why
The idea of making my own debugger came into my mind while I was writing a new chapter about nREPL and code evaluation. Although Cider provides much more powerful tools for debugging, I still believe Bogus might be useful for someone new to Clojure. The main benefit of Bogus is, it doesn’t require the whole nREPL stuff and Emacs. One can use it with any editor or environment. After all, tinkering with Bogus gave me some good material for the book.
Other
Copyright © 2022 Ivan Grishaev
-
Увольнение
Прошлый понедельник запомнился слитыми письмами, где фирмы разрывали контракты с российскими удаленьщиками. Вроде того, что от Гугла по ссылке. Тенденция не обошла меня стороной. Понедельник я провел в смутной тревоге, понимая, что работодатель способен на этот шаг. В пять вечера получил письмо об увольнении.
По этическим причинам не будут постить сюда скрин — по моим меркам слив переписки находится ниже любого дна. Это был такой же абстрактный текст, как и у Гугла. Что-то в духе “мы ценим твою работу, ничего личного, прощай”.
Дело в том, Иван, что как бы мы ни ценили три с половиной года твоей работы, есть некие полиси, которые предписывают порвать наши отношения. Что это за полиси, где их увидеть и прочесть – начальство не уточнило.
Не то чтобы меня расстроила потеря работы — не конец света, найду другую. Но такой стремительный конец отношений заставляет мысленно к нему возвращаться. Еще в пятницу расписываешь коллегам задачи, проводишь созвоны, планов громадье. В понедельник — до свидания.
Казалось бы, кому как не мне, удаленьщику с семилетним стажем, понимать, насколько ты не защищен от подобных ситуаций. В отличие от всяких EULA, договор с заказчиком я читаю по слогам до подписания. Прекрасно знаю, что одним пинком меня могут выставить. Но на созвоне все улыбаются, и это кажется невозможным. Оттого пинок ощущается сильнее.
Удивила скорость всей процедуры. В 17:00 я получаю персональное письмо. Через пятнадцать минут приходит анонс всей команде: Иван больше не с нами, будем скучать. Еще через десять минут отваливается доступ ко всей инфраструктуре. Никаких обсуждений, торгов: все линейно, от тебя ничего не зависит.
Интересно, что адекватная реакция была только у одного человека – украинского коллеги. Он эмоционально ответил в тред с анонсом, что увольнение русских не поможет Украине и ваша гнилая солидарность никому не нужна. Но разве его кто-то слушал? Швейцария знает лучше Украины, как ей помочь.
Начальство взялось отвечать на выпад: теперь мы не можем платить Ивану. Сухо возражу — никаких проблем с оплатой не было. МодульБанк, в котором я счастлив обслуживаться, не под санкциями, свифты доходят. Кроме свифта, в нем работает альтернативная система Visa B2B Connect, доступная и в Швейцарии. На какое-то время я бы согласился получать Пейпал или Transfer Wise. Можно попробовать крипту: биток, USD-токены. Тоже норм, есть знать как обращаться (а я знаю).
Да что там: на худой конец я бы мог формально уволиться и поработать бесплатно, а потом, как все наладится, заключить контракт по новой ставке, чтобы компенсировать потери. За пять минут я назвал пять вариантов, а если подумать, найдутся другие. Но если сказано “не можем” — значит не можем.
Украинский коллега, кстати, тоже попал в поле зрения “помогаторов” Украине. Если мой контракт расторгнут (агрессор), то его — “временно приостановлен” до тех пор, пока “ситуация не придет в норму” (жертва). Временно — это на сколько? Норма — как это понимать?
Не надо быть гением, чтобы понять: “временно” означает “пока ты сам не уволишься”. Будешь заморожен месяц, год, пять. Ты жертва, поэтому увольнять тебя опасно: еще сольешь переписку в Твиттер и подорвешь репутацию фирмы. Поэтому прояви инициативу.
Схожее происходит и в других фирмах: от русских надо избавиться, агрессоры, все дела. Но от украинцев тоже, только слегка по-другому. “Временно отключим” вас, пока ситуация “не придет в норму”.
По идее я должен ругать Путина и его “спецоперацию”. Но дело в том, что уволил меня не Путин — это сделали конкретные люди. Которые, в свою очередь, вешают на меня груз: это не мы, это ваш президент, к нему и обращайтесь. Со мной это не работает. Я потерял работу потому, что менеджеры решили что-то доказать. Не сегодня Путин, так завтра нашелся бы другой предлог.
Наши с фирмой отношения не прошли проверку на прочность. Фирме важнее следовать международной повестке, чем сохранить ведущего разработчика, взятого три с половиной года назад. Хорошо, как считаете нужным.
Не вздумайте меня жалеть: уже подсуетился, собеседуюсь туда-сюда. Назревают два варианта. Пишу не ради нытья, а чтобы сбросить мысли в текст и двигаться дальше.
То, что происходит с нами сегодня, ново и непонятно. Замечаю тенденции, которых раньше не было; жизнь стремительно меняется, и не так уж важно, в какую сторону. Искренне надеюсь, что смогу как-то выразить мысли на эту тему в следующем тексте.
-
Если бы тебе сказали
У демагогов популярен дешевый прием — если бы десять лет назад тебе сказали X, ты бы не поверил. Например:
— если бы десять лет назад вам сказали, что Россия нападет на Украину, вы бы не поверили.
— Если бы десять лет назад вам сказали, что мир сойдет с ума из-за ковида, вы бы не поверили.
Этим трюком демагог пытается усилить свою позицию — никто не верил в то, что случилось, но оно случилось. Поэтому в то, что я говорю сейчас, тоже сперва не верят, а потом оно сбудется.
Не дайте вас обмануть. Мир непредсказуем и сложен, и никакой прогноз на десять лет не будет точным. Прогнозы не учитывают открытия, изобретения, психические отклонения политиков и прочие вещи, которые вокруг нас. Прогноз подразумевает, что за десять лет окружение не изменится, и за это время придет в то состояние, что показывает модель. А это неверно, неважно обычный у вас машын-лернинг или дип-машин-лернинг с подкреплением (Греф.jpeg).
Возьмите любое событие и подставьте впереди “если бы десять лет назад”. Результат всегда будет истинным:
— Если бы десять лет назад вам сказали, что биткоин будет стоить пять миллионов, вы бы не поверили.
— Если бы десять лет назад вам сказали, что незаконно построенный павильон на остановке снесут, вы бы не поверили.
— Если назвать человеку дату смерти за десять лет до нее, он бы не поверил.
— За десять лет до Pokemon Go никто бы не поверил, что люди будут ловить виртуальных зверей на улице.
— За десять лет до Чернобыля никто бы не поверил.
— За десять лет до Титаника…
— За десять лет до Чечни…
— За десять лет до Гитлера…
Короче, вы поняли — важные события предсказать невозможно. Отдельным личностям остается спекулировать: если случилось то, значит случится другое. Но это неверно.
Любопытно, что то же самое было и сто, и двести лет назад. Достаточно взять Толстого, Достоевского или хронику. Их персонажи живут в изменчивой среде, никто не знает, что будет через год и каждый движется как может. И это нормально: спокойным может быть только час или день. Будущее всего тревожит — как положительно, так и негативно — своей неизвестностью.
Меньше слушайте тех, кто говорит про прогнозы десятилетней давности.
-
Единомышленники (+18)
Давно не читал Торшину и вдруг. Скриню для истории, на Фейсбук полагаться нельзя.

-
The Pact library for Clojure
(This is a copy of the readme file from the repository.)
Pact is a small library for chaining values through forms. It’s like a promise but much simpler.
Installation
Lein:
[com.github.igrishaev/pact "0.1.0"]Deps.edn
{com.github.igrishaev/pact {:mvn/version "0.1.0"}}How it works
The library declares two universe handlers:
thenanderror. When you apply them to the “good” values, you propagate further. Applying theerrorfor them does nothing. And vice versa:thenfor the “bad” values does nothing, but callingerroron “bad” values gives you a chance to recover the pipeline.By default, there is only one “bad” value which is an instance of
Throwable. Other types are considered positive ones. The library carries extensions for such async data types asCompletableFuture,Manifoldandcore.async. You only need to require their modules so they extend theIPactprotocol.Examples
Import
thenanderrormacros, then chain a value with the standard->threading macro. Boththenanderroraccept a binding vector and an arbitrary body.(ns foobar (:require [pact.core :refer [then error]])) (-> 42 (then [x] (-> x int str)) (then [x] (str x "/hello"))) "42/hello"If any exception pops up, the sequence of
thenhandlers gets interrupted, and theerrorhandler gets into play:(-> 1 (then [x] (/ x 0)) (then [x] (str x "/hello")) ;; won't be executed (error [e] (ex-message e))) "Divide by zero"The
errorhandler gives you a chance to recover from the exception. If you return a non-exceptional data inerror, the execution will proceed from the nextthenhandler:(-> 1 (then [x] (/ x 0)) (error [e] (ex-message e)) (then [message] (log/info message))) ;; nilThe
->macro can be nested. This is useful to capture the context for a possible exception:(-> 1 (then [x] (+ x 1)) (then [x] (-> x (then [x] (/ x 0)) (error [e] (println "The x was" x) nil)))) ;; The x was 2 ;; nilBesides
thenanderrormacros, the library provides thethen-fnanderror-fnfunctions. They are useful when you have a ready function that processes the value:(ns foobar (:require [pact.core :refer [then-fn error-fn]])) (-> 1 (then-fn inc) (then-fn str)) ;; "2" (-> 1 (then [x] (/ x 0)) (error-fn ex-message)) ;; "Divide by zero"Chaining with
thenanderroris especially good for maps as allowing destructuring:(-> {:db {...} :cassandra {...}} ;; Get a user from the database and attach it to the scope. (then [{:as scope :keys [db]}] (let [user (jdbc/get-by-id db :users 42)] (assoc scope :user user))) ;; Having a user, get their last items from Cassandra cluster ;; and attach them to the scope. (then [{:as scope :keys [cassandra user]}] (let [items (get-user-items cassandra user)] (assoc scope :items items))) ;; Do something more... (then [...] ...))Fast fail
To interrupt the chain of
thenhandlers, either throw an exception or use thefailurefunction which is just a shortcut for raising a exception. The function takes a map or a message with a map:(ns foobar (:require [pact.core :refer [then error failure]])) (-> 1 (then [x] (if (not= x 42) (failure "It was not 42!" {:x x}) (+ 1 x))) (error-fn ex-data)) ;; {:x 1 :ex/type :pact.core/failure}Supported types
The
corenamespace declares thethenanderrorhandlers for theObject,Throwable, andjava.util.concurrent.Futuretypes. TheFuturevalues get dereferenced when passing tothen.The following modules extend the
IPactprotocol for asynchronous types.Completable Future
The module
pact.comp-futurehandles theCompletableFutureclass available since Java 11. The module also provides its ownfuturemacro to build an instance ofCompletableFuture:(-> (future/future 1) (then [x] (inc x)) (then [x] (/ 0 0)) (error [e] (ex-message e)) (deref)) "Divide by zero"Pay attention: if you fed an instance of
CompletableFutureto the threading macro, the result will always be of this type. Thus, there is aderefcall at the end.Infernally, the
thenhandler calls for the.thenApplymethod if a future and theerrorhandler boils down to.exceptionally.Manifold
The
pact.manifoldmodule makes the handlers work with the amazing Manifold library and its types. The Pact library doesn’t have Manifold dependency: you’ve got to add it on your own.[manifold "0.1.9-alpha3"](-> (d/future 1) (then [x] (/ x 0)) (error [e] (ex-message e)) (deref)) "Divide by zero"Under the hood,
thenanderrorhandlers call thed/chainandd/catchmacros respectively.Once you’ve put an instance of Manifold deferred, the result will always be a
Deferred.Core.async
To make the library work with core.async channels, import the
pact.core-asyncmodule:(ns foobar (:require [pact.core :refer [then error]] [pact.core-async] [clojure.core.async :as a]))Like Manifold, the
core.asyncdependency should be added by you as well:[org.clojure/core.async "1.5.648"]Now you can chain channels through the
thenanderroractions. Internally, each handler takes exactly one value from a source channel and returns a new channel with the result. Forthen, exceptions traverse the channels being untouched. And instead, theerrorhandler ignores ordinary values and affects only exceptions. Quick demo:(let [in (a/chan) out (-> in (then [x] (/ x 0)) (error [e] (ex-message e)) (then [message] (str "<<< " message " >>>")))] (a/put! in 1) (a/<!! out) ) ;; "<<< class java.lang.String cannot be cast ..."Testing
To run the tests, do
lein testor justmake test.© 2022 Ivan Grishaev
-
Стоп-слова
Перечислю слова, которые никогда не использую и не советую вам. С объяснением почему.
Токсичный. Это слово по праву считается словом 2021 года. Внезапно всё у всех стало токсичным: коллеги, начальство, рекрутеры, близкие, родственники. Бездумно выдернутое из английского языка, слово перешло в русский без какого-либо смысла или конкретики.
Когда я слышу о токсичном человеке, мне не хватает деталей. Ну, токсичный, а что это значит? Чаще всего под этим имеют в виду “неприятный”, но все равно — чем именно неприятен человек? Он матерится? Делает замечания по работе? Не по работе? Он курит и затем дышит табаком на коллег (токсичен в буквальном смысле)?
Короче, мне нужны детали — что именно делает человек, как он себя ведет, что говорит. На практике оказывается, что его токсичность — плод воображения рассказчика, который с кем-то не ужился. Поэтому без конкретики слово “токсичный” ничего не значит.
Скам. От этого слова у меня просто горит. Бездумно вырванное из английского, в русском оно совершенно чужеродно. Скамом назывыют все то, в чем не разбираются, но считают подозрительным: криптовалюту, проекты Илона Маска. Нормальным считается заголовок в духе “Почему X это скам”. Хочется разбить автору лицо.
У английского слова scam есть точный, однозначный перевод — мошенничество. Других синонимов нет, точка. Вопрос — на кой черт притягивать слово, у которого есть четкий перевод? Я еще пойму английское privacy, которое трудно уместить в одно слово. Но для scam в этом нет смысла — обман, мошенничество.
Скамом называют все то, что им не является. Если учесть, что скам — мошенничество, то называя что-то скамом, вы должны понимать, в чем оно состоит. Ради интереса я спрашивал у некоторых людей, почему они называют скамом криптовалюту. Ответ удивил своей убогостью: потому что криптой платят за оружие и наркотики. Ох, беда.
Когда кто-то платит за оружие криптой, это не скам — обе стороны отдают и получают именно то, что ожидали, поэтому мошенничества нет. А когда вам звонит сотрудник безопасности Сбербанка и предлагает перевести деньги на “защищенную” карту — это мошенничество. Это значит, одно лишь участие криптовалюты не делает операцию с ней скамом, и операции с рублями не означают, что все чисто.
Короче, осторожней со “скамом” — слово короткое, а объяснить, что за ним стоит, трудно. Считаю дурным тоном использовать слова, смысл которых не понимаешь.
Лайфхак. Пошлое, уныле слово, которое заменило бездну русских слов. Способ, метод, прием, подход, решение, рецепт, алгоритм, подсказка, находка, идея — продолжать можно до бесконечности. Где-то в сети я видел картинку: перечислены эти слова, и подпись: если всё это у вас “Лайфхак”, то вы долбоёб. Грубовато, но в целом верно. Совершенно не вижу смысла в “лайфхаке”, когда говорю о способе решить проблему.
Ивент, риквест. Аналогично скаму, у этих слов есть точный, однозначный перевод. Event — событие, мероприятие, request — заявка, обращение. Поэтому когда вижу текст вроде “проведем корпоративный ивент”, становится стыдно от чужой тупизны. Самое дно — писать эти слова через и, то есть ивент и риквест. Получается декартово произведение тупизны и стыда.
Сторителлинг. Глупость этого слова обеспечена тем, что оно состоит из двух английский слов: story (история) и tell (сказать кому-то). В русском языке есть более емкое “рассказ”, когда человек доносит мысль или историю до слушателей. Как устно, так и письменно.
Таким образом, сторителлинг становится рассказом. Сторителлер, прости господи, это рассказчик. Курсы сторителлинга — курсы навыка рассказа, уроки рассказывания, мастерство рассказчика.
Современный сторителлинг, как правило, это гнилая реклама. К ней добавляют нелепых персонажей и дурацкий сюжет в надежде, что прокатит. Другой тип сторителлинга — доклады со сцены, когда человек рассказывает очевидные истины, прохаживаясь по сцене взад-вперед, смотря в пол и делая глубокие паузы.
Бумеры, зумеры. Не припомню случая, чтобы понадобилось выделить часть аудитории по возрасту. Подобная выборка отдает расизмом — предвзятостью к людям по определенному признаку. Фраза “зумеры не поймут” или “бумеры проходят мимо” в принципе не могут звучать вежливо и подходят только для пререканий в сети. Ответ “окей, бумер” я считаю настолько тупым, что кроме вздоха у меня нет другой реакции.
Выгорание. Никакого выгорания нет, есть доведенная до крайности усталость. То “выгорание”, которым страдает половина интернета, лечится сном, отказом от гаджетов в вечернее время, планированием дел на бумаге, разговорами с коллегами, начальством, родными. Всё, вы здоровы.
Уверен, читатели подскажут другие вредные слова, которых лучше не говорить.
-
Не словом, а делом
Как правило все сервисы, когда мы в них логинимся, присылают письмо. Там написано когда и с какого устройства был выполнен вход. Подобные письма присылают банки, мессаджеры, социальные сети, крипто-биржи. Это хорошо и правильно.
Как-то раз я внимательно прочитал подобное письмо. Смутила фраза, которую можно перевести так:
Если это вы, все в порядке. Если нет, немедленно заблокируйте ваш аккаунт.
Давайте представим, что вас взломали. Вы ничего не делали, тупили в телефон, и вдруг пришло письмо, что из Украины зашли ваш клиент-банк или биржу. Все, паника. Время идет на секунды. У мошенников все отработано, они моментально переводят деньги.
Что делать? Писать в техподдержку на
support@foobar.lol? Уже сам факт того, что этоsupport, говорит о том, что они доберутся до моего тикета в лучшем случае через час. Звонить? Номера нет под рукой, надо найти и потом висеть в очереди, слушая дурацкую музыку. Можно заблокировать личный кабинет через личный кабинет, но чтобы это сделать, надо сперва попасть в личный кабинет, верно? А мошенники могут этому помешать, например сменив пароль.Оказавшись в подобной ситуации, вы поймете: фраза “немедленно заблокируйте ваш аккаунт” — чистой воды профанация. Это можно сделать, только заранее потренировавшись. А кто будет тренироваться, да к тому же еще на разных сервисах?
Должно быть так. Вместо фразы “немедленно заблокируйте ваш аккаунт” в письме должна быть жирная красная кнопка “ЭТО НЕ Я!!! ЗАБЛОКИРОВАТЬ АККАУНТ!!!”. Ссылка подписана токеном, который действует пять-десять минут. Даже если письмо со временем утечет, ссылкой нельзя будет воспользоваться.
Ссылка перебрасывает на форму, где нужно подтвердить блокировку. Форма отправляется методом POST, чтобы всякие preview-сервисы не стриггерили блокировку за вас. После отправки формы аккаунт замораживается, все активные сессии завершаются, транзакции в очереди отменяются. Далее восстанавливаем доступ через поддержку.
Такая схема — истинная забота о клиенте. Не просто “заблокируйте аккаунт”, а все необходимое на месте. Конечно, она тяжелее в реализации, но сохранит деньги клиента и репутацию фирмы.
-
Качество Excel
Каждый раз, когда запускаю Эксель, поражаюсь, насколько он ужасен. Годы идут, столько всего меняется в лучшую сторону, а офисный пакет Микрософта так и остается дном.
Например, прислали мне CSV-файлик. Эксель уверен, что умеет его открывать, потому что при установке связал с собой расширение .csv. Тыкаю. Открывается картина:

Ну еб жеж тебя! Не умеешь открывать – зачем полез?
По пунктам:
-
Все поля слиплись в одну строку. CSV это Comma Separated Values, так? Comma значит запятая. Но придурочный Эксель делит поля по точке запятой. Comma, любезнейший, вы понимаете английский? Почему нельзя добавить простой детектор — пробежать строку и проверить, каких разделителей больше? Не понимаю.
-
Вместо русских букв — даже не кракозабры, которые случаются, если читать utf-8 как cp1251, а какие-то греческие письмена. Омеги, сигмы. Что происходит? Опять же, нельзя что ли прочитать десять строк и сделать анализ кодировки?
-
Ссыкливая надпись Possible Data Loss в первой желтой полоске. Некоторые данные могут быть потеряны. Что бы мне об этом пишешь, идиотский эксель? Сразу открой в формате Экселя, чтобы я мог пользоваться всеми возможностями. И только потом, если захочу, экспортирую проект в csv. А храниться он будет в Эксель-файле. Короче, разработчики не понимают разницу между проектом и промежуточным форматом. Беда.
-
Еще одна ссылкивая полоска с информацией о том, что нужно обновиться. Ни за что не поверю, что эти проблемы исправили в последней версии, так что зачем?
Другие мелочи. В нормальных программах, если мы редактируем элемент, нажимаем ввод. В экселе для редактировании ячейки надо нажать F2. Почему не F9 или F12? Тоже хорошие клавиши, и в них столько же логики.
Нажатие Enter перемещает курсор на ячейку вправо. Почему? Если я хочу вправо, то нажму стрелочку. Почему ввод что-то перемещает?
А вот тот же документ в Google Sheets. Кодировка нормальная, все разбилось по ячейкам, вопросов нет:

К чему это все?
Отдельные персонажи поругивают веб-приложения, что не натив, а декстоп весь такой шустрый, нативный, си-плюс-плюс. В широком плане это неправда — бывает так, а бывает наоборот.
Браузерный JS уже давно быстрый как незнамо что. Сравните работу в Adobe Illustrator (плюсовую настольную программу) и Фигму (Js, React + Canvas). И все станет ясно.
Или настольный Эксель с гугловым Sheets.
Десктопный софт может нещадно тормозить, а браузерный — плясать на кончиках пальцев. Десктопный софт может застрять в прошлом на два десятка лет, потому что там же застряли его разработчики.
Так что нет одного пути, все условно и не ложится на обобщения.
-
-
Опыт с телевизором
Сегодня не модно любить бренды вроде Эпл и Икеи, которые якобы заботятся о пользователях. Уже не новость, что за мнимую заботу потребитель дорого платит и подсаживается на иглу бренда. Однако у других фирм с заботой вообще все плохо.
Первое января 2022 года. Имеем дорогущий телевизор LG с OLED-матрицей. Это не просто хороший телевизор, а в принципе лучший вариант, что предлагает рынок. Своего рода Макбук-Про M2, если судить в таких категориях.
Так вот, казалось бы. Даже при столь высокой цене ни упаковать, ни подготовить к распаковке в LG его не смогли. Видимо, нет отдела, который занимается тем же в Эпле. Плюс ворох мелких косяков.
Например: достаю телевизор из коробки, собираюсь повесить на кронштейн. Выясняется, что в комплекте нет болтов для VESA-крепления. Дырки есть, а четырех болтов стоимостью, сука, 50 копеек каждый — нет.
Ладно, открываю пакетик с крепежом для кронштейна. Вижу два набора болтов: большие и маленькие. А на телевизоре дырки под СРЕДНИЕ. Получается чемодан без ручки. Дорогой, топовый чемодан. Но без ручки.
В тот момент я подумал, что неплохо бы вернуть смертную казнь, причем трансграничную. В Корею или Китай вылетает наш истребитель, захватывает служащих LG, от рабочего до исполнительного директора, и везут в Воронеж. Там показательно четвертуют на площади с трансляцией в интернет. Чтобы запомнили: если есть резьба, то в комплект должен быть болт под нее.
Отрываюсь от мечтаний. Первое января, магазины закрыты, купить болты не получится. Спокойно, товарищи: поставим телек на подставку и подождем до послезавтра. Беру подставку. При перемещении слышу, как брякает кусок металла. Елозит внутри, словно мыло в раковине. Уроды из LG не закрепили его, просто стыд.
После сборки подставка шатается. Поначалу мозг отказывается это принимать: подставка, предназначенная держать экран стоимостью около ста тысяч рублей, шатается. Кот пробежит, хвостиком махнет, и плакал твой телевизор. Ну или дети.
Эта гифка стоит тысячи слов и океана эмоций:

Вращается как шайба на льду. Это еще пол кривой, а на ровной поверхности крутится как спиннер.
В общем, обшарил я все полки-коробки и нашел пару нужных болтов. Еще пару скрутил здесь и там. Шайбы из комплекта оказались слишком толстыми, заменил на свои. Весь этот колхоз удачно лег друг на друга, как парад планет, и телек я повесил. С удовольствием повесил бы еще пару корейцев, которые отвечают за комплектацию.
Поймите меня — я не просто ною. Так делать нельзя, просто нельзя. Когда товар дорогой, забота о покупателе не просто желательна, она обязательна. В комплекте должно быть буквально все, что только понадобится: болты, гайки, стяжки, крепления, клипсы и остальное. Еще шестигранники и одноразовые отвертки. Все это стоит гроши — я ведь не прошу из закаленной инструментальной стали.
Та же Икея кладет в набор все перечисленное. Собираешь шкаф — вот тебе шестигранник, гаечный ключ и отвертка. Купил четыре кресла — получишь четыре пачки отверток и прочего. До сих пор по тумбочкам лежат.
Еще лучше пример — Эпл. Одно время я интересовался их 6К-монитором стоимостью в полмиллиона. Не чтобы купить, конечно (он мне не нужен), а с точки зрения товара. Как он выглядит, как упакован, как подключается?
Я был поражен процессом его распаковки. Ощущение, что сидела команда и рассчитывала все варианты: что покупатель подумает, что ему покажется и прочее. Распаковка напоминает запуск космической ракеты. Все уложено именно в таком порядке, и разрезы сделаны в тех местах, и материалы подобраны так, что отклонений быть не может.
Видосы:
Учтено, что сначала ты ставишь не до конца распакованный экран на подставку и только потом снимаешь остатки упаковки, чтобы не заляпать экран. При этом нет никаких инструкций. На каждом этапе доступен строго один следующий шаг, который как-то выделен. Пользователя не держат за идиота, а помогают ему.
Ясное дело, кто-то проделал большую работу, и она повышает стоимость товара. Это правильно: человек, который покупает монитор за полмиллиона, вряд ли думает о выживании, его волнует комфорт. Легче заплатить условные тридцать тысяч вместо того, чтобы одуплять сборку самому. Сборка — это досадная процедура, которая отделяет от пользования товаром. Поэтому умные люди стремятся ее сократить.
Да что там, я бы спокойно купил телевизор и за сто пять тысяч рублей, лишь бы в нем был весь нужный крепеж. Заплатил бы по тысяче за болт, только бы все было на месте. Да, такой я лошок-лопушок: не хочу бегать за болтами в строительный магазин. Подставку бы еще починить — долить миллиметр пластмассы. Не разорились бы.
Кстати, забавно вспоминать, сколько было шуток про подставку для эпловского монитора. Нога за тысячу долларов! Какой идиот ее купит? Вспоминаю анекдот про Тарантино:
— Квентин, вы так и не сняли фильма лучше “Криминального чтива”!
— А кто снял?
Смех смехом, а лучше той подставки ничего нет. Я ее видел, держал, шатал. Уверяю, когда будут бомбить Воронеж, подставка устоит. Она держит монитор и при этом красива. Видимо, сочетание этих двух и делает ее столь дорогой.

Если посмотреть на другие мониторы и телевизоры, станет ясно: их подставки либо не держат, либо уродливы. Нет, правда, все подставки отвратительны: какие-то лапы птеродактиля. На работе у меня монитор на 144 герц, который два года назад стоил 87 тысяч. На подставку нельзя смотреть без стыда. Дома монитор на 120 герц, тоже не дешевый. Подставка рвотная. Про телевизор я уже рассказал — у топовой модели она шатается.

Особое изумление вызывают инструкции к дорогим товарам. Мудаки-производители печатают брошюры объемом на сотни страниц. Плюс всякие купоны, реклама, гарантийные талоны. В итоге набегает на томик Чехова. Но почему-то схему сборки надо обязательно уместить на один лист. Чтобы картинки были со спичечный коробок. Чтобы подносить лист к глазам. Напечатать крупно на трех, четырех листах почему-то нельзя. Бумагу экономят?
Смотрите, в LG считают, что это понятная инструкция:

Забавный факт: инструкция предупреждает, что экран хрупкий и при установке его легко продавить пальцем. Как же, мудачье вы этакое, мне его держать? Почему бы не надеть на края тонкие пенопластовые бамперы, которые стоят вообще нисколько? Может, вместо предупреждений лучше обезопасить покупателя?
Короче, выводы.
-
Даже покупая дорогой товар, будьте готовы, что не хватит винтиков за два рубля. Почему это считается нормой — загадка.
-
Свою продукцию нормально пакуют только Эпл и Икея. Эти фирмы не сахар и порой вытирают ноги о покупателей. Но после их упаковки иметь дело с чем-то другим невозможно.
-
Если вы что-то производите, кладите в комплект все, что может понадобиться. Если покупатель побежал в магазин за чем-то недостающим — фирма обосралась.
-
Сложный товар нуждается в продумывании процесса распаковки и установки. Это повышает цену, но отбивается обзорами и опытом покупателя. Люди готовы платить дороже за комфорт и заботу.
-
Инструкции — крупнее. Нет, еще крупнее. ЕЩЕ СУКА КРУПНЕЕ. Один рисунок — одна страница.
-
Руководствами на малайском, болгарском и т.д. пусть подтирается СЕО.
-
Пригласите случайного Васю с улицы распаковать и включить ваш продукт. Уверяю, узнаете много нового.
Все, выговорился. Отпустило. Полегчало.
С наступившим!
-
-
Ютуб в настольном приложении
Открывая очередной видос на Ютубе, подумал — так жить нельзя. Мне ведь нужно только видео, а Ютуб в довесок льет рекламу, трекинг, похожее видео, комментарии. Браузер Brave и сторонние блокировщики помогают, но все тормозит. Плюс Гугл постоянно меняет что-то в интерфейсе, и чувствуешь себя животным, чью миску с едой передвинули в другой угол.
Наверняка же есть настольная прога, которой даешь урл — и она показывает. Слегка погуглил, и выяснилось, что так и есть.
Знаменитый плеер VLC умеет играть ютубные урлы. И не только ютубные, но и Вимео, BBC и другие (Порнохаба, увы, нет). Реализовано это скриптом на Lua, который по урлу вычисляет прямую ссылку на гугловый стрим.
Однако выяснилось, что то ли скрипт поломали, то ли Гугл обновился, и теперь просмотр Ютуба не работает. Вот что надо сделать, чтобы его починить.
Скачайте скрипт
youtube.luaс Гитхаба по этой ссылке. Далее зайдите в папку/Applications/VLC.app/Contents/MacOS/share/lua/playlistНа винде и линуксе, понятно, путь будет другим. Удалите файл
youtube.luac— это скомпилированный модуль, который сейчас не работает. Скопируйте сюдаyoutube.lua, что вы скачали. Перезапустите плеер.Чтобы открыть ютубный видос в VLC, пройдите по пунктам
File→Open Networkили нажмитеCommand+N. В окошке введите урл.
Плеер немного потупит, и появится видео:

Что радует:
- нет рекламы и трекинга;
- нет тормозных скриптов;
- нет оверлеев, по клику на которые улетаешь невесть куда;
- нет комментариев, рекомендуемых видосов и прочего.
Такой просмотр анонимный: он не осядет в истории, не будет преследовать годами на главной. Если видео длинное, плеер можно запаузить и свернуть как обычное окно. Не будет лишней вкладке в Хроме.
Работает перемотка стрелочками, при этом вы сами настраиваете, на сколько секунд. Аналогично с ускорением видео: в выпадающем меню Playback открывается бегунок.

С качеством видео все сложно. Его можно менять, но настройка спрятана так глубоко, что дойдет только сильнейший. Сначал
VLC→Preferences→Input / Codecs, кнопкаShow All.
Затем прокрутить до Preferred video resolution. По умолчанию там Best available, что слишком жирно. 1080 или 720 хватит за глаза.

Автоматизация
Чтобы быстро открыть видос, напишем функцию на bash. Добавьте в ваш
~./bashrcили~./zshrcследующее:function play(){ /Applications/VLC.app/Contents/MacOS/VLC -v $1 & }Амперсанд на конце запустит процесс в фоне, чтобы можно было закрыть терминал, не прибив плеер. Теперь достаточно вызвать в консоли
play https://www.youtube.com/watch?v=88UDgKLL7bE— и появится плеер с видосом:

Минус — VLC не сохраняет прогресс просмотра. На длинных видосах, которые смотришь урывками по нескольку дней, можно случайно потерять прогресс.
Схема не работает с плейлистами: при попытке его открыть запускается только первый видос. Однако VLC поддерживает свои плейлисты. С его точки зрения ютубное видео — один из элементов плейлиста. Откройте по очереди несколько видосов и сохраните в файл m3u. Получается локальный плейлист, не привязанный к учетке гугла. Положите его в Дропбокс или где вы храните файлы.
Можно вести несколько плейлистов: избранное, посмотреть позже, музыка и так далее.
В итоге получается полностью анонимный просмотр Ютуба, без рекламы и с поддержкой плейлистов. Пока что я тестирую такой подход, и в целом ощущения приятные — как будто глоток свежего воздуха. Конечно, ощущения другие: здесь программа реагирует медленнее, а здесь быстрее. Неизвестно, к чему приду, но попробовать стоит.
Если вы знаете аналоги, расскажите в комментах.