Привет, меня зовут Pavel Germanika

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


 

Может ли человек, проживая в унылом бесперспективном городе, чего-то добиться, имея под рукой лишь старый ноутбук и интернет? Можно ли без всяких офисов, начальных капиталов построить компанию, приносящую неплохую прибыль? Ответ на этот вопрос вы сможете узнать в моем блоге. Я Pavel Germanika, добро пожаловать!

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

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

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

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

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

Любой из вас может связаться со мной. Я рад каждому! Пишите на мой Telegram.

Дайджест свежих материалов из мира фронтенда за последние две недели №323 (8 — 22 июля 2018)

Предлагаем вашему вниманию подборку с ссылками на новые материалы из области фронтенда и около него.

    Медиа    |    Веб-разработка    |    CSS    |    Javascript    |    Браузеры    |    Занимательное

Медиа

podcast Подкаст «Веб-стандарты», Выпуск №129: Вирус в npm, зачем Feature Policy, случай в Atom, мёртвый код, разделение ответственности, стрелка или пальчик
podcast Подкаст «Frontend Weekend»: #62 – Андрей Ситник о переезде в Нью-Йорк, путешествиях и порно в Твиттере , #61 – Андрей Мелихов о работе в Яндекс.Деньгах, Ночном фронтенде и захвате власти в devSchacht
podcast Подкаст «Девшахта/Ночной фронтенд»: #42 — Автоматизация CI/CD, #41 — В поисках хорошего code review
podcast Подкаст «Фронтенд Юность (18+)» #56 Токсичное сообщество
podcast Подкаст «CSSSR» Новости 512 — Выпуск №15 (16.07 — 22.07)

Веб-разработка

habr О чем должен помнить веб-разработчик, чтобы сделать всё по SEO-феншую
Расширения для Visual Studio Code, которые поднимут процесс разработки на новый уровень
en Веб-компоненты в 2018
en Святой грааль переиспользуемых компонентов: Custom Elements, Shadow DOM и NPM
en Подробности создания веб-интерфейса Google Photos
en Анатомия вредоносных скриптов: как веб-сайт может завладеть вашим браузером
en Доступность для команд — быстрое руководство по внедрению практик доступности и инклюзивности в процесс разработки вашей команды
en Будущее WebAssembly — взгляд на планируемые функциональности и предложения
en Анимация SVG с помощью SVGator

CSS

habr Справа налево. Как перевернуть интерфейс сайта под RTL
habr API CSS Paint
CSS: новый вид JavaScript
Химия CSS-гридов
en Полное иллюстрированное руководство по Flexbox
en 9 самых больших ошибок с CSS Grid
en DSS — финальный релиз первой беты Deterministic Style Sheets, аналога CSS модулей с автоматической компиляцией в атомарные CSS классы для маленьких бандлов
en Странные штуки, которые могут делать вариативные шрифты
en Как исправить проблемы CSS лейаутов?
en Полезные штуки, которые вы можете делать с CSS pointer events
en Стоит ли мне использовать IE версию Grid Layout в 2018?
en Я попробовал функциональный CSS и он типа отстой
en Как стать лучше в написании CSS

JavaScript

habr Сравнение JS-фреймворков: React, Vue и Hyperapp, Re: «Сравнение JS-фреймворков: React, Vue и Hyperapp»
habr JavaScript ES6: слабые стороны
habr Метапрограммирование в JavaScript
habr 15 HTML-методов элементов, о которых вы, вероятно, никогда не слышали
Матрица компетенций Fullstack JS разработчика
en Введение в JavaScript MutationObserver API
en Javascript ES6 — на самом деле вам не нужно изучать генераторы
en Анонс TypeScript 3.0 RC

  • Libs & Plugins:
    en Как создать современную панель управления на NVD3.js
    en coolHue — инструмент для подбора градиентов и создания своих палитр
    en draxt — NodeList-like/jQuery-like package для File System (node.js)
    en Popbox.js — небольшой плагин для создания наслаивающихся модальных окон. Плагин без зависимостей и полностью настраивается
    en Pushbar.js — небольшой плагин для создания выезжающих панелей в веб-приложениях.

Браузеры

В ночные сборки Firefox добавлен WebRender, использующий GPU для отрисовки web-страниц
В рамках проекта Browsh развивается консольный браузер на базе Firefox
Началось формирование ASan-сборок Firefox для выявления проблем при работе с памятью
en Три новые удобные функции в Chrome DevTools

Занимательное

Так много знаний, так мало времени
Быть многопрофильным специалистом, но рекламировать себя как специалиста в одной области
Быстрота Linux на Windows 10. Ода bash-терминалу в Windows Subsystem for Linux.
6 подходов к приоритизации задач. Опыт Readdle, MacPaw, Grammarly и EduNav
Google, Microsoft, Twitter и Facebook основали проект по обеспечению переносимости данных
В популярный NPM-модуль внедрено вредоносное ПО, копирующее параметры аутентификации
Алгоритмы спасают людей: как алгоритм подбора пар сохраняет жизни
Intel рассказала о 10 своих главных достижениях за 50 лет
Check Point представил обзор киберугроз за первое полугодие 2018 года: двойной рост криптомайнеров и смена вектора атак на облака
AMD, Microsoft, NVIDIA, Oculus и Valve разрабатывают стандарт VirtualLink, который позволит подключать VR-шлемы к ПК с помощью одного USB-C кабеля
Тёмный паттерн: как веб-сервисы заставляют пользователей ошибаться в своих действиях
video Как незрячий пользуется iPhone, MacBook и Apple Watch

Просим прощения за возможные опечатки или неработающие/дублирующиеся ссылки. Если вы заметили проблему — напишите пожалуйста в личку, мы стараемся оперативно их исправлять.

Дайджест за прошлую неделю.
Материал подготовили dersmoll и alekskorovin.

Метки:
Похожие публикации

Source: habr1

[Перевод] Выбираемся из кроличей норы SPA при помощи современного Rails

  • Перевод
TL;DR: Тропа SPA темна и полна ужасов. Ты можешь бесстрашно сражаться с ними… или выбрать другой путь, который приведёт тебя к нужному месту: современный Rails.

Я вспоминаю, как думал, что Rails фокусируется на неправильной цели, когда DHH анонсировали Turbolinks в 2012 году. Тогда я был убеждён в том, что мгновенное время ответа во время взаимодействия с пользователем — это ключ к превосходному UX. Из-за возникающих задержек сети, такая интерактивность возможна, только если вы минимизируете зависимость от сети и вместо сетевых обращений поддерживаете большую часть состояния на клиенте.

Я думал, что это необходимо для приложений, над которыми я работал. И с таким мнением я перепробовал множество подходов и фреймворков для реализации одного и того же шаблона: Single-page applications (SPA). Я верил, что SPA — это будущее. Несколько лет спустя, я не уверен в том, каково же будущее, но я точно хочу найти альтернативу.

Кроличья нора SPA

Одностраничное приложение — JavaScript приложение, которое, единожды загруженное, получает полный контроль без необходимости перезагружать страницу: рендеринг, получение данных с сервера, обработка взаимодействия с пользователем, обновление экрана…

Такие приложения выглядят более нативно чем традиционные веб-страницы, где приложение зависит от сервера. Например, если вы используете Trello, вы можете заметить насколько быстро создаются карточки.

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

C SPA всё несколько сложнее. Вам всё ещё нужно серверное приложение, включающую вашу доменную модель и правила, веб-сервер, база данных и какая-то технология доступа к данным… и ещё куча дополнительных штук сверху:

Для сервера:

  • API, удовлетворяющий потребности вашего клиента в данных
  • Система сериализации в JSON для обмена данными с клиентом и система кэширования, которая поддерживает это

Для нового JavaScript клиента:

  • Система шаблонов для преобразования данных в HTML
  • Представление вашей доменной модели и правил
  • Слой доступа к данным в клиентском приложении для передачи данных серверу
  • Система обновления представлений при изменении данных
  • Система для связи URL-адресов и экранов (надеюсь, вы не будете использовать один адрес для всего, это выглядит не совсем как веб-приложение)
  • Система для склеивания всех компонентов, необходимых для отображения экранов и получения данных для этого
  • Новые шаблоны и архитектура для организации всего когда
  • Система для обработки ошибок, логгирования, отслеживания исключений и т.д.
  • Система для генерации JSON для серверных запросов
  • Фреймворк для автоматизированного тестирования, поддерживающая ваш SPA
  • Дополнительный набор тестов для написания и поддержки
  • Дополнительный набор инструментов для сборки, упаковки и развёртывания нового приложения

