Путь айтишника
130 subscribers
865 photos
1 file
482 links
Путь становления айтишника глазами практикующего специалиста. Личный опыт, полезные инструменты, разбор технологий, план развития и взгляд на индустрию изнутри.
Download Telegram
Решил проинтегрировать Asterisk и Bitrix24 через плагин Itgrix https://itgrix.ru/. Всё хорошо, но на FreeBSD он не работает. Мне понравилась фраза из документации: «Мучительно проходит установка на FreeBSD». Я даже написал в техподдержку, часть клиентов как-то настроила на FreeBSD, как разработчики не знают. Если хочется настроить на FreeBSD, настраивай. В результате плагин решил установить на виртуалку с Debian. Пока процесс идёт.

Для себя я сделал вывод: без практики все курсы и статьи остаются просто теорией. Настоящее понимание приходит только тогда, когда сталкиваешься с ошибками и ищешь выход самостоятельно. И пусть не всегда всё работает с первого раза, зато потом результат радует вдвойне. А значит, стоит продолжать пробовать новое, закреплять знания и превращать эксперименты в реальную пользу.
👍5👎1
Раз старое голосовое меню не пошло, надо реализовать новое. Когда думаешь о голосовом меню, кажется, что всё просто: сделал схему, прописал сценарии и готово. Но реальность совсем иная. Вместо стройной логики получаешь клубок переходов, бесконечные проверки и тонны тестов. Asterisk требует терпения, чат-бот в Битрикс24 добавляет новых задач, а Docker и Prisma превращают процесс в настоящее испытание. В итоге любое решение даётся через маленькую победу.

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

Программирование голосового меню через DialPlan под Asterisk — это какое-то издевательство над программистом. Есть текстовый редактор nano с подсветкой синтаксиса и всё. Никаких линтеров, ни анализаторов, ничего.
То, что ты ошибся, знаешь в лучшем случае при запуске команды dialplan reload. А чаще всего через звонок по телефону и чтение логов. Можешь запрограммировать любую чушь, и про ошибку узнаешь только минут через пять, когда дойдёшь до нужной ветки сценария. Напоминает экзамен Яндекса на доске. Алгоритм хороший, только не работает. Я оценил, оказывается, в JavaScript великолепные инструменты разработки, программировать в текстовом редакторе удовольствие ещё то.
Да и сам язык программирования DialPlan тот ещё кадр. Ну что сложного передать функцию с параметром? Например, надо вызвать функцию main-menu-busy с параметром menu-press-1. А нельзя. GotoIf не позволяет передавать параметры функциям, он может только их вызывать без параметров. Вот этот пример не работает.
same => n, GotoIf($["${QUEUESTATUS}"="TIMEOUT"]?main-menu-busy,1(menu-press-1))

Нужно вот так. Перейти на метку, и из неё через Gosub вызвать функцию с параметром.
same => n, GotoIf($["${QUEUESTATUS}"="TIMEOUT"]?start-nobody,1)
exten => start-nobody,1, Gosub(main-menu-busy,s,1(menu-press-1))
same => n, Hangup()

Код стал напоминать «лапша»-код с многочисленными Goto.

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

Но DialPlan — это только полбеды. Надо же ещё самого чат-бота запрограммировать. Неожиданно выползла библиотека Prisma https://www.prisma.io/, которая прекрасно работает на моём компьютере, но вот заставить работать её в Docker с минимальным набором зависимостей — задача ещё та. Я где-то день убил, пока выяснил, что ей нужно. 
Проблема ещё в том, что с одним источником данных она работает легко и быстро, а у меня их два. Моя база sqlite и CDR-логи Asterisk в формате MySQL. И теперь всё в ручном режиме, т. к. она не понимает, что от неё просят.
Мне ещё миграции для sqlite необходимо применять перед запуском приложения, т. к. база данных — это просто файл. Я хорошо произвращался над Dockerfile, прежде чем это организовал.
Но сама Prisma оказалась тот ещё фуфель. Простые запросы получаются красиво и читаемо, как только пошла группировка, агрегирующие функции и более-менее сложная аналитика. Она, оказывается, такие запросы не делает, только raw-режим. И зачем мне такая ORM?

