вторник, 1 января 2030 г.

О блоге

Более двадцати лет я занимался разработкой ПО, в основном как программист и тим-лид, а в 2012-2014гг как руководитель департамента разработки и внедрения ПО в компании Интервэйл (подробнее на LinkedIn). В настоящее время занимаюсь развитием компании по разработке ПО stiffstream, в которой являюсь одним из соучредителей. Поэтому в моем блоге много заметок о работе, в частности о программировании и компьютерах, а так же об управлении.

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

понедельник, 31 декабря 2029 г.

[life.photo] Характерный портрет: вы и ваш мир моими глазами. Безвозмездно :)

Вы художник? Бармен или музыкант? Или, может быть, коллекционер? Плотник или столяр? Кузнец или слесарь? Владеете маленьким магазинчиком или управляете большим производством? Реставрируете старинные часы или просто починяете примус? Всю жизнь занимаетесь своим любимым делом и хотели бы иметь фото на память?

Предлагаю сделать портрет в обстановке, связанной с вашей работой или увлечением. Абсолютно бесплатно. Очень уж мне нравится фотографировать людей в их естественной среде. Происходить это может так...

пятница, 17 марта 2023 г.

[prog.c++] Очередные шаблоны против копипасты: упоролся тут на почве обеспечения гарантии strong exception safety

Делаю новую фичу в SObjectizer и в одном месте потребовалось реализовать вставку элемента в словарь из словарей словарей. Сначала сделал просто. Потом начал делать нормально ;)

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

Итак, есть вот такая вот структура данных (ключевой тип -- это bindings_map_t):

среда, 15 марта 2023 г.

[life.music] Продолжение саги про выбор недорогих, но хороших наушников на Aliexpress

Два года назад в блоге появилась первая часть истории, которая продолжается до сих пор: Введение в сагу о выборе недорогих, но хороших наушников на Aliexpress. Точнее говоря, два года как исполнилось вчера и я было хотел этот пост написать вчера...

Но вернувшись с работы умудрился сломать только-только полученные на почте динамики пытаясь сделать пару внутриканальных наушников-затычек :( Сильно расстроился по этому поводу и плюнул на все. Сегодня уже не так обидно, поэтому попробую поделиться своими ощущениями от этого увлечения за истекший период.

Несколько общих слов

Сразу хочу сказать, что готовых наушников именно для прослушивания уже очень давно не покупаю. Еще года с 2021-го. Как начал собирать самодельные вкладыши, так и продолжаю. Если и беру что-то готовое, то буквально копеечное ради корпусов, в которые затем можно будет вставить отдельно купленные динамики.

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

Отчасти потому, что с марта 2022-го из РБ на Aliexpress закупаться стало сложнее, чем до того. Да и посылки, по ощущениям, стали идти дольше. Что сильно снижает удовольствие от процесса: одно дело, когда ты просто оплатил с карточки в белорусских рублях и посылка у тебя уже через 2-3 недели. Другое дело, когда нужна валютная карта, да еще и не любого банка. И ждать потом 1.5-2 месяца.

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

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

Какие наушники использую больше всего?

Вкладыши с 15.4mm динамиками. Одна пара с DLC-диафрагмой (на работе), она пара с LCP-диафрагмой (дома). Забавно, что изначально DLC- и LCP-динамики были для меня слишком светлыми, мне в них не хватало басов.

Но время идет, вкусы и привычки меняются. Больше обращаешь внимания на какие-то детали и особенности звучания. Так что сейчас что DLC, что LCP даже чуть темноватее, чем хотелось бы. Что меня до сих пор удивляет. Т.к. все еще помню свое разочарования от количества баса в LCP-динамиках летом 2021-го года :)

Иногда слушаю вкладыши с синей PET-диафрагмой. Но рано или поздно начинаю ощущать, что мне в них (пока?) недостаточно веса на НЧ, поэтому все равно возвращаюсь к DLC и LCP-динамикам.

Иногда слушаю внутриканальные затычки с 10mm драйвером, переделанные из Yincrow RW-919. Но пока что не смог подобрать себе подходящие для этого корпуса амбушюры. Так что основными они (пока?) не стали. Хотя по качеству звука, наверное, это самое лучшее из имеющегося. По деталям, возможно, вкладыши с PET-диафрагмой чуть посолиднее, но в этих затычках больше массы на низких частотах.

Еще у меня был эксперимент с 40mm накладными наушниками. Но пока что не удалось сделать нормальное оголовье (не встретились пока на барахолке подходящие доноры), так что здесь еще исход не ясен. Но общие впечатления прикольные. Что-то в этом направлении есть.

