Читать в телеге. Когда-то там были посты не только от меня.
Факторизация чисел
Иногда складывается ощущение, что в командной строке есть вообще все. Как import antigravity.
Наткнулся недавно абсолютно случайно на команду для факторизации чисел:
$ factor 1224234
1224234: 2 3 3 3 3 3 11 229
$ factor 24342342342342342342342342534512312123
24342342342342342342342342534512312123: 11 43053238739605007 51400086909245973599
$ factor 243423423423423423423423425345123121241
factor: ‘243423423423423423423423425345123121241’ is too large
BPMN-нотация и Camunda
Business Process Model and Notation — еще один способ описания алгоритма или процесса в виде схемы. Разрабатывался с прицелом на то, чтобы нотация была понятна и бизнесу, и разработчикам, и даже менеджерам. TLDR в виде cheatsheet.
Продолжением этой идеи являются BPMN-движки: чтобы схема была не только в документации, но по ней генерировалсь и само управление процессом, вместо какого-нибудь самопального конечного автомата. Звучит неплохо: аналитик нарисовал, разработчик интегрировал где надо, и все готово. Реальность, конечно, немного посложнее, и код все равно надо будет писать. Как и с любым фреймворком, нужно потратить некоторое время на его изучение, за абстракции придется платить производительностью, а при столкновении с ограничениями придется выдумывать костыли. Однако разработку это неплохо ускоряет и плюшка в лице наглядности довольно значимая.
Один из самых популярных BPMN-движков сейчас — это Camunda. Оперсорс, Java, REST API, внутренний API, web-морда для админки — вот, наверно, основные ключи к успеху в текущих реалиях индустрии.
Подробнее про все это можно почитать, например, в блоге о BPMN.
Баг горячих клавиш Xorg
У Xorg есть противный баг: горячие клавиши работают при нажатии, а не отжатии. Я его особо не замечал, потому что в большинстве приложений это не заметно (хотя было что-то подобное лет 10 назад в Firefox).
Однако когда постоянно начал использовать Slack, приложение которого написано на поганом электроне, то этот баг начал прям дико бесить: при переключении раскладки клавиатуры окно теряло фокус. По классике, есть открытый баг в трекере электрона, и даже не один. С одной стороны, вроде проблема не совсем в нем, но с другой — UX это портит конкретно, тем более, что проблема поправима.
Поправить баг на уровне системы можно установкой PPA.
Как запустить что-то после всех тестов
Например, проверку покрытия или отправку отчета куда-нибудь.
Очевидный вариант — сделать кастомную задачу в gradle/sbt/maven, которая оборачивает или перезаписывает старую задачу test
.
Но если писать таск неохота, то есть и другой вариант, если у вас JUnit5.
Можно сделать кастомный TestExecutionListener, переопределив testPlanExecutionFinished
. Чтобы его обнаружил JUnit, добавить полное имя класса в src/test/resources/META-INF/services/org.junit.platform.launcher.TestExecutionListener
. Такая штука полезна для составления отчета по покрытию, например.
Но, как всегда, есть нюанс: ассерты работать не будут, потому что в движке все вызовы листенеров обернуты в try-catch. Но если нельзя, но очень хочется, то можно пойти на совсем грязный трюк: запустить движок тестов внутри движка тестов:
val launcherConfig = LauncherConfig.builder().enableTestExecutionListenerAutoRegistration(false).build()
val launcher = LauncherFactory.create(launcherConfig)
val request = LauncherDiscoveryRequestBuilder.request()
.selectors(selectClass(CoverageTest::class.java))
.build()
launcher.execute(request)
Тут еще отключается обнаружение листенеров, чтобы это не превратилось в бесконечную матрешку. Звучит как извращение, но чего только не сделаешь, лишь бы не писать кастомный таск для maven…
UPD: таск все-таки пришлось написать, с использованием exec-maven-plugin на фазе test, потому что вложенный движок тестов иногда не успевает отрапортовать о результатах до того, как основной завершил свою работу.
Поиск пересечения файлов
Нашел прикольный способ найти пересечение двух файлов:
grep -Fxf file1 file2
выдаст строки, которые есть в обоих файлах, но с нюансом, что из второго файла останутся потенциальные дубликаты (которые можно отсеять через | sort | uniq
).
Принцип работы довольно прост: берем паттерны из file1
(-f file1
), говорим, что это строки, а не регулярки (-F
), и ищем точное совпадение строк (-x
) в file2
. В интернете пишут, что это быстрее, чем приколы с сортироками и однострочниками на питоне.
Мне это пригодилось без -x
, чтобы поискать в логах данные из CSV.
Типы дат java.time
С java.time жить можно, хотя Joda Time у автора получился поудобнее. Памятка про отличия различных типов.
TLDR: LocalDateTime
с большой вероятностью бэкэндщику не нужен, а OffsetDateTime
покроет большинство бытовых кейсов.
Поиск неактуальных веток git
Продолжаю прибираться в проекте. На этот раз цель — избавиться от никому не нужных веток, которые были уже вмержены или забыты.
Главный помощник в этом деле — команда git ls-remote --heads [repoUrl]
, которая позволяет получить список веток репозитория без его клонирования. Удобно, когда тебе нужно 5+ реп обработать.
Со списком веток на руках можно сделать запрос к баг-трекеру, чтобы получить статус соответствующего тикета (если ветка содержит его идентификатор, разумеется). Мне не повезло и у меня Jira, хорошо хоть к ней есть подобие клиента. А дальше — закрываем ручками то, что в финальном статусе (можно автоматизировать и удаление, но как-то стремно). Полностью скрипт можно посмотреть в gist.
Если надо почистить локальные ветки, которые уже были удалены в удаленном репозитории — есть плагин, который это делает в пару кликов (VCS → Git → Delete old branches…). Правда он скорее всего будет одноразовый: вы же будете держать репу в чистоте после генеральной уборки?
Про Slack
Долгое время я скептически относился к слаку, считая, что телега лучше. И для личного общения/ботов/перекидывания стикерами она все равно лучше. Но для работы слак оказался удобнее. В мае моя команда на него перешла и возвращаться в телегу вряд ли будет.
- Киллер-фича — это треды. Особенно, когда в чате дохрена людей и тебе не нужно читать ВСЕ. Вдобавок, когда обсуждается несколько тем одновременно, тележный чат быстро превращается в помойку. 100 непрочитанных сообщений в секунду будут читать только психи. Чаты на 100+ человек в телеге даже более-менее на 1 тему — это рак. Я вообще не понимаю, какая от них польза, особенно когда туда заходят новые люди с типовыми вопросами. Конечно, к тредам надо приучать, но как показала практика, через пару недель игры в злого полицейского останутся только совсем отъявленные “не такие как все”.
- Настоящее отключение уведомлений. Не показывать сереньким, не показывать сереньким в архиве, а просто не показывать никак. Полезно для всяких чатов поддержки: понадобилось тебе что-то, зашел, спросил, в треде тебе ответили (и на это приходят уведомления разумеется), потом об этом чате забыл.
- Настоящие имена. Мелочь, но до переезда были случаи, когда пишешь кому-то в личку по рабочему вопросу и даже его пола не знаешь, не то что имени.
- Выключил рабочий комп = выключил работу. Никаких переписок в полночь о том, что надо бы завтра какую-нибудь фигню сделать.
Но по стикерам иногда скучаешь… Радужные попугаи — это круто, но огромную рожу Гарольда уже не вбросишь.
Дебри рефлексии
Картинка с двумя стульями у меня родилась не просто так. Довольно типичная рабочая ситуация, в которую я вляпался на прошлой неделе. Ближе к концу я уже сел на третий стул пулл-реквестов и сделал их аж три штуки, но расскажу о дебрях, в которые зашел, пытаясь решить проблему через рефлексию.
Пусть у нас есть публичный метод, в котором надо немного подшаманить:
@Override
String exampleMethod(){
String firstPart = privateMethodToModify();
String secondPart = super.exampleMethod();
String thirdPart = anotherPrivateMethod();
return firstPart + secondPart + thirdPart;
}
Первая реакция будет: “Чё тут делать-то? Отнаследуйся да переопредели!”. Но есть нюанс: super
будет уже не тот. А беспокоить дедушек в java нельзя.
Ок, может тогда получим указатели на exampleMethod
и anotherPrivateMethod
, и в месте вызова ручками все подергаем? Однако полиморфизм будет суров, и exampleMethod
вызовется из дочернего класса, даже если указатель вы получали у родителя.
Что же делать? Сдаться и скопипастить дочерний класс, изменив в нем что нужно? Скорее всего да, но если вы хотите сидеть на пиках до конца, то есть еще один способ — MethodHandles
. Это новый API, который не является заменой рефлексии, а дополнением к ней, в основном для всяких низкоуровневых манипуляций для разработчиков языков под JVM. С ним можно вызвать родительский exampleMethod
для ребенка:
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Child.class, MethodHandles.lookup());
MethodHandle baseHandle = lookup.findSpecial(Parent.class, "exampleMethod", MethodType.methodType(String.class), Child.class);
return (String) baseHandle.invoke(child);
Но, как всегда, есть нюансы. Во-первых, если java меньше 9 версии, то придется еще и рефлексию использовать, чтобы в приватные методы залезть (выглядит стремно). Во-вторых, в kotlin это работать из коробки пока не будет без специальных флагов, но в 1.4 эти флаги включат по умолчанию. 100% интеропа такие 100%.
Посмотреть примеры подробнее можно github. Познакомиться с API подробнее — тут, а узнать, зачем оно вообще нужно — тут.
Случайная выборка из csv
Безо всяких питонов сделать случайную выборку данных из текстового файла можно командой shuf
:
cat dataset.csv | shuf | head -n100 | tee random_sample.csv