Посмотрел 2 лекции «Функциональное программирование» https://www.youtube.com/playlist?list=PLlb7e2G7aSpTDub2LFDVBvvjWj-53Gfuh. Курс, который хвалят за академичность и доскональность. Преподаватель-математик разбирает программирование на Haskell с точки зрения математики, всё доказывает через теоремы. За 2 лекции к программированию так и не приступили. Нафиг такой курс, который я не могу понять. Поищу попроще.
❤3
Зато начал смотреть курс «Kubernetes и Helm» от PurpleSchool, и он мне понравился. Там Kubernetes разбирать с самых азов и на простых примерах, пока всё просто и понятно. Ещё выяснил, что обозначает цифра 8 в сокращении k8s, это 8 пропущенных букв. Так слово Kubernetes писать короче. Я развернул при помощи Docker Desktop на своём компьютере кластер кубера и по курсу переношу в кластер простое приложение. Пока всё получается.

Всё это напомнило, что разработка редко бывает гладкой. Asterisk со своим DialPlan, капризная Prisma, Docker и новые для меня k8s — каждый шаг требовал времени, нервов и экспериментов. Но именно через эти пробы и ошибки приходит понимание: хаос можно приручить, а сложное сделать рабочим. В итоге остаётся не усталость, а чувство, что с каждым таким проектом я становлюсь сильнее как разработчик.
❤2
Иногда работа сисадмина напоминает не стройную инженерную систему, а череду маленьких приключений. Сегодня ковыряешься в коде, завтра упираешься в странности чужих API, послезавтра выясняешь, что офисный телефон «живет своей жизнью». Вот так и проходит мой рабочий день — то борьба с Excel, то эксперименты с телефонией, то погружение в Kubernetes.

Продолжаю программировать чат-бота, который делает отчёт о звонках. Отчёт создаю в Excel при помощи библиотеки ExcelJS https://www.npmjs.com/package/exceljs. Оказалось, создание отчёта — дело на редкость муторное, мало создать данные для отчёта. Их надо стилизовать, вывести в нужные ячейки, каждой таблице сделать заголовок и т. д. и т. п. Уйма времени ушло чисто на форматирование. Где же ты, ReactJS с шаблонными компонентами? Пообщался с нашими программистами, у них на отчёты в Excel у них тоже уходит уйма времени. Я как-то работу бэкендера представлял по-иному.

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

Были и интересные случаи в телефонии. У коллеги SIP-телефон «булькал» при городских звонках. Оказалось, не тот кодек стоит по умолчанию. Необходимо было перестроить на G711аlaw. Я изменил, но он всё равно продолжал «булькать». Загрузил портянку настроек SIP этого телефона в ChatGPT, и он предложил изменить ряд параметров, до которых я бы сам не догадался в принципе. Провёл настройку, и ушло «бульканье». Я уже хотел телефон менять.

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

Продолжаю изучать курс «Kubernetes и Helm». Количество абстракций зашкаливает. Но я так подумал, если система сложная, распределённая и отказоустойчивая, проще и не получится. Ещё оказывается у k8s есть дашбоард, но автор курса говорит, лучше всё ручками будет, меньше ошибок.

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

Всю неделю программировал чат-бота. Откровенно заколебался с тайм-зонами. У меня оказалось их три. В одной базе данных UTC, в другой Москва, а в самом чат-боте Тюмень. Работа с тайм-зонами в JavaScript реализована от слова «никак». По умолчанию даты не имеют тайм-зоны. Всё решается через сторонние библиотеки. И пока найдёшь ошибку, почему здесь работает, а здесь то работает, то не работает, можно поседеть.