Суммируя, с SPA у вас будет ещё одно приложение для поддержки. И новый набор проблем для решения. И заметьте, вы не можете заменить одно приложение другим. Вам всё ещё нужно серверное приложение (теперь оно будет рендерить JSON вместо HTML).

Если вы никогда не работали с SPA, вы можете недооценивать сложности, с которыми вы столкнётесь. Я знаю это, потому что я допустил те же ошибки в прошлом. Отрендерить JSON? Я могу с этим справиться. Богатая модель доменных объектов в JavaScript? Звучит забавно. И, знаешь, этот фреймворк решит все эти проблемы. Отличный пирог!

Неверно.

API и обмен данными.

Обмен данными между вашим новым приложением и сервером — сложная проблема.

Есть две противоположных силы:

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

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

Некоторые стандарты могут тут помочь. JSON API, чтобы стандартизировать JSON формат; или GraphQL, для выборки только нужных данных, таких сложных как потребуется, одним запросом. Но ни один из них не спасёт вас от:

  • Проработки каждого обмена данными
  • Реализации запросов, позволяющих выбрать данные эффективно на сервере

И оба эти аспекта представляют собой достаточный объём дополнительной работы.

Время начальной загрузки

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

  • Приложению нужны данные перед тем, как отрендерить что-то, и чтобы распарсить достаточно большой объём JavaScript нужно время.
  • Сверх начального HTTP запроса для загрузки приложения, обычно нужно сделать один или больше запросов для получения JSON данных, необходимых для рендеринга экрана.
  • Клиент должен преобразовать JSON в HTML, чтобы показать хоть что-то. В зависимости от устройства и количества JSON для преобразования это может вносить заметные задержки.

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

Например, Discourse, SPA на базе Ember, имеет фантастическое время загрузки, но помимо всего прочего, они предзагружают большой объём JSON данных в виде части начального HTML, чтобы не делать дополнительные запросы. И отмечу, что команда Discourse помешаны в хорошем смысле на скорости и их навыки сильно выше среднего. Подумайте об этом перед тем, как с лёгкостью воспроизводить то же самое в вашем SPA.

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

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

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

— Server: запрос к серверному API
— Server: запрос к базе данных
— Server: сгенерировать JSON
— Server: преобразовать JSON в HTML
— Client: отобразить начальный HTML
— Client: загрузить SPA
— Client: распарсить начальный HTML и подписаться на события DOM

Не могли бы вы просто запросить данные из БД, сгенерировать HTML и начать работать?

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

Архитектура

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

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

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

Существует столько же разных архитектур, сколько SPA-фреймворков:

  • Большинство фреймворков отличаются от традиционного шаблона MVC. Ember поначалу был вдохновлён Cocoa MVC, но достаточно сильно поменял свою программную модель в последних версиях.
  • Прослеживается тенденция, что разработчики предпочитают компоненты, а не традиционное разделение на контроллер и представление (некоторые фреймворки, такие как Ember и Angular, перешли к такому подходу в последних версиях). Все фреймворки реализуют некоторое подобие одностороннего биндинга данных. Двусторонний биндинг не приветствуется из-за побочных эффектов, которые он может вносить.
  • Большинство фреймворков включают систему роутинга, которая позволяет сопоставлять URL-адреса и экраны, и определяет, как создавать экземпляры компонентов для рендеринга. Это уникальный подход веб, который не существует в традиционных настольных интерфейсах.
  • Большинство фреймворков отделяют HTML шаблоны от JavaScript кода, но React ставит на смешение HTML-генерации и JavaScript и делает это вполне успешно, учитывая его массовое использование. Сейчас также наблюдается хайп вокруг встраивания CSS в JavaScript. Facebook со своей архитектурой Flux довольно сильно повлиял на индустрию, и контейнеры, такие как Redux, vuex и др., находятся под сильным влиянием от него.

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

С другой стороны, я сильно против Flux/Redux лагеря. Я видел так много умных людей, применяющих их, что приложил все усилия к его изучению и пониманию и ни один раз. Я не могу не трясти головой от разочарования, когда я вижу код. Я не вижу себя счастливым во время написания такого кода.

Наконец, Я не могу смириться со смешением HTML и CSS в компонентах, полных JavaScript логики. Я понимаю какую проблему это решает, но проблемы, которые привносит этот подход, не делают его стоящим этого.

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

Дублирование кода

При работе с SPA вероятно вы встретитесь с дублированием кода.

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

Например, представим, что вы работаете с инвойсами. Вы возможно имеете класс Invoice в JavaScript, который содержит метод total, который суммирует цену всех элементов, чтобы вы могли отрендерить стоимость. На сервере, вам также понадобится класс Invoice с методом total для вычисления этой стоимости, чтобы отправить её по e-mail. Видишь? Клиентский и серверный класс Invoice реализуют одинаковую логику. Дублирование кода.

Как сказано выше, изоморфный JavaScript мог бы нивелировать эту проблему, позволяя проще переиспользовать код. И я говорю нивелировать, потому что соответствие между клиентом и сервером не всегда 1-к-1. Вы захотите быть уверены, что некоторый код никогда не покидает сервер. Большое количество кода имеет смысл только для клиента. А также, некоторые аспекты просто отличаются (например, серверный элемент может сохранять данные в БД, а клиент может использовать удалённый API). Переиспользование кода, даже если это возможно, — это сложная проблема.

Вы можете поспорить, что вам не нужна богатая модель в вашем SPA и что вы вместо этого будете работать с JSON/JavaScript объектами напрямую, распределяя логику по компонентам UI. Теперь у вас есть то же самое дублирование кода, перемешанное с вашим кодом UI, удачи с этим.

И то же самое случится если вы захотите шаблоны для рендеринга HTML между сервером и клиентом. Например, для SEO, как насчёт сгенерировать страницы на сервере для поисковых роботов? Вам потребуется заново написать ваши шаблоны на сервере и убедится, что они синхронизированы с клиентскими. Опять дублирование кода.

Необходимость воспроизводить логику шаблонов на сервере и клиенте, по моему опыту, — источник возрастающего несчастья программистов. Сделать это один раз — это нормально. Когда вы сделаете это в 20ый раз, вы схватитесь за голову. Сделав это в 50ый раз, вы задумаетесь, нужны ли все эти SPA штуки.

Хрупкость

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

Во-первых, неважно насколько вы осторожны, неважно как много тестов вы пишете. Чем больше кода вы пишете, больше багов у вас будет. И SPA представляет (извините, если я сильно давлю) огромную кучу кода для написания и поддержки.

Во-вторых, как упоминалось выше, разработка богатого GUI это сложно и выливается в сложные системы, состоящие из множества элементов, взаимодействующих друг с другом. Чем более сложную систему вы создаёте, тем больше у вас багов. И по сравнению с традиционными веб-приложениями, использующими MVC, сложность SPA просто безумная.

Например, для сохранения консистетности на сервере вы можете использовать ограничения в БД, валидации модели и транзакции. Если что-то пойдёт не так, вы отвечаете с сообщением об ошибке. В клиенте, всё слегка сложнее. Очень многое может пойти не так просто потому, что слишком много всего происходит. Может быть так, что какая-то запись сохраняется удачно, а какая-то другая запись нет. Возможно, вы перешли в оффлайн посередине какой-то операции. Вы должны убедиться, что UI остаётся консистентным, и что приложение восстанавливается после ошибки. Всё это возможно, конечно, только намного сложнее.

Организационные вызовы

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

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

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

Шансы таковы, что вы окажетесь с людьми, которые не могут работать с SPA, и которые не могут работать на серверной стороне, просто потому что они не знают как.

Эта специализация может идеально подходить для Facebook или Google и их команд, состоящих из нескольких слоев инженерных войск. Но будет ли это хорошо для вашей команды из 6 человек?

Современный Rails

