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

Поиск сообщений в 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 ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

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

Как технологии Яндекс.Такси приближают будущее личного и общественного транспорта

Среда, 14 Июня 2017 г. 14:45 + в цитатник
Некоторое время назад Яндекс.Такси стало предлагать вызвать такси не точно туда, где вы находитесь, а пройти несколько метров, но доехать быстрее и дешевле.



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

Начну издалека


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

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

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

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

Эффективность. Технологии в очередной раз меняют мир


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

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

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

Если посмотреть на классический рынок такси в России, то доля времени, когда водитель везет пассажира, составляет 10% и меньше. Даже в Европе, где распространены стоянки городского такси, время активности машин в среднем занимает от 7% до 15%. У современных сервисов-приложений этот показатель достигает 50% и больше. Разрыв очевиден.

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

Как появилась идея


Как часто бывает в Яндексе, продуктовое решение выросло из идеи одного из сотрудников. Он даже не работает в Такси. Коллеге нужно было доехать от ближайшего к МИФИ метро до самого института. На карте это расстояние не превышает 1 км — вот как раз та ситуация, когда такси может заменить автобус или маршрутку. Но на деле ехать пришлось 11 км, так как необходимо было развернуться на Каширском шоссе. А ведь стоило перейти дорогу и пройти 100 метров, как время в пути сократилось бы в восемь раз! И, соответственно, стоимость поездки была бы ниже. На самом деле в команде Такси тоже уже обсуждали подобную фичу, но пост коллеги помог убедиться в правильном направлении мысли. 

Почему это не так просто сделать?


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

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


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

Как эта штука работает, и почему так


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


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

Что дальше?


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

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

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

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

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

* * *


Принято считать (и многие на Хабре наверняка в курсе), что идея современного общественного транспорта принадлежит математику — Блезу Паскалю. Именно он еще в середине XVII века предложил создать многоместные экипажи, запрягаемые лошадьми. Они должны были двигаться по строго определенным маршрутам — это помогало не ездить впустую (как бывало, например, с извозчиками) и увеличивать маржинальность поездки.  

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

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

https://habrahabr.ru/post/330524/


[Перевод] Dropout — метод решения проблемы переобучения в нейронных сетях

Среда, 14 Июня 2017 г. 14:38 + в цитатник

Метки:  

Топ 15 бесплатных Unity ассетов для начинающего 2D разработчика

Среда, 14 Июня 2017 г. 14:14 + в цитатник

Введение


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

Сама платформа Unity предоставляет широкий набор инструментов, но иногда не хватает и их. Тогда в дело вступает Asset Store с миллионами ассетов, моделей и примеров проектов.



Если у вас еще мало опыта в разработке приложений, имейте в виду: Asset Store – это огромный склад велосипедов, которые уже изобрели до вас. При этом там можно найти очень много бесплатного контента, или же контента по цене одной чашки кофе (сэкономьте на латте!).

Почему мы посвятили статью именно 2D играм? Посмотрите на рынок: 2D игры сейчас переживают ренессанс. Чтобы в этом убедиться, достаточно взглянуть на инди-сектор в Steam, Ketchapp и Zeptolab в мобильной разработке. 2D игры давно превратились из отжившего свое сектора в отдельную процветающую нишу рынка. Поэтому если вы решили делать 2D игру на Unity, сначала убедитесь, что у вас в арсенале есть все нужные инструменты, чтобы обеспечить должное качество продукта.

Немного про Asset Store


Если вы читаете эту статью, то скорее всего что-то слышали про Asset Store. Там хранятся несколько тысяч моделей, плагинов, систем частиц, скриптов и многое другое. Часть этого добра распространяется за деньги, а часть совершенно бесплатно! И мы настоятельно рекомендуем пользоваться этим обстоятельством. Прежде чем реализовывать A* для ваших юнитов, подумайте: может быть, кто-то уже сделал это до вас и выложил в общий доступ в удобной форме.

Ассеты с точки зрения 2D разработки


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

Что же нам может понадобиться? Вот список:

  • Готовые шаблоны проектов, с помощью которых можно быстро научиться базовым механикам создания игры. Это могут быть как платформеры, так и что-то более специфическое, например, roguelike.
  • Так называемые Sprite packs, то есть паки текстур для вашей 2D игры. Они очень полезны на том этапе, когда у вас еще нет арта, но уже появились идеи для механики. Спрайт паки можно использовать, просто чтобы было с чем работать. Естественно, в релизной версии их лучше заменить на оригинальную графику.
  • Готовые 2D объекты. Это могут быть как классические триггеры (зоны смерти, точки респауна, телепорты), так и что-то более интересное, скажем, физически верно рассчитанный меховой шарик.
  • Скрипты и расширения редактора. Это отдельный, огромный класс компонентов, которые могут выполнять широкий спектр разных задач. Можно поставить скрипт, который добавит несколько приятных визуализаций в редактор, а можно превратить Unity в инструмент визуального кодинга, вроде Unreal Blueprints.
  • Эффекты. Сюда можно отнести огромные паки частиц, эффекты на камеру, шейдеры для спрайтов и т.п. В этом сегменте попадается особенно много бесплатных ресурсов.
  • Анимации. Сюда можно отнести библиотеку простых анимаций (твинов), а также примеры покадровой или скелетной анимации.


Непосредственно ТОП


1. Standard Assets

Пак стандартных ассетов от самой Unity. Это самые необходимые и проверенные в деле ассеты. Все они относятся к следующим категориям: 2D, Cameras, Characters, CrossPlatformInput, Effects, Environment, ParticleSystems, Prototyping, Utility, Vehicles. Эти ассеты можно подключить при установке Unity.

2. LeanTween

Великолепная библиотека твинов. Содержит все необходимые виды твинов (move, scale, rotate, alpha, color). Ее отличает очень удобный вызов методов, поддержка easing type и многое другое. Комбинируя простые твины, можно создавать очень интересные эффекты.

3. Simple Sprite Packer

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

4. Advanced Polygon Collider

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



5. 2D Platformer

Более сложный пример 2D платформера от самой Unity. В отличии от 2D Platformer Controller здесь добавлена анимация, стрельба и еще множество функций и объектов.

6. 2D Platformer Controller

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

7. Collider2D Optimization

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



8. Unity Anima2D

Большой ассет для работы с скелетной 2d анимацией, включая инверсную кинематику и автоматическую генерацию весов. Раньше он стоил 60 $, но недавно Unity сделала его бесплатным. Очень мощный инструмент.

9. 2D Tilezone Lite

Удобный ассет-редактор для создания тайловых уровней; может разбивать атласы по сетке, рисовать уровни в редакторе Unity, добавлять коллайдеры на блоки и настраивать слои отрисовки.

10. Localization

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

11. AutoSave

AutoSave – ассет, который не ценишь, пока он не сработает. Суть в том, что при обычном положении вещей если Unity зависает или вылетает, а вы не сохранили сцену, то все внесенные изменения пропадут. То есть вы можете час делать уровнь, забыть сохраниться и потерять его из-за критической ошибке в скрипте (например, бесконечного цикла). AutoSave сохраняет сцену при каждом нажатии на кнопку Play. Это очень удобно.

12. Particle pack

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

13. 2D Roguelike

Мощный шаблон «рогалика». Содержит в себе управление героем, врагов, этажи уровней, звуки и эффекты.

14. TexturePacker Importer

Расширенный и усиленный вариант Simple Sprite Packer. Огромное количество функционала для работы с атласами.



15. Light2D — GPU Lighting System

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

Заключение


Разумеется, у каждого ассета из этого списка есть свои альтернативы, и, возможно, вы где-то не согласитесь с нашим выбором. Это нормально, если учесть, что в Asset Store несколько тысяч ассетов. Поэтому обязательно делитесь своими предложениями в комментариях.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330848/


Метки:  

[Из песочницы] Создание быстрых и более оптимизированных сайтов на WordPress

Среда, 14 Июня 2017 г. 14:05 + в цитатник
Большинство потребителей имеют уже сложившееся мнение о том, что касается услуг web-хостинга. Если вы будете искать отзывы о любом хостинг-провайдере, вы обнаружите десятки результатов. И обычно, негативных отзывов там намного больше, чем положительных. Я думаю, я смогу это исправить, поэтому делюсь с вами задачами, с которыми мне приходится сталкиваться как оператору поддержки хостинга для WordPress, а также их решениями.

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

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

1. Смена хостинга — не всегда решение проблемы
2. Работающие сайты не предназначены для разработки
3. Не разработчик? - Не лезь в код
4. Не экономьте на темах и плагинах
5. Контролируйте AJAX-запросы
6. Будьте аккуратны при работе с рекламными сетями и внешними сервисами
7. Чрезмерная оптимизация может нанести вред производительности
8. Популярные проблемы с производительностью легко диагностировать
9. Изменение ядра WordPress, это плохо
10. Обеспечьте совместимость с PHP 7 и HHVM до переноса сайта
11. Крупные сайты должны заниматься оптимизацией баз данных
12. Действительно ли вам необходима универсальная тема?
13. Лог ошибок - ваш друг
14. Google здесь не просто так
15. 123456 больше не допускается
16. Скрипты не всегда должны загружаться по всему сайту

1. Смена хостинга — не всегда решение проблемы


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

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

2. Работающие сайты не предназначены для разработки


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

Если вы не хотите использовать такие решения, вы можете воспользоваться локальной разработкой и тестированием, используя то, что некоторые называют LAMP или LEMP -стеком. Они предназначены для работы с Linux, Apache/Nginx, MySQL и PHP. А такие инструменты, как WAMP и MAMP упростят и ускорят сборку сервера для локальной разработки.

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

Чтобы избежать таких проблем, я рекомендую воспользоваться такими инструментами, как DesktopServer и Local, которые созданы исключительно для ускорения вашего рабочего процесса при локальной работе с WordPress. Они включают в себя упрощенные способы передачи данных рабочему сайту, а также имеют дополнительные функции, такие как работа с WP-CLI и встроенная поддержка режима мультисайтов. Поддержка мультисайтов сама по себе может быть бесценной, поскольку работа с большими локальными копиями WordPress иногда может быть довольно сложной.

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

3. Не разработчик? - Не лезь в код


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



Рекомендация для администраторов: поместите следующий код в файл wp-config.php с заменой edit_themes, edit_plugins, и edit_files привелегий для всех пользователей. Это помешает пользователям уронить сайт посредством редактирования кода.

define('DISALLOW_FILE_EDIT', true);

Также, отключите возможность редактирования файлов темы или установки плагинов для пользователей. Для этого поместите следующий код в файл wp-config.php.

define('DISALLOW_FILE_MODS', true);

Учтите, вышеприведенные команды также отключат редактор файлов для тем и плагинов. Больше информации в WordPress Codex.


4. Не экономьте на темах и плагинах


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

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



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

Ожидание обновлений установленных плагинов - это огромная проблема для пользователей WordPress, которые покупают решения в сторонних каталогах, вроде ThemeForest. Многие разработчики тем встраивают в них дополнительные плагины, такие как Revolution Slider или Visual Composer. Дело тут в том, что при обнаружении уязвимостей во встроенном плагине, пользователю приходится ждать обновления от разработчика темы, хотя сам плагин мог быть исправлен буквально сразу же. Это делает многие сайты очень уязвимыми для хакеров.


5. Контролируйте AJAX-запросы


Следите за тем, как используются AJAX-запросы на сайте, а также за плагинами, использующими AJAX. Например, API WordPress Heartbeat использует /wp-admin/admin-ajax.php для обращения к AJAX через браузер. Многие из этих обращений лишние. Особенно частое использование этого файла происходит при всплесках трафика и загрузке процессора. Это может существенно замедлить ваш сайт. Это чем-то похоже на запуск DDoS-атаки против себя самого.



Если есть сторонние плагины, использующие admin-ajax.php, убедитесь в том, что они взаимодействуют с ним правильно. Вы без труда можете отслеживать HTTP POST-запросы и, на основе имени, определять, каким плагином они вызваны. Например, тот, что обнаружил я, get_shares_count, оказался популярным плагином для взаимодействия с социальными сетями, который перегружал admin-ajax.php. На сайте с высоким трафиком, перегрузка выросла бы многократно.

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

6. Будьте аккуратны при работе с рекламными сетями и внешними сервисами


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

Вот краткое сравнение того, как рекламные сети могут повлиять на ваш сайт на WordPress.

Параметры тестирования: на тестовый ресурс я добавил три объявления из Google AdSense, размером 300x250. На сайте установлена тема по умолчанию - Twenty Sixteen. Я замерил скорость загрузки до установке AdSense, и после.

До AdSense (результаты тестирования)


  • Первая загрузка: 1,372 с.
  • Повторная загрузка: 1,013 с.

Разбивка содержимого по соединениям:



После AdSense (результаты тестирования)



  • Первая загрузка: 4,103 с.
  • Повторная загрузка: 3,712 с.

Разбивка содержимого по соединениям:



Просто установив 3 объявления Google AdSense, мы добавили 6 дополнительных подключений. Сайт на WordPress c рекламными объявлениями в 2,7 раза медленнее, чем без них. В основном это связано с дополнительным временем поиска DNS и использованием JavaScript на странице. Все это должно создать у вас картину происходящего на крупных сайтах, вставляющих 10 объявлений на одну страницу. Независимо от того, насколько быстрый хостинг вы используете, он не будет исправлять задержки от сторонних рекламных подключений.

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



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



Другим хорошим примером является сайт Huffington Post. Если вы проведете тест скорости загрузки, вы увидите огромное число HTTP-запросов к рекламным сетям. Быстрый тест показал скорость загрузки свыше 13 секунд!

  • Первая загрузка: 15,908 с. | 221 HTTP-запрос
  • Повторная загрузка: 13,957 с. | 66 HTTP-запросов

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

Пример асинхронного JavaScript:


src="example.js" async

Пример отложенного JavaScript:


src="example.js" defer

У Патрика Секстона есть другой метод отсрочки JavaScript. WordPress версии 4.1 и выше, имеет фильтр, с помощью которого вы можете легко добавить атрибуты async или defer к своим скриптам.

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


7. Чрезмерная оптимизация может нанести вред производительности


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

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

Попытка закэшировать кэш


