Все записи с тэгом dev

Нельзя просто взять и сгенерировать тему

·

В рамках работы над open-source проектом работал над задачкой по генерации тем. То есть в проекте было несколько тем: одни темы имели светлый и темный режим, другие - только светлый или только темный. И задача сводилась к тому, чтобы сделать для всех тем светлый и темный режим.

20260429_090506_ae78eb.webp

Вот на скриншоте показаны несколько темных тем: Dracula, Solarized, Gruvbox, Monokai, Moonlight. В теории можно взять и инвертировать светлоту, получив тем самым светлую тему. В теории теория и практика не отличаются. На практике всё совсем наоборот 😀. Чтобы объяснить почему, полезно сначала посмотреть на то, как устроена работа с цветом в принципе.

В 2011 году Этан Шунуовер опубликовал Solarized — палитру из шестнадцати цветов для терминалов и редакторов. Она стала популярной потому что в основе проектирования цвета была конкретная методология.

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

Ключевое свойство Solarized в том, что монотонные цвета имеют симметричные разницы светлоты в CIELAB, поэтому переключение между тёмным и светлым режимами сохраняет одинаковую воспринимаемую контрастность между каждым значением. Это достигается точным зеркалированием Lab-координат: base03 и base3 симметричны относительно средней точки шкалы, как и все остальные пары.

Solarized снижает контраст яркости, но, в отличие от многих низкоконтрастных схем, сохраняет контрастирующие оттенки для читаемости синтаксической подсветки. Это важно, потому что необходимо уменьшить «слепящий» эффект белого на чёрном, не потеряв при этом различимость элементов.

Именно поэтому я считаю, что Solarized — очень хороший пример темы, хотя и сам ей не пользуюсь. В схему вложена хорошая идея и такая же хорошая реализация — оба режима (темный и светлый) должны восприниматься как части единой системы.

Разные цветовые модели

Когда мы говорим о цвете, мы часто думаем о HEX или HSL. HEX — это просто RGB в другой записи, а HSL хоть и интуитивен, но математически нечестен. Два цвета с одинаковым L в HSL воспринимаются глазом совершенно по-разному. Зелёный при hsl(120 100% 50%) — ослепительно яркий, синий при hsl(240 100% 50%) — значительно темнее, хотя формально у них одна «светлота».

Шунуовер работал в CIELAB именно потому, что это пространство перцептивно равномерное: одинаковое числовое расстояние между точками соответствует одинаковому воспринимаемому различию для глаза. Отсюда и возможность строить симметрию: если base03 имеет L=15, а base3 имеет L=97, то их среднее — L=56, и вся палитра строится как зеркало вокруг этой оси.

Современные системы дизайна, переходят на OKLCH. Это улучшенная версия того же принципа. В нём L (lightness) означает одно и то же для любого оттенка. Поэтому цвета с L = 0.55 воспринимаются одинаково яркими. Это позволяет строить палитры более системно, а не на глаз.
В нашем случае темы хранятся именно в OKLCH, а в браузере они рендерятся как lab().

Проблема контраста

Solarized решал контраст вручную, через Lab-симметрию. В нашем же случае мы не можем всё выверять вручную. В текущей реализации есть лишь автоматическая генерации и нет симметрии. У нас есть только числа, которые нужно проверять.

Для проверки контрастности можно использовать относительную яркость (relative luminance). Она используется в WCAG. Но яркость относительна, поэтому мы не можем полагаться на нее полностью как на L в OKLCH. Синие и фиолетовые цвета при L ≈ 0.55 дают относительную яркость около 0.22–0.25, что обеспечивает контраст ~5:1 с белым текстом. Этого достаточно, для того, чтобы комфортно читать текст. Но жёлтый и оранжевый при той же OKLCH-светлоте имеют яркость 0.35–0.45, и контраст с белым падает до 2.5–3:1. А такого контраста уже недостаточно для читаемости.

Первая попытка генерации светлых тем для Gruvbox и Monokai дала золотистый primary с тёмным текстом поверх него. Визуально это выглядело плохо. У меня не сохранилось скриншотов, поверьте на слово, было так себе. Поэтому для последующей генерации я решил для тёплых хроматических primary-color (жёлтый, оранжевый, золотой) нужно опускать L до 0.45–0.50 и использовать белый foreground-color. Для холодных (синий, фиолетовый) можно оставлять L ≈ 0.50–0.58. Это нельзя вычислить автоматически без анализа конкретного цвета.

Проблема сохранения визуальной идентичности

Любая тема, которую мы генерируем в дополнение к уже существующей должна удовлетворять как минимум двум условиям:
— иметь правильный контраст
— быть узнаваемой

Solarized — это крайний случай. Тут идентичность задокументирована точными Lab-значениями. Но есть темы, у которых нет такой хорошей документации.

Например, Dracula узнаваемы по пурпурно-розовому оттенку из #bd93f9. Но этот цвет воспроизводится по-разному в разных редакторах. Более того, для многих тем существуют еще и различные вариации, то есть нет только темной или светлой темы. Есть наборы из нескольких темных и нескольких светлых вариантов.