Есть 3 вещи, входящих в современный Rails, которые могут изменить ваше мнение о разработке современных веб-приложений:

  • одна из них — Turbolinks и это взрыв мозга
  • другая — старый друг, которого сегодня упускают из вида: SJR ответы и простые AJAX запросы для рендеринга
  • и последняя была добавлена недавно: Stimulus

Трудно понять, какого это применять какой-то подход, не поиграв с ним. Поэтому я сделаю несколько отсылок на Basecamp в следующих разделах. Я не имею никакого отношения к Basecamp, кроме как счастливый пользователь. Что касается этой статьи, это просто хороший живой пример современного Rails, который вы можете попробовать бесплатно.

Turbolinks

Идея Turbolinks проста: ускорьте ваше приложение, полностью заменив перезагрузку страниц на AJAX запросы, которые заменяют « элемент. Внутреннее колдовство, выполняющее эту работу, скрыто. Как разработчик, вы можете сосредоточиться на традиционном серверном программировании.

Turbolinks вдохновлён pjax и прошёл через несколько ревизий.

Раньше я беспокоился о его производительности. Я был неправ. Ускорение огромно. То, что меня убедило, это то, как я использовал его в проекте, но вы можете просто попробовать пробную версию в Basecamp и поиграться с ней. Попробуйте создать проект с некоторыми элементами, а затем перемещайтесь по ним, щелкая по разделам. Это даст вам хорошее представление о том, как выглядит Turbolinks.

Я не думаю, что Turbolinks просто потрясает своей новизной (pjax — 8 лет). Или своей технической утонченностью. Меня поражает то, как простая идея может повысить вашу производительность на порядок по сравнению с альтернативой SPA.

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

  • Обмен данными. У вас его нет. Не нужно сериализовывать JSON, создавать API-интерфейсы или думать о запросах данных, которые удовлетворяют потребности клиентов с учётом производительности.
  • Начальная нагрузка. В отличие от SPA, этот подход стимулирует быстрое время загрузки (by design). Для рендеринга экрана вы можете получить данные, которые вам нужны непосредственно из базы данных. И эффективный запрос данных из реляционных баз данных или кэширование HTML — это хорошо решаемые проблемы.
  • Архитектура: Вам не нужна сложная архитектура для организации вашего JavaScript-кода. Вам нужно всего лишь сосредоточиться на правильной архитектуре вашего серверного приложения, что вам всё равно нужно делать при использовании SPA.

MVC на сервере, в варианте, используемом Rails и многими другими фреймворками, намного проще, чем любой из шаблонов, используемых для архитектуры богатых графических интерфейсов: получить запрос, поработать с БД для его удовлетворения и отобразить страницу HTML в качестве ответа.

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

  • Дублирование кода. Существует только одно представление вашего приложения, которое живет на сервере. Ваша доменная модель, её правила, экраны приложений и т.д. Нет необходимости дублировать концепции в клиенте.
  • Хрупкость. По сравнению с SPA, JavaScript для работы на ваших страницах и его сложность сокращены до небольших долей, и поэтому количество ошибок. Кроме того, вы можете полагаться на атомарное выполнение операций на сервере, используя транзакции базы данных, ограничения и валидации.

Заметьте, я говорю не об обозначении проблем, а об их устранении. Например, GraphQL или SPA-регидратация — это суперумные решения для очень сложных проблем. Но что, если вместо того, чтобы пытаться найти решение, вы ставите себя в ситуацию, когда эти проблемы не существуют? Это изменение подхода к проблеме. И мне потребовались годы, чтобы в полной мере оценить способность этого подхода решать проблемы.

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

  • Turbolinks поставляется со своим пользовательским событием «загрузка страницы», и существующие плагины, полагающиеся на регулярные загрузки страниц, не будут работать. Сегодня есть лучшие способы добавить поведение к DOM, но устаревшие виджеты не будут работать, если не будут адаптированы.
  • JavaScript-код, изменяющий DOM, должен быть идемпотентным, поскольку его могут запускать несколько раз. Опять же, это делает недействительным много существующего JavaScript.
  • Скорость отличная, но это не совсем как в SPA, который может обрабатывать некоторые взаимодействия, не загружая сервер. Я расскажу больше о компромиссах позже.

AJAX рендеринг и SJR ответы

Помните, когда рендеринг HTML через Ajax был в тренде 15 лет назад? Угадай, что? Это все еще замечательный инструмент, который есть в вашем арсенале:

  • Получение фрагмента HTML с сервера и добавление его в DOM, ощущается супербыстрым (на 100мс быстрым).
  • Вы можете рендерить HTML на сервере, что позволяет повторно использовать ваши представления и извлекать необходимые данные непосредственно из базы данных.

Вы можете видеть, как этот подход ощущается в Basecamp, открыв меню вашего профиля, нажав на верхнюю правую кнопку:

Открывается мгновенно. Со стороны разработки вам не нужно заботиться о сериализации JSON и клиентской стороне. Вы можете просто отобразить этот фрагмент на сервере, используя все возможности Rails.

Похожий инструмент, который Rails включает в себя в течение многих лет, — это серверные ответы JavaScript (SJR). Они позволяют вам отвечать на запросы Ajax (обычно формировать представления) с JavaScript, который исполняется клиентом. Он дает те же преимущества, что AJAX-рендеринг HTML-фрагментов: исполняется очень быстро, вы можете повторно использовать код на стороне сервера, и вы можете напрямую обращаться к базе данных для создания ответа.

Вы можете увидеть, как это происходит, если вы зайдёте в Basecamp и пытаетесь создать новый todo. После того, как вы нажмете «Добавить todo», сервер сохранит todo и ответит фрагментом JavaScript, который добавляет новый todo в DOM.

Я думаю, что многие разработчики сегодня смотрят на AJAX-рендеринг и SJR-ответы с презрением. Я тоже это помню. Они являются инструментом и, как таковые, могут подвергаться злоупотреблениям. Но при правильном использовании это потрясающее решение. Позвольте вам предложить отличный UX и интерактивность по очень низкой цене. К сожалению, как и Turbolinks, их сложно оценить, если вы ещё не сражались с SPA.

Stimulus

Stimulus — это JavaScript фреймворк, опубликованный несколько месяцев назад. Он не заботится о рендеринге или об управлении состоянием на основе JavaScript. Вместо этого, это просто хороший, современный способ организации JavaScript, который вы используете для добавления HTML:

  • Он использует MutationObserver для привязки поведения к DOM, то есть ему не важно, как HTML появляется на странице. Конечно, это отлично работает с Turbolinks.
  • Он сэкономит вам кучу шаблонного кода для привязки поведения к DOM, для привязки обработчиков к событиям и для размещения элементов в указанном контейнере.
  • Он нацелен на то, чтобы ваш HTML-код был читабельным и понятным, что приятно, если вы когда-либо сталкивались с проблемой поиска того, какая часть JavaScript действует на этом проклятом элементе.
  • Он поощряет сохранение состояния в DOM. Опять же, это означает, что ему не важно, как генерируется HTML, что подходит для многих сценариев, в том числе Turbolinks.

Если вы примете Rails-путь, ваш JavaScript будет сосредоточен на изменении HTML-кода, созданного на стороне сервера, и улучшении взаимодействия (c небольшим количеством JavaScript). Stimulus предназначен для организации такого кода. Это не система SPA и не претендует на то, чтобы быть таковой.

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

Игра компромиссов

Turbolinks обычно продается как «Получите все преимущества SPA без каких-либо неудобств». Я не думаю, что это полностью верно:

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

Теперь разработка — это игра компромиссов. И в этой игре:

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

Я считаю, что с Rails вы можете получить 90% того, что предлагает SPA с 10% усилий. Что касается производительности, Rails убивает SPA. Что касается UX, я думаю, что многие разработчики делают ту же ошибку, что и я, предполагая, что SPA UX является непревзойденным. Это не так. Фактически, как обсуждалось выше, вам лучше знать, что вы делаете при создании своего SPA, или UX будет на самом деле хуже.

Заключение

Я наблюдаю за тем, как компании массово принимают SPA фреймворки, и вижу бесчисленные статьи о том, как делать причудливые вещи в стиле SPA. Я думаю, что существует много «использований неправильного инструмента для работы», поскольку я твердо верю, что типы приложений, которые оправдывают использование SPA, ограничены.

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

