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

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

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

[Из песочницы] Действия при приходе на работу — прием дел, актуализация, документирование, аудит

Суббота, 22 Июля 2017 г. 15:06 + в цитатник
С интересом прочел Аудит ИТ-инфраструктуры — как быть новичку, но мне показалось, что список дел при аудите и приеме на работу (особенно, если оттуда уже давно уволились все, кто что-то помнил) гораздо шире.

Если у вас в организации процессы не построены — то этот текст для вас бесполезен. Если построены — то тоже бесполезен. Почти Rifleman's Creed — Without me, my rifle is useless. Without my rifle, I am useless.

Каких-то стандартных пакетов управления всей архитектурой и техникой я не видел — что не удивительно, учитывая постоянное расхождение отчетности по бухгалтерии и техники по факту и общую сложность систем. Хорошо если ведется схема сети, учет паролей и прочее необходимое, есть какой-то учет что когда (сертификаты, оплата домена) истекает, но порой этого нет. Просто одни забыли спросить, другие не волновались насчет этого. У третьих оно было, но они уже уволились, а четвертые забили, вот и имеем что имеем.
Управление жизненным циклом, SCOM/SCSM — это немного другое, а ITIL
Service Asset and Configuration Management — это благие пожелания, не содержащие некий функционал.

Соответственно, первым делом при приходе на работу нужен аудит «для себя»

— Какие устройства где стоят, за что отвечают, есть ли к ним доступ (к web панели управления/ssh/ilo), если нет — то как его восстановить. Живы ли эти устройства, или стоят для учета.

— Кто ответственный за СКУД, общую безопасность, электричество, кондиционирование (обслуживание), водопроводы, пожарную сигнализацию. Когда последний раз проводилось обслуживание тех же кондиционеров. Какова надежность (запас мощности) кондиционеров (N+0, N+1).

— ИБП и батареи. Сколько держат (в часах), когда менялись батареи, когда была калибровка, есть ли извещение о срабатывании и прочем блекауте. Какова надежность (запас мощности) ИБП — (N+0, N+1).

— Как выстроено взаимодействие с соседними отделами и бизнесом как заказчиком сервисов.

— Как работает сервис деск.

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

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

Архивация и восстановление
Надо проверять все — что куда бекапится, какова глубина хранения, есть ли свободное место на системе хранения архивов, мониторится ли свободное место, попадает ли бекап в окно резервного копирования. Как идет восстановление — как выглядит процедура восстановления и вообще восстанавливается ли.
От имени какой УЗ идет архивация (особенно в случае агентов/сервиса бекапа в машинах), не многовато ли у нее прав (в каких группах состоит), есть ли у нее (и от нее) пароль и не стоит ли его сменить. Где она (в системе резервного копирования) прописана.
Есть ли регламент, в котором прописано и утверждено все вышеперечисленное.

Контроль прав, контроль служебных УЗ (учетных записей)
Кроме простой проверки «кто в группе доменных администраторов и почему», необходим контроль служебных УЗ. В том числе контроль какой сервис от какого имени стартует (если не стартует от системы), что со встроенными УЗ, что в какую группу включено и зачем, какие им (группам) делегированы права и куда.

AD
Роли AD — где (на каких серверах) лежат, что в журналах. Кто за какие сетевые сервисы (DHCP, DNS) отвечает. Аудит — есть ли, как устроен. Пересылка логов — каких, куда, и что там с ними происходит.

Готовьтесь изучать новый для вас предмет — инженерная археология / Конструкторско-технологическая археология (1)

Типовые дыры и костыли кривокурих админов локалхоста. Начиная от правленных host
ВНЕЗАПНО для меня выяснилось, что админы локалхоста не только правят файлы etc/host (ну ладно, кто не правил в детстве?), но еще этим и гордятся, и пишут об этом статьи.

Впрочем, с настройками DNS на DC бывает тот же стыд.
Не, ну как можно не прочитать технет?? (2)

ЗАПОМНИТЕ, ГРАЖДАНЕ!
Писать в \host\etc в продакшене надо тогда и только тогда, когда ты уже прочитал инструкцию, для Оракла и Veritas netbackup, дожав инструкциями по Veeam.

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

— Задачи в Tash scheduler и автозагрузке по серверам
— файлы HOST в частности и настройки DHCP и DNS в целом
— кому, как, куда и какие даны права в AD и Exchange.

Если с первым пунктом понятно, скачиваем Sysinternals Autoruns for Windows и поехали, то с вторым и третьим пунктом все сложней.

Внезапно для многих, в Microsoft Windows server нет кнопки «сделать хорошо». Даже скрипта makegood.ps1 нет — MS WS и AD как сервис не имеет каких-то встроенных готовых графических решений для отображения кому и куда делегированы права в AD, а использование powershell огорчает инфобезопасника и любителя GUI.
С другой стороны, необходимый инструментарий для этого есть —

Для просмотра делегирования прав по organizational unit (OU) — Active Directory OU Permissions Report:
This script generates a report of all Active Directory OU permissions in the domain. I would advise all Active Directory shops to review this report on a quarterly basis to make sure there are no surprise administrators lurking in your domain.
Лежит традиционно на технете.

Для просмотра раздачи прав Exchanhe вот — на том же технете
RBAC Role Group Membership Reporting
This PowerShell script will generate a report of the Role Based Access Control (RBAC) role groups in an Exchange Server organization.

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

Ссылки:
(1)
Индустриальная археология «Мценского уезда». Часть 1.
Индустриальная археология «Мценского уезда». Часть 2.

Корпоративная память и обратная контрабанда.
Копия этой же статьи со ссылками.
Оригинал в web.archive
Конструкторско-технологическая археология

(2)
Ссылка 1
Ссылка 2
или
Ссылка 3

и наконец собственно:

DNS: DNS servers on should include the loopback address, but not as the first entry
Impact
If the loopback IP address is the first entry in the list of DNS servers, Active Directory might be unable to find its replication partners. См. по ссылке

Вообще с доступностью первого DNS для CSV есть много интересного, но о этом может быть будет позже.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333910/


Метки:  

Какие языки наиболее востребованы в сфере финансов: мнения рекрутеров с Уолл-стрит

Суббота, 22 Июля 2017 г. 11:03 + в цитатник


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

Java


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

«Специалисты по Java нужны для выполнения разных задач: от разработки систем высокочастотной торговли и управления заявками до создания собственных платформ риск-менеджмента финансовых компаний», — говорит Джаред Батлер, глава финансово-технологического рекрутинга для Северной Америки в Selby Jennings. Язык Java также хорош для проведения симуляций и моделирования работы торговых стратегий, считает Джон Рид, старший исполнительный директор Robert Half Technology.

Кроме того, распространению Java и JavaScript в финансовом секторе способствует тренд на создание простых в использовании, быстрых и защищенных сайтов — так считает вице-президент Jay Gaines & Company Джина Шиллер.

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

Python


Этот язык программирования прошел долгий путь до того, как был впервые использован в программе Quartz Банка Америки и в системе Athena от J.P. Morgan. Python просто незаменим при создании аналитических инструментов и квантовых моделей, которые являются, по мнению Шиллер, важнейшими средствами, способствующими созданию эффективных торговых стратегий инвестиционных банков и хедж-фондов.

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

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

Банки Merrill Lynch и J.P. Morgan нанимают огромное количество Python-разработчиков. «Bank of America и J.P. Morgan построили большинство своих трейдинговых систем на Python и продолжают привлекать специалистов данного профиля. Другие банки и инвесткомпании начинают обращать больше внимания на Python-программистов», — сказал Ник Вермайер, главный технический рекрутер Pencom Systems.

C++/C#


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

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

Как и Java, С# может использоваться для решения разных задач, в том числе и для создания финансовых моделей. Этот язык находится на втором месте по степени «дефицитности» квалифицированных специалистов, что дает им привилегию и возможность получения большей заработной платы. Рид сказал, что разработчики С# могут получать на 9-10% больше денег относительно своих коллег-экспертов в других языках.

«С# все еще используется, часто квантами и при разработке быстродействующих торговых систем», — поясняет Кристиан Гловер Уилсон, вице-президент технологий и стратегии в Tigerspik.

Другие языки


Под другими языками программирования в этом материале имеются в виду SQL, PHP и ETL.

«Мы видим, что инвесткомпании нанимают и специалистов, обладающих разными навыками, от знания более старых технологий ETL, таких как Informatica, и до более современных инструментов для работы с большими данными, вроде Hadoop, HBase, HDFS, MapReduce, Pig, Hive, Impala, Flume», — говорит Батлер. «Технологии ETL по-прежнему важны для хранения данных, а также для хранения крупных финансовых массивов информации, используемых, в частности, инвестиционными банками в глобальных масштабах».

С другой стороны, спрос на Microsoft Windows Presentation Foundation (WPF) снижается, а HTML5, вместе с Hadoop, Cassandra и Scala, становятся более востребованными на Уолл-стрит…

«Популярность технологий для обработке данных, такие как Hadoop, Cassandra и Scala растет, мы видим, что все больше и больше финансовых организаций внедряют их», — сказал Вермейр. «C++ и C#, как правило становятся основными средствами разработки, интерес к работе с WPF ослабевает, а к использованию HTML5 — растет».

Вермайер поддержал эту позицию: «Мы также наблюдаем рост спроса на технологии по передаче крупных массивов данных, поскольку компании ежедневно сталкиваются с огромными объемами информации. Очень часто они необходимы в качестве сопутствующих технологий в дополнение к основным языкам программирования, таким как Java или Python. Наиболее востребованными крупными технологиями по работе с данными являются Cassandra, Spark и Hadoop».

Другие материалы по теме финансов и фондового рынка от ITinvest:


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

https://habrahabr.ru/post/333908/


Метки:  

[Из песочницы] Flat Cubik (развертка кубика Рубика на плоскость)

Суббота, 22 Июля 2017 г. 10:49 + в цитатник
Идея написать эту игру-головоломку появилась примерно в ноябре 2016 года. Надо сказать, что особых успехов в сборке реального кубика я не достигал никогда. Мой личный рекорд никогда не был меньше минуты. Но само устройство в начале 80-х произвело на меня сильное впечатление.

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

Скриншот
image

В качестве среды разработки был выбран фирменный Xcode, а в качестве языка — Swift. К тому времени у меня уже был опыт работы с этой средой и языком, поэтому особых сложностей само кодирование вызывать было не должно. Хотя, некоторые моменты алгоритмического характера требовали пеших прогулок и раздумывания над ними. Вот только один пример: на каждом шаге (ходе) пользователя нужно проверять собранность кубика. Если решать задачу в лоб, то можно просто пробегать по элементам массивов и сравнивать их на одинаковость.

Исходный массив (кубик собран, как в самом начале игры) представлен в виде:

var Tnew = [
    [[1, 1, 1], [1, 1, 1], [1, 1, 1]], // синий
    [[2, 2, 2], [2, 2, 2], [2, 2, 2]], // белый
    [[3, 3, 3], [3, 3, 3], [3, 3, 3]], // зеленый
    [[4, 4, 4], [4, 4, 4], [4, 4, 4]], // желтый
    [[5, 5, 5], [5, 5, 5], [5, 5, 5]], // оранжевый
    [[6, 6, 6], [6, 6, 6], [6, 6, 6]]  // красный
]

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

var Tnew = [
    [[5, 5, 5], [5, 5, 5], [5, 5, 5]], // оранжевый
    [[3, 3, 3], [3, 3, 3], [3, 3, 3]], // зеленый
    [[1, 1, 1], [1, 1, 1], [1, 1, 1]], // синий
    [[4, 4, 4], [4, 4, 4], [4, 4, 4]], // желтый
    [[2, 2, 2], [2, 2, 2], [2, 2, 2]], // белый
    [[6, 6, 6], [6, 6, 6], [6, 6, 6]]  // красный
]

Но при этом расположении надо считать, что кубик так же успешно собран.

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

При этом движение строки или столбца должно приводить в движение «связанные» с ним строки или столбцы. Все как во взрослом кубике — перемещаете одно — в движение вовлекаются и «соседи».

Но при использовании %device% мы, если и задумываемся над этим, то весьма мимолетно и не особо глубоко. Для нас это как часть картины мира, которая особо и не удивляет. Другое дело — программная модель! Тут уже надо создать искусственную реальность, а потому понимать «реальную реальность» надо достаточно полно.

Были изрисованы и исписаны десятки листов. Иногда заметки или идеи приходилось записывать просто на том, что есть под рукой, чтобы потом уже не потерять их насовсем. И где-то к началу апреля получился работающий прототип программы. Кубик можно было собирать. Но и правило 20 на 80 (или его вариант 30 на 70) работало по полной. Надо было доделать массу сервисных мелочей: таймер сборки, счетчик ходов, какую нибудь сигнализацию об окончании сборки, подключить Game Center. И подумать о возможной монетизации. Это было бы весьма приятным бонусом.

В итоге где то к середине мая программа была готова к тому, чтобы ее можно было начинать тестировать не только на устройстве разработчика. Был оплачен аккаунт разработчика и несколько избранных из разных городов и сёл планеты получили возможность «покрутить» плоский кубик на своих устройствах (программа распространялась через Test Flight).

Что касается локализации, то я сразу решил не делать никаких надписей на экране и тем самым уйти от этой проблемы. Пока это удается.
Экран весьма минималистичен. Пользователь видит классическую развертку кубика на плоскость в виде креста, четыре кнопки: собрать кубик, запутать кубик, сменить фон и показать Game Center. Ну а вверху два счетчика: ходы и время. Время стартует только после нажатия кнопки «Запутать». Если пользователь запутал кубик сам и потом собрал — считаются только ходы.

Впечатления от программы у «аудитории»


Естественно, что меня всегда интересовало мнение тех, кто тестировал программу. Кто-то говорил, что кубик надо делать в 3D, на что я отвечал, что такие варианты кубика в АппСторе уже есть и делать их очередной клон у меня нет никакого интереса. Видимо само магическое слово «3D» уже как то привлекало людей и они считали это хорошей идеей. Кто-то сразу понимал идею развертки. Однако, наблюдения за тестерами показали, что переход «3D -> 2D» у большинства нормальных людей вызывает не иллюзорные сложности. Даже те, кто довольно легко умеют собирать реальный кубик, не могли сразу собрать правильно даже одну грань. Не говоря уже о дальнейшей сборке. Впрочем, каждый может сам попробовать это на себе.

Забавно наблюдать за Game Center. Точнее за появление в нем новых пользователей. Эта штука просто нереально крута! Я сделал в GC две таблицы: время сборки и количество ходов. В них попадает любой, кто соберет кубик полностью. А если при дальнейших сборках какой то результат будет улучшаться, то он будет оставаться в соответствующей таблице. Довольно долгое время в таблицах были только мои результаты, записанные с устройств разных тестеров под их именами. И я потихоньку начал разочаровываться в человечестве. И вот не так давно в таблицы попал совершенно не известный мне персонаж. Сначала он находился в обоих таблицах в нижних строчках. Затем начал уверенно двигаться вверх. Примерно через пару суток он занял верхние строчки обоих таблиц с довольно потрясающими результатами: 1 минута 40 секунд и 80 шагов. Впрочем, его рекорд до сих пор никем не побит в рамках Flat Cubik.

