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

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

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

Тёмные паттерны — как зловредные интерфейсы пытаются атаковать и обманывать

Вторник, 13 Июня 2017 г. 16:44 + в цитатник
Любые покупки — как поход по минному полю. Есть довольно тонкая граница между «не стоит упоминания» и «лучше тебе этого до покупки не знать». Давайте попробуем для начала найти её эмпирически. Вот это лично для меня — очевидный “dark pattern”:



Вот это тоже:



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

Теперь давайте посмотрим на менее очевидные вещи.


Вот замечательная девушка Оля прислала картинку из китайского ресторана в Петербурге:



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

Вот ещё вариант со страховкой:



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

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



Вот здесь мне не дают прочитать тариф — маленькое окно и английский:



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

Вот это явный даркпаттерн Аэрофлот-Бонуса, чтобы получить услугу, нужно подписаться на другую:





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

Вот ещё одно суровое место, где о психике пользователя заранее позаботились:



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

А вот юридически-правильное и очень крутое обоснование:



Только вот юзеру от этого не лучше. Он видел «20 Гб» в заголовке без звёздочек, и что это 10 днём, а 10 ночью — не знал:



В реальном мире даркпаттерн:



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

Вот ещё один пример «мягко навязанной» услуги:



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

Вот ещё похожий по ощущениям момент: Дропбокс открывает окно предупреждения про то, что место кончается:



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



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



Но давайте посмотрим ещё на то, что может быть явным «тёмным паттерном». Вот это объявление ЦППК — оно или нет?



Проблема в том, что тут непонятно, что такое «залоговая стоимость» — складывается ощущение, что это цена карты. Непонятно, что она бесплатная. Нет пункта (3), где говорится о получении залога обратно. Поскольку ЦППК нет особого смысла снижать количество провождающих электрички, наверное, это просто кривые руки. Для них-то понятие «Залоговая стоимость» очевидно.

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



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

Вот ещё скрин:



Там экраном ниже примечательная вещь:



За «лучшее» и другие превосходные степени без доказательства больно бьёт антимонопольный комитет. Кстати, это яркий показатель того, что компания работает втёмную — обычно это первое, что пишут на вывеске или в рекламе. Моё просто исследование показало, что как минимум это не лучшая цена — либо не хватает существенных условий сделки вроде «*при доставке до 30 минут».



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

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

Проверяем.

Терминал в сотовом салоне:



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

Вот это, как это ни странно, не подпадает под определение:



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

Вот Трипэдвайзер достал меня своей просьбой зарегистрироваться. Если нажать «Пропустить» сверху (эту кнопку ещё надо найти) — будет вот такое окно:



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

Ну и напоследок, задача, которая поставила меня в тупик:



Это Букинг предлагает подписаться на рассылку. Непонятно только, что это именно рассылка по письму в день.

Вот примерно так. И ещё очень рекомендую прочитать пост «Интерфейсы, предназначенные для обмана» в переводе JIghtuse. Только не забудьте, что переходя по этой ссылке, вы даёте согласие на установку браузера Амиго. Ну и мой пост про эксплуатацию этого всего в 2014-м в продуктовой рознице и не только. С тех пор, кстати, многое поменялось — появились пакеты молока по 850 и 800 мл.

Сразу уточню, что все суждения выше — мои личные ощущения, и, конечно, с ними можно спорить.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330826/


Метки:  

Разбираемся в джунглях программирования, или почему Маугли дружил с Python?

Вторник, 13 Июня 2017 г. 16:37 + в цитатник
В произведении Редьярда Киплинга “Книга джунглей” питон Каа олицетворял собой не только силу, но и мудрость. Маугли быстро смекнул, что такого персонажа лучше взять в союзники — так и в тропических джунглях не пропадёшь, и благодаря его советам хоть чуть-чуть станешь похожим на человека.


Современный информационный мир — такие же джунгли. Базы данных, высотой до небес, свисающие с них компьютерные сети, аляпистые динамические веб-сайты, дикие конкуренты, которые готовы вас съесть живьём. И да, Python один из немногих языков программирования, дружба с которым сделает вас царём IT-джунглей. Изучить его на уровне Junior не так сложно, но как быть, если хочется большего? Если хочется легко ориентироваться в различных библиотеках, уметь решать сложные задачи при помощи Python, в конце концов, написать серьезный проект на Python, который потом не стыдно будет показать работодателю на собеседовании? Для тех, кто хочет новых высот, мы нашли персонального Каа — преподаватель курса серьезного изучения Python будет 5 месяцев делиться мудростью и знаниями со студентами новой группы, проверять домашнии задания, давать фитбеки, направлять и поддерживать, рассказывать о тонкостях языка, чтобы после окончания курса студент мог легко ориентироваться в дебрях программирования на уровне middle/senior специалиста, имел подтверждающие навыки проект и, в случае успешного обучения, имел реальные возможности трудоустройства в крупнейшие IT компании (они гарантируют лучшим студентам курса собеседования).

Почему для нового курса мы все-таки выбрали Python? Этому есть ряд причин.

Питон очень сильный
Средняя продолжительность жизни королевского питона 20-30 лет. Язык Python прожил уже 26 и чувствует себя великолепно. Всё это время он не лежал бездушно где-то на солнце, он рос, развивался, проникал во всевозможные сферы мира IT и не только. За это время он обзавёлся очень крутым фреймворком — Django, который входит в шестёрку самых популярных по версии Hotframeworks.com.
Python сегодня на полном серьёзе конкурирует с MATLAB, Scilab и GNU Octave в области математических вычислений и больших данных благодаря мощным библиотекам и модулям. Data Science — вообще самое актуальное направление сегодня для этого языка.
В играх, особенно онлайн-играх, Python также крайне хорош для связки больших потоков информации, графики и железа. Такие Game-проекты, как Battlefield, EVE Online, Mount & Blade, Sims 4, Civilization IV использует Python для различных нужд, от серверных элементов управления до внутренней логики игры.
Python позволяет создавать функциональный и динамический код, писать веб и десктопные приложения, БД, с параллельными вычислениями, сетями, серверами. Серьёзно — для Python нет невыполнимых задач, есть только те, где он не слишком подходит. Говорят, питоны не очень быстрые.

У питона куча друзей
Среди программистов у Python огромное количество поклонников, а если верить данным некоторых рейтингов, то это вообще самый “дружный” язык программирования в мире.


В больших и богатых компаниях питона тоже любят. В своих продуктах его используют Google, Facebook, Dropbox, Yahoo, NASA, IBM, Mozilla и многие другие. Куда проще перечислить крупные IT-компании, где по какой-то причине Python обходят стороной.
Вообще очень трудно представить современную жизнь без питона. Смотрите ли вы видео на YouTube, или играете в World of Tanks, или коллективно пишите код с использованием Mercurial, что-то параллельно подкачивая в BitTorrent — везде Python.

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


К слову, примерно такой же спрос на специалистов со знанием Javascript и лишь на 0,4 процента больше у Java. Статистику по востребованности в пределах России мы уже обозначали в одном из наших предыдущих текстов. Коротко: он не огромный, но заметный. По данным trud.com, в России программистов со знанием Python требуется больше, чем разработчиков для iOS и Android вместе взятых.

Дружба с питоном выгодна всем
Мало того, что на рынке труда существует устойчивый спрос на знатоков Python, так и ещё средний уровень зарплат уверенно входит в пятерку по всей IT-области по версии всё того же портала trud.com. Взгляните на выборку по всей России:


Требования по возрасту при этом предельно либеральные — основная масса вакансий охватывает людей от 22 до 45 лет и опытом работы менее 3 лет. Правда уровень минимальных знаний, которые требуются даже на должность джуниора, — приличный, поверхностным знанием языка и фреймворка Django отделаться не получится.

P.S. В “Книге джунглей” мудрый Каа давал юному Маугли советы о жизни, проецируя их на законы джунглей. В мире реальном вам ни к чему слушать змей. Гораздо лучше схватить Python за хвост и, размахивая им, нестись по джунглям программирования навстречу новым карьерным вершинам. И Python вас за это даже не укусит.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330824/


Метки:  

Поддержка исследователей в области Deep Learning

Вторник, 13 Июня 2017 г. 16:35 + в цитатник
Хабр, нам тут пришла одна идея… В настоящий момент у нас возникло некое межсезонье между разными образовательными программами. Мы подумали, зачем нашей инфраструктуре зря простаивать, когда есть люди, которые могли бы на этой инфраструктуре что-то классное сделать.

Мы решили сделать небольшой вклад в развитие deep learning в России и выделить 3 виртуальных сервера с GPU тем, кто что-то делает в этой области. 2 виртуалки мы решили отдать нашим выпускникам, а 1 виртуалку дать в пользование кому-то «со стороны».

image


Условия следующие:

— мы даем вам на 2 недели доступ к виртуальному серверу с одним GPU Tesla M60 и всем необходимым окружением (Torch, TF, Keras, etc);
— по итогам 2 недель работы мы делаем вместе с вами пост в нашем блоге на Хабре, где вы делитесь своими результатами с сообществом;
— ваш проект должен быть обязательно связан с deep learning.

Свои заявки с описанием проекта присылайте на мою почту apichugin@newprolab.com до четверга, 15 июня, 23:59. В пятницу мы примем решение, чьи проекты больше заслуживают нашей скромной поддержки.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330820/


Метки:  

Советы начинающему скалисту (Часть 2)

Вторник, 13 Июня 2017 г. 15:56 + в цитатник

Часть 2. Обо всем и ни о чем


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


Структура цикла



Длина выражений


В Scala практически все является выражением, и даже если что-то возвращает Unit, вы всегда можете получить на выходе ваш (). После длительного программирования на языках, где превалируют операторы (statements), у многих из нас (и я не являюсь исключением) возникает желание запихнуть все вычисления в одно выражение, составив из них длинный-предлинный паровозик. Следующий пример я нагло утащил из Effective Scala. Допустим, у нас есть последовательность кортежей:


val votes = Seq(("scala", 1),
                ("java", 4),
                ("scala", 10),
                ("scala", 1),
                ("python", 10))

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


val orderedVotes = votes
  .groupBy(_._1)
  .map { case (which, counts) =>
    (which, counts.foldLeft(0)(_ + _._2))
  }.toSeq
  .sortBy(_._2)
  .reverse

Этот код прост, понятен, выразителен? Возможно — для съевшего собаку скалиста. Однако, если мы разобьём выражение на именованные составляющие, легче станет всем:


val votesByLang =
  votes groupBy { case (lang, _) => lang }

val sumByLang =
  votesByLang map { case (lang, counts) =>

val countsOnly = counts map { case (_, count) => count }
  (lang, countsOnly.sum)
}

val orderedVotes = sumByLang.toSeq
  .sortBy { case (_, count) => count }
  .reverse

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

Очень часто в Scala приходят через Spark, а уж используя Spark так и хочется сцепить побольше «вагончиков»-преобразований в длинный и выразительный «поезд». Читать такие выражения сложно, их нить повествования теряется достаточно быстро.


Сверхдлинные выражения и operator notation
Надеюсь, всем известно, что 2 + 2 в Scala является синтаксическим сахаром для выражения 2.+(2). Этот вид записи именуется операторной нотацией (operator notation). Благодаря ей в языке нет операторов как таковых, а есть лишь методы, пусть и с небуквенными именами, а сама она — мощный инструмент, позволяющий создавать выразительные DSL (собственно, для этого символьная нотация и была добавлена в язык). Вы можете сколь угодно долго записывать вызовы методов без точек и скобочек: object fun arg fun1 arg1. Это безумно круто, если вы хотите сделать читаемый DSL:


myList should have length 10

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


«Поезда» и postfix notation
Постфиксные операторы, при определенных условиях, способны вскружить голову несчастному парсеру, поэтому в последних версиях Scala эти выражения нужно импортировать явно:


import language.postfixOps

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


Неинициализируемые значения


Scala поддерживает неинициализированные значения. Например, это может вам пригодиться при создании beans. Давайте посмотрим на следующий Java-класс:


class MyClass {
    // По-умолчанию, любой наследник Object инциализируется в null.
    // Примитивные типы инициализируются значениями по-умолчанию.
    String uninitialized;
}

Такого же поведения мы можем добиться и от Scala:


class {
  // Синтаксис с нижним подчеркиванием говорит Scala, что
  // данное поле не будет инциализировано.
  var uninitialized: String = _
}

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


Никогда не используйте null


  • Всегда инициализируйте значения.
  • Оборачивайте Nullable, которые могут прийти извне в Option.
  • Не возвращайте null: используйте Option, Either, Try и др.
  • Видите предпосылки для появления null — быстрее исправляйте, пока ваши коллеги на радостях не завезли в проект специально предназначенный для борьбы с NPE язык.

Иногда встречаются ситуации, когда null-значения являются частью модели. Возможно, эта ситуация возникла ещё задолго до вашего прихода в команду, а уж тем более задолго до внедрения Scala. Как говорится: если пьянку нельзя предотвратить, ее следует возглавить. И в этом вам поможет паттерн, именуемый Null Object. Зачастую это всего-лишь еще один case-класс в ADT:


sealed trait User
case class Admin extends User
case class SuperUser extends User
case class NullUser extends User

Что мы получаем? Null, пользователя и типобезопасность.


О перегрузках


Методы
В Scala существует возможность перегрузки конструкторов классов. И это — не лучший способ решить проблему. Скажу больше, это — не идиоматичный способ решения проблемы. Если говорить о практике, эта функция полезна, если вы используете Java-reflection и ваш Scala-код вызывается из Java или вам необходимо такое поведение (а почему бы в таком случае не сделать Builder)? В остальных случаях лучшая стратегия — создание объекта-компаньона и определение в нем нескольких методов apply.


Наиболее примечательны случаи перегрузки конструкторов из-за незнания о параметрах по-умолчанию (default parameters).


Совсем недавно, я стал свидетелем следующего безобразия:


// Все включено!
case class Monster (pos: Position, health: Int, weapon: Weapon) {
  def this(pos: Position) = this(pos, 100, new Claws)
  def this(pos: Position, weapon: Weapon) = this(pos, 100, weapon)
}

Ларчик открывается проще:


case class Monster(
  pos: Position,
  health: Short = 100,
  weapon: Weapon = new Claws
)

Хотите наградить вашего монстра базукой? Да, не проблема:


val aMonster = Monster(Position(300, 300, 20), weapon = new Bazooka)

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


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


