Создаём своё подмножество javascript

image

В статье рассказывается про модуль позволяющий создавать подмножество javascript с любыми ключевыми словами. Строго для безудержного веселья.
На волне статьи про rucckuu.js я обзавидовался и решил обнародовать своё творение: небольшую экосистему для создания произвольных подмножеств javascript. Если к вам давно закрадывалась мысль о том, что некоторые ключевые слова плохо подходят к контексту их применения или мысль о том, что javascript слишком многословен (всякое бывает). Если вы хотите добродушно подшутить над коллегами или просто объяснить вашей маме чем вы всё-таки занимаетесь на работе, добро пожаловать под кат.

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

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

Я думаю, многие слышали про esprima, парсер ECMAScript. Немного меньше людей знают про jison. Без первого мы бы не увидели jsx так скоро, а второй обязан своему появлению CoffeeScript, оба инструмента достаточно мощные, но esprima специализируется как раз на том, что мы хотим сделать — поменять внешний вид наших программ.

Скупое вступление окончено, к делу.

Создаем MeowScript

  • node, npm по моему предположению не вызывают у вас ужаса
  • npm i your-script в любую удобную директорию
  • заглянем в node_modules/your-script/lexems
  • создадим файл meowscript.lex
  • откроем javascript.lex из той же папки где-нибудь неподалёку
  • в meowscript.lex заменим определения ключевых слов на что-то вроде:

VAR meow LET meoww CONST meOw FOR meowwr ...

  • any-name.js

meowScript = new translator({     to: 'meowscript' });  let output = meowScript.parse(`     var kitty = new Kitty(); if (kitty.isHungry()) {kitty.feed()} `, {   from: 'javascript',   to: 'meowscript' });  console.log(output);  // stdout: // meow kitty = MEW Kitty(); meeow (kitty.isHungry()) {kitty.feed()} 

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

Фактически, с этим набором инструментов можно создавать произвольные подмножества javascript в течении нескольких минут. Единственное ограничение — неспособность модуля находить стандартные интерфейсы ноды или браузера. Так что увы, document.body.getBoundingClientRect, господа. Добавить поддержку транспиляции интерфесов тоже не так сложно, нужно всего лишь определить правила следования identifiers и осуществлять замену согласно им.

Напоследок, картинка в хедере поста неслучайна, как пример использвания your-script, я написал redscript — русское подмножество javascript. Ну и как следствие использования настоящего парсера:

var стр = 'var';

будет корректно транспилировано в:

пусть стр = 'var';

Сам модуль валяется в npm. Для затравки, пример транспилированной программы:

функция функ(икс, игрек, зет) {                              примем и = 0;                                   примем икс = {0: "ноль", 1: "один"};               примем функ = функция () {                       }                                               если (!и > 10) {                                    для (примем j = 0; j < 10; j++) {                   переключатель (j) {                                 положение 0:                                        значение = "zero";                                 стоп;                                       положение 1:                                        значение = "one";                                  стоп;                                   }                                               примем с = джей > 5 ? "ГТ 5" : "ЛЕ 5";         }                                           } иначе {                                           примем джей = 0;                                   попробуй {                                          пока (джей < 10) {                                     если (и == джей || джей > 5) {                            a[джей] = и + джей * 12;                          }                                               и = (джей << 2) & 4;                               джей++;                                        }                                               делай {                                             джей--;                                        } пока (джей > 0)                              } лови (e) {                                        alert("Крах: " + e.message);             } затем {                                           обнулить(a, и);                                }                                           }                                           }              

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

лови (крах) {   КрахДетектор(крах); }

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

ссылка на оригинал статьи https://habrahabr.ru/post/283108/

Подростки признали зависимость от смартфонов

Автор статьи в CNN на тему опроса о зависимости подростков от планшетов пишет, что волнуется, когда у её детей восьми и десяти лет появятся собственные устройства. Мне становится ещё страшнее, потому что у моей двухлетней дочери уже есть собственные 13,3-дюймовый планшет и 11,6-дюймовый ноутбук, которыми она пользуется без посторонней помощи.

Половина американских подростков признают зависимость от смартфонов, при этом в такой зависимости своих детей уверены 59% родителей. Каждый день конфликты на тему девайсов возникают у 32% подростков в возрасте от 12 до 18 лет.