И еще совсем недавно появился второй (!) собравший, который собрал Flat Cubik за 25 минут 01 секунду и 254 хода. И занял пока шестое место в рейтинге. При этом упорства в улучшении своих достижений он не проявляет. По крайней мере лучших результатов от него не появляется.

Что сейчас и дальнейшие планы


Первая версия программы попала в App Store в последних числах июня.
Первой ошибкой было ставить на программу цену в 1$. Первый день принес 6 платных скачиваний, потом число скачиваний упало до 2.
Можно ли считать это провалом? Очень на то похоже… Позже игра стала бесплатной и в настоящее время набрала около 200 скачиваний.
Рекламы нигде не было. Если не считать короткое сообщение в конференции iXBT (внутри одной из тем MacLife).

В дальнейшем планируется добавить баннер AdMob. Была идея сделать undo для ходов пользователя. А так же определенные варианты подсказок ходов. Пока с подсказками все находится на той же стадии прогулок и размышления. Те, кто знает, как собирать кубик, понимают, что от текущего состояния можно прийти к собранному совершенно разными путями.
Да вот хотя бы маленький пример: перестановка 3-х угловых элементов: я знаю вариант в 22 хода и вариант в 8 ходов. Сам использую 8-ми ходовку.

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

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

P.S.: iOS 10 была выбрана после потери нескольких дней на поиск проблемы во внутренних библиотеках Apple (может потом напишу про это отдельную заметку). Обнаружилось, что проблема отсутствует в версиях iOS, начиная с 10. Чтобы не обходить проблему в более ранних версиях iOS и было принято решение, что Flat Cubik будет работать на устройствах с iOS10+.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333906/


Метки:  

[Перевод] Увольнять, нанимать, повышать — культура вашей компании

Суббота, 22 Июля 2017 г. 10:18 + в цитатник
Некоторое время назад мне попалась увлекательная статься на тему корпоративной культуры, переводом которой я решил поделиться с пользователями Хабра. Автору статьи, на мой взгляд, удалось очень четко, пусть и немного брутально, сформулировать положение дел, релевантное для большинства компаний в современной мире, вне зависимости от географии, возраста компании или ее текущей капитализации. Мы в, банке зачастую сталкиваемся со схожими ситуациями, и, как в любой крупной организации, у нас есть представители всех четырех блоков квадранта Производительность – ценности. Не буду лукавить, мы только учимся работать с каждым из них, рекомендации автора статьи, пусть и не новые, кажутся мне достаточно полезными. Главное – вкладывать свои силы и время в развитие сотрудников.



Автор статьи: Dr. Cameron Sepah
Источник

«Настоящие, а не фейковые ценности компании можно увидеть, посмотрев на то, кого повышают, награждают и с кем расстаются»
– Культура Netflix: Свобода и Ответственность

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

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

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

Почему поведение сохраняется (Делай, как я делаю, а не так, как я говорю)


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

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

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

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

«Сотрудники вашей компании практикуют то поведение, которое ценится в компании, а не ценности, в которые вы верите»

Оценка по ценностям (найм на работу)


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

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

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

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

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

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

Их CEO формулирует это так:

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

Как поощрять


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

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

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

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

image

1) Некомпетентные редиски (сразу увольнять)<


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

2) Компетентные редиски


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

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

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

3) Некомпетентные милаши


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

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

4) Компетентные и выдающиеся милаши


Хочется верить, что большинство сотрудников вашей компании и компетентны, и милы, и важно отметить, что в матрице Производительность-Ценности вы должны проецировать и то, и другое чтобы находится в правом верхнем квадрате. Компетентные милаши могут получить до 75% оценки, и конечно же их нужно хвалить публично, и давать возможности к росту внутри компании. Но, для того чтобы держать планку высоко сотрудники должны быть в состоянии получить 100% оценки, только если они демонстрируют выдающиеся результаты как по производительности, так и по соответствию ценностям. Принимая во внимание, как редки такие сотрудники, владельцы компании должны не мешать им и делать все для того, чтобы увлечь и удержать их внутри компании. Это текущие или будущие лидеры вашей компании, и их нужно холить и лелеять, принимая во внимание то, что они являются основной производительности и культуры для вашей компании.

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

Что же с этим делать


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

«Как говорится в старой поговорке, что посеешь, то и пожнешь. Лидеры получают то поведение, которое они вознаграждают»
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333904/


Метки:  

[Перевод] Постмортем Super Meat Boy

Суббота, 22 Июля 2017 г. 10:11 + в цитатник
image


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

Потом я вырос… но мало что поменялось.

Super Meat Boy начинался как простой прототип на Flash, который мы в свободное время с моим другом из Интернета Джоном Макэнти (Jon McEntee) создали за три недели. Я не представлял, что он станет одной из моих самых популярных игр на Flash, не говоря уже о выпуске полномасштабной консольной игры.

В 2008 году меня наняли Microsoft и Nintendo, чтобы я создал что-нибудь для их Интернет-магазинов. Изначально я хотел сделать для Microsoft Gish 2, а Nintendo больше заинтересовала расширенная версия Aether, но главным фактором, повлиявшим на меня, стала случайно завязавшаяся дружба.

Я познакомился с Томми Рефенесом в 2008 году. За долгие годы я успел поработать с множеством программистов, и отношения между художниками и программистами всегда были немного отчуждёнными. Работа с Томми напоминала общение с лучшим другом из колледжа, мы чудили и выкидывали трюки, бесившие всех вокруг. Я сразу понял, что любой наш совместный проект будет интересным, именно так и получился Super Meat Boy.

Мы просто хотели сделать что-то интересное и развлекались, создавая эту игру.

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



Что у нас получилось хорошо


1. Мы использовали собственный движок и инструменты

Томми: Когда я говорю людям, что сделал движок и инструменты сам, большинство спрашивает: «Зачем?» Мои друзья из FlashBang в каждом разговоре пытались убедить меня использовать Unity, но я твёрдо придерживался решения создать собственные инструменты разработки и движок.

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

На создание Super Meat Boy ушло 18 месяцев, от первой строки кода движка до последней строки кода сообщений об ошибках перед отправкой на сертификацию XBLA. Лично мне кажется, что это рекордное время для игры с таким объёмом контента и для двух разработчиков. Я уверен, что мы смогли справиться с этим, потому что я занимался кодом. Когда возникала ошибка, я немедленно отслеживал её, вне зависимости от платформы, на которой она обнаруживалась.

Для Super Meat Boy использовалось не так много инструментов. Бесценным оказался внутриигровой редактор уровней, потому что он позволил Эдмунду создавать уровни визуально, без возни с кодом.

Ещё одним инструментом стал созданный мной Flash Exporter. В целом это был скрипт, упаковывающий все символы Flash в одну текстуру и экспортирующий информацию об анимации со звуковыми метками. Он оправдал себя ещё при первом экспорте сделанного Эдом Meat Boy. Мы получили звуки, анимации и всё необходимое за одну быструю операцию экспорта, которой движок мог легко управлять и вызывать её при необходимости.

2. Дизайнерская среда


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

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

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


Томми Рефенес и Эдмунд Макмиллен

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

Мы с Томми стали очень близки в процессе разработки, и Super Meat Boy стал результатом этого. Мы получали удовольствие при работе над этой игрой, и не могли сдержать своих чувств, когда дело доходило до принятия решений. Super Meat Boy была шуткой «для своих», которая внезапно отбилась от рук. Думаю, привлекательнее всего в SMB то, что любой игрок в видеоигры сможет понять эту шутку.

3. Инновация в дизайне: назад к истокам


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

Super Meat Boy — это Super Mario Bros, но сделанный мной и Томми. Если бы мы писали диздок, то в нём было бы только это.

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

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

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

4. Саундтрек


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

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

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

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



5. Steam


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

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

Мы любим Steam.

Что пошло не так


1. Личные расходы

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

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

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

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

Томми: Был период, когда мой счёт в банке составлял -800 долларов. Плохо, когда заходишь в супермаркет купить Coke Zero и тебе приходит отказ. Выяснилось, что каждая из этих банок Coke Zero стоила мне примерно 40 долларов.

2. Упущенный WiiWare

Томми: Когда мы изначально объявили о выпуске Super Meat Boy для WiiWare, то планировали не более 100 уровней, без катсцен и открываемых персонажей. Мы хотели сделать прямой порт Flash-игры с некоторыми дополнениями, и ничего больше. Потом нас понесло, но не думаю, что это плохо, потому что мы сделали как раз ту игру, которую хотели. Плохо было то, что мы не смогли бы опубликовать игру для Wii.

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

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

3. Выпуск на PC

Томми: Издавать игру на нескольких платформах командой из двух человек довольно сложно. Выпуск на PC был немного проблемным из-за тестирования. Мне казалось, что у нас есть достаточный набор тестовых машин. У нас были компьютеры от минимально подходящих для игры (нетбук Acer) до мощных четырёхъядерников. Я считал, что мы учли все варианты: у нас были видеокарты ATI и NVidia. Но, очевидно, этого было недостаточно.

В день выпуска на PC нас завалило кучей отчётов об ошибках, сбоях при запуске и выходе и многом другом. За несколько первых дней после выпуска я ответил примерно на две тысячи писем. Я чувствовал себя так же, как во время последнего рывка перед выпуском на XBLA: каждый раз, когда я что-то чинил, ломалось что-нибудь другое.

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



4. Последние два месяца напряжённой работы перед выпуском в XBLA

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

Такой срок выглядет невозможным. Нам сказали, что если мы не успеем к осенней кампании, то нам придётся отложить игру до весны или попробовать выпустить её самостоятельно, без особой поддержки. При этом мы рисковали значительными потерями. Microsoft объяснила, что все игры в кампании получат собственную неделю выпуска, очень активное освещение, обзоры Major Nelson и демонстрацию на PAX и других мероприятиях. Эта рекламная кампания должна была называться Game Feast.

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

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



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

Это длилось долгими неделями. Я был слаб, зол и напряжён. Родители приносили мне еду, потому что я в буквальном смысле не выходил из дома в течение этих двух месяцев. Помню как постоянно повторял себе: «Не умри, пока не сделаешь игру», потому что я действительно этого опасался. Я чувствовал себя жалким, уровень сахара в крови скакал [прим. пер.: Томми Рефенес — диабетик], но мне приходилось пахать и исправлять ошибки. Не знаю, сделало ли это меня сильнее… но, по крайней мере, мне как-то удалось выжить!

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

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

5. Выпуск в XBLA

Эдмунд: Процесс разработки был закончен, Super Meat Boy получила на PAX несколько наград, и пресса начинала уже нацеливать на нас свои софиты. Многие веб-сайты и журналы сказали, что Super Meat Boy запросто станет хитом Feast, а возможно и новым крупным инди-хитом, но бизнесмены из Microsoft не были в этом уверены.

Нам сказали, что цена слишком высока, графика слишком грубая, да и не цепляет взгляд, как другие игры для Game Feast: Comic Jumper и Hydrophobia. У нас сердце ушло в пятки, когда нам сообщили, что по прогнозам наша игра будет продаваться так же, как Hydrophobia, если не хуже, а ведь она по их мнению, станет второй по доходам игрой в Feast.

Эти прогнозы ещё больше разочаровали после выпуска Hydrophobia: по статистике, за первую неделю в неё поиграло меньше 10 тысяч человек. Если прогнозы Microsoft были верны, то мы были в полной…

Через неделю выпустили Comic Jumper, на которую публика отреагировала примерно так же, хотя продажи были чуть лучше, но всё равно недостаточными по стандартам XBLA. Game Feast казалась огромной бомбой, и некоторые сайты уже писали о ней, как о провале

Super Meat Boy выпустили 20 октября, вместе с Costume Quest. В течение четырёх дней она рекламировалась третьей. Мы не получили никаких рекламных бонусов при выпуске, как предыдущие игры Game Feast (эксклюзивная неделя выпуска, первое рекламное место и обзор Major Nelson), но нам сказали, что если оценка на Metacritic и продажи будут хорошими, нас начнут рекламировать активнее.

К третьему дню после выпуска мы уже обогнали суммарные результаты Hydrophobia и Comic Jumper за неделю, на Metacritic наша игра была на втором месте в списке игр XBLA, а «сарафанное радио» распространяло информацию о ней с безумной скоростью.

Нас разместили на первом месте в рекламе на пятый день, и никогда уже оттуда не снимали. Мы так и не получили обзора Major Nelson, как и объяснения тому, зачем Microsoft выпустила SMB вместе с Costume Quest. Нам не рассказали, почему, несмотря на то, что мы превзошли все ожидания, с нами по-прежнему не обходились так, как обещали, даже когда продолжилась активная реклама других игр Game Feast, например Comic Jumper.

Поэтому мы были сбиты с толку и нам казалось, что нас используют. Я по-прежнему не понимаю, почему всё получилось именно так. Может быть, Microsoft просто хотела отстраниться от Game Feast? Возможно, они не верили в наш успех? А может быть, нам сильно не повезло в самое конкурентное время года для видеоигровой индустрии?

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



Самое мясо


Томми: Сложно говорить о каком-то разочаровании… мы ведь ещё не закончили! Нам нужно было доделать редактор, портал и версию для Mac. Это было трудно, ведь мы уже чувствовали, что всё закончилось, как будто мы пересекли финишную черту. Но тут как будто кто-то сказал: «Хотите поучаствовать в ещё одной гонке?», а мы такие: «Да, наверно, будет весело».

Эдмунд: А потом ты понимаешь, что это будет та же гонка, никакого приза в конце не будет, и в этот момент тебя начинает тошнить.

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

Томми: В целом я чувствую, что игра стоила всего этого стресса. Мы начинали как два простых парня без единой готовой игры, а закончили созданием четвёртой по рейтингу игры для PC 2010 года, продавшейся тиражом 400 тысяч и получившей больше 15 наград «Игра года».

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

Технические данные


Разработчик: Team Meat
Количество разработчиков: 1 Эдмунд, 1 Томми, 1 Дэнни
Время разработки: 18 месяцев
Дата выпуска: 20 октября 2010 года (XBLA), 30 ноября 2010 года (Steam)
Платформа: Xbox 360, PC
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332984/


Метки:  

Определяем номера с помощью CallKit

Суббота, 22 Июля 2017 г. 08:51 + в цитатник


Когда в CRM 57000 контактов, людям совсем не хочется записывать их в айфон вручную. Надо найти решение поизящней, которое позволит не просто искать контакты в отдельном приложении, но и отображать имя человека при входящем звонке. Мы долго гуглили, а потом вспомнили про анонс фреймворка CallKit с WWDC. Информации по этой теме оказалось не так много: немногословная документация, статья на Хабре и ни одного пошагового руководства. Хочу восполнить этот пробел. На примере создания простого приложения покажу, как научить CallKit определять тысячи номеров.

