Русский
Русский
English
Статистика
Реклама

Все категории

Миниатюрный датчик качества воздуха на батарейке с e-ink экраном

21.06.2021 12:17:59 | Автор: admin
Приветствую всех читателей Habr! В своей сегодняшней статье, хочу рассказать вам о своем новом DIY беспроводном устройстве датчике качества воздуха. Помимо оценки качества воздуха, датчик может оценивать уровень освещенности в помещении, температуру, влажность и атмосферное давление, на основе данных атмосферного давления, устройство может предсказывать прогноз погоды. Это полностью открытый проект.



Внутреннее устройство


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

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

  • основной MINEW MS88SF3 (nRF52833, nRF52840)
  • дополнительные: MINEW MS50SFA1 (nRF52810, nRF52811), MINEW MS50SFA2 (nRF52832), EBYTE E73-2G4M08S1C (nRF52840) и EBYTE E73-2G4M08S1E (nRF52833)

Используемые в проекте сенсоры:

  • сенсор качества воздуха в помещении для измерения ЛОС SGP40
  • сенсор давления, температуры и влажности BME280
  • сенсор освещенности MAX44009

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

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

Для вывода информации использовался e-ink дисплей со сверхнизким потреблением и диагональю 2.13 дюймов компании WaveShare.



Характеристики дисплея:

  • Разрешение: 250x122
  • Диапазон рабочих температур: 0 50 C
  • Потребление в рабочем режиме: 3мА
  • Потребление в режиме глубокого сна: 1мкА
  • Минимальное время обновления экрана: 0.3 сек.

В ближайшее время в проект будет добавлена поддержка дисплея DES e-Ink 2.13 c рабочим температурным режимом -20C~60C (что такое DES).
..upd Пока статья писалась сделал драйвер, дисплей протестирован, в морозильнике работает :), из минусов разрешение 212х104, но зато морозов не боится, в общем рабочий вариант.


Основная версия PCB датчика:

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



Основным сенсором в данном проекте является сенсор качества воздуха в помещении SGP40. Можно сказать что это новинка на рынке от компании Sensorion c весьма неплохими характеристиками.


Сенсор измеряет общую концентрации летучих органических веществ (TVOC). В сравнении с предыдущим датчиком этой компании SGP30 потребление было значительно снижено, 48 мА при измерении у SGP30 и 2.6мА у SGP40. Правда предыдущий датчик мог отдавать уже готовые значения VOC и эквивалента СО2, в то время как новинка отдает сырые данные которые в дальнейшем надо обрабатывать на стороне МК при помощи поставляемой с датчиком библиотеки с алгоритмом расчета качества воздуха. Даташит на датчик SGP40.


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

Схема устройства:



Передача датчиком данных с сенсоров в системы Умного Дома реализована на открытом проекте MySENSORS.




Функционал датчика


Устройство, при подаче питания, осуществляет попытку поиска сети, если сеть не найдена, то устройство переходит в основной режим работы без работы в сети (не шлет данные), но периодически делает короткие запросы на поиск сети(~раз в 2 часа). Интервал опроса сенсора SGP40 3 секунды, чтение остальных сенсоров, отправка данных, основное обновление экрана раз в 1 минуту. Обновление экрана и отправка данных(если сеть доступна) происходит при изменении данных уровня качества воздуха (TVOC) на 10 единиц, температуры на 0.5C, влажности на 5%, давления на 1 единицу, при изменении уровня освещенности на 10 люкс, при изменении прогноза по погоде. Интервал опроса батарейки задается пользователем в интервале от 1 часа до 24 часов, по умолчанию опрос один раз в 6 часов.
Так же есть дополнительная подпрограмма для обновления экрана и отправка данных при резком повышении уровня TVOC на 30 единиц, интервал проверки раз в 6 секунд.

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

Доступный функционал кнопки меню:

  1. Инверсия экрана
  2. Отправка презентации
  3. Вход в режим конфигурации внешними командами по радио
  4. Поиск сети
  5. Сброс устройства

Так же, помимо кнопки меню, датчик может настраиваться внешними командами из интерфейса УД. Для этого необходимо активировать нужный пункт меню конфигурация датчика нажатием кнопки меню. После активации режима конфигурации, датчик перейдет в режим прослушивания на 20 секунд. В этот интервал необходимо отправить команду. Внешними командами можно настроить интервал проверки батарейки, изменить вывод информации на экран в инверсии, выбор режима работы: LP (чтение сенсора SGP40 раз в 3 секунды) или ULP (чтение сенсора SGP40 раз в 5 секунд).

Датчик умеет анализировать данные атмосферного давления и рассчитывать по ним прогноз погоды, выводить на экран данные о прогнозе погоды и отправлять эти значения в УД. Описание алгоритма расчета прогноза погоды (NXP Application Note 3914 | John B. Young)

На экране рядом с каждым типом данных выводится индикация направления изменения значений.



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

//#define MY_DEBUG#define LANG_RU // If this is not used the English localization will be displayed.#ifndef LANG_RU#define LANG_EN#endif#define SN "eON Air Quality Sensor"#define SV "0.99"#define MY_RADIO_NRF5_ESB#define MY_NRF5_ESB_PA_LEVEL (0x8UL)//#define MY_PASSIVE_NODE//#define MY_NODE_ID 151//#define MY_NRF5_ESB_MODE (NRF5_1MBPS)#define MY_NRF5_ESB_MODE (NRF5_250KBPS)#define ESPECIALLY#define SEND_RESET_REASON#define MY_RESET_REASON_TEXT

Потребление датчика в режиме сна составляет в среднем 33мкА (смотрите даташит на SGP40), в режиме считывания сенсоров и обновления экрана 4мА(среднее), в режиме передачи данных 8мА(среднее), время передачи одного сообщения 10мc (идеальные условия).
Датчик работает от батарейки CR2477 (950мА), среднее расчетное время работы устройства 1 год(зависит от конфигурации прошивки, установленных сенсорах на устройстве, больше сенсоров больше данных нужно будет отправлять, а передача по воздуху это основной потребитель), данных о реальном сроке работы пока нет, устройство пока работает 2 месяца.



Модели разработанного корпуса датчика я печатал на FDM 3D принтере, что бы добиться более или менее приличного вида, корпус после печати шлифовался и полировался. На задней крышке корпуса можно установить магниты.



GitHub проекта github.com/smartboxchannel/

В файле readme находится инструкция по установке и настройке среды для редактирования и компиляции ПО для датчика.

OPEN SOURCE HARDWARE CERTIFICATION
OSHWA UID: RU000004


В завершении, уже как обычно, сделаю небольшой фото анонс проектов с которыми в скором времени поделюсь и о которых расскажу (Датчики влажности почвы Zigbee, Уличный датчик температуры и влажности Zigbee Long Range, Датчик качества воздуха bme680 c e-ink3.7).

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












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

Если вы как и я, хотите понять что такое Zigbee, попытаться сделать свои первые DIY Zigbee устройства, то приглашаю вас в чат для разработчиков zigbee девайсов/прошивок ZIGDEV

Всем, кто хочет делать устройства, начать строить автоматизацию своего дома, я предлагаю познакомиться с простым в освоении протоколом Mysensors телеграм-чат MySensors

А тех кто смотрит в будущее IOT приглашаю в телеграм-чат Open Thread (Matter, Project CHIP). (что такое Thread?, что такое Matter?)

Спасибо за внимание, всем добра!


Подробнее..

Чем кальциевые аккумуляторы отличаются от гибридных?

21.06.2021 16:11:25 | Автор: admin
Они отличаются тем, что у гибридных (Ca+, Ca/Sb) свинцовый сплав положительных решёток легирован сурьмой, а отрицательных кальцием, тогда как у кальциевых (Ca/Ca) те и другие кальцием. В результате, выделение газов происходит при разных напряжениях заряда, и токи окончания заряда при этих напряжениях тоже разные.

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


Обманывают ли нас производители, или мы не всегда учитываем влияния конструкции на электрохимические процессы? Проведём серию испытаний пары аккумуляторных батарей (АКБ), изображённых на фото.

В сегодняшнем эксперименте участвует батарея 6СТ-64L Тюмень PREMIUM СаСа 64 А*ч. Кальциевая технология освоена Тюменским аккумуляторным заводом (с лосем на логотипе) в 2019 году.


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


Тестер показывает уровень заряженности (state of charge, SoC) 0%, внутреннее сопротивление 9.77 мОм, ток холодной прокрутки (ТХП) 283 из 620 А по стандарту EN, напряжение разомкнутой цепи (НРЦ, оно же электродвижущая сила ЭДС без нагрузки) 11.53 В, и предписывает зарядить аккумулятор.


Заряжать будем зарядным устройством (ЗУ) Кулон-720. Настроим следующие параметры заряда: предзаряд до 12 В 2 А, основной заряд 14.7 В 6.4 А 24 часа, хранение 13.2 В 0.5 А.


Дозаряд у Кулона-912 реализован качелями, так принято называть управление двухпороговым компаратором или компаратором с гистерезисом по напряжению. Когда напряжение на клеммах достигает верхней планки, ЗУ отключает зарядный ток. Когда поляризация релаксирует, напряжение на клеммах снижается, и при касании нижней планки ЗУ возобновляет подачу тока. Продолжаются эти циклы до превышения максимального времени. Установим пороги 15.6 и 14.7 В, ток 3.2 А, продолжительность 16 часов.


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

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

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


Пошёл предзаряд.


Вскоре ЗУ перешло к этапу основного заряда.


За три с половиной часа залито 22.4 А*ч, напряжение на клеммах 13.3 В. Оставим ЗУ работать на ночь.


На следующий день время заряда составило 19 часов 42 минуты, аккумулятору сообщено 75.3 А*ч. Напряжение дозаряда доходит до установленных 15.6, ток при этом напряжении снизился до 1.2 А.


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


Плотность электролита уже чуть выше 1.25.


С момента начала заряда прошло 23 часа, залито 77.4 А*ч. Ток при 15.6 В снизился до 1 А.
АКБ продолжает заряжаться, плотность электролита поднялась чуть выше 1.26.


Заряд продолжался 26 с четвертью часов, батарее передано 79.2 А*ч. Ток при 15.6 В не снижается.


Плотность 1.27.


29 с половиной часов от начала заряда, залито 80.9 А*ч. Ток при 15.6 В снизился до 0.9 А. Оставим ещё на ночь.


На утро аккумулятору сообщено 82.6 ампер*часа, ЗУ в режиме хранения. С начала заряда прошло 45 с половиной часов.


Плотность во всех банках 1.28. Нам удалось зарядить эту АКБ после глубокого разряда за один подход.


Однако возникают сомнения в том, что эта АКБ полностью кальциевая. При заряде она повела себя как гибридная. Ca/Ca аккумулятору 16 часов дозаряда, а именно такое максимальное значение можно установить на Кулоне-720, и его мы как раз установили, бывает недостаточно. Приходится перезапускать заряд.

Разряжать будем электронной нагрузкой ZKE EBD-A20H, по ГОСТ током 5% номинальной ёмкости 3.2 А до касания под нагрузкой 10.5 В.


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


Через 8 часов разряда напряжение на клеммах 12.22 В. Слито 26.78 А*ч, 332.45 Вт*ч.


Через 20 с половиной часов разряд продолжается, на клеммах 11.07 В, АКБ отдала 66.86 А*ч, что уже превышает паспортную ёмкость. Как видно из графика, в конце разряда напряжение снижается быстрее, модуль первой производной выше.


На последней минуте график резко пошёл вниз.


Разряд завершён, напряжение после снятия нагрузки начало расти. Время разряда составило 20 часов 44 минуты, отданная ёмкость 67.39 А*ч.


Через 3 минуты после снятия нагрузки напряжение на клеммах выросло до 11.42 В. Подождём ещё час.


Прошёл час с момента завершения разряда, НРЦ 11.63 В.


Плотность электролита ниже 1.10. Ставим на заряд.


Заряд продолжается 26 часов 19 минут, залито 79.2 А*ч. Ток при 15.6 В 1 А.


Плотность уже 1.27. Аккумулятор заряжается очень легко при дозаряде качелями с максимальным напряжением 15.6. Так обычно ведут себя гибридные Ca/Sb, а не кальциевые Ca/Ca аккумуляторы.

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

GIF 7952.5 Кбайт

А так кипит при дозаряде с перенапряжениям вторая участница тестов оригинальная запасная часть LADA 6СТ-62VL производства жигулёвского завода АКОМ, типичная полностью кальциевая Ca/Ca батарея. Для такого газовыделения понадобилось 16.2 вольта при постоянном токе 2% ёмкости, то есть, 1.2 ампера, безо всякого прерывания качелями.

GIF 7597.95 Кбайт

Тесты АКБ Лада объёмны и заслуживают как минимум отдельной статьи, потому здесь приведём только их конечные результаты, нужные для сравнения двух испытуемых образцов.



Показания тестера у Тюмени: здоровье 100%, ТХП 687 из 620 А по EN, внутреннее сопротивление 4.02 мОм, НРЦ 12.96 В. У Лады: EN 722 из 600 A, 3.82 мОм.


Просадка под нагрузочной вилкой 200 А до 10.64 В.


Для сравнения, Лада проседает до 10.90.


Масса тюменского аккумулятора 16.4 кг.


Сведём данные тестирования двух аккумуляторных батарей в одну таблицу:
Фактическая удельная ёмкость на килограмм массы батареи у АКБ Лада на 11.57% выше, чем у Тюмень Премиум, удельный ток холодной прокрутки на 13.69%. Оба этих параметра зависят не от кальция и сурьмы в свинцовом сплаве, а от собственно массы активных масс и их рабочей площади, а также конструкции решёток и тоководов. Получается, действующих активных масс у тюменского аккумулятора меньше, а несуще-токоведущих конструкций больше. Это признаки классической докальциевой технологии, по которой часто производились гибридные Ca/Sb батареи.

Итак, по итогам испытаний двух АКБ типичной современной Ca/Ca Лада производства АКОМ (завод, использующей технологию Exide), и тюменской Premium с маркировкой Ca/Ca и лосем на логотипе, можно сделать следующие выводы:

  1. Оба аккумулятора проявили прекрасные характеристики: ёмкость по ГОСТ и пусковой ток по цифровому тестеру и нагрузочной вилке выше паспортных, однако Лада показывает заметно лучшие параметры, чем Тюмень Premium.
  2. Жигулёвская АКБ АКОМ при заряде ведёт себя как полагается Ca/Ca, тогда как тюменская заряжается как гибридная: рано начинается газовыделение, электролит перемешивается без затруднений, выравнивающий заряд проходит легко и быстро.
  3. Тюменская Премиум изготовлена по более старой технологии, чем жигулёвская Лада. Именно поэтому, несмотря на современный кальциевый сплав и отрицательных, и положительных решёток, тюменская АКБ имеет меньшую плотность упаковки пластин и проявляет свойства, характерные для гибридной, а не Ca/Ca АКБ.

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

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

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

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

Тюмень Премиум хорошая АКБ, достойно проявившая себя на испытаниях. Она не гибридная, а действительно кальциевая, в плане современного материала решёток пластин. Но конструкция батареи не модерновая плотно упакованная, а традиционная, вследствие чего, при изготовлении затрачивается больше свинца, и газовыделение наступает при меньшем напряжении. И именно поэтому АКБ маркирована не VL, как Лада, что означает очень низкий расход воды, а L низкий расход. Всё честно.

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

Напоследок сравним Тюмень Премиум с антикварной аккумуляторной батареей 6СТ-60ЭМ из статьи про капсулу времени:
Почти три десятилетия прожиты недаром, и сегодняшний технологический уровень Тюменского аккумуляторного завода позволяет производить батареи с удельной эффективностью по ёмкости на треть, а по пусковому току на две трети более высокой, чем старые сурьмянистые батареи. Потому слова классическая и модерновая применительно к конструкции АКБ не следует понимать превратно. Современные аккумуляторы разных отечественных производителей и марок показывают достойные характеристики и имеют свои области для успешного применения.

Статья написана в сотрудничестве с автором экспериментов и видео Аккумуляторщиком Виктором VECTOR.


Подробнее..

Пятьдесят лет на стезе программирования. Часть I. Начало пути. Отчий дом и Казанское суворовское военное училище

21.06.2021 16:11:25 | Автор: admin
Логотип статьи определяет три, как временные, так и географические, точки на моём жизненном пути, через которые лежал мой путь в страну под названием Программирование. В городе Чебоксары, на родине легендарного комдива Гражданской войны В.И.Чапаева, прошло моё детство (1954-1968 г.г.), там я закончил 8 классов средней школы 6. В 1968 году я переместился в следующую географическую точку, в г. Казань, в Казанское суворовское военное училище (КзСВУ). После окончания КзСВУ в 1971 году мой путь лежал в столицу нашей Родины в Москву, в Военную орденов Ленина, Октябрьской Революции и Суворова Академию им. Ф.Э.Дзержинского (сокращённое название ВА им. Ф.Э.Дзержинского или ВАД), которой в 2020 году исполнилось 200 лет со дня ее основания. И 22 июня в трагический для нашей страны день в 1941 году и знаковый для меня в 1976 году я окончил ВА им. Ф.Э.Дзержинского и получил диплом по специальности Программирование с присвоением квалификации военного инженера программиста:



Это случилось 45 лет назад. Но на стезю программирования я вступил ещё раньше, а именно, в 1971 году, когда после окончания КзСВУ и приехал в столицу нашей Родины поступать в ВАД. А это было ровно пятьдесят лет назад. И вот именно о том, как я попал на эту стезю и как шёл и иду по ней, и будет мое повествование. И посвящено оно моим родителям Орлову Николаю Егоровичу и Орловой (в девичестве Кулыгиной) Зое Федоровне:



I. Отчий дом


Мой выбор стези Программирования, я думаю, был не случаен. Он был обусловлен всем моим счастливым детством.
Детство моё прошло в небольшом провинциальном городе Чебоксары, населения в нём тогда было менее 100 000 человек. Семья наша была многодетной. У отца с матерью нас было четыре брата, слева направо, Гена, Юра, Вова, Серёжа:



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



Именно из этого дома ушёл на войну мой дед Орлов Егор Михайлович и погиб под Москвой:



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



Себя я помню с 3-4 лет. Особенно хорошо запомнил наши поездки в Москву в 1957 и 1958 годах. Самые яркие воспоминания посещение Мавзолея Ленина-Сталина, когда приходилось стоять в огромных очередях, берущих начало в Александровском саду, и тележки с горячими сосисками.
Первым нашим жильём в Чебоксарах была комната в бараке. Её дали маме от строящегося Чебоксарского завода тракторных запасных частей (сегодня это Агрегатный завод), куда она устроилась работать в горячий цех термистом.
Барак это обычно одноэтажное здание, чаще деревянное, с проходом во всю длину и разделённое перегородками на комнаты. Комнаты были по 12-16 квадратных метров. Туалет обычно находился во дворе, отопление было печным, а кухня общая. Вода в колонке на улице. К сожалению, мне не удалось найти фотографию именно нашего барака, но я нашел похожий:



После Великой Отечественной войны размер разрушений на территории СССР был колоссален, лишилось крова более 30 млн. человек, примерно, каждый седьмой по стране. Чернигов, Севастополь, Великие Луки, Белгород были разрушены полностью. В Сталинграде, Минске, Курске, Новгороде и многих других городах было разрушено более 90% зданий. В землянках оказались миллионы наших граждан. Строительство бараков было вынужденной и временной мерой как по расселению оставшихся без крова людей, так и по обеспечению жильем людей, прибывающих на строительство новых заводов. Так было и в Чебоксарах при строительстве Чебоксарского завода тракторных запасных частей.
Но если фотография нашего барака не сохранилась, то фотография нашей комнаты в этом бараке (и не одна) сохранилась:



Это где-то 1956-57 года. Посмотрите, какие счастливые лица у людей. На фотографии слева направо мой отец, из его подбородка выглядывает автор этой статьи, затем моя мама. Встреча состоялась по случаю приезда из Саратова брата отца с женой (пара в центре) и прихода в гости сестры мамы с мужем. Последние жили в Чебоксарах в своём доме на ул. Краснофлотской. Её сейчас нет, на её месте стоит Олимпийский стадион.
Как я уже сказал, бараки были временной мерой и уже в 1957 году мы переехали в более комфортабельное жильё, в коммунальную квартиру на Школьном проезде дом 4:



В СССР коммунальные квартиры, общежития и временные бараки были одним из основных типов жилья рабочих до начала массового жилищного строительства отдельных квартир в 1960-х, до начала строительства знаменитых хрущёвок.
Знаменитые стройки 70-х годов, такие как Нижнекамский и Чебоксарский химические комбинаты, КАМАЗ, Чебоксарская ГЭС, Чебоксарский завод промышленных тракторов (ЧЗПТ), уже возводились без бараков. Вместе с этими индустриальными гигантами вырастали современные города Нижнекамск, Набережные Челны, Новочебоксарск, а в Чебоксарах вырос Новоюжный район:



Но вернёмся в коммунальную квартиру. В коммунальной квартире уже были туалет, ванная, центральное отопление. Если мне не изменяет память, то в нашей квартире было четыре комнаты, в каждой из которых жила отдельная семья.
А поскольку родители работали, то мы часто дома оставались одни. Дверь в нашу комнату, естественно, всегда была открыта.
Однажды мы остались с братом одни и зашли с ним на общую кухню, где у каждой семьи был свой стол. Там нашли коробок со спичками. Кто-то из нас сказал, что они не настоящие и мы решили это проверить. Результат был плачевным, вспыхнула скатерть на одном из столов. Мы убежали с кухни в свою комнату. На наше счастье в одной из комнат дома была чья-то бабушка, которая одеялом потушила начинающийся пожар. С тех пор я на всю жизнь запомнил, что огонь можно потушить, накрыв источник огня, например, одеялом, и самое главное, что игры с огнём могут закончиться печально. Именно поэтому в те времени так был популярны плакаты на тему спичек и детей.
Отсюда я в 1960 году пошел в первый класс в школу 28, которая находилась на этой же улице рядом с домом. Здание школы сохранилось, но школы там нет:



Первый класс запомнился двумя знаменательными событиями. Первое, это полное солнечное затмение, когда нас вывели на улицу и мы первоклашки наблюдали как день становится ночью. А весной 1961 года я провалился под лёд в котлован, который находился во дворе школы. Надо сказать, что когда я пошёл в школу, то не умел ни читать, ни писать. Но этот недостаток скоро был устранён и чтение стало любимым моим занятием, особенно с фонариком под одеялом. Надо сказать, что вся наша семья много читала. У нас была хорошая библиотека. Я, например, зачитывался Карелом Чапеком (Средство Макропулоса, Война с саламандрами и др.) и, как ни странно, Емельяном Ярославским, его повествованием о Древнем Египте. Именно поэтому, наверное, у меня и появилась тяга к истории.
Как нам жилось в коммунальной квартире? Отвечу: хорошо. Вглядитесь в эти лица:



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



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



В этом же году наша семья в составе пяти человек (в 1960 году у меня появился второй брат Сергей) переезжает в отдельную со всеми удобствами квартиру по ул. Ярославская (сегодня ул. Энгельса, д.12, на фотографии первый дом справа):



Наша квартира была на шестом этаже (лифта не было) и как мы этим гордились. В те годы в Чебоксарах мало кто так высоко жил. Но самое главное было то, что весь первый этаж был отдан под Станцию Юных Техников (СЮТ). Сразу скажу, что сегодня этой станции там нет, и все помещения занимают коммерческие предприятия. И вот в один прекрасный день, уже учась во втором классе, я открыл дверь, переступил порог СЮТ и попал в волшебный мир. Меня приветливо встретили и провели по всей станции. Ребята (правда, они были постарше меня, я учился во втором классе) собирали модели кораблей и самолетов, строили планеры, печатали фотографии, а кто-то показывал фильмы. Глаза разбежались. В итоге я записался практически во все кружки: фото, авиа- и судомодельный. Записался и на курсы киномеханика. На курсах киномехаников нас учили крутить фильмы на кинопроекторе Украина.
Всё было абсолютно бесплатно. Как я успевал? Мне повезло, что СЮТ была в доме, в котором я жил, и школа 16 была рядом, в двух минутах ходьбы.
Я до сих пор с гордостью рассказываю, что уже во втором классе получил первое удостоверение киномеханика. Был случай, когда в клубе оказалось некому показать фильм Степан Разин. И тут моё удостоверение пригодилось. Пригодилось оно и в дальнейшем, когда в школе необходимо было демонстрировать учебный материал на Украине (видеомагнитофонов и компьютеров тогда не было).
А как народ сбегался смотреть, когда мы запускали в небо планеры, а тем более кордовые модели!
СЮТ была хорошей школой, она мне многое дала. Стацию юных техников я прекратил посещать после того, как мы переехали на новое местожительство.
А еще мне посчастливилось встречать в Чебоксарах в 1962 году Космонавта-3 А.Г.Николаева:



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