Готовя эту статью, я наткнулся на этот твит:

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

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

Помните, что вы можете избавиться от неприятностей. Если вы выберете путь SPA, убедитесь, что он оправдан и вы понимаете проблемы. Если вы не уверены, экспериментируйте с разными подходами и убедитесь сами. Возможно, Facebook или Google, в их масштабе, не имеют роскоши принимать такие решения, но вы, вероятно, можете.

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

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

«Империя на глубине»: зачем крупные ИТ-компании прокладывают свои подводные кабели

ИТ-ГРАД

vmware iaas provider

В середине июля подразделение Google, занимающееся облачными технологиями, объявило о начале работы над первым частным трансатлантическим подводным кабелем — Dunant. «Частный» в этом случае значит, что весь проект реализуется на средства Google. К 2020 году он соединит Вирджинию-Бич, штат Вирджиния, и западное побережье Франции.

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


/ фото SCUBACOPPER CC

Подводная империя Google

За последние три года Google потратил $30 млрд на развитие своей инфраструктуры. В эту сумму вошла и прокладка подводных кабелей.

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

Задачей Unity было связать США и Азию через Тихий океан и увеличить пропускную способность по этому маршруту на 20%. Позже к Unity в Азиатско-Тихоокеанском регионе присоединился кабель SJC. Он был проложен на маршруте между Азией и США снова в консорциуме с телекоммуникационными компаниями.

А в этом январе стало известно сразу о трех новых кабельных проектах Google — Curie, Havfrue, HK-G. Havfrue — это совместный проект с Facebook. Кабель соединит США с Данией и Ирландией дополнительным каналом. HK-G соединит Гонконг и Гуам и будет проложен при участии телекомкомпаний.

Curie стал уникальным проектом — его Google реализует собственными силами. Эта кабельная система соединит Лос-Анджелес и Чили. Curie будет первым подводным кабелем, принадлежащим частной технологической компании, и первым, проложенным до Чили за последние 20 лет.

И вот теперь пришла очередь первого частного трансатлантического кабеля — Dunant, как и Curie, названного в честь лауреата Нобелевской премии. С помощью него Google собирается расширить свою облачную инфраструктуру на «одном из самых загруженных маршрутов».

Dunant будет проложен в партнерстве с поставщиком подводных коммуникационных систем TE SubCom. Протяженность кабельной системы составит более 6,4 тыс. км.

Кто еще прокладывает частные кабели

Сегодня многие ИТ-предприятия решают выстраивать «подводную» инфраструктуру самостоятельно, а не «арендовать» кабели у телекоммуникационных операторов.

В прошлом году Microsoft, Facebook и Telxius совместными усилиями завершили работы по прокладке 160-терабитного Marea из Вирджинии в Испанию.

В 2016 году свою первую инвестицию в подводную кабельную систему совершил Amazon. Кабель Hawaiki, запущенный в этом месяце, соединил США, Австралию и Новую Зеландию. Еще один кабельный проект, в котором участвует Amazon, — Jupiter. В нем партнерами корпорации выступают Facebook и SoftBank. Он свяжет Азию и Северную Америку.

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

Что прокладка частных кабелей дает ИТ-компаниям

Важную роль в новом инфраструктурном тренде играют облачные технологии. У Google и других провайдеров облачные услуги распределяются по географическим регионам, которые, в свою очередь, делятся на зоны с привязкой к ближайшим дата-центрам. Кабели связывают ЦОДы с новыми регионами и позволяют клиентам в них получать доступ к облачным услугам.

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

  1. Прокладка частного кабеля позволяет контролировать процесс проектирования и строительства, самостоятельно определять технические характеристики и быстрее реализовывать проект.
  2. У Google уже есть информация о потребностях своих клиентов — в каких странах они испытывают трудности с работой облачных сервисов, а в каких — нет. Работая над собственными кабелями, компания может выбирать, куда в первую очередь проложить новое соединение.
  3. Кабели имеют ограниченный срок службы — от 15 до 25 лет. Корпорация может это учитывать и давать свои гарантии партнерам, а они, в свою очередь, получают возможность строить долгосрочные бизнес-планы.

Подводя итог, собственная подводная инфраструктура дает крупным ИТ-компаниям возможность «открывать» для себя новые рынки и целиком и полностью контролировать инфраструктуру на всех этапах: от проектирования и строительства до прокладки и эксплуатации.


/ фото Torkild Retvedt CC

В чем польза частных кабелей ИТ-компаний для пользователей

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

Новый кабель Dunant Google прокладывает из этих же соображений. По трансатлантическому маршруту кабели передают на 55% больше данных, чем по тихоокеанскому. Судя по этим цифрам и росту популярности облачных сервисов в Европе, этому действительно «загруженному» каналу потребовались дополнительные мощности.

В некоторых регионах мира периодически происходят перебои из-за физического повреждения подводных кабелей. В этом году это случилось у побережья Западной Африки. Проблемы с интернет-доступом тогда испытывали жители нескольких стран. Дополнительные кабели страхуют от полного обрыва связи в таких ситуациях и обеспечивают пользователей бесперебойным доступом к облачным сервисам даже в случае чрезвычайных ситуаций.

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

В будущем ИТ-компании, вероятно, продолжат работать над прокладкой собственной подводной инфраструктуры, что может полностью изменить рынок. Специалист в сфере прокладки подводных кабелей Джулиан Рол (Julian Rawle) даже предсказывает, что из-за этого тренда в течение 20 лет телекоммуникационные компании могут перестать выступать в качестве провайдеров сетевой инфраструктуры.

P.S. О чем еще мы пишем в Первом блоге о корпоративном IaaS:

P.P.S. Другие посты из нашего блога на Хабре:

Метки:
Похожие публикации

Source: habr1

Бесконечный узор на основе простых чисел

image
Привет, Хабр! Однажды утром мне пришла в голову идея находить «исключающее ИЛИ» между координатами точки пространства и проверять полученное число на простоту. Результат такого простого алгоритма вы можете видеть на картинке. Подробнее под катом.

Алгоритм генерации узора

Алгоритм на языке C++

long long temp = x ^ y; // x и y координаты точки
// Далее идет проверка temp на простоту одним из алгоритмов.
// Например алгоритм Бэйли-Померанс-Селфридж-Вагстафф (BPSW) проверки n на простоту
if(isprime(temp) == true) {
// рисуем закрашенную точку
} else {
// оставляем точку пустой
}

Такой алгоритм дает следующие бесконечные узоры:

Картинки с узорами

image
image
image
image
image
image

Можно также посмотреть видео с узорами:

Другие варианты узоров

Если заменить операцию XOR (исключающее ИЛИ) на операцию ИЛИ или И, можно получить фрактальные треугольники:

image

image

Также можно вместо проверки на простое число использовать любые другие проверки, например деление без остатка на какое-либо число. Но такие варианты дают менее разнообразные узоры.

Программа и исходники

Для тестирования генератора узора я написал простую программу, которую можно скачать вместе с исходниками здесь. Для работы с изображениями используется библиотека OpenCV.

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

[Перевод] Китайский «Лунный дворец» установил новый рекорд

  • Перевод

Двое добровольцев приветствуют зрителей изнутри «Лунного дворца-1», комплекса отработки регенеративных систем жизнеобеспечения с замкнутым циклом, построенного с целью провести серию экспериментов для программы перспективной базы на Луне в Бэйханском университете, Пекин, 10 мая 2017 года. Источник: Xinhua/Ju Huanzong.

После целого года внутри Yuegong-1 (прим. перев. — «Юэгун-1» или «Лунный дворец-1») в Пекине, последние четверо добровольцев под аплодисменты окружающих покинули симулятор, неся выращенные за это время собственными руками овощи. Успешное завершение проекта Yuegong-365 — это новый мировой рекорд по продолжительности пребывания в замкнутой среде с самообеспечением.

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

