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

Поиск сообщений в rss_rss_hh_new

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 17.03.2011
Записей:
Комментариев:
Написано: 51

Habrahabr/New








Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://habrahabr.ru/rss/new/.
Данный дневник сформирован из открытого RSS-источника по адресу http://feeds.feedburner.com/xtmb/hh-new-full, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

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

[Перевод] ES8: основные новшества

Четверг, 13 Июля 2017 г. 16:22 + в цитатник
В общем-то, тема новшеств в EcmaScript постоянно на слуху. Это далеко не случайно, так как новые стандарты, с некоторых пор, выходят ежегодно. Стандарт ES6 появился в 2015-м, ES7 — в 2016-м. Но вряд ли кто сразу вспомнит, когда вышел ES5, так как случилось это в 2009-м году, до эпохи бурного роста и развития JavaScript. Пожалуй, каждый JS-разработчик наблюдает за развитием языка. Сегодня пришло время поговорить о том, что принёс нам ES8.

image

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

Дополнение строк до заданной длины


Эта возможность реализована с помощью двух методов объекта String: padStart() и padEnd(). Слова «Начало» и «Конец» в названиях функций намекают на их роли в деле обработки строк. А именно, они позволяют задавать параметры дополнения строк до достижения ими заданной длины. Метод padStart() дополняет строку с её начала (слева), padEnd() — с конца (справа). Строки можно дополнять заданными одиночными символами, другими строками, или, по умолчанию, пробелами. Вот синтаксис функций, о которых идёт речь:

str.padStart(targetLength [, padString])
str.padEnd(targetLength [, padString])

Как видите, первый параметр этих функций — targetLength. Он представляет собой целевую длину результирующей строки. Второй параметр, необязательный padString, это строка, которой будет дополняться исходная строка. Без указания этого параметра для дополнения будет использоваться пробел. Если длина строки, к которой применяется один из этих методов, превышает заданную, исходная строка остаётся неизменной.

Вот несколько примеров:

'es8'.padStart(2);          // 'es8'
'es8'.padStart(5);          // '  es8'
'es8'.padStart(6, 'woof');  // 'wooes8'
'es8'.padStart(14, 'wow');  // 'wowwowwowwoes8'
'es8'.padStart(7, '0');     // '0000es8'

'es8'.padEnd(2);          // 'es8'
'es8'.padEnd(5);          // 'es8  '
'es8'.padEnd(6, 'woof');  // 'es8woo'
'es8'.padEnd(14, 'wow');  // 'es8wowwowwowwo'
'es8'.padEnd(7, '6');     // 'es86666'


Поддержка в браузерах (MDN)

Методы Object.values() и Object.entries()


Метод Object.values() возвращает массив собственных перечисляемых свойств переданного ему объекта в том же порядке, в котором это делает цикл for…in. Синтаксис метода предельно прост:

Object.values(obj)

Параметр obj — это тот объект, свойства которого надо получить. Он может быть объектом или массивом (иными словами, объектом с индексами наподобие [10, 20, 30] -> { 0: 10, 1: 20, 2: 30 }). Вот пример кода:

const obj = { x: 'xxx', y: 1 };
Object.values(obj); // ['xxx', 1]

const obj = ['e', 's', '8']; // то же самое, что и { 0: 'e', 1: 's', 2: '8' };
Object.values(obj); // ['e', 's', '8']


Поддержка Object.values() в браузерах (MDN)

Метод Object.entries() возвращает массив собственных перечисляемых свойств объекта в формате [ключ, значение], в том же порядке, что и Object.values(). Синтаксис метода аналогичен Object.values(), да и в остальном эти методы похожи:

Object.entries(obj)

Вот примеры:

const obj = { x: 'xxx', y: 1 };
Object.entries(obj); // [['x', 'xxx'], ['y', 1]]

const obj = ['e', 's', '8'];
Object.entries(obj); // [['0', 'e'], ['1', 's'], ['2', '8']]

const obj = { 10: 'xxx', 1: 'yyy', 3: 'zzz' };
Object.entries(obj); // [['1', 'yyy'], ['3', 'zzz'], ['10': 'xxx']]
Object.entries('es8'); // [['0', 'e'], ['1', 's'], ['2', '8']]


Поддержка Object.entries() в браузерах (MDN)

Метод Object.getOwnPropertyDescriptors()


Метод Object.getOwnPropertyDescriptors() возвращает дескриптор собственного свойства переданного объекта. Собственное свойство определено непосредственно в объекте, а не получено через цепочку прототипов. Вот синтаксис метода:

Object.getOwnPropertyDescriptor(obj, prop)

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

  • configurable — true — если тип дескриптора свойства может быть изменён и если свойство может быть удалено из содержащего его объекта, иначе false.

  • enumerabletrue — если свойство доступно при перечислении свойств объекта, иначе — false.

  • writabletrue — если значение ассоциированное со свойством, может быть изменено, иначе false (для дескрипторов данных)

  • get — функция, возвращающая значение свойства, либо, если она отсутствует — undefined (для дескрипторов доступа)

  • set — функция, изменяющая значение свойства, либо, если она отсутствует — undefined (для дескрипторов доступа)

  • value — значение, ассоциированное со свойством (для дескрипторов данных).

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

const obj = { get es8() { return 888; } };
Object.getOwnPropertyDescriptor(obj, 'es8');
// {
//   configurable: true,
//   enumerable: true,
//   get: function es8(){}, //функция-геттер
//   set: undefined
// }

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


Поддержка браузерами (MDN)

Завершающие запятые в параметрах функций


Использование завершающих запятых способно упростить редактирование кода и облегчить работу с системами контроля версий. Подобная возможность уже присутствовала в языке для литералов массивов (с самого начала) и объектов (начиная с ES5). Например: [10, 20, 30,] и { x: 1, }.

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

function es8(var1, var2, var3,) {
  // ...
}

Завершающая запятая может появиться и при вызове функции:

es8(10, 20, 30,);

Асинхронные функции


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

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

function fetchTextByPromise() {
  return new Promise(resolve => { 
    setTimeout(() => { 
      resolve("es8");
    }, 2000));
  });
}
async function sayHello() { 
  const externalFetchedText = await fetchTextByPromise();
  console.log(`Hello, ${externalFetchedText}`); // Hello, es8
}
sayHello();

Вызов sayHello() приведёт к выводу в лог строки «Hello, es8» с задержкой в 2 секунды, при этом главный поток выполнения не блокируется. Вот как это выглядит:

console.log(1);
sayHello();
console.log(2);

В консоли, после выполнения этого кода, появится следующее:

1 // немедленно
2 // немедленно
Hello, es8 // через 2 секунды

Как видно, два вызова console.log() выполняются один за другим, а асинхронная функция, не блокируя главный поток, выполняется через 2 секунды.

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


Поддержка браузерами (MDN)

Разделяемая память и объект Atomics


Если несколько потоков пользуются общей памятью, они могут одновременно писать в неё данные и читать данные из неё. Атомарные операции позволяют обеспечить целостность данных и предсказуемость результатов выполнения операций. То есть, например, гарантировать то, что некая операция завершится до того, как начнётся другая, или то, что некая операция не будет прервана. Подобную функциональность в ES8 обеспечивают новые механизмы языка. Во-первых — это объект SharedArrayBuffer, во-вторых, объект Atomics, содержащий набор статических методов.

Объект Atomics нельзя использовать как конструктор, он, в этом плане, похож на Math. Существуют методы объекта Atomics, которые позволяют выполнять различные безопасные операции с элементами типизированных массивов, служащих для доступа к объектам SharedArrayBuffer. Среди них, например, метод Atomics.add() для прибавления указанного числа к тому, что хранится в заданной позиции массива. Есть в Atomics и методы для организации управления блокировками, в частности, это Atomics.wait() и Atomics.wake().


Поддержка браузерами (MDN)

Заглянем в будущее: расширение возможностей тегированных шаблонных строк в ES9


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

const esth = 8;
helper`ES ${esth} is `;
function helper(strs, ...keys) {
  const str1 = strs[0]; // ES
  const str2 = strs[1]; // is
  let additionalPart = '';
  if (keys[0] == 8) { // 8
    additionalPart = 'awesome';
  }
  else {
    additionalPart = 'good';
  }
  
  return `${str1} ${keys[0]} ${str2} ${additionalPart}.`;
}

Если в esth записано число 8, функция возвратит «ES 8 is awesome». Если же в esth будет 7, то функция вернёт «ES 7 is good».

Однако, до сих пор на тегированные шаблоны накладываются некоторые ограничения. Они связаны с escape-последовательностями. Например, это касается подстрок, начинающихся на \u или \x. В частности, например, после \u должен следовать код символа Unicode, иначе появится сообщение об ошибке. Ожидается, что в ES9 это ограничение будет снято.


Поддержка браузерами (MDN)

Итоги


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

Уважаемые читатели! Пользуетесь ли вы новшествами ES8?
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332998/


Метки:  

В IBM создали новое поколение транзисторов из углеродных нанотрубок

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


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

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

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

В основе этой технологии — разработка Национальной лаборатории возобновляемой энергии (NREL), которая позволяет отделять полупроводящие нанотрубки от металлический с высокой точностью — вплоть до 99,9%. Специалисты из IBM, в свою очередь, создали собственную технологию размещения нанотрубок, которые плавают в растворе, на определенных местах с использованием особого рода полимеров.

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

В итоге базовая форма процессора, созданного по новой технологии, получилась. Но, к сожалению, это лишь прототип, который нельзя использовать. В итоге было решено создать отдельные транзисторы, и это себя оправдало. Каждый из 192 транзисторов получился рабочим. После этого ученые разработали опытную схему кольцевого генератора, которая заработала. Получилось 55 кольцевых генераторов с общей производительностью в 2,8 ГГц. Правда, не все генераторы получились рабочими, поскольку всего было сделано около 160 попыток.

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

https://habrahabr.ru/post/333000/


Метки:  

Как сделать сложное простым. История создания «Проекта1917»

Четверг, 13 Июля 2017 г. 16:13 + в цитатник
В конце июня 2016 года ребята из «Проекта 1917», посвященного столетию октябрьской революции в России, попросили помочь им реализовать вебчасть их проекта. Предполагалось, что это будет социальная сеть, где Николай II постит свои фотографии, Ленин ставит ему лайки, Троцкий комментирует. Мы были не первые, к кому они обратились: кто-то говорил, что в очень короткие сроки это сделать невозможно, либо стоить это будет очень дорого.

image

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

image

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

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

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

Формируем команду и начинаем работу


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

image

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

Первый принцип — no rocket science (никаких ракетных технологий), хотя сроки и сжаты. Мы строим не ракету, которая должна прилететь на Марс и спасти человека, у которого закончилась картошка. Мы всего лишь делаем социальную сеть.

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

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

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

Как мы решили построить стэк? В качестве веб-сервера мы поставили Nginx с PHP-FPM, для базы был выбран MySQL 5.7, в качестве фреймворка для бэкенда мы выбрали Laravel — это наш рабочий фреймворк. Фреймворком для фронтенда был выбран Angular 1.5.

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

Для работы с графикой мы взяли Imagemagic, для работы с видеоматериалами и с гифками мы взяли FFmpeg, обязательно используем Memcached, для сбора и работы со статикой мы используем Gulp с собственными, нами написанными тасками.

Делаем админку и верстаем


Через месяц мы уже выдали админку. Как построили админскую часть, как сайт наполняется контентом? За основу мы в бэкенде положили пакет L5-repository — это пакет для Laravel, который позволяет буквально тремя командами реализовывать нам RESTful API, делать нам все модели, создавать из коробки миграции со сложными отношениями, одним рутом генерировать нам полностью контроллер для работы с данными. Фронтенд админки был выполнен как одностраничное веб-приложение: активно используется сервис ngResource, чтобы взаимодействовать с API. На стороне фронтендa мы попытались реализовать самописный JS-cache, чтобы из админки данные постоянно не запрашивались с сервера, если мы что-то один раз загрузили, и с этим работаем на клиенте. Вся админка построена на Angular-компонентах.

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

image

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

image

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

image

Дорабатываем админку и привязываем данные


Итак, админку мы сделали, подбираемся к публичной части проекта — к фронтенду. Так получилось, что макеты нам дали чуть позже, каждый день на ходу менялись задачи. Это был первый тревожный звоночек: мы можем не успеть. Решили сразу верстать и адаптироваться на живые данные.

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

image

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

image

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

image

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

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

Во-первых, вся статика у нас сразу запрашивается из кэша, для динамической уникальной пользовательской информации мы используем API, которое не кэшируется. Вся динамическая загрузка работает через HTML. Сервер генерирует статичную ленту, например, прокрутили — пришла новая страница в HTML, то есть, данные не в JSON. Если вдруг все равно нам надо как-то работать на странице с JavaScript, мы либо оптимизируем, либо минимизируем использование AngularJS, и активно используем библиотеку Bindonce, которая позволяет реализовывать одноразовые связывания. Все изображения оптимизируются средствами Nginx, с помощью модуля http_image_filter, и в случае каких-то пиковых нагрузок мы раздачу статики переводим на CDN.

Делаем лайки, шеры, комментарии


Их реализовали за неделю. Во-первых, что такое, например, лайк или комментарий? По сути, с точки зрения базы данных, это обычная таблица, которая реализует связь many-to-many: есть, например, post id, есть user id. Мы решили подойти по-другому, и работать с этим отношением не как с отношением, то есть, например, что у нас пост имеет комментарии, мы выделили комментарии в отдельную сущность, которая имеет hasOne пост, hasOne автор. При этом, в Гугле по запросу «как написать лайки» предлагают использовать такую связь, например, как morph-by-many. Когда таблица хранит не два айдишника объектов, которые она связывает, а like-type, like-id. Например, хотите вы делать лайки для постов, для видео — вам предлагают сделать like-type, like-id. Мы решили, что это лишнее — у нас будет только одна таблица лайков.

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

Мы не кэшируем API для работы с пользователем — он должен в реальном времени получать, например, актуальные комментарии. Нельзя сказать пользователю: Извини, у нас пять минут кэша, через пять минут твой комментарий появится». И если вдруг нам понадобится какое-то, например, динамическое общение с сервером, мы спокойно можем использовать события с каналами из Laravel, которые работают уже с Node.js.

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

Также в нашей системе шеринга мы реализовали свой механизм подсчета. Для всех подобного рода систем очень важно выводить акуальную информацию (число репостов), а также хранить их в базе для подсчета определенных статистик, рейтингов и прочее. Очень часто программисты, сталкивающеся с шерингом первый раз, реализуют подсчет следующим образом: по заданиям в cron бэкенд делает запросы к апи социальных сетей, получает свежие данные, сохраняет. У этого подхода есть два серьезных недостатка — во-первых, информация в текущий момент времени может быть не актуальна (например, крон раз в 10 минут обновляет данные о 1000 постов), во-вторых за частые обращения к апи социальных сетей с одного IP-адреса вас могут забанить.

