-Поиск по дневнику

Поиск сообщений в rss_rss_hh_new

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 17.03.2011
Записей:
Комментариев:
Написано: 51

Habrahabr/New








Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://habrahabr.ru/rss/new/.
Данный дневник сформирован из открытого RSS-источника по адресу http://feeds.feedburner.com/xtmb/hh-new-full, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

Codota: использование ИИ для улучшение кода

Пятница, 11 Августа 2017 г. 09:40 + в цитатник
Привет Хабр! Хочу поделиться с вами одним инструментом, который помогает мне делать меньше ошибок в коде и реже гуглить по вопросам разработки.

image

О чем это ты?



Программируете на Java? Codota поможет вам в этом! Этот помощник разработан, чтобы помочь вам писать код, не проверяя лишний раз документацию. Codota понимает код и предлагает вам правильные решение в нужное время. Означает ли это, что однажды роботы возьмут на себя наши рабочие места разработчиков? Возможно. Но пока еще нет.

Кодить это сложно. Такие сервисы, как StackOverflow или GitHub, безусловно, помогают нам в этом.
Теперь у Java-разработчиков есть еще один альтернативный вариант: ИИ-помощник Codota. Лично я всегда хотел получить помощь искусственного интеллекта при разработке.

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

Как это работает?



По словам создателей этого сервиса, Codota создает прогностические модели кода, которые предполагают доработку кода и связанный контент на основе текущего контекста, присутствующего в вашей среде IDE.

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

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

Так, а это точно ИИ?



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

Давай теперь про минусы



Конечно, есть некоторые рамки.

Codota еще не знает сути кода. В качестве примера вам часто будет предоставлен кусок кода какого-то другого программиста из мира сего. Очевидно, это означает, что нет гарантии на всегда красивый и чистый код. Но поскольку база знаний Codota основывается на таких сервисах, как GitHub, BitBucket и StackOverflow, то каждый день ИИ становится лучше.

Codota работает на Linux, Windows и MacOS.

Программа работает с Eclipse, IntelliJ и Android Studio.




Также, есть довольно интересное промо-видео, в котором подробно показано, как это работает.



Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335388/


Метки:  

[Перевод] Законы Авери для надёжности Wi-Fi

Пятница, 11 Августа 2017 г. 00:27 + в цитатник
Замена маршрутизатора:

Производитель A: 10% сломано
Производитель B: 10% сломано
P(одновременно A и B сломаны):
10% x 10% = 1%

Замена маршрутизатора (или прошивки) почти всегда решает проблему.
Добавление усилителя Wi-Fi:

Маршрутизатор A: 90% работает
Маршрутизатор B: 90% работает
P(одновременно A и B работают):
90% x 90% = 81%

Дополнительный маршрутизатор почти всегда ухудшает ситуацию.
Все беспроводные сети, будь то LTE или mesh-сети, рано или поздно падают, но я могу поставить на то, что ваша сеть Wi-Fi менее надёжная, чем телефонное соединение LTE. На конференции Battlemesh v10 мы все сидели в комнате с десятками экспериментальных неправильно сконфигурированных маршрутизаторов Wi-Fi с открытыми сетями, которые могут дать выход в Интернет, а могут и не дать. Из-за чего сеть бывает надёжной или ненадёжной?

После нескольких лет возни с этими технологиями (в окружении кучи инженеров, работающих над другими проблемами распределённых систем, которые, как выяснилось, обладают теми же ограничениями), я думаю, что могу сделать выводы. Распределённые системы более надёжны, если вы можете получить сервис от одного узла ИЛИ от другого. Они становятся менее надёжными, если сервис зависит от одного узла И от другого. Числа сочетаются мультипликативно, так что чем больше у вас узлов, тем быстрее отвалится сервис.

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

Вернёмся к Wi-Fi. Представьте, что у меня маршрутизатор от производителя A. Маршрутизатор Wi-Fi обычно так себе, так что ради примера, предположим его надёжность на уровне 90%, и для простоты определим это как «он хорошо работает для 90% пользователей, а 10% испытывают досадные баги». Итак, 90% пользователей с маршрутизатором марки A будут довольны и никогда его ни на что не поменяют. Остальные 10% будут недовольны, так что купят новый маршрутизатор — от производителя B. Этот тоже хорошо работает у 90% пользователей, но баги не взимосвязаны, так что он будет работать у других 90%. Это значит, что 90% людей с маршрутизатором марки A довольны; и 90% из 10%, которые используют маршрутизатор марки B, тоже довольны. Получается уровень удовлетворения 99%! Даже хотя оба маршрутизатора надёжны всего на 90%. Так выходит, потому что у каждого есть выбор между маршрутизатором A ИЛИ маршрутизатором B, поэтому они выбирают хорошо работающий и выбрасывают другой.

Это одинаково применимо к программному обеспечению (прошивка вендора vs openwrt vs tomato) или версиям программы (люди могут не обновляться с v1.0 на v2.0, пока v1.0 не начнёт доставлять проблемы). В нашем проекте есть маршрутизатор v1 и маршрутизатор v2. Первая версия нормально работала для большинства пользователей, но не для всех. Когда вышла вторая версия, мы начали раздавать маршрутизаторы v2 всем новым пользователям, а также тем пользователям v1, кто жаловался на проблемы. Когда мы вывели график удовлетворённости пользователей, то увидели, что он подскочил сразу после выхода второй версии. Отлично! (Особенно отлично, потому что маршрутизатор v2 разрабатывала моя группа :)). Теперь обновить всех, правильно?

Вообще-то, не обязательно. Проблема в том, что мы исказили нашу статистику: мы обновили на v2 только тех пользователей v1, которые испытывали проблемы. Мы не «обновляли» на v1 пользователей v2 с проблемами (конечно, такие тоже были). Может быть, оба маршрутизатора были надёжны на 90%; вышеописанная история вполне могла сработать и наоборот. Тот же феномен объясняет, почему некоторые люди переходят с openwrt на tomato и восторженно отзываются, насколько эта прошивка более надёжная, и наоборот. То же самое с Red Hat и Debian или Linux и FreeBSD, и т. д. Этот феномен «У меня всё работает!» известен в мире open source; простая вероятность. Вам нужен стимул для перехода только если у вас сейчас какие-то проблемы.

Но обратная сторона уравнения тоже верна, и она имеет значение для mesh-сети. Когда вы устанавливаете многочисленные маршрутизаторы в ячеистую цепь, то зависите от нескольких маршрутизаторов одновременно, иначе ваша сеть разваливается. Wi-Fi печально известен этим: один маршрутизатор устанавливает соединения, но работает странно (например, не маршрутизирует пакеты), а клиенты по-прежнему привязаны к этому маршрутизатору, и ни у кого ничего не работает. Если увеличить количество узлов в цепочке, то вероятность такого исхода быстро возрастает.

Конечно, у базовых станций LTE тоже есть проблемы надёжности — и много. Но они обычно не организованы в виде ячеистой топологии, и каждая станция LTE обычно покрывает гораздо б'oльшую площадь, так что образуется зависимость от меньшего количества узлов. Кроме того, каждый узел LTE обычно «слишком большой, чтобы упасть» — другими словами, это мгновенно доставит проблемы настолько большому количеству людей, что телефонная компания быстро всё починит. Единственный неисправный узел в mesh-сети действует только на небольшой площади, так что проблемы возникнут только при проходе через эту территорию, хотя в большинстве ситуаций проблем не будет. Всё это ведёт к смутному впечатлению, что «mesh-сети Wi-Fi глючные, а LTE надёжен», даже если ваш собственный mesh-узел работает б'oльшую часть времени. Это всё игра статистики.

Решение: система-приятель
Пусть ваш приятель скажет, если вы стали задницей.

Маршрутизатор A: 90% работает
Маршрутизатор B: 90% работает
P(или A, или B работают):
1 - (1-0,9) x (1-0,9) = 99%

В последние примерно 15 лет теория и практика распределённых систем проделали большой путь. Теперь мы в основном знаем, как преобразовать ситуацию И в ситуацию ИЛИ. Если у вас массив RAID5 и один из дисков выходит из строя, вы выводите диск из обращения, так что можете заменить его, пока не вышел из строя другой. Если у вас сервис баз данных NoSQL на 200 узлов, вы проверяете, что к вышедшим из строя узлам не направляются запросы, так что другие узлы могут взять на себя их работу. Если один из ваших веб-серверов перегружен излишним кодом Ruby on Rails, то ваши балансировщики нагрузки перенаправляют трафик на другой узел, который менее нагружен, пока первый сервер не вернётся в нормальный режим.

То же самое должно быть с Wi-Fi: если ваш маршрутизатор работает странно, его нужно вывести из строя до починки.

К сожалению, производительность маршрутизатора Wi-Fi труднее измерить, чем производительность базы данных или веб-сервера. Сервер баз данных легко может протестировать сам себя; просто запустить пару запросов и убедиться, что сокет запросов в строю. Поскольку веб-серверы доступны через Интернет, можно запустить один проверочный сервис, который будет периодически опрашивать все сервера, и сигнализировать о необходимости перезагрузки, если сервер перестал отвечать. Но по определению не все узлы mesh-сети доступны по прямому линку Wi-Fi из одного места, так что единый проверочный сервис не будет работать.

Вот моё предложение, которое можно назвать «Wi-Fi система-приятель». Аналогия такая: как будто вы с друзьями пошли в бар, где вы слишком сильно напились и начали вести себя как придурок. Поскольку вы слишком пьяны, то необязательно знаете, что ведёте себя как придурок. Это может быть трудно определить. Но вы знаете, кто может это определить? Ваши друзья. Обычно даже в том случае, если они тоже напились.

Хотя по определению не все mesh-узлы доступны из одного места, вы можете также сказать, что по определению каждый mesh-узел доступен хотя бы для одного другого mesh-узла. Иначе это не будет ячеистой структурой, и у вас ещё более крупные проблемы. Это намекает, как исправить ситуацию. Каждый mesh-узел должен время от времени пытаться соединиться с одним или более соседними узлами, выдавая себя за конечного пользователя, и смотреть, прохожит маршрутизация трафика или нет. Если проходит, то отлично! Говорим этому узлу, что он хорошо справляется, пусть продолжает в том же духе. Если нет, то плохо! Говорим этому узлу, что ему лучше вернуться в вагон. (Строго говоря, наиболее безопасный способ реализовать это — отправлять только сообщения «ты хорошо справляешься» после опроса. Сбойный узел может быть неспособен получить сообщения «твои дела плохи». Нам нужна система вроде контролёра, которая перезагрузит узел, если он не получил сообщение «отлично!» за определённый промежуток времени).

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

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

Небольшой математический пример прошёл длинный путь!

Вам этого недостаточно?
Можете посмотреть все мои слайды (pdf) о потребительских Wi-Fi mesh-сетях (в том числе подробные заметки выступающего) с конференции Battlemesh v10 в Вене или моё выступление на YouTube:




Примечание
Так называемые «законы» — это особый случай более общих и поэтому более полезных теорем распределённых систем. Но это Интернет, так что я выбрал один особый случай и назвал его в свою честь. Давайте, попробуйте меня остановить.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335380/


Метки:  

Конкурс по программированию: JSDash (промежуточные результаты 3)

Четверг, 10 Августа 2017 г. 21:51 + в цитатник
Спасибо всем, кто уже принял участие в нашем конкурсе по программированию! Мы получили 60 решений от 34 уникальных участников. До конца конкурса осталась одна неделя (до 17 августа 2017, 23:59:59 UTC), и мы публикуем последние предварительные результаты.

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

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

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

Присылайте свои решения! Осталась неделя, чтобы обойти нынешних лидеров.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335376/


О чем всегда стоит помнить при локализации веб-сайта, чтобы потом не было стыдно

Четверг, 10 Августа 2017 г. 19:53 + в цитатник
В нашем прошлом материале, посвященному переводам, мы частично затрагивали тему локализации через адаптацию контента. Сегодня хотелось бы более детально рассмотреть вопрос локализации в вебе и на что разработчикам стоит обратить внимание.

Ориентация письменности


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

Если вы все еще не понимаете, в какую степь мы уводим разговор, то вот вам скриншот арабской Windows с правосторонним интерфейсом:

image

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

Ну, это азиаты.

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

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

Предлагаемые консорциумом скрипты юникода группируют языки на три категории:

  • LTR (left-to-right);
  • RTL (right-to-left);
  • и TTB (top-to-bottom).