В момент следования кортежа я находился в первом ряду около детского мира (на фотографии второй дом справа от левого верхнего угла) и один из мотоциклов своим колесом проехал по моему ботинку. Вот такие воспоминания. Жизнь просто бурлила.
Мой отец всю жизнь гордился, что тоже был причастен к полёту А.Г.Николаева в космос. Где-то за месяц до полёта бригаду плотников, в которой работал и мой отец, отправили в командировку (они такого слова не знали) в глухую чувашскую деревню.
Оказалось, надо срочно построить дома для простой чувашской старушки. Никто ничего не понимал, но дом был построен, а вскоре и секрет открылся, это был дом для матери Космонавта-3.
В 1961 году у меня появился еще один брат, третий Юра.
А весной 1964 года мною была предпринята первая попытка пойти учиться в суворовское военное училище. Как я уже говорил, я много читал, в том числе и про суворовцев. В те времена военно-патриотическое воспитание было на высоте. Я знал, что в суворовские военные училища (СВУ) берут после четвертого класса. Со мной в классе учился мальчик, чей отец был летчиком-испытателем и погиб при испытании самолёта. Мы с ним дружили и хотели вместе идти в СВУ. Но именно в 1964 году было принято решение о приёме в СВУ только после восьмого класса. Наша детская мечта была отложена на целых четыре года.
В этом же 1964 году мои родители получили трехкомнатную квартиру на улице В.И.Чапаева, д.11. Эта улица знаменита тем, что стоит на месте деревни Будайки, в которой родился В.И.Чапаев знаменитый комдив времен Гражданской войны. На том месте, где стоял дом семьи Чапаевых, сегодня стоит такой монумент:



Надпись на мемориальной доске гласит:
Здесь стоял дом, в котором 9 февраля 1887 года родился В.И.Чапаев

После переезда пришлось сменить и школу. Теперь я посещал школу 6, которая тоже находилась недалеко от дома. Но, перестав ходить на СЮТ, я стал посещать в школе баскетбольную секцию и секцию самбо в спорткомплексе Динамо. На баскетбольном поприще мне врезался в память мой бросок с середины поля с попаданием в кольцо противника, когда мы играли на первенство города. Это было что-то. А в самбо также врезался в память финальный поединок на первенство города, когда я мог выиграть схватку на ковре, проведя болевой приём на локте соперника (рычаг локтя). Однако я так и не смог до финального гонга разорвать сцепленные в замок кисти рук противника.
Отдельно стоит сказать о шахматах. Муж сестры отца Николай очень хорошо играл в шахматы:



Они часто приходили к нам в дом, порой с ночёвкой. Именно они подарили мне шахматы и, самое главное, привили любовь к ним. Каждый их приход к нам начинался с игры в шахматы и не просто игры, а игры с разбором. И вот наступил момент, когда Николай мне сказал:
Всё, больше я тебе ничего здесь дать не могу. Ты превзошёл своего учителя
Кстати, всех сестер отца и младшего брата я звал по именам. Таково было их пожелания. Меня они всегда считали за равного. Это здорово.
А в начале 1968 году в Будайках, недалеко от нашего дома, был открыт Дом Спорта Спартак (его можно увидеть на фотографии ниже). И вот как-то, проходя мимо него, я увидел на доске объявлений, что проводится запись для участия в квалификационном шахматном турнире II разряда. Турнир организовывал и проводил международный мастер по шахматам В.Д. Сергиевский. Имя Сергиевского в те годы гремело в Чебоксарах и я следил за его успехами. А успехи у него были. В 1966 году он стал чемпионом России по шахматам, занял шестое место на мемориале М.И.Чигорина, выиграв в турнире и у будущего чемпиона мира Б.В.Спасского. Именно на мемориале М.И.Чигорина Сергиевский выполнил норматив международного мастера по шахматам.
Когда я увидел фамилию Сергиевский, сомнений у меня не осталосьи я вошёл в Дом Спорта записываться на турнир. Турнир я провёл хорошо, занял второе место. Победитель турнира, юноша старше меня года на 2-3, был значительно сильнее меня. Но надо иметь в виду, что я всё же был самоучкой. По условиям турнира за первое место давали II разряд, а за второе III разряд. Итак, я стал третьеразрядником по шахматам и, как окажется чуть позже, будет иметь свои последствия. По ходу турнира был курьёзный случай. Одну из партий я играл с мальчиком, который был младше меня года на четыре, но он занимался у самого Сергиевского и подавал большие надежды. До встречи со мной он у всех выигрывал, но мне проиграл. И тут случилось непредвиденное, он расплакался навзрыд, его никто не мог успокоить. В итоге ко мне подошёл сам Сергиевский и попросил меня переиграть партию. Для меня это было очень неожиданно: в шахматах переиграть партию Но Сергиевский нашёл какие-то слова и я согласился. Я думаю, Сергиевский всё же пожалел о своём поступке, паренёк снова проиграл. Я не помню сейчас, на каком месте он закончил турнир, но я своим вторым местом горжусь.
Отец мне с раннего детства привил любовь к периодической печати, к газетам и журналам. Родители мне выписали сначала газету Пионерская правда, где печаталась книга А.Волкова Урфин Джюс и его деревянные солдаты. О, как я ждал прихода газеты, чтобы прочитать продолжение!
Потом я их уговорил выписать журналы Юный техник, Техника молодёжи.
В пятом классе я увлёкся радиоделом и пришла очередь журнала Радио.
Откуда пошла тяга к радиоделу или, как сейчас сказали бы, к электронике, я не помню, но увлечение было серьёзное. Сначала детекторный приёмник, потом приёмники прямого усиления, потом супергетеродинный радиоприёмник да ещё с приёмом коротких волн. Вместо корпуса мыльница. Апофеозом стал магнитофон, где самое трудное было собрать лентопротяжный механизм, и миниатюрный телевизор. Последнее осталось незаконченным, хотя была разработана схема и изготовлена печатная плата. Проблема была в отсутствии кинескопа, электронно-лучевой трубки малого размера. Но когда я дома отремонтировал телевизор, мой авторитет в глазах родителей вырос до небес.
Вершиной нашего радиолюбительства я считаю создание радиосети в вашем квартале, которую можно было бы считать нашим детским прообразом современного Интернет. Нас было человек шесть, увлечённых радиоделом. Все мы увлекались радиолюбительством, собирали усилители, радиоприемники, ремонтировали телевизоры и т.д. Самое главное, обменивались новыми схемами и радиодеталями, которые было трудно достать. Главная проблема была в оперативной связи между собой. Телефонов ни у кого не было и приходилось чуть что, бежать друг к другу. Все мы жили в пределах одного квартала (6-й квартал, ул. Чапаева, г. Чебоксары) в новых пятиэтажках (как сейчас говорят в хрущевках). И вот кому из нас пришла идея: а почему бы нам не организовать радиосвязь между собой?! Нет, не собрать радиостанции, с этим было очень сложно. Нет, не собрать, а получить разрешение. И вот что мы придумали. Пробрасываем по крышам с дома на дом провода (не могу вспомнить, где же мы их взяли), каждый дома ставит усилитель, обзаводится микрофоном, присваиваем каждому позывной (про логин, естественно, тогда никто и не знал) и общаемся. Включаешь усилитель, берешь микрофон и говоришь, например: Первый, первый, вызывает пятый. Ответь. И заработало:



Более того, таким образом, мы на весь квартал включали музыку. Все было хорошо.
Но однажды, когда я был дома один, раздался звонок в дверь. Нет, звонили не сотрудники КГБ, в дверь звонил участковый милиционер. Он вежливо спросил, что это за провода идут с крыши соседнего дома к нам на балкон (мы жили на четвертом этаже фото). Пришлось ему все рассказать. Он попросил продемонстрировать, как все работает, и я связался с одним из своих товарищей. Больше всего его интересовал микрофон. В это время была просто напасть срезали телефонные трубки в телефонных будках, как правило, ради того микрофона и динамика. Но у меня был настоящий микрофон. Я как-то познакомился с главным инженером ДОСААФ (Добровольное Общество Содействия Армии, Авиации и Флоту), он взял над нами шефство и помогал радиодеталями. Так что никаких претензий ко мне и нашей группе у участкового не возникло. Он даже похвалил, что интересным делом занимаемся, а не бесцельно по улицам болтаемся. Еще добавил, что телефонные будки надо беречь. После того, как в 1968 году я уехал учиться в КзСВУ, то, приезжая в отпуск, всегда смотрел на наши провода и иногда даже пользовался этой связью. Но прошло несколько лет и в очередной приезд я увидел, что изоляция на проводах разрушается. Я дернул провода и они оборвались. Так перестала существовать наша сеть (ещё не вычислительная). Так заканчивалось моё детство.
Как я учился? Учёба мне всегда давалась легко. Я был твёрдый ударник и блистал в математике. В этом была большая заслуга нашей учительницы по математике Гавриловой Анны Порфирьевны. Но у меня было, как я говорю до сих пор, три недостатка: у меня отсутствует (или не развит?) музыкальный слух, я не умею танцевать, не пою, и еще я не умею рисовать. При этом я люблю музыку, с удовольствием хожу на концерты, люблю живопись и архитектуру. Эти недостатки не давали мне возможности быть круглым отличником. Да я и не стремился:



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



Обилие овощей, солений, салатов, яблок на столе заставили вспомнить, что мои родители в 1957 году получили участок в 6 соток в садовом товариществе Заря. С тех пор все выходные летом, как правило, проводились, как гордо говорили мы, на даче:



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



Из взошедших по трапу на борт теплохода Ракета, окончить суворовское училище посчастливилось только четверым: Володя Орлов, Саша Усов, Саша Кленин и Ордяков.

II. Казанское суворовское военное училище


Через пару часов нас встречала Казань. А спустя ещё немного времени мы входили на территорию КзСВУ:



По приезде в КзСВУ нам дали несколько дней на подготовку к экзаменам. Экзамены мы сдавали по математике и русскому языку. Сдавали и письменный экзамен и устный. С этим проблем не оказалось. И мне объявили, что я зачислен в училище. Но был ещё и пятый экзамен, вернее, не экзамен, а собеседование по иностранному языку. Это было связано с тем, что в суворовских училищах в те времена изучению иностранных языков предавали серьёзное значение. По окончанию училища можно было получить удостоверение военного переводчика.
В училище велось обучение на двух языках: английском и французском. В школе я учил английский язык, и у меня была твердая четвёрка. Каково же было моё удивление, когда на собеседовании мне сказали, что у меня нулевые знания и что я буду учить французский язык. Удивление было, но расстройства не было. Учить французский язык язык Великой Французской революции, Парижской Коммуны! Что может быть лучше!,- думал я. А еще вспомнилось, как в пятом классе я очень хотел учить испанский язык, язык свободный Кубы, язык, на котором разговаривали Фидель Кастро и Че Гевара. И здесь мне казалось, что французский язык намного ближе к испанскому, чем английский. К французскому языку мы ещё вернёмся чуть ниже.
Я был зачислен в 3 взвод 7 роты (на фотографии третий ряд снизу, восьмой справа). Командиром роты был подполковник Харченко Б.К. (второй ряд снизу, шестой справа), а командиром взвода майор Беседин А.Г. (второй ряд снизу, четвертый справа):



На фотографии наш командир ещё в звании майора. Подполковника он получит чуть позднее, в октябре 1968 года.
Начальником Казанского суворовского военного училища был генерал-майор Смирнов А.П., участник Великой Отечественной войны, участник Сталинградской битвы. Мне на всю жизнь запомнились его слова, звучащие как напутствие:
Посеешь поступок пожнёшь привычку.
Посеешь привычку пожнёшь характер.
Посеешь характер пожнёшь судьбу
Сколько раз по жизни мне приходилось видеть подтверждение этих пророческих слов.
Когда экзамены были позади, когда мы получили форму и удостоверения суворовцев, было ещё одно собеседование, на этот раз на спортивную тему. Меня спросили, занимался ли я спортом и каким, я рассказал что занимался в баскетбольной секции и в секции самбо, а также получил III разряд по шахматам. Мне сказали, что баскетболист из меня с моим ростом так себе, а борцов в училище хватает. А вот то, что у меня разряд по шахматам, это здорово. Меня включили в группу шахматистов, которые после занятий, а также в выходные дни ходили в Дом Офицеров в шахматную секцию. Это, конечно, было что-то, у всех трехмесячный карантин без права выхода в город (без увольнительных), а ты имеешь это право выхода. А навыки самбо, естественно, пригодились на занятиях по рукопашному бою.
Но моя спортивная эпопея имела продолжение. Пришло время сдавать нормативы по ВСК (военно-спортивному комплексу). Это аналог комплекса ГТО (Готов к Труду и Обороне).
После забега на дистанцию 100 метров меня подзывает к себе преподаватель капитан Дергоусов Ю.И. и спрашивает, где я занимался бегом. Мой ответ, что это мой первый забег на 100 метров, его очень удивил. В этот момент мне было 15 лет, время я показал 12 секунд и бежали мы на стадионе по гаревой дорожке в обыкновенных кедах. С этого момента я стал тренироваться на спортивной дорожке. Пришлось мне выступать и на центральном стадионе г. Казани. Но особенно запомнился выигрыш нашей команды майской легкоатлетической эстафеты, посвященной Дню Победы (я в первом ряду третий слева):



Немножко было обидно, что нам за первое место выдали Кубок, а за второе и третье места участникам команд выдали спортивные костюмы. Но посмотрите на наши лица мы все счастливы.
Если говорить о физической подготовке, то надо всё же сказать и о лыжах. Когда наступала зима, мы начинали бегать на лыжах 5 и 10 километров и бегаешь до тех пор, пока не выполнишь норму II разряда. У нас во взводе был Серёжа Лазарев (на фотографии он на переднем плане, а я справа), родом из г. Сочи:



При этом у него были определённые успехи в легкой атлетике. Например, в высоту он брал 175 сантиметров. Но вот лыжи ему не давались, до училища он ни разу не становился на лыжи. Парень он был упёртый (в хорошем смысле этого слова) и с утра до ночи ходил и ходил на лыжах, а мы ему помогали. И он выполнил норматив. После училища он отказался от военной карьеры и в итоге стал парапсихологом, мало в чём уступающим Чумаку и Кашперовскому. Написав о Сергее, я вспомнил случай, произошедший со мной в училище. Как-то я прогуливался по нашему парку и вдруг как наяву вижу, как у моего родного брата Сергея лопается аппендицит. Я остановился как вкопанный. Что делать, как сообщить домой? Сотовых телефонов тогда не было. Да что сотовые, обыкновенные телефоны были ещё редкостью! В итоге, я решил, что это просто блажь, а через три дня (именно столько шли письма из дома в училище) получил письмо от родителей, в котором они сообщали, что у Сергея вырезали гнойный аппендицит, хорошо, что скорая помощь приехала быстро и успели отвести его в больницу. Может, мне тоже надо было в экстрасенсы податься?
Надо сказать, что все офицеры училища имели отличную физическую подготовку. Вот несколько примеров. Начальник училища генерал-майор Смирнов выезжал вместе с нами зимой в лагеря, вместе с нами рыл в заснеженном поле окопы и бросался вместе с нами в атаку вслед за танком. При этом он часто рассказывал, что именно отменная физическая подготовка спасла его от гибели под Сталинградом. Рассказывал он так, показывая рукой на левую грудь, где у него был шрам: когда сердце сжалось, в грудь вошла пуля, которая пролетела мимо сердца. После того как пуля вылетела, сердце разжалось и он продолжил бой.
Или наш ротный подполковник Харченко Борис Кузьмич. Как-то кто-то из нас что-то натворил и в воспитательных целях была объявлена тревога (дело было летом в летних лагерях и в 30-градусную жару). Рота была построена в полной выкладке (скатка шинели, автомат, противогаз). После этого прозвучала команда одеть противогазы и начался марш-бросок на 3 километра. Наш командир роты бежал вместе с нами и при этом следил, чтобы никто не снимал противогаза. Можно сказать, что это жестко, но мы так не считали. И какое было удовлетворение, когда мы это сделали и нас распустили. Можно много рассказывать, а ещё лучше написать отдельную книгу.
А теперь вернёмся к французскому языку. Обучение велось в хорошо оборудованных лингафонных кабинетах по группам. В каждой группе было не более 12 человек. Мне хорошо запомнилось первое занятие. Наше первое занятие началось с того, что преподаватель Милорадовская Е.А. предложила надеть наушники и послушать текст с пластинки. Я тоже внимательно слушал, но смог, как мне казалось, понять только два слова: Илья и Баку. И когда меня преподаватель спросила, о чём шла речь на пластинке, я ответил, что про какого-то Илью, приехавшего или жившего в Баку. Меня ждало разочарование. Оказывает Баку это не Баку, а beaucou в смысле много, а Илья тоже не Илья, а предложение il a в смысле он имеет. Так началось мое изучение французского языка. Учили нас прекрасно. Вообще мы стремились учиться, была какая-та хорошая состязательность. У меня был спарринг партнёр (если так можно выразиться) Серёжа Оглоблин, с которым мы соревновались, кто больше из нас получит отличных оценок за день, неделю и т.д.:



Сергей окончил училище с золотой медалью. А меня подвёл русский язык, несмотря на все старания нашего любимого преподавателя Смирновой Ноны Владимировны. Каждый день задавали выучить наизусть несколько страниц текста. Мы сами стремились пополнить свой словарный запас. Ряд предметов (например, астрономия, география) нам давали не на русском языке, а на том языке, который изучаешь. Естественно, была иностранная литература и военный перевод. В итоге, я выпустился из училища с удостоверением военного переводчика:



Помимо удостоверения переводчика я получил водительское удостовение и даже охотничий билет. К взрослой жизни по окончании КзСВУ я был готов, мог работать киномехаником, водителем и даже переводчиком.
Были и другие и комические, и трагические, и трагикомические случаи. Тут нашлась одна из моих записных книжек (дневник), там много чего интересного есть.
Первый мой отпуск домой в декабре 1968 года мог завершиться трагедией. Вместе со мной поступил в КзСВУ еще один юноша Кленин Саша, сын одного из офицеров Чебоксарского военкомата. Кстати, впоследствии он был участником той победной эстафеты (на фотографии второй справа в первом ряду).
Так вот, отец Саши Кленина на зимние каникулы прислал за ним машину ГАЗ-69 (газик/козлик), в которой приехали его мама и мой отец. Это было неожиданно и приятно.
И вот мы впятером отъехали от училища в сторону Чебоксар, а перед самым выездом из Казани решили пообедать в придорожном кафе (стекляшке, как их тогда называли). После обеда, удобно устроившись в машине, тронулись в сторону Чебоксар. Но мы не проехали и ста метров, как вдруг, кувыркаясь, полетели в кювет. Что же произошло? Был яркий солнечный и морозный день. Только что прошел снегопад. А вслед за снегопадом пошли грейдеры, которые расчистили не только дорогу, но и сравняли с дорогой кювет. А обрыв был приличный. И водитель, не подозревая этого подвоха, чуть-чуть прижался к правому краю дороги и мы полетели вниз. Первое, что я запомнил, это крик моего отца (машина лежала на крыше):- Володя, ты жив? Когда я откликнулся, он сумел выбраться из машины и вместе с водителем помог выбраться с заднего сидения и нам. Зрелище было печальное, машина лежит на крыше, лобового стекла нет, а у нас все лица залеплены осколками стекла. Но никто ничего не сломал, никто не порезался и кроме синяков никаких увечий никто из нас не получил. А наверху, на дороге, уже остановилось несколько машин и среди них был подъёмный кран. Когда стоящие наверху люди поняли, что с нами всё нормально, то стали думать, как нас вытащить. Решение было простым, кран опустил стрелу, водитель подцепил машину и её вытащили. Мы выбирались сами по заснеженному откосу. Оказалось, что машина на ходу, завелась с полоборота. Встала дилемма, ехать дальше в Чебоксары, но нет лобового стекла, на улице 20-градусный мороз и скоро начнёт темнеть. Либо где-то искать возможность достать и вставить стекло. Сколько на это уйдет времени неизвестно. Не забывайте на дворе 1968 год, Мы решили ехать в Чебоксары. А поскольку стекла не было, то ехали медленно. У Саши Кленина стали замерзать ноги. Как сейчас помню, как его мама всю дорогу их отогревала у себя на груди. Но худо-бедно мы добрались до Чебоксар. Мы с отцом поднялись на четвёртый этаж и позвонили в дверь. Дверь открыла мам и тут же присела, увидев нас, только и сказала:- Что с вами? Наши лица были синие, сплошной синяк. Но стол был накрыт, бульон для пельменей кипел. Жизнь продолжалась.
В суворовском училище нам, естественно, запрещали употреблять спиртные напитки и курить. Причём, наш взводный майор Беседин А.Г. говорил так:- Лучше выпить сто грамм водки, чем выкурить сигарету. Сам я курить начал только в 20 лет. Но любители побаловать сигаретой у нас во взводе были. И вот как-то утром после завтрака, но перед занятиями два моих товарища Андрей Николаев и Игорь Шишов, дают мне ключ от туалета, в котором шёл ремонт, и просят их закрыть там минут на десять, что я и сделал (третий слева я, четвёртый Игорь Шишов и пятый Андрей Николаев):



Но случилось непредвиденное я забыл про них. Удивительно и то, что за весь день, пока они сидели в туалете, никто про них не вспомнил. Ведь, когда начинались занятия, дежурный всегда докладывал преподавателю о наличии личного состава. И вспомнил я о них, когда рота строилась на вечернюю поверку. При выходе на них было жалко смотреть. Это я о вреде курения.
Был и неприятный случай, связанный с водкой. Однажды в расположении нашей роты нашлась бутылка с водкой и никто не хотел сознаваться, чья это бутылка. А поскольку в город мог свободно в рабочие дни (помните шахматы, Дом Офицеров) мог ходить только я, то волей неволей тень подозрения пала и на меня. Но спустя несколько дней отцы-командиры всё же разобрались кто и что. Этим человеком оказался суворовец, у которого были проблемы и с успеваемостью. В итоге он был отчислен из училища. Фамилию его называть не буду, но он есть на предыдущей фотографии и это не я.
Пить и курить запрещали, а жениться нет (при достижении 18 лет). И у нас был трагический случай. Один из суворовцев встречался с девушкой и она забеременела. Суворовец оказался не тот и отказался жениться на ней. Девушка бросилась под трамвай. К счастью (хотя о каком счастье может идти речь) она осталось жива, но без ступни. Суворовца отчислили, отправили служить в армию. Это о том, что за свои поступки надо отвечать.
Расскажу ещё один поучительный случай (а таких случаев было много). Летом мы выезжали в лагеря и жили в палатках:



Там, в лагерях у нас проходила и топографическая подготовка. На одном из занятий командир взвода майор Беседин раздал нам топографические карты, предупредив, что они секретные, и поставил всем задачу: какой маршрут пройти, что найти и т.д. Перед выходом на маршрут все карты мы сдали командиру. Но оказалось, не все. Когда я вернулся с маршрута, то увидел бледного своего командира, который первым делом спросил, не брал ли я карту с собой. Тут я узнал, что одной карты не хватает. Тот, кто имел дело с секретным делопроизводством, понимает, о чём идет речь. Но в итоге карта нашлась, один из нас, самый умный, взял карта с собой на маршрут в надежде, что это поможет ему лучше пройти маршрут. Оказалось, не помогло, он пришёл одним из последних, но нервы командиру потрепал. С тех пор я знаю цену секретному делопроизводству. Случались неприятные случаи и при обращении с оружием. Например, однажды наш первый стрелок кандидат в мастера спорта выпустил очередь из автомата перед носком сапога командира роты подполковника Харченко Б.К., когда тот шёл вдоль бруствера окопа, в котором с автоматами наизготовку находились мы, проверяя готовность нас к стрельбе по мишеням.
Приятными моментами нахождения в летних лагерях были заготовка берёзовых веников для отцов командиров и ловля карасей трёхлитровыми банками. Не обходилось и без самоволок до ближайшего посёлка Дербышки на танцы.
Суворовское училище было только ступенькой во взрослую жизнь. Надо было думать, кем же я хочу стать? В 1968 году выходит фильм Мертвый сезон, а в газете Комсомольская правда публикуется серия статей о советских разведчиках, если мне память не изменяет, об Абеле и Киме Филби. В 1969 году произошли кровавые события вокруг острова Даманского на Дальнем востоке. Как мы все рвались туда, на Даманский. Я решил для себя, что должен стать разведчиком. Всё шло к тому, что так и будет. Командир роты и командир взвода знали о моём заветном желании. Когда началась учёба в 11 классе, меня вдруг вызвали на собеседование. Как я потом узнал, пришла разнарядка в Приволжский военный округ на два места в высшую школу КГБ. Просмотрено было 600 (шестьсот) кандидатов и выбор пал на меня и еще одного суворовца, у которого отец служил в Комитете. Я был счастлив. Но когда в суворовском училище узнали, что я согласился идти в высшую школу КГБ, началось что-то для меня непонятное, преподаватели стали отговаривать. Кто говорил, что надо идти в академию связи, кто в академию химзащиты, кто в Можайку и т.д. И все говорили, что я зарываю свой талант, кто в математике, кто в физике, кто в химии и т.п. Но я стоял на своём и проходил различные комиссии. Однажды приехал ко мне отец и как обычно остановился у родителей Андрея Николаева. Его родители преподавали в ветеринарном институте, отец был профессором, мать доцентом (по крайней мере, так у меня отложилось в памяти) (слева на право моя мама, мама Андрея Николаева, Андрей, мой отец, внизу мой брат Сергей) и дружили с моими родителями:



