-
Разрешения
В мобильных операционках мне нравится далеко не все. Но есть одна вещь, которую я горячо поддерживаю, и которая перешла в десктопы — это система разрешений. Например, доступ к камере, микрофону, контактам, календарю. Все это дает контроль за программами, которые лезут, куда не просят.
Может быть, не все помнят ранний Андроид, а я помню. В версиях до какой-то там у Андроида не было разрешений по требованию. Это значит, ты ставишь какой-нибудь Фонарик Про, а он говорит: нужен доступ к фоткам, контактам, акселерометру и еще десяти пунктам. А если не согласен, иди лесом. У Эпла разрешения были по запросу с возможностью позже отозвать их. Модель Гугла была ужасна, ее обузили так сильно, что пришлось сделать как у Эпла.
Так вот, возвращаясь к десктопу. Хотя в нем есть система разрешений, ее возможностей не хватает. Например, я бы хотел регулировать, какой программе можно в интернет, а какой нет. Чтобы снять в настройках чекбокс у программы — и все, шабаш. Не увидишь модалки, что вышло обновление. Не появится прогресс-бар с загрузкой. Не будет сбора метрик и кликов. Сейчас, чтобы победить эту хрень, приходится возиться фаерволом.
Вряд ли такое произойдет, но помечтать не вредно.
-
Last in Clojure
Chat GPT: No, the
last
function is not particularly expensive for vectors in Clojure. It runs in O(1) time because vectors in Clojure support efficient access to their last element.Meanwhile, Clojure:
-
Подробней о last
Поскольку в заметке про last отметились только профильные специалисты (в Телеграме), считаю, нужна его подробная версия. Я и сам понимаю, что для таких огрызков служит Твиттер, но чего нет — того нет.
Итак, дело вот в чем. Коллега спрашивает у Chat GPT, насколько дорого получить последний элемент вектора функцией last в Кложе. На это чат говорит — все тип-топ, у вектора доступ к последнему элементу работает за O(1).
Все бы ничего, но в ответе напутаны правда и ложь, и в целом он не верный. Чтобы в этом убедиться, откроем исходный код функции last:
(dеf ^{:doc "Return the last item in coll, in linear time"} last (fn ^:static last [s] (if (next s) (recur (next s)) (first s))))
Полагаю, даже человек, едва знакомый с Лиспом, увидит паттерн. Функция принимает коллекцию, и если в ней больше одного элемента (есть хвост), то она вызывает себя с хвостом. Когда длина хвоста равна одному, возвращается этот элемент.
В коде нет проверок на тип коллекции, например, отдельно для вектора или списка. Все очень просто и линейно.
Наконец, докстринг функции как бы говорит нам: вернуть последний элемент коллекции за линейное время. Линейное, Карл, то есть такое, что растет с числом элементов, то есть O(N).
Поэтому буквальный ответ на вопрос таков: нет, функция last вернет последний элемент вектора за O(N) шагов. Что не подходит для больших векторов.
Спрашивается, откуда у чата уверенность в правоте? Дело в том, что вектор действительно хранит ссылку на последний элемент. Для доступа к нему служит функция с забавным названием peek (заглянуть). Она работает только для вектора и для всего остального кинет ошибку.
Можно предъявить Ричу Хикки: надо было сделать интерфейс
Lastable
с методомgetLast
. Обычные коллекции бегут с головы, а вектор берет с конца. Все это упаковано вlast
, который переключает на нужную логику. Все довольны и смеются. Но имеем то, что имеем, тем более что я согласен с текущим положением дел. Из всех коллекций только вектор может вернуть последний элемент. Остальным коллекциям это не положено по идеологическим причинам.Скорее всего, чат прочитал вопросы на StackOverflow и слепил некую компиляцию. Вроде бы да, но вроде бы нет. В этом и состоит вред: чат выдает что-то, очень похожее на истину. Выглядит настолько правдоподобно, что принимаешь за чистую монету. Но если проверить, то окажется, что не в карты, а в нарды, и не корову, а машину, и не выиграл, и проиграл.
Поэтому я не пользуюсь чатом и аналогами, я в них даже не зарегистрирован. И вам советую прибегать к ним реже.
-
Deed: a fast encoding and decoding library for Clojure
Table of Content
- About
- Motivation
- Installation & Requirements
- Quick Demo
- API
- GZipped Streams
- Appending to a File
- Handle Unsupported Types
- Supported Types
- Extending Custom Types
- Handling Defrecords
- Contrib
- Binary Format
- Benchmarks
About
Deed is a library to dump any value into a byte array and read it back. It supports plenty of types out from the box: Java primitives, most of the Clojure types, Java collections, date and time, and so on. It supports even such tricky types as atoms, refs, and input streams. The full list of supported types is shown in the “Supported Types” section below.
Deed can be extended with custom types with ease. There is a contrib package that extends encoding and decoding logic for vectors from the the well-known mikera/vectorz library.
Deed is written in pure Java and thus is pretty fast (see the “Benchmarks” section). It’s about 30-50% faster than Nippy.
It doesn’t rely on the built-in Java
Serializable
interface for security reasons. Every type is processed manually.Deep provides convenient API for reading the frozen data lazily one by one.
Motivation
Obviously you would ask why doing this if we already have Nippy? This is what I had in mind while working on Deed:
-
The library must be absolutely free from dependencies. This is true for the
deed-core
package: it’s written in pure Java with no dependencies at all. By adding it into a project, you won’t blow up you uberjar, nor you will have troubles with building a native image with GraalVM. -
Any part of Deed that requires 3rd-party stuff must be a sub-library. So you have precise control of what you use and what you don’t
-
Unlike Nippy, Deed never falls back to native Java serialization. There is no such an option. Thus, your application cannot be attacked by someone how has forged a binary dump.
-
Deed is simple: it blindly works with input- and output byte streams having no idea what’s behind them. It doesn’t take compression nor encryption into account – yet there are utilities for streams.
-
The library provides API which personally I consider more convenient than Nippi’s. Namely, Deed can lazily iterate on a series of encoded data instead of reading the whole dump at once.
-
Finally, why not using popular and cross-platform formats like JSON, Message Pack, or YAML? Well, because of poor types support. JSON has only primitive types and collections, and nothing else. Extending it with custom types is always a pain. At the same time, I want my decoded data be as close to the origin data as possible, say,
LocalDateTime
be an instance ofLocalDateTime
but not a string orjava.util.Date
. Sometimes, preserving metadata is crucial. To haldle all of these cases, there now a way other than making your own library.
-
World of Goo 2
Вышла вторая часть World of Goo. Я долго не знал об этом, потому что повестка забита другим, да и на работе зашиваюсь. Однако это самая приятная новость за последние полгода или около.
Изюминка в том, что с момента первой части прошло шестнадцать лет. И дело не в том, какая графика или саундтрек в новой части. Просто испытываешь радость за тех двух парней, которые выкатили продолжение. Такое же чувство испытываешь, когда любимая группа записала альбом после долгих лет турне.
Шестнадцать лет исполнилось моему старшему ребенку. Помню, как начал играть в Гушек, когда ему было пять месяцев. Гушек прошли вдоль и поперек двое моих детей, третьей еще предстоит.
Если вы не играли в первую часть, горячо советую это сделать. Игра — не просто залипательная казуалка. В ней много попыток что-то донести между строк. Почти каждый уровень — это метафора на что-то из жизни. Попадаются намеки на отношения, красоту и любовь. Есть серия уровней в компьютере, где моделируется перехват трафика, балансировка нагрузки и другие айтишные штучки. Есть длинный диалог на тему браузерных кук. Ближе к концу — эпичный поворот с удаленными электронными письмами.
Приятно не только расставлять шарики, но и ловить подсказки, намеки, искать отсылки. Гушки — настоящее произведение искусства. Спасибо двум парням, которые заставили часами залипать в этот мир. Прошло шестнадцать лет — и я снова загляну туда, пусть ненадолго, но с тем же интересом.
-
UI и пустота
Понимаю, что многие не любят подобный контент, но все-таки. На ужасные вещи нужно обращать внимание, что случайно не сделать так же.
Мне интересно, почему веб превращается в пустыню? На страницах чудовищно много пустоты. Кругом жирные отступы, блоки помещаются в прямоугольники с обводкой, те – в другие прямоугольники и так далее рекурсивно. И всюду отступы, отступы, отступы. Стало нормой, что на первом экране ничего не вмещается – только слои всяких виджетов и жирная блямба посередине. Нужно проматывать ради одной строки.
Фронтендеры, что же с вами случилось?
-
Мышление лямбдами
В проекте, который плотно сидит на Амазоне, я познакомился с новой для себя вещью: мышлению лямбдами. Это когда на каждый чих создается лямбда, и кто-то ее вызывает: бекенд, фронтенд, очередь или хук, повешенный на бакет.
Раньше я об этом не думал, но оказалось, что лямбда — самый сложный продукт Амазона. В экосистеме AWS лямбды повсюду. Их можно приделать к любому сервису. Загрузил файл в S3 — дернулась лямбда. Поднялся инстанс EC2 — дернулась лямбда. Лямбда может быть обработчиком очередей SNS и SQS. Это универсальный клей, которым можно соединить что угодно.
Лямбда может создана на любой технологии: на Джаве, на Го, на баше. Она может быть голым бинарником или скриптом на Питоне или Ноде. В последних случаях ее код можно поместить прямо в yaml-конфиг Cloud Formation.
Ситуация, когда лямбда вызывает лямбду, та вызывает лямбду, та вызывает лямбду, которая пишет файл в S3, и на это событие вызывается лямбда, уже не кажется абсурдом. Поначалу шокирует, но привыкаешь.
Другой случай: как поднять инстанс EC2 на заданное количество времени? А вот как: дернуть лямбду и передать ей число секунд, скажем, 7200 (два часа). Лямбда запустит инстанс из образа, после чего запишет в S3 файл с числом оставшихся секунд. В облаке работает шедулер, который каждые 5 минут запускает другую лямбду. Эта лямбда читает число секунд из бакета, вычитает из него 300 секунд и записывает обратно. Если время истекло, она дергает третью лямбду, которая убивает инстанс. Вот такие многоходовочки.
Сперва у меня было чувство, словно я рассматриваю картины Сальвадора Дали. Первая реакция — что, так можно было? Оказалось да, можно. С этим живут, это поддерживают, на этом зарабатывают деньги. Такие схемы даже работают. Тех, кто их проектирует, называют AWS-архитекторами.
Все это я понимаю и принимаю. И все же малодушно хочу, чтобы такого было меньше.
-
Баки
Со словом “баксы” (доллары) интересная ситуация. Bucks — это уже множественная форма слова buck. Один доллар — один бак. Получается, что два доллара — это два бака. Поэтому вместо “ы” на конце нужно склонять по правилам русского языка.
То же самое со словом “чиксы”. Дословно chiks означает “цыплята”, и это уже множественная форма. В переносном смысле оно означает девушек, ищущих мужского внимания. По аналогии, если “чикс” — множественная форма, то единственная будет “чик” или “чика”.
Потренируемся: Алексей показал бумажник, полный баков. За ним увязались модные чики. Все чики любят наличные баки. В Пятерочке сказали, что не принимают баки, только рубли. Чики ушли от Алексея к Михаилу. У него нет баков, зато полно рублей.
Хм, как-то непривычно.
Из комментариев в Телеграме: рельсы (рели), чипсы (чипы), джинсы (джины), комиксы (комики).
-
AirDrop
В интересном мире мы живем. Казалось бы, функция AirDrop не требует интернета, работает автономно за счет локального файфая и блютуза. И все равно — кинуть файл с ноута на мобилу проще через Телеграм. А это, на минуточку, отправка файла бог весть куда, его обработка на сервере, скан на вирусы, индексация меты и загрузка обратно. Приличный такой раунд-трип.
И все равно это быстрее, чем радиосвязь между двумя устройствами, расстояние между которыми полметра.
Был же комикс xkcd, где чел говорит: пока ты будешь регистрироваться в Dropbox, я уже с флешкой приеду. С AirDrop что-то из этой оперы: пока он сканит девайсы, Телеграм уже давно прожевал файл.
-
Подорожание Яндекса
Как вы знаете, Яндекс поднял цену на подписку «Плюс». Это событие обсуждалось на всех площадках. Теперь когда интернет отпустило, выскажусь и я.
Дело вот в чем: людей взбесил не факт подорожания, а лицемерное письмо, которое разослал Яндекс. Оно и стриггерило пользователей.
Письмо написано в таком ключе: ребята, мы тут думали-думали, как бы сделать вам хорошо, всю голову сломали. И решили добавить в подписку никому не нужный сервис А и никому не нужный сервис Б.
И это не все! В сервисе В появилась такая-то фигня, в сервисе Г – такая-то.
И лишь в третьем абзаце упоминается пустяковая деталь: подписка повышается в два раза, следующее списание тогда-то.
Читаешь и чувствуешь испанский стыд. Копирайтеры Яндекса действительно считают, что если новость о повышении задвинуть в третий абзац, то ее не заметят. Что клиент Яндекса – однозадачный человек, который держит в голове одну мысль. Если закинуть ему новость про сервисы, то подорожание он проигнорирует.
Это так глупо и дешево! Словно вернулись на десять лет в прошлое, когда копирайтеры верили в разные техники и манипуляции, чтобы управлять читателем.
Клиент Яндекса – это городской образованный человек среднего возраста. Ежедневно он читает много сообщений и прекрасно знает эти фокусы. Даже если он не может обозначить их явно, в письме чувствуется фальшь: главное задвинули в конец, а незначительное стоит впереди, чтобы запорошить глаза.
Каждому, кто прочел это письмо, ясно, что повышение цен и было главной новостью. Ведь так? Кого обманывает Яндекс? Главное должно быть вначале.
О повышении цен нужно писать явно. Сервисы регулярно поднимают цены, например, тот же Гугл. При этом он не пишет лицемерных писем, не пытается прикрыться новыми сервисами. Все просто: чуваки, через три месяца подписка станет семь долларов вместо пяти. Клиенты такие: ну ок.
Вот как можно было написать:
Дорогой Иван, мы повышаем цену на подписку Плюс. Было столько-то, через три месяца станет столько-то. Это необходимо, чтобы поддерживать и развивать продукты Яндекса.
Чтобы вы не расстраивались, мы добавили никому не нужные сервисы А и Б, а также фичи В и Г в таких-то сервисах. Ссылки на биллинг и прочая информация.
Словом, Яндекс эпично провалился с этим письмом. Еще не научились копирайтеры Яндекса общаться с аудиторией.