Очевидно, что к LTR относится большинство современных языков, TTB — это китайский, японский и корейский (в случае использования иероглифописи, от которой они постепенно отходят в пользу латиницы в процессе романизации языка). Все остальные — RTL-языки. И тут надо быть предельно осторожными: RTL-языков намного больше, чем может показаться на первый взгляд. Конечно, на ум сразу же приходят арабский и иврит, да и скриптов юникода для RTL-языков всего шесть штук (арабский, иврит, Нко, сирийский, тана и тифинаг), но на самом деле RTL-ориентация присуща более чем трем десяткам языков и наречий:

image
Таблица из памятки W3C

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

Дизайн, верстка и размерность сайта


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

Одновременная разработка и локализация сайта для LTR, RTL и TTB-языков — это тема для отдельной публикации и, возможно, мы рассмотрим этот вопрос более детально, в публикации, посвященным китайскому и японскому языкам. А теперь предлагаем перейти к обсуждению вопроса локализации на конкретных примерах.

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


Aliexpress на английском


Aliexpress на испанском


Aliexpress на русском

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


Наложение испанской страницы Aliexpress на английскую с ~50% прозрачности

Мы исходим из того, что локализацию на эти два языка делали профессионалы (ориентация на русскоязычные рынки СНГ и испаноязычные рынки Южной Америки), так что будем рассматривать все расхождения, как неизбежные и обоснованные последствия локализации, а не как «косяки» локализаторов.

Первое, что бросается в глаза — это размерность элементов шапки в выделенном блоке №1.



Видно, что строка поиска товара начинается в одном месте, но имеет разную длину — испанская заметно короче. Это обуславливается тем, что одни и те же элементы интерфейса справа от поисковой строки имеют различную размерность. Так, лаконичное английское «Cart» трансформировалось в чуть более длинное «Cesta», а «Wish List» в «Lista de Deseos». Но больше всего повлияла трансформация «Sign in» и «Login» в «Identif'icate» и «Reg'istrate». Как итог: поисковая строка «ужалась» почти на 90 пикселей.

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

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

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

В области №5 отмечена дополнительная информация по доставке для испаноязычного рынка, которая отсутствует на интернациональном англоязычном сайте. Также под нормы испанского адаптирован размер кнопки в области №6.

Но наибольший интерес, на наш взгляд, представляет область под номером 7.



В нашей прошлой статье мы упоминали о таком аспекте локализации, как формат дат. Именно в этом блоке это правило было соблюдено. По нормам английского языка даты записываются в формате месяц.число.год, когда как в испанском, как и в русском, используется порядок число.месяц.год. Поэтому на англоязычном баннере указан срок акции в виде «Aug 7-8», а на испаноязычном — «7-8 Ago».

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

image
Наложение русской страницы Aliexpress на английскую с ~50% прозрачности

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

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

  1. Наличие запаса пространства в элементах навигации.
  2. Гибкость размеров основных элементов интерфейса.
  3. Соблюдение правил написания дат и денежных единиц.
  4. Работа с виджетами социальных сетей исходя из предпочтений целевой аудитории.

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

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

А теперь о деньгах


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

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

На территории РФ для оплаты покупок в интернете лидирующее место занимает пластик, это правда. Далее идут электронные валюты (Яндекс.Деньги, WM) и PayPal для тех, кто зарабатывает, например, на другом берегу Атлантического океана.

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

Перед тем, локализовать такую вещь, как способы оплаты, необходимо ознакомиться с наиболее популярными способами на целевом для вас рынке. И если для США это кредитки и PayPal, то с рынком, вроде как находящегося прямо под боком ЕС, все не так просто.

Отличительной особенностью финансовой культуры Старого Света является то, что там крайне популярны безналичные платежи. При словосочетании «безналичный платеж» у рядового читателя сразу перед взглядом возникает стандартный прямоугольный кусок пластика с чипом и CVC-кодом. Но проблема в том, что пластиковые карты в той же Германии распространены не так сильно, как даже у нас. В ЕС крайне популярны прямые безналичные платежи с банковского счета. Те же немцы умеют считать деньги и предпочитают прямые банковские переводы с личного Р/С, которые стоят в районе 0,5%, вместо транзакций через международные платежные системы Visa/MasterCard, которые «состригают» минимум 1-2% комиссионных.

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

Для рынка Китая же все выглядит немного иначе: там крайне популярны электронные деньги и платежи через таких гигантов как AliPay и WeChat. Чтобы вы понимали масштаб популярности этих сервисов: в этом году через WeChat на китайский Новый Год было совершено 46 миллиардов денежных переводов (так называемые «красные конверты» — традиционный денежный подарок родным и близким). Это больше транзакций, чем за весь 2016 год при помощи PayPal.

Что мы хотели донести этой статьей


Единообразие элементов UI вне зависимости от языка локализации — это признак хорошего тона в разработке. Вы можете что-то добавлять для локальных потребителей (например, другие телефоны службы поддержки или дополнительную информацию о доставке товара), но базовые элементы интерфейса должны максимально совпадать. Подобный подход показывает не только степень профессионализма разработчиков, которые не прибивают элементы UI намертво к макету, но и клиентоориентированность всего ресурса. За примерами плохой локализации ходить далеко не надо: на том же Amazon часть англоязычных кнопок и элементов просто отсутствуют на других языках, а о дебрях PayPal и магическом перемещении разделов в зависимости от используемого языка и вовсе ходят легенды.

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

Ориентированная на разработчиков латформа локализации мобильных и веб-проектов:
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335200/


[Из песочницы] Разработка интерфейса приложения для пожизненного использования на примере мобильного дневника диабета

Четверг, 10 Августа 2017 г. 19:30 + в цитатник

Метки:  

Как угодить кинозрителю и не потерять деньги: составляем план закупок при помощи ML

Четверг, 10 Августа 2017 г. 19:05 + в цитатник

Как С# разработчику перейти на Unity

Четверг, 10 Августа 2017 г. 18:57 + в цитатник
Unity3D — один из самых популярных игровых движков. В последние годы всё больше отличных игр выходят благодаря тому, что Unity прост в использовании и предлагает разработчикам много готовых решений. Алексей Науменко, .NET Developer в Plarium Kharkiv, рассказал с чего разработчику начать изучение Unity.



Как я начал программировать


Я учился в ХАИ по специальности «Телекоммуникации». У нас был преподаватель, который конструировал беспилотники. Благодаря ему уже на 4-м курсе я начал писать простой код на С для микроконтроллеров, которые управляют передачей данных с земли на БПЛА. Тогда я решил, что нужно выучить какой-то актуальный язык программирования, чтобы писать на нём постоянно, а не только для решения узких задач.

Выбирал я между С# и Java: читал книги по этим языкам, но потом просто открыл Visual Studio и Java IDE и сделал выбор в пользу первого по «обертке». Не самый правильный способ анализа преимуществ и недостатков, но о выборе я не жалею.

Почему пошел в геймдев и выбрал Unity


В 5–7 классах мы с другом пытались сделать игру. И хотя получилась ерунда, романтика процесса осталась со мной. К тому же я люблю играть, особенно в древние RPG. После университета я работал в нескольких продуктовых компаниях: год занимался веб-программированием, потом 4 года разрабатывал ПО для call-центров. Но меня всё время преследовала идея попробовать себя в разработке игр. Так что в свободное от работы время я стал думать, какой движок использовать для будущей игры.

Многие разработчики используют Unity и Unreal Engine, но я хотел изучить все варианты. Поэтому я стал разбираться, на чем написаны популярные проекты. Оказалось, что это либо самописные движки, как, например, у Naughty Dog, либо движки, о которых очень мало информации в интернете — чтобы работать с ними, нужно, скорее всего, некоторое время работать в индустрии и знать хотя бы общие принципы построения игровых движков.

Я вернулся к выбору между Unity и Unreal Engine. И так как на тот момент я уже 4 года программировал на .NET, выбор был прост: в Unity есть C#, а в Unreal Engine — нет. Еще один плюс Unity: я погуглил некоторые интересные мне вопросы и почти на все из них нашел попытки ответить. Пусть не всегда профессиональные, но информация была, и было с кем ее обсудить.

У Unity есть аналог StackOverflow — Unity Answers. Там очень просто найти ответы на конкретные вопросы на начальном этапе, поэтому порог входа очень низкий, особенно если человек понимает хотя бы общие принципы программирования.

С чего начать обучение


Я изучал уже решенные задачи, похожие на те, что интересовали меня. Однажды я искал конкретное решение, но не нашел его в Asset Store. Поэтому начал мониторить форумы и наткнулся на парня, который делал именно то, что мне было нужно, но в Store его решение не пропустили по каким-то требованиям. Я написал ему сообщение и предложил купить его наработку. Он очень обрадовался возможности подзаработать — это был румынский десятиклассник. Чуть ли не лучшее мое вложение в изучение движка: 10$ плюс столько же за Swift-платеж.

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

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

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

Нет смысла изучать Unity просто так — стоит начинать с решения конкретных проектных задач. Лучше сразу определиться: «Я хочу сделать Pac-Man». Начинаешь думать, что для этого понадобится: например, нужно реализовать управление персонажем. Желтое существо ест белые точки. Существо должно понимать, что наткнулось на съедобный объект — значит, нужно начать с определения соприкосновения съедобной точки с Пакменом. Тогда появляется конкретная проблема и необходимость искать пути ее решения — а это, по-моему, и есть лучший способ изучения технологии.

Переход с .NET на Unity на практике


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

Иногда мы собеседуем Senior или Middle+ .NET программистов, которые не знакомы с Unity вообще. При этом человек не переходит на позицию Junior, потому что в Plarium, да и в работе с движком, нет понятия Unity Junior. Если с .NET всё хорошо, освоить движок будет очень просто.

Что почитать


Кроме Unity Answers есть еще UnifyWiki. Можно декомпилировать код и посмотреть результат (он не обфусцирован).

На старте очень пригодились форумы (answers.unity3d.com и forum.unity3d.com). Также я читал книгу Game Engine Architecture Джейсона Грегори. Автор в ней не говорит конкретно о Unity, но подробно рассматривает составные части и особенности игровых движков в целом. Он в деталях описывает, из чего состоит движок, какая математика нужна, как устроен рендеринг. Эта книга расширяет представление о Unity: я начал понимать, что в этом движке есть или должно быть, что с него спрашивать. Единственная трудность — для прочтения этой книги нужно быть очень мотивированным: она не нудная, но достаточно объемная.

Преимущества работы с Unity


Большие компании любят Unity за кроссплатформенность. Если ты что-то написал, оно билдится и под iOS, и под Android — пусть и с надстройками, но зато сразу работает без особых плясок. Конечно, если это не касается платежки :)

В нашем случае преимущество также в том, что Plarium — официальный партнер Unity с поддержкой уровня Enterprise Support. Нам не только быстро отвечают на запросы, но и предоставляют больше открытого кода, и мы можем сами что-то вскрыть и допилить.

Надеюсь, информация будет полезна тем, кто планирует работать с Unity. Успехов!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335370/


Метки:  

DevOps не проблема технологий. DevOps — это проблема бизнеса. (перевод)

Четверг, 10 Августа 2017 г. 18:06 + в цитатник
Дэймон Эдвардс / 8 ноября, 2010

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

Безусловно, DevOps движение имеет своих хулителей. Негативные мнения варьируются от ошибочных («DevOps — это новое название для сисадминов») и пренебрежительных («DevOps — это просто какие-то безумные разработчики (Devs), которые пытаются избавиться от админов (Ops)» или «DevOps — это какие-то безумные админы, которые хотят казаться разработчиками, чтобы их больше любили») до выражений обиды (как правило, с аргументами, не поддающимися логике).

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

DevOps это не проблема технологий.

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

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





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



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



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

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

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



Разве это не похоже на цели Agile?

Если цели DevOps и выглядят похожими на цели Agile, то это потому, что они на самом деле похожи. Но Agile и DevOps — это разные вещи. Вы можете идеально выстроить разработку по Agile, но, тем не менее, иметь много DevOps проблем. С другой стороны, вы можете хорошо справиться с устранением DevOps проблем, при этом совсем не используя разработку согласно Agile принципам (хотя это достаточно маловероятно).

Мне нравится описывать Agile и DevOps как две родственные идеи, которые берут общие корни из Lean методологии, но работают на разных уровнях. В то время, как Agile фокусируется на улучшении одной IT функции (доставка ПО), DevOps работает над улучшением взаимодействия и работы всех IT функций (покрывающих весь жизненный цикл продукта: от разработки до сопровождения).
Но я думал, что DevOps — это про крутые инструменты?

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



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

