LE Blog

Инженер от души

06.10.2016 firtree_right Сентябрь

Хорошо, что с сентябрьским постом вышла задержка, которую я провожу в Черногории на пляже Бечичи из зелёных камней. Я никогда ещё не чувствовал себя настолько расслоённым и раздробленным, настолько разъединённым на противоречивые части, как в конце этого сентября. Никогда ещё моё желание интеграции в единое целое не было так близко к тому, чтобы уехать в неизвестном направлении одному, прервав все контакты на какое-то время. Каким-то образом я набрал у себя авансов и теперь нахожусь у самого же себя в долговой яме. Это не произошло вдруг, а планомерно делалось в течение всей жизни, а сейчас я просто оказался с этим в контакте, почувствовал. Солнце, ветер, солёная вода и горные виды вернули мне некоторое ощущение опоры под ногами. Долги надо возвращать, конечно. Особенно себе :)

♯♯♯

Прекрасное открытие месяца — это Тома Нуэво и её классы в Москве. Для простоты я всем говорю, что пошёл на танцы. Но на самом деле это целый язык движения, который был создан Охадом Нахарином в израильской танцевальной компании «Батшева», и называется «Гага». Это про проживание образа в теле, про связи и свободу между движениями и частями тела. Можно назвать это двигательной медитацией или телесной практикой. Но я всем говорю, что пошёл на танцы.

♯♯♯

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

♯♯♯

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

♯♯♯

Зарисовка: «В обед встретил ёжика, а он уже косой!»

♯♯♯

Забываю написать о процессе, который вылился, как мне кажется, из того, что я начал спать в повязке на глазах в июне. Потом в июле я уезжал в коммандировку, и это добавило в динамику процесса. Организму понравилось спать в темноте, и он нашёл наилучший для этого способ: перестроился на ранние подъёмы. Долгое время я думал, что никогда не смогу вставать рано, потому что переел этого в детстве и юности, потому что ненавидел будильники и прочее. Но, похоже, что этот долг самому себе я отдал. Годы нежной мелодии на будильнике, годы свободного графика, годы отрицания встреч раньше 12:00-13:00. Теперь я стал с удовольствием просыпаться в 8:00 утра и даже в 7:00 утра и ходить в том числе на танцы к 10:00. И даже нежную мелодию будильника не меняю. Это просто прекрасно!

♯♯♯

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

♯♯♯

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

♯♯♯

Фильмы месяца (рекомендую и напишу о них в сообщество при случае):

  1. Captain Fantastic — об искренности и внимательности;
  2. Certain Women — меланхоличный фильм-состояние, фильм-атмосфера о жизни (по другому и не скжешь коротко).

♯♯♯

Посмотрите ещё про интеграцию ролик:

07.09.2016 firtree_right Телеграм-бот для Яндекс.ПДД

Введение

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

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

Chat bot

Хуки в продакшне

У ботов Телеграм есть два способа работы: когда бот сам обращается за обновлениями по определённому адресу (polling) и с помощью веб-хуков, когда сервера сами дёргают заданный хук для передачи данных боту. В продакшне, конечно, удобнее работать с хуками, а при разработке — нет, поскольку сервер запускается на локальной машине. Кроме этого я рекомендую завести другого бота для разработки, чтобы те, кто пользуются вашим ботом в продакшне, не замечали, как вы разрабатываете. Возможность сделать это я нашёл пока только в одной библиотеке: node-telegram-bot-api с помощью недокументированной функции processUpdate. Делается это довольно просто. При инициализации бота в файле lib/bot.js:

if (process.env.NODE_ENV === 'production') {
    bot = new TelegramBot(config.botToken, {polling: false});
    bot.setWebHook(config.host + config.url);
} else {
    bot = new TelegramBot(config.devBotToken, {polling: true});
}

А затем уже в серверной части, которая, хоть и запускается всегда, имеет значение только для продакшна, в файле lib/web.js:

app.post(config.url, function (req, res) {
    options.bot.processUpdate(req.body);
    res.status(200).send({}).end();
});

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

Оповещение об остановке

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

Если вы запускаете приложения с помощью pm2, то этот менеджер использует для остановки процесса тот же сигнал SIGINT, что мы используем, когда останавливаем сервер в разработке с помощью Ctrl-C. Очень удобно! В файле index.js

process.on('SIGINT', function () {
    Promise.all(config.permitUsers.map(function (userId) {
        return bot.sendMessage(userId, 'Бот временно выключается. Только спокойствие!', {
            reply_markup: {
                hide_keyboard: true
            }
        });
    })).then(gracefulClose).catch(function (err) {
        console.log(err);
        gracefulClose();
    });
});

Таким образом, останавливая наш сервер через Ctrl-C мы видим то же, что увидит пользователь, когда перезапускается приложение на сервере.

Материалы для самостоятельного изучения

  1. Полный на текущий момент код Телеграм-бота для Яндекс.ПДД;
  2. API Яндекс.ПДД;
  3. Как установить приложение node.js на ubuntu 16.04.

28.08.2016 firtree_right Август

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

♯♯♯

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

С удовольствием почитаю ваши идеи на этот счёт.

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

♯♯♯

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

Моё знакомство с айкидо длилось с 16 до 21 года включительно. 4 года из этих 6 я занимался в Москве, но даже здесь мне нравилось. Дело в том, что Москва — довольно амбициозный город. А в айкидо нет соревнований и спаррингов, поэтому айкидоки вынуждены как-то реализовывать свои амбиции или снаружи, или жёсткостью и прочим выпендрёжем. И вот приехал к нам Миямото-сенсей (7 дан) делать семинар. Пришли все чины Федерации Айкикай. И вот все упираются и кряхтят: реализуют амбиции. Миямото-сенсей это заметил и говорит: «Чуваки, это айкидо! Нужно сотрудничать!» И следующий приём я делал с Николаем Николаевичем Егоровым — тогдашним президентом Федерации Айкидо РФ. Я весил 60 килограм (при росте 183), а он был выше меня, шире меня раза в два, имел руки как мои ноги и кулаки как моя голова. А мы делали как раз что-то от захвата мототе дори (двумя руками за одну). И я помню чёткое переживание, что если бы не указание о сотрудничестве, то при таком балансе сил никакие мои знания и умения айкидо на тот момент и в обозримом будущем не помогут мне в этом противостоянии. Я чётко понял, что если ты уже достиг в соревновательном боевом искусстве чего-то значительного, то айкидо, конечно, тебе поможет. Но идти в айкидо сначала — не вариант. И больше я айкидо серьёзно не занимался, если не считать кружка для дзенствующих.

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

Более того, на семинаре большинство людей уже довольно хорошо обращаются со своим телом и в телесных практиках находятся некоторое время. Это видно, потому что на них всех очень приятно смотреть, как они ходят, сидят, лежат. Как смотреть на котиков. Очень красиво! (^._.^)ノ А я и так очень угловат, всё свободное время провожу в диссоциации от тела, да ещё в отмороженном сопротивлении в данный момент. А они уже переходят ко всяким тонким телесным ощущениям для bodywork. А я как в том анекдоте про лисёнка, волчонка и медвежонка:

