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

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

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

[Перевод] Как переусложнить дверной замок

Пятница, 23 Июня 2017 г. 11:55 + в цитатник

Метки:  

Тринадцатый опрос Developer Economics

Пятница, 23 Июня 2017 г. 11:35 + в цитатник
Developer Economics — это самое большое в мире исследование, посвященное мировым трендам в области экономики приложений и разработки. Основано оно на опросе разработчиков и компаний, который проводит британская компания VisionMobile раз в полгода.



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

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

Опрос доступен по ссылке (в том числе и на русском): http://vmob.me/DE3Q17
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331488/


Метки:  

[Перевод] Вебинар: Как будут развиваться направленные кибер-атаки?

Пятница, 23 Июня 2017 г. 11:28 + в цитатник


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

Как было отмечено экспертами Verizon в своем отчете 2017 Data Breach Investigations Report, вредоносные программы использовались в 51% случаев, в результате которых происходила утечка данных (фигурирует в отчете как «подтвержденное раскрытие данных несанкционированному лицу»). Но на эти данные можно взглянуть с другой стороны: в почти половине случаев нарушений безопасности НЕ использовались вредоносные программы, а акцент ставился на усовершенствованные техники взлома.

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

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

Чтобы ознакомиться с полным анализом будущего направленных кибер-атак, мы предлагаем Вам запись вебинара, который недавно провел Технический директор антивирусной лаборатории PandaLabs Луис Корронс.*





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

https://habrahabr.ru/post/331486/


Метки:  

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

Пятница, 23 Июня 2017 г. 11:16 + в цитатник
Предлагаю продолжить добрую традицию, которая началась в пятницу чуть больше месяца назад. Тогда я поделилась с вами вводной статьёй о том, для чего нужно машинное обучение в страховой компании и как проверялась реалистичность самой идеи. Сегодня будет её продолжение, в котором начинается самое интересное — тестирование алгоритмов.



Цикл статей «Машинное обучение для страховой компании»


1. Реалистичность идеи
2. Исследуем алгоритмы
3. Оптимизация модели

Использование возможности встраивания скриптов Python в Azure для предобработки данных


В первой статье мы говорили о том, что Azure поддерживает использование Python-скриптов. Необходимый для этого модуль может принимать на вход два массива данных и zip-архив с дополнительными материалами (например, другими скриптами, библиотеками и пр).

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



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

Анализ используемых данных. Использование MS Analysis Service


Практически в любой задаче машинного обучения необработанные данные не дают удовлетворительного результата. Для выделения наиболее информативных для модели признаков потребуется data mining.

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

  • возраст;
  • id диагнозов;
  • количество пиков затрат за последние 3 месяца.

Однако так мы только увеличим количество признаков, никак их не обработав. Для этого используем MS Analysis Services, в котором для извлечения признаков применяется машинное обучение — в частности, упрощенный алгоритм Байеса.



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

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



Это только часть выбранных диагнозов. В каждом из диагнозов, с вероятностью от 85% до 100%, последует пик затрат. Их наличие стоит вынести в отдельный признак. Не стоит упускать и наличие обычных диагнозов, которые не обойдутся компании дорого. Поэтому следует провести нормировку найденных вероятностей и ввести новый признак, который будет представлять собой взвешенную сумму количества диагнозов за последние 90 дней.

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

Тестирование различных алгоритмов и выставление их параметров


Мы определись с параметрами, которые будут использованы для обучения. Рассмотрим несколько разных алгоритмов классификации: logistic regression, support vector machine, decision jungle/random forest, Bayesian network. Очевидным вариантом также являются нейронные сети, но это отдельная сложная тема и в данном случае этот алгоритм будет излишним.

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

Logistic regression


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

На начальном этапе он позволяет получить исходное значение в промежутке от минус до плюс бесконечности. Далее осуществим преобразование, используя сигмоидальную функцию вида 1/(1+e^(-score) ),, где score — это полученное ранее значение, осуществляем преобразование. Результатом будет число в пределах от -1 до +1. Решение о принадлежности к классу принимается на основании выбранного порогового значения.



Параметры:

  • Optimization tolerance — граница для минимального изменения точности. Если разница между итерациями становится меньше указанного значения, обучение останавливается. В большинстве случаев можно оставить значение по умолчанию равное 1Е-7.

  • L1 & L2 regularization — регуляризация по нормам 1 и 2 порядка. L1 используется для уменьшения размерности входных данных через удаление признаков, наименее влияющих на результат. L2 «штрафует» признаки c большими коэффициентами, сводя эти коэффициенты к нулю на бесконечности. Указанные значения являются коэффициентами для норм и для начала могут по умолчанию оставаться равными 1.

  • L-BFGS — метод оптимизации для нахождения локального максимума (минимума) нелинейного функционала без ограничений с ограниченной памятью. Это квазиньютоновский метод (основанный на накоплении информации о кривизне целевой функции по изменению ее градиента), используемый для взвешивания параметров модели. Тут выбор зависит от предпочтений: выставляемое значение влияет на количество данных, используемых для инверсии гессиана функции. По сути, берется указанное количество последних векторов. Увеличение этого значения улучшает точность. Улучшает до определенных пределов (не следует также забывать про переобучение). При этом может сильно увеличить время выполнения, поэтому часто выставляется в окрестности 10.

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



Этот алгоритм был использован в прототипе модели, поэтому сравнение будет наиболее показательно. Даже без настройки границы определения классов и с небольшими добавками в вектор входных признаков, процент верно предсказанных пиков увеличился на 5%, а их отсутствия — на 15%. Такой важный показатель, как площадь под кривой этого графика, тоже существенно вырос. Этот параметр отражает, насколько хорошо при разных граничных значениях соотносятся друг с другом значения классов. Чем дальше кривая находится от диагонали — тем лучше.

Support Vector Machine


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



Параметры:

  • Number of iterations — количество итераций обучения алгоритма. Представляет собой параметр для размена точности и скорости алгоритма. Для начала можно поставить значение в диапазоне от 1 до 10.
  • Lambda — аналог веса для L1 в логистической регрессии
  • Normalize features — нормализация данных перед обучением. В связи со спецификой метода в большинстве случаев следует оставить параметр включенным по умолчанию.
  • Project to unit sphere — нормализация коэффициентов. Этот параметр опционален и чаще всего его использование не понадобится.
  • Allow unknown category — по умолчанию включенный параметр, который позволяет обработку неизвестных модели параметров. Он ухудшает работу модели с теми данными, которые известны классификатору, при этом улучшает точность для неизвестных.
  • Random seed — аналогично с логистической регрессией.



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

Bayesian network


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



Параметры:

  • Number of training iterations — аналогично параметру в SVM.
  • Include bias — введение постоянной величины во входные параметры модели. Это необходимо, когда ее нет в исходном векторе.
  • Allow unknown values — аналогично параметру в SVM.



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

Random Forest


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

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



Параметры:

  • Resampling method по умолчанию выставлен на bagging, что дает для каждого дерева уникальную выборку данных описанным выше способом. Можно также выставить replicate, если есть необходимость обучать все деревья на одинаковых данных.
  • Number of decision trees. Увеличение количества деревьев может дать большее покрытие выборки, но не всегда, и ценой увеличения времени обучения.
  • Maximum depth — максимальная глубина дерева. Значение по умолчанию — 32 — достаточно большое и во многих ситуациях приведет к переобучению. Чаще всего нет необходимости делать глубину больше десяти.
  • Number of random splits per node — определяет количество случайных разделений признаков при построении вершин. Слишком большое количество может привести к переобучению, поэтому стоит для начала ограничиться значением в пределах от 10 до 30.
  • Minimum number of samples per leaf node — минимальное количество записей для образования «листа» (вершины которая уже не подлежит разделению на ветви). Практически никогда нет смысла оставлять в этом месте 1, поскольку подобные листья избыточны и часто приводят модель к переобучению.
  • Allow unknown values — аналогично с SVM.



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

Во всех описанных выше алгоритмах, кроме байесовских сетей, есть параметр “create trainer mode”. Выставив его на Parameter Range, можно включить режим, в котором алгоритм обучится на различных вариантах комбинаций параметров в пределах заданных диапазонов, и выдаст лучший вариант. Эту особенность осветим позже.

Использование cross-validation для проверки variance


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

Возьмем алгоритм, показавший лучшие результаты среди остальных — Random Forest.



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

Итог


Во этой части из цикла статей о машинном обучении мы рассмотрели:

  1. Встраивание Python-скриптов в общую схему проекта на примере получения уравновешенной по классам выборки данных.
  2. Использование MS Analysis Services для извлечения новых признаков из сырых данных.
  3. Кросс-валидацию модели для оценки стабильности результата и полноты данных в обучающей выборке.

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

Об авторах


Команда WaveAccess создаёт технически сложное, высоконагруженное и отказоустойчивое программное обеспечение для компаний из разных стран. Комментарий Александра Азарова, руководителя направления machine learning в WaveAccess:
Машинное обучение позволяет автоматизировать области, где на текущий момент доминируют экспертные мнения. Это дает возможность снизить влияние человеческого фактора и повысить масштабируемость бизнеса.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331484/


Метки:  

Используем template + constexpr для создания масок регистров периферии микроконтроллера на этапе компиляции (C++14)

Пятница, 23 Июня 2017 г. 11:07 + в цитатник

Введение


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

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



Заинтересовавшихся в том, как это можно сделать, прошу под кат.

Оглавление:


  1. Основные проблемы и ограничения C++14.
  2. Решение, основывающиеся на том, что пользователь никогда не ошибается.
  3. Учет пользовательских ошибок.
  4. Расширим возможности класса.
  5. О сокращенных записях.
  6. Итог.

Основные проблемы и ограничения C++14


Как только я столкнулся с задачей, описанной во введении, я сразу же вспомнил про спецификатор языка C++ — constexpr. Поскольку необходимость решения данной задачи была выявлена еще на этапе проектирования библиотеки, то были учтены все ограничения стандарта C++11, на котором изначально планировалось построить библиотеку (невозможность использовать внутри constexpr методов циклы и т.д.), и в качестве языка библиотеки был выбран стандарт C++14, в котором убраны многие ограничения C++11 (C++17 не был выбран намеренно, т.к. он, с точки зрения поставленных перед библиотекой задач, не слишком отличался от C++14, при этом его поддержка у GCC, так же выбранным в качестве основного компилятора библиотеки, на момент написания статьи, не слишком стабильна).

Но несмотря на то, что constexpr функции в C++14 стали практически такими же гибкими, как и функции реального времени, у них остался один жирный минус, перечеркивающий большинство достоинств — отсутствие какой-либо отладки. Об этом писалось на Хабре тут. Из данной статьи я почерпнул основную мысль:
Но на этом проблемы не заканчиваются. Когда пишешь какую-то constexpr-функцию, которую потом будут часто использовать, хорошо бы возвращать читабельную ошибку. Тут можно ошибочно предположить, что static_assert как раз для этого подходит. Но static_assert использовать не получится, так как параметры функций не могут быть constexpr, из-за чего значения параметров не гарантированно будут известны на этапе компиляции.

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

И того, ситуация следующая: static_assert нельзя, throw нельзя, printf и прерывание компиляции — нельзя.

Решение, основывающиеся на том, что пользователь никогда не ошибается


Как же быть со всеми этими ограничениями и невозможностью отладки? Для начала предположим, что ПОЛЬЗОВАТЕЛЬ НИКОГДА НЕ ОШИБАЕТСЯ (да, футуристично, но пока примем это за аксиому). Тогда constexpr, выходит, в принципе не нуждается в отладке и выбрасыванию исключений о том, что параметры входных данных неверны.

Для примера рассмотрим класс объекта управления выводом порта микроконтроллера, изначально кем-то включенным (подан тактовый сигнал на блок периферии) и с настроенным на выход выводом с нужной скоростью (самое то, чтобы мигать светодиодом). По сути, объект нашего класса должен иметь методы для переключения состояния вывода из 1 в 0 и обратно. Большего от нашего объекта не требуется.

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

/*
 * Структура конфигурации вывода.
 */
struct __attribute__( ( packed ) ) pin_config_t {
    EC_PORT_NAME                port;             // Имя порта 
                                                  // ( пример: EC_PORT_NAME::A ).
    EC_PORT_PIN_NAME            pin_name;         // Номер вывода 
                                                  // ( пример: EC_PORT_PIN_NAME::PIN_0 ).
    EC_PIN_MODE                 mode;             // Режим вывода 
                                                  // ( пример: EC_PIN_MODE::OUTPUT ).
    EC_PIN_OUTPUT_CFG           output_config;    // Режим выхода 
                                                  // ( пример: EC_PIN_OUTPUT_CFG::NOT_USE ).
    EC_PIN_SPEED                speed;            // Скорость вывода
                                                  // ( пример: EC_PIN_SPEED::MEDIUM ).
    EC_PIN_PULL                 pull;             // Подтяжка вывода 
                                                  // ( пример: EC_PIN_PULL::NO ).
    EC_PIN_AF                   af;               // Альтернативная функция вывода 
                                                  // ( пример: EC_PIN_AF::NOT_USE ).
    EC_LOCKED                   locked;           // Заблокировать ли настройку данного
                                                  // вывода во время инициализации 
                                                  // global_port объекта 
                                                  // ( пример EC_LOCKED::NOT_LOCKED ).
    EC_PIN_STATE_AFTER_INIT     state_after_init; // Состояние на выходе после инициализации
                                                  // ( в случае, если вывод настроен как выход ).
                                                  // (пример EC_PIN_STATE_AFTER_INIT::NO_USE).
};

Структура использует следующие enum class-ы
/**********************************************************************
 * Область enum class-ов.
 **********************************************************************/

/*
 * Перечень выводов каждого порта.
 */
enum class EC_PORT_PIN_NAME {
    PIN_0   = 0,
    PIN_1   = 1,
    PIN_2   = 2,
    PIN_3   = 3,
    PIN_4   = 4,
    PIN_5   = 5,
    PIN_6   = 6,
    PIN_7   = 7,
    PIN_8   = 8,
    PIN_9   = 9,
    PIN_10  = 10,
    PIN_11  = 11,
    PIN_12  = 12,
    PIN_13  = 13,
    PIN_14  = 14,
    PIN_15  = 15
};

/*
 * Режим вывода.
 */
enum class EC_PIN_MODE {
    INPUT   = 0,    // Вход.
    OUTPUT  = 1,    // Выход.
    AF      = 2,    // Альтернативная функция.
    ANALOG  = 3     // Аналоговый режим.
};

/*
 * Режим выхода.
 */
enum class EC_PIN_OUTPUT_CFG {
    NO_USE      = 0,    // Вывод не используется как вывод.
    PUSH_PULL   = 0,    // "Тянуть-толкать".
    OPEN_DRAIN  = 1     // "Открытый сток".
};

/*
 * Скорость выхода.
 */
enum class EC_PIN_SPEED {
    LOW         = 0,    // Низкая.
    MEDIUM      = 1,    // Средняя.
    FAST        = 2,    // Быстрая.
    HIGH        = 3     // Очень быстрая
};

/*
 * Выбор подтяжки
 */
enum class EC_PIN_PULL {
    NO_USE  = 0,    // Без подтяжки.
    UP      = 1,    // Подтяжка к питанию.
    DOWN    = 2     // Подтяжка к земле.
};

/*
 * Выбираем альтернативную функцию, если используется.
 */
enum class EC_PIN_AF {
    AF_0        = 0,
    NO_USE      = AF_0,
    SYS         = AF_0,

    AF_1        = 1,
    TIM1        = AF_1,
    TIM2        = AF_1,

    AF_2        = 2,
    TIM3        = AF_2,
    TIM4        = AF_2,
    TIM5        = AF_2,

    AF_3        = 3,
    TIM8        = AF_3,
    TIM9        = AF_3,
    TIM10       = AF_3,
    TIM11       = AF_3,

    AF_4        = 4,
    I2C1        = AF_4,
    I2C2        = AF_4,
    I2C3        = AF_4,

    AF_5        = 5,
    SPI1        = AF_5,
    SPI2        = AF_5,
    I2S2        = AF_5,


    AF_6        = 6,
    SPI3        = AF_6,
    I2S3        = AF_6,

    AF_7        = 7,
    USART1      = AF_7,
    USART2      = AF_7,
    USART3      = AF_7,

    AF_8        = 8,
    UART4       = AF_8,
    UART5       = AF_8,
    USART6      = AF_8,

    AF_9        = 9,
    CAN1        = AF_9,
    CAN2        = AF_9,
    TIM12       = AF_9,
    TIM13       = AF_9,
    TIM14       = AF_9,

    AF_10       = 10,
    OTG_FS      = AF_10,

    AF_11       = 11,
    ETH         = AF_11,

    AF_12       = 12,
    FSMC        = AF_12,
    SDIO        = AF_12,

    AF_13       = 13,
    DCMI        = AF_13,

    AF_14       = 14,

    AF_15       = 15,
    EVENTOUT    = AF_15
};

/*
 * Разрешено ли блокировать конфигурацию вывода методами set_locked_key_port и
 * set_locked_keys_all_port объекту класса global_port.
 * Важно! Блокировка применяется только один раз объектом global_port. Во время последующей
 * работы заблокировать иные выводы или же отключить блокировку текущих - невозможно.
 * Единственный способ снять блокировку - перезагрузка чипа.
 */
enum class EC_LOCKED {
    NOT_LOCKED  = 0,    // Не блокировать вывод.
    LOCKED      = 1     // Заблокировать вывод.
};

/*
 * Состояние на выходе после инициализации
 * (в случае, если вывод настроен как выход).
 */
enum class EC_PIN_STATE_AFTER_INIT {
    NO_USE  = 0,
    RESET   = 0,
    SET     = 1
};


Как говорилось ранее, объект нашего класса должен только менять состояние на выходе вывода (ножки). Так как библиотека пишется под stm32f2 (и только), то разумным будет использовать для этих целей имеющийся в физическом блоке GPIO каждого порта регистр BSR, который позволяет записью единицы (1) в биты 0-15 устанавливать соответствующий бит (запись единицы (1) в 0-й бит выставит состояние вывода порта 0 в 1), а записью единицы (1) в 16-31 сбрасывать соответствующий бит — 16 (запись единицы (1) в 31-й бит сбросит 31-16 = 15-й вывод порта в 0).

Как видно, задача установки нужного вывода в 1 сводится к записи в BSR регистр 1 << номер_вывода, а сброса в записи 1 << номер_вывода + 16.

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

Обозначим общий вид класса нашего объекта:

class pin {
public:
    constexpr pin ( const pin_config_t* const pin_cfg_array );

    void    set     ( void ) const;
    void    reset   ( void ) const;
    void    set     ( uint8_t state ) const;
    void    set     ( bool state ) const;
    void    set     ( int state ) const;

private:
    constexpr uint32_t  p_bsr_get                ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  set_msk_get              ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  reset_msk_get            ( const pin_config_t* const pin_cfg_array );

    const uint32_t  p_bsr;
    const uint32_t  bsr_set_msk, bsr_reset_msk;
};

Как видно, класс имеет следующие методы:

  • set без параметров — устанавливает состояние на выходе вывода в 1;
  • reset — сбрасывает состояние на выходе вывода в 0;
  • set c параметрами разных типов — на деле представляет из себя одну функцию (о чем будет далее), которая устанавливает заданное состояние на выходе используя функции выше.

Все эти методы используются пользователем в реальном времени. Рассмотрим их.

/*
 * Метод устанавливает вывод порта в <<1>>,
 * если вывод настроен как выход.
 */
void pin::set ( void ) const {
    *M_U32_TO_P(this->p_bsr) = this->bsr_set_msk;
}

/*
 * Метод устанавливает вывод порта в <<0>>,
 * если вывод настроен как выход.
 */