Какие источники у меня сейчас?

Как и прежде: телефон + USB ЦАП ("свисток").

До недавнего времени было четыре основных свистка. На работе долгое время пользовался X1 на базе AK4452 (реплика того самого Trasam Q1). Но на днях он стал барахлить, поэтому пришлось от него отказаться.

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

Безымянный чуть ли не самодельный USB-цап на базе PCM2706 + ES9023 в качестве усилителя. Ценой что-то вроде 13USD. С заметным фоновым шумом, из-за чего приходится применять дополнительное сопротивление на 75ом. Не такой техничный и детальный, как Sonata BHD. Поддерживающий только 16bit/44.1kHz. Но зато очень приятный и драйвовый звук. Почти что тёплый, ламповый :) И, что немаловажно, такой же экономичный, как и Sonata BHD.

Hiby FD3 на двух ES9038Q2M. Просто самый лучший из всего, что у меня побывало. Единственная проблема -- жрет батарейку в три раза активнее, чем Sonata BHD :(

Про Hiby FD3 в Интернете не так много говорят, хотя, судя по тому, что я читал, это прямой конкурент таким распиаренным моделям, как xDuoo Link2 Bal и Moondrop Moonriver 2. Собственно, из-за того, что у меня есть FD3, пробовать Link2 Bal или Moonriver 2 даже и не хочется.

Еще не могу не отметить один ЦАП от HaaFee на базе AK4493EQ (из тех, что до пожара на фабрике Asahi Kasei). Отличный был ЦАП за свои деньги. Но, в какой-то момент у меня на руках этих самых ЦАПов скопилось очень уж много, распродал часть, вместе с ними и HaaFee. Сейчас жалею. Тот самый velvet sound от AK, чего нет в FD3.

HiFi-плееров у меня пока не было. Хотя уже задумываюсь о том, чтобы каким-то обзавестись, т.к. надоело уже таскаться со "свистками" и подключать/отключать их постоянно. Однако, хороший плеер (который бы переиграл бы FD3) для меня сейчас слишком дорогая штука, так что пока не обзавелся. Ну да поживем, увидим.

Некоторые выводы, которые я сделал для самого себя

  • Если ударяться в качественный мобильный звук, то хороших наушников мало. Надо приобрести мало-мальский приличный свисток. Благо выбор сейчас просто огромный.

    Так-то, конечно, хорошие наушники будут играть и от телефона. Однако, даже "копеечный" (по аудиофильским меркам) USB-ЦАП за 30-40USD сразу даст вам почувствовать насколько хорошие наушники могут звучать лучше.

  • Сменные кабеля -- это, наверное, must have. Т.к. со временем кабеля изнашиваются. Такова се ля ви, с этим ничего не поделаешь. Силикон на оплетке кабеля под действием времени, жира с нашей кожи, Солнца и других факторов теряет свои свойства, кабель дубеет и затем переламывается. Да и пользоваться задубевшим кабелем... Ну такое себе.

    Цены на кабеля сильно варьируются. Но нормальный кабель на распродажах вполне можно взять в диапазоне от 10 до 20USD, иногда и дешевле. У меня есть несколько кабелей от NiceHCK, пока доволен.

  • Наушники, как не крути, все-таки расходный материал. Конечно, если наушниками пользоваться аккуратно, то они могут прослужить годы (лет пять-шесть запросто, особенно если кабель сменный). Но, т.к. наушники используются активно (тем более, если используются и на улице), то случайно повредить их -- это как нефиг делать. Так что я не вижу смысла в очень уж дорогих наушниках для повседневного применения. Дорогие для меня -- это дороже 50USD (т.е. если мне их комплектующие обошлись больше чем в 50USD). Подозреваю, что брендовые наушники с таким же качеством обойдутся в разы дороже, но это уже совсем другая история.

    Если слушать музыку в фоновом режиме, то качество источника+наушников, по большому счету, не суть важно. ЦАП за 15-20USD и вкладыши с динамиками за 10USD + приличный кабель за 15USD -- и этого хватит с лихвой. Ну а если уж музыку начинаешь выслушивать специально, отгородясь от всего мира, тогда да, тогда придется раскошелиться :)

  • Амбушюры очень сильно влияют на звук. Особенно во внутриканалках. Так что если вы все еще ищете "свой звук", то имеет смысл собрать большую коллекцию разнообразных амбушюр. Чем больше, тем лучше.

    Самое забавное для меня сейчас в плане амбушюр то, что в последнее время я все вкладыши слушаю вообще без амбушюр. Не знаю почему так произошло, но как-то стал замечать, что мне четкость и резкость звука (что скрадывается амбушюрами на вкладышах) стала важнее, чем объем и масса (что добавляется амбушюрами). Еще полгода назад в такой поворот я бы не поверил.

  • Среди всех магазинов, в которых можно приобрести запчасти для самодельных наушников, я безусловно выделяю NSC Audio DIY Store и XinYue Audio Store. Тут и выбор большой, и цены низкие, и обслуживание быстрое и адекватное. Подавляющее большинство моих закупок было сделано в этих двух магазинах. Есть еще Chitty's Store. Там встречаются экзотические штуки, которые в другие магазины доезжают с изрядным опозданием (если вообще доезжают). Но зато цены... По некоторым моделям я видел разницу в 1.5-2 раза.


