Русский
Русский
English
Статистика
Реклама

Разработка

Перевод Готовимся к собеседованию по фронтенду 15 вопросов

11.09.2020 20:19:02 | Автор: admin
Автор статьи, перевод которой мы сегодня публикуем, приводит 15 вопросов, которые задавали на собеседованиях ему, и которые он задавал соискателям на должности фронтенд-разработчиков сам.



1. Что такое DOM?


DOM (Document Object Model, объектная модель документа) это программный интерфейс к HTML-документам. Этот интерфейс позволяет воздействовать на документ из скриптов, меняя его оформление, стили, содержимое. В DOM документ представлен в виде дерева узлов.

2. Какая разница между элементами <span> и <div>?


  • <span> это строчный (inline) элемент.
  • <div> это блочный (block) элемент.

Элементы <div> нужно использовать для оформления разделов документа. А элементы <span> в роли контейнеров для небольших объёмов текста, для изображений и других подобных элементов страниц.

Надо отметить, что нельзя помещать блочные элементы в строчные. Вот пример, в котором показано, кроме прочего, неправильное размещение блочного элемента внутри строчного (это фрагмент <div>I'm illegal</div>, размещённый внутри элемента <span>):

<div>Hi<span>I'm the start of the span element <div>I'm illegal</div> I'm the end of the span</span> Bye I'm the end of the div</div>

3. Что такое мета-теги?


Мета-теги это теги, находящиеся в теге страницы <head> и описывающие содержимое страницы. Мета-теги не выводятся на странице. Они имеются лишь в её коде.

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

<head><meta charset="UTF-8"><meta name="description" content="Description search engines use"><meta name="keywords" content="Keywords, of, your, page"><meta name="author" content="Me"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>

4. Какая разница между селекторами идентификаторов и классов в CSS?


Идентификаторы (id) уникальны. У элемента может быть только один идентификатор. На странице может присутствовать лишь один элемент с конкретным идентификатором.

Имена классов (class) не являются уникальными. Один и тот же класс можно назначать множеству элементов. Элементу может быть назначено несколько классов.

Если некий стиль нужно применить к нескольким элементам страницы эту задачу нужно решать с использованием классов.

5. Как пользоваться медиазапросами в CSS?


В медиазапросах используется правило @media, с помощью которого можно применять CSS-стили к различным типам содержимого. Медиазапросы могут использоваться и для настройки элементов страниц с учётом характеристик среды, в которой просматривают страницы.

/* Изменить фоновый цвет любого элемента <div> на "red" в том случае, если ширина окна браузера составляет 600px или меньше */@media only screen and (max-width: 600px) {div {background-color: red;}}

6. Что такое псевдоклассы в CSS?


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

Вот пример:

/*Любой элемент <a>, на который пользователь наведёт указатель мыши, будет окрашен в цвет green.*/a:hover {color: green;}/* Выбирает все посещённые элементы <a> и окрашивает их в цвет purple.*/a:visited {color: purple;}

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

7. Какая разница между следующими видами позиционирования элементов: относительное, фиксированное, абсолютное, статическое?


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

8. Чем отличаются PUT- и POST-запросы?


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

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

Ещё одно отличие между PUT- и POST-запросами заключается в том, что PUT-запросы являются идемпотентными, а POST-запросы нет. То есть если запрос, в котором передаются одни и те же данные, и который выполняется по одному и тому же URL, будет выполнен несколько раз, это равносильно однократному выполнению этого запроса. Многократное выполнение POST-запроса не эквивалентно его однократному выполнению. То есть несколько таких запросов, например, могут привести к созданию нескольких объектов на сервере.

9. В чём отличия технологии Long Polling, протокола WebSocket и событий, генерируемых сервером?


  • Технология Long Polling применяется при взаимодействии клиентских и серверных систем. Клиент отправляет серверу запрос, ответ на который поступает тогда, когда в распоряжении сервера оказываются данные, запрошенные клиентом. После этого клиент выполняет новый запрос.
  • Протокол WebSocket позволяет устанавливать долгоживущие двусторонние соединения между клиентом и сервером.
  • В основе событий, генерируемых сервером, лежит использование долгоживущего HTTP-соединения, которое используется для отправки клиенту новых данных по инициативе сервера.

10. Чем отличаются куки-файлы, сессионное хранилище и локальное хранилище?


Локальное хранилище, как можно понять из его названия, это место, которое браузеры могут использовать для локального хранения данных. В нём может храниться до 10 Мб данных. Сессионное хранилище это разновидность локального хранилища, которое привязано к сессии и удаляется после её завершения. В сессионном хранилище может храниться до 5 Мб данных.

Куки-файлы используются для хранения небольших объёмов данных, не превышающих 4 Кб. Ими может пользоваться браузер, их может запрашивать у браузера сервер.

11. Что такое CORS?


CORS (Cross-Origin Resource Sharing, совместное использование ресурсов между разными источниками) это браузерный механизм, который позволяет предоставлять страницам доступ к ресурсам, расположенным за пределами некоего домена. Это расширяет возможности страниц и добавляет гибкости политике одинакового источника (same-origin policy).

12. Что такое промис?


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

13. В каких состояниях может пребывать промис?


Промис может пребывать в одном из трёх состояний:

  1. Исполнено (fulfilled) операция, связанная с промисом, завершена успешно.
  2. Отклонено (rejected) операция, связанная с промисом, завершена с ошибкой.
  3. Ожидание (pending) промис находится в состоянии ожидания, то есть, о нём нельзя сказать, что он завершён успешно или с ошибкой.

14. Что такое поднятие переменных и функций в JavaScript?


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

15. Какие значения в JavaScript являются ложными?


В JavaScript ложными являются значения, которые, при преобразовании их к логическому типу, становятся значениями false. Это следующие значения:

  • ''
  • 0
  • null
  • undefined
  • NaN
  • false
  • -0
  • 0n // значения типа BigInt, при преобразовании их к логическому типу, ведут себя так же, как значения типа Number

Итоги


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

Я думаю, что для подготовки к фронтенд-собеседованию стоит разобрать гораздо больше вопросов по JavaScript, чем приведено в этом материале. Разбор вопросов по TypeScript тоже может оказаться очень кстати.

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

Какие вопросы на собеседованиях по фронтенду задавали вам?



Подробнее..

Перевод Профессиональная работа в VS Code 4 совета

12.09.2020 16:16:00 | Автор: admin
VS Code это, в наши дни, один из самых популярных редакторов кода. Продуманный подход к использованию этого редактора способен значительно повысить продуктивность программиста. В этом материале представлено несколько советов по профессиональному использованию VS Code. Хочется надеяться, что эти советы вам пригодятся.



1. Использование нескольких курсоров


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

Например, в следующем коде нужно добавить атрибут class=odd к первому, третьему и пятому элементам <li>. А ко второму, четвёртому и шестому элементам нужно добавить атрибут class=even.

<ul><li>Lorem, ipsum dolor.</li><li>Lorem, ipsum dolor.</li><li>Lorem, ipsum dolor.</li><li>Lorem, ipsum dolor.</li><li>Lorem, ipsum dolor.</li><li>Lorem, ipsum dolor.</li></ul>

Вот как выглядит то, что должно получиться, в редакторе.


Код в редакторе

Как решить эту задачу? Раньше я поступал так: вводил нечто вроде текста class=odd в одном месте, а потом копировал его в буфер обмена и вставлял везде, где он нужен. Правда, после того, как я узнал о возможности работать с несколькими курсорами в VS Code, я так делать перестал. Это значительно повысило эффективность моего труда.

В частности, речь идёт о следующем. Для добавления в текст нескольких курсоров нужно удерживать клавишу Alt на клавиатуре (в macOS клавишу Option) и щёлкать по тем местам, где должны появиться курсоры. После этого всё, что вводится с клавиатуры, будет одновременно появляться везде, где имеются курсоры.


Использование нескольких курсоров

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

  • Windows: Alt+Щелчок мышью.
  • macOS: Option+Щелчок мышью.

2. Переименование сущностей и команда Rename Symbol


Теперь давайте изучим ещё один простой приём.

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

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

function foo(){// ...}foo();foo();foo();

Если вручную менять каждую строку, то у такого подхода будет пара недостатков:

  1. Слишком много ручного труда.
  2. Высокая вероятность возникновения ошибок.

Для решения этой задачи можно воспользоваться командой контекстного меню Rename Symbol.


Использование команды меню Rename Symbol

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

3. Перемещение выделенных строк вверх и вниз


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

  • Выделим текст.
  • В Windows воспользуемся сочетанием клавиш Alt+Стрелка вверх для перемещения текста вверх. Для перемещения текста вниз, соответственно, воспользуемся сочетанием клавиш Alt+Стрелка вниз.
  • В macOS роль клавиши Alt играет клавиша Options.

Вот как это выглядит.


Перемещение текста вверх и вниз

Благодаря этому подходу можно быстро и легко менять порядок размещения текста.

4. Сниппеты


В ходе написания кода нам постоянно приходится вводить с клавиатуры одни и те же повторяющиеся конструкции.

Например, HTML5-файлы всегда содержат следующую базовую структуру документа:

<!DOCTYPE html><html lang="en"><head><title></title></head><body></body></html>

А при написании for-циклов на JavaScript мы всегда вводим такие фрагменты кода:

for(let i = 0; i < ; i++){}

Можно привести ещё очень много подобных примеров. Если бы приходилось вводить эти фрагменты кода вручную, поступая так всегда, когда они нужны, это было бы очень неэффективно.

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


Автодополнение ввода

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

Создание конфигурационного файла


Для настройки автодополнения ввода в VS Code нужно сначала создать соответствующий конфигурационный файл. Редактор читает этот файл, реализуя соответствующие механизмы. Для того чтобы создать этот файл, нужно, как показано на следующем рисунке, перейти в меню Code > Preferences > User Snippets.


Команда меню User Snippets

После этого появится следующая панель.


Панель для работы со сниппетами

Здесь можно выбирать существующие конфигурационные файлы и редактировать их. Ещё тут можно создать новый конфигурационный файл. Мы собираемся поступить именно так.

Если выбрать тут команду New Global Snippets file, будет создан конфигурационный файл, доступный глобально. Если же выбрать команду вида New Snippets file for 'test' будет создан файл, доступный локально, в текущем рабочем пространстве.

Мы создадим локальный файл.

После выбора команды New Snippets file for 'test' система запросит имя файла.


Ввод имени нового файла

Конфигурационный файл мы создали, но пока он пуст.


Новый пустой конфигурационный файл

Я, чтобы вам было удобнее, записал весь вышеописанный процесс и представил его здесь в виде анимированного gif-файла.


Создание нового конфигурационного файла

Создание сниппетов


Конфигурационный файл хранит данные в формате JSON. Вот пример его содержимого.


Содержимое конфигурационного файла

Вот то же самое, но уже в виде обычного текста:

{"html5 autocomplete": {"prefix": "html5","body": ["<!DOCTYPE html>","<html lang=\"en\">","<head>"," <title></title>","</head>","<body>","</body>","</html>"]}}

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

Разберёмся теперь с полем prefix: html5. Оно предназначено для описания задаваемого нами сокращения, которое редактор раскрывает в некий фрагмент кода. Когда мы вводим в редакторе текст html5, редактор автоматически заменяет его на то, что задано в элемент body.

Элемент body: [] содержит тот код, который редактор должен вставить в документ вместо введённого нами префикса. Так как этот код может состоять из множества строк, данное поле представлено массивом. Каждый элемент массива это одна строка кода. Если перевести конструкцию, которую мы только что рассматривали, на язык обычного HTML-кода, то получится, что она равносильна следующему:

<!DOCTYPE html><html lang="en"><head><title></title></head><body></body></html>

Теперь, когда в нашем распоряжении есть простой конфигурационный файл, давайте его протестируем.


Испытание конфигурационного файла

Область действия сниппетов


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

В таких случаях очень кстати оказывается возможность указания области действия сниппетов. А именно, речь идёт о поле scope: html, которое нужно добавить в описание сниппета.


Ограничение области действия сниппета HTML-файлами

Испытаем нашу систему снова. Попробуем префикс html5 в HTML-файле и в JS-файле.


Испытание сниппета в HTML- и в JS-файле

В JS-файле, как видно, ввод html5 ни к чему особенному не приводит. А это именно то, что нам нужно.

Курсор


Давайте снова испытаем автодополнение ввода, выполняемое на основе созданного нами файла. Присмотримся к нему. Нет ли в нём каких-нибудь изъянов?


Исследование автодополнения ввода

Видно, что после вставки блока кода в редактор курсор автоматически попадает в конец этого блока. Но блок кода, который автоматически вставлен в документ, это лишь заготовка, над которой нужно ещё поработать. В частности, надо ввести содержимое тега <title>.

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

Для того чтобы это сделать, мы можем воспользоваться в конфигурационном файле специальной конструкцией $0. Вот как это выглядит.


Настройка местоположения курсора

Теперь, после того, как код оказывается в документе, курсор автоматически устанавливается туда, где в конфигурационном файле имеется $0.


Курсор устанавливается в нужном месте

Пример


А теперь, чтобы закрепить то, что мы только что изучили, давайте рассмотрим новый пример.

Нам хотелось бы, чтобы, после ввода в JavaScript- или TypeScript-файле текста fori, там автоматически появлялась бы следующая конструкция:

for(let i = 0; i < ; i++){}

И ещё чтобы курсор автоматически устанавливался бы после i <.

Можете пока не смотреть на решение этой задачи. Попытайтесь решить её самостоятельно.

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

{"for-i loop": {"prefix": "fori","scope": "javascript, typescript","body": ["for(let i = 0; i < $0; i++){","}"]}}

Вот демонстрация.


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

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

Какие возможности VS Code помогают вам в повседневной работе?



Подробнее..

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

13.09.2020 16:10:25 | Автор: admin
В сфере серверного программирования разбиение традиционных монолитных бэкендов на микросервисы позволило добиться невиданной прежде эффективности работы и недоступных ранее возможностей по масштабированию проектов. Но, несмотря на это, большинство фронтенд-систем всё ещё представляют собой монолиты. Это усложняет оптимизацию работы над такими системами и препятствует улучшению их масштабирования.



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

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

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

1. Платформа Bit


Платформа Bit позволяет собирать фронтенды из независимых компонентов. Она помогает разрабатывать компоненты и управлять ими. Это, вероятно, наиболее популярное решение в моём списке, которое лучше других подготовлено к продакшн-разработке.

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


Домашняя страница bit.dev создана с использованием компонентов, работа с которыми организована с помощью Bit

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

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

При использовании Bit разные команды могут независимо создавать и публиковать собственные компоненты, взаимодействуя с другими командами на уровне API компонентов. Это позволяет превратить веб-разработку в процесс сборки проектов из отдельных модулей.

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

В Bit предусмотрен уникальный CI/CD-процесс, полностью основанный на компонентах, который направлен на организацию быстрой сборки проектов. Это означает, что различные команды могут, не опасаясь негативных последствий для проекта, вносить изменения в разрабатываемые ими части проектов. Им не нужно чего-то ждать от других команд или конкурировать за внесение изменений в ветку master проекта. Разработчики могут непрерывно и безопасно, не опасаясь что-то испортить в тех частях проектов, которыми заняты не они, вносить изменения в свои компоненты. Эти изменения распространяются на все приложения, в которых используются эти компоненты.


Система непрерывной интеграции, основанная на компонентах, в 50 раз быстрее обычной

В результате процесс разработки обогащается следующими возможностями:

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

Вот материал, в котором приведён пример подобной организации работы над проектами.

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

2. Webpack 5 и архитектура Module Federation


JavaScript-архитектуру Module Federation (MF, федерация модулей) предложил Зак Джексон. Он же был инициатором создания webpack-плагина для реализации этой архитектуры. Благодаря усилиями команды webpack этот плагин появился в Webpack 5, сейчас он находится на стадии бета-версии.

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

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

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

Архитектура Module Federation открывает очень интересные возможности по разработке микрофронтендов. Подробности об этой архитектуре и пример её использования можно найти здесь.

3. Проект single-spa


Создатели проекта single-spa определяют его как JavaScript-фреймворк для применения микросервисов во фронтенд-разработке. Если кратко описать его суть, то можно сказать, что он реализует идею жизненного цикла некоей сущности в применении к каждому отдельному приложению, из которого состоит проект. Каждое приложение может реагировать на события маршрутизации и должно знать о том, как ему разворачиваться, монтироваться в DOM и отмонтироваться от DOM. Основное отличие обычных SPA (Single Page Application, одностраничное приложение) и того, что получается при использовании single-spa, заключается в том, что single-spa-приложения должны иметь возможность сосуществования с другими приложениями, входящими в состав некоего проекта. При этом у этих приложений нет собственных HTML-страниц.

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

4. Загрузчик модулей SystemJS


Загрузчик модулей SystemJS это не фреймворк для разработки микрофронтендов, но этот проект позволяет решить проблему кросс-браузерного управления независимыми модулями, а это ключ к реализации микрофронтендных архитектур (этот подход используется, на самом деле, и в single-spa).

SystemJS можно рассматривать в виде оркестратора JS-модулей. Он позволяет использовать различные возможности таких модулей, вроде динамических импортов и карт импорта, не полагаясь на стандартные механизмы браузеров. И всё это с уровнем производительности, близким к тем, что дают встроенные возможности браузеров. Среди интересных возможностей SystemJS можно отметить наличие полифиллов для устаревших браузеров, импорт модулей с использованием имён (через сопоставление имён модулей и путей к ним), загрузку нескольких модулей одним запросом (с использованием API для представления нескольких модулей в виде единого файла).

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

5. Фреймворк Piral


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

Тому, кто хочет пользоваться Piral, достаточно иметь редактор кода, терминал, браузер и Node.js. Экземпляр Piral (оболочка приложения) и пилеты (модули) можно выполнять и отлаживать в эмуляторе на локальном компьютере разработчика.


Работа с Piral

6. Проект Open Components


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

  • Сущности components (компоненты) это маленькие фрагменты изоморфного содержимого, состоящие, в основном, из кода, написанного на HTML, JavaScript и CSS. Они могут, что необязательно, содержать какую-то логику, что позволяет серверному Node.js-приложению создавать модели, используемые для рендеринга визуальных представлений компонентов. После рендеринга эти сущности становятся обычным HTML-кодом, который можно встроить в любую веб-страницу.
  • Сущности consumers (потребители) это веб-сайты или микросайты (маленькие, независимо развёртываемые веб-сайты, соединённые неким механизмом маршрутизации или общим сервисом, представляющим точку входа в систему), которым компоненты нужны для рендеринга каких-то частей содержимого веб-страниц.

7. Проект Qiankun


Проект Qiankun описывается как реализация микрофронтендов, основанная на single-spa, но готовая к продакшн-использованию. Этот проект нацелен на решение некоторых из основных задач, связанных со сборкой больших приложений из маленьких подсистем (подприложений). Среди таких задач можно отметить публикацию статических ресурсов, объединение подсистем, обеспечение независимости подсистем друг от друга во время их разработки и развёртывания, обеспечение изоляции подсистем во время выполнения кода, обработка зависимостей, обеспечение высокой производительности решений.


Проект Qiankun

8. Фреймворк Luigi


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


Luigi

Фреймворк Luigi состоит из двух подсистем. Это основное приложение и клиентские библиотеки. Взаимодействие между ними основано на API postMessage.

Вот песочница, в которой вы можете поэкспериментировать с Luigi. А вот репозиторий проекта. Работой над ним, кстати, занимается компания SAP.

9. Фреймворк FrintJS


FrintJS это модульный JavaScript-фреймворк для разработки масштабируемых реактивных приложений. Он позволяет загружать приложения, собранные различными бандлерами, помогает структурировать приложения и поддерживает правильную работу таких механизмов, как маршрутизация и обработка зависимостей. Этот фреймворк, помимо React (работа с этой библиотекой хорошо документирована и протестирована), поддерживает, посредством дополнительных пакетов, React Native и Vue.


FrintJS

Здесь находится интерактивная песочница FrintJS

10. Mosaic 9


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


Архитектура Mosaic

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

11. Фреймворк PuzzleJS


PuzzleJS это микрофронтендный фреймворк, предназначенный для разработки масштабируемых и быстрых сайтов. Он позволяет создавать проекты, называемые шлюзами (gateway) и интерфейсами (storefront), которые взаимодействуют друг с другом. Создатели PuzzleJS черпали вдохновение, в плане микрофронтендной архитектуры, в проекте Facebook BigPipe.


PuzzleJS

PuzzleJS позволяет создавать независимые друг от друга порталы и интерфейсы, настраивая их взаимодействие с помощью конфигурационного файла. Он позволяет преобразовывать HTML-шаблоны в JavaScript-функции во время компиляции кода. Эта операция независима от запросов на загрузку данных. В результате функция, в ответ на запрос, начинает передавать данные очень быстро, что улучшает такой показатель производительности веб-страниц, как время до первого байта. Этот фреймворк, за счёт применения в нём серверного рендеринга материалов, хорош в плане SEO. Кроме того, если API, необходимый для работы некоего фрагмента страницы, перестаёт реагировать на запросы, это не нарушает работу других фрагментов. Вот реальный пример использования PuzzleJS.

Итоги


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

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

Как вы относитесь к микрофронтендам?



Подробнее..

Перевод Как убрать из Git-репозитория файлы с конфиденциальной информацией

16.09.2020 16:23:32 | Автор: admin
Файлы проиндексированы, написано сообщение коммита, данные отправлены на сервер И вдруг хочется повернуть время вспять. В коммит попал файл, которого там быть не должно. Когда такое случается, приходит время обращаться к поисковику.

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

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


Удаление файлов с конфиденциальной информацией из Git-репозитория (изображение большого размера)

Минимизация ущерба


Итак, вы случайно закоммитили файл с конфиденциальной информацией. Назовём этот файл .env. Сразу после того, как это случилось, надо задать себе пару вопросов:

  • Отправлен ли коммит в удалённый репозиторий?
  • Является ли удалённый репозиторий общедоступным?

Коммит пока не отправлен в удалённый репозиторий


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

git reset HEAD^ --soft

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

Если же вы хотите сохранить коммит и вам нужно просто удалить из него определённые файлы, тогда поступите так:

git rm .env --cachedgit commit --amend

Параметр --amend можно использовать только для работы с самым свежим коммитом. Если вы, после неудачного коммита, добавили ещё несколько, воспользуйтесь такой командой:

git rebase -i HEAD~{на сколько коммитов нужно вернуться?}

Это позволит исправить неправильный коммит и поможет не потерять изменения, внесённые в проект остальными коммитами.

Коммит отправлен в удалённый репозиторий


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

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

Если вы отправили в репозиторий, после проблемного коммита, и другие коммиты, это не помешает вам убрать файлы с конфиденциальными данными из истории Git, воспользовавшись командой git filter-branch или инструментом BFG Repo-Cleaner.

Вот пример использования git filter-branch:

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch .env" --prune-empty --tag-name-filter cat -- --all

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

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

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


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

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

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

Рекомендации по хранению конфиденциальных файлов в проектах, в которых для контроля версий применяется Git


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

Храните секретные данные в файле .env (или в другом подобном файле)


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

Ещё одно преимущество такого подхода заключается в том, что так у вас будет доступ ко всем ключам через глобальную переменную process.

Используйте, если это возможно, ключи API


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

Храните ключи API, пользуясь средствами вашего инструмента для сборки проектов


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


Управление переменными окружения

Добавьте запись о файле .env в файл .gitignore


Сделайте так, чтобы Git не отслеживал бы файлы, содержащие конфиденциальную информацию.

Подготовьте шаблонный файл .env.template


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

Не меняйте историю Git в удалённых репозиториях


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

Итоги


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

А вам случалось отправлять в общедоступный репозиторий что-то такое, что туда попадать не должно?



Подробнее..

Перевод Выбираем лучший бэкенд-фреймворк 2021 года

18.09.2020 16:04:09 | Автор: admin
Недавно мы опубликовали статью, автор которой размышлял о том, какой язык программирования, JavaScript, Python или Go, лучше всего подойдёт для бэкенд-разработки в 2021 году. Сегодня мы представляем вашему вниманию перевод ещё одного материала того же автора. Здесь он пытается найти ответ на вопрос о том, на какой фреймворк для разработки серверных частей приложений стоит обратить внимание тем, кто хочет во всеоружии встретить 2021 год.



О роли фреймворков в IT-индустрии


Я, проанализировав результаты опроса разработчиков, проведённого в 2020 году Stack Overflow, понял, что использование фреймворков играет огромную роль в IT-индустрии. А именно, речь идёт об ответах на вопрос о том, что разработчики считают самым важным при поиске работы.


Факторы, влияющие на выбор места работы

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

Разработчик обычно знаком хотя бы с одним фреймворком. Здесь я собираюсь рассказать о трёх фреймворках о Node.js/Express, Django и Spring Boot. Полагаю, что тот, кто, готовясь к 2021 году, решит сделать своим основным инструментом один из них, в любом случае, не прогадает. Но у каждого из них есть свои особенности, которые мне и хотелось бы здесь обсудить.

Результаты исследований и другие данные


Данные с GitHut


Ресурс GitHut позволяет узнать различные сведения о репозиториях. В частности, речь идёт о количестве активных репозиториев, об общем количестве PR, и о разных показателях, рассчитываемых по состоянию на один репозиторий: количество PR и форков, число открытых задач, количество новых подписчиков.


Популярность языков программирования на GitHub

Исследование Stack Overflow


Если взглянуть на результаты исследования Stack Overflow, то окажется, что Express находится на первом месте среди бэкенд-фреймворков, которые любят разработчики. Два других интересующих нас фреймворка, Spring и Django, следуют за Express с небольшим отрывом. В результате оказывается, что проект, основанный на самом перспективном скриптовом языке, на JavaScript, лидирует, а за ним идёт проект, в котором используется один из языков, обладающих самыми широкими возможностями, то есть Python.


Популярность веб-фреймворков

GitHub-репозитории


Некоторые люди не любят перемен, но изменения необходимо принимать, если альтернативой является катастрофа.
Илон Маск


Фреймворк Express создан на базе платформы Node.js, поэтому тут мы будем сравнивать репозитории Node.js, Spring Boot и Django


Репозиторий node


Репозиторий spring-boot


Репозиторий django

Как видно, больше всего звёзд у репозитория Node.js. Но разница между звёздами проектов не так сильна, как различие в количестве их форков. У Spring Boot и Django имеется гораздо больше форков, чем у Node.js.

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

Node.js/Express


Node.js представляет собой серверную платформу, которая является частью стека технологий, охватывающих все нужды веб-разработки, и основанных на JavaScript. В Node.js используется JavaScript-движок V8, тот же самый, что применяется в браузере Chrome и в других браузерах, основанных на Chromium. В результате оказывается, что благодаря использованию Node.js код, предназначенный для выполнения на сервере, можно писать на JavaScript. На базе платформы Node.js создано множество фреймворков, включая такие популярные, как Express.

Сильные стороны Node.js


  • Появление Node.js сделало возможным фуллстек-разработку веб-проектов на JavaScript. В результате в распоряжении разработчиков серверных частей приложений оказались и сильные возможности JavaScript, и наработки экосистемы JS, библиотеки, которыми стало реально воспользоваться в серверном окружении.
  • JavaScript-код, аналогичный по функционалу, например, коду, написанному на C, оказывается компактнее. Производительность JavaScript-кода при этом достаточно высока для применения его в проектах, в которых важна скорость работы кода.
  • Код клиентских и серверных частей проектов легче поддерживать в согласованном состоянии, так как и там и там используется один и тот же язык.
  • Один и тот же код можно совместно использовать и на клиенте, и на сервере.
  • Благодаря существованию модулей Node.js, которые, в сущности, представляют собой особым образом оформленные фрагменты кода, разработчики могут с удобством использовать в своих проектах чужой код, а так же собственные наработки.
  • Платформа Node.js, и, соответственно, основанные на ней фреймворки, отличаются нетребовательностью к ресурсам и масштабируемостью. Именно поэтому Node.js это платформа, к которой часто прибегают те, кто пользуется микросервисными архитектурами.
  • Эта платформа хорошо подходит для разработки микросервисов ещё и из-за существования системы модулей Node.js, которые можно представить себе в виде строительных блоков серверных приложений.
  • В Node.js JavaScript код компилируется в машинный код, что позволяет получить гораздо более высокую производительность, чем при интерпретации кода. Сообщество JavaScript-разработчиков видит постоянное улучшение производительности Node.js за счёт того, что Google постоянно работает над совершенствованием V8.
  • Благодаря тому, что в Node.js имеется система ввода-вывода, не блокирующая главный поток, эта платформа демонстрирует высокую производительность. Достойная скорость обработки запросов достигается благодаря использованию JavaScript-механизмов конкурентного однопоточного выполнения кода.
  • Node.js это опенсорсный проект, вокруг которого собралось огромное сообщество разработчиков. Это значит, что тот, кто столкнётся с какой-то проблемой, сможет достаточно быстро найти её решение.
  • Node.js, в ближайшем будущем, может стать платформой, которую будут использовать для проведения тяжёлых вычислений, наподобие тех, которые применяются для решения задач машинного обучения.

Компании, которые используют Node.js


  • Paypal
  • Netflix
  • LinkedIn
  • Uber
  • eBay
  • Yahoo

Если учесть сильные стороны Node.js и то, в каких компаниях используется эта платформа, становятся понятными причины её огромной популярности. Зарплата Node.js-разработчиков в США варьируется в пределах $40,000-$130,000 в год. В результате можно сказать, что если вы чувствуете, что Node.js и фреймворки, основанные на этой платформе, вам интересны, вы вполне можете выбрать именно их в качестве базы для своих разработок 2021 года.

Spring Boot


Проект Spring Boot это фреймворк для разработки бэкенд-приложений, основанный на Java, который, как и Node.js, используется для разработки микросервисов. Этот фреймворк упрощает создание приложений, основанных на Spring, его можно представить себе в виде инструмента для создания самостоятельных Spring-приложений. Если вы планируете в 2021 году перейти на Spring, то вам, определённо, стоит знать о том, чем вам в этом деле сможет помочь Spring Boot.

Сильные стороны Spring Boot


  • Spring Boot позволяет с минимальными усилиями создавать самостоятельные Spring-приложения, облегчает процесс их конфигурирования, упрощает работу над ними. Подобные приложения легко запускаются с помощью команды java -jar.
  • Если в процессе создания Spring Boot-приложения произошла ошибка, встроенный анализатор ошибок поможет справиться с проблемой.
  • Spring Boot поддерживает встроенные серверы, вроде Tomcat и Jetty. Это значит, что тем, кто пользуется Spring Boot, не нужно развёртывать .war-файлы на внешних серверах.
  • Использование Spring Boot позволяет облегчить конфигурирование Maven за счёт наличия в системе начальных вариантов файла pom.xml.
  • В возможности фреймворка входит автоматическое конфигурирование Spring.
  • Spring Boot хорошо интегрируется с другими фреймворками.
  • Фреймворк предоставляет разработчику конфигурации, готовые для продакшн-использования. Сюда входят, например, метрики состояния проекта и внешние конфигурации.
  • При использовании Spring Boot нет нужды в применении XML-конфигураций или средств для генерирования кода.
  • Применение Spring Boot облегчает труд разработчиков за счёт применения принципа проектирования ПО, известного как Convention over Configuration.

Компании, которые используют Spring


  • Platform
  • Intuit
  • MIT
  • Zillow
  • TransferWise

Честно говоря, я не фанат Java. И я не будут использовать Spring Boot для серверной разработки в 2021 году. Но, если верить статистике, существует много программистов, применяющих этот фреймворк. Если говорить о зарплатах соответствующих специалистов, то это что-то около $50,000-$104,000 в год. Это немного меньше, чем зарплаты Node.js-разработчиков.

Django


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

Сильные стороны Django


  • Django позволяет без особых сложностей создавать динамические веб-приложения с использованием Python. Данный фреймворк написан на Python. В этом заключается одно из главных достоинств Django.
  • Фреймворк поддерживает паттерн проектирования MVC. Это помогает разработчикам в разделении пользовательского интерфейса и бизнес-логики Django-приложений.
  • Это быстрый фреймворк, не перегруженный ненужными возможностями. Я имеют в виду то, что использование Django позволяет быстро выйти на работоспособный проект.
  • Django не относится к минималистичным фреймворкам, широко используемым для разработки микросервисов. Он отличается мощностью, универсальностью и определённым своеобразием.
  • Создатели этого фреймворка серьёзно относятся к безопасности. Поэтому они дают разработчикам, использующим Django, соответствующие инструменты. Я уверен, что все вы знаете о том, как много проблем существует в наши дни в сфере кибербезопасности. Поэтому чрезвычайно важными являются вопросы защиты веб-проектов. Django поддерживает систему аутентификации пользователей, содержит инструменты для защиты от различных атак. Среди них средства защиты от SQL-инъекций, от межсайтового скриптинга, от межсайтовой подделки запросов, от кликджекинга.
  • Django-проекты отличаются компактностью кода.
  • Разработчики, использующие Django, могут моделировать базовые классы. Это значит, что в их распоряжении всегда имеется ORM.
  • Django это кросс-платформенный проект. Он отлично работает на различных операционных системах. Кроме того, он поддерживает взаимодействие с различными базами данных.
  • Это фреймворк, приложения, созданные с использованием которого, хорошо поддаются масштабированию. Поэтому тот, кто выбирает Django, может быть уверенным в том, что сможет эффективно развивать свой проект по мере его роста.
  • Вокруг Django сформировалось активное сообщество. Поэтому тот, кто столкнулся с какой-то проблемой, сможет без особых сложностей её решить.

Компании, которые используют Django


  • Mozilla
  • NASA
  • Pinterest
  • Bitbucket
  • Instagram

Так как Django основан на Python, о производительности этого фреймворка и о его поддержке можно не беспокоиться. Кроме того, если взглянуть на список компаний, использующих Django, можно сделать вывод о том, что это фреймворк, достойный внимания и в этом, и в будущем году. Если проанализировать зарплаты Django-разработчиков, то окажется, что это что-то между $90,000-$120,000 в год. В результате оказывается, что спрос на Django-специалистов достаточно высок.

Итоги


Вышеприведённые факты позволяют сделать вывод о том, что платформа Node.js, в лице фреймворка Express, и Django показывают себя очень хорошо. Но, в то же время, Spring Boot тоже представляет собой достаточно интересное явление. Полагаю, что самым интересной платформой для разработки серверных частей приложений в 2021 году будет Node.js. Хотя и Django это отличный, развитый фреймворк, который вполне может стать чьим-то выбором в будущем году.

Каким фреймворком для разработки серверных частей веб-проектов вы планируете пользоваться в 2021 году?



Подробнее..

Перевод Программисту. 10 ценных GitHub-репозиториев

19.09.2020 16:20:36 | Автор: admin
GitHub это платформа, дающая программистам отличные инструменты для организации работы над кодом. Но в GitHub-репозиториях, помимо кода, можно найти массу ценных учебных материалов. Я, например, занимаюсь разработкой ПО и постоянно ищу репозитории, которые могут чем-то мне пригодиться. Вот 10 моих любимых GitHub-проектов.



1. danistefanovic/build-your-own-x


Звёзды GitHub: около 82 тысяч

Репозиторий build-your-own-x это фантастический ресурс, который предназначен для всех, кто хочет что-то создать. Такие люди могут найти тут массу идей, каждая из которых способна лечь в основу их собственного проекта. Кроме того, в этом репозитории, если даже не использовать его для поиска идей, можно найти много интересных материалов.

2. trekhleb/javascript-algorithms


Звёзды GitHub: около 81 тысячи

Одно из отличий программиста (Software Engineer) и разработчика (Software Developer) заключается в том, что программист, скорее всего, лучше, чем разработчик, разбирается в алгоритмах и структурах данных. Но вне зависимости от того, что вы уже знаете, вы сможете найти в репозитории javascript-algorithms что-то такое, что вас заинтересует. А именно, здесь имеется большой набор материалов по алгоритмам и структурам данных с примерами их реализации на JavaScript. Здесь же можно найти ответы на вопросы, которые встречаются на собеседованиях.

3. ossu/computer-science


Звёзды GitHub: около 64 тысяч

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

4. 30-seconds/30-seconds-of-code


Звёзды GitHub: около 59 тысяч

В репозитории 30-seconds-of-code имеется более сотни коротких примеров кода, написанного на JavaScript. Среди этих примеров можно встретить, скажем, реализации неких алгоритмов, а так же код, который может пригодиться программисту для решения разных рабочих задач. Полагаю, этот репозиторий, определённо, достоин вашего внимания.

5. gothinkster/realworld


Звёзды GitHub: около 46 тысяч

Хотелось вам когда-нибудь узнать о том, как создают реальные приложения с использованием некоего языка или некоей технологии? Если так значит репозиторий realworld, представляющий проект RealWorld example apps, создан специально для вас. Многие приложения-примеры представляют собой клоны типичного списка дел, известного как TODO-приложение. Репозиторий realworld идёт другим путём. А именно, здесь можно найти тщательно проработанный проект, похожий на medium.com. При этом тут показаны варианты данного проекта, созданные с использованием различных технологий разработки клиентских и серверных частей приложений.

6. EbookFoundation/free-programming-books


Звёзды GitHub: около 160 тысяч

В репозитории free-programming-books можно найти множество ссылок на бесплатные книги по самым разным темам, имеющим отношение к программированию.

7. donnemartin/system-design-primer


Звёзды GitHub: около 107 тысяч

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

8. vinta/awesome-python


Звёзды GitHub: около 86 тысяч

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

9. goldbergyoni/nodebestpractices


Звёзды GitHub: около 52 тысяч

Я постоянно читаю материалы с различными рекомендациями и лучшими практиками по Node.js и никак не могу начитаться. Именно поэтому я, когда нашёл репозиторий nodebestpractices, понял, что он увлечёт меня надолго. Одна из бед программистов-самоучек заключается в том, что они далеко не всегда начинают с того, что относится к разряду лучших практик. А ресурсы, подобные этому репозиторию, помогают профессиональному росту таких программистов.

10. josephmisiti/awesome-machine-learning


Звёзды GitHub: около 46 тысяч

Репозиторий awesome-machine-learning похож на вышерассмотренный awesome-python. Здесь можно найти массу ценных материалов по машинному обучению.

Итоги


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

А у вас есть любимые GitHub-репозитории, которые вы могли бы порекомендовать другим?



Подробнее..

Перевод Секреты JavaScript-функций

20.09.2020 18:23:47 | Автор: admin
Каждый программист знаком с функциями. В JavaScript функции отличаются множеством возможностей, что позволяет называть их функциями высшего порядка. Но, даже если вы постоянно пользуетесь JavaScript-функциями, возможно, им есть чем вас удивить.



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

Чистые функции


Функция, которая соответствует двум следующим требованиям, называется чистой:

  • Она всегда, при вызове её с одними и теми же аргументами, возвращает один и тот же результат.
  • При выполнении функции не происходит никаких побочных эффектов.

Рассмотрим пример:

function circleArea(radius){return radius * radius * 3.14}

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

Вот ещё один пример:

let counter = (function(){let initValue = 0return function(){initValue++;return initValue}})()

Испытаем эту функцию в консоли браузера.


Испытание функции в консоли браузера

Как видно, функция counter, реализующая счётчик, при каждом её вызове возвращает разные результаты. Поэтому её нельзя назвать чистой.

А вот ещё пример:

let femaleCounter = 0;let maleCounter = 0;function isMale(user){if(user.sex = 'man'){maleCounter++;return true}return false}

Здесь показана функция isMale, которая, при передаче ей одного и того же аргумента, всегда возвращает один и тот же результат. Но у неё есть побочные эффекты. А именно, речь идёт об изменении глобальной переменной maleCounter. В результате эту функцию чистой назвать нельзя.

Зачем нужны чистые функции?


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

1. Код чистых функций понятнее, чем код обычных функций, его легче читать


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

2. Чистые функции лучше поддаются оптимизации при компиляции их кода


Предположим, имеется такой фрагмент кода:

for (int i = 0; i < 1000; i++){console.log(fun(10));}

Если fun это функция, не являющаяся чистой, то во время выполнения этого кода данную функцию придётся вызвать в виде fun(10) 1000 раз.

А если fun это чистая функция, то компилятор сможет оптимизировать код. Он может выглядеть примерно так:

let result = fun(10)for (int i = 0; i < 1000; i++){console.log(result);}

3. Чистые функции легче тестировать


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

Вот простой пример. Чистая функция принимает в виде аргумента массив чисел и прибавляет к каждому элементу этого массива число 1, возвращая новый массив. Вот её сокращённое представление:

const incrementNumbers = function(numbers){// ...}

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

let list = [1, 2, 3, 4, 5];assert.equals(incrementNumbers(list), [2, 3, 4, 5, 6])

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

Функции высшего порядка.


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

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

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

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

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

const arr1 = [1, 2, 3];const arr2 = [];for (let i = 0; i < arr1.length; i++) {arr2.push(arr1[i] * 2);}

Если же над задачей поразмыслить, то окажется, что у объектов типа Array в JavaScript есть метод map(). Этот метод вызывают в виде map(callback). Он создаёт новый массив, заполненный элементами массива, для которого его вызывают, обработанными с помощью переданной ему функции callback.

Вот как выглядит решение этой задачи с использованием метода map():

const arr1 = [1, 2, 3];const arr2 = arr1.map(function(item) {return item * 2;});console.log(arr2);

Метод map() это пример функции высшего порядка.

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

Кеширование результатов работы функций


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

function computed(str) {// Представим, что в этой функции проводятся ресурсозатратные вычисленияconsole.log('2000s have passed')// Представим, что тут возвращается результат вычисленийreturn 'a result'}

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

Как оснастить функцию кешем? Для этого можно написать особую функцию, которую можно использовать в качестве обёртки для целевой функции. Этой особой функции мы дадим имя cached. Данная функция принимает целевую функцию в виде аргумента и возвращает новую функцию. В функции cached можно организовать кеширование результатов вызова оборачиваемой ей функции с использованием обычного объекта (Object) или с помощью объекта, представляющего собой структуру данных Map.

Вот как может выглядеть код функции cached:

function cached(fn){// Создаёт объект для хранения результатов, возвращаемых после каждого вызова функции fn.const cache = Object.create(null);// Возвращает функцию fn, обёрнутую в кеширующую функцию.return function cachedFn (str) {// Если в кеше нет нужного результата - вызывается функция fnif ( !cache[str] ) {let result = fn(str);// Результат, возвращённый функцией fn, сохраняется в кешеcache[str] = result;}return cache[str]}}

Вот результаты экспериментов с этой функцией в консоли браузера.


Эксперименты с функцией, результаты работы которой кешируются

Ленивые функции


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

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

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

Её код может выглядеть так:

let fooFirstExecutedDate = null;function foo() {if ( fooFirstExecutedDate != null) {return fooFirstExecutedDate;} else {fooFirstExecutedDate = new Date()return fooFirstExecutedDate;}}

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

А именно, функцию мы можем переписать так:

var foo = function() {var t = new Date();foo = function() {return t;};return foo();}

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

Это был очень простой условный пример. Давайте теперь рассмотрим нечто, более близкое к реальности.

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

function addEvent (type, el, fn) {if (window.addEventListener) {el.addEventListener(type, fn, false);}else if(window.attachEvent){el.attachEvent('on' + type, fn);}}

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

function addEvent (type, el, fn) {if (window.addEventListener) {addEvent = function (type, el, fn) {el.addEventListener(type, fn, false);}} else if(window.attachEvent){addEvent = function (type, el, fn) {el.attachEvent('on' + type, fn);}}addEvent(type, el, fn)}

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

Каррирование функций


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

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

Какая от этого польза?

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

Рассмотрим простую функцию, складывающую передаваемые ей числа. Назовём её add. Она принимает три операнда в виде аргументов и возвращает их сумму:

function add(a,b,c){return a + b + c;}

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

add(1,2,3) --> 6add(1,2) --> NaNadd(1,2,3,4) --> 6 //Дополнительный параметр игнорируется.

Как каррировать такую функцию?

Вот код функции curry, которая предназначена для каррирования других функций:

function curry(fn) {if (fn.length <= 1) return fn;const generator = (...args) => {if (fn.length === args.length) {return fn(...args)} else {return (...args2) => {return generator(...args, ...args2)}}}return generator}

Вот результаты экспериментов с этой функцией в браузерной консоли.


Эксперименты с функцией curry в консоли браузера

Композиция функций


Предположим, надо написать функцию, которая, принимая на вход, например, строку bitfish, возвращает строку HELLO, BITFISH.

Как видно, эта функция выполняет две задачи:

  • Конкатенация строк.
  • Преобразование символов результирующей строки к верхнему регистру.

Вот как может выглядеть код такой функции:

let toUpperCase = function(x) { return x.toUpperCase(); };let hello = function(x) { return 'HELLO, ' + x; };let greet = function(x){return hello(toUpperCase(x));};

Поэкспериментируем с ней.


Испытание функции в консоли браузера

Эта задача включает в себя две подзадачи, оформленные в виде отдельных функций. В результате код функции greet получился достаточно простым. Если бы нужно было выполнить больше операций над строками, то функция greet содержала бы в себе конструкцию наподобие fn3(fn2(fn1(fn0(x)))).

Упростим решение задачи и напишем функцию, которая выполняет композицию других функций. Назовём её compose. Вот её код:

let compose = function(f,g) {return function(x) {return f(g(x));};};

Теперь функцию greet можно создать, прибегнув к помощи функции compose:

let greet = compose(hello, toUpperCase);greet('kevin');

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

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

Подобная функция, способная принимать любое количество параметров, имеется в широко известной опенсорсной библиотеке underscore.

function compose() {var args = arguments;var start = args.length - 1;return function() {var i = start;var result = args[start].apply(this, arguments);while (i--) result = args[i].call(this, result);return result;};};

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

Применяете ли вы в своих JavaScript-проектах какие-то особенные способы работы с функциями?



Подробнее..

Перевод Введение в React, которого нам не хватало

21.09.2020 16:09:27 | Автор: admin
React это самая популярная в мире JavaScript-библиотека. Но эта библиотека не потому хороша, что популярна, а потому популярна, что хороша. Большинство существующих вводных руководств по React начинается с примеров того, как пользоваться этой библиотекой. Но эти руководства ничего не говорят о том, почему стоит выбрать именно React.

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



Этот материал (вот, если интересно, его видеоверсия) написан для тех, кто хочет найти ответ на следующие вопросы: Почему React? Почему React работает именно так? С какой целью API React устроены так, как устроены?.

Почему React?


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

Когда появилась библиотека React это на фундаментальном уровне изменило то, как работают JavaScript-фреймворки и библиотеки. В то время как другие подобные проекты продвигали идеи MVC, MVVM и прочие подобные, в React был выбран другой подход. А именно, тут рендеринг визуальной составляющей приложения был изолирован от представления модели. Благодаря React во фронтенд-экосистеме JavaScript появилась совершенно новая архитектура Flux.

Почему команда разработчиков React поступила именно так? Почему такой подход лучше тех, что появились раньше него, вроде архитектуры MVC и спагетти-кода, который пишут на jQuery? Если вы из тех, кого интересуют эти вопросы, можете посмотреть это выступление 2013 года, посвящённое разработке JavaScript-приложений в Facebook.

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

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

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

Отсутствие детерминизма = параллельные вычисления + мутабельное состояние.

Мартин Одерски


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

  • Однонаправленная привязка данных с использованием архитектуры Flux.
  • Иммутабельность состояния компонента. После того, как состояние компонента установлено, оно уже не может быть изменено. Изменения состояния не затрагивают визуализированные компоненты. Вместо этого подобные изменения приводят к выводу нового представления, обладающего новым состоянием.

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

Том Оччино, JSConfUS 2013


Библиотека React смогла серьёзно снизить остроту проблемы неконтролируемых мутаций благодаря использованию архитектуры Flux. Вместо того чтобы присоединять к произвольному количеству произвольных объектов (моделей) обработчики событий, вызывающие обновления DOM, библиотека React дала разработчикам единственный способ управления состоянием компонента. Это диспетчеризация действий, влияющих на хранилище данных. Когда меняется состояние хранилища, система предлагает компоненту перерендериться.


Архитектура Flux

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

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

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

JSX


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

  • Применение простой декларативной разметки.
  • Код разметки расположен там же, где и код компонента.
  • Реализация принципа разделения ответственностей (например отделение описания интерфейса от логики состояния и от побочных эффектов). Причём, реализация, основанная не на использовании различных технологий (например HTML, CSS, JavaScript).
  • Абстрагирование управления изменениями DOM.
  • Абстрагирование от особенностей различных платформ, для которых создают React-приложения. Дело в том, что благодаря использованию React можно создавать приложения, предназначенные для множества платформ (речь идёт, например, о разработке для мобильных устройств с использованием React Native, о приложениях для систем виртуальной реальности, о разработке для Netflix Gibbon, о создании Canvas/WebGL-интерфейсов, о проекте react-html-email).

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

В наши дни, если взглянуть на разные фронтенд-инструменты, окажется, что без специального синтаксиса, вроде директивы *ngFor из Angular, тоже не обойтись. Но, так как JSX можно назвать надмножеством JavaScript, создавая JSX-разметку можно пользоваться существующими возможностями JS.

Например, перебрать некий набор элементов можно, воспользовавшись методом Array.prototype.map. Можно использовать логические операторы, организовывать условный рендеринг с помощью тернарного оператора. Можно пользоваться чистыми функциями, можно конструировать строки с использованием шаблонных литералов. В общем-то, тому, кто описывает интерфейсы средствами JSX, доступны все возможности JavaScript. Полагаю, что в этом заключается огромное преимущество React перед другими фреймворками и библиотеками.

Вот пример JSX-кода:

const ItemList = ({ items }) => (<ul>{items.map((item) => (<li key={item.id}><div>{item.name}</div></li>))}</ul>);

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

  • Тут используется подход к именованию атрибутов элементов, отличающийся от того, который принят в HTML. Например, class превращается в className. Речь идёт о применении стиля именования camelCase.
  • У каждого элемента списка, который нужно вывести, должен быть постоянный уникальный идентификатор, предназначенный для использования в JSX-атрибуте key. Значение идентификатора должно оставаться неизменным в ходе различных манипуляций с элементами списка. На практике большинство элементов списков в моделях данных имеют уникальные id, эти идентификаторы обычно отлично показывают себя в роли значений для key.

React не навязывает разработчику единственно правильный способ работы с CSS. Например, компоненту можно передать JavaScript-объект со стилями, записав его в свойство style. При таком подходе большинство привычных имён стилей будет заменено на их эквиваленты, записанные по правилам camelCase. Но этим возможности по работе со стилями не ограничиваются. На практике я одновременно пользуюсь разными подходами к стилизации React-приложений. Выбор конкретного подхода зависит от того, что именно нужно стилизовать. Например, глобальные стили я применяю для оформления тем приложений и макетов страниц, а локальные стили для настройки внешнего вида конкретного компонента.

Вот мои любимые возможности React, касающиеся работы со стилями:

  • CSS-файлы, которые можно загружать в заголовочной части страницы. Они могут использоваться для настройки макетов страниц, шрифтов и прочих подобных элементов. Это надёжный, работоспособный механизм стилизации.
  • CSS-модули это CSS-файлы область применения которых ограничена локальной областью видимости. Их можно импортировать непосредственно в JavaScript-файлы. Для того чтобы применять CSS-модули, нужно воспользоваться правильно настроенным загрузчиком модулей. В Next.js, например, этот механизм активирован по умолчанию.
  • Пакет styled-jsx, который позволяет объявлять стили прямо в коде React-компонентов. Это напоминает использование тега <style> в HTML. Область видимости таких стилей можно назвать гиперлокальной. Речь идёт о том, что стили воздействуют только на элементы, к которым они применяются, и на их дочерние элементы. При применении Next.js пакетом styled-jsx можно пользоваться без необходимости самостоятельно что-то подключать и настраивать.

Синтетические события


React даёт в наше распоряжение кроссбраузерную обёртку SyntheticEvents, представляющую синтетические события и предназначенную для унификации работы с событиями DOM. Синтетические события весьма полезны по нескольким причинам:

  1. Они позволяет унифицировать особенности различных платформ, связанные с обработкой событий. Это упрощает разработку кроссбраузерных приложений.
  2. Они автоматически решают задачи по управлению памятью. Если вы, например, собираетесь создать некий список с бесконечной прокруткой, пользуясь лишь чистыми JavaScript и HTML, то вам придётся делегировать события или подключать и отключать обработчики событий по мере появления и скрытия элементов списка. Всё это нужно будет делать для того чтобы избежать утечек памяти. Синтетические события автоматически делегируются корневому узлу, что приводит к тому, что React-разработчикам не приходится решать задачи по управлению памятью.
  3. В их работе используются пулы объектов. Механизмы поддержки синтетических событий способны генерировать тысячи объектов в секунду и организовывать высокопроизводительную работу с такими объектами. Если решать подобные задачи, каждый раз создавая новые объекты, это приведёт к частой потребности в вызове сборщика мусора. А это, в свою очередь, может привести к замедлению программы, к видимым задержкам в работе пользовательского интерфейса и анимаций. Объекты синтетических событий создаются заранее и помещаются в пул объектов. Когда надобности в событии нет, оно возвращается обратно в пул. В результате разработчик может не беспокоиться о том, что сборщик мусора заблокирует главный поток JavaScript, очищая память от ставших ненужными объектов.

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

Жизненный цикл компонента


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

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

В React, начиная с версии 0.14, появился синтаксис описаний компонентов, основанных на классах, позволяющий обрабатывать события жизненного цикла компонентов. В жизненном цикле React-компонентов можно выделить три важнейших этапа: Mount (монтирование), Update (обновление) и Unmount (размонтирование).


Жизненный цикл компонента

Этап Update можно разделить на три части: Render (рендеринг), Precommit (подготовка к внесению изменений в дерево DOM), Commit (внесение изменений в дерево DOM).


Структура этапа Update

Остановимся на этих этапах жизненного цикла компонента подробнее:

  • Render на этом этапе жизненного цикла компонента производится его рендеринг. Метод компонента render() должен представлять собой детерминированную функцию, не имеющую побочных эффектов. Эту функцию стоит рассматривать как чистую функцию, получающую данные из входных параметров компонента и возвращающую JSX.
  • Precommit на этом этапе можно прочитать данные из DOM, пользуясь методом жизненного цикла компонента getSnapShotBeforeUpdate. Это может оказаться очень кстати, например, если перед повторным рендерингом компонента нужно узнать нечто вроде позиции скроллинга или размеров визуализированного элемента.
  • Commit на этой фазе жизненного цикла компонента React обновляет DOM и рефы. Здесь можно воспользоваться методом componentDidUpdate или хуком useEffect. Именно здесь можно выполнять эффекты, планировать обновления, использовать DOM и решать другие подобные задачи.

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


Жизненный цикл React-компонентов

Я полагаю, что представление компонентов в виде долгоживущих классов это не самая лучшая ментальная модель React. Помните о том, что состояние React-компонентов не должно мутировать. Устаревшее состояние должно заменяться на новое. Каждая такая замена вызывает повторный рендеринг компонента. Это даёт React его, пожалуй, самую главную и самую ценную возможность: поддержку детерминированного подхода к созданию визуальных представлений компонентов.

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

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

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

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

Хуки React


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

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

Хук useEffect позволяет ставить побочные эффекты в очередь для их последующего выполнения. Они будут вызываться в подходящее время жизненного цикла компонента. Это время может настать сразу после монтирования компонента (например при вызове метода жизненного цикла componentDidMount), во время фазы Commit (метод componentDidUpdate), непосредственно перед размонтированием компонента (componentWillUnmount).

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

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

Вот что дают нам хуки React:

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

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

Компоненты-контейнеры и презентационные компоненты


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

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

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

Презентационные компоненты


Рассмотрим особенности презентационных компонентов:

  • Они не взаимодействуют с сетевыми ресурсами.
  • Они не сохраняют данные в localStorage и не загружают их оттуда.
  • Они не выдают неких непредсказуемых данных.
  • Они не обращаются напрямую к текущему системному времени (например, путём вызова метода Date.now()).
  • Они не взаимодействуют напрямую с хранилищем состояния приложения.
  • Они могут использовать локальное состояние компонента для хранения чего-то наподобие данных, введённых в формы, но при этом они должны поддерживать возможность приёма таких данных и задания на их основе своего исходного состояния, что облегчает их тестирование.

Именно из-за последнего пункта этого списка я, говоря о презентационных компонентах, упомянул о том, что это, по большей части, чистые компоненты. Эти компоненты считывают своё состояние из глобального состояния React. Поэтому хуки вроде useState и useReducer дают в их распоряжение неявным образом определённые данные (то есть данные, не описанные в сигнатуре функции), что, с технической точки зрения, не позволяет назвать такие компоненты чистыми. Если нужно, чтобы они были бы по-настоящему чистыми, можно делегировать все задачи по управлению состоянием компоненту-контейнеру, но я полагаю, что делать этого не стоит, по крайней мере, до тех пор, пока правильность работы компонента можно проверить с помощью модульных тестов.

Лучшее враг хорошего.

Вольтер


Компоненты-контейнеры


Компоненты-контейнеры это такие компоненты, которые отвечают за управление состоянием, за выполнение операций ввода-вывода и за решение любых других задач, которые можно отнести к побочным эффектам. Они не должны самостоятельно рендерить некую разметку. Вместо этого они делегируют задачу рендеринга презентационным компонентам, а сами служат обёрткой для таких компонентов. Обычно компонент-контейнер в React+Redux-приложении просто вызывает mapStateToProps() и mapDispatchToProps(), после чего передаёт соответствующие данные презентационным компонентам. Контейнеры, кроме того, могут использоваться для решения некоторых задач общего характера, о которых мы поговорим ниже.

Компоненты высшего порядка


Компонент высшего порядка (Higher Order Component, HOC) это компонент, который принимает другие компоненты и возвращает новый компонент, реализующий новый функционал, основанный на исходных компонентах.

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

В отличие от хуков React и от механизма render props, компоненты высшего порядка поддаются композиции с использованием стандартного подхода к композиции функций. Это позволяет декларативно описывать результаты композиции возможностей, предназначенных для использования в разных местах приложения. При этом готовые компоненты не должны знать о существовании тех или иных возможностей. Вот пример HOC с EricElliottJS.com:

import { compose } from 'lodash/fp';import withFeatures from './with-features';import withEnv from './with-env';import withLoader from './with-loader';import withCoupon from './with-coupon';import withLayout from './with-layout';import withAuth from './with-auth';import { withRouter } from 'next/router';import withMagicLink from '../features/ethereum-authentication/with-magic-link';export default compose(withEnv,withAuth,withLoader,withLayout({ showFooter: true }),withFeatures,withRouter,withCoupon,withMagicLink,);

Тут показана смесь множества возможностей, совместно используемых всеми страницами сайта. А именно, withEnv читает настройки из переменных окружения, withAuth реализует механизм GitHub-аутентификации, withLoader показывает анимацию во время загрузки данных пользователя, withLayout({ showFooter: true }) выводит стандартный макет с подвалом, withFeature показывает настройки, withRouter загружает маршрутизатор, withCoupon отвечает за работу с купонами, а withMagicLing поддерживает аутентификацию пользователей без пароля с использованием Magic.

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

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

import LessonPage from '../features/lesson-pages/lesson-page.js';import pageHOC from '../hocs/page-hoc.js';export default pageHOC(LessonPage);

У подобных компонентов высшего порядка есть альтернатива, но она представляет собой сомнительную конструкцию, называемую pyramid of doom (пирамида погибели) и ей лучше не пользоваться. Вот как это выглядит:

import FeatureProvider from '../providers/feature-provider';import EnvProvider from '../providers/env-provider';import LoaderProvider from '../providers/loader-provider';import CouponProvider from '../providers/coupon-provider';import LayoutProvider from '../providers/layout-provider';import AuthProvider from '../providers/auth-provider';import RouterProvider from '../providers/RouterProvider';import MagicLinkProvider from '../providers/magic-link-provider';import PageComponent from './page-container';const WrappedComponent = (...props) => (<EnvProvider { ...props }><AuthProvider><LoaderProvider><LayoutProvider showFooter={ true }><FeatureProvider><RouterProvider><CouponProvider><MagicLinkProvider><YourPageComponent /></MagicLinkProvider></CouponProvider></RouterProvider></FeatureProvider></LayoutProvider></LoaderProvider></AuthProvider></EnvProvider>);

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

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

Итоги


  • Почему React? React даёт нам детерминированный рендеринг визуальных представлений компонентов, в основе которого лежит однонаправленная привязка данных и иммутабельное состояние компонентов.
  • JSX даёт нам возможность простого декларативного описания интерфейсов в JavaScript-коде.
  • Синтетические события сглаживают кросс-платформенные различия систем обработки событий и облегчают управление памятью.
  • Концепция жизненного цикла компонентов направлена на защиту состояния компонентов. Жизненный цикл компонента состоит из фаз монтирования, обновления и размонтирования. Фаза обновления состоит из фазы рендеринга, фазы подготовки к внесению изменений в DOM и фазы внесения изменений в DOM.
  • Хуки React позволяют подключаться к методам жизненного цикла компонентов без использования синтаксиса, основанного на классах. Применение хуков, кроме того, облегчает совместное использование одного и того же кода в разных компонентах.
  • Компоненты-контейнеры и презентационные компоненты позволяют отделить задачи формирования визуального представления интерфейсов от задач по управлению состоянием приложения и от побочных эффектов. Это улучшает возможности по многократному использованию и тестированию компонентов и бизнес-логики приложения.
  • Компоненты высшего порядка упрощают совместное использование возможностей, представляющих собой композицию других возможностей. При этом компонентам не нужно знать об этих возможностях (и не нужно, чтобы компоненты были бы тесно связаны с ними).

Что дальше?


В этом материале о React мы затронули множество концепций функционального программирования. Если вы стремитесь к глубокому пониманию принципов разработки React-приложений, вам полезно будет освежить свои знания о чистых функциях, об иммутабельности, о каррировании и частичном применении функций, о композиции функций. Соответствующие материалы вы можете найти на EricElliottJS.com.

Я рекомендую использовать React совместно с Redux, Redux-Saga и RITEway. Redux рекомендуется использовать совместно с Autodux и Immer. Для организации сложных схем работы с состоянием можно попробовать воспользоваться Redux-DSM.

Когда вы разберётесь с основами и будете готовы к созданию реальных React-приложений, обратите внимание на Next.js и Vercel. Эти инструменты помогут автоматизировать настройку системы сборки проекта и CI/CD-конвейера, с их помощью можно подготовить проект к оптимизированному развёртыванию на сервере. Они дают тот же эффект, что и целая команда DevOps-специалистов, но пользоваться ими можно совершенно бесплатно.

Какие вспомогательные инструменты вы применяете при разработке React-приложений?



Подробнее..

Перевод Выработка уникальных идей для Data Science-проектов за 5 шагов

22.09.2020 16:11:47 | Автор: admin
Вероятно, самое сложное в любом Data Science-проекте это придумать оригинальную, но реализуемую идею. Специалист, который ищет такую идею, легко может попасться в ловушку наборов данных. Он тратит многие часы, просматривая существующие наборы данных и пытаясь выйти на новые интересные идеи. Но у такого подхода есть одна проблема. Дело в том, что тот, кто смотрит лишь на существующие наборы данных (c Kaggle, Google Datasets, FiveThirtyEight), ограничивает свою креативность, видя лишь небольшой набор задач, на которые ориентированы изучаемые им наборы данных.

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



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

1. Почему я хочу начать работу над новым проектом?


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

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

2. К каким сферам относятся мои интересы и мой опыт?


Подумать над этим вопросом стоит по трём основным причинам.

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

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

3. Как найти вдохновение?


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

  • Новости, авторские статьи, публикации в блогах. Чтение о неких событиях или явлениях, которые наблюдали авторы публикаций, это отличный способ выработки идей. Например, портал WIRED опубликовал эту статью, посвящённую тому, что функция автодополнения ввода при поиске в Google демонстрирует политическую предвзятость. Вдохновившись этой идеей, можно исследовать систематические ошибки в языковых моделях. Или можно задаться вопросом о возможности предсказания географического положения человека на основе поисковых запросов, вводимых им в Google.
  • Научная литература. Научные публикации часто включают в себя рассказы о нерешённых вопросах, имеющих отношение к исследуемой теме. Например, в этой публикации рассказывается о языковой модели GPT-2 и упоминается о том, что эта модель, без её тонкой настройки, показывает себя на определённых задачах, вроде ответов на вопросы, не лучше, чем попытка решить эти задачи методом случайного угадывания. Почему бы не написать что-нибудь о нюансах тонкой настройки этой модели?
  • Материалы из сферы науки о данных. Чтение материалов, представляющих темы, связанные с Data Science, и содержащие обзоры соответствующих проектов, способно привести к новым идеям. Например, когда я прочитала об NLP-исследовании сериала Офис, я тут же пожалела о том, что мне эта идея не пришла раньше, чем автору материала. Но почему бы не исследовать какой-нибудь другой сериал? А может, изучить несколько фильмов и попытаться определить языковые паттерны? А для написания текстов к любимому сериалу можно попробовать воспользоваться моделью GPT-2.

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

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

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

4. Где найти подходящие данные?


После того, как вы определились с общим направлением исследования, вам нужно будет заняться поиском данных, которые позволят вам понять то, как реализовать вашу идею в виде Data Science-проекта. Это крайне важно в определении того, удастся ли реализовать идею. Отвечая на вопрос, вынесенный в заголовок этого раздела, стоит учитывать возможность наличия того, что вам нужно, в существующих хранилищах данных. Возможно, нужные данные вам придётся собирать самостоятельно, что усложняет задачу. Итак, вот обзор источников данных:

  • Существующие хранилища данных: Kaggle, Google Datasets, FiveThirtyEight, BuzzFeed, AWS, UCI Machine Learning Repository, data.world, Data.gov и многие другие, которые можно найти с помощью Google.
  • Источники данных, используемые другими дата-сайентистами. Поищите сведения по интересующей вас теме в Google и в Google Scholar. Выясните, пытался ли уже кто-нибудь найти ответ на вопрос, похожий на ваш. Какие данные использовались в похожих исследованиях? Например, ресурс Our World in Data представляет академические и неакадемические источники данных, о которых вы можете не знать.
  • Данные, которые нужно собирать самостоятельно. Для сбора таких данных можно прибегнуть к веб-скрапингу, к анализу текстов, к различным API, к отслеживанию событий, к работе с лог-файлами.

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

5. Реализуема ли найденная идея?


Итак, у вас есть фантастическая идея! Но можно ли её реализовать? Снова пройдитесь по этапам процесса генерирования идей. Подумайте о том, чего вы хотите достичь (вопрос 1), интересна ли вам выбранная область, если ли у вас опыт работы в ней (вопрос 2), есть ли у вас данные, необходимые для реализации идеи (вопрос 4). Теперь вам нужно определить следующее: имеются ли у вас навыки, необходимые для реализации идеи и для достижения цели.

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

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

Итоги


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

Я, пользуясь описанной здесь методикой, постоянно нахожу оригинальные идеи для своих Data Science-проектов. Надеюсь, эта методика пригодится и вам.

Как вы ищите новые идеи для своих Data Science-проектов?



Подробнее..

Перевод Первое знакомство с Moon.js

24.09.2020 16:22:36 | Автор: admin
Сегодня речь пойдёт об очередной JavaScript-библиотеке, предназначенной для разработки интерфейсов. Возникает такое ощущение, что такие библиотеки появляются всё чаще и чаще. В этом материале мы рассмотрим библиотеку Moon.js и раскроем её особенности, о которых нужно знать для того чтобы приступить к работе с ней. В частности, мы поговорим о том, как создавать новые Moon.js-проекты, о том, как создавать элементы интерфейсов, как обрабатывать события. Освоив это руководство, вы сможете пользоваться Moon.js для разработки собственных приложений.



Библиотека Moon.js


Moon.js это минималистичная JavaScript-библиотека, предназначенная для разработки быстрых и функциональных интерфейсов. Она имеет сравнительно небольшие размеры, что позволяет создавать на её основе достаточно компактные приложения. Библиотека отличается очень высокой производительностью

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

Сильные стороны Moon.js


  • Moon.js отличается компактными размерами (в минифицированном и сжатом виде это около 2 Кб). Это меньше, чем размеры других библиотек и фреймворков вроде React и Angular.
  • Эта библиотека отличается высокой скоростью рендеринга интерфейсов.
  • Moon.js это библиотека, основанная на функциональных методах разработки. При работе с ней используется подход к проектированию интерфейсов, основанный на так называемых драйверах.

Начало работы


Библиотеку Moon.js можно включить в проект двумя способами. Первый заключается в установке её из NPM. Второй в её подключении непосредственно к странице, на которой её планируется использовать.

Если решено воспользоваться NPM-вариантом библиотеки, то сначала нужно будет установить пакет moon-cli, инструмент командной строки:

$ npm i moon-cli -g

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

Для создания проекта, основанного на Moon.js, можно выполнить следующую команду:

$ moon create moon-prj

Эта команда создаёт новый проект в папке moon-prj. После того, как будет завершено создание проекта, в вашем распоряжении окажется основа будущего приложения.

Второй вариант использования Moon.js предусматривает её подключение к странице, на которой её планируется использовать. У библиотеки есть модуль moon-browser, который позволяет пользоваться её возможностями непосредственно на странице, к которой она подключена.

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

<script src="http://personeltest.ru/aways/unpkg.com/moon"></script><script src="http://personeltest.ru/aways/unpkg.com/moon-browser"></script>

Как видите, соответствующие скрипты загружаются с CDN unpkg. В первом теге импортируется основная библиотека. Во втором библиотека moon-browser. Она отвечает за компиляцию шаблонов Moon.js, за приведение их к виду, пригодному для вывода браузером.

Теперь, для того чтобы воспользоваться синтаксическими конструкциями Moon.js на странице, нужно будет включить их в тег <script>, не забыв задать его атрибут type как text/moon.

<!-- Подключение к странице внешнего скрипта --><script src="./main-script.js" type="text/moon"></script><!-- Описание интерфейса в коде, встроенном в страницу --><script type="text/moon">...</script>

Подключение Moon.js-приложения к странице


Moon.js, как и другие библиотеки и фреймворки, используемые для создания одностраничных приложений, подключается к определённому элементу страницы. Обычно роль контейнера для Moon.js-приложения играет элемент <div>:

<div id="root"></div>

Подобный элемент, являющийся корневым элементом Moon.js-приложения, размещают в коде файла index.html, представляющего собой точку входа в проект.

Для подключения Moon.js-приложения к этому элементу используется драйвер view (ниже мы поговорим о драйверах подробнее):

Moon.use({view: Moon.view.driver("#root")})

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

Moon.use({view: Moon.view.driver(document.getElementById("root"))})

Теперь поговорим о том, как в Moon.js организована работа с данными, и о том, как с помощью этой библиотеки создавать элементы интерфейсов.

Синтаксис описания элементов интерфейса


Для описания Moon.js-интерфейсов используется язык программирования Moon View Language (MVL), который был разработан специально для решения данной задачи. Он напоминает JSX. Этот язык применяется для описания элементов и для настройки их взаимоотношений. Вот пример:

<script type="text/moon">function aView(data) {return (<div>Hi from Moon</div>)}</script>

Несложно заметить то, что в этом фрагменте Moon.js-кода, ответственного за формирование элемента <div>, используются синтаксические структуры, напоминающие HTML. Но эти структуры используются в JavaScript-коде. Такой JavaScript-код браузер выполнить не сможет, но это от него и не требуется, так как Moon.js компилирует подобные конструкции в обычный JavaScript.

Работа с данными


В Moon.js для управления визуальными представлениями элементов и для работы с данными используется концепция драйверов. Здесь мы взглянем на драйвер, позволяющий работать с данными, а в следующем разделе поговорим о драйвере, предназначенном для работы с элементами интерфейса.

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

Задать начальные данные Moon.js-приложения можно с помощью API Moon.use:

Moon.use({data: Moon.data.driver})

Записывать новые данные в состояния можно, возвращая их из соответствующих функций:

Moon.run(({ data }) => {console.log(data) // undefinedreturn {data: "Nnamdi"}})

API Moon.run отвечает за запуск приложения. Коллбэк, переданный этому API, получает ссылку на глобальные данные в аргументе data. Так как на момент вызова этой функции в data пока ничего нет, команда console.log из этого примера выведет undefined.

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

Механизм работы с данными в Moon.js мы рассмотрели. Теперь подробнее поговорим о работе с элементами интерфейса.

Работа с элементами интерфейса


В Moon.js имеется драйвер view, который предназначен для создания элементов и для монтирования их в DOM.

Мы уже рассматривали фрагмент кода, повторённый ниже, в котором к элементу <div> подключается базовый элемент Moon.js:

Moon.use({view: Moon.view.driver("#root")})

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

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

function handleClick() {return {};}Moon.run(() => ({view: <button @click=handleClick>Click Me!</button>}));

Здесь коллбэк, передаваемый Moon.run, выводит в DOM кнопку. Происходит это из-за того, что функция возвращает объект со свойством view. Значение, назначенное этому свойству, попадает в DOM.

У кнопки имеется обработчик события click, представленный функцией handleClick. Эта функция возвращает пустой объект, её вызов не приводит к внесению изменений в DOM.

Создание элементов


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

const { div, text, node, p } = Moon.view.m

Moon.js экспортирует функции, имена которых соответствуют именам создаваемых с их помощью элементов. Так, функция div позволяет создавать элементы <div>. Функция text создаёт текстовые узлы. Функция node позволяет создавать пользовательские элементы. Функция p создаёт элементы <p>. Как видите, имена этих функций ясно указывают на их предназначение.

Создадим элемент <div>:

const Div = div({});

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

const Div = div({class: "DivClass"});

Здесь мы описали элемент <div>, в атрибут class которого должно быть записано значение DivClass.

Вот как создать текстовый элемент:

const Text = text({ data: "A text node" });

В свойстве data объекта, переданного функции text, имеется текст для элемента.

Создадим пользовательский элемент:

const CustomEl = node("custom-el");

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

CustomEl({ "attr": "attr-value"})

События


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

function handleClick() {return {};}Moon.run(() => ({view: <button @click=handleClick>Click Me!</button>}));

В результате на страницу будет выведена кнопка с текстом Click Me, по нажатию на которую будет вызвана функция handleClick.

Компоненты


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

Предположим, у нас есть такая функция:

function aView({ data }) {return <div>A View</div>}

Эта функция, aView, возвращает элемент, который может быть отрендерен:

Moon.run(() => {view: <div><aView /></div>})

Имя функции в этом примере используется в роли имени элемента. В результате выполнения этого кода окажется, что то, что возвращает функция, будет помещено в тег <div>. Когда всё это попадёт в DOM, там окажется такая разметка:

<div><div>A View</div></div>

Разработка приложений, основанных на Moon.js


Для того чтобы собрать воедино всё то, о чём мы только что говорили, давайте создадим на Moon.js простое TODO-приложение. Здесь мы воспользуемся соответствующим примером, который подготовлен разработчиками Moon.js.

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

Вот как выглядит страница этого приложения.


Страница приложения

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

Начнём работу с создания файла index.html. Здесь мы подключим Moon.js непосредственно к странице:

<html><body><div id="root"></div></body><script src="http://personeltest.ru/aways/unpkg.com/moon"></script><script src="http://personeltest.ru/aways/unpkg.com/moon-browser"></script><!-- Воспользуемся скриптом, встроенным в страницу --><script type="text/moon">function viewTodos({data, view}) {return (<div><input type="text" value=data.todo @input=updateTodo/><button @click=createTodo>Create</button><ul children=(data.todos.map(todo =><li>{todo}</li>))/></div>)}function updateTodo({ data, view }) {const dataNew = { ...data, todo: view.target.value };return {data: dataNew,view: <viewTodos data=dataNew/>}}function createTodo({ data }) {const dataNew = {todo: "",todos: [...data.todos, data.todo]};return {data: dataNew,view: <viewTodos data=dataNew/>}}<!-- Настройка драйверов data и view -->Moon.use({data: Moon.data.driver,view: Moon.view.driver("#root")})<!-- Запуск приложения -->Moon.run(() => {data: [],view: <viewTodos data=[]>})</script></html>

Функция viewTodos выводит элементы, необходимые для ввода сведений о новых делах и для вывода их в виде списка. Её аргументами являются data и view.

Функция createTodo создаёт новое дело и возвращает его в свойстве data возвращаемого ей объекта.

Функция updateTodo записывает новое дело в состояние приложения.

Обратите внимание на обработчики событий @click и @input, которые имеются в функции viewTodos. Событие @input вызывается при вводе текста, описывающего дело, в соответствующее поле. При обработке этого события вызывается функция updateTodo. Аргумент view в этой функции представляет произошедшее событие. Пользуясь им, мы обращаемся к DOM и получаем данные, введённые в поле. Затем эти данные попадают в состояние в виде свойства todo.

Событие @click вызывается после нажатия на кнопку. Оно выполняет запись нового дела в список дел. Для решения этой задачи используется функция createTodo. Эта функция обращается к свойству состояния todo и записывает новые данные в свойство todos, после чего, в свойстве view возвращаемого ей объекта, возвращает элемент <viewTodos>, представленный соответствующей функцией, в атрибут data которого записано значение dataNew.

Это приведёт к выполнению повторного рендеринга viewTodos и к обновлению DOM. В список дел, выводимый на странице, будет добавлено новое дело.

Запустите это приложение в браузере и поэкспериментируйте с ним.

Итоги


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

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

Пользовались ли вы Moon.js?



Подробнее..

Перевод Горячая четвёрка умирающих языков программирования

25.09.2020 16:06:58 | Автор: admin
Я занимался поиском лучших языков программирования 2020 года и наткнулся на страницы, на которых шла речь о языках, теряющих популярность. Я программист, и я понимаю, что любому программисту крайне важно знать о том, какие технологии являются актуальными, а какие нет.

Каждый программист это писатель.

Серкан Лейлек


Я, после того, как насмотрелся на отчёты о языках программирования, теряющих актуальность, выбрал 4 языка, которые, как я полагаю, уже не стоят того, чтобы их изучали. Я, ради подкрепления своих выводов, прибегну к некоторым показателям популярности языков. В частности, речь идёт об индексе PYPL (PopularitY of Programming Language Index, индекс популярности языков программирования), о данных Google Trends и о некоторых сведениях, которые можно найти на платформе YouTube.


Фрагмент рейтинга PYPL (источник)

Платформа YouTube использовалась мной в качестве источника данных о перспективности языков программирования через оценку популярности видеоуроков по соответствующим языкам.

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

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

1. Perl


Интерес к языку программирования Perl стремительно падает. Хорошие показатели он демонстрировал в период с 2004 по 2009 годы, а после этого начался спад. Хотя этот язык пока и не мёртв, но он уже и не очень-то жив.

Информацию по нему не особенно активно ищут на YouTube и в Google. Например, есть видео по Perl, загруженное 4 года назад и набравшее всего 240 тысяч просмотров.


Видео по Perl

Кроме того, показатели языка идут вниз и в рейтинге PYPL.

Я решил сравнить Perl с каким-нибудь другим языком, с Python в данном случае, и обратился к Google Trends.


Сравнение Perl (красная линия) и Python (синяя линия), последние 12 месяцев

Как видно, красная линия, представляющая Perl, находится где-то на уровне нуля.

2. Haskell


Язык Haskell выглядит лучше, чем Perl. Он, к тому же, используется во многих крупных компаниях вроде Facebook и IBM. На YouTube есть видео по Haskell, загруженное 5 лет назад. Оно набрало 585 тысяч просмотров.


Видео по Haskell

Посмотрим теперь на показатели Google Trends, сравним Haskell и Python.


Сравнение Haskell (синяя линия) и Python (красная линия), последние 5 лет

Haskell, в сравнении с Python, выглядит более чем скромно. Синяя линия, представляющая Haskell, стелется по земле, а Python, представленный красной линией, показывает уверенный восходящий тренд.

3. Objective-C


Язык Objective-C, если ориентироваться на рейтинг PYPL, вырос в популярности на 0,2%. А что будет, если взглянуть на данные с YouTube?


Видео по Objective-C

Видео, загруженное 5 лет назад, набрало 250 тысяч просмотров.

Обратимся теперь к показателям Google Trends.


Сравнение Objective-C (синяя линия) и Python (красная линия), последние 5 лет

Конечно, многие всё ещё пользуются Objective-C. Но, хотя по этому языку есть вакансии, если вы строите планы на будущее и посматриваете на Objective-C, то вам стоит переключить внимание на Swift.

4. Visual Basic for Applications


Visual Basic for Applications, VBA, был у всех на слуху в 2004 году, а вот после 2009 интерес к нему начал падать. Я, например, изучал этот язык в школе.

Рейтинг PYPL указывает на то, что популярность VBA упала на 0,2%.

В моей ленте на YouTube видео по VBA мне видеть не доводилось. Возможно, это говорит о падении интереса к данному языку. Правда, когда я поискал подобные видео, мне попалось одно, загруженное 9 месяцев назад, набравшее 810 тысяч просмотров.


Видео по VBA

Если посмотреть на данные по VBA, которые имеются на Google Trends, то окажется, что интерес к VBA с 2004 года стабильно падает.


Сравнение VBA (красная линия) и Python (синяя линия), c 2004 года по настоящее время

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

Python


Я занимаюсь серверной разработкой, используя Python. Я, кроме того, сделал несколько проектов, используя фреймворк Django. Что тут сказать мне нравится Python.

Это, если верить тому, что выдаёт Google, язык, который лучше других языков помогает в поиске работы в 2020 году.


Языки, знание которых помогает в поиске работы

Я, например, создал проект на Django. А именно, речь идёт о сайте с вопросами и ответами для разработчиков. Этот проект всё ещё в работе. Я расширяю его и занимаюсь его оптимизацией.

Python в рейтинге PYPL демонстрирует рост на 2,9%. Если поинтересоваться данными YouTube по просмотрам видео о Python, то окажется, что они, за короткие промежутки времени, набирают миллионы просмотров.


Видео по Python

Анализ исследования Stack Overflow


Выше я опирался на рейтинг PYPL, на данные с Google Trends и на анализ видео по интересующим меня языкам программирования на YouTube. Теперь же я обращусь к результатам опроса разработчиков, проведённого Stack Overflow в 2020 году. А именно, к данным по языкам программирования, на которых программисты пишут, но не хотят продолжать этим заниматься.


Данные опроса Stack Overflow (источник)

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


Зарплаты разработчиков и их связь с языками программирования (источник)

Итоги


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

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

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

Какими языками программирования вы дополнили бы список умирающих технологий из этой статьи?



Подробнее..

Код ваш, призы наши принимаем заявки на онлайн-хакатон ВТБ More.Tech

25.09.2020 18:15:34 | Автор: admin
Привет! Мы начали приём заявок на ВТБ More.Tech онлайн-хакатон для молодых амбициозных айтишников. От вас профессиональные навыки, желание участвовать в web- или mobile-треках соревнования и умение работать в команде. От нас призовой фонд 900 тыс. рублей и возможность начать карьеру в системообразующем российском банке.

image

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



Первый трек хакатона для специалистов в web-разработке, второй для разработчиков под iOS/Android. ВТБ More.Tech командное состязание, поэтому лучше заранее собрать под свои знамёна коллег-единомышленников. Впрочем, мы без проблем принимаем заявки от отдельных участников, из которых в дальнейшем сформируются команды.

Задача web-трека создание антифрод-системы для web-приложений банков. Оптимальный, на наш взгляд, состав команды для защиты от мошенников включает frontend- и backend-разработчиков, DevOps-инженера, системного аналитика и product/project-менеджера.

Участникам mobile-трека предстоит разработка приложения, которое сможет распознать модель и марку автомобиля, подобрать актуальное предложение для его продажи и сформировать кредитную заявку. Помимо мобильного и backend-разработчиков mobile-команде явно не помешают дизайнер, а также специалист по компьютерному зрению. И product/project-менеджер, куда же без него.

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

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

Проанализировав опыт крупнейших хакатонов, в том числе знаменитый Tech Fest Munich, мы решили выстроить работу над конкурсными проектами по принципу Dive-Create-Impact: 15 % времени на изучение условий задачи и мозговой штурм, 60 % непосредственно на реализацию, 25 % на доработку и создание презентации. Мы считаем, что такой тайминг способствует принятию наиболее эффективных решений. К тому же участники смогут освоить этот подход и использовать его в своей дальнейшей работе.

Несмотря на режим удалёнки, все четыре дня хакатона насыщены активностями, при этом деятельность каждой команды будут курировать наши менторы. В программе серия митапов с экспертами ВТБ (методология DevOps, гибкие технологии/Agile и другие темы) и мастер-класс по подготовке презентаций. Ознакомиться с расписанием, а также почитать о задачах и условиях участия подробнее можно на официальном сайте хакатона. Там же вы найдёте форму для подачи заявки. Решайтесь скорее: последний день приёма заявок 4 октября.
Подробнее..

Перевод NodeJS 12 пакетов для продуктивности разработчика

15.09.2020 14:04:30 | Автор: admin


Менеджер процессов для продакшна с балансировщиком нагрузки. Обёртки над отладкой и хуками Git, защита express-приложений через HTTP-заголовки, утилита в более чем 180 функциями для работы с датами и другие инструменты, которые сэкономят ваше время. Подборка особенно полезна начинающим разработчикам NodeJS, но может порадовать опытных скептиков.

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

1. Husky


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


Исходники husky

Установка


yarn add husky

Применение


Пример хуков с husky:

// package.json{  "husky": {    "hooks": {      "pre-commit": "npm lint",      "pre-push": "npm test"    }  }}

pre-commit запускается перед коммитом.
pre-push перед отправкой в репозиторий.



2. Dotenv


Dotenv модуль без зависимостей. Он загружает переменные среды из файла .env в process.env. Хранение конфигурации в среде отдельно от кода основано на методологии приложения двенадцати факторов. Исходники dotenv.

Установка


yarn add dotenv

Применение


Как можно раньше в вашем приложении пропишите require и установите значения dotenv:

require('dotenv').config()

Создайте .env файл в корневом каталоге вашего проекта. Добавьте переменные среды в новые строки в виде NAME=VALUE. Например:

DB_HOST=localhostDB_USER=rootDB_PASS=s1mpl3

Теперь process.env содержит ключи и значения из файла .env:

const db = require('db')db.connect({ host: process.env.DB_HOST, username: process.env.DB_USER, password: process.env.DB_PASS})



3. date-fns


Date-fns похож на lodash, но создан для работы с датами. Предоставляет полный, но простой и последовательный набор инструментов манипуляций с датами JavaScript в браузере и Node.JS.


Исходники date-fns

Установка


yarn add date-fns

Применение


Пример с date-fns:

import { compareAsc, format } from 'date-fns'format(new Date(2014, 1, 11), 'yyyy-MM-dd')  //=> '2014-02-11'const dates = [    new Date(1995, 6, 2),    new Date(1987, 1, 11),    new Date(1989, 6, 10),  ]  dates.sort(compareAsc)  //=> [  //   Wed Feb 11 1987 00:00:00,  //   Mon Jul 10 1989 00:00:00,  //   Sun Jul 02 1995 00:00:00  // ]

Документация с примерами и вариантами использования.



4. Bunyan


Bunyan это простая в использовании и производительная библиотека логирования JSON для Node.


Исходники bunyan

Установка


yarn add bunyan

Обратите внимание: CLI bunyan написан так, чтобы быть совместимым (в пределах разумного) со всеми версиями логов Bunyan. Поэтому вы можете установить его глобально: yarn add global bunyan, чтобы получить этот инструмент в PATH, а затем использовать локальные установки Bunyan для приложений.

Применение


Bunyan это простая и быстрая библиотека ведения журнала JSON для сервисов Node.js.

// hi.jsconst bunyan = require('bunyan');const log = bunyan.createLogger({name: "myapp"});log.info("hi");

Вот что возвращается на консоль, если вы запускаете node hi.js.





5. Ramda


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


Исходники ramda

Установка


yarn add ramda

Применение


import * as R from 'ramda'const greet = R.replace('{name}', R.__, 'Hello, {name}!'); greet('Alice'); //=> 'Hello, Alice!'

Примеры кода



6. Debug


Debug это крошечная утилита отладки JavaScript, смоделированная по образцу техники отладки Node.JS.


Исходники Debug

Установка


yarn add debug

Применение


Debug предоставляет функцию. Просто передайте этой функции имя вашего модуля, и она вернёт декорированную версию console.error для передачи отладочных операторов.

const debug = require('debug');const log = debug('http:server');const http = require('http');const name = 'My App name';log('booting %o', name);http.createServer((req, res) => {  log(req.method + ' ' + req.url);  res.end('debug examplen');}).listen(3200, () => {  log('listening');});// выполните в терминале// DEBUG=http:server node app.js

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




7. Flat


Flat принимает объект и делает его плоским. Можно также свернуть объект, разделённый ключами. [Прим. перев. разделиелем может быть не только точка].


Исходники Flat

Установка


yarn add flat

Применение


const flatten = require('flat')flatten({      key1: {          keyA: 'valueI'      },      key2: {          keyB: 'valueII'      },      key3: { a: { b: { c: 2 } } }  })// {  //   'key1.keyA': 'valueI',  //   'key2.keyB': 'valueII',  //   'key3.a.b.c': 2  // }




8. JSON5


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


Исходники JSON5

Установка


yarn add json5  const JSON5 = require('json5')

Применение


Обратите внимание на расширение файла. JSON5 это надмножество, расширение JSON.

{  // комментарии  unquoted: 'and you can quote me on that',  singleQuotes: 'I can use "double quotes" here',  lineBreaks: "Look, Mom! \No \\n's!",  hexadecimal: 0xdecaf,  leadingDecimalPoint: .8675309, andTrailing: 8675309.,  positiveSign: +1,  trailingComma: 'in objects', andIn: ['arrays',],  "backwardsCompatible": "with JSON",}



9. ESLint


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


Исходники ESLint

Установка и применение


yarn add eslint

Затем настройте конфигурационный файл:

./node_modules/.bin/eslint --init

После этого можно запускать ESLint в любом файле или каталоге, например:

./node_modules/.bin/eslint yourfile.js

Документация со множеством примеров по началу работы и настройке.



10. PM2


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


Исходники pm2

Установка


yarn add global pm2

Запуск приложения


Вы можете запустить любое приложение (Node.js, Python, Ruby, бинарные файлы в $PATH и так далее) вот так:

pm2 start app.js

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

А вот как вы можете вывести список всех запущенных приложений:

pm2 ls



Ознакомьтесь с официальной документацией, чтобы узнать полный список функций и возможностей.



11. Helmet


Helmet помогает защитить приложения express через HTTP-заголовки. Это не серебряная пуля, но она может помочь.


Исходники Helmet

Установка


yarn add helmet

Применение


Helmet написан в стиле Connect и совместим с фреймворками, похожими на Express. Если нужна поддержка Koa, смотрите koa-helmet.)

const express = require("express");  const helmet = require("helmet");const app = express();app.use(helmet());

Функция helmet это оболочка вокруг 11 меньших промежуточных программ. Другими словами эквивалентно

// Это...app.use(helmet());// ...И это: app.use(helmet.contentSecurityPolicy());  app.use(helmet.dnsPrefetchControl());  app.use(helmet.expectCt());  app.use(helmet.frameguard());  app.use(helmet.hidePoweredBy());  app.use(helmet.hsts());  app.use(helmet.ieNoOpen());  app.use(helmet.noSniff());  app.use(helmet.permittedCrossDomainPolicies());  app.use(helmet.referrerPolicy());  app.use(helmet.xssFilter());



12. Compression


Compression инструмент для сжатия данных.


Исходники compression

Установка


yarn add compression

Применение


При использовании этого модуля вместе с express или connect просто вызовите compression() в промежуточном ПО. Запросы, проходящие через промежуточное ПО, будут сжаты.

const compression = require('compression')  const express = require('express')const app = express()// сжимать все запросы  app.use(compression())// ...

А какие инструменты в работе с NodeJS используете вы?

image

Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя онлайн-курсы SkillFactory:



Подробнее..

Web Cryptography API пример использования

16.09.2020 14:04:44 | Автор: admin


Доброго времени суток, друзья!

В этом туториале мы рассмотрим Web Cryptography API: интерфейс шифрования данных на стороне клиента.

Данный туториал основан на этой статье.

Предполагается, что вы немного знакомы с шифрованием.

Что конкретно мы будем делать?

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

Сервер будет реализован на Node.js с помощью Express, клиент на JavaScript. Для стилизации будет использоваться Bootstrap.

Код проекта находится здесь.

Поиграть с кодом можно здесь.

Если вам это интересно, прошу следовать за мной.

Подготовка


Создаем директорию crypto-tut:

mkdir crypto-tut

Заходим в нее и инициализируем проект:

cd crypto-tutnpm init -y

Устанавливаем express:

npm i express

Устанавливаем nodemon:

npm i -D nodemon

Редактируем package.json:

"main": "server.js","scripts": {    "start": "nodemon"},

Структура проекта:

crypto-tut    --node_modules    --src        --client.js        --index.html        --style.css    --package-lock.json    --package.json    --server.js

Содержание index.html:

<head>    <!-- Bootstrap CSS -->    <link rel="stylesheet" href="http://personeltest.ru/aways/stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">    <link rel="stylesheet" href="style.css">    <script src="client.js" defer></source></head><body>    <div class="container">        <h3>Web Cryptography API Tutorial</h3>        <input type="text" value="Hello, World!" class="form-control">        <div class="btn-box">            <button class="btn btn-primary btn-send">Send message</button>            <button class="btn btn-success btn-get" disabled>Get message</button>        </div>        <output></output>    </div></body>

Содержание style.css:

h3,.btn-box {    margin: .5em;    text-align: center;}input,output {    display: block;    margin: 1em auto;    text-align: center;}output span {    color: green;}

Сервер


Приступаем к созданию сервера.

Открываем server.js.

Подключаем express и создаем экземпляры приложения и маршрутизатора:

const express = require('express')const app = express()const router = express.Router()

Подключаем middleware (промежуточный слой между запросом и ответом):

// разбор запросаapp.use(express.json({    type: ['application/json', 'text/plain']}))// подключение роутераapp.use(router)// директория со статическими файламиapp.use(express.static('src'))

Создаем переменную для хранения данных:

let data

Обрабатываем получение данных от клиента:

router.post('/secure-api', (req, res) => {    // получаем данные из тела запроса    data = req.body    // выводим данные в терминал    console.log(data)    // закрываем соединение    res.end()})

Обрабатываем отправку данных клиенту:

router.get('/secure-api', (req, res) => {    // данные отправляются в формате JSON,    // после чего соединение автоматически закрывается    res.json(data)})

Запускаем сервер:

app.listen(3000, () => console.log('Server ready'))

Выполняем команду npm start. В терминале появляется сообщение Server ready. Открываем http://localhost:3000:



На этом с сервером мы закончили, переходим к клиентской части приложения.

Клиент


Здесь начинается самое интересное.

Открываем файл client.js.

Для шифрования данных будет использоваться симметричный алгоритм AES-GCM. Такие алгоритмы позволяют использовать один и тот же ключ для шифрования и расшифровки.

Создаем функцию генерации симметричного ключа:

// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/generateKeyconst generateKey = async () =>    window.crypto.subtle.generateKey({        name: 'AES-GCM',        length: 256,    }, true, ['encrypt', 'decrypt'])

Перед шифрованием данные необходимо закодировать в поток байтов. Это легко сделать с помощью класса TextEncoder:

// https://developer.mozilla.org/en-US/docs/Web/API/TextEncoderconst encode = data => {    const encoder = new TextEncoder()    return encoder.encode(data)}

Далее, нам нужен вектор исполнения (вектор инициализации, initialization vector, IV), представляющий собой случайную или псевдослучайную последовательность символов, которую добавляют к ключу шифрования для повышения его безопасности:

// https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValuesconst generateIv = () =>    // https://developer.mozilla.org/en-US/docs/Web/API/AesGcmParams    window.crypto.getRandomValues(new Uint8Array(12))

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

const encrypt = async (data, key) => {    const encoded = encode(data)    const iv = generateIv()    const cipher = await window.crypto.subtle.encrypt({        name: 'AES-GCM',        iv    }, key, encoded)    return {            cipher,            iv        }}

После шифрования данных с помощью SubtleCrypto, они представляют собой буферы необработанных двоичных данных. Это не лучший формат для передачи и хранения. Давайте это исправим.

Данные, обычно, передаются в формате JSON и хранятся в базе данных. Поэтому имеет смысл упаковать данные в портируемый формат. Одним из способов это сделать является конвертация данных в строки в формате base64:

// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-Stringconst pack = buffer => window.btoa(    String.fromCharCode.apply(null, new Uint8Array(buffer)))

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

// https://developers.google.com/web/updates/2012/06/How-to-convert-ArrayBuffer-to-and-from-Stringconst unpack = packed => {    const string = window.atob(packed)    const buffer = new ArrayBuffer(string.length)    const bufferView = new Uint8Array(buffer)    for (let i = 0; i < string.length; i++) {        bufferView[i] = string.charCodeAt(i)    }    return buffer}

Остается расшифровать полученные данные. Однако, после расшифровки нам необходимо декодировать поток байтов в исходный формат. Это можно сделать с помощью класса TextDecoder:

// https://developer.mozilla.org/en-US/docs/Web/API/TextDecoderconst decode = byteStream => {    const decoder = new TextDecoder()    return decoder.decode(byteStream)}

Функция расшифровки представляет собой инверсию функции шифрования:

// https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/decryptconst decrypt = async (cipher, key, iv) => {    const encoded = await window.crypto.subtle.decrypt({        name: 'AES-GCM',        iv    }, key, cipher)    return decode(encoded)}

На данном этапе содержимое client.js выглядит так:

const generateKey = async () =>    window.crypto.subtle.generateKey({        name: 'AES-GCM',        length: 256,    }, true, ['encrypt', 'decrypt'])const encode = data => {    const encoder = new TextEncoder()    return encoder.encode(data)}const generateIv = () =>    window.crypto.getRandomValues(new Uint8Array(12))const encrypt = async (data, key) => {    const encoded = encode(data)    const iv = generateIv()    const cipher = await window.crypto.subtle.encrypt({        name: 'AES-GCM',        iv    }, key, encoded)    return {        cipher,        iv    }}const pack = buffer => window.btoa(    String.fromCharCode.apply(null, new Uint8Array(buffer)))const unpack = packed => {    const string = window.atob(packed)    const buffer = new ArrayBuffer(string.length)    const bufferView = new Uint8Array(buffer)    for (let i = 0; i < string.length; i++) {        bufferView[i] = string.charCodeAt(i)    }    return buffer}const decode = byteStream => {    const decoder = new TextDecoder()    return decoder.decode(byteStream)}const decrypt = async (cipher, key, iv) => {    const encoded = await window.crypto.subtle.decrypt({        name: 'AES-GCM',        iv    }, key, cipher)    return decode(encoded)}

Теперь реализуем отправку и получение данных.

Создаем переменные:

// поле для ввода сообщения, которое будет зашифрованоconst input = document.querySelector('input')// контейнер для вывода результатовconst output = document.querySelector('output')// ключlet key

Шифрование и отправка данных:

const encryptAndSendMsg = async () => {    const msg = input.value     // шифрование    key = await generateKey()    const {        cipher,        iv    } = await encrypt(msg, key)    // упаковка и отправка    await fetch('http://localhost:3000/secure-api', {        method: 'POST',        body: JSON.stringify({            cipher: pack(cipher),            iv: pack(iv)        })    })    output.innerHTML = `Сообщение <span>"${msg}"</span> зашифровано.<br>Данные отправлены на сервер.`}

Получение и расшифровка данных:

const getAndDecryptMsg = async () => {    const res = await fetch('http://localhost:3000/secure-api')    const data = await res.json()    // выводим данные в консоль    console.log(data)    // распаковка и расшифровка    const msg = await decrypt(unpack(data.cipher), key, unpack(data.iv))    output.innerHTML = `Данные от сервера получены.<br>Сообщение <span>"${msg}"</span> расшифровано.`}

Обработка нажатия кнопок:

document.querySelector('.btn-box').addEventListener('click', e => {    if (e.target.classList.contains('btn-send')) {        encryptAndSendMsg()        e.target.nextElementSibling.removeAttribute('disabled')    } else if (e.target.classList.contains('btn-get')) {        getAndDecryptMsg()    }})

На всякий случай перезапускаем сервер. Открываем http://localhost:3000. Нажимаем на кнопку Send message:



Видим данные, полученные сервером, в терминале:

{  cipher: 'j8XqWlLIrFxyfA2easXkJTLLIt9x8zLHei/tTKI=',  iv: 'F8doVULJzbEQs3M1'}

Нажимаем на кнопку Get message:



Видим те же самые данные, полученные клиентом, в консоли:

{  cipher: 'j8XqWlLIrFxyfA2easXkJTLLIt9x8zLHei/tTKI=',  iv: 'F8doVULJzbEQs3M1'}

Web Cryptography API открывает перед нами интересные возможности по защите конфиденциальной информации на стороне клиента. Еще один шаг в сторону бессерверной веб-разработки.

Поддержка данной технологии на сегодняшний день составляет 96%:



Надеюсь, статья вам понравилась. Благодарю за внимание.
Подробнее..

Server-Sent Events пример использования

21.09.2020 14:20:44 | Автор: admin


Доброго времени суток, друзья!

В этом туториале мы рассмотрим Server Sent Events: встроенный класс EventSource, который позволяет поддерживать соединение с сервером и получать от него события.

О том, что такое SSE и для чего он используется можно почитать здесь.

Что конкретно мы будем делать?

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

Сервер будет реализован на Node.js, клиент на JavaScript. Для стилизации будет использоваться Bootstrap, в качестве API Random User Generator.

Код проекта находится здесь.

Поиграть с кодом можно здесь.

Если вам это интересно, прошу следовать за мной.

Подготовка


Создаем директорию sse-tut:

mkdir sse-tut

Заходим в нее и инициализируем проект:

cd sse-tutyarn init -y// илиnpm init -y

Устанавливаем axios:

yarn add axios// илиnpm i axios

axios будет использоваться для получения данных пользователей.

Редактируем package.json:

"main": "server.js","scripts": {    "start": "node server.js"},

Структура проекта:

sse-tut    --node_modules    --client.js    --index.html    --package.json    --server.js    --yarn.lock

Содержание index.html:

<head>    <!-- Bootstrap CSS -->    <link rel="stylesheet" href="http://personeltest.ru/aways/stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">    <style>        .card {            margin: 0 auto;            max-width: 512px;        }        img {            margin: 1rem;            max-width: 320px;        }        p {            margin: 1rem;        }    </style></head><body>    <main class="container text-center">        <h1>Server-Sent Events Tutorial</h1>        <button class="btn btn-primary" data-type="start-btn">Start</button>        <button class="btn btn-danger" data-type="stop-btn" disabled>Stop</button>        <p data-type="event-log"></p>    </main>    <script src="client.js"></script></body>

Сервер


Приступаем к реализации сервера.

Открываем server.js.

Подключаем http и axios, определяем порт:

const http = require('http')const axios = require('axios')const PORT = process.env.PORT || 3000

Создаем функцию получения данных пользователя:

const getUserData = async () => {    const response = await axios.get('https://randomuser.me/api')    // проверяем полученные данные    console.log(response)    return response.data.results[0]}

Создаем счетчик количества отправленных пользователей:

let i = 1

Пишем функцию отправки данных клиенту:

const sendUserData = (req, res) => {    // статус ответа - 200 ок    // соединение должно оставаться открытым    // тип содержимого - поток событий    // не кэшировать    res.writeHead(200, {        Connection: 'keep-alive',        'Content-Type': 'text/event-stream',        'Cache-Control': 'no-cache'    })    // данные будут отправляться каждые 2 секунды    const timer = setInterval(async () => {        // если отправлено 10 пользователей        if (i > 10) {            // останавливаем таймер            clearInterval(timer)            // сообщаем о том, что было отправлено 10 пользователей            console.log('10 users has been sent.')            // отправляем клиенту идентификатор со значением -1            // для того, чтобы клиент закрыл соединение            res.write('id: -1\ndata:\n\n')            // закрываем соединение            res.end()            return        }        // получаем данные        const data = await getUserData()        // записываем данные в ответ        // event - название события        // id - идентификатор события; используется при повторном подключении        // retry - время повторного подключения        // data - данные        res.write(`event: randomUser\nid: ${i}\nretry: 5000\ndata: ${JSON.stringify(data)}\n\n`)        // сообщаем о том, что данные отправлены        console.log('User data has been sent.')        // увеличиваем значение счетчика        i++    }, 2000)    // обрабатываем закрытие соединения клиентом    req.on('close', () => {        clearInterval(timer)        res.end()        console.log('Client closed the connection.')      })}

Создаем и запускаем сервер:

http.createServer((req, res) => {    // обязательный заголовок для преодоления CORS    res.setHeader('Access-Control-Allow-Origin', '*')    // если адрес запроса - getUser    if (req.url === '/getUsers') {        // отправляем данные        sendUserData(req, res)    } else {        // иначе, сообщаем о том, что запрашиваемая страница не найдена,        // и закрываем соединение        res.writeHead(404)        res.end()    }}).listen(PORT, () => console.log('Server ready.'))

Полный код сервера:
const http = require('http')const axios = require('axios')const PORT = process.env.PORT || 3000const getUserData = async () => {    const response = await axios.get('https://randomuser.me/api')    return response.data.results[0]}let i = 1const sendUserData = (req, res) => {    res.writeHead(200, {    Connection: 'keep-alive',    'Content-Type': 'text/event-stream',    'Cache-Control': 'no-cache'    })    const timer = setInterval(async () => {    if (i > 10) {        clearInterval(timer)        console.log('10 users has been sent.')        res.write('id: -1\ndata:\n\n')        res.end()        return    }    const data = await getUserData()    res.write(`event: randomUser\nid: ${i}\nretry: 5000\ndata: ${JSON.stringify(data)}\n\n`)    console.log('User data has been sent.')    i++    }, 2000)    req.on('close', () => {    clearInterval(timer)    res.end()    console.log('Client closed the connection.')    })}http.createServer((req, res) => {    res.setHeader('Access-Control-Allow-Origin', '*')    if (req.url === '/getUsers') {    sendUserData(req, res)    } else {    res.writeHead(404)    res.end()    }}).listen(PORT, () => console.log('Server ready.'))


Выполняем команду yarn start или npm start. В терминале появляется сообщение Server ready.. Открываем http://localhost:3000:



С сервером закончили, переходим к клиентской части приложения.

Клиент


Открываем файл client.js.

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

const getTemplate = user => `<div class="card">    <div class="row">        <div class="col-md-4">            <img src="${user.img}" class="card-img" alt="user-photo">        </div>        <div class="col-md-8">            <div class="card-body">                <h5 class="card-title">${user.id !== null ? `Id: ${user.id}` : `User hasn't id`}</h5>                <p class="card-text">Name: ${user.name}</p>                <p class="card-text">Username: ${user.username}</p>                <p class="card-text">Email: ${user.email}</p>                <p class="card-text">Age: ${user.age}</p>            </div>        </div>    </div></div>`

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

Начинаем реализовывать основной функционал:

class App {    constructor(selector) {        // основной элемент - контейнер        this.$ = document.querySelector(selector)        // запускаем частный метод        this.#init()    }    #init() {        this.startBtn = this.$.querySelector('[data-type="start-btn"]')        this.stopBtn = this.$.querySelector('[data-type="stop-btn"]')        // контейнер для сообщений о событиях        this.eventLog = this.$.querySelector('[data-type="event-log"]')        // устанавливаем контекст для обработчика        this.clickHandler = this.clickHandler.bind(this)        // делегируем обработку события        this.$.addEventListener('click', this.clickHandler)    }    clickHandler(e) {        // если кликнули по кнопке        if (e.target.tagName === 'BUTTON') {            // получаем тип кнопки            // и либо начинаем получать события от сервера,            // либо закрываем соединение            const {                type            } = e.target.dataset            if (type === 'start-btn') {                this.startEvents()            } else if (type === 'stop-btn') {                this.stopEvents()            }            // управление состоянием кнопок            this.changeDisabled()        }    }    changeDisabled() {        if (this.stopBtn.disabled) {            this.stopBtn.disabled = false            this.startBtn.disabled = true        } else {            this.stopBtn.disabled = true            this.startBtn.disabled = false        }    }//...

Сначала реализуем закрытие соединения:

stopEvents() {    this.eventSource.close()    // сообщаем о том, что соединение закрыто пользователем    this.eventLog.textContent = 'Event stream closed by client.'}

Переходим к открытию потока событий:

startEvents() {    // создаем экземпляр для получения данных по запросу на указанный адрес    this.eventSource = new EventSource('http://localhost:3000/getUsers')    // сообщаем о том, что соединение открыто    this.eventLog.textContent = 'Accepting data from the server.'    // обрабатываем получение от сервера идентификатора со значением -1    this.eventSource.addEventListener('message', e => {        if (e.lastEventId === '-1') {            // закрываем соединение            this.eventSource.close()            // сообщаем об этом            this.eventLog.textContent = 'End of stream from the server.'            this.changeDisabled()        }        // мы можем получить такой идентификатор лишь раз    }, {once: true})}

Обрабатываем кастомное событие randomUser:

this.eventSource.addEventListener('randomUser', e => {    // парсим полученные данные    const userData = JSON.parse(e.data)    // проверяем их    console.log(userData)    // извлекаем данные с помощью деструктуризации    const {        id,        name,        login,        email,        dob,        picture    } = userData    // продолжаем формировать данные, необходимые для генерации пользовательской карточки    const i = id.value    const fullName = `${name.first} ${name.last}`    const username = login.username    const age = dob.age    const img = picture.large    const user = {        id: i,        name: fullName,        username,        email,        age,        img    }    // генерируем шаблон    const template = getTemplate(user)    // рендерим карточку на странице    this.$.insertAdjacentHTML('beforeend', template)})

Не забываем реализовать обработку ошибок:

this.eventSource.addEventListener('error', e => {    this.eventSource.close()    this.eventLog.textContent = `Got an error: ${e}`    this.changeDisabled()}, {once: true})

Наконец, инициализируем приложение:

const app = new App('main')

Полный код клиента:
const getTemplate = user => `<div class="card">    <div class="row">        <div class="col-md-4">            <img src="${user.img}" class="card-img" alt="user-photo">        </div>        <div class="col-md-8">            <div class="card-body">                <h5 class="card-title">${user.id !== null ? `Id: ${user.id}` : `User hasn't id`}</h5>                <p class="card-text">Name: ${user.name}</p>                <p class="card-text">Username: ${user.username}</p>                <p class="card-text">Email: ${user.email}</p>                <p class="card-text">Age: ${user.age}</p>            </div>        </div>    </div></div>`class App {    constructor(selector) {        this.$ = document.querySelector(selector)        this.#init()    }    #init() {        this.startBtn = this.$.querySelector('[data-type="start-btn"]')        this.stopBtn = this.$.querySelector('[data-type="stop-btn"]')        this.eventLog = this.$.querySelector('[data-type="event-log"]')        this.clickHandler = this.clickHandler.bind(this)        this.$.addEventListener('click', this.clickHandler)    }    clickHandler(e) {        if (e.target.tagName === 'BUTTON') {            const {                type            } = e.target.dataset            if (type === 'start-btn') {                this.startEvents()            } else if (type === 'stop-btn') {                this.stopEvents()            }            this.changeDisabled()        }    }    changeDisabled() {        if (this.stopBtn.disabled) {            this.stopBtn.disabled = false            this.startBtn.disabled = true        } else {            this.stopBtn.disabled = true            this.startBtn.disabled = false        }    }    startEvents() {        this.eventSource = new EventSource('http://localhost:3000/getUsers')        this.eventLog.textContent = 'Accepting data from the server.'        this.eventSource.addEventListener('message', e => {            if (e.lastEventId === '-1') {                this.eventSource.close()                this.eventLog.textContent = 'End of stream from the server.'                this.changeDisabled()            }        }, {once: true})        this.eventSource.addEventListener('randomUser', e => {            const userData = JSON.parse(e.data)            console.log(userData)            const {                id,                name,                login,                email,                dob,                picture            } = userData            const i = id.value            const fullName = `${name.first} ${name.last}`            const username = login.username            const age = dob.age            const img = picture.large            const user = {                id: i,                name: fullName,                username,                email,                age,                img            }            const template = getTemplate(user)            this.$.insertAdjacentHTML('beforeend', template)        })        this.eventSource.addEventListener('error', e => {            this.eventSource.close()            this.eventLog.textContent = `Got an error: ${e}`            this.changeDisabled()        }, {once: true})    }    stopEvents() {        this.eventSource.close()        this.eventLog.textContent = 'Event stream closed by client.'    }}const app = new App('main')


На всякий случай перезапускаем сервер. Открываем http://localhost:3000. Нажимаем на кнопку Start:



Начинаем получать данные от сервера и рендерить карточки пользователей.

Если нажать на кнопку Stop, отправка данных будет приостановлена:



Снова нажимаем Start, отправка данных продолжается.

При достижении лимита (10 пользователей) сервер отправляет идентификатор со значением -1 и закрывает соединение. Клиент, в свою очередь, также закрывает поток событий:



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

Поддержка данной технологии на сегодняшний день составляет 95%:



Надеюсь, статья вам понравилась. Благодарю за внимание.
Подробнее..

Разбираем тестовое задание на должность фронтенд-разработчика на Vue.js

22.09.2020 20:11:13 | Автор: admin

Первое правило тестовых заданий - никогда не делайте тестовые задания!

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

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

Для ознакомления с заданием, которое я получил, прошу под спойлер:

Техническое задание:

Средствами Vue.js реализуйте небольшое SPA приложение для заметок.

Каждая заметка имеет название и список задач (todo list), далее - Todo. Каждый пункт Todo состоит из чекбокса и относящейся к нему текстовой подписи.

Приложение состоит всего из 2х страниц.

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

  • перейти к созданию новой заметки

  • перейти к изменению

  • удалить (необходимо подтверждение)

Страница изменения заметки позволяет определенную заметку отредактировать, отметить пункты Todo, а после сохранить изменения. Действия с заметкой:

  • сохранить изменения

  • отменить редактирование (необходимо подтверждение)

  • удалить (необходимо подтверждение)

  • отменить внесенное изменение

  • повторить отмененное изменение Действия с пунктами Todo:

  • добавить

  • удалить

  • отредактировать текст

  • отметить как выполненный

Требования к функционалу:

  • Все действия на сайте должны происходить без перезагрузки страницы.

  • Подтверждение действий (удалить заметку) выполняется с помощью диалогового окна.

  • Интерфейс должен отвечать требованиям usability.

  • После перезагрузки страницы состояние списка заметок должно сохраняться.

  • Можно пренебречь несоответствием редактирования текста с помощью кнопок отменить/повторить и аналогичным действиям с помощью комбинацияй клавиш (Ctrl+Z, Command+Z, etc.).

Технические требования:

  • Диалоговые окна должны быть реализованы без использования "alert", "prompt" и "confirm".

  • В качестве языка разработки допускается использовать JavaScript или TypeScript.

  • В качестве сборщика, если это необходимо, используйте Webpack.

  • Верстка должна быть выполнена без использования UI библиотек (например Vuetify).

  • Адаптивность не обязательна, но приветствуется.

  • Логика приложения должна быть разбита на разумное количество самодостаточных Vue-компонентов.

Особое внимание стоит обратить на следующие моменты:

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

  • Читабельность и наличие элементарной архитектуры.

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

Тестовое задание должно быть предоставлено в следующем виде:

  • Ссылка на публичный репозиторий (GitHub, BitBucket, GitLab) с исходным кодом.

  • Ссылка на сайт для тестирования функционала. Или Dockerfile и docker-compose.yaml, позволяющие развернуть локально командой docker-compose up работоспособную копию сайта.ехническое заданиеехническое заданиеехническое задание

Вот что у меня в итоге получилось.

Надо сразу предупредить, что особым архитектурным изяществом мое решение не обладает. Этому есть свои причины. С одной стороны, конечно, хочется впечатлить работодателя, с другой стороны, тестовое задание (далее просто ТЗ) делается в ущерб времени для личной жизни, поиска других предложений, подготовки к собеседованию и т.д.

Разберем по пунктам задание и возможные способы его решения:

Средствами Vue.js реализуйте небольшое SPA приложение для заметок. Тут все просто: используем Vue CLI для создания проекта.

Каждая заметка имеет название и список задач todo list, (далее - Todo). Каждый пункт Todo состоит из чекбокса и относящейся к нему текстовой подписи. - А вот и первая сложность, у нас будет два уровня абстракции: множество заметок и множество дел, которые составляют заметку.

Приложение состоит всего из 2х страниц. Тут возник вопрос - использовать ли Vue Router? Это же всего две страницы. Дальше из задания мы узнаем, что первая страница используется для отображения списка заметок, а вторая - для редактирования отдельной заметки. Конечно, можно переключать компоненты условным оператором, но раутер даст возможность перехода на сгенерированные страницы для каждой заметки. Но это уже больше двух страниц, или сгенерированные страницы считаются за одну, так как они по одному шаблону сделаны? После недолгих колебаний я решил все-таки его использовать.

Дальше следуют подробности по каждой странице, обратим внимание на два пункта:

  • отменить внесенное изменение

  • повторить отмененное изменение

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

Do и RedoDo и Redo
  • Все действия на сайте должны происходить без перезагрузки страницы. Это означает стандартное SPA, мы и так используем Vue CLI.

  • Подтверждение действий (удалить заметку) выполняется с помощью диалогового окна.

  • Диалоговые окна должны быть реализованы без использования "alert", "prompt" и "confirm".

    Диалоговое окно должно создавать Promise, который зависит от решения юзера. Желательно, чтобы решение было переиспользуемым для всех наших случаев. Помучавшись над решением, я пришел к выводу, что лучше использовать готовое решение, к тому же запретов на пакеты не было. Я использовал vue-modal-dialogs - очень удобная библиотека, рекомендую. Надеюсь её перепишут для Vue 3.

  • Интерфейс должен отвечать требованиям usability. Другими словами, он должен быть удобным. Лучше бы написали конкретные требования, так не очень понятно.

  • После перезагрузки страницы состояние списка заметок должно сохраняться. - Так как серверной части у нашего приложения не планируется, заметки следует сохранять на стороне клиента, для этого есть два решения Cookie и localStorage. Выбираем кому что ближе. Я выбрал localStorage. К тому же я решил не использовать Vuex, а вместо него использовать локальное хранилище, как единыйисточник истины. Для небольшого приложения без бэка это выглядит разумным решением, экономящем время, в других случаях я не рекомендовал бы так делать.

  • В качестве языка разработки допускается использовать JavaScript или TypeScript. - а разве есть еще варианты? Честно говоря, ТЗ оставляет ощущение, что тот кто его составлял плохо знаком с Vue. TypeScript на Vue 2 спорно применять, слабая поддержка. Посмотрим, что будет на Vue 3.

    Важное замечание для тех, кто захочет воссоздать его с нуля на новой версии! Мой проект написан на Vue 2, обещали, что старый синтаксис будет работать, но все же.

  • В качестве сборщика, если это необходимо, используйте Webpack. Vue CLI это и есть Webpack, настроенный для удобства создания SPA на Vue.js

  • Верстка должна быть выполнена без использования UI библиотек (например Vuetify) - это минус. Для того чтобы "оживить" приложение, я использовал Material Icons от Гугла, вместо кнопок. Не знаю, оценил ли заказчик, он так и не ответил.

  • Адаптивность не обязательна, но приветствуется. - flexbox в помощь.

  • Логика приложения должна быть разбита на разумное количество самодостаточных Vue-компонентов. - у меня вышло семь: 2 на страницы, еще заметка, тудушка, заголовок заметки, кнопка-иконка и диалоговое окно.

    Остальные пункты менее важны.

Еще из вкусностей:

Я использовал пакет v-click-outside. Название говорит само за себя. Он добавляет директиву, которая срабатывает при клике вне элемента. Можно было написать самому, но я решил не изобретать велосипед. Использовал для отмены редактирования тудушки, если пользователь кликнул где-то еще. Это в задании не было, включим это в юзабилити.

Еще мне пришла в голову такая мысль: а что делать, если юзер захочет покинуть страницу редактирования заметки? Куда повесить вызов диалогового окна: на историю браузера, на кнопки меню? Есть элегантное решение. Vue-Router добавляет хуки жизненного цикла в компонент. Хук beforeRouteLeave поможет нам во всех ситуациях когда пользователь пытается покинуть страницу. Пусть наш хук вызывает модальное окно. Только не забыть сделать его асинхронным, ведь окно возвращает промис. Например, вот так:

  async beforeRouteLeave (to, from, next) {    if (await confirm('Do you realy want to leave this page?',       'All unsaved changes will be lost.')) {        this.clearNote()        next()      } else{        next(from)      }  }

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

Если возникли вопросы и замечания, прошу в комментарии или личку.

Подробнее..

Бесплатные онлайн-мероприятия по разработке (15 сентября 23 сентября)

13.09.2020 16:10:25 | Автор: admin

Нажимайте на интересующую вас тему и откроется подробная информация о мероприятии.

Bussiness Intelligence Meetup #2
Business Intelligence Meetup #2Business Intelligence Meetup #2

Business Intelligence Meetup #2

15 сентября, начало в 19:00, Вторник

Практические проблемы оценки результатов тестирования производительности приложения - Сергей Миронов, Lead Software Engineer, EPAM

Во время доклада обсудим:

  • Описание выявленных проблем;

  • Особенности тестирования длительных операций (заданий);

  • Особенности тестирования API;

  • Предложенный вариант решения и использованные инструменты;

  • Применение и варианты развития рассмотренного решения.

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

Страница мероприятия

ESCAPE - Essential Skills, Competencies and People Engineering
Нетехническая конференция для всех, кто работает в IT. Нетехническая конференция для всех, кто работает в IT.

ESCAPE - Essential Skills, Competencies and People Engineering

1517 сентября

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

Страница мероприятия

Java Meetup

Java Meetup

16 сентября, начало в 19:00, Среда

  1. Как начинается рефакторинг - Ярослав Дмитриев, Java Developer, Andersen

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

  2. Из хэшей и веток - как работает Git - Синицын Артём, Half-Stack Developer, ScienceSoft

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

Страница мероприятия

Data Science Webinar

Data Science Webinar

16 сентября, 18:00-20:00, Среда

  1. Julia: язык для высокопроизводительных вычислений - Павел Шашкин, Senior Data Scientist, EPAM

    Julia - молодой язык программирования, созданный как высокопроизводительный инструмент для научных вычислений. Проект стремится объединить в себе сильные стороны Python, R, MATLAB и других, не уступая в быстродействии компилируемым языкам. Если вы решаете вычислительно тяжёлые задачи или работаете с большими объёмами данных, то Julia благодаря своей гибкости, JIT-компиляции, встроенной поддержке асинхронных, параллельных и распределённых вычислений может стать выгодной альтернативой привычным инструментам.

    В рамках доклада мы обсудим области применения, особенности дизайна и текущие планы проекта.

  2. Реконструкция позы человека в 3D: как мы делали виртуального тренера - Екатерина Деревянка, Data Scientist, EPAM

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

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

  3. Рекомендательные системы - от ритейла до хедж-фонда - Сергей Смирнов, Lead Data Scientist, EPAM

    Мы работаем с заказчиками в разных бизнес-доменах.

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

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

Страница мероприятия

Front-end Meetup

Front-end Meetup

17 сентября, начало в 18.30, Четверг

  1. Безопасность в web - Мария Сампир, Andersen

    Несколько известных хакерских атак последних лет. Три распространенных вида атак в сети интернет, их особенности и методы защиты. Как выбрать между безопасностью и user friendly.

  2. PWA - Владислав Фай, Andersen

    Что же такое PWA и как можно "прокачать" ваше приложение? Плюсы, минусы и подводные камни. В какой ситуации нужно задуматься о внедрении PWA. Реальные кейсы.

  3. Фоновые сервисы в браузерах есть ли жизнь после закрытия вкладки? - Максим Сальников, Web/Cloud евангелист, Full Stack разработчик в ForgeRock, Google Developer Expert и Microsoft MVP

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

Страница мероприятия

C++ MeetUp

С++ MeetUp

17 сентября, 18:00-20:00, Четверг

  1. Ещё чуть быстрее: делаем свой контейнер - Антон Полухин, эксперт-разработчик C++, Яндекс.Такси

    Поговорим о решении небольшой задачи на обработку потока данных, об алгоритмах, о нагрузке и об оптимизациях C++

  2. Rust vc C++ - Алексей Афанасьев, С++ разработчик, DataArt

    Кратчайший обзор Rust, сравнение производительности, стоит ли разработчику С++ переходить на Rust

  3. Обход проблем Pymalloc через модули Python на С++ - Александр Боргардт, С++ разработчик, IVA CV

    При обработке больших массивов данных на Python возникают проблемы потребления сотни гигабайт RAM из-за некомпактного хранения данных в памяти и низкой скорости загрузки и сохранения больших коллекций в память и на диск. Один из способов решения проблемы сделать allocator в Python через С++ API, Embedded VM и Module.

Страница мероприятия

Online Frontend Meetup: куда развиваться в 2020 году?

Online Frontend Meetup: куда развиваться в 2020 году?

19 сентября, 12:0017:00, Суббота

  1. React Hooks и производительность - Дмитрий Карпунин, Head of Frontend, Evrone

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

  2. Прогрессивно ли PWA? - Алексей Дорофеев, Senior Front-End developer, DataArt

    Идеал PWA и вероятность его реализации. Зачем нам PWA и чем оно лучше нативного. И лучше ли. Подводные камни и основные преимущества.

Страница мероприятия

Управление IT-персоналом: инструменты и технологии

Управление IT-персоналом: инструменты и технологии

23 сентября, начало в 19:00, Среда

Компания Andersen приглашает Вас на онлайн-встречу с бизнес-тренером, экспертом по управлению и мотивации персонала, Александром Фридманом.

Будет полезно для PM, руководителей высокотехнологичного бизнеса и просто любопытствующих теоретиков.

Страница мероприятия

Подробнее..

Какой язык программирования быстрее работает, проще изучается, легче пишется и вообще всех прекрасней на свете?

11.09.2020 12:04:11 | Автор: admin
В преддверии дня разработчика мы решили поднять извечный вопрос: Какой язык программирования самый лучший?




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

Конечно тему выбрали не просто так, в этом году наш учебный центр получил откровенный и полезный фидбек после интенсива по SRE. На мероприятии настраивали и поддерживали микросервисный сайт-агрегатор билетов в кино, написанный на ruby.

Интересность проекта была в том, что работоспособность такого сайта описывается множеством метрик, а инциденты имеют самую разную природу. Билеты не подгружаются в базу. Постеры фильмов в 0,1% случаев загружаются из хранилища за 10+ секунд. 0,01% заказов резервируют уже зарезервированное место. На 30 секунд отваливается система обработки платежей. Сам проект отлично вписался в тему интенсива.

Но очень многим не зашёл ruby в качестве языка проекта. Поэтому на следующем интенсиве по SRE, который пройдёт в декабре 2020 года, проект будет на другом языке, и это решение будет принято по рекомендациям выпускников.

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

Пишите в комментариях свой аргумент, например, Я выбираю Паскаль, потому что меня учительница информатики Светлана Петровна ему ещё в школе научила или Python круче всех, потому что решает в Data Science, а это наше будущее
Подробнее..

Любовь, смерть и роботы рассматриваем рассказы Азимова глазами разработчика

15.09.2020 10:12:59 | Автор: admin


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

Из множества рассказов знаменитого фантаста показательна серия о компании Ю. С. Роботс и её сотрудниках. Несколько историй повествуют о буднях испытателей Пауэлла и Донована своего рода тестировщиков роботов, другие о главном робопсихологе, докторе Кэлвин. Спектр проблем, с которыми они сталкиваются, широк и знаком многим современным их коллегам по сей день.

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

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

Я сказал Постой Я сказал: Спиди, нам нужен селен. Ты найдёшь его там-то и там-то. Пойди и принеси его. Вот и всё. Что же ещё я должен был сказать?
Ты не говорил, что это очень важно, срочно?
Зачем? Дело-то простое.

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

Я посылал его к другому селеновому озеру на этот раз с приказом добыть селен во что бы то ни стало. Он принёс его через сорок две минуты и три секунды, я засёк время.

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

Однако робот Кьюти, новая разработка для обслуживания преобразователя энергии, в причастность людей к своему созданию не поверил. Ну правда, как же могут эти слабые существа создать нечто более совершенное, чем они сами? Это нелогично. У него есть более правдоподобная версия:

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

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

Не верит, грустно согласился Пауэлл. Это же рассуждающий робот, чёрт возьми! Он верит только в логику, и в этом-то всё дело
В чём?
Строго логическим рассуждением можно доказать всё что угодно смотря какие принять исходные постулаты. У нас они свои, а у Кьюти свои.

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

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

Конечно, но дело-то не в этом. Нельзя же, чтобы он продолжал нести эту чепуху про Господина.
А почему бы и нет?
Потому что это неслыханно! Как можно доверить ему станцию, если он не верит в существование Земли?
Он справляется с работой?
Да, но
Так пусть себе верит во что ему вздумается!

Третий рассказ про испытателей Поймать кролика хорошо показывает, что бывает, когда продукт не проходил нагрузочное тестирование перед выходом. История описывает полевые испытания робота-рудокопа Дейва, причём новой конструкции составного (один робот-командир управляет шестью другими роботами, как рука пальцами). Но стоит роботу остаться без присмотра, как он перестаёт работать. Более того, пускается маршировать всей командой весьма подозрительное занятие для рудокопа.

Лучше всего проблему испытателей описывает цитата из самого рассказа:

Правильно. Теперь слушай тут вот какая логика! Донован начал загибать волосатые пальцы. Первое: новый робот прошёл все испытания в лаборатории. Второе: Ю. С. Роботс гарантировала, что он пройдёт и полевые испытания на астероиде. Третье: вышеупомянутых испытаний робот не выдерживает. Четвёртое: если он не пройдёт полевых испытаний, Ю. С. Роботс теряет десять миллионов наличными и примерно на сотню миллионов репутации. Пятое: если он не пройдёт испытаний и мы не сможем объяснить почему, очень может быть, что нам предстоит трогательное расставание с хорошей работой.

Под угрозой потери хорошей работы тестировщик способен на многое факт. Герои рассказа перебрали и отвергли множество вариантов проверки от unit-тестирования на месте (можно было бы разобрать его на части и проверить по отдельности, но есть всего 10 дней и ещё неизвестно, даст ли это что-нибудь) до специального тестового окружения (которое есть, но на далёкой Земле и весит 10 тонн). Что остаётся? Имитировать условия, при которых появляется баг, и искать, искать причину. Такова, увы, доля многих тестировщиков современности. Правда, им повезло больше в отличие от героев рассказа, нынешним специалистам хотя бы не приходится для этого умышленно взрывать шахту вместе с собой. Зато под завалом камней человек и думает куда эффективнее, и хорошо, что разработчики пока не взяли на вооружение этот приём.

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

Я и говорю. Команды, отдаваемые одновременно по шести каналам! В обычных условиях один или несколько пальцев выполняют несложную работу, которая не требует пристального наблюдения за ними. Ну, точно так же, как наши привычные движения при ходьбе. А в чрезвычайных обстоятельствах нужно немедленно и одновременно привести в действие всех шестерых. И вот тут что-то сдаёт. Остальное просто. Любое уменьшение требуемой от него инициативы, например появление человека, приводит его в себя. Я уничтожил одного из роботов, и Дейву пришлось командовать лишь пятью, инициатива уменьшилась, и он стал нормальным!

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

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

Мы с вашим молодым мистером Блэком приготовили небольшой сюрприз. Видите ли, пространство между мной и роботами было залито не гамма-лучами, а инфракрасными. Обычным тепловым излучением, абсолютно безобидным. Нестор-10 знал это и ринулся вперёд. Он ожидал, что и остальные поступят так же под действием Первого закона. Только через какую-то долю секунды он вспомнил, что обычный НС-2 способен обнаружить наличие излучения, но не его характер. Что среди них только он один может определять длину волны благодаря обучению, которое он прошёл на Гипербаэе под руководством обыкновенных людей. Эта мысль не сразу пришла ему в голову, потому что была слишком унизительной для него. Обычные роботы знали, что пространство, отделявшее их от меня, гибельно для них, потому что мы им это сказали, и только Нестор-10 знал, что мы лгали. И на какое-то мгновение он забыл или просто не захотел вспомнить, что другие роботы могут знать меньше, чем люди Комплекс превосходства погубил его.

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

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

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

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

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

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

И если бы робот не был надёжнее человека, всё было бы в порядке. К сожалению, на Ю. С. Роботс считали своим долгом сделать робота надёжнее человека. Роботу было приказано крепко схватить рычаг, притянуть его к себе и держать. Крепко! Это слово было выделено, повторено, подчёркнуто. И робот выполнил приказ. Но вот незадача: робот раз в десять сильнее человека, в расчёте на которого был сконструирован рычаг.
Вы хотите сказать
Я не хочу сказать, а говорю, что рычаг погнулся. Погнулся вполне достаточно для того, чтобы сместить спусковой механизм. И когда тепло рук робота сместило термоэлемент, контакта не произошло

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

Перевод HDTree настраиваемое дерево решений на Python

16.09.2020 18:22:11 | Автор: admin

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

TL;DR

  • Репозиторий HDTree
  • Дополняющий Notebook внутри examples. Каталог репозитория здесь (каждая иллюстрация, которую вы видите здесь, будет сгенерирована в блокноте). Вы сможете создавать иллюстрации самостоятельно.

О чём пост?


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

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

Мотивация и предыстория


Для диссертации я начал работать с деревьями решений. Моя цель сейчас реализовать ориентированную на человека ML-модель, где HDTree (Human Decision Tree, если на то пошло) это дополнительный ингредиент, который применяется как часть реального пользовательского интерфейса для этой модели. Хотя эта история посвящена исключительно HDTree, я мог бы написать продолжение, подробно описав другие компоненты.

Особенности HDTree и сравнение с деревьями решений scikit learn


Естественно, я наткнулся на реализацию деревьев решений scikit-learn [4]. Реализация sckit-learn имеет множество плюсов:

  • Она быстра и оптимизирована;
  • Написана на диалекте Cython. Cython компилируется в C-код (который, в свою очередь, компилируется в двоичный код), сохраняя при этом возможность взаимодействия с интерпретатором Python;
  • Простая и удобная;
  • Многие люди в ML знают, как работать с моделями scikit-learn. Вам помогут везде благодаря его пользовательской базе;
  • Она испытана в боевых условиях (её используют многие);
  • Она просто работает;
  • Она поддерживает множество методов предварительной и последующей обрезки [6] и предоставляет множество функций (например, обрезка с минимальными затратами и весами выборки);
  • Поддерживает базовую визуализацию [7].

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

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

Особенности HDTree


HDTree предлагает решение большинства этих проблем, но при этом жертвует многими преимуществами реализации scikit-learn. Мы вернемся к этим моментам позже, поэтому не беспокойтесь, если вы еще не понимаете весь следующий список:

  • Взаимодействует с обучающим поведением;
  • Основные компоненты имеют модульную структуру и их довольно легко расширить (реализовать интерфейс);
  • Написана на чистом Python (более доступна);
  • Имеет богатую визуализацию;
  • Поддерживает категориальные данные;
  • Поддерживает отсутствующих значений;
  • Поддерживает многовариантные разделения;
  • Имеет удобный интерфейс навигации по структуре дерева;
  • Поддерживает n-арное разбиение (больше 2 дочерних узлов);
  • Текстовые представления путей решения;
  • Поощряет объясняемость за счет печати удобочитаемого текста.

Минусы:

  • Медленная;
  • Не проверена в боях;
  • Качество ПО посредственно;
  • Не так много вариантов обрезки. Хотя реализация поддерживает некоторые основные параметры.

Недостатков не много, но они критичны. Давайте сразу же проясним: не скармливайте этой реализации большие данные. Вы будете ждать вечно. Не используйте её в производственной среде. Она может неожиданно сломаться. Вас предупредили! Некоторые из проблем выше можно решить со временем. Однако скорость обучения, вероятно, останется небольшой (хотя логический вывод допустим). Вам нужно будет придумать лучшее решение, чтобы исправить это. Приглашаю вас внести свой вклад. Тем не менее, какие возможны варианты применения?

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

Структура деревьев решений


Хотя в этой работе не будут подробно рассмотрены деревья решений, мы резюмируем их основные строительные блоки. Это обеспечит основу для понимания примеров позже, а также подчеркнет некоторые особенности HDTree. На следующем рисунке показан фактический результат работы HDTree (за исключением маркеров).



Узлы

  • ai: текстовое описание правила проверки и разделения, которое использовалось на этом узле для разделения данных на его дочерние элементы. Отображает соответствующий атрибуты и словесное описание операции. Эти тесты *легко настраиваются* и могут включать любую логику разделения данных. Разработка собственных пользовательских правил поддерживается за счет реализации интерфейса. Подробнее об этом в разделе 3.
  • aii: оценка узла измеряет его чистоту, то есть то, насколько хорошо данные, проходящие через узел, разделены. Чем выше оценка, тем лучше. Записи также представлены цветом фона узлов. Чем больше зеленоватого оттенка, тем выше оценка (белый цвет означает нечистые, т.е. равномерно распределенные классы). Эти оценки направляют построение дерева и являются модульным и заменяемым компонентом HDTree.
  • aiii: рамка узлов указывает на то, сколько точек данных проходит через этот узел. Чем толще граница, тем больше данных проходит через узел.
  • aiv: список целей прогнозирования и меток, которые имеют точки данных, проходящие через этот узел. Самый распространенный класс отмечен .
  • av: опционально визуализация может отмечать путь, по которому следуют отдельные точки данных (иллюстрируя решение, которое принимается, когда точка данных проходит дерево). Это отмечено линией в углу дерева решений.

Ребра

  • bi: стрелка соединяет каждый возможный результат разделения (ai) с его дочерними узлами. Чем больше данных относительно родителя перетекает по краю, тем толще они отображаются.
  • bii: каждое ребро имеет удобочитаемое текстовое представление соответствующего результата разбиения.

Откуда разные разделения наборов и тесты?


К этому моменту вы уже можете задаться вопросом, чем отличается HDTree от дерева scikit-learn (или любой другой реализации) и почему мы можем захотеть иметь разные виды разделений? Попробуем прояснить это. Может быть, у вас есть интуитивное понимание понятия пространство признаков. Все данные, с которыми мы работаем, находятся в некотором многомерном пространстве, которое определяется количеством и типом признаков в ваших данных. Задача алгоритма классификации теперь состоит в том, чтобы разделить это пространство на не перекрывающиеся области и присвоить этим областям класс. Давайте визуализируем это. Поскольку нашему мозгу трудно возиться с высокой размерностью, мы будем придерживаться двухмерного примера и очень простой задачи с двумя классами, вот так:



Вы видите очень простой набор данных, состоящий из двух измерений (признаков/атрибутов) и двух классов. Сгенерированные точки данных были нормально распределены в центре. Улица, которая является просто линейной функциейf(x) = y разделяет эти два класса: Class 1 (правая нижняя) и Class 2 (левая верхняя) части. Также был добавлен некоторый случайный шум (синие точки данных в оранжевой области и наоборот), чтобы проиллюстрировать эффекты переобучения в дальнейшем. Задача алгоритма классификации, такого как HDTree (хотя он также может использоваться для задач регрессии), состоит в том, чтобы узнать, к какому классу принадлежит каждая точка данных. Другими словами, задана пара координат (x, y) вроде (6, 2). Цель в том, чтобы узнать, принадлежит ли эта координата оранжевому классу 1 или синему классу 2. Дискриминантная модель попытается разделить пространство объектов (здесь это оси (x, y)) на синюю и оранжевую территории соответственно.
Учитывая эти данные, решение (правила) о том, как данные будут классифицированы, кажется очень простым. Разумный человек сказал бы о таком подумайте сначала самостоятельно.
Это класс 1, если x > y, иначе класс 2. Идеальное разделение создаст функция y=x, показанная пунктиром. В самом деле, классификатор максимальной маржи, такой как метод опорных векторов [8], предложил бы подобное решение. Но давайте посмотрим, какие деревья решений решают вопрос иначе:



На изображении показаны области, в которых стандартное дерево решений с увеличивающейся глубиной классифицирует точку данных как класс 1 (оранжевый) или класс 2 (синий).
Дерево решений аппроксимирует линейную функцию с помощью ступенчатой функции.
Это связано с типом правила проверки и разделения, которое используют деревья решений. Они все работают по схемеattribute <threshold, что приведет к к гиперплоскостям, которые параллельны осям. В 2D-пространстве вырезаются прямоугольники. В 3D это были бы кубоиды и так далее. Кроме того, дерево решений начинает моделировать шум в данных, когда уже имеется 8 уровней, то есть происходит переобучение. При этом оно никогда не находит хорошего приближения к реальной линейной функции. Чтобы убедиться в этом, я использовал типичное разделение тренировочных и тестовых данных 2 к 1 и вычислил точность деревьев. Она составляет 93,84%, 93,03%, 90,81% для тестового набора и 94,54%, 96,57%, 98,81% для тренировочного набора (упорядочены по глубине деревьев 4, 8, 16). Тогда как точность в тесте уменьшается, точность обучения увеличивается.
Повышение эффективности тренировок и снижение результатов тестов признак переобучения.
Полученные деревья решений довольно сложны для такой простой функции. Самое простое из них (глубина 4), визуализированное с помощью scikit learn, уже выглядит так:



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

Применение пакета HDTree


Этот раздел познакомит вас с основами HDTree. Я постараюсь коснуться некоторых частей его API. Пожалуйста, не стесняйтесь спрашивать в комментариях или свяжитесь со мной, если у вас есть какие-либо вопросы по этому поводу. С радостью отвечу и при необходимости дополню статью. Установка HDTree немного сложнее, чем pip install hdtree. Извините. Для начала нужен Python 3.5 или новее.

  • Создайте пустой каталог и внутри него папку с именем hdtree (your_folder/hdtree)
  • Клонируйте репозиторий в каталог hdtree (не в другой подкаталог).
  • Установите необходимые зависимости: numpy, pandas, graphviz, sklearn.
  • Добавьте your_folder в PYTHONPATH. Это включит директорию в механизм импорта Python. Вы сможете использовать его как обычный пакет Python.

В качестве альтернативы добавьте hdtree в папку site-packages вашей установки python. Я могу добавить установочный файл позже. На момент написания код недоступен в репозитории pip. Весь код, который генерируют графику и выходные данные ниже (а также ранее показанные), находятся в репозитории, а непосредственно размещены здесь. Решение линейной проблемы с помощью одноуровневого дерева

Давайте сразу начнем с кода:

from hdtree import HDTreeClassifier, SmallerThanSplit, EntropyMeasurehdtree_linear = HDTreeClassifier(allowed_splits=[SmallerThanSplit.build()], # Split rule in form a < b    information_measure=EntropyMeasure(), # Use Information Gain for the scores attribute_names=['x', 'y' ]) # give the    attributes some interpretable names # standard sklearn-like interface hdtree_linear.fit(X_street_train,    y_street_train) # create tree graph hdtree_linear.generate_dot_graph() 




Да, результирующее дерево имеет высоту только в один уровень и предлагает идеальное решение этой проблемы. Это искусственный пример, чтобы показать эффект. Тем не менее, я надеюсь, что он проясняет мысль: иметь интуитивное представление о данных или просто предоставлять дерево решений с различными вариантами разделения пространства признаков, которое может предложить более простое, а иногда даже более точное решение. Представьте, что вам нужно интерпретировать правила из представленных здесь деревьев, чтобы найти полезную информацию. Какую интерпретацию вы сможете понять первой, а какой больше доверяете? Сложная интерпретация, использующая многошаговые функции, или небольшое точное дерево? Думаю, ответ довольно прост. Но давайте немного углубимся в сам код. При инициализации HDTreeClassifier самое важное, что вы должны предоставить, это allowed_splits. Здесь вы предоставляете список, содержащий возможные правила разделения, которые алгоритм пробует во время обучения для каждого узла, чтобы найти хорошее локальное разделение данных. В этом случае мы предоставили исключительноSmallerThanSplit. Это разделение делает именно то, что вы видите: оно принимает два атрибута (пробует любую комбинацию) и разделяет данные по схеме a_i < a_j. Что (не слишком случайно) соответствует нашим данным настолько хорошо, насколько это возможно.

Этот тип разделения обозначается как многовариантное разделение Оно означает, что разделение использует более одного признака для принятия решения. Это не похоже на одновариантное разделение, которое используются в большинстве других деревьев, таких как scikit-tree (подробнее см. выше), которые принимают во внимание ровно один атрибут. Конечно, у HDTree также есть опции для достижения нормального разделения, как те, что есть в scikit-деревьях семейство QuantileSplit. Я покажу больше по ходу статьи. Другая незнакомая вещь, которую вы можете увидеть в коде гиперпараметр information_measure. Параметр представляет измерение, которое используется для оценки значения одного узла или полного разделения (родительского узла с его дочерними узлами). Выбранный вариант основан на энтропии [10]. Возможно, вы также слышали о коэффициенте Джини, который был бы еще одним допустимым вариантом. Конечно же, вы можете предоставить своё собственное измерение, просто реализовав соответствующий интерфейс. Если хотите, реализуйте gini-Index, который вы можете использовать в дереве, не реализовывая заново ничего другого. Просто скопируйте EntropyMeasure() и адаптируйте для себя. Давайте копнем глубже, в катастрофу Титаника. Я люблю учиться на собственных примерах. Сейчас вы увидите ещё несколько функций HDTree с конкретным примером, а не на сгенерированных данных.

Набор данных


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



Вы можете заметить, что там все виды атрибутов. Числовые, категориальные, целочисленные типы и даже пропущенные значения (посмотрите на столбец Cabin). Задача в том, чтобы спрогнозировать, выжил ли пассажир после катастрофы Титаника, по доступной информации о пассажире. Описание атрибутов-значений вы найдёте здесь. Изучая ML-учебники и применяя этот набор данных, вы выполняете все виды предварительной обработки, чтобы иметь возможность работать с обычными моделями машинного обучения, например, удаляя отсутствующие значения NaN путём замещения значений [12], отбрасывания строк/столбцов, унитарным кодированием [13] категориальных данных (например, Embarked и Sex или группировки данных, чтобы получить валидный набор данных, который принимает ML-модель. Такая очистка технически не требуется HDTree. Вы можете подавать данные как есть, и модель с радостью примет их. Измените данные только в том случае, когда проектируете реальные объекты. Я упростил всё для начала.

Тренировка первого HDTree на данных Титаника


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

    hdtree_titanic = HDTreeClassifier(allowed_splits=[FixedValueSplit.build(), # e.g., Embarked = 'C'    SingleCategorySplit.build(), # e.g., Embarked -> ['C', 'Q', 'S']    TwentyQuantileRangeSplit.build(), # e.g., IN Quantile 3-5    TwentyQuantileSplit.build()], # e.g., BELOW Quantile 7    information_measure=EntropyMeasure(),    attribute_names=col_names,    max_levels=3) # restrict to grow to a max of 3 levels    hdtree_titanic.fit(X_titanic_train.values, y_titanic_train.values)    hdtree_titanic.generate_dot_graph()    



Присмотримся к происходящему. Мы создали дерево решений, имеющее три уровня, которые выбрали для использования 3 из 4 возможных правил разделения SplitRules. Они помечены буквами S1, S2, S3. Я вкратце объясню, что они делают.

  • S1: FixedValueSplit. Это разделение работает с категориальными данными и выбирает одно из возможных значений. Затем данные разделяются на одну часть, имеющую это значение, и другую часть, для которой значение не установлено. Например, PClass = 1 и Pclass 1.
  • S2: (Двадцать) QuantileRangeSplit. Они работают с числовыми данными. Правила разделят соответствующий диапазон значений оцениваемого атрибута на фиксированное количество квантилей и интервалов, находящихся в пределах последовательных подмножеств. От квантиля 1 до квантиля 5 каждый включает одинаковое количество точек данных. Начальный квантиль и конечный квантиль (размер интервала) ищутся для оптимизации измерения информации (measure_information). Данные делятся на (i) имеющие значение в пределах этого интервала или (ii) вне его. Доступны разделения различного количества квантилей.
  • S3: (Двадцать) QuantileSplit. Подобно разделению диапазона (S2), но разделяет данные по пороговому значению. Это в основном то, что делают обычные деревья решений, за исключением того, что они обычно пробуют все возможные пороги вместо их фиксированного числа.

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

  • S4: SingleCategorySplit будет работать аналогично FixedValueSplit, но создаст дочерний узел для каждого возможного значения, например: для атрибута PClass это будет 3 дочерних узла (каждый для Class 1, Class 2 и Class 3). Обратите внимание, что FixedValueSplit идентичен SingleValueSplit, если есть только две возможные категории.

Индивидуальные разделения несколько умны по отношению к типам/значениям данных, которые принимают. До некоторого расширения они знают, при каких обстоятельствах они применяются и не применяются. Дерево также обучалось с разделением тренировочных и тестовых данных 2 к 1. Производительность 80,37% точности на тренировочных данных и 81,69 на тестовых. Не так уж и плохо.

Ограничение разделений


Предположим, что вы по какой-то причине не слишком довольны найденными решениями. Может быть, вы решите, что самое первое разделение на вершине дерева слишком тривиально (разделение по атрибуту sex). HDTree решает проблему. Самым простым решением было бы запретить FixedValueSplit (и, если уж на то пошло, эквивалентному SingleCategorySplit) появляться на вершине. Это довольно просто. Измените инициализацию разбиений вот так:

    - SNIP -    ...allowed_splits=[FixedValueSplit.build_with_restrictions(min_level=1),    SingleCategorySplit.build_with_restrictions(min_level=1),...],    - SNIP -

Я представлю получившееся HDTree целиком, поскольку мы можем наблюдать недостающее разбиение (S4) внутри только что сгенерированного дерева.



Запрещая разделению по признаку sex появляться в корне благодаря параметруmin_level=1 (подсказка: конечно же, вы также можете предоставить max_level), мы полностью реструктурировали дерево. Его производительность сейчас составляет 80,37% и 81,69% (тренировочные/тестовые). Она не менялась вообще, даже если мы взяли предположительно лучшее разделение в корневом узле.

Из-за того, что деревья решений строятся в жадной форме, они найдут только локальное _наилучшее разбиение для каждого узла, что не обязательно является _ лучшим _ вариантом вообще. На самом деле нахождение идеального решения проблемы дерева решений NP-полная задача, это доказано в [15].
Так что лучшее, чего мы можем желать, это эвристики. Вернёмся к примеру: обратите внимание, что мы уже получили нетривиальное представление данных? Хотя это тривиально. сказать, что мужчины будут иметь только низкие шансы на выживание, в меньшей степени может иметь место вывод, что, будучи человеком в первом или втором классе PClass вылет из Шербура (Embarked=C) Может увеличить ваши шансы на выживание. Или что если вы мужчина изPClass3 и вам меньше 33 лет, ваши шансы тоже увеличиваются? Помните: прежде всего женщина и дети. Хорошее упражнение сделать эти выводы самостоятельно, интерпретируя визуализацию. Эти выводы были возможны только благодаря ограничению дерева. Кто знает, что еще можно раскрыть, применив другие ограничения? Попробуйте!

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

    - SNIP -    ...allowed_splits=[TwentyQuantileRangeSplit.build_with_restrictions(blacklist_attribute_indices=['PassengerId']),    FixedValueSplit.build_with_restrictions(blacklist_attribute_indices=['Name Length']),    ...],    - SNIP -    



Вы можете спросить, почемуname length вообще появляется. Нужно учитывать, что длинные имена (двойные имена или [благородные] титулы) могут указывать на богатое прошлое, увеличивая ваши шансы на выживание.
Дополнительная подсказка: вы всегда можете добавить то жеSplitRule дважды. Если вы хотите внести в черный список атрибут только для определенных уровней HDTree, просто добавьте SplitRule без ограничения уровня.

Прогнозирование точек данных


Как вы, возможно, уже заметили, для прогнозирования можно использовать общий интерфейс scikit-learn. Это predict(), predict_proba(), а такжеscore(). Но можно пойти дальше. Есть explain_decision(), которая выведет текстовое представление решения.

print(hdtree_titanic_3.explain_decision(X_titanic_train[42]))

Предполагается, что это последнее изменение в дереве. Код выведет это:

Query:Query:  {'PassengerId': 273, 'Pclass': 2, 'Sex': 'female', 'Age': 41.0, 'SibSp': 0, 'Parch': 1, 'Fare': 19.5, 'Cabin': nan, 'Embarked': 'S', 'Name Length': 41}Predicted sample as "Survived" because of: Explanation 1:Step 1: Sex doesn't match value maleStep 2: Pclass doesn't match value 3Step 3: Fare is OUTSIDE range [134.61, ..., 152.31[(19.50 is below range)Step 4: Leaf. Vote for {'Survived'}    

Это работает даже для отсутствующих данных. Давайте установим индекс атрибута 2 (Sex) на отсутствующий (None):

    passenger_42 = X_titanic_train[42].copy()    passenger_42[2] = None    print(hdtree_titanic_3.explain_decision(passenger_42))    

Query:  {'PassengerId': 273, 'Pclass': 2, 'Sex': None, 'Age': 41.0, 'SibSp': 0, 'Parch': 1, 'Fare': 19.5, 'Cabin': nan, 'Embarked': 'S', 'Name Length': 41}Predicted sample as "Death" because of: Explanation 1:Step 1: Sex has no value availableStep 2: Age is OUTSIDE range [28.00, ..., 31.00[(41.00 is above range)Step 3: Age is OUTSIDE range [18.00, ..., 25.00[(41.00 is above range)Step 4: Leaf. Vote for {'Death'}---------------------------------Explanation 2:Step 1: Sex has no value availableStep 2: Pclass doesn't match value 3Step 3: Fare is OUTSIDE range [134.61, ..., 152.31[(19.50 is below range)Step 4: Leaf. Vote for {'Survived'}---------------------------------    

Это напечатает все пути решения (их больше одного, потому что на некоторых узлах решение не может быть принято!). Конечным результатом будет самый распространенный класс среди всех листьев.

другие полезные вещи


Вы можете продолжить и получить представление дерева в виде текста:

    Level 0, ROOT: Node having 596 samples and 2 children with split rule "Split on Sex equals male" (Split Score:    0.251)    -Level 1, Child #1: Node having 390 samples and 2 children with split rule "Age is within range [28.00, ..., 31.00["    (Split Score: 0.342)    --Level 2, Child #1: Node having 117 samples and 2 children with split rule "Name Length is within range [18.80,    ..., 20.00[" (Split Score: 0.543)    ---Level 3, Child #1: Node having 14 samples and no children with    - SNIP -    

Или получить доступ ко всем чистым узлам (с высоким баллом):

    [str(node) for node in hdtree_titanic_3.get_clean_nodes(min_score=0.5)]    

    ['Node having 117 samples and 2 children with split rule "Name Length is within range [18.80, ..., 20.00[" (Split    Score: 0.543)',    'Node having 14 samples and no children with split rule "no split rule" (Node Score: 1)',    'Node having 15 samples and no children with split rule "no split rule" (Node Score: 0.647)',    'Node having 107 samples and 2 children with split rule "Fare is within range [134.61, ..., 152.31[" (Split Score:    0.822)',    'Node having 102 samples and no children with split rule "no split rule" (Node Score: 0.861)']    

Расширение HDTree


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


image

Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя онлайн-курсы SkillFactory:



Подробнее..

Категории

Последние комментарии

© 2006-2020, personeltest.ru