В СИБУРе я отвечаю за разработку сервиса видеоаналитики. По сути, это система, которая в реальном времени обрабатывает видеопоток с камер на нефтехимических предприятиях. Камеры следят за технологическим процессом: считают продукцию на конвейере, определяют уровень жидкости в колбах, проверяют наличие касок на людях. Результат нужен в течение пяти секунд, потом уже поздно.
Про техническую сторону, как мы оптимизировали пайплайн и добились ускорения в 28 раз без GPU, я уже рассказывал на Хабре. Но есть вторая часть работы, и она занимает не меньше времени, чем код. Это коммуникация.
Наши заводы расположены от Твери до Амура. Серверы стоят в закрытом контуре, доступ к ним имеет ограниченное количество людей, и зачастую подключиться к машине напрямую из офиса не представляется возможным. Заказчики на производстве и мы, разработчики, говорим на разных профессиональных языках. Я сейчас не про английский и русский, а про то, что одно и то же слово может означать совершенно разные вещи для программиста и для человека на заводе. Если этот перевод не делать, технически нормальное решение просто не будет использоваться.
Кто с кем разговаривает
В нашей команде видеоаналитики три роли. Разработчики (нас двое, я как техлид и ещё один бэкенд-разработчик), инженеры-девопсы (три человека, каждый сопровождает свои кейсы на нескольких заводах) и ML-разработчик.
Отдельно есть заказчики на производстве (это могут быть разные люди, от операторов до руководителей направлений).
Для сравнения: я знаю, что в бигтехе на один продукт может выделяться команда тестировщиков, команда бэкендеров, команда фронтендеров, команда девопсов. В моем направлении вместо «команда такого-то направления» может быть один человек. А часто один человек совмещает роли нескольких направлений. Например, в одном из проектов я был одновременно техлидом, бэкендером, фронтендером и немного девопсом.
Я как разработчик не общаюсь с заводом напрямую. Между мной и заказчиком всегда стоит инженер. Он ведёт кейс: разворачивает сервисы на сервере завода, настраивает камеры, выделяет регионы на кадрах, составляет документы для реализации изменений. У него есть физический доступ к серверам в закрытом контуре, а у меня нет.
Это значит, что любая информация с производства доходит до меня через инженера: логи, обратная связь от заказчика, понимание того, как реально используется наш продукт. Если я не выстрою с ним нормальную коммуникацию, я буду разрабатывать вслепую.
Отдельно есть ML-разработчик, который обучает модели компьютерного зрения. Наши инженеры тоже сейчас осваивают обучение моделей, и ML-разработчик их лидирует в этом направлении.
Получается такая цепочка. Заказчик на заводе говорит инженеру, что ему нужно. Инженер переводит это в задачу. Я как техлид определяю, какие задачи нужно сделать нам как разработчикам, и продумываю, как новое решение встроится в текущую архитектуру, какие могут быть ответвления в дальнейшем. ML-разработчик делает или дорабатывает модель. Инженер разворачивает готовое решение на заводе. И дальше по кругу: обратная связь, корректировки, новые вопросы.
Одно слово, два значения
У каждой профессии есть своя терминология. Проблема начинается, когда одно и то же слово значит разные вещи для разных людей, и обе стороны уверены, что понимают друг друга.
Простой пример: слово «таблица». Для меня таблица это реализация сущности в базе данных. Строки, столбцы, у каждого столбца своё название на латинице, свой тип данных. Для человека с производства таблица это то, что он видит глазами: Excel-файл или форма на сайте с полями на русском языке.
Вот реальная ситуация. Допустим, в компании есть две системы, А и Б, они между собой не связаны. У бизнеса возникает потребность: когда менеджер вносит изменения в системе А, нужно, чтобы они подтянулись в систему Б. Мне, как разработчику, чтобы сделать такую интеграцию, нужно понять, как данные хранятся в базе. Я спрашиваю заказчика: «Как в базе данных называется вот это поле?» И он начинает говорить то, что написано у него на экране, по-русски, терминами из его предметной области.
Но это с базой данных вообще ничего общего не имеет. Потому что разработчики, которые создавали эту систему, могли назвать поля как угодно. Перевести термины на английский. Использовать сокращения. Написать транслитом, просто русское слово на латинице. И если это нигде не задокументировано, нужно найти человека, который помнит, почему поле называется именно так. А потом связать три слоя: то, что пользователь видит на экране; то, что имеет смысл с точки зрения бизнеса; и то, что реально лежит в базе данных. По сути, три разных названия одного и того же.
Когда начинаешь работать с людьми другого направления, быстро понимаешь: нельзя принимать слова за чистую монету. Нужно каждый раз уточнять, что конкретно человек имеет в виду. Это вроде бы очевидно, но на практике забывается постоянно, особенно когда кажется, что вопрос простой.
Два канала: приходят с болью и спрашиваю сам
У меня два способа узнать, что что-то не так.
Первый: инженеры или ML-разработчики приходят сами. Обычно это значит, что проблема уже достаточно болезненная, чтобы человек оторвался от своих задач и пришёл с ней. Инженер говорит: «У меня конфиг разросся, я не могу в нём ориентироваться». Или: «Мы не можем использовать новое решение, потому что при изменении настроек одной камеры перезапускается весь сервис». ML-разработчик жалуется, что при каждом обновлении библиотек нужно переписывать тесты во всех репозиториях. Это конкретная боль, с которой можно работать.
Второй: я сам спрашиваю. Примерно раз в две-три недели обращаюсь к инженерам и ML-разработчикам: что неудобно в работе, чем не пользуетесь, что мешает, может быть нужен какой-то инструмент. Начал я это делать примерно через год после прихода в СИБУР, первый год ушёл на то, чтобы разобраться, как у нас всё устроено. И за полтора года запросы не заканчиваются: продукт живой, кейсы добавляются, заводы подключаются, люди меняются.
Оба канала при этом упираются в одну и ту же особенность: закрытый контур. Все наши решения развёрнуты на серверах непосредственно на заводах, в изолированной сети. Я не могу сам зайти на сервер и посмотреть логи. Мне нужно просить инженера. Либо мы созваниваемся и вместе смотрим, либо я прошу выгрузить логи по конкретному сервису с конкретными ключевыми словами для поиска. Инженер подключается к машине через терминальный сервер, через несколько промежуточных соединений, находит нужное, а потом ещё нужно прокинуть файл из закрытого контура ко мне по почте.

