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

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

Наглядный пример, почему важны хорошие генераторы случайных чисел и QA

Неплохой разбор вскрывшейся недавно уязвимости биткоин-кошелька Coldcard. Вкратце: из-за кривой сборки (в этой статье чуть подробнее расписано) вместо нормального генератора случайных чисел с физическим источником энтропии использовался программный, с гораздо меньшей энтропией. Как следствие, стало легко подобрать приватный ключ. В итоге украдено более 1500 BTC ($100 млн.+) с 7300+ адресов.

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

Время рефакторить

Мне всегда нравилось рефакторить — медленный дофамин, быстрая обратная связь, чувство достижения, автономность, можно разгрузиться от более вдумчивой работы и т.д. Однако обычно более-менее крупный рефакторинг занимает приличное время.

Сейчас, как мне кажется, сложились обстоятельства, благоприятствующие большим рефакторингам. Обычно рефакторинг довольно однообразный и рутинный в плане действий и редко влечет за собой подводные камни. Это хороший кандидат для одноразового скрипта, но если раньше такое было писать нецелесообразно (ну разве что состряпать что-то на коленке а-ля регулярку в IDE), то сейчас нейронка выплюнет его за пару секунд, и можно быстро проитерироваться. Кроме того, нейронки позволяют попробовать несколько вариантов (даже если это сотни измененных файлов) и выбрать подходящий. Как и раньше, уверенности добавят компилятор, статические проверки и тесты (и если их нет, то стоит позаботиться сначала о них). Вдобавок, все можно сделать автономно, пока ждешь код-ревью других своих PR в переполненной очереди.

Сам недавно сделал несколько рефакторингов: миграция с одной библиотеки на другу, аннотации публичного API, разбиение по модулям, удаление мертвого кода и т.п.

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

Граф цитирований

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

Даже были мысли самостоятельно что-то напрограммировать для решения проблемы, но сначала руки не доходили, а потом уже и задача для меня актуальность потеряла. При этом у проблемы есть масса “оттягчающих” факторов:

  1. Для статей нет единой базы.
  2. Нет единого ID — самое близкое — DOI, но он присвоен не всем статьям, две разные работы могут иметь один DOI (например, доклады в сборнике докладов с конференции), одна (фактически) работа может иметь разные DOI (доклад/статья/препринт).
  3. Нет машиночитаемого формата — даже нет единого стандарта по оформлению списка источников (и нюансы могут зависеть от журнала). В BibTex базах (которых тоже несколько) никакой нормализацией вообще не пахнет.

Случайно наткнулся на сервис ConnectedPapers, который вроде как позволяет строить взвешенный граф цитирования и как-то внятно работать с данными, но даже этот инструмент имеет проблемы: граф не ориентированный, да и есть сомнения, что решена проблема с несколькими базами цитирований. Чуть позже нашел еще LitMaps, но там функциональность очень куцая. Печально, что при одинаковом вводе даже список связанных статей отличается — например, в ConnectedPapers нет моей же статьи 2014 года, а в LitMap — моей статьи 2018 года (точнее она как бы есть, но ее надо специально искать). В общем, какой-то прогресс как будто есть, но до хорошего решения еще неблизко…

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

Приложения по умолчанию на маке

На маке меня всегда бесило, когда скачиваешь какой-нибудь текстовый файл (.log, .md или .sh), мак предлагает открыть его через xcode. Я бы с удовольствием снес бы его вообще, если бы от него половина пакетов из brew не зависела. Как я не пытался выбрать приложение по умолчанию, в следующий раз — снова здорово, xcode.

В итоге мне помогла установка duti:

brew install duti

duti -s com.apple.TextEdit .md all

osascript -e 'id of app "TextEdit"' # чтобы получить id приложения
СсылкаКомментировать

Масштабное разгребание тикетов

Похвастаюсь немного: в корпоративном блоге вышла статья, где описывается мои достижения в плане взятия бэклога и входящих тикетов под контроль.