Мы пошли другим путем. В момент, когда пользователь шерит пост в свою социальную сеть, мы паралельно с попапом шеринга делаем запрос к api социальной сети из js-кода (соответственно — с ip-адреса клиента), получаем актуальное число репостов, прибавляем к этому числу 1 (пользователь же еще не пошерил) и сохраняем в базу данных. Соответственно, мы постоянно поддерживаем базу количества шерингов в актуальном состоянии, и даже возникает такой эффект, что, например, ты пошерил, а число увеличилось на 10, значит, кто-то с тобой вместе сейчас шерит, ты такой: «О, круто, все в реальном времени работает, как мне это нравится!».

Разрабатываем пуш-уведомления и запускаем


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

image
Вы не сохранили токен, а просто его законсолили

Как мы решили реализовывать пуши. За основу был взят сервис Google Fairbase. Так как времени оставалось мало, мы обязательно смотрим документацию и делаем все по ней. В случае, если человек не был авторизован на сайте, решили делать очень просто. Мы генерируем какую-то уникальную cookie этому человеку, и в базу сохраняем токен с ней. Потом человек авторизовался на сайте, мы посмотрели, что у него есть cookie, в базе есть токен с ней, перепривязываем токен на конкретного пользователя, и потом уже ему рассылаем какие-то персональные уведомления.

В качестве рассыльщика решили использовать пакет Laravel-FCM. Тот, кто работал с FCM или Firebase, знает, что, для того, чтобы отправить сообщение, нужно все поделить на пачки по тысяче токенов, сделать отдельно запросы. Laravel-FCM это берет на себя. При этом он очень просто позволяет нам генерировать payload в пуши, делать какую-то персональную картинку для человека, персональный заголовок, персональный текст, персональную ссылку и так далее.

Мы успели. Выкатили пуши за час до релиза. На следующий вечер про проект написали The Village, Медуза, CNN, BBC, в «Третьяковской галерее» устроили банкет для СМИ, на который нас пригласили. И такая небольшая ирония: до декабря 2016 года главный офис нашей компании официально располагался посреди леса. Представьте, как круто — вы сделали проект, о котором написали в CNN, а сделали вы его в лесу.

Делаем локализацию


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

Хранить в базе данных информацию о двух языковых версиях мы решили так. Для каждой сущности, которая может быть переведена на другой язык (пост, герой, группа, видео, геолокация) мы добавили поля: lang, которое хранит язык — 0русский/1английский) и поле mirror_id, куда сохраняется id записи «дублера» при копировании.

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

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

Что дальше?


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

Например, из спецпроектов мы сделали:


Выводы


  1. Сложное сделать простым легко, усложнить что-то и сделать простую вещь сложной еще легче.
  2. Помните историю, революция не всегда приводит к хорошим результатам.
  3. Учитесь на своих ошибках. Пока вы сами не положите сервер, не поймете, из-за чего он лег. Пока вы сами не допустите какую-то сложную ошибку, не поймете, почему что-то сломалось. Потерянный домен в пушах — это не самое страшное, что может случиться.
  4. Не гонитесь за модой. Следите за своим стэком, не создавайте там больших огородов. Если вам нужно решить какую-то новую задачу, посмотрите, есть ли у вас уже инструмент, который для нее подходит, не надо находить новый модный фреймворк, документация к которому есть только на китайском языке, вы такой: «О, это модно, давайте попробуем». Так делать не надо.
  5. И цифра аптайма 99,99 – это не предел. Всегда можно это улучшить.

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

https://habrahabr.ru/post/332786/


Метки:  

Продуктивность и юзабилити

Четверг, 13 Июля 2017 г. 15:25 + в цитатник
Рассуждаем о том, как юзабилити сайта / приложения соотносится с его продуктивностью. Тема сложная, к обсуждению, даю тезисно своем мнение.

Терминология


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

Тезисы


1) Продуктивность на порядок более объемное понятие, чем юзабилити, второе входит в первое некоторой частью. В моей методике оценки продуктивности удобству пользования отведен один пункт из 22-х.

2) Не всегда улучшение юзабилити повышает продуктивность, часто наоборот.
Например, для контент-проектов с точки зрения юзабилити реклама не нужна, она только мешает. Для продуктивности же рекламы надо поставить больше, пойдя на компромиссы с удобством пользования. И всем владельцам_сайтов это хорошо понятно.
Другой пример: форма регистрации в #ecommerce-сайте. Добавили регистрацию через соцсети, стало региться больше людей. Но, часть пользователей в базе теперь без e-mail. Рассылка стала работать хуже. Юзабилити повысилось, продуктивность упала.

3) У юзабилити более размытые критерии т.к. нет четко определенной цели. Ок, допустим мы убрали все явные косяки и глюки. Что дальше? Что именно будет цифровым показателем удобства? Скажем, глубина просмотра: чем удобней сайт, тем по нему лучше ходят. Хорошо, давайте разделим контент на части и поставим листалку. Глубина повысилась. А удобство? Вопрос.

4) Если с помощью юзабилити заниматься изменением показателей бизнеса (например, конверсией), то это уже не удобство пользования, а продуктисность, но в сильно урезанном виде.

Резюме


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

https://habrahabr.ru/post/332996/


Метки:  

Ссылочная TCP/IP стеганография

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

Метки:  

[Из песочницы] Тестирование в Openshift: введение

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

Здравствуйте уважаемые участники ИТ сообщества. Меня зовут Олег, я работаю в компании, которая занимается разработкой ПО. Я занимаюсь ручным и автоматизированным тестированием Linux и Unix продуктов и я хотел бы поделиться положительным опытом автоматизированного тестирования в Openshift Origin.


Цели, которые я преследую:


  1. Донести до русскоязычного сообщества особенности работы с Openshift Origin в контексте тестирования.
  2. Рассказать о преимуществах и недостатках тестирования в контейнерах.
  3. Агрегировать и актуализировать свои знания о Kubernetes/Openshift.

Весь материал изложен в трёх статьях:


  1. Тестирование в Openshift: Введение
  2. Тестирование в Openshift: Внутреннее устройство кластера
  3. Тестирование в Openshift: Автоматизированное тестирование

Примечание: хотелось бы сразу заметить, что излагаемый материал касается Openshift v3, а не Openshift v2 (когда компания Red Hat еще не начала использовать Kubernetes в качестве ядра для своих продуктов и сервисов).


Почему был выбран Openshift Origin:


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


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


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


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


Следующим этапом стала проработка быстрого (в контексте быстродействия окружений) CI/CD c учетом новых требовании, а именно (основные, согласно приоритетам):


  1. Open Source решение без каких-либо затрат на покупку ПО.
  2. Быстрая скорость развертывания тестируемых сред. Связность и осведомленность о существовании сервисов между средами. Встроенная поддержка и контроль запусков тестов внутри окружения. Высокая плотность размещения для удовлетворения пункта 4.
  3. Активное сообщество, популярный проект с прогнозируемым будущем, репутация владельца, наличие документации.
  4. Отсутствие дополнительных вложений в аппаратную составляющую.

Я не буду утруждать читателей подробным пересказом о тернистом пути поиска подходящих продуктов, но хочу ознакомить со списком рассмотренного ПО (февраль 2016):


  1. Замена полной виртуализации: Docker, LXC, OpenVZ, kvmtool.
  2. Оркестрация и управление кластером: Kubernetes, Nomad, Openshift, Openstack, Swarm.
  3. Поддержка в Jenkins: Docker plugin, Kubernetes plugin, Openshift plugin

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


Своими словами oб Openshift Origin:


Openshift Origin — это в первую очередь Open Source платформа для разработки и публикации ПО, которая базируется на платформе оркестрации контейнеров Kubernetes. Платформа расширяет возможности Kubernetes с помощью специальных объектов и механизмов.


Кластер:


Кластер может быть развернут или обновлен с помощью сценариев Ansible. Внутри кластера может использоваться как встроенный так и внешний Docker регистр. Узлы кластера могут быть закреплены на основе специальных меток за отдельными проектами. Присутствует сборщик мусора и настраиваемый планировщик. Кластер может быть развернут внутри Openstack и интегрирован с ним с целью автоматического масштабирования и предоставления хранилища данных. Среды могут быть осведомлены об опубликованных сервисах и других узлах с помощью переменных окружений и DNS имен. Возможна проверка доступности сервисов через HTTP/TCP запрос и/или через выполнение команды внутри контейнера. Ресурсы кластера могут быть квотированы на уровне проектов (процессор, память, количество объектов и т.д.). Присутствует возможность мониторинга кластера на уровне контейнеров и рабочих узлов.


Данные:


В качестве способа харанения данных могут выступать временные или постоянные тома, которые монтируются непосредственно в контейнеры. Backend для данных томов могут выступать: NFS, GlusterFS, OpenStack Cinder, Ceph RBD, AWS Elastic Block Store (EBS), GCE Persistent Disk и т.д. Присутствует возможность (hostPath) монтирования локального каталога того рабочего узла, на котором запущен контейнер.


Сеть:


По умолчанию все коммуникации осуществляются с помощью Open vSwitch, но существует поддержка других сетевых решений через систему плагинов Kubernetes. По умолчанию все среды могу коммуницировать друг с другом, но возможна изоляция на уровне проектов. Поддерживается разрешение DNS имен сервисов с помощью встроенной службы SkyDNS. Опубликованные внутри кластера сервисы могут быть доступны извне. Всю функциональность по изоляции и функциям NAT берет на себя Iptables.


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


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


Управление:


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


Заключение:


Несмотря на обилие технологий и продуктов, которые представлены на рынке, найти подходящий инструмент достаточно сложно. Балансируя между унификацией и интеграцией процессов CI/CD, учитывая сложность сопровождения, отслеживая цепочки задействованных технологий, всё же была найдена Kubernetes, а затем и Openshift Origin. В отличии от базовой платформы оркестрации контейнерами Kubernetes, Openshift привносит необходимые элементы для удобной и эффективной работы.

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

https://habrahabr.ru/post/332994/


Метки:  

IceCash 2.0 Web АРМ Кассира и АИС по обмену данными с кассами под Linux на Python

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

Как-то меня спросили: «Зачем писать то, что уже написано многократно и на более профессиональном уровне? То что ты сделаешь будет заведомо хуже и лишено грамотной поддержки». Я тогда ответил просто: «Мне хочется, чтоб под линух и чтоб код свободный. Чтоб драйвера не покупать для кассы».

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


Нафига козе боян?


Вообще, конечно, «зачем?» это очень важный вопрос. Им нужно озадачится заранее. Прежде чем что-то писать, нужно оценить необходимость, полезность, чтобы самому было не обидно потом. Я после, не раз оценивал зачем я делаю этот проект, находил умные объяснения, но на самом деле… просто чтобы под Linux и чтобы код свободный. Ну и, конечно, драйвера для фискальных аппаратов — это слабо понимаемый мной бизнес.

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

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

Первая версия. С дикими глазами и маниакальным трудолюбием.


image

Первую версию, я смастерил быстро. Об этом, я писал статью на хабре когда-то. Да там было много ошибок и ужасный код. Но это выполняло на тот момент задачу минимум. В начале это был легкий и слабенький (практически HTML) сайт на PHP и несколько утилит на питоне. База данных в MySQL, транспорт данных перл-скриптами. На бэкофисе тоже сайт для просмотров чеков и производных отчетов. Свободный драйвер для Штрих-М, написанный неким кодером, был прилеплен к моей системе. Хотя, если быть справедливым, то правильнее сказать, что основой послужил этот драйвер и без него ничего бы не вышло. Именно тогда я уяснил основную проблему самописного свободного кассового ПО — свободных драйверов для ФРК нет.

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

Нам всем пришел ЕГАИС! И не только..




К тому моменту, когда назрело написание второй версии, уже во всю трубили о том, что не долог век обычных фискальных аппаратов. Напомню, что за последние два года были существенные изменения в законодательстве в области учета розничной торговли. И долгое время не меняющееся положение дел в этом секторе нехило тряхнуло рядом нововведений. Первым пришел ЕГАИС. Да, моя организация занималась торговлей пивом и алкогольной продукцией. Мои коллеги из других организаций, также как и мы, с «радостью» встретили единый электронный документооборот. Я не буду ныть по поводу изъянов этой системы. Сейчас, все как-то более или менее нормально. Конечно, момент внедрения это всегда особенно яркие и запоминающиеся дни и ночи… Все было как обычно — сумасшедшие сроки, невозможность нормального тестирования, сложность регистрации, отсутствие техподдержки и Новый год ). Сейчас мне кажется, что все что мы делали, это какая-то нереалистичная комедия, участники которой делают вид что это всерьез.

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

В общем, к сроку, оборудовать торговые точки новыми системами ПО под ЕГАИС мы не успели. Но, честно говоря, менять ПО на пятидесяти объектах, покупая попутно лицензионный Windows и кассовое ПО, не очень-то хотелось. Только на ключи JaCarta пришлось единовременно выкинуть приличные средства. А ведь многие тогда вообще отказались от торговли алкоголем. Почесав репу, мы сделали по старинке. Был быстренько накидан веб-сервис, который взаимодействовал с единственной копией УТМ и десятками аккаунтов на торговых объектах, где осуществлялось подтверждение приходных документов. Связка пятидесяти ключей jaCarta была вручена специально подготовленной сотруднице. Ей был поставлен комп с мастдаем и нужным ПО. Перетыкая каждый день (на протяжении полугода) ключи и тыкая мышкой на сайте в нужные места, новоявленный внештатный провайдер ЕГАИСА осуществлял обмен документами. Думаю мы не единственные в этом идиотизме, некоторые так делают по сей день.

Продажа алкоголя предполагает работу с ЕГАИС в момент продажи каждого чека, а это уже требовало доработки кассового ПО. До момента внедрения было всего полгода. Так что работая на нехитрой времянке по приему документов ЕГАИС, мы быстро быстро начали делать вторую версию нашей кассы.

Пишем по феншую.


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

СЕРВЕР ДРАЙВЕРОВ


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

Вообще, идея подключить еще и термо-принтеры, коих у нас было навалом, мне показалась удачной. Я же не знал что спустя два года будет возможна печать только фискальных чеков на обновленных ФРК, подтвержденных онлайн у оператора фискальных данных. Хотя впоследствии, вариант, при котором термо-принтер всерьез пытался прикинуться ФРК+ОФД оказался кстати в моменты, когда фискальник был сломан.