Определяем один номер


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

Начнем с пустого проекта. Создадим Single View Application с именем TouchInApp.

Добавим extension для определения номеров. В меню Xcode выберите File > New > Target… В разделе Application Extension выберите Call Directory Extension, нажмите Next.


В поле Product Name введите TouchInCallExtension, нажмите Finish. В появившемся алерте нажмите Cancel.

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

В Project navigator раскройте TouchInCallExtension и откройте CallDirectoryHandler.swift. Найдите функцию addIdentificationPhoneNumbers. Там вы увидите массивы phoneNumbers и labels. Удалите номера из phoneNumbers, впишите туда тестовый номер. Удалите содержимое массива labels, впишите туда «Test number».

У вас получится что-то вроде этого:

private func addIdentificationPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws {
   let phoneNumbers: [CXCallDirectoryPhoneNumber] = [ 79214203692 ]
   let labels = [ "Test number" ]

   for (phoneNumber, label) in zip(phoneNumbers, labels) {
       context.addIdentificationEntry(withNextSequentialPhoneNumber: phoneNumber, label: label)
   }
}

CXCallDirectoryPhoneNumber — просто typealias для Int64. Номер должен быть в формате 7XXXXXXXXXX, то есть сначала код страны (country calling code), потом сам номер. Код России +7, поэтому в данном случае пишем 7.

Поставьте приложение на устройство и тут же закройте. В нем пока нечего делать. Зайдите в настройки телефона > Phone > Call Blocking & Identification. Найдите там приложение TouchInApp и позвольте ему определять и блокировать вызовы. Бывает, что приложение не сразу появляется в списке. В таком случае закройте настройки, откройте и закройте еще раз приложение и попробуйте снова.


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

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


Определяем тысячи номеров


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

Итак, контакты мы должны добавлять в расширении. Из приложения мы это сделать не можем. Мы можем лишь вызвать функцию reloadExtension, вызов которой приведет к вызову addIdentificationPhoneNumbers. О ней я расскажу чуть позже.

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

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

А теперь представьте, что Call Directory Extension — это кот, а вы — приложение. И вы хотите накормить контактами Call Directory Extension. Что в нашем случае будет исполнять роль миски, которую мы должны наполнить контактами и из которой extension впоследствии будет их потреблять? К сожалению, вариантов у нас не так много. Мы не можем использовать Core Data или SQLite, так как очень сильно ограничены в ресурсах во время работы расширения.


Когда вы редактировали функцию addIdentificationPhoneNumbers, вы наверняка заметили комментарии. Там говорится о том, что «Numbers must be provided in numerically ascending order.». Сортировка выборки из базы слишком ресурсоемка для расширения. Поэтому решение, использующее БД, нам не подходит.

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


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

Увы, мы не можем просто так взять и получить доступ к одному файлу как из приложения, так и из расширения. Однако, если воспользоваться App Groups, это становится возможным.

Делимся контактами с помощью App Groups



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

В Project navigator кликните по вашему проекту. Выберите target приложения, перейдите на вкладку Capabilities, включите App Groups. Добавьте группу «group.ru.touchin.TouchInApp». Логика тут та же, что и с bundle identifier. Просто добавьте префикс group. У меня bundle identifier — «ru.touchin.TouchInApp», соответственно, группа — «group.ru.touchin.TouchInApp».

Перейдите к target'у расширения, перейдите на вкладку Capabilities, включите App Groups. Там должна появиться группа, которую вы вводили ранее. Поставьте на ней галочку.

Если мы используем опцию «Automatically manage signing», App Groups настраиваются достаточно легко. Как видите, я уложился в пару абзацев. Благодаря этому я могу не превращать статью о CallKit в статью об App Groups. Но если вы используете профайлы из аккаунта разработчика, то нужно в аккаунте добавить App Group и включить ее в App ID приложения и расширения.

Записываем контакты в файл


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

let container = FileManager.default
   .containerURL(forSecurityApplicationGroupIdentifier: "group.ru.touchin.TouchInApp")

«group.ru.touchin.TouchInApp» — это наша App Group, которую мы только что добавили.

Назовем наш файл «contacts» и сформируем для него URL:

guard let fileUrl = FileManager.default
   .containerURL(forSecurityApplicationGroupIdentifier: "group.ru.touchin.TouchInApp")?
   .appendingPathComponent("contacts") else { return }

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

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

let numbers = ["79214203692",
               "79640982354",
               "79982434663"]

let labels = ["Иванов Петр Петрович",
              "Сергеев Иван Николаевич",
              "Николаев Андрей Михайлович"]

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

Теперь сформируем из контактов будущее содержимое файла:

var string = ""
for (number, label) in zip(numbers, labels) {
   string += "\(number),\(label)\n"
}

Каждую пару номер-имя записываем в одну строку, разделяя запятой. Завершаем символом перевода строки.

Записываем все это дело в файл:

try? string.write(to: fileUrl, atomically: true, encoding: .utf8)

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

CXCallDirectoryManager.sharedInstance.reloadExtension(
   withIdentifier: "ru.touchin.TouchInApp.TouchInCallExtension")

Параметр функции — bundle identifier расширения.

Полный код:

@IBAction func addContacts(_ sender: Any) {
    let numbers = ["79214203692",
                   "79640982354",
                   "79982434663"]
        
    let labels = ["Иванов Петр Петрович",
                  "Сергеев Иван Николаевич",
                  "Николаев Андрей Михайлович"]
        
    writeFileForCallDirectory(numbers: numbers, labels: labels)
}

private func writeFileForCallDirectory(numbers: [String], labels: [String]) {
   guard let fileUrl = FileManager.default
       .containerURL(forSecurityApplicationGroupIdentifier: "group.ru.touchin.TouchInApp")?
       .appendingPathComponent("contacts") else { return }
  
   var string = ""
   for (number, label) in zip(numbers, labels) {
       string += "\(number),\(label)\n"
   }
  
   try? string.write(to: fileUrl, atomically: true, encoding: .utf8)

   CXCallDirectoryManager.sharedInstance.reloadExtension(
      withIdentifier: "ru.touchin.TouchInApp.TouchInCallExtension")
}

Читаем контакты из файла


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

Увы, iOS не предоставляет возможность читать текстовые файлы построчно. Воспользуемся подходом, предложенным пользователем StackOverflow. Скопируйте к себе класс LineReader вместе с расширением.

Вернемся к файлу CallDirectoryHandler.swift и внесем изменения. Сначала получим URL нашего файла. Делается это точно так же, как и в приложении. Затем инициализируем LineReader путем к файлу. Читаем файл построчно и добавляем контакт за контактом.

Код обновленной функции addIdentificationPhoneNumbers:

private func addIdentificationPhoneNumbers(to context: CXCallDirectoryExtensionContext) throws {
   guard let fileUrl = FileManager.default
       .containerURL(forSecurityApplicationGroupIdentifier: "group.ru.touchin.TouchInApp")?
       .appendingPathComponent("contacts") else { return }
  
   guard let reader = LineReader(path: fileUrl.path) else { return }
  
   for line in reader {
       autoreleasepool {
           // удаляем перевод строки в конце
           let line = line.trimmingCharacters(in: .whitespacesAndNewlines)
          
           // отделяем номер от имени
           var components = line.components(separatedBy: ",")
          
           // приводим номер к Int64
           guard let phone = Int64(components[0]) else { return }
           let name = components[1]
          
           context.addIdentificationEntry(withNextSequentialPhoneNumber: phone, label: name)
       }
   }
}

Функция должна использовать минимум ресурсов, поэтому заверните итерацию цикла в autoreleasepool. Это позволит освобождать временные объекты и использовать меньше памяти.

Все. Теперь после вызова функции addContacts телефон будет способен определять номера из массива numbers.

Окончательную версию проекта можете скачать в репозитории на GitHub.

Что дальше?


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

Когда у вас есть представление о том, как это работает, все в ваших руках.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333364/


Метки:  

Android Architecture Components. Часть 3. LiveData

Пятница, 21 Июля 2017 г. 19:15 + в цитатник
image
Компонент LiveData — предназначен для хранения объекта и разрешает подписаться на его изменения. Ключевой особенностью является то, что компонент осведомлен о жизненном цикле и позволяет не беспокоится о том на каком этапе сейчас находиться подписчик, в случае уничтожения подписчика, компонент отпишет его от себя. Для того чтоб LiveData учитывала жизненный цикл используется компонент Lifecycle, но также есть возможность использовать без привязки к жизненному циклу.

Сам компонент состоит из классов: LiveData, MutableLiveData, MediatorLiveData, LiveDataReactiveStreams, Transformations и интерфейса: Observer.

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

Для обновления значения мы должны передать его с помощью метода setValue(T), будьте внимательны поскольку этот метод нужно вызывать с main треда в противном случае мы получим IllegalStateException, если же нам нужно передать значение из другого потока можно использовать postValue(T), этот метод в свою очередь обновит значение в main треде. Интересной особенностью postValue(T) является еще то, что он в случае множественного вызова, не будет создавать очередь вызовов на main тред, а при исполнении кода в main треде возьмет последнее полученное им значение. Также в классе присутствует два калбека:
onActive() — будет вызван когда количество подписчиков изменит свое значение с 0 на 1.
onInactive() — будет вызван когда количество подписчиков изменит свое значение с 1 на 0.
Их назначение соответственно уведомить наш класс про то, что нужно обновлять даные или нет. По умолчанию они не имеют реализации, и для обработки этих событий мы должны переопределить эти методы.
Давайте рассмотрим как будет выглядеть наш LiveData класс, который будет хранить wife network name и в случае изменения будет его обновлять, для упрощения он реализован как синглтон.
public class NetworkLiveData extends LiveData {
  private Context context;
  private BroadcastReceiver broadcastReceiver;
  private static NetworkLiveData instance;

  public static NetworkLiveData getInstance(Context context){
      if (instance==null){
          instance = new NetworkLiveData(context.getApplicationContext());
      }
      return instance;
  }

  private NetworkLiveData(Context context) {
      this.context = context;
  }

  private void prepareReceiver(Context context) {
      IntentFilter filter = new IntentFilter();
      filter.addAction("android.net.wifi.supplicant.CONNECTION_CHANGE");
      filter.addAction("android.net.wifi.STATE_CHANGE");
      broadcastReceiver = new BroadcastReceiver() {
          @Override
          public void onReceive(Context context, Intent intent) {
              WifiManager wifiMgr = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
              WifiInfo wifiInfo = wifiMgr.getConnectionInfo();
              String name = wifiInfo.getSSID();
              if (name.isEmpty()) {
                  setValue(null);
              } else {
                  setValue(name);
              }
          }
      };
      context.registerReceiver(broadcastReceiver, filter);
  }

  @Override
  protected void onActive() {
      prepareReceiver(context);
  }

  @Override
  protected void onInactive() {
      context.unregisterReceiver(broadcastReceiver);
      broadcastReceiver = null;
  }
}


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

Для того чтоб добавить подписчика есть два метода: observe(LifecycleOwner, Observer) — для добавления подписчика с учетом жизненного цикла и observeForever(Observer) — без учета. Уведомления об изменении данных приходят с помощью реализации интерфейса Observer, который имеет один метод onChanged(T).
Выглядит это приблизительно так:
public class MainActivity extends LifecycleActivity implements Observer {
  private TextView networkName;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      networkName = (TextView) findViewById(R.id.network_name);
      NetworkLiveData.getInstance(this).observe(this,this);
      //NetworkLiveData.getInstance(this).observeForever(this);
  }

  @Override
  public void onChanged(@Nullable String s) {
      networkName.setText(s);
  }
}


Примечание: Этот фрагмент только для примера,  не используйте этот код в реальном проекте. Для работы с LiveData лучше использовать ViewModel(про этот компонент в следующей статье) или позаботиться про отписку обсервера вручную.
В случае использования observe(this,this) при повороте экрана мы будем каждый раз отписываться от нашего компонента и заново подписываться. А в случае использование observeForever(this) мы получим memory leak.


Помимо вышеупомянутых методов в api LiveData также входит getValue(), hasActiveObservers(), hasObservers(), removeObserver(Observer observer), removeObservers(LifecycleOwner owner) в дополнительных комментариях не нуждаются.

Класс MutableLiveData, является расширением LiveData, с отличием в том что это не абстрактный класс и методы setValue(T) и postValue(T) выведены в api, тоесть публичные.
По факту класс является хелпером для тех случаев когда мы не хотим помещать логику обновления значения в LiveData, а лишь хотим использовать его как Holder.
void update(String someText){
      ourMutableLiveData.setValue(String);
}


Класс MediatorLiveData, как понятно из названия это реализация паттерна медиатор, на всякий случай напомню: поведенческий паттерн, определяет объект, инкапсулирующий способ взаимодействия множества объектов,  избавляя их от необходимости явно ссылаться друг на друга. Сам же класс расширяет MutableLiveData и добавляет к его API два метода: addSource(LiveData, Observer)  и removeSource(LiveData). Принцип работы с классом заключается в том что мы не подписываемся на конкретный источник, а на наш MediatorLiveData, а источники добавляем с помощью addSource(..). MediatorLiveData в свою очередь сам управляет подпиской на источники.  
Для примера создадим еще один класс LiveData, который будет хранить название нашей мобильной сети:
public class MobileNetworkLiveData extends LiveData {
  private static MobileNetworkLiveData instance;
  private Context context;

  private MobileNetworkLiveData(Context context) {
      this.context = context;
  }

  private MobileNetworkLiveData() {

  }

  @Override
  protected void onActive() {
      TelephonyManager telephonyManager = (TelephonyManager) context
              .getSystemService(Context.TELEPHONY_SERVICE);
      String networkOperator = telephonyManager.getNetworkOperatorName();
      setValue(networkOperator);
  }

  public static MobileNetworkLiveData getInstance(Context context) {
      if (instance == null) {
          instance = new MobileNetworkLiveData(context);
      }
      return instance;
  }

}


И перепишем наше приложение так чтоб оно отображало название wifi сети, а если подключения к wifi нет, тогда название мобильной сети, для этого изменим MainActivity:
public class MainActivity extends LifecycleActivity implements Observer {
  private MediatorLiveData mediatorLiveData;
  private TextView networkName;


  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      networkName = (TextView) findViewById(R.id.network_name);
      mediatorLiveData = new MediatorLiveData<>();
      init();
  }


  private void init() {
      final LiveData network = NetworkLiveData.getInstance(this);
      final LiveData mobileNetwork = MobileNetworkLiveData.getInstance(this);
      Observer networkObserver = new Observer() {
          @Override
          public void onChanged(@Nullable String s) {
              if (!TextUtils.isEmpty(s))
                  mediatorLiveData.setValue(s);
              else
                  mediatorLiveData.setValue(mobileNetwork.getValue());
          }
      };
      Observer mobileNetworkObserver = new Observer() {
          @Override
          public void onChanged(@Nullable String s) {
                  if (TextUtils.isEmpty(network.getValue())){
                      mediatorLiveData.setValue(s);
                  }
          }
      };
      mediatorLiveData.addSource(network, networkObserver);
      mediatorLiveData.addSource(mobileNetwork,mobileNetworkObserver);
      mediatorLiveData.observe(this, this);
  }


  @Override
  public void onChanged(@Nullable String s) {
      networkName.setText(s);
  }
}


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

