Читать в телеге. Когда-то там были посты не только от меня.
Local-first приложения
Мартин Клеппман (тот самый, который автор книги с кабанчиком) продвигает подход Local-first. Основная идея довольно простая: все действия должны по максимуму производиться локально на машине пользователя, а облако нужно использовать для синхронизации изменений. Когда программисты работают над кодом, им не нужно, чтобы постоянно было подключение к git-серверу, а если он взорвется, то можно будет поднять свой, и данные полностью под контролем. Так почему в каких-нибудь гугл-документах все не так?
Кроме того, с точки зрения архитектуры классический путь данных в приложении сейчас — это HTML-DOM → JS-фреймворк → REST → модель → сущность ORM → запись на диске, и большая часть кода — это конвертеры одного слоя в другой. В Local-First подходе предлагается оставить HTML-DOM → JS-фреймворк, оттуда писать в локальное хранилище, а всю синхронизацию вынести в фоновый режим. Сеть — ненадежный способ передачи данных, и в классических приложениях надо решать как технические проблемы, так и проблемы с UX. Для синхронизации данных можно использовать не привязанный ни к конкретной компании, ни к конкретным моделям данных фреймворк, основанный на CRDT (conflict-free replicated data type). Группа Клеппмана разрабатывает свой фреймворк для этого, Automerge.
Идея классная, технически интересная, и как пользователю мне она нравится, но увы, непонятно, кто готов будет за это платить. Тут, как минимум, две проблемы: единство протокола и бесконтрольность компании. С единым протоколом/форматом данных можно привести в качестве канонического примера миллиард мессенджеров, при этом плюс-минус единый стандарт — это XMPP (пользуетесь jabber’ом?), а еще и рабочий при этом — это email (которому уже больше 35 лет). А когда контроль над данными переходит от сервиса к пользователю, то автоматом всплывают проблемы с моделью продажи (это уже не SaaS, в котором можно сделать что угодно), тайной алгоритмов, стоимостью поддержки старых версий, аналитикой, обновлениями и т.п.. Кажется, что подобный подход к ПО пока могут позволить себе только энтузиасты от Open Source и единичные производители.
JMX в Kubernetes
JMX (Java Management Extensions) — технология, с помощью которой можно подключится к java-процессу через сокет и посмотреть использование ресурсов, снять дамп памяти или даже поменять какие-нибудь значения в памяти через управляемые ресурсы (MBeans). Есть два плюс-минус стандартных инструмента для этого: jconsole
и jvisualvm
.
Но сейчас нельзя просто так взять и подключиться к чему-то по сокету — все в кубере лежит. А поды еще и со сгенерированными айдишниками. Сначала надо получить id пода от желаемого сервиса:
POD=`kubectl -n $NAMESPACE get pods -l app=$APPNAME -o name`
флаг -l
фильтрует по метке пода, -o
— оставляет в выводе только имя.
Потом получаем случайный порт (можно заморочиться и проверить, что он свободен):
PORT=`echo $(( $RANDOM % (65550 - 15000) + 15000))`
# или
PORT=`shuf -i 15000-65550 -n 1`
Перенаправляем порт ($JMX_PORT
— номер порта, через который JMX выставлен локально в поде):
kubectl -n $NAMESPACE port-forward $POD $PORT:$JMX_PORT &
процесс запускается в фоне, и перенаправление будет работать только пока он запущен.
Наконец, запускаем jconsole
или jvisualvm
… и получаем облом из-за того, что удаленный порт-то не настоящий: нужно больше одного порта для подключения через RMI. Это можно вылечить работой через JMXMP-протокол, но нужно будет добавить его jar и в приложение, и в клиент. А после этого запустить так:
jvisualvm -cp:a jmxremote_optional.jar --openjmx "service:jmx:jmxmp://localhost:$PORT"
Или можно просто добавить в настройки приложения -Djava.rmi.server.hostname=127.0.0.1
и подключаться так:
jvisualvm --openjmx "localhost:$PORT"
PROFIT! Все это, разумеется, можно накидать в баш-скрипт, чтобы не запоминать, а указывать только namespace и имя сервиса.
Null в SQL
Сколько результатов вернет этот запрос?
SELECT * FROM ABS(null) as r WHERE (r >= 0) OR NOT (r >= 0)
Ответ
Правильный ответ — ни одного, потому что условие вернет ложь. А связано это с тем, что null
обрабатывается по особому, почти как NaN: почти любое выражение с ним возвращает null
: ABS(null)
— это null
, null >=0
и NOT null
— тоже. Можно сказать, что SQL реализует тернарную логику, где любое выражение может быть правдой, ложью или неизвестным. Поэтому стоит очень аккуратно писать запросы для nullable колонок, а еще лучше избегать их, если это возможно.
UPD:
Стоит дополнить, что вместо
WHERE (r IS NULL OR r != 'value')
можно использовать
WHERE r IS DISTINCT FROM 'value';
Когда нужно создавать корутины?
Интересный вопрос задали на форуме котлина: а как собственно стартовать корутины, если не рекомендуется использовать GlobalScope
и runBlocking
? TLDR: suspend fun main
или явные CoroutineScope
. А вообще в этом плане лучше читать статьи от Елизарова, он неплохо объясняет их нюансы (что неудивительно, с учетом того, что он сейчас лид разработчиков Kotlin).
Цвета организаций
Некоторое время назад была популярна тема деления организаций на “красные”, “янтарные”, “бирюзовые” и т.п., во многом благодаря книге 2014 года “Открывая организации будущего”. В ней консультант McKinsey Фредерик Лалу описал разные подходы к управлению компаниями, во многом опираясь на спиральную динамику (модель эволюционного развития людей) из 60-70-х, в которой уровни мышления разбиты на несколько уровней. Спиральная динамика, в свою очередь, во многом опирается на теорию циклического развития систем и теорию иерархических потребностей Маслоу (та самая пирамида, которой не было в оригинальной статье 1943 г.). В некоторых статьях это все еще щедро удобряется типами личности и прочей соционикой.
Как и многие теории человеческих отношений, все вышеперечисленные слабо выдерживают критику. В основном замечания сводятся к отсутствию нормальных экспериментов и статистических значимых данных, сильным упрощениям и направленности на бизнес — на этих темах неплохо зарабатывают всякие коучи и консультанты. Однако в мире поголовного скрама и самоуправляемых команд лучше быть знакомым с основными идеями, как с “мемами” менеджмента, чтобы уметь их использовать в своих целях.
Принцип наименьшего удивления
Как говорится, единственный нормальный способ измерения кода — это количество WTF в минуту.
В более мягкой форме — это принцип наименьшего удивления. Даже Википедия говорит, что принцип хоть и формализован в ИТ, но использовался и раньше, да и люди находят ему применение в оффлайне. Одно из следствий принципа — существование шаблонов проектирования (чтобы архитектура была “привычной”). Другое — самодокументируемый код. Еще одна инкарнация этого принципа — анекдот про плохие интерфейсы: “Пользовательский интерфейс — как анекдот. Если его надо объяснять, то он плохой”.
Суть принципа очень проста: код, дизайн, UI, тесты и т.п. должны быть логичны, последовательны, соответствовать общепринятым (среди пользователей/команды) практикам и вообще не удивлять негативно. Например, строит проектировать код так, чтобы нельзя было написать “неправильно” или “неочевидно”. Если текущие инструменты не позволяют это сделать — обеспечить преодоление порога вхождения в контекст обучением, документацией и т.п., чтобы было хотя бы понятно, “как принято” писать. Другой пример: покрытие тестами не должно вызывать по причине “WTF, все сломал, а тесты еще зеленые”. А постановка задачи не должна вызывать “WTF, кому и нафиг это надо”. Даже на процессы это можно натянуть: новый сотрудник не должен в первые дни WTF’ить: что делать, как это работает, к кому идти, почему это так, кто это вообще такую дичь придумал, у кого это спросить и т.п.
Сам себе схемотехник
Прикольная игруля, где можно самостоятельно собрать NAND-элемент (он же штрих Шеффера) из реле/транзисторов, потом другие логические элементы, сумматор, шифратор, АЛУ и т.д. вплоть до простейшего процессора.
Статус-код ответа graphql
Если почитать рандомные статьи (раз, два) про работу с GraphQL, то получается, что обработка ошибок как в REST — это “неправильный” подход к использованию GraphQL. Потому что, во-первых, GraphQL не привязан к транспортному протоколу, а во-вторых, спецификация явно определяет, что для ошибок есть специальное поле. Кроме того, один запрос может содержать несколько подзапросов, и не понятно, что делать, если один обработался успешно (как вариант, предлагают 207), а другой — нет. И вроде как надо возвращать 200, если запрос выполнился успешно, и 500 — в любом другом случае.
Однако, когда тебе на невалидный запрос возвращается 200 с пустыми данными, это выглядит, как минимум, странно. Если копнуть глубже, то выяснится, что в официальной документации про статус-код не говорится ничего. В 2018 в рабочей группе GraphQL поднимался этот вопрос, и потом еще в 2019 и 2020. Но четкого результата у этих обсуждений нет, только черновик.
Я в итоге на текущем проекте решил группировать по убыванию. Если нет ошибок — 200, хотя бы один 5xx код — это 500, несколько 4xx = 400, один 4xx — его и вернуть, в любой непонятной ситуации — 500.
Почему формальные методы редко используются
Интересная статья про доказательство корректности программ, точнее, почему оно редко применяется на практике. TLDR:
- Чтобы что-то доказать, нужны четкие требования и спецификация. Их получить довольно тяжело, если вообще возможно.
- Надо понимать, что хотим получить от верификации. В бизнесе всем насрать, правильно ли у тебя сортировка работает, если клиенты не приносят бабки.
- Надо формализовать хотелки. Человеческие понятия тяжело формализовать. Кстати, эта же проблема — причина многих проблем с безопасностью ИИ.
- Доказывать что то формально — тяжело. Например, доказать ассоциативность сложения — либо дорого, либо опасно (например, в C++ сложение не ассоциативно в районе INT_MAX).
- Чем язык богаче фичами, тем тяжелее в нем доказать что-то.
- В повседневной работе хороших тестов и документации достаточно для приемлемо хорошего качества. Каждый следующий “процент качества” обычно кратно дороже предыдущего.
- Многие проблемы лежат на уровне проектирования. Но в него почти никто не вкладывается, потому что мало кто понимает его ценность. Большой вклад вносит культурный барьер.
Ревью пулл-реквестов
Более-менее серьезные пулл-реквесты довольно неудобно смотреть в самом GitHub. Даже переключение diff на две колонки (split-view) не очень помогает: например, лично мне не хватало дерева файлов. Делать ревью через Intellij стало уныло с обновлением интерфейса — там есть просто позорные баги.
Но можно на странице PR нажать обычную точку ., и будет загружена веб-версия VS Сode, в которой делать ревью приятнее. Причем можно ставить плагины (хоть и не все работают полноценно).