Поскольку зарождающееся DevOps движение в основном состоит из инженеров, несложно понять, откуда берется такой азарт сразу же погрузиться в обсуждение инструментария. Но возможно, нам нужно приложить больше усилий, чтобы удостоверится, что все достаточно вникли и понимают, почему нужны те или иные инструменты и что является желаемыми улучшениями бизнес-процесса, прежде, чем окунуться в обычные споры «Puppet vs. Chef» или «Files Centric vs. Package Centric».



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

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



В этом карикатурном Dev/Ops примере, основная часть внимания DevOps методологии на раннем этапе была обращена на улучшение процесса деплоя. И, поскольку процесс внесения изменений составляет львиную долю работы в IT организациях, это было также логическим и естественным местом для начала.
Возможно, Патрику стоило назвать первую конференцию «BizDevQASecurityOpsCloudUsers Days» или «SolvingABroaderProblemThanAgile Days»… Но я сомневаюсь, что кто-то бы пришел.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335368/


Метки:  

[Из песочницы] Пишем (недо)интерпретатор на Haskell с помощью alex и happy

Четверг, 10 Августа 2017 г. 18:01 + в цитатник
Привет, Хабр! В этой статье мы рассмотрим, как сделать своими руками (недо)интерпретатор на Haskell. Заинтересовавшихся прошу под кат!

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

Шаг 1: формулировка ТЗ самим себе


Наш (недо)интерпретатор будет работать так:

let a = 2 in a*2
4
let a = 8 in (let b = a - 1 in a*b)
56

Только let-in, только Int, из операций: сложение, вычитание, умножение, деление (целочисленное). Поехали!

Шаг 2: alex


Первое, что нам нужно — лексер (программа, которая будет делить код на частички — токены). Те, кто писал свои трансляторы на великом и могучем C, наверное, вспомнили про flex — великий и могучий генератор лексеров. Мы будем использовать не менее великий и могучий alex — тоже генератор лексеров, но для Haskell. Скачиваем alex отсюда или

$ sudo apt-get install alex

затем открываем любимый текстовый редактор и пишем:

{
module Lex where
}

%wrapper "basic"

$digit = 0-9
$alpha = [a-zA-Z]