Класс LiveDataReactiveStreams, название ввело меня в заблуждение поначалу, подумал что это расширение LiveData с помощью RX, по факту же, класс являет собой адаптер с двумя static методами: fromPublisher(Publisher publisher), который возвращает объект LiveData и toPublisher(LifecycleOwner lifecycle, LiveData liveData), который возвращает объект Publisher. Для использования этого класса, его нужно импортировать отдельно:
compile «android.arch.lifecycle:reactivestreams:$version»

Класс Transformations, являет собой хелпер для смены типизации LiveData, имеет два static метода:
map(LiveData, Function)  - применяет в main треде реализацию интерфейса Function и возвращает объект LiveData

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


LiveData location = ...;

LiveData locationString = Transformations.map(location, new Function() {
  @Override
  public String apply(Location input) {
      return input.toString;
  }
});


switchMap(LiveData, Function>)  - похож к методу map с отличием в том, что вместо смены типа в функции мы возвращаем сформированный объект LiveData.
LiveData location = ...;
LiveData getPlace(Location location) = ...;

LiveData userName = Transformations.switchMap(location, new Function>() {
  @Override
  public LiveData apply(Location input) {
      return getPlace(input);
  }
});


Базовый пример можно посмотреть в репозитории: git    

Также полезные ссылки:
https://developer.android.com/topic/libraries/architecture/livedata.html
https://developer.android.com/reference/android/arch/lifecycle/LiveData.html
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333890/


Правила хорошего тона для API

Пятница, 21 Июля 2017 г. 18:37 + в цитатник
Перенос функциональности сайта, интернет-магазина или портала в мобильное приложение имеет ряд преимуществ как для владельца онлайн-сервиса, так и для его клиентов. Владелец получает дополнительный канал связи со своей целевой аудиторией и возможность персонализировать рекламные объявления, а пользователь – более удобный интерфейс, дополнительный функционал и возможность получения своевременных оповещений.

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

Существует множество фреймворков, ориентированных на разработку API. Особенно их много на NodeJS, но и на других языках – достаточно. Тем не менее, когда задача состоит в использовании существующего функционала и данных проекта, то менять его архитектуру в корне, переписывать всё на другом языке или фреймворке – нерационально. Мы пишем на своём фреймворке ZeroEngine, который ориентирован на высоконагруженные проекты и работает по принципу plug-in’ов. Кратко принцип работы ZeroEngine можно описать так: новый «модуль» можно встроить в любой уже существующий, а также перехватить управление выдачей в нужный момент.

Резюмируем вводные данные


Требуется написать REST API для сайта. Архитектура позволяет внедрить роутер и использовать существующий функционал полностью или частично.

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

ДЕЙСТВИЕ /объект/идентификатор/метод


Метод и URL должны чётко описывать выполняемую методом API функцию. Строго говоря, при именовании метода API, метод запроса (GET, POST, PUT, DELETE) является в предложении «глаголом», а адрес представляет собой «путь» от общего к частному.

Например:

  • GET /images («получить изображения») – вернёт список изображений;
  • POST /image – опубликует изображение;
  • PUT /image/123 – «положит» переданное значение в изображение номер 123.

Мы сознательно разделяем image и images, чтобы было сразу понятно, что именно придёт в ответ на запрос – массив или единичный объект.

Семантические ошибки


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

Меньше методов — меньше запросов


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

Не тестировать дважды


Разумеется, речь идёт о дублировании функциональных тестов модульными. Как и в остальных случаях, мы стараемся использовать инструменты по их назначению: юнит-тестами мы покрываем модули сайта и роутера, а сам API тестируем с помощью dredd и API Blueprint.

Разработка через документацию


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

Версионность


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

Постоянная интеграция


Мы используем TeamCity, но любой CI-сервис, в том числе облачный, поддерживает unit и dredd-тесты, а также интеграцию с Apiary. При успешном тестировании мы актуализируем внешние тестовые площадки и анализируем несколько метрик. Эти действия позволяют быстро отследить возникшие проблемы и обеспечивают постоянное наличие свежей документации.

Внедрение Unit-тестирования в существующий проект


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

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

Мы делаем это примерно так: в папке нашего модуля мы устанавливаем PHPunit и его зависимости, а в теле самого модуля вызываем модифицированный testRunner:

$out = '';
$module = "console";
		
$testRunner = new PHPUnit_TextUI_TestRunner();
$testPrinter = new ZeroTech_printer($out);
	
$testRunner->setPrinter($testPrinter);
$testSuite = new PHPUnit_Framework_TestSuite();
		
foreach (glob(U_PATH . "/tests/*test.php") as $filename)
{
    $testSuite->addTestFile($filename);
}
$testRunner->doRun($testSuite, array("verbose" => true));	

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

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



Функциональные тесты с помощью dredd


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

  • Описываем функционал в формате API Blueprint (своеобразный markdown на стероидах): Разделяем методы на группы, описываем, зачем он нужен; какие заголовки / формат данных / параметры / атрибуты метод принимает, какие из них обязательные; какие есть ограничения; что метод возвращает; на что отвечает ошибками; в каком именно формате.
  • Сохраняем в файл и запускаем dredd file.apib.
  • Чиним проваленные тесты, рефакторим.
  • Выгружаем на apiary.

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

 FORMAT: 1A 
# Group User 
 
## /user 
###  GET - Получение данных профиля пользователя [GET]
   + Response 200 (application/json)
   + Attributes
   + first_name: Иван (required, string) - Имя пользователя (только русские символы)        
   + last_name: Иванов (required, string) - Фамилия пользователя (только русские символы)        
   + dob: 1988-10-01 (required, string) - Дата рождения 
   + sex: 1 (required, number) - Пол (0 - женский, 1 - мужской) 
   + city: Москва (required, string) - Город         

### POST - Создание нового пользователя [POST] 
   + Request (application/json)    
   + Attributes        
   + first_name: Иван (required, string) - Имя пользователя (только русские символы)        
   + last_name: Иванов (required, string) - Фамилия пользователя (только русские символы)        
   + dob: 1988-10-01 (required, string) - Дата рождения        
   + sex: 1 (required, number) - Пол (0 - женский, 1 - мужской)        
   + city: Москва (required, string) - Город 
 
   + Response 201  
      {      
        message: “Successfully created”,      
        id: 123 
       } 

Apiary преобразует всё это в удобный интерфейс с mock-сервером. Разработчики приложения могут использовать его даже в том случае, если «живой» API ещё не написан или работает некорректно. Можно также использовать mock-сервер в качестве песочницы.



Кроме того, можно смотреть историю тестов утилитой dredd, если у вас, например, нет интерфейса непрерывной интеграции.

Заключение


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

https://habrahabr.ru/post/333884/


Метки:  

Security Week 29: Как взломать ICO, RCE-баг в десятках миллионах инсталляций, Nukebot пошел в народ

Пятница, 21 Июля 2017 г. 18:21 + в цитатник
Взломать одностраничный сайт на Wordpress и украсть $7,7 млн – это теперь не сценарий безграмотного кино про хакеров, а состоявшаяся реальность. Технологии! Все же заметили повальное увлечение ICO? Это как IPO, когда компания впервые выпускает свои акции и продает их через биржу. Только не акции, а токены, не через биржу, а напрямую, и строго за криптовалюту.

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

Неизвестные хакеры тоже оценили удобство ICO и решили поучаствовать. Нашли талантливых парней CoinDash, которые ICOшились с помощью сайта на Wordpress, ломанули его, подменили ethereum-адрес для инвестиций – и сидят, считают валящиеся миллионы. Первыми жертвами стали 2000 инвесторов, утратившие 37 тысяч эфира (на тот момент по $209 за каждую эфиринку).



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

Десятки миллионов инсталляций софта и IoT-устройств содержат критическую RCE-уязвимость

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

Как-то в этом роде и поступили Senrio взявшись изучить крутую секьюрити-камеру от Axis Communications. Быстро научились вызывать через 80й порт переполнение буфера и без всякой аутентификации перехватывать видеопоток, перезагружать камеру, и ставить запись на паузу. Уязвимость окрестили Devil’s Ivy.

После этого они выяснили, что этот же софт стоит в других 248 моделях линейки Axis Communications, и этот баг, разумеется, есть и там. Просканировали Интернет с помощью Shodun – нашли 14700 уязвимых камер онлайн (понятно, что большая часть таких камер сидят за файрволлами).

Затем вскрылось еще одно звено этой цепи: дело в том, что дырявый компонент, библиотека gSOAP, используется очень много где, в том числе и в продуктах Microsoft, IBM, Xerox и Adobe. Это не значит, что уязвимы все продукты, использующие gSOAP, но, определенно, проблема очень масштабна. Отсюда и взялись заявленные в новости «десятки миллионов». От таких совсем приблизительных цифр не становится страшно, но если вдруг объявится какой-нибудь самоходный троянский червь, использующий эту дыру, мало не покажется.

Обнаружены многочисленные модификации Nukebot

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

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



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

Древности


«Sunday-1631»

Очень опасен – уничтожает файлы при их запуске на выполнение. В воскресенье выдает сообщение «Today is SunDay! Why do you work so hard? All work and no play make you a dull boy! Come on! Let’s go out and have some fun!»

Цитата по книге «Компьютерные вирусы в MS-DOS» Евгения Касперского. 1992 год. Страницa 35.

Disclaimer: Данная колонка отражает лишь частное мнение ее автора. Оно может совпадать с позицией компании «Лаборатория Касперского», а может и не совпадать. Тут уж как повезет.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333882/


Метки:  

RubyMine 2017.2: Docker Compose, автокоррекции RuboCop в редакторе, улучшенный VCS

Пятница, 21 Июля 2017 г. 18:09 + в цитатник
Здравствуй, Хабр! На днях мы выпустили RubyMine 2017.2, новую версию нашей IDE для Ruby и Rails, и спешим рассказать о новинке.



  • Docker Compose
  • Отладка приложений в Docker Compose
  • Автокоррекции RuboCop
  • “Хлебные крошки” для Ruby
  • Улучшения поддержки JavaScript
  • Новое в VCS
  • Пользовательский интерфейс
  • Другие улучшения

А теперь по порядку:

Docker Compose


В прошлом релизе мы анонсировали поддержку Docker. Однако пользователям значительно не хватало поддержки Docker Compose, которую мы успешно добавили в новую версию. Откройте Docker проект в RubyMine, и в настройках установите Docker Compose в качестве удаленной SDK (Preferences / Settings | Languages & Frameworks | Ruby SDK and Gems | New remote | Docker Compose). Теперь можно работать с приложениями в контейнерах, используя всю функциональность IDE от автодополнения кода до отладки. Подробнее об установке в блоге (англ.)



Отладка приложений в Docker Compose


Отладка заслуживает отдельного анонса, так как ее очень ждали. Отладчик RubyMine отныне можно использовать для приложений в контейнерах через Docker и Docker Compose. Для этого после настройки Docker/Compose в Gemfile нужно добавить гемы ruby-debug-ide и debase и установить их через команду docker-compose build, запускаемую прямо из редактора Gemfile вместо bundle install. Об этом также подробнее в блоге.



Автокоррекции RuboCop


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



Находим код, подсвеченный инспекцией rubocop как ошибка, нажимаем Alt+Enter, и, вуаля, ошибки исправлены во всем файле.

“Хлебные крошки” для Ruby


Мы добавили “хлебные крошки” для Ruby. Небольшая, но довольно полезная деталь. Показывает текущий контекст типа модулей, классов, методов, блоков, а в файлах RSpec — названий групп и примеров.



Кстати, вы также обнаружите “хлебные крошки” и в файлах JavaScript. А для HTML, XML и YAML мы обновили их дизайн.

Улучшения поддержки JavaScript


Среди улучшений для JavaScript стоит выделить следующие:

  • Новый рефакторинг Move symbol позволяет аккуратно перенести классы, глобальные функции и переменные в модулях ES6 из одного файла JavaScript/TypeScript в другой.
  • Автодополнение и навигация в JavaScript-коде теперь учитывают конфигурацию проекта (например, aliases), описанную в webpack.config.js.
  • Код внутри классов в JavaScript- и TypeScript-файлах теперь легко упорядочить с помощью нового действия Rearrange code и настроек Code Style — Arrangement и Blank lines.
  • Если вы используете ESLint для проверки форматирования кода, RubyMine предложит импортировать некоторые правила из .eslintrc в настройки форматирования в IDE и будет применять их автоматически при форматировании.
  • Для селекторов Sass и SCSS, созданных через амперсанд (&), теперь работает автодополнение в файлах HTML и навигация к самому селектору.


Новое в VCS


В Git-логе появилось сразу два новых действия: Revert и Reword.

Revert — имплементация git revert в IDE, позволяющая сделать Revert выбранных комитов.



Reword же просто позволяет переименовать любые коммиты, для которых еще не был сделан Push (не только последние).



Мы доработали настройки диалога Commit и перенесли их в отдельную вкладку Commit Dialog (Preferences / Settings | Version Control | Commit Dialog). Появилась возможность контролировать разделение заголовка и содержимого коммита пустой строкой, а также указывать максимальную длину строки.



Если вы пользуетесь IDE от JetBrains, то знаете о возможности временно откладывать текущие изменения, Shelve. Это полезно, когда, к примеру, нужно срочно переключиться на другую задачу, а текущие изменения положить “на полочку”, чтобы они не мешали выполнению срочной задачи.

В этом релизе во вкладке Shelf появился предварительный просмотр, Preview, отображающий внесенные изменения в выбранный файл, а также возможность сравнения “отложенной” версии с текущей.



Пользовательский интерфейс


В прошлый раз мы добавили предварительный просмотр в Find in Path. Теперь там же находится и Gutter — панель слева от редактора, содержащая номера строк, навигационные иконки, и индикаторы внесенных в файл изменений.



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

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


  • Улучшения в инструментах работы с базами данных.
  • Анализ кода и автокоррекции RuboCop в scratch-файлах.
  • Ряд исправлений для повышения производительности IDE.
  • Возможность создавать патчи в буфер обмена.

Скачать новую версию можно со страницы What’s new. Для новых пользователей действует 30-дневный бесплатный пробный период. Для компаний мы также готовы предоставить расширенный пробный период (90 дней).

Делитесь вашими мыслями с нами в комментариях, докладывайте о багах в трекер и присоединяйтесь к нам в Slack!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333880/