Построенный в Бэйханском университете Пекина, Yuegong-1 — комплекс общей площадью около 150 квадратных метров, из трёх связанных между собой отсеков, один из которых бытовой, а два предназначены для выращивания биомассы. На столь небольшом пространстве тем не менее удалось вырастить множество различных растений, таких как клубника, соевые бобы и морковь. Восемь добровольцев, из числа студентов университета, разделили на две группы. Первая, двое юношей и двое девушек, находилась в комплексе с 10 мая в течение 60 дней, затем их сменила вторая такая же группа, которой предстояло провести внутри уже 200 дней. Затем, 26 января 2018 года, вторую группу вновь сменила первая, завершившая программу спустя ещё 110 дней.

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

Эксперимент проводился с целью испытать систему жизнеобеспечения с замкнутым циклом (BLSS, bioregenerative life support system), в которой — теоретически — растения, животные и микроорганизмы могут сосуществовать в течение долгого времени в изолированном объёме, поддерживая круговорот веществ; точно такой же цикл предполагается в перспективе организовать на долговременной лунной базе. Поэтому BLSS имитирует жизненные процессы на Земле, подвергая кислород, воду и пищу вторичной переработке. Кроме того, это позволило учёным выяснить, как именно долговременное пребывание в подобной среде влияет на физическое и психологическое состояние человека.

Таким образом, знания, полученные в проекте Yuegong-365, не только серьёзно повлияют на научно-технический прогресс Китая, но и помогут понять, как именно организовать комфортную для людей среду, если они захотят задержаться на Луне надолго.

Как сказала профессор Лю Хун, ведущий разработчик Yuegong-1, её основной задачей являлась проверка того, не нарушится ли стабильность среды при пересменке «астронавтов». «Сейчас мы уже достигли 80 процентов по объему рециркуляции пищи», — утверждает Лю Хун — «Поэтому, если мы в будущем хотим надолго оставаться на Луне, Марсе или где-либо ещё, эти технологии определённо увеличат наши шансы на выживание».

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

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

Механизм комиссий в Биткоине и зачем дружить с майнерами

В этой статье мы постараемся детально описать основную задачу комиссий в Биткоине, как они работают и на что влияют. Мы объясним причины волатильности комиссий, задержки в подтверждении транзакций и опишем подходы к решению этих проблем. Кроме того, проясним, как именно обновление Segregated Witness способствует снижению стоимости транзакций. А в качестве бонуса поделимся мыслями по поводу того, как дружба с майнерами снижает комиссии до нуля и к чему такая тенденция может привести в будущем. Итак, приступим.

Время полного подтверждения транзакции


Важно отличать процесс обработки транзакций (verification) от процесса их подтверждения (confirmation). В сети Bitcoin транзакции обрабатываются практически мгновенно, а подтверждаются – целый час. В других цифровых валютах все может осуществляться в течение пары секунд. От чего же зависит время полного подтверждения транзакции в децентрализованной среде? Главным образом, от механизма достижения консенсуса.

В чистом виде PoW не может обеспечить достижение консенсуса менее, чем за один час. В свою очередь протоколы достижения консенсуса, основанные на PBFT , и протоколы на основе DPoS могут обеспечивать достижение консенсуса за несколько секунд. Однако уровень децентрализации и независимости таких систем гораздо меньше, чем в Биткоине.
image

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

Ограниченность пропускной способности


С ростом популярности Биткоина значительно увеличился поток новых транзакций в сети. Известно, что размер блока определен правилами протокола и строго ограничен. В Биткоине максимальный размер блока составляет 1 MB, следовательно, пропускная способность ограничена (1.7 KB/s). Если поток новых транзакций превысит пропускную способность, то не все из них будут обработаны. И такие ситуации случаются нередко. Какие транзакции получат подтверждение первыми, а какие останутся ждать – это вопрос, который требует четкого ответа. Суть его в том, что транзакции должны конкурировать друг с другом.

Роль комиссий


Механизм комиссий в Биткоине необходим для оплаты услуг распределенной сети, где услугой сети, по сути, является надежное хранение данных. Пользователи сети Биткоин фактически платят за каждый байт данных, добавленных в общую базу. В силу того, что пропускная способность этой базы данных ограничена, пользователи конкурируют между собой за приоритет записи.
image

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

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

Волатильность цены записи


Пользователи сети Биткоин время от времени сталкиваются с непривычно высокой волатильностью комиссий. Например, в 2017 году усредненная цена записи одного байта данных в блокчейн Биткоина колебалась в диапазоне от 1 до 500 satoshi. А очередь неподтвержденных транзакций варьировалась от нескольких KiB до десятков, и даже сотен, MiB.

По причине того, что цена на запись данных может резко изменится, пользователи вынуждены конкурировать друг с другом почти вслепую. Это обусловлено тем, что фактически транзакция будет подтверждена в среднем в течение 8 минут, тогда как комиссию за обработку нужно установить еще до ее подписания. Поэтому вопрос правильно установленной комиссии все равно остается актуальным, потому что все хотят быстрого подтверждения своих транзакций с минимальными затратами. Естественно, платить больше 50 USD за типичную транзакцию – не лучший вариант, особенно, когда можно сэкономить до 90% этой суммы, если грамотно рассчитать комиссию.

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

Решение проблемы с волатильностью комиссий


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

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

transaction fee = transaction size * byte price

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

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

Повышение комиссии после отправки транзакции


Отметим, что протокол Биткоин весьма гибкий и в отношении комиссий. Например, есть два улучшения протокола: replace-by-fee и child-pays-for-parent, – которые позволяют повысить комиссию уже сформированной и отправленной транзакции. К сожалению, очень немногие кошельки реализуют эту функциональность для удобства своих пользователей, хотя со временем их становится больше.

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

Как помогает Segregated Witness


Одним из изменений протокола, которое внесло обновление Segregated Witness, является введение нового формата транзакции и ее веса (transaction weight). До появления Segregated Witness при расчете комиссии обычно учитывали только размер транзакции. Теперь важными являются и размер, транзакции и ее вес. Новая транзакция хранит доказательства владения монетами в отдельной структуре (witness data). Чтобы перевести размер транзакции (total size) в ее вес, размер witness data умножается на меньший коэффициент, чем остальные данные транзакции. Вес транзакции рассчитывается по специальной формуле:
weight = base size * 3 + total size.

В этом случае base size – это размер транзакции без учета размера witness data. Как можно догадаться, любые данные, которые включаются в witness data, требуют в 4 раза меньшей комиссии, чем остальные данные транзакции. Подобный подход позволяет майнерам определить более выгодную транзакцию в отношении занимаемого в блоке места и получаемого вознаграждения.

Известно, что около 60% всех данных транзакции составляют именно данные доказательства владения монетами (т. е. такие, которые можно записать в witness data). Соответственно, вес транзакций нового формата значительно уменьшится. Таким образом, пользователь может платить меньше за подтверждение новой транзакции, при этом она будет иметь тот же приоритет у майнеров при включении в блок, что и старая транзакция с большей комиссией.

image

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

Вариант с другом-майнером


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

image

Первое подтверждение ваша транзакция с вероятностью 50% получит в течение 50 минут, а полное подтверждение – в среднем через 50 минут после первого. В итоге ваши транзакции будут получать полное подтверждение приблизительно в течение 100 минут. Если бы у вас такого друга не было, полное подтверждение транзакция получала бы приблизительно в течение 60 минут, но уже с оплатой полноценной комиссии.

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

Вариант с токенизацией места


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

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

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

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

Более того, пул может даже токенизировать свободное место в своих блоках (да, чтобы токены продавать).

Заключение


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

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

Source: habr1

[Из песочницы] User Memory Design: Как проектировать на века

Привет, Хабр! Представляю вашему вниманию перевод статьи User Memory Design: How To Design For Experiences That Last

Если мы поймем разницу между опытом и памятью, мы сможем повысить свои навыки проектирования пользовательского опыта (UX).

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

В этот раз я дам несколько рекомендаций по созданию UX, который запомнится надолго. Но для начала поясню эти два графика.


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

Графики отображают интенсивность болевых ощущений, которые два пациента испытывали во время болезненной медицинской процедуры. Пациенты поминутно оценивали интенсивность боли по шкале от 0 («нет боли») до 10 («высшая степень боли»).

Один взгляд на эти два графика говорит, что пациент B провел время эксперимента гораздо хуже: он страдал в 3 раза дольше, а пик боли достигался тот же, что и у пациента А. Если бы вам пришлось выбирать, на месте какого пациента оказаться, вы бы выбрали А. Разумный выбор.