Перегрузка операторов
Считается достаточно противоречивой фичей Scala. Когда я только-только погрузился в язык, перегрузка операторов использовалась повсюду, всеми и везде, где только можно. Сейчас эта фича стала менее популярна. Изначально перегрузка операторов была сделана, в первую очередь, для того, чтобы иметь возможность составлять DSL, как в Parboiled, или роутинг для akka-http.


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


А если перегружаете (вам нужен DSL или ваша библиотека делает нечто математическое (или трудновыразимое словами)), обязательно дублируйте оператор функцией с нормальным именем. И думайте о последствиях. Так, Благодаря scalaz оператор |@| (Applicative Builder) получил имя Maculay Culkin. А вот и фотография "виновника":


Шокированный Maculay Culkin


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


О геттерах и сеттерах


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


Слышали ли вы о Project Lombok? В стандартной библиотеке Scala имеется схожий механизм. Он именуется BeanProperty. Все, что вам нужно, — создать bean и добавить аннотацию BeanProperty к каждому полю, для которого хотите создать getter или setter.


Для того чтобы получить имя вида isProperty для переменных булева типа, следует добавить scala.beans.BooleanBeanProperty в вашу область видимости.

Аннотацию @BeanProperty можно так же использовать и для полей класса:


import scala.beans.{BooleanBeanProperty, BeanProperty}

class MotherInLaw {
  // По закону, она может сменить имя:
  @BeanProperty var name = "Megaera"

  // А эти ребята имеют свойство плодиться.
  @BeanProperty var numberOfCatsSheHas = 0

  // Но некоторые вещи неизменны.
  @BooleanBeanProperty val jealous = true
}

Для case class-ов тоже работает:


import scala.beans.BeanProperty

case class Dino(@BeanProperty name: String,
                @BeanProperty var age: Int)

Поиграем с нашим динозавром:


// Начнем с того, что он не так стар как вы думаете
val barney = Dino("Barney", 29)

barney.setAge(30)

barney.getAge
// res4: Int = 30

barney.getName
// res14: String = Barney

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


barney.setName
:15: error: value setName is not a member of Dino
     barney.setName

Кстати о case-классах


Появление case-классов — это прорыв для JVM-платформы. В чем же их основное преимущество? Правильно, в их неизменяемости (immutability), а также наличию готовых equals, toString и hashCode. Однако, зачастую и в них можно встретить подобное:


// Внимание на var.
case class Person(var name: String, var age: Int)

Иногда case-классы приходится-таки делать изменяемыми: например, если вы, имитируете beans, как в примере выше.

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


case class Person (name: String, age: Int) {
  def updatedAge(newAge: Int) = Person(name, newAge)
  def updatedName(newName: String) = Person(newName, age)
}

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


// Обновили возраст, получили новый инстанс.
person.copy(age = 32)

О размерах case-классов


Иногда case-классы имеют свойство раздуваться до 15–20 полей. До появления Scala 2.11 этот процесс хоть как-то ограничивался 22 элементами. Но сейчас ваши руки развязаны:


case class AlphabetStat (
  a: Int, b: Int,
  c: Int, d: Int,
  e: Int, f: Int,
  g: Int, h: Int,
  i: Int, j: Int,
  k: Int, l: Int,
  m: Int, n: Int,
  o: Int, p: Int,
  q: Int, r: Int,
  s: Int, t: Int,
  u: Int, v: Int,
  w: Int, x: Int,
  y: Int, z: Int
)

Хорошо, я вам наврал: руки, конечно, стали свободнее, однако ограничения JVM никто не отменял.

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


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


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


Почему линзы называются линзами? Потому что они способны сфокусироваться на главном. Вы фокусируете линзу на определенную часть структуры, и получаете ее, вместе с возможностью ее (структуру) обновить. Для начала объявим наши case-классы:


case class Address(street: String,
                   city: String,
                   postcode: String)

case class Person(name: String, age: Int, address: Address)

А теперь заполним их данными:


val person = Person("Joe Grey", 37,
                    Address("Southover Street",
                            "Brighton", "BN2 9UA"))

Создаем линзу для улицы (предположим что наш персонаж захотел переехать):


import shapeless._

val streetLens = lens[Person].address.street

Читаем поле (прошу заметить что строковый тип будет выведен автоматически):


val street = streetLens.get(person)
// "Southover Street"

Обновляем значение поля:


val person1 = streetLens.set(person)("Montpelier Road")
// person1.address.street == "Montpelier Road"

Пример был нагло украден «из отсюда»

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


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


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


Переизобретение enum'ов


Берем опытного Java-разработчика и заставляем его писать на Scala. Не проходит и пары дней, как он отчаянно начинает искать enum'ы. Не находит их и расстраивается: в Scala нет ключевого слова enum или, хотя бы, enumeration. Далее есть два варианта событий: или он нагуглит идиоматичное решение, или начнет изобретать свои перечисления. Часто лень побеждает, и в результате мы видем вот это:


object Weekdays {
  val MONDAY = 0
  // догадайтесь что будет дальше...
}

А дальше то что? А вот что:


if (weekday == Weekdays.Friday) {
   stop(wearing, Tie)
}

Что не так? В Scala есть идиоматичный способ создания перечислений, именуется он ADT (Algebraic Data Types), по-русски алгебраические типы данных. Используется, например в Haskell. Вот как он выглядит:


sealed trait TrafficLight
case object Green extends TrafficLight
case object Yellow extends TrafficLight
case object Red extends TrafficLight
case object Broken extends TrafficLight

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


def tellWhatTheLightIs(tl: TrafficLight): Unit = tl match {
  case Red => println("No cars go!")
  case Green => println("Don't stop me now!")
  case Yellow => println("Ooohhh you better stop!")
}

И получим:


warning: match may not be exhaustive.
It would fail on the following input: Broken
       def tellWhatTheLightIs(tl: TrafficLight): Unit = tl match {
                                                        ^
tellWhatTheLightIs: (tl: TrafficLight)Unit

Мы получаем перечисление, свободное от привязки к каким либо константам, а также проверку на полноту сопоставления с образцом. И да, если вы используете «enum для бедных», как их обозвал один мой небезызвестный коллега, используйте сопоставление с образцом. Это наиболее идиоматичный способ. Стоит заметить, об этом упоминается в начале книги Programming in Scala. Не каждая птица долетит до середины Днепра, так же как и не каждый скалист прочтет Magnum Opus.


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


Избегайте булевых аргументов в сигнатурах функций


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


PrettyPrinter.print(text, 1, true)

Что может означать 1? Доверимся интуиции и предположим что это количество копий. А за что отвечает true? Это может быть что угодно. Ладно, сдаюсь, схожу в исходники и посмотрю, что это.


В Scala вы можете использовать ADT:


def print(text: String, copies: Int, wrapWords: WordWrap)

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


// К интам тоже применимо,
// а вдруг это не количество копий, а отступы?
PrettyPrinter.print(text, copies = 1, WordWrap.Enabled)

Об итерации


Рекурсия лучше


Хвостовая рекурсия работает быстрее, чем большинство циклов. Если она, конечно, хвостовая. Для уверенности используйте аннотацию @tailrec. Ситуации бывают разными, не всегда рекурсивное решение оказывается простым доступным и понятным, тогда используйте while. В этом нет ничего зазорного. Более того, вся библиотека коллекций написана на простых циклах с предусловиями.


For comprehensions не для итерации (по индексам)


Главное, что вам следует знать про генераторы списков, или, как их еще Называют, «for comprehensions», — это то, что основное их предназначение — не в реализации циклов.


Более того, использование этой конструкции для итерации по индексам будет достаточно дорогостоящей процедурой. Цикл while или использование хвостовой рекурсии — намного дешевле. И нагляднее.


«For comprehension» представляет собой синтаксический сахар для методов map, flatMap и withFilter. Ключевое слово yield используется для последующей агрегации значений в результирующей структуре. Используя «for comprehension» вы, на самом деле, используете те же комбинаторы, просто в завуалированой форме. Используйте их напрямую:


// хорошо
1 to 10 foreach println

// плохо
for (i <- 1 to 10) println(i)

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


Об именах переменных
Занимательная история имен переменных в формате вопрос-ответ:


Вопрос: Откуда вообще взялись i, j, k в качестве параметров циклов?
Ответ: Из математики. А в программирование они попали благодаря фортрану, в котором тип переменной определяется ее именем: если первая буква имени начинается с I, J, K, L, M, или N, это автоматически означает, что переменная принадлежит к целочисленному типу. В противном случае, переменная будет считаться вещественной (можно использовать директиву IMPLICIT для того, чтобы изменить тип, устанавливаемый по умолчанию).


И этот кошмар живет с нами вот уже почти 60 лет. Если вы не перемножаете матрицы, то использованию i, j и k даже в Java нет оправдания. Используйте index, row, column — все что угодно. А вот если вы пишете на Scala, старайтесь вообще избегать итерации с переменными внутри for. От лукваого это.


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


О выражениях


Не используйте return


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


Не используйте метки


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


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

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


Этот пример взят отсюда:


breakable {
  for (i <- 1 to 10) {
    println(i)
    if (i > 4) break  // выскочить из цикла.
   }
 }

Об исключительных ситуациях


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


В Scala нет checked exceptions. Так что если где-то у нас исключения и могут возникнуть — обязательно их обрабатывайте. И самое главное, не бросайтесь исключениями. Да, есть ситуации когда зеленые монстры вынуждают вас это делать. И более того, у зеленых монстров и их почитателей это вообще является нормой. Во всех остальных случаях — не бросайтесь исключениями. То, что в свое время Джоэл Спольски писал применительно к C++ и Java, к Scala применимо даже в большей степени. И в первую очередь именно из-за ее функциональной природы. Метки и goto недопустимы в функциональном программировании. Исключения ведут себя схожим образом. Бросив исключение, вы прерываете flow. Но, как уже было сказано выше, ситуации бывают разными, и если ваш фреймворк этого требует — Scala дает такую возможность.


Вместо того, чтобы возбуждать исключения, вы можете использовать Validation из scalaz, scala.util.Try, Either. Можно использовать и Option, если вам не жалко людей, которые будут поддерживать ваш код. И это будет все-равно лучше, чем бросаться исключениями.


Структурные типы


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


? extends App


Знаете что не так с этим кодом:


object Main extends App {
  Console.println("Hello World: " + (args mkString ", "))
}

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


It should be noted that this trait is implemented using the DelayedInit functionality, which means that fields of the object will not have been initialized before the main method has been executed.

По-русски:


Следует учесть, что данный трейт реализован с использованием функциональности DelayedInit, что означает то, что поля объекта не будут проинициализированны до выполнения метода main.

В будущем это обещают исправить:


Future versions of this trait will no longer extend DelayedInit.

Плохо ли использовать App? В сложных многопоточных приложениях я бы не стал этого делать. А если вы пишете «Hello world»? Почему бы нет. Я стараюсь лишний раз не связываться и использую традиционный метод main.


Коллекции


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


tvs.filter(tv => tv.displaySize == 50.inches).headOption

Тоже самое, только короче:


tvs.find(tv => tv.displaySize == 50.inches)

Подобные «антипаттерны» не редкость:


list.size = 0  // плохо
list.isEmpty   // ok

!list.empty    // плохо
list.nonEmpty  // ok

tvs.filter(tv => !tv.supportsSkype)    // плохо
tvs.filterNot(tv => tv.supportsSkype)  // ok

Конечно, если вы используете IntelliJ IDEA, она вам обязательно подскажет наиболее эффективную комбинацию методов. Scala IDE, насколько мне известно, так не умеет.

О неэффективном использовании библиотеки коллекций Scala можно рассказывать сколь угодно долго. И это уже очень не плохо сделал Павел Фатин в своей статье Scala collections Tips and Tricks, с которой я вам очень рекомендую ознакомиться. И да, старайтесь не вызывать элементы коллекций по индексам. Нехорошо это.


Список литературы


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


Книги


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


Официальная документация


Руководство по стилю Scala


Статьи



Видео



Благодарности


Автор хотел бы выразить свою признательность


  • Владу Ледовских — за вычитку,
  • Павлу Кретову (@firegurafiku) — за безуспешные попытки привести этот текст к литературной норме, а также за помощь с разделом о typedef в первой части статьи,
  • Арсению Жижелеву (@primetalk) — за внесение многочисленных уточнений в изначальный текст,
  • Семёну Попугаеву (@senia) — за найденные неточности.

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

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

https://habrahabr.ru/post/330816/


Метки:  

[Перевод] Декораторы в JavaScript

Вторник, 13 Июня 2017 г. 15:44 + в цитатник

Метки:  

LXC aka Linux Container: простота и надёжность

Вторник, 13 Июня 2017 г. 15:21 + в цитатник

Что такое LXC? image




Аббревиатура расшифровывается просто Linux Container. Это контейнерная система виртуализации, которая действует в пределах операционной системы Linux. Что это значит? С LXC можно запустить несколько полностью изолированных и независимых друг от друга экземпляров ОС Linux на одном компьютере. Помимо этого есть возможность создать надежный кластер из нескольких десятков серверов, когда один и тот же экземляпр контейнера выполняется сразу на нескольких физических машинах и в случае выхода из строя одного сервера работа контейнера не приостанавливается ни на минуту. Так же данные контейнера находятся сразу на нескольких хранилищах, реализуется это различными методами (ceph ). Что позволяет помимо живой миграции контейнера между нодами кластера так же еще больше повысить надежность хранения данных, гибко увеличивать дисковую подсистему контейнера в пределах … ну пределы практически неограничены –настолько насколько хватит хранилища, а хранилища могут быть очень большие, например, в нашем случае мы сейчас строим хранилище в несколько петабайт информации.


Немного о механизмах виртуализации




В чем разница между виртуальными машинами и контейнерами? традиционные типы виртуализации, например, KVM тратят ресурсы сервера на обcлуживание самой виртуальной среды, в случае же контейнера до 95% мощности отдается непосредственно в контейнер и он работает по сути на уровне хостовой машины. Замеры производительности контейнеров мы приведем ниже в этой статье.


Сравнение LXC и KVM




LXC KVM
Изменение размера диска – в случае контейнера LXC увеличение или уменьшение диска происходит очень быстро практически на «лету» Так как KVM это полноценно изолированный контейнер измение размера диска требует перезагрузки виртуальной машины, все как на физическом сервере
Расщирение RAM, ядер CPU, диска etc. Не требует перезагрузки, если требуется непрерывная работа виртуальной машины то выбор очевиден При любых изменениях в параметрах VPS требуется перезагрузка
Быстрая перезагрузка контейнера Как писали выше – KVM требует столько же времени на рестарт как и обычный сервер
Быстрая установка любого образа как операционной системы так и готовых шаблонов (OpenVPN, TorrenServer,OpenLDAP,MediaServer, OwnCloud у нас больше 100 различных шаблонов на все случаи жизни) Возможность установки различных версий Windows и FreeBSD как из шаблонов так и из собственного ISO
Создание собственной внутренней сети между контейнерами Создание собственной внутренней сети между контейнерами

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


Создание контейнера на примере нашего хостинга





Итак приступим к заказу (ссылка на корзину) – выбираем имя хоста, пароль для root, параметры CPU, RAM и диска, далее переходим к выбору шаблона для контейнера и жмем «Далее», для тестов мы сделали промо-код HelloHabr, который позволит месяц тестировать совершенно бесплатно. Далее регистрируемся в билинге и если что-то пошло не так создаем запрос в сапорт. Заходим в клиентский кабинет выбираем свежесозданный контейнер и приступаем к тестам. Какие же возможности по доступу нам предлагают в личном кабинете – самое простое это noVNC консоль которая позволяет управлять контейнером непосредственно из браузера , далее SPICE консоль — представляет собой систему отображения (рендеринга) удаленного дисплея, построенную для виртуальной среды, которая позволяет вам просматривать виртуальный «рабочий стол» вычислительной среды не только на машине, на которой он запущен, но и откуда угодно через Интернет(из wiki), так же в разделе Backup мы можем сделать как мгновенный снимок контейнера, так и полное резервное копирование виртуально машины, есть возможность выбрать как тип архива, так и вид копии. Так же мы можем настроить задания для Backup которые будут выполнятся по определенному расписанию с оповещением на емейл.
Так же хотел бы отметить еще одну удобную опцию – настройка firewall непосрдественно из бразуера, что очень удобно для тех кто не владеет тонкими настройками firewall в Linux. Все очень удобно как для опытных администраторов, так и совсем начинающих.


Тестирование производительности




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


apt-get install build-essential libx11-dev libgl1-mesa-dev libxext-dev

далее скачиваем сам unixbench и приступаем к тестированию —


cd /tmp/
wget https://github.com/kdlucas/byte-unixbench/archive/master.zip
 unzip master.zip

и запускаем


./Run

Ждем пока unixbench потестирует контейнер и любуемся результатом


BYTE UNIX Benchmarks (Version 5.1.3)

   System: test: GNU/Linux
   OS: GNU/Linux -- 4.4.59-1-pve -- #1 SMP PVE 4.4.59-87 (Tue, 25 Apr 2017 09:01:58 +0200)
   Machine: x86_64 (unknown)
   Language: en_US.utf8 (charmap="ANSI_X3.4-1968", collate="ANSI_X3.4-1968")
   CPU 0: Intel(R) Xeon(R) CPU E5649 @ 2.53GHz (5076.7 bogomips)
          Hyper-Threading, x86-64, MMX, Physical Address Ext, SYSENTER/SYSEXIT, SYSCALL/SYSRET, Intel virtualization
   09:14:27 up 33 min,  2 users,  load average: 0.23, 0.06, 0.06; runlevel Jun

------------------------------------------------------------------------
Benchmark Run: Tue Jun 13 2017 09:14:28 - 09:42:27
24 CPUs in system; running 1 parallel copy of tests

Dhrystone 2 using register variables       29175436.4 lps   (10.0 s, 7 samples)
Double-Precision Whetstone                     3707.9 MWIPS (8.9 s, 7 samples)
Execl Throughput                               4656.0 lps   (30.0 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        874980.2 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          243115.0 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       1778945.2 KBps  (30.0 s, 2 samples)
Pipe Throughput                             1587733.6 lps   (10.0 s, 7 samples)
Pipe-based Context Switching                 273143.4 lps   (10.0 s, 7 samples)
Process Creation                              11873.0 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   5665.4 lpm   (60.0 s, 2 samples)
Shell Scripts (8 concurrent)                   1061.0 lpm   (60.0 s, 2 samples)
System Call Overhead                        1897076.6 lps   (10.0 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   29175436.4   2500.0
Double-Precision Whetstone                       55.0       3707.9    674.2
Execl Throughput                                 43.0       4656.0   1082.8
File Copy 1024 bufsize 2000 maxblocks          3960.0     874980.2   2209.5
File Copy 256 bufsize 500 maxblocks            1655.0     243115.0   1469.0
File Copy 4096 bufsize 8000 maxblocks          5800.0    1778945.2   3067.1
Pipe Throughput                               12440.0    1587733.6   1276.3
Pipe-based Context Switching                   4000.0     273143.4    682.9
Process Creation                                126.0      11873.0    942.3
Shell Scripts (1 concurrent)                     42.4       5665.4   1336.2
Shell Scripts (8 concurrent)                      6.0       1061.0   1768.3
System Call Overhead                          15000.0    1897076.6   1264.7
                                                                   ========
System Benchmarks Index Score                                        1372.3

------------------------------------------------------------------------
Benchmark Run: Tue Jun 13 2017 09:42:27 - 10:10:50
24 CPUs in system; running 24 parallel copies of tests

Dhrystone 2 using register variables       28791897.2 lps   (10.1 s, 7 samples)
Double-Precision Whetstone                     3650.7 MWIPS (9.0 s, 7 samples)
Execl Throughput                               4573.6 lps   (29.9 s, 2 samples)
File Copy 1024 bufsize 2000 maxblocks        899496.3 KBps  (30.0 s, 2 samples)
File Copy 256 bufsize 500 maxblocks          243438.3 KBps  (30.0 s, 2 samples)
File Copy 4096 bufsize 8000 maxblocks       1960457.7 KBps  (30.0 s, 2 samples)
Pipe Throughput                             1588441.9 lps   (10.1 s, 7 samples)
Pipe-based Context Switching                 221247.7 lps   (10.0 s, 7 samples)
Process Creation                              10910.9 lps   (30.0 s, 2 samples)
Shell Scripts (1 concurrent)                   8683.0 lpm   (60.1 s, 2 samples)
Shell Scripts (8 concurrent)                   1088.9 lpm   (60.8 s, 2 samples)
System Call Overhead                        1899698.1 lps   (10.1 s, 7 samples)

System Benchmarks Index Values               BASELINE       RESULT    INDEX
Dhrystone 2 using register variables         116700.0   28791897.2   2467.2
Double-Precision Whetstone                       55.0       3650.7    663.8
Execl Throughput                                 43.0       4573.6   1063.6
File Copy 1024 bufsize 2000 maxblocks          3960.0     899496.3   2271.5
File Copy 256 bufsize 500 maxblocks            1655.0     243438.3   1470.9
File Copy 4096 bufsize 8000 maxblocks          5800.0    1960457.7   3380.1
Pipe Throughput                               12440.0    1588441.9   1276.9
Pipe-based Context Switching                   4000.0     221247.7    553.1
Process Creation                                126.0      10910.9    865.9
Shell Scripts (1 concurrent)                     42.4       8683.0   2047.9
Shell Scripts (8 concurrent)                      6.0       1088.9   1814.9
System Call Overhead                          15000.0    1899698.1   1266.5
                                                                   ========
System Benchmarks Index Score                                        1399.9

Немного рекламы


Так же хотел бы напомнить про наши выделенные сервера с защитой от ДДОС атак
Сейчас вы можете заказать 2x Intel Xeon E5540 с 32Gb ECC DDR3 RAM с полной защитой и SSD диском на 240Gb всего за 3127 руб
Так же всегда в наличии Intel Core i7-7700 от 3769 руб
За дополнительными скидками велкам в личку


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

https://habrahabr.ru/post/330794/


Метки:  

ГИС и распределенные вычисления

Вторник, 13 Июня 2017 г. 15:17 + в цитатник
Всем привет!

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

Сегодня нас окружает огромное количество неструктурированных данных, которые до недавнего времени было немыслимо обработать. Примером таких данных могут служить, например, данные метеодатчиков, используемые для точного прогноза погоды. Более структурированные, но не менее массивные датасеты – это, например, спутниковые снимки (алгоритмам обработки снимков c помощью машинного обучения даже посвящен ряд статей у сообщества OpenDataScience). Набор снимков высокого разрешения, допустим, на всю Россию занимает несколько петабайт данных. Или история правок OpenStreetMap — это терабайт xml. Или данные лазерного сканирования. Наконец, данные с огромного количество датчиков, которыми обвешано множество техники – от дронов до тракторов (да, я про IoT). Более того, в цифровую эпоху мы сами создаем данные, многие из которых содержат в себе информацию о местоположении. Мобильная связь, приложения на смартфонах, кредитные карты – все это создает наш цифровой портрет в пространстве. Множества этих портретов создают поистине монструозные наборы неструктурированных данных.


На рисунке — визуализация треков OpenStreetMap с помощью GeoWave

Где стык ГИС и распределенных вычислений? Что такое «большие геоданные»? Какие инструменты помогут нам?

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

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

Пространственное партицирование


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


Одним из наиболее интересных методов является многообразие «заполняющих пространство кривых», Z-Curve и Gilbert Curve на рисунке выше. Первооткрывателем этих кривых был Джузеппе Пеано. Основная идея заключается в том, чтобы превратить многомерное пространство в одномерное с помощью кривой, которая фрактально заполняет собой все пространство. Вот, например, так кривая Гильберта заполняет собой плоскость:


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


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

GeoJinni (в прошлом SpatialHadoop)



spatialhadoop.cs.umn.edu

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

На самом нижнем уровне добавляется новый тип данных, позволяющий хранить и обрабатывать геоданные как ключ-значение. Также добавляются инструменты для загрузки и выгрузки различных форматов геоданных. В противовес классической структуре (точнее, ее отсутствию) хранилища Hadoop, GeoJinni создает два слоя индексного пространства, локальный и глобальный. Глобальный индекс позволяет партицировать данные по нодам кластера, локальный же отвечает за партиции на каждый ноде. Эта концепция позволяет использовать три типа индексов – Grid, R-tree и R+-tree. Все индексы строятся по запросу пользователя и размещаются непосредственно в HDFS.

GeoJinni устанавливается как расширение к уже существующему кластеру Hadoop, что не требует сборки кластера заново. Расширение может быть без проблем установлено в различных дистрибутивах Hadoop, например, Apache Hadoop, Cloudera или Hortonworks.

GeoMesa



www.geomesa.org

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

Основой для хранения массивных наборов данных являются распределенные колоночные типы хранение, такие как Accumulo, HBase, Google Bigtable. Это позволяет быстро обращаться к этим данным через запросы с использованием расстояний и площадей. Также GeoMesa позволяет обрабатывать данные практически в реальном времени через специальный слой для системы потоковых сообщений Apache Kafka.

Наконец, с помощью подключения к ГИС-серверу GeoServer GeoMesa предоставляет доступ к своим потоковым сервисам через OGC протоколы WFS и WMS, что дает большой простор для пространственно-временных анализа и визуализации, от карт до графиков.

GeoWave



locationtech.github.io/geowave

GeoWave в своей концепции задумывался как аналог PostGIS, пространственному расширению PostgreSQL, но для распределенного колоночного хранилища Accumulo. Этим хранилищем он долгое время и ограничивался, при этом оставаясь проектом с закрытым кодом. Лишь недавно код был передан в фонд Apache. И уже подключаются хранилище HBase и картографический движок Mapnik.

Предоставляет для Accumulo мультипространственные индексы, стандартные географические типы и операции, а также возможность обработки облаков точек PDAL. Обработка данных происходит через расширения для MapReduce, а визуализация через плагин к GeoServer.
Очень похож в своей концепции с GeoMesa, использует те же хранилища, но сосредоточен не на пространственно-временных выборках, а на визуализации многомерных массивов данных.

GeoTrellis



geotrellis.io

GeoTrellis отличается от своих собратьев. Он задумывался не как инструмент для работы с большими массивами геоданных, а как возможность утилизации распределенных вычислений для максимальной скорость обработки даже стандартных объемов геоданных. В первую очередь, речь идет об обработки растров, но за счет эффективной системы партицирований стало возможно выполнять и пространственные операции, и конвертацию данных. Основными инструментами разработки являются Scala и Akka, инструментом распределенной аналитики – Apache Spark.

Глобальная цель проекта – предоставление отзывчивого и богатого инструментария на уровне веб-приложения, что должно изменить пользовательский опыт в использовании систем распределенных вычислений. В конечном итоге, развитие экосистемы открытых геотехнологий, где GeoTrellis дополнит PostGIS, GeoServer и OpenLayers. Основными целями команда разработки ставит следующие:
  • Создание масштабируемых высокопроизводительных веб-геосервисов
  • Создание распределенных геосервисов для обработки «больших геоданных»
  • Максимальная параллелизация процессов обработки данных

GeoTrellis – прекрасный фреймворк для разработчиков, предназначенный для создания отзывчивых и простых REST-сервисов для обращения к моделям геопроцессинга. Оптимизация и параллелизация производится самим фреймворком.

GIS Tools for Hadoop



esri.github.io/gis-tools-for-hadoop

Наборы инструментов от Esri хотя формально и являются открытыми, но их применение имеет смысл в первую очередь с продуктами Esri. По концепции очень схожи с GeoJinni.

Инструменты разделены на три уровня
  • Esri Geometry API for Java. Библиотека для расширения Hadoop геопространственными абстракциями и операциями
  • Spatial Framework for Hadoop. Расширение для использования геопространственных запросов в Hive Query Language
  • Geoprocessing Tools for Hadoop. Непосредственно средства интеграции Hadoop и ArcGIS, позволяющие выполнять операции распределенного пространственного анализа в настольном и серверном приложениях.


Что дальше?


Геоданные всегда были где-то рядом с большими данными, и приход инструментов распределенных вычислений позволяет делать действительно интересные вещи, позволяя не только географам, но и аналитикам данных (или как их модно называть, Data Science), совершать новые открытия в области анализа данных. Мгновенные моделирование затоплений, создание линий горизонта, пространственная статистика, анализ населения, создание трехмерных моделей из облаков точек, анализ спутниковых снимков.

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

https://habrahabr.ru/post/330758/


Метки:  

FabricPool — технология экономии для All Flash хранилищ

Вторник, 13 Июня 2017 г. 15:11 + в цитатник
Эта статья будет полезна в первую публичным облачным провайдерам, а также конечным пользователям, владельцам СХД NetApp ONTAP у которых есть SSD накопители.
В этой статье я поговорю о репликации между СХД, SSD технологиях, All Flash хранилищах, куда движется рынок СХД, об объектных СХД, о технологии СХД FabricPool, видении DataFabric, снэпшотах и о новой прошивке ONTAP для СХД. СХД, СХД, СХД — это все системы, которые ставятся, у заказчика в ЦОД для построения классической инфраструктуры или частного облака, это заказчики, которые держат свой собственный ЦОД, свою систему хранения и основная часть их инфраструктуры работает на их собственном оборудовании. Какое вообще отношение эти хранилища, и все перечисленные темы, имеют к облаку и публичным провайдерам? Я расскажу об всех этих технологиях, которые, казалось бы, не имеют к публичным облачным провайдерам никакого отношения. Но по ходу рассказа станет понятно, как все они образуют тренд и помогают двигаться в сторону гибридного облака: Частное + Публичное и как NetApp поможет перенести часть данных заказчика, которые ранее всегда жили только у заказчика на его собственном оборудовании в публичное облако.

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


SSD тренд


SSD накопители дешевеют, но пока по-прежнему дорогие. У кого есть в компах или ноутах SSD? Заметно ускорение работы, не так ли? Мы уже прошли несколько стадий развития NAND: SLC, MLC, теперь уже поколение TLC накопителей, с каждым новым витком развития стоимость технологии удешевляется. Множество потенциальных новых типов носителей обещают в будущем ещё больше ёмкость, ещё больше скорость и т.д. И возможно, когда-нибудь, технологии, где ячейки памяти не изнашиваются. SSD даже для ноутбука не дешевые, а что говорить о больших промышленных решениях All Flash Array? Как сделать, чтобы SSD удешевить в таких решениях? Ответ таков: использовать технологии дедупликации и компрессии данных, чтобы удешевить стоимость терабайта. У NetApp есть целый ряд технологий сжатия данных. Так к примеру базу данных SQL вполне было реально сжать в два раза, это я видел у одного нашего заказчика, при этом производительность была лучше, чем у других конкурентов на тесте и её включение/выключение не влияло на производительность. Это было в прошивке ONTAP 8.3.2, а сейчас уже вышла ONTAP 9.2 с агрегат инлайн дедупликацией. SSD это однозначно будущее СХД, все без исключения вендоры это признали. Некоторые вендоры отказались развивать экстремально дорогие High-End хранилищ и начали разрабатывать более дешевые и производительные AFA.

DataFabric


DataFabric это не одна технология, а целый набор технологий, видение, желание NetApp по движению в сторону объединения и интеграции всех своих продуктов тем как можно большим количеством способов и большей мобильности данных. К примеру:
  • В новых версиях двух абсолютно разных систем и архитектур, таких как ONTAP и AltaVault, поддерживается репликация SnapMirror, которая ранее поддерживалась только между двумя FAS системами
  • Поддержка репликации данных расположенных на СХД с аппаратной платформой NetApp E-Series и ОС SANtricity в облако для разворацивания там резервной площадки.
  • Интеграция SolidFier и StorageGRID.
  • StorageGRID и AltaVault
  • ну и естественно возможность FAS <-> ONTAP Cloud / ONTAP Select репликации


Подробнее о DataFabric

StorageGRID объектное хранилище


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

Снэпшоты


Кто работал со снэпшотами VMware и Hyper-V на высоконагруженных виртуальных машинах? Плохо работают не так ли? Чем больше снэпшотов тем хуже работает виртуалка, тем дольше они удаляются и это удаление ещё сильнее убивает производительность этой машины. Для NetApp ONTAP, снэпшоты это сущий пустяк, никаких проблем производительности при создании или удалении. Множество интеграций с софтом резервного копирования типа Veeam или CommVault и т.д., позволяющих снимать консистентные снэпшоты. VMware vVol позволяют снимать hardware-assistant снэпшоты хранилищем гранулярно для каждой отдельной виртуальной машины, что устраняет проблемы вызванные снэпшотами гипервизоров. Такие не тормозящие снэпшоты выгодно использовать для резервного копирования и DR. Там, где есть возможность использовать hardware-assistant снэпшоты хранилища, не влияющие на производительность, везде стоит их использовать.

Новая версия ONTAP 9.2


Напомню, что ONTAP это прошивка 9.2, которая устанавливается или на аппаратную платформу FAS/AFF или доступна в виде софта (SDS) с виртуальной машиной у вас на сервере (ONTAP Select) или в публичном облаке (ONTAP Cloud). Пару месяцев назад вышла новая прошивка ONTAP, большинство текущих заказчиков уже сейчас может обновить систему до 9.2.

В своей предыдущей статье я расписал новый функционал доступный в прошивке 9.2.

Replication


Репликация для DR на FAS или ONTAP Select. Работает на базе снэпшотов между двумя нетапами. Так вот эта репликация с FabricPool позволяет экономить не только на основной площадке. Можно на резервную площадку поставить СХД с 10-20% пространства от основной, а все остальное опять таки смешать на холодный уровень.

Tiering или FabricPool


Первое что стоит сказать о FabricPool, что как и любая технология тиринга она призвана в первую очередь экономить ресурсы СХД, а это деньги заказчика. Если же бюджет не ограничен, то можно тупо купить All Flash систему и хранить на ней снэпшоты за 3 года плюс купить ещё одну такую же систему на резервный сайт, построить метрокластер и третью такую же на резервный бэкапный сайт. Но как правило денег на такую архитектуру нет, но интерес к SSD есть и деньги на объем для продуктива (или какой-то его важной части) всё же есть, а вот для бэкапов, снэпшотов и резервирований, уже нет. Здесь и приходит на помощь FabricPool.

FabricPool это технология, позволяющая объединить быстрое и медленное хранилище для создания гибридного пула (агрегата) состоящего из SSD и облака S3, на подобии как это работает в технологии кеширования FlashPool. Также как и в FlashPool, все данные сначала попадают на горячий уровень SSD уровень, а холодные данные потом смещаются на медленный и дешевый уровень, это позволяет экономить дорогостоящее место на SSD.
FabricPool это технология, реализована в рамках стратегии DataFabric, которая в свою очередь должна расширить интеграцию всех продуктов NetApp и расширить возможности мобильности данных.

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

FabricPool это технология смещения холодных данных с SSD агрегата (AFF, FAS, ONTAP Cloud систем) на холодный объектный уровень — в облако Amazon S3 или на объектную СХД NetApp StorageGRID.

Внедрение FabricPool для перемещения данных на Object Storage будет состоять из двух стадий. В 9.2RC будет доступна возможность смещать только снэпшоты. А следующей стадией будет возможность смещения холодных данных из активной файловой системы вольюма на холодный уровень, доступно с версии 9.2GA. Пока с FabricPool не поддерживаются FlexFroup, MetroCluster, ONTAP Select, SnapLock и др.

FabricPool на FAS/AFF и третестороннее объектное хранилище холодных данных

Для использования функционала FabricPool на FAS/AFF системах с третесторонним объектным хранилищем Amazon S3 необходимо приобретать по-терабайтные лицензии, которые добавляются в ONTAP, добавление лицензии FabricPool сразу добавляет 10ТБ. Потом можно добавлять по терабайту.

FabricPool на FAS/AFF и StorageGRID

Для работы функционала FabricPool на системах хранения FAS/AFF, лицензия необходима только в случае использования Amazon S3. В случае NetApp StorageGRID лицензия для работы FabricPool не нужна.

FabricPool и ONTAP Cloud

Для систем ONTAP Cloud живущая в публичном облаке также нет потерабайтного лицензирования со стороны ONTAP Cloud для включения FabricPool — заказчик оплачивает только фактическое потребленное пространство холодного уровня в объектном хранилище S3 напрямую самому облачному провайдеру. На данный момент FabricPool поддерживается только в ONTAP Cloud для Amazon.





FabricPool и Disaster Recovery

Как и раньше, для построения DR площадки и передачи данных между двумя СХД ONTAP используется репликация SnapMirror. Очень часто для экономии финансов, на DR площадку покупался более простое и дешевое хранилище. Теперь же FabricPool позволяет немного по-другому подойти к этому вопросу. К примеру, если на основной площадке используется AFF система, то на резервную можно разместить такую же или похожую, но все же AFF систему. В All Flash хранилищах большую часть бюджета отъедают не контроллеры, а сами SSD накопители. Теперь с FabricPool можно установить на резервную площадку AFF систему, но только с 10%-20% полезного пространства от основного хранилища, так как холодные данные будут уходить на холодный объектный уровень. Позволяя таким образом экономить на дисках, но не ставить контроллеры, которые не тянули бы производительность. В случае если на горячем уровне нет места для новых горячих блоков, они будут читаться напрямую из холодного объектного хранилища.

Чем FabricPool может быть интересен облачным провайдерам?


СХД предоставляет высокоскоростной, но достаточно дорогой уровень хранения данных. Владельцев СХД NetApp FabricPool это способ экономить. А некоторые заказчики просто согласно законам своей страны не могут выносить все или часть своих данных за рубеж в Amazon S3. Для облачного провайдера FabricPool это новые заказчики и дополнительный сервис хранения данных.

Что необходимо облачному провайдеру


Технология FabricPool это технология Tiering позволяющая новым и существующим заказчикам смещать снэпшоты (бэкапы) и холодные данные продуктивных СХД использующий SSD (дорогой уровень) из их ЦОДов, в публичное облако на холодный (дешевый уровень). В публичном облаке необходимо развернуть софт NetApp StorageGrid (доступен в виде образов VMware, KVM и Docker). Для облачных провайдеров NetApp StorageGrid лицензируется потерабайтно помесячно, это очень удобно: пока есть заказчики этой услуги, облачный провайдер платит за лицензии, нет — не платит. Для владельцев СХД NetApp, которые будут использовать StorageGrid расположенный у облачного провайдера лицензию покупать не нужно.

Высчитать стоимость услуги хранения холодных данных FabricPool для провайдера


стоимость будет включать следующие основные затраты для провайдера:
  • У софта StorageGrid есть системные требования (CPU, Memory), соответственно это затраты для провайдера
  • Заказчик будет подключаться по IP к сервис провайдеру соответственно это или просто внешний белый IP адрес с пробросом порта https на StorageGrid внутри облака. Внешний белый IP и возможно FireWall стоят каких-то денег; Или это опять-таки белый IP для подключения по VPN, по которому заказчик будет перегонять холодные данные. Построить VPN тоже стоит денег; или это выделенный канал связи
  • Дисковое пространство которое будет занято для разворачивания узлов StorageGrid — выделяется один раз, не меняется на протяжении всей жизни узла. Но количество узлов может со временем расти по мере нагрузки и роста занятого пространства. Минимальное число 5 узлов StorageGrid (могут быть виртуальными машинами): 3 узла (storage node) + 2 административных узла (Gateway node & Admin node).
  • По-месячно — по-терабайтное лицензирования NetApp
  • И собственно дисковое пространство занятое под хранение собственно данных от заказчиков.


Выводы


Технология FabricPool позволяет интегрировать ONTAP и объектные хранилища для холодных данных в рамках стратегии DataFabric. Для владельцев СХД, FabricPool позволяет более рационально использовать дорогостоящие ресурсы All Flash систем и SSD агрегатов, смещая неактивные холодные данные на дешевый уровень, что в свою очередь делает системы хранения NetApp All Flash более доступными по стоимости владения. Объектное хранилище легко масштабируется по мере роста и теоретически не имеет ограничений по пространству (текущий Soft Limit 70PB). Для облачных провайдеров FabricPool это способ привлечь новых заказчиков, которые ранее продуктивные данные хранили только на своём оборудовании.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330526/


LTS Webinar — Топ-5 интересных уязвимостей или как Вас могли взломать за последний год

Вторник, 13 Июня 2017 г. 14:47 + в цитатник


15 июня пройдёт онлайн-конференция со спикером Luxoft.

Тема — Топ-5 интересных уязвимостей или как Вас могли взломать за последний год.
Основные тезисы доклада:
1. Потребность в средствах обеспечения безопасности приложений и преимущества всестороннего процесса application security.
2. Безопасность приложений и тестирование на проникновение: фундаментальные отличия и внешние сходства.
3. Автоматический статический и динамический анализы.
4. Пределы автоматизации и улучшение автоматизации ручными проверками.

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

Конференция стартует 15 июня в 17:00 часов по московскому времени.

Для участия в конференции необходимо зарегистрироваться по ссылке career.luxoft.com/lts-luxoft-technology-series/ru

Участие – бесплатное.

Для того, чтобы принять участие в онлайн-конференции, достаточно иметь компьютер или мобильное устройство, подключённые к интернету. Никакого специального программного обеспечения устанавливать не нужно. Плагин платформы загрузится за несколько секунд.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330808/


Метки:  

Сервис будущего: возможности и риски

Вторник, 13 Июня 2017 г. 14:23 + в цитатник

Метки:  

Win32/Industroyer: новая угроза для промышленных систем управления

Вторник, 13 Июня 2017 г. 14:21 + в цитатник
Win32/Industroyer – сложная вредоносная программа, предназначенная для нарушения рабочих процессов в промышленных системах управления (ICS), в частности, на электрических подстанциях.

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



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

  • IEC 60870-5-101 (IEC 101)
  • IEC 60870-5-104 (IEC 104)
  • IEC 61850
  • OLE for Process Control Data Access (OPC DA)

В дополнение к этому авторы Industroyer разработали инструмент для выполнения DoS-атак (denial-of-service – отказ в обслуживании), нацеленных на определенные устройства релейной защиты, в частности, линейку Siemens SIPROTEC.

Возможности Win32/Industroyer впечатляют. Если сравнить его с инструментами, которые использовались в атаках на украинскую энергосистему в 2015 году и привели к массовым отключениям электроэнергии 23 декабря 2015 года (BlackEnergy, KillDisk и другие компоненты, включая легитимное ПО для удаленного доступа), можно утверждать, что за Industroyer стоит кибергруппа более высокого уровня. Авторы создали вредоносную программу, которая позволяет напрямую управлять выключателями и прерывателями цепи в сети электрических подстанций. По некоторым признакам мы предполагаем, что Industroyer может быть связан со сбоем энергоснабжения в Киеве в декабре 2016 года. Тем не менее, на момент написания отчета это не было подтверждено, и расследование продолжается. Вектор заражения пока не установлен.

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


Рисунок 1. Упрощенная схема компонентов Win32/Industroyer.

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

Основной бэкдор


Главный компонент Industroyer – основной бэкдор – используется атакующими для управления остальными компонентами программы.

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

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


Рисунок 2. Декомпилированный код основного бэкдора с возможностью задать время.

После подключения к удаленному C&C-серверу основной бэкдор отправляет в POST-запрос следующие данные:
  • строка GUID (глобально-уникальный идентификатор) для текущего профиля оборудования, полученная при помощи функции GetCurrentHwProfile
  • версия вредоносного ПО – 1.1e
  • жестко запрограммированный ID образца
  • результат любой ранее полученной команды

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

  • DEF
  • DEF-C
  • DEF-WS
  • DEF-EP
  • DC-2-TEMP
  • DC-2
  • CES-McA-TEMP
  • CES
  • SRV_WSUS
  • SRV_DC-2
  • SCE-WSUS01

Основной бэкдор поддерживает следующие команды:


Получив права администратора, атакующие могут обновить установленный бэкдор до более привилегированной версии, которая выполняется как Windows service program. Для этого им нужно выбрать существующий некритический процесс Windows и заменить параметр реестра ImagePath на путь к новому бинарному файлу бэкдора.

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


Рисунок 3. Обфусцированный ассемблерный код основного бэкдора, работающего как служба Windows.

Дополнительный бэкдор


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

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

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


Рисунок 4. Сравнение оригинального бинарного кода Notepad (слева) и бэкдора.

Компонент запуска (Launcher)


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

Компонент запуска содержит определенное время и дату. В изученных образцах было задано две даты: 17 и 20 декабря 2016 года. Как только одна из двух дат наступает, компонент создает два потока. Первый пытается загрузить вредоносную DLL, второй ждет один или два часа (в зависимости от версии компонента), а затем пытается загрузить компонент стирателя данных. Оба потока имеют высший приоритет THREAD_PRIORITY_HIGHEST, что означает, что они получают более высокую долю ресурсов центрального процессора.

Имя вредоносной DLL добавляется атакующими через параметр командной строки, предоставленный в одной из команд основного бэкдора («Выполнить shell-команду»). Имя файла стирателя данных – всегда haslo.dat. Ожидаемые командные строки имеют вид:

%LAUNCHER%.exe %WORKING_DIRECTORY% %PAYLOAD%.dll %CONFIGURATION%.ini

Каждый аргумент командной строки обозначает следующее:
%LAUNCHER%.exe – имя файла компонента запуска
%WORKING_DIRECTORY% – каталог, в котором хранится вредоносная DLL и конфигурация
%PAYLOAD%.dll – имя файла вредоносной DLL
%CONFIGURATION%.ini – файл, в котором хранятся данные конфигурации конкретной полезной нагрузки. Путь к этому файлу передается вредоносной DLL компонентом запуска

Полезная нагрузка и компонент стирателя данных – стандартные файлы DLL Windows. Чтобы быть загруженными компонентом запуска, они должны экспортировать функцию Crash как показано на рис. 5.


Рисунок 5. Пример вредоносной DLL с внутренним именем Crash101.dll и экспортированной функцией Crash.

Компонент 101


Вредоносная DLL с именем файла 101.dll названа в честь международного стандарта IEC 101 (он же IEC 60870-5-101), который описывает протокол мониторинга и управления электроэнергетическими системами. Протокол обеспечивает коммуникацию между промышленными системами управления и удаленными терминальными блоками (Remote Terminal Units – RTUs). Обмен данными осуществляется через последовательное соединение.

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

После выполнения компонент 101 анализирует конфигурацию, хранящуюся в INI-файле. Конфигурация может содержать несколько записей: имя процесса, имена устройств Windows (обычно COM-порты), количество диапазонов и значения диапазонов для адресов информационных объектов (Information Object Address – IOA). IOA – номер, который идентифицирует конкретный элемент данных в устройстве. На рис. 6 показан файл конфигурации компонента 101 с двумя определенными диапазонами IOA: 10-15 и 20-25.


Рисунок 6. Пример конфигурации компонента 101.

Имя процесса, указанного в конфигурации, принадлежит приложению, которое, как предполагают атакующие, работает в системе жертвы. Это должно быть приложение, которое машина использует для коммуникаций с RTU через последовательное соединение. Компонент 101 пытается завершить этот процесс и обращается к указанному устройству, используя функции Windows API CreateFile, WriteFile и ReadFile. Первый СОМ-порт из файла конфигурации используется для фактической связи, два остальных – открыты, чтобы предотвратить обращение других процессов. Таким образом, компонент 101 может взять на себя управление устройством RTU.

Компонент выполняет итерацию по всем диапазонам IOA. Для каждого IOA он создает пакеты команд выбора и исполнения с однопозиционной (C_SC_NA_1) и двухпозиционной командой (C_DC_NA_1) и отправляет на устройство RTU. Основная цель компонента – изменить значение выключателя On/Off для однопозиционного и двухпозиционного командного типа IOA. Так, на первом этапе компонент пытается переключить IOA в состояние Off, на второй – On, на заключительном этапе – вернуть в значение Off.


Рисунок 7. Пример разобранного пакета полезной нагрузки в Kaitai Struct WebIDE.

Компонент 104


DLL с именем файла 104.dll названа в честь стандарта IEC 104 (IEC 60870-5-104). Протокол IEC 104 дополняет IEC 101 так, чтобы передавать данные по TCP/IP. Благодаря гибко изменяемой конфигурации, компонент может быть настроен атакующими под различное оборудование. Рис. 8 показывает, как может выглядеть файл конфигурации.


Рис. 8. Образец файла DLL конфигурации компонента 104.

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

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

Наш анализ этого компонента показывает следующие возможные параметры конфигурации:


После прочтения файла конфигурации компонент 104 создает процесс для каждого фрагмента STATION, по одному на каждый. В каждом таком процессе компонент 104 попытается связаться с указанным адресом IP при помощи протокола, описанного в стандарте IEC 104. До установления соединения он попытается завершить легитимный процесс, который должен отвечать за обмен данными с устройством. Это происходит только в том случае, если свойство stop_comm_service прописано в конфигурации. По умолчанию компонент 104 завершает процесс с именем D2MultiCommService.exe, либо с тем именем, которое прописано в его конфигурации.

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

Первый такой режим operationrange. Хакеры используют его для обнаружения возможных IOA в интересующем устройстве. Им приходится применять данный подход, потому что протокол, описанный в стандарте IEC 104, не дает определенного метода получения этой информации.

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


Рис. 9. Пример декодированного в Wireshark пакета компонента 104.

Как только все возможные IOA из определенного диапазона опрошены, компонент 104 переходит ко второму этапу режима range. Если возможность записи в логи включена, компонент запишет в него Starting only success. Остальная часть второго этапа состоит в бесконечном цикле использования ранее обнаруженных IOA однопозиционного типа. В цикле компонент непрерывно передает пакеты команд выбора и исполнения. Вдобавок, если опция change определена, компонент переключает состояние On/Off между этапами цикла.

На рис. 10 показан файл лога, который выдал компонент 104 во время нашего анализа. Из него мы видим, что компонент опросил IOA от 10 до 15 и, когда IOA однопозиционного типа были обнаружены, начал их использование в цикле. В конфигурации опция change была включена, так что между циклами компонент переключал значение выключателя с On на Off и писал это в лог.


Рис. 10. Пример логов компонента 104.

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

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

Кроме способности писать в лог, компонент 104 может выводить отладочную информацию в консоль, как это показано на рис. 11.


Рис. 11. Вывод на консоль компонента 104.

Компонент 61850


В отличие от компонентов 101 и 104, существует в виде отдельного вредоносного инструмента, состоящего из исполняемого файла под названием 61850.exe и DLL 61850.dll. Назван в честь стандарта IEC 61850. Этот стандарт описывает протокол, используемый для обмена данными между устройствами различных производителей, которые выполняют функции защиты, автоматизации, измерения, мониторинга и управления систем автоматики электрических подстанций. Это сложный и надежный протокол, но компонент 61850 использует только небольшой ряд его параметров, чтобы привести к разрушительным последствиям.

После исполнения DLL компонента 61850 пробует прочесть файл конфигурации, чей путь предоставляется компонентом запуска. Отдельная версия по умолчанию берет конфигурацию из i.ini. Ожидается, что файл конфигурации содержит список IP-адресов устройств, которые имеют возможность обмена данными по протоколу, описанному в стандарте IEC 61850.

Если файл конфигурации не находится, компонент 61850 нумерует все подключенные адаптеры сети для определения их масок подсети TCP/IP. Затем компонент нумерует все возможные IP-адреса для каждой из масок подсети и пробует подключиться к порту 102 каждого адреса. Таким образом, компонент умеет автоматически обнаруживать подходящие устройства в сети.

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


Рис. 12 Декодированный пакет запроса на подключение в Wireshark.

Если целевое устройство отвечает должным образом, компонент 61850 передает пакет InitiateRequest при помощи Спецификации производственных сообщений (MMS). Если ожидаемый ответ получен, он передает MMS запрос getNameList. Таким образом, компонент составляет список имен объектов в виртуальном производственном устройстве (VMD).

Затем этот компонент 61850 нумерует компоненты, обнаруженные на предыдущем этапе, и отправляет предметно-ориентированные запросы getNameList с каждым именем объекта. Таким образом, компонент нумерует названные переменные в определенном домене.


Рис. 13. Декодированный запрос MMS getNameList в Wireshark.

Затем компонент 61850 парсит информацию, полученную в ответ на эти запросы, и ищет переменные, которые содержат следующие строковые последовательности:

  • CSW, CF, Pos и Model
  • CSW, ST, Pos и stVal
  • CSW, CO, Pos, Oper, но не $T
  • CSW, CO, Pos, SBO, но не $T

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

Для переменных, которые содержат последовательности Model или stVal, компонент 61850 передает дополнительный MMS запрос Read. Для некоторых из этих переменных компонент также может передать MMS запрос Write, который изменит их текущее состояние.

Компонент 61850 создаст файл с логами его работы, содержащий IP-адреса, MMS домены, названные переменные и состояние узлов (открытые или закрытые) его целей.

Компонент OPC DA


Компонент OPC DA внедряет клиент для протокола, описанного в спецификации OPC Data Access. OPC (OLE for Process Control) — это стандарт ПО и спецификация, основанная на технологиях Microsoft, таких как OLE, COM и DCOM. Часть, относящаяся к доступу к данным (DA) спецификации OPC, позволяет производить обмен данными в реальном времени между распространяемыми компонентами по принципу модели «клиент-сервер».

Этот компонент существует в качестве отдельного вредоносного инструмента с именем файла OPC.exe и DLL, который использует функционал и 61850, и OPC DA компонентов. Внутреннее название DLL в экспортированной таблице PE OPCClientDemo.dll, что дает основание предположить, что этот компонент может быть основан на проекте с открытым исходным кодом OPC Client.


Рис. 14. Таблица PE показывает внутреннее имя DLL компонента OPC DA.

Компонент OPC DA не требует какого-либо файла с конфигурацией. После исполнения атакующим он номерует все OPC-серверы при помощи метода ICatInformation::EnumClassesOfCategories с идентификатором категории CATID_OPCDAServer20 и IOPCServer::GetStatus для определения тех, которые запущены.

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

  • ctlSelOn
  • ctlOperOn
  • ctlSelOff
  • ctlOperOff
  • \Pos и stVal

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


Рис. 15. Пример имен элементов OPC в поле IN, полученным при помощи инструмента списков объектов процесса OPC.

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


Рис. 16. Дизассемблированный код компонента OPC DA, который использует строку Abdul.

На финальном этапе компонент OPC DA пробует изменить состояние обнаруженных элементов OPC при помощи интерфейса IOPCSyncIO, прописывая значение 0x01 дважды.


Рис. 17. Дизассемблированный код компонента OPC DA, который использует интерфейс IOPCSyncIO.

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

  • [ServerName: %SERVERNAME%] [State: Before]
  • [ServerName: %SERVERNAME%] [State: After ON]
  • [ServerName: %SERVERNAME%] [State: After OFF]

Компонент стирателя данных


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

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

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

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services

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

Следующий этап — удаление содержимого файла. Компонент нумерует файлы с определенными расширениями на всех приводах, подключенных к компьютеру, от C:\ до Z:\. Нужно отметить, что во время нумерации компонент пропускает файлы, расположенные в подкаталоге, которые содержат слово Windows в названии.

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

Чтобы ускорить процесс стирания, компонент переписывает только часть содержимого файла в его начале. Объем информации, который будет переписан, зависит от размера файла. Наименьший объем информации будет переписан у файлов размером 1 Mb (4096 байтов) и меньше. Наибольший объем информации будет переписан у файлов размером 10 Mb (32768 байтов) и меньше.

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


Рис. 18. Список процессов, которые не завершаются во время второй попытки.

Маски имен файлов, которые переписывает компонент стирателя:

  • SYS_BASCON.COM
  • *.v
  • *.PL
  • *.paf
  • *.v
  • *.XRF
  • *.trc
  • *.SCL
  • *.bak
  • *.cid
  • *.scd
  • *.pcmp
  • *.pcmi
  • *.pcmt
  • *.xml
  • *.CIN
  • *.ini
  • *.prj
  • *.cxm
  • *.elb
  • *.epl
  • *.mdf
  • *.ldf
  • *.bak
  • *.bk
  • *.bkp
  • *.log
  • *.zip
  • *.rar
  • *.tar
  • *.7z
  • *.exe
  • *.dll

Этот список содержит расширения имен файлов, которые используются в стандартной среде, такие как бинарники Windows (.exe/.dll), архивы (.7z /.tar/.rar/.zip), файлы бэкапа (.bak/.bk/.bkp), файлы сервера Microsoft SQL (.mdf/.ldf) и различные файлы конфигурации (.ini/.xml). Вдобавок компонент стирает файлы, которые могут использоваться в промышленных системах управления, например, написанные при помощи языка описания конфигурации подстанций (.scl/.cid/.scd), а также файлы и расширения, которые используются продуктами ABB.

Например, файл под названием SYS_BASCON.COM используется решениями ABB для хранения информации с конфигурацией, а файлы с расширением .paf (Product Authorization File) – для хранения информации по лицензиям для продуктов ABB MicroSCADA.

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


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


Рис. 19. Пример использования сканера портов.

Дополнительные инструменты: DoS Tool


Еще один инструмент из арсенала хакеров — инструмент отказа в обслуживании (DoS), нацеленный на устройства Siemens SIPROTEC. Инструмент эксплуатирует уязвимость CVE-2015-5374, чтобы вызвать зависание устройства. Как только эта уязвимость будет использована, устройство перестанет отвечать на какие-либо команды до тех пор, пока не будет перезагружено вручную.

Чтобы использовать эту уязвимость, атакующие жестко запрограммировали в DoS-инструменте IP-адреса устройств. При использовании инструмент посылает специально созданные пакеты на порт 50000 на целевой IP-адрес при помощи UDP (User Datagram Protocol). Пакет UDP содержит всего 18 байтов.


Рис. 20. Содержимое пакета UDP, задействованного при использовании уязвимости CVE-2015-5374.

Вывод


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

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

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

Индикаторы заражения (IoCs)


Хеши SHA-1:
F6C21F8189CED6AE150F9EF2E82A3A57843B587D
CCCCE62996D578B984984426A024D9B250237533
8E39ECA1E48240C01EE570631AE8F0C9A9637187
2CB8230281B86FA944D3043AE906016C8B5984D9
79CA89711CDAEDB16B0CCCCFDCFBD6AA7E57120A
94488F214B165512D2FC0438A581F5C9E3BD4D4C
5A5FAFBC3FEC8D36FD57B075EBF34119BA3BFF04
B92149F046F00BB69DE329B8457D32C24726EE00
B335163E6EB854DF5E08E85026B2C3518891EDA8


IP-адреса C&C серверов:
195.16.88[.]6
46.28.200[.]132
188.42.253[.]43
5.39.218[.]152
93.115.27[.]57

Внимание! Большинство серверов с этими IP-адресами были частью сети Tor, что означает, что использование индикаторов может дать ложноположительное совпадение.

Задать дополнительные вопросы или передать образцы вредоносного ПО, имеющие отношение к Win32/Industroyer, можно по электронной почте threatintel@eset.com.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330730/


Метки:  

Интернатура в геймдеве: быть или не быть? Первый опыт краснодарской студии Plarium

Вторник, 13 Июня 2017 г. 14:02 + в цитатник


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

Кто такой интерн и чем он отличается от джуниора


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

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

Рассмотрим программы обучения интернов Art Department и Support & Community Department краснодарской студии Plarium. В каждом отделе руководство определяет разницу между понятиями «интерн» и «джуниор» и формирует обязанности претендентов на эти позиции. Главное же отличие двух должностей заключается в уровне самостоятельности и ответственности: на каждом этапе действия интерна контролирует наставник, в то время как джуниор полноценно выполняет свою работу и отвечает за результат.



Какие условия нужны для обучения интернов


За время практики интернатуры в отделах Art и Support & Community был определен ряд шагов, которые могут помочь подготовить из интерна компетентного специалиста.

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




Как происходит отбор интернов


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

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

Для Community Division в первую очередь важны коммуникативные качества претендента, усидчивость, креативность и знание специфики работы в социальных сетях. В Support Division приветствуются опыт в техподдержке, аналитическое мышление, а также внимательность и терпение. Для тех, кто хочет в команду Art Department, профильное образование — несомненный плюс, но у художников-самоучек тоже есть шанс попасть в компанию. Кандидаты, научившиеся рисовать самостоятельно, могут быть очень талантливы, и некоторые из них уже работают в краснодарской студии Plarium.

Обучение интернов в Art Department


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

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

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

Обучение интернов в Support & Community Department


Как вы уже успели заметить, в Support & Community Department интернатура есть в двух подразделениях: Support Division и Community Division. В отличие от Art Department интерн Support & Community Department начинает работу на проекте еще во время обучения. Наставник дает подопечному посильные задачи и контролирует их выполнение. Система подготовки в этом отделе представлена набором тестов и специальной учебной программой как для одного человека, так и для группы интернов.

Кроме проверки профессиональных навыков обязательным является итоговый экзамен на знание проекта. Он проходит в два этапа: предварительное тестирование и итоговое. Сотрудники Support Division должны досконально знать проект, а к интернам Community Division предъявляют чуть менее строгие требования.

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



Результаты


Опыт работы с интернами отделов Art и Support & Community студии Plarium в Краснодаре крайне позитивен. Практически все, кто к нам пришел, выросли профессионально, стали частью команды и усилили ее. Случаи, когда после испытательного срока мы были вынуждены расстаться с сотрудниками, единичны.

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

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

https://habrahabr.ru/post/330800/


Метки:  

[Из песочницы] Симметричное и асимметричное шифрование. Разбор алгоритма передачи шифрованных данных между серверами

Вторник, 13 Июня 2017 г. 13:37 + в цитатник
Если имеется две машины и требуется переслать в одну или другую cторону данные в шифрованном виде — библиотека на php, написанная мною несколько месяцев назад и допиленная вчерашним вечером — то чем я хотел бы поделиться.

Условимся, что машина, которая передает шифрованные данные — это всегда машина A, а машина, которая их принимает — имеет условное обозначение B.

Библиотека решает два возможных случая (при необходимости довнесу функционал):

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

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

Для первого случая в папке server_b_1 есть скрипт testGetDataFromA.php
Для второго случая в папке server_a_1 есть скрипт testPushDataToB.php

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

Теперь о том как реализованы оба решения:

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

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

$encrypted_data = urlencode(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $sinc_key, $notice_text, MCRYPT_MODE_ECB)));

$test_decrypted = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256,$sinc_key, base64_decode(urldecode($encrypted_data)),MCRYPT_MODE_ECB));