В отличии от типичных VPS или обычных серверов, многие хостинги WordPress имеют собственное кеширование, которое выполняется на уровне сервера (например, Redis или Memcache). Многие провайдеры запрещают использование кэширующих плагинов, потому что их использование может вызвать все типы проблем, но чаще всего, 502 Bad Gateway. Попытка “закэшировать кэш”, как я это называю, никогда не является хорошей идеей.

Плагины, такие, как WP Rocket и Cache Enabler, великолепны, но они разрабатывались для серверов, которым необходима дополнительная помощь в ускорении вашего сайта. Рекомендую почитать подробнее о том, что касается кэширования объектов - популярной серверной формой кэширования, часто используемой сегодня.

2x CDN = 2x скорость загрузки, верно?


CDN действительно могут значительно уменьшить время загрузки контента в разных географических регионах, но только при грамотной настройке. Один из самых популярных сервисов - Cloudflare, технически является прокси-сервером, и немного отличается от обычного поставщика CDN, поскольку вы направляете к нему весь свой DNS, а не только содержимое сайта.

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

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


Вы хотите доминировать в поисковой выдаче, это понятно. Но ведь добавление 3 плагинов для SEO не поможет вам достичь этой цели. На самом деле, есть много проблем с совместимостью, возникающих при использовании All In One SEO, Yoast и других плагинов для SEO одновременно, например, вывод дублирующих метатегов. Установка дополнительных плагинов не гарантирует улучшение вашей поисковой оптимизации.

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


Даже если вы не являетесь продвинутым пользователем WordPress, общие проблемы с производительностью достаточно легко обнаруживать. Продвинутым пользователям я рекомендую пользоваться WebPageTest, поскольку он поддерживает последние протоколы HTTP/2. Для остальных подойдет Pingdom. Простой каскадный анализ покажет вам, есть ли у вас ненужные переадресации, отсутствующие файлы, избыток DNS-запросов или перегрузка сайта через сторонние скрипты или рекламные сети.

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




9. Изменение ядра WordPress, это плохо


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

10. Обеспечьте совместимость с PHP 7 и HHVM до переноса сайта


Известно, что PHP 7 и HHVM очень способствуют повышению производительности сайтов на WordPress. И конечно, всегда приятно использовать новейшее и самое лучшее. Но сначала стоит убедиться, что ваш сайт совместим с этими технологиями. Например, если вы обновляетесь с PHP 5.6 до PHP 7, вы должны протестировать все функции вашего сайта на WordPress в обкаточной среде или локально, чтобы убедиться, что проблем с совместимостью нет. Один устаревший, но очень важный для вас плагин, может не работать с PHP 7, что означает, что вам придется подождать его обновления, прежде чем переходить на более свежие технологические решения.

11. Крупные сайты должны заниматься оптимизацией баз данных


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

Вы можете конвертировать свои таблицы всего в несколько простых действий. Для начала, убедитесь, что вы используете MySQL 5.6.4 или более новую, а также, что вы сделали резервную копию, в качестве меры предосторожности. В этом примере используется таблица wp_comments. Просто запустите команду ALTER, чтобы преобразовать для работы с InnoDB.

ALTER TABLE wp_comments ENGINE=InnoDB;

Если же вы работаете с актуальной версией phpMyAdmin, вы можете открыть нужную таблицу, перейти во вкладку “Операции” и изменить механизм хранения там.



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

define('WP_POST_REVISIONS', false );

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

define('WP_POST_REVISIONS', 3);

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

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

DELETE FROM wp_posts WHERE post_type = "revision";


Вы также можете воспользоваться плагином WP-Optimize для этих целей.


12. Действительно ли вам необходима универсальная тема?


Существует огромная проблема, которую я наблюдаю в сообществе WordPress. Люди покупают универсальные темы, а используют лишь 1% её функционала или и того меньше. Они смотрят на демо-страницы и видят красивые слайдеры и кастомизированные блоки, которые убеждают их в необходимости приобретения, однако, на самом деле, эти возможности могут никогда им не пригодиться. Можно купить более простую и менее функциональную тему, и тем самым, сэкономить и деньги и время, которое, в итоге, будет затрачено на ее оптимизацию, ведь простая тема будет быстрее прямо “из коробки”.

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



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

13. Лог ошибок - ваш друг


Если вы знаете, как вести себя с файлами WordPress и файлом wp-config.php, журнал ошибок может сослужить вам хорошую службу. Регулярно проверяя его, вы спасете себя от всевозможных головных болей, а также глубже изучите работу WordPress. Мало кто из пользователей заглядывает в лог перед обращением за помощью к техподдержке хостинга. С помощью нескольких простых настроек в wp-config.php, вы сможете включить ведение журнала ошибок, который по умолчанию сохраняется в /wp-content/debug.log.

Включение логирования:

define( 'WP_DEBUG_LOG', true );

Вывод логов на странице:

define( 'WP_DEBUG_DISPLAY', true );

Подробнее в WP_DEBUG codex.


14. Google здесь не просто так


Не бойтесь искать ответы в Google. Интернет полон подсказок и решений. В течение пары минут, вы можете исправить большинство ваших проблем. Ответы на типичные вопросы, вроде “как изменить DNS в GoDaddy” или “как пользоваться sFTP”, легко могут быть найдены в Google.

В Интернете есть крупные ресурсы, посвященные работе с WordPress, такие, как StackExchange и WordPress Codex, не говоря уже о сотнях блогов с обучающими статьями.

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


15. 123456 больше не допускается


SpashData собирает список наиболее часто используемых слитых паролей (более 2 млн.) каждый год. Неудивительно, что в 2015 году самым популярным паролем был “123456” - тот же, что и в 2014 году. Это довольно неприятно для хостингов, так как использование таких паролей держит сайты буквально в шаге от взлома. Одним из лучших решений является использование KeePass или его аналогов. Зашифрованный пароль в облаке всегда намного безопаснее, чем “123456”.


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


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

Один из таких примеров - популярный плагин Contact Form 7. Как показано ниже, он загружает файлы CSS и JavaScript на домашнюю страницу сайта, хотя там не используется ни одной контактной формы.



Есть несколько способов это исправить. Первый - использовать функцию wp_dequeue_script(), введенную в WordPress 3.1. Она позволяет удалять скрипты из очереди загрузки на вашем сайте. Вот пример использования этой функции с Contact Form 7. Разработчик Contact Form 7 также имеет документацию о том, как использовать JavaScript и CSS только там, где это необходимо.

Второй способ - использовать специальные плагины для WordPress, например, Gonzalez или Plugin Organizer. Ниже приведен пример использования Gonzalez на нашем сайте. Удобное окно настроек позволяет за пару щелчков мыши убрать JavaScript и CSS файлы плагина Contact Form 7 со всех страниц, кроме страницы контактов, тем самым, увеличив скорость загрузки остального сайта.



Заключение


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

Это перевод статьи «Creating Better, Faster And More Optimized WordPress Websites» за авторством Brian Jackson.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330878/


Метки:  

gdb-дуэль — списки, деревья и хэш таблицы против командной строки

Среда, 14 Июня 2017 г. 13:56 + в цитатник

Первый раз я увидел команду duel в gdb на каком-то древнем IRIX-е, лет пятнадцать назад. Это была невероятно крутая штука для просмотра разных связанных списков, массивов структур, и прочих подобных конструкций. Помечтал, мол, если б в Линуксе такая была, и забыл. Лет десять назад вспомнил, погуглил — оказалось, что DUEL, это вообще-то патч 93-го года для gdb 4.6, а вовсе не что-то уникальное в IRIX. Только автор по идейным соображениям выпустил его как public domain, а gdb-шники были тоже идейные и хотели GPL, так что попасть в upstream этому патчу не грозило. Я портировал его на тогдашний gdb 6.6.2, отдал в gentoo и до выхода 7-го gdb наслаждался жизнью. Потом duel из gentoo выкинули, портировать на новый gdb было сложно, никто не взялся. А недавно я его попробовал оживить. Только вместо патча (надо собирать вместе с gdb из исходников, использует всякие внутренние gdb-шные функции) я его написал с нуля на питоне. Теперь Duel.py (так называется новая реализация Duel-а) грузится в gdb на лету, и, надеюсь, Python API не будет меняться от версии к версии так, как недокументированные gdb-шные потроха. Итак, встречайте: DUEL — высокоуровневый язык анализа данных для gdb.


Примеры


Сразу, чтоб показать, на что он способен:

(gdb) dl table_list-->next_local->table_name
tables->table_name = 0x7fffc40126b8 "t2"
tables->next_local->table_name = 0x7fffc4012d18 "t1"
tables-->next_local[[2]]->table_name = 0x7fffc4013388 "t1"

Это из отладки MariaDB. Команда проходит односвязный список структур TABLE_LIST и для каждого элемента списка выводит TABLE_LIST::table_name.

(gdb) dl longopts[0..].name @0
longopts[0].name = "help"
longopts[1].name = "allow-suspicious-udfs"
longopts[2].name = "ansi"
<... cut ...>
longopts[403].name = "session_track_schema"
longopts[404].name = "session_track_transaction_info"
longopts[405].name = "session_track_state_change"

Оттуда же (я вырезал адреса, чтоб не захламлять текст). Есть массив структур, задающий опции командной строки. Команда выводит только имена опций, проходя весь массив до name == 0. А можно просто посчитать, сколько их:

(gdb) dl #/longopts[0..].name @0
#/longopts[0..].name@0 = 406


Основная идея


Duel построен на том, что выражение может возвращать много значений. Например,

(gdb) dl 1..4
1 = 1
2 = 2
3 = 3
4 = 4

или вот

(gdb) dl my_long_options[1..4].(name,def_value)
my_long_options[1].(name) = "allow-suspicious-udfs"
my_long_options[1].(def_value) = 0
my_long_options[2].(name) = "ansi"
my_long_options[2].(def_value) = 0
my_long_options[3].(name) = "autocommit"
my_long_options[3].(def_value) = 1
my_long_options[4].(name) = "bind-address"
my_long_options[4].(def_value) = 0

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

Операторы


Синтаксис похож на С, и C-шные операторы работают, как обычно. Гораздо интереснее, новые, специфичные для DUEL, операторы. Рассмотрим самые полезные из них:

Диапазон и перечисление, .. и ,


Выше я приводил пример обоих операторов. Это знакомые конструкции, они есть и в других языках. При этом в диапазоне можно опустить один из концов. Если указать только конец диапазона, например, ..20, то диапазон начнется с нуля и в нем будет 20 значений, так же, как если бы было написано 0..19. Если же указать только начало, то получится открытый диапазон! Чтобы duel не продолжал генерировать числа до тепловой смерти вселенной (или до переполнения счетчика, смотря что случится раньше), вместе с открытым диапазоном обычно используют оператор остановки по условию, @.

Остановка по условию, @


В выражении x@y, выражение x будет генерировать значения до тех пор, пока y ложно. Например,

(gdb) dl arr[0..]@(count > 10)

И duel будет выводить элементы массива arr[] до тех пор, пока arr[i].count будет не больше десяти.

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

(gdb) dl str[0..]@0

вернет все символы строки, вплоть до '\0'. Более практичный пример — вывести все опции командной строки из argv:

(gdb) dl argv[0..]@0
argv[0] = "./mysqld"
argv[1] = "--log-output=file"
argv[2] = "--gdb"
argv[3] = "--core-file"


Хотя тот же эффект достигается и

(gdb) dl argv[..argc]
argv[0] = "./mysqld"
argv[1] = "--log-output=file"
argv[2] = "--gdb"
argv[3] = "--core-file"


Перейти по указателю, -->


Генератор a-->b порождает множество значений a, a->b, a->b->b, и так далее, пока не уткнется в NULL. Я уже приводил пример, как таким образом можно пройтись по односвязному списку. Но это точно так же работает и для деревьев, например:

(gdb) dl tree-->(left,right)->info


Вычисляющие скобки {}


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

(gdb) dl i:=5
i = 5
(gdb) dl i+6
i+6 = 11
(gdb) dl {i}+6
5+6 = 11
(gdb) dl {i+6}
11 = 11

Это, в основном, нужно для массивов:

(gdb) dl if (my_long_options[i:=1..20].name[0] == 'd') my_long_options[i].name
if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-abort-slave-event-count"
if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-assert-on-error"
if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-assert-if-crashed-table"
if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-disconnect-slave-event-count"
if(my_long_options[i].name[0] == 'd') my_long_options[i].name = "debug-exit-info"
(gdb) dl if (my_long_options[i:=1..20].name[0] == 'd') my_long_options[{i}].name 
if(my_long_options[i].name[0] == 'd') my_long_options[16].name = "debug-abort-slave-event-count"
if(my_long_options[i].name[0] == 'd') my_long_options[17].name = "debug-assert-on-error"
if(my_long_options[i].name[0] == 'd') my_long_options[18].name = "debug-assert-if-crashed-table"
if(my_long_options[i].name[0] == 'd') my_long_options[19].name = "debug-disconnect-slave-event-count"
if(my_long_options[i].name[0] == 'd') my_long_options[20].name = "debug-exit-info"

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

Фильтры

https://habrahabr.ru/post/328180/


Метки:  

Бизнес на данных: стероиды для компании

Среда, 14 Июня 2017 г. 13:45 + в цитатник
Цифровая эра основательно вошла в нашу жизнь, теперь мир — набор данных. Это касается не только обычных людей, IoT или научных изысканий. Прежде всего, это касается бизнеса. Любого, от стартапа на коленке до мега холдинга. Сейчас практически у каждой компании такая конкурентная среда, что приходится действовать, как на полях сражений: собирать данные, анализировать и принимать стратегические и тактические решения. Иначе клиент просто не проявит интерес к вашей разработке, продукту, услуге. Встают вопросы: какие данные собирать, где их брать, как хранить и вообще — зачем на это тратить время? Мы знаем на них ответы.


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

На самом деле, бизнес не всегда собирает информацию о клиентах — точнее, ту информацию, которой будет достаточно для выстраивания именно отношений, а не попыток выцепить пару дополнительных продаж email или SMS-рассылкой. Даже по нашей предыдущей статье и комментариям к ней можно судить о том, какая информация чаще всего собирается: ФИО, контакты, что и когда купил. Этого мало. Поверьте опыту CRM-щиков: какую систему бы вы ни взяли, в карточке клиента предусмотрено множество полей, заполнение которых делает клиентскую базу более качественной.

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

