Компоненты веб-интерфейса

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

Я решил не переживать, дочитают ли мой текст до конца и что обо мне подумают дочитавшие (но, думаю, воронка получится узкой). Что меня действительно беспокоит: за все эти годы у меня ни с кем не получилось поднятую тему обсудить (по разным причинам). Поэтому текст неприлично длинный, довольно подробный, со множеством лирических отступлений; а еще там куски кода, цитирование Щедровицкого, наброски моих интерфейсов, что-то про лингвистический детерминизм и пренебрежение догмами, на которых зиждится промышленная веб-разработка, что на всех конференциях делает вид, будто у нее все просто замечательно (ну вот, я уже).

Захлебывающееся проектирование

Начиналось всё, как на Диком Западе: сайты экстенсивно росли и вбирали десятки мертвых страниц, соединяя их гиперссылками. Стать HTML-верстальщиком можно было за неделю; ниш хватало на всех; люди были рады уже тому, что их веб просто работает. Низкий порог входа в индустрию и высокий болевой порог пользователя позволяли не думать об «экологии».

Сначала рынок выделил три основные роли для участников процесса:

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

За кадром остались маркетологи, сисадмины, тестировщики, тех. писатели — т.к. они в меньшей степени влияют на проектирование.

Мыслить продуктом удобнее: он не привязывается ни к технологии, ни к онлайну, и подразумевает определенные сценарии использования, целевую аудиторию, функции, без которых выпускаться нельзя, показатели успеха/неуспеха и запасы по ходам в развитии.

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

Первая на моей памяти волна js-фреймворков: jquery, mootools, prototype — оживляет веб, но процесс разработки остается бомбой замедленного действия: трудозатраты на внедрение очередной функциональности растут экспоненциально, проекты захлебываются. Следом приходили новые волны фреймворков, которые навязывали свой словарь абстракций, новые способы установления связей и втаптывали в грязь предыдущее с его недостатками: «не поняли вы суть MVC», «MVC в чистом виде не существует», «MVC не хватает еще одной буквы», «ООП не решает моих проблем, а лишь создает новые», «данные надо передавать в одном направлении», «о боже, у вас данные мутируют». Бесконечная конкуренция за внимание.

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

  1. Отсутствие единого для всех ролей в команде словаря компонентов продукта.
  2. Несогласующиеся методологии работы с компонентами у менеджеров, дизайнеров и разработчиков.
  3. Инструменты проектирования и разработки с креном в ту или иную догму и понятные лишь разработчикам.

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

Начнём с начала

Абстрактное мышление — процесс когда мы в уме манипулируем названными проекциями объектов реального мира. И здесь я уточняю объекты до компонентов интерфейса.

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

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

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

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

https://vimeo.com/180190633

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

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

Если вы дизайнер, менеджер или разработчик, можете провести эксперимент — разберите свой продукт на составные части и проверьте:

  • А продукт вообще разбирается? [Помещается ли он в голову?]
  • Для каждой ли части найдется имя в вашем лексиконе? [Сформирован ли язык?]
  • А какие имена используют ваши коллеги?
  • Устоялись ли схемы принятия решений о судьбе частей? Как создавать новое. Как изменять старое. [Есть ли методология?]
  • Насколько гармоничны отношения родительских частей с дочерними?

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

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

  • Как дизайнер вы рискуете растянуть разработку на месяцы, когда безобидная правка макета встанет поперек зафиксированной в коде системы. Суть противоречия вы, скорее всего, не поймете, потому что будете говорить на разных языках — и перейдете к торгам. И так многие ваши правки будут вставать поперек системы, потому что вы отказываетесь эту систему изучать.
  • Как менеджер вы можете бороться со сложностью и скоростью разработки наймом и планированием — но до тех пор, пока у вас хватает денег и пока это помогает. Однажды вокруг неработающей формы оплаты соберется митинг из десяти программистов, на котором выяснится, что скоро следующий митинг, а форма оплаты — не самая важная проблема.
  • Как разработчик вы способны плодить сущности не хуже остальных участников: несогласованные с анатомией продукта требования менеджера и спонтанные графические решения дизайнера выльются в дубликаты, подпорки и заплатки на вашей стороне. Вам даже документация не поможет, потому что в бардаке её никто не будет читать. А ещё вы можете взять всё под свой контроль и начать принимать решения и за менеджера, и за дизайнера — «в конце останется только один».

В чем коварство ситуации — никто не поймет этого сразу. Понимание приходит постепенно, с ростом сроков, с количеством седых волос.

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