Управление фискальными рестораторами и термо-принтерами, поддерживающими протокол ESCPOS должно было осуществляться через отдельный web-сервис. То есть, все что касается взаимодействия с оборудованием отделяем в отдельное независимое приложение, взаимодействие с которым должно осуществляться по XML протоколу.



Все это было написано и оттестировано за пару месяцев. Мне повезло, что я писал подобную задачу на заказ. То есть реализация печати на термо-принтерах по XML была реализована накануне. Оставалось только написать атоловский драйвер и как-то унифицировать весь этот зоо технопарк одинаковой печатью чеков и их копий. В итоге получился отдельный сервис, который я назвал DTPrint. У него тоже был небольшой сайт, для детальной настройки ФРК. Позже я написал консольный скрипт, с помощью которого можно было обращаться к сервису и передавать ему текстовый файл для печати с нужными параметрами. Так у меня на работе завелся свой факс-лог сообщений с сервера, который печатал всякую админскую инфу с сервака. А позже и дублировал сообщения с jabber-клиента pidgin. В общем, я себе ни в чем не отказывал, в процессе творческого прорыва порыва ). Ах да, еще драйвер fprint играл бипером имперский марш после снятия зет-отчета.

САЙТ КАССЫ


Также как и в первой версии, основой должен стать web-сайт. Только теперь без apache и PHP — только Python. Интерфейс кассира должен стать более дружелюбным ). Также необходимо было навернуть админских функций к интерфейсу и сервисных функций по инициализации обмена данными и прочим полезностям.
Веб-касса, понятное дело, должна была взаимодействовать с сервером драйверов, сервисом обмена данными, бонусным сервером и рядом других бекофисных сервисов.

Данные решили также хранить в MySQL. От системы хранения транзакций (как у Штрих-М) я решил уйти. Теперь в БД хранились именно чеки, целиком. Все необходимые дополнительные данные об операциях с чеком оседали в виде значений полей заголовка или содержимого чека. Это я хотел сделать уже давно. Выборки из такой БД были просты и лаконичны. Расчет зет отчетов прозрачен и без заморочек.

Структура программы-сайта должна была быть максимально разделена внутри на отдельные модули, содержащие объекты подзадач. ЕГАИС модуль, бонусный модуль, модуль обработки чека, модуль БД запросов и т.д.

Важным дополнением должна была стать реализация ЕГАИС. Во первых, в части получения и подтверждения приходов, во вторых в части реализации алкоголя. Вообще, ЕГАИС, в дальнейшем оказался большим и нескончаемым потоком различных документов, запросов и обновлений. Сейчас, я бы его выделил в отдельный модуль над УТМ. Сама программа UTM постоянно менялась, менялся и протокол. Недавно (1юля 2017) ввели его вторую версию. Не удобным осталось обновление ключа на токене JaCarta. Хотя сейчас, многие организации предлагают это сделать удаленно, для Linux+JaCarta это пока еще сложновато. Поэтому обновляем мы ключи, подключая их в ноутбук с Windows. Думаю, эту часть можно было бы доработать, а то слишком хлопотно получается.

Я долго колебался, на счет того, как именно реализовать выгрузку чеков. Если сказать проще, то мучил вопрос: «Сколько онлайна нужно кассе?». Будет ли она иметь режимы онлайн, оффлайн, как будет проходить обмен? В итоге касса была реализована отдельно от функции обмена. Сайт откликается на команды выгрузки чеков, зет отчетов или загрузки данных с сервера. Процессы обмена, запускаемые с нужной частотой из crontab не влияют на работу кассы. Нет связи — не беда, как появится, накопленные данные по отбитым чекам уйдут, прайс обновится.

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



Код был написан, как мне кажется, достаточно хорошо. Всегда можно лучше, разумеется. Но того, что было сделано надолго хватало для стабильного усложнения проекта без опаски съехать в гов хаотичный код (G-CODE). Есть, конечно некоторые некрасивости. Так, применяются разные способы взаимодействия с javascript. Началось с разработки шаблонов в серверной части, закончилось json подгрузкой и более сложными функциями javascript на стороне клиента. XML для взаимодействия с сервером драйверов, конечно, лучше было бы заменить на json. Но, перерабатывать это было уже некогда. И, конечно, я сэкономил на дизайне, так как дизайнер во мне умер еще при рождении.

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



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

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

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



Вообще скорость администрирования существенно увеличилась. Стало возможно вмешиваться в процесс оплаты, настроек, управление драйвером с браузера в телефоне (через VPN). Хотя VNC и ssh никто не отменял и все инструменты активно использовались. Некоторые настройки были глобальными и кассы сами их забирали с сервера, заодно отсылая информацию о самих себе (существенные параметры настроек, ip-адрес, время подключения, версия ПО). Со временем на кассе образовался богатый crontab и скрипты всякой самодиагностики и отсылки отчетов на сервер. Но тут особо хвалиться нечем, так делают все.

СЕРВЕР УПРАВЛЕНИЯ КАССАМИ


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

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



Первая важная функция этого сервера — принимать и раздавать кассам новые прайсы, с нее я и начал. Прайсы должны были привязываться к кассам. То есть на самом сервере мы указываем для каждой кассы свой прайс из имеющихся. Касса же просто обращается к серверу сообщая свой идентификационный номер. В ответ, сервер дает добро на GET скачивание zip-архива. Если скачивание было успешно, то сервер сам у себя помечает время последнего скачивания для этого клиента и больше ему прайс не дает. Ну, разумеется, пока новый прайс не будет загружен на сам сервер.
А загрузка файла на сервер это тоже обычная PUT HTTP операция, только нужно указать идентификатор филиала и самого прайса. Позже, мой товарищ, которому мы на работе тоже внедряли часть моей системы, на 1С написал нужную обработку для выгрузки прайса сразу на сервер. Заодно им были написаны обработки для загрузки JSON зет-отчетов с этого же сервера.



Вторая важная функция — это сбор данных с касс. Зет отчеты и чеки. Вообще я пришел к тому, что зет-отчеты на кассе стала формировать сама касса. То есть уже готовые, сгруппированные по товарам, с нужными итоговыми параметрами, зет отчеты находятся в БД. И в веб-интерфейсе их можно детально изучить. На ранней стадии написания кассы, я все реализовывал без сервера сбора данных, поэтому касса и сервер содержат идентичные функции по выдаче зет отчетов и чеков по запросу извне. Получается, что при желании можно обойтись без сервера, просто запрашивать данные у кассы напрямую. Итак, касса, по запросу формирует два потока данных в json — поток не выгруженных зет-отчетов и поток не выгруженных чеков. Данные загружаются на сервер, а оттуда по запросу, выгружаются для 1С. Как вариант, были написаны скрипты, которые выгружают зет отчеты в специализированные текстовые файлы, наподобие фалов Штрих-М.



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





Также на сервер была возложена функция обновления кассового ПО. Обновления были двух типов: обновление системы и обновление программы. Любое обновление начинается с отслеживания версий. Версии, которые мы вводим в эксплуатацию (prod), просто устанавливаются глобальными переменными на сервере (update и upgrade). Все серверные переменные автоматически раздаются кассам. Сюда же могут входить и любые интересующие нас глобальные параметры для всех касс, требующие постоянной репликации. Например, у меня так раздается температура воздуха. Каждый филиал может иметь свой набор переменных и значений, так что погода раздается регионально. Это потребовалось не ради забавы. Была такая акция — по погоде, там формула скидки ориентировалась на температуру.

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

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



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

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

  1. Сами с собой.
  2. С бонусной системой.
  3. Системой ограничений, основанной на прайсах.
  4. Со всеми системами, работающими с чеком.




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



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



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

Дополнительные сервисы


У нас уже была разработана своя бонусная система в виде сервиса на Python+Mysql. Поэтому, был лишь дописан модуль для взаимодействия с ним. Также, была система розыгрышей призов. Это что-то типа лотереи на сервере, где каждая касса после оплаты чека инициирует розыгрыш. Для этого тоже был написан отдельный модуль. А призовая система на точке включалась определенной акцией.

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

Оператор фискальных данных


Да, мы справились. Но было еще предостаточно пространства для творческого маневра. Нам бы немного времени, чтобы запилить все красиво. Но… Пришла вторая волна изменений. Тем кто знаком с требованием ФЗ-54, объяснять не надо. Сначала запустили страшилки от налоговых органов. Попутно, как обычно, наврали заверили, что в итоге эксплуатация ФРК будет дешевле, чем раньше. Потом обещания от производителей фискальных регистраторов, заверяющие нас, что все будет в срок. Потом, как обычно, оказалось что никто не готов… Организация шабаша была на троечку.

Бизнес медленно и фырча от недовольства сплевывал горький привкус предвкушаемых затрат и пробовал на вкус незрелые плоды от бистро-автоматизаторов. А мы тоскливо посмотрели на сибирские сугробы и криво улыбались — до лета нам было чем скоротать время.

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

  1. Новый АТОЛ
  2. Новый Штрих-М
  3. Старый Штрих-М с комплектом доработки.

По идее, производители фискальных аппаратов должны были поменять ЭКЛЗ на Фискальный накопитель и реализовать отправку данных в ОФД, снабдив фискальник возможностью взаимодействовать с каналом интернет связи. Но выполнить одну и туже задачу можно миллионами способов. И, конечно, их будет в итоге хотя-бы несколько. Итак, были фискальники без LAN гнезда. С помощью специального драйвера, можно было создать LAN over USB и радоваться жизни… если ты под windows или если у тебя много времени. Но, у меня этого времени не было. Поэтому от новой дешевой поделки от Штрих-М РИТЭЙЛ-01 пришлось отказаться.

Зато вариант с комплектом доработки вполне себе подошел. Фискальнику делали шунтирование, вставляли новые мозги и LAN выход. Однако, Штрих не работал как сетевой принтер, он подключался двумя хвостами. Одним, как и раньше, к компьютеру, другим (LAN) к роутеру. Таким образом, он самостоятельно отправлял данные в ОФД и работал с драйвером привычным образом. Но драйвер немного пришлось доработать.

У Атола решение было поинтереснее. Принтер вообще можно было сделать сетевым и обращаться с кассы к нему по LAN. Здесь, в драйвере тоже пришлось сделать некоторые доработки.

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

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

Пилите, Шура, мне не жалко.


Так получилось, что сейчас я работаю программистом в крупной компании и нахожусь далеко от региона, где внедрена касса IceCash. Я что-то дописываю, но у меня жуткий напряг со временем. Требования к ПО тоже не стоят на месте, развивается ЕГАИС, возникают новые потоки документов. Жалко будет, если вдруг очередная розничная сеть прекратит свое существование, а вместе с ней и проект. Возможно, кому-то приглянется эта поделка, его часть, модуль, кусок кода. Может, тогда удастся поддержать, развить проект или создать хороший форк.

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

Ссылки


Здесь выложен код IceCash2 на git GIT ICECASH2
Сервер обмена GIT ICESERV
Вики, которую я не дописал: WIKI
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/323100/


Метки:  

Linux Foundation представила бесплатный вводный онлайн-курс по Kubernetes

Четверг, 13 Июля 2017 г. 14:42 + в цитатник
На образовательной онлайн-площадке edX появился курс «Introduction to Kubernetes», созданный некоммерческой организацией The Linux Foundation и проводимый специалистом из компании CloudYuga Technologies.



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

Практические навыки, которые получат слушатели:
  • как настраивать и использовать кластер Kubernetes с помощью Minikube (т.е. локально);
  • как можно запускать приложения в обычном окружении Kubernetes и получить доступ к развёрнутым приложениям;
  • какую помощь можно найти в сообществах Kubernetes и как в них поучаствовать.

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

Курс, разумеется, на английском языке и, что примечательно, бесплатен (с возможностью получить сертификат об успешном прохождении за 99 USD). Продолжительность курса — 4—5 недель (в неделю потребуется тратить по 2—3 часа). Заявки на участие подаются на странице курса.

P.S.


В прошлом месяце организации Cloud Native Computing Foundation (CNCF) и The Linux Foundation объявили о наборе энтузиастов на бета-тестирование их первого сертификационного экзамена по Kubernetes (его содержимое). Регистрация проводилась до 23 июня, и мы подали заявки, однако никаких новостей от организаторов с тех пор не поступало — ждём…

Читайте также в нашем блоге:
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332990/


Метки:  

МТС ищет лучших IT-специалистов

Четверг, 13 Июля 2017 г. 14:35 + в цитатник
Мы хотим поделиться с вами крутой новостью! В этом и следующем году мы планируем нанять около 1,5 тысяч IT-экспертов разных специальностей. Зачем, спросите вы? Чтобы создавать лучшие IT-продукты. Друзья, айда к нам в команду!

image

Мы ищем разработчиков для Android, iOS, Java, системных аналитиков, специалистов по информационной безопасности и системных архитекторов для работы по всей стране. Наши главные ИТ-хабы находятся в Москве, Санкт-Петербурге, Новосибирске, Екатеринбурге и Краснодаре, но и этими городами география поисков IT-кадров не ограничивается.

Обновленная IT-команда МТС будет развивать инновационные продукты для десятков миллионов наших клиентов (и десятков — не наших :) ). Сейчас в центре интересов МТС — решения в области интернета вещей, Big Data, облачных технологий, системной интеграции, электронной коммерции, финансовых услуг. Мы уже предлагаем своим клиентам более 20 мобильных приложений, тестируем телемедицинский сервис, планируем запуск продуктов в области онлайн-образования и киберспорта. И во всем этом вы можете поучаствовать. Скучно точно не будет! И, вполне возможно, следующее направление для разработки сервисов предложите нам именно вы.

Совсем скоро все наши новые вакансии можно будет найти здесь!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332986/


Яндекс.Такси и Uber поедут вместе

Четверг, 13 Июля 2017 г. 14:35 + в цитатник
Друзья,

Хочу рассказать вам об очень важной новости. Мы, Яндекс.Такси и Uber, решили объединить наши сервисы и бизнесы в России, а также в Азербайджане, Армении, Беларуси, Грузии и Казахстане. Вместе мы будем строить “персональный общественный транспорт” – альтернативу личному автомобилю, автобусам или метро.

Вот как выглядит объединенная платформа в цифрах за июнь:
– 127 городов, 6 стран
– 35 млн поездок в месяц
– 7,9 млрд рублей суммарная стоимость поездок в месяц