Первая автоматически сгенерированная версия Dracula использовала --primary: oklch(0.550 0.178 295°). Цвет синевато-фиолетовый, контраст с белым нормальный. Вроде технически верно. Но полученный оттенок был скорее пурпурно-розовый. При 295° тема начинает напоминать Moonlight. В результате смещение на 10 градусов по оттенку разрушало идентичность.

Инвертированная логика акцентов

В качестве компонентов в проекте используются shadcn. Одна из неочевидных конвенций shadcn это то, как работает accent в светлых и тёмных темах. В тёмной теме accent — это насыщенный цвет. Он используется для подсветки активных элементов. В светлой теме accent — это очень бледная, почти белая поверхность для hover-состояний, а accent-foreground — тёмный текст поверх неё. При автоматической генерации мы копируем тёмные значения accent в светлые варианты. В результате получаются элементы с насыщенным фоном и светлым текстом. Все это можно описать некрасивым эмодзи, но не буду этого делать 😁.

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

Результат работы можно посмотреть ниже или открыть пулл реквест и исследовать код. Конечно, некоторые моменты еще можно докрутить и улучшить. Хотя у меня и нет года, как у Шунуовера, я считаю, что результат получился вполне достойным.

20260429_094839_58ea6a.webp
Solarized Light

20260429_094846_02ec2b.webp
Solarized Dark

20260429_094839_cafb2d.webp
Dracula Light

20260429_094846_7ee90c.webp
Dracula Dark

20260429_094846_424701.webp
Bubblegum Light

20260429_094839_34dd69.webp
Bubblegum Dark

Про подключение Garmin MCP к Claude Code и забег в Бечее

·

На днях с подачи приятеля подключил Garmin MCP к Claude Code. Опыт интересный. В первую очередь, потому что все эти данные мне и так известны и доступны в виде сухой статистики в Garmin Connect. Хотелось попробовать новый опыт взаимодействия.

20260328_202912_0a7bbc.webp

Вот что Claude делает очень хорошо, так это строит графики и выполняет рутинные задачи. Ну а еще льстит, конечно. Для эксперимента я попросил построить прогноз на сегодняшний забег. Я долго сомневался бежать 5км или 10км. По итогу бежал 10, потому что слоты на 5 просто закончились :)

Вот с такими данными я пришел к Claude и планировал бежать 28-го марта 10км.

20260328_203523_5c64f5.webp

Прогноз Garmin: 48:56. Реалистичная цель: 48–50 мин. Оптимистичная (при хорошем самочувствии): 47:30.

... Сказал Claude и дал раскладку на гонку:
— Км 1–2: 5:05–5:10 Разгон
— Км 3–8: 4:50–4:55 Основной блок
— Км 9–10: 4:35–4:45 Финишное ускорение

Тут я посмеялся. Уверен, что мой тренер, читающий этот пост тоже посмеялся, зная меня. Для тех кто не знает, скажу: никакого финишного ускорения у меня быть не может. Я так не делаю. У меня или всё ровно, или финишное замедление :D Хотя последнее я стараюсь избегать. И вот, чтобы его избегать и не сбрасывать, мне очень важно бежать всю дистанцию ровно.

"Любой каприз за ваши токены". Claude скорректировал раскладку после уточнения.

20260328_204152_1de959.webp

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

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

20260328_204823_e7cc57.webp

20260328_210604_33ee8e.webp

Зачем вообще всё это? Использование ИИ сейчас повсеместно. Но надо быть очень аккуратными с тем, что мы получаем в результате его использования. Чтобы прогнозы были точными, любую модель нужно обучать, запросы должны быть точнее, ограничения в рамках которых модель мыслит должны быть жестче. Иначе результат будет далек от истины.

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

Ниже опишу кратко шаги, необходимые для подключения Garmin MCP к Claude Code.


Требования

  • macOS / Linux
  • Python 3.10+
  • uv — менеджер пакетов Python
  • Аккаунт Garmin Connect

Шаг 1 — Установка uv

curl -LsSf https://astral.sh/uv/install.sh | sh

Проверка:
bash
uv --version


Шаг 2 — Клонирование репозитория

git clone https://github.com/Taxuspt/garmin_mcp ~/dev/garmin
cd ~/dev/garmin
uv sync

Шаг 3 — Аутентификация в Garmin Connect

Токены сохраняются в ~/.garminconnect и используются повторно — пароль вводится только один раз.

cd ~/dev/garmin
GARMIN_EMAIL=your@email.com GARMIN_PASSWORD=your_password uv run garmin-mcp-auth

Если включена MFA — нужно ввести код при запросе.

Проверка токенов:
bash
uv run garmin-mcp-auth --verify

Принудительная повторная аутентификация (если токены устарели):
bash
uv run garmin-mcp-auth --force-reauth

Токены действительны ~6 месяцев.


Шаг 4 — Подключение к Claude Code

Добавить MCP-сервер глобально (для всех проектов):

claude mcp add -s user garmin -- /path/to/uv --directory ~/dev/garmin run garmin-mcp

Узнать полный путь к uv:
bash
which uv

Например: /Users/denis/.local/bin/uv

Итоговая команда:
bash
claude mcp add -s user garmin -- /Users/denis/.local/bin/uv --directory /Users/denis/dev/garmin run garmin-mcp

Проверь подключение:
bash
claude mcp list

В случае успеха, должны увидеть что-то вроде garmin: ... - ✓ Connected