tokens :-

  $white                                       ;
  let                                              { \s -> TLet }
  in                                               { \s -> TIn }
  $digit+                                     { \s -> TNum (read s)}
  [\=\+\-\*\/\(\)]                          { \s -> TSym (head s)}
  $alpha [$alpha $digit \_ ']*  { \s -> TVar s}

{
data Token = TLet | TIn | TNum Int | TSym Char | TVar String deriving (Eq, Show)
}

Страшновато.

На самом деле, все просто. Сначала мы объявляем модуль Lex (код в фигурных скобках — чистый Haskell), затем говорим, что хотим использовать basic wrapper, т. е. без всяких наворотов — дешево и сердито, дальше идут определения наборов символов (charsets) — имя charset'а должно начинаться с $, значение — (почти) регулярное выражение. $digit — это все цифры, $alpha — все буквы. Теперь самое главное — токены. после :- должны идти их определения, слева регулярное выражение, справа токен. Пробелы мы игнорируем (слева charset для пробельных символов, справа точка с запятой), let — это токен TLet, in — TIn, одна или более цифр — TNum, всякие плюсы-минусы — TSym, буквы, подчерки и ' — TVar. Дальше мы видим, что все страшные слова на букву T — это значения типа Token — ничего сложного.

Теперь настало время магии.

Сохраняем файл как Lex.x, затем

$ alex Lex.x

Готово! Унас есть модуль нашего лексера — Lex.hs!

Шаг 3: happy


Теперь нам нужен генератор парсеров — happy. Его аналоги для C — это bison и yacc. Качаем его отсюда или

$ sudo apt-get install happy

Создаем файл Synt.y

{
module Synt where
import Lex
}

%name synt
%tokentype { Token }
%error { parseError }

%token
  let         { TLet }
  in          { TIn }
  num         { TNum $$ }
  var         { TVar $$ }
  '='         { TSym '=' }
  '+'         { TSym '+' }
  '-'         { TSym '-' }
  '*'         { TSym '*' }
  '/'         { TSym '/' }
  '('         { TSym '(' }
  ')'         { TSym ')' }

%%

Exp:
  let var '=' Exp in Exp        { Let $2 $4 $6 }
  | Exp1                        { Exp1 $1 }

Exp1:
  Exp1 '+' Term                 { Plus $1 $3 }
  | Exp1 '-' Term               { Minus $1 $3 }
  | Term                        { Term $1 }

Term:
  Term '*' Factor               { Mul $1 $3 }
  | Term '/' Factor             { Div $1 $3 }
  | Factor                      { Factor $1 }

Factor:
  num                           { Num $1 }
  | var                         { Var $1 }
  | '(' Exp ')'                 { Brack $2 }

{
parseError :: [Token] -> a
parseError _ = error "Parse error"

data Exp = Let String Exp Exp | Exp1 Exp1 deriving (Show)
data Exp1 = Plus Exp1 Term | Minus Exp1 Term | Term Term deriving (Show)
data Term = Mul Term Factor | Div Term Factor | Factor Factor deriving (Show)
data Factor = Num Int | Var String | Brack Exp deriving (Show)
}

Еще страшней.

Здесь тоже код на Haskell берется в фигурные скобки, так что сначала мы объявляем модуль Synt, затем импортируем Lex (нам нужен тип Token оттуда). "%name synt" значит, то наша функция-парсер будет называться synt, "%tokentype { Token }" — что мы используем тип Token в качестве типа токенов никогда бы не догадался, "%error { parseError }" задает функцию, которая будет обрабатывать ошибки.

Далее идут соответствия токенов их псевдонимам. А вот сейчас будет страшно. Мы говорим, что выражение (Exp) — это let переменная = выражение in выражение или подвыражение (Exp1). В первом случае нужно создать конструкцию Let (ее тип — Exp, см. объявление ниже), а в качестве аргументов взять второе, четвертое, и шестое слова (т. е. var, Exp и Exp), а во втором случае создать конструкцию Exp1 с первым словом в качестве аргумента. Exp1 же может быть операцией сложения или вычитания с первым и третьим словами в качестве аргументов или Term'ом. Term устроен аналогично, но для операций сложения и умножения. Читатель спросит: «Зачем разбивать на два типа, неужели нельзя запихнуть умножение и деление в Exp1?» Дело в том, что работа парсера заключается в том, чтобы построить так называемое «дерево парсинга». Самые глубоко вложенные операции выполняются первыми. Term у нас будет глубже, чем Exp1, а значит операции умножения выполнятся раньше, чем сложения! Factor, в свою очередь, может быть числом, переменной или выражением в скобках — опять же для порядка действий. Далее мы объявлем функцию parseError для «обработки» ошибок и все типы данных вроде Exp или Factor.

Все, парсер готов!

$ happy Synt.y

Теперь у нас есть файл Synt.hs

Последний рывок: интерпретатор


Код интерпретатора представлен ниже:

module Main where
import qualified Data.Map as M
import Lex
import Synt

newtype Context = Context {getContext :: M.Map String Int} deriving (Show)

pull :: Maybe a -> a
pull (Just m) = m
pull Nothing = error "Undefined variable"

createContext :: Context
createContext = Context {getContext = M.empty}

getValue :: Context -> String -> Maybe Int
getValue ctx name = M.lookup name $ getContext ctx

solveExp :: Context -> Exp -> Maybe Int
solveExp ctx exp = case exp of (Let name expl rexp) -> solveExp newCtx rexp where newCtx = Context {getContext = M.insert name (pull (solveExp ctx expl)) (getContext ctx)}
                               (Exp1 exp1) -> solveExp1 ctx exp1

solveExp1 :: Context -> Exp1 -> Maybe Int
solveExp1 ctx exp1 = case exp1 of (Plus lexp1 rterm) -> (+) <$> (solveExp1 ctx lexp1) <*> (solveTerm ctx rterm)
                                  (Minus lexp1 rterm) -> (-) <$> (solveExp1 ctx lexp1) <*> (solveTerm ctx rterm)
                                  (Term term) -> solveTerm ctx term

solveTerm :: Context -> Term -> Maybe Int
solveTerm ctx term = case term of (Mul lterm rfactor) -> (*) <$> (solveTerm ctx lterm) <*> (solveFactor ctx rfactor)
                                  (Div lterm rfactor) -> (div) <$> (solveTerm ctx lterm) <*> (solveFactor ctx rfactor)
                                  (Factor factor) -> solveFactor ctx factor

solveFactor :: Context -> Factor -> Maybe Int
solveFactor ctx factor = case factor of (Num n) -> (Just n)
                                        (Var s) -> getValue ctx s
                                        (Brack exp) -> solveExp ctx exp

main = do
       s <- getContents
       mapM putStrLn $ (map (show . pull . (solveExp createContext) . synt . alexScanTokens) . lines) s

Здесь мы объявляем тип Context, который содержит ассоциотивный массив (Map) с именами переменных и их значениями, функцию pull, которая возвращает значение переменной, если оно есть, иначе поднимает ошибку. Функция createContext просто создает пустой контекст, getValue ищет значение переменной в контексте. Теперь самое интересное! Чтобы понять, что здесь происходит, представим, что строчка нашего кода такова:

8

Тогда дерево парсинга будет таково:

let res = Exp (Exp1 (Term (Num 8)))

а результат (т. е. 8) будет после

((solveFactor ctx) <- (solveTerm ctx) <- (solveExp1 ctx) <- (solveExp ctx)) res

Это не код на Haskell, а схема: solveExp передаст res solveExp1 и т. д.
ctx здесь — это просто некий контекст.

Т. е. работа функции solveExp заключается в том, чтобы если ей на вход идет конструкция let-in добавить переменную в контекст и вычислить Exp после in, иначе просто вычислить Exp1.
Функция solveExp1 складывает или вычитает, solveTerm — умножает и делит. solveFactor достает значения переменных, возвращает числа, а если ей на вход идет Exp в скобках — передает его solveExp (не опять а снова).

Функция main берет с stdin строки до EOF, разбивает их на список строк, выделяет в каждой токены (alexScanTokens), прогоняет через парсер (synt), вычисляет значение выражения (solveExp) с пустым контекстом (createContext), и делает из Maybe Int Int, а затем String, после чего выводит результат.

Все! Теперь точно все! Компилируем все, и наш интерпретатор готов! Отзывы, замечания, предложения — прошу в комментарии.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335366/


Метки:  

[Перевод] Почему я до сих пор использую Vim?

Четверг, 10 Августа 2017 г. 17:59 + в цитатник
Vim — мой любимый редактор. Я начал его использовать много лет назад, когда перешел на Linux. Он пришелся мне по душе, так как я мог редактировать небольшие исходные файлы на своем четырехъядерном компьютере без необходимости долго ждать, пока он откроется.

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

Как вы думаете, сколько памяти нужно редактору, чтобы открыть следующий C файл?

#include 
int main() {
  printf("Hello, world!\n");
}

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


А вот и ответ:

1*ZdqL3eJXV4v-ZlkDKJIlNgРедактору Code для открытия 60-байтного кода потребуется 349 мегабайт! Atom потребуется 256 мегабайт. А вот Vim нуждается всего в 5 мегабайтах.

Я также включил Nano, чтобы сравнить его с Vim и результат получился меньше чем 1 мегабайт.

Как насчет больших файлов? Открытие 6-мегабайтного XML-файла в Vim потребляет около 12 мегабайт. Nano практически на ровне с Vim. Code нуждается в 392 мегабайтах, а Atom в 845 мегабайтах!

1*UoLGhJjMeCbXfL0rBpcfBwВремя запуска


Давайте рассмотрим сколько времени требуется редакторам для открытия того же файла XML, а после открытия перемести курсор в конец файла. Atom и Code потребуется почти 20 секунд. Vim выполнит задачу за 4 секунды. Sublime меня приятно удивил, открыв всего лишь за секунду. Быстрее всех был Nano.


1*nWL-IyPzxygwIKBkhvuzQAВыполнение поиска и замена 100 000 слов, в том же XML файле показали достаточно неожиданные результаты. Nano и Atom потерпели неудачу, так как для выполнения задачи потребуется почти 10 минут. Atom завис несколько раз, перед тем как получить результат. Code выполнил задачу за 80 секунд, Sublime за 6 секунд. Vim справился за 4 секунды.

1*9m9YNUPgQWRgk-6dtlSFMgПечально смотреть на то, когда редактор потребляет всю вычислительную мощность и память, которые доступны на «современном» дорогостоящем ноутбуке.

Библиотека видеоматериалов по Vim, здесь вы можете познакомиться с программистами работающими на VIM и посмотреть как он работает.
Какой из перечисленных редакторов чаще всего используете вы?

Проголосовало 490 человек. Воздержалось 119 человек.

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

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335364/


Метки:  

[Из песочницы] Исследование соответствия интернет-магазинов закону 152 ФЗ «О персональных данных»

Четверг, 10 Августа 2017 г. 17:20 + в цитатник
Исследование соответствия интернет-магазинов закону 152 ФЗ «О персональных данных" проведено некоммерческим сайтом 152rf.com. Как известно, в случае если ваш сайт обрабатывает персональные данные россиян, вам необходимо предупреждать об этом ваших пользователей. Если на сайте не будет галочки «Согласие на обработку персональных данных», либо не будет «Политики конфиденциальности», владелец сайта может получить достаточно крупный штраф, в зависимости от найденных нарушений. В данном исследовании было проверено 36 750 российских интернет-магазинов.

Нарушения и соответствующие им штрафы:

  • обработка данных без согласия пользователя: штраф для юридических лиц – от 15 до 75 тысяч рублей, для должностных лиц – от 10 до 20 тысяч рублей;
  • политика обработки персональных данных недоступна: штраф для юридических лиц – от 15 до 30 тысяч рублей, для должностных лиц – от 3 до 6 тысяч рублей;
  • база данных находится на зарубежном хостинге: штраф от 30 до 75 тысяч рублей.
  • Также, нередки случаи, когда сайт по каким-либо причинам попадает в черный список Роскомнадзора.
  • Интернет-магазины были проверены на соответствие следующим правилам:
  • наличие на сайте согласия на обработку персональных данных;
  • наличие на сайте политики конфиденциальности;
  • нахождение хостинга сайта на территории РФ;
  • наличие сайта в черном списке Роскомнадзора.

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

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

image

Как видно из диаграммы, лишь 52% интернет-магазинов предупреждают своих пользователей об использовании их персональных данных. Между тем, штраф за данное нарушение может достигать 75 тысяч рублей.

Затем интернет-магазины были проверены на наличие «Политики конфиденциальности».

image

В соответствии с результатами исследований, лишь 30% интернет-магазинов соблюдают закон РФ об обязательном наличии «Политики конфиденциальности» на сайте, обрабатывающем персональные данные россиян.

Кроме того, интернет-магазины были проверены на одно из самых серьезных нарушений закона 152ФЗ РФ «О Персональных данных», а именно – расположение хостинга за пределами территории РФ.

image

Оказалось, что лишь 57% интернет-магазинов размещены на российских хостингах, а остальные 43% нарушают закон и могут быть оштрафованы на сумму до 75 тыс. руб.

В завершении, интернет-магазины были проверены на наличие их в черном списке Роскомнадзора. Фактически наличие сайта в черном списке является крахом для проекта, так как 99% пользователей не смогут посетить его.

image

К счастью, интернет-магазинов, которые находятся в черном списке Роскомнадзора, всего 2%.
Как видно из всего, сказанного выше, забота о персональных данных россиян — это большая ответственность. Законы о персональных данных появляются в последнее время во всех странах мира. Россия не является исключением и тоже следует данному тренду. Чтобы следовать тенденции, необходимо тщательно следить за соблюдением новых законов РФ.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335360/


Метки:  

Как я написал мобильное приложение на react-native

Четверг, 10 Августа 2017 г. 17:07 + в цитатник
Меня зовут Алексей Андросов, я уже много лет работаю в Яндексе фронтенд-разработчиком. Два года назад мне и моим партнерам пришла в голову идея создать мобильную социальную сеть Verb. Идея Verb в том, что пользователи могут делиться небольшими статусами — “вербами” — о том, чем они занимаются в данную минуту, простыми вещами, о которых хочется рассказать друзьям, но некуда об этом написать.
И мы уже даже получили инвестиции, но сейчас не об этом. Сегодня я хочу рассказать о том, как и почему я написал мобильное приложение на react-native.

У меня есть бэкграунд бекенд-разработчика, более 10 лет опыта веб-разработки, но создание мобильного приложения для меня было абсолютно новой областью. Что было делать в такой ситуации? Быстро изучить Objective-C или Swift для iOS и Java для Android? Параллельно писать два приложения сразу показалось плохой идеей, я один явно не смог бы быстро реализовывать все идеи на двух платформах. Поэтому я начал искать варианты для кроссплатформенной разработки.

Как раз кстати пришлась шумиха вокруг React, появился react-native. Тогда мне и захотелось его попробовать. Оглядываясь назад, выбор на react-native пал, по большому счету, не из-за каких-то объективных причин, а скорее из-за субъективных:
до него уже были PhoneGap (WebView на JavaScript, CSS, HTML), Xamarin (C#) и NativeScript (JavaScript, TypeScript, Angular).
Опыт работы с PhoneGap у меня уже был и использовать его не хотелось (уже очень подкупали нативные компоненты вместо их реализации на веб-технологиях), C# я не знал, писать на Angular не хотелось, так что выбор пал на RN.
Как и NativeScript, RN имеет биндинги нативных компонент в JS, схожую систему работы (об этом поговорим позже) и возможности.

Первой версией, с которой мы начали, стала 0.7.1 (текущая версия — 0.46), первый мой коммит 21 июля 2015. Поддержки Android тогда не было совсем. Она появилась только в сентябре 2015 (0.11). При этом это была “первоначальная поддержка” платформы с кучей проблем и недоработок. Пройдет еще много времени до того, как поддержка iOS и Android станет более-менее равноценной в react-native.

Забегая вперед, скажу, что Android-версию мы в какой-то момент все же решили писать на Java. Приложение уже было нужно, а RN в тот момент оказался не готов (на текущий момент такой проблемы уже нет). А вот iOS-версия Verb полностью написана на react-native.

Что такое react-native?


Итак, react-native – это фреймфорк для разработки на react кроссплатформенных приложений для iOS и Android. React здесь используется именно как идея, а не реализация: JSX, компонентный подход, state, props, жизненный цикл компонентов, CSS-in-JS.

Если проводить аналогию с обычной веб-разработкой, то тут:
  • нет HTML, но есть нативные компоненты в JSX (, , )
  • нет CSS. Все стили пишутся CSS-in-JS, layout строится на полифиле для flexbox (при этом он немного отличается от стандарта, например, flex-direction по-умолчанию column, а не row).
  • нет привычного DOM API. Никаких window, document и всего подобного. Из привычных API только GeoLocation API (navigator.geolocation) и XHR

Верстка компонент выглядит примерно вот так:

render() {
    return (
        
            
                icons/close.png') } resizeMode="cover"/>
            
            
                { myText.join(', ') }
            
            }
            />
                {this.props.children}
            
        
    );
}

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


CSS выглядит более привычным:

const styles = StyleSheet.create({
    default: {
        fontSize: PixelRatio.getPixelSizeForLayoutSize(7),
        color: 'rgba(0, 0, 0, 0.60)'
    },
    
    suggestUser: {
        height: PixelRatio.getPixelSizeForLayoutSize(100),
    
        backgroundColor: '#FFF',
        shadowColor: '#000',
        shadowOffset: {
            height: -5
        },
        shadowRadius: 5,
        shadowOpacity: 0.5
    }
};


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

Как работает RN


Если прекрасная статья от Tadeu Zagallo про кишки RN, я вам вкратце расскажу ее суть.

В iOS есть три треда:
— shadow queue — очередь обработки и отрисовки layout
— main thread — тут работают компоненты
— JavaScript thread — тут работает JS

Общая схема работы выглядит так: исполняется JS (по сути React), результат работы надо передать в нативный код. Для этого есть специальный мост, который с помощью JSON передает набор инструкций. RN их исполняет и отрисовывает нативные компоненты платформы. Результат работы через тот же мост может вернуться обратно в JS.

image

Все общение асинхронное. При этом самым узким местом является непосредственно мост, сериализация и десериализация данных. Отсюда интересные особенности:
  • Отправлять большие пачки данных JS<->native — плохая идея, будет тормозить
  • Делать большие действия на JS тоже плохая идея. Это будет лочить треды и тормозить отрисовку, никаких 60fps не получится.
  • Делать частые действия (например, анимацию или контроль скролла) на JS тоже не получится, будет тормозить.

Итого, общее правило: не надо забывать, что мы работает с нативным кодом, а не JS. Все, что можно сделать native, должно быть native.

Write once, run everywhere?


Не тут-то было ). На самом деле парадигма звучит так: learn once, write everywhere.
Почему так получается? Все нативно, поэтому забудьте про полную кроссплатформенность. Платформы разные, поэтому и нативные компоненты разные. У них разная логика работы и механика взаимодействия. В основном это касается компонентов навигации и взаимодействия с пользователем. Поэтому в начале разработки имеет смысл сразу накидать болванку приложения с базовыми экранами и переходами. На этом разница заканчивается, все внутренние компоненты скорее всего окажутся одинаковыми. Удобство добавляет и сам RN, весь платформоспецифичный код можно разделять на файлы component.ios.js и component.android.js, тогда для каждой платформы будет собираться своя версия без всяких if внутри.

iOS версия Verb изнутри


Изнутри приложение написано на react-native + redux. Redux пригодился, кстати, не только, как хорошая библиотека для организации работы с состоянием приложения, но и для общения между компонентами. RN провоцирует писать pure компоненты без сайд-эффектов или использования глобальных объектов, поэтому общение компонентов через общий state является чуть ли не единственным нормальным способом.

Плагины:
  • React-native-deprecated-custom-components — я использую старый Navigator, т.к. еще не переехал на новый react-navigation из-за кучи багов
  • React-native-device-info — информация про UUID, версию и локаль устройства
  • React-native-fbsdk — мост в FBSDK
  • React-native-imagepicker — моя собственная обвязка над ActionSheetIOS, CameraRoll и ImagePickerIOS для загрузки фоток
  • React-native-l20n — локализация с помощью l20n
  • React-native-linear-gradient — реализация градиентов
  • React-native-pagecontrol — мой биндинг в UIPageControl
  • React-native-photo-view — простенькая библиотека, чтобы сделать полноэкранный просмотр фоток
  • React-native-svg — биндинг в svg
  • React-native-vkontakte-login — мост в VKSDK


Статистика:
  • react-native-fabric — мост в Fabric и Crashlytics
  • React-native-google-analytics-bridge — мост в GA
  • React-native-sentry — сбор крешей и отправка в собственную инсталляцию Sentry
  • React-native-bugsnag — мост в BugSnag

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

Так же мы используем геолокацию и пуши. В react-native для этого есть все необходимое.

Важная часть — производительность. Как я уже писал, узким местом в RN является мост JS<->native, поэтому проблема уменьшения количества перерисовок становится во весь рост. Отсюда следует, что все советы и best practice от react и redux имеют очень большое значение. React.PureComponent или shouldCompomentUpdate, меньше connect-компонентов, плоские структуры данных, иммутабельность — все дает хороший прирост производительности.

Неочевидные советы


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

Унификация react-компонент (тут понадобится помощь дизайнера) позволяет очень быстро разрабатывать новые экраны. Вообще, компонентный подход и быстрое связывание компонент — это хорошая фишка как react, так и react-native.

boilerplate для создания новых экранов в rn + redux достаточно большой. Как и в react+redux, так и rn+redux придется написать много кода для создания нового экрана: создать компонент экрана, зарегистрировать его в Navigator, написать actions и reducer для перехода на экран. Плюс к этому стандартный boilerplate для обработки данных для нового экрана.

Не надо все писать на JS. Приложение надо писать максимально близко к native, искать биндинги в нужные native-компоненты или писать их самим. Уверяю, это совсем не сложно.

Надо участвовать в сообществе. В RN достаточно багов и недоработок, но нет никаких проблем их поправить. Мейнтейнеры активно участвуют в PR. Правда, зачастую приходится исправлять баги в самом native-коде, так что Java или Objective-C придется подучить. Все мои PR приняли. Например, я исправил несколько багов в работе камеры или загрузке фотографий на сервер.

Заключение


Писать на react-native оказалось удобно, быстро и приятно. Он правда позволяет быстро создавать прототипы приложений и доводить их до релиза. Технология молодая, поэтому есть типичный проблемы early adopters (например, периодические несовместимые изменения). Но с каждый релизом RN становится все лучше и стабильнее, Facebook прилагает к этому много усилий и делает на него ставку. К текущему моменту часть приложения Facebook уже написано react-native, а поддержка Android достигла уровня iOS.

Я достаточно поработал с технологией и могу сказать, что написать не слишком большое iOS-приложения, аналогичное Twitter или Instagram, вполне реально. К сожалению, глубоко попробовать android так и не получилось, поэтому утверждать не могу, но, надеюсь, что в будущем можно будет попробовать конкурировать с нашей нативной iOS-версией.

А еще мы ищем удаленного разработчика на частичную занятость! Пишите на doochik@ya.ru.

Полезные ссылки


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335354/


Метки:  

UI-тесты для iOS: почему нужно поверить в дружбу QA и разработки, но не обольщаться

Четверг, 10 Августа 2017 г. 15:51 + в цитатник

С недавних пор мы взялись за внедрение UI-тестирования в iOS для iFunny. Путь этот тернист, долог и холиварен. Но все равно хочется поделиться с умными людьми своими первыми шагами в этом направлении. На истину не претендуем – всё примеряли к собственному продукту. Поэтому под катом немного информации о том, что такое iFunny на iOS и зачем нам понадобился UI + много фидбека по инструментам и примеров кода.

Что такое iFunny на iOS


iFunny — это популярное в США приложение про юмор и мемы с ежемесячной аудиторией в 10М. Подробнее о том, как все затевалось, можно прочитать здесь. Разработка приложения на iOS стартовала 6 лет назад, и мы до сих пор обходимся без каких-либо революционных вкраплений:
  • 99% кода держим на Objective-C;
  • придерживаемся классического MVC с аккуратными делениями на модули;
  • активно работаем с Cocoapods для зависимостей;
  • используем собственный проигрыватель webm-контента: сторонние решения тормозили, не давали контенту зацикливаться и прочее. В случае с iFunny, который является полностью UGC, эта тема критична;
  • форк от SDWebImage используем не только для картинок, но и для остального загружаемого контента;
  • для API выбираем RestKit – достаточно зрелый фреймворк, за несколько лет работы с которым почти не было проблем.

Unit-тесты


У нас все наоборот: работать — значит мемы смотреть :)

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