Эксперты оценивают совокупную стоимость поездок легальных перевозчиков в России в 501 млрд рублей в 2016 году (VTB Capital). При этом “теневой” сегмент был оценен Аналитическим центром при Правительстве РФ в 116 млрд рублей в 2015 году. Таким образом, доля объединенной компании в России в 2016 году была бы примерно 5-6% по этому показателю.


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

Теперь о том, как это будет выглядеть. После объединения для пользователей обоих сервисов такси ничего не изменится: для заказа поездок по-прежнему будут доступны оба приложения – Яндекс.Такси и Uber. Водители будут объединены в единую платформу. Это позволит им в одном приложении получать заказы как от Яндекс.Такси, так и от Uber. Такое объединение существенно увеличит количество доступных машин, сократит время ожидания и холостого пробега. Всё это позволит водителям получать больше заказов в час, а пассажирам – сохранить доступную стоимость поездки.

“Под капотом” будут работать наши алгоритмы распределения заказов и навигационно-картографические технологии Яндекса. За последний год мы совершили несколько качественных скачков в технологиях, которые обеспечивают оптимальную загрузку машин. Например, теперь в час пик водители совершают на 30% больше поездок, чем ранее. Объединение платформ даст возможность совершить еще один рывок в качестве сервиса и эффективности водителей.

Кроме того, мы с Uber договорились о роуминговом соглашении по всем странах, где работают компании. Например, прилетев в Лондон или Бангкок вы сможете из приложения Яндекс.Такси заказать Uber, а туристы из Парижа – заказать Яндекс.Такси из приложения Uber.

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

UberEATS продолжит свое развитие в новой компании. Это сложнейший логистический сервис, в котором нам поможет международный опыт UberEATS и технологии пешей маршрутизации Яндекс.Карт.

Uber и Яндекс приняли решение проинвестировать в новую компанию 225 и 100 млн долларов соответственно, оценивая объединенную компанию в 3,725 млрд долларов. На 59,3% компания будет принадлежать Яндексу, на 36,6% – Uber, а на 4,1% – сотрудникам объединенной компании. Наши команды будут объединены. Я становлюсь генеральным директором объединенной компании.

Отдельно хочу поблагодарить команду Яндекс.Такси, которая построила невероятный сервис и успешный бизнес. Это одна из самых сильных команд, в которых я когда-либо работал. Теперь к нам присоединяется талантливая и не менее успешная команда Uber – и мы очень этому рады! Важной задачей для меня и для всех нас после объединения будет сплотить две команды в одну, объединив наш опыт и лучшие идеи.

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

Тигран Худавердян
CEO
Яндекс.Такси
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332988/


Метки:  

Подготовка IT-инфраструктуры иностранного банка для переезда информационных систем в Россию

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


Наверное, уже все слышали, что в соответствии с вступившим в силу Федеральным законом от 21 июля 2014 г. № 242-ФЗ "О внесении изменений в отдельные законодательные акты Российской Федерации в части уточнения порядка обработки персональных данных в информационно-телекоммуникационных сетях" необходимо организовать хранение и обработку персональных данных в России. Тема, конечно же, коснулась почти всех зарубежных финансовых организаций, представленных у нас в стране. Колесо завертелось и волею судьбы мы выиграли на исполнение проект одного зарубежного банка по созданию ИТ-инфраструктуры под миграцию его информационных систем (ИС) в Россию. Сорри, контракт включает NDA, поэтому назвать банк не можем. Но можем рассказать, как все это мы реализовали, какое решение предложили, архитектуру, СПД, какие вендоры – в общем, весь наш опыт передаем ниже.



Немного подробнее о предпосылках задачи


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


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


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


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


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


Задача банка


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


Требования


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




По показателям:


RPO (Recovery point objective – сколько данных будет потеряно при аварийном восстановлении) – в нашем случае заказчик хотел получить восстановлении RPO = 0 в случае локальных сбоев, и RPO стремящееся к 0 в случае катастрофы в основном ЦОД. Иными словами, в случае локального сбоя не должно быть потери данных, а в случае глобального сбоя потеря данных должна быть минимальна.


RTO (Recovery time objective – время, за которое возможно восстановить ИТ-систему) — заказчик хотел время восстановление <= 1 часа в случае самого худшего локального сбоя и RTO <= 2 часов в случае катастрофы в основном ЦОД.


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


2. Достаточная производительность информационных систем на новом оборудовании не хуже, чем до переезда. Это должно было обеспечиваться со всех точек зрения – например, как вычислительных ресурсов, так и с точки зрения СХД.


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


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


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


3. Эффективное вложение денег и эффективное использование оборудования. Заказчик ставил задачу с точки зрения бизнеса обеспечить выполнение требований №1 и №2 в минимальный бюджет. При этом в отличие от многих проектов российских заказчиков учитывалась не только стоимость первоначальных вложений – CAPEX, но и OPEX — стоимость поддержки и сопровождения решения в течение 5 лет.


Решение


ЦОДы и резервирование


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


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


Соответственно, требовался либо «теплый» резерв, либо «горячий». Заказчики, как нормальные иностранцы, предъявляли требования, чтобы между ЦОДами было не менее 100 км для исключения всякого влияния (веерного отключения ЛЭП или, например, глобальной катастрофы в Москве). С экономической точки зрения синхронная репликация была не целесообразна, так как потребовались бы существенные инвестиции в канал между ЦОД, трафик по которому должен был быть зашифрован. С технической точки зрения задержки на таком расстоянии между ЦОД уже могли начать влиять на скорость работы информационных систем, поэтому был выбран вариант с асинхронной репликацией между ЦОД.


«Железо» и ПО под RISC-системы


Для информационных систем, работающих на архитектуре RISC, были выбраны сервера E870 на платформе IBM Power. Они предназначены для размещения бизнес-критичных нагрузок с самым высоким уровнем доступности и обладают полным набором функционала RAS (Reliability, Availability and Serviceability).


Эти серверы виртуализуются на аппаратном уровне с помощью IBM PowerVM, и в них создаются разделы виртуальных серверов (LPAR). В LPAR выделяют процессорные ядра для выполнения нагрузки. Их можно выделить в LPAR как монопольно – без переподписки ресурсов, так и в общий пул для совместного использования пулом виртуальных серверов. Можно ограничить предельное потребление ресурсов из общего пула виртуальных серверов сверху в пиковых режимах. Архитектура подсистем Power представлена на рисунке ниже.



Рис. Архитектура подсистем IBM Power


Любые серверы, даже такие надежные как IBM Power E870, где практически все задублировано, могут отказать. Поэтому для защиты от сбоя сервера используется программное обеспечение высокой доступности (HA). В нашем случае наиболее хорошо подходило кластерное ПО – Veritas Infoscale. Это ПО имеет существенное преимущество перед решениями с простым HA. Оно позволяет сделать одновременно локальный кластер (HA) как между серверами на одной площадке, так и между площадками (DR). В итоге заказчик будет застрахован от локального сбоя и сбоя всего основного ЦОДа.


Veritas Infoscale позволяет организовать 3-х стороннюю репликацию данных. Это когда данные дублируются в 2-ух местах на одной площадке и одновременно идет непрерывная IP репликация в РЦОД. Технически, возможно было бы сделать это и более простыми и дешевыми средствами, но существенный плюс ПО Veritas Infoscale в том, что в случае сбоя одной из реплик на локальной площадке не потребуется вручную перенастраивать репликацию. В результате данные клиента постоянно остаются под защитой, даже в случае локального сбоя.


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



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


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


Однако в серверах High End IBM Power (в том числе E870) можно максимально эффективно использовать активации процессоров и памяти, объединяя их в общий Enterprise Pool. Активации из пула можно использовать на любом из серверов пула. Для оптимизации стоимости решения на резервных серверах можно закупить меньше активаций по сравнению с основным, что и было нами сделано. В тоже время в случае сбоя на этих серверах можно будет использовать весь объем активаций пула.


«Железо» и ПО под архитектуру x86 банка


Для информационных систем, работающих на x86/VMware, было выбрано решение на блейд-серверах HP Proliant Bl460 Gen9 и ПО виртуализации VMware vSphere Enterprise Plus. Архитектура подсистемы серверной виртуализации показана на рисунке ниже.



Рис. Архитектура подсистемы серверной виртуализации


Для защиты от сбоя одного хоста использовалась кластерная технология VMware High Availability, которая позволяет рестартовать виртуальные машины сбойного хоста на других.


Образы и данные виртуальных машин хранятся на нескольких СХД. Бизнес-критичные данные дублируются на как минимум 2-мя СХД и презентуются хостам через виртуализатор СХД EMC VPLEX. Это позволяет исключить одну СХД как точку отказа. Сбои на 2-ух контроллерной СХД обычно редки, но они бывают. Может отказать батарейка кэш-памяти одного контроллера, что приведет к выключению кэша и существенной деградации производительности.


Данные передаются через сеть хранения данных по Fibre Channel с использованием 2-ух фабрик для резервирования от логических и физических сбоев. Фабрики между ОЦОД и РЦОД не объединяются из-за существенного расстояния между ними (более 600 км).


Для защиты от катастрофы в ОЦОД применено апробированное решение на базе VMware SRM и репликации с помощью выделенных устройств — EMC RecoverPoint. Они дублируют все операции вывода из ОЦОД в РЦОД в асинхронном режиме. В случае достаточной пропускной способности канала такая репликация дает RPO близкое к 0. Устройства RecoverPoint позволяют сжимать трафик между площадками и передавать только уникальные блоки, что снижает требования к каналу.


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


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


Преимущество созданного нами комплекса решений EMC VPLEX + EMC RecoverPoint + VMware vSphere HA позволяет обеспечить защиту от сбоев на базе 3-ех ЦОД – двух близко расположенных и одного расположенного относительно далеко на случай катастрофы. Это позволяет банку получить синхронную репликацию с нулевой потерей данных в случае сбоя в одном ЦОД, а также защиту от глобальных катастроф.


В нашем проекте мы реализовали 2-е площадки – ОЦОД и РЦОД. Но в ОЦОД мы разместили 2-а комплекта оборудования. Получается, как 2-а ЦОД в одном. В обычном случае полезная нагрузка работает на обоих, но в случае отказа продуктивная нагрузка может работать и на одном комплекте. Это позволяет обеспечить самые высокие требования по доступности информационных систем в различных случаях сбоев.


Решение в части СПД


Итак, в части СПД нам необходимо было построить катастрофоустойчивое решение на три ЦОДа для обеспечения максимальной доступности ИС.


Заказчик к началу проекта уже имел два ЦОДа с сетевым оборудованием Cisco. Использовались коммутаторы Nexus, включая FEX, а также DMVPN с филиальной сетью. Естественно, это определило сохранение вендора при модернизации сети.


Архитектура


В целом архитектура в основном ЦОДе у нас вышла классическая:


• в качестве ядра Nexus 5672;
• в качестве коммутаторов доступа Nexus 2000 серии;
• для портов управления использовался Catalyst 2960X.


В WAN и Internet сегментах:


• пара маршрутизаторов ASR 1001X для подключения к операторам с L3VPN облаками;
• пара маршрутизаторов ASR 1001X для организации функций DMVPN и QOS;
• маршрутизаторы ISR4431 для подключения к Интернет;
• файерволлы PaloAlto для связи с офисами;
• файерволлы Chackpoint для связи с Интернет.


В резервном ЦОДе все аналогично за исключением переиспользуемых моделей Nexus 5548UP и ASR1001. Также нужно упомянуть про Out of band (OOB) интернет-каналы в каждый ЦОД с отдельными межсетевыми экранами. Схемы там самые классические, поэтому здесь их даже не прилагаем.


Связь с сетью Интернет


Со связью с Интернетом получилось более интересное решение. У заказчика в наличии была только одна сеть PI /24. При этом было необходимо:


• анонсировать PI сеть только из основного ЦОД (ОЦОД) пока он жив (как в Интернет, так и вовнутрь СПД);
• PI сеть должна переезжать в РЦОД при отказе всего ЦОД;
• PI сеть должна переезжать при двойных отказах одного типа оборудования в ОЦОД: ядро, Интернет-каналы, маршрутизаторы, файерволлы или WAN коммутаторы;
• PI сеть не должна переезжать при двойных отказах аналогичного оборудования в резервном ЦОДе;
• PI сеть не должна переезжать при двойных отказах каналов между ЦОД;
• доступность Интернет-каналов должна проверяться по нескольким подсетям из Интернет (например, 8.8.8.0/24).


Таким образом, доступность ОЦОД из РЦОД нужно было проверять через внутреннюю сеть и через Интернет одновременно. Проверка доступности Интернета у нас осуществляется с помощью Cisco IP SLA. Естественно, в ОЦОД и РЦОД используется условное анонсирование PI сети по BGP в сторону операторов, а также условное анонсирование в локальную сеть в ОЦОД.


Ниже приведена логическая схема:




Обнаруженные интересные детали с оборудованием Nexus


Как уже отмечалось, в проекте были использованы коммутаторы Nexus 5672UP. При их использовании обнаружено 2 бага, которые Cisco планирует переделать в фичи :)


Первое — медные breakout DAC кабели 40G на 4x10G. В нашем случае эти кабели были совместимы со всем оборудованием, но они периодически флаппали. Понятно, что даунтайм небольшой, но это происходило достаточно часто. Сами кабели изображены ниже:



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



Вроде бы Cisco пока планирует исправлять документацию – исключать данные кабели из списка совместимых. Так что лучше не экономить и покупать только оптические DAC кабели.
Про Nexus 7000 серии есть вот такой документ. Ключевая фраза «Passive copper optic cables are not supported on the non-EDC ports». Получается, что вся пассивная QSFP медь может некорректно работать и на Nexus 5600 серии.


Второе — Microsoft SLB. Все помнят режим, при котором на сети настраиваются статические ARP и MAC записи без IGMP. Причем, если не указать статические MAC записи, то пакеты будут флудиться по всему VLAN. Так вот, теперь последнее утверждение не будет верным для Nexus 5672UP. Чтобы данные передавались, нужно будет в обязательном порядке указывать статические mac записи. Под этот кейс Cisco тоже планирует изменить документацию.


Предложенное решение в части СПД – связь между ЦОД (DCI) и офисов (WAN)


При модернизации связь между Main ЦОД и DR ЦОД, а также между ЦОД и филиалами должна быть переведена на шифрование с ГОСТ алгоритмами. Между ОЦОД и РЦОД достаточно было L3 связности.


Сетевое оборудование Cisco ничего не должно знать о криптошлюзах, поэтому поверх шифрованных туннелей мы построили GRE/mGRE. Таким образом, остаются работать протокол динамической маршрутизации EIGRP.