Посмотреть короткую GIF-ку карточки клиента в RegionSoft CRM


Гифка кликабельна

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

Всем очевидно, но мы напомним, что отдавая свою личную и финансовую информацию вам, клиенты рассчитывают, что она останется в безопасности (все знают про ужесточение 152-ФЗ с 1 июля?)  и вы не будете злоупотреблять доверием, как то продавать данные третьим лицам, спамить пару раз в день, небрежно хранить данные и т.д. Кстати, есть такая распространённая ситуация, как уход менеджера с клиентской базой. Это одна из проблем, частичное решение которой лежит на CRM-системе. Так вот, если ваш менеджер «уводит» или продаёт данные, это двойная проблема: во-первых, потеря части клиентской базы, а во-вторых, передача информации третьим лицам, которые потенциально будут извлекать коммерческую выгоду. То есть фактически компания не справилась с защитой переданных ей данных.

Какие данные собирать и зачем?


Персональные данные


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

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

Транзакционные данные


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

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

Коммуникационные данные


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

Откуда брать данные о клиентах?


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

  • Информация при регистрации на сайте. Создавайте формы на сайте, которые помогут вам собрать данные от клиентов. Правила: не требуйте данные за незначительные бонусы (типа скачивания рекламного буклета), собирайте данные поэтапно (часть — при регистрации, часть — во время совершения заказа), не забудьте прописать политику обработки данных (вы же всё ещё помните про 152-ФЗ?).

  • Информация с онлайн-презентации. Постарайтесь собрать данные при оформлении заявки, а также во время общения с клиентом. Правила: задавайте наводящие вопросы, подготовьтесь к работе с клиентом заранее, сформируйте стандартную анкету (например, в RegionSoft CRM анкетирование — встроенная функция).

  • Информация из чата. Спросите имя и электронную почту в чате. Многие приложения имеют встроенную возможность запроса информации о клиенте. Правила: не используйте назойливые всплывающие кнопки «перезвонить», в случае нежелания оставить свои данные клиент должен иметь возможность продолжить чат на сайте.

  • Информация из телефонных переговоров. Уточняйте необходимые данные во время общения по телефону с клиентом. Правила: записывайте звонки и сохраняйте их, это даст возможности для обучения менеджеров и избавит вас от сотен конфликтных ситуаций (мы предусмотрели такую штуку — в RegionSoft CRM все разговоры записываются и сохраняются).

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

  • Информация в обмен на информацию. Предлагайте полезную информацию в обмен на данные клиента. Это могут быть интересные рассылки, статьи, видео уроки и т.д. Правила: не скатывайтесь в инфобизнес и не гоните дешёвый контент, работайте над содержанием.

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

  • Интернет вещей (IoT). Отлично работает для ритейла, B2C. Поставьте NFC-метки, счётчики потока клиентов, интерактивные экраны — так ваши покупатели расскажут о себе сами. Правила: всё должно быть в рамках закона.

  • Системы аналитики. Самый щедрый и безопасный способ сбора данных. Используйте привычные Яндекс.Метрику и Google Analytics, расширяйте свой арсенал систем BI, используйте трекеры, парсеры и т.д. Правила: информация на вас буквально польётся, но это не значит, что вы сможете её правильно обработать и интерпретировать. Выбирайте и используйте ценные данные, сравнивайте, ищите новые закономерности.

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

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


— Там, куда ты копаешь, откуда ты возьмёшь новую одежду, Как ты рассчитываешь преодолеть забор?
— Да кто ты?!
— Я бизнес-аналитик.


Как хранить информацию?


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

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

Методы сбора и обработки информации


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

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

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

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

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

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

Бизнес инвестирует в аналитику (как минимум, платит за софт и зарплату маркетологам, аналитикам и сопровождающим программистам), а значит, должен получать отдачу от инвестиций. То есть информацию мало получить — её важно уметь проанализировать. Мы уже писали о принципах аналитики в бизнесе, но повторим несколько базовых способов применения этого актива.
 
  • Оперативная аналитика: разведка и работа с данными при продвижении продукта, оперативная отчетность.

  • Описательная аналитика: сегментация потребителей, создание портрета клиента, разработка программы лояльности.

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

Что считать и как не облажаться?


Есть целая группа информации, которую собирать строго обязательно любому бизнесу, поскольку она отражает его «здоровье» и адекватность требованиям клиентов.

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

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

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

    Пример из жизни. Компания продавала свои сервисы и свои продукты через монобрендовые салоны, дилеров, агентов, почтовые киоски и отделения, интернет-магазин. после исследования выяснилось, что цена продажи в монобренде в 10 раз выше средней цены по каналам. Закрыли два монобренда — выручка от подписок в полугодовом периоде ощутимо снизилась. Оказалось, что монобренды приносили самых высокодоходных и лояльных клиентов, которые приходили в салон с «серьёзными намерениями», а не брали продукт «на погонять недельку».

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

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

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

  • Информационный шум вокруг вашей компании. Собирайте максимум внешней информации о вашей компании: отзывы, упоминания, цитирования и т.д. Чем больше вы заметны на рынке, тем больше шума. Но даже небольшие компании обязаны мониторить абсолютно всё во избежание репутационных потерь или во имя использования удачного момента. Тут вам на помощь придут специальные запросы в поисковиках, google alerts и т.д.

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

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

Между тем, чем раньше компания узнает о проблеме, тем дешевле и эффективнее окажется её решение. Так почему об информации не знают?

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

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

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

  4. Данные аккумулируются в нескольких корпоративных информационных системах, между которыми взаимодействие настроено слабо или не настроено вообще. Это у нас здесь под номером три, а в сердцах CRM-щиков и других вендоров решений автоматизации бизнеса это номер один и гран-при среди причин аналитических фейлов бизнеса. Есть прекрасное исследование, которое показывает, что компании в среднем используют в работе 14 рабочих приложений. Среди них нередко есть и пересекающиеся в аналитике, а также те, которые должны друг друга дополнять (например, CRM и биллинг, CRM и 1С). Так вот, отстутствие интеграций делает данные лоскутными и снижает их информативность и полезность для бизнеса.


Чем хороша для сбора и хранения информации CRM-система?


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


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

Кстати, такой контроль проще всего осуществлять в CRM-системе с помощью инструментов планирования, план-фактного анализа, воронки продаж и т.д. Начальник получает доступ к важным для бизнеса показателям в режиме реального времени, может иметь удалённый доступ к рабочему месту. Повторимся в сотый раз, CRM — инструмент контроля оперативной работы и выполнения задач, а не инструмент тотального контроля и слежки за сотрудниками. Система не умеет шпионить (мы о своей, конечно), да и вообще «фу» таким быть.

Экономия времени на отчётности. Можно сколько угодно хвалить Excel, но ваши сотрудники гарантированно тратят на него слишком много времени. Чтобы сделать отчёт в электронных таблицах, в 90% случаев необходимо приложить усилия — это касается численных данных. Хуже обстоит дело с задачами — например, если работник должен по окончании дня или недели отчитаться сколько времени на какую задачу у него ушло. Вы не просто получите материал, на создание которого убито около полутора часов, — вы получите поток вдохновенного вранья. В то время как в CRM у вас отобразятся сделанные, просроченные и отложенные задачи по каждому из подчинённых.

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

No Big Data или почему мы не «прикрутили» машинное обучение к RegionSoft CRM


В Facebook нас спросили, есть ли в нашей CRM-системе машинное обучение. Не будем делать интриги из этого вопроса — нет. Просто потому что пока нашей системе такая функциональность не нужна. И вот почему.

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


— Ну и как там твой проект с большими данными, Хоскинс?

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

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

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



У нас есть работа


У нас есть вакансии в Нижнем Новгороде (разработка, офис) и в регионах (толковые продажники, удалёнка)
В Нижнем Новгороде:

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

Web-разработчик — работа по созданию и поддержке web-сервисов, SAAS-технологий, web-сайтов, интеграционных проектов.

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

Пишите письмо, шлите резюме и портфолио на contact@regionsoft.ru

Кстати, есть и такое:

Программист 1С — работа в отделе внедрения проектов на базе 1С: Предприятие 8, интеграционные решения.

По России:

Мы ищем надёжных и сообразительных продажников на удалёнке в Санкт-Петербурге, Новосибирске, Екатеринбурге, Москве и других городах. Обучим, разъясним и поддержим. Фактически у вас будет интересная и стабильная работа прямо из дома. Если есть технический опыт — оторвём с руками.

Пишите на contact@regionsoft.ru
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330858/


Метки:  

Своя CRM система за 3 часа в Гугл-таблицах

Среда, 14 Июня 2017 г. 13:19 + в цитатник
В этом посте хочу поделиться опытом, как с помощью гуглдока можно создать CRM-систему, которая полностью будет закрывать потребности небольшой или средней студии ИТ-разработки.

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



На создание этой системы ушло часа 3 — не больше.
Давайте расскажу, как работает:

1. На листе «Активности» у нас исходные данные — мы указываем, все контакты по какому проекту, когда, что обсуждали и как изменился статус проекта. (Проекты, разумеется, выбираются из выпадающего списка — можно сделать кликнув по ячейке правой кнопкой -> проверка данных, и в графе «Правила» указать столбец со списком проектов, который у нас на странице «Лиды»)



2. Лиды — Это сводный лист со всеми проектами и статусами по ним. Взглянув на него сразу понятно, в каком состоянии продажи компании (даты последних контактов подсвечиваются в зависимости от свежести. Чем дольше не пинговал контакт, тем он белее) Это делается «Условным форматированием» во вкладке «Градиент»). Самое удобное, это то, что к каждому проекту подтягивается информация о последнем контакте и всегда видно, чем завершился последний контакт и чего ждать дальше.



3. Ну и, конечно, планирование: лист «План контактов». Тут все просто — пишем проект, дату будущего контакта и тему. Статус указывает, произошел контакт или еще нет, либо плановый контакт отменен.


На листе «Звонки на сегодня» уже поинтереснее в плане формул — выбирается с одной стороны все будущие контакты (а те, что на сегодня подсвечиваем цветом: в условном форматировании ставим, что условие равно =today() ) а во втором столбце подсвечиваем красным те, что просрочены. По формуле видно, что как только статус на странице с плановыми контактами изменится на «Проведен» или «Отменен», из списка пропущенных они уйдут.


Таким образом, чтобы всегда быть в курсе происходящего и видеть картинку по всем проектам, мне достаточно просто записывать результаты всех своих контактов, заполнять план контактов и отмечать, когда они произошли.
Скажу вам, что после начала учета видение бизнеса меняется кардинальным образом, как и подход к продажам. Контакты с лидами становятся периодическими и системными (а не только во время панических атак на тему «Мы скоро разоримся!111!!!!»)

Сам шаблон файла можете скачать тут

Всем успешного ведения внутренних продаж!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330870/


Метки:  

Что угрожает информационной безопасности или обзор форума PHDays VII 2017 в Москве

Среда, 14 Июня 2017 г. 13:07 + в цитатник
В конце мая в Москве прошел ежегодный форум по практической безопасности PHDays VII, организованный компанией Positive Technologies. Форум посетили около 5000 участников из самых разных стран. Мы — компания ООО “ИНФОРИОН” — также приняли участие в форуме и хотим рассказать о самых, на наш взгляд, интересных докладах:

image

Лазейки в прошивке ядра LTE-модема (Андрей Ловянников)

Андрей Ловянников выступил с докладом по анализу прошивки ядра LTE-модема Huaiwei E3372. В результате анализа было получено устройство с полностью отключенным шифрованием трафика. Анализ происходил по следующей схеме: выявление технической документации об устройстве; выявление архитектуры микропроцессора; определение работающих операционных систем; выявление основных API системы, связанных с GSM; выявление функций, отвечающих за шифрование.

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

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

Методы защиты JAVA-приложений и их обход (Филипп Лебедев, Андрей Ловянников)

Популярные JAVA –приложения не так надежны, как кажутся на первый взгляд. Несмотря на то, что у приложений существует несколько методов защиты, их можно обойти. Филипп Лебедев и Андрей Ловянников из компании ASP рассмотрели следующие методы:

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

А также был рассмотрен наиболее интересный случай защиты JAVA-приложения:

• Bootstrap Classloader;
• Extension Classloader;
• System Classloader – загружает основные классы приложения;
• Secured Classloader – шифрует и расшифровывает загружаемые классы;
• Classloader 1;
• …
• Classloader N.

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

Взлом учетных записей в WhatsApp и Telegram (Роман Заикин)

Роман Заикин доказал, WEB-версии WhatsApp и Telegram весьма уязвимы. Атаки вирусов направлены, прежде всего, на получение контроля над аккаунтами пользователей в указанных сетях. В основе реализации атаки лежит принцип End-to-End шифрования, в результате которого сервер не знает и не может знать, какие данные подвержены пересылке по каналу связи, вследствие чего проверка пересылаемых данных невозможна. WhatsApp и Telegram хранят историю сообщений на своих серверах (за исключением секретных чатов Telegram), вследствие чего, получив доступ к отрыктой сессии клиентской стороны, становится возможным чтение всей истории сообщений, получение и отправка новых сообщений. Роман воспользовался данными фактами и модифицировал доступные для загрузки MIME-типы данных в WEB-версии WhatsApp. Был сформирован гибрид картинки и HTML-страницы с JavaScript-кодом, отсылающим на подконтрольный атакующему бэкэнд данные об открытых сессиях на клиентской стороне, после чего Роман успешно продемонстрировал данную атаку на примере WhatsApp. Для выявления уязвимости Telegram потребовалось создать гибрид описанной выше страницы HTML с JavaScript-кодом и MP4-файлом. После чего, предполагаемая «жертва» должна была открыть зараженный документ в новой вкладке, и активировать вирус. Этот сценарий атаки был аналогичным образом продемонстрирован участникам форума.

Знакомимся с уязвимостями macOS – 2016 (Патрик Уордл)