Существующие системы компонентов

Тут есть чему поучиться у старших братьев — операционных систем. Цена архитектурной ошибки у них несоизмеримо выше, как и порог входа специалиста в индустрию. Я часто опираюсь на их опыт. Рассмотрим архитектуру UI-классов Cocoa Framework (библиотека iOS-компонентов):

Всё внимание на узел UIView

Сейчас я пробегусь по основам ООП — важно наметить язык, который мы будем в дальнейшем развивать и дополнять. Чтобы не сорить терминами, я буду называть UI-классы компонентами.

Нас интересует ветка UIView — этот компонент дает жизнь текстовым полям, картинкам, контролам и прочим визуальным элементам. Далее внимание на кнопку (UIButton):

Связи между компонентами определяются наследованием: потомок наследует признаки предка и добавляет свои. UIButton — потомок UIControl, который в свою очередь потомок UIView. Обязанности распределены между компонентами так:

UIControl собирает в себе поведение, общее для всех контролов, а внешний вид и характерное именно для кнопки поведение собрано в потомке UIButton. Это позволяет переиспользовать «опыт предков» и распределяет сложность реализации по черным ящикам (aka инкапсуляция).

Грамотная архитектура компонентов определяет живучесть всей системы. Потому что мир постоянно меняется, требования к системе тоже — новые компоненты рождаются, старые умирают. С этими процессами надо не бороться, ими следует управлять.

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

Для красоты рассказа я наследуюсь; но именно от UIButton разработчики фреймворка рекомендуют не наследоваться — по ряду причин предлагается более безопасный механизм Object Composition, что своего рода тоже наследование, но с ограничениями.

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

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

Многие не представляют себе, какое количество труда втаптывается в грязь, когда приходят новые участники в команду и начинается: новые цели, новые планы и новый дизайн, господи. Я переплетаю вопросы проектирования, программирования и человеческих отношений, потому что вижу, как одно рушит другое. Очень часто дизайнеры и понятия не имеют о структуре связей, зафиксированной в коде; менеджеры лишь поверхностно вникают в то, что прорабатывают дизайнеры; а программисты перепридумывают архитектуру интерфейса, которую уже придумал дизайнер, но выразил молчаливым макетом. Если сторонам и удается достичь хрупкого взаимопонимания, оно всё равно не фиксируется на понятном всем языке. Важнейшие решения продолжают принимать в коридорах, лифтах, сабтасках и тредах, где тебя нет в копии — да, команда не может быть всё время вместе, но единая модель продукта, выраженная формальным языком, могла бы всех синхронизировать.

Мнения против

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

Каждый, кто трогал ООП, наверняка проваливался в inheritance hell, путался в границах объекта, затем читал статьи, что всё это — огромная ошибка, и надо возвращаться к процедурному или даже функциональному подходу (можно много такого найти по запросам «oop goes wrong» или «diamond problem»).

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

Со мной иногда спорят, что иерархии устарели, и будущее за категориями (например, теги в постах). Только вот что вы предпочтете в качестве конечного продукта: книгу с классическим содержанием или аналогичные посты с тегами; треки размеченные по жанрам и исполнителям или собранный в высказывание альбом? Категории тоже ценны и важны, из них можно делать срезы, строить разные иерархии — но с моей точки зрения, это материал, а не конечный продукт.

Мне и правда хочется рассуждать и рассуждать на эту тему, хотя рассказ не совсем об этом. Если вам доводилось писать ОО-код на языках, которые его синтаксически не поддерживают (perl, например), где всё собирается на голой ссылочной модели, вы, возможно, спокойнее отнесетесь к ограничениям применимости наследования — там как-то сразу становится ясно, что оно нужно для вынесения общих знаменателей за скобку, поэтому часто родительский класс создается задним числом. Если что-то за скобку не выносится, это никакая не проблема, а другой сценарий, для которого подойдут композиция, интерфейсы, протоколы и пр. И наоборот, в повсеместной композиции (aka «убийцы наследования») я вижу другую проблему: нужно носить за собой знание, какому объекту какой метод принадлежит; с ростом глубины композиции объем знания тоже растет; и ещё где-то рядом поджидает проблема сильного связывания.

Слой семантики

Интерфейс существует и меняется во многих измерениях. Не все измерения были мне открыты сразу.

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

Семантика интерфейса— иерархия поименованных частей.

Веб-дизайнеры иногда выражают её структурой слоёв (но в большинстве случаев ни о какой семантике они не думают), а фроненд-разработчики — DOM-структурой и CSS-классами. И оба этих способа плохие.