Криптошлюзы в обоих ЦОД должны строить VPN-туннель между собой, а также до филиалов. В качестве криптошлюзов были выбраны S-Terra. Одной из причин стала очень похожая настройка на Cisco. В принципе такой вариант работы с S-Terra описан на их сайте, поэтому ничего сложного обычно не возникает.


Время восстановления сети после сбоев


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


Все сетевое оборудование и каналы резервировались по схеме 1+1.Для резервирования на канальном уровне использовались популярные вещи LAСP и VPC с субсекундным временем восстановления после отказа.


В данном проекте у заказчика уже использовались протоколы EIGRP в локальной сети, между филиалами и BGP для взаимодействия с операторами. В случае локальной сети EIGRP делает конвергенцию с субсекундными таймерами при обнаружении отказа. По сравнению с OSPF протокол EIGRP для таких результатов гораздо проще настраивать. Нужно только выполнять одно из двух условий для резервного маршрута – equal cost multi path (ECMP) или feasible successor. В OSPF для этого придется тюнить много таймеров.


В целом, в локальной сети практически невозможны неявные отказы оборудования или кабелей. Поэтому общее время конвергенции будет меньше 1 секунды. Если говорить про WAN сегмент и всю распределенную сеть (связь между филиалами и ЦОД), то максимальное время восстановления при отказах составит 5 секунд.


В случае связи с интернетом, время восстановления получается, конечно, больше – до 1 минуты. У заказчика уже была своя PI сеть. В рамках модернизации в BGP стали принимать всю таблицу маршрутизации. Собственно это нужно, чтобы защититься от некоторых отказов внутри интернет провайдеров. Так, мы исключаем ситуацию, когда BGP peer виден, но дальше со связью все плохо.


Чтобы добиться восстановления интернета за 1 минуту при отказе оборудования или канала необходимо договариваться с операторами об уменьшении keepalive и hold таймеров. На практике у нас показывают хорошие результаты keepalive в 3 секунды и hold в 10 секунд. Флапов при таких значениях никогда не происходит, хотя при 2-х и 7 секунд соответственно — уже наблюдаются. Правда, не все операторы готовы по умолчанию поддерживать такие значения, но договориться можно. :)


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


Авторы материала:


Артем Бурдин, инженер-проектировщик отдела вычислительных систем центра компетенций по вычислительным комплексам компании «Техносерв»


Михаил Шеронкин, руководитель направления корпоративных сетей центра компетенций по сетевым технологиям компании «Техносерв»

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

https://habrahabr.ru/post/332982/


Вуз или техникум: куда поступать, чтобы удачно трудоустроиться и хорошо зарабатывать?

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

[Из песочницы] Как я заказывал мобильное приложение

Четверг, 13 Июля 2017 г. 13:46 + в цитатник
… или история о том, как увеличить продажи студии разработки.

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

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

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

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

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

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

image

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

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

Этап 2 (выбор подрядчика)

Зачем я посылал легенду? Понятное дело, чтобы выбрать наиболее адекватного исполнителя. Того, кто предложит мне за реальный срок и вменяемые деньги сделать то, что мне надо.
В ответ на мою легенду мне присылали брифы. О, это шедевры издевательского искусства над заказчиком. Word, Excel, интерактивные варианты на сайтах, терминология: аж зубы разболелись. Только один из двадцати двух перезвонил мне, подробно спросил, что мне нужно и на следующий день прислал письмо с оффером по цене и срокам. Как думаете, кому в своем тендерном списке я поставил плюсик?

image

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

Этот же призыв относится и к этапу составления подробного ТЗ на разработку, когда все предварительные переговоры уже прошли и клиент определился.

Этап 3 (цена)

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

image

На уточнение цены по предварительному ТЗ в трех студиях нам понадобилось около одной недели! Это уже после брифа, после пресейла… Вы только вдумайтесь: целая рабочая неделя, чтобы добиться ответов на вопросы: «а за все, что мы просим, сколько?».

Естественно, самый вменяемый и самый быстрый получил еще один плюсик в тендерном списке.

Этап 4 (MVP)

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

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

Финал (чем еще зацепить на сайте)

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

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

image

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

Рынок приложений сейчас на стадии бурного роста. Это не просто модно. Это скоро станет must have, так же, как рынок сайтостроения 10 лет назад. И поэтому надо быть ближе к простому клиенту. Человечнее.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332978/


Метки:  

Google Developer Days приходит в Европу

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

image


Нам в Google очень нравится встречаться и общаться с разработчиками. Это помогает нам лучше понимать ваши потребности и улучшать наши продукты, чтобы они подходили для самых разных регионов, где вы работаете. Мероприятия для разработчиков — отличный способ сделать это. Именно поэтому мы проводим различные мероприятия, где мы можем общаться напрямую с разработчиками. Сегодня мы запустили специальный сайт и открываем регистрацию для европейской части нашей глобальной серии мероприятий для разработчиков – Google Developers Days (GDD).


Google Developers Days — это событие, на котором мы расскажем про последние обновления наших продуктов и платформ для разработчиков, которые помогут вам и дальше разрабатывать высококачественные приложения, развивать ваши продукты и сохранять активную базу пользователей. GDD Europe пройдет 5 и 6 сентября в Кракове в Польше. Вас ожидают технические доклады по целому ряду продуктов, включая Android, Mobile Web, Firebase, Cloud, Machine Learning и IoT. В дополнение к техническим докладам у всех участников будет возможность присоединиться к практическим занятиям, один на один пообщаться с сотрудниками Google и Google Developers Experts.



Если вы заинтересованы и хотите к нам присоединиться, то регистрация уже открыта. Сейчас билеты можно купить со скидкой, по цене в 199$ (полная цена 250$). Учтите, что количество билетов ограниченно.


Если вы по каким-то причинам не можете добраться до Кракова — никаких проблем! Все доклады будут доступны в прямом эфире на YouTube канале Google Developers, а после будут доступны в виде записей. Всегда здорово смотреть такие мероприятия в компании с другими разработчиками, поэтому в разных городах и регионах будут проходить GDD Extended. Это такой формат, когда разработчики собираются для совместного просмотра и обсуждения прямой трансляции. Как правило, Google Developers Groups в разных городах организуют такие мероприятия. Если в вашем регионе кто-то уже организовал GDD Extended, то подумайте о том, чтобы посетить его. Не нашли такое поблизости, но всё ещё хотите собрать коллег по цеху, чтобы вместе обсудить последние новинки? Вы можете организовать GDD Extended самостоятельно.


Независимо от того, есть ли у вас возможность присоединиться к нам лично или удаленно, будьте в курсе последних новостей, следите за специальным хештегом – #GDDEurope в Twitter, Facebook и Google+.


С нетерпением ждем скорой встречи с вами в Европе!

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

https://habrahabr.ru/post/332968/


Агрегация интернет-каналов через операторов сотовой связи

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


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


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


  1. «С неба». Спутник, стратостаты и прочие технологии, которые ретранслируют канал передачи данных «сверху».
  2. С помощью наземной инфраструктуры. Любые способы передачи радиосигнала через базовые станции, установленные на земле. Это может быть инфраструктура сотовых операторов, Wi-Fi-инфраструктура, дедушка радио Ethernet и т. д.

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


Суть агрегации каналов передачи данных можно выразить коротко: суммировать емкость, предоставленную разными физическими линиями. Условно, если у нас есть четыре канала емкостью 1 Мбит/с каждый, на выходе мы должны получить один канал емкостью 4 Мбит/с. В нашем случае есть четыре оператора сотовой связи, через каждый из них в пределе можно выжать до 70 Мбит/с, а в сумме, если звезды сойдутся правильно, — 280 Мбит/с.


Кто-то скажет, что 280 Мбит/с никак не хватит на всех пассажиров поезда, коих в среднем 700 человек, и что получить такую скорость за пределами населенных пунктов нельзя. Более того, там, где связи нет совсем, никакой магии не произойдет: в транспорте также связи не будет. Конечно, этот кто-то совершенно прав. Поэтому мы решаем задачу не комфортного канала для всех, а хоть какого-то — там, где обычные смартфоны физически не в состоянии установить связь.


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


Суть проекта


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


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


image


Инфраструктура операторов сотовой связи дает основу для задачи:


  1. Конвергентная среда. Передача данных происходит через открытый интернет и разных операторов связи. Это значит, что EtherChannel и другие аппаратно поддерживаемые протоколы работать, естественно, не будут.
  2. Высокая энтропия каналов ПД при движении транспорта. Емкость и задержка в каждом канале непредсказуемо и быстро изменяется, поскольку сильно зависит от расстояния до БС оператора, ее загрузки, помех и т. д.

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


Со стороны клиентского оборудования:


  1. Настройка сети. Через независимые каналы передачи данных устанавливаются L3-тоннели до единой точки агрегации (любой внешний сервер с настроенным NAT). Один канал — один тоннель. Поднимается интерфейс, который будет шлюзом по умолчанию для всей сети.
  2. Специальное ПО. Делает всего две вещи: мониторит целевые метрики качества каналов и тоннелей, потом на основе метрик распределяет NAT-трафик по тоннелям.

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


К слову, есть решения разного уровня приемлемости, в которых агрегация работает. Например, стандартный bonding интерфейсов в Linux. Поднимаем L3-тоннель через любой доступный инструментарий, хоть через VPN-сервер или SSH-тоннель, настраиваем вручную маршрутизацию и добавляем в бондинг виртуальные интерфейсы тоннелей. Всё будет нормально, пока емкость тоннелей в каждый момент времени одинакова. Дело в том, что при такой топологии сети работает только режим агрегации balance-rr, т. е. в каждый тоннель попадает равное количество байтов по очереди. Это значит, что если у нас будет три канала емкостью (Мбит/с) 100, 100 и 1, то результирующая емкость окажется 3 Мбит/с. То есть минимальная ширина канала умножается на количество каналов. Если емкость — 100, 100, 100, то результирующая будет 300.


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


Qedr Train


Начали с мониторинга метрик операторов сотовой связи (уровень сигнала, тип сети, ошибки сети и т. д.) Нужно отметить, что модемы выбирались как раз исходя из того, как хорошо они могут отдавать метрики операторов. Мы выбрали модем SIM7100 производства компании Simcom. Все интересующие нас метрики отдаются через обращение в последовательный порт. Этот же модем также отдает GPS/ГЛОНАСС-координаты с хорошей точностью. Также необходимо отслеживать статус метрик компьютера (температуру CPU, SSD, свободное количество оперативной памяти и дискового пространства, S.M.A.R.T. показатели SSD). Отдельно модуль мониторит статистику сетевых интерфейсов (наличие ошибок на прием и отправку, длина очереди на отправку, количество переданных байтов). Поскольку производительность устройства крайне ограничена и пакет передаваемых данных должен быть минимален, а также учитывая простоту мониторинга этих метрик под Linux через /proc/sys, вся подсистема мониторинга также была разработана с нуля.


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


  1. При запуске читает конфиг в формате JSON, в котором описаны настройки виртуальных интерфейсов. Адреса серверов агрегации подтягиваются из центральной системы динамически. Это обеспечивает балансинг нагрузки на серверную часть и условно бесшовный хендовер при сбое любого сервера агрегации.
  2. На основе прочитанных данных создает L3-тоннели до серверов агрегации. Настраивает маршрутизацию. Тоннель опционально может иметь сжатие данных и шифрование.
  3. На основе данных от модуля мониторинга присваивает каждому тоннелю свой «вес». Чем больше вес, тем больше трафика пойдет именно через этот тоннель. Вес каждого тоннеля актуализируется каждую секунду
  4. Статистика работы устройства, геопозиция и метрики бизнес-логики накапливаются в течение 10 минут, формируется транзакция. Транзакции хранятся в локальной базе Tarantool и отправляются в «голову» нативным механизмом репликации данных СУБД «Тarantool», за что отдельное спасибо разработчикам и активному комьюнити этой СУБД.

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


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


Стек технологий проекта стандартный. Визуализация: Grafana, OpenStreetMap, сервер приложений на клиентской и серверной стороне: Go, СУБД Tarantool.


image


Tarantool


История эволюции СУБД в наших проектах начинается с PostgreSQL в 2009 году. Мы успешно хранили в нем геоданные от бортовых устройств, установленных на спецтранспорте. Модуль PostGIS вполне справлялся с задачами. Со временем очень сильно стало не хватать производительности в обработке данных без схемы хранения. Экспериментировали с MongoDB c версии 2.4 до версии 3.2. Пару раз не смогли восстановить данные после аварийного отключения (полностью дублировать данные не позволял бюджет). Далее обратили внимание на ArangoDB. Если учесть, что бэкенд в то время мы писали на JavaScript, стек технологий выглядел очень приятно. Однако и эта базейка, побыв с нами добрые два года, ушла в прошлое: мы не смогли контролировать потребление оперативной памяти на больших объемах данных. В этом проекте обратили внимание на Tarantool. Ключевым для нас было следующее:


  1. Встроенный механизм транзакций.
  2. Хранение нереляционных данных.
  3. Система хранения данных InMemory и Vinyl (на диске).
  4. Механизм мастер-слейв репликации.
  5. Эффективная работа на мощном железе в ЦОДе и на очень ограниченном оборудовании в транспортном средстве.

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


У нас всего три основных профиля данных: это финансовые операции, временные ряды (т. е. журналы работы систем) и геоданные.


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


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


Геоданные — простой трек транспортного средства по пути следования. Каждую секунду мы опрашиваем GPS-датчик, встроенный в модем, и получаем координаты и высоту над уровнем моря. Трек длительностью 10 минут собирается в пакет и отправляется в ЦОД. По требованию заказчика эти данные должны храниться вечно, что при возрастающем количестве транспортных средств заставляет заранее очень серьезно планировать инфраструктуру. Однако в Tarantool шардинг сделан очень просто, и ломать голову над масштабированием хранилища под самые быстрорастущие данные никакой необходимости нет. Резервная копия данных не пишется, поскольку исторической ценности сейчас в этих данных нет.


Для всех типов данных мы использовали движок Vinyl (хранение данных на диске). Финансовых операций не так много, и нет смысла всегда хранить их в памяти, как и журналы, естественно, и геоданные, пока по ним не будет производиться аналитика. Когда аналитика потребуется, в зависимости от требований к быстродействию, возможно, будет иметь смысл подготовить уже агрегированные данные и хранить их на движке InMemory, а далее анализировать эти данные. Но всё это начнется, когда заказчик сформирует свои требования.


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


CPU: ARMv8, 4Core, 1.1 Ghz
RAM: 2 Gb
Storage: 32 GB SSD
Спецификация сервера ЦОДа:
СPU x64 Intel Corei7, 8Core, 3.2 Ghz
RAM: 32 Gb
Storage: 2 x 512 Gb (Soft Raid 0)