Я долго мучался с eslint и prettier, так новый конфиг eslint и не победил. Он то алиасы TypeScript не видит, то декораторы. Посмотрел видео Михаила Непомнящего «Next.js 15 перешёл на Biome» https://www.youtube.com/watch?v=FBbywTFHbRU
и перешёл на Biome https://www.npmjs.com/package/@biomejs/biome. Это eslint и prettier в одном флаконе. И он мне это понравился, что не нужно отключил. Работает быстро, т. к. написан на Rust. Пакет рекомендую.

Загрузку файлов на сервер Bitrix24 я победил. Есть 4 варианта, как загружать файлы. Работает по факту только один. Надо файл представить в виде base64 и загрузить в нужный каталог, а чат-бот вернёт ссылку на файл.

Наконец добрался до сисадминской задачи. Поднимал Elastic Stack (ELK) Elasticsearch, Kibana & Logstash на VPS. Решил использовать мои наработки по Ansible. И они сработали на новом сервере. Неделя работы на автоматизацию и в результате 5 минут первоначальной настройки. Кроме того, перенёс файлы Docker на второй большой диск. В целом почти настроил, но не до конца.

Начал изучать Haskell. По бесплатному курсу «Функциональное программирование на языке Haskell» https://stepik.org/course/75/syllabus. Преподаватель тот же, что и у роликов на YouTube, которые я бросил смотреть. В этом курсе он каждое своё утверждение не доказывает как теорему, и это радует. Я в математике после ВУЗа больше не практиковался. Я, конечно, понимаю, что за всеми этими буквами и цифрами заключен большой смысл, но я его уже не понимаю.

Haskell — чисто функциональный язык программирования. И в нём главное — функция.
- Функциональное программирование позволяет создавать сложные функции через композиции.
- Функции передаются как параметры и могут быть получены и возращены.
- Композиции функций позволяют строить более сложные алгоритмы.

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

Ключевое отличие между функцией и объектом — наличие состояния у объекта, у функции никакого состояния нет.

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

Все эти разнородные задачи — от автоматизации серверов до философии функционального программирования — объединяет одно: практика. Я всё больше убеждаюсь, что рост программиста измеряется не только написанными строками кода, но и способностью искать решения в разных областях. А такие недели напоминают, что развитие всегда идёт параллельными треками — и это делает процесс интересным.
👍6
За короткий промежуток времени мне удалось прикоснуться к целому спектру задач: от настройки Click2Call в Asterisk и оптимизации Elastic Stack до запуска нового IVR и первых шагов в Kubernetes. Каждая история оказалась с неожиданными поворотами: техническими, организационными и даже человеческими. Этот опыт хочется зафиксировать и рассказать подробнее.

Пришла следующая задача. Пользователь кликнул на ссылку с номером телефона на сайте, и его телефон звонит и соединяет с абонентом, по ссылке которому он кликнул. Эта технология называется Click2Call (c2c).
На Asterisk эта технология реализуется при помощи технологии Asterisk Manager Interface (AMI). Смысл технологии простой: надо подключится к Asterisk через telnet и послать текстовый файл, и Asterisk выполнит команды из него.
Но реализация хитрая, при помощи текстового файла Asterisk позвонит пользователю, а вот чтобы соединить с клиентом, надо использовать context из DialPlan.
Отправку текстового файла можно реализовать через WebSocket и через них же получение ответа, что я и сделал, написав приложение на Typescript.
Я уже радостный хотел сдавать задачу, но была пара нюансов, которые я начал выяснять в Project Manager. Выяснил, то, что написано у меня в тех. задании и то, что имел в виду клиент, это две большие разницы. И моё решение нафиг никому не нужно. Но я его довёл до конца, выложил на хостинг. Может, когда-то кому-то и будет нужно. Т. к. подсистему телефонии в нашем приложении уже давно хотят переписывать. А я разобрался с технологией AMI, поэтому поводу напишу статью в блог.