Патрик Уордл – бывший сотрудник АНБ и NASA – представил свой доклад, описывающий наиболее популярные зловреды для операционной системы macOS. В силу меньшей распространенности данной операционной системы, под macOS существует куда меньше вредоносного програмнного обеспечения, чем под Windows, однако его количество продолжает расти. Наиболее ярким примером оказался шифровальщик KeRanger. Злоумышленники взломали официальный сайт торрент-клиента Transmission, разместили в программе свой код, пересчитали хеш-суммы и переподписали цифровой подписью дистрибутив, после чего выложили его на официальный сайт, что привело к заражению машин. Зловред шифровал файлы в системе и требовал выкуп размером в 1 биткоин. Еще одним характерным примером из доклада стала установка на машину жертвы старой версии брандмауэра LittleSnitch, содержащей опасную уязвимость и имеющую доступ к функциям ядра системы. Автор описал основные распространения зловредов в системе и осветил основные способы защиты: утилита Gatekeeper – блокировщик неподписанного кода; утилиты KnockKnock / BlockBlock – мониторы демонов и событий в системе.

DDoS-атаки в 2016-2017: переворот (Артем Гавриченков)

Артем Гавриченков в своем докладе обратил внимание общественности на современные возможности DDoS-атак, а также привел краткий экскурс в историю их модификаций. В своем докладе он привел список наиболее распространенных уязвимых протоколов (DNS, LDAP, NetBIOS и т.д.), многие из которых проектировались в то время, когда о безопасности никто не думал. Автор обратил внимание на характер старых DDoS атак: маленький запрос к серверу генерировал непропорционально большой ответ, вследствие чего не требовалось большое количество нод для выведения сервера из строя. Новые атаки используют большое количество зараженных машин и “умных” вещей, объединенных в ботнеты, для атаки на сервисы. Были сделаны выводы об архитектурах сетей, предсказано усиление DDoS-атак вследствие распростанения интернета вещей (IoT).

Взлом в прямом эфире: как хакеры проникают в ваши системы (Себастиан Шрайбер)

Доклад Себастиана Шрайбера был более похож на некий перформанс, нежели на технический доклад. Себастиан описал и продемонстрировал ряд впечатляющих атак:

• DOS-атаку на WEB-сервер (посылка специально сформированных запросов останавливала обработку входящих соединений вследствие ошибки SSL);
• перехват и воспроизведение сообщений беспроводных клавиатур и мышек с помощью Raspberry Pi и радиоантенны;
• собственные модификации зловредов на основе распространенного фреймворка для создания зловредов под Android (демонстрация включала в себя аналог криптолокера WannaCry, шпионские функции со снятием снимков с фотокамер устройства и их загрузкой на удаленный сервер);
• посылку SMS-сообщений от произвольного отправителя (был выбран случайный человек в зале, ему было послано SMS-сообщение с номера 900, принадлежащего Сбербанку);
• атаки на USB-ключи со встроенной реализацией стойкого ассиметричного шифрования (атаки направлены не на схему шифрования, а на слабую реализацию оной);
• обход сигнатурных проверок антивирусов (с помощью аналога утилиты Veil Evasion).

Антология антифрода: переход к математическим моделям с применением элементов искусственного интеллекта (Алексей Сизов)

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

Уязвимости мобильной связи (Дмитрий Курбатов)

Дмитрий Курбатов и его коллеги в своем докладе, посвященном уязвимостям сетей мобильной связи, показали реальные угрозы, поджидающие любого пользователя мобильных сетей 2G, 3G, 4G. В докладе были подробно описаны уязвимости протокола SS7 (2G и 3G сети) при относительной легкости их реализации, был показан целый спектр атак на пользователя – от простой атаки типа отказ в обслуживании и раскрытия местоположения пользователя до перехвата SMS и голосовых сообщений. Авторы описали уязвимости протокола DIAMETER (4G) и показали, что большинство описанных ими атак возможно и в этом стандарте. Были описаны причины появления подобных угроз, а также даны рекомендации об отношении к мобильным сетям как к недоверенному каналу связи.

Обход проверки безопасности в магазинах мобильных приложений (Пауль Амар)

Пауль Амар представил свой доклад, посвященный обходу проверки безопасности в магазинах мобильных приложений. Автор описал цикл мобильной разработки с использованием инструментария Apache Cordova (Hybrid App), после чего продемонстрировал возможность удаленного обновления приложения в обход магазина мобильных приложений (App Store, Play Market и т.д.). Таким образом, подобный способ порождает новый спектр проблем в безопасности мобильных устройств.

С подробной программой конференции можно познакомиться на официальном сайте:
www.phdays.ru/program
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330866/


Метки:  

Издательство Питер. Летняя распродажа

Среда, 14 Июня 2017 г. 13:02 + в цитатник
image

Привет, Хаброжители! Настало время для очередной распродажи. Подробности внутри.

image

В хронологическом порядке представлены книги, вызвавшие интерес читателей за последние 2 месяца.

Отдельные категории на сайте — Классика Computer Science, Бестселлеры O'Reilly, Head First O'Reilly, Бестселлеры Manning, научные серии: New Science и Pop Science

Условия акции: 14-18 июня, скидка 30% на все бумажные книги по купону — Summer_Sale, скидка 50% на все электронные книги по купону — E-book_summer
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330862/


Метки:  

Microsoft на CodeFest 2017 — отчёт, слайды и видео докладов

Среда, 14 Июня 2017 г. 11:16 + в цитатник
Привет!
В этом году, в апреле, мы снова участвовали на CodeFest 2017, крутейшей за Уралом конференция разработчиков, тестировщиков, дизайнеров, менеджеров проектов и продуктов (с).

На этот раз от Microsoft было несколько докладчиков — Джеффри Рихтер (Microsoft Corporation), Андрей Беленко (Microsoft) и покорный слуга (Microsoft Россия). Коллеги из команды CodeFest выложили слайды, видео докладов и отчетное видео до ката. Под катом я собрал все доклады, в которых говорили о Microsoft.






Джеффри Рихтер, Partner Software Engineer, Microsoft/WintellectО Джеффри все сказано в Википедии. Сейчас он работает в команде Microsoft Azure Hyper-Scale и активно занимается Service Fabric. В докладе Джеффри рассказал про важные пункты и нюансы, которые необходимо учитывать при проектировании распределённых облачных приложений. Must see для архитекторов.

-> Посмотреть слайды и видео доклада «Architecting Distributed Cloud Applications»



Рафаэль Риальди много лет как Microsoft Most Valuable Professional, автор книг и популяризатор технологий. По разработке на С++, архитектуре программных систем, IoT — к нему. Рафаэль в этот раз рассказал несколько прекрасных докладов про .NET Core — один про использование с NodeJS, второй про поддержку .NET Core в Visual Studio 2017.

-> Посмотреть слайды и видео доклада про .NET Core и NodeJS
-> Посмотреть слайды и видео доклада про .NET Core в Visual Studio 2017



Андрей Беленко работает в Microsoft на должности Senior Program Manager. Работает с мобильными платформами и безопасностью. Доклад от представителя Microsoft по безопасности мобильных приложений с акцентом на iOS был тепло встречен аудиторией. :)
Были рассмотрены доступные механизмы защиты данных в iOS, антишаблоны при их использовании, распространенные проблемы и способы их избежать. Must see для разработчиков :)

-> Посмотреть слайды и видео доклада про безопасность мобильных приложений


Александр Белоцерковский, автор сей статьи, работает в Microsoft в России на должности технологического евангелиста. Разрабатывает на .NET, работает с Microsoft Azure с почти ее запуска и любит людей. В этот раз рассказал про свой pet project, который помогал разрабатывать своим американским коллегам как коммьюнити-проект.

-> Посмотреть слайды и видео доклада про модель акторов, Project Orleans, IoT и телеметрию



Сергей Звягин, ведущий разработчик в DevExpress. Фронтендер с прошлым бэкендера. Любит виртуальную реальность, и популяризирует её в России, а также является хабом, распределяющим официальные пряники DevExpress. В докладе Сергей рассказал про различные устройства VR/AR, разные проекты — успешные, не очень и те, которые так и остались красивой идеей. Был продемонстрирован Hololens, даны рекомендации.

-> Посмотреть слайды и видео доклада про виртуальную реальность, Hololens и общие вопросы индустрии



Дон Вибьер, еще один коллега из DevExpress, технологический евангелист из Microsoft Most Valuable Professional. Хардкорный разработчик и прекрасный собеседник — надеюсь, что он снова приедет на CodeFest в следующем году.

-> Посмотреть слайды и видео доклада про
Creating Desktop Apps for Windows, Mac OS and Linux with your favorite web-tools and Electron.

Из названия слова не выкинешь :)




Мет Атамель, Developer Advocate в Google.
Приятно видеть, что коллеги из индустрии рассказывают о том, как на их платформах строить решения на наших технологиях. Категорически рекомендую посмотреть интересующимся контейнеризированием ASP.NET Core на Kubernetes.

-> Посмотреть слайды и видео доклада про





Насколько я могу судить, это все доклады от нас и не от нас, раскрывающие технологии Microsoft. Хочу сказать, что благодаря отличной работе команды CodeFest, почти все доклады были прекрасны, а эффект демонстрации, судя по моим наблюдениям, каким-то образом сведён к минимуму. :)
А вы поедете на CodeFest 2018?

Никто ещё не голосовал. Воздержавшихся нет.

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

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

https://habrahabr.ru/post/330850/


Метки:  

В чем особенности работы дисков в NAS: экспресс-тест HDD WD Red

Среда, 14 Июня 2017 г. 11:09 + в цитатник
Это одна из историй о технологиях, которые отличают серию WD Red от обычных дисков. Они помогают повысить отклик системы, не дают выпасть диску из массива и позволят ему беспроблемно работать в круглосуточном режиме. Плюс мы сделали базовые тесты производительности самих дисков и их работы в WD MY CLOUD DL2100. Читать далее

https://habrahabr.ru/post/330804/


Метки:  

Пишем простой драйвер под Windows для блокировки USB-устройств

Среда, 14 Июня 2017 г. 10:26 + в цитатник
Вряд ли пользователь домашнего ПК заинтересуется тем, чтобы блокировать устройства на своем ПК. Но если дело касается корпоративной среды, то все становится иначе. Есть пользователи, которым можно доверять абсолютно во всем, есть такие, которым можно что-то делегировать, и есть те, кому доверять совсем нельзя. Например, вы заблокировали доступ к Интернету одному из пользователей, но не заблокировали устройства этого ПК. В таком случае пользователю достаточно просто принести USB-модем, и Интернет у него будет. Т.е. простым блокированием доступа к Интернету дело не ограничивается.

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

В этой статье я расскажу немного теоретическую часть, на основе которой все строится, и расскажу принцип самого решения.

Также полные исходные коды могут быть найдены в папке USBLock хранилища git по адресу: https://github.com/anatolymik/samples.git.

Структура DRIVER_OBJECT


Для каждого загруженного драйвера система формирует структуру DRIVER_OBJECT. Этой структурой система активно пользуется, когда отслеживает состояние драйвера. Также драйвер отвечает за ее инициализацию, в частности за инициализацию массива MajorFunction. Этот массив содержит адреса обработчиков для всех запросов, за которые драйвер может отвечать. Следовательно, когда система будет посылать запрос драйверу, она воспользуется этим массивом, чтобы определить, какая функция драйвера отвечает за конкретный запрос. Ниже представлен пример инициализации этой структуры.
for ( ULONG i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
	DriverObject->MajorFunction[i] = DispatchCommon;
}
DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = DispatchCleanup;
DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;
DriverObject->DriverUnload = DriverUnload;
DriverObject->DriverExtension->AddDevice = DispatchAddDevice; 

Такая инициализация обычно выполняется при вызове системой точки входа драйвера, прототип которой изображен ниже.
NTSTATUS DriverEntry( PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath ); 

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

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

Обратите внимание на то, что в поле DriverExtension->AddDevice устанавливается адрес обработчика, который вызывается всякий раз, когда система обнаруживает новое устройство, за работу которого драйвер отвечает. Данное поле может быть оставлено непроинициализированным, в таком случае драйвер не сможет обрабатывать это событие.

Более подробно данная структура описана по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff544174(v=vs.85).aspx.

Структура DEVICE_OBJECT


Структура DEVICE_OBJECT представляет ту или иную функциональность драйвера. Т.е. эта структура может представлять физическое устройство, логическое устройство, виртуальное устройство или просто некий функционал, предоставляемый драйвером. Поэтому когда система будет посылать запросы, то в самом запросе она будет указывать адрес этой структуры. Таким образом, драйвер сможет определить, какой функционал от него запрашивается. Если не использовать такую модель, тогда драйвер может обрабатывать только какую-нибудь одну функциональность, а в современном мире это недопустимо. Прототип функции, которая обрабатывает конкретный запрос, приведена ниже.
NTSTATUS Dispatch( PDEVICE_OBJECT DeviceObject, PIRP Irp ); 

Массив MajorFunction ранее упомянутой структуры DRIVER_OBJECT содержит адреса обработчиков именно с таким прототипом.

Сама структура DEVICE_OBJECT всегда создается драйвером при помощи функции IoCreateDevice. Если система посылает запрос драйверу, то она всегда направляет его какому-либо DEVICE_OBJECT, как это следует из вышепредставленного прототипа. Также, прототип принимает второй параметр, который содержит адрес IRP-структуры. Эта структура описывает сам запрос, и она существует в памяти до тех пор, пока драйвер не завершит его. Запрос отправляется драйверу на обработку при помощи функции IoCallDriver как системой, так и другими драйверами.

Также со структурой DEVICE_OBJECT может быть связано имя. Таким образом, этот DEVICE_OBJECT может быть найден в системе.

Более подробно структура DEVICE_OBJECT описана по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff543147(v=vs.85).aspx. А структура IRP описана по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff550694(v=vs.85).aspx.

Фильтрация


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


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

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

PnP менеджер


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

Когда драйвер той или иной шины обнаруживает устройства на своих интерфейсах, то для каждого дочернего устройства он создает DEVICE_OBJECT. Этот DEVICE_OBJECT также называют Physical Device Object или PDO. Затем посредством функции IoInvalidateDeviceRelations он уведомляет PnP менеджер о том, что произошли изменения на шине. В ответ на это PnP менеджер посылает запрос с minor кодом IRP_MN_QUERY_DEVICE_RELATIONS с целью запросить список дочерних устройств. В ответ на этот запрос драйвер шины возвращает список PDO. Ниже изображен пример такой ситуации.


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