Вот как-то так.

Если у кого-то возникнут вопросы, то задавайте в комментариях, постараюсь ответить.

Ссылок на разное не давал, т.к. эти самые ссылки имеют неприятное свойство "протухать" (т.е. устаревать). Если что-то интересует, то я дам в комментарии актуальную, на текущий момент, ссылку.

понедельник, 13 марта 2023 г.

[prog.c++] Кратко про свои впечатления от библиотеки WebSocket++

В текущем проекте потребовалось поработать с библиотекой WebSocket++, которая, как мне видится, является чуть ли не самой часто рекомендуемой библиотекой по работе с WebSocket-ами в C++.

Ряд моментов в дизайне WebSocket++ вызывают недоумение.

Например, в именах некоторых типов используется суффикс _ptr, но где-то это означает shared_ptr (acceptor_ptr), а где-то просто голый указатель (io_service_ptr).

Тип connection_ptr вроде как является shared_ptr-ом, но и вроде как пользоваться им напрямую можно только до тех пор, пока не будет вызван connect у endpoint-а. Потом можно оперировать исключительно connection_hdl. Но connection_hdl -- это weak_ptr, который нужно вручную трансформировать в connection_ptr, что захламляет код обработчиков. Могу предположить, что отдавать готовый connection_ptr в обработчики событий -- это создавать просадку производительности в тех редких случаях, когда обработчикам достаточно только connection_hdl. Но насколько это разумный баланс между производительностью и удобством использования -- это для меня открытый вопрос.

Не смог найти никаких идентификаторов для соединений. Подозреваю, что в качестве connection_id нужно использовать сам connection_hdl + std::owner_less. Но connection_hdl суть weak_ptr и, как мне кажется, в полный рост может встать ABA проблема.

Еще в WebSocket++ я не нашел никаких способов узнать было ли сообщение записано в соединение или еще нет. В принципе, без этого можно и обойтись, но когда есть нотификаторы о завершении записи в канал, то контролировать поток исходящих данных, имхо, проще.

Качество и количество примеров не впечатлило. Качество и количество документации впечатлило еще меньше :(

Но в исходниках разобраться можно, что и спасает. И хотя у нас в RESTinio шаблонных наворотов, может быть, еще побольше, но временами кажется, что разработчики WebSocket++ обобщенным программированием увлеклись ну очень уж сильно :)))

PS. RESTinio для задачи не подходит, т.к. у нас нет реализации клиента (да и вообще поддержка WebSocket только самая базовая, до более продвинутого варианта руки так и не дошли). Но познакомившись с WebSocket++ без ложности могу сказать, что RESTinio как продукт выглядит более чем достойно ;)

четверг, 9 марта 2023 г.

[prog.impressions] Любопытная статья про проблемы с unsafe Rust и отсутствием таковых в Zig

Со мной поделились ссылкой на статью When Zig is safer and faster than Rust. Показалась любопытной, хоть далек от Rust, и еще более далек от Zig.

В общем, решил поделиться и я :)

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


Больше всего меня впечатлил вот этот кусочек синтаксиса Zig-а:

const STACK_TOP = 256;
const VM = struct {
    // pointer to unknown number of items
    stack_top: [*]Value,
    // like a rust slice:
    // contains a [*]Value + length
    // has bounds checking too
    stack: []Value,
    // alternative to slices when
    // N is a comptime known constant
    stack_alt: *[STACK_TOP]Value
};

Как по мне, как это и умно, и хитро, и практично.