- (void)testIsNewFeaturedSetForContentArrayFalse {
    FNContentFeedDataSource *feedDataSource = [FNContentFeedDataSource new];
    NSMutableArray *insertArray = [NSMutableArray arrayWithArray:[self baseContentArray]];
    feedDataSource.currentSessionCID = @"0";
    BOOL result = [feedDataSource isNewFeaturedSetForContentArray:insertArray];
    XCTAssertFalse(result, @"cid check assert");
    feedDataSource.currentSessionCID = @"777";
    result = [feedDataSource isNewFeaturedSetForContentArray:insertArray];
    XCTAssertTrue(result, @"cid check assert");
}


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

- (void)testAllAnalyticParametersClasses {
    NSArray *parameterClasses = [FNTestUtils classesForClassesOfType:[FNAnalyticParameter class]];
    for (Class parameterClass in parameterClasses) {
        FNAnalyticParameter *parameter = [parameterClass value:@"TEST_VALUE"];
        XCTAssertNotNil(((FNAnalyticParameter *)parameter).key);
        XCTAssertNotNil(((FNAnalyticParameter *)parameter).dictionary);
    }
}


Здесь проверяется, что у класса определены 2 статичных метода, key и dictionary, необходимых для правильной работы отправки событий в системы аналитики.

UI-тесты


Мы уже достаточно хорошо изучили работу с UI-элементами и поразмышляли над тестовым окружением в процессе написания тестов для Android. Получилось примерно так:
  • отдельный flavor для запуска приложения с предварительными настройками, чтобы не задавать их вручную в тестах каждый раз;
  • моки для API с использованием WireMock, чтобы каждый раз не лезть за ответами на сервер и не зависеть от него;
  • поигрались с процессом запуска тестов и настроили на CI Bitrise достаточно удобный флоу, в ходе которого тесты заливаются и запускаются на реальных девайсах в Amazon Device Farm, отчеты со скриншотами и видео мы можем посмотреть там же, перейдя по ссылке из Bitrise.

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

Пришла очередь iOS, и мы, команда QA и iOS-разработчики, начали с того, что еще раз собрались и аргументировали для себя, зачем нам нужны автотесты. Это был важный ритуал, и действовал он почти как мантра:
  • уменьшить объем ручных проверок;
  • автоматизировать регресс;
  • обеспечить постоянное тестирование приложения, чтобы в любой момент времени знать, в каком состоянии оно находится.


Инструменты


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


Appium – популярный кроссплатформенный фреймворк. Бытует мнение, что именно он станет стандартом в тестировании мобильных приложений в ближайшем будущем. Несколько месяцев назад мы решили потестить его как с полгода вышедшей iOS 10, но немного огорчились: версия Appium с ее поддержкой была в бете, а использовать в проде нестабильную версию не очень хотелось. Appium Inspector, который работает на Android, тоже использовать не смогли: не было поддержки Xcode 8 и iOS 10. Вскоре они выпустили stable-версию, но ждать полгода после обновления оси для нас крайне нежелательно. Решили не мучить ни себя, ни Appium.


Calabash – кроссплатформенное open source решение, которое использует подход BDD в написании тестов и до последнего времени поддерживалось компанией Xamarin. Недавно разработчики сообщили, что поддержка – всё. Мы тоже решили дальше не идти.


И, наконец, XCTest – нативный фреймворк от Apple, который мы в итоге выбрали. Поэтому почитайте про плюсы:
  • нет лишних зависимостей, которых у нас в проекте и так много;
  • кроме самого Apple, никто со стороны не принесет и не добавит багов. У нас уже был опыт с Appium и KIF. Получалось так, что внизу все равно используется XCTest и баги Apple накладываются на баги KIF, а это значит садись, дружок, и ковыряй большие фреймворки. Эти зависимости нам точно были не нужны;
  • можно использовать стандартные языки iOS-разработки Objective-C и Swift: QA могут легко взаимодействовать с разработчиками;
  • тестируемое приложение – это черный ящик, кроме того, в тесте можно работать с любым приложением в системе.

Потом рассмотрели еще и Recorder — нативный инструмент от Apple, который позиционируется как вспомогательный, без надежды на то, что он будет использоваться при написании реальных тестов. С его помощью можно изучить лейблы UI-элементов и поиграться с основными жестами. Recoder сам пишет код и генерирует указатели на объекты, если это не было сделано при разработке. Это единственное преимущество, которое мы смогли выделить. Минусов оказалось гораздо больше:
  • сложно записать тест, потому что UI тормозит – делаешь какое-то действие и ждешь секунд 10-15, чтобы оно записалось. Неудобно;
  • код пишется всегда разный. Сегодня я такой умный и назову этот элемент button[1], а завтра – “smilebutton”. Непонятно;
  • постоянные ошибки в распознавании жестов. Вы можете сделать swipe left, а он определит, что это tap. Делаешь tap, а это уже swipe. Нестабильно;
  • сломанный тест, записанный с помощью Recorder, скорее всего, придется заново полностью переписывать, потому что он не будет отражать реальной ситуации. Просто WTF?!


Разработчик спешит на помощь


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

Черный ящик



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

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

xcrun simctl uninstall booted ${PRODUCT_BUNDLE_IDENTIFIER}


C Environment-переменными мы работаем так:

app = [[XCUIApplication alloc] init];
app.launchEnvironment = @{
                          testEnviromentUserToken  : @"",
                          testEnviromentDeviceID   : @"",
                          testEnviromentCountry    : @""
                          };
app.launchArguments = @[testArgumentNotClearStart];


В тесте создается объект приложения и в поля launchEnviroment и launchArguments записывается словарь (или массив) с настройками, которые нужно передать в приложение.
В приложении настройки и аргументы считываются в делегате при самом старте приложения в методе:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

Так у нас выполняется обработка:

NSProcessInfo *processInfo = [NSProcessInfo processInfo];

[FNTestAPIEnviromentHandler handleArguments:processInfo.arguments
                                 enviroment:processInfo.environment];


Класс TestAPIEnvHandler реализует обработку словаря настроек и массива аргументов.

Свойства элементов


Когда мы начали работать с ХСТest для UI, возникла проблема: стандартный набор инструментов не дает считывать шрифты и цвета.
Мы можем работать только с жестами для элементов, но не можем читать текст, который в них записан, брать их позицию или другие интересные для UI-тестирования свойства.
После поиска альтернативных решений мы посмотрели в сторону Accessibility API, с помощью которого работают UI-тесты.

В качестве “моста” между тестом и приложением решили использовать accessibilityValue, который есть у каждого видимого элемента из iOS SDK.
Поехал велосипед, и получилось такое решение:
  1. В accessibilityValue записываем json-строку.
  2. В тесте читаем и декодируем.
  3. Для UI-элементов пишем категории, которые определяют набор необходимых нам в тестах полей.

Вот пример для UIButton:

@implementation UIButton (TestApi)

- (NSString *)accessibilityValue {
    NSMutableDictionary *result = [NSMutableDictionary new];
    UIColor *titleColor = [self titleColorForState:UIControlStateNormal];
    CGColorRef cgColor = titleColor.CGColor;
    CIColor *ciColor = [CIColor colorWithCGColor:cgColor];
    NSString *colorString = ciColor.stringRepresentation;
    if (titleColor) {
        [result setObject:colorString forKey:testKeyTextColor];
    }
    return [FNTestAPIParametersParser encodeDictionary:result];
}

@end


Чтобы прочитать accessibilityValue в тесте нужно обратиться к ней, для этого у каждого объекта XCUElement есть поле value:

XCUIElement *button = app.buttons[@"FeedSmile"];
NSData *stringData = [button.value dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:stringData options:0 error:&error];


Пользовательские взаимодействия


Проблема жестов и экшенов решается (о чудо!) самим инструментом, благодаря большому набору стандартных методов – tap, double tap. Но в нашем приложении есть не только стандартные, но и очень нетривиальные вещи. Например triple tap, свайпы по всем осям в разные стороны. Чтобы это решить, мы использовали те же стандартные методы, конфигурируя параметры. Большой занозой это не оказалось.

Пример простого теста с использованием подхода:



  • запускаем iFunny с определенными настройками;
  • выбираем страну;
  • выбираем нужного пользователя;
  • указываем доп.настройки (первый ли это запуск приложения или нет);
  • проверяем открытие ленты и загрузку контента;
  • делаем смайл;
  • проверяем через UI засмайлен ли контент (изменилось состояние кнопки). Продолжаем скролить;
  • смотрим мемасики и радуемся жизни.


- (void)testExample {
    XCUIElement *feedElement = app.otherElements[@"FeedContentItem"];
    XCTAssertNotNil(feedElement);
    XCUIElement *button = app.buttons[@"FeedSmile"];
    [button tap];
    [[[[XCUIApplication alloc] init].otherElements[@"FeedContentItem"].scrollViews childrenMatchingType:XCUIElementTypeImage].element tap];

    NSDictionary *result = [FNTestAPIParametersParser decodeString:button.value];
    CIColor *color = [CIColor colorWithString:result[testKeyTextColor]];
    XCTAssertFalse(color.red    - 1.f   < FLT_EPSILON &&
                color.green  - 0.76f < FLT_EPSILON &&
                color.blue   - 0.29f < FLT_EPSILON,
                @"Color not valid");
    XCUIElement *feed = app.scrollViews[@"FeedContentFeed"];
    [feed swipeLeft];
    [feed swipeLeft];
    [feed swipeLeft];
}


Мы не планировали делать полное тестовое покрытие, поэтому на этом наши эксперименты пока закончились. Стало ясно, что если мы когда-то решимся полноценно внедрить автотесты в процесс, использовать будем XCtest, но сейчас заниматься этим на постоянной основе очень трудозатратно. И вот почему:
  • все равно придется изобретать велосипеды;
  • QA не сможет в полном объеме тестировать приложения без разработчиков;
  • UI-тесты для нашей продуктовой разработки – это лухари функционал и применять его получается только в исключительных случаях.

P.S. При съёмке превью ни один баг не пострадал. Семён продолжает вдохновлять команду QA.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335328/


Не думай о минутах свысока

