• Стереокартинки

    В детстве я любил стереокартинки. У меня был альбом с ними, и я их подолгу рассматривал. Мне казалось это магией: на плоской бумаге возникала 3D-сцена, и это было невероятно. Были картинки, где текстура удачно совпадала с моделью, и от этого становилось еще круче.

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

    Оказалось, в семье никто кроме меня этого не умеет. Пытаюсь научить жену и старших детей, но не получается (UPD: получилось). Младшая, которой три с половиной, посмотрела на карточку и сказала: папа, что ты тут намазал?

    Завтра попробую другой подход. А вам вопрос: любите стереокартинки? Умеете их смотреть?

  • Правильное ООП

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

    То же самое я чувствую, когда говорящая голова ездит по городам с лекцией о “правильном” ООП. Тут можно сказать одно: современное программирование настолько широко и сложно, что искать в нем “правильное” ООП — то же самое, что искать “правильное” изложение “Колобка” или “Курочки Рябы”. Все версии правильные — бери по вкусу.

    Этот тезис закрывает любую лекцию по ООП.

  • Форматирование строк

    Шел 2025 год, а в Питоне делают очередное форматирование строк. На этот раз оно называется t-строки из-за префикса t. Такие строки по-настоящему всемогущи: могут делать любые преобразования, ходить по модулям, вызывать такси и заказывать пиццу. Без шуток, найдется тот, кто напишет на них интерпретатор Питона.

    Может показаться странным, но именно из-за подобных штучек я завязал с Питоном. Я любил его где-то до версии 2.7, ну и немного третью. Переход на тройку был тяжелым, но необходимым, и это можно было стерпеть. А потом начались бесконечные улучшения: новые операторы, синтаксический сахар на каждый чих, f-строки, t-строки и так далее.

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

    Особенно меня коробит форматирование строк. Напомню, что в Питоне, наверное, десять способов форматировать строки, и число вариантов все растет. Есть процент с кортежем, есть метод .format, есть f-строки, string.Template, сейчас готовят t-строки. Это только стандартная библиотека, а еще полно сторонних пакетов.

    Крафтить подобные вещи интересно, я не спорю. Но почему не нашлось никого, кто бы сказал: братцы, мы делаем херню. Плодим одно и то же, засоряем стандартную библиотеку. Неужели, имея с десяток способов сделать X, нужно писать еще один? Где был это человек? Или их выгнали?

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

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

    Бесконтрольное развитие языка — тоже плохо. Это трудно заметить в моменте, потому что эффект проявляет себя десятилетиями. Но нужно держать его в голове.

  • Видео с митапа о Postgres и JSON

    Подъехала запись, очень оперативно, как раз на выходные. Сначала болтология минут на 30, потом техническая демка тоже на 30 минут. Потом вопросы. В сумме почти два часа.

  • Разрешения

    Обновил яблочную операционку, и началось: слетели все разрешения. Каждое приложение при запуске кукарекает: можно ли сканить локальную сеть? Можно ли смотреть файлы в Downloads? Воткнул флешку — можно ли подключить Kingston Datatraveler 8Gb? Воткнул микрофон — можно ли подключить микрофон?

    Причем это было минорное обновление (последняя правая цифра).

    Увы, в 2025 году обновления по-прежнему ломают то, что работало до них. Что у Микрософта, что у Гугла, что у Эпла. Все одинаково хороши. Или это нарочно?

  • Большой запрос

    Последние дни я безвылазно сижу в PGAdmin: пишу запрос, чтобы построить важный репорт. В нем уже 470 строк плюс понадобились пять функций для разных преобразований (например денег, округления дат). Итого 550 строк чистого скуля.

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

    Со временем понимаешь следующий момент. В SQL любое значение — это таблица, а операторы — различные JOIN-ы: левое, правое, внутреннее или декартово произведение. Как только пришел к этому, мышление поворачивается под другим углом.

    Скажем, вот список мап в Кложе:

    [{:id 1 :name "Ivan"}
     {:id 2 :name "Huan"}
     {:id 3 :name "Juan"}]
    

    То же самое в SQL:

    id name
     1 Ivan
     2 Huan
     3 Juan
    

    Любая операция над этим списком сводится либо к фильтрации, либо джоину, либо агрегатной функции. Скажем, фильтрация по ID это обычный where:

    select * from users where id > 2
    

    То же самое, что написать:

    (filter #(> % 2) users)
    

    Предположим, есть список мап вида “пользователь -> аватар”. В SQL его легко выразить таблицей:

    user_id    photo_url
          1    https://test.com/avatar.jpg
          3    https://test.com/cat.jpg
    

    А вот их различные объединения: с сохранением левой части (пользователи без аватары останутся):

    select users.*, p.photo_url
    from users u
    left join photos p on p.user_id = u.id
    
    id name   photo_url
     1 Ivan   https://test.com/avatar.jpg
     2 Huan
     3 Juan   https://test.com/cat.jpg
    

    и без:

    select users.*, p.photo_url
    from users u
    join photos p on p.user_id = u.id
    
    id name   photo_url
     1 Ivan   https://test.com/avatar.jpg
     3 Juan   https://test.com/cat.jpg
    

    В общих словах, любой SQL-оператор сводится к джоину. Скажем, новички часто передают список айдишников с оператором IN:

    where id in (1, 2, 3, ...999)
    

    И не знают, что гораздо эффективнее выразить то же самое джоином и таблицей с полем id:

    select * from users u
    join user_ids on u.id = user_ids.id
    

    В SQL даже одно значение является таблицей. Переменная x=42 — это таблица с колонкой X и кортежем (42, ). Примерно как в Матлабе все является матрицей.

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

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

  • Возможности JSON_TABLE

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

    Предположим, есть пользователи, они совершают заказы. Каждый заказ состоит из позиций. У позиции есть стоимость и код валюты. Одна позиция может быть в евро, вторая в долларах и так далее.

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

    Вот что получается на практике. Вы идете в микросервис А и получаете джейсончик как на первой картинке:

    Потом идете в микросервис В, чтобы получить курсы валют:

    Из этих данных вам предстоит слепить конфету. Имейте в виду, что на картинах — лишь малые подмножества данных. В реальности и полей, и вложенных сущностей больше.

    Первая беда в том, что данные вложены, и с ними нельзя нормально работать. Я уже сто раз писал об этом: когда у вас мапа с вектором мап с вектором мап с вектором мап, ни о каком удобстве не может быть и речи. Код, который обходит такое дерево, поддерживать невозможно, неважно Питон это или Кложа. В первом случае это будет императивный быдлокод, во втором — функциональный. Это когда код — цепочка из десяти вызовов map/mapcat/reduce/group-by.

    В Кложе есть макрос for для декартовых произведений, но для каждого дерева нужно писать свою логику. Универсальный вариант я пока не придумал.

    Вот как сделать то же самое в SQL. Загоняем оба джейсона в базу. Теперь плющим первый функцией JSON_TABLE:

    Получаем таблицу users. Все плоско и декларативно. Обратите внимание на суррогатные поля order_i и pos_i — номера мап в массивах. Это значит, если я захочу свернуть таблицу обратно в дерево, не будет никаких проблем.

    Теперь плющу курсы валют:

    Потом присоединяю слева к юзерам курсы валют по их названиям. Это значит, каждая позиция получит коэфициент ее валюты:

    И последний шаг: считаю сумму price_eur с группировкой по пользователю и заказу.

    Готово. Самое важное: все декларативно и без циклов, без присваиваний и аккумуляции списков. Среда, что выполняет этот код, написана на чистом Си и многократно протестирована. Что еще нужно?

    Все это можно уместить в один запрос, но я специально расписал по шагам.

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

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

  • Покупка нот

    Часто ищу маме ноты. И порой думаю: хватит шариться по ВК-помойкам, куплю за деньги как белый человек. Открывается форма заказа. Смотрю на нее минуту и опять иду на помойку. С такой формой я ничего не куплю. Интересно, нашелся ли отважный, кто прошел эту форму и купил? Сомневаюсь.

  • Онлайн-книги по программированию

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

    Онлайн-книги по программированию

    На сайте собраны учебники по разным языкам программирования. На главной странице примерно 60 языков, в каждом от 20 до 50 уроков. В числе прочего есть Кложа, Хаскель, F# и прочая экзотика.

    Сайт интересен следующим: на мой взгляд, он полностью сделан на AI-утилитах. Думаю так, потому что:

    • сайт максимально обезличен. Никаких контактов, имен, адресов, только почта. В блоге не упоминаются авторы уроков; есть только абстрактные “мы”: мы обновили сайт, мы добавили уроки и прочее.

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

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

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

    Ради интереса я походил по сайту, почитал уроки по языкам, которые хорошо знаю. Очень похоже на правду, но местами есть неточности. Например, в одном уроке по Кложе написано, что поток создается функцией (Thread.). Все бы хорошо, но такой функции нет: эта форма — инициация класса Thread, краткий вариант записи (new Thread ...). Ну и местами похожие огрехи.

    При этом я нисколько не умаляю заслуг создателя сайта. Из метаданных домена видно, что это некий Дмитрий из Казахстана. Полагаю, каждый день он генерит урок за уроком и выкладывает на сайт, а заодно занимается продвижением. Структуру уроков, скорее всего, подглядывает у Хекслета или в других онлайн-школах.

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

    Тем, кому не нужны конспекты, все равно советую сходить на сайт: посмотреть как выглядит нейро-контент. Так сказать, подучить свою сеть для выявления таких случаев. Ну и Дмитрию из Казахстана капнет денежка за рекламу.

  • Выпадашки в Телеграме

    А вот прикол с выпадашками в мобильном Телеграме. Если открыть диалог в режиме просмотра, то он будет в выпадающем окне. Точнее, их будет два: диалог и контекстное меню. Если долбить кнопку Block User, то Телеграм выкинет бесконечное число попапов с затемняющим слоем. При этом диалог и затеняшка будут ПОД выпадашкой с диалогом.

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

    Лет 7 назад я делал мобильное приложение на гремучей смеси технологий: Кложа, React.Native и Objective-C для доступа к нативным штучкам. В том числе я делал интерфейс. И быстро понял: если лепить на каждый чих выпадашку, рано или поздно проиграешь. Легко сделать так, что человек ушел на другой экран, а выпадашка осталась. Либо ты не закрыл ее, и чел наспамил их триста штук.

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

Страница 1 из 95