После этого MCP доступен в любом проекте без дополнительных настроек.


Шаг 5 — Подключение к Claude Desktop

Нужно открыть файл конфигурации:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Добавить секцию mcpServers:

{
"mcpServers": {
"garmin": {
"command": "/Users/denis/.local/bin/uv",
"args": [
"--directory",
"/Users/denis/dev/garmin",
"run",
"garmin-mcp"
]
}
}
}

Важно заменить /Users/denis на свой домашний каталог. Полный путь к uv важен — Claude Desktop не использует PATH из терминала.

Перезапустить Claude Desktop. В интерфейсе появится иконка с подключённым сервером garmin.


Использование

Тут все конечно зависит от фантазии. Можно начать с простого:

Покажи мою сегодняшнюю активность
Проанализируй мою последнюю пробежку
Сколько шагов я сделал вчера?
Какой у меня был сон на этой неделе?
Сравни тренировки за последние 7 дней

Доступно 96+ инструментов: активности, шаги, сон, пульс, стресс, вес, тренировки, устройства и др.


Обновление токенов

Токены Garmin истекают примерно раз в полгода. При ошибке подключения:

cd ~/dev/garmin
GARMIN_EMAIL=your@email.com GARMIN_PASSWORD=your_password uv run garmin-mcp-auth --force-reauth

Решение проблем

Failed to connect в claude mcp list. Токены не найдены или истекли — повтори Шаг 3.

429 Too Many Requests при аутентификации. Garmin временно заблокировал IP. Надо подождать 15–30 минут и попробуй снова.

Claude Desktop не видит MCP. Нужно убедиться, что в claude_desktop_config.json указан полный путь к uv (не просто uv). Проверь: which uv.

Логи Claude Desktop

  • macOS: ~/Library/Logs/Claude/mcp-server-garmin.log
  • Windows: %APPDATA%\Claude\logs\mcp-server-garmin.log

PS: Еще экспериментировал дополнительно с локальными моделями Ollama + qwen + openapi с гарминовскими ендпоинтами. Но в базовом варианте, это решение выглядит абсолютно нерабочим, если вы хотите просто общаться с ИИ через чат, не тратя время на настройку модели.

TrueNorth для ясности в делах

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

20260118_132929_a4d078.webp
TrueNorth Dashboard

О чем вообще речь?

Это инструмент для таких же, как я — фрилансеров, контракторов, тех, кто работает над разными проектами и любит осознанно подходить к своей работе.

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

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

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

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

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

Ну так вот, в череде дел очень сложно держать фокус на разных проектах. Кажется, что вот делаешь что-то, и дела вроде двигаются вперёд, но понять ценность нельзя. Опишу пару примеров.

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

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

Учтённое время можно конвертировать в деньги — заработанные или незаработанные. Можно прикинуть ценность дел, проектов, затраченных сил и времени. За всю свою жизнь я успел поработать во множестве проектов. И очень часто мне приходилось считать своё время и выставлять счета на основе фактических трудозатрат. Я пробовал разные инструменты. Был Toggl, Harvest, ещё что-то, о чём успел забыть. Но в результате я перенёс опыт использования этих инструментов на собственное решение, которое воплотилось в TrueNorth.

Для чего этот сервис? Чтобы осознанно подходить к ведению своих проектов. С помощью учёта времени вы можете видеть объём вложенных усилий. С помощью отслеживания расходов вы можете видеть ценность своей деятельности.

Следуя идее «делайте продукт, которым будете пользоваться сами», я разработал решение для себя. Насколько оно подходит остальным — покажет время. Именно поэтому я пишу, предлагая вам попробовать и дать обратную связь. Пока всё бесплатно, но с регистрацией.

Что даёт система? Она позволит вам видеть затраченное время на работу, которой вы занимаетесь. Если вы работаете над несколькими проектами, вы увидите, где и откуда приходит больше денег, а где вы, наоборот, теряете. А ещё это простой способ увидеть, сколько времени вы действительно занимаетесь какой-то деятельностью. Сделает ли этот сервис вас продуктивнее? Однозначно нет. Ни один сервис не сделает вас продуктивным, пока вы сами этого не захотите. Но TrueNorth может показать вам те реальные цифры, которые побудят вас к размышлениям.

В общем, попробовать стоит. Возможно, статистика сделает вам больно. Но также возможно, что это поможет вам осознать те пробелы, которые вы можете закрыть. В этом и заключается осознанность, правда?

Как найти удобное время для встречи, когда команда разбросана по миру

·

Недавно добавил на Syn-co.me новую функцию — поиск удобного времени для встреч. Если вы уже пользовались сайтом, то знаете: он показывает время всей команды на одном таймлайне. Просто добавляете участников с их часовыми поясами, и сразу видно, кто работает, кто спит, кто только проснулся.

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

20251016_075043_f3deed.webp

Проблема

Представьте: ваш коллега в Токио, партнер в Нью-Йорке, а вы в Москве. Когда в Москве 14:00 (отличное время для звонка), в Нью-Йорке 6 утра (кто-то еще спит), а в Токио уже 20:00 — конец рабочего дня.

Можно, конечно, открыть мировые часы и начать перебирать: "А если в 10 утра по Москве? Нет, подождите, тогда в Токио будет..." Через пять минут такой арифметики голова идет кругом.