void pin::reset ( void ) const {
    *M_U32_TO_P(this->p_bsr) = this->bsr_reset_msk;
}

/*
 * Метод выставляет на выход заданное состояние,
 * если вывод настроен как выход.
 */
void pin::set ( uint8_t state ) const {
    if ( state ) {
        this->set();
    } else {
        this->reset();
    }
}

void pin::set ( bool state ) const {
    this->set( static_cast< uint8_t >( state ) );
}

void pin::set ( int state ) const {
    this->set( static_cast< uint8_t >( state ) );
}

Методы set и reset используют приведенный ниже define для явного преобразования значения в uint32_t переменной в указатель на uint32_t переменную.

// Преобразует число в uint32_t переменной в указатель на uint32_t.
// Данные по указателю можно изменять.
#define M_U32_TO_P(point)				((uint32_t *)(point))

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

Класс имеет три метода:

  1. set_msk_get — возвращает значение uint32_t переменной, являющееся маской регистра BSR для установки заданного пользователем вывода в <<1>>.
  2. reset_msk_get — возвращает значение uint32_t переменной, являющееся маской регистра BSR для сброса заданного пользователем вывода в <<0>>.
  3. p_bsr_get — возвращает значение uint32_t переменной, содержащее в себе адрес регистра BSR на физической карте памяти микроконтроллера.

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

/**********************************************************************
 * Область constexpr функций.
 **********************************************************************/

/*
 * Метод возвращает маску установки выхода в "1" через регистр BSR.
 */
constexpr uint32_t pin::set_msk_get ( const pin_config_t* const pin_cfg_array ) {
    return 1 << M_EC_TO_U8(pin_cfg_array->pin_name);
}

/*
 * Метод возвращает маску установки выхода в "0" через регистр BSR.
 */
constexpr uint32_t pin::reset_msk_get ( const pin_config_t* const pin_cfg_array ) {
    return 1 << M_EC_TO_U8( pin_cfg_array->pin_name ) + 16;
}

/*
 * Метод возвращает указатель на регистр BSR, к которому относится вывод.
 */
constexpr uint32_t pin::p_bsr_get( const pin_config_t* const pin_cfg_array ) {
    uint32_t p_port = p_base_port_address_get( pin_cfg_array->port );
    return p_port + 0x18;
}

Эти функции используют define для преобразования значения enum class-а в uint8_t переменную.

// Преобразует enum class в uint8_t.
#define M_EC_TO_U8(ENUM_VALUE)			((uint8_t)ENUM_VALUE)

Так же метод p_bsr_get используют не принадлежащий никакому конкретному классу метод p_base_port_address_get, который принимая значение enum class-а EC_PORT_NAME (имя порта) возвращает физический адрес начала расположения регистров этого порта на физической карте микроконтроллера. Выглядит он следующим образом:

Общий метод p_base_port_address_get
/*
 * Возвращает указатель на базовый адрес выбранного порта ввода-вывода
 * на карте памяти в соответствии с выбранным контроллером.
 */
constexpr uint32_t p_base_port_address_get( EC_PORT_NAME port_name ) {
    switch( port_name ) {
#ifdef PORTA
    case EC_PORT_NAME::A:   return 0x40020000;
#endif
#ifdef PORTB
    case EC_PORT_NAME::B:   return 0x40020400;
#endif
#ifdef PORTC
    case EC_PORT_NAME::C:   return 0x40020800;
#endif
#ifdef PORTD
    case EC_PORT_NAME::D:   return 0x40020C00;
#endif
#ifdef PORTE
    case EC_PORT_NAME::E:   return 0x40021000;
#endif
#ifdef PORTF
    case EC_PORT_NAME::F:   return 0x40021400;
#endif
#ifdef PORTG
    case EC_PORT_NAME::G:   return 0x40021800;
#endif
#ifdef PORTH
    case EC_PORT_NAME::H:   return 0x40021C00;
#endif
#ifdef PORTI
    case EC_PORT_NAME::I:   return 0x40022000;
#endif
    }
}
Конструктор класса, заполняющий константы масок сброса/установки и адреса регистра выглядит следующим образом.

/**********************************************************************
 * Область constexpr конструкторов.
 **********************************************************************/

constexpr pin::pin ( const pin_config_t* const pin_cfg_array ):
    p_bsr               ( this->p_bsr_get( pin_cfg_array ) ),
    bsr_set_msk         ( this->set_msk_get( pin_cfg_array ) ),
    bsr_reset_msk       ( this->reset_msk_get( pin_cfg_array ) ) {};

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

Учет пользовательских ошибок.


Теперь, когда у нас имеется рабочий и отлаженный класс, осталось только доработать проверку входной структуры и можно спокойно использовать объекты нашего класса. Но, как говорилось ранее, сделать это в constexpr комфортно — невозможно. Но решение есть — template. Так как все объекты в коде пользователя должны задаваться глобально (это основное условие использования библиотеки, о котором можно будет почитать в документе ее (библиотеки) описания, ссылку на которую дам в конце статьи), то использование template-ов кажется наиболее разумным. Дело в том, что в template-ах разрешен static_assert. Так же в них можно использовать разного рода код для проведения более сложных проверок. И, что самое главное:

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

Такую возможность просто нельзя не использовать!

/**********************************************************************
 * Область template оболочек.
 **********************************************************************/
template < EC_PORT_NAME              PORT,
           EC_PORT_PIN_NAME          PIN_NAME,
           EC_PIN_MODE               MODE,
           EC_PIN_OUTPUT_CFG         OUTPUT_CONFIG,
           EC_PIN_SPEED              SPEED,
           EC_PIN_PULL               PULL,
           EC_PIN_AF                 AF,
           EC_LOCKED                 LOCKED,
           EC_PIN_STATE_AFTER_INIT   STATE_AFTER_INIT >
class pin_config_check_param : public pin_config_t {
public:
    constexpr pin_config_check_param(): pin_config_t( {
        .port               = PORT,
        .pin_name           = PIN_NAME,
        .mode               = MODE,
        .output_config      = OUTPUT_CONFIG,
        .speed              = SPEED,
        .pull               = PULL,
        .af                 = AF,
        .locked             = LOCKED,
        .state_after_init   = STATE_AFTER_INIT
    } ) {
/*
 * Проверяем введенные пользователем данные в структуру инициализации.
 */
#if defined(STM32F205RB)|defined(STM32F205RC)|defined(STM32F205RE) \
    |defined(STM32F205RF)|defined(STM32F205RG)
            static_assert( PORT >= EC_PORT_NAME::A && 
                    PORT <= EC_PORT_NAME::H, 
                    "Invalid port name. The port name must be A..H." );
#endif
            
            static_assert( PIN_NAME >= EC_PORT_PIN_NAME::PIN_0 &&
                    PIN_NAME <= EC_PORT_PIN_NAME::PIN_15,
                    "Invalid output name. An output with this name does not"
                    "exist in any port. The output can have a name PIN_0..PIN_15." );

            static_assert( MODE >= EC_PIN_MODE::INPUT &&
                    MODE <= EC_PIN_MODE::ANALOG,
                    "The selected mode does not exist. "
                    "The output can be set to mode: INPUT, OUTPUT, AF or ANALOG." );

            static_assert( OUTPUT_CONFIG == EC_PIN_OUTPUT_CFG::PUSH_PULL ||
                    OUTPUT_CONFIG == EC_PIN_OUTPUT_CFG::OPEN_DRAIN,
                    "A non-existent output mode is selected. "
                    "The output can be in the mode: PUSH_PULL, OPEN_DRAIN." );

            static_assert( SPEED >= EC_PIN_SPEED::LOW &&
                    SPEED <= EC_PIN_SPEED::HIGH,
                    "A non-existent mode of port speed is selected. "
                    "Possible modes: LOW, MEDIUM, FAST or HIGH." );

            static_assert( PULL >= EC_PIN_PULL::NO_USE &&
                    PULL <= EC_PIN_PULL::DOWN,
                    "A non-existent brace mode is selected."
                    "The options are: NO_USE, UP or DOWN." );

            static_assert( AF >= EC_PIN_AF::AF_0 &&
                    AF <= EC_PIN_AF::AF_15,
                    "A non-existent mode of the alternative port function is selected." );

            static_assert( LOCKED == EC_LOCKED::NOT_LOCKED ||
                    LOCKED == EC_LOCKED::LOCKED,
                    "Invalid port lock mode selected." );

            static_assert( STATE_AFTER_INIT == EC_PIN_STATE_AFTER_INIT::NO_USE ||
                    STATE_AFTER_INIT == EC_PIN_STATE_AFTER_INIT::SET,
                    "The wrong state of the output is selected."
                    "The status can be: NO_USE, UP or DOWN." );
    };
};

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

const pin_config_check_param< EC_PORT_NAME::C,        EC_PORT_PIN_NAME::PIN_4,  
                              EC_PIN_MODE::OUTPUT,    EC_PIN_OUTPUT_CFG::PUSH_PULL,   
                              EC_PIN_SPEED::MEDIUM,   EC_PIN_PULL::NO_USE,    
                              EC_PIN_AF::NO_USE,      EC_LOCKED::LOCKED,      
                              EC_PIN_STATE_AFTER_INIT::SET > lcd_res;


После чего, при создании объекта класса pin сослаться не него, как на обычную структуру:

const constexpr pin pin_lcd_res( &lcd_res );

После чего, в коде пользователя можно пользоваться методами этого объекта:

void port_test ( void ) {
    pin_lcd_res.reset();
    pin_lcd_res.set();
}

Расширим возможности класса


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

Дополним класс двумя (2) константами:

  1. p_bb_odr_read — здесь будет находиться указатель на бит вывода объекта в регистре ODR (выставленное пользователем положение на выходе вывода, если вывод используется на выход). Используется bit-banding область.
  2. p_bb_idr_read — здесь будет находиться указатель на бит вывода объекта в регистре IDR (в данном регистре содержится реальное состояние на входах вывода, в не зависимости от того, как настроен вывод). Используется bit-banding область.

Напишем методы, которые возвращают значения этих констант для конкретного вывода.

/*
 * Метод возвращает указатель на bit_banding
 * область памяти, в которой находится бит состояния входа.
 */
constexpr uint32_t pin::bb_p_idr_read_get ( const pin_config_t* const pin_cfg_array ) {
    uint32_t p_port = p_base_port_address_get( pin_cfg_array->port );
    uint32_t p_idr  = p_port + 0x10;
    return M_GET_BB_P_PER(p_idr, M_EC_TO_U8(pin_cfg_array->pin_name));
}
/*
 * Метод возвращает указатель на bit banding область памяти,
 * с выставленным пользователем состоянием на выходе вывода.
 */
constexpr uint32_t pin::odr_bit_read_bb_p_get ( const pin_config_t* const pin_cfg_array ) {
    uint32_t p_port     = p_base_port_address_get( pin_cfg_array->port );
    uint32_t p_reg_odr  = p_port + 0x14;
    return M_GET_BB_P_PER(p_reg_odr, M_EC_TO_U8(pin_cfg_array->pin_name));
}

Здесь используется define M_GET_BB_P_PER который по uint32_t значению адреса регистра в области периферии и uint32_t номера бита порта возвращает bit-banding адрес этого бита.

define M_GET_BB_P_PER
//*********************************************************************
// Определения, не касающиеся основных модулей.
//*********************************************************************
#define BIT_BAND_SRAM_REF   0x20000000
#define BIT_BAND_SRAM_BASE  0x22000000

//Получаем адрес бита RAM в Bit Banding области.
#define MACRO_GET_BB_P_SRAM(reg, bit) \
  ((BIT_BAND_SRAM_BASE + (reg - BIT_BAND_SRAM_REF)*32 + (bit * 4)))

#define BIT_BAND_PER_REF   ((uint32_t)0x40000000)
#define BIT_BAND_PER_BASE  ((uint32_t)0x42000000)

// Получаем адрес бита периферии в Bit Banding области.
#define M_GET_BB_P_PER(ADDRESS,BIT) \
    ((BIT_BAND_PER_BASE + (ADDRESS - BIT_BAND_PER_REF)*32 + (BIT * 4)))


Допишем в конструктор инициализацию этих команд.

/**********************************************************************
 * Область constexpr конструкторов.
 **********************************************************************/

constexpr pin::pin ( const pin_config_t* const pin_cfg_array ):
    p_bsr               ( this->p_bsr_get( pin_cfg_array ) ),
    p_bb_odr_read       ( this->odr_bit_read_bb_p_get( pin_cfg_array ) ),
    bsr_set_msk         ( this->set_msk_get( pin_cfg_array ) ),
    bsr_reset_msk       ( this->reset_msk_get( pin_cfg_array ) ),
    p_bb_idr_read       ( this->bb_p_idr_read_get( pin_cfg_array ) ) {};

Ну и допишем функции реального времени, которые будут работать с этими константами:

/*
 * Метод инвертирует состояние на выходе вывода,
 * если вывод настроен как выход.
 */
void pin::invert( void ) const {
    if (*M_U32_TO_P_CONST(p_bb_odr_read)) {			// Если был 1, то выставляем 0.
        this->reset();
    } else {
        this->set();
    }
}

/*
 * Метод возвращает состояние на входе вывода.
 */
int pin::read() const {
    return *M_U32_TO_P_CONST(p_bb_idr_read);
}

Здесь используется еще 1 define (M_U32_TO_P_CONST), который преобразует значение, хранящееся в uint32_t переменной в указатель на uint32_t переменную, защищенную от записи.

// Преобразует число в uint32_t переменной в указатель на uint32_t.
// Причем запрещает переписывать то, что по указателю (только чтение).
#define M_U32_TO_P_CONST(point)		((const uint32_t *const)(point))

В конечном итоге, наш класс приобрел следующий вид:

class pin {
public:
    constexpr pin ( const pin_config_t* const pin_cfg_array );

    void    set     ( void ) const;
    void    reset   ( void ) const;
    void    set     ( uint8_t state ) const;
    void    set     ( bool state ) const;
    void    set     ( int state ) const;
    void    invert  ( void ) const;
    int     read    ( void ) const;

private:
    constexpr uint32_t  p_bsr_get                ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  set_msk_get              ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  reset_msk_get            ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  odr_bit_read_bb_p_get    ( const pin_config_t* const pin_cfg_array );
    constexpr uint32_t  bb_p_idr_read_get        ( const pin_config_t* const pin_cfg_array );


    const uint32_t  p_bsr;
    const uint32_t  bsr_set_msk, bsr_reset_msk;
    const uint32_t  p_bb_odr_read, p_bb_idr_read;
};

О сокращенных записях.


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


template < EC_PORT_NAME              PORT,
           EC_PORT_PIN_NAME          PIN_NAME >
class pin_config_adc_check_param : public pin_config_check_param< PORT, PIN_NAME,
                                                                  EC_PIN_MODE::INPUT,
                                                                  EC_PIN_OUTPUT_CFG::NO_USE,
                                                                  EC_PIN_SPEED::LOW,
                                                                  EC_PIN_PULL::UP,
                                                                  EC_PIN_AF::NO_USE,
                                                                  EC_LOCKED::LOCKED,
                                                                  EC_PIN_STATE_AFTER_INIT::NO_USE > {
public:
    constexpr pin_config_adc_check_param() {};
};

Объявление в коде займет многократно меньше места:

const pin_config_adc_check_param< EC_PORT_NAME::B, EC_PORT_PIN_NAME::PIN_1 >      adc_left;

Итог


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

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

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

Приведенный в статье код — часть этой библиотеки. Библиотека еще в начальной стадии разработки. Как будет альфа версия — будет отдельная статья на эту тему.

Отдельное спасибо madcomaker за ответ на Тостере, натолкнувший на идею.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331468/


Метки:  

Apache Cassandra + Apache Ignite — как совместить лучшее

Пятница, 23 Июня 2017 г. 11:01 + в цитатник
Apache Cassandra — это одна из популярных распределенных дисковых NoSQL баз данных с открытым исходным кодом. Она применяется в ключевых частях инфраструктуры такими гигантами как Netflix, eBay, Expedia, и снискала популярность за свою скорость, способность линейно масштабироваться на тысячи узлов и “best-in-class” репликацию между различными центрами обработки данных.

Apache Ignite — это In-Memory Computing Platform, платформа для распределенного хранения данных в оперативной памяти и распределенных вычислений по ним в реальном времени с поддержкой JCache, SQL99, ACID-транзакциями и базовой алгеброй машинного обучения.

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

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

Как? Читайте дальше, и смотрите пример кода.


Ограничения Cassandra


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

  1. Пропускная способность и время отклика ограничены характеристиками жесткого диска или твердотельного накопителя;
  2. Специфическая структура хранения данных, оптимизированная под последовательные запись и чтение, не адаптирована под оптимальное выполнение классических реляционных операций над данными. Это не позволяет нормализовать данные и эффективно сопоставлять при помощи JOIN-ов, а также накладывает значительные ограничения, например, на такие операции, как GROUP BY и ORDER;
  3. Как следствие из п. 2 — отсутствие поддержки SQL в пользу своей более ограниченной вариации — CQL;
  4. Отсутствие ACID-транзакций.

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

Как же можно обойти эти ограничения?

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

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

Apache Ignite


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

  1. Исчезает накладываемое диском ограничение производительности: Apache Ignite работает с оперативной памятью, сейчас нет ничего быстрее. Кроме того, она дешевеет настолько стремительно, что поставить достаточное количество RAM на пул серверов (Apache Ignite — распределенная система, как и Cassandra) — посильная задача;
  2. Полная поддержка классического SQL99, включая JOIN-ы, GROUP BY, ORDER BY, а также INSERT, UPDATE, DELETE, MERGE и так далее, позволяет нормализовать данные, облегчает аналитику, а с учетом производительности при работе с RAM — открывает потенциал HTAP, аналитики в реальном времени по операционным данным;
  3. Поддержка стандартов JDBC и ODBC облегчает интеграцию с существующими инструментами, например, Tableau, и фреймворками вроде Hibernate или Spring Data;
  4. Поддержка ACID-транзакций, гибкие и глубокие настройки обеспечения отказоустойчивости и дублирования данных;
  5. Распределенные вычисления, потоковая обработка данных, машинное обучение — можно легко реализовать множество новых для бизнеса сценариев использования, приносящих дивиденды.

В такой схеме Apache Ignite встает поверх Apache Cassandra, которая играет роль слоя постоянного энергонезависимого хранения. Несмотря на то, что уже в ближайших версиях Apache Ignite появится свое собственное решение Persistence с поддержкой расширения памяти диском, lazy run и сквозным SQL, Cassandra всё равно может быть интересна в этой роли за счет своей вылизанности за долгие годы развития, распространенности и возможности разделить ответственность, не складывая все яйца в одну корзину там, где это не нужно.

Кластер Apache Ignite вбирает в себя из Apache Cassandra все или часть данных (например, за исключением архивных), по которым нужно выполнять запросы, после чего работает в режиме write-through, самостоятельно обслуживая API- или SQL-запросы на чтение, и дублируя в синхронном или асинхронном режиме запросы на запись в Cassandra, надежно сохраняя их на диск.

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

А на примере?


Далее я приведу пример простой «синтетической» интеграции Apache Cassandra и Apache Ignite, чтобы показать, как это работает и что это совсем не сложно, пусть и требует определенной доли boilerplate-кода.

Для начала я создам необходимые таблицы в Cassandra и заполню их данными, затем инициализирую Java-проект и напишу DTO-классы, после чего покажу основную часть — конфигурирование Apache Ignite для работы с Cassandra.

Я буду использовать Mac OS Sierra, Cassandra 3.10 и Apache Ignite 2.0. В Linux команды должны быть аналогичны.