Четверг, 10 Августа 2017 г. 15:47 + в цитатник
Широкое распространение облачных сервисов не обошло стороной и такую традиционную услугу как «виртуальный частный/выделенный сервер – VPS/VDS. Современное решение в сфере хостинга – «облачный VPS» (Cloud VPS) с гибкой системой пользования ресурсами и гибкой схемой оплаты. Клиент платит только за пользование услугой и согласно установленному для определенного объема ресурсов тарифу. Он самостоятельно определяет и задает объем ресурсов для своего сервера, которые требуются в данный момент для решения его задач. Пользователь создает себе сервер с нужными характеристиками и может в любое время изменить объем потребляемого ресурса, временно приостановить работу сервера, создать второй сервер и т.д.


Облачный хостинг – это виртуальные машины (ВМ) в облаке или IaaS (инфраструктура как сервис). При таком хостинге физические серверы объединяются в кластер, а системы хранения – в сеть хранения данных (SAN). В совокупности все это образует пул гибко выделяемых клиентам ресурсов. Таким образом, при облачном хостинге задействованы сразу несколько серверов, ресурсы которых равномерно распределяются по нагрузке.

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

Понять разницу между видами хостинга поможет следующая таблица:
Модель
Инфраструктура
Масштабируемость
Для чего лучше всего подходит
Ценообразование
VPS
Физический сервер, используемый ограниченным числом пользователей. Общая среда.
Масштабируется «вручную» посредством запроса к провайдеру.
Сайты с предсказуемым трафиком
Оплачиваются прописанный в договоре ресурсы, ежемесячно или ежегодно. Требуются контракты.
Выделенный сервер
Физический сервер, используемый одним клиентом / пользователем. Изолированная среда.
Не модернизируется. Если пользователь нуждается в увеличении ресурсов, нужно получить другой пакет, определенный поставщиком, даже если он не оптимален для ваших нужд.
Высоконагруженные веб-приложения
Оплачиваются необходимые ресурсы — ежемесячно или ежегодно. Требуются контракты.
Облачный сервер
Распределенные ресурсы на нескольких физических серверах. Изолированная виртуальная среда.
Быстрое самостоятельное администрирование и развертывание (несколько кликов), масштабирование за несколько секунд, нулевые простои.
Широкий спектр задач
Оплачиваются ресурсы, которые самом деле используются. Оплата обычно почасовая. Не требуется контрактов.



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

Что такое тариф «За ресурсы» от RUVDS и как он работает?


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

Минимальная оплата, которая будет взиматься с клиента, это разовый установочный платеж в размере 30 рублей, а также полная оплата выделенного дискового пространства и адреса IPv4 согласно тарифу.

Итак, тариф «За ресурсы» за 1 минуту использования:
Тип ресурса/услуги
Цена в рублях
Тарификация
Установочный платеж
30
единоразово
1 МГГц
0,000008
поминутно
1 Мб RAM
0,000006
поминутно
1 Мб, прочитанный с диска
0,002
поминутно
1 Мб, записанный на диск
0,003
поминутно
1 Мб, HDD
0,00000007
поминутно
1 Мб, SSD
0,00000025
поминутно
1 IOPS
0,001
поминутно
1 Мб исходящего трафика
0,001
поминутно
1 Мб входящего трафика
0,001
поминутно
1 Мб исходящего защищенного от DDOS трафика
0,001
поминутно
1 Мб входящего защищенного от DDOS трафика
0,0035
поминутно
1 IPv4 адрес
0,0025
поминутно

Для примера рассмотрим конфигурацию:

  • 10 ядер 2,2 ГГц
  • 10 Гб RAM
  • 50 Гб HDD
  • 1 IPv4 адрес

По стандартному тарифу RUVDS месяц работы с таким сервером стоит 2 475 рублей. При работе же с данным сервером по тарифу «За ресурсы» минимальный платеж составит 535,95 рублей в месяц, плюс 30 рублей единовременно за установку. Минимальный платеж складывается из оплаты за место на жестком диске и IPv4 адреса(ов) в аренде.

Таким образом, клиент получает:

  • Мощный вычислительный ресурс.
  • Значительную экономию средств за счет тарификации реально потребленных ресурсов в каждую минуту и отсутствия платежей за простой сервера.
  • Прозрачную тарификацию.
  • Легкую и быструю масштабируемость — от сервера до вычислительного кластера и обратно.

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



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

Тарифы на облачные VPS с поминутной оплатой уже предлагают YourHost, NetPlace, 1сloud, Lioo.ru, ForeverHost, HosterProf, Tvoi-host.ru, LX-host.net, EU-host.ru и некоторые другие хостинг-провайдеры. Теперь к ним присоединился и RUVDS.

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

Преимущества предложения RUVDS — низкая цена в сравнении с аналогами на российском рынке, наличие двух дата-центров — в Москве и в Европе, так что клиенты могут выбирать «место дислокации» своих VPS, новейшее оборудование от Huawei, используемое в качестве серверной платформы. Наконец, стоимость лицензии на ОС Windows включена в цену сервера VPS, а это дополнительная экономия.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335350/


Метки:  

[Из песочницы] Основные ошибки accessability при разработке сайта

Четверг, 10 Августа 2017 г. 15:43 + в цитатник
Приветствую!

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

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

Картинки и атрибут ALT


Самой распространенной ошибкой многих web мастеров является неиспользование атрибута alt="" в теге или неправильное его использование.

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

  • Использование одного и того же слова для разных картинок (alt=«image»);
  • Использование не несущего смысла набора символов (alt=«dsf86sdfgbvc94nf56»);
  • Дублирование заголовка страницы;
  • Размещение в атрибуте целого предложения, словосочетания;
  • Указание в атрибуте одной буквы, зачастую не являющуюся даже первой буквой названия предмета на изображении.

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

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

В этом случае самым верным решением будет у каждой аватарки в атрибуте alt="" вывести имя с фамилией пользователя. Таким образом, с точки зрения графического отображения, ничего не изменится, а незрячий посетитель сможет найти нужного человека.

Заголовки


Всем отлично известны теги заголовков с

по

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

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

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

Таким образом, при нажатии стрелки вниз на слишком длинном заголовке, программа озвучивает на двух строках «Заголовок уровня 1-6».

Всплывающий подсказки


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

Решение очень простое, достаточно использовать у ссылок атрибут title="", но никак не использовать скрипты.

Примечание: есть непроверенная информация, что на планшетах атрибут title не озвучивается, но в статье речь идет в первую очередь о программах экранного доступа для Windows: Jaws и NVDA.

Таблицы и табличная верстка


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

Основные ошибки при использовании таблиц:

  • Вложенность одной или нескольких таблиц в другую очень затрудняет навигацию, так как скринридер читает координаты каждой ячейки;
  • Использование тега там, где он не требуется. Примером может выступить скрипт игр «Ogame», «2moons», «Supernova» и подобных;

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

Роли и метки


Наверное самое известное из accessability — это роли и метки.

Атрибут role="" обычно прописывают в блоках
, но с приходом HTML5 надобность прописывания ролей в блоках исчезла.

В таблице представлен список ролей и заменяющих тегов из HTML5.

Роль Заменяющий тег Представление скринридером
banner
Банер ориентир
navigation Навигация ориентир
main
Основной ориентир
complementary Добавочный ориентир
contentinfo
Информация о содержимом ориентир
search - Поиск ориентир

Как видно из таблицы, в HTML5 нет альтернативного тега для роли «search», ну или я ее не знаю.

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

В этом случае выручает атрибут area-label="".

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

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

Как по мне, например, роль «banner» вообще только мешается, так как всем понятно, что сверху шапка, а не подвал.

Капча


Напоследок хотелось бы затронуть тему капчей.

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

  • капча представлена текстовым арифметическим примером с просьбой ввести ответ;
  • В форме используется виджет Recaptcha от Google, в котором необходимо просто отметить флажок;
  • если используется графическая картинка, то у нее должен быть атрибут alt, желательно alt=«captcha» или alt=«картинка с кодом».

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

На этом все


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

Если у кого-то остались еще какие-либо вопросы, охотно постараюсь ответить на них в комментариях.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335352/


Метки:  

Dagaz: Шажки

Четверг, 10 Августа 2017 г. 15:17 + в цитатник
image — Давненько не брал я в руки шашек!
        — говорил Чичиков, подвигая тоже шашку.
— Знаем мы вас, как вы плохо играете!
        — сказал Ноздрев, выступая шашкой.
 
Николай Васильевич Гоголь «Мёртвые души» 

Я очень смутно помню диалектику Гегеля, которую нам давали в институте. Обычно, неудержимая сонливость побеждала меня в самом начале лекций. Помню только, что-то говорилось о том, что «история развивается по спирали». Вроде бы это связывалось с принципом «отрицания отрицания». Я не вполне уверен в универсальности этого закона, но в отношении меня он выполняется. Сколько себя помню, я снова и снова делаю одно и тоже. Это мой способ стать лучше. Как бы там ни было, я вновь делаю шашки. И это здорово!

Как я уже неоднократно говорил, шашки — это сложно! Сами шашечные игры возможно и проще Шахмат (хотя сравнивать их не совсем корректно, игры принципиально разные), речь не о том. Реализация шашек гораздо сложнее! Если Шахматы «подложили свинью» с каскадными ходами (рокировка), то в играх шашечного семейства имеется сразу две ещё более сложных «опции»:

  • Приоритеты и ...
  • Составные ходы!

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




В этой партии (позиция взята из книги Ю.Барского и Б.Герцензона «Приключения на шашечной доске»), белые не просто жертвуют фигуры, вынуждая противника ходить определённым образом. Они пользуются тем, что чёрные обязаны выполнить все взятия и (в это время) свободно перемещают по доске свои фигуры, подготавливая финальную ловушку. Своими ходами белые создают «роздых» и это превосходная иллюстрация того, насколько красивой может быть позиционная игра в шашках.

К слову сказать
Взятия в шашках не всегда были строго обязательными. И в русских шашках и в английских и даже в ещё более раннем Алькуэрке существовало "правило гнева", позволявшее забрать «зевнувшую» фигуру, не выполнившую взятие. Такое действие не считалось ходом и называлось «взять за фук» (Huffing — в «Английских шашках»). Я ещё застал это правило в раннем детстве, но похоже, история уже вынесла окончательный приговор.

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

Для меня, приоритеты — это, прежде всего, оптимизация. В самом деле, используя "фирменную магию" Dagaz, я могу запретить выполнение любых ранее сформированных ходов на стадии пост-обработки (именно так я и поступаю в шахматных играх). Более того, я могу изменять сгенерированные ходы и даже добавлять к ним новые. Но всё это ценой памяти и времени (а когда за дело берётся UCT-бот, и то и другое становится весьма критично). Производительность, в моём случае, это не столько интерактивность, сколько «разумность» компьютерного оппонента. Работая быстрее, бот успеет разобрать большее количество позиций!

В случае шашек, генерация ходов сводится к двум возможным ситуациям. Когда взятий нет — «тихих» ходов не так много. Всё меняется когда взятия появляются. Поскольку я генерирую все составные ходы целиком, в дело включается комбинаторика. Например, вот в этом тесте, заурядная позиция с дамкой генерирует 42 возможных хода! И этих ходов было бы гораздо больше, если бы по правилам "Турецких шашек" я не отфильтровывал ходы со взятием максимального количества фигур! Добавление к этому списку ещё и «тихих» ходов, с их последующей фильтрацией в пост-обработке, было бы пустым расточительством.

Здесь-то я и словил первый нетривиальный баг



Gauntlet — очень динамичная и довольно интересная шашечная игра. Разработал её Phillip L.Leduc в 1980 году. Игра ассиметрична. Белым необходимо прорваться (хотя бы одной фигурой) на последнюю горизонталь. Чёрные — стараются не допустить этого. Взятия аналогичны шашечным, но, поскольку все фигуры двигаются только в одном направлении, полноценная реализация составных ходов не требуется (кстати, есть ещё одна, традиционная гавайская игра, со сходным механизмом взятия). Приоритеты, в этой игре, напротив, используются, поскольку взятия обязательны и это важная составляющая игры.

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

Всё дело вот в этом коде
var priors = [];
_.chain(_.keys(this.pieces))
 .filter(function(pos)  
    { return Dagaz.Model.sharedPieces || 
             Dagaz.Model.isFriend(this.pieces[pos], this.player); 
    }, this)
 .each(function(pos) {
     var piece = this.pieces[pos];
     _.chain(design.pieces[piece.type])
      .filter(function(move) { return (move.type == 0); })
      .each(function(move) {
          var g = Dagaz.Model.createGen(move.template, move.params, this.game.design);
          g.init(this, pos);
          addPrior(priors, move.mode, g);
      }, this);
  }, this);