Как это работает

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

Оптимальное время — середина рабочего дня, примерно с 10 до 16 часов. Люди уже проснулись, выпили кофе, разобрали почту. Максимальная продуктивность.

Хорошее время — начало или конец рабочего дня. С 9 до 10 утра или с 16 до 17 вечера. Можно созвониться, но кто-то может быть не в лучшей форме.

Приемлемое время — чуть за границами обычного расписания. Например, 8:30 утра или задержаться до 18:00. Неудобно, но терпимо.

Некомфортное время — приходится серьезно менять планы. Встать пораньше в 7 утра или остаться после работы до 19:00. Такие встречи лучше избегать, но иногда выбора нет.

Алгоритм выбирает варианты, где всем хотя бы приемлемо, и сортирует их от лучших к худшим.

20251016_075109_ecec26.webp

Что делает время действительно удобным

Тут начинается самое интересное. Я бы выделил три столпа на которых основана логика алгоритма.

Справедливость важнее общего удобства. Лучше, когда всем "хорошо", чем когда двоим "отлично", а одному "ужасно". Поэтому алгоритм в первую очередь смотрит на того, кому хуже всего. Если есть вариант, где минимальный комфорт выше — он побеждает.

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

Избегаем экстремальных часов. Никто не хочет созваниваться в 5 утра или в 11 вечера. Такие варианты получают серьезный штраф. Также учитывается обеденное время — встреча с 12 до 13 нравится немногим.

Гибкость как параметр

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

Поэтому в инструменте есть параметр гибкости — от 0 до 12 часов. С нулевой гибкостью алгоритм ищет только время в пределах рабочих часов. С гибкостью в 3-4 часа появляются варианты, где кто-то начинает чуть раньше или задерживается. Чем выше гибкость, тем больше вариантов, но тем менее комфортными они становятся.

Когда компромиссы неизбежны

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

Для Москвы, Нью-Йорка и Токио практически невозможно найти время, когда всем комфортно. Разница часовых поясов слишком велика. В таких случаях алгоритм предлагает несколько вариантов с разными компромиссами.

Может быть, один раз неудобно будет Токио, в следующий раз — Нью-Йорку. Справедливость можно обеспечить не за одну встречу, а в серии созвонов.

Про Syn-co.me

20251016_075151_e87e85.webp

Инструмент работает прямо в браузере. Никаких регистраций, никаких серверов, никакого сбора данных. Вся информация о команде кодируется в URL — можете сохранить в закладки или отправить коллегам.

Изначально Syn-co.me создавался как простой таймлайн часовых поясов команды. "Stop doing timezone math in your head" — главная идея. Поиск времени встреч — логичное продолжение: показывать не просто "когда все свободны", а "когда всем будет действительно удобно".

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

Подборка ссылок #06

·

Статья «Rails for Everything» на Literally The Void отстаивает универсальность Ruby on Rails для разработки различных типов проектов, опровергая стереотип о его ограниченной применимости и подчеркивая преимущества использования полного стека Rails вместо разделения на микросервисы, в то время как комментарии на Reddit отражают разнообразие мнений разработчиков об актуальности фреймворка в 2025 году, его производительности и сравнении с современными альтернативами.

Petr.codes в «Flexible API versioning with Rails» предлагает гибкий подход к версионированию API в Ruby on Rails, рассматривая проблемы традиционных методов и демонстрируя эффективную архитектуру с использованием наследования и модулей в контроллерах, что позволяет разработчикам легко управлять изменениями между версиями API без дублирования кода.

Статья Мартейна Холса «The European Accessibility Act for websites and apps» разъясняет требования Европейского акта о доступности для цифровых продуктов, описывая сроки внедрения, технические стандарты и необходимые меры соответствия, которые должны предпринять разработчики и владельцы бизнеса для обеспечения доступности своих веб-сайтов и приложений в соответствии с законодательством ЕС.

Марк Мэнсон в статье «Why You Should Quit the News» утверждает, что следует отказаться от регулярного потребления новостей, поскольку они вызывают стресс, фокусируются на негативе и отнимают время, которое можно потратить на более ценные занятия, при этом большинство новостных материалов не имеют практического влияния на нашу повседневную жизнь.

Статистика от Stackoverflow по использованию технологий за 2024 год

Алекс Рассел в своей статье «If Not React, Then What?» критикует React за создание избыточного уровня абстракции над веб-платформой, что приводит к проблемам с производительностью и большим JavaScript-пакетам, и предлагает Web Components как более эффективную альтернативу, которая работает в гармонии с нативными возможностями браузера и следует принципам прогрессивного улучшения.

Ахмад Шадид выпустил гайд о новых CSS свойствах — «Relative Colors».

Как настроить WezTerm для удобной работы над проектами

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

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

Я когда-то пробовал разбираться с tmux, но бросил. Было непонятно, и не очень надо. Сейчас использую WezTerm. Это современный кроссплатформенный терминальный эмулятор и мультиплексер. До этого работал с iTerm2, Wrap.dev, Kitty. Пробовал даже Alacrity. Но прижился WezTerm. Он довольно производительный (не самый-самый), но норм. Написан на Rust. Поддерживает GPU-ускорение рендеринга. Имеет встроенную поддержку шрифтов с лигатурами и поддерживает конфигурацию на Lua. В общем, он стоит того, чтобы его попробовать.