Cassandra: таблицы и данные


Для начала загрузим дистрибутив Cassandra в директорию ~/Downloads, пройдя по ссылке, либо используя curl/wget.

Далее зайдем в директорию и распакуем его:

$ cd ~/Downloads
$ tar xzvf apache-cassandra-3.10-bin.tar.gz
$ cd apache-cassandra-3.10

Запустим Cassandra с настройками по умолчанию, для тестирования этого будет достаточно.

$ bin/cassandra

Далее запустим интерактивный шелл Cassandra и создадим тестовые структуры данных (выберем обычный суррогатный id как ключ — для таблиц в Cassandra зачастую имеет смысл выбирать ключи, более осмысленные с точки зрения последующего извлечения данных, но мы упростим пример):

$ cd ~/Downloads/apache-cassandra-3.10
$ bin/cqlsh

CREATE KEYSPACE IgniteTest WITH replication = {'class': 'SimpleStrategy', 'replication_factor' : 1};

USE IgniteTest;

CREATE TABLE catalog_category (id bigint primary key, parent_id bigint, name text, description text);
CREATE TABLE catalog_good (id bigint primary key, categoryId bigint, name text, description text, price bigint, oldPrice bigint);

INSERT INTO catalog_category (id, parentId, name, description) VALUES (1, NULL, 'Бытовая техника', 'Различная бытовая техника для вашего дома!');
INSERT INTO catalog_category (id, parentId, name, description) VALUES (2, 1, 'Холодильники', 'Самые холодные холодильники!');
INSERT INTO catalog_category (id, parentId, name, description) VALUES (3, 1, 'Стиральные машинки', 'Замечательные стиралки!');

INSERT INTO catalog_good (id, categoryId, name, description, price, oldPrice) VALUES (1, 2, 'Холодильник Buzzword', 'Лучший холодильник 2027!', 1000, NULL);
INSERT INTO catalog_good (id, categoryId, name, description, price, oldPrice) VALUES (2, 2, 'Холодильник Foobar', 'Дешевле не найти!', 300, 900);
INSERT INTO catalog_good (id, categoryId, name, description, price, oldPrice) VALUES (3, 2, 'Холодильник Barbaz', 'Люкс на вашей кухне!', 500000, 300000);
INSERT INTO catalog_good (id, categoryId, name, description, price, oldPrice) VALUES (4, 3, 'Машинка Habr#', 'Стирает, отжимает, сушит!', 10000, NULL);

Проверим, что все данные записались корректно:

cqlsh:ignitetest> SELECT * FROM catalog_category;

id | description | name | parentId
----+--------------------------------------------+--------------------+-----------
1 | Различная бытовая техника для вашего дома! | Бытовая техника | null
2 | Самые холодные холодильники! | Холодильники | 1
3 | Замечательные стиралки! | Стиральные машинки | 1

(3 rows)
cqlsh:ignitetest> SELECT * FROM catalog_good;

id | categoryId | description | name | oldPrice | price
----+-------------+---------------------------+----------------------+-----------+--------
1 | 2 | Лучший холодильник 2027! | Холодильник Buzzword | null | 1000
2 | 2 | Дешевле не найти! | Холодильник Foobar | 900 | 300
4 | 3 | Стирает, отжимает, сушит! | Машинка Habr# | null | 10000
3 | 2 | Люкс на вашей кухне! | Холодильник Barbaz | 300000 | 500000

(4 rows)


Инициализация Java-проекта


Есть 2 способа работы с Ignite: можно скачать дистрибутив с сайта ignite.apache.org, подложить ему необходимые Jar-файлы с собственными классами и XML с конфигурацией, либо использовать Ignite как зависимость в Java-проекте. В этой статье я рассмотрю второй вариант.

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

В зависимости пропишем:

  • ignite-cassandra-store для обеспечения интеграции с Cassandra;
  • ignite-spring для загрузки XML-конфигурации в формате Spring Context, отсюда транзитивно нам прилетит кусок Spring, альтернативно можно не включать данный пакет и самим создать необходимые классы (в первую очередь IgniteConfiguration).

Транзитивно будет также загружен ignite-core, который содержит основные классы Apache Ignite.


    
        org.apache.ignite
        ignite-spring
        2.0.0
    

    
        org.apache.ignite
        ignite-cassandra-store
        2.0.0
    

Далее необходимо создать DTO-классы, которые будут представлять таблицы Cassandra в мире Java:

import org.apache.ignite.cache.query.annotations.QuerySqlField;

public class CatalogCategory {
    @QuerySqlField private long id;
    @QuerySqlField private Long parentId;
    @QuerySqlField private String name;
    @QuerySqlField private String description;

    // public getters and setters
}

public class CatalogGood {
    @QuerySqlField private long id;
    @QuerySqlField private long categoryId;
    @QuerySqlField private String name;
    @QuerySqlField private String description;
    @QuerySqlField private long price;
    @QuerySqlField private long oldPrice;

    // public getters and setters
}

...или на Kotlin
import org.apache.ignite.cache.query.annotations.QuerySqlField

data class CatalogCategory(@QuerySqlField var id: Long,
                           @QuerySqlField var parentId: Long?,
                           @QuerySqlField var name: String?,
                           @QuerySqlField var description: String?) {
	constructor() : this(0, null, null, null)
}

data class CatalogGood(@QuerySqlField var id: Long,
                       @QuerySqlField var categoryId: Long,
                       @QuerySqlField var name: String?,
                       @QuerySqlField var description: String?,
                       @QuerySqlField var price: Long,
                       @QuerySqlField var oldPrice: Long) {
	constructor() : this(0, 0, null, null, 0, 0)
}


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

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

Конфигурация Apache Ignite


Создадим в src/main/resources нашу конфигурацию в файле apacheignite-cassandra.xml (название выбрано произвольно). Я приведу полную конфигурацию, которая достаточно объемна, после чего рассмотрю ее по частям:




    
        
    

    
        
            
                
                    
                    
                    
                    
                        
                            java.lang.Long
                            com.gridgain.test.model.CatalogCategory
                        
                    
                    
                        
                            
                            
                                
                                    
                                
                            
                        
                    
                

                
                    
                    
                    
                    
                    
                        
                            java.lang.Long
                            com.gridgain.test.model.CatalogGood
                        
                    
                    
                        
                            
                            
                                
                                    
                                
                            
                        
                    
                
            
        
    


Формат конфигурации — Spring Beans.

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

Первая часть конфигурации лаконична:

    
        
    

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

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

    
        
            
                ...
            
        
    

Первый кеш — представляющий таблицу catalog_category:

                
                    
                    ...
                

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

                    
                    
                    
                    
                        
                            java.lang.Long
                            com.gridgain.test.model.CatalogCategory
                        
                    

Наконец, зададим связь с Cassandra, здесь будет два основных подраздела. Во-первых, укажем ссылку на созданный ранее DataSource: cassandra. Во-вторых, нам нужно будет указать, как соотносить между собой таблицы Cassandra и записи «ключ-значение» Ignite. Это будет делаться через свойство persistenceSettings, в котором лучше сослаться на внешний XML-файл с конфигурацией меппинга, но для простоты встроим этот XML непосредственно в Spring-конфигурацию как CDATA-элемент:

                    
                        
                            
                            
                                
                                    
                                
                            
                        
                    

Конфигурация меппинга выглядит достаточно интутивно понятно:


    
    

На верхнем уровне (тег persistence) указывается Keyspace (IgniteTest в данном случае) и Table (catalog_category), которые мы будем соотносить. Затем указывается, что ключом Ignite-кеша будет тип Long, который является примитивным и должен соотноситься с колонкой id в таблице Cassandra. При этом значением является класс CatalogCategory, который должен при помощи Reflection (stategy="POJO") формироваться из колонок таблицы Cassandra.

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

Конфигурация второго кеша, содержащего данные о товарах аналогична.

Запуск


Для запуска создадим класс com.gridgain.test.Starter:

package com.gridgain.test;

import org.apache.ignite.Ignite;
import org.apache.ignite.Ignition;

public class Starter {
    public static void main(String... args) throws Exception {
        final Ignite ignite = Ignition.start("apacheignite-cassandra.xml");

        ignite.cache("CatalogCategory").loadCache(null);
        ignite.cache("CatalogGood").loadCache(null);
    }
}

Здесь мы используем инструкцию Ignition.start(...) для запуска узла Apache Ignite, указав в качестве источника конфигурации лежащий на classpath файл apacheignite-cassandra.xml.

SQL


Для выполнения SQL-запросов можно использовать любой клиент, который поддерживает JDBC, например, встроенный в IntelliJ IDEA, либо SquirrelSQL. В последнем случае, например, нужно будет добавить драйвер Apache Ignite (который находится в Jar-файле ignite-core, его можно скачать в составе дистрибутива):



Создадим новое соединение по URL вида jdbc:ignite://localhost/CatalogGood, где localhost — адрес одного из узлов Apache Ignite, а CatalogGood — кеш, к которому будут идти по умолчанию запросы.



Пара примеров возможных SQL-запросов:

SELECT cg.name goodName, cg.price goodPrice, cc.name category, pcc.name parentCategory
FROM catalog_category.CatalogCategory cc
  JOIN catalog_category.CatalogCategory pcc
  ON cc.parentId = pcc.id
  JOIN catalog_good.CatalogGood cg
  ON cg.categoryId = cc.id;

goodName goodPrice category parentCategory
Холодильник Buzzword 1000 Холодильники Бытовая техника
Холодильник Foobar 300 Холодильники Бытовая техника
Холодильник Barbaz 500000 Холодильники Бытовая техника
Машинка Habr# 10000 Стиральные машинки Бытовая техника

SELECT cc.name, AVG(cg.price) avgPrice
FROM catalog_category.CatalogCategory cc
  JOIN catalog_good.CatalogGood cg
  ON cg.categoryId = cc.id
WHERE cg.price <= 100000
GROUP BY cc.id;

name avgPrice
Холодильники 650
Стиральные машинки 10000

Заключение


На этом простом примере можно видеть, как используя Apache Ignite можно поверх Apache Cassandra поднять распределенный SQL-движок с ACID-транзакциями и скоростью оперативной памяти.

Столкнувшись с Apache Cassandra в существующей инфраструктуре либо в greenfield-проекте, вспомните об этой статье и о том, что Cassandra хороша со вкусом Ignite. Или можно уже сейчас попробовать сочинить какой-то проект, например, из мира интернета вещей, использующий сильные стороны Ignite и Cassandra.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/329736/


Метки:  

Возможности CodeRush for Roslyn для XAML

Пятница, 23 Июня 2017 г. 10:54 + в цитатник

Редактировать XAML-разметку в Visual Studio достаточно удобно благодаря таким фичам как IntelliSense, автозакрытие тэгов, сворачивание тэгов. Но при реальной работе с этими фичами приходит понимание, что XAML в чистой студии достаточно обособлен: например, плохо отслеживаются связи между кодом и разметкой. Это не позволяет чистой студии делать многие полезные вещи, которые умеет делать студия c CodeRush for Roslyn. Под катом подробности...




Навигация


Find References


Одна из наиболее важных задач среды разработки — поиск ссылок. В Visual Studio он есть, но CodeRush for Roslyn делает его полноценным: с этим расширением вы можете искать вхождения идентификатора не только в XAML, но и по коду во всем солюшне.





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


Tab to Next Reference


У нас также есть лёгкая версия поиска ссылок. Просто нажмите Tab. Если курсор находится на идентификаторе, он мгновенно переместится к следующему его использованию и одновременно подсветятся все вхождения. Чтобы перемещаться назад, можно использовать Shift+Tab.





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


Jump to Resource


F12 работает в XAML. Можно переходить на ResourceDictionary.Source или на Image.Source.





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


Jump to Symbol Declaration


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





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


Форматирование разметки


Format XAML Document


XAML полезно форматировать. Есть разные подходы к форматированию XAML: можно вручную, можно использовать онлайн-инструменты для форматирования XML, а можно воспользоваться фичей CRR.
Прямо в Visual Studio.



У нашего форматтера гибкая конфигурация и он крайне удобен в работе.



Break Apart/LineUp Attributes


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



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


Рефакторинги


Import Type/All Types


При копировании фрагмента кода в проект, CRR помогает правильно заполнить заголовок XAML файла.


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


Optimize Namespace References


У нас есть рефакторинг Optimize Namespace References, он приводит в порядок референсы на пространства имен в XAML: сортирует их и убирает ненужные.
Этот рефакторинг будет полезен тем, кто еще работает в Visual Studio 2015. В последней версии студии он есть из коробки.


Convert Nested Element to Attribute/Attribute to Nested Element


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


Визуализация


Show Color


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



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



Region Painting


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


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


Помощь в написании разметки


Templates


Шаблоны CodeRush работают в XAML в полном объеме. Можно использовать встроенные шаблоны или писать свои с учётом ваших потребностей.





Selection Embedding


Когда нужно положить определённый блок разметки внутрь какого-либо тэга, приходится несколько раз перемещать курсор, потом форматировать. Чтобы упростить этот процесс у нас есть фича Selection Embedding, которая помещает выделение внутрь тэга одним кликом. Благодаря фичам Selection Expand и Include Previous/Next Element, можно даже не выделять необходимый блок мышкой/стрелочками, а просто нажимать горячие клавиши для управления выделением.


Paste Vector Drawing as XAML


Копируем из иллюстратора



Переключаемся на Visual Studio и вставляем в XAML-файл. Рисунок вставится в векторном формате, его можно дальше масштабировать и менять как угодно.



Также мы поддерживаем копирование векторов из Microsoft Visio, Microsoft PowerPoint.


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


Smart Duplicate Line


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



Большинство примеров этой статьи было сделано на исходных текстах открытой библиотеки Material Design in XAML Toolkit.


Скачать попробовать можно в Visual Studio Marketplace.

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

https://habrahabr.ru/post/331350/


Метки:  

Как провести розыгрыш призов среди Java программистов

Пятница, 23 Июня 2017 г. 10:50 + в цитатник
Давно ли вы участвовали в лотерее или розыгрыше? Приходилось ли вам самим их устраивать? Даже если ответы: никогда и нет, уверен, что вы знаете что это такое.
А какие у вас ассоциации от слов «лотерея» и «розыгрыш»? У меня — разноцветные шары с номерами и лотерейная машина, из которой разноцветные шары выпадают по одному и определяют победителя.

Вот и мне некоторое время назад понадобилось “определить” победителей розыгрыша бесплатных места на курс “Разработчик Java” в Otus.ru. Задача звучала просто: есть N email-ов, нужно выбрать среди них случайным образом M email-ов тех, кто будет учиться бесплатно.

Сложность задачи была в том, что это были email-ы всех, кто успешно прошел входное тестирование курса. То есть email-ы программистов. Я представил себе, как я “достаю из кармана” M email-ов и говорю: “Вот эти победили”. И… мне никто не верит. Даже если победители начинают радостно писать в общий чат: “Спасибо, как мы рады!”, мне все равно никто из оставшихся не поверит.
Да я бы и сам не поверил, если бы мне просто сказали «победили эти».

image

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

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

Итак, как провести розыгрыш призов среди программистов:
  1. Убрать из выбора организатора розыгрыша. Выбирать должен робот.
  2. Сделать робота открытым, чтобы любой мог посмотреть как он выбирает.
  3. Сделать случайный выбор псевдослучайным. Так, чтобы любой, кто знает зерно последовательности, его мог повторить.
  4. И при этом, формировать зерно псевдослучайности на случайности материальной.
  5. Выложить в общий доступ… email-ы? Чтобы каждый мог найти себя в списке? Нет, этого наши пользователи не оценили бы. Но каким-то образом дать проверить, что ты в списке, нужно.

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

Она состоит из класса для чтения email-ов, класса который производит выбор “шаров” с индексами победителей и класса, который все запускает.

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

Результат прочтения email-ов — List я передаю в лотерейную машину. Кроме этого, она на вход получает количество победителей. И еще ей можно задать seed — зерно псевдослучайной последовательности. Его можно задать числом, или строкой. Во втором случае зерном будет hash от строки.
Если у вас есть seed, то лотерейная машина будет выдавать одну и туже “случайную” последовательность победителей при каждом запуске. Случайную, но псевдо. Что, собственно, нам и надо.

Хорошо, список с email-ми у нас есть, лотерейная машина есть, и она использует в работе класс java.util.Random, который дает нам псевдослучайную последовательность на основе seed-а.

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

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

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

Мы запустили лотерейную машину и получили победителей. Потом запустили ее еще раз и получили тех же самых.

После чего я предложил изменить текст, и удалил последнее сообщение. Со словами: “а теперь посмотрим как повлиял этот последний комментарий на результат”, я запустил машину и среди результатов был email того кто этот последний комментарий написал. Если бы он его не писал, приз был бы у него. Конечно он это заметил. Конечно мы все это заметили. И победители поблагодарили автора комментария за подарок.

Выкладывать в github email-ы мы конечно не стали. Но в репо вы можете посмотреть файл в котором записаны “обфусцированные” email-ы.

А как бы вы разыграли призы среди программистов? Понятен ли код и принцип работы машины?
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331478/


Метки:  

Видеозаписи: Android meetup в офисе Badoo

Пятница, 23 Июня 2017 г. 10:23 + в цитатник


В прошлую субботу, 17 июня, мы снова проводили митап в офисе. На этот раз принимали Android-сообщество. Эта встреча, вероятно, была самой разнообразной по темам докладов, поэтому каждый интересующийся найдет что-то для себя.


Спикеры


Филипп Уваров, Avito


Тема: Компонентные тесты: как сделать жизнь вашего QA немного проще?


Филипп говорил о компонентных тестах, о лучших практиках, которые выработала команда Филиппа в Avito. И как эти самые практики помогают делать качественный продукт.





Слайды



Аркадий Гамза, Badoo


Тема: Android Studio умеет больше, чем вы думаете


Я провел небольшой воркшоп в Android Studio. Показал некоторые полезные приемы, которые помогают разработчику не тратить время впустую.





Андрей Сидоров, Яндекс


Тема: Измерение энергопотребления мобильных и внедрение в Continuous Integration


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





Слайды



Григорий Джанелидзе, OK.ru


Тема: Как перестать беспокоиться и начать запускать фичи


Гриша рассказал о том, как Android-команда Одноклассников запускает новые фичи и о том, с какими проблемами приходится сталкиваться.





Слайды



Фотоотчет вы можете найти в нашей группе на Facebook, а посмотреть все видео в одном плейлисте – на нашем Youtube-канале.

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

https://habrahabr.ru/post/331426/


Метки:  

Знакомство с ServiceNow и управлением ИТ-инфраструктурой: Дайджест #2

Пятница, 23 Июня 2017 г. 10:22 + в цитатник
Сегодня «ИТ Гильдия» подготовила второй дайджест материалов (часть 1). В этой подборке мы использовали наши ознакомительные статьи для начинающих, руководства и обзоры.

Изображение Bruno Cordioli CC

Что читать в 2017 году для успешного внедрения ServiceNow
  • 5 основных книг, которые помогут познакомиться с новыми способами предоставления ИТ-услуг и по-новому взглянуть на организацию управления ИТ вашей компании.

Лучшие бесплатные ресурсы для специалиста ServiceNow
  • Еще одна подборка источников, которые помогут быстро разобраться с принципами работы ServiceNow. Здесь есть канал в Slack, официальные форумы и многое другое.

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

О платформе ServiceNow и как она помогает в работе (видео)
  • Здесь мы рассказываем о платформе ServiceNow для тех, кто только знакомится с темой. Мы говорим об основной концепции и автоматизации рабочих процессов.

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



Бюджетирование и оценка затрат в ServiceNow
  • Как использовать модуль Financial Management — говорим о финансовой составляющей ИТ, расчете стоимости сервиса и других возможностях ServiceNow.