Почему по почте — потому что другого варианта нет. У нас доменный ноутбук для работы с закрытым контуром и недоменный, на котором мы пишем код. Прямого канала между ними не существует. А почему у меня вообще нет доступа к серверам — повышенные требования безопасности нефтехимического производства. Формально доступ можно получить, но это не так быстро.
Бывают проблемы с кодировкой, бывают проблемы с подключением. И всё это при том, что система работает круглосуточно, включая выходные. Поэтому в моих интересах максимально сократить рутину для инженеров: чем быстрее они диагностируют проблему, тем быстрее она решается.
Четыре типа находок
За полтора года регулярной коммуникации я научился различать четыре типа проблем. Каждый тип обнаруживается по-своему и решается по-своему.
Лишнее: фичи, которые жрут ресурсы, но никому не нужны
Нашему продукту больше шести лет. За это время накопилось большое количество фичей, которые кто-то когда-то попросил, но которыми давно не пользуются. При этом некоторые из них отнимают вычислительные мощности, потому что постоянно что-то обрабатывают в фоне.
Вот пример. У нас есть веб-интерфейс, через который можно смотреть видеопоток, проходящий через сервис. В этом интерфейсе было два потока: один напрямую с камеры, второй с кадрами после обработки детектором. На практике инженеры пользуются только одним. Второй дублировал нагрузку впустую.
Я не могу сам зайти в логи и проверить, пользуется ли кто-то конкретной фичей, поэтому спрашиваю инженеров напрямую. Иногда ответ: «Нет, никогда не пользовались». Тогда отключаем и высвобождаем ресурсы.
В идеале на каждую фичу вешается метрика использования — ты просто смотришь на дашборд и видишь, включает кто-то эту штуку или нет. Такая практика используется для новых фичей, но в случае легаси быстрее ответить на эти вопросы разговорами.
Отдельная сложность в том, что люди меняются. Человек, который пять лет назад попросил добавить какую-то штуку, уже не работает. Я вижу эту штуку в коде, кодовая база уже большая, прошло несколько лет, и единственный способ разобраться, нужна она кому-то или нет, это спросить.
Такие фичи обнаруживаются обычно через мои опросы, а не потому что кто-то пришёл пожаловаться. Людям неоткуда знать, что фича в фоне ест ресурсы, если она не мешает им в интерфейсе.
Забытое: готовое решение, о котором никто не знает
Бывает наоборот. Ко мне за какое-то время приходили с разной обратной связью: неудобства, пожелания, жалобы. А потом, когда я делаю какую-то задачу и копаюсь в коде, нахожу фичу, которая уже реализована и которая закрывает именно эти запросы. Просто о ней никто не знает.
Вот пример. Бывает, что сервис зависает: внешне выглядит так, как будто работает, и по основным показателям тоже всё нормально. Но чтобы понять, реально он работает или нет, нужно лезть в логи. А это подключение через несколько соединений в закрытый контур. Просто чтобы проверить, тратится заметное время.
А у нас, оказывается, уже есть метрика, которая экспортируется на дашборд. Она отправляет одно значение, когда компонент работает, и другое, когда не работает. Либо вообще перестаёт отправлять. По сути, нужно просто настроить алерт на эту метрику. Я прихожу к инженерам и говорю: вот, ребята, есть такая штука, давайте настроим, и не надо будет каждый раз лезть на сервер руками.
Когда у тебя в продукте много разных метрик, накопившихся за годы, а за их актуальностью некому следить системно — потому что людей мало и приоритеты всегда на стороне бизнес-задач — такие вещи теряются. Находятся они именно на стыке: я вижу код изнутри, а инженеры приносят боль снаружи. По отдельности ни те, ни другие это решение бы не нашли.
Это особенно важно, потому что система работает круглосуточно, в том числе по выходным. Если что-то падает ночью, инженер получает сообщение и подключается. Разница между «подключился и за минуту разобрался по дашборду» и «полчаса копался в логах через три соединения» для человека, которого разбудили в три часа ночи, очень ощутима.
Такие находки появляются, когда я соединяю две вещи: запросы, которые копились за время опросов, и код, который я вижу изнутри. Ни инженеры, ни я по отдельности не нашли бы это решение, оно возникает на стыке.
Рутина: инструмент, которого не хватает
Третий тип находок: человек приходит с конкретной болью, и оказывается, что можно сделать инструмент, который эту боль снимает. Здесь ко мне приходят сами, потому что боль уже ощутимая.
Конфиг на 2000 строк
Наши сервисы настраиваются через конфигурационные файлы в формате YAML. Там описываются камеры (у каждой есть источник видеопотока, тип, опции, регионы на кадре, которые нас интересуют), детекторы, правила оповещения при эскалации инцидентов, и другое. Если завод небольшой и камер немного, конфиги компактные и читаемые. Но на одном из заводов камер было около двухсот. Структура описания некоторых модулей одинаковая, кроме одной строчки. Всё остальное копировалось. Один из конфигов разросся до 2000 строк.
Приходит инженер и говорит: конфиг огромный, уже в глазах двоится, можно ли сократить? Проблема не только в размере. Когда нужно что-то поменять, допустим обновить параметр в правилах оповещения о событиях со всех камер, нужно пробежать все 2000 строк и внести изменение в каждый блок. Что-то забудешь, поставишь не ту скобку, и можешь отключить нотификации для десятков камер разом.
notifiers: siiot_1: args: archive: after_sec: 5 before_sec: 8 host: http://127.0.0.1:12345/ login: user password: '12345' kafka: bootstrap_servers: - s01.local - s02.local - s03.local ssl_cafile: ./certs/rootCA.crt ssl_certfile: ./certs/kafka.crt ssl_keyfile: ./certs/kafka.key kafka_topic: detection video_path: incident_dir: ./video/video_camera_1 base_dir: /data/video/video_camera_1 time_before: 5 time_diff_limit: 60 cls: siiot siiot_2: args: archive: after_sec: 5 before_sec: 8 host: http://127.0.0.1:12345/ login: user password: '12345' kafka: bootstrap_servers: - s01.local - s02.local - s03.local ssl_cafile: ./certs/rootCA.crt ssl_certfile: ./certs/kafka.crt ssl_keyfile: ./certs/kafka.key kafka_topic: detection video_path: incident_dir: ./video/video_camera_2 base_dir: /data/video/video_camera_2 time_before: 5 time_diff_limit: 60 cls: siiot video_1: args: host: 127.0.0.1 login: user password: '12345' path: /video_1 port: 12346 retries: 10 time_correction: 300 timeout: 30.0 video_bitrate: 5000k cls: video video_2: args: host: 127.0.0.1 login: user password: '12345' path: /video_2 port: 12346 retries: 10 time_correction: 300 timeout: 30.0 video_bitrate: 5000k cls: video version: 0
До: каждый модуль (siiot, video) дублировался под каждую камеру целиком. siiot_1 и siiot_2 — это одинаковые блоки по 20+ строк, у которых отличается только одна вложенная секция video_path (пути к файлам конкретной камеры). Тоже самое с video_1 и video_2 — идентичные блоки, разница в одной строке path. При 200 камерах это 200 копий каждого блока.
Я посмотрел и понял, что здесь можно применить наш инструмент для миграции конфигов: когда выпускается новая версия сервиса с изменённой структурой конфига, старый конфиг автоматически преобразуется в новый формат при запуске. Старая версия при этом сохраняется, если что, можно откатиться. Мы переработали структуру так, чтобы убрать дублирование: общие параметры описываются один раз, а отличающиеся параметры перемещены в другую секцию конфига, где описываются аргументы сообщения при нотификации. 2000 строк сократились до 900. 1100 строк копипасты просто исчезла.
notifiers: siiot_1: args: archive: after_sec: 5 before_sec: 8 host: http://127.0.0.1:12345/ login: user password: '12345' kafka: bootstrap_servers: - s01.local - s02.local - s03.local ssl_cafile: ./certs/rootCA.crt ssl_certfile: ./certs/kafka.crt ssl_keyfile: ./certs/kafka.key kafka_topic: detection time_before: 5 time_diff_limit: 60 cls: siiot video_1: args: host: 127.0.0.1 login: user password: '12345' port: 12346 retries: 10 time_correction: 300 timeout: 30.0 video_bitrate: 5000k cls: video version: 2
После: модуль описан один раз. Секция video_path вообще убрана из конфига нотификатора — параметры base_dir и incident_dir перемещены в другую секцию, где описываются аргументы сообщения при нотификации. . Тоже с path у video. А time_before и time_diff_limit, которые раньше были вложены внутри video_path, просто поднялись на уровень выше, в args напрямую.
На первый взгляд, было 2000, стало 900, масштаб вроде бы тот же. Но на практике стало сильно проще. Раньше конфиг был портянкой из одинаковых блоков, в которых глаз не мог зацепиться за разницу. Теперь остались блоки, которые визуально отличаются друг от друга. Инженер видит структуру, а не месиво. И редактировать нормально, потому что одинаковые части описаны один раз.
Упрощённый продакшен для тестов
Похожая история с ML-разработчиками. Когда они разрабатывают детекторы и пишут под них тесты, каждый раз приходится воспроизводить большой массив кода, который использует наши внутренние библиотеки. Этот код дублируется из теста в тест. А когда в библиотеках что-то меняется (ребята с этими изменениями напрямую не взаимодействуют, они сконцентрированы на моделях и данных), нужно пройтись по всем тестам во всех репозиториях и обновить. Это занимает много времени.
def test_raw_events_five_region1_and_one_outside(conf: HybridConfig): with ( conf.getCamera("somecamera") as camera, # Инициализация детекторов вручную # Недостаток: привязка к структуре класса HybridConfig # Недостаток: нужно использовать контекстный менеджер или управлять контекстом вручную conf.getDetector("crop_helmet_colors_bytetrack_1") as detector_1, conf.getDetector("crop_helmet_colors_bytetrack_2") as detector_2, ): # Инициализация роутера кадров FramesRouter вручную. # Недостаток: привязка к внутренней архитектуре гибрида frames_router = FramesRouter(conf) # Получение маршрута кадра вручную для каждого детектора # Недостаток: невозможно обработать кадр в цепочке `камера -> детектор 1 -> ...`, только `камера -> детектор` route_1 = frames_router.get_route(detector=detector_1.name, camera=camera.name) route_2 = frames_router.get_route(detector=detector_2.name, camera=camera.name) # Задание общих параметров и настройка каждого детектора # Недостаток: общие параметры нужно дублировать для каждого детектора detector_1.return_raw_events = True detector_2.return_raw_events = True detector_1.return_counter_events = False detector_2.return_counter_events = False detector_1.object_min_status_count = 3 with conf.get_camera("somecamera") as camera: frames = list(limited(camera, detector_1.object_min_status_count)) for frame in frames: # Выполнение детекции по одному кадру # Недостаток: нет функциональности для получения артефактов и регионов, только ивенты events = detect_with_regions(conf, route_1, frame, detector_1) # Обработка результатов ... # Передача следующему в цепочке детектору # Недостаток: нужно вручную делать кропы кадров по ивентам с предыдущей детекции crops = make_crops(frame, events) for crop in crops: events = detect_with_regions(conf, route_2, crop, detector_2) # Обработка результатов ...
ML-разработчик вручную инициализирует каждый детектор, создаёт роутер, прописывает маршруты, дублирует параметры и нарезает кропы между стадиями. Комментарии в коде — шесть недостатков, с которыми приходилось мириться
Я разработал инструмент, который всю эту повторяющуюся логику капсулирует. По сути, он моделирует то, как работает сервис в продакшене, только сильно упрощённо. ML-разработчик может понять, как его модель будет вести себя в реальных условиях, не разворачивая всё окружение целиком. Код теста сводится буквально к пяти строчкам с понятной, повторяющейся логикой. При этом важно, чтобы интерфейс инструмента был понятным: зачем это нужно, как использовать. Потому что если инструмент неудобный, им просто не будут пользоваться.
def test_raw_events_five_region1_and_one_outside(conf: HybridConfig): # Инициализация цепочки chain_tester = DetectorChainTester(conf, camera_name="somecamera", chain_name="chain_crop_helmet_colors_bytetrack") # Задание общих параметров и настройка каждого детектора chain_tester.set_return_raw_events(True) chain_tester.set_return_counter_events(False) chain_tester.detectors[0].object_min_status_count = 3 # Подготовка кадров with conf.get_camera("somecamera") as camera: frames = list(limited(camera, chain_tester.detectors[0].object_min_status_count)) # Прогон кадров по цепочке detection_result = chain_tester.execute_chain(frames) # Получение результатов детекции на каждой стадии прохождения кадра for stage_num, stage in enumerate(detection_result): name, events, artifacts_raw, artifacts_ndarray, regions, ignore_regions = stage # Обработка результатов ...
Тот же тест с DetectorChainTester: инициализация цепочки, настройка параметров, прогон кадров и получение результатов по каждой стадии — всё в нескольких строчках. Маршрутизация, кропы и управление контекстом спрятаны внутри инструмента
Архитектурные тормоза: старое мешает новому
Четвёртый тип: фичи, которые сами по себе вроде не вредят, но архитектурно усложняют внесение изменений. Когда нужно добавить что-то новое, приходится учитывать, как это повлияет на старую фичу, которой, возможно, вообще никто не пользуется. Приходится как-то вкрячивать изменения, чтобы эта фича продолжала работать, хотя она никому не нужна. Это замедляет разработку и увеличивает риск что-нибудь сломать.
Такие вещи обычно обнаруживаются не через опрос, а в процессе работы, когда пытаешься реализовать новую задачу и натыкаешься на ограничение, которого быть не должно.
Вот пример:
Мы извлекаем видеопоток из разных источников данных: IP-камеры, изображения и видео на диске, СТВН. У каждого источника есть свои особенности, поэтому под каждый мы разрабатываем свой плагин.
Несколько лет назад был кейс, на котором видеопоток извлекался с мультикамеры - это устройство с несколькими независимыми объективами и сенсорами внутри одного корпуса, но подключенное к сети как одно логическое устройство. Мы разработали плагин под мультикамеру и реализовали кейс. Прошло несколько лет, плагин мультикамеры нигде не пригождался.
Затем начались архитектурные оптимизации сервиса, которые затрагивали и процесс чтения видеопотока. В этот момент возникла дилемма - нужно ли продолжать поддержку этого плагина, жертвуя производительностью и увеличивая время разработки, или избавиться от неиспользуемой логики и повысить производительность для всех актуальных кейсов?
Три типа задач и зачем нужна уборка
У нас каждые две недели планирование на спринт. Приоритеты по бизнесу выставляет руководитель проекта, но я и сам спрашиваю, что приоритетнее, когда есть несколько задач. В самый высокий приоритет всегда идут задачи от бизнеса: конкретный запрос, конкретный результат, конкретный срок. Допустим, подключить новый кейс на заводе, реализовать новый тип оповещения, добавить интеграцию.
Но помимо бизнес-задач я всегда беру себе одну-две задачи, которые не сильно горят, но хорошо было бы сделать. Это задачи по разработке (рефакторинг, оптимизация, обновление архитектуры, инструменты вроде тех, о которых я рассказывал выше) или работа с легаси (разложить по полочкам, убрать ненужное, переписать или выкинуть устаревшее).
Такое разбиение на три типа задач применяется ко всем разработчикам в команде.
Постоянно работать только над тяжёлыми бизнес-задачами выматывает, контекст размывается. Постоянно сидеть в легаси больно и бессмысленно, потому что по сути только уборкой занимаешься и ничего не создаёшь. Нужно и создавать, и убираться - комбинировать.
Задачи по работе с легаси я рассматриваю как разминку. С утра, когда ещё не включился в тяжёлую задачу, или вечером, когда мозги уже не соображают для сложного, можно взять что-то такое и сделать. Это вещи, которые просто нужно, чтобы кто-то сделал.
Вот пример покрупнее. В какой-то момент стало понятно, что наш ключевой сервис, который обрабатывает видеопоток, архитектурно устарел. Он изначально строился под одну камеру на один экземпляр сервиса. А бизнесу нужно было, чтобы один сервис работал с множеством камер. Не получалось нормально распараллелить обработку, а при изменении настроек одной камеры перезапускался весь сервис и все остальные камеры останавливались. Инженеры прямо пришли и сказали: мы не можем это использовать.
Мы приостановили внедрение крупных фичей на несколько месяцев, и я занялся архитектурным обновлением сервиса. Обстановка позволяла, рабочее решение уже было, заказчики не ждали критических изменений. Я специально уточнял: какие запросы от бизнеса на ближайшее время, сколько времени есть на то, чтобы этот эксперимент провести.
Если бы я полностью сфокусировался на этом, уложился бы месяца за три. В календарном времени вышло около десяти, потому что меня отвлекали на другие проекты. Но результат себя оправдал. Мы получили систему, где каждый компонент независим: можно менять настройки одной камеры, не трогая остальные; можно экспериментировать с одним детектором, не ломая соседние цепочки; два разработчика могут параллельно вносить изменения и не мешать друг другу. Плюс по дороге разгребли много накопившегося легаси.
Потом практика подтвердила, что это было правильное решение, возникли кейсы, которые без новой архитектуры было бы либо слишком сложно реализовать, либо вообще невозможно. Подробнее про техническую сторону этой переработки я рассказывал в предыдущей статье.
Вместо итогов

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

Sazonov
17.04.2026 05:54Немного не по теме статьи, но будучи лидом осознал следующее: с одной стороны у тебя больше прав чтобы влиять на проект, к тебе прислушивается команда, но с другой - часто недостаточно полномочий чтобы принимать серьезные решения. И это очень стопорит карьерный рост - мол, тебе как лиду есть еще куда расти, рано тебе повышаться до техдира.
WEBVESTA
Вот кстати да, до 80% иногда времени тратишь не на прямые задачи, а на то, чтобы просто определиться с терминологией и начать разговаривать с клиентом на одном языке. Элементарно: "директ яндекс" и "директ запрещенограмма". Еще совсем недавно, не всегда была понятно о какой именно боли пытается объяснить клиент, говоря: "у меня не работает директ".