image

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

В 2011 году обзор 18 исследований на тему цифровой зависимости выявил, что среди подростков и студентов колледжей до 26% интернет-зависимых. Но если в Китае эту зависимость уже рассматривают как угрозу здоровья нации и лечат в специальных учреждениях военного типа, в США подобной практики нет.

Некоммерческая организация Common Sense Media провела опрос с участием 1240 родителей и подростков в возрасте от 12 до 18 лет и опубликовала его результаты.

80% детей проверяют смартфон каждый час, 72% чувствуют необходимость немедленно ответить на смс и сообщения в социальных сетях. 77% родителей чувствуют, что мобильные устройства слишком сильно отвлекают внимание их детей даже во время разговоров. А это приводит к семейным ссорам: в ежедневных конфликтах признаются 32% детей и 36% родителей. И треть опрошенных подростков рассказали, что они самостоятельно пытались сократить время, которые они тратят на устройства.

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

У 66% опрошенных семей есть правило: не пользоваться смартфонами и планшетами за обеденным столом. 36% подростков признают, что нарушают это правило, а 32% говорят, что его нарушают их родители.

image
Инфографика кликабельна

Ваши дети пользуются мобильными устройствами?

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

Мобильные устройства становятся причиной конфликтов в семье?

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

Вы пользуетесь смартфоном за рулём для ответов на SMS или сообщения в соцсетях?

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

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

ссылка на оригинал статьи https://geektimes.ru/post/275462/

Swift и время компиляции

Пост основан на статье medium.com/@RobertGummesson/regarding-swift-build-time-optimizations-fc92cdd91e31 + небольшие изменения/дополнения, то есть текст идет от моего лица, не третьего.

Всем знакома ситуация после изменения файла(ов) или просто переоткрытия проекта:


Нужно сказать, что какой-то особой проблемы с компиляцией я не замечал когда писал на Objective-C, но всё изменилось с приходом в массы swift. Я частично отвечал за CI сервер по сборке iOS проектов. Так вот, проекты на swift собирались невыносимо медленно. Еще разработчики любят тащить поды (cocoapods зависимости) на каждый чих в свои swift проекты, иногда, в безумном количестве. Так вот, компиляция всей этой смеси могла продолжаться несколько минут, хотя сам проект состоял буквально из пары десятков классов. Ну ладно, как бы ясно, язык новый, на этапе компиляции происходит намного больше проверок, чем в том же ObjC, глупо ожидать, что она будет работать быстрее (да, swift это строго типизированный язык и всё должно быть максимально явно объявлено (как в Java, например), в отличии от ObjC, где не всё так строго). Разработчики swift с каждым релизом обещают в x раз ускорения скорости компиляции. Ну вроде, действительно, сборка 2.0 и уже потом 2.2 стала работать быстрее, вот вот на носу уже 3.0 версия (конец года).

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

time swiftc -Onone file.swift 

Список того, что может замедлить ваш компилятор

Неосторожное использование Nil Coalescing Operator

func defIfNil(string: String?) -> String { 	return string ?? "default value" } 

Оператор ?? разворачивает Optional, если там что-то есть, то возвращает значение иначе выполняется выражение после ??. Если связать подряд несколько этих операторов, то можем получить увеличение времени компиляции на порядок (не ошибся, на порядок 🙂 ).

// Без оператора компиляция занимает 0,09 секунд func fn() -> Int {          let a: Int? = nil     let b: Int? = nil     let c: Int? = nil          var res: Int = 999          if let a = a {         res += a     }          if let b = b {         res += b     }          if let c = c {         res += c     }          return res }   
// С операторами 3,65 секунд func fn() -> Int {          let a: Int? = nil     let b: Int? = nil     let c: Int? = nil          return 999 + (a ?? 0) + (b ?? 0) + (c ?? 0) } 

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

return 999 + (a ?? 0) + (b ?? 0) 

уже будет ок.

Объединение массивов

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

res = ar1.filter { ... } + ar2.map { ... } + ar3.flatMap { ... } 

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