Про разного рода photoshop etiquette я даже писать не хочу. По-моему, единственное, на что стоит тратить время в графредакторе — графика. Ребята, не сходите с ума, пожалуйста; хотя, это ваше право. Но никто из посторонних не воспримет всерьез вашу структуру слоёв; да и вы через месяц тоже.

У фронтенда тоже странная ситуация (рассказываю дизайнерам). Не так давно многие верили в семантическую верстку — последний вздох морально устаревшей идеи HTML: когда списки предлагалось верстать исключительно тегами <ul> и <li>, заголовки непременно <h1>…<h6>; позже с выходом HTML5 неуклюжих правил досыпали: для навигации <nav>, для чего-то второстепенного <aside> и так далее. Якобы поисковикам понятнее, якобы верстальщикам удобнее, якобы браузерам приятнее.

Проблема в том, что насколько далёк от предметной области продукта тэг <b> (от слова bold), настолько же от неё далек псевдосодержательный <strong> — элемент login-tabs-item на моём экране жирный просто потому что я так решил, и это никак не связано с его семантикой. Завтра я решу что некоторый список пунктов user-stats лучше сделать строчкой текста — семантика при этом останется прежней. HTML в попытке мне помочь просто путается под ногами:

<h1 class="form-title">
<nav class="main-navigation">
<ul class="user-stats">

И в какой-то момент многие устали от этих суеверий:

<div class="form-title">
<div class="main-navigation">
<div class="user-stats">

С CSS ситуация немного лучше, но лишь немного. Классами я могу выразить семантику своей предметной области, но фокус почему-то остается на вырожденном HTML:

<div class="head">
<div class="menu">
<div class="item selected">...</div>
<div class="item">...</div>
<div class="item">...</div>
</div>
</div>

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

<div class="...">

Этому не сопротивляется даже топовый фреймворк React, где ничего не означающий виртуальный элемент <div> преобразуется в функцию React.createElement(‘div’), которая возвращает некий объект, который всё равно выводится в браузер как <div>. И ещё своеобразная ирония есть в синтаксическом конфликте — это HTML, но не совсем: вместо привычного <div class=”…”> просят писать <div className=”…”>, потому что у программистов всему найдется объяснение.

render() {
return (
<div className="MarkdownEditor">
<h3>Input</h3>
<textarea
onChange={this.handleChange}
ref="textarea"
defaultValue={this.state.value} />
<h3>Output</h3>
<div
className="content"
dangerouslySetInnerHTML={this.getRawMarkup()}
/>
</div>
);
}

Другими словами, никто не хотел исправлять ситуацию. И на этой странной почве росли разные семантические нотации CSS-классов:

<div class="item selected">...</div>
<div class="item state-selected">...</div>
<div class="item item-selected">...</div>

А давайте представим, что кроме признака «selected» ещё появились: тема внешнего вида, указание ширины в колонках сетки и класс для корректной работы внешнего плагина; потом могут приехать дополнительные атрибуты.

<div class="item item-selected theme-dark grid-col-3 plugin-tooltip" data-tooltip-event="hover">...</div>

То, что было похоже на семантику, уже стало месивом. А я даже не начинал говорить о первичных признаках (имя компонента) и вторичных (состояние, стиль, поведение и пр.). И тем более я не касался вопросов методологии декомпозиции: как определять границы компонента, что является компонентом, а что его частью, и как это наглядно показать.

Задача грамотной декомпозиции веб-интерфейса долгое время оставалось нерешенной. Я считаю, во-многом потому, что ей досталась такая ущербная форма — строчка CSS-классов. Это как изучать мир через замочную скважину.

Декомпозиция по методологии БЭМ

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

Кому интересна история вопроса, технические предпосылки и мотивы конкретных решений — вот вам лекция Витали Харисова (один из отцов-основателей).

Теперь подытожу:

БЭМ — методология декомпозиции интерфейса на компоненты и определения их границ; независимые компоненты называются блоками, компоненты, не имеющие смысла вне блока, называются элементами, а изменяемые признаки компонентов называются модификаторами.

Но поскольку все привыкли видеть и выражать семантику интерфейса в CSS-классах, то и удобство БЭМ оценивали через эту призму:

<div class="menu__item menu__item_state_selected theme_dark grid__col_3 plugin-tooltip" data-tooltip-event="hover">...</div>

