Верхняя полка📝
361 subscribers
284 photos
11 videos
3 files
145 links
Путевые заметки программного инженера и легкоатлета-любителя.

Автор: Владимир @Toparvion Плизга

Домашняя страница: https://toparvion.pro/
Download Telegram
Минувшие выходные целиком прошли под хэштегом #спорт — вместе с товарищами по спортивному клубу я был в Красноярске на двухдневном фестивале открытой воды Шумиха 2025 🌊

В оба дня нас забрасывали катерами на дикие речные берега, откуда мы возвращались вплавь в стартовый городок. В субботу у меня был заплыв на 3,8 км по заливу Енисея с прикольным названием Шумиха, а в воскресенье — 5 км уже по самому Енисею-батюшке. Оба старта, в целом, прошли хорошо; я показал результаты, соответствующие своему текущему уровню подготовки. Правда, во второй день плылось заметно сложнее — несмотря на твёрдое намерение не упарываться в первый день, сил было потрачено немало, а они, как известно, не бесконечные 🙃

Высокие берега, сплошь поросшие вековыми хвойными деревьями; чистая прохладная вода, местами придававшая изюминки своим волнением; несокрушимая мощь и масштабное величие Красноярской ГЭС, расположенной всего в 1,5 км от места старта — всё это вкупе с хорошей организацией и отличной компанией сделали прошедшие два дня очень яркими и богатыми на позитивные впечатления, хоть и напряженными физически🫠

Не знаю, удастся ли ещё поплавать в открытой воде в этом сезоне; всё же наше сибирское лето весьма скоротечно. Но даже если нет, эти выходные вполне можно считать достойным завершением сезона🌅

P.S. Для любопытствующих: итоговый протокол соревнований лежит здесь.
🔥15👏2
SSH-туннели для #Java Dev&Ops 🔭

Ни один из последних моих проектов не обходился без подключения по SSH, чтобы что-то посмотреть/настроить/отладить/пофиксить и т.д. Но часто для этого нужно подключиться к определённому TCP-порту удалённого сервера, а он недоступен: то открыт лишь на localhost, то где-то маршрута не хватает, то безопасники запрещают. Во всех этих случаях на выручку приходили SSH-туннели. Расскажу о них чуть подробнее, вдруг кто-то не знал или недооценивал 🧐

Что это?
Фича SSH клиента и сервера, позволяющая "пробросить" порт с удалённого сервера на свою локальную машину (где запущен SSH клиент). То есть сделать так, чтобы обращение на этот порт у localhost'а волшебным образом приводило к обращению на этот же (или другой) порт у сервера, но при этом весь траффик оставался закрытым внутри SSH-соединения.
По смыслу это похоже на port-forwarding у kubectl и docker, но может применяться в бОльшем числе случаев ⚒️

Зачем?
Чтобы мультиплексировать множество соединений с удалённым сервером по одному SSH-каналу без открытия портов на внешних сетевых интерфейсах сервера. Проще говоря, чтобы завернуть весь траффик внутрь SSH независимо от протокола. Например:
• чтобы удалённо отлаживать JVM-приложение, не выпячивая порт отладчика наружу;
• чтобы мониторить приложение по JMX, не заморачиваясь с настройкой SSL для этого;
• чтобы дергать Spring-приложение за actuator, не затеваясь с получением сертификатов для HTTPS 📌

Как включить?
В общем случае включение сводится примерно к такой команде в консоли:
ssh -L <local-port>:<remote-address>:<remote-port> -N -f <ssh-host>

, где:
-L — команда на включение локального туннеля;
local-port — порт, на котором вы хотите видеть удалённый сервис на своей машине (как правило, равен remote-port);
remote-port — порт удаленного сервера, который нужно сделать доступным у себя (как правило, равен local-port);
remote-address — IP или имя сетевого интерфейса, на котором открыт удалённый пробрасываемый порт; чаще всего это localhost, но могут быть и другие;
-N — признак отсутствия команды, которую нужно выполнить на удалённом сервере (обычно она не нужна);
-f — признак запуска туннеля в фоновом режиме; если не добавить, управление не вернётся в консоль, и туннель будет висеть в ней;
<ssh-host> — либо имя хоста для подключения (может быть с именем пользователя, например, root@somehost.com), либо название настроек подключения из файла ~/.ssh/config, например:
Host my-sandbox-vps
Hostname 55.555.555.0
User root
IdentityFile ~/.ssh/id_dsa
IdentitiesOnly yes