// Время 0,15 секунд func fn() -> [Int] {     let ar1 = (1...50).map { $0 }.filter { $0 % 2 == 0 }     let ar2 = [4, 8, 15, 16, 23, 42].map { $0 * 2 }          var ar3 = (1..<20).map { $0 }          ar3.appendContentsOf(ar1)     ar3.appendContentsOf(ar2)          return ar3 } 
// Время 2,86 секунд func fn() -> [Int] {     let ar1 = (1...50).map { $0 }     let ar2 = [4, 8, 15, 16, 23, 42]          return (1..<20).map { $0 } + ar1.filter { $0 % 2 == 0 } + ar2.map { $0 * 2 } } 

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

return ar1.filter { $0 % 2 == 0 } + ar2.map { $0 * 2 } 

уже ок.

Ternary operator

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

// Build time: 0,24 секунды let labelNames = type == 0 ? (1...5).map{type0ToString($0)} : (0...2).map{type1ToString($0)}  // Build time: 0,017 секунд var labelNames: [String] if type == 0 {     labelNames = (1...5).map{type0ToString($0)} } else {     labelNames = (0...2).map{type1ToString($0)} } 

Избыточные касты

Тут автор просто убрал лишние касты в CGFloat и получил существенную скорость в компиляции файла:

// Build time: 3,43 секунды return CGFloat(M_PI) * (CGFloat((hour + hourDelta + CGFloat(minute + minuteDelta) / 60) * 5) - 15) * unit / 180  // Build time: 0,003 секунды return CGFloat(M_PI) * ((hour + hourDelta + (minute + minuteDelta) / 60) * 5 - 15) * unit / 180 

Сложные выражения

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

// Build time: 1,43 секунды let expansion = a - b - c + round(d * 0.66) + e  // Build time: 0,035 секунд let expansion = a - b - c + d * 0.66 + e 

Правда тут автор оригинально поста так и не понял почему так.


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

пс.

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

ссылка на оригинал статьи https://habrahabr.ru/post/283106/

Различные опыты с приемом и передачей радиосигналов в ПЛИС


Поскольку сегодня, 7-го мая, мы отмечаем День Радио, то позвольте представить вашему вниманию серию проектов для FPGA плат, которые были выполнены мной в разное время, но так или иначе связаны с радио. На этом видео выше есть демонстрация маленького чуда — сеанс радиосвязи на столе. Две одинаковые платы с ПЛИС служат одна передатчиком, а другая радиоприемником.
Далее расскажу, как я это сделал.


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

Несущая частота, как синусоидальное колебание, задана в виде таблицы в ПЛИС, звуковой файл передается в плату из ноутбука через последовательный порт со скоростью 230400 бод, что примерно соответствует обычной звуковой дорожке 22050 samples/sec, 8 бит, моно. Два сигнала: несущая частота и звуковой сигнал перемножаются и происходит перенос спектра в область высоких частот, плюс еще несущая. Потом этот цифровой сигнал отправляется на аналогово-цифровой преобразователь, в нашем случае — это простейший R2R DAC — и затем на антенну. Антенна — несколько витков провода и конденсатор. Они подобраны примерно так, чтобы резонансная частота этого колебательного контура была в районе несущей частоты. Обычный бытовой приемник может принимать такой радиосигнал на расстоянии нескольких метров. Несущая частота оригинального проекта 1,5МГц, но лучше взять чуть повыше — 7МГц.

Полное описание проекта и исходные текста всех программ и проекта для ПЛИС Altera Cyclone III для платы Марсоход2 можно взять вот здесь: marsohod.org/projects/marsohod2/298-am-radio-transmitter

Радиоприемник — это гораздо более сложная штука.
Я сделал его так же на основе платы Марсоход2, но я взял за основу другой проект "Простой SDR приемник на ПЛИС" автора iliasam. Большое ему спасибо за замечательную эту статью.

Проект выполнен по вот такой структурной схеме:

Мой ПЛИС проект имеет несколько отличий от оригинального:

  • для связи с ПК используется не ethernet, а последовательный порт, 12Мбод, это проще;
  • используется АЦП платы Марсоход2 20MSamples/sec, всего 8бит, то есть разрядности в вычислениях и разрядности фильтров в проекте получаются другие;
  • корректирующий FIR фильтр перерасcчитан на меньшее число тапов (21), так как немного не хватает умножителей в ПЛИС Cyclone III;
  • используются 32-х битные (вместо 16-ти битных) выборки каналов I/Q, которые передаются в программу HDSDR — это значительно улучшает свойства приемника.

