Фронтенд-новости №8. Вышел WordPress 6.0, найдена оптимальная длина строки, под вопросом
Дайджест новостей из мира фронтенд-разработки за последнюю неделю 23–29 мая.
К сожалению, на хабре нельзя устанавливать alt для картинок, поэтому …ДоступностьHTMLCSSJavaScriptReactNode.jsAngularVueИнструментыОбщее
Как выделяться с помощью типографики. Рассматривайте возможности типографики как дополнительную возможность привлечь внимание вашего интерфейса.
Оптимальная длина строки. Спойлер: 50-75 символов. Меньше 50 или больше 75 может ухудшить читабельность
Почему в вебе закругляют углы?
Как читать статьи на английском языке
В дайджесте много статей и видео на английском языке, чтобы это не стало препятствием: в Google Chrome есть функция перевода страницы с любого популярного языка, а видео можно перевести в Яндекс Браузере.
Для того чтобы создать сайт, который будет максимально привлекателен для посетителя, мало купить оригинальное доменное имя, разработать уникальный дизайн и вставить яркие картинки. Для сайта не менее важным элементом являются используемые шрифты, являющиеся частью дизайна. Если веб шрифты страницы, заголовков и текстовых блоков правильно подобраны, то прочтение основного текста будет более простым и комфортным, а это положительно скажется на общем впечатлении о сайте. В большинстве случаев именно текст является одним из главных способов коммуникации посетителя сайта и компании, поэтому важно понимать, что шрифты для инстаграма или для фотошопа далеко не всегда будут логично смотреться на информационном портале или в Интернет-магазине.
Виды шрифтов для сайта
Все веб шрифты страницы сайта делятся по начертанию на рукописные и печатные. Кириллические рукописные в большинстве случаев используются для того, чтобы оформить привлекательный заголовок, логотип, выделить в тексте отдельные фразы. Также такие шрифты подойдут для инстаграма и для фотошопа, когда необходимо персонализировать картинку. Для основных текстовых блоков такие шрифты не подходят, так как не особо удобны для чтения и восприятия, поэтому для основного текста используются печатные шрифты. Они делятся на три категории:
С засечками (в их названии часто присутствует serif) – они хорошо подходят для печатных изданий, а для сайта не совсем логично их использовать, так как они не всегда удобны к восприятию и рассеивают внимание посетителя. Поэтому такие шрифты востребованы для заголовков, подзаголовков и выделения отдельных блоков;
Рубленые или без засечек (обозначаются как sans serif) – нейтральные и универсальные шрифты, которые удобны к прочтению и восприятию. Многие сайты оформляются только при помощи таких шрифтов;
Декоративные – отличаются оригинальностью и яркостью, но текст, который ими написан, сложен для чтения, поэтому чаще всего такие шрифты применяются при создании заголовков и логотипов. Стоит сказать, что далеко не всегда можно скачать кириллицу отдельных шрифтов, из-за чего имеется ряд ограничений по их использованию.
Наиболее востребованные шрифты для сайтов
Количество популярных бесплатных css на просторах Интернета достаточно большое, равно как и количество шрифтов, которые доступны для бесплатного скачивания. Найти жирный (bold) шрифт не составляет труда, но необходимо знать о самых популярных шрифтах, использование которых практически всегда оправдано. Среди таких шрифтов (они все могут быть кириллическими рукописными) можно выделить:
Roboto – наиболее популярный шрифт, имеющий громадное количество вариаций, среди которых можно найти жирный (bold), light, black;
Open Sans – наиболее удобочитаемый всего читать, поэтому в Интернете его можно встретить почти на каждой интернет-странице;
Montserrat – простой, интересный и привлкательный для чтения, но при этом позволяющий «зацепиться» взгляду во время просмотра больших документов;
Roboto Condensed – имеет особенность – он узкий и несколько вытянутый, но при этом понятный и читабельный;
Source Sans Pro – имеет максимальный набор начертаний, причем разработан Adobe, поэтому отлично подойдет для Фотошопа и других графических приложений. Скачать кириллицу для него можно во всех вариантах;
Oswald – чаще всего применяется для заголовков, как для полноценных сайтов, так и для приложений;
Merriweather – имеет засечки и немного вытянутые и плавные буквы. При желании можно скачать вариант и без засечек;
Noto Sans – отличается упрощенным дизайном символов, но при этом очень хорошо читаем, благодаря чему отлично походит для текстовых материалов;
Yanone Kaffeesatz – имеет стиль типографской печати кофеен начала 20-го века. Немного старомоден, но выглядит дорого, благодаря чему отлично подходит для заголовков рекламного характера;
Caveat – имеет элегантные прописные литеры, которые узнать довольно просто. Хорошо подойдет для заголовков, но для текста.
Естественно, количество шрифтов, которые могут использоваться в популярных бесплатных css, исчисляется десятками тысяч, поэтому выбрать обычно довольно сложно. Особенно в тех случаях, если имеется желание выделиться. В такой ситуации оптимальным вариантом будет обращение к профессиональному дизайнеру, который подберет набор шрифтов с учетом дизайна сайта, его специфики и количества текстовой информации, размещенной на нем.
Особенности выбора шрифтов для сайта
Интересно то, что по статистике пользователи перед тем, как прочитать текстовые блоки на сайте, бегло просматривает заголовки, после чего принимают решение о дальнейшем прочтении, поэтому важно уделить особое внимание выбору шрифтов и их сочетанию. Использование традиционных шрифтов – Open Sans, Roboto, Montserrat – это беспроигрышный вариант, так как они простые, читабельные, привычные. Поэтому важно учесть то, какой контент необходимо оформить.
Отдельного внимания заслуживает тематика сайта и стилистика шрифтов, поэтому при возникновении сомнений относительно выбора стоит доверить этот процесс профессиональному дизайнеру. Среди общих рекомендаций по выбору шрифтов можно отметить:
Не стоит применять более трех шрифтов на странице, иначе текст никто не будет читать. Если необходимо выделить отдельные фрагменты, то имеет смысл использовать один и тот же шрифт, но в разных начертаниях;
Читабельность на первом месте – шрифт должен быть, прежде всего, читабельным, иначе страница будет только просматриваться и закрываться;
Шрифтовые пары должны сочетаться между собой. Если шрифты плохо сочетаются между собой, то стоит один из них сразу же менять;
Логичность обязательна – цвета букв должны быть подобраны с учетом фона, а размер быть таким, чтобы его было удобно читать.
Независимо от того, для какого сайта подбираются шрифты, необходимо экспериментировать – так можно подобрать оптимальное и при этом оригинальное сочетание, благодаря которому посетитель прочитает все от начал до конца, ведь именно это важно для многих.
Знакомство с профилировщиком производительности вашего браузера / Хабр
Эта статья — перевод оригинальной статьи Thomas Belin “Get to know your browser’s performance profiler”
Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов.
Вступление
В какой-то момент своей карьеры вы, возможно, просматривали вкладку «Производительность» в инструментах разработки вашего любимого браузера. В конце концов вы попытались создать profile, но, вероятно, быстро разочаровались. Высокая плотность отображаемой информации делает ее немного подавляющей и несколько пугающей. Я был там, я понимаю тебя!
Хорошая новость: кривая обучения на самом деле не такая крутая!
Как только вы усвоите несколько концепций, он внезапно станет вашим самым ценным инструментом для устранения узких мест в производительности.
Эта статья даст вам несколько ключей к пониманию того, как работает профайлер и как правильно его использовать.
Давайте полностью забудем о console.log и console.time, сегодня мы погрузимся в профилировщик производительности!
Примечание: я не буду слишком углубляться в сложные сценарии, но в конечном итоге напишу дополнительную статью о продвинутых методах.
Модель данных
Первым шагом, который я предпринял, чтобы понять, как работает профилировщик, было чтение документации Mozilla об их новом профилировщике производительности (это отличный документ, прочтите его).
Первый вау-эффект, который у меня был, был, когда я увидел модель данных, которую использовал профайлер. Это на самом деле довольно просто
В документации Mozilla модель данных представлена следующим образом:
A A A | | | v v v B B B | v C
A, B и C — имена функций, а по оси X мы получаем время. По умолчанию профилировщик Firefox и Chrome настроен на создание снимка каждые 1 мс, что означает, что здесь каждый столбец представляет 1 мс.
В этом примере это означает, что стек со временем развивался таким образом.
в 0мс A вызывал B, а B все еще работал;
в 1 мс B вызывал C, а C все еще работал;
в 2 мс C закончил свою работу, и мы вернулись в B;
в 3 мс стек оказался пуст.
Из этого профилировщик может сделать следующие выводы:
А почти сразу вызвал B;
Мы пробыли ~1 мс в B, прежде чем вызвать C;
C потребовалось ~ 1 мс для выполнения;
B снова потребовалось еще ~ 1 мс после вызова C;
А закончил выполнение сразу после вызова B.
Имея в виду эту модель, мы можем создать некоторые данные:
A A A A A A A A A | | | | | | | | | V V V V V V V V V B B B B B B B B B | V C
B занимает немного времени до и после вызова C. Мы потратили ~1 мс на C и не потратили время на A:
A A A A A A A A A | | V V B B | V C
A занимает некоторое время перед вызовом B. B и C занимают ~1 мс.
Ограничения этой модели
Поскольку профилировщик берет только 1 выборку в мс, это означает, что вызов функции, который занимает менее 1 мс, имеет высокую вероятность не отображаться в сгенерированном профиле.
Сгенерированный профиль, скорее всего, будет выглядеть примерно так:
A A | | v v B D
В этом профиле не будет упоминаний о C или E.
Но мы здесь для отладки долгих задач, помните? Нет необходимости разбирать эти быстро выполняющиеся функции. Нам до них нет дела!
Собственное время (self time) против общего времени (total time)
Одно немного запутанное понятие в профилировщике — это собственное и общее время. Однако на самом деле это понятие довольно легко понять.
Их можно определить так:
собственное — время, проведенное в самой функции;
общее — время, проведенное в функции и всех дочерних функциях, которые она вызывает.
Чтобы прочувствовать это, вот конкретный пример:
function superExpensive() { for (let i = 0; i < 1e10; i++) {
console.log(i);
}
}
function main() {
superExpensiveComputation(); // < takes 1000ms
for (let i = 0; i < 1e6; i++) {
// ^ takes 5ms
console.log(i);
}
}
main будет иметь собственное время 5мс, но общее время 1005мс. superExpensiveComputation будет иметь общее и собственное время 1000мс
Общее время помогает выявить проблемные части кода, а собственное время позволяет сузить область поиска до функции, которая действительно требует вашего внимания.
Погружение в UI
Имея в виду эту модель, пользовательский интерфейс начинает обретать смысл. Понятия, которые мы видели ранее, начинают пригодиться для эффективного использования пользовательского интерфейса.
Здесь я сосредоточусь на профилировщике Firefox, но те же принципы применимы и к профилировщику Chrome.
Определение долгих функций верхнего уровня: дерево вызовов
Для начала возьмем очень простой пример кода. Представьте, что где-то есть кнопка, и при нажатии на нее мы запускаем функцию calculateNumber.
function generateNumber(nbIterations) { let number = 0; for (let i = 0; i < nbIterations; i++) {
number += Math.random();
}
return number;
} function computeNumber() {
console.log(generateNumber(1e9));
}
Вот что мы получим в нашем отчете профилировщика:
Поскольку профилировщик фактически профилирует все процессы Firefox, мы хотим убедиться, что мы просто проверяем текущее веб-приложение, над которым работаем.
Мы здесь веб-разработчики, нам не нужны внутренние трассировки стека браузера, давайте оставим только трассировки стека JS.
Мы ясно видим, что больше всего времени мы тратим на функцию generateNumber (здесь функция появилась в 488 выборках, что означает, что она выполнялась как минимум 488мс).
Дерево вызовов позволит вам быстро определить, какие функции верхнего уровня требуют времени. Это хороший обзор того, с чего начать копать, но он не поможет вам быстро определить вложенные функции, которые имеют большое собственное время работы.
Определение долгих вложенных функций: инвертирование стека вызовов
Теперь рассмотрим следующее:
function computeMultipleNumbers() { let number = 0; for (let i = 0; i < 10; i++) {
const fnName = `gen${Math.round(Math.random() * 100)}`; // We create a function with a random name
const fn = new Function(`function ${fnName}() {
return generateNumber(1e7);
} return ${fnName}`);
number += fn()();
}
result.innerText = number;
}
Особенность этой функции в том, что она генерирует именованные функции со случайными именами. Это означает, что теперь generateNumber будет вызываться из множества различных функций.
Посмотрим, как выглядит результат:
Здесь мы видим, что вызывается много функций, но все они имеют пустое собственное время. А это значит, что это не та функция, на которую мы на самом деле потратили время, они ждали завершения чего-то другого.
Теперь, если мы инвертируем стек.
Тут становится понятно, где мы собственно потратили время: в функции generateNumber 🙂
Инверсия фактически сортирует функцию с наибольшим собственным временем и сглаживает их в корне дерева. Это отличный способ идентифицировать трудоемкую функцию, и вы получаете ее стек вызовов прямо рядом с ней. При этом вы точно знаете, какая функция является проблемой и откуда она была вызвана.
Это дерево вызовов:
topLevel // self 0 first // self 0 second // self 0 third // self 10 fourth // self 7 fifth // self 8
Это инверсия стека вызовов:
third //self 10 second topLevel fifth // self 8 fourth second topLevel fourth // self 7 second topLevel
Таким образом, мы можем быстро определить, что мы потратили ~ 10мс на вызов third из topLevel > second
Заключение
В этой статье мы рассмотрели основные функции профайлера. Мы увидели, как использовать дерево вызовов и перевернутый стек вызовов для быстрого определения функций, требующих много времени, в вашем приложении.
Теперь эти трудоемкие функции не обязательно являются функциями, которые вам нужно оптимизировать. Проблема может заключаться в родительской функции или даже выше в дереве. Перевернутый стек вызовов дает вам хорошую отправную точку для изучения проблемной части вашего приложения.
Мы не рассмотрели здесь, что такое Flame Graph или Stack Chart, как профилировать асинхронный код или продвинутые методы, такие как маркеры. Это то, что я хотел бы осветить в следующей статье.
Архитектура фронтенда и какой она должна быть / Хабр
Все мы знаем про, или слышали про практики и паттерны проектирования SOLID, GRASP, MVC, MV** и даже применяем их с переменным успехом, стараясь нащупать эффективный подход к построению приложений. Но это лишь приводит к разнообразию реализаций наших приложений и частей функционала.
И поэтому я уже долгое время пытаюсь понять по каким правилам должно строиться фронтенд приложение чтобы оно удовлетворяло следующим критериям:
легкое расширение функционала приложения;
безболезненное внесение изменений в существующий функционал;
унифицированная структура приложения;
быстрый onboarding новых разработчиков на проект;
понятный и прозрачный код;
всегда понятно где в структуре файлов расположить ту или иную функциональность.
Какие у нас есть варианты?
«Организация файловой структуры это все что нам нужно»
Каждый лид или сеньор сами для себя выбирают варианты компоновки структуры приложения и выделения сущностей приложения. По итогу каждая система становится уникальной и неповторимой. И для того, чтобы разобраться в ней, нужны время и усилия, которые нужно будет тратить каждый раз при смене проекта. Плюс никто не отменял “бас фактор”.
Существует большое кол-во статей, описывающих «оптимальные», по мению авторов, варианты таких подходов. Пример.
Но это, в основном, про структуру файлов и частные случаи использования какого-то функционала. Такой подход только частично унифицирует структуру приложения, но этого мало для того, чтобы называться архитектурой. Может есть что-то лучше?
Domain Driven Design
Много умных дядек, таких как Мартин Фаулер и дядюшка Боб, написали много статей про него. На бэкенде в больших и сложных проектах он неплохо себя зарекомендовал. Но есть и много изъянов: туча абстракций, для простых действий нужно писать много кода, ну и разобраться, как готовить DDD та еще задача.
Есть примеры как готовить это на фронте, но, как видно, проблемы никуда не уходят и кол-во абстракций удручают. Простой onboarding тут невозможен, без прочтения “The Big Blue Book” и пары недель общения с ментором.
Есть переосмысленные подходы к архитектуре, которые больше похожи на правду и наверняка могут где-то успешно применены.
Основательная статья от Кхалила Стеммлера о возможной архитектуре клиентских приложений частично полагается на DDD подход, но при этом сильно его упрощает, освобождая нас от ненужных абстракций и смещая понятия в сторону фронт приложений.
Но бизнес логика в таких приложениях немного размывается и подход больше сфокусирован на функциональных слоях приложения, что отдаляет нас от требования к прозрачному коду и явной бизнес логики.
Джимми Богарт в своей статье пишет что DDD подход не совершенен и избыточен, и, как следствие, он предлагает переработанный подход vertical slices. И это отличный подход, о котором стоит почитать отдельно. Эта идея довольно простая и мы можем адаптировать ее к фронтенд приложениям.
Если DDD не удалось применить для наших нужд, то можно попробовать построить его на более общих правилах, которые предоставляет нам “Clear architecture”, ведь DDD основывается именно на них.
Clear architecture
Также есть попытки следовать всем постулатам чистой архитектуры и абстрагироваться от представления совсем. В этом случае мы сможем подменять view на любой фреймворк или вообще отказаться от его использования. Интересный подход и в некоторых случаях вполне обоснован и может оказаться отличным решением. Самый частый кейс, это использование одной и той же логики в браузере и на мобильном приложении. Подробнее об этом можно почитать тут.
Разработчики Flutter тоже столкнулись с проблемой сложности переиспользования логики между различными представлениями, и предложили подход – Business Logic Component (BLoC). Он позволяет снизить нагрузку на компоненты пользовательского интерфейса, отделив от них бизнес-логику.
Тут пример одной из реализаций BLoC в React.
Вроде неплохо, но все же есть много вопросов. И почти нет сообщества, которое бы могло помочь с возникающими вопросами.
FCD – Feature Sliced Design
И недавно для меня стало открытием методология FCD – Feature Sliced Design. На мой взгляд лучшем решением будет обратить внимание именно на эту методологию.
Ссылка на офф сайт.
Методология не привязана к конкретному стеку технологий и применима к большинству frontend-приложений. Документация содержит примеры реализации на JavaScript + React, но FSD успешно адаптируется и к другим комбинациям инструментов.
Для проектирования архитектуры методология предлагает следующие архитектурные абстракциями на основе которых строиться наше приложение.
Ниже приведу описание терминов из документации:Layers
Первый уровень абстрагирования – согласно скоупу влияния.
model – бизнес-логика модуля (store, effects/actions, hooks/contracts, …);
lib – вспомогательные библиотеки;
api – логика взаимодействия с API;
config – модуль конфигурации приложения и его окружения.
Ниже приведу пример описания фичи авторизации.
# Сегменты могут быть как файлами, так и директориями | ├── features/auth # Layer: Бизнес-фичи | | # Slice Group: Структурная группа “Авторизация пользователя” | ├── by-phone/ # Slice: Фича “Авторизация по телефону” | | ├── ui/ # Segment: UI-логика (компоненты) | | ├── lib/ # Segment: Инфраструктурная-логика (helpers/utils) | | ├── model/ # Segment: Бизнес-логика | | └── index.ts #
| | | ├── by-oauth/ # Slice: Фича “Авторизация по внешнему ресурсу” | …
Помимо унификации структуры, мы получаем наглядную бизнес логику, отличное описание слоев приложения с примерами на популярных ЯП. Также есть ответы на вопросы о расположении функционала и понятные правила уменьшения зависимостей в коде.
Эта методология только развивается и есть хорошее комьюнити, которое так же как и мы задается вопросами архитектуры фронтенда.
Заключение
У каждого из подходов есть свои плюсы и минусы. Учитывая что каждый проект имеет разный размер, сложность и специфику и цели, то что подойдет многим не факт что подойдет вам. Надеюсь что после прочтения статьи вы откроете для себя что то новое и сможете улучшить ваши собственные проекты.
Также если вам интересно в своем Telegram я время от времени выкладываю интересные находки по фронтенду. И всем чистой архитектуры.
Речь пойдёт про мощный инструмент, реализующий собой подход реактивного программирования и в разы упрощающий разработку — RxJS. В частности разберём один момент, про который нужно не забывать при использовании этой библиотеки, а именно — отписки.
Да, да, этот базовый момент может упускаться разработчиком, и это в свою очередь может привести к утечке памяти — об этом далее.
Кейс — отправка запросов на бэк и показ данных в реальном времениЗадача
Представим, что мы разрабатываем приложение, которое в реальном времени показывает нам курсы валют. Клиент часто обращается к бэку либо через обычные запросы, либо через веб-сокеты, и нам нужно каждый ответ от бэка отображать на стороне клиента.
Решение
Будем использовать RxJS в связке с Angular и нашу функцию, которая будет отдавать нам рандомный курс.
Функция будет нам отдавать через определённый промежуток времени курс, который будет сгенерирован рандомайзером:
// fake-currency.function.ts
import { interval } from ‘rxjs’; import { map } from ‘rxjs/operators’;
// Простой рандомайзер, который отдаёт случайное число в определённом диапазоне function getRandomByLimits(min: number, max: number) { return Math.round(Math.random() * (max – min) + min); }
Рандомные курсы валют у нас есть, теперь нам нужно реализовать компонент нашей страницы.
// my-component.component.ts
import { Component } from ‘@angular/core’; import { fakeCurrency } from ‘../fake-currency.function’;
@Component({ selector: ‘my-component’, templateUrl: ‘./my-component.component.html’, styleUrls: , }) export class MemoryLeakComponent { // свойство, которое мы будем использовать в шаблоне num: number;
Поздравляю!!! 🥳🥳🥳 У нас получилось вывести рандомный курс валюты на страницу!!!
Также поздравляю с получением первой утечки памяти!)
О какой утечке памяти идёт речь?
Дело в том, что если мы с этой страницы переместимся на другую, то работа функции fakeCurrency не остановится. Мы можем это проверить добавив логирование в подписку.
// my-component.component.ts
import { Component } from ‘@angular/core’; import { fakeCurrency } from ‘../fake-currency.function’;
@Component({ selector: ‘my-component’, templateUrl: ‘./my-component.component.html’, styleUrls: , }) export class MemoryLeakComponent { // свойство, которое мы будем использовать в шаблоне num: number;
Как мы видим — отображения курса на странице нет, но в консоль продолжают сыпаться логи. Если юзер продолжительное время будет переключаться между страницами, то такая утечка может вызвать дикие тормоза на его компьютере.
Как же нам избежать этого?
Конечно же отписаться!)
И способов отписки существует несколько.
Async Pipe
В данном случае этот способ наиболее предпочтительный. Немножко изменим наш код:
// my-component.component.ts
import { Component } from ‘@angular/core’; import { fakeCurrency } from ‘../fake-currency.function’; import { Observable } from ‘rxjs’; import { tap } from ‘rxjs/operators’;
@Component({ selector: ‘my-component’, templateUrl: ‘./my-component.component.html’, styleUrls: , }) export class MemoryLeakComponent { // свойство, которое мы будем использовать в шаблоне num$: Observable;
Если же нам значение в шаблоне не нужно, но при этом подписаться всё-таки нужно, то можно воспользоваться паттерном Destroy Subject и оператором отписки takeUntil:
// my-component.component.ts
import { Component } from ‘@angular/core’; import { fakeCurrency } from ‘../fake-currency.function’; import { takeUntil } from ‘rxjs/operators’;
@Component({ selector: ‘my-component’, templateUrl: ‘./my-component.component.html’, styleUrls: , }) export class MemoryLeakComponent implements OnDestroy { // свойство, которое мы будем использовать в шаблоне num: number; destroy$ = new Subject();
constructor() { // Случайный id const id = Math.floor(Math.random() * 100000); fakeCurrency(500) // Прокидываем оператор в поток и передаём ему другой поток .pipe(takeUntil(this.destroy$)) .subscribe((num) => { console.log(`ID: ${id}`, num); this.num = num; }); }
ngOnDestroy() { // завершаем поток // когда переданный поток завершается, то оператор takeUntil отписывается от текущего потока this.destroy$.next(); this.destroy$.complete(); } }Может есть решение красивее?
Конечно, есть!)
Не забываем, что Subject сущности — те же классы, от которых мы можем наследоваться. (Нагло беру пример из библиотеки taiga-ui)
Создаём сервис, который будет наследоваться от ReplaySubject и имплементировать OnDestroy интерфейс:
// destroy.service.ts import { Injectable, OnDestroy } from ‘@angular/core’; import { ReplaySubject } from ‘rxjs’;
Первый взгляд на CSS свойство object-view-box / Хабр
Эта статья — перевод оригинальной статьи Ahmad Shadeed “First Look At The CSS object-view-box Property”
Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов.
Вступление
Я всегда хотел, чтобы CSS умел обрезать изображение и размещать его в любом нужном мне направлении. Это стало возможным благодаря использованию дополнительного элемента HTML в сочетании с различными свойствами CSS, которые я объясню позже.
В этой статье я познакомлю вас с новым CSS свойством object-view-box, предложенным Джейком Арчибальдом в начале этого года. Это позволяет нам обрезать или изменять размер HTML-элементов, таких как или
Проблема
В следующем примере у нас есть изображение, которое нужно обрезать. Обратите внимание, что нам нужна только определенная часть этого изображения.
В настоящее время мы можем решить это одним из следующих способов:
Использование и его обёртывание в дополнительный элемент.
Добавления изображения через background-image и изменение положения и размера.
Обертывание дополнительным элементом
Это распространенное решение этой проблемы, вот как это происходит:
Обернул изображение в другой элемент (в нашем случае
).
Добавил position: relative и overflow: hidden.
Добавил position: absolute для изображения и поиграл со значениями позиционирования и размера для достижения результата.
Это прекрасно работает, но что, если мы хотим применить вышеописанное к тегу ? Ну, это то, что касается object-view-box.
Представляем Object-View-Box
Я был заинтригован, когда увидел, что свойство object-view-box может быть добавлено в Chrome 104. Теперь оно доступно в Chrome canary.
Обращаясь к CSS спецификации:
Свойство object-view-box определяет «view box» над элементом, аналогичное атрибуту
Свойство принимает значение basic-shape-rect, оно может иметь значения inset() | rect() | . Для демонстрации в этой статье я сосредоточусь на использовании inset().
Вернемся к проблеме.
С помощью object-view-box мы сможем использовать inset для рисования прямоугольника с четырех сторон (сверху, справа, снизу, слева), а затем применить object-fit: cover, чтобы избежать искажений.
Как это вообще работает? Не волнуйтесь, я объясню все ниже.
Исходный размер изображения
Исходный размер — это ширина и высота изображения по умолчанию. Изображение, с которым я имею дело, имеет размер 1194 × 1194 пикселей.
img { aspect-ratio: 1; width: 300px; }
С помощью приведенного выше CSS размер отображаемого изображения будет 300 × 300 пикселей.
Наша цель — нарисовать прямоугольник на исходном изображении. Для этого мы будем использовать значение inset().
Применение значения inset
Значение inset() будет основано на исходной ширине и высоте изображения, в результате чего изображение будет обрезано. Это поможет нам в рисовании вложенного прямоугольника и управлении четырьмя краями, аналогично работе с полями или отступами.
Значение inset определяет прямоугольник. Мы можем управлять четырьмя ребрами точно так же, как мы имеем дело с полями или отступами. В следующем примере .card имеет inset в 20 пикселей со всех краев.
Вот и все. Разве это не круто? Возможность оформления изображения может быть очень полезна для адаптивного дизайна или даже для демонстрации различных частей изображения.
Увеличение или уменьшение масштаба
Мы можем использовать inset для увеличения или уменьшения изображения. Согласно моим тестам, переход или анимация не будут работать с object-view-box.
Мы также можем уменьшить масштаб с отрицательным значением вставки.
Представьте, как это будет полезно для возможности масштабирования изображения, не оборачивая его в дополнительный элемент.
Демо
Вот демо, которое вы можете протестировать в Chrome Canary уже сегодня. Обязательно включите флаг «Экспериментальные функции веб-платформы».
Ссылка на Демо
Заключение
Я так заинтригован другими потенциальными вариантами использования этой новой функции. Это был быстрый первый взгляд, и я вернусь позже с новыми исследованиями.
Про поддержку Certificate Transparency для национальных сертификатов / Хабр
Недавно мы рассказывали Хабру про поддержку в Яндекс Браузере тех сайтов, которые перешли на использование национальных TLS-сертификатов. Если вы пропустили, то рекомендуем прочитать пост, он содержит ответы на популярные вопросы.
Сегодня мы расскажем про следующий большой шаг в этом направлении — про обещанную поддержку публичных логов, созданных на базе открытого стандарта Certificate Transparency.
Краткая предыстория
Напомним, что с недавних пор российские организации и даже обычные вебмастеры всё чаще сталкиваются с невозможностью купить или продлить сертификат для сайта. Без действующего сертификата невозможно обеспечить безопасную передачу данных между сайтом и пользователями. Самоподписанные сертификаты — не выход по многим причинам: их нужно находить и устанавливать вручную, за ними нет никакого контроля, их используют злоумышленники для перехвата трафика.
Для решения проблемы был создан национальный удостоверяющий центр (НУЦ). Его сертификаты стали приниматься в Яндекс Браузере для сайтов из публичного белого списка. Это решение помогло не допустить ситуации, при которой пользователи лишились бы доступа к онлайн-сервисам или были бы вынуждены на свой страх и риск устанавливать сторонние корневые сертификаты на уровне всей системы.
На старте это решение работало так:
Владелец сайта запрашивает сертификат у НУЦ.
НУЦ проверяет права владельца и выпускает сертификат.
НУЦ добавляет домен сайта в публичный список по адресу gosuslugi.ru/tls.
Яндекс регулярно кэширует этот список на свои серверы, перепроверяет на ошибки, затем раздаёт всем копиям Яндекс Браузера.
Если сайт использует национальный сертификат, Яндекс Браузер проверяет, что его домен содержится в публичном списке, и только в этом случае устанавливает защищённое соединение. Если домена там нет, пользователь увидит стандартную ошибку про некорректный сертификат на сайте.
Быстрый для внедрения механизм. Но в долгосрочной перспективе непригодный. Причин несколько.
История знает немало случаев компрометации удостоверяющих центров. Например, в 2011-м злоумышленники взломали удостоверяющий центр Comodo, чтобы выпустить сертификаты для Gmail и других популярных сайтов. Чуть позже похожая проблема случилась у DigiNotar. Примерно тогда все в индустрии поняли, что время слепого доверия к подписям удостоверяющих центров прошло. Если сертификат был выпущен по ошибке, то у сообщества должен быть механизм узнать об этом. По этой причине белый список gosuslugi.ru/tls не подходит в качестве долгосрочного решения: в нём содержится лишь список доменов, но нет никакой информации обо всех выпущенных для них сертификатах. Это не прозрачно для сообщества.
Кроме того, у списка доменов есть и серьёзные технические ограничения. Любые изменения в списке нужно сначала скачать на наши серверы и проверить, затем каждая копия браузера должна скачать его у нас для локального хранения на устройстве. На всё это может уйти несколько дней, в течение которых сайт с новым сертификатом будет недоступен для пользователей. А ещё при существенном росте числа записей в списке возрастёт потребление трафика и памяти, что тоже может не обрадовать людей.
Мы не стали изобретать велосипед для этой задачи, а воспользовались уже принятым в индустрии открытым решением — стандартом Certificate Transparency.
Коротко про Certificate Transparency (CT)
Certificate Transparency предполагает создание публичных логов (CT-логов), в которых регистрируются выпускаемые сертификаты. Такие логи допускают только добавление записей. Если сертификат был выпущен по ошибке, то его можно только отозвать, но не удалить бесследно. Технологически это работает за счёт применения хэш-деревьев, как и в блокчейне. Верить этому не обязательно: CT-логи открыты для внешнего аудита. Это позволяет:
пользователям и браузерам — отслеживать выпуск всех сертификатов для домена и проверять их подлинность;
Когда удостоверяющий центр (УЦ) регистрирует новый сертификат в CT-логе, в ответ он получает подписанную метку (SCT) этого сертификата. Каждый лог предоставляет свою метку.
УЦ передаёт заказчику сертификат. Метки логов содержатся в сертификате.
Когда браузер устанавливает соединение с сайтом, доверие к сертификату определяется не только доверием к УЦ, который выписал сертификат, но и по меткам CT-логов. К примеру, браузер Chrome при установке HTTPS-соединения требует, чтобы у сертификата было как минимум две любые метки от доверенных CT-логов.
Вот детальная схема с сайта проекта Certificate Transparency:
Как видно из схемы, доступность CT-логов для внешнего аудита — это ключевое свойство решения. Можно не полагаться на хэш-деревья, мониторить любые изменения в логах и сопоставлять изменения из разных логов.
Про CT-логи для национальных сертификатов
Чтобы вся эта схема работала, нужны CT-логи, которые будут записывать национальные сертификаты, выдавать для них подписанные метки. Они должны быть открыты для мониторинга. Должны иметь стабильный аптайм, хотя бы 99%. Один из примеров полного списка требований к логам можно найти на гитхабе. Там же есть готовый код, который позволяет поднять свой лог любому. На текущий момент ни один уже существующий CT-лог не принимает национальные сертификаты. Их поддержка — это вопрос договорённостей между владельцами логов и удостоверяющим центром. Будем надеяться, что в будущем такие договорённости появятся.
Яндекс разрабатывает Браузер, поэтому мы заинтересованы в появлении CT-логов, которые помогут защитить наших пользователей от компрометации сертификатов. Разработчики любого браузера в этом заинтересованы, поэтому, к примеру, компании Google и Apple создали и поддерживают свои логи. Мы пошли этим же путём и создали свой лог, воспользовавшись уже существующим открытым решением. Наш лог уже запущен и работает, НУЦ уже вносит в него новые сертификаты.
Свои CT-логи также запустили VK и «Минцифры России». Технические адреса всех трёх логов с поддержкой национальных сертификатов можно найти по адресу https://browser-resources.s3.yandex.net/ctlog/ctlog.json. Этих данных уже достаточно для того, чтобы сообщество смогло читать логи, искать в них конкретные сайты и вести аудит всех изменений.
Со своей стороны мы также создали форму в Яндекс Вебмастере, которая упрощает получение информации обо всех выпущенных национальных сертификатах для конкретного сайта. Сейчас поиск идёт по CT-логу Яндекса, а также по белому списку доменов. В ближайшее время планируем начать искать и по другим CT-логам.
Про поддержку CT-логов в Яндекс Браузере
Мы уже добавили поддержку новых CT-логов в Яндекс Браузер для Windows, macOS, Linux, Android и iOS. Теперь мы прекращаем обновлять список доменов с gosuslugi.ru/tls, замораживаем состав этого списка на наших серверах. Примерно год он продолжит использоваться в Браузере для тех сертификатов, которые были выпущены по старой схеме (пока не истечёт их срок действия).
Для новых национальных сертификатов, выпущенных с поддержкой CT-логов, сейчас действует простое правило: Браузер принимает сертификат, только если для него есть подписанная метка CT-лога Яндекса. Это стартовое решение.
Дальше мы планируем запустить мониторинг сторонних CT-логов, чтобы убедиться в их работоспособности и стабильности. После этого начнём учитывать метки любых других логов национальных сертификатов. Мы открыты для поддержки новых CT-логов в Яндекс Браузере: достаточно соответствовать нашим техническим требованиям. При этом политика ужесточится: Браузер будет требовать как минимум две метки, причём одну из них — обязательно от лога Яндекса.
Кроме того, мы готовимся выложить в опенсорс ту часть нашего Браузера, которая отвечает за поддержку сайтов и CT-логов с национальными сертификатами. Это может быть полезно не только со стороны аудита, но и тем командам, которые захотят добавить такую поддержку себе.
На всякий случай скажу, что нововведение никак не влияет на логику работы всех остальных (не национальных) сертификатов и их CT-логов. Для них мы, как и прежде, полагаемся на политики и списки из проекта Chromium.
Заключение
Поддержка сайтов с национальными сертификатами поможет не допустить ситуации, когда пользователи лишатся доступа к онлайн-сервисам или будут вынуждены устанавливать сомнительные корневые сертификаты на уровне всей системы. Прозрачность и открытость этого решения для пользователей, владельцев сайтов и разработчиков браузеров должны обеспечиваться строгим соблюдением правил Certificate Transparency. Хочется верить, что в будущем мы увидим не только новые CT-логи, но и новые инструменты для их удобного мониторинга. В этом нам нужна помощь сообщества.
Идеальных решений не бывает, поэтому повторю свой призыв из предыдущего поста: если вы знаете, как сделать лучше, — приходите, советуйте. Хотите покритиковать решения — критикуйте и предлагайте улучшения. Спасибо.
Пришлось искать способ защитить домены в зонах RU, РФ…
Если вам нужен SSL-сертификат, но вы не являетесь специалистом в веб-технологиях, то эта заметка для вас. Описан простой способ выпуска базового SSL-сертификата Let’s Encrypt в ручном режиме, на локальном компьютере с Windows, с помощью приложения Certbot. Этот способ позволяет получить файлы SSL-сертификата в папку на своём локальном компьютере, после чего можно установить сертификат на свой хостинг.
Потребность в SSL-сертификатах возникла у меня в связи с тем, что срок старых истёк, а создать новые оказалось невозможным из-за возникших ограничений на доменные зоны RU и РФ. Если у вас такая же проблема или вам просто надоело искать веб-сервис для выпуска SSL-сертификатов, то эта заметка вам поможет.
Поскольку я пока не знаю наилучшего пути, то ниже просто опишу ту последовательность действий, которую сам выполнил и которая позволила мне создать SSL-сертификаты для десяти своих доменов (в том числе в зонах RU и РФ), а значит и вам этот способ может помочь.
Создание SSL-сертификата на локальном компьютере
Установил на свой локальный компьютер (с операционной системой Windows 11) программу Certbot.
Установочный файл Certbot взял с официального сайта здесь (см. ссылку на загрузку дистрибутива в п.3 на открывшейся по ссылке странице).
Запустил скачанный установщик и в диалоге установки изменил адрес установки на: C:Certbot
Работа с программой Certbot осуществляется через командную строку или PowerShell (я использовал PowerShell). На время выпуска сертификата, естественно, компьютер должен быть подключен к сети Интернет.
Открыл PowerShell (х86) с правами администратора.
Для этого нажал на кнопку “Пуск” и набирая первые буквы названия PowerShell увидел нужный пункт в результатах поиска, затем правым щелчком мыши по названию найденной программы открыл контекстное меню и в нём выбрал пункт “запуск от имени администратора”.
В окне PowerShell с помощью команд cd перешёл в каталог Certbot (вводил как показано на скриншоте и нажимал в конце строки клавишу Enter):
Вставил из буфера обмена команду для создания сертификата (можете скопировать её из этой строки):
certbot certonly –authenticator manual
И нажал клавишу Enter.
Перед нажатием Enter окно PowerShell выглядело с этой командой так:
Система предложила ввести свой email (я ввёл), согласился с условиями (нажимая клавишу Y), в следующий раз программа на этом шаге уже не просила вводить email, а сразу предлагала ввести имена доменов (я вводил сразу по два – второй с www, через запятую):
Программа попросила создать файл проверки прав на домен. При этом показано какую строку символов и в файл с каким именем поместить, по какому адресу на веб-сервере этот файл положить:
Поскольку я вводил по два доменных имени (обычное и с www), то после нажатия Enter программа точно так же просила создать ещё один проверочный файл.
С помощью Filezilla Client я создал нужные файлы по требуемому адресу, создав нужные директории. Выделенный текст из окна PowerShell можно копировать просто правым кликом, или привычным сочетанием клавиш Ctrl+C.
Нажал клавишу Enter для создания сертификата, но только после того, как проверочные файлы на веб-сервере были созданы.
Система сообщила об успешном создании файлов сертификата, которые я нашёл на своём локальном компьютере, в папке:
C:Certbotarchive
Если бы сертификат не был создан, то программа сообщила бы об ошибке.
Вот и всё, сертификаты готовы!
Для установки их на хостинг мне потребовались три файла из четырёх, из данной папки:
Через каждые 90 дней нужно перевыпускать сертификат заново.
P.S.:
Я ещё не озадачился тем, как автоматизировать описанный выше процесс (мне интересен перевыпуск сертификата именно на локальном компьютере с Windows). Было бы здорово, если бы знающий человек написал в комментариях как это сделать.
Что написать на кнопке: “с вас тысяча рублей” или “подайте на хлебушек”? Влияют ли мемасы на продажу платных сервисов? Какую таблетку пользователи предпочитают чаще – красную или синюю? А если предложить им зелёную, то поползут ли метрики вверх? На эти вопросы можно получить ответ, если проводить А/В-эксперименты и growth hack-сессии.
Меня зовут Денис, я бэкенд-разработчик в hh.ru. Эта статья о том, как мы проводим и анализируем различные эксперименты. Дам немного теории, слегка обрисую внутреннюю кухню и расскажу с какими проблемами могут столкнуться команды, которые только внедряют у себя А/В-эксперименты.
А и B сидели на проде
Для начала поговорим о том, кто вообще такие эти А/В-тесты и для чего они нужны.
Идея А/В-тестов предельно проста – пользователи приложения или сайта делятся на две группы или больше. Группа А – контрольная, пользователи этой группы видят приложение или сайт без изменений, as it is. Группа B и остальные, если они есть – экспериментальные. Пользователи из этих групп видят сайт или приложение в несколько измененном виде: с дополнительной функциональностью, измененным дизайном или иначе работающими компонентами.
Короче говоря, в одно и то же время разные группы пользователей видят приложение или сайт по-разному.
Зачем нужны A/B-тесты?
А нужны они вот зачем. При разработке продукта необходимо, чтобы изменения не приводили к ухудшению пользовательского опыта или оттоку пользователей, а наоборот – UX улучшался, пользователям становилось хорошо и их количество возрастало. Если же выпускать изменения без оглядки на реакцию пользователей, руководствуясь лишь своим “чутьем”, то возникает большой риск не заметить что-то, из-за чего пользователям стало хуже. Откатывать неудачные изменения сложно и дорого, гораздо проще провести эксперимент, который можно просто выключить в случае провала.
Метрики или что компании знают о пользователях
Обычно, когда компании приходят к идее А/В-экспериментов, они уже что-то анализируют: собирают метрики, по которым ориентируются на реакцию пользователей. Это может быть время, проведенное на сайте, количество кликов, средний чек покупки etc. Соответственно, когда вы планируете будущий эксперимент, необходимо заранее определиться с метриками, на которые ваш эксперимент должен повлиять. Например, при тестировании различных моделей поиска в hh.ru, одной из ключевых метрик может быть количество откликов соискателей на вакансии из выдачи. А если мы говорим про эксперименты в области монетизации и прайс-листа, то ключевыми метриками станут конверсия покупок или средний чек.
Когда начинать собирать результаты?
После того, как метрики определены, пользователи разбиты на группы и эксперимент запущен, остается дождаться “вызревания” эксперимента – когда придёт нужное число пользователей, чтобы мы смогли анализировать результат. Пример определения такого числа пользователей можно посмотреть в калькуляторе Эвана Миллера. Затем можно интерпретировать результат.
А может сразу на всех раскатить?
Но почему бы не выкатить изменения сразу на всех пользователей? Ведь потом можно просто сравнить метрики после изменений со старыми метриками. Не совсем так. Важную роль играет сезонность: показатели откликов, числа покупок и среднего чека, могут меняться не только от сезона к сезону, но и различаться в рамках недели. И отследить, связаны ли изменения в исследуемых метриках с новой функциональностью или же сезонностью бывает довольно сложно.
Гроусхачим на всю котлету
Говоря про А/B тесты нельзя не затронуть тему гроусхаков.
Гроусхаки – это такие незначительные изменения в дизайне или функциональности, которые могут привести к значительному росту метрик. Отсюда название “growth hack” – сломали привычную систему роста. Из примеров: смена кнопки “положить в корзину” или изменение ее расположения на сайте может привести к значительному росту конверсий покупок. Но может и не привести. Чтобы проверить, к чему в итоге приведут изменения, отлично подходят А/В-эксперименты.
Но не каждый гроусхак в итоге можно провести через А/В. Например, он может быть чересчур экспериментальным, и мы не хотим раскатывать такую функциональность на большое число пользователей. Или становится понятно, что эксперимент придется держать месяц, что в корне не соответствует концепции быстрой проверки. В таком случае можно отойти от А/В-метода в сторону глубинных интервью с пользователями.
В названии “Growth hack” два слова, и “hack” здесь далеко не случайно. Ведь для создания гроусхаков вводятся особые правила. Часто что-то пилится прямо на коленке: в виде развилок в коде if-else, делается упрощенный code review для ускорения вывода на прод. Самое главное, чтобы такие хаки могли моментально выпилиться из кода и не отравляли кодовую базу.
Особые правила гроусхаков
В hh.ru мы часто проводим так называемые “гроусхак-сессии”: продакт, проджект и несколько разработчиков собираются в одной комнатушке и генерируют массу разных гипотез. Какие-то отметаются сразу, какие-то требуют большого количества ресурсов, но есть и те, которые могут принести существенную пользу. Такие сессии могут помочь вам получить множество инсайтов о вашем продукте и аудитории, так что настоятельно рекомендую попробовать.
Теперь на практике
Т.к. я сам из команды “Монетизация”, то и наши эксперименты так или иначе будут связаны с прайс-листом и предоставляемыми услугами. Процесс создания новой услуги, продаваемой на сайте, не прост. Необходимо завести новый код услуги, добавить логику обработки в биллинге, согласовать формулировки закрывающих документов с юристами, сверстать и закодить основную логику. Необходимость всех этих действий сильно замедляет и усложняет процесс вывода новой функциональности. Тратится время и ресурсы команды, притом заранее никогда неизвестно, будет ли востребована новая услуга или все усилия окажутся напрасными. Чтобы предотвратить напрасную трату ресурсов, можно прибегнуть к А/В-тестам и протестировать услугу в несколько упрощенном виде.
Сформулируем гипотезу
Одна из предоставляемых нами услуг – это доступ работодателей к базе кандидатов. Клиенты бывают разные: крупные компании, где найм ведётся 365 дней в году 24/7, и совсем небольшие, которым новый сотрудник нужен раз в пятилетку. И кажется логичным дать последним возможность просмотра контактов поштучно, небольшими пакетами по 1-10 штук. Но внедрить такую услугу – довольно большая задача, которая потребует участия множества людей из самых разных сфер: начиная от разработки с QA и заканчивая маркетингом с юристами. Поэтому надо провести небольшой эксперимент, который позволит понять, а стоит ли овчинка выделки.
Заводим эксперимент в ABT
Итак, мы сформулировали гипотезу. Теперь для нее нужно завести эксперимент. Для этого существует большое количество различных инструментов, например, Google optimise, AB Tasty, Firebase, которые позволяют создавать эксперименты и интерпретировать результат. Каждый из них обладает своими преимуществами, недостатками и ограничениями. Мы в hh.ru используем свой сервис для проведения А/В-тестов – hhABT. Он позволяет проводить эксперименты, добавлять какие-то метрики и интерпретировать результаты. Более подробно про нашу ABT-платформу расскажем в отдельной статье.
А что дальше?
А дальше нужно писать код. Создавать новую услугу с нуля – это слишком большая задача, поэтому поштучные доступы мы реализовывали на уже существующей функциональности. Мы умеем ограничивать длительность доступа и число просмотров контактов, поэтому просто завели две новые конфигурации существующих услуг: доступ на 10 дней с одним просмотром и доступ на 30 дней с десятью просмотрами. После этого выделяем эти конфигурации на нашем UI, где продаем эти услуги.
Акцентируем внимание на количестве контактов, а не на длительности
Делаем акцент на числе просмотров, раскрашиваем баннерами, чтобы привлечь внимание.
Карточку с экспериментальным продуктом выделяем другим цветом на нашем UI
И всё, что нам остается сделать – это включить эксперимент и дождаться сбора метрик.
Результаты эксперимента
Прошло несколько недель, мы собрали результаты. И благодаря им поняли, что в таком виде добавлять новую услугу не стоит. Возможно, если изменим конфигурацию, целевую аудиторию и стоимость, у нас получится что-то полезное. Но, так или иначе, мы сэкономили кучу времени и получили новые знания о нашем продукте.
Подытожим
Давайте подведем итоги:
А/В-эксперименты позволяют определить, куда двигаться вашему продукту дальше. Какие фичи вызывают у пользователей экстаз, а от каких они уходят в отказ.
Гроусхаки – полезные штуки, которые позволяют быстро получить инсайты о вашей аудитории, а также могут резко и быстро повысить или понизить метрики.
Есть множество платформ, которые позволяют вам проводить А/В-эксперименты. Мы, например, написали свою. Возможно, в вашем случае дешевле будет использовать готовую.
Вот так мы и проводим в А/В-тесты в hh.ru. Расскажите о своем опыте и задавайте любые вопросы, я буду рад на них ответить.
Два года назад, утомлённый длинным списком нереализованных идей проектов в телефоне, я решил попробовать осуществлять по идее за неделю в их минимальном виде.
Мне так и не удалось придерживаться еженедельного графика, однако я продолжал неторопливо работать, пока не выпустил восемь проектов.
Каждое утро я сидел с кофе и набрасывал код какого-то проекта. Это моё любимое хобби, а теперь оно стало приносить приличный пассивный доход.
В этом посте я хочу рассказать о том, что я выпустил, и поделиться тем, чему научился в процессе создания этих крошечных Интернет-проектов.
Начнём с самого начала.
Tiny Website
Первый мой проект — это блог, в котором я опубликовал статью.
В этом блоге я намеревался просто документировать все остальные проекты.
Я запустил его на следующий день после того, как мне исполнилось 25, и первый написанный пост «Tiny Websites are Great» оказался довольно популярным; это было очень кстати и мотивировало меня двигаться дальше.
С тех пор изменилось немногое. Я написал 17 постов и, разумеется, теперь на сайте есть тёмный режим.
Объективно, судя по просмотрам страниц, это мой самый успешный проект.
Запущен: в мае 2020 года
Просмотров страниц: 840 тысяч
Доход: 0 фунтов
Доменные имена Кремниевой долины
Неделю спустя после запуска блога я решил, что будет гениальной идеей купить доменные имена нескольких FAANG-компаний, например,
google.קום
Это было не совсем проектом, но меня всегда интересовали домены, и написанный мной пост «I bought netflix.soy» снова завирусился.
Я по-прежнему владею netflix.soy. Учитывая рост цен на акции Netflix, возможно, когда-нибудь он чего-то будет стоить.
Запущен: в мае 2020 года
Требований Facebook о прекращении нарушений: 1
Доход: 0 фунтов
8-битная «Королевская битва»
Следующим сделанным мной проектом стала небольшая 8-битная игра для Android в жанре «королевская битва».
Создавать её было очень интересно, но в результате это оказался мой наименее успешный проект.
На её выпуск никто не обратил внимания, что очень разочаровало после успеха предыдущих постов.
К сожалению, я утерял код игры после замены ноутбука. Она по-прежнему работает, но очень забагованная. Впрочем, это не помешало кому-то стримить её на Twitch в прошлом месяце.
Выпущен: в июне 2020 года
Скачиваний: 183
Доход: 0 фунтов
Магазин для одного товара
Затем я собрал генератор онлайнового микромагазина, продающего на повторе один и тот же товар; можно сказать, это крошечный Shopify.
Я работал над этим проектом в течение двух недель, а затем опубликовал его на Product Hunt.
Как ни странно, люди начали продавать в нём реальные товары, что позволило мне заработать аж целых 1,63 фунта (комиссионный сбор в 1%).
Хотя этого не хватило бы даже на гамбургер, я впервые ощутил вкус Интернет-денег, и как же он мне понравился!
Внезапно, спустя несколько месяцев после запуска One Item Store со мной связался покупатель с предложением его продать.
В результате я продал его за 5300 долларов, и это взорвало мой крошечный мозг.
Запущен: в июне 2020 года
Просмотров страницы: 28 тысяч
Доход: 1,63 фунтов
Snormal
Завоевав мир электронной коммерции, я решил, что следующим логичным шагом будет создание социальной сети.
Спустя несколько недель я запустил «Snormal»: социальную сеть для публикации повседневной обычной информации типа «сегодня я съел багет».
Оказалось, что подобную социальную сеть люди посещают без особой охоты, поэтому её веб-сайт практически мёртв.
Я забросил этот проект, но в него всё равно ежедневно приходит несколько пользователей.
Запущен: в августе 2020 года
Просмотров страницы: 9,8 тысяч
Доход: 0 фунтов
Earlyname
Я регистрировался во множестве новых продуктов, чтобы сохранить за собой «редкое» имя пользователя, например,
ben
. Мой следующий проект превратил это в бизнес.
Каждый месяц я отправлял рассылку с четырьмя новыми социальными сетями и сообщал, свободно ли выбранное имя пользователя.
За дополнительные 10 долларов в месяц я регистрировал эти имена на подписчиков.
Поработав над проектом месяц, я запустил «Earlyname» на Product Hunt, и, к своему удивлению, привлёк несколько платных клиентов.
В течение шести месяцев я отправлял рассылки, добившись дохода 350 долларов в месяц, но потом решил, что меня не радует его поддержка.
Уже имея опыт продажи одного проекта, я уверенно зарегистрировал Earlyname на MicroAcquire и продал его за 10500 долларов.
Запущен: в октябре 2020 года
Просмотров страницы: 10 тысяч
Доход: 4200 долларов в год
Mailoji
Однажды я узнал, что в адресах электронной почты можно использовать эмодзи-домены, например
Осознав, что существует множество свободных эмодзи-доменов .kz, я решил, что будет здорово купить 300 казахстанских эмодзи-доменов и запустить сервис эмодзи-адресов электронной почты.
Месяц спустя после запуска у меня было 150 клиентов, но на самом деле я ушёл в минус из-за оплаты доменных имён.
Как и в случае с остальными проектами, я написал пост в блог и выложил его на Hacker News.
В течение получала пост никак себя не проявлял, а потом его популярность взлетела до небес.
За выходные я продал подписок на 9 тысяч долларов; самая большая сумма, которую мне удавалось заработать за такой короткий промежуток времени.
Mailoji по-прежнему живёт и процветает, теперь он имеет 700 эмодзи-доменов. Я коллекционирую их как покемонов. Недавно я поймал ❤️.gg.
Теперь даже можно создавать адреса электронной почты, целиком состоящие из эмодзи, например, 🦄🚀@🍉.fm.
Запущен: в марте 2021 года
Просмотров страницы: 129 тысяч
Суммарный доход: 18500 долларов
Paper Website
Мне очень нравится писать ручкой на бумаге, и я хотел начать публиковать ежедневный блог.
За несколько недель я создал прототип приложения, позволяющего сделать снимок рукописной страницы и превратить его в веб-сайт.
Немного побаловавшись с написанием «бумажных блог-постов», я решил превратить прототип в полнофункциональный сервис Paper Website.
Я купил 100 блокнотов для раздачи первым клиентам и приготовился к запуску.
К счастью, сервис стартовал успешно. Свой бумажный веб-сайт создало более двухсот людей, и у меня на кухне осталось лишь несколько блокнотов.
Мой ежедневный блог работает на Paper Website, и я написал от руки более ста бумажных блог-постов, ни разу не порезавшись бумагой.
Запущен: в ноябре 2021 года
Просмотров страницы: 69 тысяч
Доход: 9370 долларов в год
Плюсы крошечных проектов
Быстро разрабатывать множество крошечных проектов очень интересно. И это основная причина, по которой я этим занимаюсь.
Однако после каждого запуска я постепенно учусь тому, что делает проект «успешным». После восьми запусков я начинаю видеть некие паттерны.
Кроме того, я понял, какими микробизнесами мне нравится заниматься: я не люблю составлять рассылки, но люблю странные технические проекты, генерирующие пассивный доход. Я ни за что не узнал бы этого, запустив только один проект.
Самое лучшее в крошечных проектах то, что они настолько малы, поэтому ставки невероятно низки. Нет никакого давления — если какой-нибудь из них закончится неудачей, можно двигаться дальше без ощущения вины и попробовать заново.
Ещё один неожиданный выигрыш заключается в том, что за два года создания таких проектов мои навыки разработчика улучшились в десять раз. Я и раньше был хорош, но теперь нахожусь на другом уровне.
Минусы крошечных проектов
Большой вопрос, стоит ли запускать кучу мелких проектов или сосредоточиться лишь на одном.
Лично мне нравится стратегия «микроставок», но я часто задаюсь вопросом, смог бы ли я добиться большего финансового успеха, если бы я уделил всё своё внимание одному проекту.
В настоящее время у меня три активных проекта, работающих на автопилоте. С тайм-менеджментом и переключением контекстов я справляюсь, но при пяти и более активных проектах это может стать уже затруднительным.
Ещё один странный недостаток заключается в том, что в процессе привлечения аудитории при создании этих проектов, я иногда задавался вопросом: «нужно ли создавать что-то только ради „лайков“».
Это соблазнительная мысль, потому что я знаю, что смог бы, и всё бы, скорее всего, получилось. Но мне кажется, что это верный путь к быстрому выгоранию.
Выводы и будущее
Когда я приступил к этой миссии, у меня был большой список идей проектов, накопившихся в телефоне. Возможно, у вас есть подобный список.
Два года спустя я осознал, что многие из этих первоначальных идей попросту ужасны.
Это парадокс, но я обнаружил, что мои лучшие идеи теперь появляются при реализации других идей.
В обычной жизни я никогда бы не подумал о сервисе эмодзи-адресов электронной почты, если бы не решился на глупый эксперимент с доменами и не купил netflix.soy.
Если у вас возник ступор с идеями, то рекомендую что-нибудь создать; что угодно, пусть даже это ужасно; я гарантирую, что вскоре после этого в голове появится идея получше.
Каждый создаваемый мной проект содержит искру, взятую из предыдущего. Это похоже на то, как обезьяна скачет с лианы на лиану, только лианы — это проекты, а я всего лишь глупая обезьяна.
Я хочу продолжать десятками лет работать над созданием крошечных проектов и с радостью жду появления новых идей.