И вот, когда я пришел к ним в гости и мы все сели за обеденный стол, опять поднялся разговор о том, где мне дальше учиться. Николай Сергеевич, отец Андрея, сказал: Представляешь, Володя, пройдет время и ты окажешься вот также за столом, но как только ты сядешь за стол, все замолчат и ты почувствуешь себя очень неуютно. И сейчас ты не горячись, а подумай хорошенько. Когда мы остались с отцом вдвоём, он мне сказал: Володя, а может они правы, они же грамотные люди в отличие от нас с матерью, может, правда не стоит туда идти. Эта была последняя капля. Я сказал, что хорошо, я откажусь от предложения учиться в вышке, но куда я пойду, пока не знаю. Потом у меня состоялся тяжелый разговор, тяжелый для меня, что я не оправдал оказанного мне доверия, с направленцем, который курировал отбор кандидатов в вышку. Мне кажется, он понял меня и когда он спросил, а кто, если не я, то я, не задумываясь, назвал Сережу Оглоблина. Так и случилось, Сергей пошёл вместо меня. Позже в Москве мы с ним встречались, а потом потерялись.
Надо было решать куда идти. Была мысль податься в медицинскую академию им. С.М.Кирова, то тут на глаза в газете Красная Звезда попалось объявление о наборе слушателей в Военную Академию им. Ф.Э.Дзержинского. Я срочно написал туда письмо с просьбой прислать условия приёма. И мне пришла бандероль с буклетом и программой вступительных экзаменов. Надо сказать, что в училище никто ничего не знал про эту академию. Но для меня всё было решено. Это учеба в Москве, есть факультет связи и радиоэлектроники, и самое главное это название им. Ф.Э.Дзержинского, где-то рядом с моей мечтой о подвигах разведчика. Да, о подготовке программистов там не было ни слова. Да я ещё и слова такого не знал. Меня опять стали отговаривать, но я уже не обращал внимания. Предпринял попытку меня отговорить и наш командир взвода майор Беседин А.Г. Он говорил следующее: Володя, у меня товарищ служил на острове Земля Франца Иосифа, там, куда продукты питания завозят раз в полгода. И вот настал момент, когда ему удалось вырваться оттуда и поступить именно в академию Дзержинского. Каково же было его разочарование, когда после окончания академии его снова направили на этот остров. Я не знал, что академия им. Ф.Э.Дзержинского готовил ракетчиков. Но теперь уже ничто меня не могло заставить сменить решение. Перед самым окончанием училища наш преподаватель математики Егорова Л.Ф. сказала, что сразу после выпускного начинаем готовиться к экзаменам. Но я ответил, что сразу после выпускного еду к родителям, а оттуда в академию. К поступлению я готов. Мне показалось, что её обидел мой отказ. Но в итоге я оказался прав.
В один из последних дней пребывания в училище вдруг ко мне подходит суворовец из соседней шестой роты, золотой медалист Женя Арсентьев. Он спросил: Это правда, что ты едешь в академию Дзержинского? Получив положительный ответ, он предложил идти в академию вместе. Оказалось, что его родной старший брат преподает в академии химию, имеет воинское звание полковник и ученую степень доктора наук. Мы договорились встретиться у академии, дай бог памяти, числа 30 июня 1971 года. Я всё ещё не знал, что с сентября 1971 года в академии начинается подготовка военных инженеров-программистов
Сейчас я понимаю, что у меня было три реперных точки, которые привели меня на стезю программирования: поступление в КзСВУ, отказ от учебы в высшей школе КГБ и встреча с Женей Арсентьевым. Но самое главное, это те глубокие знания, которые я получил в Казанском суворовском военном училище. Огромное спасибо нашим педагогам:



Перед выпуском из КзСВУ нас переодели в новенькую парадную курсантскую форму, выдали проездные, предписания и мы убыли во взрослую жизнь.

III. Поступление в Военную академию им. Ф.Э.Дзержинского


По дороге в ВАД я на несколько дней впервые в курсантской форме заскочил к родителям домой:



Но отпуск летом 1971 года был чисто символическим. И уже через несколько дней меня провожали в аэропорт на самолёт до Москвы. Отец настоял как всегда (за что я ему глубоко благодарен) на общей фотографии:



И вот я уже в Москве стою у КПП (контрольно пропускной пункт) академии им. Ф.Э.Дзержинского, жду Женю Арсентьева:



На этой фотографии ещё слева видна гостиница Россия. Подошёл Женя и сказал, что брат предложил пожить пару дней у него дома, пока в академии всё устаканится с приёмом абитуриентов. В Москве я был в самом раннем детстве в далёких 1957-58 годах. Поэтому для меня всё было вновь. Как оказалось, многое и для Евгения. Всё началось у нас с ним с комического случая. Когда мы приехали в дом брата Жени, то надо было подниматься на лифте (до этого на лифте я ездил раз-два и то на один-два этажа). Здесь надо было подниматься повыше. Когда мы вошли в лифт, то пол, естественно, но не для нас, опустился. Мы нажали нужный этаж и поехали, но тут кто-то из нас предложил давай подпрыгнем! И мы сделали это. Как результат, лифт остановился. Вокруг никого. Что делать, не знаем. На наше счастье минут через тридцать мимо проходила старушка, увидев нас, запричитала, опять сломался. Сейчас я вызову лифтера. Пришёл лифтер, открыл дверь и мы выползли (именно выползли) из лифта. Никто и не подумал, что это мы по своей провинциальной безграмотности сломали лифт. Вечером из академии вернулся полковник Арсентьев, мы поужинали и он сказал:-
В академии открыт новый факультет, на котором будут готовить специалистов по программированию.

Что это такое он толком не понимает, но чувствует, что за этим стоит большое будущее и его нам совет держать путь на второй факультет на специальность Программирование. Но если младшему Арсентьеву как золотому медалисту требовалось только его желание, то мне еще предстояло сдать экзамены.
Через три дня я прихожу в академию и начинаю искать приёмную начальника II факультета. Заблудиться в коридорах академии не составляет труда. И тут навстречу мне идет курсант в повседневной форме, сапоги блестят, форма отутюжена и самое главное с суворовским знаком. Мне показалось, что этот курсант учится здесь уже не первый год и я обратился к нему за помощью, спросив, куда и как пройти. Это сейчас я сразу вспоминаю Фросю Бурлакову из кинофильма Доживём до понедельника, а тогда этот курсант всё уверенно мне рассказал и показал и мы расстались. Каково же было моё удивление, когда на письменном экзамене по математике (я уже по традиции собирался сдавать работу и выходить из аудитории) меня кто-то потрогал сзади по плечу. Я оглянулся и увидел того курсанта, который так толково мне всё объяснил. Он меня попросил не сдавать работу, не уходить и помочь решить его задачу. Я выполнил его просьбу. Николай Гудим (на фотографии он слева), именно так его звали, в итоге тоже поступил в академию:



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



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



IV. Послесловие к первой части


После окончания академии наши пути с Колей Гудимом разошлись. Но спустя шесть лет, после того как я послужил в ГРУ (так или иначе, но я следовал своей мечте), защитил в 1982 году диссертацию по системам управления распределёнными базами данных в той же Дзержинке, мы с ним встретились в 4-м Центральном научно-исследовательском институте Министерства Обороны (4 ЦНИИ МО). Но об этом речь пойдет в следующей части:



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

USB over IP удалённое администрирование

21.06.2021 16:11:25 | Автор: admin

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

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

Работа в тихом городке

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

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

Буквально за пару недель я обзавёлся первыми клиентами небольшими компаниями-мелкооптовиками. В штате 10-50 работников, главбух на аутсорсе, сервер с 1С и одним общим для всех каталогом. Почту используют бесплатную, вопросами ИБ заморачиваются по минимуму. В-общем, достаточно типичный для нашей страны мелкий бизнес.

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

Токены головная боль

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

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

Всё действительно сложно

Сначала задача показалась мне простой. Технология USB over IP существует достаточно давно все токены подключены к одному устройству, а сотрудники работают с ними, как с локальными. Ничего не теряется, поскольку не покидает пределов офиса.

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

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

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

Поскольку айтишников на фултайме ни в одной конторе не было, самодельные и софтовые решения исключались. Делать, настраивать и чинить некому.

По масштабированию прекрасно подходят облака. Но цены у них откровенно кусаются. Например, сервис FlexiHub обойдётся заказчику более 10 тыс. рублей в месяц за 5 ключей, не считая стоимости хаба. И это без гарантий совместимости.

Но самое главное сервисы требуют регулярной своевременной оплаты. У небольшой компании с этим могут быть проблемы. У неё не всегда есть возможность даже зарплаты сотрудникам заплатить вовремя. Задержка в неделю-другую дело обыкновенное.

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

Если ориентироваться на мировые бренды, то надо брать Digi AnywhereUSB. За 2 USB-порта больше 20 тыс. рублей, за 14 портов в районе 150 тыс. рублей. Для небольших компаний это явно дорого.

Конечная остановка USB over IP концентратор

Перебирая варианты я пришёл к отечественному аппаратно-программному решению DistKontrolUSB. На нём и остановился. Причин этому несколько.

Прежде всего цена. За концентратор на 4 порта мой мелкий клиент заплатит 26 тыс. рублей с хвостиком, а более крупным придётся выложить около 69 тыс. рублей, но за 16 портов. Дешевле западного аналога в два раза.

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

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

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

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

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

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

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

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

В настройках USB over IP концентратора было сформировано автоматическое задание, по которому устройство отключается в заданное время. А чтобы директор не волновался и спал спокойно он получает уведомление о выполнении на электронную почту.

Итоги

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

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

Например, дневная задержка в оплате счёта на один миллион стоит от 100 до 1000 рублей в зависимости от договора. С отчётностью ещё хуже 5% от суммы налога. А это уже несколько тысяч даже для небольшой фирмочки. Причём, только прямого ущерба о каких-то сорвавшихся сделках я даже не говорю.

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

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

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

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

Подробнее..

Идеальный инструмент для создания прогрессивных веб-приложений или Все, что вы хотели знать о Workbox. Часть 2

21.06.2021 12:17:59 | Автор: admin

image


Что такое Workbox?


Workbox (далее WB) это библиотека (точнее, набор библиотек), основной целью которой является "предоставление лучших практик и избавление от шаблонного кода при работе с сервис-воркерами" (далее СВ).


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



WB предоставляет следующие возможности:


  • предварительное кэширование
  • кэширование во время выполнения
  • стратегии (кэширования)
  • обработка (перехват сетевых) запросов
  • фоновая синхронизация
  • помощь в отладке

Это вторая часть руководства. Вот ссылка на первую часть.


Модули, предоставляемые WB


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


  • workbox-background-sync: фоновая синхронизация, позволяющая выполнять сетевые запросы в режиме офлайн
  • workbox-broadcast-update: отправка уведомлений об обновлении кэша (через Broadcast Channel API)
  • workbox-cacheable-response: фильтрация кэшируемых запросов на основе статус-кодов или заголовков ответов
  • workbox-core: изменение уровня логгирования и названий кэша. Содержит общий код, используемый другими модулями
  • workbox-expiration: установка лимита записей в кэше и времени жизни сохраненных ресурсов
  • workbox-google-analytics: фиксация действий пользователей на странице в режиме офлайн
  • workbox-navigation-preload: предварительная загрузка запросов, связанных с навигацией
  • workbox-precaching: предварительное кэширование ресурсов и управление их обновлением
  • workbox-range-request: поддержка частичных ответов
  • workbox-recipes: общие паттерны использования WB
  • workbox-routing: обработка запросов с помощью встроенных стратегий кэширования или колбэков
  • workbox-strategies: стратегии кэширования во время выполнения, как правило, используемые совместно с workbox-routing
  • workbox-streams: формирование ответа на основе нескольких источников потоковой передачи данных
  • workbox-window: регистрация, управление обновлением и обработка событий жизненного цикла СВ

workbox-background-sync


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


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


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


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


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