Затем несколько дней я переносил Elastic Stack (ELK) на другой сервер. При помощи Elastic можно не только логи собирать, но и реализовывать полнотекстовый поиск. Поэтому решили сделать два сервера: один для программистов, другой для админов.
Первоначально, когда я настраивал ELK, я решил писать всё. Это «всё» оказалось горой ненужного мусора, всякие debug, трассировки и т. д. В результате свободное место заканчивалось за пару дней. Сейчас весь мусор остаётся на сервере, а на ELK идут информативные логи. Буду мониторить, что я настроил.

С понедельника вся фирма перешла на новое голосовое меню. Оказалось, уйма клиентов тупо набирают основной номер и не выбирают ни одну цифру из меню, сидят и ждут. Итак 3–4 раза. Им позвонили, оказываются, они ждут оператора. Ну нет у нас оператора, цифру надо нажимать. Они просто не слушают, что им говорят по телефону.
Или один клиент, ему обещал перезвонить инженер и не перезвонил в течение последующих 2-х минут, и он начал обзванивать всех, но только не менеджера, с которым работает. Уйма звонков, которые не ведут никуда. В результате недовольный клиент.

Я завершил курс по «Kubernetes и Helm». Теперь, если по шкале от 0 до 10, я знаю Kubernetes (k8s) на 0.1. Он реально огромный. Но курс понравился, хоть и сильно вводный. Автор сначала поднял фронтенд, бекенд и nginx локально. Этот вариант от docker compose отличается мало. А затем всё шаблонизировал через helm. Больше всего не понравилось, в самом k8s всё очень сильно завязано на пробелы в yaml-файлах. Дело в том, что helm код для yaml-файлов генерирует, и при добавлении лишних 2-х пробелов создаётся такая простыня с ошибками. Ощущение, что система умерла в муках и не воскреснет никогда.
Ещё, что не понравилось в k8s. Есть система хранения секретов (пароли, доступы и т. д.), по умолчанию она ничего не защищает. Просто все секреты кодирует в base64. Нет, это решает дополнительными плагинами, но по умолчанию дыра дырой.

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

Все эти задачи — от Click2Call до Kubernetes — показали мне простую истину: технологии редко работают «из коробки», а ещё реже совпадают с ожиданиями бизнеса. Но именно в этих несовпадениях и рождается опыт. Каждый новый шаг, даже если он кажется бесполезным, открывает дверь к пониманию глубже, чем любой учебник или курс.
Знаете, что такое Click2Call? Это когда нажал на номер на сайте — и твой телефон уже звонит нужному человеку. Удобно, правда? Я решил разобраться, как эта штука работает на Asterisk, и оказалось, что всё не так уж сложно, если знать, куда копнуть.
Я написал статью в блоге, где подробно показал, как настроить manager.conf, проверить подключение через telnet и собрать рабочий AMI-скрипт для звонка. Там же есть пример контекста в extensions.conf и кусок кода на TypeScript, который отправляет команды прямо на сервер. Короче, пошаговый разбор от идеи до живого сценария, который реально работает.
Хочется посмотреть все детали и попробовать самому? Тогда заглядывайте в блог https://infoblog72.ru/moi-proektyi/click2call-na-asterisk-ot-idei-do-rabochego-sczenariya.html — там полная версия с примерами и кодом.
👍2
Эта неделя выдалась не самой продуктивной: грипп выбил из колеи, и большую часть времени я валялся на кровати, изображая тюленя. Но сидеть совсем без дела не получилось — включил обучающие видео и решил прокачать голову в сторону функционального программирования. Haskell снова напомнил, что программировать можно по-другому, а параллельно я посмотрел на новые фреймворки, чтобы оценить, как их можно применить в своих проектах.

Изучил видео по Haskell «Haskell Programming Full Course 2024» https://www.youtube.com/watch?v=TklkNLihQ_A. Было всё понятно, пока не дошли до метапрограммирования — монады, функторы, моноиды.
Т. е. если функция просто перебирает список — это просто функция. А если функция перебирает любую последовательность от дерева до хеш-таблицы, включая списки — это уже абстракция более высокого порядка под названием функтор. Монады с моноидами как-то понял, но слабо. Мне понравилась цитата: «Монада — это просто моноид в категории эндофункторов. Что может быть проще?» Может, для кого-то и проще, но я не разобрался. Кто может объяснить эту цитату, пишите в комментариях.
Функциональное программирование — это хорошо, развивает как профессионала, показывает, что можно программировать по-другому. Пока Haskell поставил на паузу, но буду присматриваться к Rescript https://rescript-lang.org/ на фронте и Elixir https://elixir-lang.org/ на беке.