С такими настройками включение SSH-туннеля для удалённой отладки может выглядеть так:
ssh -L 5005:localhost:5005 -N -f my-sandbox-vps

Причём и эта команда, и файл настроек останутся точно такими же даже под Windows, если у вас установлен OpenSSH 🪟

Как выключить?
Поскольку каждый туннель — это отдельный процесс, для его выключения достаточно этот процесс остановить. На Linux/MacOS это может выглядеть примерно так:
$ ss -tulpn | grep 5005
tcp LISTEN 0 128 127.0.0.1:5005 0.0.0.0:* users:(("ssh",pid=307017,fd=5))
$ kill 307017

А если туннель запущен без флага -f, то в его консоли достаточно нажать Ctrl+C✖️

Какие недостатки?
• быстродействие: как правило, скорость передачи заметно падает, поэтому смотреть видосики в UHD по такой схеме будет не комфортно;
• искажение цепочки вызовов: все запросы в целевой сервис будут приходить с localhost, где запущен SSH-сервер; это может создавать проблемы;
• непрозрачность: если целевой хост перестанет быть доступен, туннель просто молча упадёт, не подавая явных признаков и не пытаясь переподключиться (это всё преодолимо, но потребует усилий) 🧟

P.S. Картинка взята из этой статьи Ивана Величко, где он также объясняет и другие варианты построения туннелей на SSH. Почитайте, и пусть вам это никогда не пригодится 🫠
🔥171
В последнее время, в связи со сдачей напряжённого проекта с московскими коллегами, стало нередко приходиться начинать рабочий день по Новосибирску, а заканчивать по Москве.

На этом фоне в обиход вошёл новый речевой оборот:

Сегодня в третьей половине дня...
😢14😁10
Новость для тех, кто всерьёз задумывался начать своё дело в IT 💼

C 26 сентября по 30 октября в Новосибирском Технопарке пройдёт 31-ый сезон А:Старт — одной из топовых в России и уж точно крутейшей за Уралом акселерационной программы для начинающих предпринимателей и технологических стартапов. Туда можно прийти с IT-проектом на любой стадии от голой идеи до рабочего решения, а уйти с упакованным продуктом, готовым к выводу на рынок или даже имеющим выручку 💰

Для этого на протяжении пяти недель (как правило, по три дня: четверг-суббота) нужно посещать профильные лекции, прорабатывать конкретные вопросы с экспертами и менторами и, конечно, выполнять много домашней работы по контролем трекера: проводить проблемные интервью, анализировать рынок, считать unit-экономику, стряпать лендинги и (наверняка) допиливать свой продукт. Легко будет едва ли, а вот полезно — по-любому 💯

Фишка программы в привлечении множества экспертов из индустрии: владельцев бизнесов, опытных технопредпринимателей, инвесторов — словом, тех, кто собственными руками и головой уже добился значимых успехов и понимает реальные проблемы начинающих. Об них можно как следует "обстучать" все свои идеи, вопросы и сомнения, что очень сильно помогает трезво взглянуть на свою задумку и выбрать ей правильный путь развития 🌄

Участие в программе платное: 12К лично и 24К за команду. Но есть лайфхак. Незадолго до начала акселератора, 13 сентября в том же Академпарке будет проходить Easy Pitch — открытая презентация идей и проектов для всех желающих. Если к ней нормально подготовиться и уверенно выступить, то присутствующие там эксперты могут подарить бесплатную проходку на акселератор. Схема рабочая, проверял сам в 2023-ем и в этом году 👌🏼

Кому интересно, можно полистать сайт программы, а также задать вопросы организаторам (они хорошо реагируют) или мне — как выпускник весеннего А:Старт 2023, ни разу не пожалевший о содеянном, я с удовольствием поделюсь своим опытом участия 👐
🔥3❤‍🔥1
Media is too big
VIEW IN TELEGRAM
Сегодня с товарищами завершил сезон плавания на открытой воде. В этом году он выдался славным: помимо разных водоёмов Новосибирска, довелось поплавать в водах Кузбасса, Урала, Ленинградской области и Красноярска 🗺

А завершением стал рекордно туманный заплыв на домашнем Обском водохранилище — видимость была не больше 100 метров, и это вскрыло любопытный эффект: кто бы ни был направляющим группы, без визуальных ориентиров он всё равно не мог плыть прямо и забирал вправо, постепенно вырисовывая круг и возвращаясь к берегу. Разница между пловцами была только в радиусе этого круга 🤭