Как я уже говорил, репликация данных из транспорта в ЦОД налажена средствами самой СУБД. Шардинг данных между десятью шардами — также функционал «из коробки». Вся информация присутствует на сайте Tarantool, и описывать это тут, думаю, не нужно. В настоящий момент система обслуживает всего 866 транспортных средств. Заказчик планирует расширение до 8 тысяч.


Александр Родин, CIO и основной разработчик (да, такое случается не только в стартапах) проекта Qedr Train компании «Региональные телематические системы». Если возникнут вопросы, пишите в комменты или на a.rodin@r-t-s.ru. Постараюсь по возможности ответить всем.

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

https://habrahabr.ru/post/332950/


Метки:  

Вышел первый накопитель на 64-слойной 3D TLC NAND от компании Intel

Четверг, 13 Июля 2017 г. 12:47 + в цитатник
В конце июня компания Intel представила свой первый SSD на базе 64-слойной 3D TLC NAND флеш-памяти — Intel SSD 545s. Этот SSD с SATA-интерфейсом представляет собой первое запоминающее устройство потребительского уровня, в котором используется новая трёхмерная 64-слойная память второго поколения.

/ Flickr / Laineema / CC

Модель 545s — это наследник прошлогоднего Intel SSD 540s, который должен закрыть определённые пробелы, образовавшиеся в технологической дорожной карте Intel. На рынке потребительских твердотельных накопителей ИТ-гигант в последнее время делал упор на продвижение бюджетных моделей, базировавшихся на контроллерах Silicon Motion. Причём в ряде SSD, например, в том же в Intel SSD 540s, Intel отказывались от использования флеш-памяти собственного производства в пользу планарных чипов от SK Hynix.

Intel SSD 545s же оказывается на ступеньку выше своего предшественника. В запоминающем устройстве используется контроллер SMI SM2259, являющийся улучшенной версией SM2258 с более высокой производительностью. Повышенную скорость работы обеспечивает и новая IMFT 3D TLC NAND второго поколения, обладающая вдовое большим количеством слоев. Контроллер также работает с ECC-памятью — это делает 545s более устойчивым к повреждениям данных.

Сравнение спецификаций 545s и 540s

Для 512-гигабайтного Intel SSD 545s производитель указывает скорость последовательного чтения 550 Мбайт/с, а записи — 500 Мбайт/с. В случае произвольного чтения производительность накопителя составляет порядка 75 тыс. IOPS, а при записи — 90 тыс. IOPS. По словам представителей компании Intel, новый SSD превосходит своего предшественника по показателям быстродействия и способен конкурировать с Samsung 850 EVO и Crucial MX300. Примерно к этому же уровню приведена и цена нового накопителя — $179. По параметрам же «выносливости» Intel SSD 545s своих конкурентов превосходит. Ресурс перезаписи Intel SSD 545s, по оценкам производителя, составит 288 Тбайт.

Накопитель уже поступил в продажу, однако ввиду достаточно скоромных объёмов производства 64-слойной памяти его доступность пока серьёзно ограничена. Сейчас представлен лишь 2,5-дюймовый SSD ёмкостью 512 Гбайт.

Однако Intel планирует использовать более маленькие кристаллы 256Gb 64L TLC для версий SSD 545s всех объемов. Кристалл 512Gb 64L TLC пока не попал в массовое производство, а ИТ-гигант хочет выпустить всю линейку потребительских накопителей на рынок как можно скорее. В дальнейшем модельный ряд Intel 545s пополнится запоминающими устройствами ёмкостью от 128 Гбайт до 2 Тбайт. Правда, конкретные сроки компания Intel все же не назвала.

Отметим, что работу над созданием 3D TLC NAND успешно ведет и компания Toshiba. 11 июля компания сообщила о разработке первой в мире флеш-памяти TLC BiCS FLASH с объемной компоновкой кристаллов с использованием межслойных соединений (Through Silicon Via, или TSV). Образцы будут представлены публике в текущем полугодии.

Инженеры компании объединили 8 кристаллов 48-слойной памяти 3D NAND и создали микросхему объемом 512 Гбайт. По словам производителя, новая память найдет применение в SSD верхнего ценового сегмента.

P.S. А вот еще несколько материалов из нашего блога:

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

https://habrahabr.ru/post/332976/


Метки:  

[Перевод - recovery mode ] Import() из webpack вскоре освоит JS+CSS, а вот как вы можете пользоваться этим уже сейчас

Четверг, 13 Июля 2017 г. 12:40 + в цитатник
image

Полтора месяца назад создатель webpack Тобиас Копперс выпустил “Большой план” для CSS в Webpack в своей статье "Новый рабочий процесс для CSS (шаг1)".

Самый первый вывод, который можно сделать — заключался в том, что разделение кода CSS станет приоритетом первого класса. Вы сможете получить css-файлы, сгенерированные для каждого из ваших динамических фрагментов кода, а вызовы import() вернут вам 2 файла: JS + CSS.

Вот цитата из статьи:

Большой план


В долгосрочной перспективе мы хотим сделать добавить “первоклассный” модуль поддержки CSS в webpack. Он будет работать следующим образом:
  • Мы добавляем новый тип модуля в webpack: Stylesheet (рядом с Javascript)
  • Мы настраиваем шаблоны фрагментов для записи двух файлов. Один для javascript и один для таблиц стилей (в файле .css).
  • Мы настраиваем логику загрузки блока, чтобы можно было загружать таблицы стилей. Нам нужно дождаться применения CSS или, по крайней мере, его загрузки, перед выполнением JS.
  • Когда мы генерируем загрузку фрагмента кода, мы можем параллельно загружать часть js и часть таблицы стилей (в сочетании с Promise.all)


Основой, конечно же, является возможность создания CSS-файлов для каждого динамического фрагмента. В настоящее время модуль extract-text-webpack-plugin не осуществляет этого. Доступная на сегодня бета-версия 3.0 не поддерживает данного функционала. Существует конечно мой extract-css-chunks-webpack-plugin, который какое-то время находился в активном пользовании, но он недостаточно хорош. Недостаточно хорошо он потому, что компиляция выполняется медленно и не увеличивает кеширование в браузере. Причина в том, что он создает 2 разных фрагмента JS для того, что в основе всей этой идеи должно идти как неделимое целое. Эти фрагменты:

  • Один без CSS-инъекции через загрузчик стилей
  • Другой с CSS-инъекцией через загрузчик стилей


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

Предыстория


Для того, чтобы всё это имело смысл, в случае если вы впервые слышите об этом, то вам вероятнее всего будет интересна следующая статья: Code Cracked for Code-Splitting + SSR in Reactlandia: React Universal Component + Webpack Flush Chunks and more [ENG]

Если обобщить написанное в статье, упомянутой выше, есть следующие компоненты: react-universal-component и webpack-flush-chunks по средствам которых вы можете легко и универсально рендерить свое приложение одновременно с разделением кода. Впервые в качестве общедоступного пакета NPM (не требуется никаких фреймворков). Для тех, кто не в курсе, вынос заключается в следующем: рендер на стороне сервера (SSR) — это решённая проблема, разделение кода — это решённая проблема, но до этих самых пор использование обоих разом оставалось проблемой не разрешённой.

Больше не нужно жертвовать SEO / SSR для разделения кода и/или наоборот.

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

На самом деле, через статически разделяемый CSS вы отправляете меньше байтов клиентам, чем популярные решения «render path» du jour (поскольку они должны отправлять определения вашего CSS как в фрагменты JS, так и в дополнительный CSS). И, что еще важнее, это также экономит много потраченных циклов, генерирующих CSS во время рендеринга на серверной и клиентской сторонах.

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

Введение в Babel-Plugin-Dual-Import + Extract CSS Chunks Webpack Plugin 2.0


babel-plugin-dual-import преобразует ваш запрос в Promise.all и, в качестве бонуса, он автоматически выдает вам webpackChunkName. “Волшебные комментарии” настолько волшебны, что они исчезают! Разумеется, под капотом я использую их для генерации имен ваших фрагментов кода.

Что касается extract-css-chunks-webpack-plugin 2.0, я обошёл серьезную проблему производительности с точки зрения времени сборки (не более двух JS-фрагментов), и теперь все, с чем вы имеете дело, это таблицы стилей, которые браузеры ваших пользователей могут кэшировать. И да, быстрая замена модулей (HMR) все еще работает (лучше, чем когда-либо на самом деле).

Также обратите внимание: все эти четыре пакета беспрепятственно работают вместе. Я условно называю это “универсальным” семейством пакетов. Разумеется, все они могут быть индивидуально использованы, потому что это то, в чём заключается гибкая разработка фреймворков. Но естественно лучше всего работают они вместе. Наслаждайтесь.

Установка


Так как мы в первую очередь внедряем плагин babel, на том и сосредоточимся:
yarn add --dev babel-plugin-dual-import


.babelrc:
{
    "presets": [whatever you usually have],
    "plugins": ["dual-import"]
}


App.js:
import('./Foo.js')
      V V V V V V
import { importCss } from 'babel-plugin-dual-import/importCss.js'

Promise.all ( [
  import( /* webpackChunkName: 'Foo' */ './Foo'),
  importCss('Foo')
] ).then(promises => promises[0]);


И если вы используете всё это динамически, необходимо добавить:
import('../base/${page}')
      V V V V V V
import { importCss } from 'babel-plugin-dual-import/importCss.js'

Promise.all([
  import( /* webpackChunkName: 'base/[request]' */ `./base/${page}`),
  importCss(`base/${page}`)]
).then(promises => promises[0]);

Если вы ранее смотрели, как работает webpack-flush-chunks, новое дополнение — это cssHash, которое похоже на то, что webpack кладёт в bootstrap скрипт, сопоставляя фрагменты javascript с их идентификаторами. cssHash ориентирует имена фрагментов css в файлы их стилей. Babel-plugin-dynamic-import запрашивает таблицы стилей оттуда параллельно с импортом javascript.

Заключение


Не слишком много чего осталось сказать, потому git clone демо работы всех четырёх пакетов отсюда и вперёд.
Если вы совершенно не знакомы с React Universal Component + Webpack Flush Chunks, советую хотя бы просмотреть описание по диагонали. В настоящее время это единственное решение, объединяющее все это для разработчиков React, опасающихся избыточного количества фреймворков. Разработчиков, у которых были подобные проблемы, знайте, те дни закончились.



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

Ссылки:
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/332974/


Метки:  

[Из песочницы] Исторический очерк о великом математике Карле Фридрихе Гауссе

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

Карл Фридрих Гаусс


Математик и историк математики Джереми Грей рассказывает Гауссе и его огромном вкладе в науку, о теории квадратичных форм, открытии Цереры, и неевклидову геометрию*


image

Портрет Гаусса Эдуарда Ритмюллера на террасе обсерватории Геттингена // Карл Фридрих Гаусс: Титан науки Г. Уолдо Даннингтона, Джереми Грея, Фриц-Эгберт Дохе


Карл Фридрих Гаусс был немецким математиком и астрономом. Он родился у бедных родителей в Брауншвейге в 1777 году и скончался в Геттингене в Германии в 1855 году, и к тому времени все, кто его знал, считали его одним из величайших математиков всех времен.


Изучение Гаусса


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


Ранняя жизнь и путь к математике


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





Первоначально Гаусс собирался изучать филологию, приоритетный предмет в Германии того времени, но он также проводил обширные исследования по алгебраическому построению правильных многоугольников. В связи с тем, что вершины правильного многоугольника из N сторон задаются решением уравнения $inline$x^{(n – 1)} = 0$inline$ (что численно равно $inline$e^{(2ki \pi/17)} = cos(2k \pi/17) + i sin(2k \pi/17), k =0, 1, . . . 16)$inline$. Гаусс обнаружил, что при n = 17 уравнение факторизуется таким образом, что правильный 17-сторонний многоугольник может быть построен только по линейке и циркуля. Это был совершенно новый результат, греческие геометры не подозревали об этом, и открытие вызвало небольшую сенсацию — новости об этом даже были опубликованы в городской газете. Этот успех, который пришел, когда ему едва исполнилось девятнадцать, заставил его принять решение изучать математику.


Но то, что сделало его знаменитым, было два совершенно разных явления в 1801 году. Первым было издание его книги под названием «Арифметические рассуждения», которая полностью переписала теорию чисел и привела к тому, что она( теория чисел) стала, и до сих пор является, одним из центральных предметов математики. Она включает в себя теорию уравнений вида x ^ n — 1, являющейся одновременно очень оригинальной и в то же время легко воспринимаемой, а также гораздо более сложную теорию, называемую теорией квадратичной формой. Это уже привлекло внимание двух ведущих французских математиков, Джозефа Луи Лагранжа и Адриена Мари Лежандра, которые признали, что Гаусс ушел очень далеко за пределы всего того, что они делали.


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


Поздняя жизнь и семья


Первая работа Гаусса была математиком в Геттингене, но после открытия Цереры, а затем и других астероидов он постепенно переключил свои интересы на астрономию, а в 1897 году стал директором Геттингенской обсерватории, и занимал эту должность почти до самой смерти. Он также оставался профессором математики в Геттингенском университете, но это, похоже, не требовало от него большого преподавания, а записи о его контактах с молодыми поколениями была довольно незначительной. Фактически, он, кажется, был отчужденной фигурой, более комфортной и общительной с астрономами, и немногими хорошими математиками в его жизни.


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


Гаусс женился дважды, в первый раз довольно счастливо, но когда его жена Джоанна умерла во время родов в 1809 году, он снова женился на Минне Вальдек, но этот брак оказался менее успешным; Она умерла в 1831 году. У него было трое сыновей, двое из которых эмигрировали в Соединенные Штаты, скорее всего, потому что их отношения с отцом были проблемными. В результате в Штатах существует активная группа людей, которые ведут свое происхождение от Гаусса. У него также было две дочери, по одной от каждого брака.


Величайший вклад в математику


Рассматривая вклад Гаусса в этой области, мы можем начать с метода наименьших квадратов в статистике, который он изобрел, чтобы понять данные Пьяцци и найти астероид Церера. Это был прорыв в усреднении большого количества наблюдений, все из которых были немного не точными, чтобы получить из них наиболее достоверную информацию. Что касается теории чисел, говорить об этом можно очень долго, но он сделал замечательные открытия о том, какие числа могут быть выражены квадратичными формами, которые являются выражениями вида $inline$3x^2 + 5xy + 6y^2$inline$. Вам может казаться, что это важно, но Гаусс превратил то, что было собранием разрозненных результатов в систематическую теорию, и показал, что многие простые и естественные гипотезы имеют доказательства, которые лежат в том, что похоже на другие разделы математики вообще. Некоторые приемы, которые он изобрел, оказались важными и в других областях математики, но Гаусс обнаружил их еще до того, как эти ветви были правильно изучены: теория групп — пример.


