Минутка просвещения

Читать в телеге. Когда-то там были посты не только от меня.

HEAD

У меня случайно был включен Caps Lock, и вместо head s<Tab>omefile я напечатал HEAD S<Tab>omeOtherFile. ВНЕЗАПНО, HEAD это валидная команда, так же как и GET и POST — это утилита lwp-request, которая, по сути, аналог curl, причем еще написанный на перле! Судя по всему, это стандартный пакет Debian.

СсылкаКомментировать

Вычисление двоичного логарифма

Найти ответ на вопрос, как в стандартной библиотеке реализовано вычисление логарифма, оказалось сложнее, чем можно подумать. Во-первых, алгоритмов вычисления довольно много: от наивной итерации по Тейлору до хитрых методов с таблицами. Во-вторых, реализация будет отличаться в зависимости от архитектуры процессора, наличия векторизации (SIMD, SVE и прочие страшные аббревиатуры) и от авторов библиотеки (GNU, musl, UCRT и т.п.).

Если смотреть на среднебольничную реализацию, то это будут математические преобразования по сужению области определения, набор предвычисленных таблиц и вычисление 5-7 членов ряда Тейлора. Некоторые процессоры имеют встроенную команду fyl2x для x * log2(y), и она даже используется, правда она может выполнятся довольно медленно: на некоторых старых процессорах — больше 1000 тактов, а в среднем за 50-100 тактов.

При этом двоичный логарифм довольно особенный. Если работать с числами с плавающей точкой и нам не очень важна дробная часть, то можно просто взять показатель двоичной степени при помощи frexpf. А если работаем с целыми числами, то достаточно знать позицию первой единицы слева или количество нулей слева — для этого у некоторых процессора есть команды bsr и/или clz соответственно, а в GCC — встроенная функция __builtin_clz.

СсылкаКомментировать

Будущее эффектов

Интересная статья про будущее работы с эффектами в Scala. Это своего рода продолжение обсуждения про добавление suspend-функций и про новые подходы к обработке ошибок.

Один из главных выводов статьи: асинхронные функции — это решение проблемы, однако у сообщества нет четкого и однозначного понимания, в чем эта проблема состоит (без внятного ТЗ результат ХЗ).

В статье затронуты такие проблемы как много способов сделать одно и то же в Scala, несовершенство двухцветной реализации корутин в Kotlin и трактовку RPC как локальных функций. Открыт вопрос, надо ли делать решение только под JVM или под все платформы, и должно ли решение быть на уровне языка или библиотек.

Для постановки проблемы нужно понять:

  1. Должны ли эффекты фигурировать в сигнатуре метода? Почти все в сообществе склоняются к “да”.
  2. Должна ли эта информация распространятся на вызывающие методы вплоть до точки входа? А вот тут мнения разделяются.
  3. Что вообще надо отслеживать? Это занятно пересекается с п.1 Нужно ли учитывать асинхронность вычислений? А с учетом Loom? Любой ввод-вывод? Ошибки?

Обсуждение все еще в процессе. А еще Одерски запустил исследовательскую программу Caprese для поиска способов отслеживать эффекты, так что может что-то новое оттуда родится.

СсылкаКомментировать

Рефлексия и продуктивность

Интересное исследование от GitHub про то, что нужно разработчикам, чтобы быть продуктивными и чувствовать, что день был прожит не зря. Много довольно очевидного, но тут хотя бы есть какие-никакие экспериментальные данные. Из довольно капитанских выводов:

  1. Состояние потока это важно, должно быть выделенное время для сосредоточенной работы
  2. Больше двух встреч в день — это рак, 1 встреча — норм.
  3. Даже оформление пулл-реквеста — это выход из потока.
  4. Больше времени в состоянии потока — больше достижений и меньше стресса.

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

Когда я впервые столкнулся с agile, я писал себе коротенько, что делал за день, чтобы потом на стендапе не надо было вспоминать. Но вскоре я, к сожалению, в этом разочаровался: увы, большинству людей абсолютно насрать, че ты там делал, проквакал че-то нормальное и пофиг. До agile я записывал только свои достижения. Вот это полезно, и я продолжаю везде это делать. На Performance Review ты молодец-огурец, кучу всего достиг и ничего не забыл. Да и в резюме есть что записать.