На этом фоне вспомнилось закрытие аналогичного сезона в 2020-ом — тогда заплыв, напротив, выдался необыкновенно солнечным, и поскольку я был начинающим дроноводом, вместо плавания с товарищами я снимал их с воздуха 🚁

Делюсь с вами кадрами того дня. Едва ли вы захотите приобщиться, но, быть может, хотя бы поймёте, за что я полюбил это отнюдь не самый комфортный #спорт 🏊‍♂️
🔥7
This media is not supported in your browser
VIEW IN TELEGRAM
На заметку troubleshooter'ам ✍️

На днях вышел alpha-релиз четвертой версии Recaf — среды для реверс-инжениринга приложений на #Java. Она позволяет получить множество сведений о готовом приложении (или его процессе) даже без доступа к исходному коду 👨‍💻

Вот примеры применений из моего опыта:
• проверить, что недавние изменения в определённом классе действительно попали в финальный артефакт приложения — это бывает полезно при косячном CI/CD или путанице с версиями приложения;
• выяснить значение определённого свойства или флага у запущенной JVM — пригождается при анализе проблем производительности и расследовании некорректного поведения;
• определить classLoader, которым был загружен такой-то класс в runtime — бывает полезно при разбирательствах с ClassNotFoundException, NoClassDefFoundError, ClassCastException и прочими непотребствами 🐞

Разумеется, всё это можно сделать и другими средствами (я так и делал), но, согласитесь, удобнее и быстрее работать, когда есть единый инструмент с интуитивно понятным интерфейсом, который не надо каждый раз вспоминать (в отличие от синтаксиса под-команд jcmd) 🛠

Из любопытного: Recaf также позволяет менять байт-код (в том числе структуру классов) и применять эти изменения на лету. Интуитивно кажется, что это нужно, например, чтобы обманывать локальный Minecraft и накручивать себе очки и жизни (такой ArtMoney для Java). Если знаете реальные кейсы применения такой фичи в неигровых приложениях (и с законными целями), то поделитесь, пожалуйста — будет интересно 🤲
👍7🔥2
По моим наблюдениям за последние 10+ лет, почти все самые сложные вопросы и проблемы в разработке ПО начинаются со слов "Почему не ...?" 🧐

— Почему не был вызван этот метод?
— Почему не пришёл ответ на вон тот запрос?
— Почему не обработано отправленное событие?
— и т.д., и т.п., и др.

Их все объединяет тот факт, что в качестве вводной даётся лишь негативное следствие (где-то что-то не произошло), а первопричина (где-то что-то произошло, но не так) остаётся спрятанной раньше на шаг, два или больше... И эти шаги приходится делать в обратном направлении исходного развития событий, то есть реверс-инженирингом 🥷🏼

А если такой подход неприменим, то приходится брать ту же или аналогичную систему, и повторять в ней те же шаги в прямой последовательности, пытаясь понять/заметить/угадать момент, в который поведение могло стать ошибочным. Любопытно, но по моему опыту, примерно в 1/3 таких случаев инженер, пошедший этим путём, приходит к неутешительному выводу в духе: "ДА ОНО ВАЩЕ НЕ МОГЛО РАБОТАТЬ!" 🫠

Универсального решения для всех проблем "почему не...?" мне неизвестно, но как разработчик я нередко вижу на code review, что алгоритм воплощается в коде по сугубо оптимистичному пути, т.е. автор как бы ведёт его строго в успешном направлении, а всё, что может сбить с этого пути, но не мешает явно, игнорирует (зачастую несознательно). Код получается компактным, менее развесистым, пишется быстро, читается легко — казалось бы, всем хорошо. Вот только этими намерениями выстлана дорога в "почему не ...?" 🛣

В этом свете хочется пожелать почаще включать в себе параноика. И в местах соприкосновения компонентов системы спрашивать себя: "А что если здесь сломается?", "А точно ли я могу полагаться на эти данные?", "А где гарантии, что это будет так?" Все эти сомнения необязательно выражать громоздкими if'ами, зашумляющими код. Есть ряд компактных однострочных решений, например:
— ключевое слово assert (с которым, правда, есть серьёзные нюансы);
— семейство методов java.util.Objects.require*()
— семейства методов check* и verify* из классов Preconditions и Verify в библиотеке Google Guava 🥑