import { BackgroundSyncPlugin } from 'workbox-background-sync'import { registerRoute } from 'workbox-routing'import { NetworkOnly } from 'workbox-strategies'const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {  maxRetentionTime: 24 * 60, // Попытка выполнения повторного запроса будет выполнена в течение 24 часов (в минутах)})registerRoute(  /\/api\/.*\/*.json/,  new NetworkOnly({    plugins: [bgSyncPlugin],  }),  'POST')

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


Рассматриваемый модуль предоставляет класс Queue, который, после инстанцирования, может использоваться для хранения провалившихся запросов. Такие запросы записываются в IndexedDB и извлекаются из нее при восстановлении соединения.


Создание очереди


import { Queue } from 'workbox-background-sync'const queue = new Queue('myQueueName') // название очереди должно быть уникальным

Название очереди используется как часть названия "тега", который получает register() глобального SyncManager. Оно также используется как название "объектного хранилища" IndexedDB.


Добавление запроса в очередь


import { Queue } from 'workbox-background-sync'const queue = new Queue('myQueueName')self.addEventListener('fetch', (event) => {  // Клонируем запрос для безопасного чтения  // при добавлении в очередь  const promiseChain = fetch(event.request.clone()).catch((err) => {    return queue.pushRequest({ request: event.request })  })  event.waitUntil(promiseChain)})

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


workbox-cacheable-response


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


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


Кэширование на основе статус-кода


import { registerRoute } from 'workbox-routing'import { CacheFirst } from 'workbox-strategies'import { CacheableResponsePlugin } from 'workbox-cacheable-response'registerRoute(  ({ url }) =>    url.origin === 'https://example.com' && url.pathname.startsWith('/images/'),  new CacheFirst({    cacheName: 'image-cache',    plugins: [      new CacheableResponsePlugin({        statuses: [0, 200]      })    ]  }))

Данная настройка указывает WB кэшировать любые ответы со статусом 0 или 200 при обработке запросов к https://example.com.


Кэширование на основе заголовка


import { registerRoute } from 'workbox-routing'import { StaleWhileRevalidate } from 'workbox-strategies'import { CacheableResponsePlugin } from 'workbox-cacheable-response'registerRoute(  ({ url }) => url.pathname.startsWith('/path/to/api/'),  new StaleWhileRevalidate({    cacheName: 'api-cache',    plugins: [      new CacheableResponsePlugin({        headers: {          'X-Is-Cacheable': 'true'        }      })    ]  }))

При обработке ответов на запросы к URL, начинающемуся с /path/to/api/, проверяется, присутствует ли в ответе заголовок X-Is-Cacheable (который добавляется сервером). Если заголовок присутствует и имеет значение true, такой ответ кэшируется.


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


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


import { registerRoute } from 'workbox-routing'import { StaleWhileRevalidate } from 'workbox-strategies'import { CacheableResponsePlugin } from 'workbox-cacheable-response'registerRoute(  ({ url }) => url.pathname.startsWith('/path/to/api/'),  new StaleWhileRevalidate({    cacheName: 'api-cache',    plugins: [      new CacheableResponsePlugin({        statuses: [200, 404],        headers: {          'X-Is-Cacheable': 'true'        }      })    ]  }))

При использовании встроенной стратегии без явного определения cacheableResponse.CacheableResponsePlugin, для проверки валидности ответа используются следющие критерии:


  • staleWhileRevalidate и networkFirst: ответы со статусом 0 (непрозрачные ответы) и 200 считаются валидными
  • cacheFirst: только ответы со статусом 200 считаются валидными

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


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


Для определения логики кэширования за пределами стратегии можно использовать класс CacheableResponse:


import { CacheableResponse } from 'workbox-cacheable-response'const cacheable = new CacheableResponse({  statuses: [0, 200],  headers: {    'X-Is-Cacheable': 'true'  }})const response = await fetch('/path/to/api')if (cacheable.isResponseCacheable(response)) {  const cache = await caches.open('api-cache')  cache.put(response.url, response)} else {  // Ответ не может быть кэширован}

workbox-expiration


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


Ограничение количества записей в кэше


import { registerRoute } from 'workbox-routing'import { CacheFirst } from 'workbox-strategies'import { ExpirationPlugin } from 'workbox-expiration'registerRoute(  ({ request }) => request.destination === 'image',  new CacheFirst({    cacheName: 'image-cache',    plugins: [      new ExpirationPlugin({        // ограничиваем количество записей в кэше        maxEntries: 20      })    ]  }))

При достижении лимита удаляются самые старые записи.


Ограничение времени хранения ресурсов в кэше


import { registerRoute } from 'workbox-routing'import { CacheFirst } from 'workbox-strategies'import { ExpirationPlugin } from 'workbox-expiration'registerRoute(  ({ request }) => request.destination === 'image',  new CacheFirst({    cacheName: 'image-cache',    plugins: [      new ExpirationPlugin({        // ограничиваем время хранения ресурсов в кэше        maxAgeSeconds: 24 * 60 * 60      })    ]  }))

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


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


Класс CacheExpiration позволяет отделять логику ограничения от других модулей. Для установки ограничений создается экземпляр названного класса:


import { CacheExpiration } from 'workbox-expiration'const cacheName = 'my-cache'const expirationManager = new CacheExpiration(cacheName, {  maxAgeSeconds: 24 * 60 * 60,  maxEntries: 20})

Затем, при обновлении записи в кэше, вызывается метод updateTimestamp() для обновления "возраста" записи.


await openCache.put(request, response)await expirationManager.updateTimestamp(request.url)

Для проверки всех записей в кэше на предмет их соответствия установленным критериям вызывается метод expireEntries():


await expirationManager.expireEntries()

workbox-precaching


СВ позволяет записывать файлы в кэш во время установки. Это называется предварительным кэшированием, поскольку контент кэшируется перед использованием СВ.


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


WB предоставляет простой и понятный API для реализации этого паттерна и эффективной загрузки ресурсов.


При первом запуске приложения workbox-precaching "смотрит" на загружаемые ресурсы, удаляет дубликаты и регистрирует соответствующие события СВ для загрузки и хранения ресурсов. URL, которые содержат информацию о версии (версионную информацию) (например, хэш контента) используются в качестве ключей кэша без дополнительной модификации. К ключам кэша URL, которые не содержат такой информации, добавляется параметр строки запроса, представляющий хэш контента, генерируемый WB во время выполнения.


workbox-precaching делает все это при обработке события install СВ.


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


Новый СВ не будет использоваться для ответов на запросы до его активации. В событии activate workbox-precaching определяет кэшированные ресурсы, отсутствующие в новом списке URL, и удаляет их из кэша.


Обработка предварительно кэшированных ответов


Вызов precacheAndRoute() или addRoute() создает маршрутизатор, который определяет совпадения запросов с предварительно кэшированными URL.


В этом маршрутизаторе используется стратегия "сначала кэш".


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


Список предварительно кэшируемых ресурсов


workbox-precaching ожидает получения массива объектов со свойствами url и revision. Данный массив иногда называют "манифестом предварительного кэширования":


import { precacheAndRoute } from 'workbox-precaching'precacheAndRoute([  { url: '/index.html', revision: '383676' },  { url: '/styles/app.0c9a31.css', revision: null },  { url: '/scripts/app.0d5770.js', revision: null },  // другие записи])

Свойства revision второго и третьего объектов имеют значения null. Это объясняется тем, что версионная информация этих объектов является частью значений их свойств url.


В отличие от JavaScript и CSS URL, указывающие на HTML-файлы, как правило, не включают в себя версионную информацию по той причине, что ссылки на такие файлы должны быть статическими.


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


Обратите внимание: для генерации списка предварительно кэшируемых ресурсов следует использовать один из встроенных инструментов WB: workbox-build, workbox-webpack-plugin или workbox-cli. Создавать такой список вручную очень плохая идея.


Автоматическая обработка входящих запросов


При поиске совпадения входящего запроса с кэшированным ресурсом workbox-precaching автоматически выполняет некоторые манипуляции с URL.


Например, запрос к / оценивается как запрос к index.html.


Игнорирование параметров строки запроса


По умолчанию игнорируются параметры поиска, которые начинаются с utm_ или точно совпадают с fbclid. Это означает, что запрос к /about.html?utm_campaign=abcd оценивается как запрос к /about.html.


Игнорируемые параметры указываются в настройке ignoreURLParametersMatching:


import { precacheAndRoute } from 'workbox-precaching'precacheAndRoute(  [    { url: '/index.html', revision: '383676' },    { url: '/styles/app.0c9a31.css', revision: null },    { url: '/scripts/app.0d5770.js', revision: null }  ],  {    // Игнорируем все параметры    ignoreURLParametersMatching: [/.*/]  })

Основной файл директории


По умолчанию основным файлом директории считается index.html. Именно поэтому запросы к / оцениваются как запросы к /index.html. Это поведение можно изменить с помощью настройки directoryIndex:


import { precacheAndRoute } from 'workbox-precaching'precacheAndRoute(  [    { url: '/index.html', revision: '383676' },    { url: '/styles/app.0c9a31.css', revision: null },    { url: '/scripts/app.0d5770.js', revision: null },  ],  {    directoryIndex: null  })

"Чистые" URL


По умолчанию к запросу добавляется расширение .html. Например, запрос к /about оценивается как /about.html. Это можно изменить с помощью настройки cleanUrls:


import { precacheAndRoute } from 'workbox-precaching'precacheAndRoute([{ url: '/about.html', revision: 'b79cd4' }], {  cleanUrls: false})

Кастомные манипуляции


Настройка urlManipulation позволяет кастомизировать логику определения совпадений. Эта функция должна возвращать массив возможных совпадений:


import { precacheAndRoute } from 'workbox-precaching'precacheAndRoute(  [    { url: '/index.html', revision: '383676' },    { url: '/styles/app.0c9a31.css', revision: null },    { url: '/scripts/app.0d5770.js', revision: null }  ],  {    urlManipulation: ({ url }) => {      // Логика определения совпадений      return [alteredUrlOption1, alteredUrlOption2]    }  })

workbox-routing


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


workbox-routing это модуль, позволяющий "связывать" поступающие запросы с функциями, формирующими на них ответы.


При отправке сетевого запроса возникает событие fetch, которое регистрирует СВ для формирования ответа на основе маршрутизаторов и обработчиков.


Обратите внимание на следующее:


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

Определение совпадений и обработка запросов


В WB "роут" это две функции: функция "определения совпадения" и функция "обработки запроса".


WB предоставляет некоторые утилиты для помощи в реализации названных функций.


Функция определения совпадения принимает ExtendableEvent, Request и объект URL. Возврат истинного значения из этой функции означает совпадение. Например, вот пример определения совпадения с конкретным URL:


const matchCb = ({ url, request, event }) => {  return (url.pathname === '/special/url')}

Функция обработки запроса принимает такие же параметры + аргумент value, который имеет значение, возвращаемое из первой функции:


const handlerCb = async ({ url, request, event, params }) => {  const response = await fetch(request)  const responseBody = await response.text()  return new Response(`${responseBody} <!-- Глядите-ка! Новый контент. -->`, {    headers: response.headers  })}

Обработчик должен возвращать промис, разрешающийся Response.


Регистрация колбэков выглядит следующим образом:


import { registerRoute } from 'workbox-routing'registerRoute(matchCb, handlerCb)

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


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


import { registerRoute } from 'workbox-routing'import { StaleWhileRevalidate } from 'workbox-strategies'registerRoute(  matchCb,  new StaleWhileRevalidate())

Определение совпадений с помощью регулярного выражения


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


import { registerRoute } from 'workbox-routing'registerRoute(  new RegExp('/styles/.*\\.css'),  handlerCb)

Для запросов из одного источника данная "регулярка" будет регистрировать совпадения для следующих URL:



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



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


new RegExp('https://cdn\\.third-party-site\\.com.*/styles/.*\\.css')

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


Роут для навигации


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


import { createHandlerBoundToURL } from 'workbox-precaching'import { NavigationRoute, registerRoute } from 'workbox-routing'// Предположим, что страница `/app-shell.html` была предварительно кэшированаconst handler = createHandlerBoundToURL('/app-shell.html')const navigationRoute = new NavigationRoute(handler)registerRoute(navigationRoute)

При посещении пользователем вашего сайта, запрос на получение страницы будет считаться навигационным, следовательно, ответом на него будет кэшированная страница /app-shell.html.


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


import { createHandlerBoundToURL } from 'workbox-precaching'import { NavigationRoute, registerRoute } from 'workbox-routing'const handler = createHandlerBoundToURL('/app-shell.html')const navigationRoute = new NavigationRoute(handler, {  allowlist: [    new RegExp('/blog/')  ],  denylist: [    new RegExp('/blog/restricted/')  ]})registerRoute(navigationRoute)

Обратите внимание, что denyList имеет приоритет перед allowList.


Обработчик по умолчанию


import { setDefaultHandler } from 'workbox-routing'setDefaultHandler(({ url, event, params }) => {  // ...})

Обработчик ошибок


import { setCatchHandler } from 'workbox-routing'setCatchHandler(({ url, event, params }) => {  // ...})

Обработка не-GET-запросов


import { registerRoute } from 'workbox-routing'registerRoute(  matchCb,  handlerCb,  // определяем метод  'POST')registerRoute(  new RegExp('/api/.*\\.json'),  handlerCb,  // определяем метод  'POST')

workbox-strategies


Стратегия кэширования это паттерн, определяющий порядок формирования СВ ответа на запрос (после возникновения события fetch).


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


Stale-While-Revalidate


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


import { registerRoute } from 'workbox-routing'import { StaleWhileRevalidate } from 'workbox-strategies'registerRoute(  ({url}) => url.pathname.startsWith('/images/avatars/'),  new StaleWhileRevalidate())

Cache-Fisrt


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


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


import { registerRoute } from 'workbox-routing'import { CacheFirst } from 'workbox-strategies'registerRoute(  ({ request }) => request.destination === 'style',  new CacheFirst())

Network-First


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


import { registerRoute } from 'workbox-routing'import { NetworkFirst } from 'workbox-strategies'registerRoute(  ({ url }) => url.pathname.startsWith('/social-timeline/'),  new NetworkFirst())

Network-Only


import { registerRoute } from 'workbox-routing'import { NetworkOnly } from 'workbox-strategies'registerRoute(  ({url}) => url.pathname.startsWith('/admin/'),  new NetworkOnly())

Cache-Only


import { registerRoute } from 'workbox-routing'import { CacheOnly } from 'workbox-strategies'registerRoute(  ({ url }) => url.pathname.startsWith('/app/v2/'),  new CacheOnly())

Настройка стратегии


Каждая стратегия позволяет кастомизировать:


  • название кэша
  • лимит записей в кэше и время их "жизни"
  • плагины

Название кэша


import { registerRoute } from 'workbox-routing'import { CacheFirst } from 'workbox-strategies'registerRoute(  ({ request }) => request.destination === 'image',  new CacheFirst({    cacheName: 'image-cache',  }))

Плагины


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


  • workbox-background-sync
  • workbox-broadcast-update
  • workbox-cacheable-response
  • workbox-expiration
  • workbox-range-requests

import { registerRoute } from 'workbox-routing'import { CacheFirst } from 'workbox-strategies'import { ExpirationPlugin } from 'workbox-expiration'registerRoute(  ({ request }) => request.destination === 'image',  new CacheFirst({    cacheName: 'image-cache',    plugins: [      new ExpirationPlugin({        // Хранить ресурсы в течение недели        maxAgeSeconds: 7 * 24 * 60 * 60,        // Хранить до 10 ресурсов        maxEntries: 10      })    ]  }))

WB также позволяет создавать и использовать собственные стратегии.


workbox-recipies


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


Рецепты


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


Резервный контент


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


По умолчанию резервная страница должна иметь название offline.html.


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


Рецепт


import { offlineFallback } from 'workbox-recipes'import { setDefaultHandler } from 'workbox-routing'import { NetworkOnly } from 'workbox-strategies'setDefaultHandler(  new NetworkOnly())offlineFallback()

Паттерн


import { setCatchHandler, setDefaultHandler } from 'workbox-routing'import { NetworkOnly } from 'workbox-strategies'const pageFallback = 'offline.html'const imageFallback = falseconst fontFallback = falsesetDefaultHandler(  new NetworkOnly())self.addEventListener('install', event => {  const files = [pageFallback]  if (imageFallback) {    files.push(imageFallback)  }  if (fontFallback) {    files.push(fontFallback)  }  event.waitUntil(self.caches.open('workbox-offline-fallbacks').then(cache => cache.addAll(files)))})const handler = async (options) => {  const dest = options.request.destination  const cache = await self.caches.open('workbox-offline-fallbacks')  if (dest === 'document') {    return (await cache.match(pageFallback)) || Response.error()  }  if (dest === 'image' && imageFallback !== false) {    return (await cache.match(imageFallback)) || Response.error()  }  if (dest === 'font' && fontFallback !== false) {    return (await cache.match(fontFallback)) || Response.error()  }  return Response.error()}setCatchHandler(handler)

Подготовка кэша


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


Рецепт


import { warmStrategyCache } from 'workbox-recipes'import { CacheFirst } from 'workbox-strategies'// Здесь может испоьзоваться любая стратегияconst strategy = new CacheFirst()const urls = [  '/offline.html']warmStrategyCache({urls, strategy})

Паттерн


import { CacheFirst } from 'workbox-strategies'// Здесь может использоваться любая стратегияconst strategy = new CacheFirst()const urls = [  '/offline.html',]self.addEventListener('install', event => {  // `handleAll` возвращает два промиса, второй промис разрешается после добавления всех элементов в кэш  const done = urls.map(path => strategy.handleAll({    event,    request: new Request(path),  })[1])  event.waitUntil(Promise.all(done))})

Кэширование страницы


Данный рецепт позволяет СВ отвечать на запрос на получение HTML-страницы с помощью стратегии "сначала сеть". При этом, СВ оптимизируется таким образом, что в случае отсутствия подключения к сети, возвращает ответ из кэша менее чем за 4 секунды. По умолчанию запрос к сети выполняется в течение 3 секунд. Настройка warmCache позволяет подготовить ("разогреть") кэш к использованию.


Рецепт


import { pageCache } from 'workbox-recipes'pageCache()

Паттерн


import { registerRoute } from 'workbox-routing'import { NetworkFirst } from 'workbox-strategies'import { CacheableResponsePlugin } from 'workbox-cacheable-response'const cacheName = 'pages'const matchCallback = ({ request }) => request.mode === 'navigate'const networkTimeoutSeconds = 3registerRoute(  matchCallback,  new NetworkFirst({    networkTimeoutSeconds,    cacheName,    plugins: [      new CacheableResponsePlugin({        statuses: [0, 200]      })    ]  }))

Кэширование статических ресурсов


Данный рецепт позволяет СВ отвечать на запросы на получение статических ресурсов, таких как JavaScript, CSS и веб-воркеры с помощью стратегии "считается устаревшим после запроса" (ответ возвращается из кэша, после чего кэш обновляется). Поддерживается разогрев кэша (warmCache).


Рецепт


import { staticResourceCache } from 'workbox-recipes'staticResourceCache()

Паттерн


import { registerRoute } from 'workbox-routing'import { StaleWhileRevalidate } from 'workbox-strategies'import { CacheableResponsePlugin } from 'workbox-cacheable-response'const cacheName = 'static-resources'const matchCallback = ({ request }) =>  // CSS  request.destination === 'style' ||  // JavaScript  request.destination === 'script' ||  // веб-воркеры  request.destination === 'worker'registerRoute(  matchCallback,  new StaleWhileRevalidate({    cacheName,    plugins: [      new CacheableResponsePlugin({        statuses: [0, 200]      })    ]  }))

Кэширование изображений


Данный рецепт позволяет СВ отвечать на запросы на получение изображений с помощью стратегии "сначала кэш". По умолчанию кэшируется до 60 изображений в течение 30 дней. Поддерживается разогрев кэша.


Рецепт


import { imageCache } from 'workbox-recipes'imageCache()

Паттерн


import { registerRoute } from 'workbox-routing'import { CacheFirst } from 'workbox-strategies'import { CacheableResponsePlugin } from 'workbox-cacheable-response'import { ExpirationPlugin } from 'workbox-expiration'const cacheName = 'images'const matchCallback = ({ request }) => request.destination === 'image'const maxAgeSeconds = 30 * 24 * 60 * 60const maxEntries = 60registerRoute(  matchCallback,  new CacheFirst({    cacheName,    plugins: [      new CacheableResponsePlugin({        statuses: [0, 200]      }),      new ExpirationPlugin({        maxEntries,        maxAgeSeconds      })    ]  }))

Кэширование гугл-шрифтов


Данный рецепт кэширует таблицу стилей для шрифтов с помощью стратегии "считается устаревшим после запроса" и сами шрифты с помощью стратегии "сначала кэш". По умолчанию кэшируется до 30 шрифтов в течение 1 года.


Рецепт


import { googleFontsCache } from 'workbox-recipes'googleFontsCache()

Паттерн


import { registerRoute } from 'workbox-routing'import { StaleWhileRevalidate } from 'workbox-strategies'import { CacheFirst } from 'workbox-strategies'import { CacheableResponsePlugin } from 'workbox-cacheable-response'import { ExpirationPlugin } from 'workbox-expiration'const sheetCacheName = 'google-fonts-stylesheets'const fontCacheName = 'google-fonts-webfonts'const maxAgeSeconds = 60 * 60 * 24 * 365const maxEntries = 30registerRoute(  ({ url }) => url.origin === 'https://fonts.googleapis.com',  new StaleWhileRevalidate({    cacheName: sheetCacheName  }))// Кэшируем до 30 шрифтов с помощью стратегии "сначала кэш" и храним кэш в течение 1 годаregisterRoute(  ({ url }) => url.origin === 'https://fonts.gstatic.com',  new CacheFirst({    cacheName: fontCacheName,    plugins: [      new CacheableResponsePlugin({        statuses: [0, 200],      }),      new ExpirationPlugin({        maxAgeSeconds,        maxEntries      })    ]  }))

Быстрое использование


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


import {  pageCache,  imageCache,  staticResourceCache,  googleFontsCache,  offlineFallback} from 'workbox-recipes'pageCache()googleFontsCache()staticResourceCache()imageCache()offlineFallback()

workbox-window


Данный модуль выполняется в контексте window. Его основными задачами является следующее:


  • упрощение процесса регистрации и обновления СВ в наиболее подходящие для этого моменты жизненного цикла СВ
  • помощь в обнаружении наиболее распространенных ошибок, совершаемых разработчиками при работе с СВ
  • облегчение коммуникации между кодом СВ и кодом, запускаемым в window

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


<script type="module">import { Workbox } from 'https://storage.googleapis.com/workbox-cdn/releases/6.1.5/workbox-window.prod.mjs'if ('serviceWorker' in navigator) {  const wb = new Workbox('/sw.js')  wb.register()}</script>

Использование сборщика модулей


Установка


yarn add workbox-window# илиnpm i workbox-window

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


import { Workbox } from 'workbox-window'if ('serviceWorker' in navigator) {  const wb = new Workbox('/sw.js')  wb.register()}

Примеры


Регистрация СВ и уведомление пользователя о его активации


const wb = new Workbox('/sw.js')wb.addEventListener('activated', (event) => {  // `event.isUpdate` будет иметь значение `true`, если другая версия СВ  // управляет страницей при регистрации данной версии  if (!event.isUpdate) {    console.log('СВ был активирован в первый раз!')    // Если СВ настроен для предварительного кэширования ресурсов,    // эти ресурсы могут быть получены здесь  }})// Региструем СВ после добавления обработчиков событийwb.register()

Уведомление пользователя о том, что СВ был установлен, но ожидает активации


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


const wb = new Workbox('/sw.js')wb.addEventListener('waiting', (event) => {  console.log(    `Новый СВ был установлен, но он не может быть активирован, пока все вкладки браузера не будут закрыты или перезагружены`  )})wb.register()

Уведомление пользователя об обновлении кэша


Модуль workbox-broadcast-update позволяет информировать пользователей об обновлении контента. Для получения этой информации в браузере используется событие message с типом CACHE_UPDATED:


const wb = new Workbox('/sw.js')wb.addEventListener('message', (event) => {  if (event.data.type === 'CACHE_UPDATED') {    const { updatedURL } = event.data.payload    console.log(`Доступна новая версия ${updatedURL}!`)  }})wb.register()

Отправка СВ списка URL для кэширования


В некоторых приложениях имеет смысл кэшировать только те ресурсы, которые используются посещенной пользователем страницей. Модуль workbox-routing принимает список URL и кэширует их на основе правил, определенных в маршрутизаторе.


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


const wb = new Workbox('/sw.js')wb.addEventListener('activated', (event) => {  // Получаем `URL` текущей страницы + все загружаемые страницей ресурсы  const urlsToCache = [    location.href,    ...performance      .getEntriesByType('resource')      .map((r) => r.name)  ]  // Передаем этот список СВ  wb.messageSW({    type: 'CACHE_URLS',    payload: { urlsToCache }  })})wb.register()

Практика


В этом разделе представлено несколько сниппетов, которые можно использовать в приложениях "как есть", а также краткий обзор готовых решений для разработки PWA, предоставляемых такими фреймворками для фронтенда, как React и Vue.


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


О том, что такое манифест можно почитать здесь, здесь и здесь.


Как правило, манифест (и СВ) размещаются на верхнем уровне (в корневой директории) проекта. Манифест может иметь расширение .json или .webmanifest (лучше использовать первый вариант).


Манифест


{  "name": "Название приложения",  "short_name": "Краткое название (будет указано под иконкой приложения при его установке)",  "scope": "/", // зона контроля СВ, разные страницы могут обслуживаться разными СВ  "start_url": ".", // начальный URL, как правило, директория, в которой находится index.html, в котором регистрируется СВ  "display": "standalone",  "orientation": "portrait",  "background_color": "#f0f0f0",  "theme_color": "#3c3c3c",  "description": "Описание приложения",  // этих иконок должно быть достаточно для большинства девайсов  "icons": [    {      "src": "./icons/64x64.png",      "sizes": "64x64",      "type": "image/png"    },    {      "src": "./icons/128x128.png",      "sizes": "128x128",      "type": "image/png"    },    {      "src": "./icons/256x256.png",      "sizes": "256x256",      "type": "image/png",      "purpose": "any maskable"    },    {      "src": "./icons/512x512.png",      "sizes": "512x512",      "type": "image/png"    }  ],  "serviceworker": {    "src": "./service-worker.js" // ссылка на файл с кодом СВ  }}

Ручная реализация СВ, использующего стратегию "сначала кэш"


// Название кэша// используется для обновления кэша// в данном случае, для этого достаточно изменить версию кэша - my-cache-v2const CACHE_NAME = 'my-cache-v1'// Критические для работы приложения ресурсыconst ASSETS_TO_CACHE = [  './index.html',  './offline.html',  './style.css',  './script.js']// Предварительное кэширование ресурсов, выполняемое во время установки СВself.addEventListener('install', (e) => {  e.waitUntil(    caches      .open(CACHE_NAME)      .then((cache) => cache.addAll(ASSETS_TO_CACHE))  )  self.skipWaiting()})// Удаление старого кэша во время активации нового СВself.addEventListener('activate', (e) => {  e.waitUntil(    caches      .keys()      .then((keys) =>        Promise.all(          keys.map((key) => {            if (key !== CACHE_NAME) {              return caches.delete(key)            }          })        )      )  )  self.clients.claim()})// Обработка сетевых запросов/*  1. Выполняется поиск совпадения  2. Если в кэше имеется ответ, он возвращается  3. Если ответа в кэше нет, выполняется сетевой запрос  4. Ответ на сетевой запрос кэшируется и возвращается  5. В кэш записываются только ответы на `GET-запросы`  6. При возникновении ошибки возвращается резервная страница*/self.addEventListener('fetch', (e) => {  e.respondWith(    caches      .match(e.request)      .then((response) =>          response || fetch(e.request)            .then((response) =>              caches.open(CACHE_NAME)                .then((cache) => {                  if (e.request.method === 'GET') {                    cache.put(e.request, response.clone())                  }                  return response                })          )      )      .catch(() => caches.match('./offline.html'))  )})

Конфигурация Webpack


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


Предположим, что в нашем проекте имеется 4 директории:


  • public директория со статическими ресурсами, включая index.html, manifest.json и sw-reg.js
  • src директория с кодом приложения
  • build директория для сборки
  • config директория с настройками, включая .env, paths.js и webpack.config.js

В файле public/sw-reg.js содержится код регистрации СВ:


if ('serviceWorker' in navigator) {  window.addEventListener('load', () => {    navigator.serviceWorker      .register('./service-worker.js')      .then((reg) => {        console.log('СВ зарегистрирован: ', reg)      })      .catch((err) => {        console.error('Регистрация СВ провалилась: ', err)      })  })}

В файле config/paths.js осуществляется экспорт путей к директориям с файлами приложения:


const path = require('path')module.exports = {  public: path.resolve(__dirname, '../public'),  src: path.resolve(__dirname, '../src'),  build: path.resolve(__dirname, '../build')}

Допустим, что в качестве фронтенд-фреймворка мы используем React, а также, что в проекте используется TypeScript. Тогда файл webpack.config.js будет выглядеть следующим образом:


const webpack = require('webpack')// импортируем пути к директориям с файлами приложенияconst paths = require('../paths')// плагин для копирования статических ресурсов в директорию сборкиconst CopyWebpackPlugin = require('copy-webpack-plugin')// плагин для обработки `index.html` - вставки ссылок на стили и скрипты, добавления метаданных и т.д.const HtmlWebpackPlugin = require('html-webpack-plugin')// плагин для обеспечения прямого доступа к переменным среды окруженияconst Dotenv = require('dotenv-webpack')// плагин для минификации и удаления неиспользуемого CSSconst MiniCssExtractPlugin = require('mini-css-extract-plugin')// плагин для сжатия изображенийconst ImageminPlugin = require('imagemin-webpack-plugin').default// плагин для добавления блоков кодаconst AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin')// Плагин для генерации СВconst { GenerateSW } = require('workbox-webpack-plugin')// настройки Babelconst babelLoader = {  loader: 'babel-loader',  options: {    presets: ['@babel/preset-env', '@babel/preset-react'],    plugins: [      '@babel/plugin-proposal-class-properties',      '@babel/plugin-syntax-dynamic-import',      '@babel/plugin-transform-runtime'    ]  }}module.exports = {  // режим сборки  mode: 'production',  // входная точка  entry: {    index: {      import: `${paths.src}/index.js`,      dependOn: ['react', 'helpers']    },    react: ['react', 'react-dom'],    helpers: ['immer', 'nanoid']  },  // отключаем логгирование  devtool: false,  // результат сборки  output: {    // директория сборки    path: paths.build,    // название файла    filename: 'js/[name].[contenthash].bundle.js',    publicPath: './',    // очистка директории при каждой сборке    clean: true,    crossOriginLoading: 'anonymous',    module: true  },  resolve: {    alias: {      '@': `${paths.src}/components`    },    extensions: ['.mjs', '.js', '.jsx', '.ts', '.tsx', '.json']  },  experiments: {    topLevelAwait: true,    outputModule: true  },  module: {    rules: [      // JavaScript, React      {        test: /\.m?jsx?$/i,        exclude: /node_modules/,        use: babelLoader      },      // TypeScript      {        test: /.tsx?$/i,        exclude: /node_modules/,        use: [babelLoader, 'ts-loader']      },      // CSS, SASS      {        test: /\.(c|sa|sc)ss$/i,        use: [          'style-loader',          {            loader: 'css-loader',            options: { importLoaders: 1 }          },          'sass-loader'        ]      },      // статические ресурсы - изображения и шрифты      {        test: /\.(jpe?g|png|gif|svg|eot|ttf|woff2?)$/i,        type: 'asset'      },      {        test: /\.(c|sa|sc)ss$/i,        use: [          MiniCssExtractPlugin.loader,          {            loader: 'css-loader',            options: { importLoaders: 1 }          },          'sass-loader'        ]      }    ]  },  plugins: [    new CopyWebpackPlugin({      patterns: [        {          from: `${paths.public}/assets`        }      ]    }),    new HtmlWebpackPlugin({      template: `${paths.public}/index.html`    }),    // это позволяет импортировать реакт только один раз    new webpack.ProvidePlugin({      React: 'react'    }),    new Dotenv({      path: './config/.env'    }),    new MiniCssExtractPlugin({      filename: 'css/[name].[contenthash].css',      chunkFilename: '[id].css'    }),    new ImageminPlugin({      test: /\.(jpe?g|png|gif|svg)$/i    }),    // Добавляем код регистрации СВ в `index.html`    new AddAssetHtmlPlugin({ filepath: `${paths.public}/sw-reg.js` }),    // Генерируем СВ    new GenerateSW({      clientsClaim: true,      skipWaiting: true    })  ],  optimization: {    runtimeChunk: 'single'  },  performance: {    hints: 'warning',    maxEntrypointSize: 512000,    maxAssetSize: 512000  }}

Здесь вы найдете шпаргалку по настройке вебпака. Пример полной конфигурации вебпака для JS/React/TS-проекта можно посмотреть здесь.


React PWA


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


yarn create react-app my-app --template pwa# илиnpx create-react-app ...

Или, если речь идет о TypeScript-проекте:


yarn create react-app my-app --template pwa-typescript# илиnpx create-react-app ...

Кроме прочего, в директории src создаются файлы service-worker.ts и serviceWorkerRegister.ts (последний импортируется в index.tsx), а в директории public файл manifest.json.


Затем, перед сборкой проекта с помощью команды yarn build или npm run build, в файл src/index.tsx необходимо внести одно изменение:


// доserviceWorkerRegistration.unregister();// послеserviceWorkerRegistration.register();

Подробнее об этом можно прочитать здесь.


Vue PWA


С Vue дела обстоят еще проще.


Глобально устанавливаем vue-cli:


yarn global add @vue/cli# илиnpm i -g @vue/cli

Затем, при создании шаблона проекта с помощью команды vue create my-app, выбираем Manually select features и Progressive Web App (PWA) Support.


Кроме прочего, в директории src создается файл registerServiceWorker.ts, который импортируется в main.ts. Данный файл содержит ссылку на файл service-worker.js, который, как и manifest.json, автоматически создается при сборке проекта с помощью команды yarn build или npm run build. Разумеется, содержимое обоих файлов можно кастомизировать.

Подробнее..

История о том, как я иду к должности JS разработчика через обучение на курсах в Skillbox

21.06.2021 14:12:41 | Автор: admin

Как пришел я к тому чтобы вообще начать учить JS

В 2019 году, 1 сентября, в дождливый осенний день, я решил навсегда завязать с прошлым. Последние 5 лет работы менеджером не приносили удовольствия и не несли перспектив. Увольняюсь с должности менеджера вино-торговой компании, подумал я. И погружаюсь в программирование!

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

  • Angular.js;

  • Vue.js;

  • React.js;

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

Морской бой тестовое задание в ТензорМорской бой тестовое задание в Тензор

Мой первый купленный курс

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

Принимаю решение вложить 13 тысяч рублей в курсы по верстке сайтов. Стоит сказать что такую смешную сумму, мне пришлось просить разбить на 4 платежа по 3 250 рублей. Ибо в додо я делал 20 тысяч в месяц максимум.

Моя морда на работе в феврале 2020Моя морда на работе в феврале 2020

К тому моменту, я имел за спиной 1 2 кривых пет-проекта по верстке, но основ все еще не понимал до конца. На курсе познакомился с такими инструментами как: HTML, CSS Bootstrap, SASS Git, Gulp Autoprefixer, Pixel perfect, БЭМ JavaScript, Ajax, PHP

Нужно сказать что было крайне интересно и не сложно. Хорошая подача материала и трудолюбие сделали свое дело. Но почему-то дальше все мое продвижение встало мертвым грузом. Как будто я застрял и не знал как выбраться, как продолжить увеличивать знания?! Основные ошибки новичка (на моём опыте).

Ошибка 1 Не закреплял полученные знания

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

Ошибка 2 Дал слабину, расслабился

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

Ошибка 3 Начал искать новую информацию для изучения не имея четкого плана

Еще 3 месяца я читал, пытался кодить, изучал JavaScript. Но не по учебнику или по плану, а просто так, хаотично, без примеров и задач, чаще просто смотря видео. А без базы понять что такое prototype или методы перебора массивов было почти нереальной задачей.

Ошибка 4 Мало теории, еще меньше практики

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

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

Книга по JS для начинающихКнига по JS для начинающих

Вот я и на полпути к мечте! подумал про себя и начал искать работу снова

Редактирование резюме, вставка парочки кривых учебных проектов и подача на все вакансии в своем городе. Из 30 откликов 25 игноров, 3 отказа и 2 тестовых задания. Два тестовых задания были мне не по зубам и я честно признаться, сразу писал что-то типа:

Прошу меня простить, но я еще видимо не дорос до уровня чтобы выполнить этот тест и вернусь к Вам, как только у меня появится понимание как решать.

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

Олицетворения меня как трусаОлицетворения меня как труса

Я же поступал как удобно мне. Ведь я был вынужден где-то работать. У меня ребенок, кредиты, я как обычный среднестатистический человек устаю в течении дня и приношу домой копейки чтобы хватало на оплату еды, жилья и дешевых вещей. А тут вечером нужно еще позаниматься JavaScript + верстка, а лучше React поучить и всякие там видеоуроки посмотреть (обязательно с практикой). Одним словом не до тестовых заданий, особенно которые не знаешь даже как решать.

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

Сразу скажу это не реклама для Skillbox, это лично мое мнение

В моменте захотелось выбрать какой-то серьезный для себя вектор, мол, мало мне коротких курсов или самостоятельного обучения. Хочу связать себя с долгим и кропотливым трудом на года. Да и диплом об окончании скилов показался мне престижной бумагой. Размечтался что поеду в офис компании в Москву, буду защищать свой дипломный проект. А я такой опытный манагер, все презентую по красоте! Все будут аплодировать стоя и кричать:

Это junior с задатками team lead! Наш мальчик! Браво!.

Мой пыл спустя восемь месяцев подостыл, но я все еще фигачу и двигаюсь дальше. Кто знает, может я действительно поеду защищать диплом в МСК.

Несколько выводов для сомневающихся:

  • покупка курса в кредит (точнее в рассрочку) не сделала меня более мотивированным. Однако, у меня появился структурированный материал по стеку Frontend по которому я в свободное время мог теперь двигаться и не тратить время на поиск инфы;

  • общение с преподавателем не супер дружеское конечно, но присутствует. Если вы просите фидбек по примерам, задачам или домашней работе вы его получаете;

  • чат таких же сокурсников как вы, в телеграмм, где можно спросить, подсказать или просто увидеть, что сложно не только вам, или что кто-то уже впереди;

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

Моя шкала прогресса Моя шкала прогресса

Как лучше проходить курс на Skillbox по моему мнению

Сложно сказать однозначно. Типа так делай, а так не делай. Ведь все мы разные. Кто-то обладает 12 часами свободного времени в день и тонной мотивации. А кто-то только 1 час вечером и абсолютно без сил.

Но скажу следующее. Важно ежедневно, от 30 минут до 2 часов (хотя бы) заниматься каждый день.

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

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

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

  4. Фреймворк тут на ваше усмотрение какой выбрать. Главное начинайте освоение хотя бы после прохождения основ.

Представим что у вас 30 уроков в каждом разделе. При ежедневных вложениях по чуть-чуть, уже через 90 дней вы сможете сделать от 30% до 50%. А это всего 3 месяца. Еще 3 месяца и можно приступать к фреймворкам.

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

Мотивация на результатМотивация на результат

В процессе обучения мои амбиции росли и я вместе с ними.

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

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

Представьте, вам звонят днем, вы поднимаете трубку с незнакомого номера телефона, а там:
Добрый день, это HR компании войтиВайти, ваше резюме нам прислали из центра подбора персонала компании Skillbox, вас рекомендовали как разработчика и так далее.
Помню когда получил первый раз такой звонок, чуть не выпал в осадок. Хорошо стул был неподалеку. К сожалению, у меня не вышло устроиться пока что никуда.
НО отмечу, что я прошел 8 собеседований. Выполнил несколько тестовых заданий, вспотел на нескольких технических интервью. С вопросами про reduce, map, filter, работу с объектами и про жизненный цикл компонент (и массу чего еще).

Получил ссылки на книги которые лучше бы прочитать. Получил ссылки на источники которые лучше бы изучить.

Вот и фидбек. Получается я стал и стану еще опытнее и умнее. А получилось бы это если бы я ничего не делал. А просто пытался учиться самостоятельно? Не знаю.

Напишите в комментариях что вы думаете по этому поводу!?

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

Вот я и на Хабре, благодаря обучению и постоянному желанию поймать свою первую компанию за хвост и устроиться Junior разработчиком.
Здесь научился заполнять аккаунт таким образом, чтобы быть не привлекательным, а техничным. Смешно, конечно, когда смотря на резюме Senior разработчика, там написано только знание 2-3 технологий и нет волшебных слов, которые можно скопипастить себе в профиль.
Но главное писать то в чем ты точно разбираешься. Я так и сделал! Жаль что Junior специалистов ищут крайне редко, в наше время. Сейчас скорее возможно устроиться middle. Но это другая тема для следующего разговора.

В итоге мое резюме выглядит следующим образом:

Резюме мое первая страничкаРезюме мое первая страничка

Как это все организовало меня как личность и изменило в лучшую сторону

В итоге, друзья, две попытки устроиться куда-либо показали, что порог входа в IT-индустрию на 2021 год серьезно так подрос!

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

Между нами говоря. я как будто очень медленно двигаюсь. Учусь, пишу что-то, читаю книги, но движение все равно медленное! Проанализировав все что делаю и делал, понял, видимо мало реализовал пет-проектов, мало практики. Нужно больше!

Сейчас план такой:

  • делать 1 пет-проект в неделю, чтобы их было больше. Это плюс для работодателя понять мой уровень, а для меня, набить руку на практике;

  • изучать алгоритмы 1 в неделю, с закреплением на практическом примере;

  • читать 10 страниц в день разнообразных книг по JavaScript, таким образом если 1\10 от всей информации прилипнет это уже победа;

  • 1 метод в неделю изучать, усваивать и закреплять на примере.

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

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

Изучая React по гайдам Димыча IT-kamasutra путь самурая, в каком то 6 или 8 выпуске, в комментах нашел инстаграм не равнодушного человека изучающего JS + React. Попав к нему на канал телеграмм, познакомился с ребятами из разных уголков мира и все хотят что то уметь, и умеют в чем-то больше меня, а в чем-то меньше.

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

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

Спасибо Андрею из Питера за помощь в освоении сложных моментов и Тимуру из Владикавказа за легкое менторство. Это очень ценно парни!

Учусь писать на ReactУчусь писать на React

Точно не пожалел о своем пути

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

Я уверен, что важно не сдаваться! В любом случае нас неминуемо ждет успех если очень долго и упорно идти к цели. И если ежедневно уделять этому время!

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

Тогда еще в 2019 году я задался целью, изучать JavaScript минимум три года. И только после этого времени оглянуться и спросить себя на верном ли я пути?! Знаете, в нашем мире сегодня все достается очень быстро. Кредит пожалуйста за 15 минут. Пицца доставка от 30 минут. Телевизор доставим на дом.

Мы привыкли, что все чего бы не захотели, достигается быстрым путем. И это ошибка. Ведь скорость и доступность создает в нас иллюзию простоты. И когда у нас что-то не получается быстро, мы расстраиваемся и бросаем начатое. Я же готов еще 3 года положить на изучение Frontend. Сразу сегодня, готов продлить данное себе же обещание!

Радость за успехРадость за успех

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

Продолжайте учиться каждый день, друзья.

Продолжайте делать, даже когда не понимаете.

Продолжайте стараться, даже когда нет сил.

И мы вместе однажды достигнем результата ради которого начинали.

Подробнее..

Недоумение про ещё один корпоративный чат или как сделать приятно всем

21.06.2021 12:17:59 | Автор: admin

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

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

Чтоб было безопасно. Т.е. чтоб не просто data scientist модный в шортиках из одной американской/китайской/российской компании не мог в рамках своих задач узнать что-то полезное, а даже рядовой админ банка не смог увидеть или унести переписку одного уважаемого человека с другим. Даже в качестве картинки. Даже на свой админский супер-защищённый комп. Следовательно, оно должно быть self-hosted разворачиваемо отдельно и полностью контролируется исключительно теми, кому положено следить и зарплату за это платят. Ещё нужно подключиться к системам, отвечающим за безопасность передаваемого контента. Ещё нужно иметь в руках команды сопровождения все возможные рычаги, чтобы нерадивого пользователя можно было ограничить в желании другому пользователю передавать то, что не положено.

Чтобы было удобно. Сейчас на дворе 2021 год. Но даже закачать справочник пользователей или синтегрить с корпоративной телефонией банка что-то это уже подвиг на грани фантастики. И удивлению моему не было предела тот же slack обладает пользовательским интерфейсом, который физически невозможно объяснить курьеру из доставки подавай ему пользовательский интерфейс ala telegram. И желательно с видео конференциями встроенными. И прям очень нужен голосовой виртуальный ассистент, голосом удобнее. Ещё невозможно объяснить человеку, у которого есть одновременно два телефона, планшет и два компьютера почему ему нужно выбрать, где же можно работать с этим мессенджером, а где остаться без мессенджера. Ну и зачем каждый раз свой номер телефона светить не ясно.

Чтобы было удобно для внутренних коммуникаций. Тут приходят умные люди из разных отделов, департаментов и цельных предприятий и говорят нам возможность узконаправленных рассылок нужна. Таргетированных, как это модно называть. По полу, по городу, по региону, по подразделению, по должности и т.д. И в этот момент все open-source решения для чатов (а их только на github больше 2100 штук) куда-то деваются. Остаются те, кто реально зарабатывает. Но первый пункт не выполняется.

Чтобы развитие продукта помогало бизнесу, а не мешало всем подряд. Удивительно, но с этой точки зрения почти никто не смотрит. Сколько времени сотрудник тратит на поиск телефона в адресной книге где-то там, потом нужно найти телефон, чтобы позвонить и на этом телефоне набрать 11 заветных цифр. И выяснить, например, что номер с ошибкой. Гораздо удобнее нашёл ФИО, посмотрел фото и сразу набрал. Нужно ещё двоих подключить аналогично набрал и добавил. И никакой музыки от абонента, которому кто-то в это время позвонил, портящей всем 114 остальным участникам совещания не только настроение. 2021 на дворе. И чтоб если нужно любой модуль за месяц прикрутить можно было. Ну хорошо, иногда за два

Отсутствие зависимости от вендора и его капризов. Если ты маленькая организация из 50 человек (а по статистике таких ох как много), тебе нужно решение готовое. Даже когда 3000 человек нужно обслужить вопрос даже не стоит идёшь и выбираешь решение. Можно даже покапризничать и тендер объявить. А если у тебя 400 000 сотрудников? А если миллион планируется? Тут и вендоров вечных с хорошим SLA мало, и возможности их контролировать тоже не велики. Или вендор маленький и может случайно помереть при очередном кризисе или принятии закона/уехать ему понадобится всей командой, или вендор большой, но его мало интересуют проблемы конкретного клиента у него самого может быть 40 000 сотрудников и 1000 таких же клиентов по миру.

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

Ну и на всякий случай сошлюсь на бородатые требования одного habrовода (http://personeltest.ru/aways/habr.com/ru/post/405887/ - их мы тоже учли и удовлетворили): кроссплатформенность. Чтоб я наконец-то мог сидя на обеде, или в транспорте, или в отпуске кому-то что-то написать с телефона, да и узнать, что мне кто-то написал. И чтоб мой коллега, у которого Линукс, не делал каждый раз печальное лицо при слове чат. заточенный под общение в компаниях. Чтоб у меня был чат, где есть все мои коллеги и только мои коллеги живой активный проект. Чтобы баги, как застывшие в янтаре насекомые, не висели в продукте до конца времён передача файлов. Ну зачем мне заливать эту картинку в общую папку, если я просто могу кинуть её через чат! нормальная синхронизация уведомлений / непрочитанного. Чтобы не как в Скайпе словил сообщение, и потом в течение 24 часов находишь уведомление о нём на каждом своём девайсе.

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

Подробнее..

Перевод Карманная книга по TypeScript. Часть 8. Модули

21.06.2021 10:15:25 | Автор: admin

image


Мы продолжаем серию публикаций адаптированного и дополненного перевода "Карманной книги по TypeScript".

Другие части:



Определение модуля


В TS, как и в ECMAScript2015, любой файл, содержащий import или export верхнего уровня (глобальный), считается модулем.


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


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


Не модули


Для начала, давайте разберемся, что TS считает модулем. Спецификация JS определяет, что любой файл без export или await верхнего уровня является скриптом, а не модулем.


Переменные и типы, объявленные в скрипте, являются глобальными (имеют глобальную область видимости), для объединения нескольких файлов на входе в один на выходе следует использовать либо настроку компилятора outFile, либо несколько элементов script в разметке (указанных в правильном порядке).


Если у нас имеется файл, который не содержит import или export, но мы хотим, чтобы этот файл считался модулем, просто добавляем в него такую строку:


export {}

Модули в TS


Существует 3 вещи, на которые следует обращать внимание при работе с модулями в TS:


  • Синтаксис: какой синтаксис я хочу использовать для импорта и экспорта сущностей?
  • Разрешение модулей: каковы отношения между названиями модулей (или их путями) и файлами на диске?
  • Результат: на что должен быть похож код модуля?

Синтаксис


Основной экспорт в файле определяется с помощью export default:


// @filename: hello.tsexport default function helloWorld() {  console.log('Привет, народ!')}

Затем данная функция импортируется следующим образом:


import hello from './hello.js'hello()

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


// @filename: maths.tsexport var pi = 3.14export let squareTwo = 1.41export const phi = 1.61export class RandomNumberGenerator {}export function absolute(num: number) {  if (num < 0) return num * -1  return num}

Указанные сущности импортируются так:


import { pi, phi, absolute } from './maths.js'console.log(pi)const absPhi = absolute(phi)  // const absPhi: number

Дополнительный синтаксис импорта


Название импортируемой сущности можно менять с помощью import { old as new }:


import { pi as  } from './maths.js'console.log()        /*          (alias) var : number          import         */

Разные способы импорта можно смешивать:


// @filename: maths.tsexport const pi = 3.14export default class RandomNumberGenerator {}// @filename: app.tsimport RNGen, { pi as  } from './maths.js'RNGen/*  (alias) class RNGen  import RNGen*/console.log()/*  (alias) const : 3.14  import */

Все экспортированные объекты при импорте можно поместить в одно пространство имен с помощью * as name:


// @filename: app.tsimport * as math from './maths.js'console.log(math.pi)const positivePhi = math.absolute(math.phi)  // const positivePhi: number

Файлы можно импортировать без указания переменных:


// @filename: app.tsimport './maths.js'console.log('3.14')

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


Специфичный для TS синтаксис модулей


Типы могут экспортироваться и импортироваться с помощью такого же синтаксиса, что и значения в JS:


// @filename: animal.tsexport type Cat = { breed: string, yearOfBirth: number }export interface Dog {  breeds: string[]  yearOfBirth: number}// @filename: app.tsimport { Cat, Dog } from './animal.js'type Animals = Cat | Dog

TS расширяет синтаксис import с помощью import type, что позволяет импортировать только типы.


// @filename: animal.tsexport type Cat = { breed: string, yearOfBirth: number }// 'createCatName' cannot be used as a value because it was imported using 'import type'.// 'createCatName' не может использоваться в качестве значения, поскольку импортируется с помощью 'import type'export type Dog = { breeds: string[], yearOfBirth: number }export const createCatName = () => 'fluffy'// @filename: valid.tsimport type { Cat, Dog } from './animal.js'export type Animals = Cat | Dog// @filename: app.tsimport type { createCatName } from './animal.js'const name = createCatName()

Такой импорт сообщает транспиляторам, вроде Babel, swc или esbuild, какой импорт может быть безопасно удален.


Синтаксис ES-модулей с поведением CommonJS


Синтаксис ES-модулей в TS напрямую согласуется с CommonJS и require из AMD. Импорт с помощью ES-модулей в большинстве случаев представляет собой тоже самое, что require в указанных окружениях, он позволяет обеспечить полное совпадение TS-файла с результатом CommonJS:


import fs = require('fs')const code = fs.readFileSync('hello.ts', 'utf8')

Синтаксис CommonJS


CommonJS это формат, используемый большинством npm-пакетов. Даже если вы используете только синтаксис ES-модулей, понимание того, как работает CommonJS, поможет вам в отладке приложений.


Экспорт


Идентификаторы экпортируются посредством установки свойства exports глобальной переменной module:


function absolute(num: number) {  if (num < 0) return num * -1  return num}module.exports = {  pi: 3.14,  squareTwo: 1.41,  phi: 1.61,  absolute}

Затем эти файлы импортируются с помощью инструкции require:


const maths = require('maths')maths.pi  // any

В данном случае импорт можно упростить с помощью деструктуризации:


const { squareTwo } = require('maths')squareTwo  // const squareTwo: any

Взаимодействие CommonJS с ES-модулями


Между CommonJS и ES-модулями имеется несовпадение, поскольку ES-модули поддерживают "дефолтный" экспорт только объектов, но не функций. Для преодоления данного несовпадения в TS используется флаг компиляции esModuleInterop.


Настройки, связанные с разрешением модулей


Разрешение модулей это процесс определения файла, указанного в качестве ссылки в строке из инструкции import или require.


TS предоставляет две стратегии разрешения модулей: классическую и Node. Классическая стратегия является стратегией по умолчанию (когда флаг module имеет значение, отличное от commonjs) и включается для обеспечения обратной совместимости. Стратегия Node имитирует работу Node.js в режиме CommonJS с дополнительными проверками для .ts и .d.ts.


Существует большое количество флагов, связанных с разрешением модулей: moduleResolution, baseUrl, paths, rootDirs и др.


Настройки для результатов разрешения модулей


Имеется две настройки, которые влияют на результирующий JS-код:


  • target определяет версию JS, в которую компилируется TS-код
  • module определяет, какой код используется для взаимодействия модулей между собой

То, какую цель (target) использовать, зависит от того, в какой среде будет выполняться код (какие возможности поддерживаются этой средой). Это может включать в себя поддержку старых браузеров, более низкую версию Node.js или специфические ограничения, накладываемые такими средами выполнения, как, например, Electron.


Коммуникация между модулями происходит через загрузчик модулей (module loader), определяемый в настройке module. Во время выполнения загрузчик отвечает за локализацию и установку всех зависимостей модуля перед его выполнением.


Ниже приведено несколько примеров использования синтаксиса ES-модулей с разными настройками module:


import { valueOfPi } from './constants.js'export const twoPi = valueOfPi * 2

ES2020


import { valueOfPi } from './constants.js'export const twoPi = valueOfPi * 2

CommonJS


"use strict";Object.defineProperty(exports, "__esModule", { value: true });exports.twoPi = void 0;const constants_js_1 = require("./constants.js");exports.twoPi = constants_js_1.valueOfPi * 2;

UMD


(function (factory) {  if (typeof module === "object" && typeof module.exports === "object") {    var v = factory(require, exports);    if (v !== undefined) module.exports = v;  }  else if (typeof define === "function" && define.amd) {    define(["require", "exports", "./constants.js"], factory);  }})(function (require, exports) {  "use strict";  Object.defineProperty(exports, "__esModule", { value: true });  exports.twoPi = void 0;  const constants_js_1 = require("./constants.js");  exports.twoPi = constants_js_1.valueOfPi * 2;});

Пространства имен (namespaces)


TS имеет собственный модульный формат, который называется namespaces. Данный синтаксис имеет множество полезных возможностей по созданию сложных файлов определений и по-прежнему активно используется в DefinitelyTyped. Несмотря на то, что namespaces не признаны устаревшими (deprecated), большая часть его возможностей нашла воплощение в ES-модулях, поэтому настоятельно рекомендуется использовать официальный синтаксис.




VPS серверы от Маклауд быстрые и безопасные.


Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!


Подробнее..

Странник VIPER как сконструирован планетоход и что он будет делать на Луне

21.06.2021 14:12:41 | Автор: admin
Обложка к комиксу Weird science. 50-годы

NASA разрабатывает планетоход VIPER (Volatiles Investigating Polar Exploration Rover), который будет искать и составлять карту залежей воды на Луне. VIPER планируют доставить на поверхность Луны уже к концу 2023 года. Исследовательский центр Эймса отвечает за управление работой планетохода, разработку его программного обеспечения и систем контроля. Оборудованием занимается космический центр Джонсона, научными инструментами исследовательский центр Эймса и космический центр Кеннеди. Компания Astrobotic из Питтсбурга выиграла контракт на запуск, транспортировку и доставку планетохода на поверхность Луны. По данным NASA, общие затраты на разработку миссии составляют $433,5 млн долларов.

Ключевые факты



  • Способ доставки на Луну: ракета-носитель и посадочный модуль;
  • Продолжительность полета: 100 земных дней.
  • Высадка планетохода должна осуществиться на Луне в начале летнего сезона на Южном полюсе, в самые продолжительные периоды солнечного света, чтобы было легче поддерживать работу ровера.

Задачи планетохода VIPER


В ближайшие годы в NASA намерены вновь отправлять людей на Луну (программа Артемида). Целью миссии планетохода является сбор данных, которые помогут составить дальнейшие планы по постройке баз на Луне. В лунных полярных регионах большое количество водяного льда. Его наличие связано с осевым наклоном Луны, который обеспечивает постоянное затенение полярных областей, а отсутствие прямых солнечных лучей не позволяет льду сублимироваться в кислород и газообразный водород. Лед будет необходим для жизни человека на Луне. Он будет использоваться для всего питья, орошения, производства газообразного кислорода и водородного топлива.

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

Что мы знаем о конструкции планетохода VIPER



Ровер оснащен:

  • системой спектрометров NIRVSS, NSS (будет использоваться для выявления воды под поверхностью);
  • инструментами для наблюдения за лунными операциями с масс-спектрометром MSolo;
  • буровой установкой TRIDENT (длина бура 1 м) для изучения новой местности, получения и последующего анализа образцов почвы;
  • аккумулятором на солнечной батарее (максимальная мощность 450 Вт);
  • четырьмя колесами.

Параметры VIPER:

  • Размер 1,5 м х 1,5 м х 2,5 м,
  • Вес 430 кг;
  • Максимальная скорость 0,8 км/ч;
  • Шаг от 4 до 8 метров (в зависимости от указаний диспетчеров миссии на Земле).

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

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

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

Предшественники планетохода VIPER


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

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

Луноходы:

  1. Луноход-1 (1970, СССР) первый в мире планетоход, успешно работавший на поверхности Луны;
  2. Лунные автомобили программы Аполлон (1971-1972 гг., США) использовались для обеспечения большей подвижности экипажей Аполлон -15, 16, 17;
  3. Луноход-2 (1973, СССР) предназначен для изучения механических свойств лунной поверхности, фото- и телесъемки Луны, проведения экспериментов;
  4. Yutu (2013, КНР) первый китайский луноход. После 40 дней работы потерял подвижность и продолжил работу в стационарном режиме;
  5. Yutu-2 (2019, КНР) первый в мире луноход, изучавший обратную сторону Луны;
  6. Прагъям (2019, Индия) разбился о поверхность Луны в результате неудачной посадки.

Марсоходы:

  1. ПрОП-М (1971, СССР) название двух первых в мире марсоходов, которые достигли поверхности Марса, но так и не начали работу;
  2. Sojourner (1997, США) первый работающий марсоход, передал 550 фотографий и более 15 раз провел химический анализ марсианских камней и грунта;
  3. Spirit (2004, США) первый из двух запущенных марсоходов, в рамках проекта Mars Exploration Rover. Осуществлял анализ геологических пород. В 2009 году марсоход застрял в песчаной дюне.
  4. Opportunity (2004, США) второй марсоход проекта Mars Exploration Rover. В конце апреля 2010 года продолжительность миссии достигла 2246 солов ( марсианские сутки 24 часа 39 минут 35,24409 секунды), что сделало ее самой длительной марсианской операцией. В 2019 году миссия была официально завершена.
  5. Curiosity (2012, США) автономная химическая лаборатория, работает в настоящее время, проводит полноценный анализ марсианских почв и компонентов атмосферы;
  6. Perseverance (2021, США) разработан для исследования кратера Езеро. Марсоход впервые переработал углекислый газ из атмосферы Марса в кислород;
  7. Zhurong (2021, КНР) первый китайский марсоход, приземлившийся на планете. В его задачи входит картирование структуры планеты, изучение характеристик поверхностного слоя и распределения водяного льда в нем, анализ состава материалов поверхности, измерение параметров ионосферы планеты, электромагнитного и гравитационного полей и получение информации о климате.

Подробнее..

Что нам стоит дом построить? (часть 2)

21.06.2021 12:17:59 | Автор: admin

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

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

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

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

Какие есть варианты?

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

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

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

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

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

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

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

А что у нас?

Второй вариант - это использование специализированных документоориентированных (или документных, как больше нравится) баз данных, реализующих NoSQL-подход к хранению и обработкенеструктурированной или слабоструктурированной информации. Наиболее часто данные хранятся в виде JSON объектов, но с предоставлением производителями СУБД инструментария для доступа к данным внутри этих структур.

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

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

  • ограничиваем ситуации случайного воздействия на данные - модифицировать json объект гораздо сложнее, чем данные в колонке.

  • проще описывать объекты в коде - иногда можно вообще не описывать структуру документа в коде, а работать прямо с полями в JSON.

Но есть и минусы:

  • невозможно нативно реализовать проверки данных при размещении в хранилище.

  • валидацию данных придется проводить в коде.

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

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

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

Делаем прототип

Возьмем гипотезу, что NoSQL-подход для нашей системы применим как минимум не хуже, чем классический. Для ее проверки создадим прототип, в рамках которого реализуем оба подхода. В качестве СУБД возьмем Postgre, который уже давно умеет хорошо работать с JSON полями.

Создадим следующие таблицы:

Для описания объектов в табличном виде:

  • r_objects, базовые данные по объектам: тип, дата создания и ссылка на хранилище атрибутов.

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

Для описания объектов в виде JSON:

  • objects. Данные по объектам, где в поле data формата jsonb хранятся искомые атрибуты.

Остальные таблицы - это различные вспомогательные хранилища.

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

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

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

  • добавление данных по объекту. Критерий успешности: объект с данными появился в хранилище, метод вернул в ответе его идентификатор.

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

  • извлечение данных по объекту. Критерий успешности: объект с данными возвращен в ответе на запрос. Извлечение объекта происходит по конкретному идентификатору, по критериям поиска и постранично (пагинация).

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

Тестирование показало следующие результаты:

График по тестированию табличного хранилищаГрафик по тестированию табличного хранилищаГрафик по тестированию NoSQL-хранилищаГрафик по тестированию NoSQL-хранилища

Первая (высокая) часть графика - это получение объектов по случайной странице - пагинация. Здесь в обоих случаях пришлось применить небольшой трюк - так как Postgres не агрегирует точное число строк в таблице, то узнать, сколько всего записей на объеме данных теста простым count - это долго, и для получения количества записей пришлось брать статистику данных по таблице. Также время получения данных на страницах свыше 10000-й неприлично велико, поэтому верхняя планка для получения случайного номера страницы была установлена в 10000. Учитывая специфику нашей системы, получение пагинированных данных не будет частой операцией, и поэтому такое извлечение данных применяется исключительно в целях тестирования.

Вторая (средняя) часть графика - вставка или обновление данных.

Третья (низкая) часть графика - получение данных по случайному идентификатору.

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

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

Результаты тестов на 40000 запросов приведу в виде таблицы:

Табличная

NoSQL

Объем хранилища

74

66

Среднее количество операций в секунду

970

1080

Время тестирования, секунды

42

37

Количество запросов

40000

40000

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

Что получилось?

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

Подробнее..

Создание терминала для СКУД и УРВ

21.06.2021 12:17:59 | Автор: admin

Вступление

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

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

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

Поэтому был придумал предельно простой и быстрый сценарий действий на терминале:

  1. Прийти на рабочее место, подойти к терминалу и пройти идентификацию (приложить палец, карту к считывателю или ввести PIN)

  2. Выбрать на тачскрине Работа, после чего отправиться на свое рабочее место и приступить к работе

  3. При необходимости перерыва подойти к терминалу, пройти идентификацию, выбрать Перерыв

  4. При возвращении на рабочее место - подойти к терминалу, пройти идентификацию, выбрать Работа

  5. По окончанию рабочей смены подойти к терминалу, пройти идентификацию и выбрать Завершить работу.

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

Разработка

Имея на руках техническое задание, была разработана структурная и функциональная схема. Далее пошло самое интересное: мы начали рассматривать различные варианты одноплатных компьютеров, которые бы смогли обеспечить нужный функционал терминала. Среди вариантов были следующие компьютеры: Banana Pi M4, Orange Pi PC+, ODROID-C4, NanoPi M4 и Raspberry PI Computer Module 3+. Произведем небольшое сравнение данных моделей.

Banana Pi M4

Orange Pi PC+

ODROID-C4

NanoPi M4

Raspberry PI CM3+

Память

Слот MicroSD с поддержкой расширения до 256 ГБ и флэш-память eMMC 8 ГБ с поддержкой до 64 ГБ

TF-карта (макс. 32ГБ) / слот для карты eMMC

8 ГБ флэш-память EMMC

1x разъем EMMC (доступно 8/16/32/64 ГБ)

1 слот Micro SD

нет встроенной eMMC, но есть разъем eMMC,
1 слот для MicroSD до 128 GB

8 GB eMMc + поддержка 1 слота microSD

RAM

1 GB DDR4 (опционально 2 GB)

1GB DDR3

4GB DDR4

Двухканальный 2GB DDR3-1866

1GB LPDDR2 SDRAM

CPU

Realtek RTD1395 ARM Cortex-A53 Quad-Core 64 Bit 1.8 GHz

H3 Quad-coreCortex-A71.2 GHz

Amlogic S905X3 Quad-Core Cortex-A55 ARMv8.2-A 64-bit 1.5GHz

RK3399- Cortex-A72 + Quad Core Cortex-A531.8 GHz

Broadcom BCM2837B0 с четырьмя ядрами Cortex A53 1.2 GHz

GPU

Mali 470 MP4 GPU OpenGL ES 1.1/2.0

Mali400MP2 GPU 600MHz
с поддержкой OpenGL ES 2.0

Mali-G31, поддержка OpenGL ES 3.2 и API Vulkan последнего поколения

Mali-T864поддержка OpenGL ES1.1/2.0/3.0/3.1, OpenCL, DX11 и AFBC

Broadcom VideoCore IV

Сеть

Ethernet 10/100/1000 Мбит / с
Опциональный USB-ключ Wi-Fi. Поддержка PoE

10/100 Ethernet RJ45

RJ45 Ethernet порт (10/100/1000)

Порт Gbps Ethernet

10/100 для подключения маршрутизатора или коммутатора с функцией PoE

После детального изучения и анализа цены (все модели находились в примерно одном ценовом диапазоне на момент их анализа - 2019 год), мы все же пришли к выводу, что лучше всего подойдет Raspberry PI Computer Module 3+. Почему Raspberry ? Да, некоторые характеристики уступают конкурентам, однако главным преимуществом стало то, что по Raspberry банально больше поддерживаемых библиотек и лучше техническая поддержка, т.к Raspberry на рынке с 2012 года и вокруг него сформировалось активное комьюнити.

Решение со встроенной памятью eMMC, предусмотренное в CM3, позволяет не использовать флеш-карту в качестве носителя ОС. Большое количество циклов перезаписи eMMC повышает надежность и срок службы памяти по сравнению с флеш-картами. При этом мы зарезервировали разъем для SD карт. Сразу можно сказать, что заявленной памяти для терминала хватает с лихвой, ибо сохраняемые события весят от силы пару килобайт. Что касается хранения фотографий, то здесь все сложнее: программно мы поставили ограничение в 5000 фото, но так как у нас зарезервирована флеш-карта, то данный лимит можно расширить до приемлемого значения.

Разработку управляющей платы мы начали с организации необходимых питающих напряжений. На нашей плате нам необходимо было обеспечить 3 значения напряжений: 5.0В, 3.3В и 1.8В. Внешний источник питания у нас 12В 3А. Для получения 5В и 3.3В мы использовали схему на основе широтной импульсной модуляции. Для источника питания 1.8В мы задействовали линейный понижающий преобразователь. Это выглядит, примерно, следующим образом.

Схема питания терминалаСхема питания терминала

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

Отметим также и схему защиты питания внешних считывателей, представленную ниже.

Схема защиты питания считывателя от диверсийСхема защиты питания считывателя от диверсий

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

Питание мы организовали, самое время перейти к периферии.

К слову, Raspberry поддерживает UART-интерфейс и 2 USB версии 2.0. Через один из доступных USB мы решили организовать доступ к Ethernet с помощью микросхемы LAN9514 . Второй USB используется для подключения периферии, например индикатор алкоголя. Также задействовав GPIO для подключения кнопок, электромагнитных замков, защёлок, алкостестера в дискретном режиме работы и картаприемников.

Схема реализации Ethernet и USBСхема реализации Ethernet и USB

У CM3 на борту всего 2 UART. Один нам пригодится для организации интерфейса RS-485, а второй - debug. Поэтому мы использовали микросхему FT4232HL, для увеличения количества интерфейсов. У нее есть входной интерфейс USB, который поддерживает связь с LAN9514, он же в свою очередь коннектится с CM3.

Схема расширения количества UART-овСхема расширения количества UART-ов

Вот теперь у нас стало больше на целых 4 UARTa (задействуем всего 2). Один используется для подключения биометрического модуля отпечатков пальцев от южнокорейского производителя Suprema-SFM6020-OP6-8M/16M (8M - 5К отпечатков, 16М- 25К отпечатков).

Второй для подключения карточного модуля 7941D (поддерживает 2 частоты Emarine (125 кГц) и Mifare (13,56 МГц).

Suprema-SFM6020-OP6-8MSuprema-SFM6020-OP6-8M

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

RS-485RS-485

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

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

Входной WiegandВходной WiegandВыходной WiegandВыходной Wiegand

Немаловажным моментом будет, что терминал имеет 2 реле для управления замком, турникетом или шлагбаумом. Рассмотрим данный момент на примере подключения турникета (стандартная ситуация для СКУД). Есть два режима управления турникетом, потенциальный режим и импульсный. При потенциальном режиме управления для разблокировки турникета в направлении А срабатывает выход L1 OUT (в направлении В выход L2 OUT). При окончании данного времени или при совершении прохода выходной сигнал возвращается в исходное состояние.

В импульсном режиме для разблокировки выхода L1 OUT и L2 OUT срабатывают кратковременно, посылая управляющий импульс на турникет (обычно 0,2-0,3 секунды). При получении импульса турникет разблокируется в соответствующем направлении на время 5 секунд либо пока не будет совершен проход в данном направлении.

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

Например, для работы с турникетами PERCo в контроллере должен быть установлен импульсный режим управления. Для этого время срабатывания сигналов L1 OUT и L2 OUT должно быть установлено в пределах от 0,2 до 1 секунды.

Подключение турникета PERCoПодключение турникета PERCo

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

  1. RPi D - 72.4 градуса обзор, 5 mpx, размер камеры 25x24 мм (старое исполнение).

  2. RPi G - 160 градусов обзор, 5 mpx, размер камеры 25x24 мм (теперь используем только этот вариант).

Схема организации интерфейсов DSI и CSIСхема организации интерфейсов DSI и CSI

Выбирая дисплей, выбор снова пал на знакомый бренд - 7-ми дюймовый touch-screen от Raspberry с разрешением 800x480 и DSI интерфейсом.

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

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

Собрав все воедино мы получили терминал данного вида.

Знакомьтесь, терминал D1!Знакомьтесь, терминал D1!

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

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

Подробнее..

Перевод Лучшие фреймворки для микросервисов

21.06.2021 16:11:25 | Автор: admin

Выберите правильный фреймворк для архитектуры микросервисов

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

Преимущества микросервисов

  • Внедрение новых технологий и процессов.

  • Независимое масштабирование приложений.

  • Готовность к облачным вычислениям.

  • Безупречная интеграция.

  • Эффективное использование аппаратного обеспечения.

  • Безопасность на уровне услуг.

  • Функции на базе API для эффективного повторного использования.

  • Независимая разработка и развертывание приложений.

Критерии выбора фреймворка

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

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

  • Зрелость сообщества репутация поддерживающих фреймворк компаний, таких как Apache, Google или Spring. Зрелость фреймворка с точки зрения поддержки сообщества / коммерческой поддержки и частоты выпуска релизов для устранения проблем и добавления новых функций.

  • Простота разработки Фреймворки облегчают разработку приложений и повышают производительность разработчиков. IDE (Integrated Development Environment) и инструменты, поддерживающие фреймворки, также играют существенную роль в быстрой разработке приложений.

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

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

  • Поддержка автоматизации Фреймворк поддерживает автоматизацию задач, связанных со сборкой и развертыванием микросервисов.

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

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

Для разработки микросервисов доступны различные фреймворки в соответствии с требованиями проекта. Java, Python, C++, Node JS и .Net вот несколько языков для разработки микросервисов. Давайте подробно рассмотрим языки и связанные с ними фреймворки, которые поддерживают разработку микросервисов.

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

Фреймворки для микросервисов (Microservices Frameworks)

1. Java

Существует несколько фреймворков для разработки архитектуры микросервисов с использованием языка программирования Java:

  • Spring Boot Spring Boot это популярный фреймворк микросервисов на Java. Позволяет создавать как небольшие, так и крупномасштабные приложения. Spring boot легко интегрируется с другими популярными фреймворками с помощью инверсии управления.

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

  • Restlet фреймворк Restlet следует архитектурному стилю RST, который помогает Java-разработчикам создавать микросервисы. Принят и поддерживается Apache Software License.

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

  • AxonIQ Событийно-ориентированный фреймворк микросервисов с открытым исходным кодом, сфокусированный на Command Query Responsibility Segregation (CQRS), Domain-Driven Design (DDD) и скоринге событий.

  • Micronaut full-stack фреймворк на основе JVM для построения модульных, легко тестируемых микросервисных и бессерверных приложений. Создает полнофункциональные микросервисы, включая внедрение зависимостей, автоконфигурацию, обнаружение служб, маршрутизацию HTTP и клиент HTTP. Micronaut стремится избежать недостатков фреймворков Spring, Spring Boot, обеспечивая более быстрое время запуска, уменьшение объема памяти, минимальное использование рефлексии и спокойное юнит-тестирование.

  • Lagom Реактивный фреймворк микросервисов с открытым исходным кодом для Java или Scala. Lagom базируется на Akka и Play.

2. GoLang

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

  • GoMicro подключаемая библиотека RPC предоставляет фундаментальные строительные блоки для написания микросервисов на языке Go. Поддерживаются API-шлюз, интерактивный CLI, сервисный прокси, шаблоны и веб-панели.

3. Python

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

  • Flask Web Server Gateway Interface (WSGI) Веб-ориентированный легкий фреймворк микросервисов на языке Phyton. Flask-RESTPlus - расширение для Flask, которое предоставляет поддержку для быстрого создания REST API.

  • Falcon веб-фреймворк API для построения надежных бэкендов приложений и микросервисов в Phyton. Фреймворк отлично работает как с асинхронным интерфейсом шлюза сервера (ASGI), так и с WSGI.

  • Bottle Быстрый, легкий и простой WSGI микросервисный веб-фреймворк на основе Phyton. Распространяется одним файловым модулем и не имеет зависимостей, кроме стандартной библиотеки Python.

  • Nameko Фреймворк Nameko для построения микросервисов на Phyton со встроенной поддержкой RPC через AMQP, асинхронных событий, HTTP GET и POST, а также WebSocket RPC.

  • CherryPy CherryPy позволяет разработчикам создавать веб-приложения, используя объектно-ориентированное программирование на Python.

4. NodeJS

Существует несколько фреймворков для разработки архитектуры микросервисов с использованием языков программирования NodeJS

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

5. .NET

ASP.Net, фреймворк, используемый для веб-разработки и делающий ее API. Микросервисы поддерживают встроенные функции, для их (микросервисов) построения и развертывания с помощью контейнеров Docker.

6. MultiLanguage

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

  • Spark создание веб-приложений микросервисов с использованием Kotlin и Java. Выразительный и простой веб-фреймворк DSL на Java/Kotlin, созданный для быстрой разработки.

Заключение

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

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


Перевод подготовлен в рамках курса "Microservice Architecture".

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

Подробнее..

Как WCF сам себе в ногу стреляет посредством TraceSource

21.06.2021 14:12:41 | Автор: admin

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

Предыстория

В дистрибутиве PVS-Studio есть одна утилита под названием CLMonitor.exe, или система мониторинга компиляции. Она предназначена для "бесшовной" интеграции статического анализа PVS-Studio для языков C и C++ в любую сборочную систему. Сборочная система должна использовать для сборки файлов один из компиляторов, поддерживаемых анализатором PVS-Studio. Например: gcc, clang, cl, и т.п.

Стандартный сценарий работы данной Windows утилиты очень простой, всего 3 шага:

  1. Выполняем 'CLMonitor.exe monitor';

  2. Выполняем сборку проекта;

  3. Выполняем 'CLMonitor.exe analyze'.

Первый шаг запускает 'сервер', который начинает отслеживать все процессы компиляторов в системе до тех пор, пока его не остановят. Как только мы запустили сервер выполняем сборку проекта, который мы хотим проанализировать. Если сборка прошла, то нужно запустить анализ. Для этого мы исполняем третий шаг. 'CLMonitor.exe analyze' запускает 'клиент', который говорит серверу: "Всё, хватит, выключайся и давай сюда результаты мониторинга за процессами". В этот момент сервер должен завершить свою работу, а клиент запустить анализ. Подробнее о том, как внутри работает система мониторинга и зачем сервер вообще собирает процессы, мы поговорим чуть позже.

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

Примечание. Проблема у пользователя возникла при использовании Windows утилиты CLMonitor.exe. Поэтому все дальнейшие примеры будут актуальны именно для Windows.

Как работает CLMonitor.exe

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

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

Зачем мы вообще отлавливаем процессы

Как вы поняли, история начинается с того, что нужно запустить сервер, который будет отлавливать все процессы. Делаем мы это не просто так. Вообще, более удобный способ проанализировать C++ проект это прямой запуск анализатора через утилиту командной строки PVS-Studio_Cmd. У неё, однако, есть существенное ограничение она может проверять только проекты для Visual Studio. Дело в том, что для анализа требуется вызывать компилятор, чтобы он препроцессировал проверяемые исходные файлы, ведь анализатор работает именно с препроцессированными файлами. А чтобы вызвать препроцессор, нужно знать:

  • какой конкретно компилятор вызывать;

  • какой файл препроцессировать;

  • параметры препроцессирования.

Утилита PVS-Studio_Cmd узнает все необходимое из проектного файла (*.vcxproj). Однако это работает только для "обычных" MSBuild проектов Visual Studio. Даже для тех же NMake проектов мы не можем получить необходимую анализатору информацию, потому что она не хранится в самом проектном файле. И это несмотря на то, что NMake также является .vcxproj. Сам проект при этом является как бы обёрткой для другой сборочной системы. Тут в игру и вступают всяческие ухищрения. Например, для анализа Unreal Engine проектов мы используем прямую интеграцию с *Unreal Build Tool * сборочной системой, используемой "под капотом". Подробнее здесь.

Поэтому, для того чтобы можно было использовать PVS-Studio независимо сборочной системы, даже самой экзотической, у нас и появилась утилита CLMonitor.exe. Она отслеживает все процессы во время сборки проекта и отлавливает вызовы компиляторов. А уже из вызовов компиляторов мы получаем всю необходимую информацию для дальнейшего препроцессирования и анализа. Теперь вы знаете, зачем нам нужно мониторить процессы.

Как клиент запускает анализ

Для обмена данными между сервером и клиентом мы используем программный фреймворк WCF (Windows Communication Foundation). Давайте далее кратко опишем, как мы с ним работаем.

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

static ErrorLevels PerformMonitoring(....) {  using (ServiceHost host = new ServiceHost(                       typeof(CLMonitoringContract),                          new Uri[]{new Uri(PipeCredentials.PipeRoot)}))   {    ....    host.AddServiceEndpoint(typeof(ICLMonitoringContract),                             pipe,                             PipeCredentials.PipeName);    host.Open();         ....  }}

Обратите тут внимание на две вещи: *CLMonitoringContract *и ICLMonitoringContract.

*ICLMonitoringContract * это сервисный контракт. *CLMonitoringContract * реализация сервисного контракта. Выглядит это так:

[ServiceContract(SessionMode = SessionMode.Required,                  CallbackContract = typeof(ICLMonitoringContractCallback))]interface ICLMonitoringContract{  [OperationContract]  void StopMonitoring(string dumpPath = null);} [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]class CLMonitoringContract : ICLMonitoringContract{  public void StopMonitoring(string dumpPath = null)  {    ....    CLMonitoringServer.CompilerMonitor.StopMonitoring(dumpPath);  } }

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

public void FinishMonitor(){  CLMonitoringContractCallback сallback = new CLMonitoringContractCallback();  var pipeFactory = new DuplexChannelFactory<ICLMonitoringContract>(           сallback,            pipe,            new EndpointAddress(....));  ICLMonitoringContract pipeProxy = pipeFactory.CreateChannel();  ((IContextChannel)pipeProxy).OperationTimeout = new TimeSpan(24, 0, 0);  ((IContextChannel)pipeProxy).Faulted += CLMonitoringServer_Faulted;  pipeProxy.StopMonitoring(dumpPath);}

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

Всё, теперь вы, хоть немного, имеете представление о внутренней работе утилиты CLMonitor.exe.

Просмотр дамп файла и осознание проблемы

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

**Интересный факт. **Откуда вообще взялись эти 10 минут? Дело в том, что мы задаем время ожидания ответа от сервера намного больше, а именно - 24 часа, как видно в примере кода, приведённом выше. Однако для некоторых операций фреймворк сам решает, что это слишком много и он успеет быстрее. Поэтому берет только часть от изначального значения.

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

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

Дамп 'клиента'

Так вот, когда мы открыли дамп файл клиента, перед глазами предстал следующий список потоков:

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

public void FinishMonitor(){  ....  ICLMonitoringContract pipeProxy = pipeFactory.CreateChannel();  ((IContextChannel)pipeProxy).OperationTimeout = new TimeSpan(24, 0, 0);  ((IContextChannel)pipeProxy).Faulted += CLMonitoringServer_Faulted;  pipeProxy.StopMonitoring(dumpPath);            // <=  ....}

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

Дамп 'сервера'

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

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

Получается, что у пользователя запускается очень много процессов, которые, конкретно для нас, являются 'мусором'. Ну допустим, что это так. Однако данная картина все равно выглядит очень подозрительно. Почему же таких потоков так много? Ведь, по идее, логирование должно происходить быстро. Очень похоже на то, что все эти потоки висят на какой-то точке синхронизации или критической секции и чего-то ждут. Давайте зайдем на ReferenceSource и посмотрим исходный код метода TraceEvent.

Открываем исходники и действительно видим в методе TraceEvent оператор lock:

Мы предположили, что из-за постоянной синхронизации и логирования накапливается большое количество вызовов методов TraceEvent, ждущих освобождения TraceInternal.critSec. Хм, ну допустим. Однако это пока не объясняет, почему сервер не может ответить клиенту. Посмотрим еще раз в дамп файл сервера и заметим один одинокий поток, который висит на методе DiagnosticsConfiguration.Initialize:

В данный метод мы попадаем из метода NegotiateStream.AuthenticateAsServer, выполняющего проверку подлинности со стороны сервера в соединении клиент-сервер:

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

И тут мы замечаем, что в данном методе имеется критическая секция, да еще и на ту же самую переменную. Посмотрев, что вообще такое этот critSec, увидим следующее:

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

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

"Also one of the locks, TraceInternal.critSec, is only present if the TraceListener asks for it. Generally speaking such 'global' locks are not a good idea for a high performance logging system (indeed we don't recommend TraceSource for high performance logging at all, it is really there only for compatibility reasons)".

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

Итоги изучения дампов

Итак, что мы имеем:

  1. Клиент общается с сервером с помощью фреймворка WCF.

  2. Клиент не может получить ответа от сервера. После 10 минут ожидания он падает по тайм-ауту.

  3. На сервере висит множество потоков на методе TraceEvent и всего один - на Initialize.

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

  5. Потоки, в которых выполняется метод TraceEvent, бесконечно появляются и из-за lock не могут быстро сделать свое дело и исчезнуть. Тем самым они долго не отпускают объект в lock.

  6. Метод Initialize возникает при попытке клиента завершить работу сервера и висит бесконечно на lock.

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

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

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

Воспроизведение проблемы

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

private void CrazyLogging(){  for (var i = 0; i < 30; i++)  {    var j = i;    new Thread(new ThreadStart(() =>    {      while (!Program.isStopMonitor)        Logger.TraceEvent(TraceEventType.Error, 0, j.ToString());    })).Start();  }}

За работу сервера у нас отвечает метод Trace, поэтому добавляем наше логирование в него. Например, вот сюда:

public void Trace(){  ListenersInitialization();  CrazyLogging();  ....}

Готово. Запускаем сервер (я буду это делать с помощью Visual Studio 2019), приостанавливаем секунд через 5 процесс и смотрим что у нас там с потоками:

Отлично! Теперь запускаем клиент (TestTraceSource.exe analyze), который должен установить связь с сервером и остановить его работу.

Запустив, мы увидим, что анализ не начинается. Поэтому опять останавливаем потоки в Visual Studio и видим ту же самую картину из дамп файла сервера. А именно появился поток, который висит на методе DiagnosticsConfiguration.Initialize. Проблема воспроизведена.

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

Проблему мы "решили" следующим образом. По умолчанию теперь вся информация логируется в консоль, используя метод Console.WriteLine. В большинстве случаев, даже если эта логируемая информация и будет потеряна из-за не приаттаченной консоли, она всё равно не требуется для решения задач в работе утилиты, а проблема исчезла. Плюс изменения заняли какие-то минуты. Однако мы оставили возможность старого способа логирования с помощью специального флага enableLogger.

Код, воспроизводящий проблему

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

Чтобы запустить имитирование работы сервера, запустите .exe с флагом trace. Чтобы запустить клиент, воспользуйтесь флагом analyze.

**Примечание: **количество потоков в методе CrazyLogging следует подбирать индивидуально. Если проблема у вас не воспроизводится, то попробуйте поиграться с этим значением. Также можете запустить данный проект в Visual Studio в режиме отладки.

Точка входа в программу:

using System.Linq;namespace TestTraceSource{  class Program  {    public static bool isStopMonitor = false;    static void Main(string[] args)    {      if (!args.Any())        return;      if (args[0] == "trace")      {        Server server = new Server();        server.Trace();      }      if (args[0] == "analyze")      {        Client client = new Client();        client.FinishMonitor();      }    }    }}

Сервер:

using System;using System.Diagnostics;using System.ServiceModel;using System.Threading;namespace TestTraceSource{  class Server  {    private static TraceSource Logger;    public void Trace()    {      ListenersInitialization();      CrazyLogging();      using (ServiceHost host = new ServiceHost(                          typeof(TestTraceContract),                           new Uri[]{new Uri(PipeCredentials.PipeRoot)}))      {        host.AddServiceEndpoint(typeof(IContract),                                 new NetNamedPipeBinding(),                                 PipeCredentials.PipeName);        host.Open();        while (!Program.isStopMonitor)        {          // We catch all processes, process them, and so on        }        host.Close();      }      Console.WriteLine("Complited.");    }    private void ListenersInitialization()    {      Logger = new TraceSource("PVS-Studio CLMonitoring");      Logger.Switch.Level = SourceLevels.Verbose;      Logger.Listeners.Add(new ConsoleTraceListener());      String EventSourceName = "PVS-Studio CL Monitoring";      EventLog log = new EventLog();      log.Source = EventSourceName;      Logger.Listeners.Add(new EventLogTraceListener(log));    }    private void CrazyLogging()    {      for (var i = 0; i < 30; i++)      {        var j = i;        new Thread(new ThreadStart(() =>        {          var start = DateTime.Now;          while (!Program.isStopMonitor)            Logger.TraceEvent(TraceEventType.Error, 0, j.ToString());        })).Start();      }    }   }}

Клиент:

using System;using System.ServiceModel;namespace TestTraceSource{  class Client  {    public void FinishMonitor()    {      TestTraceContractCallback сallback = new TestTraceContractCallback();      var pipeFactory = new DuplexChannelFactory<IContract>(                                сallback,                                new NetNamedPipeBinding(),                                new EndpointAddress(PipeCredentials.PipeRoot                                                   + PipeCredentials.PipeName));      IContract pipeProxy = pipeFactory.CreateChannel();      pipeProxy.StopServer();      Console.WriteLine("Complited.");        }  }}

Прокси:

using System;using System.ServiceModel;namespace TestTraceSource{  class PipeCredentials  {    public const String PipeName = "PipeCLMonitoring";    public const String PipeRoot = "net.pipe://localhost/";    public const long MaxMessageSize = 500 * 1024 * 1024; //bytes  }  class TestTraceContractCallback : IContractCallback  {    public void JobComplete()    {      Console.WriteLine("Job Completed.");    }  }  [ServiceContract(SessionMode = SessionMode.Required,                    CallbackContract = typeof(IContractCallback))]  interface IContract  {    [OperationContract]    void StopServer();  }  interface IContractCallback  {    [OperationContract(IsOneWay = true)]    void JobComplete();  }  [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]  class TestTraceContract : IContract  {    public void StopServer()    {      Program.isStopMonitor = true;    }  }}

Вывод

Будьте осторожны со стандартным методом TraceSource.TraceEvent. Если у вас теоретически возможно частое использование данного метода в программе, то вы можете столкнуться с подобной проблемой. Особенно если у вас высоконагруженная система. Сами разработчики в таком случае не рекомендуют использовать всё, что связано с классом TraceSource. Если вы уже сталкивались с чем-то подобным, то не стесняйтесь рассказать об этом в комментариях.

Спасибо за просмотр. Незаметно рекламирую свой Twitter.

Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Nikolay Mironov. How WCF Shoots Itself in the Foot With TraceSource.

Подробнее..

Ваш безлимит как увеличить пропускную способность автомерджа

21.06.2021 14:12:41 | Автор: admin

Отыщи всему начало, и ты многое поймёшь (Козьма Прутков).

Меня зовут Руслан, я релиз-инженер в Badoo и Bumble. Недавно я столкнулся с необходимостью оптимизировать механизм автомерджа в мобильных проектах. Задача оказалась интересной, поэтому я решил поделиться её решением с вами. В статье я расскажу, как у нас раньше было реализовано автоматическое слияние веток Git и как потом мы увеличили пропускную способность автомерджа и сохранили надёжность процессов на прежнем высоком уровне.

Свой автомердж

Многие программисты ежедневно запускают git merge, разрешают конфликты и проверяют свои действия тестами. Кто-то автоматизирует сборки, чтобы они запускались автоматически на отдельном сервере. Но решать, какие ветки сливать, всё равно приходится человеку. Кто-то идёт дальше и добавляет автоматическое слияние изменений, получая систему непрерывной интеграции (Continuous Integration, или CI).

Например, GitHub предлагает полуручной режим, при котором пользователь с правом делать записи в репозиторий может поставить флажок Allow auto-merge (Разрешить автомердж). При соблюдении условий, заданных в настройках, ветка будет соединена с целевой веткой. Bitbucket поддерживает большую степень автоматизации, накладывая при этом существенные ограничения на модель ветвления, имена веток и на количество мерджей.

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

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

Термины

Main. Так я буду ссылаться на основную ветку репозитория Git. И коротко, и безопасно. =)

Сборка. Под этим будем иметь в виду сборку в TeamCity, ассоциированную с веткой Git и тикетом в трекере Jira. В ней выполняются как минимум статический анализ, компиляция и тестирование. Удачная сборка на последней ревизии ветки в сочетании со статусом тикета To Merge это однo из необходимых условий автомерджа.

Пример модели ветвления

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

На основе ветки main разработчик создаёт ветку с названием, включающим идентификатор тикета в трекере, например PRJ-k. По завершении работы над тикетом разработчик переводит его в статус Resolved. При помощи хуков, встроенных в трекер, мы запускаем для ветки тикета сборку. В определённый момент, когда изменения прошли ревью и необходимые проверки автотестами на разных уровнях, тикет получает статус To Merge, его забирает автоматика и отправляет в main.

Раз в неделю на основе main мы создаём ветку релиза release_x.y.z, запускаем на ней финальные сборки, при необходимости исправляем ошибки и наконец выкладываем результат сборки релиза в App Store или Google Play. Все фазы веток отражаются в статусах и дополнительных полях тикетов Jira. В общении с Jira помогает наш клиент REST API.

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

Первая версия: жадная стратегия

Сначала мы шли от простого и очевидного. Брали все тикеты, находящиеся в статусе To Merge, выбирали из них те, для которых есть успешные сборки, и отправляли их в main командой git merge, по одной.

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

Наличие в TeamCity актуальной успешной сборки мы проверяли при помощи метода REST API getAllBuilds примерно следующим образом (псевдокод):

haveFailed = False # Есть ли неудачные сборкиhaveActive = False # Есть ли активные сборки# Получаем сборки типа buildType для коммита commit ветки branchbuilds = teamCity.getAllBuilds(buildType, branch, commit)# Проверяем каждую сборкуfor build in builds:  # Проверяем каждую ревизию в сборке  for revision in build.revisions:    if revision.branch is branch and revision.commit is commit:      # Сборка актуальна      if build.isSuccessful:        # Сборка актуальна и успешна        return True      else if build.isRunning or build.isQueued        haveActive = True      else if build.isFailed:        haveFailed = Trueif haveFailed:  # Исключаем тикет из очереди, переоткрывая его  ticket = Jira.getTicket(branch.ticketKey)  ticket.reopen("Build Failed")  return Falseif not haveActiveBuilds:  # Нет ни активных, ни упавших, ни удачных сборок. Запускаем новую  TriggerBuild(buildType, branch)

Ревизии это коммиты, на основе которых TeamCity выполняет сборку. Они отображаются в виде 16-ричных последовательностей на вкладке Changes (Изменения) страницы сборки в веб-интерфейсе TeamCity. Благодаря ревизиям мы можем легко определить, требуется ли пересборка ветки тикета или тикет готов к слиянию.

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

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

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

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

Конфликты слияния

Если изменить одну и ту же строку кода в разных ветках и попытаться соединить их в main, то Git попросит разрешить конфликты слияния. Из двух вариантов нужно выбрать один и закоммитить изменения.

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

Если команда git merge завершилась с ошибкой и для всех файлов в списке git ls-files --unmerged заданы обработчики конфликтов, то для каждого такого файла мы выполняем парсинг содержимого по маркерам конфликтов <<<<<<<, ======= и >>>>>>>. Если конфликты вызваны только изменением версии приложения, то, например, выбираем последнюю версию между локальной и удалённой частями конфликта.

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

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

Логические конфликты

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

Попробуем воспроизвести это на примере Bash-скрипта test.sh:

#!/bin/bashget_a() {    printf '%d\n' 1}get_b() {    printf '%d\n' 2}check_limit() {    local -i value="$1"    local -i limit="$2"    if (( value > limit )); then        printf >&2 '%d > %d%s\n' "$value" "$limit"        exit 1    fi}limit=5a=$(get_a)b=$(get_b)sum=$(( a + b ))check_limit "$a" "$limit"check_limit "$b" "$limit"check_limit "$sum" "$limit"printf 'OK\n'

Закоммитим его и создадим пару веток: a и b.
Пусть в первой ветке функция get_a() вернёт 3, а во второй get_b() вернёт 4:

diff --git a/test.sh b/test.shindex f118d07..39d3b53 100644--- a/test.sh+++ b/test.sh@@ -1,7 +1,7 @@ #!/bin/bash get_a() {-    printf '%d\n' 1+    printf '%d\n' 3 } get_b() {git diff main bdiff --git a/test.sh b/test.shindex f118d07..0bd80bb 100644--- a/test.sh+++ b/test.sh@@ -5,7 +5,7 @@ get_a() { }  get_b() {-    printf '%d\n' 2+    printf '%d\n' 4 }  check_limit() {

В обоих случаях сумма не превышает 5 и наш тест проходит успешно:

git checkout a && bash test.shSwitched to branch 'a'OKgit checkout b && bash test.shSwitched to branch 'b'OK

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

git merge a bFast-forwarding to: aTrying simple merge with bSimple merge did not work, trying automatic merge.Auto-merging test.shMerge made by the 'octopus' strategy. test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)bash test.sh7 > 5

Было бы проще, если бы вместо get_a() и get_b() использовались присваивания: a=1; b=2, заметит внимательный читатель и будет прав. Да, так было бы проще. Но, вероятно, именно поэтому встроенный алгоритм автомерджа Git успешно обнаружил бы конфликтную ситуацию (что не позволило бы продемонстрировать проблему логического конфликта):

git merge a Updating 4d4f90e..8b55df0Fast-forward test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)git merge b Auto-merging test.shCONFLICT (content): Merge conflict in test.shRecorded preimage for 'test.sh'Automatic merge failed; fix conflicts and then commit the result.

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

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

Превентивные меры

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

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

Вторая версия: последовательная стратегия

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

Git, по идее, как раз и является средством синхронизации. Но порядок попадания веток в main и, наоборот, main в ветки определяем мы сами. Чтобы определить точно, какие из веток вызывают проблемы в main, можно попробовать отправлять их туда по одной. Тогда можно выстроить их в очередь, а порядок организовать на основе времени попадания тикета в статус To Merge в стиле первый пришёл первым обслужен.

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

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

Но есть у этой схемы существенный недостаток: пропускная способность автомерджа линейно зависит от времени сборки. При среднем времени сборки iOS-приложения в 25 минут мы можем рассчитывать на прохождение максимум 57 тикетов в сутки. В случае же с Android-приложением требуется примерно 45 минут, что ограничивает автомердж 32 тикетами в сутки, а это даже меньше количества Android-разработчиков в нашей компании.

На практике время ожидания тикета в статусе To Merge составляло в среднем 2 часа 40 минут со всплесками, доходящими до 10 часов! Необходимость оптимизации стала очевидной. Нужно было увеличить скорость слияний, сохранив при этом стабильность последовательной стратегии.

Финальная версия: сочетание последовательной и жадной стратегий

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

Давайте вспомним идею жадной стратегии: мы сливали все ветки готовых тикетов в main. Основной проблемой было отсутствие синхронизации между ветками. Решив её, мы получим быстрый и надёжный автомердж!

Раз нужно оценить общий вклад всех тикетов в статусе To Merge в main, то почему бы не слить все ветки в некоторую промежуточную ветку Main Candidate (MC) и не запустить сборку на ней? Если сборка окажется успешной, то можно смело сливать MC в main. В противном случае придётся исключать часть тикетов из MC и запускать сборку заново.

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

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

Следуя этому алгоритму, для k проблемных тикетов в худшем случае нам придётся выполнить O(k*log2(n)) сборок, прежде чем мы обработаем все проблемные тикеты и получим удачную сборку на оставшихся.

Вероятность благоприятного исхода велика. А ещё в то время, пока сборки на ветке MC падают, мы можем продолжать работу при помощи последовательного алгоритма!

Итак, у нас есть две автономные модели автомерджа: последовательная (назовём её Sequential Merge, или SM) и жадная (назовём её Greedy Merge, или GM). Чтобы получить пользу от обеих, нужно дать им возможность работать параллельно. А параллельные процессы требуют синхронизации, которой можно добиться либо средствами межпроцессного взаимодействия, либо неблокирующей синхронизацией, либо сочетанием этих двух методов. Во всяком случае, мне другие методы неизвестны.

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

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

  1. SM-SM и GM-GM: между командами одного типа.

  2. SM-GM: между SM и GM в рамках одного репозитория.

Первая проблема легко решается при помощи мьютекса по токену, включающему в себя имя команды и название репозитория. Пример: lock_${command}_${repository}.

Поясню, в чём заключается сложность второго случая. Если SM и GM будут действовать несогласованно, то может случиться так, что SM соединит main с первым тикетом из очереди, а GM этого тикета не заметит, то есть соберёт все остальные тикеты без учёта первого. Например, если SM переведёт тикет в статус In Master, а GM будет всегда выбирать тикеты по статусу To Merge, то GM может никогда не обработать тикета, соединённого SM. При этом тот самый первый тикет может конфликтовать как минимум с одним из других.

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

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

Немного о TeamCity

В процессе реализации GM нам предстояло обработать много нюансов, которыми я не хочу перегружать статью. Но один из них заслуживает внимания. В ходе разработки я столкнулся с проблемой зацикливания команды GM: процесс постоянно пересобирал ветку MC и создавал новую сборку в TeamCity. Проблема оказалась в том, что TeamCity не успел скачать обновления репозитория, в которых была ветка MC, созданная процессом GM несколько секунд назад. К слову, интервал обновления репозитория в TeamCity у нас составляет примерно 30 секунд.

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

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

<lastChanges>  <change    locator="version:{{revision}},buildType:(id:{{build_type}})"/></lastChanges>

В этом примере {{revision}} заменяется на 16-ричную последовательность коммита, а {{build_type}} на идентификатор конфигурации сборки. Но этого недостаточно, так как TeamCity, не имея информации о новом коммите, может отказать нам в запросе.

Для того чтобы новый коммит дошёл до TeamCity, нужно либо подождать примерно столько, сколько указано в настройках конфигурации корня VCS, либо попросить TeamCity проверить наличие изменений в репозитории (Pending Changes) при помощи метода requestPendingChangesCheck, а затем подождать, пока TeamCity скачает изменения, содержащие наш коммит. Проверка такого рода выполняется посредством метода getChange, где в changeLocator нужно передать как минимум сам коммит в качестве параметра локатора version. Кстати, на момент написания статьи (и кода) на странице ChangeLocator в официальной документации описание параметра version отсутствовало. Быть может, поэтому я не сразу узнал о его существовании и о том, что это 40-символьный 16-ричный хеш коммита.

Псевдокод:

teamCity.requestPendingChanges(buildType)attempt = 1while attempt <= 20:  response = teamCity.getChange(commit, buildType)  if response.commit == commit:    return True # Дождались  sleep(10)return False

О предельно высокой скорости слияний

У жадной стратегии есть недостаток на поиск ветки с ошибкой может потребоваться много времени. Например, 6 сборок для 20 тикетов у нас может занять около трёх часов. Можно ли устранить этот недостаток?

Допустим, в очереди находится 10 тикетов, среди которых только 6-й приводит к падению сборки.

Согласно жадной стратегии, мы пробуем собрать сразу все 10 тикетов, что приводит к падению сборки. Далее собираем левую половину (с 1 по 5) успешно, так как тикет с ошибкой остался в правой половине.

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

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

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

Примерно такой же алгоритм реализован в премиум-функции GitLab под названием Merge Trains. Перевода этого названия на русский язык я не нашёл, поэтому назову его Поезда слияний. Поезд представляет собой очередь запросов на слияние с основной веткой (merge requests). Для каждого такого запроса выполняется слияние изменений ветки самого запроса с изменениями всех запросов, расположенных перед ним (то есть запросов, добавленных в поезд ранее). Например, для трёх запросов на слияние A, B и С GitLab создаёт следующие сборки:

  1. Изменения из А, соединённые с основной веткой.

  2. Изменения из A и B, соединённые с основной веткой.

  3. Изменения из A, B и C, соединённые с основной веткой.

Если сборка падает, то соответствующий запрос из очереди удаляется, а сборки всех предыдущих запросов перезапускаются (без учёта удалённого запроса).

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

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

Но если преград человеческой мысли нет, то пределы аппаратных ресурсов видны достаточно отчётливо:

  1. Каждой сборке нужен свой агент в TeamCity.

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

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

Взвесив все плюсы и минусы, мы решили пока остановиться на алгоритме SM + GM. При текущей скорости роста очереди тикетов алгоритм показывает хорошие результаты. Если в будущем заметим возможные проблемы с пропускной способностью, то, вероятно, пойдём в сторону Merge Trains и добавим пару параллельных сборок GM:

  1. Вся очередь.

  2. Левая половина очереди.

  3. Левая четверть очереди.

Что в итоге получилось

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

  • уменьшение среднего размера очереди в 2-3 раза;

  • уменьшение среднего времени ожидания в 4-5 раз;

  • мердж порядка 50 веток в день в каждом из упомянутых проектов;

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

Примеры графиков слияний за несколько дней:

Количество тикетов в очереди до и после внедрения нового алгоритма:

Среднее количество тикетов в очереди (AVG) уменьшилось в 2,5 раза (3,95/1,55).

Время ожидания тикетов в минутах:

Среднее время ожидания (AVG) уменьшилось в 4,4 раза (155,5/35,07).

Подробнее..

Перевод Перерасти ПО код это современное электричество

21.06.2021 12:17:59 | Автор: admin
image

Десять лет назад Марк Андриссен написал для Wall Street Journal статью под названием "Софт пожирает мир", в которой говорит о фундаментальном сдвиге роли, которую ПО играет в экономике. В прошлом IBM, Oracle или Microsoft продавали технологии другим компаниям как инструмент. Они продавали компьютеры и ПО GE, P&G и Citibank. Теперь есть поколение компаний, которые и создают ПО, и самостоятельно используют его, чтобы войти на рынок другой отрасли, а часто и изменить его. Uber и Airbnb не продают ПО компаниям, владеющим такси или отелями, Instacart не продаёт ПО компаниям, занимающимся продуктами питания, а Transferwise не продаёт ПО банкам.

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

Но также любопытно будет взглянуть на отдельные отрасли, которые уже были подорваны программным обеспечением, и подумать над тем, что случилось дальше. Первой, очевидно, стала отрасль звукозаписей. Технологии значительно повлияли на музыкальный бизнес, но сегодня никто в сфере технологий об этом особо не задумывается. 15 или 20 лет назад музыка была способом продажи устройств и удержания людей в экосистеме, но возникновение сервисов стриминга по подписке означало, что музыка больше не является сильным стратегическим оружием ты не потеряешь свою библиотеку музыки, если перейдёшь с iPhone на Android, или даже со Spotify на Apple Music. В то же время, абсолютный размер рынка стал очень мал по сравнению с тем, чем стала сфера технологий в прошлом году общие доходы отрасли звукозаписи составили менее 20 миллиардов долларов (половина от максимума, который был в 2000 году), а доходы Apple составили 215 миллиардов. Больше никого не заботит музыка.

Нечто подобное произошло и с книгами. Amazon занимает половину рынка, электронные книги стали реальным бизнесом (хоть и остались нишевыми), а самиздат стал вертикальным, но я подозреваю, что если бы у Apple был выбор, она не стала бы снова заниматься электронными книгами. Как и в случае с музыкой, здесь нет возможности стратегического давления: общие доходы рынка книг США в прошлом году составили около 25 миллиардов, а доходы Amazon в США 260 миллиардов. Никого в сфере технологий не интересуют онлайн-продажи книг или электронные книги.

Однако в более фундаментальном смысле, с точки зрения музыки и книг, большинство споров и вопросов относятся к индустрии музыки и книг, а не к технологиям или ПО. Spotify судится с Apple по поводу правил комиссий App Store, но во всём остальном все вопросы Spotify связаны с музыкой. Почему исполнители не зарабатывают больше денег на стриминге? Спрашивайте у лейблов. Почему Интернет не убил лейблы или издателей? Спрашивайте у любителей музыки и книг.

Думаю, то же самое происходит сегодня с телевидением и кинематографом. Технологии (а теперь и локдаун) разрушили старую модель и изменили все правила, но вопросы о новых моделях это вопросы о телевидении и кино, а не о программном обеспечении. Что произойдёт с гарантированной долей Тома Круза от выручки фильма, если он стал частью пакета, используемого для продажи подписок на стриминговый сервис? Каков срок жизни шоу на Netflix, кому переходят права на спортивные трансляции, и как будут устроены периоды релизов, когда снова откроются кинотеатры? Не спрашивайте меня всё это вопросы для Лос-Анджелеса, а не для Кремниевой долины. Netflix использовал технологии в качестве рычага для попадания на телевизионный рынок, но, повторюсь, все вопросы о его будущем это вопросы о телевидении. Тем временем, фильмы и телевидение (что бы это сегодня не значило), как и музыка с книгами, имеют ограниченное стратегическое значение для крупных технологических платформ Amazon использует их как мотиватор к покупке подписок Prime, а Apple только как маркетинговый инструмент. Контент больше не главное.

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

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

Но после того, как технологии всё изменят, вопросы снова будут касаться в основном розницы, а не технологий. Какой это продукт, как ты о нём узнал, и как его получить? Это вопросы ретейла, бренда и маркетинга. Разумеется, ретейлер, продающий через новый онлайн-канал, должен быть в этом хорош, но тогда он должен быть хорош и в физическом канале. Наличие большого онлайн-опыта это условие для входа на рынок, но благодаря инструментам наподобие Shopify и Stripe он всё больше становится просто слоем в стеке. Однако правильной реализации онлайна недостаточно если бы Netflix показывал бы заново Друзей или Скорую помощь, то дело было бы не в качестве приложения, а Hulu не так популярен, как Netflix, не из-за качества сжатия. Правильная реализация онлайна и необходима, и сложна, но ваш успех будет определяться вопросами ретейла, телевидения или музыки.

На самом деле, то же относится и к Tesla: автономность это определённо вопрос ПО, но с электроприводом не всё так очевидно. Tesla бык в том, что она программная компания, и медведь в том, что автомобильная компания.

В начале статьи я упомянул Walmart как компанию, изменившую лицо рынка ретейла, но она также изменила ретейл благодаря пониманию того, что автомобилями уже владеют массы людей. Вероятно, автомобилестроение создало больше миллионеров в ретейле и недвижимости, чем в автомобильной отрасли производство автомобилей было просто одной из отраслей, но массовое владение автомобилями изменило всё остальное. Часто я думаю, что это хорошая точка зрения на современное состояние технологий: 80% взрослого населения мира имеет сегодня смартфон, что же мы можем с этим сделать? Именно это и означает софт пожирает мир. Но можно ещё и сказать, что Walmart не был создан людьми из автомобильной отрасли, из Детройта. Он был создан ретейлерами. Сэм Уолтон родился на десять лет позже появления Model T, а сегодняшние выпускники MBA родились в год выпуска Netscape. В какой-то момент в этой обстановке будет расти каждый, и все компании будут софтверными, а важные вопросы будут связаны не с ПО.



На правах рекламы


Облачный хостинг для размещения сайтов от маленького блога на Wordpress до серьёзных проектов и порталов с миллионной аудиторией. Создайте собственный тарифный план в пару кликов, максимальная конфигурация 128 ядер CPU, 512 ГБ RAM, 4000 ГБ NVMe!

Подписывайтесь на наш чат в Telegram.

Подробнее..

Перевод Учимся понимать таблицы на меньшем объеме данных

21.06.2021 14:12:41 | Автор: admin

Задача распознавания семантического следования (textual entailment), или импликации (natural language inference), в текстах на естественном языке состоит в определении того, может ли часть текста (посылка, антецедент) подразумеваться или противоречить (или не противоречить) другому фрагменту текста (следствию, консеквенту). Хотя эта проблема часто считается важным тестом на понимание в системах машинного обучения (ML) и была глубоко изучена для простых текстов, гораздо меньше усилий было приложено для применения таких моделей к структурированным данным, таким как веб-сайты, таблицы, базы данных и т. д. Тем не менее, распознавание семантического следования особенно актуально, когда содержимое таблицы необходимо точно суммировать и представить пользователю, и важно для таких приложений, где необходима высокая точность: в вопросно-ответных системах и виртуальных ассистентах.


В статье Understanding tables with intermediate pre-training, опубликованной в материалах EMNLP 2020, авторы представили первые методы предварительного обучения, адаптированные для анализа таблиц и позволяющие моделям учиться лучше, быстрее и на меньшем объеме данных. Авторы основываются на своей более ранней модели TAPAS, которая была расширением двунаправленной модели на основе Трансформера BERT со специальными эмбеддингами для поиска ответов в таблицах. Новые методы предварительного обучения на TAPAS позволяют получить лучшие метрики на нескольких наборах данных, включающих таблицы. В TabFact, например, сокращается разрыв между результатами выполнения этого задания моделью и человеком примерно на 50%. Авторы также систематически тестируют методы выбора подходящих входных данных для повышения эффективности, что позволяет достичь четырёхкратного увеличения скорости и снижения объема затрачиваемой памяти при сохранении 92% результатов. Все модели для разных задач и размеров выпущены в репозитории GitHub, где их можно опробовать в Colab-ноутбуке.


Семантическое следование


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


image5


Таблица вместе с несколькими предложениями из TabFact. Содержание таблицы может быть использовано для подтверждения или опровержения предложения.


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


TAPAS


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


Поскольку единственная информация в обучающих примерах это двоичное значение (т.е. правильно или неправильно), обучение модели для понимания того, присутствует ли в предложении семантическое следование, является нетривиальной задачей. Это в очередной раз подтверждает сложность достижения генерализации в глубоком обучении, особенно в случае достаточно скудных средств выражения необходимого значения в обучающих данных. Видя отдельные предполагаемые или опровергнутые примеры, модель может легко уловить ложные закономерности в данных. Например, в предложении Greg Norman and Billy Mayfair tie in rank (Грег Норман и Билли Мейфэр занимают равное положение) модель может выделить слово tie (галстук/связывать, разделять) вместо истинного сравнение положения Нормана и Мейфэра, необходимого для успешного применения модели за пределами исходных обучающих данных.


Методы предварительного обучения


Предварительное обучение можно использовать для прогрева моделей, предоставляя им большие объемы легко доступных неразмеченных данных. Однако предварительное обучение обычно включает в себя в основном простой текст, а не табличные данные. Фактически, TAPAS изначально был предварительно обучен с использованием простой задачи маскированного языкового моделирования, которая не предназначалась для приложений с табличными данными. Чтобы улучшить результаты модели для табличных данных, авторы представили две новые задачи бинарной классификации предварительного обучения: контрфактическую (counterfactual) и синтетическую (synthetic). Эти задачи могут применяться в качестве второго этапа предварительного обучения (часто называемого промежуточным предварительным обучением intermediate pre-training).


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


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


image1


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


Результаты


Авторы оценивают успешность контрфактического и синтетического методов предварительного обучения на наборе данных TabFact, сравнивая с базовой моделью TAPAS и двумя предыдущими моделями, которые показали хорошие результаты в области семантического следования, LogicalFactChecker (LFC) и Structure Aware Transformer (SAT). Базовая модель TAPAS демонстрирует более высокие метрики по сравнению с LFC и SAT, но предварительно обученная модель (TAPAS + CS) работает значительно лучше, достигая наивысших метрик.


Авторы также применили TAPAS + CS для вопросно-ответных задач на наборе данных SQA, для которого модель должна находить ответы из содержимого таблиц в формате диалога. Включение в задачи предварительного обучения CS повышает метрики более чем на 4 балла, демонстрируя, что этот подход также способен к генерализации за пределами семантического следования.


Accuracy


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


Данные и эффективность вычислений


Другой аспект контрфактической и синтетической задач предварительного обучения заключается в том, что, поскольку модели уже обучены для двоичной классификации, их можно применять без какой-либо тонкой настройки на TabFact. Авторы исследуют, что происходит с каждой из моделей при обучении только на поднаборе данных (или даже без них). Не увидев ни одного обучающего пример, модель TAPAS + CS способна соперничать с сильной базовой моделью Table-Bert, а при обучении всего на 10% данных, результаты становятся сопоставимы с предыдущими наивысшими метриками для этой задачи.


image7


Точность (Accuracy) на валидационном наборе данных в зависимости от объема обучающих примеров


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


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


Например, все модели, описанные выше, используют последовательности из 512 токенов, что примерно соответствует обычному порогу для модели Трансформера (хотя недавние методы повышения эффективности, такие как Reformer или Performer, доказали свою эффективность при масштабировании размера ввода). Предлагаемые в статье методы выбора столбцов позволяют ускорить обучение, сохраняя при этом высокую точность TabFact. Для 256 входных токенов получается очень небольшое снижение точности, но теперь модель можно предварительно обучить, дообучить на конкретную задачу и делать предсказания до двух раз быстрее. С 128 токенами модель по-прежнему превосходит предыдущую современную модель с еще более значительным ускорением в 4 раза быстрее по всем направлениям.


image6


Точность (Accuracy) на TabFact с использованием разной длины последовательности за счет сокращения входа с помощью предложенного метода выбора столбца.


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


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


Авторы


Подробнее..

Стоит ли смотреть в сторону Data science?

21.06.2021 16:11:25 | Автор: admin

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

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

Написать этот пост меня натолкнуло то, что полгода назад я начал писать цикл статей о самообучении и переквалификации в data sceince. В итоге, за 5 месяцев мне написало больше сотни людей с разными вопросами по такой переквалификации. И, вероятно, многие недооценивают объем знаний, который необходимо получить для этого. В этом, наверное, виноваты и заголовки моих постов "с нуля до senior data scientist за 2 года". Как мне подсказали в комментариях к тому посту - мой начальный уровень был отнюдь не нулевой (был топовым разработчиком 1С).

Почему в data science сложно попасть

Это очень много учебы и практики

Идеальный data scientist - специалист максимально высокой квалификации, знающий, одновременно:

  • всё что должны знать "простые аналитики" (SQL+визуализация данных)

  • хороший Python программист

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

  • с отличным знанием хотя бы основ теории вероятностей (в идеале - значительно глубже + линал, мат.анализ)

  • хорошие коммуникативные навыки и понимание бизнеса (невозможно эффективно обрабатывать данные из предметной области, если вы её не понимаете)

По большому счету, это несколько лет профильного (само)образования + опыт работы.

Это дорого

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

Аналитика - сестра Data science

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

Отличие аналитика: нет нужды хорошо знать статистику, нет нужны заниматься машинным обучением.

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

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

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

Суть решаемых задач аналитка: разобраться в данных, понять их и найти интересные закономерности, представить результаты в удобном и понятном для коллег виде (обычно, графики и презентации).
Ключевой набор навыков для подобной работы: это прирожденные "аналитические способности" + знания базовых инструментов (SQL+Excel) + инструменты визуализации данных (Tableau, PowerBI).

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

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

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

Рекомендуемый набор знаний для аналитика:

  • SQL + Excel

  • Tableau / PowerBI

  • Когортный анализ (принципы)

  • Понимать парадокс симпсона, чтобы не делать ошибок, к которым он приводит

  • Нужно знать основы теории вероятностей:

    • вероятности зависимых и независимых событий, условные вероятности

    • разные статистики: среднее, медиана, мода, стандартное отклонение.

  • знать что такое АВ-тесты: понимать принципы, калькуляторы есть онлайн

  • знать основы regexp. Например, веб-аналитике он используется в инструментах типа google analytics

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

Маркетинговая/веб аналитика

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

Знания специфические для веб-маркетинга (помимо обще-аналитических):

  • Понимание принципов работы контекстной рекламы (основные метрики и схемы оплаты).

  • Знание как работают UTM метки.

  • Понимание основных принципов юнит-экономики.

  • Желательно знание основ HTML

  • Популярные инструменты: Google Analytics, Яндекс.Метрика (эти инструменты можно учить уже выйдя на первую работу)

Продуктовая аналитика

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

Data engineer - брат для Data scientist

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

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

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

  • SQL

  • Python (Java, Kotlin)

  • bash

  • Docker, Kubernets

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

Ищете работу, которая вам подходит

Цель этого поста - показать что есть море вариантов интересной работы.

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

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

Подробнее..

Краткая история Windows и что у нее под капотом

21.06.2021 16:11:25 | Автор: admin


Несколько дней назад в сеть просочился образ ранней версии Windows 11. Различные издательства провели тесты по производительности и пришли к неутешительному выводу: Windows 11 в среднем работает хуже, чем Windows 10. Но расстраиваться рано! Проблемы производительности могут быть связаны с сыростью слитого образа и нюансами совместимости с текущими программами. Так или иначе, 24 июня состоится официальная презентация нового поколения операционных систем Windows, которая, возможно, даст ответы на многие вопросы. Если сегодня у вас есть настроение для ностальгии, предлагаем вам окунуться в мир Windows: познакомиться с историей, как менялась ось и что у нее внутри.

История Windows



В начале 80 годов прошлого века компания IBM работала над персональным компьютером на базе процессора Intel 8088. С середины 70 годов компания Microsoft была основным поставщиком Basic для восьмибитных микрокомпьютеров. Когда IBM обратилась к Microsoft для лицензирования Basic для их нового компьютера IBM PC, Microsoft согласилась, а также посоветовала обратиться к компании Digital Research для лицензирования операционной системы CP/M. Но, получилось так, что глава Digital Research не нашел в своем графике времени для встречи для IBM, и IBM снова обратилась к Microsoft, теперь уже с просьбой решить вопрос операционной системы для IBM PC. Microsoft купила клон ОС CP/M у компании Seattle Computer Products и перенесла её на IBM PC. Итоговым названием получившейся ОС стало MS-DOS 1.0.


IBM PC

Первые продукты с названием Windows от Microsoft не были операционными системами. Это были графические среды для MS-DOS. На фоне успеха, в том числе и коммерческого, пользовательского интерфейса на Apple Lisa, компания решила реализовать графический интерфейс на IBM PC с MS-DOS. В отличии от относительно дешевых IBM PC, Apple Lisa стоили дорого (почти 10 тысяч долларов), и немногие покупатели могли позволить купить их. Microsoft решила занять нишу дешевых компьютеров с графическим интерфейсом. При этом низкая стоимость достигалась экономией на комплектующих и более низкая производительность, по сравнению с Lisa, избежать не получилось. Так, в 1985, 1987 и в 1990 выходят первые три версии Windows 1.0, 2.0 и 3.0. Причем за первые шесть месяцев после релиза Windows 3.0 было продано более 1 миллиона экземпляров. Дальнейшее развитие Windows можно разделить на два направления Windows на базе MS-DOS и Windows на базе NT.


Windows 1.01

Windows 9x


Windows на базе MS-DOS или Windows 9x не были первыми ОС от Microsoft, но они продолжали старые традиции и были построены на основе 16-битного кода MS-DOS. В августе 1995 года была выпущена Windows 95 первая система семейства Windows 9x. Она уже была полноценной операционной системой с соответствующими возможностями. Однако у системы были проблемы с безопасностью (например, не было администратора) и с изоляцией приложений. Зависание 16-битного приложения приводило к блокировке всей системы. Проблемы со стабильностью достались и Windows 98 и Windows ME, которые отличались от выпуска 95 года рядом небольших обновлений.


Windows 95

Windows NT


В целом, к концу 80-х годов в Microsoft появилось понимание о необходимости разработки операционной системы не на базе MS-DOS. Параллельно с разработкой софта, связанного с MS-DOS, Microsoft наняла команду инженеров из компании DEC для разработки новой 32-битной операционной системы. Главой группы стал Дэйв Катлер один из главных разработчиков ОС VMS. Новая система была названа NT от сокращения New Technology. Основной упор при разработке NT делался на безопасность и надежность системы, а также на совместимость с Windows на MS-DOS. Так получилось, что опыт при разработке VMS повлиял на NT и сходство между ними стало причиной спора между DEC и Microsoft. По итогу спор был решен во внесудебном порядке.


Дэйв Катлер

Первая система Windows называлась Windows NT 3.1 и была выпущена в 1993 году. Это была первая ОС от Microsoft. Индекс 3.1 был выбран для соответствия Windows 3.1 на MS-DOS. Эта версия не имела особого успеха. Для NT требовалось больше памяти, 32-разрядных приложений на рынке было мало, возникали проблемы с совместимостью драйвером. Достичь поставленных целей смогли в NT 3.5. А первым серьезным обновлением для NT стала версия 4.0 в 96 году. Теперь эта система была мощна, надежна и безопасна, а также обеспечивала тот же интерфейс, что и Windows 95 (которая к тому моменту была чрезвычайно популярной).


Windows NT 3.1

В 2000 году вышла новая версия Windows Windows 2000. Она развивала идеи, заложенные в системы NT. Был добавлена технология Plug-and-Play, управление электропитанием и улучшен интерфейс пользователя.


Windows 2000

Успех Windows 2000 задал вектор развития для следующего поколения Windows XP. В хрюшке Microsoft улучшила совместимость, интерфейс стал более дружелюбным. Стратегия Microsoft завоевывать аудиторию уже знакомыми системами дала плоды за несколько лет Windows XP была установлена на сотнях миллионах ПК. Эпоха MS-DOS подошла к концу.


Windows XP

Следующий проект Microsoft пал жертвой собственных амбиций. Через пять лет после Windows XP, в 2006 году на свет вышла Windows Vista. В ней был переделан графический интерфейс, переработаны и добавлены функциональные возможности в плане безопасности. Была улучшена производительность, надежность.

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


Windows Vista

Проблемы Vista были учтены при разработке Windows 7. Microsoft уделила большее внимание тестированию и производительности новой системы. Windows 7 быстро вытеснила Vista, а затем и XP, став самой популярной версией Windows до появления Windows 10 (сейчас Windows 7 на втором месте по популярности).


Windows 7

Бум смартфонов в начале 2010-х подтолкнул Microsoft к созданию операционной системы, которую можно было бы развернуть на разных устройствах: на телефонах, планшетах, приставках и т. д. В результате этой работы мир узрел Windows 8. Восьмерка построена на модульном подходе MinWin для получения небольшого ядра ОС, которое можно было бы расширить на линейку других типов устройств. Но аудитория встретила холодно такой подход. Многие люди критиковали смартфоноподобный интерфейс на ПК, отсутствие кнопки пуск. Для решения многих проблем Microsoft выпустила обновление под названием Windows 8.1, которая, помимо исправления имеющихся ошибок, добавила новые функции.


Windows 8.1

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


Технические аспекты


Чтобы осветить все технические аспекты и тонкости операционной системы Windows понадобится не менее 1000 страниц. Для особо любопытных советуем 7-е издание Внутреннего устройства Windows Марка Руссиновича, специалиста по внутреннему устройству Windows. Также можно почитать Современные операционные системы Эндрю Таненбаума и Operating System Concepts: в обеих книгах есть главы, посвященные Windows. Здесь же ограничимся рассмотрением инструментов взаимодействия приложений пользователя с операционной системой (Windows API) и архитектуры оси.

Архитектура


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

Windows считается операционной системой с гибридным ядром. С одной стороны компоненты ядра Windows располагаются в вытесняемой памяти и взаимодействуют друг с другом путем передачи сообщений, как в микроядерных системах. С другой стороны ядро слишком велико (более 1 Мбайт), а большая часть кода ОС и кода драйверов устройств использует одно защищенное пространство памяти защищенного режима, что свойственно монолитным ОС. Это означает, что в теории любой компонент ОС или драйвер устройства может повредить данные, используемые другими системными компонентами. В Windows эта проблема решается за счет повышения качества и контроля происхождения сторонних драйверов через такие программы, как WHQL или KMCS. Одновременно применяются дополнительные технологии защиты ядра, такие как безопасность на базе виртуализации, функции Device Guard.

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


Упрощенная схема архитектуры Windows

Вторая линия разделяет компоненты режима ядра и гипервизор (Hyper-V). Гипервизор перехватывает многие привилегированные операции, выполняемые ядром, и эмулирует их таким образом, чтобы позволить на одной и той же машине одновременно работать нескольким операционными системам. Гипервизор работает на том же уровне привилегий процессора (0), что и ядро. Но из-за использования специализированных команд процессора (VT-x у процессоров Intel, SVM у АMD) он может изолироваться от ядра с сохранением контроля над ним и приложениями. Поэтому некоторые иногда применяют термин кольцо -1.

Четыре базовых типа процессов пользовательского режима:

  • Пользовательские процессы. Эти процессы относятся к одному из следующих типов: 32- или 64-разрядные приложения Windows (приложения Windows Apps, работающие на базе среды Windows Runtime в Windows 8 и выше, включаются в эту категорию), 16-разрядные приложения Windows 3.1, 16-разрядные приложения MS-DOS, 32- и 64-разрядные приложения POSIX. Заметим, что 16-разрядные приложения могут выполняться только в 32-разрядных версиях Windows, а приложения POSIX в Windows 8 уже не поддерживаются.
  • Процессы служб. В эту категорию входят процессы, являющиеся хостами для служб Windows (например, службы планировщика задач и диспетчер печати). Обычно к службам предъявляется требование независимости выполнения от входа пользователя. Многие серверные приложения Windows (например, Microsoft SQL Server и Microsoft Exchange Server) также включают компоненты, выполняемые как службы.
  • Системные процессы. Фиксированные процессы, такие как процесс входа или диспетчер сеансов, не являются службами Windows. Другими словами, они не запускаются диспетчером служб.
  • Серверные процессы подсистем среды. Такие процессы реализуют часть поддержки среды ОС, предоставляемой пользователю и программисту. Изначально в Windows NT было три подсистемы среды: Windows, POSIX и OS/2. Подсистема OS/2 включалась только до Windows 2000, подсистема POSIX в последний раз была включена в Windows XP.Ultimate- и Enterprise-выпуски клиента Windows 7. Все серверные версии Windows 2008 R2 включают поддержку расширенной подсистемы POSIX, называемой SUA (Subsystem for UNIX-based Applications). Сейчас подсистема SUA не поддерживается и уже не включается как необязательное часть в версии Windows (Windows 10 версии 1607 включает подсистему Windows для Linux WSL, Windows Subsystem for Linux).

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

Компоненты режима ядра:

  • Исполнительная система. Она содержит базовые сервисные функции ОС: управление памятью, управление процессами и потоками, безопасность, ввод/вывод, сетевая поддержка и межпроцессные коммуникации.
  • Ядро Windows. Низкоуровневые функции ОС: планирование потоков, диспетчеризация прерываний и исключений и многопроцессорная синхронизация. Также ядро предоставляет набор функций и базовых объектов, которые используются исполнительной системой для реализации высокоуровневых конструкций.
  • Драйверы устройств. Сюда входят как драйверы физических устройств, преобразующие вызовы пользовательских функций ввода/вывода в конкретные запросы ввода/вывода к устройству, так и драйверы устройств, не относящихся к физическому оборудованию, например драйверы файловой системы или сетевые драйверы.
  • Слой абстрагирования оборудования (HAL). Прослойка кода, изолирующее ядро, драйверы устройств и прочий исполняемый код Windows от платформенно-зависимых различий в работе оборудования, например различий между системными платами.
  • Оконная и графическая система. Реализация функций графического интерфейса (GUI), также известных как функции GDI: работа с окнами, элементы пользовательского интерфейса и графический вывод.
  • Уровень гипервизора. Включает всего-навсего один компонент: сам гипервизор. В этой среде нет ни драйверов, ни других модулей. При этом сам гипервизор состоит из нескольких внутренних уровней и служб: собственный диспетчер памяти, планировщик виртуальных процессов, управление прерываниями и таймером, функции синхронизации, разделы (экземпляры виртуальных машин) и внутрипроцессные коммуникации (IPC, Inter-Process Communication) и многие другие.

В таблице ниже представлены некоторые файлы некоторых базовых компонентов Windows:

Имя файла Компоненты
Ntoskrnl.exe Исполнительная система и ядро
Hal.dll HAL
Win32k.sys Часть подсистемы Windows режима ядра (GUI)
Hvix64.exe (Intel), Hvax64.exe (AMD) Гипервизор
.sys в \SystemRoot\System32\Drivers Основные файлы драйверов: DirectX, Volume Manager, TCP/IP и поддержка ACPI
Ntdll.dll Внутренние вспомогательные функции и заглушки диспетчеризации системных сервисных функций
Kernel32.dll, Advapi32.dll, User32.dll, Gdi32.dll Dll основных подсистем Windows

Windows API


Windows API (Application Programming Interface) это программный интерфейс пользовательского режима для Windows. До появления 64-разрядной версии операционной системы программный интерфейс 32-разрядных версий Windows назывался Win32 API в отличие от исходного 16-разрядного Windows API (программный интерфейс для исходных 16-разрядных версий Windows). На данный момент термин Windows API или Win32 API относят как к 32-разрядным, так и к 64-разрядным версиям.

В доисторические времена Windows API состоял только из функций в стиле C. Выбор языка C был обусловлен тем, что написанный на нем код также мог использоваться из других языков. Он являлся достаточно низкоуровневым для предоставления сервиса ОС. Но огромное количество функций в сочетании с недостаточной последовательностью выбора имен и отсутствием логических группировок (вроде пространств имен C++) привели к тому, что в некоторых новых API используется другой механизм модель COM.

COM базируется на двух основных принципах. Во-первых, клиенты взаимодействуют с объектами (серверные объекты COM) через интерфейсы четко определенные контракты с набором логически связанных методов, сгруппированных посредством механизма диспетчеризации по виртуальным таблицам. Такой же механизм, к слову, обычно применяется компиляторами C++ для реализации диспетчеризации виртуальных функций. Таким образом обеспечивается двоичная совместимость и снимаются проблемы с декорированием имен компилятором. Поэтому, такие методы могут вызываться из многих других языков и компиляторов, включая C, C++, VB, языки .NET, Delphi и т. д. Вторым принципом является динамическая загрузка компонентов (вместо статической компоновки с клиентом).

WinRT


В Windows 8 появился новый API и исполнительная среда поддержки Windows Runtime (WinRT). WinRT состоит из платформенных сервисов, предназначенных для разработчиков приложений Windows Apps (приложения Windows Apps подходят для устройств, начиная от миниатюрных IoT-устройств до телефонов, планшетов, десктопных систем, ноутбуков и даже Xbox One и Microsoft HoloLens).

С точки зрения API платформа WinRT строится на базе COM, добавляя в базовую инфраструктуру COM различные расширения. С архитектурной точки зрения она обладает намного большей целостностью: в ней реализованы иерархии пространств имен, последовательная схема назначения имен и паттерны программирования. На базовом двоичном уровне WinRT API все равно строится на основе унаследованных двоичных файлов и API Windows. Это не новый машинный API для системы: ситуация немного напоминает то, как .NET строится на основе традиционного Windows API.

.NET Framework


.NET Framework является частью Windows. Он состоит из двух основных компонентов:

  • CLR (Common Language Runtime). Исполнительная среда .NET, включает JIT-компилятор для преобразования инструкций языка CIL в низкоуровневый язык машинных команд процессора, сборщик мусора, систему проверки типов, безопасность обращения к коду и т. д. Среда реализована в виде внутрипроцессного сервера COM (DLL) и использует различные средства, предоставляемые Windows API.
  • .NET Framework Class Library (FCL). Обширная подборка типов, реализующих функциональность, часто используемую в клиентских и серверных приложениях, средства пользовательского интерфейса, поддержка сети, работа с базами данных и т. д.

На схеме представлены отношения между .NET Framework и ОС Windows:


Отношение между .NET и ОС Windows. Термин сервер COM обычно относится к DLL библиотеке или исполняемому файлу (EXE), в котором реализованы классы COM.
Подробнее..

Работа в Dell Technologies мнение девушки. Гендерное равенство, декреты и построение карьеры после рождения детей

21.06.2021 14:12:41 | Автор: admin

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

А начнём мы с темы девушек в IT, причём посмотрим на неё под особым углом. Главная героиня сегодняшней статьи Любовь Филимонова. Она закончила СПбГЭТУ ЛЭТИ, пришла работать в Санкт-Петербургский Центр Разработок Dell Technologies по стажёрской программе и прошла карьерный путь до инженера-тестировщика ПО в команде Dell EMC VMAX. У Любы двое детей, соответственно в декретный отпуск за время работы она уходила дважды. Именно этим опытом мы и попросили её поделиться. Отношение начальства, возможности для развития, построение карьеры после рождения детей, адаптация после долго отпуска об этом и многом другом в формате прямой речи Люба сама рассказывает под катом.

Трудоустройство мужчины и женщины в IT: есть ли разница?

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

Если говорить про карьерный путь, то тут, на мой взгляд, всё в первую очередь зависит от уверенности в себе, а не от пола. К сожалению, по моим наблюдениям, девочки из IT нередко менее уверены в себе, чем мальчики. Но в Dell Technologies всегда можно рассчитывать на помощь коллег из нашего внутреннего сообщества Women in Action, которому уже более 5 лет. Это открытая площадка, где женщины могут общаться друг с другом. Нетворкинг плюс возможность получения дополнительных знаний очень эффективная комбинация. Здесь всегда ответят на вопросы, направят, помогут прокачать софт-навыки, если их вдруг не хватает, и дадут мощный заряд позитивной мотивации. Главная цель сообщества поддерживать женщин в технологических областях, помогать им развиваться и строить карьеру.

О гендерной дискриминации в IT-индустрии

Мне кажется, что в IT-сфере уровень гендерной дискриминации гораздо ниже, чем во многих других областях. Особенно в больших международных корпорациях. Мой личный опыт показывает, что в Dell Technologies её нет вообще: просто невозможно представить, чтобы на собеседовании кто-то спросил у девушки замужем ли она и планирует ли детей. А ещё умные девочки всегда в топе: из моих однокурсниц из СПбГЭТУ ЛЭТИ нет ни одной, которая сейчас бы не работала в IT-индустрии.

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

Как руководители команд относятся к уходу девушек в декрет?

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

Отношение менеджеров и коллег

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

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

Что нравится в компании?

Для себя я вижу в Санкт-Петербургском Центре Разработок Dell Technologies много преимуществ. У коллег высокий уровень экспертизы, команды дружные, руководство лояльное и понимающее. С коллегами из Америки работать тоже комфортно. Задачи интересные и масштабные мы ведь делаем продукты для всего мира, а не только для России, и это здорово мотивирует, когда любишь свою работу, как я. А в момент выхода в декрет я увидела на собственном опыте, как быстро и эффективно передаются и подхватываются дела. Руководитель оперативно перераспределил задачи, работа не останавливалась и не провисала ни на день.

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

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

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

Если говорить про меня, то мне прокачиваться в профессиональном плане было сложно. Специфика продукта, над которым я работаю, предполагает только внутреннее обучение: что-то новое мы узнаём в основном непосредственно во время работы. Но я оставалась в курсе событий читала статьи, смотрела обучающие видео, изучала документацию. И смогла ощутимо подтянуть английский, за что, кстати, тоже спасибо компании курсы для сотрудников организует и полностью оплачивает Dell Technologies.

Как совмещать работу и воспитание детей?

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

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

Влияет ли декрет и материнство на процесс построения карьеры?

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

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

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

Смещается ли фокус на семью после рождения детей?

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

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

Мой личный опыт показывает, что включаться в работу после 3-недельного отпуска порой может быть сложнее, чем после 1,5-летнего декрета. Я думаю, что процесс адаптации в значительной степени зависит от подхода компании и руководителя команды. У нас в этом плане всё очень классно.

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

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


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

Подробнее..

Летняя распродажа

21.06.2021 12:17:59 | Автор: admin
image

Привет, Хаброжители! Стартовала летняя распродажа от издательства Питер.

image


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

Отдельные категории на сайте Бестселлеры O'Reilly, Head First O'Reilly, Manning, No Starch Press, Packt Publishing, Классика Computer Science, программирование для детей, научно-популярная серия New Science.

Книги по бизнесу, психологии, детский ассортимент.

Условия акции: 21 июня27 июня, скидка 40% на все бумажные книги по купону Бумажная книга, скидка 50% на все электронные книги по купону Электронная книга
Подробнее..

Категории

Последние комментарии

© 2006-2021, personeltest.ru