СсылкаКомментировать

"Понятность" java

Очень часто чуть ли не единственным техническим аргументом в пользу использования java, а не какого-нибудь высокоуровневного языка, слышу что-то вроде “ой, ну вот с этим синтаксическим сахаром ничего не понятно, вот на java все просто и логично, там легко читать и все понятно”.

Вот отличный видео ответ этим “простакам”: да, там “паззлеры”, но не какие-то хитровычурные, а вполне себе обычный код, который может попасться при работе с коллекциями.

СсылкаКомментировать

Ноутбук как монитор

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

Для создания виртуального экрана есть даже специальные HDMI-затычки и масса программных вариантов. Из них я попробовал 2:

  1. DeskPad — ноль настроек, запустил и готово. Но экран только один.
  2. BetterDisplat — настроек до фига. Но при запуске какого-то черта меняет настройки основного экрана. И хотя тут можно добавить больше одного виртуального экрана, я не разобрался, как сделать так, чтобы они не были зеркалом друг друга.

Шарил экраны с помощью Deskreen. Что тут сказать… вроде работает, но мыльно и тормознуто: лаг довольно заметен. Что интересно, я пробовал еще подключать iPad как третий монитор, и там лаг меньше. Еще совсем не помогало, что у личного ноута 16:10, iPad 4:3, а у мака вообще 1800x1169 — этот зоопарк либо обрезался, либо растягивался (возможно это можно настроить нормально, но из коробки работало так себе).

Столкнулся с проблемой, что окно не может быть на нескольких экранах одновременно, но оказалось, что это решается настройками мака. Кроме этого, было два случая, когда “все сломалось”:

  1. Когда в настройках мака сделал виртуальный экран основным, то маковский экран “завис”, а ноутный просто отвалился. Хорошо, что на iPad был запущен терминал, через который я прибил виртуальные экраны.
  2. Когда открыл окно на полный экран, мак сходит с ума и на своем экране показывает черноту, а на остальных получается либо статическая картинка, либо артефакты.

Паравозик между разными экранами я в итоге запустил (но понадобилось запускать два разных приложения для виртуального экрана, чтобы не было зеркала).

В общем, great idea, does not work.

СсылкаКомментировать

awk

Недавно понадобилось сделать простую операцию над текстовым файлом: посчитать минимальную/максимальную длину строки. Звучит элементарно, ща быстренько состряпаем что-нибудь из cat + wc + sort… Только надо подобрать правильную комбинацию параметров и xargs вставить. С наскока, разумеется, не получилось. На питоне ради этого писать лениво, и в итоге на StackOverflow было найдено решение с awk:

awk '{print length}' input.txt | sort -rn | head

На чистом awk минимум будет выглядеть так (решение предложено ChatGPT):

awk 'NR == 1 || length < min { min = length } END { print min }' input.txt

Еще проще будет посчитать среднюю длину строки:

awk '{total += length} END {print total/NR}' input.txt 

Раньше я обычно игнорировал решения на awk, потому что они были не очень понятны в отличие от различных комбинаций grep, sed, cut, wc, sort и прочих: они достаточно простые, и “делают одну вещь хорошо”. А если что-то серьезное возникало — то писал что-то на питоне.

Но после описанного случая решил немного почитать про awk и, оказывается, он из коробки поддерживает построчную обработку (питонячий бойлерплейт), разбивку на поля (cut) и регулярки (grep/sed). Достигается это за счет довольно интересной концепции: каждая строка проверяется по паттерну(ам) — условию/регулярке, и если она соответствует, то выполняется действие в фигурных скобках. В общем, планирую попробовать.

Хотя можно не париться и просто ChatGPT попросить скрипт написать.

СсылкаКомментировать

Сколько мониторов нужно для счастья

За время своей работы встречал разнообразные мнения по данному вопросу:

  1. Нужно 4 монитора! На одном реверсить, на другом даташит открыт, на третьем среда разработки, на четвертом разводка платы… Больше мониторов богу мониторов!
  2. Два монитора норм, на одном кодишь, на другом открыт тикет/чат/порнуха/унылый созвон. Или запускаешь созвон на одном экране, а другой шаришь.
  3. Нужен только один монитор (но большой), потому что если много мониторов — теряешь фокус на одной задаче.