Его работа по уравнениям вида $inline$x ^{(n - 1)} = 0$inline$ и, что более удивительно, по глубоким особенностям теории квадратичных форм, открыла использование комплексных чисел, например, для доказательства результатов о целых числах. Это говорит о том, что многое происходило под поверхностью предмета.


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


image

Поверхность с отрицательной кривизной, где сумма углов треугольника меньше, чем у треугольника на плоскости //source:Wikipedia


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


И мы также должны помнить, что Гаусс открыл, но не опубликовал довольно много. Никто не знает, почему он так много сделал для себя, но одна теория состоит в том, что поток новых идей, которые он держал в голове был еще более захватывающим. Он убедил себя в том, что геометрия Евклида не обязательно истинна и что по крайней мере одна другая геометрия логически возможна. Слава этому открытию досталась двум другим математикам, Бойяю в Румынии-Венгрии и Лобачевскому в России, но только после их смерти — настолько это было спорно в то время. И он много работал над так называемыми эллиптическими функциями — вы можете рассматривать их как обобщения синусоидальных и косинусных функций тригонометрии, но, если более точно, они являются сложными функциями комплексной переменной, а Гаусс изобрел целую теорию из них. Десять лет спустя Абель и Якоби прославились тем, что сделали то же самое, не зная, что это уже сделал Гаусс.


Работа в других областях


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


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


Прочное Наследие


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


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


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


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


image

Неевклидова геометрия // источник: Numberphile


Человек за легендой


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


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


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


Джереми Грей, доктор, заслуженный пр.фессор истории математики, Открытый университет.


-> Оригинал статьи


* Неточный перевод.

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

https://habrahabr.ru/post/332966/


[Перевод] 35 советов для тех, кто собирается на техническую конференцию

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

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

1. Не бойтесь знакомиться с людьми! Скажите им, что это ваша первая конференция, и в большинстве случаев они сами представят вас кому-нибудь ещё :)

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

3. Приносите визитки вашей организации, если вы не ищите работу. Приносите ваши персональные визитки, если вы её ищете. Если у вас нет визиток — сделайте их.

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

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

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

7. Если вам трудно пойти на контакт с незнакомыми людьми, используйте дежурный вопрос: «Над чем вы сейчас работаете?»

8. Рюкзак и кеды предпочтительнее, чем прикольная сумка для ноутбука и высокие каблуки (одевайтесь комфортно!).

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

10. Заранее планируйте расписание посещения секций и держите в уме запасные варианты на случай, если на какой-то из секций вам физически не хватит места.

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

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

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

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

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

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

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

18. Не чувствуйте себя так, словно вы обязаны посетить КАЖДОЕ выступление.

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

20. Не полагайтесь на WiFi, который будет на конференции.

21. Хорошо бы иметь закуску в вашем рюкзаке или карманах.

22. Выясните, будут ли после конференции доступны слайды или (даже лучше!) видео. Если будут — не волнуйтесь о том, что что-то пропустите, просто расслабьтесь и наслаждайтесь.

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

24. Во время кофе-брейка или обеда садитесь за стол со случайными людьми и общайтесь с ними.

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

26. Не бойтесь заходить на доклад или уходить с доклада в то время, когда он идёт. Только вам решать какой доклад интересен, а какой нет. Закон двух ног: если вам не нравится выступление — уходите. Сходите лучше по крайней мере на одно выступление не из вашего графика.

27. Если вы добились встречи и разговариваете с вашими героями  - не нервничайте! Это обычные люди, которые счастливы делать классные вещи.

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

29. ЗАБУДЬТЕ О ВАШЕЙ РАБОТЕ. Даже не пытайтесь делать её на конференции, потому что обязательно упустите что-то важное.

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

31. Кому нужны халявные брендированные сувениры? Главное — это общение и контакты! Встретьтесь с людьми, которые помогали вам многие годы, и скажите им спасибо.

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

33. Посещайте выступления, в которых рассказывается о технологиях, с которыми вы НЕ столкнётесь со дня на день, о технологиях, которые вы НЕ используете в повседневной трудовой деятельности.

34. Не забудьте дополнительный внешний аккумулятор (Power Bank)! Написание твитов и заметок быстро истощит аккумулятор вашего смартфона или другого гаджета.

35. После окончания доклада побыстрее подходите к докладчику, чтобы послушать беседу или задать вопросы. Некоторая бесценная информация поступает как раз из вопросов после завершения выступления.

А какой совет дали бы вы? Пишите в комментариях!


О переводчике

Перевод статьи выполнен в Alconost.

Alconost занимается локализацией приложений, игр и сайтов на 68 языков. Переводчики-носители языка, лингвистическое тестирование, облачная платформа с API, непрерывная локализация, менеджеры проектов 24/7, любые форматы строковых ресурсов, перевод технических текстов.

Мы также делаем рекламные и обучающие видеоролики — для сайтов, продающие, имиджевые, рекламные, обучающие, тизеры, эксплейнеры, трейлеры для Google Play и App Store.

Подробнее: https://alconost.com

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

https://habrahabr.ru/post/332958/


[Перевод] Как создаются изометрические миры

Четверг, 13 Июля 2017 г. 10:39 + в цитатник
image

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

Для этого я решил использовать Phaser с кодом на JS. В результате у нас получится интерактивная приложение HTML5.

Учтите, что это не туториал по разработке на Phaser, мы просто используем его для удобного ознакомления с базовыми концепциями создания изометрической сцены. Кроме того, в Phaser есть простые способы создания изометрического контента, например, Phaser Isometric Plugin.

Для упрощения при создании сцены мы будем использовать тайлы.

1. Игры на основе тайлов


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

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



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

[
 [1,1,1,1,1,1],
 [1,0,0,0,0,1],
 [1,0,0,0,0,1],
 [1,0,0,0,0,1],
 [1,0,0,0,0,1],
 [1,1,1,1,1,1]
 ]


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



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

[
 [3,1,1,1,1,4],
 [2,0,0,0,0,2],
 [2,0,0,0,0,2],
 [2,0,0,0,0,2],
 [2,0,0,0,0,2],
 [6,1,1,1,1,5]
 ]

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



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

for (i, loop through rows)
    for (j, loop through columns)
        x = j * tile width
        y = i * tile height
        tileType = levelData[i][j]
        placetile(tileType, x, y)

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

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

2. Изометрическая проекция


Лучшее техническое объяснение изометрической проекции, как мне кажется, дано в этой статье Клинта Белленджера:
Мы наклоняем камеру по двум осям (поворачиваем камеру на 45 градусов вбок, потом на 30 градусов вниз). При этом создаётся ромбическая сетка, в которой ширина ячеек в два раза больше высоты. Такой стиль стал популярным благодаря стратегическим играм и экшн-RPG. Если посмотреть в этом виде на куб, то мы видим три его стороны (верхнюю и две боковые).

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



Размещение изометрических тайлов


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

Исходная функция просто отрисовывает изображения тайлов в переданных ей x и y, а для изометрического вида нам нужно вычислить соответствующие изометрические координаты. Уравнения для этого представлены ниже. isoX и isoY обозначают изометрические координаты X и Y, а cartX и cartY — декартовы координаты X и Y:

//Преобразование из декартовых в изометрические координаты:
 
isoX = cartX - cartY;
isoY = (cartX + cartY) / 2;

//Преобразование из изометрических в декартовы координаты:
 
cartX = (2 * isoY + isoX) / 2;
cartY = (2 * isoY - isoX) / 2;

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

function cartesianToIsometric(cartPt){
    var tempPt=new Phaser.Point();
    tempPt.x=cartPt.x-cartPt.y;
    tempPt.y=(cartPt.x+cartPt.y)/2;
    return (tempPt);
}


function isometricToCartesian(isoPt){
    var tempPt=new Phaser.Point();
    tempPt.x=(2*isoPt.y+isoPt.x)/2;
    tempPt.y=(2*isoPt.y-isoPt.x)/2;
    return (tempPt);
}

Итак, мы можем использовать вспомогательный метод cartesianToIsometric для преобразования входных 2D-координат в изометрические внутри метода placeTile. За исключением этого, код отображения остаётся тем же, но нам нужно создать новые картинки тайлов. Мы не можем использовать старые квадратные тайлы из вида сверху. На рисунке ниже показаны новые изометрические тайлы травы и стен вместе с готовым изометрическим уровнем:



Невероятно, правда? Давайте посмотрим, как обычное двухмерное положение преобразуется в изометрическое:

2D point = [100, 100];
// изометрическая точка вычисляется следующим образом
isoX = 100 - 100; // = 0
isoY = (100 + 100) / 2;  // = 100
Iso point == [0, 100];

То есть входные данные [0, 0] преобразуются в [0, 0], а [10, 5] — в [5, 7.5].

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

function getTileCoordinates(cartPt, tileHeight){
    var tempPt=new Phaser.Point();
    tempPt.x=Math.floor(cartPt.x/tileHeight);
    tempPt.y=Math.floor(cartPt.y/tileHeight);
    return(tempPt);
}

(Здесь мы предполагаем, что высота и ширина тайла одинаковы, как и бывает в большинстве случаев.)

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

getTileCoordinates(isometricToCartesian(screen point), tile height);


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

Точки регистрации


Во Flash можно выбирать произвольные точки графики в качестве базовой точки или [0,0]. Аналогом этого в Phaser является Pivot. Когда мы располагаем графику, скажем, в точке [10,20], то эта точка Pivot соответствует [10,20]. По умолчанию [0,0] или Pivot считается левая верхняя точка. Если вы попробуете создать приведённый выше уровень с помощью этого кода, то вы не получите нужного результата. Вместо этого у вас получится плоская земля без стен, как показано ниже:



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



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

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

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

3. Движение в изометрических координатах


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

y = y + speed;
placetile(cartesianToIsometric(new Phaser.Point(x, y)))

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

Сортировка по глубине


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

for (i, loop through rows)
    for (j, loop through columns)
        x = j * tile width
        y = i * tile height
        tileType = levelData[i][j]
        placetile(tileType, x, y)

Представьте, что объект или персонаж находится на тайле [1,1], то есть на самом верхнем зелёном тайле в изометрическом виде. Для правильной отрисовки уровня персонаж нужно отрисовывать после отрисовки углового тайла стены, левого и правого тайла стены, а также земли, как показано на рисунке:



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

4. Создание графики


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

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

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

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

Посты по теме


5. Изометрические персонажи


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



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

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

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



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

Мы назначим две переменные, dX и dY, значение которых зависит от нажатых клавиш управления. По умолчанию эти переменные равны 0, а значения им присваиваются согласно таблице внизу, где В, Н, П и Л означают, соответственно верхнюю, нижнюю, правую и левую клавиши направления. Значение 1 под клавишей означает, что клавиша нажата, 0 — что она не нажата.

Клавиша    Положение
В Н П Л    dX dY
================
0 0 0 0     0  0
1 0 0 0     0  1
0 1 0 0     0 -1
0 0 1 0     1  0
0 0 0 1    -1  0
1 0 1 0     1  1
1 0 0 1    -1  1
0 1 1 0     1 -1
0 1 0 1    -1 -1

Теперь с помощью значений dX и dY мы можем обновлять декартовы координаты следующим образом:

newX = currentX + (dX * speed);
newY = currentY + (dY * speed);

Итак, dX и dY представляют собой изменение положения персонажа по X и Y в зависимости от нажатых клавиш. Как сказано выше, мы легко можем вычислить новые изометрические координаты:

Iso = cartesianToIsometric(new Phaser.Point(newX, newY))

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

Распознавание коллизий


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

tile coordinate = getTileCoordinates(isometricToCartesian(current position), tile height);
if (isWalkable(tile coordinate)) {
  moveCharacter();
} else {
  //ничего не делать;
}

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

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

Сортировка по глубине с персонажами


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

Чтобы хорошо разобраться в сортировке по глубине, нам нужно понять, что когда координаты X и Y персонажа меньше, чем у дерева, то дерево перекрывает персонажа. Когда координаты X и Y персонажа больше, чем у дерева, то персонаж перекрывает дерево. Когда их координаты X равны, то решение принимается только по координате Y: объект с большей координатой Y перекрывает другой. Если совпадают координаты Y, то решение принимается только по X: объект с большим X перекрывает другой.

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

6. Время для демо!


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

7. Собираемые предметы


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

Данные о предметах можно хранить прямо в данных уровня, как показано ниже:

[
[1,1,1,1,1,1],
[1,0,0,0,0,1],
[1,0,8,0,0,1],
[1,0,0,8,0,1],
[1,0,0,0,0,1],
[1,1,1,1,1,1]
]

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

Обычно в изометрической графике бывает множество проходимых тайлов. Допустим, у нас их 30. Если использовать приведённый выше подход, то если у нас есть N поднимаемых предметов, к уже имеющимся 30 тайлам потребуется ещё N x 30. Это не очень эффективно. Поэтому нам стоит создавать такие сочетания динамически. Для решения этой задачи можно использовать тот же способ, который мы использовали выше для размещения персонажа. Когда мы доходим до тайла с предметом, мы сначала отрисовываем тайл травы, а потом помещаем на него предмет. Таким образом в дополнение к 30 проходимым тайлам нам потребуется всего N тайлов предметов, но нам нужны будут числовые значения для обозначения каждого сочетания в данных уровня. Чтобы не вводить N x 30 значений, можно хранить отдельный массив pickupArray для хранения данных о предметах, отдельно от levelData. Законченный уровень с предметом показан ниже:



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

Собирание предметов


Распознавание предметов выполняется точно так же, как и распознавание коллизий, но после перемещения персонажа.

if(onPickupTile()){
    pickupItem();
}


function onPickupTile(){//проверяем, есть ли предмет на тайле с персонажем
    return (levelData[heroMapTile.y][heroMapTile.x]==8);
}

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

Стоит также заметить, что данные коллизий обычно никогда не меняются, а данные о предметах изменяются, когда мы подбираем предмет. (При этом обычно просто меняется значение в массиве levelData, например, с 8 на 0.)

Это приводит к проблеме: что случится, когда нам нужно перезапустить уровень, то есть восстановить все предметы на их исходных точках? У нас нет информации для этого, потому что массив levelData изменяется при поднятии предмета. Решение заключается в использовании копии массива уровня в процессе игры и сохранении неизменного массива levelData. Например, мы используем levelData и levelDataLive[], клонируем последний из первого при начале уровня, а затем меняем в процессе игры только levelDataLive[].

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

