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

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

Впечатления от GitHub Copilot

На всякий случай: пробовал не последний Copilot X, а обычную версию.

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

Довольно часто предлагает вообще невалидный код — например, с несуществующим методом. Нет, я бы конечно сам попробовал так написать, но хоть какую-то валидацию хотелось бы иметь, благо можно спросить IntelliJ, в которой все это запущено. Но иногда Copilot предлагает откровенную дичь — например, предлагает паттерн-матчинг для Option для метода, который обычный String возвращает.

В некоторых простых случаях предлагает прямо то, что надо. Однако это обычно бойлерплейт. Да, для него он весьма хорош, но казалось бы, если надо писать бойлерплейт, то стоит что-то поменять в архитектуре или сменить язык? Хотя даже с ним Copilot может налажать — например, он передал не все аргументы в функцию с аргументами по умолчанию. Да и типовые задачи а-ля получить Stream из Iterator (что в java делается миллионом способов) иногда не может решить, на StackOverflow все еще надо было ходить.

В общем, вау-эффекта не произвело, но и отключать его пока не стал. Если пишете на чем-то унылом типа Java или Go, то иногда может помочь. Если на чем-то помощнее, то чаще будут подсказки не в тему, которые будут отвлекать.

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

Автоматический поиск индексов для базы

Я сталкивался со следующими подходами по добавлению индексов:

  1. Что-то стало тормозить — добавляем индекс “на глаз”. По умолчанию добавляем на что-то очевидное.
  2. Мониторим slow query, анализируем запросы, добавляем индекс по анализу статистики (это обычно выделенные DBA).
  3. Добавляем индексы на все поля по умолчанию, а там авось что пригодится.

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

На прошлой работе написал велосипед, который извлекал все SQL-запросы из юнит-тестов и прогонял их через EXPLAIN ANALYZE на копии продовой базы. Это работало весьма неплохо, но доавтоматизировать это до CI-стадии я так и не успел.

Что-то похоже есть и в опенсорсе — эта утилита делает примерно то же самое, только еще и сама создает “гипотетические” индексы и проверяет, что они дадут ускорение запросов. Использовать ее на проекте не смог, т.к. расширение для этих гипотетических индексов нельзя поставить на AWS-овский Postgres :/

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

GraalVM

Наконец-то дошли руки попробовать компиляцию в нативный код (aka AOT compilation) от GraalVM.

Написал Hello World на java, выбрал GraalVM в качестве JVM, подключил официальный плагин Gradle, запустил nativeCompile и… все, оно скомплировалось и работает. Без ошибок, без разбора какой-то дичи, просто заработало сразу и все. Минут 15 на все про все ушло.

Ладно, попробуем что-нибудь поинтереснее — схавает ли GraalVM Spring с его рефлексией и прокси-классами в рантайме? Создаем простенький контроллер, теперь уже на Kotlin, который выплевывает JSON. Компилируем и… оно тоже работает! о_О

Я просто в шоке, до чего дошел прогресс. Ожидал веселых или не очень потрахушек примерно как с Kotlin native или с KotlinJS, но испытал преимущественно позитивные эмоции. Справедливости ради, на большом проекте все-таки магия сломалась:

Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of CensoredLoggerContext are allowed in the image heap as this class should be initialized at image runtime.

Возможно, еще вернусь к подобным экспериментам в будущем, интересно на перф-тесты всего этого посмотреть.

Единственная проблемка, которая возникла — нужно корректно выставлять JAVA_HOME при компиляции. Кроме этого отмечу, что компиляция довольно долгая (1 контроллер на спринге компилировался аж 2 минуты). Разумеется, больше получается конечный файл — 73 Мб (при этом fat jar занимает 22 Мб), но с учетом того, что сама JVM занимает больше 200 Мб, это фигня.

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

Переназначение клавиш в macOS (часть 2)

Опять появился рабочий мак, опять надо что-то делать с раскладкой. Гореть в аду тем, кто в левом нижнем углу размещает Fn вместо Ctrl! Другой прикол — поставить вместо ~ знак параграфа § — кто его вообще использует? Не помню, когда его в последний раз видел.