Только почему-то люди редко думают рационально.

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

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


Как пациенты запомнили боль: среднее значение между пиком и заключительным моментом.

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

Двадцать лет дополнительных исследований в этой области показали, что закон пика-окончания работает в экспериментах, связанных не только с болью, но и с многими другими состояниями (например, с удовольствием). Разумеется, опыт может включать в себя как приятные, так неприятные моменты, как отражено ниже на графике с положительными и отрицательными значениями по оси OY. Этот тип диаграмм назван контуром опыта (experience profile).


Контуры опыта отражают положительный и отрицательный опыт за определенное время.

Потоки и кадры

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

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

Два «Я»

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

С одной стороны, переживающее Я спрашивает: «Как я себя сейчас чувствую?», и каждое мгновение познает мир с помощью чувств удовольствия, скуки, расстройства и страха. С другой стороны, запоминающее Я интересуется: «Как я в целом?». Оно анализирует переживания и опыт после того, как событие произошло, не учитывая его длительность и концентрируясь на ярких моментах (пике и окончании).

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

Дизайн пользовательской памяти

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

Мой ответ прост: мы должны быть и теми, и другими.

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

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

Не испортите концовку

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

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

Несколько примеров хороших завершений:

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

А вот примеры не очень хороших завершений:

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

Наконец, если пользователь хочет отписаться от ваших рекламных писем, не будьте чудовищем и не усложняйте процесс отписки! Есть целый Tumblr Spot the Unsubscribe посвященный e-mail, в которых до смешного тяжело найти ссылку для отписки.

Замедлитесь, когда это необходимо

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

Сложно сказал, поясню на примере.

В вебе все происходит очень быстро – настолько, что порой сложно захватить внимание пользователя. Но не торопитесь все делать по принципу «Не заставляйте меня думать». Вместо того, чтобы поскорее впечатлить пользователя, добавьте то, что Эндрю Граймс называет мета моментами: «небольшие моменты размышлений, которые заставляют нас осознавать, что мы испытываем». Например, Slack использует пульсирующие всплывающие подсказки на протяжении обучения, которые занимают дополнительное время и внимание, но помогают обучить совершенно новых пользователей, а более продвинутым придает энергии начать использовать те функции Slack, которые они раньше не использовали.

Психолог Дэн Арили в своем блоге рассказывает историю о том, как он встретился со слесарем и поговорил с ним о работе:

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

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


TurboTax использует искусственное время ожидания для создания иллюзии, что вы на что-то влияете.

Разумеется, этому софту не нужно дважды проверять данные. Но когда вы смотрите на экран, возникает ли у вас ощущение, что TurboTax делает намного больше, чтобы позаботиться о вас? Другими словами, этот диалог – пустышка без смысла, но при этом улучшает впечатление об использовании. В данном случае, увеличение времени выполнения задачи – приятное дополнение, которое останется в памяти после использования. И TurboTax не единственная компания, использующая этот способ.

Создавайте пиковые моменты

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

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

Одна из техник эмоционального дизайна – моя любимая – создавать удивляющие моменты, позволяя пользователям делать собственные открытия в пользовательском интерфейсе. Когда мы с коллегами создали JamBells, коллективную интернет-игру для мобильных устройств, мы добавили секретик в список воспроизводимых песен. Проверьте на смартфоне: сможете найти?..

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

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

В конце истории Норман дает совет: «Перфекционизм редко стоит усилий. Так почему бы не оставить нерешенными некоторые проблемы… Важно впечатление в целом.»

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

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


Опыт без ярких моментов чувствителен к внезапным проблемам.

Напротив, опыт с ярким положительным моментом (пример на графиках ниже) устойчивее к проблемам. Теоретически, один положительный пик перекрывает остальной негативный опыт.


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

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

Будьте дизайнерами историй

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

Но потом я посмотрел видео Курта Воннегута. (Прикрепляю ниже. Посмотрите, это займет максимум 4 минуты.)

Не кажутся ли вам знакомыми типы графиков, которые рисует Воннегут? Это то же, что и графики впечатлений в исследовании Канемана.


Курт Воннегут изображает на графике жизнь Золушки из одноименной сказки.

Студент Тафтского Университета прошел чуть дальше, показав, что данный график отражает практически каждый мультфильм Диснея. И Дисней годами делает деньги на этой схеме.

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

Человеческая память разделяет поток впечатлений на отдельные моменты. Получается последовательность моментов, происходящих с течением времени, четко обозначенные начало и конец, чередование хороших и плохих моментов на протяжении сюжета. Это история. Люди пишут истории каждый день. Мы постоянно создаем истории из моментов, которые имеют для нас смысл.

Как же использовать это преимущество? Полезная вещь для применения мышления рассказчика в UX дизайне – карта опыта или карта пути. Эта карта – отличный способ связать качественное и количественное исследование и визуализировать историю, которую пользователь изучит вместе с продуктом или услугой. Adaptive Path сделал полезный гайд.

Карты опыта могут быть составными и детальными, но самое важное здесь – график опыта. Где получаются пики? Где возникают разногласия? Как заканчивается опыт?

Наконец, мысли, выражаемые рассказчиком, не должны быть расплывчатыми и невнятными. Донна Лико обращает внимание, что любая последовательность шагов, предпринимаемых пользователем за некоторое время, может быть описана как данными (факты, статистика), так и в повествовательном формате с элементами историй (описание, завязка, кульминация). Данные и истории поддерживают друг друга и обмениваются информацией. Аналитика рассказывает «Что», истории – «Как», и вместе они вдохновляют на новые идеи для дизайна и тестовые гипотезы.

Заключение

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

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

И чтобы закончить на мажорной ноте:


Image: http://www.memegen.com/meme/hx9szq

Об авторе

Курт Арледж

Курт: исследователь, дизайнер, теоретик, писатель и лектор по UX дизайну. Работает в Viget’s в городе Фолс-Черч в штате Вирджиния для таких клиентов как POLITICO, Massachusetts General Hospital и National Trust for Historic Preservation.

Другие посты Курта

Оригинальную статью можно посмотреть здесь
Перевод выполнен rishavant

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

[Из песочницы] MVIDroid: обзор новой библиотеки MVI (Model-View-Intent)

Всем привет! В этой статье я хочу рассказать о новой библиотеке, которая привносит шаблон проектирования MVI в Android. Эта библиотека называется MVIDroid, написана 100% на языке Kotlin, легковесная и использует RxJava 2.x. Автор библиотеки лично я, исходный код её доступен на GitHub, а подключить её можно через JitPack (ссылка на репозиторий в конце статьи). Эта статься состоит из двух частей: общее описание библиотеки и пример её использования.

MVI

И так, в качестве предисловия, позвольте напомнить что такое вообще MVI. Model — View — Intent или, если по-русски, Модель — Представление — Намерение. Это такой шаблон проектирования, в котором Модель (Model) является активным компонентом, принимающим на вход Намерения (Intents) и производящая Состояния (State). Представление (View) в свою очередь принимает Модели Представления (View Model) и производит те самые Намерения. Состояние преобразуется в Модель Представления при помощи функции-трансформера (View Model Mapper). Схематически шаблон MVI можно представить следующим образом:

MVI

В MVIDroid Представление не производит Намерения напрямую. Вместо этого оно производит События Представления (UI Events), которые затем преобразуются в Намерения при помощи функции-трансформера.

View

Основные компоненты MVIDroid

Модель

Начнём с Модели. В библиотеке понятие Модели немного расширено, здесь она производит не только Состояния но и Метки (Labels). Метки используются для общения Моделей между собой. Метки одних Моделей могут быть преобразованы в Намерения других Моделей при помощи функций-трансформеров. Схематически Модель можно представить так:

Model

В MVIDroid Модель представлена интерфейсом MviStore (название Store заимствовано из Redux):

interface MviStore<State : Any, in Intent : Any, Label : Any> : (Intent) -> Unit, Disposable {
    @get:MainThread
    val state: State
    val states: Observable<State>
    val labels: Observable<Label>
    @MainThread
    override fun invoke(intent: Intent)
    @MainThread
    override fun dispose()
    @MainThread
    override fun isDisposed(): Boolean
}

