...

суббота, 11 июля 2015 г.

Перевод документации RivetsJS


Доброго времени суток, уважаемые хабровчане. Некоторое время назад, я познакомился с библиотекой RivetsJS. Она мне пришлась по вкусу, хотя содержит в себе только инструменты для data-binding. Сразу хочу сказать, что даже не собираюсь спорить, для этих вещей есть замечательные AngularJS и др. фреймворки, но лично я не вижу смысла подключать такой мощный инструмент, как Angular, если мне требуется только малая толика его возможности. Поэтому, для этих целей, я выбрал именно RivetsJS. И вот, воодушевленный идеей перевести его документацию на русский, я пишу эту статью. Мотив простой — рассказать об этой библиотеке, и я не нашел ничего лучше, чем просто перевести её документацию, которая, возможно только на мой взгляд, написана на немного «ломаном» английском. Итак, поехали.

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

Документация RivetsJS

Гайд

  • Установка
  • Использование
  • Биндинг
  • Форматеры
  • Компоненты
  • Адаптер
  • Свойства
  • Итерации биндинга

Справочник

  • text
  • html
  • show
  • hide
  • enabled
  • disabled
  • if
  • unless
  • value
  • checked
  • unchecked
  • on-[event]
  • each-[item]

Гайд


Установка

Вы можете скачать последнюю стабильную версию на GitHub, или установить используя менеджер пакетов по вашему выбору. В настоящее время мы поддерживаем релизы на на npm, component, jam, bower (рекомендуется).
bower install rivets

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

<script src="bower_components/sightglass/index.js"></script>
<script src="bower_components/rivets/dist/rivets.min.js"></script>

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

<script src="bower_components/rivets/dist/rivets.bundled.min.js"></script>

Примечание: CommonJS модуль и загрузчики скриптов AMD такие как RequireJS и almond полностью поддерживаются, если это вам потребуется.

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

Шаблоны

Шаблон формируют ваш UI в обычном HTML. Вы можете определить их непосредственно в документе, используя элементы шаблонизатора, или хранить и загружать их так, как вам нравится. Просто используйте удобный для вас способ вывода данных в шаблон.
<section id="auction">
  <h3>{ auction.product.name }</h3>
  <p>Текущая ставка: { auction.currentBid | money }</p>

  <aside rv-if="auction.timeLeft | lt 120">
    Поторопись! До окончания аукциона осталось { auction.timeLeft | time }.
  </aside>
</section>

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

(keypath | примитив) [Форматтеры...]

Keypath'ы получают данные наблюдения и пересматривают биндинг, когда происходят какие-либо изменения. Примитивами могут быть string, number, boolean, null или undefined.
Поподробнее о форматерах, о их свойствах и возможностях будет рассказано в соответствующей главе.

Биндинг

Просто вызовите rivets.bind на элементе в шаблоне и передайте ему те данные, которые надо вывести.
rivets.bind($('#auction'), {auction: auction})

При каждом вызове rivets.bind возвращается полный набор предстваления данных. Используйте view.unbind(), для того чтобы остановить событие биндинга.

Конфигурирование

Используйте rivets.configure чтобы задать настройки приложению. Учтите, что если потребуется, все настройки могут быть заменены локально на определенном представлении.
rivets.configure({
  // Префикс атрибута в представлении
  prefix: 'rv',

  // Предзагрузка шаблона с инициализации дата-байдинга.
  preloadData: true,

  // Root sightglass interface for keypaths
  rootInterface: '.',

  // Шаблонные разделители для встраивания в текст
  templateDelimiters: ['{', '}'],

  // Дополнительный обработчик событий on-* binder
  handler: function(target, event, binding) {
    this.call(target, event, binding.view.models)
  }
})

Биндеры

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

Односторонние биндеры обновляют DOM, когда свойства модели изменяются (только модель-вид). Скажем, нам нужен просто биндер, который обновляет цвет элемента, когда свойства модели меняются. Здесь мы можем определить односторонний биндер простым замыканием. Функция принимает элемент и текущее значение свойства модели, которое мы будем использовать для обновления свойства элемента.
rivets.binders.src = function(el, value) {
    var href = "/my/path/to/image/" + value
    el.setAttribute("src ", src);
}

rivets.binders.alt = function(el, value) {
    var alt = value
    el.setAttribute("alt", alt);
}

С определенными биндерами выше, вы можете использовать "rv-src" и “rv-alt” в вашем шаблоне.

<img rv-src="data.image" rv-alt=”data.title” />

Двусторонние биндеры

Двусторонние биндеры, как и односторонние, могут обновлять DOM, когда свойство модели меняется (модель-вид), но также может обновлять модель, когда пользователь взаимодействует с DOM (вид-модель), такие как обновление личного кабинета, введя данные для авторизации и нажав submit, или же взаимодействие со сторонними виджетами.
Для того, чтобы обновить модель, когда пользователь взаимодействует с DOM, вы должны сказать Rivets.js, как забиндить и разбиндить этот DOM элемента, чтобы установить значение в данной модели. Вместо объявления биндера как простой функции-замыкания, двусторонние биндеры объявляются как объекты, содержащие несколько дополнительных функций.
rivets.binders.toggle = {
  bind: function(el) {
    adapter = this.config.adapters[this.key.interface]
    model = this.model
    keypath = this.keypath

    this.callback = function() {
      value = adapter.read(model, keypath)
      adapter.publish(model, keypath, !value)
    }

    $(el).on('click', this.callback)
  },

  unbind: function(el) {
    $(el).off('click', this.callback)
  },

  routine: function(el, value) {
    $(el)[value ? 'addClass' : 'removeClass']('enabled')
  }
}


API

binder.bind
Данная функция вызывается для инициализации view.bind().Используйте её для хранения начального состояния биндинга, или чтобы назначить слушателей событий в элементе.

binder.unbind
Данная функция вызывается для инициализации view.unbind(). Используйте её, чтобы сбросить любое состояния элемента, который был бы изменен binder.routine, или отвязать любые слушатели событий на элемент, который вы установили в функции binder.bind.

binder.routine
Шаблонная функция вызывается когда наблюдаемый атрибут модели меняется и используется для обновления DOM. Когда объявляется односторонний биндинг как простая функция-замыкание, она на самом деле и является шаблонной функцией(routine function), которую вы определяете.

binder.publishes
Установите значение true, если хотите вызвать view.publish() и опубликовать эти биндинг.

Форматеры

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

Это, безусловно, наиболее распространенные и практичные способы использования форматирования — простые видоизменения значения только для чтения. В предоставленном примере ниже, мы можем определить форматер количества дней, оставшихся до окончания какого либо события. Допустим, до окончания события осталось 3ое суток.
rivets.formatters.remain = function(value){
  value = parseInt(value / 86400);
  return value;
}



Форматтеры применяются при объявлении биндинга, символ "|" применяется в качестве разделителя.
<span rv-text="event.endDate | remain"></span>

Двусторонние форматеры

Двусторонние форматеры полезны, когда вы хотите хранить значения в конкретном формате, например как стоимость в долларах, но одновременно дать возможность пользователю вводить данные в другом формате, например в рублях.
Вместо объявления форматера как простой функции-замыкания, вы можете объявить её как объект, содержащий функции read и publish. Когда форматер объявлен как простое замыкание, Rivets предполагает что это будет только для чтения, но когда форматтер объявлен как объект, Rivets использует функции read и publish для эффективной сериализации и обратной конвертации значений.
Скажем, мы хотим хранить денежное значение в долларах, но пусть пользователь вводит это значение в рублях, а форматтер автоматически конвертирует эти значения по стоимости на валютном рынке(опустим тот момент как эта стоимость туда подгружается) при занесении этого значения в модель. Как раз для этой цели, мы будем использовать двусторонний форматтер валют.
rivets.formatters.currency = {
  read: function(value) {
    return (value / 50)
  },
  publish: function(value) {
    return Math.round(parseInt(value) * 50)
  }
}

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

<input rv-value="item.price | currency">

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

Аргументы Форматеров

Форматеры могут принимать любое количество аргументов в виде keypath'ов и примитов.
Форматтеры могут разделять значения используя символ "|".
Аргументами форматтера могут быть keypath'ы и примитивы. Keypath'ы в качестве аргументов форматтера наследуют все свойства и возможносты обычных keypath'ов.
(Форматеры) [keypath | Примитив...]
<span>{ alarm.time | time user.timezone 'hh:mm' }</span>