Для работы над проектом я обычно две вкладки. Одна содержит 3-4 панели, в каждой из которых запускаются
— Redis-сервер
— Rails-сервер
— Сборка фронта
Еще одна вкладка в редакторе с Neovim для работы с кодом.

В результате экспериментов, я пришел вот к такой конфигурации. Это ссылка на gist, чтобы не копировать все 200 строк кода в пост.

Сам файл .wezterm.lua лежит в корневой директории пользователя. В общем, ничего не обычного. Базовая конфигурация WezTerm выглядит так. Остальное в gist — пример настройки панелей.

local wezterm = require("wezterm")
local config = wezterm.config_builder()
-- Настройки шрифта и интерфейса
config.font_size = 13.0
config.font = wezterm.font("JetBrains Mono", { weight = "Bold" })
config.color_scheme = "Tokyo Night Storm"
config.line_height = 1.05
config.use_dead_keys = false
-- Настройки окна
config.window_padding = {
left = 5,
right = 5,
top = 5,
bottom = 5,
}
config.initial_cols = 120
config.initial_rows = 36
return config

Про технический долг

·

Представьте, что вы строите дом. Можно быстро построить его из доступных материалов, игнорируя некоторые строительные нормы, чтобы скорее въехать. Или можно делать всё по правилам, но это займёт больше времени. В первом случае вы "берёте в долг" – экономите время сейчас, но потом придётся исправлять недочёты, причём обычно с гораздо большими затратами.

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

За 19 лет работы с различными проектами я выделил три верных признака того, что технический долг начинает тормозить бизнес:

Во-первых, разработка новых функций постоянно замедляется. То, что раньше занимало пару недель, растягивается на месяц или больше. Разработчики боятся трогать старый код, опасаясь сломать существующий функционал. А некоторые части системы становятся "священными" – к ним вообще никто не хочет прикасаться.

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

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

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

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

Я бы предложил начать с простого — с простых вопросов команде: сколько времени занимает добавление типовой фичи? Насколько уверенно вы чувствуете себя при внесении изменений? Какие части системы вызывают больше всего проблем?

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

Работа с техническим долгом – это не разовая акция, а постоянный процесс. Я рекомендую начать с трёх шагов:

Первое – выделите ресурсы на технические улучшения. Классическое правило: 20% времени команды должно уходить на технический долг. Да, это может казаться дорого, но альтернатива обойдётся дороже.

Второе – внедрите культуру качества. Каждый новый код должен быть лучше старого. Код ревью, автоматические тесты, современные инструменты разработки должны стать стандартом, а не роскошью.

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

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

Переход на Neovim: как изменить мышление и полюбить композицию команд

·

Последние пару недель нет времени ни писать, ни бегать. Сначала боролся с соплями, потом со знаниями. Из интересного, почти отказался от VS Code и перешёл в VIM. Тут надо сразу оговориться, я пишу vim, но подразумеваю nvim. То есть в том контексте, о котором я пишу разницы нет.

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

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

Вообще я долго пытался понять что неудобно в vim и почему он для меня не работает. И в какой-то момент пришла мысль о том, что я пытаюсь использовать его как использую все остальные GUI редакторы. А надо изменить подход. То есть мало отказаться от использования мышкой, надо еще изменить способ мышления. Идея не в том, чтобы мыслить не символами и хоткеями, а командами.

Композиция команд — это очень мощная концепция в Vim/Neovim. Например, команда может состоять из трех частей:

— Оператор (что делать)
— Модификатор (сколько раз или как)
— Движение (с чем делать)

Примеры:

d2w - delete 2 words
da{ - delete around {}
y$ - yank to end of line
ciw - change inner word
c3j - change 3 lines down

Вот к примеру основные операторы

  • d - delete (удалить)
  • y - yank (копировать)
  • c - change (изменить)
  • p - put (вставить)

и основные движения

  • w - слово
  • b - назад по словам
  • e - конец слова
  • $ - конец строки
  • 0 - начало строки
  • ^ - первый непробельный символ в строке

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

Более того, команды регистрозависимые. Например,

  • word - последовательность букв, цифр и символа подчёркивания
  • WORD - последовательность не пробельных символов

Поэтому

example_variable_name # три words, то есть три нажатия w
example_variable_name # один WORD
some-compound-word # три words
some-compound-word # один WORD

gg — прыжок к началу файла, а G — к концу. Команд так много, что сложно все запомнить. Но я стараюсь каждый раз, когда чувствую сложность и непонимание "как сделать так чтобы было удобно" идти гуглить и пытаться запомнить как же.

Вот последние находки для разделения одно окна на панели

<C-w>v или :vsp - вертикальное разделение
<C-w>s или :sp - горизонтальное

Для навигации между панелями:

<C-h> - в левое окно
<C-j> - в нижнее окно
<C-k> - в окно сверху
<C-l>- в правое

То есть идея понятна, те же hjkl + нажатый Ctrl.

А еще метки. Про них наверное отдельно надо писать. Если кратко, то ma ставит метку 'a'. mb — метку 'b'. Не важно где была поставлена эта метка в этом файле и сегодня ли. Но

- `a и `b позволяет переключаться между файлами или теми блоками где вы были очень быстро
- `` позволяет вернуться к предыдущей позиции
- '. возвращает к последним изменениям

В общем, пока я нажимал www, гуляя по словам, было прикольно, но как-то странно. Потому что преимущества с обычным редактором не были заметны. А вот метки как раз принесли очень интересные возможности.

PS: Как я писал в начале поста "я почти отказался от VS Code". Мне все еще нравится VS Code. Он прекрасен и привычен. Поэтому когда я устаю разбираться с vim, я просто переключаюсь на VS Code.

Подборка ссылок #05

Из рассылки Ruby Weekly узнал о геме для пагинации Pagy. Судя по тестам, это прекрасная замена Kaminari. Pagy быстрее и потребляет меньше памяти.

Вышел Rails 8.0 🥳 и Ruby 3.3.6.

У "Марсиан" вышла классная статья 11 HTML best practices for login & sign-up forms.

Сразу две статьи про логический оператор присваивания &&=: JavaScript's &&= Operator: Understanding Logical AND Assignment и JavaScript's ??= Operator: Default Values Made Simple.

Вышел в свет Rspack 1.0, это сборщик модулей написанный на Rust. Судя по тестам он в несколько раз быстрее Webpack и чаще всего быстрее Vite (за исключением HMR режима).

Подборка ссылок #04

·

Design tokens cheatsheet — статья о том что такое дизайн-токены и их структурировать. А вот еще одна инструкция по работе с токенами The ultimate Design Token setup

С тех пор как David Heinemeier Hansson перешел на линукс, он много рассказывает о том, как прекрасен VIM. В общем-то я с ним согласен. Вот его пост на эту тему Wonderful vi

SQLite кажется недооценен. Почитайте почему его стоит использовать Why you should probably be using SQLite. Кстати, в Ruby on Rails 8 планируется поддержка SQLite в продакшене.

На Reddit наткнулся на пост о том, как добавить поддержку Vue в NeoVim Finally, NeoVim + Native Vue LSP Perfection.

WebStorm сделали бесплатным для некоммерческих проектов.

Обновления в блоге

·

Последние пару неделю работаю над блогом. До этого я писал, что он работает на Nuxt.js + Wordpress. И до начала октября все было именно так. Nuxt.js на фронте, бэкенд (если можно так выразится) на Wordpress. И утверждал и продолжаю утверждать, что панель управления Wordpress одна из самых удобных.

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

Еще один момент — система плагинов и технически сложная кастомизация. Чтобы что-то сделать в админке, например, добавить кастомные поля к посту, нужно ставить плагин. Все это здорово, но кажется, что ты не владеешь продуктом. Если завтра плагин обновится и с ним будет проблема, это может поломать сайт. Так совпало, но спустя неделю после переезда у Wordpress и wpengine был спор о правах и отчислениях. Дошло до того, что команда Wordpress выпустила свой плагин Secure Custom Fields.

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

Так что с недавнего времени я переехал на Ruby on Rails. Это интересный опыт. С одной стороны, хотелось посмотреть версию 7.2 в работе. С другой, хотелось быстренько сделать проект так, как хочется внутри, без лишнего усложнения. Без проблем и экспериментов не обошлось.

Попробовал Active Storage, понял что мне не нравится это решение и откатил всё обратно. В итоге, решил, что картинки я буду заливать на CloudFire при создании поста, а удалять их буду вручную. Решение не совсем идеальное, но оно работает и на текущий момент меня устраивает.

Вообще старался сделать всё как можно проще. После админки Wordpress это сильно заметно 😀

Из функционала: подписка на RSS, оптимизация и конвертация картинок в webp на стороне рельс, а не на CloudFire, собственный сборщик статистики. Не люблю Google Analytics, а большинство других аналитик платные. Мне же интересно общее количество посещений, страны и устройства. Нет так уж много, согласитесь. Ранее я использовал SimpleAnalytics. Отличный сервис, но на этот раз решил реализовать свою версию. Ну и конечно же самый настоящий серверный рендеринг приготовленный на самом настоящем сервере. Без костылей и хаков 😀.

В планах есть еще идеи по улучшению и доработки. Например, email рассылка, конвертация :) => 😀, хранение черновика заметки в localStorage, кросс-постинг в телеграм канал и прочие нужные и ненужные штуки. В общем, всё то, что неизбежно ведет систему к усложнению.

Как подключить кастомный домен на Cloudflare к Railsway

·

Перенес управление доменом на Cloudflare. И пришлось немного почитать документацию, как же настроить и соединить сайт на railway.app и домен на Cloudflare.

В первом приближении всё казалось просто. Railway.app генерирует проекту CNAME. Казалось бы бери, подставляй конфиг и всё. На практике оказалось чуть интереснее и документацию пришлось почитать немного внимательнее.

Сохраню для истории ссылку настройка корневого домена Cloudflare

Про технологии

·

Этот блог работает на WordPress. Точнее его часть — админка. А фронтенд на nuxtjs. Когда-то я много работал с WordPress. Был даже модератором русскоязычного сообщества, делал темы и сайт на заказ. И вот что хочу сказать: панель управления WordPress была и остается одной из лучших. Знаете слоган у Эппл “это просто работает”. Так вот то же самое можно сказать про админку вордпресса. Кликаешь пару кнопок и всё, можно писать.