Когда-то мне казалось, что надо 3 монитора, но сейчас я склоняюсь к умеренному варианту №2, причем это экран ноута + монитор. На одном большом экране даже со всякими приемами разделения окон может быть не очень удобно переключаться между контекстами (а на маке разделение экрана само по себе конченое). А двух экранов достаточно, чтобы выполнять переключение поворотом головы.

Вообще, переключение контекста — довольно дорогая операция. И если их нужно одновременно больше двух, то, возможно, вы что-то делаете не так? Может надо сделать какую-то предварительную обработку “вспомогательных” контекстов, чтобы они работали как один?

А что говорит по этому поводу наука? Нашел мета-исследование на тему (по DOI можно найти на сцихабе полный текст). Если смотреть на опросы пользователей, то там все понятно: минимум 17”, большинству подавай два монитора. Однако кто говорил, что ему надо четыре, не использовал их по полной. Если смотреть на более объективные измерения, то в одном исследовании измеренная продуктивность выше с двумя мониторами, чем с одним, но при этом третий монитор существенно на нее не влияет. В другом исследований не обнаружили разницу между одним и двумя мониторами 17” или 22” (зависит от задачи, в общем). При этом есть умеренные свидетельства уменьшения числа кликов/переключений окон при увеличении размера и количества мониторов.

СсылкаКомментировать

Работа с файловой системой

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

Правильно реализовать работу с символическими ссылками — довольно нетривиальная задача. Хорошую презентацию по этому поводу можно посмотреть тут. Если вкратце, то ссылки могут меняться между системными вызовами, что открывает массу возможностей для повышения привилегий из-за того, что их проверка и действие над ссылкой происходит неатомарно. Даже в системных вызовах Linux не смогли поправить это с первого и даже со второго раза.

А еще символические ссылки ломают иерархию (и связанные с ней проверки) — например, путь с .. уже нельзя нормализовать без запроса к файловой системе. А еще ссылка может ссылаться на другую ссылку, и эти случаи в два раза веселее обрабатывать.

В добавок к этому, я недавно нашел интересное поведение в java. Если создать папку, содержащую юникодные символы, то ее имя по-разному будет нормализовано в зависимости от того, был ли использован метод Files.createDirectory или File.mkdir. Это приводит к тому, что оригинальный путь не совпадает с “реальным” путем к файлу, который только что был создан по этому пути:

package test;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
import java.util.function.Function;


public class App {

    @FunctionalInterface
    public interface Action {
        void apply(Path path) throws IOException;
    }

    public static void main(String[] args) throws IOException {
        check("createDirectory", Files::createDirectory);
        check("mkdir", x -> x.toFile().mkdir());
    }

    private static void check(String hint, Action createDir) throws IOException {
        String name = "teŝt files";
        Path root = Path.of(name).toAbsolutePath();
        Path file = root.resolve("file1");

        Files.deleteIfExists(file);
        Files.deleteIfExists(root);
        createDir.apply(root);
        Files.createFile(file);

        Path alternative = file.toRealPath();

        System.out.printf("%s - Equals: %s, isSameFile: %s\n", hint, file.equals(alternative), Files.isSameFile(file, alternative));
    }
}

Вывод:

createDirectory - Equals: true, isSameFile: true
mkdir - Equals: false, isSameFile: true
СсылкаКомментировать

Запись команд терминала

Чтобы записать демонстрацию какой-нибудь последовательности команд, можно воспользоваться Asciinema. Работает примерно так:

Можно конвертировать результат в гифку или использовать js-проигрыватель.

На удивление, эта штука без проблем сработала, когда я ее запустил внутри самой себя. В целом прикольно, но мне текстовый формат нравится больше — оттуда, как минимум, проще копировать. Еще один минус — вся тупка при записи записывается, т.е. нет нормализации: задержки и ошибки при печати команд тоже сохраняются. С другой стороны, за счет этого запись более “живая”.

СсылкаКомментировать