Значение каждого аргумента в объявлении биндинга будет оцениваться и передается в функцию-форматер в качестве дополнительного аргумента.

rivets.formatters.time = function(value, timezone, format) {
  return moment(value).tz(timezone).format(format)
}

Компоненты

Компоненты позволяют вам определять многоразовые виды, которые могут быть использованы в любом из ваших шаблонов. Это полезно использовать там, где компоненты нужно встроить в ваш шаблон в связи с биндерами; Биндеры определяют ваши собственные атрибуты, в то время как компоненты определяются как собственные элементы.
Объект компонента должен быть определен как функция template, возвращающая шаблон для компонента(это может быть строка HTML, или другой необходимый элемент). Он также должен определять initialize функцию, которая возвращает специальный объект scope для биндинга в шаблон (данная функция имеет некую схожесть с MVC).
rivets.components['todo-item'] = {
  // Возвращает шаблон для компонента.
  template: function() {
    return JST['todos/todo-item']
  },

  // Берет оригинальный элемент и данные которые проходят через компонент
  // (Либо из rivets.init или атрибут элемента шаблона в компоненте.
  initialize: function(el, data) {
    return new ItemController({
      item: data.item
    })
  }
}

Чтобы использовать компонент внутри шаблона, просто используйте элемент с таким же названием тега как в ключе компонента. Все атрибуты элемента будут расценены как keypath'ы перед вставкой в функцию компонента initialize.

<todo-item item="myItem"></todo-item>

Дополнительно, если вы хотите чтобы определенный атрибут был статичен, вместо keypath'а вы можете задать ему свойство static.

rivets.components['todo-item'] = {
  static: ['list-style'],
  …
}

<todo-item item="myItem" list-style="condensed"></todo-item>

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

rivets.init('my-app', $('body'), {user: user})
rivets.init('todo-item', $('#modal-content'), {item: myItem})

Адаптеры

Rivets.js является агностиком по отношению к объектам и их описанию. Это делает его очень гибким, и он может подстраиваться и адаптироваться под разработку вместе с другими библиотеками и фрейморками, но это также значит, что вы должны сказать Rivet.js как он должен описывать те или иные объекты. Данная фича управляется библиотекой Sightglass.
Каждый адаптер определяется как уникальный интерфейс(одиночный символ), который используется для разделения ключей и keypath'ов. Интерфейсы, используемые в keypath'ах, определяют какой адаптер использовать для каждого промежуточного ключа.

user.address:city

В примере указанном выше, keypath использует адаптер "." для доступа к ключу address объекта user, и адаптер ":" для доступа к ключу city объекта address. Представьте на секунду, что address это нормальное, свойство объекта user указывающий на модель Backbone, но city на самом деле это атрибут модели Backbone, вы можете увидеть, насколько этот вид обозначения на самом деле лаконичен и выразителен.

Встроенный адаптер