Подробнее о проекте написано вот здесь.
Исходники можно взять на github github.com/marsohod4you/FPGA_SDR.

Есть еще один мой проект: FM радиопередатчик из той же самой платы Марсоход2.
Это вообще один из моих самых любимых проектов!

FM диапазон находится на частотах выше 80МГц, так что даже для ПЛИС манипулировать данными на таких частотах не очень просто.

Для имитации FM модулированного сигнала в ПЛИС был реализован вот такой модулятор:

Это 5 соединенных последовательно триггеров, но имеющие обратную связь назад на 5 или 4 шага. После сброса схемы в триггерах движется по большому кругу единичный импульс. На выходе схемы получается частота в 5 раз меньше, чем тактовая. Если тактовая около 450МГц, то на выходе схемы будет 90МГц.
Иногда на схему можно подавать управляющие импульсы short — и тогда единичка будет двигаться в триггерах по малому кругу, а частота на выходе схемы значительно возрастет и будет 450/4~112МГц. Таким образом, можно добиться некоторой девиации средней частоты, если вставлять короткие периоды среди нескольких длинных. Например, 4 длинных периода и один короткий — коэффициент деления получится 4,8, то есть при тактовой 450МГц на выходе получится 93,73МГц.

Тогда FM передатчик получается вот таким:

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

Весь проект описан вот здесь, в наше блоге: marsohod.org/projects/marsohod2/246-fmradio

Ну вот, получается, одна плата Марсоход2 позволяет пощупать такие разные темы связанные с радиосвязью: АМ передача, SDR прием, FM передача.

Ну и еще раз: с Днем Радио!

ссылка на оригинал статьи https://habrahabr.ru/post/283104/

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

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

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

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

Зачем все это нужно

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

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

Реализация

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

Что было раньше

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

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

Тест с использованием «канареек»

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

У инженеров Instagram был набор готовых тестов, однако, он запускался только сотрудниками ИТ-департамента на их рабочих машинах. А значит, рецензентам (тем, кто выполняет code review) при определение успешности или неуспешности теста приходилось верить коллегам на слово. Кроме того были неизвестны результаты теста при развертывании коммита на боевой системе.

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

Для рефакторинга инженеры Facebook используют инструмент Phabricator и хорошо интегрирующуюся с ним систему Sandcastle. Их коллеги из Instagram также. воспользовались Sandcastle для запуска теста и получения отчетов.

Автоматизация

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

image

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

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

Проблемы

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

Ошибки тестирования

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

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

Накопление очереди изменений

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

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

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

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

Памятка по развертыванию от инженеров Instagram

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

  1. Тесты. Набор тестов должен быть быстрым. Охват тестов также должен быть обширным, однако здесь не обязательно пытаться объять необъятное. Тесты должны часто запускаться: при оценке кода, перед применением изменений (в идеале блокируя реализацию при ошибке), после реализации изменений.
  2. Тесты с использованием «канареек». Необходим автоматизированный тест с использованием «канареек» для предотвращения развертывания действительно плохих коммитов на всей инфраструктуре. Опять же, перфекционизм здесь не обязателен, даже простого набора статистических метрик и пороговых значений будет достаточно.
  3. Автоматизация обычного сценария. Не надо автоматизировать все, достаточно лишь стандартных и простых ситуаций. Если происходит что-то необычное, следует остановить автоматическое исполнение, чтобы в ситуацию могли вмешаться люди.
  4. Людям должно быть удобно. Одним из самых больших препятствий, возникающих в ходе подобных проектов по автоматизации, является тот факт, что люди перестают понимать, что происходит в текущий момент времени, и лишаются возможности контроля. Для решения этой проблемы, система должна обеспечивать хорошее понимание того, что сделано, что делается, и (в идеале) будет сделано на следующем шаге. Так же необходим хорошо работающий механизм экстренной остановки автоматического развертывания.
  5. Стоит ждать плохих развертываний. Не стоит надеяться на то, что все развертывания будут проходить без проблем. Ошибок не избежать, но это нормально. Главное уметь быстро находить проблемы и «откатывать» изменения до работающей версии.

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

Что инженеры Instagram планируют делать дальше

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

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

Другие технические статьи от «Латеры»:

ссылка на оригинал статьи https://habrahabr.ru/post/283102/