Функциональное программирование занимательно, но живём мы в реальном мире, я критически посмотрел, что я напрограммировал со своим чат-ботом под Bitrix24, и понял, надо было сразу использовать фреймворк.
Поизучал, что есть из фреймворков для JavaScript, и понял, что мой выбор NestJS https://nestjs.com/.
Вот по нему базовое видео «NestJS — быстрый курс по лучшему Node.js фреймворку» https://www.youtube.com/watch?v=j2-GqaeSueA.
У этого же автора вышло новое видео «Вайб-кодинг: 10 советов, которые сразу сделают ваш код лучше» https://www.youtube.com/watch?v=DDRJg1zp_eI.
И мне понравились инструкции по архитектуре, которые давал автор, чтобы ИИ программировал приложение:
«Краткие требования: реализация на NestJS с CQRS (Command Query Responsibility Segregation).
Основные ограничения:
1. CQRS: команды (изменяют состояние) и запросы (чтение) разделены, отдельные CommandHandler и QueryHandler.
2. Тонкие контроллеры: только DTO + делегирование в CommandBus / QueryBus, бизнес-логика в хендлерах.
3. Идемпотентность: обязательна для команд создания (Idempotency-Key + таблица idempotency_keys).
4. Read-модели: агрегации (daily / weekly / monthly clicks) обновляются асинхронно, статистика eventually consistent.
5. Валидация: nestjs-zod для DTO, бизнес-инварианты — в domain-слое.
6. Авторизация: Guards + проверки владельца в хендлерах.»
Архитектуру CQRS активно использовали на моей одной из прошлых работ, правда, на .Net Core, но это нюансы. Самое интересное, модули для CQRS уже есть в NestJS. Я просто внедрял архитектуру Feature-Sliced Design (FSD) в проект, без слёз сложно вспомнить. Так что фреймворк NestJS достаточно развитый, буду учить его.

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

На этой неделе я наконец-то выздоровел, но по ощущениям не до конца. Монады в Haskell меня затянули. Я решил всё-таки разобраться, что же это такое. Если убрать строгие определения, монады — это способ программирования в функциональных языках, но для реальных систем. Это когда данных то нет, то они искажены, то они могут неожиданно прийти из другой системы и т. д. Математики - это всё собрали в красивую функциональную обёртку. Вот хорошее видео «Монады, или зачем программисту математика» https://www.youtube.com/watch?v=SXu4b3C8wtI.

А в этом видео «Виталий Брагилевский — Монады — не приговор» https://www.youtube.com/watch?v=IkXg_mjNgG4 автор показал, что императивный стиль программирования, что функциональный — это просто разный взгляд на решение одних и тех же задач. И ничуть не проще, чем императивный.
Мне понравилась цитата: «Адепты функционального программирования очень любят завлекать неопытных программистов обещаниями идеальной выразительности кода, его стопроцентной корректности, лёгкости поддержки и простоты рефакторинга. Иные даже пророчат высочайшую производительность и попадание после смерти напрямую в райские кущи. Опытные разработчики знают, что ничего такого не бывает, программирование — это тяжёлый труд, а серебряные пули, может, и помогают от вампиров, но никак не в процессе разработки ПО».

На работе я доделал Elastic Stack (ELK). Я всё думал, что за ветвистая наркомания нужна, чтобы просто парсить логи. Начал строить Dashboard и понял, для чего все многочисленные обработчики и конвейеры. По факту есть 2 сервера: один на Debian, а второй на FreeBSD. А в Dashboard должна быть табличка, самые популярные ошибки из логов и количество этих ошибок. Всё хорошо, только логи с ошибками — это текстовые строки. И эти строки сильно разные в Debian и во FreeBSD. И чтобы привести их к сопоставимым параметрам, надо использовать уйму регулярок, агрегирующих функций и т. д. Я сначала сам писал, потом плюнул и отдал на парсинг ChatGPT. Dashboard я построил, но осознал мощь дополнительного функционала.