Как только PnP менеджер получит список всех PDO, он по отдельности соберет всю необходимую информацию об этих устройствах. Например, будет послан запрос с minor кодом IRP_MN_QUERY_ID. Посредством этого запроса PnP менеджер получит идентификаторы устройства, как аппаратные, так и совместимые. Также PnP менеджер соберет всю необходимую информацию о требуемых аппаратных ресурсах самим устройством. И так далее.

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

Следующая задача PnP — это запуск драйвера устройства. Если драйвер не был ранее установлен, тогда PnP будет ожидать установки. Иначе, при необходимости, PnP загрузит его и передаст ему управление. Ранее упоминалось, что поле DriverExtension->AddDevice структуры DRIVER_OBJECT содержит адрес обработчика, который вызывается всякий раз, когда система обнаруживает новое устройство. Прототип этого обработчика изображен ниже.
NTSTATUS DispatchAddDevice( 
	PDRIVER_OBJECT DriverObject, 
	PDEVICE_OBJECT PhysicalDeviceObject 
); 

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

В задачу обработчика входит создание DEVICE_OBJECT и его прикрепление к PDO. Прикрепленный DEVICE_OBJECT также называют Functional Device Object или FDO. Именно этот FDO и будет отвечать за работу устройства и представление его интерфейсов в системе. Ниже представлен пример, когда PnP завершил вызов драйвера, отвечающего за работу устройства.


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

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

Также, когда драйвер шины определяет, что произошли изменения на шине, он посредством функции IoInvalidateDeviceRelations уведомляет PnP о том, что следует заново собрать информацию о подключенных устройствах. В этот момент драйвер не удаляет ранее созданный PDO. Просто при получении запроса с minor кодом IRP_MN_QUERY_DEVICE_RELATIONS он не включит этот PDO в список. Затем PnP на основании полученного списка опознает новые устройства и устройства, которые были отключены от шины. PDO отключенных устройств драйвер удалит тогда, когда PnP пошлет запрос с minor кодом IRP_MN_REMOVE_DEVICE. Для драйвера этот запрос означает, что устройство более никем не используется, и оно может быть безопасно удалено.

Более подробную информацию о модели драйверов WDM можно найти по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff548158(v=vs.85).aspx.

Суть решения


Суть самого решения заключается в создании верхнего фильтра класса USB-шины. Зарезервированные классы можно найти по адресу: https://msdn.microsoft.com/en-us/library/windows/hardware/ff553419(v=vs.85).aspx. Нас интересует класс USB с GUID равным 36fc9e60-c465-11cf-8056-444553540000. Как гласит MSDN, этот класс используется для USB хост контроллеров и хабов. Однако практически это не так, этот же класс используется, например, flash-накопителями. Это немного добавляет нам работы. Код обработчика AddDevice представлен ниже.
NTSTATUS UsbCreateAndAttachFilter( 
	PDEVICE_OBJECT PhysicalDeviceObject, 
	bool UpperFilter 
) {

	SUSBDevice*		USBDevice;
	PDEVICE_OBJECT		USBDeviceObject = nullptr;

	ULONG			Flags;

	NTSTATUS		Status = STATUS_SUCCESS;

	PAGED_CODE();

	for ( ;; ) {

		// если нижний фильтр уже прикреплен, тогда здесь больше делать нечего
		if ( !UpperFilter ) {
			USBDeviceObject = PhysicalDeviceObject;
			while ( USBDeviceObject->AttachedDevice ) {
				if ( USBDeviceObject->DriverObject == g_DriverObject ) {
					return STATUS_SUCCESS;
				}
				USBDeviceObject = USBDeviceObject->AttachedDevice;
			}
		}

		// создаем фильтр
		Status = IoCreateDevice(
			g_DriverObject,
			sizeof( SUSBDevice ),
			nullptr,
			PhysicalDeviceObject->DeviceType,
			PhysicalDeviceObject->Characteristics,
			false,
			&USBDeviceObject
		);
		if ( !NT_SUCCESS( Status ) ) {
			break;
		}

		// инициализируем флаги созданного устройства, копируем их из объекта к 
		// которому прикрепились
		Flags = PhysicalDeviceObject->Flags & 
		 (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE);
		USBDeviceObject->Flags |= Flags;

		// получаем указатель на нашу структуру
		USBDevice = (SUSBDevice*)USBDeviceObject->DeviceExtension;

		// инициализируем деструктор
		USBDevice->DeleteDevice = DetachAndDeleteDevice;

		// инициализируем обработчики
		for ( ULONG i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++ ) {
			USBDevice->MajorFunction[i] = UsbDispatchCommon;
		}
		USBDevice->MajorFunction[IRP_MJ_PNP] = UsbDispatchPnp;
		USBDevice->MajorFunction[IRP_MJ_POWER] = UsbDispatchPower;

		// инициализируем семафор удаления устройства
		IoInitializeRemoveLock( 
			&USBDevice->Lock, 
			USBDEVICE_REMOVE_LOCK_TAG, 
			0, 
			0 
		);

		// заполняем структуру
		USBDevice->SelfDevice = USBDeviceObject;
		USBDevice->BaseDevice = PhysicalDeviceObject;
		USBDevice->UpperFilter = UpperFilter;

		// инициализируем paging семафор
		USBDevice->PagingCount = 0;
		KeInitializeEvent( &USBDevice->PagingLock, SynchronizationEvent, true );

		// прикрепляем устройство к PDO
		USBDevice->LowerDevice = IoAttachDeviceToDeviceStack( 
			USBDeviceObject, 
			PhysicalDeviceObject 
		);
		if ( !USBDevice->LowerDevice ) {
			Status = STATUS_NO_SUCH_DEVICE;
			break;
		}

		break;

	}

	// в зависимости от результата делаем

	if ( !NT_SUCCESS( Status ) ) {

		// отчистку

		if ( USBDeviceObject ) {
			IoDeleteDevice( USBDeviceObject );
		}

	} else {

		// или сбрасываем флаг инициализации
		USBDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;

	}

	return Status;

}

static NTSTATUS DispatchAddDevice( 
	PDRIVER_OBJECT DriverObject, 
	PDEVICE_OBJECT PhysicalDeviceObject 
) {

	UNREFERENCED_PARAMETER( DriverObject );

	return UsbCreateAndAttachFilter( PhysicalDeviceObject, true );

}

Как следует из примера, мы создаем DEVICE_OBJECT и прикрепляем его к PDO. Таким образом, мы будем перехватывать все запросы, направленные к USB-шине.

В нашу задачу входит перехватывать запросы с minor кодом IRP_MN_START_DEVICE. Код обработчика этого запроса изображен ниже.
static NTSTATUS UsbDispatchPnpStartDevice( SUSBDevice* USBDevice, PIRP Irp ) {

	bool		HubOrComposite;
	NTSTATUS	Status;

	PAGED_CODE();

	for ( ;; ) {

		// проверить, позволено ли устройству работать, также обновить
		// информацию об устройстве, является ли оно хабом или композитным
		Status = UsbIsDeviceAllowedToWork( &HubOrComposite, USBDevice );
		if ( !NT_SUCCESS( Status ) ) {
			break;
		}
		USBDevice->HubOrComposite = HubOrComposite;

		// продвинуть запрос
		Status = ForwardIrpSynchronously( USBDevice->LowerDevice, Irp );
		if ( !NT_SUCCESS( Status ) ) {
			break;
		}

		break;

	}

	// завершаем запрос
	Irp->IoStatus.Status = Status;
	IoCompleteRequest( Irp, IO_NO_INCREMENT );

	// и освобождаем устройство
	IoReleaseRemoveLock( &USBDevice->Lock, Irp );

	return Status;

}

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

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

Все упомянутые определения выполняются на основе идентификаторов устройств.

Заключение


Несмотря на свою простоту в моем случае данный драйвер достаточно эффективно решает поставленную задачу. Хотя из недостатков следует выделить обязательную перезагрузку после того, как список разрешенных устройств будет обновлен. Чтобы устранить этот недостаток, драйвер потребуется несколько усложнить. Еще большим недостатком является полное блокирование устройства, а не частичное. Описание, представленное выше, не раскрывает всех деталей реализации. Сделано это было намеренно, и упор был сделан больше на саму концепцию. Желающие разобраться во всем до конца могут ознакомиться с исходным кодом.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330844/


Метки:  

[Перевод] RESTForms — REST API для ваших классов InterSystems Cach'e

Среда, 14 Июня 2017 г. 09:19 + в цитатник

В этой статье я хотел бы представить проект RESTForms — универсальный REST API бэкэнд для современных веб-приложений.
Идея проекта проста — после написания нескольких REST API стало понятно, что, как правило, REST API состоит из двух частей:


  • Работа с хранимыми данными
  • Пользовательская бизнес-логика

И, хотя вам придется писать свою собственную бизнес-логику, RESTForms предоставляет все необходимое для работы с хранимыми данными из коробки.


Варианты использования:


  • У Вас уже есть модель данных в Cach'e, и Вы хотите представить некоторую (или всю) хранящуюся информацию в форме REST API.
  • Вы разрабатываете новое Cach'e приложение и хотите сразу предоставлять REST API.

Клиент


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


Возможности


Что уже можно делать с RESTForms:


  • CRUD по классу данных — возможно получить метаданные класса, создавать, обновлять и удалять свойства класса.
  • CRUD по объекту — возможно получать, создавать, обновлять и удалять объекты.
  • R по наборам (через SQL) — защита от SQL-инъекций.
  • Selfdiscovery – сначала вы получаете список доступных классов, после этого вы можете получить метаданные класса, и на основе этих метаданных выполнять CRUD запросы по объекту.

Пути


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


URL Описание
test Тестовый метод
form/info Список классов
form/info/all Метаинформация всех классов
form/info/:class Метаинформация одного класса
form/field/:class Добавить свойство в класс
form/field/:class Изменить свойство
form/field/:class/:property Удалить свойство
form/object/:class/:id Получить объект
form/object/:class/:id/:property Получить свойство объекта
form/object/:class Создать объект
form/object/:class/:id Обновить объект из динамического объекта
form/object/:class Обновить объект из объекта класса
form/object/:class/:id Удалить объект
form/objects/:class/:query Выполнить SQL запрос
form/objects/:class/custom/:query Выполнить пользовательский SQL запрос

Установка


  1. Загрузите и импортируйте из последнего релиза на странице релизов 20161.xml (для Cach'e 2016.1) или 201162.xml (для Cach'e 2016.2 +) в любую область
  2. Создайте новое веб-приложение /forms с классом брокером Form.REST.Main
  3. Откройте http://localhost:57772/forms/test?Debug в браузере, чтобы проверить установку (должен выводиться {"Status": "OK"}, возможно, будет запрошен пароль).
  4. Если Вы хотите сгенерировать тестовые данные, вызовите:
    do ##class(Form.Util.Init).populateTestForms()

Как начать использовать RESTForms?


  1. Импортируйте проект из GitHub (рекомендуется: добавить его как подмодуль (submodule) в ваш собственный репозиторий или просто загрузить релиз).
  2. Для каждого класса, который Вы хотите представить через RESTForms:
    • Унаследуйте от класса адаптера (Form.Adaptor)
    • Определите свойство, используемое в качестве "имени" объекта
    • Определите свойства, которые надо отображать
  3. Используйте RESTForms API для работы с хранимым классом. Как пример сразу можно получить UI для ваших хранимых классов — RESTForms UI. Ниже пример того, как RESTForms UI отображает тестовый класс Person

Cписок объектов класса:
список объектов класса


И объект класса:
объект класса


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


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


http://localhost:57772/forms/form/info

Вы получите в ответ что-то вроде этого:


[
   { "name":"Company",     "class":"Form.Test.Company" },
   { "name":"Person",      "class":"Form.Test.Person"  },
   { "name":"Simple form", "class":"Form.Test.Simple"  }
]

На данный момент с RESTForms поставляются 3 тестовых класса. Давайте посмотрим метаданные для формы Person (класс Form.Test.Person). Чтобы получить эти данные, нужно вызвать:


http://localhost:57772/forms/form/info/Form.Test.Person

В ответ Вы получите метаданные класса:
{
   "name":"Person",
   "class":"Form.Test.Person",
   "displayProperty":"name",
   "objpermissions":"CRUD",
   "fields":[
      {
         "name":"name",
         "type":"%Library.String",
         "collection":"",
         "displayName":"Name",
         "required":0,
         "category":"datatype"
      },
      {
         "name":"dob",
         "type":"%Library.Date",
         "collection":"",
         "displayName":"Date of Birth",
         "required":0,
         "category":"datatype"
      },
      {
         "name":"ts",
         "type":"%Library.TimeStamp",
         "collection":"",
         "displayName":"Timestamp",
         "required":0,
         "category":"datatype"
      },
      {
         "name":"num",
         "type":"%Library.Numeric",
         "collection":"",
         "displayName":"Number",
         "required":0,
         "category":"datatype"
      },
      {
         "name":"аge",
         "type":"%Library.Integer",
         "collection":"",
         "displayName":"Age",
         "required":0,
         "category":"datatype"
      },
      {
         "name":"relative",
         "type":"Form.Test.Person",
         "collection":"",
         "displayName":"Relative",
         "required":0,
         "category":"form"
      },
      {
         "name":"Home",
         "type":"Form.Test.Address",
         "collection":"",
         "displayName":"House",
         "required":0,
         "category":"serial"
      },
      {
         "name":"company",
         "type":"Form.Test.Company",
         "collection":"",
         "displayName":"Company",
         "required":0,
         "category":"form"
      }
   ]
}

Что все это значит?


Метаданные класса:


  • name – отображаемое имя класса
  • class – название хранимого класса
  • displayProperty – свойство объекта, использующееся при отображении объекта
  • objpermissions – что может делать пользователь с объектом. В нашем случае пользователь может читать (Read), создавать (Create) новые объекты, изменять (Update) и удалять (Delete) существующие объекты.