Как внедрить процесс управления конфигурацией (часть 1)
  • Зачем нужно управлять конфигурацией, с чего стоит начать и как подойти к планированию этого процесса с точки зрения масштабирования.

Как внедрить процесс управления конфигурацией (часть 2)
  • Продолжение первой части, в котором мы рассказываем про этапы определения, контроля, учета состояния и аудита. Плюс немного о том, как задействовать ServiceNow.

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

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



К 2030 году ITSM перестанет быть только «IT»
  • Анализируем исследование «The Future IT Service Management Professional», которое открывает обсуждение будущего управления ИТ-процессами (ITSM) и роли ITIL.

Управление разработкой ПО — Agile Development
  • Как активировать Agile Development на платформе ServiceNow, немного о бэклоге релизов (Release Backlog), спринта (Sprint Backlog) и других нюансах.

IT Operations Management — управление ИТ-инфраструктурой
  • Как меняются корпоративные ИТ, с какими трудностями сталкиваются компании, как ITOM помогает ИТ-подразделению и сценарии его использования.

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

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

https://habrahabr.ru/post/331472/


Метки:  

[Перевод] Google и Apple против инди-разработчиков

Пятница, 23 Июня 2017 г. 10:13 + в цитатник


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

Нашу игру Fake Slap! засуспендили в Google Play за нарушение Политики в отношении насилия. Мы получили автоматическое письмо, сообщающее, что игра засуспенжена, и — бам! Она исчезла. Для нас это стало серьёзным шоком, игра находилась в Google Play и App Store уже больше месяца без каких-либо проблем. Политика в отношении насилия гласит: «Запрещается публиковать приложения, изображающие безнаказанное насилие или другие опасные действия». Ниже приводится несколько примеров, таких как: инструкции по причинению себе вреда, документирование своих атак террористическими группами, изготовление взрывных устройств и другого оружия и реалистичные изображения или подробные описания насильственных действий. Наша игра точно ничему из этого НЕ соответствует. Да, наша игра про политику, и её персонажем является президент США, но она определённо не относится к перечисленным видам насилия.

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

Автоматический ответ на апелляцию гласил, что мы получим ответ в течение 72 часов. Мы приостановили все планы по маркетингу игры и стали ждать. Потом подождали ещё немного. Через 11 нервных дней мы наконец получили ответ — нашу апелляцию не приняли. Мы снова и снова настаивали в течение пары недель, и продолжали получать автоматические ответы, отклоняющие наши апелляции. В этот момент мы уже потеряли надежду — все реакции были отстранёнными и равнодушными. Переписка не имела никакого смысла. Я решил связаться с журналистами, чтобы рассказать им нашу историю: может быть, кого-то заинтересует сюжет о том, как Google Play удалил политическую игру. Я переписывался с Колином Кэмпбеллом из Polygon. Раньше я читал его статьи и подумал, что ему это будет интересно. После рассказа о нашей истории он связался с отделом прессы Google и сделал заявление. Примерно через 5 часов мы «таинственным образом» получили письмо из Google, сообщающее, что игра будет восстановлена, аж через месяц после удаления. Совпадение? Не думаю.


Наша игра Fake Slap!, удалённая из Google Play

Восстановление игры было, конечно же, хорошей новостью, но мы чувствовали себя отвратительно. Почему нам пришлось найти журналиста, чтобы Google восприняла нас всерьёз? Я начала искать других людей, столкнувшихся с похожими проблемами, и была шокирована тем, насколько часто это происходит. Солидное количество игр и приложений автоматически удаляется из магазинов приложений (в основном из Google Play) даже без предупреждения и малейших шансов на исправление ошибок. Некоторым разработчикам везёт, но похоже, что многим даже не удаётся пробиться сквозь автоматические сообщения и они продолжают получать одинаковые письма с отклонением апелляций. Всем разработчикам известно, что добраться до живого человека в Google практически невозможно. Apple считается твёрдым орешком в процессе первоначального утверждения (многие разработчики даже не пытаются публиковаться на App Store), но если возникает проблема после или отклоняется обновление, то обычно всегда можно найти живого собеседника для обсуждения.

Есть множество причин для блокировок и удаления — от нарушения прав на товарные знаки за употребление слов типа «Flow» (в случае пользователя Reddit JakeSteam), «Candy» или «Saga», до спама, порнографии и насилия.

В случае Хау Нгуена (Hau Nguyen) игра Dodge Dodge изначально называлась «Circles Dodge». Она лежала в Google Play шесть месяцев (у неё были десятки тысяч скачиваний и сотни отзывов), но внезапно её удалили из-за «нарушения правил о спаме Политики в отношении контента». Google отклоняла апелляции Хау автоматическими письмами. Он не мог получить ответа о том, что же в игре посчитали спамом, и после того, как пообщался с коллегами-разработчиками на Reddit, решил опубликовать ту же игру под другим названием. Но конечно же, он потерял все загрузки и отзывы на предыдущую версию, и поставил под угрозу свой аккаунт разработчика (2 «страйка» и ты вылетаешь!).

У TK-Squared, LLC удалили два приложения: их программы Banger и Tuxedo показывали веб-сайты с потоковым воспроизведением радио (соответственно, рока и классической музыки). Причиной удаления было «нарушение правил платных и бесплатных услуг Политики в отношении контента». Это означало, что их обвинили в попытке зарабатывать деньги через сторонее приложение (не через Google Play), хотя они вообще не зарабатывали денег. Одна из потоковых радиостанций, включённых в список приложений, независимо от них собирала пожертвования на радио в своём колледже, но оно не имело никакой связи с TK-Squared. В случае с приложением Banger после недель переписок в попытках доказать Google, что компания не требует денег, не является благотворительной и не нарушает политику, апелляция была наконец принята. В случае Tuxedo Google перестала отвечать после двухмесячной переписки. Компания отправила обновление и повторно опубликовала приложение. Вот как разработчики описывают из общение с Google: «В ответах (на апелляции) никогда не ссылались на то, что мы говорили в предыдущем ответе и в обсуждениях ранее. Это ставило в тупик. Мы попробовали общаться в той же манере или найти другой способ отвечать, и ко второму месяцу переписки поняли, что разговариваем с ботом, потому что ничего, что мы говорили или делали, не приводило к осмысленным ответам Google».

У Джона (он попросил не упоминать его полного имени, потому что «старший брат» (Google) следит), опытного разработчика приложений из США, полностью удалили аккаунт разработчика. Google удалила три разных приложения, которые он разрабатывал для клиентов, за нарушение политики относительно мошенничества (выдачи себя за другое лицо) и политики в отношении порнографии (он утверждает, что ничего такого не было). После этого был полностью удалён его аккаунт с 120 приложениями. У него ушло три месяца на апелляции для возврата аккаунта и ещё несколько месяцев на повторную отправку всех приложений в магазин. Теперь Google автоматически отклоняет все приложения, отправляемые им без предварительного договора между ним и его клиентами под предлогом того, что он выдаёт себя за их организации. Он говорит, что приходится неделями ждать одобрения Google. Его цитата: «Как будто на продажу каждого яблока мне нужно спрашивать разрешения у садовника!»


Игра Exp3D: удалена через три года после публикации в магазине

Игру Адриана Курежа (Adrian Courr'eges) с открытым исходным кодом Exp3D засуспендили через три (!) года после публикации за нарушении политики размещения метаданных. Ему ещё повезло, после апелляции суспенд сменили на удаление, поэтому он смог просто опубликовать игру заново, сохранив все загрузки, отзывы и пользователей.

Приложение-виджет Reddit пользователя Reddit wrayjustin засуспендили за выдачу себя за другое лицо/введение в заблуждение после того, как он снял её с публикации. Приложение находилось в магазине с 2010 года, ни разу не обновлялось и не изменялось. Пользователь удалил его, потому что прослышал об агрессивных «страйках» за нарушение политик. За это его засуспендили.

Как я упоминала выше, похоже, что у Apple меньше историй с отклонением приложений. Apple известна тем, что у неё есть «конкретные» стандарты относительно контента, публикуемого в App Store. Поэтому отклонение большинства игр и приложений происходит заранее. В прошлом году было несколько статей о удалённых политических играх, например, о палестинском политическом платформере Liyla and the Shadows of War, политико-сатирических играх Everyday Arcade и других. Многие разработчики жалуются на ежегодный стодолларовый сбор с разработчиков и на то, что Apple обязует поставщиков услуг по разработке открывать учётную для каждого клиента (по 100 долларов на каждого).

Обновление игры Pixel Strike 3D компании Ascella Mobile Inc. отклонили за нарушение прав на торговый знак. Персонаж, который присутствовал в игре несколько месяцев, неожиданно напомнил кому-то шерифа Вуди (на самом деле игровой персонаж — это воксельный ковбой, похожий на любого ковбоя). Компании пришлось удалить его и все связанные с ним маркетинговые материалы.


Pixel Strike 3D: Тигги очень похож на Вуди?

У Гереона Стефенса (Gereon Steffens) было приложение-помощник для игры «Android: Netrunner». Очевидно, что в описании должно было присутствовать слово «Android», никак не связанное с операционной системой. За это слово приложение отклоняли несколько раз. К счастью, апелляции Гереона всегда принимались, но это не мешало постоянному отклонению обновлений.

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

Но почему технологические гиганты обеспечивают такую плохую поддержку разработчикам и поставщикам контента? Разработчики игр и приложений и так трудятся вовсю, пытаясь добиться признания на этом перенасыщенном рынке. Так зачем же владельцы магазинов приложений ещё больше усложняют им жизнь? Да ещё и забирают в процессе 30% их заработка? Ответ: потому что они могут.

И Google (или родительская компания Alphabet), и Apple, конечно же, являются частными компаниями, которые могут выбирать, кого пускать в свои магазины, но всё громче жалобы о том, что они стали в своих секторах настоящими монополиями. Это значит, что они могут обращаться с разработчиками (да и с кем угодно) как «принимай условия или проваливай». Передовицы New York Times и Business Insider недавно потребовали применить антимонопольное законодательство против технологических гигантов, заявляя о том, что они затрудняют конкуренцию, препятствуют инновациям и личным свободам. И Google, и Apple полностью доминируют на рынке магазинов приложений — 76% всех приложений публикуется в их магазинах (по данным statista.com на март 2017 года). Магазины Windows и Amazon намного позади них и не могут представлять реальной конкуренции ни одному из гигантов. Объединённые AT&T и Time-Warner вызывали гораздо большее внимание общества, имея при этом меньший процент рынка, так почему ничего не предпринимается в отношении техногигантов и их эксплуатации собственной мощи? Именно для этого и нужно антимонопольное законодательство: в первую очередь благодаря нему и возникла Google (в 90-х иск против Microsoft позволил стартапу Google предложить инновационный поисковый движок). Для Google уже давно прошли дни, когда девиз «Don’t Do Evil» был справедлив.


Количество приложений, доступных в ведущих магазинах приложений на март 2017 года (Statista)

В январе агентство Reuters сообщило, что суд США постановил: пользователи iPhone App могут подать иск против Apple за монополизацию iPhone App Market, которая ведёт к росту цен и уменьшению возможностей для разработчиков. Это было важной новостью для потребителей и разработчиков, но подали ли пользователи iPhone иск против Apple? Будет ли подобное юридическое дело для пользователей Android? Сомневаюсь в этом. Мне кажется, что изменения могут появиться только после вмешательства государства или общественного давления на технологических гигантов. Ясно то, что есть огромная потребность изменений во взаимоотношениях монополистов магазинов приложений с создателями контента. Необходимо разрушить монополии и открыть рынки для честной конкуренции, чтобы дать небольшим разработчикам (и другим магазинам приложений) настоящий шанс.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331404/


Метки:  

Где в ZX Spectrum системный монитор? Загадка ПЭВМ Дуэт

Пятница, 23 Июня 2017 г. 10:12 + в цитатник
ПЭВМ Дуэт — это российский клон ZX Spectrum 48k, производился Лианозовским электромеханическим заводом (ЛЭМЗ). Это мой самый первый компьютер и он со мной до сих пор. С юного возраста я начал постигать на нем азы программирования, микропроцессорных архитектур и проектирования цифровых схем. Но с тех пор мне не давал покоя вопрос: где системный монитор? Ведь он упоминается в документации. В стандартном ZX Spectrum я не припомню наличия какого-либо системного монитора. И в документации про системный монитор больше ни слова. Существует Монитор для 48к в ПЗУ версии от 1990г. Однако, после включения, ПЭВМ Дуэт выводит на экран вместо стандартного приветствия — "(с) 1982 sinclair research ltd" другое приветствие: "(с) DUET". А это значит, что ПЗУ там всё же изменено. А может быть есть аппаратные возможности мониторинга? К примеру, клон Орель БК-08 имеет целый ряд доработок: теневое ОЗУ, кнопка NMI и монитор MZ80. Было бы очень интересно, спустя столько лет, найти какие-то скрытые возможности своей железки.

Наконец-то я нашел ответ на вопрос, который меня периодически волновал все эти годы.

image

Почему сейчас?


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

Очередное пришествие вопроса о мониторе


Впервые вопросом про монитор я задался практически сразу после покупки, но ответа так и не нашел. Уже в наше время, в начале 2016 года я попробовал узнать на форуме, но ответ опять не нашелся. Вопрос так бы и забылся, но случайно на глаза попалось объявление о продаже клона спектрума — «Нафаня», и там была фотография странички документации, в которой было написано: «ПЗУ содержит интерпретатор языка Бейсик и системный монитор». Ну и мы решили все же разобраться и поставить точку в этом вопросе

image

Товарищи по форуму дали совет:
Скорее всего под системным монитором понимается набор стандартных подпрограмм ПЗУ. Попробуйте:
1. посмотреть на плате установленные ПЗУ, похоже что у вас стоит 2 шт по 8К, это 16К, если дополнительных ПЗУ нет, то искать нужно среди имеющихся 16К.
2. слить дамп ПЗУ и сравнить со стандартным синклеровским, обычно менялась только надпись в клонах. По различиям можно прикинуть есть-ли что-то интересное.
Ну не может быть, что все так просто! Изучение схемы показало, что никаких дополнительных ПЗУ там нет: две ПЗУ по 8Кб (составляющие стандартные 16кБ ПЗУ с бейсиком). Судя по фотографии внутренностей именно моего экземпляра, мой вариант ничем не отличается от схемы на сайте (на самом деле, есть мелкие доработки/изменения, о которых, может быть, в другой раз). Таким образом, аппаратных возможностей для существования монитора не обнаружено.

Сверяем дампы ПЗУ


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

1) Получить данные из ПЗУ на ПЭВМ Дуэт. Вынимать ПЗУ из платы и пользоваться программатором для этого вовсе не требуется. По той простой причине, что ПЗУ в 48к версии целиком отображается в адресное пространство по адресам 0..16383. Это самый низ адресного пространства. Ее можно как считывать программно, так и сохранить через магнитофонный выход командой Бейсика SAVE "ROM" CODE 0, 16384
2) Преобразовать данные из звукового файла в TAP файл с помощью утилиты на ПК
3) Извлечь данные из формата TAP в двоичный формат
4) Написать или найти утилиту для сравнения побайтно двух двоичных файлов — с Дуэта и с оригинального спектрума.

Уже на первом этапе я эту идею отбросил, потому что в ноутбуке нет линейного входа, да и переходник у меня спаян только в сторону воспроизведения звука на ПК или смартфоне через линейный выход для подключения на вход ПЭВМ Дуэт. Потому что 99% времени сейчас это загрузка данных в Дуэт, а не наоборот.

Поэтому я решил поступить с точностью до наоборот. Взять оригинальное ПЗУ и загрузить его в оперативную память Дуэта через магнитофонный вход. Затем написать программу для сверки данных в ячейках памяти с выводом информации отличающихся ячеек. Двоичные данные оригинального ПЗУ есть практически в каждом эмуляторе ZX Spectrum. Но для перевода их в звук, для последующей загрузки через магнитофонный вход, пришлось немного повозиться. Я перебрал 3-4 программы, прежде чем смог сделать из двоичного файла TAP файл. Потом уже проще — с помощью утилиты Tape2WAV получил звуковые файлы.

Для загрузки данных с магнитофона в Бейсике ZX Spectrum используется команда LOAD, с параметрами, которые указывают, что грузится код, и в какой адрес памяти его грузить, соответственно, команда LOAD "" CODE 40000 загрузила данные оригинального ПЗУ в память, начиная с адреса 40000.

Написание программы для сверки памяти


Я радостно потираю руки, потому что придется вспомнить свой школьный опыт и программировать под ZX Spectrum причем на нём самом! А, впрочем, чего там вспоминать? Бейсик забыть невозможно, тем более такой простой. Ошибиться в наборе команд трудно, потому что каждое нажатие клавиши вводит сразу целую команду. Быстро и удобно, как Т9, только для Бейсика! Еще хочу сказать, что пользоваться 48к Бейсиком на эмуляторе как раз не удобно, из за того, что на современных компьютерах не подписаны команды Бейсика. Еще один плюс даже такой маленькой машины, как 48к: мы сразу готовы к работе после включения. Никакую среду разработки, компилятор загружать не потребуется. Все, что нужно для работы — есть в ПЗУ.

Бейсик внутри ZX Spectrum интерпретируется. Это снижает скорость работы программ. Но писать такую простую и не критичную к скорости программу на ассемблере — это я считаю уже перебор. Программа пишется за 5 минут. И даже если она будет работать столько же, то меня это устроит. Но оказалось, что потребовалось даже меньше пяти минут:

image

На скриншоте программа, которую я набрал в эмуляторе (только для того, чтобы сделать скриншот с исходным кодом). Такую же програму я набрал на Дуэте. Поверх скриншота я подписал данные по различиям, найденным в ячейках памяти. Чтож, изменений не так и много. Теперь нужно понять, чего коснулись эти изменения. Для этого нужно знать, что находится в ПЗУ по найденным адресам. К счастью, вся информация есть в книге «Полный дизассемблер ПЗУ ZX-Spectrum» на русском.

Ячейка 109 — в оригинальной ПЗУ 40d в Дуэте 32d
006d 32 вместо 40. Значит 20h(JR nz,*) вместо 28h (JR z,*), а в книге jr nz.

image