...
for (var i = 0; i <= design.modes.length; i++) {
     var f = false;
     if (!_.isUndefined(priors[i])) {
         while (priors[i].length > 0) {
            var g = priors[i].pop();
            g.generate();
            if (g.completed && !g.move.isPass()) {
                if (cont && (g.moveType == 0)) {
                    CompleteMove(this, g);
                }
                f = true;
            }
         }
     }
     if (f) break;
     if (i >= design.modes.length) break;
}

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

Ошибка была в том, что я помечал ход как сгенерированный раньше времени, при первом взятии. В результате, генератор видел взятие, помечал ход, а после этого шёл дальше и натыкался на занятое поле, в том месте, где он должен был разместить фигуру. Это приводило к сбросу почти завершённого хода, но поскольку ход был уже помечен, низкоприоритетные «тихие» ходы попросту отбрасывались. После исправления, AI Gauntlet-а стал играть гораздо лучше. Производительность — это важно!

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



Картинка кликабельна. Дважды! За начало отсчёта возьмём средневековые "Алькуэрк" и "Лису и гусей". Похоже, что это первые игры, в которых появилось составное взятие. Идея здесь в том, что выполнив «шашечное» взятие, фигура получает право продолжить ход, взяв ещё одну фигуру. И так, до тех пор, пока есть кого брать.

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

Со стороны другого семейства, произошло одновременно два важных исторических события — отказ от ортогональных перемещений (в пользу диагональных) и использование традиционной шахматной доски (на волне роста популярности Шахмат, это решение самым благотворным образом сказалось на распространении игры). Мы вновь не знаем, где и когда это случилось. Возможно, связующим звеном послужили "Дана" — Филиппинские шашки, сложно сказать.

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




В "Испанских шашках" доска всё также развёрнута на 90 градусов, но здесь появляются «летающие» дальнобойные дамки (простые фигуры по прежнему не могут «рубить» назад). Дамки становятся очень сильными и впервые возникает задача их «ловли».

Каждый шашист должен уметь делать это!
Три дамки ловят одну (при условии того, что она не заняла «большак» — главную диагональ доски). Это интересная задача, для решения которой можно использовать, как минимум, два тактических построения: знаменитый "Треугольник Петрова" и менее известный "Штык Гоняева".




Желающие попрактиковаться могут сделать это здесь.

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

Ещё немного о взятиях
Практически все варианты шашек с дальнобойными дамками (кроме «Турецких» и «Греческих») используют правило "Турецкого удара", также направленное на ограничение мобильности дамок. Суть его в том, что взятые фигуры убираются с доски лишь по завершении хода. Это ограничивает дамку, мешая её перемещениям (разумеется, повторные взятия фигур, в течение хода, запрещены). С этим правилом был связан второй сложный баг текущей итерации.

Я решил поступить просто — переместить все взятия составного хода в его последний частичный ход. Это сработало как и было задумано — фигуры оставались на доске в течение всего хода и удалялись с доски после его завершения. Разумеется, мне пришлось внести изменения в модель, препятствующие повторному взятию фигур (в противном случае, генератор ходов просто зацикливался и ни до какой «магии расширений» дело просто не доходило). К сожалению, я забыл сделать главное — запустить тесты после этого изменения! В результате, я потратил много времени. Логика составных взятий «сломалась» весьма не тривиальным и довольно незаметным образом. Это было внезапно и ужасно. Всё сломалось!

В конце концов, я нашёл решение
ZrfMoveGenerator.prototype.isCaptured = function(pos, level) {
  if (this.parent) {
      return this.parent.isCaptured(pos, level);
  }
  if (_.isUndefined(this.captured)) {
      this.captured = [];
  }
  if (this.captured[pos] && (this.captured[pos] < level)) return true;
  _.each(Dagaz.Model.getDesign().allPositions(), function(p) {
      if (this.captured[p] && (this.captured[p] >= level)) {
          delete this.captured[p];
      }
  }, this);
  this.captured[pos] = level;
  return false;
}

ZrfMoveGenerator.prototype.capturePiece = function(pos) {
  if (Dagaz.Model.deferredStrike) {
      if (this.isCaptured(pos, this.level)) return false;
  }
  this.move.capturePiece(pos, this.level);
  if (!Dagaz.Model.deferredStrike) {
      this.setPiece(pos, null);
  }
  return true;
}

Но сил и времени на это было потрачено очень много. Никогда не забывайте про тесты! И ещё, никогда не делайте вот так:
_.chain(move.actions)
 .filter(function(action) {
      return (action[0] !== null) && (action[1] === null);
  })
 .each(function(action) {
      action[3] = mx;
  });
Последствия будут чудесны, но вряд ли вам понравятся! Не изменяйте поля (пусть даже самые безобидные) внутри коллекции, которую итерируете. Лучше пересоздайте её, пусть она остаётся иммутабельной:

var actions = [];
_.each(move.actions, function(action) {
    var pn = action[3];
    if ((action[0] !== null) && (action[1] === null)) {
        pn = mx;
    }
    actions.push([ action[0], action[1], action[2], pn ]);
});
move.actions = actions;

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

Тем временем, Алькуэрк тоже эволюционировал. Развитие происходило параллельно развитию шашек и почерпнуло из последних такие идеи как ход простых фигур «только вперёд», «летающие дамки» и даже правило «турецкого удара». Получились вполне самобытные и весьма оригинальные игры "Замма" и "Харбага", могу порекомендовать их тем, кто устал от шахматной доски.





Финны сохранили для нас ещё одну древнюю игру

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

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

  if (_.chain(board.moves)
       .filter(function(move) {
           return _.isUndefined(move.failed);
        })
       .filter(function(move) {
           return move.actions.length > 1;
        })
       .filter(function(move) {
           ...
-        }).value().length > 1) {
+        }).value().length >= 1) {
        _.chain(board.moves)
         .filter(function(move) {
             return move.actions.length == 1;
          })
         .each(function(move) {
             move.failed = true;
          });
  }

Венцом развития этого направления игр я считаю мадагаскарскую "Фанорону". Она уже совсем непохожа на шашки, поскольку использует совершенно иной механизм взятия. Общие черты конечно есть — взятие тоже составное. При этом, Фанорона — единственная известная мне игра, в которой цепочку взятий игрок имеет право прерывать (само взятие по прежнему остаётся обязательным)!




Эта игра стала для меня настоящей проверкой на прочность. Здесь было всё: и ломка модели и переписывание контроллера и новые забавные баги. Но всё хорошо, что хорошо кончается. Итерация завершена и я могу с чистой совестью отправляться в отпуск!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335228/


Метки:  

Материализуем результаты поиска, или как мы освободили 25 процессорных ядер

Четверг, 10 Августа 2017 г. 15:15 + в цитатник


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


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


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


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

Что такое метрика


Когда мы начинали разработку okmeter (в тот момент еще не было публичных версий influxdb, prometheus), нам было сразу понятно, что метрики не должны быть "плоскими". В нашем случае идентификатор метрики это словарь ключ-значение (у нас он исторически называется label_set):


{
     "name": "nginx.requests.rate",
     "status": "403",
     "source_hostname": "front3",
     "file": "/var/log/access.log",
     "cache_status": "MISS",
     "url": "/order"
}

Для каждой такой метрики у нас есть значения, привязанные к определенным моментам времени (временной ряд).


Как мы храним метрики


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



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


Запись метрик


Когда от агента, установленного на сервере клиента, приходит пачка метрик, на сервере для каждой метрики происходит примерно следующее:


  • Вычисляем metric_key, проверяем, есть ли эта метрика в хранилище метаинформации (C*)


  • Регистрируем новую, если нужно (записали в C* и ES)


  • Поднимаем updated_ts и вычисляем, пора ли его обновить (обновляется раз в 12 часов, ради снижения нагрузки на индексацию в ES)


  • Если пора – обновляем updated_ts в C* и ES


  • Пишем значение в metric_storage

Чтение метрик


У нас есть 2 основных источника запросов на чтение метрик: запросы пользователей на отрисовку графиков и система проверки триггеров. Такие запросы представляют собой некие выражения на нашем dsl:


top(5, sum_by(url, metric(name=“nginx.requests.rate”, status=“5*”)))

Это выражение содержит:


  • "Селектор" метрик (аргументы функции metric()), который является поисковым запросом для выбора всех метрик, интересных пользователю. В данном случае мы выбираем все метрики с именем "nginx.requests.rate" и меткой status, имеющей префикс на "5" (хотим посчитать все http-5xx ошибки)


  • Функции преобразования метрик. В данном случае все выбранные метрики мы сгруппируем (суммой) по метке url (например значения с разных серверов или файлов просумируются), а потом возьмем только 5 наибольших по сумме урлов, а хвост сложим в значение с меткой "~other"

При этом всегда наш запрос работает в каком-то интервале времени: [since_ts=X, to_ts=Y]


  • Селектор метрик преобразуется в примерно такой запрос к elasticsearch (валидный json запроса сильно многословнее):


    {"name": “nginx.requests.rate”, "status_prefix": "5",  "created_lt": "Y", "updated_gt": "X+12h"}

  • Получили N (часто тысячи) ключей


  • Идем в C* получать label_sets по ключам


  • Идем в metric_storage получать данные по ключам


  • Вычисляем выражение top(5, sum_by(…))

Нагрузка и размер данных


В данный момент наше облако обрабатывает чуть больше 100 тысяч метрик в секунду на запись. Посковых запросов в среднем около 350 rps (90% из них от триггеров). Каждый поисковый запрос идет по 1-3 индексам ES, каждый индекс ~100млн документов (~30GB).


При этом потребление CPU эластиком не оставит равнодушным любого, кто считает деньги, потраченные на хостинг :)



Elasticsearch


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


Внешний кэш


Мы решили сделать внешний по отношению к ES кэш результатов поиска и сформулировали к нему такие требования:


  • Поиск всегда идет по интервалу времени


  • Метрики, которые перестали приходить, должны уходить из кэша


  • Новые метрики должны попадать в результаты поиска в течении 1 минуты

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


Перколятор


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


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



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



Реализации перколятора:



Мы рассматривали только elasticsearch, там перколятор представляет из себя специальный тип индекса, в котором мы описываем структуру наших будущих документов: какие будут поля у документа и их типы (mapping). Дальше в этот индекс мы сохраняем наши запросы, после чего ищем, подавая на вход документы.


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


На нашем простеньком бенчмарке мы получили 2-10ms на проверке 1 документа на соответствие 1 запросу в перколяторе. При нашем потоке документов, это будет очень накладно. К тому же мы так и не научились "готовить" elasticsearch:)


Наивный самодельный перколятор


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


Мы решили попробовать сделать "наивную" реализацию перколятора, то есть в лоб проверять соответствие каждой метрики всем известным запросам. У нас есть поток записи ~100 тысяч метрик в секунду, каждую метрику нужно проверить на соответствие ~100 запросам.


Бенчмарк одной проверки (данный кусок нашего кода работает на golang, на нем и писали прототип) показал ~300ns. Так как это полностью cpu bound задача, имеем право суммировать время, получаем:


100k * 100 = 10M проверок в секунду
10M * 300ns = 3 секунды в секуду = 3 процессорных ядра


Логика работы нашего кэша получилась примерно такой:



В процесс записи метрик добавились дополнительные этапы:


  • Поднимаем все сохраненные запросы для данного клиента из С*
  • Проверяем каждую пришедшую метрику на совпадение по каждому запросу
  • В случае совпадения записываем метаинформацию о метрике в кэш, одна и та же метрика может быть много раз записана в кэш (дубликаты уберет кассандра)

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


Как устроен кэш


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



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


Значением является словарь ключ метрик и json представление label_set. Таким образом, если мы используем результаты из кэша, нам не нужно дополнительно идти в кассандру еще и за метаданными метрики по ключу, как мы делали это после получения результатов из ES.


Выкатили в production


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



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



А бэкенд, который выполняет перколяцию вырос как раз на прогнозируемые ~3 ядра:



Как бонус мы получили хорошую оптимизацию по latency, взять из кэша результаты оказалось в ~5 раз быстрее, чем сходить в ES и потом достать метаинформацию из C*:



Проверка консистентности


Чтобы убедиться, что мы нигде не накосячили с логикой работы кэша, первые несколько дней поиск шел одновременно и по ES и по кэшу, при этом мы сравнивали результаты и писали соответствующую метрику. После переключения нагрузки на кэш, мы не стали выпиливать логику валидации кэша и делаем спекулятивные запросы в ES для 1% запросов. Эти же запросы являюся ещё и "грелкой" для ES, в противном случае без нагрузки индексы могут не попасть в page cache и запросы пользователей будут тупить.