Rivets.js поставляется с адаптером "." описывающим свойства простых Javascipt объектов. Данный адаптер уже реализован в ES5(ECMAScript 5), на примере Object.defineProperty. В будущем, данный адаптер будет реализован, используя исключительно Object.observe, как только браузеры начнут его поддерживать.
Если вам нужно использовать браузеры без поддержки ES5(
Создание адаптера.

Адаптеры определяются с помощью rivets.adapters с интерфейсами в качества имени свойства и объектом адаптера в качестве значения.
Следующий адаптер ":" работает и для моделей Backbone.js, и для модулей Stapes.js.
rivets.adapters[':'] = {
  observe: function(obj, keypath, callback) {
    obj.on('change:' + keypath, callback)
  },
  unobserve: function(obj, keypath, callback) {
    obj.off('change:' + keypath, callback)
  },
  get: function(obj, keypath) {
    return obj.get(keypath)
  },
  set: function(obj, keypath, value) {
    obj.set(keypath, value)
  }
}

Расчетные свойства

Расчетные свойства — это функции, которые получают данные на переоценку в случае когда одно или более зависимых свойств меняется. Объявляются расчетные свойства в Rivets.js довольно просто, просто разделите функцию от её зависимости с помощью знака "
<span rv-text="event.duration < start end"></span>

Обратите внимание, что зависимый keypath берется из целевого объекта, а не из контекста модели. Так для примера указанного выше, целевым является объект event, с зависимостями event.start и event.end.

Итерации биндинга.

Используйте rv-each-[item] биндер, который представлен в Rivets.js, для того чтобы вывести циклом все элементы массива и добавить связанные экземпляры этого элемента.
<ul>
  <li rv-each-todo="list.todos">
    <input type="checkbox" rv-checked="todo.done">
    <span>{ todo.summary }</span>
  </li>
<ul>

Справочник


text


Вывод текста в элемента
<h1 rv-text="user.name"></h1>


Вы также можете вывести текст, используя интерполяцию.
<p>{ user.name } is { user.age } years old.</p>


html


Вывод HTML содержимое в элемент.
<section rv-html="item.summary"></section>


show


Вывод элемента в зависимости от значения — если true, то вывод, если false, то скрыть.
<button rv-show="user.admin">Remove</button>


hide


Обратный атрибут rv-show, если значение установлено true, то скрыть, если false, то вывести.
<section rv-hide="feature.disabled"></section>


enabled


Атрибут, задающий активность элементам. True — элемент enabled, false — disabled.
<button rv-enabled="user.canVote">Upvote</button>


disabled


Атрибут обратный rv-enabled. True — disabled, false — enabled.
<button rv-disabled="user.suspended">Upvote</button>


if


Вставляет и биндит элемент, а также узлы(nodes) в DOM, когда значение равно true, и не выводит элементы когда значение расценено как false.
<section rv-if="item.editable"></section>


unless


Атрибут обратный rv-if.
<section rv-unless="item.locked"></section>


value


Устанавливает значение элемента, когда изменяется атрибут, и устанавливает значение связанного объекта, когда элемент input изменяется от пользовательского ввода (работает в обе стороны).
<input rv-value="item.name">


checked


Легко догадаться, предназначено для и . Устанавливает атрибут «checked», когда значение расценено как true, и убирает атрибут «checked», когда значение расценено как false. Также устанавливает значение связанного объекта, когда элемент чекбокс изменяется от пользовательского ввода(работает в обе стороны).
<input type="checkbox" rv-checked="item.enabled">


unchecked


Атрибут, обратный rv-checked.
<input type="checkbox" rv-unchecked="item.disabled">


on-[event]


Биндит слушателя событий на элемент, используя событие указанное в [event] и cвязанный объект(должен возвращать функцию) как обратный вызов (callback)
Примечание: Если конечное значение биндинга меняется на другую функцию, данный биндер автоматически разбиндит старый колбэк и забиндит нового слушателя событий на новую функцию.
<button rv-on-click="item.destroy">Remove</button>


each-[item]


Добавляет новый экземпляр элемента для каждого элемента в массиве. Каждый элемент связан с совершенно новым вложенным видом, который содержит дополнительное свойство, который указывает на текущий итерируемый элемент массива.
<ul>
  <li rv-each-todo="todos">
    <input type="checkbox" rv-checked="todo.done"> { todo.name }
  </li>
<ul>

P.S. Если к данной документации проявится интерес, я дополню её «живыми» примерами.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Конец — это только начало

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

В 2011 я, как кажется, не осознавал, что стартапом был не тот романтичный проект lovepinger, а стартапом был я сам, а точнее так: во мне случился не start, а reset, что привело к существенным изменениям в жизни.

Но, прежде чем начать, ремарка. Это четвертая попытка написать пост для хабра, потому как мне всегда чего-то не хватало, какой-то законченности, завершенности. Ее не было в 2012, в 2013 и год назад тоже не было. Но выбрасывать старые записи мне не хочется, и я решил частично их использовать в рубрике «Из блокнотика». Это может быть довольно интересно. Посему считайте так, что этот пост писался четыре года к ряду.

Сам проект Lovepinger я перестал поддерживать еще в 2012. Хотя количество зарегистрированных пользователей и превысило 25 тыс., их активность была не велика, а совпадений и вовсе было всего три штуки. Но просто так сдаваться не хотелось и верилось, если уж не в чудо, то как минимум в необходимость мобильного приложения. Бесплатного, разумеется.

Не буду вдаваться в объяснения (для этого нужно писать еще одну заметку), просто скажу, что выбор пал на Windows Phone, а значит – здравствуй C#.

Вы представляете, что такое для новичка C#? После поверхностного изучения JavaScript и PHP. С нуля. В тридцать лет. С экономическим и юридическим образованием. Я вот не представлял, совсем не представлял.

Из блокнотика, 2012 год, где-то зимой.

Решено. Качаем Visual Studio, SDK под Windows Phone. Заказываем пару книг по C#.

Вот так я ее впервые и увидел, мою Шарли (C#). После Скарлет (JavaScript), Шарли казалось строгой и до безобразия привередливой, ведь у нее непременно все должно быть classно. Пусть даже мелочь ты делаешь – делай это classно. Она как жесткая супруга, для которой главная ценность – семья (логика), а муж есть тот, кто ценность эту должен охранять.

Шарли оказалась полным антиподом Скарлет: она не терпит беспорядка; у нее все на своих местах; с ней общаться нужно только трезвым. И с ней мне было несоизмеримо сложней, трудней и утомительней. А когда она открыла мне reflection, хотелось просто застрелиться.

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

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

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

К моменту публикации приложения в магазине Microsoft, я был уже не в России. Я уехал, еще в начале 2012.

Ощущение того, что ты занят чем-то не тем и где-то не там, не покидало меня, наверное, год, тот год, что я занимался Lovepinger. И к его (проекта) завершению я был уже готов, готов на все плюнуть и изменить свою жизнь (я слукавлю, если не упомяну, что сильное влияние на мое решение оказало и то, что в 2011 стало понятно, кто будет следующий президент в РФ)

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

Уезжая, я иллюзий не питал. В Европе российское экономическое и тем паче юридическое образование, как бы это помягче сказать, бесполезно. Иные законы, иные подходы, иные стандарты. Я прекрасно понимал, что единственный способ самореализации – это двигаться в сторону web-разработки. И я был готов к этому: готов не спать ночами; готов читать порой невыносимо нудные книжки; готов учиться, пробовать, ошибаться и снова учиться. Но…

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

Из блокнотика, 2012 год, осень.

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

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

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

После приложения для lovepinger к середине 2012 я сделал и другое – int.SMS, все под ту же платформу. Это был менеджер sms-сообщений с возможностью их отправки через мой шлюз, что как бы подразумевало существенно более низкую стоимость сообщения. Стоимость действительно на тот момент была примерно в три, четыре раза ниже среднерыночной (для роуминга, на постоянных пользователей которого и делалась ставка).

То, что проект оказался не таким провальным, как lovepinger, а придуманные мною решения по интерфейсу удачными, подтвердил тот факт, что через 2-3 месяца после выхода int.SMS «сломали», а «раскупоренная» версия приложения красовалась на 4pda. Война с администрацией этого сайта ни к чему не привела – копии как лежали, так и лежат.

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

Окончательно расставшись (на время) с мыслью, что Сергею Брину в ближайшее время руку мне не пожать, я пришел к мысли, что свою руку надо бы набивать как можно большим количеством практики. Ставку я сделал на web-разработку и… ну и понеслась: фабрика библиотек (JavaScript); модуль по работе с CSS анимацией, с анимацией в canvas; свой собственный WYSIWYG редактор (JavaScript); загрузчик ресурсов (JavaScript, PHP, C#) и много-много чего еще. Я просто брал и выдумывал себе задачу, а затем решал. И снова выдумывал. И снова решал. Собственно, так и прошел почти весь 2013 год.

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

Из блокнотика, 2013 год, лето.

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

Но кроме всей этой романтики, иногда возникает желание кушать. А деньги от всего проданного стремительно кончались. Где-то в середине 2013 года я создал свое первое резюме разработчика. Смотрелось скудновато, кто ж тут спорит, но то лишь начало. Через 3 месяца муссирования HR сайтов и кадровых агентств – bingo! Я нашел свою первую работу в Европе.

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

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

Из блокнотика, 2013 год, осень.

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

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

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

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

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

Завести учетную запись в уютной жжшке, скажете вы? Ну, да, вариант. Но не интересно.

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

Продать не получилось.

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

Вообще за несколько лет на примерах разных магазинов ПО (будь то Microsoft MarketPlace или тот же ThemeForset) я осознал насколько же бесправна профессия программиста, разработчика, дизайнера, всех кто решается устраивать свою жизнь сам, а не через работодателя. Как юрист, я насчитал десятки нарушений положений по честной конкуренции и защите прав производителя (не потребителя). Самым ярким из которых, был ответ от EnvatoMarket, где я пытался разместить свой plugin. Близко к тексту и по-русски: «Ваш плагин во многом повторяет функциональность уже имеющихся в нашем магазине». Трудно представить себе продуктовый магазин, где был бы лишь один вид молока, одной марки; а вот в мире EnvatoMarket только такие магазины и есть.

Быть может, когда-нибудь, подам на кого-нибудь в суд, хорошенько подготовившись).

Из блокнотика, 2012 год, глубокая осень.

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

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

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

Из блокнотика, 2014 год, лето.

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

В общем спустя полтора или два месяца с момента первых экспериментов с этой CMS, я занялся разработкой своего небольшого framework’a для WordPress, чтобы хоть как-то структурировать код и не запутаться в «расползающейся» логике. Критерий был до неприличия прост: отделить данные от логики, логику от представления, то есть приблизиться к MVC. И, полагаю, у меня что-то из этого получилось, ведь несмотря на то, что шаблон включает в себя более полутора тысяч файлов, я прекрасно понимаю, что и где лежит, и легко дополняю нужным функционалом сам движок. А сделал я не так уж и много: ввел понятие провайдера данных (контролер, отвечающий за доставку данных из базы данных и их обработку); разработал элемент «компонент» (специфический функционал, подключаемый только по необходимости) и сделал контролер представлений (полностью отделив логику от разметки, что позволило прийти к использованию «чистых» html файлов взамен php шаблонов и раскидать описание стилей для каждого элемента по отдельным файлам (css)).

Из блокнотика, 2014 год, осень.

Мне вот интересно, почему подавляющее число разработчиков для WordPress непременно запихивают все стили в один файл, получая таблицу стилей на 10 тысяч строк? А как потом искать, как править? Почему нельзя собрать в один файл из многих, сохранить на сервере и передавать клиенту, а при обновлении какой-то части – просто пересобрать этот, скажем, результирующий файл? Или почему нельзя написать двадцать строк JavaScript и 10 строк PHP и сохранять ресурсы в localStorage оттуда же их подгружая при повторном открытии страницы?

Вообще я должен честно сказать, я никогда так много не работал. Будучи «по ту сторону баррикад» (выражение из первого поста) продолжительность моего рабочего дня в среднем была около 10 часов (да, некоторые директора так работают). Плюс, почти всегда один из выходных (часов на 6-7) тоже жертвовался для работы. Но, понимаете в чем соль – я не уставал. Я мог запариться, заколебаться, задолбаться в конце концов, но вряд ли устать.

Тут же совсем иное дело. Разработчик – это, как я теперь понимаю, довольно непросто, особенно если ты ищешь решение. Не копи-пастишь, как модно говорить, «лучшие практики», а разбираешься, пытаешься понять все до последнего if и else. 5-6 часов сна – это нормально. 7 – это праздник. Но… усталость эта, она в кайф, она приятная, ибо ты делаешь то, что тебе по душе, то чем ты, как оказалось, всю жизнь хотел заниматься, но не решался себе в этом признаться.

* * *

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

  • Не слушайтесь никого, слушайтесь только себя и верьте только себе и только в свои силы. Эту жизнь живете вы и как бы это эгоистично не звучало, проживать ее надо для себя в первую очередь. Даже в падающем самолете инструкция нас учит – думай вначале о себе, а потом уж о других. И, да, «никого» значит никого; исключений нет.
  • Чем сложнее цель вы себе выбираете, тем больше на пути к ней будет спотыканий, падений и неудач – тут прямая корреляция. Все что нужно, просто легче к этому относиться и ехидно улыбаться судьбе в глаза.
  • Если вы решились на какие-то серьезные перемены в жизни, то идти придется до самого конца. Назад пути, как правило нет. Если же путь назад есть, то это не серьезные перемены)
  • Вы обязательно встретите двух опасных врагов – лень и уныние. Они меж собой тесно связаны, порождая друг друга и питаясь неудачами. Но лучшие оружие против них – мечта и вера в себя, а еще, иногда, бутылочка хорошего вина. Сюда же я бы посоветовал почитать эссе Альберта Эйнштейна «Наука и религия» (вроде 1930 года или 1932 года).
  • Самая лучшая книга из всех (не считая книг Стивена Хокинга), что я на данный момент прочитал – М.Фаулер, «Рефакторинг. Улучшение существующего кода». И пусть вас не смущает, что она десятилетней давности – эта книга не о программировании, эта книга о проектировании. Тут я повторюсь, но это важно. Учится надо по книжкам, а не статьям и уж тем более видео-курсам с youtube.
  • Не бывает неудобного времени что-то начать, равно как и не бывает удобного. Однако, «завтра» всегда будет сложнее чем «сегодня».
  • Если вы знаток PHP и JavaScript, то изучение ООП языка (того же C# или Java) будет вам на пользу хотя бы потому, что вы будете писать совершенно иной код на вашем любимом PHP и JavaScript.

Большое спасибо, тем кто прочитал, надеюсь не скучали. Удачи, света и тепла.

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

P.P.S.
Обращаю ваше внимание, что написанное выше – есть описание моего собственного опыта, а значит и те выводы, что сделаны мною априори субъективны.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

[Из песочницы] Генерация и решение лабиринта с помощью метода поиска в глубину по графу

image

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

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

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

Описание алгоритма

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

1. Сделайте начальную клетку текущей и отметьте ее как посещенную.
2. Пока есть непосещенные клетки
  1. Если текущая клетка имеет непосещенных «соседей»
    1. Протолкните текущую клетку в стек
    2. Выберите случайную клетку из соседних
    3. Уберите стенку между текущей клеткой и выбранной
    4. Сделайте выбранную клетку текущей и отметьте ее как посещенную.
  2. Иначе если стек не пуст
    1. Выдерните клетку из стека
    2. Сделайте ее текущей
  3. Иначе
    1. Выберите случайную непосещенную клетку, сделайте ее текущей и отметьте как посещенную.

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

Реализация

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

 0.    image

 1.    image  < — Выбираем начальную точку стартовой.

 2.1. image  < — Перемещаемся к случайному непосещенному соседу, пока таковые есть.

 2.2. image  < — Непосещенных соседей нет. Возвращаемся назад по стеку, пока нет непосещенных соседей.

 2.1. image  < — Непосещенные соседи есть. Перемещаемся к случайному непосещенному соседу.

 2.    image  < — Нет непосещенных клеток. Лабиринт сгенерирован.

Программный код

Приступаем к самому интересному.

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

int maze[height][width]; //создаем матрицу - двумерный массив
for(i = 0; i < height; i++){
        for(j = 0; j < width; j++){
            if((i % 2 != 0  && j % 2 != 0) && //если ячейка нечетная по x и y, 
               (i < height-1 && j < width-1))   //и при этом находится в пределах стен лабиринта
                   maze[i][j] = CELL;       //то это КЛЕТКА
            else maze[i][j] = WALL;           //в остальных случаях это СТЕНА.
        }
    }


Теперь, когда все приготовления сделаны, можно приступать к генерации.
typedef struct cell{ //структура, хранящая координаты клетки в матрице
    unsigned int x;
    unsigned int y;
} cell;

typedef struct cellString{ 
    cell* cells;
    unsigned int size;
} cellString;


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

Отрывок кода, отвечающий за генерацию:

cell startCell = {1, 1}
cell currentCell = startCell;
cell neighbourCell;
do{
    cellString Neighbours = getNeighbours(width, height, maze, startPoint, 2);
    if(Neighbours.size != 0){ //если у клетки есть непосещенные соседи
        randNum  = randomRange(0, Neighbours.size-1);
        neighbourCell = cellStringNeighbours.cells[randNum]; //выбираем случайного соседа
        push(d.startPoint); //заносим текущую точку в стек
        maze = removeWall(currentCell, neighbourCell, maze); //убираем стену между текущей и сосендней точками
        currentCell = neighbourCell; //делаем соседнюю точку текущей и отмечаем ее посещенной
        maze = setMode(d.startPoint, d.maze, VISITED);
        free(cellStringNeighbours.cells);
    }
    else if(stackSize > 0){ //если нет соседей, возвращаемся на предыдущую точку
        startPoint = pop();
    }
    else{ //если нет соседей и точек в стеке, но не все точки посещены, выбираем случайную из непосещенных
        cellString cellStringUnvisited = getUnvisitedCells(width, height, maze);
        randNum = randomRange(0, cellStringUnvisited.size-1);
        currentCell = cellStringUnvisited.cells[randNum];
        free(cellStringUnvisited.cells);
    }
while(unvisitedCount() > 0);


Как видно, реализация алгоритма проста и абстрактна от теории, как говорится, «справится даже ребенок».
Чтобы не перегружать статью, код функций, используемых в вышеприведенном отрывке, под спойлером.
Код функций
Функция getNeighbours возвращает массив непосещенных соседей клетки
cellString getNeighbours(unsigned int width, unsigned int height, int** maze, cell c){
    unsigned int i;
    unsigned int x = c.x;
    unsigned int y = c.y;
    cell up = {x, y - distance};
    cell rt = {x + distance, y};
    cell dw = {x, y + distance};
    cell lt = {x - distance, y};
    cell d[4]  = {dw, rt, up, lt};
    unsigned int size = 0;

    cellString cells;
    cells.cells = malloc(4 * sizeof(cell));

    for(i = 0; i < 4; i++){ //для каждого направдения
        if(d[i].x > 0 && d[i].x < width && d[i].y > 0 && d[i].y < height){ //если не выходит за границы лабиринта
            unsigned int mazeCellCurrent = maze[d[i].y][d[i].x];
            cell     cellCurrent     = d[i];
            if(mazeCellCurrent != WALL && mazeCellCurrent != VISITED){ //и не посещена\является стеной
                cells.cells[size] = cellCurrent; //записать в массив;
                size++;
            }
        }
    }
    cells.size = size;
    return cells;


Функция removeWall убирает стенку между двумя клетками:
mazeMatrix removeWall(cell first, cell second, int** maze){
    short int xDiff = second.x - first.x;
    short int yDiff = second.y - first.y;
    short int addX, addY;
    cell target;

    addX = (xDiff != 0) ? (xDiff / abs(xDiff)) : 0;
    addY = (yDiff != 0) ? (yDiff / abs(yDiff)) : 0;

    target.x = first.x + addX; //координаты стенки
    target.y = first.y + addY;

    maze[target.y][target.x] = VISITED;
    return maze;
}


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

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

Так как мы точно знаем, что вектор разности между координатами стенки и первой точке равен либо (|1|, 0) либо (0, |1|), мы можем этим воспользоваться.

Таким образом, аддитив для x координаты при xDiff != 0 будет равен xDiff / |xDiff|, при xDiff = 0, нулю. Для y соответственно.
Получив аддитивы для x и y, мы легко вычисляем координаты стенки между первой и второй клетками и назначаем клетку по этим координатам посещенной.


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

В итоге, мы можем получить что-то такое:

Лабиринты. Осторожно, трафик!
  100x100
image
  500x500
image

Генерация работает, теперь дело за малым: найти в таком лабиринте выход.

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

И все еще сильнее упрощается, так как нам больше не надо убирать стенки.

Алгоритм поиска пути бэктрекингом:
1. Сделайте начальную клетку текущей и отметьте ее как посещенную.
2. Пока не найден выход
  1. Если текущая клетка имеет непосещенных «соседей»
    1. Протолкните текущую клетку в стек
    2. Выберите случайную клетку из соседних
    3. Сделайте выбранную клетку текущей и отметьте ее как посещенную.
  2. Иначе если стек не пуст
    1. Выдерните клетку из стека
    2. Сделайте ее текущей
  3. Иначе выхода нет

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

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

Посмотрим что вышло:

Решенные лабиринты. Траффик!

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

Для тех, кто заинтересовался, полный исходный код проекта на GitHub: Maze Generator and Solver (offscreen rendering)

Внимание!
OSMesa не поддерживается некоторыми драйверами на unix-based, а на Windows не поддерживается совсем, так что желающим, кому не повезло с ОС/железом, могу предложить ознакомиться со смежным проектом: Maze Generator and Solver
В обоих проектах реализованы одни и те же алгоритмы, но первый рисует в памяти и выводит последовательность png-изображений, а второй на экране.
Сборка cd build && ../configure && make, если неудобно, в папке src есть файл-проект QtCreator'a.

Источники

1. Walter D. Pullen: Think Labyrinth.
2. Wikipedia: Maze generation algorithm.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

[Перевод] Сборщик мусора в Go: решение проблемы отзывчивости в Go 1.5

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

Ричард Л. Хадсон (Рик) знаменит по своим работам в управлении памятью, включая изобретение алгоритмов Train, Sapphire и Mississippi Delta, а так же GC stack maps, которые позволили реализовать сборку мусора в статически-типизированных языках вроде Java, C# и Go. Под его авторством были опубликованы документы о рантаймах языков, управлении памятью, многопоточности, синхронизации, моделей памяти и транзакционной памяти. Сейчас Рик является одним из членов команды Go в Google и работает над проблемами сборщика мусора и рантайма.


В экономике существует понятие “замкнутого цикла”, когда один процесс усиливает другой, что приводит к усилению первого. Исторически, в мире компьютеров такой “замкнутый цикл” был между развитием железа и софта. Процессоры становились быстрее, что способствовало написанию более мощного софта, что, в свою очередь, стимулировало дальнейшее повышение скорости процессоров и мощностей компьютера в целом. Этот цикл работал примерно до 2004-го, когда Закон Мура перестал работать.

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

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

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

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

Но Расс Кокс, почему-то, эти идеи завалил на корню, и они решили закатать рукава и на самом деле улучшить сборщик мусора в Go. Они пришли к алгоритму, который уменьшает паузы GC, но делает программу чуточку медленнее. Программы на Go станут чуть медленнее в обмен на гарантированно низкие паузы фаз сборки мусора.

Какие задержки мы можем различать?

  • Наносекунда: Грейс Хоппер сравнила время с дистанцией. Наносекунда — это 11.8 дюймов.
  • Микросекунда: 5.4 микросекунд это время, за которое свет проходит 1 милю в вакууме.
  • Миллисекунды:
    • 1: Последовательное чтение 1МБ с SSD.
    • 20: Чтение 1МБ с вращающегося диска.
    • 50: Порог восприятия (порог реакции)
    • 50+: Различные задержки сети
    • 300: Моргание глаза

Так сколько работы по сборке мусора мы можем успеть в одну миллисекунду?

Java GC против Go GC


Go:

  • тысячи горутин
  • синхронизация через каналы
  • рантайм написан на Go, используя его особенности, как и обычный код
  • контроль пространственной локальности (можно встраивать структуры, внутренние указатели(&foo.field))

Java:

  • десятки потоков Java
  • синхронизация через объекты/локи
  • рантайм написан на C
  • объекты связаны через указатели

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

Основы сборщика мусора


Вот краткий пример работы сборщика мусора. Обычно, она состоит из двух фаз:

  1. Фаза сканирования: определить, какие вещи в куче достижимы. Сюда входят указатели в стеках, регистры, глобальные переменные, и далее, указатели в куче.
  2. Фаза маркировки: проход по графу указателей. Пометить объекты, как достижимые по ходу исполнения программы. С точки зрения сборщика мусора, проще всего “остановить мир”, чтобы указатели не изменялись во время этой фазы вообще. По-настоящему параллельный сборщик мусора сделать очень сложно, потому что указатели постоянно изменяются. Программа использует так называемые “барьеры на запись” (write barriers), чтобы сообщать сборщику мусора, что этот объект не нужно захватывать. На практике, правда, барьеры на запись могут давать результат даже хуже, чем “остановка мира”.

Сборщик мусора в Go


Новый алгоритм сборщика мусора Go использует комбинацию барьеров на запись и коротких пауз для “остановки мира”. Вот его фазы:

Вот как выглядела работа сборщика мусора в Go 1.4:

А вот как она выглядит в Go 1.5:

Заметьте, что паузы для “остановки мира” намного короче. Во время работы параллельного сборщика мусора, он использует 25% процессора.

Вот результаты тестов:

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

Если приблизить цифры, то видно, что всё ещё есть слабая позитивная корреляция между размером кучи и длительностью пауз GC. Но они знают, в чём причина и она будет устранена в Go 1.6.

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

Глядя в будущее


Сообщите людям, что паузы сборщика мусора больше не являются проблемой в Go. Глядя в будущее, они планируют затюнить сборщик мусора для достижения ещё более коротких пауз, большей производительности и большей предсказуемости. Они хотят найти оптимальное соотношение в этом компромисе. Разработка Go 1.6 будет зависеть от обратной связи, поэтому они очень ждут отзывов сообщества.

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

Дополнительно о сборщике мусора в Go


Go 1.5 concurrent garbage collector pacing
Go 1.4+ Garbage Collection (GC) Plan and Roadmap

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Три мысли для любителей Android по мотивам I/O 2015

В данной статье я хочу поделиться с сообществом тремя мыслями по мотивам Google I/O 2015, которые, на мой взгляд, могут быть очень полезными для всех любителей Android в этом году.

image


Я знаю, что многие разработчики и дизайнеры продолжают мыслить в терминах «у Android нет гайдлайнов». Прекратите! Они есть, они классные, и имя им — Material Design.

На Google I/O было сделано всё возможное для того, чтобы каждый из участников погрузился в мир Material Design и получил все необходимые знания для создания классных приложений в духе Material. Интересно отметить, что в этом году сама конференция была оформлена в стиле Material! А помимо докладов и дискуссий каждый желающий мог посетить специальную material-станцию и создать бумажный прототип своего приложения с использованием необходимых средств для творчества.

Ключевыми анонсами конференции стали:


image
(Эксперты помогают участникам конференции в постижении философии Material Design)

40% приложений, опубликованных в Google Play за прошедший год, сделаны в стиле Material Design. Если ваше приложение ещё не поддерживает Material Design, ваши шансы попасть в немилость пользователям стремительно растут с каждым днём. И наоборот, даже если у вашей идеи есть конкурент, но он сделан в старом стиле, то вы можете произвести успешную атаку на его позиции за счет поддержки Material Design. Кроме того, разработка приложений в стиле Material Design занимает меньше времени и проста в масштабировании между различными Android устройствами (от смартфона до автомобиля).

Если вы ещё не чувствуете себя экспертом в Material Design, то я крайне советую найти время, чтобы разобраться в теме!

Ещё по теме:


На мой взгляд, автоматическое тестирование — это самая интересная тема текущего года. Исторически автотесты являются больной темой для мобильных разработчиков, и в Android нам особо нечем было раньше похвастаться. Ситуация начала меняться 2-3 года назад, когда в дополнение к популярным, но ненадежным Android Instrumentation Framework и Robotium появились Robolectric и Espresso. Подробнее про возможности и особенности этих инструментов можно узнать в моем докладе «Автоматическое тестирование Android приложений с любовью» с MBLTDev 2014.

Ключевыми анонсами конференции стали:

  • Android Studio теперь поддерживает unit-тесты.
  • Android Testing Framework теперь поддерживает работу с JUnit4.
  • Espresso теперь является частью Android Open Source Project и будет активно развиваться в его рамках.
  • Эмулятор стал чуть быстрее, надежнее и будет активно улучшаться в этом направлении, что позволит достаточно просто создавать качественную тестовую инфраструктуру в облаках.
  • Google запускает Cloud Test Lab на основе приобретенного в прошлом году стартапа Appurify.

Если вы занимаетесь разработкой больших и сложных Android проектов, но не пишите тесты для них, то, на мой взгляд, 2015 год – это лучшее время для того, чтобы начать делать это. Сегодня у нас есть Espresso и Android Testing Support Library, есть специальная команда в Google, которая активно занимается их развитием и рада помогать разработчикам в освоении новых инструментов. Также совсем скоро у всех желающих будет доступ к Cloud Test Lab (в рамках Google Play Developer Console).

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

image
(если вы узнали как минимум трех людей на фото, то вы в теме тестирования под Android)

Ещё по теме:


На мой взгляд, Google отлично умеет организовывать сообщества вокруг своих продуктов и технологий. На Google I/O наиболее ярко были представлены три сообщества — Google Developer Experts (GDE), Google Developer Groups (GDG) и Women Tech Makers (WTM).

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

image
(весь мир GDG в одном фото, сделанном на GDG Summit, который прошел перед I/O)

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

Для тех, кому интересно изучать Android вместе, я советую узнать подробней про Google Developer Group и стать участником ближайших к вам мероприятий. А если вы чувствуете в себе силы помогать другим, то вам наверняка стоит попробовать себя в роли GDG организатора или стать GDE!

Ещё по теме:

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

[Перевод] Эволюция Go

image

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

Роберт Грисмер (@robertgriesemer) — разработчик в Google, один из авторов языка Go. В прошлом Роберт работал над генерацией кода для высокопроизводительного JavaScript, занимался языком программирования Sawzall и разработкой современной реализации Smalltalk — Strongtalk. По собственному заявлению, он «провел слишком много времени в виртуальных Java-машинах, но так и не понял, как ими пользоваться».

Интерес Роберта к языкам программирования возник при знакомстве с Pascal — до этого момента он в основном писал на BASIC. Будучи аспирантом, он обучался у Никлауса Вирта, создателя Pascal.

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

Истоки


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

Не составляло труда понять, что же не так с C++ — это был очень сложный, трудный для понимания язык, которому недоставало поддержки конкурентности, который не масштабировался и чье время сборки проектов было действительно большим. В Google стала общепринятой следующая процедура: если у кого-то возникала проблема с С++, то он отправлял email с просьбой о совете, и каждый прочитавший отвечал на него по-разному. В итоге, под конец дня гуру С++ из команды (который написал книгу по теме вопроса) давал окончательный ответ. Было очевидно, что такой процесс никуда не годился.

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

  1. Простота, безопасность, читабельность первостепенны. Однако, простота языка не означает, что созданный на нем продукт обязан быть простым — иногда это просто неосуществимое условие.
  2. Стремление к ортогональности в дизайне языка. Означало множество средств языка, которые бы не пересекались между собой и которые можно было бы проще комбинировать (combine) и составлять композиции (compose). Авторам хотелось, чтобы существовал только один путь написания конкретной конструкции.
  3. Минимализм: существует всего один способ написать некоторый кусок кода (для этого правила сейчас есть несколько исключений — например, определения переменных)
  4. Все дело в выразительности алгоритмов, а не в системе типов.
  5. Отсутствие желания приспосабливать язык к какому-либо одному способу использования (к примеру, разработчики не хотели делать написание lock-free алгоритмов суперпростым, потому что эта область интересует лишь немногих экспертов, в то время как большинство программистов на Go не должны о них беспокоиться).
  6. Коллективное осознание истории развития языков программирования.

Еще одним ключевым источником вдохновения стали две научные статьи Хоара (C.A.R. Hoare, Hints on Programming Language Design, Communicating Sequential Processes).

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

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


Оглядываясь назад, можно сказать, что многие из идей, пришедших в голову разработчикам в тот день, дожили до финального релиза Go:
  1. Синтаксис: нотация с ведущими ключевыми словами, большая «зачистка»
  2. Выражения: 5 уровней приоритета операций (вместо 14 в C++)
  3. Явно указанные размеры базовых типов, нет неявных преобразований
  4. Пакеты и импорты
  5. Методы с явным указанием параметра-получателя (receiver)

Многие из концептов потерялись по пути, однако, еще больше идей до воплощения не дожило. Критики Go любят замечать, что «в Go нет ничего нового», но они упускают то, что это является хорошим качеством для языка программирования. Цитируя Алана Кея, «большинство идей происходит из предшествующих идей»; Хоар в 1973 году выразился еще точнее: «Задача дизайнера языка программирования в консолидации идей, а не в инновациях».

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

image

История


Algol 60 (John Backus, John McCarthy, Alan Perlis, 1958-1960):
Точка отсчета для всего. Этот язык представлял собой сплав лучших идей, взятых из Fortran и Lisp. Передовой язык для своего времени. Хоар сказал про него, «Вот язык, настолько превосходящий свое время, что ему суждено стать лучшим не только относительно своих предшественников, но и потомков». В языке появились блочные структуры, вложенные и рекурсивные функции, объявления типов, инструкция «for», оператор возврата «return», разделенные точкой с запятой операторы, блоки «begin/end», «вызов по имени» и многое другое из того, что сегодня нам кажется существовавшим всегда.

Наследники Algol — C и Pascal — оказали прямое влияние на Go.

Pascal (N. Wirth, 1968-70):

BEGIN/END для блоков, точки с запятой как разделители, объявления слева-направо, структурированные типы данных, понятие предопределенных стандартных функций, создан для преподавания.

C (Ritchie, 1969-73):

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

В свою очередь, Pascal вдохновил Modula и Oberon, которые оказали существенное влияние на Go.

Modula, Modula-2 (Wirth, 1978-1980):

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

Oberon (Wirth, 1986):

Упрощенные модули. Попытка очистить Modula-2 до настолько маленького языка, насколько это возможно.

Object Oberon (Templ, 1989):

Диалект Оберона с классами и методами.

Oberon-2 (Wirth, 1991):

Переработанный Object Oberon; Oberon с методами на записях (структурах)

Сравните 2 сниппета кода на Oberon и на Go:

image
image

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

Объектная ориентация и дженерики


В 90-ых на языки программирования нашло «сумасшествие» систем типов:
  1. C++, Java, другие языки
  2. сложные OO системы типов
  3. сложные системы типов для дженериков

Также в это время происходит активное распространение динамически типизированных интерпретируемых языков (Perl, Python, Lua, Javascript, Ruby, Erlang).

В 00-ых начинает набирать ход реакционное движение: выясняется, что сложный объектно-ориентированный код тяжело читается; многие жалуются на то, что с того света вернулся «спагетти-код» времен 70-ых. У многих языков излишне загроможденная нотация (“public static void”). Кроме этого, до людей начинает доходить, что большие программы на динамически типизированных языках тяжело поддерживать.

Тем не менее, для нас было очевидным, что Go требуется некоторая поддержка объектной ориентации. В этом случае вдохновением послужил Smalltalk (Kay, Ingalls, Goldberg, 1972-80). В Smalltalk всё — объект; сообщение может быть послано любому объекту.

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

Конкурентность


Грамотная поддержка конкурентности планировалась с самых первых дней. Однако, по этой теме лучше может рассказать Роб Пайк, чем докладчик. Поэтому рекомендуется посмотреть доклады Пайка и почитать статьи:
  1. “Newsqueak” (Pike)
  2. “Communicating Sequential Processes” (Hoare)

Дженерики


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

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

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

Собирая все вместе


Спасибо Google: они предоставили авторам языка непозволительную роскошь, позволив им потратить 2 года на обкатку основ языка. Разработчики поступали принципиально: они добавляли только по одной функции языка за раз. Например, при добавления отображений (maps), авторы языка потратили несколько недель на обдумывание их дизайна и реализации. Это помогло добиться ортогонального дизайна, к которому так стремились создатели Go.

Трое отцов-основателей (Роберт, Роб и Кен) были людьми весьма своеобразными и непохожими друг на друга; поэтому не было ничего удивительно, что их дискуссии были очень острыми и часто достигали сурового эмоционального накала. Из-за этого местами все получалось не так хорошо, как хотелось бы. Но возможность иметь в одном проекте разные точки зрения сделало финальный продукт гораздо сильнее, в то время как присоединившийся позже Расс Кокс помог убрать весь мусор и собрать все воедино. Ян Ланс Тэйлор создал вторую реализацию компилятора (gccgo), о существовании которой никто не подозревал до момента ее выхода. Это было подтверждением успешного достижения целей, заложенных в дизайне языка с самого начала. Реализации разнились по мелочи, и это серьезно помогло для отладки оригинального компилятора и спецификаций языка. Теперь у разработчиков языка есть третий фронтенд к gcc (пакет go/types), который помогает с дальнейшей проверкой компиляторов и спецификаций. Как выяснилось, иметь 3 компилятора-фронтенда для gcc — это чрезвычайно полезная штука.

Эволюция Go


Go сильно менялся с течением времени — в частности, изменялись синтаксис и семантика языка. Полезным решением стала разработка стандартной библиотеки параллельно созданию языка — так разработчики смогли убедиться, что не занимаются бессмысленным проектированием. Утилиты gofmt (для изменений в языке) и gofix (для изменений в API) сослужили разработчикам хорошую службу в тех случаях, когда их желание что-то изменить требовало серьезного рефакторинга.

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

Будущее Go


Что делает язык программирования успешным?
  • Ясная цель (антипример — PL/1);
  • Комплексная и цельная реализация: язык, библиотеки, утилиты;
  • Готовность рынка. Верно выбранное время для выхода;
  • Технологический прорыв;
  • Языковые средства, отсутствующие у конкурентов. Lisp был первым языком, в котором была настоящая рекурсия и много других возможностей. Smalltalk был интерактивным, графическим, объектно-ориентированным и чрезвычайно простым.
  • Редко: маркетинг (бывает, что он помогает). Sun поставила все на Java. Java живет до сих пор, а Sun — мертва.

Что насчет Go?

  1. Авторы имели четкую цель в отношении дизайна языка
  2. Мультипарадигменность (императивный, функциональный, объектно-ориентированный)
  3. Синтаксическая легкость
  4. Средства языка, которых нет у конкурентов: горутины, интерфейсы, defer (теперь и в Swift)
  5. Утилиты, которых нет у конкурентов: быстрый компилятор, gofmt (который теперь пытаются скопировать в сообществах других языков), go build (отсутствие необходимости во внешнем описании или Makefile)
  6. Сильная стандартная библиотека
  7. Цельная реализация
  8. Отличная документация и онлайн-средства (Go playground)
  9. Отсутствие корпоративного маркетинга

Станет ли Go мейнстримом?

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

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

  1. build tags и другие специальный комментарии;
  2. специальные интерпретации путей импорта;
  3. внутренние пакеты;
  4. зависимости (с которыми разработчики пролетели, если бы не помощь сообщества)

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

Мысли напоследок (которые не следует воспринимать слишком серьезно)


  1. В 1960, языковые эксперты из США и Европы объединили свои усилия для создания Algol 60. (Роберт замечает, что комитет состоял целиком из людей, которые непосредственно занимались дизайном и реализацией языков программирования — в отличие от наших дней, когда в составе комитетов отдельных полно хватает людей, которые никогда ничем подобным даже не занимались)
  2. В 1970, дерево Algol разделилось на ветви C и Pascal. В некотором смысле, это были американская и европейская ветви.
  3. Во многих смыслах, язык отражает личность своего создателя и его национальность. “Однажды кто-то сказал Никлаусу Вирту, что ему показалось, что его язык (Pascal) отражает страну, в которой тот родился и вырос (Швейцарию). Этому человеку казалось, что языки Вирта стремились быть маленькими и компактными, и «не слишком-то свободными» (к примеру, в сравнении с C).”
  4. 40 лет спустя, 2 ветви развития объединяются в Go. (В команде Go был один человек из США, один — из Европы, и третий — из Канады, про которого Роберт в шутку назвал «нейтральным арбитром»)

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

image

Q & A


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

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

Q: Можете ли вы рассказать о процессе проектирования и разработки стандартной библиотеки?

A: В начале библиотека std строилась по образу и подобию других стандартных библиотек — в частности, на нее сильно повлияла std из Plan 9. К примеру, пакет fmt был вдохновлен именно Plan 9 (хотя там использовались другие команды), но само имя fmt пришло как раз оттуда. По большей части, разработка происходила стихийно, особенно на ранних стадиях, поэтому многое лишнее в стандартной библиотеке было со временем убрано; какого-то особенного дизайна за всем этим не стояло.

Q: Автоматический подсчет ссылок или GC?

A: В начале создатели языка думали об автоматическом подсчете ссылок как о лучшем варианте. Проблема в том, что этот способ плохо сочетается с конкурентностью; возможно, в этом вопросе могут помочь lock-free алгоритмы. Разработчики общались с Дэвидом Бэконом из IBM, который создал подобный GC под названием Metronome. Проблема в том, что даже если вы все сделаете правильно, в конце концов у вас все равно могут появиться циклические ссылки; и для сбора циклических ссылок вам придется написать GC, так что мы пошли путем выбора чистого GC.

Q: Большинство разработчиков использует Go для сервер-сайда. Собираетесь ли вы сделать Go более привлекательным для клиент-сайда?

A: Согласно оригинальному дизайну, Go не был обычным универсальным языком; это был системный язык программирования для сервер-сайда. Поэтому у нас нет пакета для создания UI. Теперь, когда мы движемся в сторону универсального языка, мы хотели бы создать такой пакет, однако это очень большой объем работы, т.к. необходимо делать его кроссплатформенным. В этом вопросе нужно будет прибегнуть к помощи экспертов из коммьюнити.

Q: Были ли попытки сделать Go языком более функциональным?

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

Q: Что вы думаете насчет маленьких языков, или DSL (предметно-специфичный язык)? Особенно, учитывая что Go — универсальный язык широкого профиля.

A: Авторы работали в Google над DSL под названием Sawzall. Наблюдения показали, что со временем DSL начинает использоваться не для тех целей, для которых он предназначался изначально; а когда вы начинаете добавлять в язык все новые возможности, он со временем в любом случае превращается в «большой» язык. DSL сейчас определенно играют важную роль, но авторы языка, что для Go этот вариант использования не подходит.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

В Adobe Flash Player обнаружена очередная критическая уязвимость

сегодня в 12:09

Компания Adobe выпустила второе за неделю уведомление безопасности APSA15-04, которое посвящено критической RCE уязвимости CVE-2015-5122. Как и ее предшественница, эта уязвимость позволяет удаленно исполнять код в популярных браузерах и обходить механизм sandbox. Эксплойт для этой уязвимости также находился в архиве с утекшими данными Hacking Team. Рабочая версия эксплойта уже размещена в сети тем же автором, который ранее публиковал эксплойт для CVE-2015-5119.

Существует серьезная опасность встраивания этого 0day эксплойта в популярные наборы эксплойтов для установки вредоносных программ на полностью обновленные up-to-date версии Windows, при чем это может быть сделано в самое ближайшее время. Эксплойт для прошлой 0day уязвимости Flash Player CVE-2015-5119 за несколько дней был адаптирован для использования сразу в шести наборах эксплойтов.

CVE-2015-5122 присутствует в версиях Flash Player для Windows, OS X и Linux. Компания собирается закрыть эту уязвимость завтра, 12 июля.


Рис. Часть кода эксплойта Flash Player, которая специализируется на создании процесса в 32-битной версии Windows, после успешной эксплуатации уязвимости.

Мы настоятельно рекомендуем пользователям отключить Flash Player для используемого браузера до выхода исправления со стороны Adobe. Инструкции по этому процессу можно найти здесь.

image
be secure.

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

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Что новые версии UEFI-стандартов нам готовят, часть третья, UEFI 2.5

В последней части цикла я постараюсь рассказать о новшествах стандарта UEFI 2.5, первые реализации которого должны появиться примерно через полгода на новых платах с процессорами Intel Skylake и AMD R-Series. В первой и второй частях речь шла о более низкоуровневых (и потому менее интересных неспециалистам) стандартах PI 1.4 и ACPI 6.0, здесь же поговорим об изменениях, напрямую влияющих на работу ОС и возможности загрузки по сети. Если вы хотите узнать, что нового в UEFI 2.5, почему PXE уходит в прошлое и зачем UEFI поддержка WiFi и Bluetooth — искренне прошу под кат.
В отличие от своих низкоуровневых собратьев, стандарт UEFI развивается в очень высоком темпе, и с момента выпуска предыдущей версии 2.4 Errata C не успело пройти и полугода. Изменений масса, поэтому я постараюсь отфильтровать мелкие и не слишком важные, вроде исправлений опечаток и правок некоторых частей текста, допускавшего двоякое толкование. Если вас это не устраивает и вам нужны все изменения до последней запятой — оригинал документа к вашим услугам.

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

ESRT и новый способ обновления прошивки

В UEFI 2.5 вводится новая необязательная таблица ESRT, при помощи которой UEFI может сообщить операционной системе типы и версии имеющихся компонентов прошивки, а также статус их последнего обновления.
С использованием этой таблицы ОС может инициировать обновление не только всей прошивки целиком (как это было практически на всех произведенных материнских платах с UEFI), но и конкретных независимых друг от друга компонентов, таких как VBIOS/GOP-драйвер, Raid-драйвер, UNDI-драйвер и т.п. Для инициации обновления будет использован стандартный механизм UEFI Capsule Update, а само обновление будет произведено при следующей загрузке. Файлы с обновлениями компонентов защищены от модификации ЭЦП на основе RSA2048/SHA256 и могут быть выпущены только обладателями закрытого ключа, поэтому прошивать модифицированные образы (и не важно, выполнена ли модификация злобным вирусом или опытным пользователем) с помощью Capsule Update не выйдет, так что программатор по прежнему наше всё.
ESRT также будет использоваться для доставки обновлений через подсистему обновления компонентов ОС (т.е. Windows Update для Win10 и fwupd для Linux).

SysPrep, OS Recovery и Platform Recovery

Изначально в фазе BDS можно было запустить только один тип EFI-приложений — bootloader, он же EFI-загрузчик. Порядок загрузки задается в переменной BootOrder, а путь и параметры загрузчика сохраняются в переменных Boot####, начиная с Boot0000 и заканчивая BootFFFF. В UEFI 2.3 был добавлен еще один тип — DXE-драйвер, который будет запущен диспетчером BDS до запуска любых загрузчиков из Boot####, и вместе с типом добавились соответствующие переменные DriverOrder и Driver####. В версии 2.4 добавили возможность привязать к EFI-загрузчику из Boot#### горячую клавишу, которая хранится в переменной Key####. В текущей версии и этого оказалось мало, и были добавлены сразу 3 новых типа приложений: SysPrep, OsRecovery и PlatformRecovery.
SysPrep
Иногда получалось, что запускать какой-либо код из Driver#### слишком рано (к примеру, нужна консоль или полностью инициализированное железо), а из Boot#### — слишком поздно (BS-переменные уже недоступны, приходится шаманить с BootOrder'ом, чтобы гарантированно запускаться первым, если риск сломать загрузку совсем). Чтобы решить эту проблему, предложен третий тип приложений — System Preparation Application. Такие приложения запускаются после драйверов, но до загрузчиков и имеют доступ к консоли и графическому режиму. К приложениям такого типа могут относиться шифровальщики дисков, эмуляторы IPMI, системы адаптированного UI для людей с ограниченными возможностями и т.п. На SysPrep-приложения распространяются те же ограничения, что и на загрузчики, т.е. для использования их вместе с SecureBoot они должны быть подписаны подходящей ЭЦП.
Возможно выглядит весьма полезной, осталось дождаться реализации и попробовать в деле.
OS Recovery
Если ни один из загрузчиков не смог запустить ОС, то ОС может инициировать восстановление загрузчика, для чего используются переменные OsRecoveryOrder и OsRecovery####. Эта возможность доступна только системам с поддержкой SecureBoot и для её использования SecureBoot должен быть активирован. При ее использовании приложения из SysPrep и PlatfromRecovery загружаться не будут.
Platform Recovery
Если ни один из загрузчиков не смог запустить ОС, то UEFI тоже может инициировать восстановление загрузчика, используя данные из PlatfromRecoveryOrder и PlatfromRecovery####. Обе эти переменные недоступны для модификации из ОС, и будут использованы только в случае, когда OS Recovery недоступен. Одна из переменных PlatfromRecovery#### может быть помечена флагом Default Boot Behavior, т.е. именно указанное в ней приложение будет запущено в случае, если ничего другого запустить не удалось.
Если обе вышеперечисленные возможности производители прошивок реализуют правильно, то о проблемах вроде этой можно будет наконец забыть.

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

В новом стандарте появилось несколько новых протоколов, которые предлагается использовать для контроля целостности компонентов прошивки и шифрования. Протокол EFI_PKCS7_VERIFY_PROTOCOL с двумя функциями VerufySignature и VerifyBuffer позволяет проверить целостность как самой ЭЦП (в формате PKCS7 binary DER), как и подписанных ей данных. Протокол EFI_HASH2_PROTOCOL добавляет к уже имеющейся возможности посчитать хеш-сумму от непрерывного буфера заранее заданного размера тройку функций HashInit, HashUpdate и HashFinal, которые позволяют вычислять хеш от потока данных или нескольких буферов на разных концах доступной памяти. Протокол EFI_BLOCK_IO_CRYPTO_PROTOCOL добавляет возможность чтения/записи данных с шифрованием «на лету»
Также в стандарт добавлена поддержка использования NX-бита для защиты буферов и областей с данными от исполнения.

NVM

Как и в стандарты более низкого уровня, в UEFI 2.5 добавлена поддержка NVDIMM и других типов Persistent Memory. В основном это разного рода определения в заголовочных файлах, но нашлось место и новому протоколу — EFI_NVM_EXPRESS_PASS_THRU_PROTOCOL, используя который можно общаться с NVMe-устройствами напрямую, передавая «сырые» команды обнаруженным NVMe-устройствам и обрабатывая ответы от них.

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

Загрузка по HTTP
Основным новшеством стандарта UEFI 2.5 является добавление загрузки по HTTP в качестве альтернативы уже имевшейся реализации UEFI PXE с использованием протокола TFTP. Для этого понадобилось добавление поддержки протоколов DNSv4, DNSv6 и самого HTTP, поддержки IPv6 драйвером UNDI, предложены изменения для корпоративных DHCP-серверов и некоторые другие улучшения. Окончательная схема загрузки по HTTP по стандарту выглядит вот так:

Загрузчик — обычное UEFI-приложение (чтобы отличать удаленные загрузчики от локальных, в стандарте их обозвали NBP), которые для использование совместно с SecureBoot требуется подписать подходящей ЭЦП. NBP может использовать сетевой стек для загрузки следующих стадий, так что написание многостадийных загрузчиков теперь небольшая проблема, в отличие от PXE.
Поддержка WiFi и Bluetooth
Также в новом стандарте появилась поддержка VLAN, WIFI и Bluetooth как компонентов сетевого стека. Вместе с ней появился целый ворох новых протоколов вроде EFI_WIRELESS_MAC_CONNECTION_PROTOCOL или EFI_BLUETOOTH_HC_PROTOCOL, которые, при наличии драйвера для аппаратной части, позволят получить доступ к беспроводным сетям из UEFI-драйверов и приложений.
В итоге с прошивкой на базе UEFI 2.5 можно загрузить ОС ноутбука по WiFi с удаленного HTTP(S)-сервера без слишком уж сильного колдунства. Не могу сказать, что мне это очень нужно или меня это сильно радует, мой внутренний параноик немного ворчит, но если сетевая инфраструктура не нужна — ее можно отключить (и проконтролировать, что она действительно отключена) или выпилить совсем, это тоже не очень сложно.

Остальное

Осталась еще масса мелких изменений, о которых почти нечего рассказывать: поддержка устройств чтения смарт-карт, которые могут быть использованы как источники данных для различного-рода криптографии, новый протокол EFI_USBFN_IO_PROTOCOL для низкоуровневого общения с USB-устройствами, новые протокол EFI_REGULAR_EXPRESSION_PROTOCOL и HII-опкод EFI_IFR_MATCH2, который это самый RegExp-протокол будет использовать, несколько новых типов DevicePath-нод — BMC, SD-карта, RAM-диск, и так далее, всего не перечислить.

Заключение

Мое общее впечатление от новых версий UEFI-стандартов — скорее положительное. Не могу сказать, что все изменения ожидаемы или очень нужны простому пользователю, часть сможет «выстрелить» только при грамотной реализации стандарта со стороны разработчиков UEFI-платформ (т.е. AMI, Insyde, Phoenix и т.д.), а некоторые очень понравятся разработчикам (ASL 2.0 FTW!), но в конечном итоге мой вердикт — пойдет. Посмотрим, конечно, получится ли реализовать все, что гладко выглядит на бумаге, но я надеюсь, что через полгода мне не придется писать статью вроде «почему не работает UEFI HTTP Boot и как с этим бороться».
Спасибо читателю за потраченное время, и удачных вам прошивок.

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.