И так, что мы имеем:

  • Интерфейс имеет три Generic-параметра: State — тип Состояния, Intent — тип Намерений и Label — тип Меток
  • Содержит три поля: states — текущее состояние Модели, states — Observable Состояний и labels — Observable Меток. Последние два поля дают возможность подписаться на изменения Состояния и на Метки соответственно.
  • Является потребителем (Consumer) Намерений
  • Является Disposable, что даёт возможность разрушить Модель и прекратить все происходящие в ней процессы

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

Компонент

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

Component

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

Полный список функции Компонента выглядит следующим образом:

  • Связывает входящие События Представлений и Метки с каждой Моделью используя предоставленные функции-трансформеры
  • Выводит исходящие Метки Моделей наружу
  • Разрушает все Модели и разрывает все связи при разрушении Компонента

Компонент тоже имеет свой интерфейс:

interface MviComponent<in UiEvent : Any, out States : Any> : (UiEvent) -> Unit, Disposable {
    @get:MainThread
    val states: States
    @MainThread
    override fun invoke(event: UiEvent)
    @MainThread
    override fun dispose()
    @MainThread
    override fun isDisposed(): Boolean
}

Рассмотрим интерфейс Компонента подробнее:

  • Содержит два Generic-параметра: UiEvent — тип Событий Представления и States — тип Состояний Моделей
  • Содержит поле states, дающее доступ к группе Состояний Моделей (например в виде интерфейса или data-класса)
  • Является потребителем (Consumer) Событий Представления
  • Является Disposable, что даёт возможность разрушить Компонент и все его Модели

Представление (View)

Как несложно догадаться, Представление нужно для отображения данных. Данные для каждого Представления группируются в Модель Представления (View Model) и обычно представляются в виде data-класса (Kotlin). Рассмотрим интерфейс Представления:

interface MviView<ViewModel : Any, UiEvent : Any> {
    val uiEvents: Observable<UiEvent>
    @MainThread
    fun subscribe(models: Observable<ViewModel>): Disposable
}

Здесь всё несколько проще. Два Generic-параметра: ViewModel — тип Модели Представления и UiEvent — тип Событий Представления. Одно поле uiEvents — Observable Событий Представления, дающее возможность клиентам подписаться на эти самые события. И один метод subscribe(), дающий возможность подписаться на Модели Представления.

Пример использования

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

Представление

Для начала опишем Модель Представления:

data class ViewModel(val text: String)

И События Представления:

sealed class UiEvent {
    object OnGenerateClick: UiEvent()
}

Теперь реализуем само Представление, для этого нам понадобится наследование от абстрактного класса MviAbstractView:

class View(activity: Activity) : MviAbstractView<ViewModel, UiEvent>() {
    private val textView = activity.findViewById<TextView>(R.id.text)
    init {
        activity.findViewById<Button>(R.id.button).setOnClickListener {
            dispatch(UiEvent.OnGenerateClick)
        }
    }
    override fun subscribe(models: Observable<ViewModel>): Disposable =
        models.map(ViewModel::text).distinctUntilChanged().subscribe {
            textView.text = it
        }
}

Всё предельно просто: подписываемся на изменения UUID и обновляем TextView при получении нового UUID, а по нажатию кнопки отправляем событие OnGenerateClick.

Модель

Модель будет состоять из двух частей: интерфейс и реализация.

Интерфейс:

interface UuidStore : MviStore<State, Intent, Nothing> {
    data class State(val uuid: String? = null)
    sealed class Intent {
        object Generate : Intent()
    }
}

Здесь всё просто: наш интерфейс расширяет интерфейс MviStore, указывая типы Состояния (State) и Намерений (Intent). Тип Меток — Nothing, т. к. у наша Модель их не производит. Также в интерфейсе содержатся классы Состояния и Намерений.

Для того что реализовать Модель, надо понять как она работает. На вход Модели поступают Намерения (Intent), которые преобразуются в Действия (Action) при помощи специальной функции IntentToAction. Действия поступают на вход Исполнителю (Executor), который выполняет их и производит Результаты (Result) и Метки (Label). Результаты затем поступают в Редуктор (Reducer), который преобразует текущее Состояние в новое.

Все четыре состовляющие Модели:

  • IntentToAction — функция, преобразующая Намерения в Действия
  • MviExecutor — исполняет Действия и производит Результаты и Метки
  • MviReducer — преобразует пары (Состояние, Результат) в новые Состояния
  • MviBootstrapper — специальный компонент, позволяющий инициализировать Модель. Выдаёт всё те же Действия, которые также поступают в Исполнитель (Executor). Можно выполнить разовое Действие, а можно подписаться на источник данных и выполнять Действия при определённых событиях. Bootstrapper запускается автоматически при создании Модели.

Чтобы создать саму Модель, необходимо использовать специальную фабрику Моделей. Она представлена интерфейсом MviStoreFactory и его реализацией MviDefaultStoreFactory. Фабрика принимает составляющие Модели и выдаёт готовую к использованию Модель.

Фабрика нашей Модели будет выглядеть следующим образом:

class UuidStoreFactory(private val factory: MviStoreFactory) {
    fun create(factory: MviStoreFactory): UuidStore =
        object : UuidStore, MviStore<State, Intent, Nothing> by factory.create(
            initialState = State(),
            bootstrapper = Bootstrapper,
            intentToAction = {
                when (it) {
                    Intent.Generate -> Action.Generate
                }
            },
            executor = Executor(),
            reducer = Reducer
        ) {
        }
    private sealed class Action {
        object Generate : Action()
    }
    private sealed class Result {
        class Uuid(val uuid: String) : Result()
    }
    private object Bootstrapper : MviBootstrapper<Action> {
        override fun bootstrap(dispatch: (Action) -> Unit): Disposable? {
            dispatch(Action.Generate)
            return null
        }
    }
    private class Executor : MviExecutor<State, Action, Result, Nothing>() {
        override fun invoke(action: Action): Disposable? {
            dispatch(Result.Uuid(UUID.randomUUID().toString()))
            return null
        }
    }
    private object Reducer : MviReducer<State, Result> {
        override fun State.reduce(result: Result): State =
            when (result) {
                is Result.Uuid -> copy(uuid = result.uuid)
            }
    }
}

В этом примере представлены все четыре составляющие Модели. Сначала фабричный метод create, затем Действия и Результаты, за ними следует Исполнитель и в самом конце Редуктор.

Компонент

Состояния Компонента (группа Состояний) опишем data-классом:

data class States(val uuidStates: Observable<UuidStore.State>)

При добавлении новых Моделей в Компонент, их Состояния следует также добавить в группу.

И, собственно, сама реализация:

class Component(uuidStore: UuidStore) : MviAbstractComponent<UiEvent, States>(
    stores = listOf(
        MviStoreBundle(
            store = uuidStore,
            uiEventTransformer = UuidStoreUiEventTransformer
        )
    )
) {
    override val states: States = States(uuidStore.states)
    private object UuidStoreUiEventTransformer : (UiEvent) -> UuidStore.Intent? {
        override fun invoke(event: UiEvent): UuidStore.Intent? =
            when (event) {
                UiEvent.OnGenerateClick -> UuidStore.Intent.Generate
            }
    }
}

Мы наследовали абстрактный класс MviAbstractComponent, указали типы Состояний и Событий Представления, передали нашу Модель в super класс и реализовали поле states. Кроме того мы создали функцию-трансформер, которая будет преобразовывать События Представления в Намерения нашей Модели.

Маппинг Модели Представления

У нас есть Состояния и Модель Представления, настало время преобразовать одно в другое. Для этого мы реализуем интерфейс MviViewModelMapper:

object ViewModelMapper : MviViewModelMapper<States, ViewModel> {
    override fun map(states: States): Observable<ViewModel> =
        states.uuidStates.map {
            ViewModel(text = it.uuid ?: "None")
        }
}

Связь (Binding)

Наличия самих по себе Компонента и Представления не достаточно. Чтобы всё начало работать, их необходимо связать. Пришло время создать Activity:

class UuidActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_uuid)
        bind(
            Component(UuidStoreFactory(MviDefaultStoreFactory).create()),
            View(this) using ViewModelMapper
        )
    }
}