Когда я только пришел в компанию и мне показали процесс управления бэклогом, моя первая реакция была “Bitch, you live like this?”. Появилась работенка, которая хорошо скрещивает сразу несколько моих привычных активностей:

  • разгребание и причесывание большого бэклога — в каждой компании такое делал, вот только масштаб тут был не ~500 тикетов, а несколько тысяч, да еще и все публично.
  • налаживание процессов — “обожаю” зрелость процессов на уровне “ну как-нибудь образуется” и “да, посмотрю как будет время”.
  • “доделывание” — 20% усилий на 80% результата были уже потрачены, я добавил сверху еще 80.
  • автоматизация всякой дичи — тут были вертолеты от GitHub и его API, штук пять багов им отправил, а местами настолько все плохо, что приходится парсить HTML :/
  • документирование — процессы, принципы, инструкции и т.п.

И это все было побочной активностью, и по большей части было сделано руками, без ИИ. Только в конце, когда разгребал stale тикеты, навайбкодил, прости господи, скилл для поиска дупликатов и воспроизведения багов. Честно говоря, совсем не ожидал хороших результатов от такого, но с учетом того, что решение все равно принимали люди, а результат нейронки был просто вспомогательной информацией, получилось нормально: больше 500 тикетов через него прошло, процент ошибок не очень высокий.

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

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

Написание кода и не было узким местом

Уже в каждом утюге обсудили эту тему, но пусть и у меня будет, чтобы можно было ссылаться.

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

Пришел ИИ, и все стало как в анекдоте (“печатаю 1000 знаков в минуту, правда, такая ерунда получается…”). Начались (продолжились) разговоры, что разработчики не нужны. Проблема в том, что большая часть разработки — это определение требований, выработка понимания предметной области, формализация модели, согласование видения, определение способа решения и т.п., думание мозгами и взаимодействие с коллегами. Написание кода помогает исследовать, но вторично, да и занимает малую часть времени разработчика. А если в компании еще невнятные цели или мутные процессы, то вопросы скорости разработки вообще не очень релевантны. Про согласования с другими командами вообще молчу.

Ок, даже если у вас все хорошо с постановкой задач и прекрасные процессы, то с ускорением кодинга вы просто перенесли нагрузку из одного места в другое, а именно на QA и код-ревью и/или на продактов/аналитиков. И если вы оптимизируете не самое узкое место, то вместо более быстрой системы получаете более сломанную.

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

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

Уважаем собеседника

При рабочем общении важно уважать время собеседника, но, увы, не все умеют это делать. Проявляется это по-разному, но из простых и при этом распространенных проблем можно было выделить привет без контекста. Коллег можно было направить на путь истинный ссылкой на NoHello.

Сейчас, когда стало очень легко делегировать мышление, часто встречается ситуация, когда кто-то тупо постит вывод нейронки без какой-то обработки. Что весьма грубо: скопипастить сообщение в/из чат-бота кто угодно может, и лишняя прослойка тут ни к чему. Если нечего толкового сказать — лучше промолчать. Чтобы с этим бороться, можно в качестве ссылки указывать no slop grenade или stop sloppypasta. Но если это не очень работает, а коллектив толерантен к токсичности, можно ввести в оборот и более агрессивные методы.

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

Роутинг на фронте

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

Тупейшее решение — просто ссылаться на нужный путь строкой, но это очень хрупко и при любом изменении путей есть шанс, что что-то поломается. В идеале нужно, чтобы была проверка на уровне компиляции, что все ссылки рабочие. Можно обмазаться проверками при сборке, но это так себе вариант.

Окей, может тогда сделаем модуль или файлик под пути с константами и все будут зависеть от него? Это получается почти God-object, со всеми вытекающими. При этом тяжело следить, как модули связаны между собой. И может остаться путь, на который уже никто не ссылается. Есть еще вариации вроде генерации общего файла (например, из путей в модулях) или роутинг на основе расположения исходников (например, “/user/$id” лежит в папке “/user”), но проблемы там похожие. Можно поиграться с динамической регистрацией путей, но это уже рантайм.

Ладно, можно сделать объявление путей локальным для модуля, и сделать по модулю чисто с путями. Т.е. для users будет routes-users с белым списком путей, которые торчат наружу. В этом подходе плохо, что число модулей удваивается.

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

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