— А мне мама вчера курочку принесла! Так вкусно было!

  • А мне папа барашка притащил! Просто объедение! — А мне... А я... А я вам всем сейчас пизды дам!

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

  1. Котики! ଲ( ⓛ ω ⓛ *)ଲ Наблюдательность и чувствительность группы вызывает очень большое уважение.

  2. Поскольку я хорошо понимаю английский, у меня в два раза больше времени и можно замечать интересные особенности про перевод. Например, неоднократную фразу Пола «this doesn't make sense but it works» все переводят как «это не имеет смысла, но это работает». Хотя английский тут про чувства, а русский про мысли. Поэтому я уверен, что смысл как раз есть — в том, что это работает, но то, почему это работает, — неочевидно и/или нелепо. Или ещё Пол сказал, что я «handsome», а Саша перевела это как «милый», и я это Саше припомню, если представится возможность. А Оля при переводе активно использует пальцы ног: они как будто дирижируют. И много чего ещё.

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

  4. Как работает айкидо. Пол использует айкидо, чтобы вернуть силу человеку, с помощью движений. И преображение видно даже мне. Человек получает аналогию жизненной ситуации в виде айкидошного этюда. Выполнив его, находясь в верном состоянии, человек получает силу, которую считал утраченной в данной ситуации. Все боевые искусства решают вопрос о сохранении жизни и осознанности в конфликтной и некомфортной ситуации таким образом, чтобы выйти победителем. Это отличная аналогия. Почему айкидо? Мой вопрос варился весь второй и третий день. Финальная его формулировка была такая: «Если ты используешь айкидо как аналогию жизни, то как ты можешь давать силу людям (иллюзию силы?) с его помощью, если у тебя есть хотя бы один процент сомнений в том (а за 50 лет практики наверняка есть), что айкидо работает в реальности? Если айкидо не самое сильное боевое искусство, то почему для придания сил не использовать самое сильное?» И когда вопрос сформулировался, сразу же пришёл ответ (кроме того, что отсутствует самое сильное б.и.): для придания силы не требуется самое сильное боевое искусство, а требуется то, которое эффективно возвращает силу самому широкому кругу людей. В чём я мог уже к тому времени убедиться. Сложно описать, но исчезновение вопроса я прямо в теле почувствовал.

Потом, когда всё закончилось, у меня оставался час до тренички по файту. И я вернулся в центр, где проходил семинар. И застал Пола уже в рюкзаке. Рассказал ему всю историю от начала и до конца, включая вопрос и ответ. Он на это и говорит: «Да, большинство айкидок нихрена не знают про драку. Айкидо было придумано, чтобы драки прекратить.»

Хорошо провёл время, короче.

♯♯♯

А как у вас дела?

03.08.2016 firtree_right Июль

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

♯♯♯

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

♯♯♯

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

А ещё мы сходили на совершенно прекрасный фильм Swiss Army Man, но я уверен, что он понравится меньшинству моих знакомых. Хотя я всем готов рассказать, какой он прекрасный. Но это потому, что я люблю постмодернизм и сказки о смерти.

♯♯♯

Как раз, когда все страсти успокоились, хочу сказать про флэшмоб «я не боюсь сказать». Живя в большом городе уже довольно долго, я обнаружил, что стал совершенно невосприимчив к просьбам помочь деньгами. В большом городе много попрошаек, но со временем им всё больше и больше приходится пускаться на хитрости. В большом городе вероятность встретить человека, история которого про зачем ему нужны деньги правда, крайне мала. Большой город отключает во мне сострадание случайному человеку. Я всегда настроен критически. Интернет создаёт перманентное ощущение большого города. Здесь тоже всё время орудуют попрошайки. И здесь ещё проще обманывать. И здесь нужно ещё больше всё проверять. Невозможно точно определить, сколько действительно историй людей, нуждающихся в сочувствии, а сколько историй людей просто жаждущих внимания. И самое плохое, что делает в этой ситуации интернет — он обесценивает сам факт сочувствия и само понятие о поддержке. Лайки, репосты, реакции, комментарии — это всё настолько мало стоит человеку, что любому проще не разбираться и не вникать, а тупо полайкать всё подряд. И получается странный дисбаланс: с одной стороны никто не может прожить все те истории, которые на него сыплются из интернета, а с другой стороны, любой выплеск в этом тренде получит море поддержки. Вывода не будет. Пусть расцветают все цветы.

♯♯♯

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

01.07.2016 firtree_right Июнь

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

♯♯♯

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