Выбор конкретного способа проверок — тема отдельной дискуссии. Главное — эти проверки добавлять. По сути, это применение принципа fail-fast, только с целью обратить что-то не произошедшее вовсе (и оттого сложное для диагностики) во что-то произошедшее не так. Тогда и отвечать на трудный вопрос "почему не ...?" придётся пореже 🙂

#мыслиВслух
🔥12👍103
Моим первым в жизни полумарафоном (21,1 км) был забег А. Раевича в Новосибирске в 2016 году. Мне было интересно и вместе с тем как-то жутковато бежать такую дистанцию, потому что столько же километров было между посёлком, в котором я рос, и районным центром, куда мы с родителями периодически ездили на автобусе или машине, и никто даже подумать не мог, что такое расстояние можно преодолеть на ногах, тем более бегом 😳

С тех пор я сбегал уже немало всяких "половинок", но полумарафон Раевича остаётся любимым и очень важным стартом, потому что он позволяет довольно чётко ответить на вопрос "Как я провёл лето?" (в плане беговой подготовки). Этот год не стал исключением — я вписался в этот старт уже в 8-ой раз и, больше того, решил замахнуться на обновление своего личного рекорда (1:26:03), который поставил в 2023 году и не сумел побить в 2024, проиграв себе около 40 секунд ⏱️

Несмотря на то, нынешнее лето выдалось для меня больше плавательным, чем беговым, в нём был одна важная беговая "фича" — почти каждый четверг в 7:00 мы с товарищами по спортивного клубу встречались на стадионе НГУ и под руководством тренера (который готовился вместе с нами) делали много специальной беговой и силовой работы 🦵🏼

Видимо, это сработало, потому что сегодня мы подтвердили ожидаемые результаты, в том числе я: пробежал 21,1 км за 1:25:09, улучшив личный рекорд почти на минуту. В мужском абсолюте стал 78-ым из 865 бегунов, а в категории М35-40 оказался 23-им из 233. Да, отнюдь не пьедестал, но при такой конкуренции всё равно приятно. Равно как и то, что личник вообще удалось обновить, ведь есть мнение, что у любителей результаты растут только первые 5 лет 📈

Ещё одной прелестью таких стартов является сообщество — там заводятся и укрепляются очень приятные (и порой весьма полезные) знакомства, а ежегодные встречи с некоторыми людьми становятся доброй традицией. Пример тому — фото двух инкубаторских в синих майках и черных шортах🤪
Кто не узнал - слева на фото Иван Углянский, тоже обновивший личник, но аж на 5 минут 👏🏼

#спорт
👍108🔥6
Парадоксально, но чем бОльшая задача приходит на Code Review, тем хуже её смотрят 👀

Впрочем, оно и понятно, если вспомнить, как начинает сводить зубы при виде Pull Request'а на десятки, а тем более сотни файлов 🤦‍♂️ Как решается эта проблема у вас? 🧐
Anonymous Poll
24%
Жестко декомпозируем задачи на мелкие
9%
Назначаем больше ревьюеров
23%
Дополняем code review личным обсуждением/презентацией
12%
Привлекаем AI-ревьюеров
27%
Нет code review — нет проблем
6%
Свой вариант (в комментах)
24%
Просто покажи мне ответы
Я понятию не имею, как отмечать День программиста. Видимо, тот мем с двумя одинаковыми картинками — про меня. Лучше вспомню какой-нибудь случай из профессиональных будней 📜

Как-то давно, когда мы в прошлой компании активно переходили с монолита на микросервисы, и у нас ещё не было устоявшейся практики функционального описания на эти микросервисы, основным источником информации были файлы README, писавшиеся разработчиками. Понятно, что степень полезности от них была сильно разной, но это всё же было лучше, чем ничего... ⚖️

И вот как-то раз меня занесло в микросервис, отвечавший за работу с push-уведомлениями. Назывался он PUSHkin (да, мы тогда креативили как могли). Сервис был мне мало знаком, но при том был довольно сложным. Безо всякой надежды я мимолётом ткнул на его readme-файл и приятно удивился — описание сервиса оказалось не только подробным, но и было сделано что называется с душой, а местами и с юмором 💎

Понимая, скольких трудов это стоило, я решил публично поблагодарить коллегу Диму за старания, но так, чтобы это не выглядело как дежурное "объявление благодарности". Возможно, выбрал не самый удачный способ, но в тот день во внутренней соц.сети компании появилась вот такая картинка (теперь можно кликать в спойлер)👆🏼

