Заметки Андрея Романова
1.3K subscribers
40 photos
100 links
Разработка интерфейсов, дизайн, программирование и всё остальное. Вопросы, пожелания, комментарии — @andrew_r

https://andrew-r.ru
Download Telegram
Раньше я думал, что создавать новые продукты нужно исходя из их целевой аудитории. Такое понимание сложилось ещё пару лет назад после чтения каких-то мутных статей в интернете. В них советовали составить портрет типичного представителя целевой аудитории: например, делаем трекер задач для менеджера, которому 30 лет, он работает в веб-студии, воспитывает дочь и по утрам выгуливает собаку.

На самом деле всё это полный булшит: делая продукт, нужно исходить из решаемой задачи/проблемы, а не из примерного портрета пользователя. Такой подход к разработке продуктов описан фреймворком Jobs-to-be-Done, о котором есть целая книжка от Интеркома. Для поверхностного знакомства с подходом можно прочесть введение в Jobs-to-be-Done от Анны Булдаковой.
​​Закон Хика

Чем больше вариантов выбора, тем больше времени нужно на принятие решения.

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

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

Подробнее о том, на какие метрики влияет закон Хика и как его применять в веб-дизайне — https://www.interaction-design.org/literature/article/hick-s-law-making-the-choice-easier-for-users.
Вечерняя инфографика: как блокировка ВК на Украине отразилась на статистике Форвеба
Ещё одна инфографика о том, что такое степень доктора наук — https://matt.might.net/articles/phd-school-in-pictures/
Утилитарные функции

В программировании есть два подхода. Первый — не использовать утилитарные функции и каждый раз заново писать код, решающий типичную задачу вроде группировки элементов массива. Второй — максимально использовать уже написанные утилитарные функции и выносить повторяющийся код в новые. К большому сожалению, в джаваскрипте довольно скудная стандартная библиотека, что бы ни говорили сторонники первого подхода («зачем тебе лодаш, если forEach, map и filter уже давным-давно реализованы нативно?»). Из-за этого приходится подключать сторонние библиотеки или писать свои велосипеды, что, конечно, плохо.

Тем не менее, мне ближе второй подход, потому что:
— утилитарные функции позволяют максимально сконцентрироваться на задаче и не отвлекаться на мелочи вроде написания очередного редьюса;
— утилитарные функции лучше выражают намерения программиста: flatten, pluck или chunk выглядят куда содержательнее, чем array.reduce((result, item) => /* какой-то код */);
— каждое дублирование кода вместо использования утилитарной функции повышает вероятность ошибки и требует дополнительных тестов.
Пишете всё каждый раз руками или используете утилитарные функции?
anonymous poll

Использую утилитарные функции – 44
👍👍👍👍👍👍👍 51%

Пишу руками – 24
👍👍👍👍 28%

Пофиг, главное чтобы работало, у меня дедлайн – 18
👍👍👍 21%

👥 86 people voted so far.
​​Оказывается, режимы экономии трафика в Chrome, Opera и Яндекс.Браузере не просто прогоняют сайты через свои прокси-сервера, но ещё и добавляют ко всем запросам заголовок Save-Data. То есть можно самостоятельно проверять наличие этого заголовка в запросе и отдавать пользователю облегчённую версию сайта. Подробно о Save-Data рассказывал Илья Григорик, а сам этот заголовок входит в черновик стандарта HTTP Client Hints.
Запоздало прощаюсь с 2017 годом: https://andrew-r.ru/notes/?go=all/bye-2017/
Рубрика «возможности джаваскрипта, о которых лучше бы и не знать»

Сегодня обнаружил, что в джаваскрипте есть аналог goto, и это не throw/catch. Любой цикл или блок можно подписать, а затем сослаться на него в инструкциях break/continue. Внутри блоков разрешён только break:

foo: {
console.log('ух');
bar: {
console.log('сейчас как залогируется');
break bar;
console.log('чёрта с два!');
}
console.log('ну же...');
break foo;
console.log('ну вот опять :–(');
}

// -> ух
// -> сейчас как залогируется
// -> ну же...


А в циклах можно ещё и continue:

outerLoop:
for (var i = 0; i < 5; i++) {
innerLoop:
for (var ii = 0; ii < 3; ii++){
if (ii === 2) {
continue outerLoop;
} else if (i === 2) {
break outerLoop;
}

console.log(`${i}${ii}`);
}
}

// -> 00
// -> 01
// -> 10
// -> 11


Пользуйтесь на здоровье!
Потихоньку начинаю выкладывать рекомендации прочитанных книг, первая — «Грокаем алгоритмы»: https://andrew-r.ru/notes/?go=all/grokaem-algoritmy/

Пока не очень понимаю, каким должен быть этот формат. Напишите, чего не хватает или хотелось бы видеть в рекомендациях (конспекты, пересказы интересных мест, цитаты, etc): @andrew_r
Рассказываю, насколько мы близки к ванильному CSS без препроцессорного сахара — https://andrew-r.ru/notes/?go=all/preprocessors-vs-vanilla-css/
Рецензия на «Микрорешения» и конспект основных идей — https://andrew-r.ru/notes/?go=all/microresolutions/
TL; DR, если лень переходить по ссылке: решения вроде «стать более аккуратным» не работают. Вместо них принимайте конкретные, небольшие решения, которые легко осуществить и от которых сразу же есть профит — например, «заправлять постель утром». Привяжите эти решения к каким-либо событиям (сигналам), чтобы сформировать привычку. Фокусируйтесь не больше, чем на 1–2 микрорешениях, пока не выработаете привычку.
В SPA сломано много вещей, которые нормально работают в обычных сайтах. Одна из таких вещей — переходы между страницами. Используете динамический роутинг? Оберните содержимое страниц в элемент с tabindex="-1", role="region" и aria-label="Содержимое текущей страницы", а при переходах между страницами устанавливайте фокус на эту обёртку. Эта базовая техника сделает ваше приложение немного доступнее для тех, кто пользуется кнопкой tab или экранными читалками.
Реализация такой обёртки на Реакте
Использование обёртки с Реакт-Роутером (v3)
Ваня Акулов (@iamakulov_channel) справедливо спрашивает, зачем нужна эта обёртка — я не объяснил, в чём проблема.

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

IntersectionObserver это новый браузерный API, позволяющий асинхронно следить за степенью пересечения элемента с вьюпортом или другим элементом. С его помощью можно определить, виден ли элемент на экране, если виден, то насколько (целиком или частично), а также когда именно он оказался виден. Пример того, где это может потребоваться — модуль для ленивой загрузки картинок.

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

const observer = new IntersectionObserver(handleIntersection, {
root: null, // отслеживаем пересечение с вьюпортом, а не с элементом, поэтому null
threshold: 1 // порог видимости, при котором сработает обзёрвер; 1 означает полную видимость, 0.5 означало бы 50% видимости
});

observer.observe(document.getElementById('target'));

function handleIntersection(entries) {
// Обзёрвер срабатывает в том числе когда элемент скрывается из вьюпорта, поэтому нужна дополнительная проверка
if (entries[0].intersectionRatio === 1) {
logBlockView();
}
}


IntersectionObserver поддерживается в последних версиях Chrome, Edge и Firefox, для остальных браузеров есть полифил (6.6 КБ в минифицированном виде). Подробнее об IntersectionObserver на MDN.
У Эстонии есть собственная дизайн-система — https://brand.estonia.ee/
А ребята из https://gov.design теперь пилят единый навигатор по государственным сайтам и услугам — https://gov.gosuslugi.ru/
На собеседованиях иногда просят назвать способы отправки запроса на сервер. Помимо очевидных fetch/XMLHttpRequest и прочих джаваскриптовых штук есть более экзотические способы вроде <img src="...">.

Вчера узнал о ещё более экзотическом и извращённом способе отправки запроса на сервер с помощью CSS:


body::after {
content: url('...');
}


Этот способ может использоваться для аналитики и трекинга пользователей, у которых отключен JS. Можно отследить клики по ссылкам, ввод текста в инпуты, клики по чекбоксам, длительность ховера на каком-либо элементе; также можно приблизительно определить браузер и операционную систему пользователя. Подробности — https://github.com/jbtronics/CrookedStyleSheets

Защититься от этого можно только отключив CSS. Параноикам пора переходить на текстовые браузеры :–)