Мы использовали метод bind(), который принимает Компонент и массив Представлений с мапперами их Моделей. Этот метод является extension-методом над LifecycleOwner (коими являются Activity и Fragment) и использует DefaultLifecycleObserver из пакета Arch, который требует Java 8 source compatibility. Если по каким-либо причинам Вы не можете использовать Java 8, то Вам подойдёт второй метод bind(), который не являеся extension-методом и возвращает MviLifecyleObserver. В этом случае, Вам придётся вызывать методы жизненного цикла самостоятельно.

Ссылки

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

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1

Создание бота для участия в AI mini cup. Опыт применения GPU


продолжение статьи1 и статьи 2.
Ниже под катом, расскажу об опыте автора по использованию GPU для расчетов, в том числе в рамках создания бота для участия в AI mini cup. Но скорее это эссе на тему GPU.

-Имя у вас волшебное…
-Знаете что, Джоэл?.. Волшебство уходит…

В детстве, говорим о том возрасте когда еще в школе еще не проходят химию или только начинают проходить, автора увлекала реакция горения, так получилось что родители не препятствовали ему и московский пустырь около дома время от времени озарялся вспышками различной детской активности, ракеты на самодельном черном порохе, на сахарно-селитровой карамели и тд. Два обстоятельства ограничили детские фантазии это реакция разложение нитроглицерина в домашней лаборатории с шипящим от кислот потолком и привод в детскую комнату милиции в попытке достать хим реактивы на одном из оборонных предприятий щедро разбросанных по району м.Авиамоторная.
А потом появилась физмат школа с компьютерами yamaha msx, программируемый калькулятор МК дома и стало не до химии. Интересы ребенка сместились к компьютерам. И что не хватало автору с первого знакомства с компьютером так это реакции горения, его программы тлели, не было этого ощущения природной мощи. Можно было увидеть процесс оптимизации вычислений в играх, но в то время заменять вычисление sin() на таблицу значений этой функции автор не умел, интернета не было…
Так вот чувство радости от вычислительной мощности, чистого горения, автор смог получить использую в расчетах GPU.
На хабре есть несколько хороших статей про вычисления на GPU. В интернете тоже много примеров, поэтому решено было просто написать в субботнее утро о личных ощущениях и возможно подтолкнуть других в сторону массового параллелизма.

Начнем с простых форм. Вычисления на GPU поддерживают несколько фреймворков, но самые известные NVIDIA CUDA и OpenCL. Мы возьмем CUDA и сразу нам придется сузить свой набор языков программирования до C++. Существуют библиотеки подключения к CUDA других языков программирования, например ALEA GPU на С#, но это скорее тема отдельной обзорной статьи.

Как не смогли в свое время сделать массовый автомобиль с реактивным двигателем, хотя некоторые показатели у него выше чем у двигателя внутреннего сгорания, так и параллельные вычисления не всегда возможно применить в реальных задачах. Основное применение для параллельных вычислений: нужна задача содержащая какой-то элемент массовости, многочисленности. В нашем случае создания бота под массовость попадает нейронная сеть(много нейронов, нейронных связей) и популяция ботов(вычисления динамики движения, коллизии по каждому боту занимают определенное время, если ботов от 300-1000 то центральный процессор сдается и вы будете наблюдать как раз медленное тление вашей программы, например длительные паузы между кадрами визуализации).
Лучший вариант массовости когда каждый элемент вычислений не зависит от результата вычислений по другому элементу списка, например простая задача сортировки массива уже обрастает всевозможными ухищрениями, так как позиция числа в массиве зависит от других чисел и в лоб на параллельном цикле ее не взять. Еще более упростим формулировку: первый признак удачной массовости, это если вам не нужно менять положение элемента в массиве, вы можете свободно проводить вычисления над ним, брать для этого значения других элементов, но не двигайте его с места. Чем то на сказку похоже: не меняй порядок элементов, иначе GPU превратится в тыкву.

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

Появились первые элементы параллельных конструкций: параллельный цикл. Для большинства задач его будет достаточно. В широком смысле это и есть квинтэссенция
параллельных вычислений.
Пример записи основного цикла в CUDA (kernel):

    int  tid = blockIdx.x * blockDim.x + threadIdx.x;
    int  threadN = gridDim.x * blockDim.x;
    for (int pos = tid; pos < numElements; pos += threadN)
    {
        //  вычисления по параметру pos,  итерации цикла будут выполняться параллельно, другими словами цикл распадется на отдельные thread  каждый со своим параметром pos.
Важное замечание: порядок выполнения отдельных  thread не зависит от вас, поэтому thread с номером pos=1146  может выполняться раньше чем thread c номером pos=956. Это надо помнить при работе с параллельными алгоритмами. Здесь как в зазеркалье много вещей непривычных для последовательно исполняемых программ.
     }

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

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

Вот картинка вполне себе пламя ракеты изображено.

К слову о задачах, которые параллельный цикл в ваших руках не сможет решить.
И об этом уже подумали создатели CUDA в лице разработчиков NVIDIA.
Существует библиотека Thrust местами полезная до «без вариантов» сделать по другому.
Кстати, не нашел полноценного ее обзора на Хабре.
Чтобы понять принцип ее работы, то нужно сказать три предложения о принципах работы CUDA. Если нужно больше слов то по ссылке можно почитать.
Принципы работы CUDA:
Вычисления происходят на GPU программным образом которого является ядро(kernel) и вам придется его написать на языке С. Ядро в свою очередь общается только с памятью GPU и вам придется загружать данные в память видеопроцессора из основной программы и выгружать обратно в программу. Сложные алгоритмы на CUDA требуют гибкости ума.

Так вот, библиотека Thrust снимает часть рутины и берет на себя часть «сложных» для CUDA задач вроде суммирования массивов или их сортировки. Вам больше не нужно писать отдельное ядро, загружать в память указатели и копировать данные по этим указателям в память GPU. Всë таинство произойдет у вас на глазах в основной программе, но со скоростью немного уступающей CUDA. Библиотека Thrust написана на CUDA, так что это одного поля ягоды в части производительности.

Что нужно сделать в Thrust так это создать массив(thrust::vector) в рамках его библиотеки, который совместим с обычным массивов(std::vector). То есть конечно не так все просто, но смысл сказанного автором похож на правду. Действительно два массива, один на GPU(device) другой в основной программе(host).
Пример все объяснит ( X, Y, Z массивы):

// initialize X to 0,1,2,3, ....
    thrust::sequence(X.begin(), X.end());
    // compute Y = -X
    thrust::transform(X.begin(), X.end(), Y.begin(), thrust::negate<int>());
    // fill Z with twos
    thrust::fill(Z.begin(), Z.end(), 2);
    // compute Y = X mod 2
    thrust::transform(X.begin(), X.end(), Z.begin(), Y.begin(), thrust::modulus<int>());
    // replace all the ones in Y with tens
    thrust::replace(Y.begin(), Y.end(), 1, 10);

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

У автора небольшой опыт использования CUDA и С++, месяца два. До этого около года C#. Это конечно немного противоречит началу статьи о его раннем знакомстве с компьютерами, физмат школе и прикладной математики в качестве образования. Но скажу, так получилось. Но для чего это пишу, что С++ оказался комфортным языком, годы его развития привели к вполне дружелюбным средам разработки(IDE). Сам язык в его последней версии вроде как и мусор из памяти собирает, не знаю как было до этого. По крайней мере, программы написанные автором на самых простых алгоритмических конструкциях, сутками гоняли вычислительные алгоритмы для ботов и не было утечек памяти. Это касается и CUDA, поначалу кажется сложным, но в основе лежат простые принципы и конечно местами трудоемко инициализировать массивы на GPU, но ведь потом у вас будет своя маленькая ракета, с дымком с видеокарты.

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

Если будет интересно почитать про клеточные автоматы на CUDA пишите в комментариях, там материала на небольшую статью наберется.
Идея написать статью после завтрака, на одном дыхании мне кажется получилась. Время второго кофе. Хороших выходных мой читатель.

Метки:
Похожие публикации

Ой, у вас баннер убежал!

Ну. И что?

Source: habr1