Глядя на этот фрагмент подумалось, что в C++ можно самостоятельно замутить что-то подобное. Например, класс raw_ptr<T>, который просто хранит указатель и позволяет получить его значение, но не допускает адресной арифметики. А также классы dynamic_span<T> и static_span<T, N>, которые описывают последовательность расположенных друг за другом объектов типа T. Для span-классов возможны операции итерации по содержимому, а также преобразования из static_span в dynamic_span. Соответственно, для доступа к элементу по индексу доступны и operator[], и метод at.

Хотя я бы отошел от принятого в STL соглашения о том, что operator[] не делает проверки в run-time, а at делает. И сделал бы так, чтобы operator[] осуществлял бы проверки в run-time. А для доступа без проверок использовался бы какой-то метод с некрасивым и бросающимся в глаза именем, вроде unsafe_get.

Более того, раз уж в C++ сообществе заговорили о том, чтобы превратить C++ в безопасный язык (не то, чтобы я верил в подобные перспективы, но раз пытаются, то зачем мешать?), то можно было бы пойти и дальше: сделать классы вроде raw_ptr, dynamic_span, static_span и т.п., частью языка. И таки ввести в язык что-то вроде "эпох", "поколений" или "ревизий". Чтобы начиная с какой-то "ревизии" нельзя было оперировать голыми указателями. Ну вот вообще. Только специальными классами. С автоматическим преобразованием raw_ptr в соответствующий указатель при обращении к C API, но только лишь в этом случае.

Эх, мечты, мечты :(


Еще одно впечатление связано с тем, что мне все еще непонятен хайп вокруг Rust-а.

Одно дело, если бы Rust позиционировался исключительно как околосистемный язык, полноценная замена и C, и C++, и Ada. Но, судя по описанным в упомянутой статье проблемам с unsafe Rust, это как бы не совсем так. По меньшей мере есть что улучшать в языке для того, чтобы на нем было удобно программировать в unsafe.

Однако же, изрядное количество шума вокруг Rust-а создавали (может и сейчас создают, просто уже не слежу) пользователи всяких там Ruby и Python-ов. Мол, раньше мы писали на динамически-типизированном языке и имели кучу разных проблем и с производительностью, и с сопровождаемостью... А как попробовали Rust, так волосы сразу стали гладкими и шелковистыми ;)

ИМХО, очень странно выглядят попытки применять Rust для высокоуровневого прикладного программирования.

По моему разумению (или заблуждению, тут уж и сам не понимаю) приходится так делать потому, что в нулевых годах слишком уж все увлеклись Java и C#, которые безопасные, но не нативные. Т.е. не производят ни Java, ни C# сразу нативный код. Вместо этого есть промежуточное представление, которое тем или иным образом транслируется в нативный код уже при исполнении программы.

И вот когда увлечение "write once, run everywhere" таки логично сошло до оправданного минимума, то оказалось, что удобного и безопасного нативного языка для прикладного программирования-то и нет.

Ну вот сходу вспоминаются разве что Eiffel (который старый, не модный, сильно платный и нифига не приспособленный для фигак-фигак-и-в-продакшен), Object Pascal в разных его проявлениях (который старый и незаслуженно нелюбимый массами из-за begin/end, хотя казалось бы какая нафиг...), да и не взлетевший D (он то может и взлетел, но низенько-низенько). Вот, собственно, и все, что можно вспомнить из середины-конца нулевых.

Раньше всех сориентировались в Google и сделали Go. Который как раз таки и простой, и безопасный, и нативный, и в меру быстрый. Но убогий :) Да и заточенный только под определенную нишу.

Вот и получается, что Ruby-истам и Python-истам, которых не устраивает скорость и надежность их кода на динамически-типизированных языках, переходить особо-то и не на что. Java и C# в пролете изначально, т.к. их сразу можно было использовать, но почему-то не использовали. Go может подойти, а может и нет. Таки убогость Go никуда не девается.

А тут Rust, нативный, быстрый, безопасный, да еще и модный, и молодежный. Bingo! :)))

Хотя, как по мне, будь какой-нибудь стабильный D1 с поддержкой от какой-то крупной корпорации (или их группы), то смотреть на Rust для прикладной разработки и не пришлось бы.

среда, 1 марта 2023 г.

[prog.c++] Продолжение экспериментов с шаблонами для улучшения tagged_value_t

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

Давеча удалось эту идею проверить. Результат мне понравился. ИМХО, так можно гораздо проще расширять функциональность шаблона tagged_value_t, чем в случае наследования от вспомогательных классов.

Получившееся решение показано под катом. Поиграться с ним можно на wandbox.

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