Тащить что-то тяжелое вроде karabiner, как в прошлый раз, не хотелось. Fn вместо Ctrl легко поменялись через обычные настройки клавиатуры, а вот для ~ пришлось немного баш-команд выполнить.

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

Фингерпринтинг

Надеюсь, ни для кого уже не секрет, что “приватный режим” в браузерах вообще ни разу не приватный. Комбинация заголовков, информации от JS и локации по IP-адресу и т.п. сама по себе может быть уникальна. Проверить свой браузер можно еще тут. Чуть сгладить проблему в Firefox можно с помощью настройки privacy.resistFingerprinting = true.

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

P.S. это все конечно прикольно на компе, но будет ли кто-то с этим морочиться на телефоне?:)

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

Переопределение методов в java

Постоянным читателям хорошо известно, что я недолюбливаю java. Как только я начал чуть забывать, почему, она решила мне преподнести очередной сюрприз. Возьмем простенький класс

public class TestClass {
  public void foo(){ System.out.println(getBar()); }

  String getBar(){ return "bar"; }
}

И создадим от него наследника, переопределяя метод (довольно частый прием в тестах):

new TestClass(){
  String getBar() { return "baz"; }
}.foo();

Как думаете, что выведет foo?

Ответ

Правильный ответ — неизвестно. Потому что если вызывающий класс находится в том же пакете, то baz, а если в другом — то bar. И компилятор даже предупреждения не даст. Т.е. простой перенос класса из одного пакета в другой ломает функциональность без предупреждений.

Казалось бы — используй @Override и будет счастье: если попытаешься переопределить то, чего нет, то получишь ошибку. Но возникает вопрос: а какого черта тогда компилятор спокойно делает переопределение без этой аннотации?

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

Конспект по солверам

В процессе поиска ответов на свои вопросы про cvc5 наткнулся на конспект по солверам. Это большой сборник примеров. Очень легко читается (и он на рунглише), местами написана чушь, но он неплох для погружения в область, если кому интересна эта тема. От души разбавлено байками.

Среди интересного можно увидеть ломание генератора случайных чисел, решение задачки из комикса xkcd, доказательство корректности всяких битовых хаков, факторизацию числа, решение задачи расцветки графа, чтобы занимать меньше регистров памяти, поиск коллизий в CRC32, минимизацию количества тестов.

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

Калькулятор

Когда-то я в качестве калькулятора использовал bc. Но потом мне открыли глаза на очевидную истину: лучший калькулятор для командной строки — это питон.

Только недавно я узнал (а может вспомнил, просто уже давно забыл), что в интерпретаторе можно использовать _ для использования предыдущего результата:

>>> 9 + 10
19
>>> _ * 12
228
>>>
СсылкаКомментировать

Cvc5

По совету Петра Георгиевича после z3 решил попробовать солвер cvc5.

У него есть API, который почти полностью повторяет синтаксис z3 — надо просто заменить импорт на from cvc5.pythonic import * и убрать z3.. (Ну или в стиле злодеев сделать import cvc5.pythonic as z3). Однако данные из модели выковыриваются немного по-другому: вместо

model.eval(el).as_long()

надо писать

model[el].ast.getIntegerValue()

С получением результатов еще связан один очень дебильный баг (и это не только у меня руки кривые).

Несмотря на то, что cvc5 побеждает на конкурсах, на моей машине работал он ощутимо медленнее. Если z3 решил судоку за 100мс примерно (и это с учетом запуска интерпретатора), то cvc5 пыхтел аж 9,5 секунд. Решение для магического квадрата 5x5 он не нашел. А для рюкзака нет аналога Optimization из z3.

За разумное время последние две проблемы я решить не смог. Вообще cvc5 показался существенно менее дружелюбным к пользователю с точки зрения документации и настройки по сравнению с z3. С учетом ниши, которую я описывал ранее, z3 выглядит более адекватно.

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

Проверка наличия команды

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

Более очевидный способ — использовать which, который еще и путь покажет, но внезапно, это не самый лучший вариант:

  • which может отсутствовать в некоторых системах (особенно если система урезана под контейнер);
  • which на некоторых системах может не устанавливать код ошибки;
  • which может вызывать под капотом пакетный менеджер.
СсылкаКомментировать