Но за такое удобство приходится платить. Размер базы растет как на дрожжах. Версионность и черновики штука хорошая, но некоторые вещи сохраняются избыточное количество раз. В каталоге с изображениями через некоторое время начинается хаос, через полгода-год туда вообще лучше не смотреть — непонятно используются ли загруженные картинки или уже нет. Плагины и темы тоже стоят отдельной дискуссии. За столько лет развития WordPress написано огромное количество плагинов. Часть из них уже давно стали платными и перешли на систему месячных подписок. В результате обновления от разработчиков приходят чуть ли не каждую неделю и следить за всем стало очень сложно. WordPress стал очень сложным продуктом.

Но сложными стали многие системы. Помню как лет десять назад раскладывал в директориях css и js и прогонял gulp-task, чтобы мои псевдокомпонентики склеивались в банды. Потом появился вебпак, react/vue и компоненты стали настоящими, не псевдо. Потом структура приложений и сервисов усложнялась и вот уже появляются различные архитектурные слои. Нельзя просто взять и, простите, наговнякать. Надо все разложить по полочкам, настроить вебпак, отрастить бороду. Усложнился и javascript. Вот менеджеры состояний, вот веб-сокеты, local first подход. В какой-то момент проектирование архитектуры пет-проектов стало такой, что пока все подготовишь, уже запал кончился. А список пакетов из npm, которые еще надо установить — нет. Не то, чтобы это прям плохо, это естественное развитие и взросление системы. Просто стало сложно следить и управлять всем этим.

Но я тут начал книжку про Ruby on Rails читать. И для закрепления знаний, конечно писать код. И знаете что? В мире есть место где можно говнякать. Что 10 лет назад, что сейчас. Хочешь свалить все стили в assets/stylesheets? Пожалуйста. Хочешь вмонстрить кусок скрипта прямо во вьюху? Не возбраняется. Тем более, что это местами очень даже удобно. И вот я раньше сильно плевался от подобного подхода. Но сейчас… Не то чтобы я стал сторонником, но если кусок скрипта нужен только на этой странице, то может быть проще вздохнуть и добавить его туда.

И вот пет-проект на рельсах, где можно немного отступить от привычных норм выглядит каким-то глотком свободы. Уверен, что развивая проект, со временем он тоже станет сложным и его придется делать архитектурно красивым и структурированным. Но вот сейчас, кажется, я до конца понимаю как вышло так, что Ruby on Rails стал таким популярным, почему каждый год все ждут когда же он помрёт. А DHH раз за разом выпускает новую версию и RoR всё ещё популярен.

Мне кажется потому, что это то самое место, где все ещё можно г… Гибко решать свои задачи. Ну вы поняли 😀

Подборка ссылок #03

Интересная идея о дизайне url
Web-based трекер финансов с поддержкой local-first и упором на privacy.
How We Designed a White-Label In-Car Infotainment System — классная статья и проектировании интерфейса для Android Auto.
The State of ES5 on the Web — статья о том, что пора уже перестать транспилировать код в ES5 и вместо этого использовать современные стандарты.

Опубликую сразу несколько ссылок про VIM. Во-первых, это на справочник Vim help files. Во-вторых, это книга Practical Vim: Edit Text at the Speed of Thought. И ссылка на AstroNvim, если вдруг решите сменить VS Code и попробовать что-то новенькое.

Путь к освоению VIM: от плагина до Practical VIM

·

Решил разобраться в VIM. Вообще я часто пользуюсь им, для быстрого редактирования файлов. Этакая разовая работа. Но полноценно переключиться на работу с VIM у меня не получается. По умолчанию использую VS Code + VIM плагин. Получается неплохой симбиоз: удобные хоткеи VS Code + удобная навигация внутри файла. Но одно дело удалять строчки и прыгать туда-сюда по файлы, а другое дело полноценно работать с большим проектом.

Обычно многие статьи заканчиваются командами h, j, k, l. А дальше читайте официальную документацию, там всё подробно описано. А выйти-то как? А как отступ добавить?

Так вот, отступ в режиме NORMAL задаётся через двойное нажатие >. И тут вот какая проблема: статьи-то на самом деле хорошие, просто команд и сценариев так много, что всего не перечислишь. А еще есть куча разнообразных форков со своими доработками. Например, я пользовался LunarVim. В целом, было неплохо, но некоторые вещи долгое время не исправлялись. И вот однажды я полез искать как же поправить один баг и с удивлением обнаружил, что проект не развивается.

Решил попробовать Astronvim. Проект оказался поинтереснее: быстрее, более структурированнее. И как-то так увлекся настройкой (что-то добавил, что-то переназначил), что в итоге сделал свой форк.

В какой-то момент, устав читать документацию и статьи, я купил себе книжку Practical VIM. Сначала читал демо, потом еще раз читал демо. Понял, что очень понравилось. Простой английский, легкое повествование. Текст читается прекрасно. К слову, у меня есть ещё одна книга про VIM “Изучаем vi и VIM”. Так вот в этой книге я продвинулся всего на четыре главы. В общем, “Practical VIM” понравилась больше.

И вот к примеру пара цитат из книги:

The combination of operators with motions forms a kind of grammar. The first rule is simple: an action is composed from an operator followed by a motion. Learning new motions and operators is like learning the vocabulary of Vim. If we follow the simple grammar rules, we can express more ideas as our vocabulary grows.
Neil, Drew. Practical Vim (pp. 24-25). Pragmatic Bookshelf. Kindle Edition.

и

when an operator command is invoked in duplicate, it acts upon the current line. So dd deletes the current line, while >> indents it.
Neil, Drew. Practical Vim (p. 25). Pragmatic Bookshelf. Kindle Edition.

Ещё книга содержит много отсылок к документации. При желании можно пойти и узнать больше деталей. В общем, книга классная, рекомендую.

Что касается VIM и ежедневного его использования, могу сказать, что в процессе чтения книги снова появился живой интерес к использованию. Некоторые вещи уже не выглядят болью. Еще один важный момент — готовый настроенный конфиг. Возможно, когда-нибудь я попробую всё настроить с нуля. Но вот прямо сейчас хочется использовать то, что работает из коробки. Поэтому решения вроде AstroNvim хорошо подходят.

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

Вывода у статьи не будет. Скорее это просто чекпоинт на тему “вот узучаю VIM”.

Тесты на Playwriter

·

Немного про разработку. Работал тут с Playwright. До этого писал тесты на Cypress. И после двух лет на Cypress кажется, что вдохнул свежего воздуха. При параллельном выполнении тестов Playwriter прогоняет их быстрее. А еще он запускает отдельный процесс для управления браузером, вместо выполнения тестов непосредственно в браузере.

В результате, переписал тесты к блогу на Playwriter и настроил Github Action.

20241014_082200_e4c38c.webp

Из интересного: для запуска тестов Nuxt + Playwriter нужно в playwright.config.js указать reuseExistingServer: true.

export default defineConfig({
...
webServer: {
command: 'npm run preview',
url: 'http://localhost:3000',
reuseExistingServer: true
}
}

Отладка через git bisect

·

Сегодня узнал о способе отладки через git bisect. Работает это путем поиска по истории репозитория.

Допустим зарелизили в прод стопицот фич и что-то сломалось. Неделю назад работало, а теперь нет. Берем коммит недельной давности, когда точно все работало и переключаемся в него: git checkout <тот самый коммит>. Ставим метку git bisect start.

Проверяем, все ли работает и если да ставим метку: git bisect good. Далее git кидает нас на следующий коммит. Если все работает ставим good, если нет: git bisect bad. И так продолжаем искать с середины диапазона сужая поиск пока не останется один коммит.

Найдя коммит, где все сломалось, уже можно понять проблему. Для завершения поиска: git bisect reset. Эта штука сегодня сильно помогла мне найти проблему, так что я решил записать все, пока не забыл 🙂

Подробнее можно почитать вот тут.

Немного git-а

·

git branch --contains <commit> – позволяет посмотреть в какой ветке коммит. А чтобы найти все ветки, понадобится флаг -a:

git branch -a --contains <commit>

При необходимости можно просто перейти на коммит: git checkout <commit>. Или вынести его в новую ветку: git checkout -b new-branch-name <commit>.

Подборка ссылок #02

— Вышел Neovim 0.10.
— Обзор нововведений в браузерах. Поддержка новых анимаций, нативные поповеры. Ну и ждём кастомные селекты. The latest in Web UI (Google I/O ‘24)
— Статья описывает концепцию рецептов в дизайн системе
— Отличное видео для новичков: React JS c Нуля – Курс для начинающих БЕЗ ВОДЫ
— Если вы помните, что когда-то был такой Wunderlist (который потом Microsoft купил), то знайте: разработчики вандерлиста выпустили новое приложение — Superlist. Выглядит красиво, пользоваться приятно, как и раньше.

Настройка VSCode

·

20241014_084139_87417a.webp

У меня VS Code выглядит довольно аскетично. Простая белая тема, минимум настроек. Иногда переключаюсь на темную тему, но рано или поздно возвращаюсь к белой.

Шрифт Fira Code.

Плагины must have для работы с Vue: Vue(Volar, не Vetur), ESLint, Prettier, GraphQL.

Еще дополнительно у меня установлены:

— эмулятор VIM
Better Comments
Color Highlight
EditorConfig
TODO Highlight

Файл .vscode/settings.json содержит вот такой конфиг:

{
// prettier
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
// eslint
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
// to see functions arguments name (optional)
"javascript.inlayHints.parameterNames.enabled": "all",
// quick suggestions while typing (optional)
"editor.quickSuggestions": {
"strings": true
}
// Common settings
"workbench.statusBar.visible": false,
"workbench.sideBar.location": "right",
"editor.fontSize": 13,
"editor.fontFamily": "Fira Code",
"editor.fontLigatures": true,
"editor.tabSize": 2,
"editor.fontWeight": "500",
"search.showLineNumbers": true,
// For VIM
"editor.lineNumbers": "relative",
"editor.rulers": [100],
"workbench.iconTheme": "vscode-icons",
"workbench.activityBar.location": "hidden",
"telemetry.telemetryLevel": "off",
"explorer.compactFolders": false,
"workbench.editor.showTabs": "none",
"breadcrumbs.enabled": false,
}