P.S. С профессиональным праздником, коллеги! 👨‍💻
😁12🔥92
Совсем недавно с лёгкой подачи Ивана Углянского (@gdb_dbg) мне довелось попробовать себя в роли преподавателя: прочёл студентам "Системного программирования" на МехМате НГУ две лекции по основам компьютерных сетей. Не знаю, насколько интересно и полезно было ребятам, но кажется, что получилось норм; по крайней мере, опыт позитивный 🙂

Пока готовился, наткнулся на эту прелесть — http.cat — сайтик, где для каждого стандартного статуса ответа HTTP подобран мемасик с котом (открывать из-под VPN) 😸

Любопытно, что автору вообще удалось разместить такой сайт на таком домене, ведь .cat вопреки названию создан вовсе не для залипания на котиках, а для популяризации каталонского языка и сохранения культуры народов-носителей каталонской речи (Каталония, Андорра, части Франции и Италии) 🇮🇹

В своё время я помогал в создании сайта для одного котокафе, и мы конечно очень хотели разместить его именно в этом домене, но упёрлись в то, что для регистрации сайт должен быть на каталонском, а его размещение должны одобрить несколько других владельцев сайтов в этом домене — короче, всё как в элитарных клубах. Видимо, поэтому сайт про HTTP и котиков внезапно имеет версию на каталонском языке 🤭
😁13🔥3👍2👏2
Одной из долгожданных фич вышедшего намедни 25-го релиза #Java для меня стал JEP-520 "JFR Method Timing & Tracing" — доработка Java Flight Recorder'а, которая позволяет профилировать приложения с помощью инструментирования, то есть считать точные количества вызовов методов и средние времена исполнения, да и вообще даёт более высокую точность по сравнению с сэмплингом 📐

Как бы в ответ на это Андрей Паньгин сегодня выпустил пост с ненавязчивым напоминанием о том, что в async-profiler возможность трейсить указанные Java-методы появилась ещё в 2020-ом году. И возможность замерять времена исполнения методов тоже есть, правда, подвезли её совсем недавно, поэтому доступна она пока только в ночных сборках 🌃

Заодно он прошёлся и по самому JEP-520: объяснил, чем принятый в async-profiler'е подход выгодно отличается от реализованного в JDK, и подсветил два бага (раз, два), которые сам же и обнаружил 🪲

Если опираться только на этот пост, может показаться, что async-profiler безоговорочно лучше JFR подходит для трассирующего профилирования. Но, как обычно, на деле всё не так однозначно. Например, JFR может оказаться предпочтительнее, когда:
— нельзя профилировать сторонними инструментами;
— нужно подключиться к процессу удалённо;
— профилируемые методы нельзя описать маской имени, но у них есть общие аннотации 📧

Словом, всему своё место. В любом случае здорово, что оба инструмента развивают схожий функционал, ведь это даёт нам — конечным пользователям — возможность выбрать из них наиболее подходящий для каждой конкретной задачи👷
👍113
Нанёс немножко непоправимой пользы #opensource проекту Spring PetClinic REST, который я использую в качестве лабораторного кролика в своих тренингах 🎓

В феврале в этот проект нагрянула небезызвестная в #Java мире Monica Beckwith (которая, кстати, выступала у нас онлайн на конференции SnowOne в 2021 году!) и привезла туда поддержку встраиваемой СУБД H2, логично мотивировав этом тем, что раз проект учебный, то должен соответствовать лучшим практикам Spring Boot, а там уже давно H2 используется по умолчанию 🤐

И хотя её issue и PR были оформлены очень хорошо (видать, ChatGPT постарался%)), само нововведение не обошлось без багов, поэтому пришлось:
починить (и упростить) переключение между разными СУБД;
обеспечить доступность веб-консоли H2 при (якобы) выключенном Spring Security 🔐

Ещё там сломалась пара SQL-запросов при работе на H2 в режиме plain JDBC; я уже поправил, но теперь надо как-то покрыть тестами. С этими opensource-проектами почти всегда так — стоит только сунуться... 🤦🏼‍♂️
❤‍🔥8👏6😁2🔥1
Коротко о погоде в окрестностях Новосибирска 📺

(снято во время утренней пробежки)
🔥14🎄9🆒3😁21👍1