Как оказалось, в изначальной версии ПЗУ от 82 года, в этом месте допущена ошибка. Это код обработки немаскируемого прерывания. Без этой ошибки, можно задать в переменной NMIADD адрес перехода на обработчик, например, тот же монитор. И по сигналу NMI (кнопкой NMI, как на Орель БК-08), компьютер перешел бы на этот обработчик. Исправления по этому адресу говорят о том, что в Дуэте эта ошибка исправлена и сигнал NMI может полноценно использоваться. Чтож, уже не плохо, но судя по количеству оставшихся изменений в ПЗУ, код монитора в него всетаки не вшит :(

Ожидаемо, 4 байта — это «DUET» вместо (С) 1982 Sinclair Research Ltd
1539 (C)
153A пробел " "
153B 68 "D"
153C 85 "U"
153D 69 "E"
153E 212 последний символ. инвертированный. 212d + 80h = 54h - "T"

(СООБЩЕНИЯ — Каждое сообщение выдается с инвертированным последним символом (+80, шестнадцатеричное).

Монитора нет, расходимся?


К сожалению, никакого системного монитора-отладчика я не нашел, хотя очень старался. Но я очень рад, что смог это выяснить самостоятельно… Но. Но что же такое «системный монитор»? Почему про него написано в доументации к Дуэту и Нафане? Как и было написано выше, «Скорее всего под системным монитором понимается набор стандартных подпрограмм ПЗУ». Так же, в книге с полным дизассемблером ПЗУ ZX Spectrum мы можем прочитать следущее:
...
ПОЛНОЕ ОПИСАНИЕ ПЗУ КОМПЬЮТЕРА ZX SPECTRUM
...
ВВЕДЕНИЕ
Монитор Spectrum, объемом 16K, представляет собой сложную программу в машинных кодах
Z80. Ее можно разделить на три основные части:
а. Программы ввода/вывода.
б. Интерпретатор BASIC.
в. Вычислительные процедуры.
Однако, для подробного описания эти блоки слишком громоздки, и поэтому монитор
разделен еще на 10 частей. Каждая часть будет представлять собой элемент монитора.


В последние годы, когда кто-то пишет про ZX Spectrum, то содержимое ПЗУ он скорее всего назовет ОС ZX Spectrum — это встроенный Бейсик. Но в те времена, видимо, такого понятия еще не сформировалось. Были небольшие программы — мониторы для просмотра и изменения содержимого ячеек памяти в HEX виде. Использовались для отладки программ в машинных кодах. По сравнению с ними, спектрумовский «монитор» был очень крут. А то, что мы сейчас называем «монитор», тогда чаще называли «дисплеем».

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

https://habrahabr.ru/post/264913/


Метки:  

Как с помощью блокчейна защитить свои данные

Пятница, 23 Июня 2017 г. 10:00 + в цитатник
Прошлый, 2016 год оказался богат на новости, связанные с технологией блокчейн и кейсами ее применения в реальной жизни. Barclays провел первую в мире реальную торговую сделку между ирландским производителем молочной продукции Ornua и сейшельской торговой компанией, австралийский финансовый конгломерат Commonwealth Bank of Australia, американская финансовая компания Wells Fargo и компания Brighann Cotton Marketing Australia впервые в мире оформили сделку по продаже и доставке хлопка из США в Китай, а авиакомпания S7 и Альфа-Банк провели первую в России сделку-аккредитив. В связи с этим может показаться, что область применения блокчейна ограничивается исключительно финансовым сектором, однако блокчейн затронул и область защиты данных.



Блокчейн на страже ваших данных


Когда открылась возможность вносить в регистр не только данные транзакций, но и различные метаданные, мы в Acronis начали активно изучать технологию блокчейн на предмет ее применения в направлении резервного копирования и защиты информации. Мы увидели, что благодаря ей у пользователя появляется возможность гарантировать не только сохранность, но и неизменность/подлинность самых важных данных.
 
В 2016 году началась разработка и тестирование первых решений, построенных на открытой платформе Ethereum, которая на тот момент была одной из самых продвинутых и удобных, а также позволяла обойти ограничения Bitcoin-блокчейна.
 
Первым решением, выпущенным нами на рынок, стал trusted timestamping сервис Acronis Notary. Технология была реализована в рамках функционала продукта для индивидуальных пользователей Acronis True Image 2017 New Generation. С его помощью можно проверять аутентичность хранящихся в резервных копиях данных. Например, музыканты или художники могут подтверждать дату и время создания своих произведений, предоставляя в качестве доказательства сертификат Acronis Notary с указанием данной информации, наряду с метаданными о самом произведении.


Вторым решением, которое мы также продемонстрировали в рамках функционала продукта Acronis True Image 2017 New Generation, стало Acronis ASign. Решение открыло возможность электронного подписания резервных копий документов с автоматической нотаризацией. Пользователь просто загружает в облако Acronis подписанные со своей стороны документы и рассылает другим подписантам электронные приглашения. Каждый из подписантов заходит в облако и с помощью специального интерфейса ставит свою электронную подпись на документе. Таким образом, между сторонами «подписывается» своего рода договор, который автоматически фиксируется в блокчейне.
 

Техническая сторона вопроса


Как отмечалось выше, нам удалось обойти ряд ограничений блокчейна, тем самым создать достойный задел на будущее. Хранение данных в наших решениях построено на основе деревьев Меркла. Благодаря этому можно существенно повысить скорость работы и объем хранимой информации о файлах, а также (что очень важно в долгосрочной перспективе) снизить требования к производительности обрабатывающих систем.
 
Про деревья Меркла aka «хэш-деревья» известно давно, их концепция была запатентована Ральфом Мерклом еще в 1979 году. Это особая структура данных, содержащая итоговую информацию о каком-то большом объеме данных, и которая может быть использована для их верификации. При этом набор информации может быть самым разнообразным: можно хранить любые необходимые данные о файле, будь то его размер, дата создания или еще что-то.
 
Таким образом, понятно, что структура данных имеет древовидную форму, в узлах которой находятся хэши, созданные на основе данных других, нижестоящих узлов. В конечных формируются корневые хэши, которые и записываются в блокчейн.
 
Мы используем двоичную структуру, при которой каждый вышестоящий хэш состоит из двух нижестоящих хэшей. Если представить это в форме схемы, то получим следующее.



Одно из главных свойств дерева Меркла состоит в том, что, зная data 1, hash 2, hash 02 и hash 001, можно подтвердить аутентичность данных data 1, даже если остальные данные не известны. Это означает, что, если вы поместите какой-то файл в Acronis Notary или подпишете какой-то документ с помощью Acronis ASign, затем дадите кому-то из друзей/коллег только хэш исходного файла (hash 1), «ветвь» с хэшами от hash 1 до корневого хэша (hash 001) и корневой хэш (такая структура назвывается «доказательством Меркла»), то друг/коллега с легкостью сможет проверить, тот ли файл сейчас находится в хранилище или нет.


 

Де Факто/Де Юре


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

Будущее наступило


Недалекое будущее. Космические корабли бороздят просторы Большого театра, самозавязывающиеся кроссовки от Nike доступны в продаже, а записи в блокчейне признаются судебной системой нашей страны.
 
Вы решили приобрести машину/квартиру/дачу, нашли подходящий вариант и связались с продавцом. Договор купли-продажи было решено подписать с помощью электронных подписей и внести данные в блокчейн. Вы взяли типовой текст договора, внесли необходимые реквизиты, сохранили в защищенном облаке и направили с помощью Acronis ASign на подпись продавцу. Он внимательно изучил договор, обратил ваше внимание на опечатку в фамилии и подписал исправленную версию.
 
Машина/квартира/дача ваша. Но проходит какое-то время, и вдруг объявляется прошлый владелец, заявляющий, что вы не расплатились, должны ему X рублей, и вообще незаконно забрали его собственности. Вы же все оплатили вовремя, не собираетесь идти на поводу у мошенника и направляетесь в суд.
 
Договор существует только в электронном виде, не был заверен у нотариуса и в суд его так просто не принести. Это означает, что перед вами вырисовывается очень интересный квест, в рамках которого вам понадобится доказать три вещи:
 
  • Договор, находящийся в защищенном хранилище, никто не менял;
  • Договор прочитали и подписали обе стороны;
  • Договор был подписан в определенное время.

Скорее всего, на судебное разбирательство необходимо будет пригласить эксперта, который расскажет представителям правосудия, что из себя представляет технология блокчейн, как хранятся данные и почему их нельзя незаметно подделать/изменить. После краткого ликбеза эксперт попросит вас предоставить электронный документ суду, и тут начнется все самое интересное.
 
При подписании документа в Acronis ASign пользователю выдается специальный файл в формате PDF, содержащий «Signature Certificate» и «Audit Trail».


В «Signature Certificate» содержится следующая информация:
 
  • Имя документа, который вы подписали и поместили в хранилище, например, «Договор купли-продажи №1»;
  • Дата подписания;
  • Размер документа;
  • Хэш или «контрольная сумма» документа;
  • Текущий статус;
  • Информация о подписантах;
  • Подпись.

В «Audit Trail» содержится детальная история событий, происходивших с документом (создание, отправка подписантам, подписание), включая временные отметки и IP-адреса подписантов. Это необходимо, чтобы поставленная электронная подпись соответствовала требованиям международного «Electronic Signature Law» и признавалась в суде.

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

 
После завершения загрузки файла на сайте будет показан статус этого документа. Таким образом, вы докажете в суде, что договор купли-продажи был подписан обеими сторонами в определенное время. Часть квеста пройдена!
 
Кроме статуса, также будет предоставлена ссылка на сертификат Acronis Notary, содержащий всю информацию о документе в защищенном хранилище. С помощью этого сертификата вы доказываете аутентичность, то есть подлинность подписанного договора. Victory!
 
Есть еще один путь, несколько сложнее, но намного интереснее.
 
Вы берете документ и самостоятельно рассчитываете его хэш. Затем из сертификата Acronis Notary берется адрес транзакции в блокчейне (Transaction ID) и находится в онлайн-сервисе, вроде Etherscan.io, позволяющем подтвердить наличие транзакции в Ethereum-блокчейне. В поле данных этой транзакции вы находите Merkle Root и проверяете вхождение хэша, который вы рассчитали для своего документа, в дерево с таким корневым элементом, с помощью open source утилиты verifyhash. Если проверка прошла успешно, аутентичность подписанного документа в хранилище подтверждена. И снова Victory!
 

Продолжение следует


Внедрив Acronis Notary и Acronis ASign в наш продукт Acronis True Image 2017 New Generation, мы собрали огромное количество положительных отзывов от индивидуальных пользователей. Фактически мы провели масштабное тестирование в реальных условиях. И уже сейчас, обработав все результаты и максимально устранив шероховатости, мы внедрили эти решения в наш корпоративный продукт – Acronis Backup 12.5.  
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331326/


Метки:  

Возможности PostgreSQL для тех, кто перешел с MySQL

Пятница, 23 Июня 2017 г. 09:27 + в цитатник

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


Мы рады сообщить, что подготовка к PG Day'17 Russia идет полным ходом! Мы опубликовали полное расписание предстоящего мероприятия. Приглашаем всех желающих прийти и похоливарить с Антоном лично :-)


image


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


Почему вообще возникла идея такого доклада? Дело в том, что PostgreSQL сейчас явно хайповая технология, и многие переходят на эту СУБД. Иногда — по объективным причинам, иногда — просто потому что это модно.


Но сплошь и рядом складывается такая ситуация, когда какой-нибудь условный программист Вася вчера писал на MySQL, а сегодня вдруг начал писать на Посгресе. Как он будет писать? Да в целом также, как и раньше, используя лишь самый минимальный набор возможностей новой базы. Практика показывает, что проходят годы, прежде чем СУБД начинает использоваться более менее полноценно.


Не холивар


Сразу disclaimer: это не статья "мускуль vs посгрес". Переходить на посгрес или нет — ваше дело. Uber, к примеру, перешел обратно на MySQL по своим каким-то причинам.


Надо отдать должное Oracle, они явно двигают MySQL в правильном направлении. В 5.7 сделали strict mode по умолчанию. В восьмой версии обещают CTE и оконные функции, а также избавление от движка MyISAM в системных таблицах. Т.е. видно, что в базу вкладываются ресурсы, и хотелки юзеров исследуются очень серьёзно.


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


Встроенные типы данных


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


Например, есть типы cidr, inet, macaddr для работы с ip адресами.


-- проверяем, входит ли ip адрес '128.0.0.1' в cidr '127.0.0.0/24' 
-- с помощью оператора &&
select '127.0.0.0/24'::cidr && '128.0.0.1';
-- вернет false

Или например, время с таймзоной (timestamptz), интервал времени и т.д.


-- Сколько сейчас времени в Нью-Йорке?
SELECT NOW() AT TIME ZONE 'America/New_York';

-- Сколько часов разницы сейчас между Москвой и Нью-Йорком?
SELECT NOW() AT TIME ZONE 'America/New_York' 
     - NOW() AT TIME ZONE 'Europe/Moscow';
-- результат: -07:00:00  

Когда я готовил этот слайд, я решил из любопытства посмотреть, а какое смещение времени относительно UTC было 100 лет назад, в 2017 году:


select '1917-06-17 00:00:00 UTC' at time zone 'Europe/Moscow';
-- результат: 1917-06-17 02:31:19

Т.е. москвичи жили по времени UTC+02:31:19.


Кроме перечисленных, есть и другие встроенные типы данных: UUID, JSONB, XML, битовые строки и т.д.


Тип array


Отдельно надо рассмотреть тип "array". Массивы давно и хорошо интегрированы в PostgreSQL. Многомерные массивы, слайсы, операторы пересечения, объединения и т.д. Существует множество функций для работы с массивами.


--- Пример проверки пересечения массивов
SELECT ARRAY [1, 2, 8, 10] && ARRAY [1, 2, 3, 4, 5];

--- Входит ли один массив в другой?
SELECT ARRAY [1, 2] <@ ARRAY [1, 2, 3, 4, 5]

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


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


INSERT INTO users
  (id, status, added_at)

  SELECT user_id, 5, '2010-03-03 10:56:40'
    FROM unnest(array[123, 1232, 534, 233, 100500]) as u(user_id)

Создаем собственные типы


Собственные типы можно создавать тремя способами. Во-первых, если вы знаете язык Си, то вы можете создать базовый тип, наравне с каким-нибудь int или varchar. Пример из мануала:


CREATE TYPE box (
  INTERNALLENGTH = 16,
  INPUT = my_box_in_function,
  OUTPUT = my_box_out_function
);

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


CREATE TABLE myboxes (
  id integer,
  description box
);

Второй способ — это композитный тип. Например, для хранения комплексных чисел:


CREATE TYPE complex AS (
  r       double precision,
  i       double precision
);

И потом использовать это:


CREATE TABLE math (
  result complex
);

INSERT INTO math
  (result)

  VALUES
    ((0.5, -0.6)::complex);

SELECT (result).i FROM math;
-- результат: -0.6

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


CREATE DOMAIN us_postal_code AS TEXT;

us_postal_code — это более семантично, чем некий абстрактный text или varchar.


Создаем собственные операторы


Можно делать свои операторы. Например, сложение комплексных чисел (сам тип complex мы определили выше):


-- описываем функцию сложения, например, на языке SQL
CREATE OR REPLACE FUNCTION sum_complex(x COMPLEX, y COMPLEX) 
RETURNS COMPLEX AS $$
  SELECT x.r + y.r, x.i + y.i;
$$ language sql;

-- создаем оператор "плюс" для комплексных чисел
CREATE OPERATOR +
(
  PROCEDURE = sum_complex,
  LEFTARG = COMPLEX,
  RIGHTARG = COMPLEX
);

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


Давайте сделаем какой-нибудь сферический в вакууме пример. Создадим типы RUR и USD, и правило для преобразования одного типа в другой. Так как я плохо знаю си, то для примера сделаем простой композитный тип:


CREATE TYPE USD AS (
  sum FLOAT
);

CREATE TYPE RUR AS (
  sum FLOAT
);

-- функция преобразования долларов в рубли (по курсу 60, это же сферический пример)
CREATE FUNCTION usd2rur(value USD)
RETURNS RUR AS $$
  SELECT value.sum * 60.0;
$$ LANGUAGE SQL;

-- описываем правило для посгреса, какой тип как "кастить".
CREATE CAST ( USD AS RUR )
  WITH FUNCTION usd2rur(USD) AS ASSIGNMENT;

Собственно, это всё, теперь можно использовать. Сколько там будет 100 баксов в рублях?


select '(100.0)'::usd::rur;

Результат будет таким:


rur
--------
(6000)
(1 row)

Типы в расширениях PostgreSQL


Существуют расширения, где описаны типы данных и все, что для них нужно. Например, расширение ip4r, описывающее типы для IP-адресов и их диапазонов.


Если вы посмотрите исходники https://github.com/RhodiumToad/ip4r/blob/master/ip4r--2.2.sql, то увидите, что расширение — это просто, по сути, набор иструкций CREATE TYPE, CREATE OPERATOR, CREATE CAST и т.д.


Описаны правила индексирования. Например, тип ip4r (диапазон IP-адресов) можно проиндексировать индексом GIST по оператору && (и другим). Таким образом, можно сделать таблицу для поиска городов по IP.


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


Индексы


Помимо стандартного btree есть и другие: GIN (можно использовать для некоторых операций с массивами, для jsonb, для полнотекстового поиска), GIST, brin и т.д.


Partial indexes


Бывают ситуации, когда у вас 10 миллионов строк в таблице, при чем из них только штук 100, допустим, в статусе "Платеж обрабатывается". И вы постоянно дергаете этот статус "обрабатывается" как-то так: select ... where status = 2.


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


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


CREATE INDEX my_money_status_idx on my_money(status) WHERE status = 2;

Этот индекс будет хорошо работать на запросах select * from my_money where status = 2 и при этом занимать мало места.


Индексы по выражению


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


CREATE INDEX people_names
ON people ((first_name || ' ' || last_name));

И потом такой запрос будет быстро работать:


SELECT *
FROM people
WHERE
(first_name || ' ' || last_name) = 'John Smith';

Constraints


Помимо стандартных UNIQUE и NOT NULL, в базе можно делать еще и другие проверки целостности. В доменном типе можно прописать check:


CREATE DOMAIN us_postal_code AS TEXT
CHECK(
  VALUE ~ '^\d{5}$'
  OR VALUE ~ '^\d{5}-\d{4}$'
);

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


Также check можно прописать в таблице:


CREATE TABLE users (
  id integer,
  name text,
  email text,
  CHECK (length(name) >= 1 AND length(name) <= 300)
);

Т.е. в имени должен быть хотя бы один символ, и не больше 300.


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


INSERT INTO math (result) VALUES ((0.5, 'привет')::complex);
ERROR: invalid input syntax for type double precision: "привет"

Таким образом, иногда композитный тип может быть предпочтительнее, чем jsonb, потому что в json вы можете напихать что угодно вообще.


Частичная уникальность и уникальность по выражению


В отличие от простой уникальности UNIQUE или PRIMARY KEY, в посгресе можно сделать уникальность среди определенного набора строк, заданного условием. Например, email должен быть уникальным среди неудаленных юзеров:


CREATE UNIQUE INDEX users_unique_idx
  ON users(email)
  WHERE deleted = false;

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


CREATE TABLE test_summ (
  a INT,
  b INT
);

CREATE UNIQUE INDEX test_summ_unique_idx
  ON test_summ ((a + b));

INSERT INTO test_summ VALUES (1, 2);

INSERT INTO test_summ VALUES (3, 0);
-- выдаст ошибку уникальности

Constraint Exclude


Ключевое слово EXCLUDE позволяет делать так, что при вставке/обновлении строки, эта строка будет сравниваться с другими по заданному оператору. Например, таблица, содержащая непересекающиеся диапазоны IP (проверяется оператором пересечения &&):


CREATE TABLE ip_ranges (
  ip_range ip4r,
  EXCLUDE USING gist (ip_range WITH &&)
);

Вообще, обычный UNIQUE — это, по сути, EXCLUDE с оператором =.


Хранимые процедуры


Хранимые процедуры можно писать на SQL, pl/pgsql, javascript, (pl/v8), python и т.д. Например, можно на языке R обсчитать какую-то статистику и вернуть из нее график с результатом.
Это отдельная большая тема, советую поискать доклад Ивана Панченко на этот счет.


CTE (Common Table Expressions)


Это будет и в MySQL 8, но всё равно давайте кратко остановимся на этом.


CTE — это просто. Вы берете какой-то кусок запроса и выносите его отдельно под каким-то именем.


WITH  subquery1 AS (
  SELECT ... -- тут куча всяких условий и тд.
),
subquery2 AS (
  SELECT ... -- тут тоже куча условий, группировок
)
SELECT *  -- начался основной запрос
  FROM subquery1
    JOIN subquery 2
  ON ...

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


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


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


В CTE можно использовать не только SELECT-запросы, но и UPDATE.


Пример: обновить юзеров с возрастом > 20 лет, и в том же запросе выдать имена обновленных вместе с какой-нибудь там страной.


with users_updated AS (
  UPDATE users
    SET status = 4
    WHERE age > 20
    RETURNING id
)

SELECT name, country
  FROM users
  JOIN countries
    ON users.country_id = countries.id
  WHERE id IN (
  SELECT id
    FROM users_updated
);

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


WITH
update1 AS (
  UPDATE test
  SET money = money + 1
),

update2 AS (
  UPDATE test
  SET money = money - 1
)

SELECT money FROM test;

Кажется, что мы прибавили рубль, потом отняли рубль, и должно остаться всё как есть.


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


Оконные функции


Про оконные функции я уже когда-то подробно писал здесь: https://habrahabr.ru/post/268983/. Оконные функции тоже обещают в MySQL 8.


Разное


FILTER


К агрегатным функциям (например, COUNT или SUM), можно дописывать условие FILTER, т.е. агрегировать не все строки, а только ограниченные неким выражением:


SELECT
  count(*) FILTER (WHERE age > 20) AS old,
  count(*) FILTER (WHERE age <= 20) AS young

FROM users;

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


\watch


Все знают, что в psql есть команды для просмотра разных объектов, например \d, \dt+ и т.д.
Есть особая команда, называется \watch. Т.е. вы выполняете запрос, потом пишете
\watch 5 и ваш запрос будет выполняться каждые 5 секунд, пока не отмените.
Это работает не только с select, но и с любым другим, например с update (например, когда нужно большую таблицу медленно обновить по чуть-чуть).


Materialized View


Это как View, только закешированное (материализованное). Кеш можно обновлять с помощью команды REFRESH MATERIALIZED VIEW. Есть также ключевое слово CONCURRENTLY, чтобы Postgres не лочил при обновлении SELECT-запросы.


Listen / Notify


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


FDW


Механизм Foreign Data Wrappers позволяет использовать некоторые внешние данные, как простые таблицы. Т.е. к примеру, можно заджойнить постгресовую таблицу, мускульную таблицу, и csv файл.


Sequences


SEQUENCE — это посгресовый аналог MySQL-ного AUTO_INCREMENT. В отличие от MySQL, sequence может существовать отдельно от таблиц или наоборот, "тикать" сразу для нескольких таблиц. Можно задавать различные параметры, например, размер инкремента, зацикливание и проч.


Вместо выводов


Это верхушка айсберга, на самом деле. Есть еще куча нюансов, вообще никак не затронутых в статье, потому что на всё никакой статьи не хватит. По одним только хранимым процедурам можно написать книгу. Или посмотрите, к примеру, полный список sql-команд текущей версии: https://www.postgresql.org/docs/9.6/static/sql-commands.html


Главное, что я хотел показать в статье: несмотря на хайповость, PostgreSQL — очень старая СУБД, в которой очень много чего есть, и которая очень хорошо расширяется. Поэтому при переходе на нее с MySQL рекомендуется полистать мануал, почитать статьи и т.д.

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

https://habrahabr.ru/post/331460/


Метки:  

Виртуальные твари и места их обитания: прошлое и настоящее TTY в Linux

Пятница, 23 Июня 2017 г. 09:03 + в цитатник
Ubuntu интегрирована в Windows 10 Redstone, Visual Studio 2017 обзавелась поддержкой разработки под Linux – даже Microsoft сдает позиции в пользу растущего числа сторонников Торвальдса, а ты всё еще не знаешь тайны виртуального терминала в современных дистрибутивах?

Хочешь исправить этот пробел и открываешь исходный код? TTY, MASTER, SLAVE, N_TTY, VT, PTS, PTMX… Нагромождение понятий, виртуальных устройств и беспорядочная магия? Всё это складывается в довольно логичную картину, если вспомнить, с чего всё началось…

1. START FROM SCRATCH & KEEP CALM


TTY: ПАЛЕОЗОЙ


Мы шагнули прямиком в тридцатые годы XX века и оказались в совсем еще молодой Teletype Corporation. Прямо перед нами перед нами Тот-С-Которого-Всё-Началось – телетайп, представляющий из себя «буквопечатающий телеграф», который передает текстовые сообщения между двумя абонентами.

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


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

TTY: МЕЗОЗОЙ


Прошло сорок лет, мы в лаборатории Digital Equipment Corporation, любуемся первым мини-компьютером (интерактивным!) PDP-1. Для ввода и вывода информации, а также для обеспечения взаимодействия с пользователем к нему подключен уже знакомый нам телетайп.

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

TTY: ПАЛЕОГЕН


Оказываемся в самом начале 80-ых годов, на этот раз в Bell Laboratories. Здесь только что выпущен один из важнейших релизов «раннего» UNIX – Version 7 для PDP-11. Особенности у этого релиза следующие: вводимая пользователем команда теперь отображается по принципу ECHO (набранный на клавиатуре символ сначала попадает в буфер накопления и только потом ОС отправляет инструкцию вывести этот символ на печать), поддерживаются простые возможности редактирования вводимых команд (можно «стирать» символ или целую строку, перемещать каретку), появляется разделение режимов:
  • raw mode (редактирование строки не производится; управляющие последовательности распознаются как обычные символы; введенный символ немедленно передается процессу);
  • cooked mode (происходит распознавание специальных символов и генерирование сигналов остановки и прерывания для процесса; передача готовой строки процессу осуществляется только после нажатия клавиши Return).

Вполне ожидаемый вопрос: как же можно «стереть» то, что уже напечатал телетайп? Для наглядного выполнения операций редактирования Unix Version 7 предусмотрена печать определенных символов: например, @ — стереть всю строку, # — стереть последний символ. То есть, если наш телетайп напечатал ld@lk#s, и оператор нажал Return, то на исполнение пошла команда ls. Это еще не TTY LINE DISCIPLINE (о ней речь пойдет дальше), но уже большой шаг вперед в отношении обработки ввода на уровне ОС.

Кстати говоря, Digital Equipment Corporation за эти 20 лет не только разработала упомянутый PDP-11, но и подумала о том, как усовершенствовать телетайп: появились так называемые умные терминалы.

Смотрим направо: это VT100, один из первых терминалов, умеющих работать в любви и согласии с PDP-11 и поддерживаемый Unix Version 7.

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


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

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

TTY: НЕОГЕН


Мы очутились в редакции журнала «PC MAGAZINE», рассматриваем свежий выпуск от 13 января 1987 года. Один из разворотов активно убеждает нас не жалеть денег на ПК с UNIX System V. Каковы аргументы? В частности – grep, awk, sort, split, cut, paste, vi, ed – word processing явно шагнул вперед. И самое интересное: к нашим услугам сейчас эмуляторы терминалов! Благодаря виртуальным консолям, уже можно запустить целых четыре сессии без нужды подключать всё новые и новые физические телетайпы.

Кроме того, жизнь монохромных терминалов нынче можно расцветить: поддерживается CGA, Hercules, EGA графика. Бедолага-оператор может вздохнуть спокойно, телетайп (а также умный терминал) в виде железного зверя угрожает ему только в ночных кошмарах.

Посоветуем оператору лишь одно: ни за что не лезть в директорию /dev – ведь его ждут там аж несколько ttyX и напоминают о том, что под капотом виртуальной консоли живет всё тот же старый-добрый телетайп.

TTY: АНТРОПОГЕН


На предыдущем шаге мы убедились: консоль сделали виртуальной (не будет же солидное издание «PC MAGAZINE» лгать). Что это значит – весь механизм ввода/вывода переписан и в корне изменен? Тогда почему виртуальное устройство – всё еще ttyX? Всё просто: виртуальная консоль эмулируется как самая что ни на есть физическая, а место UART-драйвера, вероятно, занимает кто-то другой. Изменившуюся схему подробно обсудим чуть дальше.

До финишной прямой один шаг, но пропустить его мы не можем хотя бы из уважения к Линусу Торвальдсу. Сейчас 1993 год, и мы наконец имеем счастье рассматривать исходный код Linux 0.95. Почему именно этот релиз? Именно в нем уже сформировалась TTY-абстракция, наиболее близкая к тому, что мы имеем в самых последних дистрибутивах: оформились три обособленных слоя (TTYX — TTY_LINE_DISCIPLINE — TTY_DRIVER).

Кроме того, спустя всего год будет выпущен Linux 1.0, где появится оконный интерфейс, предоставленный проектом XFree86. С этого момента к виртуальным консолям добавятся в придачу еще виртуальные терминалы, которые пользователь (в почти не ограниченном количестве) сможет запускать, не покидая графическую оболочку… Однако прежде, чем окунуться в тонкости и детали усовершенствованной io-магии, вернемся в наше настоящее к Ubuntu 16.04.

2. STOP BEAT AROUND THE BUSH & LOOK INSIDE



ВИРТУАЛЬНЫЕ ТВАРИ И МЕСТА ИХ ОБИТАНИЯ


Лишь некоторые устройства директории /dev/ используются повседневно: /dev/sdaX, /dev/mem, /dev/zero, /dev/random… Но есть несколько групп устройств, которые не часто привлекают наше внимание, однако более чем его заслуживают. Это устройства /ttyX, /vcsX, /vcsaX, а также /ptmx и /pts/X. Собственно говоря, о них и пойдет речь дальше.



И первый наш объект – виртуальная консоль. Каждому такому объекту присущи как минимум сакральное число идентификатор и тотемное животное файл виртуального устройства /tty, коих в виртуальном лесу директории /dev встречают аж 64.

Проверим, есть ли у нас возможность пообщаться с ними. Выполняем Ctrl-Alt-FX (или chvt X, где X – номер консоли, например, Ctrl-Alt-F1) и замечаем, что X может быть равно 1, 2 … 6. При этом перед нами открывается виртуальная консоль, при первом запуске нам предлагают ввести имя пользователя и пароль и создают для нас новый сеанс работы. Если X равен 7, то мы возвращаемся в родные графические пенаты и понимаем, что /tty7 связан с XServer’ом. Идем дальше. Восемь, девять, десять и так далее до 63 — признаков жизни не подают.

Дело в том, что в Linux есть макрос MAX_NR_CONSOLES (64), определяющий максимально допустимое число виртуальных консолей, которые и представлены 64-мя файлами виртуальных устройств /dev/ttyX. Однако последнее слово остается за параметром ACTIVE_CONSOLES (/etc/default/console-setup), и параметр этот по умолчанию равен шести.

Инициализация консолей происходит в несколько стадий. Сперва ядро, получив управление от Grub’a, в ходе инициализации подсистем вызывает функцию «console_init», которая создает первичную консоль – «boot console», предназначенную для вывода отладочной информации. Это консоль осуществляет вывод символов самым примитивным образом: через «putchar», которая напрямую обращается к BIOS, инициализируя и заполняя структуру biosregs, и осуществляет вывод символа в консоль, используя прерывание 0x10.

Позже, в ходе выполнения «fs-initcall» и «console-initcall» происходит создание виртуальных устройств и структур под 6 полноценных виртуальных консолей – «real console». Активацию этих консолей выполняет первый запущенный ядром процесс /sbin/init, запускающий программу getty, которая выполняет чтение конфигурационных файлов /etc/init/console.conf и /etc/init/ttyX.conf и впоследствии отображает на консоль содержимое файла-приветствия etc/issue и запускает login. Далее XServer инициирует активацию консоли на dev/tty7, на которой запускается графическая оболочка.



Однако у нас есть еще вопросы. Что за неведомый объект /dev/tty0? И если каждый /dev/ttyX — это виртуальное устройство консоли, то зачем нужны /dev/console и /dev/tty? За ответом переходим на tty1 (нажимая Ctrl-Alt-F1) и в фоновом режиме запускаем такой скрипт:

sleep 10
echo “tty0” > /dev/tty0
echo “tty” > /dev/tty
echo “console” > /dev/console


Затем переходим на, скажем, tty4 и ждем несколько секунд. По истечении видим следующую картину:



Распределение ролей становится понятно: /dev/tty0 = /dev/console = текущая консоль, т.е. оба всегда ассоциированы с той консолью, которую мы в данный момент видим перед собой, а /dev/tty «помнит» консоль, с которой стартовал процесс. Поэтому пока наш процесс выполнялся, /dev/tty0 и /dev/console определялись для него по ходу пьесы в зависимости от текущей активной консоли, а вот /dev/tty оставался неизменным.

Не спешим покидать директорию /dev. Здесь еще чуть больше дюжины любопытных объектов: /dev/vcsX (virtual console screen) и /dev/vcsaX (virtual console screen with attributes). Еще один опыт: перемещаемся на tty5 и оставляем какие-нибудь следы своего пребывания, затем переходим в любую другую консоль (пусть ее номер 3), делаем «cat» на /dev/vcs5 и видим именно то состояние консоли 5, в каком мы оставили ее несколько секунд назад. При этом, соответственно, /dev/vcs3 и /dev/vcs (а также /dev/vcsa) относятся к консоли 3, на которой мы находимся в данный момент.

Понимаем, что /dev/vcsX — не что иное как омут памяти устройство виртуальной памяти консоли, позволяющее нам без потерь перемещаться между экземплярами tty. В паре с ним — /dev/vcsaX, который предоставляет базовые сведения о состоянии экрана: цвета, различные атрибуты (напр. мерцание), текущее положение курсора, конфигурацию экрана (количество строк и столбцов). Подытожим увиденное схемой:



ВИД СВЕРХУ ЛУЧШЕ


Теперь остановимся с изучением зоологии tty на какое-то время и перейдем к самой tty-абстракции, частью которой и являются наши виртуальные устройства. Посмотрим на общую структуру tty-комплекса и выделим три компонента:
  1. /dev/ttyX – виртуальное устройство консоли в файловой системе, которое заняло место UART-драйвера и с которым мы уже знакомы. На этом же уровне располагаются устройства /dev/vcsX и /dev/vcsaX, общение с ними осуществляется непосредственно через /dev/ttyX.
  2. TTY Line Discipline — драйвер, который делает ECHO набираемой команды и дает нам возможности ее редактирования. Также драйвер этого слоя генерирует сигналы при наборе управляющих последовательностей (^C, ^Z и т.д.). По умолчанию здесь царствует N_TTY, однако этот модуль можно заменить, например, своим драйвером – с этим поэкспериментируем немного позже;
  3. TTY driver – драйвер, который предоставляет набор методов инициализации и открытия консоли, а также методы, обрабатывающие операции ввода/вывода, приостановку консоли при переключении и возобновление ее работы и, конечно, обеспечивает «передачу» полученной от пользователя команды активному процессу.

Помните жалобы оператора PDP-11? Ему не нравилось тратить время на переходы от одной физической консоли к другой. Сейчас дело обстоит следующим образом: у нас есть по умолчанию 7 виртуальных консолей, а перед ними — офисное кресло на колесиках (разумеется, тоже виртуальное). Когда мы переключаемся с одной консоли на другую, операционная система перемещает наше кресло к нужному tty, а вместе с креслом «переключаются» на него и комплекс физических io-устройств: на мониторе теперь состояние нашей новой консоли, на нее же поступает ввод с клавиатуры и т.п.

При этом процессы от первого tty продолжают работать: считывают команды с файла своей виртуальной консоли, пишут в этой файл, но – так как они оторваны от «кресла» – не получают никаких событий (те же ^C и ^Z) и – так как физические устройства «уехали» вместе с «креслом» – могут только накапливать свой «вывод» в буфере, чтоб отправить его на монитор, как только «кресло» вернется.



ПУТЕШЕСТВИЕ К ЦЕНТРУ ЗЕМЛИ


Да, сверху всё смотрится вполне презентабельно. Но тебе, %username%, вероятно, хочется увидеть, как трехуровневое взаимодействие tty-компонентов реализовано непосредственно в коде? За ответом придется опуститься с небес на землю, даже лучше сказать – под землю, в недра исходного кода Ubuntu (работать будем с ядром версии 4.4).

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

Во-первых, это «tty_struct», у которой есть поле «tty_ldisc» (это структура методов драйвера 2-ого слоя), поле «tty_driver» (это драйвер 3-ого слоя) и тут же «tty_operations» (это структура методов драйвера 3-ого слоя, ради удобства вынесенная прямо в «tty_struct»).

То есть, «tty_struct» обеспечивает доступ к слоям TTY_LINE_DISCIPLINE и TTY_DRIVER. Получили к ней доступ – 2/3 стека tty-абстракции, считай, перед нами. Теперь нам нужно понять, как осуществляется переход от файлов виртуальных устройств к этой самой структуре. Ответ прост: у структуры «tty_file_private» как раз есть поле типа «tty_struct». Следовательно, обращаясь к файлу виртуального устройства на 1-ом уровне, мы с легкостью получаем доступ к уровням повыше.

Пока пазл складывается, но нам этого недостаточно. Продебажим ядро (с помощью qemu и cgdb) и рассмотрим backtrace вывода (эхо) единичного символа, введенного пользователем с клавиатуры:



Итак, мы на I уровне tty-стека. Происходит системный вызов «write», который на нашем tty обрабатывается функцией «tty_write». В нее передаются указатель на структуру файла виртуального устройства и буфер с символом. В функции «tty_write» по файлу происходит получение экземпляра «tty_struct». Принимая игру, «tty_struct» первым делом вызывает драйвер TTY_LINE_DISCIPLINE – «tty_ldisc», место которой по умолчанию занимает N_TTY. Первый уровень пройден!

N_TTY принимает эстафету: в свою очередь вызывает метод «n_tty_write», а затем передает буфер функции «output_process_block», которая, удостоверившись, что мы ввели не символ позиционирования каретки, просит «tty_struct» позвать «tty_driver». Всё верно, мы переходим на III уровень.

«Tty_struct» успешно играет роль посредника, и вот – уже запускается метод «con_write» tty-драйвера по имени «console_driver». Драйвер III-его уровня рад бы выполнить своё дело, но он один, консолей много – с какой надо работать? На помощь опять приходит «tty_struct» и вручает драйверу нужный экземпляр структуры «vc» (она отвечает за состояние своей конкретной консоли и содержит её клавиатурные, экранные установки, а также набор методов графического отображения).

«Сonsole_driver» блокирует консоль и призывает «vc_data» выполнить наконец эхо символа. «Vc_data» с ужасом осознает: к ней обратились не ради вопроса о самочувствии вверенной ей консоли, а ради действия. Это значит лишь одно: пора звать на помощь методы «consw», которые в нашем случае представляет VGA (при другой конфигурации ядра это может быть, например, framebuffer). И точно – VGA споро берется за дело, скрывает курсор, печатает символ, при необходимости прокручивает экран или переходит на новую строку, перемещает и отображает курсор. «Vc» выдыхает: «console_driver» работу принял и консоль разблокировал. Можем выдохнуть и мы, ведь все три уровня успешно пройдены, каждый компонент свою миссию выполнил.



3. KEEP AN EYE ON VIRTUAL TERMINAL


Но это еще не всё: пришло время познакомиться с представителями еще одного класса обитателей /dev – c эмуляторами терминалов. Это те самые xterm или gnome-terminal, которые мы запускаем с консоли, оснащенной графической оболочкой, используя, например, Ctrl-Alt-T или Ctrl-Shift-T.

Живут они в отдельном вольере /dev/pts (=pseudo-terminal slave) и представляют собой файлы под номерами 0, 1, 2 и т.д. Выполняем ps в текущем терминале и видим – мы на /dev/pts/1. Нажимаем Alt+5 – перемещаемся на наш четвертый по порядку открытия терминал, файл виртуального устройства которого /dev/pts/20. На любом терминале нас встречает bash, с каждым терминалом связано своё множество процессов. Пока никаких сюрпризов.




Но заметим: /dev/pts/X создаются динамически, запускаются на одной консоли /dev/tty7, не требуют запуска login и самое интересное – здесь нет правила «кресла»: мы можем открыть несколько виртуальных терминалов и одновременно наблюдать, как происходит работа на каждом из них. В очередной раз у %username% может появиться повод для сомнений: сохраняется ли и здесь принцип tty-абстракции и как в этот принцип вписывается устройство — slave, которым, вероятно, управляет некое устройство — master?

Новый объект не заставляет себя ждать: в единственном экземпляре файл ptmx лежит в той же директории /dev (На самом деле он может быть и не один: если запущено более одной консоли с графической оболочкой). По ману, при открытии /dev/ptmx создается подчиненная часть псевдотерминала /dev/pts/X, связанного со своей ведущей частью «ptm» (обращение происходит через дескриптор файла, но реальный файл не создается). Затем «ptm» передается в функции grantpt и unlockpt, и после всего этого можно открывать непосредственно /dev/pts/X, который будет вести себя точно так же, как виртуальная консоль (за исключением описанных выше особенностей).

Для нас в ключе идеи tty-абстракции это означает следующее: когда пользователь хочет запустить эмулятор терминала, XServer обращается к /dev/ptmx с просьбой создать виртуальное устройство /dev/pts/X. Могущественный «мультиплексер» /dev/ptmx любезно делает это, закрепляет файл устройства за экземпляром терминала и … /dev/pts/X занимает место /dev/ttyX, ему назначается драйвер слоя TTY_LINE_DISCIPLINE, его ласково принимает в свои объятия TTY_DRIVER. Стек над /dev/pts/X принимает уже привычный вид. Задача изучения механизма эмулятора терминала плавно сводится к предыдущей истории с виртуальной консолью, однако его подробное изучение требует отдельной статьи (которая входит в планы на будущее!).



4. LET’S PLAY WITH TTY LINE DISCIPLINE


На секунду вспомним tty-«палеозой»: было время, когда слой TTY_LINE_DISCIPLINE и отдельным слоем-то не был и полноценной современной функциональностью не обладал. Попробуем оценить вес перемен, произошедших с тех пор.

Для начала убедимся, что мы действительно имеем дело с N_TTY:



Всё познается в сравнении, поэтому действуем кардинально и с помощью stty отключаем все полезные фичи N_TTY:



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

К сожалению, N_TTY сама по себе является частью ядра. Поэтому за основу возьмем другие драйверы слоя LINE_DISCIPLINE, предусмотренные в Linux и загружаемые в виде модулей. По их образу и подобию модифицируем файл исходного кода n_tty.c:

  1. Добавим функцию отгрузки модуля, в которой вызывается функция tty_register_ldisc, осуществляющая «знакомство» ядра с нашей персональной линией дисциплины. В эту функцию первым параметром передадим ее уникальный идентификатор, а вторым – указатель на структуру с методами драйвера.
  2. Добавим функцию «выгрузки» модуля, в которой вызывается, соответственно, функция tty_unregister_ldisc.
  3. В самой структуре «tty_ldisc_ops» зададим новое имя драйвера.
  4. Позаботимся о том, чтобы наш модуль «узнал» нужные ему функции из файла tty_io.c (он не радует нас макросами «EXPORT SYMBOL», что заставляет либо дописывать все требуемые функции вручную, либо линковать вместе с tty_io.c).




Теперь добавим какой-нибудь функционал, отличающий нашу линию дисциплины от оригинальной. Помним, что именно TTY_LINE_DISCIPLINE обрабатывает служебные последовательности, поэтому грех не поколдовать на этом поприще. Для этого открываем функцию «n_tty_receive_char_special», в которой TTY_LINE_DISCIPLINE проверяет, не является ли введенные символы специальными и при нахождении оных посылает соответствующий сигнал. Для примера поменяем местами сигналы, генерирующиеся для Ctrl+Z и Ctrl+С:



После этого получим из нашего модифицированного файла непосредственно модуль ядра our_ldisc.ko. Загрузим его, убедимся, что загрузка произошла успешно. Проверим, что «our_modyfied_ldisc» действительно зарегистрировалась как TTY_LINE_DISCIPLINE. Откроем терминал и посмотрим номер pts. После этого назначим наш драйвер ответственным за слой TTY_LINE_DISCIPLINE у /dev/pts/X:



Настроим новую линию дисциплины с помощью команды «stty echo cooked» — теперь терминал работает в привычном для нас режиме. Запустим тестовую программу свечным циклом и сравним эффект Ctrl+Z и Ctrl+С:



Мы добились желаемого: генерация сигналов переопределена на уровне драйвера слоя TTY_LINE_DISCIPLINE в индивидуальном порядке для одного эмулятора терминала! Есть поле для работы фантазии: от фокусов с обработкой служебных последовательностей до кастомизированного фильтра команд.

В ЗАКЛЮЧЕНИЕ


Теперь для тебя, %username%, тайны виртуальных консолей и эмуляторов терминала – больше не тайны, беспорядочная магия – не магия, а технология, прошедшая немалый путь, чтоб создать гибкую подсистему tty, а телетайп – не артефакт древности, а изобретение (кстати говоря, наше, отечественное), без потомков которого современный компьютер представлять как-то не хочется.

Мы любим рассказывать увлекательные истории. Хочешь послушать их вживую? Приходи на «Очную ставку» NeoQUEST-2017, там тебя ждёт множество интересных докладов: от «железа» до криптографии! Вход свободный при регистрации на сайте.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330764/


Метки:  

История разработки и жизни одной маленькой игры. Релиз

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

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

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

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



К концу 2014 года удалось достичь третьей позиция в топ бесплатных по России, в мире все намного печальнее.
Статистика за 3 месяца:
Всего было 2 797 876 игровых сессий, при этом средняя длительность игровой сессии 4.30 мин.
Было проведено 6 363 900 заездов
180 человек открыли все достижения (мне такое не разу не удалось =D )
174 человека поглотили весь игровой контент
Сервер знает о 250 000 игроках

Конечно после своего пика, количество пользователей пошло на убыль, но приложение заняло стабильное место в разделе гонки, на первой странице и куча хороших отзывов, дает даже по сей день хороший приток пользователей. Игра людям нравится, в него играют и порой очень много.
Общая статистика спустя год работы игры:
Количество игроков: 451 007
Количество заездов на сервере: 12 553 441
Максимальное количество заездов, совершенных одним игроком: 3 054
Среднее количество заездов: 27,68
Медианное количество заездов: 9

А так выглядел топ игроков в игре:

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

Есть игроки, которые прошли всю игру и требующие новый контент, специально для них была создана новая карта с кучей новых препятствий с еще большим количеством зон выгрузки, но заглянуть в статистику и понять, что делают игроки, на тот момент не удосужились. Если на первой карте кол-во игроков, сделавших хотя-бы один заезд, составляло 320 328 (не удивляйтесь расхождению цифр, это серверная статистика, она меньше гугловской, почему, я так и не понял, возможно из-за блокировки UDP), то на крайней карте это цифра была 11 443 (это в районе 3.5%), а если учесть, что при переходе от карты к карте отваливалось в районе 30%, то новая карта была сделана для 8 000 пользователей. Это конечно большое кол-во людей, но сложность добавления контента в конец наиболее большая.
Да и при дальнейшем рассмотрении заездов, очень много игроков доезжают до первой выгрузки и не ездят дальше. Этой стратегии придерживаются игроки, вошедшие в топ. Хотя довести до конца один камень выгоднее, чем перевести все камни до первой выгрузки.

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

Варианты решения:
  1. Добавить карту в середину игрового процесса, это удовлетворит 30-60% аудитории в зависимости от места добавления. Сложность зависит от протяжённости трассы, а протяжённость от зон выгрузки, а большинство игроков доезжает до 1 выгрузки. Количество зон выгрузки можно использовать минимальное. Срок разработки новой карты составит 2-3 недели.
  2. Добавить карту в конец игрового процесса, это удовлетворит 2,5% аудитории. Количество зон выгрузки должно быть не меньше чем в предыдущей карте. Срок разработки 6-9 недель.

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

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

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

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

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

https://habrahabr.ru/post/331458/


Метки:  

HelpDesk и ServiceDesk. Что это и зачем это нужно вашей компании

Пятница, 23 Июня 2017 г. 07:49 + в цитатник
Самая популярная и, пожалуй, самая удобная методика работы в ИТ сфере – это методология IT Infrastructure Library (ITIL). Она была разработана британской правительственной организацией для упорядочивания отношений с подрядчиками ИТ услуг. Первоначально библиотека ITIL состояла из 7 книг, из которых основными были «Предоставление услуг» и «Поддержка» (Service Delivery и Service Support). В них были описаны процессы, которые составляют ядро ITIL, в том числе Incident management.

Главное назначение Incident management – максимально быстрая ликвидация проблем в ИТ инфраструктуре – аварий, проблем с оборудованием и т.д. Для реализации процесса в организации и создается специальный отдел, который контактирует с сотрудниками и согласовывает ликвидацию проблем с ИТ подразделением. Этот отдел может называться Центр обслуживания пользователей (Service Desk) или Центр поддержки пользователей (Help Desk).



Библиотеки ITIL рассматривают ИТ подразделение как поставщика определенного списка услуг, которые направлены на поддержание бизнес-процессов. Соответственно, уровень качества обслуживания закрепляется между производителем услуг служб Service Desk и их потребителем через документы SLA (Service Level Agreement). Например, они определяют допустимый максимальный период бездействия во время аварий.

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

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


Процессы Service Desk в ИТ


Процессы в Service Desk регламентируют все сложности, которые возникают в работе ИТ-отдела.

Incident Management – процесс, отвечающий за быстрое решение инцидентов — неисправностей, повреждений, критических ошибок, требующих ответных действий. Service Desk регистрирует статистику инцидентов и время их ликвидации.

Problem Management – цель этого процесса в уменьшении количества инцидентов, поступающих в Service Desk. Для этого выявляются и устраняются их причины.

Change Management – процесс, который регламентирует только осмысленные изменения и согласование их реализации среди всех пользователей бизнес-сервисов.

Release Management – процесс, которой ставит условие не нарушать работу компании во время выполнения каких-либо изменений. Процесс управления релизами выполняет наблюдение и установку обновленных версий программ и аппаратных средств через службу Service Desk.

Service Level Management – процесс, определяющий количество и состав задействованных сотрудников, а также качество услуг в службе Service Desk. С его же помощью идет мониторинг уровня качества и проводятся операции по снижению вероятности того, что может быть оказан недоброкачественный сервис.

Financial Management – процесс, который описывает распоряжение финансами для обеспечения деятельности других процессов

Availability Management – задачи, относящиеся к доступности услуг ИТ подразделения; выделяются изолированные процессы, чтобы их можно было отслеживать и делать выводы. Уровень доступности определяется постоянством, ремонтоспособностью и надежностью.

Capacity Management – задача, отвечающая за управление ИТ активами.

Continuity Management – контроль непрерывности ИТ сервисов. Главные направления задачи – разработка, сопровождение, реализация и проверка действий по обеспечению непрерывности деятельности бизнес-сервисов.

Information Security Management – гарантия непрерывной безопасности сервиса и информационная надежность.


Зачем нужно внедрять Help Desk и Service Desk в компании


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



Для пользователей внедрение Service Desk и Help Desk характеризуется повышением уровня предоставляемого сервиса и уменьшением периодов остановок из-за проблем в ИТ инфраструктуре. А для самих ИТ служб внедрение подобной организации работы становится решением проблемы, когда бизнес не может понять запросов айтишников. Появляется возможность просто обосновывать вложения в ИТ и планировать бюджет согласно потребностям в развитии бизнес-процессов. Кроме того, ИТ департамент может предоставлять актуальные и достоверные данные о своей работе и повышать доступность своих услуг для пользователей.

Внедрение Service Desk и Help Desk также позволяет сформировать определенные требования к сотрудникам ИТ подразделений и развивать у них определенные навыки.



(https://realitsm.ru/2016/10/desyat-samyx-modnyx-navykov-servis-deska-i-chto-s-nimi-budet-v-sezone-2017/)

Это статистика ассоциации HDI по результатам отчета «2015 Support Center Practices & Salary Report». Они же назвали 10 важнейших навыков для сотрудников Service Desk, которые учитываются при их найме:

  • Умение задавать вопросы.
  • Коммуникабельность.
  • Быстрая обучаемость.
  • Навыки диагностики и решения проблем.
  • Способность работать в стрессовых условиях.
  • Адаптивность.
  • Навыки работы в команде.
  • Навыки межличностного общения.
  • Опыт работы в поддержке пользователей.
  • Честность.


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

Что в этом случае останется на долю Service Desk? Это будут более сложные случаи, требующие от сотрудников техподдержки гораздо больше, чем умение читать скрипты. То есть сотрудникам Service Desk требуется больше технических навыков.

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


Как внедрять Help Desk и Service Desk в ИТ


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

1. Убедите руководство в необходимости внедрения и поддержки ITSM-решения



2. Определите структуру ИТ отдела


Распределите функциональные обязанности и определите алгоритмы работы сотрудников ИТ отдела. Это понадобится для понимания изменений в организации его работы с внедрением ITSM-системы.

3. Определите и зафиксируйте зоны ответственности ИТ отдела


Определите основные цели службы технической поддержки пользователей и разработайте каталог ИТ сервисов.

4. Определите критерии качества


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

5. Определите порядок внедрения изменений


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

6. Сформулируйте требования к системе


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

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


Deskun


Внедрить систему Service Desk следует, если ваша компания уже доросла до полноценного ИТ департамента со службой технической поддержки. Однако, отдельные элементы методологии ITIL можно использовать даже в небольшом стартапе. Например, почти любой компании, которая выпускает продукт для людей, нужна поддержка пользователей – как клиентов, так и сотрудников. Для этого необходимо купить или разработать, а затем внедрить соответствующую систему, которая могла бы работать на эти два фронта. Мы в Deskun создали свой сервис на основе Gmail почты. Знакомый пользователям веб-интерфейс почтового клиента от Google позволяет организовать работу службы Help Desk как для клиентов так и для пользователей, быстро и без привлечения дополнительных ресурсов компании.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331354/


Метки:  

[Перевод] Уроки, извлечённые из трёх миллионов загрузок на AppStore

Пятница, 23 Июня 2017 г. 07:47 + в цитатник
В январе 2011 года у меня были летние каникулы [разработчик из южного полушария, а именно из Новой Зеландии — прим.пер.], но вместо поиска работы на день или общения с людьми я много времени скрывался от всех в своей комнате, где писал первую версию iOS приложения под названием Class Timetable. Годом ранее я искал простое, лёгкое в использовании приложение для учебных расписаний, и ничего в AppStore не подходило под мои нужды — всё было сложно и трудно использовать. Идея состояла в том, чтобы создать простое, без суматохи, прямолинейное решение, нечто более простое и более убедительное, чем бумажное расписание. За несколько месяцев я потратил около 500 часов, проектируя и кодируя его. На сегодня у программы более трёх миллионов загрузок, много положительных отзывов, а временами оно было моим основным источником дохода. Не слышали о приложении? Да, оно ещё не взлетело в США, но довольно популярно в Австралии/Новой Зеландии/Великобритании, по крайней мере, среди студентов колледжей и школьников.



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



В отличие от сорвавших джекпот, моя история «умеренного успеха» ближе к тяжёлой работе и медленному, постепенному прогрессу. Вероятно, она ближе к реальной жизни, чем другие истории успеха, потому что давайте посмотрим правде в глаза: не каждый раскрутится, создав следующую Flappy Bird. Вместо того, чтобы выстрелить как вирусный хит, Class Timetable была умеренно популярна более шести лет, что немного примечательно само по себе — многие #1 приложения не могут похвастаться такой долгой жизнью. Я бы хотел поделиться некоторыми вещами, которые узнал за последние несколько лет. Надеюсь, что-то из этого вы найдёте полезным, независимо от того, насколько вы успешны или нет.

Перед написанием приложением, которое «сделало это», я написал много вещей, которые не сделали это


Я всё ещё думаю, что некоторые из них были отличными идеями — возможно, им не хватило хорошего продвижения или немного удачи. Было приложение Ginge-O-Meter, в которое я вложил много сил. Концепция: сделай фотографию кого-нибудь и определи, сколько рыжего в его волосах. Оно использовало реальное распознавание изображений и техники анализа цвета, чтобы выдать ответ, и действительно работало (почти всегда). К сожалению, идея не взлетела… Думаю, я заработал около $50. Это была моя первая большая попытка, и если честно, меня довольно встревожило то, сколько усилий я вложил в приложение, чтобы в итоге столкнуться с таким провалом. Но на этом я не остановился, и Class Timetable развилось в то, что мы имеем сейчас. В любом случае, я хочу сказать, что не нужно ставить всё на одну ставку. Если ваша победная идея не добилась успеха: вставайте и пробуйте снова и снова… и снова, потому что всё что вы знаете, это то, что ваша следующая идея может сделать это.

Создавайте дизайн в расчёте на новичка


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

Когда Class Timetable впервые запустился с тысячами скачиваний в день, я получал примерно 20 писем в неделю. Уверен, были и другие пользователи с теми же проблемами, которые не затруднили себя написанием письма, а просто удалили приложение. Улучшив программу согласно жалобам из писем, я сейчас вышел на уровень в одно письмо каждые два или три дня — и большинство из них не о проблемах, а с предложением фич или редкие письма фанатов (я не вру).

Слушайте критиков, но не делайте того, что они говорят


Наверное, я получил сотни писем пользователей с предложением реализовать разные функции, от действительно хороших до сомнительных предложений. Но теперь, если бы я реализовал все эти функции, приложение превратилось бы в непонятное месиво, с 17 фоновыми выборами, 72 другими фичами, отвлекающими на экране, и списком настроек буквально обо всём. Блин, даже если бы я реализовал каждую разумную идею, результат был бы совсем иным. Дело в том, что даже если пользователи видят истинную проблему с продуктом, они не всегда знают лучшее решение. Так что же делать? Слушайте своих пользователей — их истинные, исконные проблемы — и решайте их так, чтобы это было полезно для продукта в целом. Иногда хорошее предложение фичи имеет побочные эффекты для продукта в целом, и это значит, что такое лучше пропустить. Это часто случалось с Class Timetable: одно из его главных качеств — простота и лёгкость использования. Хотя много функций было добавлено за годы, но многие предложения функций усложнили бы продукт в целом. Иногда это нормально, но чаще я выбирал простоту — ту фичу, которая делает уникальным это приложение.

Отличный продукт лучше, чем вирусные уловки


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

Будьте щедрыми


Когда Class Timetable впервые появился в AppStore, он стоил $1. Я рассчитал, что на то время, которое я затратил (около 500 часов), 1 доллар — это халява. Итак, в первую неделю приложение купили четыре человека, а на следующую неделю ещё меньше. Не знаю, какие ощущения у человека, сорвавшего джекпот, но у меня таких ощущений не было. 500 часов — это немало времени, чтобы спустить в унитаз! Я мог бы оставить его умирать медленной смертью по одному доллару в неделю, но вместо этого решил сделать приложение бесплатным. Я создал его для решения реальной проблемы и посчитал, что другие найдут его по-настоящему полезным. Почти сразу же скачивания начали расти. 50 скачиваний в день, затем 100, 1000… вау. Если бы я принял в расчёт количество потраченных часов и не был щедрым, то очень сомневаюсь, что скачивания когда-нибудь вообще начались. Вскоре после этого я добавил функцию внутрипрограммной покупки дополнительных функций, что начало приносить уже разумные деньги. Намного больше, чем несколько долларов в неделю. Так что не скупитесь: продукт без платных пользователей (обычно) лучше, чем платный продукт вообще без пользователей. Намного проще получить оплату с существующих пользователей, чем привлечь абсолютно нового платного пользователя.

Делайте шаг назад, часто


Иногда вы застряли с проблемой, и хороших решений не просматривается: это может быть связано с кодом, который вы пишите, или с решением, как продвигать приложение. И тогда вы начинаете думать о проблеме в широком смысле. Вы осознаёте, что этот хитрый кусок кода вообще не нужно писать, если правильно спроектировать программу, а проблему с маркетингом отлично решит один ваш друг, у которого талант решать такие проблемы. Это можно описать как «шаг назад» от проблемы. За всю мою карьеру разработчика я не пожалел ни о секунде, когда так делал. Очень много раз, особенно в начале карьеры, мне следовало так поступить, а я этого не сделал. Я прошёл по трудному пути с Class Timetable: в версии 1.0 куча времени ушло, когда я заходил в тупик, но скрипя зубами добивался своего. Я решал хитрые проблемы, срезая углы и реализуя задуманное, вместо того, чтобы сделать шаг назад. Пока пользователи не знают, в этом нет ничего постыдного, правда? Через год или два пришлось переписывать всю кодовую базу с нуля — по многим причинам — что стало серьёзным мероприятием. Сделайте шаг назад! Оно того стоит.

Сегодня Class Timetable по-прежнему чувствует себя хорошо. Я всегда строю планы, будь то ближайшее обновление под iOS или глобальные планы, во что может превратиться программа. Если вы учитесь в школе или колледже, не стесняйтесь попробовать Class Timetable — надеюсь, вы найдёте её по-настоящему полезной.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331466/


Метки:  

Это вопрос должен решать архитектор. Или нет?

Четверг, 22 Июня 2017 г. 18:21 + в цитатник
У меня есть некоторый опыт в реализации систем на базе микросервисной архитектуры и я хотел бы поделится вопросами (и ответами), которые возникают при реализации подобных проектов. К сожалению, я не имею права распространяться о проектах в которых я участвовал, поэтому я выдумал собственный сферический проект в вакууме. В этом проекте нам встретится множество стандартных проблем.

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

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

image

Основная идея проекта


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

Я предлагаю вам другой подход. Смотрите, вы идете ко мне на сайт, регистрируетесь, заполняете анкету. В анкете будет примерно следующее: хочу каждый день с понедельника по пятницу в 8:15 выйти из дома (пункт А) сесть в мерседес и доехать до работы (пункт Б). Потом вечером в 18:00 выйти из офиса (пункт Б) сесть в ауди и доехать до дома (пункт А). Там же еще можете пометить галочкой пункт: хочу иметь возможность уехать с работы раньше, машину готов ждать не более 8 минут.

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

За все удовольствие с вас попросят 150 у.е. в месяц. Звучит неплохо, не правда ли?

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

Наш сервис будет давать нам множество данных из которых мы можем добыть много интересной информации:

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

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

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

В общем и целом речь идет о большом и сложном проекте, который можно назвать модным словом «cognitive solution» для бизнеса с элементами из мира Internet of Things.

Методология разработки и анализ требований


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

Язык, фреймворк, архитектура


Изначально я Java Developer, и потому имплементация будет на java. Не обессудьте.

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

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

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

А какой фреймворк возьмем? Если немного погуглить, то станет понятно, что особо вариантов нет, мы будем делать на Spring Framework. Причина проста, в Spring Cloud есть все, что нам потребуется.

Еще у нас будут всякие API Gateway’и, Config Service’ы, Message Broker’ы, Docker, Workflow, Rule Engine и много всяких других заумных слов по мелочи.

Есть два основных подхода к проектированию микросервиса.
  • Domain Driven Design
  • Functional Driven


Domain Driven Design означает определение доменных объектов и имплементирование всех необходимых действий, которые требует ваш заказчик. Например заказчик какой нибудь аптечной системы говорит: мне нужно иметь возможность вносить новое лекарство в систему, удалять старые, а вот редактирование уже внесенного лекарства надо запретить. Вы делаете класс «Medicine» со всеми нужными полями и имплементируете названный функционал. Так у вас появляется MedicineService. Т.е. при таком подходе начальной точкой является доменные объекты.

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

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

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

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

Начнем с транспорта. Например с Car. Хотя просто Car не пойдет. Поясню. Например вдруг человеку будет удобно доехать на машине до вокзала, там пересесть на поезд, доехать до города, а потом последние два километра проехать на велосипеде? Мы ведь хотим с этого милого человека еще и за велосипед денег попросить? А вдруг кто то захочет эту самую последнюю милю на моноколесе проехать? Не обижать же человека, тем более, если у него на это деньги есть? Давайте сдадим ему в аренду моноколесо! Таким образом в будущем нам может потребоваться множество классов, описывающих разные транспортные средства.

Возьмем за стартовую точку некоторый абстрактный класс Vehicle

 public abstract class Vehicle {
….
   protected String model;
   protected int wheelNumber;
   protected Date manufactureYear;
   protected EngineType engineType; 
   protected Producer producer;
}

Как мы выяснили у нас будут разные Vehicle, давайте сделаем парочку:

public class Car extends Vehicle {
   public Car() {
       wheelNumber = 4;
   }
}

и еще один для бедных, но спортивных:

public class Bicycle extends Vehicle {
 
   public Bicycle() {
       wheelNumber = 2;
   }
}

Замечательно. Теперь нам нужен тот, ради кого мы все это делаем: наш клиент, он же источник нашего дохода. Назовем эту сущность Customer’ом

public class Customer {
   private String firstName;
   private String lastName;
   private Date birthDay;
}

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

public class Contract {
   private long customerId;
   private long vehicleId;
}

Итого мы имеем одну иерархию классов с Vehicle на вершине, Customer и Contract. Предлагаю сделать из них VehicleService, ContractService и CustomerService.

Что означает 'микро' в слове 'микросервис'?
Раньше меня мучал вопрос, а что означает «микро» в слове «микросервис»? По идее это означает «маленький». Но что значит маленький?

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

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

Если ваш ответ «да», то это микросервис. А если нет, то и нет. И что важно, задавайте себе этот вопрос регулярно по мере реализации. Если вдруг у вас проскочил ответ «нет», начинайте рефакторить/дробить/переосмысливать этого монстра. Хотя обычно к этому времени все полимеры уже <..censored..>

Рудиментарную имплементацию сервисов вы можете посмотреть тут.

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

Что бы засунуть наши сервисы в докер нам потребуется плагин для мавена (смотрите в pom.xml docker-maven-plugin) и dockerfile.

Все сервисы мы будем запускать через docker-compose, для этого в корне проекта лежит docker-compose.yml.

Обратите так же внимание на файл .env и его содержимое. Больше об этом файле найдете в документации . Без этого файла у меня на машине с Windows 7 не получилось инициализировать MySQL.

Что у меня получилось?


Начнем с плюсов:

  • эта штука работает.

На этом плюсы к сожалению закончились

Минусы:

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

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

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

Добавление нового типа транспорта в систему


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


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

Сейчас VehicleService выглядит вот так.

image

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

image

Мы напишем новый класс Scooter в VehicleService, протестим, скомпилим, задеплоим. А если у нас будут десятки типов транспортных средств? Будем каждый раз писать новый класс, тестить, компилить и т.д.? Есть ли другой способ?

Можно, например, сделать так. Сделаем класс VehicleType.

public class VehicleType {
    private String name;
    private List properties;
    ….
}

Как видите у VehicleType есть VehicleProperty:

public class VehicleProperty {
   private String name;
   private T value;
   private String description;
…..
}

Сделаем еще класс Vehicle:

public class Vehicle {
  private VehicleType vehicleType ;
  private List customProperties;
   …...
}

Теперь, если хотим добавить скутер в систему, то мы создадим сначала VehicleType «Scooter»:

VehicleProperty wheelNumberProperty = new VehicleProperty("wheelNumber", 2, "number of wheels");
…….
VehicleType scooterType = new VehicleType("Scooter");
 scooterType.addProperty( wheelNumberProperty);
……..

А если нам нужно создать экземпляр скутера:

Vehicle scooter1 = new Vehicle(scooterType);
….. 

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

image

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

Скрытый business case
Вообще вопрос изменения чего либо в сервисе требует отдельного внимания. Поясню на примере.

У меня был такой случай. На митинге презентирую клиенту нашу будущую архитектуру. Ответил на вопросы. Вроде все хорошо, всем все нравится, все довольны. И тут главный айтишник клиента задает такой простой вопрос: как быстро вы можете добавить новое поле к доменному объекту «АBC»? Простой ведь вопрос, правда? Я и ответил просто: добавить поле — 2 минуты, написать тесты еще от нескольких минут до пары часов, потом прогон всех тестов (может длится часами), и т.д. В общем назвать какую то конкретную цифру я не смог и думаю что никто не сможет, пока это хотя бы раз не было сделано. Вроде как я правильно ответил, но ощущение, что ответ неверен меня не покидало. И вот однажды я таки понял, как я должен был ответить.

На сегодняшний день мой ответ звучит так: «А как часто это должно происходить?» Если это исключительная ситуация, то в принципе не важно сколько длится добавление поля, лишь бы этот срок был адекватным с точки зрения бизнеса. Если же это происходит часто, то надо бы задать вопрос: а не является ли это Business case? И если да, то этот функционал нужно изначально закладывать в систему и тогда ответ должен быть: 20-30 минут (это вранье, конечно, но звучит хорошо), может дольше, если случай тяжелый.

Также возникает другой вопрос: как так получилось, что этот business case всплыл только сейчас?
И еще более важный вопрос, а нет ли других подобных business case’ов, которые мы упустили?

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

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

Предположим, опять же, наш VehicleService упал. Это значит, что ни машины, ни велосипеды арендовать нельзя. Было бы не плохо, чтобы если сервис для машин не доступен, то сервис для велосипедов работал бы дальше. Как это можно сделать? Делить VehicleService на несколько сервисов по одному на каждый тип транспортного средства?

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

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

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

  • Car
  • Bicycle
  • Scooter
  • Traktor
  • ……

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

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

А вот еще интересный вопрос. Как видите у Vehicle есть поле EngineType.

public abstract class Vehicle {
   …...
   protected EngineType engineType;
 

В моей рудиментарной имплементации EngineType имеет enum’ы:

  • Gas
  • Diesel
  • Elektro

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

Сделаем вместо EngineType список EngineType’ов (и тогда у 99% машин вдруг появится список с одним элементом)?

public abstract class Vehicle {
   …...
   protected List engineTypes;
 

А может добавим новый тип в enum, что то вроде Gibrid?

Кто в этом случае принимает решение и, соответственно, несет за него ответственность?

Можно ли сказать, что здесь идет речь об архитектуре или это слишком «мелкий» вопрос?

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

На самом деле тип двигателя конечно же важен, но не для клиента, а для нас, компании, которая этот сервис предоставляет. Одна из причин — статистика (например по затратам на топливо или необходимому ремонту). Она будет сильно различаться для каждого типа двигателя. Отсюда возникает еще один вопрос: а не должны ли быть доменные объекты (или их представления) различными для нашего backend’a и frontend’a?

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

Сложные запросы


Предположим, я хочу посмотреть всех клиентов с их договорами, которые живут на улице Апельсиновой в славном городе Берлине. Т.е. я хочу увидеть что то вроде такой таблички:
Фамилия, Имя Номер договора Дата подписания договора Машина
Пупкин, Вася 12345 01.01.2017 Audi Q4
...... ...... ...... ......

Как вы видите в таблице содержатся данные из трех микросервисов: CustomerService, VehicleService и ContractService. Как мы будем их собирать вместе? В случае монолита вопрос решается одним запросом в базу, а что делать когда у нас три базы?

image

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

Спасибо, Кэп!
А теперь минуточку внимания. Когда надо было задаваться этими вопросами? Ответ: конечно же перед тем как писать код. И отвечать на эти вопросы должен в том числе и архитектор.

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

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

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

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

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

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

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

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

На последок еще две мысли.

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

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

Однажды я прошляпил этот момент и только на Sprint Review абсолютно случайно узнал, что программист сделал совсем не так, как было ему сказано. На вопрос: написано же черным по английски, посылай «event», почему ты шлешь http request? был получен ответ: ну я подумал, что так будет лучше. Естественно все проконтролировать невозможно, надо доверять своей команде. Но, как говорят немцы, доверие хорошо, а контроль лучше.

История изменений


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

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

Как это можно сделать мы обсудим в следующей статье.

Проблемы с инфраструктурой


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

  • единая точка входа, он же API Gateway
  • поиск сервисов, он же Service Discovery
  • одна точка конфигурации, он же Config Service
  • центральная точка сбора и анализа логов
  • мониторинг
  • ……

Эти и другие вопросы в следующей части.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331104/


Метки:  

Использование музыки вместо лингафонного курса при изучении иностранного языка

Четверг, 22 Июня 2017 г. 17:13 + в цитатник
В моем предыдущем материале рассматривалось использование лингафонного курса на начальных этапах изучения иностранного языка (в составе метода Умин, для английского языка). Практика показала что большой проблемой лингафонных курсов является их скучность, неинтересность. При недосточной мотивации эта проблема может стать непреодолимой и сделать невозможным дальнейшее обучение.

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

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

Основным требованием к такому контенту является его доступность одновременно в трех вариантах: английская аудиозапись, соответствующий английский текст, соответствующий русский текст (перевод), а также готовность прослушивать его многократно (хотя бы 20-30 раз) и суммарная продолжительность, соответствующая среднему лингафонному курсу (2-3 часа аудио).

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

Подготовка материала


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

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

Для начала будет достаточно собрать примерно 20 композиций, потом аналогичным образом можно будет собрать больше и довести общее количество примерно до 50, что будет примерно соответствовать объему лингафонного курса.
  1. Открываем историю просмотров в YouTube https://www.youtube.com/feed/history
  2. Копируем оттуда в какой-нибудь текстовый файл названия подходящих композиций (по перечисленным выше критериям)
  3. Делаем поиск в YouTube по названиям (именам) исполнителей, чтобы найти еще (опять же, учитывая критерии – контент должен быть не просто интересным, но и в некоторой мере привычным) и тоже копируем их в текстовый файл

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

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

Приведенные выше цифры – 20 и 50 – ориентировочные, вполне нормально, если будет чуть меньше или чуть больше.

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

Открываем сайт https://en.lyrsense.com/. Нужным нам функционалом этого сайта (точнее, его полной, десктопной версии) является то, что песни и слова к ним представлены там именно в виде «композиций», причем доступ возможен одновременно к каждому из ее трех элементов – при прослушивании можно одновренно смотреть английский и русский текст, т. к. их соответствующие строки выровнены между собой.
Кроме английского, на этом сайте также доступны композиции для изучения испанского, итальянского, немецкого и французского языка.

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

Есть еще похожий сайт http://www.amalgama-lab.com/ , но там неудобно то, что страницы содержат только две части композиций из трех – английский и русский тексты, а аудио каждый раз надо будет хранить и открывать отдельно (в виде еще одной ссылки или mp3-файла).

Создаем в закладках браузера папку «English», а внутри ее еще две папки – «Неразобранные» и «Разобранные».
По очереди вбиваем в поиск на lyrsense.com названия композиций из текстового файла, если композиция обнаруживается там, то запускаем воспроизведение аудио, проверяем, что это именно то, что нужно (а не аранжированная или упрощенная версия) и, если это так, добавляем закладку для найденной страницы lyrsence.сom с композицией в папку «Неразобранные».
Повторяем до тех пор, пока в этой папке не наберется примерно 20 закладок.

Крайне желательно также перед началом обучения установить в браузер расширение Google Dictionary.
Следует заметить, что lyrsense.com и аналогичные сайты имеют аналогичный функционал – по однократному щелчку мыши над словом выводится его перевод и произношение. Но расширение Google Dictionary более универсально, т. к. работает на всех сайтах.

Очень желательно выполнять перечисленные выше упражнения ежедневно и тратить на них хотя бы полчаса в течение дня – это не так сложно – как будет показано ниже, их в большинстве случаев можно будет совмещать с другими делами.
Далее при описании упражнений будет проводиться их аналогия с книгой Е. А. Умин «Английский легко и с удовольствием».
Отмечу, что упражнение Л1 в соответствии с этой книгой уже фактически выполнено, т. к. выбирались песни, уже многократно прослушанные ранее.

Выяснение смысла английских слов в тексте


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

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

В соответствии с классификацией из книги Умин, это будет соответствовать упражнению Л3 (~Л3). Далее сочетание ~Л<цифра> будет обозначать соответствие упражнению оттуда.

Прослушивание аудио с параллельным просмотром текста


Включаем воспроизведение и слушаем аудио. Параллельно смотрим в английский текст и находим соответствия между звуком и словами в тексте (~Л2). Когда в английском тексте встречается непонятный фрагмент, пытаемся сразу же найти его в русском тексте (~Л4). Воспроизведение аудио при этом можно останавливать, а можно и нет, как Вам удобнее.

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

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

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

Прослушивание разобранного аудио без параллельного просмотра текста


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

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

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

Открываем папку «Разобранные», выбираем композицию, включаем ее воспроизведение и слушаем, отслеживая при этом понимание отдельных слов (~Л5). При этом можно сразу включить автоповтор и прослушать ее 2-4 раза или больше, пока не надоест. При воспроизведении можно заниматься другими своими делами, но иметь ввиду, что они должны быть простыми и позволять постоянно уделять часть своего внимания тому, что прослушиваемый аудиоконтент действительно разбирается и Вы можете правильно разделить его на отдельные слова.

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


Если Вы обнаружите, что уже хорошо запомнили отдельные фрагменты аудио и не сильно заняты, можно попробовать проговорить эти фрагменты (вслух или про себя) сразу после аудио (~Л7) или непосредственно перед ним (~Л9). Но делать это не обязательно, достаточно просто следить за тем, чтобы разбирались все (или почти все) слова.

Проговаривание выученного текста без аудио (необязательно)


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

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

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

Потом можно использовать текстовые файлы из «Englsh Mobile» для проговаривания текстов – вслух или про себя (~Л8), a аудиофайлы – для прослушивания с пониманием английского текста (~Л5) или проговариванием его (~Л7, ~Л9). Такая организация работы дает возможность делать эти упражнения практически везде, без привязки к компьютеру и рабочему месту.

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

Теоретические предположения – почему тексты с музыкой или рифмой учить проще, чем без них


Мне кажется, что представление «special nature of music and singing's activity pattern in the human brain… unique relationship between music and our brains» («особая природа паттерна активности музицирования и пения в человеческом мозгу… уникальная взаимосвязь между музыкой и нашим мозгом») является упрощенным. Нужно рассматривать не только мозг, но и все тело в целом. Я думаю, что в мультимодальном обучении принимает участие вся нервная система, и это участие активное – оно не сводится только к передаче импульсов. T. е. выражения «думать сердцем» (автоматизм эмоций) и «думать спинным мозгом» (автоматизм движений) на самом деле следуют понимать скорее в буквальном, чем в переносном смысле.

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

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

Из западной науки наиболее близко подходит к этому теория множественного интеллекта Говарда Гарднера, предполагающая существование отдельных «интеллектов» для различных аспектов деятельности человека и очень слабую взаимосвязь между ними. Слово «интеллекты» при этом употребляется в скорее в смысле «способности» в отличие от общепринятого его значения: «Generally, linguistic and logical-mathematical abilities are called intelligences, but artistic, musical, athletic, etc. abilities are not. Gardner argues this causes the former to be needlessly aggrandized» («В основном интеллектами называются лингвистические и логико-математические способности, а артистические, музыкальные, атлетические и др. способности нет. Гарднер утверждает, что это приводит к необоснованному возвеличиванию первых.»)

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

https://habrahabr.ru/post/331454/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1019 1018 [1017] 1016 1015 ..
.. 1 Календарь