♯♯♯

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

♯♯♯

Внезапно угорел по когнитивным искажениям. Кстати, какое у вас любимое из списка?

♯♯♯

Представилась возможность сказать: «Я же говорил!» Но я не стал. Во-первых, действительно, иногда более эффективно расходовать ресурс, когда ситуация уже происходит по факту, чем готовиться на всякий случай. А во-вторых, «я же говорил» — это тоже когнитивная ошибка. Я много чего говорил, что потом не произошло. Поэтому в момент предсказания по-прежнему неясно, нужно ли меня слушать. Также, если не прессовать заранее и не говорить «я же говорил», то, возможно, удастся не превратиться в злобного старикашку. :)

♯♯♯

Ещё не досмотрел шестой сезон «Игры престолов», но заметил интересный ход. С самого начала саги авторы заставили всех переживать за героев, дав понять, что любого из них могут убить в любой момент. Это интересный ход, потому что гораздо привычнее в литературе считать, что если герой удостоился заметной роли в повествовании, то его жизнь каким-то образом важна для сюжета. У него есть Предназначение, что-то должно срастись и совпасть и выстроиться в красивую линию. (Возможно, потому что вступает в силу ассоциация с собой, а про себя всегда есть какая-то история, которая всё обосновывает, потому что тяжело жить в бессмысленности бытия) Убивая героев первого плана, авторы шокируют публику. Но со временем и к этому публика привыкает, начиная следить за развитием сюжета, как за бесполезной вознёй и, видимо, теряет интерес. И вот уже авторы вынуждены воскрешать героев, возвращать забытых героев в повествование. Но при этом уже открытым текстом говорить об их избранности и предназначении. Что будет, когда и это окажется ложью? Ощущение собственной малости и незначительности — это сильное переживание. Даже, временами, интересное и привлекательное. Но кому в него охота тыкаться носом постоянно?

♯♯♯

Ещё значимое событие произошло в моём рабочем процессе. Я разбирался с показом панорам с помощью таблиц стилей. Там в браузере всё немного по странной логике построено, но вроде бы я разобрался. Собрал кубик, посчитал матрицу поворота, начал тестировать. И обнаружил, что поворот искривляется в определённом месте. То есть в одном из 16 членов матрицы поворота я ошибся в знаке. Ну, допустим, в 10 из 16 я был уверен. Но я не смог найти у себя ошибку в выводе и тупо методом тыка нашёл неверный знак в одном из оставшихся под вопросом 6 членов. То есть, моя матрица поворота теперь работает, но я не знаю, почему. Такое со мной впервые.

♯♯♯

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

♯♯♯

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

23.06.2016 firtree_right Тестирование сервера Node.js

Вводная

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

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

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

Staged reality

Кто запускает сервер

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

if (require.main === module) {
    app.use('/', require(path.join(__dirname, 'routes', 'main'))());
    var server = app.listen(5000, function () {
        ...
    });
} else {
    exports = module.exports = function (options) {
        app.use('/', require(path.join(__dirname, 'routes', 'main'))(options));
        return app;
    };
}

Таким образом, уже в тестовом фреймворке мы будем запускать:

app = require('index.js');
server = app(...).listen(6000, function (err) {...});

перед каждым тестом, а после каждого теста:

server.close(function (err) {...});

Очень удобно!

Имитация библиотек

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

В случае с паттерном фабрики мы возвращаем в качестве модуля не объект, а функцию, которая создаёт объект в соответствии с нашими параметрами:

exports = module.exports = function (options) {
    options = options || {};
    var customLib = options.customLib || require(...);

    /* GET main page. */
    router.get('/', function (req, res, next) {
        res.end('Real server text. CustomLib: ' + customLib.name);
    });

    return router;
};

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

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

Для самостоятельного изучения

Полный код примера в сборе

09.06.2016 firtree_right Куда уходят программисты

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

Missing people

Без следа