Метки:  

Что читать о нейросетях

Пятница, 21 Июля 2017 г. 18:04 + в цитатник


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


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


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


Neural Network Design


image


Если у вас уже есть базовые знания в области машинного обучения, и вы хотите двигаться дальше, то авторы «Neural Network Toolbox для MATLAB» предложат вам четкое и подробное погружение в фундаментальные основы архитектуры нейронных сетей и методов обучения. Методы обучения приводятся как для нейронных сетей прямого распространения (включая многослойные и радиальные сети), так и для рекуррентных сетей. Дополнительно к книге можно получить иллюстрации и код для примеров (сайт).


Deep Learning (Adaptive Computation and Machine Learning series)


image


Священная книга сверточных нейронных сетей и глубокого обучения — без шуток, это действительно очень важная книга, которую рекомендуют многие успешные разработчики… и не только они. «Написанная тремя экспертами, "Deep Learning" является единственной всеобъемлющей книгой в этой области», — так сказал Илон Маск, и если вы верите в надежность автопилота Tesla и перспективы проекта OpenAI, то ему можно верить. :)


Книга предлагает математический инструментарий и фундаментальные основы, охватывающие линейную алгебру, теории вероятностей и теории информации, численные методы и непосредственно машинное обучение. В «Deep Learning» описываются методы глубокого обучения, используемые специалистами-практиками в промышленности, в том числе глубокие сети прямого распространения, алгоритмы оптимизации, сверточные сети, методы Монте-Карло, построение сетевой модели и т.д. Кроме того, вы узнаете много интересного про обработку естественного языка, распознавание речи, компьютерное зрение, системы рекомендаций, биоинформатику и даже игры. Проще сказать, чего в этой книге нет… хотя и это сложно — если вы чего-то не найдете на 800 страницах, есть еще сайт к книге с дополнительными материалами.


P.S. Электронная версия книги выложена в открытый доступ.


Neural Networks: A Systematic Introduction


image


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


Pattern Recognition and Machine Learning (Information Science and Statistics)


image


Если вам понравится предыдущая книга из подборки, то можете усилить знания схожим по концепции изданием 2006 года. «Распознавание образов и машинное обучение» стал первым учебником по распознаванию образов, представляющим Байесовский метод (хотя сама формула Байеса была опубликована аж в 1763 году). В книге представлены алгоритмы вывода, которые позволяют быстро найти ответы в ситуациях, когда точные ответы невозможны. Автор Кристофер Бишоп, директор лаборатории Microsoft Research Cambridge, первым дал пояснение графическим моделям для описания вероятностных распределений.


P.S. В 2013 году подразделение Microsoft Research выпустила в открытый доступ отдельную книгу Deep Learning.


Programming Collective Intelligence


image


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


Make Your Own Neural Network


image


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


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


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


Python Machine Learning


image


«Машинное обучение на Python» это сборник полезных советов для начинающих специалистов по машинному обучению. Почему Python? Так автор захотел, просто ему язык нравится. Себастьян Рашка объясняет самые общие концепции, дополняет их необходимым математическим аппаратом для понимания темы на внутрисистемном уровне, приводит примеры и объясняет способы реализации. Также есть репозиторий на GitHub с общей информацией и примерами кода. Планируется перевод книги на русский язык.


Learning From Data


image


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


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


Artificial Intelligence: A Modern Approach


image


Популярная книга от известных авторов Stuart Russell и Peter Norvig, которая пережила уже третье издание. Полное, современное введение в теорию и практику искусственного интеллекта, предназначенное для учащихся первых курсов вуза. Книга используется в качестве введения в тему на огромном количестве курсов по Data science и ИИ. Если вас интересует применение нейросетей именно для создания искусственного интеллекта, с нее можно начать путь в этой увлекательной и очень сложной области.


Artificial Intelligence: A Modern Approach есть в открытом доступе.


Neural Networks and Deep Learning


image


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


Заключение


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


Что касается книг по нейросетям на русском, то отзывы о них противоречивые. «Нейронные сети. Полный курс» Саймона Хайкина отличается повышенной сложностью и неоднозначным переводом (но если вас не пугает, можете ознакомиться). Найти книгу, которая была бы на таком же уровне качества, как и другие издания в подборке, нам так и не удалось. Если вы можете что-то порекомендовать, напишите в комментариях.

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

https://habrahabr.ru/post/333862/


Метки:  


Процитировано 1 раз

[Перевод] Сети Docker изнутри: как Docker использует iptables и интерфейсы Linux

Пятница, 21 Июля 2017 г. 17:56 + в цитатник

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


Я нашел много разной документации о том, как создавать контейнерные сети и управлять ими, но в отношении того, как именно они работают, материалов намного меньше. Docker широко использует Linux iptables и bridge-интерфейсы для создания контейнерных сетей, и в этой статье я хочу подробно рассмотреть именно этот аспект. Информацию я почерпнул, в основном, из комментариев на github-е, разных презентаций, ну и из моего собственного опыта. В конце статьи можно найти список полезных ресурсов.


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


Оглавление



Обзор сетей Docker


Сеть Docker построена на Container Network Model (CNM), которая позволяет кому угодно создать свой собственный сетевой драйвер. Таким образом, у контейнеров есть доступ к разным типам сетей и они могут подключаться к нескольким сетям одновременно. Помимо различных сторонних сетевых драйверов, у самого Docker-а есть 4 встроенных:


  • Bridge: в этой сети контейнеры запускаются по умолчанию. Связь устанавливается через bridge-интерфейс на хосте. У контейнеров, которые используют одинаковую сеть, есть своя собственная подсеть, и они могут передавать данные друг другу по умолчанию.
  • Host: этот драйвер дает контейнеру доступ к собственному пространству хоста (контейнер будет видеть и использовать тот же интерфейс, что и хост).
  • Macvlan: этот драйвер дает контейнерам прямой доступ к интерфейсу и суб-интерфейсу (vlan) хоста. Также он разрешает транкинг.
  • Overlay: этот драйвер позволяет строить сети на нескольких хостах с Docker (обычно на Docker Swarm кластере). У контейнеров также есть свои адреса сети и подсети, и они могут напрямую обмениваться данными, даже если они располагаются физически на разных хостах.

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


Сети типа мост (bridge)


По умолчанию для контейнеров используется bridge. При первом запуске контейнера Docker создает дефолтную bridge-сеть с одноименным названием. Эту сеть можно увидеть в общем списке по команде docker network ls:


docker network ls


Чтобы проинспектировать ее свойства, запустим команду docker network inspect bridge:


docker network inspect bridge


Вы также можете создать свои собственные bridge-сети при помощи команды docker network create, указав опцию --driver bridge.


Например, команда docker network create --driver bridge --subnet 192.168.100.0/24 --ip-range 192.168.100.0/24 my-bridge-network создает еще одну bridge-сеть с именем “my-bridge-network” и подсетью 192.168.100.0/24.


Bridge-интерфейсы в Linux


Каждая bridge-сеть имеет свое представление в виде интерфейса на хосте. С сетью “bridge”, которая стоит по умолчанию, обычно ассоциируется интерфейс docker0, и с каждой новой сетью, которая создается при помощи команды docker network create, будет ассоциироваться свой собственный новый интерфейс.


ifconfig docker0


Чтобы найти интерфейс, который ассоциируется с сетью, которую вы создали, введите команду ifconfig, чтобы вывести все интерфейсы, а затем найти тот интерфейс, который относится к созданной вами подсети. Например, если нам надо найти интерфейс для сети my-bridge-network, которую мы только что создали, то можно запустить такую команду:


ifconfig


Bridge-интерфейсы Linux похожи на свичи тем, что они присоединяют несколько интерфесов к одной подсети и перенаправляют трафик на основе MAC-адресов. Как будет видно ниже, у каждого контейнера, привязанного к bridge-сети, будет свой собственный виртуальный интерфейс на хосте, и все контейнеры в одной сети будут привязаны к одному интерфейсу, что позволит им передавать друг другу данные. Можно получить больше данных о статусе моста при помощи утилиты brctl:


brctl


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


Виртуальные интерфейсы Linux


Container Networking Model дает каждому контейнеру свое собственное сетевое пространство. Если запустить команду ifconfig внутри контейнера, то можно увидеть его интерфейсы такими, какими их видит сам контейнер:


ifconfig


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


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


До запуска каких-либо контейнеров у bridge-интерфейса docker0 нет никаких других присоединенных интерфейсов:


docker0


Затем я запустил два контейнера на образе ubuntu:14.04:


docker ps


Сразу стало видно, что два интерфейса присоединены к bridge-интерфейсу docker0 (по одному на каждый контейнер):


sudo brctl show docker0


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


ping google.com


Аналогично можно выполнить пинг от одного контейнера к другому.


Во-первых, надо получить IP-адрес контейнера. Это можно сделать либо при помощи команды ifconfig, либо при помощи docker inspect, что позволяет проинспектировать контейнер:


docker inspect


Затем начинаем пинг от одного контейнера к другому:


docker exec ping


Чтобы увидеть трафик с хоста, мы можем сделать захват на любом из виртуальных интерфейсов, которые соотносятся с контейнерами, либо на bridge-интерфейсе (в данном случае docker0), что покажет нам все коммуникации внутри контейнеров данной подсети:


sudo tcpdump


Находим Veth-интерфейс в контейнере


Если вы хотите узнать, какой veth-интерфейс хоста привязан к интерфейсу внутри контейнера, то простого способа вы не найдете. Однако, есть несколько методов, которые можно найти на разных форумах и в обсуждениях на github. Самый простой, на мой взгляд, способ я почерпнул из этого обсуждения на github, немного его изменив. Он зависит от того, присутствует ли ethtool в контейнере.


Например, у меня в системе запущены 3 контейнера:


docker ps


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


docker exec


Затем на хосте я использую peer_ifindex, чтобы узнать имя интерфейса:


sudo ip link


В данном случае интерфейс называется veth7bd3604.


iptables


Docker использует linux iptables, чтобы контролировать коммуникации между интерфейсами и сетями, которые он создает. Linux iptables состоят из разных таблиц, но нам в первую очередь интересны только две из них: filter и nat. Таблица filter содержит правила безопасности, которые решают, допускать ли трафик к IP-адресам или портам. С помощью таблицы nat Docker дает контейнерам в bridge-сетях связываться с адресатами, которые находятся снаружи хоста (иначе пришлось бы добавлять маршруты к контейнерным сетям в сети хоста).


iptables:filter


Таблицы в iptables состоят из различных цепочек, которые соответствуют разным состояниям или стадиям обработки пакета на хосте. По умолчанию, у таблицы filter есть 3 цепочки:
Input для обработки входящих пакетов, предназначенных для того же хоста, на который они приходят;
Output для пакетов, возникающих на хосте, предназначенных для внешнего адресата;
Forward для обработки входящих пакетов, предназначенных для внешнего адресата.


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


Чтобы увидеть текущие правила цепочки и дефолтные установки в таблице filter, запустите команду iptables -t filter -L или iptables -L, если таблица filter используется по умолчанию и не указана никакая другая таблица:


sudo iptables -t filter -L


Жирным выделены разные цепочки и дефолтные установки для каждой из них (у кастомных цепочек дефолтных установок нет). Также видно, что Docker добавил две кастомные цепочки: Docker и Docker-Isolation, также добавил правила в цепочку Forward, целью которых являются эти две новые цепочки.


Цепочка Docker-isolation

Docker-isolation содержит правила, которые ограничивают доступ между разными сетями. Чтобы узнать подробности, добавляйте -v, когда запускаете iptables:


sudo iptables -t filter -L -v


Можно увидеть несколько правил DROP, которые блокируют трафик между всеми bridge-интерфейсами, которые создал Docker, и таким образом не дают сетям обмениваться данными.


icc=false

Одна из опций, которую можно передать команде docker network create, — это опция, которая отвечает за передачу данных внутри контейнера: com.docker.network.bridge.enable_icc. Если задать ей значение false, то передача данных между контейнерами внутри одной сети будет заблокирована. Для этого нужно добавить DROP-правило в цепочку forward, которое соответствует пакетам, приходящим от bridge-интерфейса, связанного с сетью для данного интерфейса.


Например, если создать новую сеть при помощи команды docker network create --driver bridge --subnet 192.168.200.0/24 --ip-range 192.168.200.0/24 -o "com.docker.network.bridge.enable_icc"="false" no-icc-network, то мы получим следующее:


ifconfig


iptables:nat


С помощью nat можно поменять IP-адрес или порт пакета. В данном случае он используется, чтобы за IP-адресом хоста спрятать адреса источников пакетов, которые приходят от bridge-сетей (например, хосты в подсети 172.18.0.0/24) и направлены во внешний мир. Эта фича контролируется опцией com.docker.network.bridge.enable_ip_masquerade, которую можно передать docker network create (если не задать ничего специфического, то по умолчанию будет значение true).


Результат этой команды можно увидеть в таблице nat:


sudo iptables -t nat -l


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


Итог


  • У bridge-сети есть соответствующий bridge-интерфейс в Linux на хосте, который действует как layer2 свич и который соединяет разные контейнеры одной подсети.
  • У каждого интерфейса сети есть соответствующий виртуальный интерфейс на хосте, который создается во время работы контейнера.
  • Захват трафика с хоста на bridge-интерфейсе равноценен созданию SPAN-порта в свиче, в котором можно увидеть все внутренние коммуникации между контейнерами данной сети.
  • Захват трафика с хоста на виртуальном интерфейсе (veth-*) покажет весь трафик, исходящий из контейнера по конкретной подсети.
  • Правила iptables в цепочке filter используются, чтобы не давать разным сетям (и иногда еще хостам внутри сети) обмениваться данными. Эти правила обычно добавляют в цепочку Docker-isolation.
  • Контейнеры, которые обмениваются данными с внешним миром через bridge-интерфейс, прячут свой IP за адресом хоста. Для этого добавляются необходимые правила nat-таблицу в iptables.

Ссылки/ресурсы


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

https://habrahabr.ru/post/333874/


Метки:  

[recovery mode] Openstack. Детективная история или куда пропадает связь? Часть третья

Пятница, 21 Июля 2017 г. 17:47 + в цитатник

«Кто так строит?!»


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

В итоге ты опомниться не успеваешь, как всё падает. Почему? Потому что неожиданно для всех default gw оказывается не на роутере, как ему положено, а на твоём опенстеке. Клиенты звонят, шеф лютует. А ты ищешь очередную причину падения. Просто коллега отцепил существующий адрес с целью замены, а опенстек оказался хитрее…


Жизнь продолжается


В некоторых случаях проблема возникает сразу, в некоторых – нет. Напомню: старая проблема состояла в том, что периодически начинались пропадания части IP-пакетов.


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


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