Итого


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


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

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335266/


Метки:  

Релиз YouTrack 2017.3: автоматизация рабочих процессов на JavaScript, улучшенная поддержка Kanban и многое другое

Четверг, 10 Августа 2017 г. 15:15 + в цитатник
Всем привет! Недавно мы выпустили новую версию системы управления проектами — YouTrack 2017.3 — и спешим поделиться с вами нововведениями.




Что нового в YouTrack 2017.3?
  • Автоматизация рабочих процессов с использованием JavaScript.
  • Улучшенная поддержка методологии Kanban.
  • Шаблон для создания персональной доски.
  • Свимлэйны на основе проектов.
  • Ограничение попыток аутентификации.

Что еще?
  • Расширенная настройка видимости задач.
  • Улучшения в отчете по времени.
  • Предустановки OAuth 2.0 для GitLab и Bitbucket Cloud.
  • Поддержка пользовательских виджетов как часть экспериментальной функциональности.

Автоматизация рабочих процессов с использованием JavaScript


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



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

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

Улучшенная поддержка Kanban


В YouTrack 2017.3 мы добавили возможность отключать спринты на Agile-доске. Теперь командам, которые следуют методологии Kanban, больше не придется адаптировать свои процессы к работе на основе спринтов. Вы также можете настроить доску таким образом, чтобы карточки на нее попадали по заданному поисковому запросу.



Шаблон для персональной доски


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



Свимлэйны по проектам


Теперь свимлэйны на Agile доске можно идентифицировать по проектам. Данная функциональность удобна тем, кто следит за процессом выполнения задач из разных проектов. Чтобы добавить проекты в качестве свимлэйнов, необходимо включить данную опцию в настройках доски.



Ограничение запросов


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



Другие улучшения


Улучшения в настройках видимости


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



Улучшения отчете по времени


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

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



Предустановки OAuth 2.0 для GitLab и Bitbucket Cloud


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



Улучшенная интеграция с Zendesk


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




Экспериментальная функциональность


Пользовательские виджеты


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



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

Будем рады, если вы попробуете YouTrack 2017.3 и поделитесь впечатлениями. Можно скачать бесплатную версию для 10 пользователей или зарегистрироваться в облаке, чтобы воспользоваться пробной версией на 30 дней.

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

Кстати, в среду, 16 августа, в 17:00 по московскому времени мы проводим бесплатный вебинар, на котором рассмотрим новый способ пользовательской настройки YouTrack c использованием встроенного редактора и рабочих процессов на JavaScript. Присоединяйтесь!

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

Ваша команда JetBrains YouTrack
The Drive to Develop
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335270/


Метки:  

Стартап дня (июль 2017-го)

Четверг, 10 Августа 2017 г. 15:14 + в цитатник

Продолжая серию дайджестов «Стартап дня», сегодня я представляю самые интересные проекты за июль. Если хотите ознакомиться с остальными, то прошу в мой блог. Записи доступны в Facebook, ICQ и Телеграм.


Twiggle


Лет восемь назад таких проектов было много, но, кажется, качества продукта никому не хватило, все умерли. Может быть, сейчас пришло время и теперь получится. Twiggle продает e-commerce-сервисам технологию интеллектуального поиска по товарам с пониманием естественного языка.


image


В качестве демонстрационного примера они используют запрос “Open back button dress for a wedding under 200 not blue” — попробуйте вбить его аналог в любую Ламоду, в лучшем случае как раз синие платья в выдаче и окажутся. Или, например, “under 200” — самый тупой консультант в магазине отлично поймет, что это про цену, но какой-либо интернет-магазин — нет. Даже Амазон не понимает! Запрос “tv under 200 dollars” там легко выпадает в предложениях, он популярен, живые люди хотят так искать, но посмотрите, что в ответ находит «магазин всего».


У Twiggle в демонстрациях, разумеется, всё работает. И “not blue”, и “under 200”, и “dress shirt” с “without” в других хитрых примерах — всё это стартап понимает корректно, и результаты выдачи соответствуют человеческим ожиданиям. Посмотреть на проект в реальной жизни, а не в презентациях пока, к сожалению, нельзя — никто ещё не внедрил полностью, хотя «у некоторых клиентов уже идут A/B-тесты».


Технически Twiggle работает как SaaS, предоставляя партнерам по сути два метода API: «загрузить базу» и «получить результаты поиска». Интеграция, соответственно, несложная, дизайн менять не надо, использовать легко. Русский язык, к сожалению, не поддерживается, в местные проекты чудо-оружие внедрить не получится, но можно попробовать отечественный аналог — Детектум


Cardlytics


image


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


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


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


Теоретически, всё, что делает Cardlytics, может делать и сам банк: Умные Алгоритмы на BigData там весьма условны, имея доступ к тратам по карте можно использовать и прямолинейные фильтры. На практике у маленьких банков нет ни ресурсов на разработку, ни возможностей достучаться до больших рекламодателей, а стартап дает им единую точку входа.


Сейчас с Cardlytics работает 1500 американских банков, вместе они видят порядка 10 % всех американских трат по картам и чекам. Для сравнения, в России такая доля соответствовала бы позиции номер два после Сбербанка. Объёмы инвестиций соответствуют масштабам: за почти 10 лет жизни компания «освоила» 180 миллионов долларов — попробуйте дешевле подключить к своей платформе 1500 мелких банков. Серьезная выручка пошла только в самое последнее время: 80 миллионов за 2016-й год при быстром росте.


Tile


image


Новый гаджет для забывчивых хипстеров предлагает стартап Tile. Он продает небольшие электронные карточки с Bluetooth-чипом, которые пользователи кладут в кошелек, вешают на брелок с ключами, прикрепляют к ошейнику собаки или как-то иначе соединяют с тем, что они боятся потерять. Теперь, если страхи сбудутся, достаточно нажать кнопку в мобильном приложении, Tile зазвенит и вещь найдется. Маленький wow-эффект от дизайнеров продукта: если вдруг потеряется телефон, то всё работает совершенно симметрично — нажать кнопку надо на Tile и зазвенит уже смартфон.


Такой подход отлично работает, если ключи завалились куда-то в пределах квартиры. Но когда они вылетели из кармана где-нибудь в дороге, Bluetooth, скорее всего, не добьет. На этот случай Tile предлагает два механизма. Приложение умеет показывать точку на карте, в которой у него в последний раз получилось связаться с карточкой. Если это, скажем, работа или любимое кафе, то проблема с большой вероятностью решена. Если же кошелек выпал в автобусе и географическая координата этого места совершенно бессмысленна, то в бой вступает сообщество. Когда карточка теряет из «виду» хозяйский телефон, она начинает посылать сигнал SOS для всех. Любой оказавшийся рядом с пропажей смартфон с приложением Tile получит сигнал и переправит его в облако, откуда информация о перемещениях вещи отправится уже её хозяину. Стопроцентной гарантии, конечно, никто не дает, но шансы на счастливый конец истории есть.


Стоит одна карточка двадцать пять баксов, при покупке одновременно нескольких можно получить существенную скидку. Батарейка служит год, после этого срока компания предлагает за доплату обменять карточки на новые — по сути, скрытая подписная модель с годовым контрактом, не очень понимаю, почему она не оформляется явно. Сейчас стартап вышел на оборот в 100 миллионов долларов в год, а за всю историю продал 10 миллионов устройств, из них больше половины за последние 12 месяцев. Примерно так же растут и инвестиции: из полученных 59 миллионов 25 пришли в этом мае.


LevelUp


image


Американский LevelUp предлагает пользователям киоски предзаказа — как в McDonalds, только через приложение, а не в железном ящике. Офисный сотрудник спускается на обед, в лифте вводит заказ в соседней забегаловке, и к тому моменту, как он подойдет, еда на вынос уже будет его ждать. Пользователю не надо терять время, ресторану не надо платить кассиру, стартап собирает свои $69 в месяц за подписку, довольны даже другие, менее продвинутые, гости — очередь-то стала короче.


Одна эта функция и подписка на неё — это уже большой бизнес, LevelUp говорит о 300 тысячах подключенных точек. Оценивать выручку умножением их на $69 и на 12, конечно, нельзя, у сетей огромные скидки, но денег всё равно много. И подписка — это не всё, другой источник дохода — реклама и продвижение. Человек запускает приложение, когда идет куда-то за едой, причем его местоположение известно — идеальный момент для рекламы какого-нибудь нового бургера от кафешки неподалеку.


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


Интересно, что продукт молодой, а стартап очень старый, но раньше он занимался совсем другим — делал эдакий Appe Pay через QR-коды. Свою бизнес-модель LevelUp изменил примерно год назад, но во всех статьях в прессе, и даже в собственном разделе Help описывается ещё старый вариант. Если считать с момента пивота, то инвестиций получено 42 миллиона долларов, 37 из них совсем недавно.


Meet For Charity


image


Иногда стартапом может быть и просто страница в социальной сети. У российского стартапа Meet For Charity нет никакой IT-платформы, но это не мешает ему добиваться успехов.


Идея проекта очень проста — это регулярный благотворительный аукцион за право встретиться с интересной личностью. Каждый день объявляется новый гость («лот»), и подписчики страницы прямо в комментариях делают свои ставки — кто какую сумму готов заплатить за возможность пообщаться с этим человеком. После окончания торгов победитель перечисляет свою ставку благотворительному фонду, а тот делится с Meet For Charity 15 % комиссии. В результате в выигрыше абсолютно все: мир получает больше добра, стартап зарабатывает деньги, а кто-то получает важную для себя встречу.


Гости «в лотах» бывают самые разные: бизнесмены, шоу-звезды, спортсмены. В момент написания оригинального поста «разыгрывался» Кортнев из «Несчастного случая», а рекордную сумму в 1,2 миллиона рублей выручили два месяца назад за обед с Дмитрием Гришиным. Для сравнения, ставкой в 20-25 тысяч долларов заканчивались аналогичные аукционы за встречу с Уорреном Баффеттом в начале двухтысячных.


Текущая средняя финальная цена лота — 90 000 рублей (год назад была 20 000), 15 % комиссии дали за прошедшие полгода больше полутора миллионов выручки, при практически нулевых расходах и органическом росте. На рост неорганический основатели ищут инвестиции — хотят уйти от страницы на Facebook к мобильному приложению и выйти со своей моделью в другие страны. Мне кажется, надо как минимум пожелать им удачи!

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335314/


Метки:  

Как искусственный интеллект может спасти email

Четверг, 10 Августа 2017 г. 15:00 + в цитатник


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

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

Как AI делает письма лучше


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

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



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

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

Робот знает, что вы хотите прочитать


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

Уже сейчас системы email-маркетинга с внедрением AI-технологий умеют разбивать посетителей сайта на группы по ключевым словам, приведшим их на страницу, или даже на основе активности конкретного подписчика. В результате возможно не только создавать письма, «заточенные» под интересы конкретного пользователя, но и понимать, какого характера сообщения нужно ему отправить — подогревающее интерес или что-то, чтобы постараться разбудить человека, который подписался на рассылку, но совсем ее не читает.

К примеру, купленный Zeta Global сервис Boomtrain анализирует поведение пользователей на сайте, а затем использует эту информацию при составлении сообщений, а виртуальный помощник Conversica отправляет письмо потенциальному покупателю спустя пару минут после того, как он оставит свой email — и около 50% собеседников отвечают на такие роботизированные письма, потому что они написаны как будто от лица человека, это нравится людям больше чем безликие автоответы.

Но это еще не все — AI-системы, вроде той, что встроена в сервис email-рассылок SendPulse, умеют собирать информацию о поведении подписчиков email-рассылки в прошлом: в какие дни и какое время они открывали письма, в каких случаях кликали на ссылки. Все это значительно повышает процент открываемости писем — в среднем на 60%.

image

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

Вывод


Несмотря на то, что остаются и проблемы email, которые пока ни один искусственный интеллект решить не в силах — например, сложности с корректным отображением писем на любом мобильном устройстве — очевидно, что AI может стать ключевым фактором сохранения популярности email в будущем.

Внедрение AI-технологий решает проблемы и бизнеса, и конечных пользователей — люди получают полезные и понятные лично им письма, а компании отмечают рост бизнес-показателей. А раз так — то не остается причин, по которым электронная почта не сможет оставаться средством коммуникации номер один.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/335342/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1090 1089 [1088] 1087 1086 ..
.. 1 Календарь