Работа с асимметричным шифрованием происходит с использованием php OpenSSL

Итак:

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

1) Случай, когда имеется машина (B), которой нужны данные от машины A (например, ей нужно получить толкен клиента) и эти данные должны быть получены безопасно. Т.е. инициатором передачи является машина B.

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

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

Нет гарантии, что машина A — именно наша машина, а не ФСБ-шника Анатолия. Поэтому реализация этого алгоритма библиотекой немного изменена подполнительной проверкой:

(Демо скрипта — server_b_1/testGetDataFromA.php)

На обоих машинах прописан секретный ключ SIGNATURE_KEY, который учавствует в дополнительной проверке. Машина B генерирует пару ключей (приватный и публичный), ключ текущей коннекции и делает запрос (http://.../server_a_1/getDataToB.php) на машину A, отослав ключ текущей коннекции и публичный ключ (приватный оставив у себя). Машина А генерирует симметричный ключ, шифрует им требуемую к передаче секретную информацию N. Также формируются допданные M, которые представляют собой md5 от строки содержащей SIGNATURE_KEY и ключ текущей коннекции. После этого машина А возвращает зашифрованную публичным ключом строку из симметричного ключа и допданных М, а так же зашифрованную симметричным ключом секретную информацию N. Машина B расшифровывает данные с симметричным ключом своим приватным ключом, генерирует строку, подданным М (поскольку вполне может вычислить md5 от строки содержащей SIGNATURE_KEY и ключ текущей коннекции). Если допданные совпадают (что является просто дополнительной проверкой для каждой транзакции, что машина A знает SIGNATURE_KEY, а следовательно — наша машина), машина В извлекает симметричный ключ с помощью которого она расшифровывает секретную информацию N.

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

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

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

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

(Демо скрипта — server_a_1/testPushDataToB.php)

На обоих машинах прописан секретный ключ SIGNATURE_KEY, который участвует в дополнительной проверке. Машина A, сгенерировав md5 от ключа текущей коннекции и SIGNATURE_KEY отправляет эти данные (вместе с незашифрованым ключом текущей коннекции) машине B (http://.../server_b_1/get_public_key.php), которая генерирует публичный ключ только если у нее получается такой же md5 от своего SIGNATURE_KEY и полученного ключа текущей коннекции. Это не решает вопроса, что публичный ключ будет получен именно от машины A, а не от машины ФСБ-шника Василия, но гарантирует машеине B, что она генерирует публичный ключ именно для машины A (хотя генерация публичного ключа — дело вообще говоря произвольное, но даже тут лучше перестраховаться). Вместе с публичным ключом генерируется md5 от SIGNATURE_KEY и вторым ключом текущей коннекции. Второй ключ текущей коннекции — произвольный хеш. Данные публичного ключа, второго ключа произвольной коннекции и указанный md5 возвращаются на машину A. Получив второй ключ произвольной коннекции машина A, зная SIGNATURE_KEY генерирует проверочный md5 и если он совпадает с тем, что машина получила — публичный ключ считается именно от машины B, а не от Василия.

Далее машина A (тут уже схема аналогична первому случаю передачи данных) генерирует симметричный ключ и доп проверку, которая представляет собой md5 от SIGNATURE_KEY и ключа текущей коннекции. Эти данные шифруются публичным ключом от машины B. Далее данные вместе с ключом текущей коннекции отправляются на машину B (http://.../server_b_1/pushDataFromA.php), которая генерирует на основе полученного из этих данных ключа текущей коннекции и SIGNATURE_KEY md5, сверяет с полученным, что дает гарантию, что данные не от ФСБ-шника Николая. Если все в порядке и проверка пройдена — с помощью приватного ключа извлекается симметричный ключ, которым уже расшифровывается сообщение.

Буду рад, если кому-то пригодится эта информация.

-> Код на гите (там же демо)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330792/


Метки:  

[recovery mode] Релиз chrome, исправляющий уязвимостей на 23,500$

Вторник, 13 Июня 2017 г. 13:18 + в цитатник

На прошлой неделе Chrome обновился до 59 версии. Кроме изменений в сторону материал дизайна, было закрыто 30 ошибок безопасности. Общий размер вознаграждений за которые превысил 23k$, что еще раз доказывает работоспособность bugs bounty.



Наиболее серьезная брешь была обнаружена Чжао Цюйшуном (Zhao Qixun), также известным как S0rryMybad. Затрагивает эта уязвимость движок JavaScript V8 (CVE-2017-5070), эксперт получил за нее 7500 долларов. В апреле двое других экспертов сообщили разработчикам Chrome о недостатках, связанных с выполнением кода вне пределов памяти (CVE-2017-5071) и спуфингом омнибокс-адресов (CVE-2017-5071). За каждую из этих уязвимостей исследователи заработали 3000 долларов США.


Security Fixes and Rewards


Подробности о большинстве ошибок не раскрываются, пока большинство пользователей не установит обновления или если проблема была в сторонней библиотеке
[$7500] High CVE-2017-5070: Type confusion in V8. Reported by Zhao Qixun(@S0rryMybad) of Qihoo 360 Vulcan Team on 2017-05-16
[$3000] High CVE-2017-5071: Out of bounds read in V8. Reported by Choongwoo Han on 2017-04-26
[$3000] High CVE-2017-5072: Address spoofing in Omnibox. Reported by Rayyan Bijoora on 2017-04-07
[$2000] High CVE-2017-5073: Use after free in print preview. Reported by Khalil Zhani on 2017-04-28
[$1000] High CVE-2017-5074: Use after free in Apps Bluetooth. Reported by anonymous on 2017-03-09
[$2000] Medium CVE-2017-5075: Information leak in CSP reporting. Reported by Emmanuel Gil Peyrot on 2017-01-05
[$1000] Medium CVE-2017-5086: Address spoofing in Omnibox. Reported by Rayyan Bijoora on 2017-05-16
[$1000] Medium CVE-2017-5076: Address spoofing in Omnibox. Reported by Samuel Erb on 2017-05-06
[$1000] Medium CVE-2017-5077: Heap buffer overflow in Skia. Reported by Sweetchip on 2017-04-28
[$1000] Medium CVE-2017-5078: Possible command injection in mailto handling. Reported by Jose Carlos Exposito Bueno on 2017-04-12
[$500] Medium CVE-2017-5079: UI spoofing in Blink. Reported by Khalil Zhani on 2017-04-20
[$500] Medium CVE-2017-5080: Use after free in credit card autofill. Reported by Khalil Zhani on 2017-04-05
[$N/A] Medium CVE-2017-5081: Extension verification bypass. Reported by Andrey Kovalev (@L1kvID) Yandex Security Team on 2016-12-07
[$N/A] Low CVE-2017-5082: Insufficient hardening in credit card editor. Reported by Nightwatch Cybersecurity Research on 2017-05-11
[$N/A] Low CVE-2017-5083: UI spoofing in Blink. Reported by Khalil Zhani on 2017-04-24
[$N/A] Low CVE-2017-5085: Inappropriate javascript execution on WebUI pages. Reported by Zhiyang Zeng of Tencent security platform department on 2017-02-15


Кроме этих ошибок, команда Хрома пользуется и постоянно исправляет то, что находят известные сканеры — AddressSanitizer, MemorySanitizer, Control Flow Integrity, и libFuzzer.

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

https://habrahabr.ru/post/330788/


Метки:  

[Перевод] Теория современного Go

Вторник, 13 Июня 2017 г. 13:12 + в цитатник

tl;dr магия это плохо; глобальные состояние это магия -> глобальные переменные в пакетах это плохо; функция init() не нужна


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


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


Функции (включая методы) по сути являются единственным механизмом, который есть в Go, чтобы строить абстракции. Давайте посмотрим на следующее определение функции:


fund NewObject(n int) (*Object, error)

По соглашению, мы ожидаем, что функции в форме NewXXX это конструкторы типов. Это ожидание подтверждается, когда мы видим, что функция возвращает указатель на Object и ошибку. Из этого мы можем вывести, что конструктор может не сработать, и в этом случае он вернёт ошибку, в которой объяснена причина. Также мы видим, что функция принимает на вход единственный целочисленный параметр, который, как мы полагаем, контролирует какой-то аспект или свойство объекта, который будет возвращён. Вероятно, есть какие-то допустимые значения n, которые, будучи нарушенными, приведут к ошибке. Но, поскольку, функция больше не принимает других параметров, мы ожидаем, что функция больше никаких побочных эффектов нет, кроме (вероятно) выделения памяти.


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


Теперь, давайте посмотрим на тело функции:


func NewObject(n int) (*Object, error) {
    row := dbconn.QueryRow("SELECT ... FROM ... WHERE ...")
    var id string
    if err := row.Scan(&id); err != nil {
        logger.Log("during row scan: %v", err)
        id = "default"
    }
    resource, err := pool.Request(n)
    if err != nil {
        return nil, err
    }
    return &Object{
        id:  id,
        res: resource,
    }, nil
}

Функция использует глобальный объект из пакета sql — database/sql.Conn, чтобы произвести запрос к какой-то непонятной базе данных; затем глобальный для пакета логгер, чтобы записать строку в непонятном формате в непонятно куда; и глобальный объект пула запросов, чтобы запросить какой-то ресурс. Все эти операции имеют побочные эффекты, которые абсолютно невидимы при чтении сигнатуры функции. У программиста, читающего её, нет способа предсказать ни одно из этих действий, кроме как чтения тела функции и заглатывания в определения глобальных переменных.


Давайте попробуем такой вариант сигнатуры:


func NewObject(db *sql.DB, pool *resource.Pool, n int, logger log.Logger) (*Object, error)

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


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


// RowQueryer models part of a database/sql.DB.
type RowQueryer interface {
    QueryRow(string, ...interface{}) *sql.Row
}

// Requestor models the requesting side of a resource.Pool.
type Requestor interface {
    Request(n int) (*resource.Value, error)
}

func NewObject(q RowQueryer, r Requestor, logger log.Logger) (*Object, error) {
    // ...
}

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


Если бы все наши конструкторы и функции принимали зависимости явно, нам бы не нужны были глобальные переменные вообще. Взамен, мы бы могли создавать все наши соединения с базами данных, логгеры и пулы ресурсов, в функции main, давая возможность будущим читателям кода очень четко понимать граф компонентов. И мы можем очень явно передавать все наши зависимости, убирая вредную для понимания магию глобальных переменных. Также, заметьте, что если у нас нет глобальных переменных, нам больше не нужна функция init, чья единственная функция это создавать или изменять глобальное состояние пакета. Мы можем затем посмотреть на все случаи использования функций int со справедливым подозрением: что, собственно, это код вообще делает? Если он не в функции main, зачем он?


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


--


И на этом моменте я могу сформулировать теорию современного Go. Отталкиваясь от слов Дейва Чини, я предлагаю следующие правила:


  • отсутствие глобальных переменных в пакетах
  • отсутствие функции int

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

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

https://habrahabr.ru/post/330786/


Метки:  

Пошаговая настройка Apache с выбором версий php + Nginx как reverse proxy (с mod_pagespeed) на ubuntu 16.0.4

Вторник, 13 Июня 2017 г. 13:10 + в цитатник
В интернете кучу статей по настройке сервера, настройки Apache, Nginx и т.п. В данной статье будет пошагово настроен простой shared хостинг. Все операции производятся через консоль.
В посте будут решены и описаны следующий задачи:
1. Установка Apache + PHP
2. Возможность выбора версий PHP
3. Возможность работы сайтов от разных пользователей, с ограничением на чтение директорий других сайтов.
4. Установка Nginx с модулем pagespeed от google
5. Настройка Nginx как reverse proxy
Все этапы будут содержать описание и пояснения. Сам пост писался больше для себя, чтобы не потерять порядок настройки, но будет очень полезным для новичков, которые начинают разбираться в администрировании сервера. В качестве сервера установлен Ubuntu 16.0.4 только с SSH.

ЭТАП 1 (Установка Apache + PHP)
Запускаем оболочку с root правами:
sudo -i

Устанавливаем apache:
apt install -y apache2

Ключ
 -y 
нужен для того чтобы в процессе установки, автоматически на все вопросы отвечал положительно.
К примеру если выполнить:
 apt install apache2 

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

Устанавливаем php (как mod_php)
 apt install -y php libapache2-mod-php 

На данном этапе у нас установиться php версии 7 как модуль apache.

ЭТАП 2 (Возможность выбора версий PHP)
На первом этапе мы установили сервер Apache + PHP при чем PHP у нас работает как модуль Apache. Существует несколько режимов работы PHP подробную информацию можно прочитать по ссылке «Коротко о CGI, FastCGI, PHP-FPM и mod_php»
Если вам лень читать, то объясню проще:
1. mod_php — сам Apache выполняет php скрипт.
Плюсы: работает быстро, требует минимум настроек и знаний
Минусы: скрипты выполняются от пользователя apache (как правило www-data)

2. CGI/FastCGI — Сервер Apache запускает прикладной скрипт интерпретатора php-cgi, который в свою очередь выполняет php скрипт
Плюсы: скрипты выполняются от произвольного пользователя, можно использовать в связке с другими приложениями (Nginx + PHP), конфигурацию PHP можно сделать индивидуальной
Минусы: скорость работы, дополнительная настройка

3.PHP-FPM — это модернизированный fast-cgi сервер который постоянно держит готовые для работы пул-процессов.
Плюсы: скорость работы, скрипты выполняются от произвольного пользователя, можно использовать в связке с другими приложениями (Nginx + PHP-FPM — самая распространная реализация)
Минусы: дополнительная настройка, занимает порт, на каждого пользователя открывается свой порт.

Мы остановимся на CGI/FastCGI. На самом деле многие может испугать, что он самый медленный, но на большинстве shared хостингов, именно этот режим работы (ispmanager использует именно этот режим работы). Нам потребуется собрать из исходников версии php которые нам необходимы.

2.1 Сборка php из исходников
Обновляем репозиторий:
apt update

Устанавливаем необходимые для сборки пакеты:
apt install -y make \
git autoconf \
lynx \
wget \
build-essential \
libxml2-dev \
libssl-dev \
libbz2-dev \
libcurl4-openssl-dev \
libpng12-dev \
libfreetype6-dev \
libxpm-dev \
libmcrypt-dev \
libmhash-dev \
libmysqlclient-dev \
libjpeg62-dev \
freetds-dev \
libjson-c-dev \
re2c \
zlib1g-dev \
libpcre3 \
libpcre3-dev \
unzip \
libxslt1-dev

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

Создаем папки для php:
mkdir -p /opt/source/php
mkdir -p /opt/php/

Переходим в директорию в которой будут храниться исходники php
cd /opt/source/php


Скачиваем необходимую версию php и распаковываем ёё:
wget -c http://php.net/get/php-5.6.18.tar.bz2/from/this/mirror -O php-5.6.18.tar.bz2
tar xvjf php-5.6.18.tar.bz2

В последней команде мы скачали по ссылке php-5.6.18 и сохранили как php-5.6.18.tar.bz2
После чего распаковали архив.

Переходим в директория скаченного и распакованного php
cd /opt/source/php/php-5.6.18


Конфигурируем php
./configure --enable-cli \
 --prefix=/opt/php/php-5.6.18		\
 --disable-rpath		\
 --enable-calendar		\
 --enable-discard-path 		\
 --enable-fastcgi		\
 --enable-force-cgi-redirect		\
 --enable-fpm		\
 --enable-ftp		\
 --enable-gd-native-ttf		\
 --enable-inline-optimization		\
 --enable-mbregex		\
 --enable-mbstring		\
 --enable-pcntl		\
 --enable-soap		\
 --enable-sockets		\
 --enable-sysvsem		\
 --enable-sysvshm		\
 --enable-zip		\
 --with-bz2		\
 --with-curl		\
 --with-curl 		\
 --with-freetype-dir		\
 --with-gd		\
 --with-gd 		\
 --with-gettext		\
 --with-jpeg-dir 		\
 --with-jpeg-dir=/usr/lib/		\
 --with-libdir=/lib/x86_64-linux-gnu		\
 --with-libxml-dir=/usr		\
 --with-mcrypt		\
 --with-mhash		\
 --with-mysql		\
 --with-mysql 		\
 --with-mysqli		\
 --with-mysqli 		\
 --with-openssl		\
 --with-pcre-regex		\
 --with-pdo-mysql		\
 --with-png-dir=/usr		\
 --with-zlib		\
 --with-zlib-dir

Стоить обратить внимание на строку --prefix=/opt/php/php-5.6.18. Именно в эту директорию будет собран проект. Также вы самостоятельно можете добавлять или удалять необходимые модуль и компоненты php. Но при конфигурации обязательно должны быть --enable-fastcgi и --enable-force-cgi-redirect
После конфигурации собираем php

make
make install

Процесс сборки непривычно долгий, поэтому не стоит переживать по этому поводу.
По завершению сборки можно проверить командой:
/opt/php/php-5.6.18/bin/php -v


В результате будет что то вроде:
PHP 5.6.18 (cli) (built: Jun 8 2017 15:59:20)
Copyright © 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright © 1998-2016 Zend Technologies


2.2 Настройка Apache
Далее нам потребуется чтобы Apache вызывал php скрипт через режим fastcgi
Устанавливаем и активируем mod_fcgi
apt install libapache2-mod-fcgid
a2enmod cgi fcgid actions

перезапустим сервис Apache
service apache2 restart


2.3 Создание CGI скрипта
Создадим обертку для запуска PHP-FastCGI
mkdir -p /opt/php/php-5.6.18/fcgi-bin

В данной папке создадим скрипт с именем php со следующим содержимом
#!/opt/php/php-5.6.18/bin/php-cgi
Лично я использую редактор nano.
nano /opt/php/php-5.6.18/fcgi-bin/php

Вставляем код, выходим CTRL+X и подтверждаем изменения.

Делаем файл испольняемым
chmod +x /opt/php/php-5.6.18/fcgi-bin/php

В той же директории создаем файл php.ini () можно скопировать /opt/source/php/php-5.6.18/php.ini-production

2.4 Настройка хоста для Apache
В примере будет показана настройка виртуального хоста по умолчанию:

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html
        
            IPCCommTimeout 7200
            FcgidConnectTimeout 320
            MaxRequestLen 25728640
            FcgidMaxRequestsPerProcess 0
            FcgidBusyTimeout 3600
            FcgidOutputBufferSize 0
        

        
                SetHandler fcgid-script
                FCGIWrapper /opt/php/php-5.6.18/fcgi-bin/php
        
        ErrorLog /var/www/html/error.log
        CustomLog /var/www/html/access.log combined

var/www/html>
        Options +Includes +ExecCGI



Перезапускаем настройки Apache
service apache2 reload


ЭТАП 3 ( Возможность работы сайтов от разных пользователей, с ограничением на чтение директорий других сайтов.)
Для разграничения прав по пользователям у Apache есть 2 разных модуля suEXEC и ITK.

Рассмотрим как работает каждый из них:
ITK — При поступлении запроса, apache создает процесс-обработчик, который наследует права корневого процесса, но после проверки контекста меняет свои права на указанного пользователя.

suEXEC -При поступлении запроса apache запускает CGI и аналогичные собственные или сторонних разработчиков скрипты/программы внутри веб-папки домена от имени указанного пользователя.

suEXEC в нашем варианте предпочтительней из-за особенности архитектуры работы. Устанавливаем suEXEC
apt install apache2-suexec-custom
a2enmod suexec


Важно, для правильной работы suexec необходимы правильно выставить права на директории.
Как располагать директории вы должны определиться сами, в примере приведется пример, и он не является оптимальным.
Иерархия папок следующая
|--/var/www/ - Корневая папка, права 751 владелец root
|----/php-bin - Папка храннения дефолтных настроек для php
|------/php-5.6.18 - Папка храннения дефолтных настроек для php-5.6.18
|--------php - Исполняемый файл для php-5.6.18
|--------php.ini - Дефольный файл настроке
|--------php.ini - Дефольный файл настроке
|----/apache-cert - папка хранения сертификатов для apache


Создаем папки для пользователя:
mkdir -p /var/www/users/admin
mkdir -p /var/www/users/admin/domain.ru
mkdir -p /var/www/users/admin/apache-log
mkdir -p /var/www/users/admin/php-bin
mkdir -p /var/www/users/admin/temp
mkdir -p /var/www/users/admin/temp/php-session


Копируем файлы настроек для php:
cp /opt/php/php-5.6.18/fcgi-bin/php /var/www/users/admin/php-bin/php
cp /opt/php/php-5.6.18/fcgi-bin/php.ini /var/www/users/admin/php-bin/php.ini


Создаем юзера (важно помнить что все пользователи в группе admin имеют доступ на запуск программ из sudo, поэтому при выборе имени admin он автоматически будет иметь права на выполнения sudo. В данном примере это не критично, но вам следует помнить об этом при создании пользователя)
useradd -m -s /bin/bash admin
passwd admin

Выставляем владельца папки
chown admin:admin -R /var/www/users/admin

Выставляем корневую директорию для пользователя
usermod -d /var/www/users/admin admin


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

	ServerAdmin webmaster@localhost
	DocumentRoot /var/www/users/admin/domain.ru

	SuexecUserGroup admin admin	

	
	      RemoteIPHeader X-Forwarded-For
	      RemoteIPHeader X-Real-IP
	      RemoteIPInternalProxy 127.0.0.1
	

	
		RewriteEngine On
		RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
	


	
	    IPCCommTimeout 7200
	    FcgidConnectTimeout 320
	    MaxRequestLen 25728640
	    FcgidMaxRequestsPerProcess 0
	    FcgidBusyTimeout 3600
	    FcgidOutputBufferSize 0
	

	
		SetHandler fcgid-script
		FCGIWrapper /var/www/users/admin/php-bin/php
	

	ErrorLog /var/www/users/admin/apache-log/error.log
	CustomLog /var/www/users/admin/apache-log/access.log combined

var/www/users/admin/www>
	AllowOverride All
	Options +Includes +ExecCGI



В настройках php.ini пользователя меняем session.save_path
session.save_path = /var/www/users/admin/temp/php-session

Перезапускаем apache
service apache2 restart


ЭТАП 4 (Установка Nginx с модулем pagespeed от google)
Забегая вперед, для поддержки pagespeed в Nginx требуется пересобрать сам Nginx с этим модулем, но чтобы потом не лазить дополнительно в настройках, проще сначало установить его.
Изменяем порты для Apache
/etc/apache2/ports.conf
+ Ваши созданные виртуальные хосты

Перезапускаем Apache
service apache2 restart

Устанавливаем ngnix
apt-get install nginx


Собираем Nginx с pagespeed

Вначале необходимо установить все необходимы для сборки пакеты:
apt install -y build-essential zlib1g-dev libpcre3 libpcre3-dev unzip libxslt1-dev libgd-dev libgeoip-dev


Создаем папки для исходников nginx
mkdir -p /opt/source/nginx
cd /opt/source/nginx


Скачиваем и распаковываем pagespeed и psol. Yt cnjbn g
wget https://github.com/pagespeed/ngx_pagespeed/archive/v1.11.33.4-beta.zip
unzip v1.11.33.4-beta.zip
cd ngx_pagespeed-1.11.33.4-beta
wget https://dl.google.com/dl/page-speed/psol/1.11.33.4.tar.gz
tar -xzvf 1.11.33.4.tar.gz

Сам psol скачивается и распаковывается в директории с ngx_pagespeed.
Переходим в папку с Ngnix
cd /opt/source/nginx

Проверяем версию ngnix (по умолчанию в ubuntu 16.0.4 устанавливается 1.10.0)
nginx -V

Загружаем т версию NGINX:
wget https://nginx.ru/download/nginx-1.10.0.tar.gz
tar -xvzf nginx-1.10.0.tar.gz


Собираем nginx с теми же параметрами что и установленный, но в конце добавляем дополнительные модули:
cd /opt/source/nginx/nginx-1.10.0
./configure \
--with-cc-opt='-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_v2_module --with-http_sub_module --with-http_xslt_module --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-threads \
--add-module=/opt/source/nginx/ngx_pagespeed-1.11.33.4-beta \
--with-http_mp4_module

Собираем Nginx:
make
make install

Собранный бинарный файл Nginx располагается в директории /opt/source/nginx/nginx-1.10.0/objs/nginx. Для того чтобы установить, требуется просто заменить текущий испоняемый файл Nginx на собранный.
Остановим Nginx, заменим файл, и перезапустим его.
service nginx stop

#Переименовываем (на всякий случай) текущий nginx в nginx_backup:
mv /usr/sbin/nginx /usr/sbin/nginx_backup

# Перемещаем на его место новый собранный бинарник:
mv /opt/source/nginx/nginx-1.10.0/objs/nginx /usr/sbin/nginx

перезапускаем Nginx
service nginx start


Создаем папку хранения кэша для pagespeed
/var/www/temp/
/var/www/temp/page-speed/


Добавим /etc/nginx/nginx.conf в секцию http
pagespeed on;
pagespeed FileCachePath "/var/www/temp/page-speed/";
pagespeed EnableFilters combine_css,combine_javascript,rewrite_images,rewrite_css,rewrite_javascript,inline_images,recompress_jpeg,recompress_png,resize_images;
pagespeed JpegRecompressionQuality 85;
pagespeed ImageRecompressionQuality 85;
pagespeed ImageInlineMaxBytes 2048;
pagespeed LowercaseHtmlNames on;


ЭТАП 5 (Настройка Nginx как reverse proxy )
Скажу скажу что в интернете кучу статей для настройки Nginx как reverse proxy. Я лиш приведу ознакомительный вариант настройки

server { 

	listen 80; 
	server_name domain.ru; 
	access_log /var/log/nginx.access_log;


	location ~* \.(jpg|jpeg|gif|png|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|tar|wav|bmp|rtf|swf|ico|flv|txt|xml|docx|xlsx)$ { 
		root /var/www/users/admin/domain.ru; 
		index index.html index.php; 
		access_log off; 
		expires 30d; 
		error_page 404 = @prox;
	} 

	location @prox{
		proxy_pass 127.0.0.1:8880; 
		proxy_set_header X-Real-IP $remote_addr; 
		proxy_set_header X-Forwarded-for $remote_addr; 
		proxy_set_header Host $host; 
		proxy_connect_timeout 60; 
		proxy_send_timeout 90; 
		proxy_read_timeout 90; 
		proxy_redirect off; 
		proxy_set_header Connection close; 
		proxy_pass_header Content-Type; 
		proxy_pass_header Content-Disposition; 
		proxy_pass_header Content-Length;
	}


	location ~ /\.ht { 
		deny all; 
	} 


	location / { 
		proxy_pass 127.0.0.1:8880; 
		proxy_set_header X-Real-IP $remote_addr; 
		proxy_set_header X-Forwarded-for $remote_addr; 
		proxy_set_header Host $host; 
		proxy_connect_timeout 60; 
		proxy_send_timeout 90; 
		proxy_read_timeout 90; 
		proxy_redirect off; 
		proxy_set_header Connection close; 
		proxy_pass_header Content-Type; 
		proxy_pass_header Content-Disposition; 
		proxy_pass_header Content-Length; 
	} 
} 

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

https://habrahabr.ru/post/330772/


Метки:  

Багфикс человека: как фиксить баги, которые мешают работать

Вторник, 13 Июня 2017 г. 12:51 + в цитатник

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


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



image


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


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


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



Генерализация частных случаев



image

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


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


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


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



Это невозможно!



image

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


У такой реакции несколько причин:


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


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


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


Ну и в будущем, если ситуация повторится, на «Это невозможно!» у вас будет кейс, как человек задачу с таким же диагнозом решил за N минут. Напомните ему этот случай пару раз — и дальше он уже научится сам фиксить этот баг.



Проклятие знания



image

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


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



Личное оскорбление



image

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


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


  1. Отделить хорошее и плохое.
  2. В работе, пусть её и нужно переделать, все равно были какие-то положительные моменты — вспомните их и похвалите коллегу.
  3. Объясните, в чём ошибка. Возможно, человек не знает, как эту ошибку исправить, и именно поэтому сопротивляется и бунтует.
  4. Инициируйте повторное обсуждение или брейншторм по уже пройденным вопросам.
  5. Попросите помощи коллег или выделите дополнительный ресурс — например, время на рисёрч.
  6. Настаивайте на переделке плохого.
  7. Закрепите пройденный урок: выясните причину, почему искажение активировалось, и запомните, как вы его пофиксили.


Эффект генерации



image

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


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


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



Слепое пятно



image

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


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



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


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

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

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

https://habrahabr.ru/post/330784/


Метки:  

[Перевод] Выпуск Rust 1.18

Вторник, 13 Июня 2017 г. 12:23 + в цитатник

Команда Rust рада представить выпуск Rust 1.18.0. Rust — это системный язык программирования, нацеленный на безопасность, скорость и параллельное выполнение кода.


Если у вас установлена предыдущая версия Rust, то для обновления достаточно выполнить:


$ rustup update stable

Если у вас ещё не установлен Rust, вы можете установить rustup c соответствующей страницы нашего веб-сайта и ознакомиться с подробным примечанием к выпуску 1.18.0 на GitHub.


Что вошло в стабильную версию 1.18.0


Как и всегда, Rust 1.18.0 собрал в себе множество улучшений и новых возможностей.


Одно из крупнейших и самых ожидаемых изменений: члены команды Carol Nichols и Steve Klabnik пишут новую редакцию "Язык программирования Rust", официальной книги о Rust. Она пишется открыто на GitHub, и уже более ста человек внесли в нее свой вклад. Этот выпуск включает первый черновой вариант второго издания в нашей онлайн документации. 19 из 20 глав уже написаны, черновой вариант 20 главы будет добавлен в выпуске Rust 1.19. Когда книга будет завершена, версия для печати будет доступна через No Starch Press, если вы предпочитаете бумажную копию. Мы все еще работаем совместно с редакторами No Startch, чтобы улучшить текст, но мы бы хотели представить книгу широкой аудитории уже сейчас.


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


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


pub(crate) bar;

Выражение внутри () является 'ограничением', уточняющим область видимости. Использование ключевого слова crate в примере выше означает, что bar будет публичным для всего контейнера (crate), но не вне него. Это упрощает создание API, которые "публичны для вашего контейнера", но не доступны вашим пользователям. Это было возможно с существующей системой модулей, но очень часто выглядело неудобно.


Вы также можете указать путь, например:


pub(in a::b::c) foo;

Это означает "foo публично внутри иерархии a::b::c, но нигде больше". Эта особенность была определена в RFC 1422 и описана в документации.


Для пользователей Windows, Rust 1.18.0 имеет новый атрибут, #![windows_subsystem]. Это работает так:


#![windows_subsystem = "console"]
#![windows_subsystem = "windows"]

Эти выражения контролируют флаг /SUBSYSTEM компоновщика. В настоящий момент, доступны только console и windows.


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


Наконец, кортежи, перечисления и структуры (без #[repr]) всегда имели неопределенное размещение в памяти. Мы включили автоматическое переупорядочивание, что может привести к меньшим размерам структур.
Представьте следующую структуру:


struct Suboptimal(u8, u16, u8);

В предыдущих версиях Rust на платформе x86_64, эта структура будет занимать в памяти шесть байт. Но смотря на код, вы ожидаете только 4. Дополнительные два байта появляются из-за выравнивания: так как наибольший тип в структуре u16, она должна быть выравнена по два байта. Но в этом случае u16 расположено в памяти со смещением в один байт. Чтобы разместить его со смещением в два байта, нужно добавить еще один байт выравнивания после первого u8. Добавив еще один байт после второго u8, получаем
1 + 1 (выравнивание) + 2 + 1 + 1 (выравнивание) = 6 байт.


Но что, если наша структура выглядит так?


struct Optimal(u8, u8, u16);

Эта структура выровнена оптимально; u16 лежит с выравниванием в два байта, как и вся структура в целом. Никакого выравнивания не требуется. Это дает нам 1 + 1 + 2 = 4 байт.


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


Мы планировали это изменение в течение длительного времени; предыдущие версии Rust включали эту оптимизацию в ночных (nightly) сборках, но некоторые люди писали небезопасный код, который требовал точных данных о размещении в памяти. Мы откатили это изменение и исправили все подобные случаи, о которых знали. Но если вы найдете какой-нибудь код, который работает неправильно, сообщите нам, чтобы мы смогли его исправить!


Мы планировали перенести rustdoc на Markdown-совместимый парсер CommonMark в течение долгого времени. Однако, простой переход может привести к проблемам, так как спецификация CommonMark отличается от нашего текущего парсера, Hoedown. Как часть нашего плана перехода, новый флаг был добавлен в rustdoc,
--enable-commonmark. Этот флаг включает использование нового парсера вместо старого. Пожалуйста попробуйте его! Насколько мы знаем, оба парсера производят одинаковые результаты, но мы хотим знать, если вы найдете сценарий, при котором их результаты отличаются!


Наконец, компиляция самого rustc теперь на 15%-20% быстрее. Сообщения коммитов в этом PR содержат некоторые детали; существовало множество неэффективных мест, но теперь все они исправлены.


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


Стабилизация стандартной библиотеки


Семь новых API были стабилизированы в этом выпуске:


  • Child::try_wait, неблокирующая версия Child::wait.
  • HashMap::retain и HashSet::retain добавляют retain из API Vec для этих двух хранилищ.
  • PeekMut::pop позволяет вам вытащить верхний элемент из BinaryHeap после того как вы уже прочитали его без необходимости упорядочивать кучу второй раз.
  • TcpStream::peek, UdpSocket::peek, UdpSocket::peek_from позволяют вам просматривать поток или сокет.

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


Функции Cargo


В Cargo появилась поддержка для Pijul VCS, написанной на Rust.
cargo new my-awesome-project --vcs=pijul включает ее!


В дополнение к флагу --all, Cargo теперь имеет несколько новых флагов, например --bins, --examples, --tests и --benches, которые позволяют вам собирать все программы заданного типа.


Наконец, Cargo теперь поддерживает Haiku и Android!


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


Вклад в 1.18.0


Множество людей участвовало в создании Rust 1.18. Мы не смогли бы этого добиться без помощи каждого из вас. Спасибо!


От переводчика
Благодарю Gordon-F и ozkriff за помощь в переводе.
Если вы заинтересовались Rust и у вас есть вопросы, присоединяйтесь!

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

https://habrahabr.ru/post/330778/


Метки:  

[Из песочницы] Автоматизация тестирования OpenStack

Вторник, 13 Июня 2017 г. 12:22 + в цитатник
image

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

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

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

Построение процесса автоматизации тестирования OpenStack

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

Этапы:

  1. Разработчик делает изменение;
  2. В данном изменении системой контроля версий проверяется синтаксис кода;
  3. Изменение попадает в ветку разработчика;
  4. Запускается процесс тестирования на CHECK окружении:

    1. Разворачивание окружения
    2. Deploy
    3. Запуск тестов на проверку синтаксиса кода
    4. Запуск unit тестов
    5. Удаление окружения

  5. Создание запроса к слиянию в основную ветку проекта;
  6. Изменение попадает в основную ветку системы контроля версий;
  7. Запускается процесс тестирования на DEV окружении

    1. Deploy на DEVELOPMENT окружение
    2. Запуск unit тестов
    3. Запуск приемочных тестов для нового функционала
    4. Запуск smoke тестов

  8. При готовности всего необходимого функционала

    1. Создание новой версии ПО

  9. Запускается процесс тестирования на QA окружении

    1. Deploy на QA окружение
    2. Параллельная проверка нового функционала инженером по обеспечению качества
    3. Запуск тестов на проверку инфраструктуры окружения
    4. Запуск функциональных тестов
    5. Запуск нагрузочных тестов

  10. Запуск процесса внедрения новой версии в PRODUCTION окружение

    1. Deploy на боевое окружение
    2. Запуск тестов на проверку основного функционала


Схема 1. Процесс автоматизации тестирования OpenStack

image

Рис.1. Общая диаграмма деятельности процесса автоматизации тестирования OpenStack

image

Рис.2. Диаграмма деятельности первого pipeline для тестирования на CHECK и DEV окружениях

image

Рис.3. Диаграмма деятельности второго pipeline для тестирования на QA и развертывания на PRODUCTION окружении

image

Рис.4. Общая диаграмма последовательности процесса автоматизации тестирования OpenStack

image

Шаги при неуспешности выполнения одного из этапов тестирования

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

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

  • через рабочую электронную почту;
  • через мессенджер;

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

Инструментарий

Для автоматизации процесса тестирования OpenStack можно использовать разные инструменты, но после проведения анализа были выявлены следующие инструменты:

image

Приведенные выше инструменты рекомендованы к построению процесса автоматизации тестирования OpenStack.

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

https://habrahabr.ru/post/330776/


Метки:  

Тест на знание мобильной рекламы в Facebook

Вторник, 13 Июня 2017 г. 12:11 + в цитатник
Вместе с коллегами из Aitarget мы в Mobio сделали тест по мобильной рекламе в Facebook.

10 вопросов о настройке рекламных кампаний, выборе таргетинга и look-a-like аудиторий, измерении эффективности, выборе плейсмента и многом другом.



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

Начать прохождение теста ->
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330774/



Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1004 1003 [1002] 1001 1000 ..
.. 1 Календарь