Начал разбираться с Prometheus и Grafana. Ещё одна система мониторинга, всё думал, почему её админы Kubernetes так любят. Оказалось, система Kubernetes на редкость динамичная — контейнер появился и исчез, контейнеров было 10, а стало 100 и т. д., а в Prometheus вся динамика встроена изначально, а вот в Zabbix это надо программировать вручную. И кроме того, это всё встроено в сам Kubernetes.
Пока разбираюсь, но система интересная.

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

Заболел в очередной раз ОРВИ, с сентября всё болею, уже достало. Прошлый пост пропустил, так как все выходные «изображал тюленя» на диване. Хочется крикнуть: «Лунная призма дай мне силы», но не поможет.

Попробую выступить в жанре «коротко о длинном». В моей компании на главной странице сайта написаны номера телефонов. И начальник сообщил, чтобы я нарисовал маршрутизацию звонков. Оказалось, на 3 номера телефона приходится 4 оператора связи. Один номер на 8-800 тупо, безусловно переадресуется на тюменский номер. 2 номера приходят на старую версию голосового меню. А внутренняя адресация звонка ну до того дивная, что напоминает скорее горный серпантин, чем прямую дорогу. Убил день, чтобы 3 номера на официальном сайте звонили напрямую на новое голосовое меню. Миром правит не тайная ложа, а явная лажа.

На работе мне поручили написать очередного чат-бота. Он должен читать письма из почтового ящика и пересылать их в «Телеграмм». В письмах необходимо вырезать персональные данные, показывать только сокращённую версию и т. д. Я уже становлюсь экспертом по чат-ботам. Зная, что аппетит начальства приходит во время еды. Чувствую, что мой чат-бот будет ждать уйму доработок. Я решил не изобретать велосипед и использовать фреймворк NestJS https://nestjs.com/. На него есть уйма критики, но он мне как-то понравился. Любая моя проблема гуглится на раз-два. Код получается хоть многословным, но логичным. Есть другой безумно популярный фреймворк на NodeJS — NextJS https://nextjs.org/, но он про другое, он про генерацию страниц на стороне сервера, концепцию Backend for frontend (BFF) и т. п. А NestJS — чисто бэкенд, про вызов функций через API и Cron. Пока мой выбор — NestJS.

Я уже наученный горьким опытом, прежде чем что-то судорожно программировать начал, сначала реализовал архитектуру приложения. Нарисовал и довольный эти кубики и стрелочки начальнику отдела программистов. Он добро посмеялся и указал места, где много оверинжениринга. В результате архитектура получилась простая как табуретка. Сначала чат-бот получает почтовые сообщения. MessageID сохраняет в Redis, чтобы избежать дедупликации. Затем полученные письма отправляет в RabbitMQ, а другой модуль приложения из «кролика» считывает и отправляет 3 раза в Telegram. По результатам этой операции сообщение перемещается в папку Processed или Failed.
А можно обойтись без RabbitMQ? А нельзя, операции получения и отправки должны быть разделены. Telegram может быть недоступен, писем придёт много и т. д. В результате один созвон с начальником сэкономил уйму времени на ненужное программирование.

Haskell меня не отпускает, решил разобраться в нём до конца. На Windows Haskell полный фуфель, программирование в нём напоминает кодинг в блокноте. Что-то написал, а результаты увидишь только после компиляции. А вот бы сделать так, чтобы глупые ошибки видеть ещё до компиляции? Я решил поставить Haskell на MacOS. Больше всего меня добило, что все инструменты Haskell собирают из исходных кодов. Набрал команду и ждёшь 20-30 минут, это линтер собирается. Но я всё-таки установил и сам язык программирования, и линтер, и форматер. Эх, ещё бы IDE для Haskell, но это мечты.
Haskell решил изучать по книге Курта Уилла «Программируй на Haskell», прочитал первую главу, пока понравилась. Почему я решил изучить Haskell? Просто этот язык программирования заложен в основу многих других популярных языков. И когда команда разработки с гордостью заявляет о реализованном новом функционале, на проверку оказывается, это уже до них придумали лет 40-50 назад.