Поэтому мне с коллегами сложно было отделить и выявить проблему. Хуже того – в созданной вновь ферме проблема не возникала. Мы сгенерировали триста машин, и всё работало, как часы. Конечно мы тут же мы стали готовить её в «продакшн». Это подразумевало введение «рваных» диапазонов ip адресов. Мы очистили ферму, убрав эти самые триста машин. И вдруг, при наличии всего трёх тестовых виртуальных машин случилось то же, что и на старой ферме – стали пропадать пакеты, в большом количестве. Так мы определились, что проблема где-то в глубине OpenStack.


Странные временные решения


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


Решение где-то рядом


В ходе долго расследования, прерываемые на проектные работы, отвлекаемые проблемами от VIPов, мы всё-таки смогли выявить несколько ошибок. Кроме того, эти самые файлы различаются, если вы используете контроллер в качестве вычислительного узла, и если не используете. В одной из первых удачных конфигураций, мы его использовали. Затем от этого отказались. Часть настроек –осталась. Таким образом в двух из девяти машин были неправильные настройки (на вычислительные узлы попал параметр не dvr, а dvr-snat). В конце концов я нашёл правильный параметр и поставил на место.


Без понимания того, как работает виртуальный роутер – где же он берёт настройки, пришлось настраивать и его. Он, по идее, должен быть с одним адресом и, соответственно, с одним мак-адресом. Логично? Мы так рассуждали и соответственно настраивали с коллегой.


В какой-то момент при расследовании проблем с DHCP (см. часть 2) я нашёл задваивающиеся мак-адреса. Не один, два, а гораздо больше. Вот это номер!


Было принято решение сменить параметры настройки base_mac и dvr_base_mac. Теперь в каждой вычислительной машине и в каждом контроллере эти параметры разные.


Мы с самого начала ещё не включили l2population – ну просто руки не доходили. А в новой ферме включили. И гляди, после всех таких изменений – заработало! Мало того – пинги перестали пропадать от слова «вообще»! Раньше нет-нет, да и пропадёт пакетик просто так – 0,1% и мы считали, что это вообще неплохо. Потому что гораздо хуже, когда пропадала четверть, а то и половина.


Настройки, которые сделали нам хорошо - neutron.conf для controller node
root@mama:~# cat /etc/neutron/neutron.conf |grep -v "^#.*"|strings
[DEFAULT]
bind_host = 192.168.1.4
auth_strategy = keystone
core_plugin = ml2
allow_overlapping_ips = True
service_plugins = router
base_mac = fa:17:a1:00:00:00
notify_nova_on_port_status_changes = true
notify_nova_on_port_data_changes = true
advertise_mtu = true
allow_automatic_dhcp_failover = true
dhcp_agents_per_network = 3
dvr_base_mac = fa:17:b1:00:00:00
router_distributed = true
allow_automatic_l3agent_failover = true
l3_ha = true
max_l3_agents_per_router = 3
rpc_backend = rabbit
[agent]
root_helper = sudo /usr/bin/neutron-rootwrap /etc/neutron/rootwrap.conf
[database]
connection = mysql+pymysql://neutron:ZPASSWORDZ@mama/neutron
[keystone_authtoken]
auth_uri = mama:5000
auth_url = mama:35357
memcached_servers = mama:11230
auth_plugin = password
project_domain_name = default
user_domain_name = default
project_name = service
username = neutron
password = ZPASSWORDZ
[nova]
auth_url = mama:35357
auth_plugin = password
project_domain_name = default
user_domain_name = default
region_name = RegionOne
project_name = service
username = nova
password = ZPASSWORDZ
[oslo_messaging_rabbit]
rabbit_userid = openstack
rabbit_password = ZPASSWORDZ
rabbit_durable_queues = true
rabbit_hosts = mama:5673
rabbit_retry_interval = 1
rabbit_retry_backoff = 2
rabbit_max_retries = 0
rabbit_ha_queues = false
[quotas]
quota_network = 100
quota_subnet = 200
quota_port = -1
quota_router = 100
quota_floatingip = -1
quota_security_group = -1
quota_security_group_rule = -1

Настройки, которые сделали нам хорошо - neutron.conf для compute node
root@baby:~# cat /etc/neutron/neutron.conf |grep -v "^#.*"|strings
[DEFAULT]
bind_host = 192.168.1.7
bind_port = 9696
auth_strategy = keystone
core_plugin = ml2
allow_overlapping_ips = True
service_plugins = router
base_mac = fa:17:c1:00:00:00
notify_nova_on_port_status_changes = true
notify_nova_on_port_data_changes = true
allow_automatic_dhcp_failover = true
dhcp_agents_per_network = 3
dvr_base_mac = fa:17:d1:00:00:00
router_distributed = true
allow_automatic_l3agent_failover = true
l3_ha = true
max_l3_agents_per_router = 3
rpc_backend = rabbit
[agent]
root_helper = sudo /usr/bin/neutron-rootwrap /etc/neutron/rootwrap.conf
[database]
connection = mysql+pymysql://neutron:ZPASSWORDZ@mama/neutron
[keystone_authtoken]
auth_uri = mama:5000
auth_url = mama:35357
memcached_servers = mama:11230
auth_plugin = password
project_domain_name = default
user_domain_name = default
project_name = service
username = neutron
password = ZPASSWORDZ
[nova]
auth_url = mama:35357
auth_plugin = password
project_domain_name = default
user_domain_name = default
region_name = RegionOne
project_name = service
username = nova
password = ZPASSWORDZ
[oslo_messaging_rabbit]
rabbit_hosts = mama:5673
rabbit_userid = openstack
rabbit_password = ZPASSWORDZ
rabbit_durable_queues = true
rabbit_retry_interval = 1
rabbit_retry_backoff = 2
rabbit_max_retries = 0
rabbit_ha_queues = true

Сутки терпеливо выждав (а ведь хотелось бегать, с криками «всё заработало!»), мы применили подобные изменения и в старой ферме. Вторая неделя – полёт нормальный.


Вывод


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

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

https://habrahabr.ru/post/333872/


Метки:  

Разработка мобильных приложений с помощью SAP Cloud Platform SDK для iOS, часть 1

Пятница, 21 Июля 2017 г. 17:25 + в цитатник
В прошлом году SAP и Apple объявили о начале стратегического сотрудничества. Весной этого года SAP выпустил SAP Cloud Platform SDK для iOS – набор инструментов для создания корпоративных приложений, которые сочетают требования корпоративной среды и стандарты приложений для iOS.
В нескольких постах в нашем блоге мы расскажем о том, что такое SAP Cloud Platform SDK для iOS, какие функции и сервисы он поддерживает, а также как помогает разработчикам мобильных приложений ускорить подготовку и запуск корпоративных приложений для iOS.
image


Краткий FAQ о том, что такое SAP Cloud Platform SDK для iOS:

1. Что такое SAP Cloud Platform SDK для iOS?
Данный SDK – это набор фреймворков iOS, разработанных на Swift. Он должен помочь разработчикам создавать, расширять и запускать новый класс нативных корпоративных приложений для iOS с использованием SAP Cloud Platform и её сервисов.

2. Что включает в себя SAP Cloud Platform SDK для iOS?
В SDK входит несколько блоков для разработки, включая элементы пользовательского интерфейса Fiori для дизайнерского языка iOS (например, элементы управления), модели UI, шаблоны, доступ к сервисам бэкенда, упрощенный доступ к возможностям iOS и функциям устройства и т.п.

3. Как можно использовать SAP Cloud Platform SDK для iOS?
Основные сценарии для использования нового SDK – это разработка мобильных приложений для работы с S/4HANA, для локального ПО SAP (on-premise), расширения для SAP Cloud Platform или же кастомных приложений для iOS на базе SAP Cloud Platform.

4. Чем SAP Cloud Platform SDK для iOS отличается от других существующих мобильных SDK?
Новый SDK полностью разработан на современном языке программирования Apple — Swift. Он содержит набор заменяемых фреймворков, с помощью которых разработчик может подбирать необходимые функции приложения. В нём также есть набор компонентов пользовательского интерфейса для разработки корпоративных iOS-приложений. SDK позволяет подключить к приложению новые мобильные сервисы для SAP Cloud Platform.

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

6. Нужно ли быть пользователем SAP Cloud Platform, чтобы воспользоваться SDK для iOS?
Чтобы воспользоваться данным SDK, вам необходим базовый или пробный аккаунт SAP Cloud Platfrom. SAP Cloud Platform – это открытая платформа, которая поддерживает подключения к другим системам (от SAP или не от SAP). Например, вы можете безопасно подключиться к своему локальному пакету продуктов SAP Business Suite через SAP Cloud Platform Connector.

7. Можно ли бесплатно скачать SAP Cloud Platform SDK, чтобы протестировать разработку и запуск приложений?
Пробная версия SAP Cloud Platform SDK для iOS доступна для скачивания здесь.

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

9. А что с поддержкой SAP мобильных приложений для Android и Microsoft?
Мы продолжаем поддерживать другие мобильные платформы, включая Google и Microsoft. Сотрудничество с Apple – это шаг к тому, чтобы помочь разработчикам создать новый класс корпоративных приложений для iOS. Для поддержки разработки мобильных приложений для других ОС можно, как и прежде, использовать SAP Mobile Platform как в режиме onprem, так и облачную версию, как сервис SAP Cloud Platfrom.

Что ещё входит в SAP Cloud Platform SDK для iOS.

Для работы с нашим SDK нужно знать о нескольких ключевых вещах:

• Приложение SAP Cloud Platform SDK for iOS Assistant
• Набор фреймворков
• Управляющие элементы Fiori для iOS
• Приложение SAP Fiori for iOS Mentor
• Оффлайн-режим
• Push-нотификации
• Регистрация и отслеживание сообщений в приложении

SCP SDK for iOS Assistant – это приложение для Mac, которое помогает быстро генерировать объектно-ориентированные proxy классы Swift для сервисов OData, чтобы уменьшить зависимость от низкоуровневых API. Ассистент также помогает генерировать конфигурации мобильных сервисов и проекты в Xcode, готовые к запуску на iPhone или iPad.

image

Набор фреймворков в SDK. Фреймворки SAPFoundation и SAPCommon включают в себя компоненты, которые интегрируют приложение с мобильным сервисом SAP Cloud Platform. Здесь мы помогаем разработчикам упростить подключение аутентификации, подгрузки логов, push-нотификаций, подключение к сети и т.п. На глобальном сайте SAP есть несколько туториалов по настройке аутентификации и входа в приложение.

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

image

SAP Fiori for iOS Mentor – это приложение для iPad, в котором вы можете протестировать управляющие элементы, UI и другие доступные компоненты Fiori. С помощью приложения вы можете также изучить и подобрать все возможные варианты, а также сгенерировать уже готовые для использования сниппеты с кодом, в которых будут выбранные вами настройки.

image
image

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

Push-нотификации. С помощью нотификаций пользователи смогут получать уведомления о том, когда новая информация становится доступной в приложении. Сервис работает через REST API и с помощью простой интеграцией с сервисом push-нотификаций Apple (APNs). Можно таргетировать нотификации по устройству, приложению, списку или группе пользователей. Среди доступных типов сообщений – баннеры, звуки и многое другое.

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

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

-> Обучающие материалы для мобильных разработчиков по SAP Fiori
-> Гайдлайны сервиса SAP Fiori Design
-> Бесплатная пробная версия SAP Cloud Platform SDK for iOS в SAP Store
-> Интерактивные обучающие материалы

В следующих постах мы подробнее расскажем о том, как запустить и протестировать SAP Cloud Platform SDK для iOS, о доступных сервисах и интеграциях.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333802/


[Из песочницы] Red Architecture — красная кнопка помощи для сложных и запутанных систем

Пятница, 21 Июля 2017 г. 17:24 + в цитатник


В начале несколько слов о названии, почему Red?


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

Наверное у кого-то возникнет вопрос — а зачем нужна ещё одна архитектура?


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

Задача Red Architecture — свести сложность реализации логики приложения к минимуму, оставляя при этом нетронутыми возможность применения и все преимущества других паттернов проектирования.

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



Единственный класс в Red Architecture характеризуется следующими возможностями:

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

Вы можете сказать, что похожий паттерн уже существует и называется KVO, NSNotification и NSNotificationCenter, шаблон Delegate и т.п. Но, во-первых, данный класс имеет ряд ключевых отличий. Во-вторых — главное в Red Architecture вовсе не содержание этого класса, а как он используется в совокупности с представленными здесь соглашениями. Это мы и рассмотрим дальше.

Конкретный пример:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Common
{
    public enum k {OnMessageEdit, MessageEdit, MessageReply, Unused, MessageSendProgress, OnMessageSendProgress, OnIsTyping, IsTyping, MessageSend, JoinRoom, OnMessageReceived, OnlineStatus, OnUpdateUserOnlineStatus }

    public class v : ObservableCollection >
    {
        static v i;

        static v sharedInstance()
        {
            if (i == null)
                i = new v();

            return i;
        }

        public static void h(System.Collections.Specialized.NotifyCollectionChangedEventHandler handler)
        {
            i.CollectionChanged += handler;
        }

        public static void m(System.Collections.Specialized.NotifyCollectionChangedEventHandler handler)
        {
            i.CollectionChanged -= handler;
        }

        public static void Add(k key, object o)
        {
            i.OnCollectionChanged(new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Add,
new List>(new KeyValuePair[] { new KeyValuePair(key, o) })));
        }

        protected v()
        {
        }
    }
}

Маленький класс, унаследованный от ObservableCollection. Из названия базового класса следует, что есть возможность следить за изменениями в данной коллекции, такими как добавление и удаление элементов. На самом деле, в классе v используется только механизм нотификации об изменениях в коллекции. Никакие данные в коллекцию не добавляются и не удаляются — в Red Architecture есть соглашение “Consume now or never”, которое не подразумевает хранение данных на стадии их передачи по логической цепочке с использованием класса v. Метод Add() всего лишь отправляет нотификацию, содержащую “добавляемые” данные всем функциям подписчикам. Так же в классе присутствуют функции h() для добавления нового подписчика и m() для его удаления.

Кроме того, в классе присутствует перечисление k. И если сам класс является ключевым элементом всей архитектуры, то данное перечисление является ключевым элементом этого класса. Взглянув на имена элементов перечисления (которые в самом хорошем случае могут быть дополнены подробными комментариями) можно легко понять, какие функции реализованы в приложении. Более того, если вам станет интересно, как же всё таки реализована каждая из этих функций, вам будет достаточно поискать по проекту, например “k.OnMessageEdit”. Вы удивитесь небольшому объёму кода, который найдёте, а его содержание вызовет у вас желание незамедлительно приобщиться к разработке, поскольку, очень вероятно, что вам сразу станет понятна логика рассматриваемой функции на каждом из этапов — от получения результата запроса, до отображения результата в UI. В то же время, вас вряд ли на текущий момент заинтересует какие слои есть в приложении, и вообще, как физически организован код. Даже в текущем файле вам вряд ли будет интересен близлежащий контекст.

Но давайте вернёмся к дальнейшему рассмотрению примера.