Метаданные свойств:


  • name – название свойства
  • collection – является ли класс коллекцией (списком или массивом)
  • displayName – отображаемое имя свойства
  • required – обязательное ли свойство
  • type – тип свойства
  • category – категория типа свойства. Это обычные категории класса Cach'e, кроме всех классов, наследующихся от адаптера RESTForms — они имеют категорию "form"

Определение класса выглядит следующим образом:
/// Test form: Person
Class Form.Test.Person Extends (%Persistent, Form.Adaptor)
{

/// Отображаемое имя формы
Parameter FORMNAME = "Person";

/// Разрешения
/// Объекты этого класса могут быть Созданы (C), Получены (R), Изменены (U), и удалены (D)
Parameter OBJPERMISSIONS As %String = "CRUD";

/// Свойство "имени" объекта
Parameter DISPLAYPROPERTY As %String = "name";

/// Свойство сортировки по-умолчанию
Parameter FORMORDERBY As %String = "dob";

/// Имя
Property name As %String(DISPLAYNAME = "Name");

/// Дата рождения
Property dob As %Date(DISPLAYNAME = "Date of Birth");

/// Число
Property num As %Numeric(DISPLAYNAME = "Number") [ InitialExpression = "2.15" ];

/// Возраст, вычисляется автоматически
Property аge As %Integer(DISPLAYNAME = "Age") [ Calculated, SqlComputeCode = { set {*}=##class(Form.Test.Person).currentAge({dob})}, SqlComputed, SqlComputeOnChange = dob ];

/// Вычисление возраста
ClassMethod currentAge(date As %Date = "") As %Integer [ CodeMode = expression ]
{
$Select(date="":"",1:($ZD($H,8)-$ZD(date,8)\10000))
}

/// Родственник - ссылка на другой объект класса Form.Test.Person
Property relative As Form.Test.Person(DISPLAYNAME = "Relative");

/// Адрес
Property Home As Form.Test.Address(DISPLAYNAME = "House");

/// Ссылка на компания, в которой человек работает
/// http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GOBJ_relationships
Relationship company As Form.Test.Company(DISPLAYNAME = "Company") [ Cardinality = one, Inverse = employees ];
}

Добавляем класс в RESTForms


Чтобы сделать хранимый класс доступным для RESTForms, надо:


  1. Добавить наследование от Form.Adaptor
  2. Добавить параметр FORMNAME со значением – имя класса
  3. Добавить параметр OBJPERMISSIONS – что можно делать с объектами класса (CRUD)
  4. Добавить параметр DISPLAYPROPERTY – имя свойства, используемое для отображения имени объекта
  5. Добавить параметр FORMORDERBY – свойство по умолчанию для сортировки по запросам с использованием RESTForms
  6. Для каждого свойства, которое хочется видеть в метаданных, надо добавить параметр свойства DISPLAYNAME

После того как мы сгенерировали некоторые тестовые данные (см. Установку, шаг 4), давайте получим Person с идентификатором 1. Чтобы получить объект, вызовем:


http://localhost:57772/forms/form/object/Form.Test.Person/1

И получим ответ:


{
   "_class":"Form.Test.Person",
   "_id":1,
   "name":"Klingman,Rhonda H.",
   "dob":"1996-10-18",
   "ts":"2016-09-20T10:51:31.375Z",
   "num":2.15,
   "аge":20,
   "relative":null,
   "Home":{
      "_class":"Form.Test.Address",
      "House":430,
      "Street":"5337 Second Place",
      "City":"Jackson"
   },
   "company":{
      "_class":"Form.Test.Company",
      "_id":60,
      "name":"XenaSys.com",
      "employees":[
         null
      ]
   }
}

Чтобы изменить объект (в частности, свойство num), вызовем:


PUT http://localhost:57772/forms/form/object/Form.Test.Person

С телом:


{
   "_class":"Form.Test.Person",
   "_id":1,
   "num":3.15
}

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


Теперь, давайте создадим новый объект. Вызовем:


POST http://localhost:57772/forms/form/object/Form.Test.Person

С телом:


{
   "_class":"Form.Test.Person",
    "name":"Test person",
    "dob":"2000-01-18",
    "ts":"2016-09-20T10:51:31.375Z",
    "num":2.15,
    "company":{ "_class":"Form.Test.Company", "_id":1 }
}

Если создание объекта завершилось успешно, RESTForms вернёт идентификатор:


{"Id": "101"}

В противном случае, будет возвращена ошибка в формате JSON. Обратите внимание на то, что на персистентные свойства необходимо ссылаться через свойства _class и _id.


Демо


Вы можете попробовать RESTForms онлайн здесь (пользователь: Demo, пароль: Demo).
Кроме того, есть приложение RESTFormsUI — редактор для данных RESTForms. Демо стенд доступен здесь (пользователь: Demo, пароль: Demo). Скриншот списка классов:
список классов


Заключение


RESTForms выполняет почти всю работу, требуемую от REST API в отношении хранимых классов.


Что же дальше?


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


Ссылки


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

https://habrahabr.ru/post/330822/


Метки:  

[Перевод] Если вы это читаете, то работа у вас наверняка не тяжелая

Среда, 14 Июня 2017 г. 09:13 + в цитатник


Небезызвестный Джейсон Фрайд из Basecamp разразился дискуссионным эссе о работе, вызвавшем ожесточенные споры на зарубежных сайтах. Мы в Alconost поспешили его перевести.

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

Давайте будем честными.

Тяжелая работа — это собирать овощи по восемь часов в день при 30-градусной жаре.

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

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

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

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

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

Если большую часть времени работать вам нравится, то работа у вас наверняка не тяжелая.

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

Работать сверхурочно не значит работать тяжело — это значит просто работать сверх обычного времени. Уделяемое какой-либо задаче время никак не определяет тяжесть этой задачи.

Мозговой штурм — это не тяжело. Увольнять сотрудников — это не тяжело. Объединять усилия — это не тяжело. Ездить на конференции — это не тяжело. Маневрировать в потоке машин — тоже не тяжело, ведь это просто вождение. Возможно, это утомительно, но — не тяжело.

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

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

Но от этого работа тяжелой не становится.

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

Из комментариев к статье:
«Мне это напомнило прочитанный где-то хороший совет на случай, когда в не самом важном разговоре повисла пауза.
1. Спросите, чем человек занимается.
2. Затем (неважно, что вам ответили) скажите: «Тяжело вам, наверное!»
Собеседник сразу приободряется и продолжает болтать».

О переводчике

Перевод статьи выполнен в Alconost.

Alconost занимается локализацией приложений, игр и сайтов на 68 языков. Переводчики-носители языка, лингвистическое тестирование, облачная платформа с API, непрерывная локализация, менеджеры проектов 24/7, любые форматы строковых ресурсов, перевод технических текстов.

Мы также делаем рекламные и обучающие видеоролики — для сайтов, продающие, имиджевые, рекламные, обучающие, тизеры, эксплейнеры, трейлеры для Google Play и App Store.

Подробнее: https://alconost.com

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

https://habrahabr.ru/post/330802/


Метки:  

[Перевод] От чего зависит интересность геймплея?

Среда, 14 Июня 2017 г. 09:08 + в цитатник
image

Думаю, каждый согласится, что ощущения от игрового процесса в разных играх отличаются. Одни игры кажутся более «игровыми», чем другие. Просто сравните игру в Super Mario с чем-нибудь вроде Dear Esther, и, как мне кажется, ясно, что в первой по ощущениям больше геймплея, чем в последней. Чем вызвано это чувство? Моя гипотеза такова: разница в возможности планирования.

Чем больше игрок может планировать в игре заранее, тем более захватывающей она кажется.

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



Вот как обычно выглядит мир для рыбы:



Они могут видеть всего на 1-2 метра перед собой, и часто ситуация ещё хуже. Это значит, что рыбы не могут строить далёкие планы. Они просто реагируют на то, что возникает перед их глазами, в этом и заключается вся их жизнь. Если бы жизнь рыбы была игрой, то это была бы ограниченная версия Guitar Hero со случайным шумом вместо музыки. Именно так и происходит рыбалка. Рыбы не думают, как мы, ими управляют реакции с жёстко заданной логикой.

Б'oльшую часть истории Земли таковой была жизнь организмов. Но после этого прошло около 400 миллионов лет эволюции. Рыбы стали переселяться на сушу. Внезапно их зрению предстала следующая картина:



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

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

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

Продемонстрировать вышесказанное можно на следующем примере:



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

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



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

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

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

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

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

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

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

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



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

Существует модель увлечённости игроков, которая называется PENS (Player Experience of Need Satisfaction), и она довольно строго исследована. Для оценки того, что игрок думает об игре, она использует следующие критерии.

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

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

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

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

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

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

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

Подобным же образом, если в игре есть только линейная последовательность событий, то планировать остаётся не так много. Чтобы игрок мог составлять планы, у него должны быть варианты выбора. Это не применимо к случаям, когда возможна только определённая цепочка действий. Такие случаи – это типичный пример отсутствия свободы, и они не удовлетворяют игрока с точки зрения свободы. Повторюсь – планирование и независимость связаны очень замысловатыми способами.

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



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

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

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

Эти дополнительные функции могут также придать остроты обычному геймплею. Вспомните, как нужно думать о том, какое оружие использовать в The Last of Us. У игрока есть мусор, из которого можно крафтить предметы, и все эти предметы позволяют применять в бою различные тактики. И поскольку невозможно применить их все одновременно, игроку нужно делать выбор. Принятие такого решения — это всегда создание плана, поэтому чувство вовлечённости в игру усиливается.

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



И, наконец, я хочу рассказать о том, что же собственно привело меня к размышлениям о планировании. Началось с того, что я начал сравнивать SOMA с Amnesia: The Dark Descent. При создании SOMA нам было очень важно добавить как можно больше интересных функций, и мы хотели, чтобы у игрока было множество разных занятий. Думаю, будет справедливо сказать, что в SOMA есть более широкий диапазон взаимодействий и б'oльшая вариативность, чем в Amnesia: The Dark Descent. Но несмотря на это, многие люди жаловались на то, что SOMA слишком походила на «симулятор ходьбы» (walking simulator). Не могу вспомнить ни одного похожего комментария об Amnesia. Почему так вышло?

Сначала я не мог этого понять, но потом я выделил основные различия между этими играми:

  • Система душевного состояния в Amnesia.
  • Управление ресурсами освещения/здоровья.
  • Головоломки, распределённые по разным уровням.

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

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

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

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



У «обычной» игры, использующей стандартный основной геймплейный цикл, не возникает таких проблем. Возможность планирования встроена в образ реализации классического геймплея. Разумеется, это знание можно использовать для того, чтобы сделать такие игры лучше, но это ни в коем случае не обязательно. Я думаю, именно по этой причине планирование как фундаментальный аспект игр столь недооценено. Единственный хороший пример, который мне удалось найти [1] — эта статья Дуга Чёрча (Doug Church), где он объясняет всё следующим образом:

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

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

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

Единственный случай, который примерно подходит к этому принципу – обсуждение жанра «симулятора погружения» (Immersive Sim). Возможно, это не очень удивительно, веть Дуг Чёрч сыграл большую роль в становлении этого жанра. Например, непредвиденный геймплей, которым особенно славятся симуляторы погружения, сильно связан со способностью понимания мира и планирования действий на основе этой информации. Такой тип идеала дизайна чётко виден в таких современных играх, как Dishonored 2 [2]. Поэтому довольно очевидно, что дизайнеры игр думают в этой системе координат. Но для меня гораздо менее очевидно, почему это рассматривается не как фундаментальная часть того, что делает игры увлекательными, а как некое подмножество дизайна.

Как я упоминал выше, возможно, так получается потому, что при участии в «обычном» геймплее большой объём планирования возникает автоматически. Однако это не относится к случаю нарративных игр. На самом деле, нарративные игры часто считаются «не совсем играми» в том отношении, что они содержат не так много обычного геймплея по сравнению с такими играми, как Super Mario. По этой причине очень часто обсуждается, должно ли в играх быть больше истории или геймплея, как будто они обязательно исключают друг друга. Однако я считаю, что причина сохранения такого большого расхождения в том, что мы не совсем правильно понимаем, как работает геймплей в нарративных играх. Как я говорил в предыдущих постах, с точки зрения дизайна мы застряли в локальных максимумах.

Идея о том, что планирование – фундаментальная основа игр даёт нам решение этой проблемы. Не будем говорить: «нарративным играм нужен геймплей получше», скажем: «нарративным играм нужно лучшее планирование».



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

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

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

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

  1. Оценка информации, полученной из пространств системы и истории.
  2. Создание ментальной модели на основании имеющейся информации.
  3. Моделирование последствий выполнения определённого действия.
  4. Если последствия выглядят хорошими, отправка игре соответствующего ввода (например, нажатие на кнопку).

Многое из этого происходит подсознательно. С точки зрения игрока он видит эту последовательность в основном как «выполнение чего-то» и не осознаёт происходящий мысленный процесс. Но на самом деле он всегда происходит, когда игрок делает что-то в игре, будь то прыжок через пропасть в Super Mario или строительство дома в Sim City.

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



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

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

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

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

Давайте вкратце рассмотрим реальные примеры из настоящих игр.



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

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

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

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

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



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

Теперь сравним эти два примера с такой игрой, как Dear Esther:



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

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

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

Сравните два следующих плана:

1) «Сначала я соберу 10 предметов, чтобы увеличить показать доверия персонажа X,
что позволит мне достичь необходимого показателя „дружбы“, после чего X станет частью моей команды. Это даст мне бонус в 10 очков дальнего боя».

2) «Если я помогу X с уборкой комнаты, то мы сможем стать с ней друзьями. Это будет замечательно, ведь тогда я смогу позвать её в путешествие вместе с нами. Похоже, она меткий стрелок, и с ней я буду чувствовать себя гораздо спокойнее».

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



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

Примечания:

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

2) Стив Ли (Steve Lee) провёл в этом году на GDC превосходную лекцию «Подход к целостному дизайну уровней», на которой мы много говорили о преднамеренности действий игрока. Это ещё одна концепция, тесно связанная с планированием.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330810/


Метки:  

[recovery mode] Работа с сервером с помощью Alamofire на Swift