Недавно я проникся новым молодым языком программирования elm. Читал статьи, потом решил потрогать руками. Установил подсветку синтаксиса для текстового редактора, поставил библиотеки, и вдруг — беда! Поскольку язык молодой (максимум 4 года ему), то синтаксис немного поменялся в последнем релизе. И оказалось, что подсветка не работает с новым синтаксисом.

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

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

Уйти красиво

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

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

Почему

Первой же историей, которая обратила мой внимание на то, что люди отделены от своего виртуального персонажа, была история Why the Lucky Stiff. По его учебнику я изучал руби. Но в какой-то момент он решил уйти из интернета. Перед тем, как уйти в оффлайн, он написал: «Программирование весьма неблагодарно. Через год ты видишь, как твою работу замещает лучше сделанная, а через несколько лет её уже и не запустить». Это он сказал в 2009-м.

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

01.06.2016 firtree_right Май

Уже довольно долго тело находится в режиме «плато», про которое говорят в разных текстах про спорт. Изнутри это, конечно, ощущается как вечная врождённая инвалидность. Очевидно, что это естественное положение вещей: тело адаптируется наименьшей кровью ко всему. С минимально возможными затратами, и чтобы минимально измениться. Если я учусь делать что-то одно, то очень медленно прогрессирую, но только в нём: если делать упражнения на равновесие на БОСУ (такая половинка шара большая), то на полу не станет лучше получаться, пока на полу тоже не буду их делать.

♯♯♯

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

♯♯♯

Наступает эра некомпетентности. Большие и сложные системы, которые уже никто не понимает, как работают, охватывают совсем все сферы жизни.

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

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

♯♯♯

На файт к нам пришёл молодой юноша южных кровей. Ещё месяца не проходил рассказывает мне по дороге домой:

— Вот, круто, файт даже прямо придаёт уверенности в себе. Вот мы тут едем с девушкой на моей машине. У меня прав нет (лишили за езду по встречке), — она за рулём. И там есть одно место, там всегда на поворот стоят, а навстречу две полосы, ну и там все по встречке ездят. И мы едем, и мужик начинает возмущаться. Я стекло опустил, — говорит. — и даже не разозлился. Улыбаюсь и говорю ему: «Ну, зачем ты возмущаешься, езжай себе спокойно!»

Я, конечно, сделал паузу. Кто меня знает лично, знает, как я отношусь к нарушениям правил во всех областях. Думаю, как бы ему объяснить, что «поубывав бы» за такое. Говорю:

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

♯♯♯

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

26.05.2016 firtree_right Создание своих правил для udev

Магия

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

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

Вставил диск

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

Sorting robot

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

udevadm info -a --name=/dev/sdd1
udevadm info --query=env --name=/dev/sdd1

как уже говорил, имея инструкцию, как подготовить диск для копирования, можно всегда иметь одинаковую метку тома. Чем и пользуемся: создаём файлик /etc/udev/rules.d/90-my-storage-copy.rules, куда пишем:

ACTION=="add", ENV{ID_FS_USAGE}=="filesystem", ENV{ID_FS_TYPE}=="ext4", ENV{ID_FS_LABEL_ENC}=="storage-copy", RUN+="/usr/local/bin/storage-copy-mount.sh"
ACTION=="remove", ENV{ID_FS_USAGE}=="filesystem", ENV{ID_FS_TYPE}=="ext4", ENV{ID_FS_LABEL_ENC}=="storage-copy", RUN+="/usr/local/bin/storage-copy-umount.sh"

Всё, что выдавалось нам с параметром --query=env будет в параметрах окружения нашего скрипта /usr/local/bin/storage-copy-mount.sh:

#!/bin/sh
mount_point="/mnt/myrules/$(basename $DEVNAME)"
mkdir -p $mount_point
mount -t $ID_FS_TYPE -o ro $DEVNAME $mount_point

/usr/local/bin/storage-copy-umount.sh:

#!/bin/sh
mount_point="/mnt/myrules/$(basename $DEVNAME)"
umount -l -f $mount_point
rmdir $mount_point

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

Массив без массива

Второй случай — половина рэйд-массива. Нужно собирать и разбирать массивы так, чтобы это не пересекалось с работой остальной системы. Некоторые хранилища задают метки тома своим разделам с информацией, а некоторые можно определить только по номеру партиции. /etc/udev/rules.d/90-my-storage-rais.rules:

ACTION=="add", ENV{ID_FS_USAGE}=="raid", ENV{ID_FS_TYPE}=="linux_raid_member", ENV{ID_PART_ENTRY_NUMBER}=="3", ENV{ID_FS_LABEL_ENC}!="system*", RUN+="/usr/local/bin/storage-raid-mount.sh"
ACTION=="add", ENV{ID_FS_USAGE}=="raid", ENV{ID_FS_TYPE}=="linux_raid_member", ENV{ID_FS_LABEL_ENC}=="DiskStation*", RUN+="/usr/local/bin/storage-raid-mount.sh"
ACTION=="remove", ENV{ID_FS_USAGE}=="raid", ENV{ID_FS_TYPE}=="linux_raid_member", ENV{ID_PART_ENTRY_NUMBER}=="3", ENV{ID_FS_LABEL_ENC}!="system*", RUN+="/usr/local/bin/storage-raid-umount.sh"
ACTION=="remove", ENV{ID_FS_USAGE}=="raid", ENV{ID_FS_TYPE}=="linux_raid_member", ENV{ID_FS_LABEL_ENC}=="DiskStation*", RUN+="/usr/local/bin/storage-raid-umount.sh"

То есть, говоря человеческим языком, это или рэйд-партиция с номером 3, название которой не начинается с system или рэйд-партиция с именем, начинающимся с DiskStation. Теперь нам нужно собрать массив так, чтобы у него было уникальное имя, но при этом однозначно связанное с устройством, чтобы не плодить лишних сущностей. Для этого я решил точку для монтирования называть так же как имя устройства в /dev, а номер рейда брать из кода последней буквы. /usr/local/bin/storage-raid-mount.sh:

#!/bin/sh

mount_point="/mnt/myrules/$(basename $DEVNAME)"
num=$(printf %d "'$(echo $DEVNAME | head -c8 | tail -c1)")
raid_device="/dev/md$num"

mkdir -p $mount_point
mdadm -S $raid_device
mdadm -A -R $raid_device $DEVNAME
mount -o ro $raid_device $mount_point

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

echo $DEVNAME | head -c8 | tail -c1

Выдаёт нам восьмую букву имени устройства, то есть «d» для «/dev/sdd3», например, и «f» для «/dev/sdf5».

printf %d "'d"

Выдаёт нам 100, а в случае с «f» — 102. И мы получаем имя «/dev/md100», под которым насильно поднимаем raid1 на одном диске из двух. И обратно то же самое. /usr/local/bin/storage-raid-umount.sh

#!/bin/sh

mount_point="/mnt/myrules/$(basename $DEVNAME)"
num=$(printf %d "'$(echo $DEVNAME | head -c8 | tail -c1)")
raid_device="/dev/md$num"

umount -l -f $mount_point
mdadm -S $raid_device
rmdir $mount_point

Понятно, что с вытаскиванием сложнее, даже если монтировать, как это делаю я, только для чтения. Это всё актуально, если после работы с диском прошло значительное время. И я предпочитаю хотя бы размонтировать вручную. Но при этом совершенно прекрасно то, что все наши устройства будут создавать папки и появляться в /mnt/myrules, как флэшки появляются в /media на десктопных версиях Убунту.

Для самостоятельного изучения

  1. man udev

11.05.2016 firtree_right Как показать Яндекс Панорамы где угодно

История

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

Со временем, сменился плеер и появился код вставки вида:

<script src="//panoramas.api-maps....."></script>

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

Hack

Параметры

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

ll=37.61782676%2C55.75074572

Это же долгота и широта (в таком порядке) через запятую! Второе, с чем сразу же хочется повозиться — это параметр:

size=690%2C495

Это ширина и высота окна через запятую. Если посмотреть на то, как работает скрипт, и что он оставляет после себя на странице, то совсем не обязательно лезть и деобфусцировать код. Всё понятно: скрипт создаёт вместо себя тег iframe и другой тег script, а себя удаляет. Параметр size и задаёт размеры айфрейма.

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

var latlng = L.latLng(55.75074572, 37.61782676);
var $map = L.map('map', {center: latlng, zoom: 15});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo($map);

function openPanoramaAt(latlng) {
    var panoDiv = $('#panorama');
    var panoScript = document.createElement('script');
    panoScript.type = 'text/javascript';
    panoScript.src = 'https://panoramas.api-maps.yandex.ru/embed/1.x/?lang=ru&ll=' + latlng.lng + '%2C' + latlng.lat + '&ost=dir%3A0.0%2C0.0~span%3A130%2C70.26418362927674&size=' + panoDiv.width() + '%2C' + panoDiv.height() + '&l=stv';
    panoDiv.empty();
    panoDiv[0].appendChild(panoScript);
}

openPanoramaAt(latlng);

$map.on('click', function (me) {
    $map.panTo(me.latlng);
    openPanoramaAt(me.latlng);
});

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

Но нам нужно идти дальше. Ведь внутри панорам можно переходить по стрелкам, а у нас это никак не отображается на карте. Что же делать?

Человек посередине

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

Переходя по стрелкам мы увидим, что, кроме всего прочего, плеер запрашивает файлик по адресу _https://panoramas.api-maps.yandex.ru/panorama/1.x/?l=stv&lang=ru_RU&...&format=json_. Тут уже нет широты и долготы, а присутствует идентификатор, но если открыть этот джейсон в новой вкладке, то внутри него мы увидим нужные нам координаты:

JSON.parse(response).data.Data.Point.coordinates

То, что браузер видит это запрос, означает, что скорее всего в основе лежит XMLHttpRequest. Так как заголовка Content-Security-Policy не видно (по правде сказать, настраивать его довольно сложно, и обычно если кто и прописывает такой заголовок, то там среди прочего есть unsafe-inline), то мы попробуем подслушать, о чём говорит плеер с сервером.

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

Сразу видно несколько недостатков:

  1. Размеры панорамы не адаптируются при изменении размеров окна.
  2. Невозможно отследить направление взгляда, чтобы показать его на карте. Я рылся в объектах, но ничего не нашёл.
  3. Пришла беда, откуда не ждали: случился прогресс!

Правильный API

Тема этого топика была запланирована у меня некоторое время назад. И основные фишки были опробованы и сделаны тоже некоторое время назад. Но когда я сел писать конкретный код, то обнаружил, что в стандартной поставке API карт уже есть панорамы. Произошло это в прошлой версии 2.1.38 от 31 марта 2016. Сейчас я работал с 2.1.39. Всего 42 дня как можно ставить панорамы на карты!

Конечно же, я собрал такой же пример на API Яндекс Карт. (Всё-таки синтаксис лифлета намного изящнее, извините). Это настолько новое явление, что даже не входит в стандартный полный набор модулей. Заметьте во внешних ресурсах слева я написал для загрузки (иначе не работает):

load=package.full,panorama.isSupported,panorama.locate,panorama.createPlayer,panorama.Player

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

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

Отдельно ссылки:

  1. Как приспособить код для вставки Яндекс Панорам на свои карты (jsfiddle);
  2. Как показать панорамы с помощью API Яндекс Карт (jsfiddle);
  3. Intercept all ajax calls (stackoverflow);
  4. API Яндекс Карт;
  5. Лучший API для картографических сервисов Leaflet.