Каждый мой осенний вирус — повод перезапустить не только тело, но и мозг. Очередной бот почти готов, архитектура вычищена, Haskell побеждён наполовину. Возможно, именно так и выглядит взросление программиста — когда вместо таблеток ищешь новые фреймворки и способы думать.
👍5
Неделя выдалась насыщенной: боты, почта, Docker и вечные «давайте уточним». Хотел просто закрыть задачи и выдохнуть, но вместо этого получил классический набор приключений — от зависшего начальства до капризной Prisma. Делюсь, как всё это прошло и чем закончилось.

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

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

Но ещё правил ошибки в моём первом боте для Bitrix24. Создал багфикс, дай, думаю, задеплою на production. Залил исходники на удалённый сервер, а Docker-образ не собирается, оказывается, библиотека Prisma ORM русских не любит. Поднимать VPN на внутреннем сервере — результат так себе. Я прекрасно знаю про container registry, и он у нас даже поднят, но залогиниться я туда не могу, сколько я ни бился. Пообщался с коллегой, он подсказал простую идею: Docker-контейнеры — это просто файл, в котором каждая команда создаёт слой. Этот файл можно сохранить у себя и восстановить на production. Сказано — сделано.
; Сохраняем образ на своём компьютере
docker save -o chat-bot.tar chat-bot:latest

; Восстанавливаем образ на production
docker load -i chat-bot.tar

Сам создал себе проблему, сам решил. А container registry я внедрю.

Посмотрел 2 хороших видео блогера Soer по функциональному программированию.
«Три реализации задачи в функциональном стиле» https://www.youtube.com/watch?v=aoFZG6l8iiU и «FizzBuzz: четыре варианта решения на JS» https://www.youtube.com/watch?v=TWmmfDvcYO0. Оба видео очень хорошо показывают причудливую логику функционального программирования.

В общем, как обычно: хотел просто написать бота, а в итоге прокачал терпение, DevOps-скиллы и немного философию. Главное — не забывать сохранять образы, не только Docker, но и собственные.
Продолжаю путь в мир автоматизации, инфраструктуры и телефонии. Иногда попадаются неожиданные преграды, но тем интереснее искать обходные манёвры и проверять гипотезы. Собрал заметки о свежем опыте, чтобы не потерялось и вдруг кому-то оказалось полезным.

Завершил разработку бота, который пересылает сообщения из почты в Telegram. Проблему с библиотекой Prisma удалось обойти: отправил маршрут на роутере на адрес https://binaries.prisma.sh через сервис из трёх букв, который нельзя называть. Может кому пригодиться. Блокировку осуществляет не сама Prisma, а сервис Cloudflare, где она расположена.

Мечту о написании CI/CD для моего бота я не оставляю. У нас в качестве Container Registry используется система Harbor https://goharbor.io/. Поговорил с инженером, который поднял эту систему. Основной критерий выбора этой системы был, что у неё хорошая админка, и всё. Оказалось, что контейнер из-под Windows на неё не залить, чтобы я не делал. А вот под Linux всё идёт с полпинка. Буду «мучить» Linux.
Ещё есть мечта ошибки ошибки бота отправить на Sentry, но времени не хватает.

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

Неделя как сборка конструктора: что-то починил, что-то выкинул, что-то временно прилепил скотчем. Главное, что система становится чище и предсказуемее. Работа идёт — боты шевелятся, телефония перестаёт быть зоопарком. Продолжаю шаг за шагом приводить хаос в порядок и двигать автоматизацию вперёд.
👍3