Среда, 14 Июня 2017 г. 00:27 + в цитатник


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


Содержание



Зачем



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


Существует нативный инструмент для этого — URLSession, но работать с ним немного сложнее, чем хотелось бы. Для облегчения этого процесса существует framework Alamofire — это обвертка над URLSession, которая сильно упрощает жизнь при работе с сервером.


Установка



Воспользуемся CocoaPods т.к. с ним очень легко и быстро работать.


Добавим в Podfile:


pod 'Alamofire'

Для использования Alamofire версии 4+ необходимы следующие требования:


  • iOS 9.0+ / macOS 10.11+ / tvOS 9.0+ / watchOS 2.0+
  • Xcode 8.0+
  • Swift 3.0+
  • CocoaPods 1.1.0+

Так же нам необходимо добавить use_frameworks!.


Так будет выглядеть минимальный Podfile:


platform :ios, '9.0'
use_frameworks!

target 'Networking' do

    pod 'Alamofire'

end

Настройка доступа HTTP



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


Мы будем работать с сервером http://jsonplaceholder.typicode.com, а он работает по http. Поэтому нам надо открыть доступ для него.


Для тренировки мы откроем доступ для всех сайтов. Открытие для одного сайта в данной статье не буду рассматривать.


Открываем Info.plist и добавляем в него App Transport Security Settings и внутрь этого параметра необходимо добавить Allow Arbitrary Loads, со значением YES.


Выглядеть это должно следующим образом:


![Info.plist](/Users/zdaecqzezdaecq/Downloads/Работа с запросам с помощью Alamofire/info_plist.png)


Или вот Source code, который необходимо добавить:


правой кнопкой мыши на Info.plist -> Open as -> Source code

NSAppTransportSecurity

    NSAllowsArbitraryLoads
    

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



Открываем проект.


Не забудьте, что нам нужно открыть Networking.xcworkspace, а не Networking.xcodeproj, который создался после pod install

Открываем файл ViewController.swift и заменяем его код на следующий:


import UIKit
import Alamofire

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        request("http://jsonplaceholder.typicode.com/posts").responseJSON { response in
            print(response)
        }
        print("viewDidLoad ended")
    }
}

Запускайте проект.
В консоли выведится:


viewDidLoad ended
SUCCESS: (
        {
        body = "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto";
        id = 1;
        title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit";
        userId = 1;
    },
    ...

Поздравляю! Вы сделали первый запрос на сервер и получили от него ответ с результатом.


Подробнее о минимуме



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


import Alamofire


Собственно сам метод запроса:


request


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


"http://jsonplaceholder.typicode.com/posts"


Метод responseJSON говорит о том, что ответ от сервера нам нужен в JSON формате.


Далее в клоужере мы получаем ответ от сервера и выводим его в консоль:


{ response in
    print(response)
}

Важно заметить, что код в этом клоужере происходит асинхронно и выполнится после выхода из viewDidLoad, тем самым строка viewDidLoad ended в консоль выводится раньше.


Методы HTTP



На самом деле мы сделали GET запрос, но нигде этого не указывали. Начиная с Alamofire 4 по умолчанию выполняется GET запрос. Мы может его явно указать, заменив соответствующий код на следующий:


request("http://jsonplaceholder.typicode.com/posts", method: .get)

Как Вы уже поняли в параметре method: передается метод запроса и от него зависит, как мы будем общаться с сервером. Чаще всего мы будем:


  1. получать (GET)
  2. изменять (PUT)
  3. отправлять, создавать (POST)
  4. удалять (DELETE)

данные с сервера.


Подробнее про эти и другие методы HTTP можете почитать на википедии:


  1. Протокол HTTP
  2. Методы HTTP

Alamofire.request



Функция request — глобальная функция, поэтому мы можем ее вызывать через Alamofire.request или просто request.


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


request(URLConvertible, method: HTTPMethod, parameters: Parameters?, encoding: ParameterEncoding, headers: HTTPHeaders?)

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


URLConvertible


Первым параметром является путь запросу и он принимает URLConvertible. (Ваш КЭП)


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


public protocol URLConvertible {
    func asURL() throws -> URL
}

и он уже реализован для следующих типов данных:


  • String
  • URL
  • URLComponents

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


HTTPMethod


Это enum, со всеми возможными типами запросов:


public enum HTTPMethod: String {
    case options = "OPTIONS"
    case get     = "GET"
    case head    = "HEAD"
    case post    = "POST"
    case put     = "PUT"
    case patch   = "PATCH"
    case delete  = "DELETE"
    case trace   = "TRACE"
    case connect = "CONNECT"
}

Как мы уже выяснили: по умолчанию .get
Тут ничего сложного, идем дальше.


Parameters


Это простой Dictionary:


public typealias Parameters = [String: Any]

Через параметры мы будем передавать данные на сервер (например, для изменения или создания объектов).


ParameterEncoding


Это тоже протокол с одной функцией:


public protocol ParameterEncoding {
    func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest
}

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


Этот протокол реализуют:


  • URLEncoding
  • JSONEncoding
  • PropertyListEncoding

По умолчанию у нас URLEncoding.default.


В основном этот параметр не используется, но иногда бывает нужен, в частности JSONEncoding.default для кодировки в JSON формате и PropertyListEncoding.default в XML.


Я заметил, что Int не отправляется без JSONEncoding.default, но возможно это было в Alamofire 3, а может из-за сервера. Просто имейте это ввиду.


HTTPHeaders


Это также Dictionary, но другой типизации:


public typealias HTTPHeaders = [String: String]

Headers(заголовки) нам будут необходимы в основном для авторизации.


Подробнее про заголовки на википедии:


Заголовки HTTP


DataRequest


На выходе мы получаем объект типа DataRequest — сам запрос. Его мы можем сохранить, передать, как параметр в другую функцию при необходимости, донастроить и отправить. Об этом далее.


Обработка ответа



Ответ от сервера может прийти, как с результатом, так и с ошибкой. Для того, чтобы их различать у ответа есть такие параметры, как statusCode и contentType.


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


Ручная обработка ответа



Если мы не настраивали валидацию, то в


responseJSON.response?.statusCode


у нас будет статус код ответа, а в


responseJSON.result.value


будет результат, если ответ пришел без ошибки, и в


responseJSON.result.error


если с ошибкой.


request("http://jsonplaceholder.typicode.com/posts").responseJSON { responseJSON in

    guard let statusCode = responseJSON.response?.statusCode else { return }
    print("statusCode: ", statusCode)

    if (200..<300).contains(statusCode) {
        let value = responseJSON.result.value
        print("value: ", value ?? "nil")
    } else {
        print("error")
    }
}

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


Коды состояния HTTP


Настройка запроса



Для этого у DataRequest есть 4 метода:


  1. validate(statusCode: _ )
  2. validate(contentType: _ )
  3. validate(клоужер для ручной валидации)
  4. validate()

Рассмотрим только последний, потому что его нам будет хватать для 95% запросов.


Взглянем на его реализацию:


public func validate() -> Self {
    return validate(statusCode: self.acceptableStatusCodes).validate(contentType: self.acceptableContentTypes)
}

Видим, что он состоит из двух других валидаций:


  1. self.acceptableStatusCodes — возвращает массив статус кодов(Int) из range 200..<300
  2. self.acceptableContentTypes — возвращает массив допустимых хедеров(String)

У DataResponse есть параметр result, который может сказать нам, пришел ответ с ошибкой или с результатом.


Итак, применим валидацию для запроса:


request("http://jsonplaceholder.typicode.com/posts").validate().responseJSON { responseJSON in

    switch responseJSON.result {
    case .success(let value):
        print(value)
    case .failure(let error):
        print(error)
    }
}

Если у нас не будет вылидации запроса (validate()), то result всегда будет равен .success, за исключением ошибки из-за отсутствия интернета.


Можно обрабатывать ответ обоими способами, но я настоятельно рекомендую пользоваться настройкой валидации запроса — будет меньше ошибок!


Обработка результата ответа



Ответ от сервера чаще всего бывает в виде одного объекта или массива объектов.


Если мы посмотрим на тип результата ответа, то увидим тип Any. Чтобы из него что-то достать — нам надо его привести к нужному формату.


В логах мы замечали, что у нас приходит массив Dictionary, поэтому к нему и будем приводить:


request("http://jsonplaceholder.typicode.com/posts").responseJSON { responseJSON in

    switch responseJSON.result {
    case .success(let value):
        print("value", value)

        guard let jsonArray = responseJSON.result.value as? [[String: Any]] else { return }
        print("array: ", jsonArray)
        print("1 object: ", jsonArray[0])
        print("id: ", jsonArray[0]["id"]!)
    case .failure(let error):
        print(error)
    }
}

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


В отдельном файле создадим структуру Post:


struct Post {
    var id: Int
    var title: String
    var body: String
    var userId: Int
}

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


request("http://jsonplaceholder.typicode.com/posts").responseJSON { responseJSON in

    switch responseJSON.result {
    case .success(let value):

        guard let jsonArray = value as? Array<[String: Any]> else { return }

        var posts: [Post] = []

        for jsonObject in jsonArray {
            guard
                let id = jsonObject["id"] as? Int,
                let title = jsonObject["title"] as? String,
                let body = jsonObject["body"] as? String,
                let userId = jsonObject["userId"] as? Int
            else {
                return
            }
            let post = Post(id: id, title: title, body: body, userId: userId)
            posts.append(post)
        }

        print(posts)

    case .failure(let error):
        print(error)
    }
}

Парсинг объекта внутри запроса выглядит очень плохо + нам придется всегда копировать эти строки для каждого запроса. Чтобы от этого избавиться создадим конструктор init?(json: [String: Any]):


init?(json: [String: Any]) {

    guard
        let id = json["id"] as? Int,
        let title = json["title"] as? String,
        let body = json["body"] as? String,
        let userId = json["userId"] as? Int
    else {
        return nil
    }

    self.id = id
    self.title = title
    self.body = body
    self.userId = userId
}

Он может вернуть nil, если сервер нам что-то не вернул


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


request("http://jsonplaceholder.typicode.com/posts").responseJSON { responseJSON in

    switch responseJSON.result {
    case .success(let value):

        guard let jsonArray = value as? Array<[String: Any]> else { return }
        var posts: [Post] = []

        for jsonObject in jsonArray {
            guard let post = Post(json: jsonObject) else { return }
            posts.append(post)
        }
        print(posts)

    case .failure(let error):
        print(error)
    }
}

Пойдем еще дальше и в Post добавим метод обработки массива:


static func getArray(from jsonArray: Any) -> [Post]? {

    guard let jsonArray = jsonArray as? Array<[String: Any]> else { return nil }
    var posts: [Post] = []

    for jsonObject in jsonArray {
        if let post = Post(json: jsonObject) {
            posts.append(post)
        }
    }
    return posts
}

Тогда метод запроса примет следующий вид:


request("http://jsonplaceholder.typicode.com/posts").responseJSON { responseJSON in

    switch responseJSON.result {
    case .success(let value):
         guard let posts = Post.getArray(from: value) else { return }
         print(posts)

    case .failure(let error):
        print(error)
    }
}

Конечный вариант файла Post.swift:


import Foundation

struct Post {

    var id: Int
    var title: String
    var body: String
    var userId: Int

    init?(json: [String: Any]) {

        guard
            let id = json["id"] as? Int,
            let title = json["title"] as? String,
            let body = json["body"] as? String,
            let userId = json["userId"] as? Int
        else {
            return nil
        }

        self.id = id
        self.title = title
        self.body = body
        self.userId = userId
    }

    static func getArray(from jsonArray: Any) -> [Post]? {

        guard let jsonArray = jsonArray as? Array<[String: Any]> else { return nil }
        var posts: [Post] = []

        for jsonObject in jsonArray {
            if let post = Post(json: jsonObject) {
                posts.append(post)
            }
        }
        return posts
    }
}

Для тех кто уже разобрался в работе с flatMap, то функцию getArray можно написать так:


    static func getArray(from jsonArray: Any) -> [Post]? {
        guard let jsonArray = jsonArray as? Array<[String: Any]> else { return nil }
        return jsonArray.flatMap { Post(json: $0) }
    }

Разные типы ответов



responseJSON


Как отправлять запрос и получать ответ в виде JSON с помощью responseJSON мы научились. Теперь разберем в каком еще виде можем получить ответ.


responseData


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


request("http://jsonplaceholder.typicode.com/posts").responseData { responseData in

    switch responseData.result {
    case .success(let value):
        guard let string = String(data: value, encoding: .utf8) else { return }
        print(string)

    case .failure(let error):
        print(error)
    }
}

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


responseString


Здесь все просто. Ответ придет в виде JSON строки. По факту он делает, то, что мы написали выше в responseData:


request("http://jsonplaceholder.typicode.com/posts").responseString { responseString in

    switch responseString.result {
    case .success(let value):
        print(value)

    case .failure(let error):
        print(error)
    }
}

response


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


request("http://jsonplaceholder.typicode.com/posts").response { response in
    guard
        let data = response.data,
        let string = String(data: data, encoding: .utf8)
        else { return }
    print(string)
}

Выведется строка, если ответ пришел без ошибки.


responsePropertyList


Существует еще метод .responsePropertyList. Он нужен для получения распарсенного plist файла. Я им еще не пользовался и не нашел тестого сервера, чтобы привести пример. Просто знайте, что он есть или можете сами с ним разобраться по аналогии с другими.


Прогресс загрузки



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


Вместо https://s-media-cache-ak0.pinimg.com/originals/ef/6f/8a/ef6f8ac3c1d9038cad7f072261ffc841.jpg можете вставить любую ссылку на фотографию. Желательно большую, чтобы запрос не выполнился моментально и вы увидели сам процесс.

request("https://s-media-cache-ak0.pinimg.com/originals/ef/6f/8a/ef6f8ac3c1d9038cad7f072261ffc841.jpg")
    .validate()
    .downloadProgress { progress in
        print("totalUnitCount:\n", progress.totalUnitCount)
        print("completedUnitCount:\n", progress.completedUnitCount)
        print("fractionCompleted:\n", progress.fractionCompleted)
        print("localizedDescription:\n", progress.localizedDescription)
        print("---------------------------------------------")
    }
    .response { response in
        guard
            let data = response.data,
            let image = UIImage(data: data)
            else { return }
        print(image)
}

Класс Progress — это класс стандартной библиотеки.

В логах будет выводиться прогресс в виде блоков:


totalUnitCount:
 2113789
completedUnitCount:
 2096902
fractionCompleted:
 0.992011028536907
localizedDescription:
 99% completed

Мы можем поделить completedUnitCount на totalUnitCount и получим число от 0 до 1, которое будет использоваться в UIProgressView, но за нас это уже сделали в свойстве fractionCompleted.


Чтобы увидеть саму картинку, поставьте breakpoint на строку с print(image) и нажмите на Quick Look (кнопка с глазом) в дебаг панели:


![Debug console](/Users/zdaecqzezdaecq/Downloads/Работа с запросам с помощью Alamofire/image_quick_look.png)


Примеры



Создание объекта (POST)



Самое простое создание объекта на сервере выглядит так:


let params: [String: Any] = [
    "title": "new post",
    "body": "some news",
    "userId": 10
]

request("http://jsonplaceholder.typicode.com/posts", method: .post, parameters: params).validate().responseJSON { responseJSON in

    switch responseJSON.result {
    case .success(let value):
        guard
            let jsonObject = value as? [String: Any],
            let post = Post(json: jsonObject)
            else { return }
        print(post)

    case .failure(let error):
        print(error)
    }
}

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

Обновление объекта (PUT)



При обновлении объекта, его id зачастую прописывается не в параметре, а в пути запроса (~/posts/1):


let params: [String: Any] = [
    "title": "new post",
    "body": "some news",
    "userId": 10
]

request("http://jsonplaceholder.typicode.com/posts/1", method: .put, parameters: params).validate().responseJSON { responseJSON in

    switch responseJSON.result {
    case .success(let value):
        guard
            let jsonObject = value as? [String: Any],
            let post = Post(json: jsonObject)
            else { return }
        print(post)

    case .failure(let error):
        print(error)
    }
}

Конечно, могут сделать и через параметр, но это будет не по REST. Подробнее про REST в статье на хабре:


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


Загрузка фотографии на сервер (multipartFormData)



Так выглядит загрузка фотографии на сервер:


let image = UIImage(named: "some_photo")!
let data = UIImagePNGRepresentation(image)!

let httpHeaders = ["Authorization": "Basic YWNjXzE4MTM2ZmRhOW*****A=="]

upload(multipartFormData: { multipartFormData in
    multipartFormData.append(data, withName: "imagefile", fileName: "image.jpg", mimeType: "image/jpeg")
}, to: "https://api.imagga.com/v1/content", headers: httpHeaders, encodingCompletion: { encodingResult in
    switch encodingResult {
    case .success(let uploadRequest, let streamingFromDisk, let streamFileURL):
        print(uploadRequest)
        print(streamingFromDisk)
        print(streamFileURL ?? "streamFileURL is NIL")

        uploadRequest.validate().responseJSON() { responseJSON in
            switch responseJSON.result {
            case .success(let value):
                print(value)

            case .failure(let error):
                print(error)
            }
        }

    case .failure(let error):
        print(error)
    }
})

Ужасно не правда ли?


Давайте разберем, что за что отвечает.


Я закинул фотографию с именем some_photo в Assets.xcassets

Создаем объект картинки и преобразуем ее в Data:


let image = UIImage(named: "some_photo")!
let data = UIImagePNGRepresentation(image)!

Создаем словарь для передачи токена авторизации:


let httpHeaders = ["Authorization": "Basic YWNjXzE4MTM2ZmRhOW*****A=="]

Это необходимо т.к. сервис www.imagga.com требует авторизацию, чтобы залить картинку.


Чтобы получить свой токен, вам необходимо всего лишь зарегистрироваться на их сайте и скопировать его из своего профиля по ссылке: https://imagga.com/profile/dashboard

До этого мы использовали метод request. Сдесь же используется метод upload. Первым параметром идет клоужер для присоединения нашей картинки:


upload(multipartFormData: { multipartFormData in
    multipartFormData.append(data, withName: "imagefile", fileName: "image.jpg", mimeType: "image/jpeg")
}

Следующими параметрами идут URL и headers:


to: "https://api.imagga.com/v1/content", headers: httpHeaders

Дальше идет клоужер с закодированным запросом:


encodingCompletion: { encodingResult in
    switch encodingResult {
    case .success(let uploadRequest, let streamingFromDisk, let streamFileURL):
        print(uploadRequest)
        print(streamingFromDisk)
        print(streamFileURL ?? "streamFileURL is NIL")
        ...

    case .failure(let error):
        print(error)
    }
})

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


Про потоки говорить не буду, достаточно редкая штука. Пока вы просто увидите, что эти две переменные равны false и nil соответственно.

Дальше мы должны отправить запрос в привычной для нас форме:


uploadRequest.validate().responseJSON() { responseJSON in
    switch responseJSON.result {
    case .success(let value):
        print(value)

    case .failure(let error):
        print(error)
    }
}

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


{
    status = success;
    uploaded =     (
                {
            filename = "image.jpg";
            id = 83800f331a7f97e41e0f0b70bf7847bd;
        }
    );
}

filename может не отличаться, а id будут.

Итог



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

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

https://habrahabr.ru/post/330760/


Метки:  

Внимание, Хабрахабр: IBM открывает бесплатный доступ к большому количеству своих ресурсов

Вторник, 13 Июня 2017 г. 23:52 + в цитатник


Компания IBM уже много лет публикует материалы о своих разработках на Хабрахабре. Мы рады, что многие статьи интересны читателям. Тем не менее, мы также не раз видели желание наших читателей начать работу с сервисами и ресурсами IBM на бесплатной основе. И сегодня мы рады сообщить о том, что теперь многие пользователи смогут получить бесплатный доступ к большинству ресурсов Академического хаба, IBM Bluemix, когнитивным технологиям IBM Watson и Интернета вещей.

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

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

Для этого нужно зайти на Академический хаб: Onthehub.com/ibm и в поисковом окне найти свою организацию. Рекомендуется использовать название, фигурирующее на сайте организации.



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



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

А теперь остается только получить подтверждение. Если возникнут сложности – вы можете написать в техническую поддержку, кликнув Help в правом верхнем углу. В разделе приведены ответы по наиболее распространенным ошибкам. Гиперссылка Contact Us открывает кнопку для телефонного звонка, а также окно для отправки сообщения.

После регистрации доступными окажется большое количество ресурсов и возможностей. Вы получите доступ к популярным курсам, флагманским программным продуктам и сервисам компании, таким как контейнерные технологии, инструменты разработки, когнитивные технологии IBM Watson, IBM SPSS, IBM Rational DOORS, ILOG, IBM Spectrum LSF Suite for HPC, IBM Watson Analytics, IBM Watson Explorer, IBM Cognos, IBM Sterling Order Management, IBM Connections, IBM Worklight Studio, IBM Rational Rhapsody, и многое другое.

Успехов в их освоении. Александр Сорокин, менеджер университетских проектов в России и СНГ, IBM Восточная Европа \ Азия

email: alexander_sorokin@ru.ibm.com
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330838/


Метки:  

Дизайн как всемирный язык 21 века

Вторник, 13 Июня 2017 г. 18:59 + в цитатник
Когда человек говорит, что знает всего один язык, то на самом деле он знает их куда больше. Почти наверняка он понимает простейший язык жестов, а также профессиональный сленг своих сотрудников. Если он меломан, то обязательно понимает особенный неповторимый язык своей любимой музыки и, в конце концов, понимает современный цифровой язык общения с современными интерфейсами смартфона, компьютера, банкомата, ноутбука.

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

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

image

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

image

С помощью данного примера мне бы хотелось показать, что же именно относится к форме языка и его акцентам, а что составляет саму сущность и смысл послания; ведь многим изначально кажется, что единственное требование к форме — полное соответствие гайдлайнам iOS/ Material Design, но в дальнейшем мы увидим, что это не совсем так.

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

image

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

image

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

image

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

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

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

image

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

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

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

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

Посмотрим, были ли способы не столь витиевато и громоздко донести первоначальное послание владельцев авиакомпании до своих клиентов:

Регистрация

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

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

Рассмотрим экран после верификации почты:

image

И тут же в соседней вкладке Личного Кабинета — все сначала:

image

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

Облегчение поиска

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

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

а) Сибирь
Красноярск (Емельяново)
Иркутск IKT
Новый уренгой (Ягельное)
Тюмень (Рощино) TJM
Курган KRO
Уфа UFA
Магнитогорск MQF
Анадырь DYR
Сургут SGC