function pickupItem(){
    pickupCount++;
    levelData[heroMapTile.y][heroMapTile.x]=0;
    //создаём следующий собираемый предмет
    spawnNewPickup();
}

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

8. Тайлы-триггеры


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

Давайте посмотрим, как можно реализовать дверь, переносящую игрока на другой уровень. Тайл рядом с дверью будет триггером. Когда игрок нажимает клавишу x, то перемещается на другой уровень.



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

Логика реализации здесь такая же, как и для собираемых предметов. Для хранения значений тайлов-триггеров мы снова используем массив levelData. В нашем примере 2 будет означать тайл с дверью, а значение рядом с ним будет триггером. Я использовал 101 и 102, решив, что любой тайл со значением больше 100 будет активным тайлом, а значение минус 100 будет уровнем, на который он ведёт:

var level1Data=
[[1,1,1,1,1,1],
[1,1,0,0,0,1],
[1,0,0,0,0,1],
[2,102,0,0,0,1],
[1,0,0,0,1,1],
[1,1,1,1,1,1]];

var level2Data=
[[1,1,1,1,1,1],
[1,0,0,0,0,1],
[1,0,8,0,0,1],
[1,0,0,0,101,2],
[1,0,1,0,0,1],
[1,1,1,1,1,1]];

Код проверки на событие срабатывания триггера показан ниже:

var xKey=game.input.keyboard.addKey(Phaser.Keyboard.X);

xKey.onUp.add(triggerListener);// добавление Signal listener для события up

function triggerListener(){
    var trigger=levelData[heroMapTile.y][heroMapTile.x];
    if(trigger>100){//активный тайл
        trigger-=100;
        if(trigger==1){//переход на уровень 1
            levelData=level1Data;
        }else {//переход на уровень 2
            levelData=level2Data;
        }
        for (var i = 0; i < levelData.length; i++)
        {
            for (var j = 0; j < levelData[0].length; j++)
            {
                trigger=levelData[i][j];
                if(trigger>100){//находим новый активный тайл и помещаем на него персонажа
                    heroMapTile.y=j;
                    heroMapTile.x=i;
                    heroMapPos=new Phaser.Point(heroMapTile.y * tileWidth, heroMapTile.x * tileWidth);
                    heroMapPos.x+=(tileWidth/2);
                    heroMapPos.y+=(tileWidth/2);
                }
            }
        }
    }
}

Функция triggerListener() проверяет, больше ли 100 значение массива данных триггеров в заданной координате. Если это так, то мы определяем, на какой уровень нам нужно перейти, вычтя 100 из значения тайла. Функция находит тайл-триггер в новом levelData, который будет координатой создания персонажа. Я сделал так, чтобы триггер активировался при отпускании клавиши x; если просто считывать нажатую клавишу, то мы окажемся в цикле, который будет перебрасывать нас между уровнями, пока нажата клавиша, потому что персонаж всегда создаётся на новом уровне на активном тайле.

Вот работающее демо. Попробуйте пособирать предметы, наступая на них, и менять уровни, встав перед дверью и нажав x.

9. Снаряды


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

Интересно, что изометрическая высота соответствует высоте в двухмерном виде сбоку, хотя и меньше по величине. Здесь нет сложных преобразований. Если мяч в декартовых координатах находится в десяти пикселях над землёй, то в изометрических координатах он может быть над землёй в 10 или 6 пикселях. (В нашем случае соответствующей осью будет ось Y.)

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

Прежде чем мы начнём разбираться с скачками в изометрической системе, попробуем реализовать их в двухмерной декартовой системе. Обозначим силу отскока мяча переменной zValue. Для начала представим, что сила отскока мяча равна 100, то есть zValue = 100.

Мы используем две переменные: incrementValue, которая изначально имеет значение 0, и gravity, имеющая значение -1. В каждом кадре мы будем вычитать incrementValue из zValue и вычитать gravity из incrementValue для создания эффекта затухания. Когда zValue достигает 0, это значит, что мяч достиг земли. В этот момент мы меняем знак incrementValue, умножив её на -1, и превратив в положительное число. Это значит, что со следующего кадра мяч начнёт двигаться вверх, то есть отскочит.

Вот как это выглядит в коде:

if(game.input.keyboard.isDown(Phaser.Keyboard.X)){
    zValue=100;
}
incrementValue-=gravity;
zValue-=incrementValue;
if(zValue<=0){
    zValue=0;
    incrementValue*=-1;
}

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

function drawBallIso(){
    var isoPt= new Phaser.Point();//Не рекомендуется создавать точки в цикле обновления
    var ballCornerPt=new Phaser.Point(ballMapPos.x-ball2DVolume.x/2,ballMapPos.y-ball2DVolume.y/2);
    isoPt=cartesianToIsometric(ballCornerPt);//находим новое изометрическое положение для персонажа из положения на двухмерной карте
    gameScene.renderXY(ballShadowSprite,isoPt.x+borderOffset.x+shadowOffset.x, isoPt.y+borderOffset.y+shadowOffset.y, false);//отрисовка тени на текстуре рендера
    gameScene.renderXY(ballSprite,isoPt.x+borderOffset.x+ballOffset.x, isoPt.y+borderOffset.y-ballOffset.y-zValue, false);//отрисовка персонажа на текстуре рендера
}

См. интерактивный пример.

Играемая тенью роль очень важна, она добавляет реализма этой иллюзии. Кроме того, заметьте, что теперь мы используем две экранные координаты (x и y) для представления трёх измерений в изометрических координатах — ось Y в экранных координатах также является осью Z в изометрических координатах. Это может запутать.

10. Нахождение пути и движение по нему


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

Посты по теме



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

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

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

Поиск пути


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

easystar = new EasyStar.js();
easystar.setGrid(levelData);
easystar.setAcceptableTiles([0]);
easystar.enableDiagonals();// мы хотим, чтобы в пути были диагонали
easystar.disableCornerCutting();// без диагональных путей при движении в углах стен

Поскольку в массиве levelData содержатся только 0 и 1, мы можем сразу передать его в массив узлов. Значением 0 мы обозначили проходимый узел. Также мы включили возможность движения по диагонали, но отключили её, когда движение происходит рядом с углами непроходимых тайлов.

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

Мы будем распознавать нажатие мышью на любой свободный тайл в уровне и вычислять путь с помощью функции findPath. Callback-метод plotAndMove получает массив узлов созданного пути. Мы помечаем найденный путь на миникарте.

game.input.activePointer.leftButton.onUp.add(findPath)

function findPath(){
    if(isFindingPath || isWalking)return;
    var pos=game.input.activePointer.position;
    var isoPt= new Phaser.Point(pos.x-borderOffset.x,pos.y-borderOffset.y);
    tapPos=isometricToCartesian(isoPt);
    tapPos.x-=tileWidth/2;//настройка для нахождения нужного тайла для ошибки из-за округления
    tapPos.y+=tileWidth/2;
    tapPos=getTileCoordinates(tapPos,tileWidth);
    if(tapPos.x>-1&&tapPos.y>-1&&tapPos.x<7&&tapPos.y<7){//нажатие мышью внутри сетки
        if(levelData[tapPos.y][tapPos.x]!=1){//не тайл стены
            isFindingPath=true;
            //алгоритм делает своё дело
            easystar.findPath(heroMapTile.x, heroMapTile.y, tapPos.x, tapPos.y, plotAndMove);
            easystar.calculate();
        }
    }
}
function plotAndMove(newPath){
    destination=heroMapTile;
    path=newPath;
    isFindingPath=false;
    repaintMinimap();
    if (path === null) {
        console.log("No Path was found.");
    }else{
        path.push(tapPos);
        path.reverse();
        path.pop();
        for (var i = 0; i < path.length; i++)
        {
            var tmpSpr=minimap.getByName("tile"+path[i].y+"_"+path[i].x);
            tmpSpr.tint=0x0000ff;
            //console.log("p "+path[i].x+":"+path[i].y);
        }
        
    }
}



Движение по пути


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

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

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

function aiWalk(){
    if(path.length==0){//путь закончился
        if(heroMapTile.x==destination.x&&heroMapTile.y==destination.y){
            dX=0;
            dY=0;
            isWalking=false;
            return;
        }
    }
    isWalking=true;
    if(heroMapTile.x==destination.x&&heroMapTile.y==destination.y){//достигли текущей точки назначения, задаём новую, меняем направление
        //перед поворотом ждём, пока не войдём на несколько шагов на тайл
        stepsTaken++;
        if(stepsTaken/ставим персонажа в центр тайла    
        heroMapSprite.x=(heroMapTile.x * tileWidth)+(tileWidth/2)-(heroMapSprite.width/2);
        heroMapSprite.y=(heroMapTile.y * tileWidth)+(tileWidth/2)-(heroMapSprite.height/2);
        heroMapPos.x=heroMapSprite.x+heroMapSprite.width/2;
        heroMapPos.y=heroMapSprite.y+heroMapSprite.height/2;
        
        stepsTaken=0;
        destination=path.pop();//узнаём следующий тайл в пути
        if(heroMapTile.xdestination.x){
            dX = -1;
        }else {
            dX=0;
        }
        if(heroMapTile.ydestination.y){
            dY = -1;
        }else {
            dY=0;
        }
        if(heroMapTile.x==destination.x){
            dX=0;
        }else if(heroMapTile.y==destination.y){
            dY=0;
        }
        //......
    }
}

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

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

Можно посмотреть работающее демо.

11. Изометрический скроллинг


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



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

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

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

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

Все эти шаги можно выразить следующим образом:

  • Обновление декартовых координат X и Y угловой точки.
  • Преобразование в изометрическое пространство.
  • Вычитание этого значения из изометрического положения отрисовки каждого тайла.
  • Отрисовка на экране только заданного количества тайлов, начиная с этого нового угла.
  • Дополнительно: отрисовка тайла, только если новое изометрическое положение отрисовки находится в пределах экрана.

var cornerMapPos=new Phaser.Point(0,0);
var cornerMapTile=new Phaser.Point(0,0);
var visibleTiles=new Phaser.Point(6,6);

//...
function update(){
    //...
    if (isWalkable())
    {
        heroMapPos.x +=  heroSpeed * dX;
        heroMapPos.y +=  heroSpeed * dY;
        
        //перемещаем угол в противоположном направлении
        cornerMapPos.x -=  heroSpeed * dX;
        cornerMapPos.y -=  heroSpeed * dY;
        cornerMapTile=getTileCoordinates(cornerMapPos,tileWidth);
        //получаем новый тайл персонажа
        heroMapTile=getTileCoordinates(heroMapPos,tileWidth);
        //сортировка по глубине и отрисовка новой сцены
        renderScene();
    }
}
function renderScene(){
    gameScene.clear();//удаляем предыдущий кадр, потом отрисовываем заново
    var tileType=0;
    //ограничиваем цикл видимой областью
    var startTileX=Math.max(0,0-cornerMapTile.x);
    var startTileY=Math.max(0,0-cornerMapTile.y);
    var endTileX=Math.min(levelData[0].length,startTileX+visibleTiles.x);
    var endTileY=Math.min(levelData.length,startTileY+visibleTiles.y);
    startTileX=Math.max(0,endTileX-visibleTiles.x);
    startTileY=Math.max(0,endTileY-visibleTiles.y);
    //проверяем граничное условие
    for (var i = startTileY; i < endTileY; i++)
    {
        for (var j = startTileX; j < endTileX; j++)
        {
            tileType=levelData[i][j];
            drawTileIso(tileType,i,j);
            if(i==heroMapTile.y&&j==heroMapTile.x){
                drawHeroIso();
            }
        }
    }
}
function drawHeroIso(){
    var isoPt= new Phaser.Point();//Не рекомендуется создавать точки в цикле обновления
    var heroCornerPt=new Phaser.Point(heroMapPos.x-hero2DVolume.x/2+cornerMapPos.x,heroMapPos.y-hero2DVolume.y/2+cornerMapPos.y);
    isoPt=cartesianToIsometric(heroCornerPt);//находим новое изометрическое положение персонажа из положения на 2D-карте
    gameScene.renderXY(sorcererShadow,isoPt.x+borderOffset.x+shadowOffset.x, isoPt.y+borderOffset.y+shadowOffset.y, false);//отрисовываем тень на текстуре рендера
    gameScene.renderXY(sorcerer,isoPt.x+borderOffset.x+heroWidth, isoPt.y+borderOffset.y-heroHeight, false);//отрисовываем персонажа на текстуре рендера
}
function drawTileIso(tileType,i,j){//располагаем изометрические тайлы уровня
    var isoPt= new Phaser.Point();//не рекомендуется создавать точку в цикле обновления
    var cartPt=new Phaser.Point();//Добавлено для лучшей читаемости кода.
    cartPt.x=j*tileWidth+cornerMapPos.x;
    cartPt.y=i*tileWidth+cornerMapPos.y;
    isoPt=cartesianToIsometric(cartPt);
    //Можно оптимизировать дальше и не отрисовывать ничего за пределами экрана.
    if(tileType==1){
        gameScene.renderXY(wallSprite, isoPt.x+borderOffset.x, isoPt.y+borderOffset.y-wallHeight, false);
    }else{
        gameScene.renderXY(floorSprite, isoPt.x+borderOffset.x, isoPt.y+borderOffset.y, false);
    }
}

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

Пара примечаний:

  • При скроллинге нам может понадобиться отрисовка дополнительных тайлов на границах экрана, иначе по краям экрана тайлы будут появляться и исчезать.
  • Если в игре есть тайлы, занимающие несколько единичных размеров тайлов, то потребуется рисовать больше тайлов на границах. Например, если самый большой тайл из всего набора имеет размер X на Y, то потребуется отрисовывать на X больше тайлов слева и справа, и на Y больше тайлов сверху и снизу. Так мы гарантируем, что углы большого тайла будут видимы при скроллинге.
  • Нам по-прежнему нужно обеспечивать отсутствие пустых областей на экране, когда отрисовка выполняется рядом с границами уровня.
  • Уровень должен скроллиться только до тех пор, пока на соответствующем крае экрана не будет отрисован соответствующий крайний тайл. После этого персонаж должен продолжать двигаться в пространстве экрана без скроллинга уровня. Для этого нам нужно отслеживать все четыре угла внутреннего экранного прямоугольника и соответствующим образом управлять логикой скроллинга и перемещения персонажа. Готовы ли вы реализовать это самостоятельно?

Заключение


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

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

https://habrahabr.ru/post/332922/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1049 1048 [1047] 1046 1045 ..
.. 1 Календарь