Технические заметки
19 subscribers
57 photos
15 videos
30 links
Здесь я делюсь техническим опытом, который приобретаю каждый день на работе и дома.

Сетка: https://set.ki/Nheuhoc
LinkedIn: linkedin.com/in/magrega
Download Telegram
Я придумал аудиосообщения в телеграм

Когда я учился в 7-8 классе школы, я оооочень активно переписывался смсками. Тогда у Теле2 был классный тариф, в котором смски стоили то ли 5, то ли 10 копеек, что позволяло продолжительно чатиться.

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

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

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

А лет 5 назад, кстати, я подумал о том, как меня достали проводные мышки, клавы и наушники. Как было бы круто сделать все беспроводным, но при этом не иметь необходимости это всё заряжать. Например, мышки и клавиатуры могли бы заряжаться от коврика (типа MagSafe). То есть, пока периферия на коврике - она заряжается, не надо пихать в нее никакие провода. В любой момент можно ее взять с коврика и работать уже от аккумулятора.

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

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

А вас посещали передовые идеи?

#telegram #wireless #idea
❤‍🔥1🔥1🤯1
Важность понимания сложности алгоритмов

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

В какой-то момент стали поступать жалобы от пользователей на то, что приложение вылетает на андроид-устройствах. Сами устройства довольно старые: RFID-считыватели на Android 6 и Android 14. После диагностики поняли, что суть в том, что тупо кончается оперативная память и приложение падает. Сразу оговорюсь, что к падению приложения причастен был и ряд других проблем, но в рамках темы рассмотрим только алгоритм.

Суть: в приложении есть функционал выгрузки части базы данных на устройство для оффлайн работы. При выгрузке из БД (у нас couchdb 1.7.2 😢) тянется 130000 документов. Пару секунд приложение пыжится, потом ломается. Предлагаю рассмотреть изначальный код:
obj_arr.forEach(obj => {
if (obj.m_type === OT_BAG) {
obj.art_count = obj_arr
.filter(x => (x.m_type === OT_ART) && (x.container === obj.id))
.length;
}
});

Как мы видим, внутри цикла forEach на каждой итерации вызывается filter, который проходит по тому же массиву. У нас квадратичная сложность вычисления O(n²).

Для тех, кто не в теме, приведу пример: представим, что у нас есть массив, в котором 1000 элементов. Проходя по нему одним циклом мы имеем линейную сложность вычисления O(n), потому что мы пройдем по всем элементам без исключения один раз. В данном случае n - количество элементов в массиве (1000). Количество операций равно количеству элементов.

А теперь представим, что проходя по одному элементу, мы вызываем еще один цикл, который проходится по тому же массиву (цикл в цикле). Сколько будет операций? На каждую операцию будет тоже O(n) вычислений. То есть, 1000 * 1000 = 1000000 операций. То есть, O(n * n) = O(n²).

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

В общем, решили мы это так:
let bag_art_count = {};

rows.forEach(r => {
const value = r.value || {};
if (value.m_type === OT_ART && value.container) {
bag_art_count[value.container] =
(bag_art_count[value.container] || 0) + 1;
}
});

let obj_arr = rows.map(r => {
const obj = Object.assign(
{ _id: r.value.tag.substr(0, 24), id: r.id },
r.value
);

if (obj.m_type === OT_BAG) {
obj.art_count = bag_art_count[obj.id] || 0;
obj.is_suited = (obj.art_count === 0);
}

return obj;
});

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

#javascript #algo #android
🔥31
У нас довольно непростая история с доступами во внешнюю сеть на работе. Если еще в рамках ежедневной работы что-то можно погуглить, но если нужно посветить виртуалкой в инет для простоты работы, то тут начинаются разнообразные этапы согласований, которые могут отнять время и желание вообще что-либо делать.

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

Если кратко, то мы выпустили самописный сертификат на айпи адрес в локальной сети. По сути, работает точно так же, как сертификат от Let's Encrypt. Отличие лишь в том, что нужно вручную устанавливать этот сертификат в операционную систему. Вот процедура:

1) Создаем чистую папку для работы, чтобы не запутаться в файлах.
mkdir -p /root/certs
cd /root/certs


2) Создаем «Главный ключ» и «Главный сертификат». Этим сертификатом мы будем подписывать все остальные.
openssl genrsa -aes256 -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 -out rootCA.crt

Итог: Появятся rootCA.key (секретный, никому не давать) и rootCA.crt (публичный, его будем ставить на устройства, которые будут ходить на наш сервер).

3) Создается файл настройки с расширением .conf примерно такого содержания:
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = req_distinguished_name
req_extensions = req_ext
x509_extensions = v3_req

[req_distinguished_name]
C = RU
ST = Moscow
L = Moscow
O = CompanyGroup
CN = 101.148.223.60

[req_ext]
subjectAltName = @alt_names

[v3_req]
subjectAltName = @alt_names

[alt_names]
# List all DNS names and IPs here
DNS.1 = app.mycompany.ru
IP.1 = 101.148.223.60
IP.2 = 190.118.127.12
IP.3 = 127.0.0.1

В [alt_names] мы прописываем адреса, по которым будем ходить на сервер, для которого выпускается сертификат. Нас интересует IP.1 - адрес сервера в локальной сети.

4) Генерим ключ сервера и запрос на подпись:
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 \
-keyout /etc/nginx/ssl/server.key \
-out /etc/nginx/ssl/server.crt \
-config cert_config.cnf

Появятся файлы server.key (секретный ключ) и server.csr (запрос).

5) Подписываем запрос нашим корневым сертификатом:
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \
-out server.crt -days 3650 -sha256 -extfile server.conf -extensions req_ext

Появится server.crt.

6) На этом этапе я добавил созданные сертификаты server.crt и server.key в nginx и перезапустил службу.

По сути с сертификатами всё. Теперь просто берем rootCA.crt и устанавливаем его на устройства, с которых планируется работа с сервером. Я устанавливал на Android и на Windows 11.

#ssl #dev #debian
👏3🔥2❤‍🔥1💯1
Сегодня расскажу про проброс портов в VScode. Удобная фишка, когда разрабатываешь сайт и его нужно показать кому-то. Позволяет не делать никакой деплой, все делается в рамках среды разработки.

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

Делается просто:
Например, допустим, у нас просто вёрстка HTML-файлов с помощью встроенного Live Server на порту 5500.

В VScode в терминале жмем Порты. Если терминал закрыт, можно открыть с помощью Ctrl + `, либо Вид - Терминал.

Жмем Перенаправить порт. Вводим порт 5500. Расширение попросит залогиниться - делаем.

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

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

На скринах можно посмотреть как это все выглядит.

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

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

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

#personal #thailand
2