б) Юг
Ставрополь STW
Махачкала MCX
Минеральные воды MRV
Сочи (Адлер) AER
Душанбе DYU
Ташкент TAS
Ереван (Звартноц) EVN
Краснодар (Пашковская) KRR
Ростов-на-дону ROV

в) Центр
Москва (Внуково) VKO
Белгород EGO
Мурманск (Основной)
Санкт-Петербург (Пулково) LED
Казань (Основной) KZN

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

image

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

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

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

image

Дизайн может быть разным и даже… любым!

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

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

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

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

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

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

image

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

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

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

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

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

Здесь я трактую супрематизм как выражение мироустройства через простейшие формы, как предельный минимализм, упрощающий объекты любой сложности до простейших фигур и линий.
Если при этом реализована привязка банковской карты, то почему бы и нет? Хотя бы в виде А\Б тестирования?

image

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

image

В классическом приложении первым шагом только формируется запрос к системе, в нашем же варианте запрос отправляется при загрузке, и первый пользовательский экран уже является ответом, предвосхищая пользовательское “А что я могу тут сделать?”

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

image

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

image

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

image

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

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

image

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

image

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

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

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

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

image

Выводы

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

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

Говорить с пользователем нужно в первую очередь функционально, понятно и лаконично.

Статья, вдохновившая меня на эту небольшую зарисовку.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330834/


Метки:  

Microsoft MVP – путь просветленного самурая

Вторник, 13 Июня 2017 г. 18:49 + в цитатник
Специалиста высшего класса отличают не только опыт и умение, но и готовность делиться знаниями с другими. Настоящий эксперт точно знает, что обучая, он сам профессионально растёт. В технических сообществах экспертиза ценится особенно – она не просто даёт самореализоваться и приносит пользу другим, но и позволяет получить нечто большее. Например, стать MVP-экспертом Microsoft и ценным лидером сообщества. Это почётное звание, значок на фотографии и горизонт колоссальных возможностей. О них мы и поговорили с действующими MVP и с руководителем программы Microsoft Most Valuable Professional в странах Центральной и Восточной Европы Гербертом Шопником. Читать далее

https://habrahabr.ru/post/330768/


Метки:  

[Перевод] Адаптация Xamarin.Forms к разработке корпоративных и B2E приложений

Вторник, 13 Июня 2017 г. 17:44 + в цитатник
Немного об авторе:
Adam Pedley (Microsoft MVP, Xamarin MVP, Xamarin Certified Developer)

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


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


Архитектура приложения


Я предполагаю, что большинство из вас уже слышали о MVVM и Dependency Injection. Я рекомендовал бы это для любой разработки на Xamarin.Forms, не только корпоративной. Использование MVVM с Dependency Injection, поможет вам создать качественное приложение на Xamarin.Forms. Как спроектировать архитектуру вашего приложения, если оно будет иметь очень большую кодовую базу — это еще одна история, но в этой статье она рассмотрена не будет.


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


API


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


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


Схема устройства слоя доступа к данным


Это защищает ваше приложение от изменений API и удаляет его как зависимость при модульном тестировании.


Сложная навигация


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


  1. Не позволяйте кнопке «Назад» вернуть пользователя на страницу входа в систему;
  2. Начать заполнение многостраничной формы, с возможностью уйти, затем вернуться и ожидать возобновления в том же состоянии;
  3. Предупреждать или останавливать навигацию, если пользователь не выполнил требуемые действия;
  4. Просмотр страницы, но не сохранение в навигационном стеке, когда пользователь двинулся дальше;
  5. Избегайте дублирования страниц в стеке навигации и загружайте существующие, если они есть.

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


Безопасность


Системы безопасности корпоративного класса, на самом деле, не более безопастны чем и стандартная система безопасности, обычно они сложнее, а следовательно повышается риск неправильной реализации. Вы можете обратиться к Citrix, Microsoft Online или Azure Active Directory. Если вам повезет, у вас будет хороший OAuth API.


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


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

Ключ шифрования должен быть сгенерирован мобильным приложением во время выполнения, а затем безопасно сохранен, например в KeyChain или KeyStore.


Убедитесь, что вы также следуете отраслевым стандартам, таким как OWASP Mobile Security Testing Guide.


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


B2C приложения в основном имеют роскошь говорить — «Вы должны быть подключены к Интернету», при использовании приложения. B2E приложения не всегда имеют такую возможность, например в шахтах или пробелы Wi-Fi зон в больших зданиях. Это означает, что вам потребуется какое-то автономное хранилище. В этом случае, чтобы избежать осложнений, лучше всего всегда запускать приложение из базы данных с помощью службы синхронизации, чтобы обеспечить подключение к API.


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


DevOps


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


Как DevOps связан с разработкой на Xamarin.Forms? По сути, никак, но есть вещи которые могут сделать вашу жизнь проще.


  1. Создание конфигурационных файлов основанных на JSON, а не жестко закодированные. Это поможет при развертывании в различных окружениях, например тестировании или UAT;
  2. Настройка VSTS (или другие) и подключить к HockeyApp или Mobile Center;
  3. Настройка аналитики в вашем приложении для записи релевантных метрик по сравнению с ожидаемым результатом.

Аналитика


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


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


Управление мобильными устройствами


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


Заключение


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


  1. Абстрактные вызовы API;
  2. Спланируйте навигацию перед началом разработки;
  3. Требования безопасности, вероятно, будут выше;
  4. Ожидать автономного использования;
  5. Настройте свой проект, для простого DevOps;
  6. Убедитесь, что аналитика настроена и соответствует ожиданиям бизнеса;
  7. Аккаунт для MDM’s в вашем процессе Continuous Delivery.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330828/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1005 1004 [1003] 1002 1001 ..
.. 1 Календарь