Для каждого элемента перечисления k существует два способа использования:

1. Ключ “добавляется” в класс v инициируя рассылку данных с этим ключом по подписчикам.
2. Данные, присланные с данным ключом обрабатываются объектами — подписчиками.

Приведём подробные пояснения к пункту 1:

К слову сказать, в перечислении k могут быть отражены далеко не все функции, реализованные в приложении. Т.е. я хочу обратить внимание на один немаловажный аспект Red Architecture — для начала перехода к Red Architecture не требуется масштабных реорганизаций кода. Вы можете начать применять её прямо “здесь и сейчас”. Red Architecture мирно сосуществует с прочими шаблонами проектирования благодаря не связанному со слоями или физической организацией программы способу построения логики. Единственный необходимый инфраструктурный элемент Red Architecture — программный объект, реализующий интерфейс подобный тому, который есть у рассматриваемого нами класса v.

Рассматриваемый здесь класс v не оптимален. Давайте рассмотрим что следовало бы улучшить.

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

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

Вероятно, можно сделать и ещё одно улучшение. На текущий момент класс v единственный и содержит в себе все ключи функций, реализованных с помощью Red Architecture. Правильнее было бы отдельные группы ключей выделить в собственные классы, подобные v. Например ключи MessageEdit и OnMessageEdit имеют очевидную связь — ключ MessageEdit используется в логической цепочке отправки отредактированного сообщения, ключ OnMessageEdit — в обработке прихода данных. Для них можно создать отдельный класс по шаблону класса v. Таким образом, на данную логическую цепочку смогут подписаться только “заинтересованные” программные объекты. В текущем же рассматриваемом примере уведомления о “добавлении” данных рассылаются всем подписчикам, в том числе и незаинтересованным в каком-то из ключей.

Если же не хочется “размножать” класс v, то можно изменить метод h(), добавив в него первым параметром ключ, на который подписывается данный объект.

Теперь приведём примеры к пункту 2, а именно возможные варианты обработки данных функциями обработчиками:

void OnEvent(object sener, NotifyCollectionChangedEventArgs e)
{
	if (e.Action == NotifyCollectionChangedAction.Add)
	{
		var newItem = (KeyValuePair)e.NewItems[0];
		if (newItem.Key == k.OnMessageSendProgress)
		{
			var d = (Dictionary)newItem.Value;
			if ((string)d["guid"] == _guid && (ChatMessage.Status)d["status"] == ChatMessage.Status.Deleted)
			{
				Device.BeginInvokeOnMainThread(() =>
				{
					FindViewById(Resource.Id.message).Text = "";
				});
			}
		}
		else if (newItem.Key == k.OnMessageEdit)
		{
			var d = (Dictionary)newItem.Value;
			if ((string)d["guid"] == _guid)
			{
				Device.BeginInvokeOnMainThread(() =>
				{
					FindViewById(Resource.Id.message).Text = (string)d["message"];
				});
			}
		}
	}
}

В приведённом примере функция OnEvent() является обработчиком, находящимся прямо в объекте класса ячейки списка (таблицы). Нас интересуют только события «добавления» данных, для фильтрации только этих событий мы в первую очередь добавляем условие if (e.Action == NotifyCollectionChangedAction.Add). Далее мы получаем данные которые пришли с событием, и проверяем чтобы ключ этих данных соответствовал ключу, для обработки данных которого предназначена данная функция:

	
var newItem = (KeyValuePair)e.NewItems[0];
if (newItem.Key == k.OnMessageSendProgress)

После прохождения условия на соответствие ключа мы уже точно знаем формат данных, которые к нам пришли. В рассмартваемом примере это словарь: var d = (Dictionary)newItem.Value;

Теперь, всё что нам осталось, это убедится, что пришедшие данные соответствуют данной ячейке таблицы if ((string)d[«guid»] == _guid И статус данного сообщения говорит о том, что оно было удалено: && (ChatMessage.Status)d[«status»] == ChatMessage.Status.Deleted). После этого мы заменяем значение текстового поля в текущей ячейке на строку "\":

Device.BeginInvokeOnMainThread(() =>
{
	FindViewById(Resource.Id.message).Text = "";
});

Заметьте использование Device.BeginInvokeOnMainThread() — мы должны помнить, что OnEvent() может быть вызван не только в главном потоке, а как мы все знаем, перерисовка UI элементов возможна только в главном потоке. Поэтому мы должны вызывать

FindViewById(Resource.Id.message).Text = "";
в главном потоке.

Наличие в предложенном примере else if (newItem.Key == k.OnMessageEdit) подсказывает, что нам ничто не мешает обрабатывать более одного ключа, если это необходимо в данном конкретном случае.

Архитектурные соглашения:

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

Для данного соглашения приведём пример:

                   
 string s = Response.ResponseObject["success"].ToString();
 success = Convert.ToBoolean(s);
 if (success)
 {
     var r = Response.ResponseObject["data"].ToString();
     if(r.Contains("status")) // response not empty
     {
           Dictionary retVal = JsonConvert.DeserializeObject>(r);

           // convert status from web to internal type
           retVal["status"] = (ChatMessage.Status)Enum.ToObject(typeof(ChatMessage.Status), retVal["status"]);

           await PersistanceService.GetCacheMessagePersistance().UpdateItemAsync(retVal);
           v.Add(k.OnMessageSendProgress, retVal);
      }
}

Здесь мы видим обработку поля status из ответа запроса. Сначала status приводится к внутреннему типу ChatMessage.Status и только после этого вызывается v.Add() куда передаются уже конвертированные во внутренний формат данные, которые ожидают обработчики.

Тоже касается и ошибок и полученных значений null и т.п. Если мы получили null, например, в результате ошибки, мы не делаем v.Add(k.SomeKey, null). Вместо этого мы интерпретируем null здесь — в месте его получения в употребимую понятную информацию, и отправляем её с данным ключом, например так: v.Add(k.SomeKey, {errorCode: 10, errorMessage: “Error! Try later.”});

— Потребление данных сейчас или никогда. (Consume now or never). Полученные данные (в результате вызова функции или запроса) не сохраняются в памяти для будущей обработки. Они должны быть “употреблены” сразу же после получения, в другом случае они просто не будут обработаны. Потребителями данных являются функции-обработчики. Например, если ячейка списка запросила данные для своего отображения, и данные пришли после того, как ячейка вышла из области видимости на экране смартфона пользователя, то такие данные не будут обработаны (или, если это был веб-запрос, то они могут быть сохранены в кеш, чтобы не делать в будущем ещё один запрос, когда данная ячейка вновь появится на экране пользователя и запросит данные для своего отображения).

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

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

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

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

— В Red Architecture не обязательно применять известный подход, когда внутренняя структура программы описывается в терминах объектов или явлений из реальной жизни. Данная архитектура предполагает возможность успешной реализации задач при внутренней структуре приложения не отражающей объекты или явления из предметной области реальной жизни. Вместо этого, приложение фактически поделено на маленькие части логики, которые ничего “не знают” друг о друге, и “общаются” друг с другом опосредованно, используя для этого специальный программный компонент, в нашем случае класс v. Части логики объединены в цепочку посредством передачи друг другу данных с использованием ключей имеющихся в классе v в перечислении k.

Заключение

Данная архитекрура реализует все плюсы описанные, например, в «Чистой архитектуре» (Clean Architecture) + имеет дополнительные преимущества:

  • Основные принципы легко понять и применить

  • Решает проблему зависимости одного объекта от жизненного цикла другого. Например, контроллер делает запрос данных, но на момент их получения контроллер или вью в котором данные должны быть обработаны/отражены уже не существует. Или в Андроиде, при перевороте экрана пересоздаются фрагменты, что для многих разработчиков является вопросом, который нужно специально прорабатывать. В Red Architecture таких проблем нет, поскольку жизненный цикл объекта важен только для него самого. Другие объекты системы, отправляющие данные с ключами, обрабатываемыми данным объектом, ничего про него не знают.

  • Легко найти/понять где/как реализованы фитчи приложения по ключам в Главном классе

  • Для взаимодействия между частями программы не используются интерфейсы и/или адаптеры, что избавляет объекты от необходимости «следить» за состоянием и жизненным циклом друг друга, проверять слабые ссылки (weak references), делегаты на null, и т.п.

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

  • Благодаря отсутствию завязки на слои (бизнес, слой данных, слой приложения и т.п.) достигается гораздо более глубокий уровень разделения (обязанностей) в коде. Прочие архитектуры, например Clean Architecture, описывают взаимодействие между слоями приложения, в то время как Red Architecture описывает взаимодействие между частями программы “сквозь” слои логики или физической организации кода.

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

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

Для примеров используется код из приложения на С# Xamarin, но паттерн Red Architecture поможет упростить любое клиентское приложение независимо от платформы.

В названии статьи не случайно упоминаются термины одной из теорий, составляющих «тело» Agile, а именно из Теории запутанности. Red Architecture помогает эффективнее реализовывать принципы Agile в независимости от фреймворка — будь то Scrum или Kanban.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333870/


Метки:  

Жизнь разработчика на Кипре

Пятница, 21 Июля 2017 г. 16:23 + в цитатник
Если вы, как и я когда-то, планировали вырваться из нежных и цепких объятий родины в цивилизованный мир, то наверняка сталкивались с персонажами, не вынесшими такого счастья и вернувшимися из иммиграции на территорию отечества. Наверняка можете вспомнить и полный недоуменного негодования вопрос «Почему?», обращенный к тем самым сумасшедшим. Вопрос этот зачастую оставался риторическим, ибо абстрактные ответы о непреодолимых культурных различиях и страстном желании обнять березки ответами де-факто не являются.



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

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

Что, спрашивается, может пойти не так? Да, в общем-то, всё что угодно.

Климат


Давайте начнем с климата. Сейчас в июне, когда я пишу эти строки, термометр показывает +31C. В июле будет примерно +40С. Сколько будет в августе — не знает никто, т.к. к этому времени ласковое солнышко выдавливает оставшихся в живых представителей относительно разумной фауны куда-нибудь в горы или вообще за пределы острова. В связи с этим могу поделиться тремя занимательными фактами о лете.

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

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

Факт третий. Летом забываешь, какой кран отвечает за горячую воду, а какой за холодную. Ибо из обоих течет водичка «комнатной» (за бортом +40С, напомню) температуры. Очень приятно и освежающе.

Наверное, я сгущаю краски и вот уж зимой-то точно все хорошо? Конечно, хорошо. Температура существенно опускается, но, тем не менее, остается положительной. И вот тут начинают играть роль представления киприотов о домах — с тонкими стенами, большими окнами и не менее большими щелями везде, где только можно. В результате героическое поддержание хотя бы +18С в небольшой квартире-студии обходится примерно в 100 евро/мес. Еще никогда в жизни мои кошки не были такими пушистыми! Ну а необходимость самостоятельно греть воду чтобы помыться так и вовсе выбивает скупую мужскую слезу в память о централизованном горячем водоснабжении.



Природа и города


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

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

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

Любителям красивой и/или старинной архитектуры на Кипре тоже ничего не светит — всю власть в стране захватили стандартные 2-4-этажные белые коробки. Церкви, пожалуй, выделяются кирпичного цвета черепицей, но выглядят они настолько одинаково, что начинаешь верить, будто в их строительстве применялся единственный метод, а именно Ctrl+C, Ctrl+V.

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

С Кипра чертовски приятно улетать! Любая Тьмутаракань начинает блистать архитектурой, каждое пятиэтажное здание превращается в небоскреб, а от обилия зелени — да даже в центре Москвы — просто захватывает дух.

Аэропорт


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



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

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

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

Налоги


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

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

Итак, трудности преодолены, логины и пароли получены, заполняем декларацию. В общем и целом она не сильно отличается от российской 3-НДФЛ, где указываются полученные доходы и уплаченные с них налоги, в результате чего подбивается баланс (в идеале — нулевой).
Все просто, но киприоты не были бы киприотами, если бы не накосячили и здесь. Причем со вкусом: половина полей анкеты принимала вещественные числа, а другая половина — только целые, причем в совершенно бессистемно. Результат очевиден — дебит с кредитом не сошлись на пару десятков центов.



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

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

Банки


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

Можно долго рассказывать об особенностях банковского обслуживания, или о том, что заказанная пластиковая карточка вместе с пин-кодом в обязательном порядке отправляется письмом на домашний адрес (во имя безопасности — в разных конвертах и с разницей в 1 день).
Во всей красе кипрские банки проявили себя, когда мне надо было обменять евро на фунты для поездки в Британию. 2000 евро сумма не то, чтобы астрономически большая, но просто так ее с собой таскать не хочется, поэтому для начала зашел в свое банковское отделение с вопросом, можно ли произвести обмен. «Конечно, можно! За свои евро получите вот столько вот фунтов,» — ответили мне.

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

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

Наступает следующий день. Банк предсказуемо молчит. Не беда, иду туда ножками. «О, вы пришли 2000 евро обменять?» — кричит мне через весь зал ставший уже родным кассир — «А деньги только приехали, подходите.»

Полиция


Подобные увлекательные квесты поджидают счастливых обитателей острова буквально на каждом шагу. Понадобилось мне однажды получить кипрскую справку о несудимости (Criminal records certificate). Делаться справка должна в полиции, а вот где конкретно — вопрос. Разумеется, в полицию можно позвонить и всё узнать. Заходим на сайт кипрской полиции и лицезреем список полезных телефонов:



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



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

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

Транспорт


Местные таксисты при всем при этом — так же совершенно прекрасные и чудесные люди, делящиеся на несколько категорий:

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

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

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

Вместо такси, в принципе, можно рискнуть воспользоваться общественным транспортом. Ходит он по расписанию с интервалом движения минут в 40. Само расписание можно посмотреть через официальное приложение. В нем же, теоретически, можно и проложить маршрут, но поскольку написано оно профессиональными индусами, пользоваться этой функцией совершенно невозможно — проще построить маршрут по 2ГИС, а затем уже в приложении свериться с расписанием.

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

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

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

Работа в IT


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

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

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

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

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

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

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

Выводы


Какие, в целом, выводы можно сделать из этой длинной и не совсем связной истории?

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

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

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

https://habrahabr.ru/post/333866/


Метки:  

Отчет с Science Slam Digital 7 июля

Пятница, 21 Июля 2017 г. 15:44 + в цитатник

image


7 июля Science Slam Digital собрал в нашем офисе более 600 зрителей, а число просмотров трансляции в соцсетях Одноклассники и ВКонтакте превысило 420 тысяч. Формат Science Slam зародился в Германии семь лет назад для популяризации научных достижений среди простых обывателей. Он состоит из серии научных лекций, которые читают молодые ученые. Доклад участника должен быть коротким (10 минут), доступным и информативным. Победителя слема определяют с помощью определения громкости аплодисментов зрителей шумометром.