«Нет, ну и куда это годится? Стало только хуже.» — мало кто видел в БЭМ определение, которое я дал выше. Сегодня среди разработчиков с пониманием сути становится лучше. Осталось отказаться от работы с семантикой в терминах HTML.

Сами авторы БЭМ предлагают работать с такой JSON-семантикой (была методология, теперь имплементация):

{
block: 'head',
content: {
block: 'menu',
content: [
{elem: 'item', mod: {state: 'selected'}, content: ...},
{elem: 'item', content: ...},
{elem: 'item', content: ...}
]
}
}

Которая компилируетя в соответствующий HTML:

<div class="head">
<div class="menu">
<div class="menu__item menu__item_state_selected">...</div>
<div class="menu__item">...</div>
<div class="menu__item">...</div>
</div>
</div>

И, с одной стороны, это важный шаг — перестать руками трогать HTML. С другой, я вижу две проблемы:

  1. Убрали одну формальность, но добавили другую — повторяющиеся конструкции «block:», «elem:» и «content:» заслоняют мне семантику предметной области (жирным я выделил то, что имеет смысл).
  2. Данные отделили от работы с ними — вернулись в процедурную эпоху программирования (да-да, immutable data, MVC — я в курсе, но всё равно не согласен).

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

<Head>
<Menu>
<item state="selected">...</item>
<item>...</item>
<item>...</item>
</Menu>
</Head>

Я работаю с иерархическими структурами всю свою сознательную практику. Ничего удобнее и универсальнее XML я не встречал. Основные конкуренты, видимо, JSON и YAML. Но там нет разделения данных на содержимое узла и мету (зато есть костыли с резервированием названий полей для меты); и глубокие вложенности эти форматы визуализируют очень плохо.

Вплетание XML-синтаксиса в Си-подобный я впервые увидел у ActionScript 3 (помните такой?). Поначалу это смотрелось диковато, но в процессе понимаешь, насколько это удобно. А недавно все распробовали JSX, в том числе и я.

Декларативный подход

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

Году в 2008 я столкнулся со всеми забытой технологией XSLT — у неё был избыточный синтаксис, нетривиальные решения тривиальных задач (циклы выражались рекурсией, хоть это и не баг, а фича), но методологически инструмент был очень выверенным для своих задач. Никогда не забуду свой путь: от вскипающих после первого погружения мозгов (рекурсия контекстов, отсутствие классических переменных) до момента просветления и принятия методологии.

XSLT — декларативный подход к трансформации XML-деревьев. Что в нём было такого особенного:

  1. Понятие селектора — путь до контекста в структуре данных.
  2. Понятие шаблона, который устанавливал соответствие селектора контекста и правил его обработки.
  3. Шаблоны применяются в порядке срабатывания селекторов, начиная с корня исходного дерева. Набор шаблонов был базой знаний о том, как поступать в тех или иных контекстах. Это очень похоже на модель человеческого опыта.

Инструмент заставлял искать оптимальную декомпозицию шаблонов и поднимал правильные вопросы. Так шаблоны превратились в компоненты: стремление переиспользовать шаблоны в схожих ситуациях склоняло к переопределению (наследование компонентов); а декомпозицию шаблонов (структуру компонента) в последствии удачно описала БЭМ-методология.

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

Эталон компонента

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

Формальное описание абстрактной кнопки в моей голове выглядит так:

КНОПКА:
Наследует свойства от: Контрол, Сетка и Типографика
Стандартные значения свойств:
Высота: средняя
Ширина в колонках сетки: не определена
Размер текста: средний
Главная на экране: нет
Ссылка: не определена
Структура:
Содержит иконку или текст
Реакции:
При нажатии:
Уводит по ссылке при наличии такого свойства

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

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

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

Такое описание я называю декларацией компонента. И, на мой взгляд, это самое удобное и наглядное описание интерфейсного элемента:

  1. Такую лесенку удобно пробегать глазами, как содержание книги или план рассказа.
  2. Иерархия объявлений свойств позволяет пере- или доопределять любую из веток дерева декларации.
  3. Порядок, состав и глубина такого описания не ограничена — компоненты могут добавлять свои поля и передавать их потомкам, создавая диалект поверх основного языка.

Вот вы и встретились

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

https://github.com/kovchiy/beast — внешний репозиторий с неактуальной документацией. Простите, не успеваю за всем.

https://github.com/kovchiy/beast/tree/master/docs/beast-practice — cookbook. Тоже недописанный.


— А можно сразу вопрос?

— Да, конечно

— Вам так нравится Bloodborne?

— Очень нравится.

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