Нам очень понравился этот формат, и мы захотели провести свой Science Slam, только цифровой, чтобы рассказать о технологиях просто и понятно. О том, что происходит внутри компании и чем занимаются сотрудники. Шесть разработчиков рассказали гостям и зрителям трансляции, что можно определить по почте, не открывая самих писем; как выяснить возраст человека в социальных сетях, даже если он не указан; какие тренды в медиапотреблении можно выделить уже сейчас и как они влияют на восприятие информации; как модифицировать социальную сеть, которой пользуются 100 миллионов человек, чтобы у них ничего не сломалось. Как это у нас получилось, вы можете посмотреть по нашим докладам.


Ян Романихин (руководитель команды машинного обучения Почты Mail.Ru): «Когда умрет электронная почта? Не сегодня»





Борис Ребров (руководитель разработки клиентской части в группе frontend-разработки медиапроектов): «Как технологии меняют медиа»





Вячеслав Шебанов (старший разработчик ВКонтакте): «Как менять сервис, которым пользуются 100 миллионов человек»





Виталий Худобахшов (разработчик отдела дата-майнинга Одноклассников): «Как узнать возраст человека в социальной сети, даже если он не указан»





Дмитрий Суконовалов (руководитель направления аналитики):«Как вернуть ушедшего пользователя»





Алексей Петров (директор по качеству в отделе тестирования Почты Mail.Ru): «Баги есть? А если найду?»





Записи видеотрансляций доступны во ВКонтакте и Одноклассниках. А здесь можно найти фотоотчет с мероприятия и видеоотчет. В ноябре у нас состоится новый Science Slam Digital, но на этот раз он будет межкорпоративным. Встретимся осенью!

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

https://habrahabr.ru/post/333814/


Метки:  

Чёрная Лямбда ефрейтора Волкова: новое направление и гранты на летнюю школу

Пятница, 21 Июля 2017 г. 15:43 + в цитатник

Bitfury Group провела 1-ю транзакцию в Lightning Network c использованием биткойн-протокола

Пятница, 21 Июля 2017 г. 15:41 + в цитатник
В начале месяца Bitfury Group провела первую multi-hop-транзакцию в сети Lightning Network, переслав несколько лайткойнов off-chain. Теперь же нам удалось успешно протестировать работу Lightning Network c использованием биткойн-протокола.

/ изображение Vadim Kurland CC

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




«Это крупное достижение нашей технической команды и важный шаг на пути к росту сети Lightning и биткойна, — говорит Валерий Вавилов, CEO Bitfury Group. — Lightning Network способна решить проблему масштабирования биткойн-блокчейна и предоставить функциональность мгновенных платежей. Продемонстрировав состоятельность LN-концепции, мы проложили путь дальнейшему развитию биткойна»
Программное обеспечение, написанное разработчиками Bitfury, базируется на протоколе LND (Lightning Network Daemon), разрабатываемом Lightning Labs. Модифицированный код можно найти по ссылке на GitHub.

В транзакции были задействованы три LND-узла. Два из них были соединены с промежуточным платежными двунаправленными каналами. Хеши фундирующих транзакций вы можете найти в любом обозревателе блоков:
d8dc019280a8531fdcf26e350874fe3100c06925306f002d85c943d9c215609e 8a4bf5481b12ee572639454939bef0d5e5b1a92bb3892db431ebb88f944e3f90

После открытия каналов были проведены две транзакции: одна single-hop и одна multi-hop. После чего в биткойн-блокчейн были отправлены закрывающие транзакции. Их хеши выглядят следующим образом:

5e1ddeb8ebdc1a8603e6294546858da3e432af532f2b71ba0fc2214a9ecafd0c 00843a49178ba5304d1940945312d66e066dc59f96a006d04c21adbb4f074656

Логи LND, участвующих в транзакции, также были опубликованы на GitHub.

О сети Lightning


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

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

Компания Bitfury более года поддерживает разработку сети Lightning. В июле 2016 нами был представлен отчет со спецификацией алгоритма маршрутизации Flare, разработанного совместно с командой Lightning Network. Алгоритм был протестирован компанией ACINQ.

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

Дополнительные материалы для чтения:

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

https://habrahabr.ru/post/333864/


Метки:  

[Перевод] MVC на чистом JavaScript

Пятница, 21 Июля 2017 г. 15:00 + в цитатник
Шаблоны проектирования часто встраивают в популярные фреймворки. Например, шаблон MVC (Model-View-Controller, Модель-Представление-Контроллер) можно встретить буквально повсюду. В JavaScript трудно отделить фреймворк от реализованного в нём шаблона проектирования, причём, часто авторы фреймворков интерпретируют MVC по-своему и навязывают программистам своё видение вопроса.



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

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

Шаблон проектирования MVC появился несколько десятков лет назад. Полагаю, в его изучение стоит вложить время любому программисту. Этот шаблон можно использовать без привязки к каким-либо фреймворкам.

Реализация MVC — это ещё один фреймворк?


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

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

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

Стоит ли избегать клиентских фреймворков? Каждый сам ответит на этот вопрос, однако, вот несколько веских причин от них отказаться:

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

Шаблон MVC


Шаблон проектирования MVC родом из 1970-х. Он появился в научно-исследовательском центре Xerox PARC в ходе работы над языком программирования Smalltalk. Шаблон прошёл проверку временем в деле разработки графических пользовательских интерфейсов. Он пришёл в веб-программирование из настольных приложений и доказал свою эффективность в новой сфере применения.

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

Пример реализации MVC


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

При создании приложения пользоваться мы будем шаблоном MVC, строго следуя его принципам. Кроме того, в процессе решения задачи будет задействована методология экстремального программирования, а также модульные тесты. Всё будет сделано на JS, HTML и CSS — никаких фреймворков, ничего лишнего.

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

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

Итак, приступим.

Общий обзор проекта


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

Вот как это выглядит в виде схемы.


Схема проекта

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

Представление PenguinView взаимодействует с DOM. DOM — это API браузера, с помощью которого работают с HTML. В MVC только представление отвечает за изменения DOM. Представление может выполнять подключение обработчиков событий пользовательского интерфейса, но обработка событий — прерогатива контроллера. Основная задача, решаемая представлением — управлять тем, что пользователь видит на экране. В нашем проекте представление будет выполнять манипуляции с DOM, используя JavaScript.

Модель PenguinModel отвечает за работу с данными. В клиентском JS это означает выполнение Ajax-операций. Одно из преимуществ шаблона MVC заключается в том, что всё взаимодействие с источником данных, например — с сервером, сосредоточено в одном месте. Такой подход помогает программистам, которые не знакомы с проектом, разобраться в нём. Модель в этом шаблоне проектирования занята исключительно работой с JSON или объектами, которые поступают с сервера.

Если при реализации MVC нарушить вышеописанное разделение сфер ответственности компонентов, мы получим один из возможных анти-паттернов MVC. Модель не должна работать с HTML. Представление не должно выполнять Ajax-запросов. Контроллер должен играть роль посредника, не заботясь о деталях реализации других компонентов.

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

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

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


Приложение на CodePen

Рассмотрим этот код.

Контроллер


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

var PenguinController = function PenguinController(penguinView, penguinModel) {
  this.penguinView = penguinView;
  this.penguinModel = penguinModel;
};

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

Затем подключаются события, связанные со взаимодействием с пользователем:

PenguinController.prototype.initialize = function initialize() {
  this.penguinView.onClickGetPenguin = this.onClickGetPenguin.bind(this);
};

PenguinController.prototype.onClickGetPenguin = function onClickGetPenguin(e) {
  var target = e.currentTarget;
  var index = parseInt(target.dataset.penguinIndex, 10);

  this.penguinModel.getPenguin(index, this.showPenguin.bind(this));
};

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

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

PenguinController.prototype.showPenguin = function showPenguin(penguinModelData) {
  var penguinViewModel = {
    name: penguinModelData.name,
    imageUrl: penguinModelData.imageUrl,
    size: penguinModelData.size,
    favoriteFood: penguinModelData.favoriteFood
  };

  penguinViewModel.previousIndex = penguinModelData.index - 1;
  penguinViewModel.nextIndex = penguinModelData.index + 1;

  if (penguinModelData.index === 0) {
    penguinViewModel.previousIndex = penguinModelData.count - 1;
  }

  if (penguinModelData.index === penguinModelData.count - 1) {
    penguinViewModel.nextIndex = 0;
  }

  this.penguinView.render(penguinViewModel);
};

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

Представленные здесь модульные тесты построены по модели AAA (Arrange, Act, Assert — размещение, действие, утверждение). Вот модульный тест для стандартного сценария показа информации о пингвине:

var PenguinViewMock = function PenguinViewMock() {
  this.calledRenderWith = null;
};

PenguinViewMock.prototype.render = function render(penguinViewModel) {
  this.calledRenderWith = penguinViewModel;
};

// Arrange
var penguinViewMock = new PenguinViewMock();

var controller = new PenguinController(penguinViewMock, null);

var penguinModelData = {
  name: 'Chinstrap',
  imageUrl: 'http://chinstrapl.jpg',
  size: '5.0kg (m), 4.8kg (f)',
  favoriteFood: 'krill',
  index: 2,
  count: 5
};

// Act
controller.showPenguin(penguinModelData);

// Assert
assert.strictEqual(penguinViewMock.calledRenderWith.name, 'Chinstrap');
assert.strictEqual(penguinViewMock.calledRenderWith.imageUrl, 'http://chinstrapl.jpg');
assert.strictEqual(penguinViewMock.calledRenderWith.size, '5.0kg (m), 4.8kg (f)');
assert.strictEqual(penguinViewMock.calledRenderWith.favoriteFood, 'krill');
assert.strictEqual(penguinViewMock.calledRenderWith.previousIndex, 1);
assert.strictEqual(penguinViewMock.calledRenderWith.nextIndex, 3);

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

Объект assert взят из Node.js, но можно воспользоваться аналогичным объектом из библиотеки Chai. Это позволяет писать тесты, которые можно выполнять и на сервере, и в браузере.

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

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


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

var PenguinView = function PenguinView(element) {
  this.element = element;

  this.onClickGetPenguin = null;
};

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

PenguinView.prototype.render = function render(viewModel) {
  this.element.innerHTML = '

' + viewModel.name + '

' +    '' + viewModel.name + '' +    '

Size: ' + viewModel.size + '

' +    '

Favorite food: ' + viewModel.favoriteFood + '

' +    'Previous ' +    'Next';  this.previousIndex = viewModel.previousIndex;  this.nextIndex = viewModel.nextIndex;  // Подключение обработчиков событий щелчков по кнопкам и передача задачи обработки событий контроллеру  var previousPenguin = this.element.querySelector('#previousPenguin');  previousPenguin.addEventListener('click', this.onClickGetPenguin);  var nextPenguin = this.element.querySelector('#nextPenguin');  nextPenguin.addEventListener('click', this.onClickGetPenguin);  nextPenguin.focus(); }

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

Для того, чтобы всё это протестировать, мы можем проверить обновление элементов и изменение состояния приложения:

var ElementMock = function ElementMock() {
  this.innerHTML = null;
};

// Функции-заглушки, необходимые для того, чтобы провести тестирование
ElementMock.prototype.querySelector = function querySelector() { };
ElementMock.prototype.addEventListener = function addEventListener() { };
ElementMock.prototype.focus = function focus() { };

// Arrange
var elementMock = new ElementMock();

var view = new PenguinView(elementMock);

var viewModel = {
  name: 'Chinstrap',
  imageUrl: 'http://chinstrap1.jpg',
  size: '5.0kg (m), 4.8kg (f)',
  favoriteFood: 'krill',
  previousIndex: 1,
  nextIndex: 2
};

// Act
view.render(viewModel);

// Assert
assert(elementMock.innerHTML.indexOf(viewModel.name) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.imageUrl) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.size) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.favoriteFood) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.previousIndex) > 0);
assert(elementMock.innerHTML.indexOf(viewModel.nextIndex) > 0);

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

Модель


В шаблоне MVC модель занята взаимодействием с источником данных. В нашем случае — с севером. Например:

var PenguinModel = function PenguinModel(XMLHttpRequest) {
  this.XMLHttpRequest = XMLHttpRequest;
};

Обратите внимание на то, что модуль XMLHttpRequest внедрён в конструктор модели. Это, кроме прочего, подсказка для других программистов касательно компонентов, необходимых модели. Если модель нуждается в различных способах работы с данными, в неё можно внедрить и другие модули. Так же, как и в рассмотренных выше случаях, для модели можно подготовить модульные тесты.

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

PenguinModel.prototype.getPenguin = function getPenguin(index, fn) {
  var oReq = new this.XMLHttpRequest();

  oReq.onload = function onLoad(e) {
    var ajaxResponse = JSON.parse(e.currentTarget.responseText);
    // Индекс должен быть целым числом, иначе это работать не будет
    var penguin = ajaxResponse[index];

    penguin.index = index;
    penguin.count = ajaxResponse.length;

    fn(penguin);
  };

  oReq.open('GET', 'https://codepen.io/beautifulcoder/pen/vmOOLr.js', true);
  oReq.send();
};

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

var LIST_OF_PENGUINS = '[{"name":"Emperor","imageUrl":"http://imageUrl",' +
  '"size":"36.7kg (m), 28.4kg (f)","favoriteFood":"fish and squid"}]';

var XMLHttpRequestMock = function XMLHttpRequestMock() {
  // Для целей тестирования нужно это установить, иначе тест не удастся
  this.onload = null;
};

XMLHttpRequestMock.prototype.open = function open(method, url, async) {
  // Внутренние проверки, система должна иметь конечные точки method и url
  assert(method);
  assert(url);
  // Если Ajax не асинхронен, значит наша реализация весьма неудачна :-)
  assert.strictEqual(async, true);
};

XMLHttpRequestMock.prototype.send = function send() {
  // Функция обратного вызова симулирует Ajax-запрос
  this.onload({ currentTarget: { responseText: LIST_OF_PENGUINS } });
};

// Arrange
var penguinModel = new PenguinModel(XMLHttpRequestMock);

// Act
penguinModel.getPenguin(0, function onPenguinData(penguinData) {

  // Assert
  assert.strictEqual(penguinData.name, 'Emperor');
  assert(penguinData.imageUrl);
  assert.strictEqual(penguinData.size, '36.7kg (m), 28.4kg (f)');
  assert.strictEqual(penguinData.favoriteFood, 'fish and squid');
  assert.strictEqual(penguinData.index, 0);
  assert.strictEqual(penguinData.count, 1);
});

Как видите, модель заботят лишь необработанные данные. Это означает работу с Ajax и с JavaScript-объектами. Если вы не вполне владеете темой Ajax в JavaScript, вот полезный материал об этом.

Модульные тесты


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

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

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

О развитии учебного проекта


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

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

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

Итоги


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

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

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

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

Уважаемые читатели! Какие шаблоны проектирования вы применяете в своих JS-проектах?
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/333856/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1060 1059 [1058] 1057 1056 ..
.. 1 Календарь