— То есть вы спрашиваете, зачем вам знать об очередном велосипеде? Относитесь к этому как к формализации всего того, о чем я говорил выше. Мне нужно было на чем-то проверять и развивать свои идеи — со временем набор вспомогательных скриптов сложился в такую библиотеку. Больше всего я ценю в ней заложенную методологию — уверен, ее можно воспроизвести и в других средах; но там на меня, как на автора, давила чужая предметная область и чужие термины. Зато сегодня, если очень захотеть, Beast можно сделать надстройкой над другими инструментами.

[Еще несколько человек вышло из зала]


Выше я на псевдоязыке описал декларацию кнопки. А вот как эта декларация выглядит в Beast:

Вы дошли до первого босса

Декларация очень похожа на объявление класса — в общем-то, это оно и есть, но с некоторыми расширениями и допущениями: например, множественное наследование, выборочное наследование и перекомпиляция в рантайме некоторых методов (хотя я тут подумал, что ее стоит вынести на этап сборки). Я не стану объяснять каждую строку кода: выше есть две ссылки на детальное описание и в общем-то большая часть конструкций говорит сама за себя.

Итак, за что я полюбил этот формат:

  • Описание полного жизненного цикла компонента без распихивания разных его этапов по файлам и другим технологиям.
  • Тут же изоморфность: часть полей декларации могут выполняться на сервере, часть на клиенте. Ну или все может выполняться на клиенте — я не думаю об этом, когда описываю интерфейсный блок.
  • Предсказуемость кода — компоненты описанные разными людьми выглядят примено одинаково, одни и те же вещи лежат в одних и тех же местах.
  • Такую лесенку удобно документировать:
Да, у нас тут своя атмосфера и свой jsdoc
  • И очень удобно расширять. Например, захотел я к стандартному набору полей добавить счетчик статистики:
Я пропустил момент, когда инструмент превратился в язык создания языков

Какую задачу решаем?

Что еще оказало влияние на инструмент, так это то, что он написан дизайнером для дизайнеров. Да, у меня есть техническое образование (как вы уже могли догадаться), я более-менее в курсе заморочек и догм про то, как принято писать код, но мало что принимал на веру — это не экономило мне время, но помогало лучше понять суть вещей.

Технологии создаются под задачи бизнеса. Вот на React сильно сказалась специфика фейсбука с его ajax-цепочками запросов и точечным обновлением страниц. Технологии от Google обычно помешаны на скорости работы и потоковой шаблонизации — от них обычно слышишь про всякие веб-ассемблеры. Для Яндекса как для интернет-портала критично было создавать абсолютно независимые интерфейсные блоки, чтобы встраивать в любой контекст — так появился БЭМ.

Технологией для дизайнеров, пожалуй, долго время оставался jQuery — я сам очень любил эту штуку. Но был один существенный недостаток: код больших проектов быстро становился лапшой. Там, понятное дело, сказался и низкий порог входа, но технология все-таки не давала никаких направляющих рамок, а лозунгом «write less, do more!» поощряла сильное связывание и размывала границы компонентов.

Сегодня, как мне кажется, дизайнеры возвращаются в графические среды с элементами программирования: sketch, framer, etc. Я могу понять этих ребят — сам 50% рабочего времени провожу в скетче. Но, помимо того, что у всех этих редакторов есть потолок в развитии, они не сильно-то помогают инвестировать в тот самый единый словарь, о котором я говорил в самом начале.

Поэтому Beast создавался с сильным креном в ранние прототипы и постоянные изменения поведения компонентов и связей между ними. Чем отличаются условия работы дизайнера от условий разработчика — степенью детерменированности задачи. Разработчики требуют (вполне справедливо) четкой постановки задачи и под нее закладывают архитектуру, а затем обкладывают всё тестами и документацией. Для дизайнера, особенно на начальном этапе, что макеты и прототипы, что код — это постоянные эксперименты, прощупывание территории и способ общения с командой.

Компоненты в Beast сами себя обслуживают, сами ходят в API за данными, а друг с другом общаются по безопасным связкам. Автономность компонент снижает требования к качеству кода — сложность кода или нечеткая бизнес-логика одного компонента изолируется внутри него самого и не приводит к росту общей сложности системы. Консервативная распределенная модель, напротив, размазала бы неоптимальный код сразу по нескольким уровням — тогда и уборку делать сложнее.

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

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

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

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

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

Вижу, вы устали

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

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

Show your support

Clapping shows how much you appreciated Danil Kovchiy’s story.