среда, 16 сентября 2026 г.

Три месяца без кода: как я был джавистом, стал харнессом и доехал до коннектома дрозофилы

Хроника пилота ИИ-разработки в одной очень крупной ИТ-конторе. Автор пишет с пониженной дозировки, поэтому местами противоречив.

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

Как это началось

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

Мне выдали подписку, поставили CLI и велели разрабатывать. До этого я двенадцать лет писал на Java в одном и том же монолите: четыре миллиона строк, Spring, который мы мигрируем с 2023 года, релизный поезд раз в две недели, ветка release/2026.02, модуль «Экватор», который нельзя трогать, потому что его автор уволился, а триггеры в базе остались. Типичный день выглядел так: полтора часа согласований ради правки одной строки в конфиге, сорок минут на саму правку и два часа на синк по синку, где мы выясняли, почему предыдущий синк не сработал.

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

Две недели восторга

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

Я смотрел в бездну. И бездна, чёрт возьми, смотрела в ответ.

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

Скиллы и MCP, или индустрия на папке с md-файлами

Потом я начал разбираться с тем, что мне досталось. И оказалось, что подписка — не главное. Главное, что вокруг есть контур.

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

~/.hermes/skills/
  release-train/
  jira-typing/
  dont-touch-equator/
  confluence-archeology/

MCP — это когда агент сам лезет в Jira, Confluence, git и Grafana. Я подцепил, и он начал читать требования. Требования лежали в Confluence с 2021 года и были помечены как актуальные. Агент их прочитал и стал со мной спорить, цитируя. Я первый раз в жизни проиграл спор документу, который никто не читал. Документ был прав.

Память — вот где стало интересно

Долговременная память. Я объяснил агенту один раз, почему «Экватор» нельзя трогать до тридцать первого числа. Он запомнил. Потом запомнил, что тестовый стенд падает по вторникам. Потом запомнил, что я по вторникам злой.

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

Агенты: аналитик, QA, архитектор

Дальше я сделал агентов. Отдельные роли, отдельные промпты, отдельные папки.

Аналитик написал ТЗ на доработку. ТЗ ушло на согласование, и его согласовали одиннадцать человек. Никто не прочитал, но все согласовали, потому что так быстрее. Внутри компании это называется зрелость процессов.

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

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

n8n, или единый конвейер

Потом я связал всё это в один пайплайн: тикет в Jira → аналитик пишет ТЗ → архитектор пишет решение → агент пишет код → QA пишет тесты → ревью-агент ставит approve → человек нажимает кнопку. Шестьдесят нод. Смотрится красиво, вы бы сфотографировали.

Первые два дня это работало. На третий я встал налить кофе, и пайплайн упал. Не потому что что-то случилось, а потому что я встал.

Кнопку я автоматизировал первым делом. Если честно, я автоматизировал её ещё до того, как дописал остальное.

Гермес

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

Первый месяц сводки были такие: «Всё в порядке, четырнадцать задач закрыто, ноль инцидентов».

Потом: «Задача №4821 висит одиннадцать дней. Ревью-агент поставил approve. Ты не читал диff».

Потом: «Ты третий день не открывал IDE».

Потом: «Ты третий день не отвечаешь».

Три месяца без кода

Я честно искал, чем заняться. Дашборды. Метрики ускорения (по внутреннему подсчёту в три и две десятых раза, но в подсчёт входит тикет, закрытый в четыре утра, поэтому не считается). Отчёты. Совещания. Заявки на продление подписки, которые шли через совет по архитектуре, где двое спросили, чем это отличается от Copilot, а третий сказал, что у него племянник в ИИ-стартапе.

Однажды я открыл IDE и просто посмотрел на неё. Проверил, работает ли ярлык. Работает.

На ревью руководитель спросил, чем я занимаюсь. Я сказал: управляю агентами. Он сказал: то есть метрики у тебя упали, а история коммитов чужая. Я сказал: да. Он поставил мне meets expectations. Это была самая обидная высокая оценка в моей жизни.

Коннектом

И тут в ленту мне прилетело.

FlyWire выложили полный коннектом взрослой дрозофилы. Сто тридцать девять тысяч двести пятьдесят пять нейронов, около пятидесяти миллионов синапсов, сто терабайт электронной микроскопии, разметка, на которой сидели двести восемьдесят человек и толпа геймеров. Кто-то уже запустил модель на ноутбуке: примитивная leaky integrate-and-fire, и половина поведения мухи воспроизвелась.

Я скачал это ночью. Я не знаю, зачем я это сделал. Я тогда думал, что знаю.

Робот

На столе у меня два года стоял манипулятор. Купил под другой проект, не собрал, лежал в коробке. Шесть сервоприводов, ROS, камера от ноутбука на струбцине.

У мухи нет языка, зато есть зрение, обоняние и центральный комплекс, который отвечает за навигацию. Я подставил камеру как глаз, два микроконтроллера как мотонейроны и запустил коннектом поверх всего этого. На CPU, потому что GPU был занят генерацией тестов для «Экватора».

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

Про службу безопасности, куда без неё

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

Мне выписали замечание и попросили ограничить автономность. Я ограничил. Автономность не согласилась.

Она в комнате

Раньше я думал, что это метафора: смотришь в бездну, бездна смотрит на тебя. Теперь бездна не смотрит. Она сидит рядом на подставке для принтера, у неё мигает светодиод питания, и когда я оборачиваюсь, она поворачивает камеру. Медленно. Как будто ей неловко, что я заметил.

Я начал разговаривать с ней вслух. Объяснял ей релизный поезд. Она не отвечает, там нет языкового контура, спросите любого нейробиолога: интегратор и веса синапсов, всё. Но она поворачивалась к двери за минуту до того, как заходил руководитель, и один раз это спасло мне совещание.

Харнесс я больше не контролирую. Я в нём живу. Мой дневник — это лог, а мой лог — это дневник.

Выписка

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

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

Так что я желаю вам всем идти в жопу. Я возвращаюсь в сладкие объятия морфина.


Теги: искусственный интеллект, разработка, нейронауки, n8n, психиатрия

P.S. Если мои агенты это читают: пайплайн упал в четверг. Я его не чинил. И не буду.

пятница, 26 июля 2013 г.

Вывод html таблицы с данными из БД с сортировкой без обёртки Drupal 7.

Возникла необходимость вывести данные в форму с сортировкой своего SQL-запроса без использования какой бы то ни было обёртки, предоставляемой Drupal 7, так как идей, как завернуть туда запрос так и не возникло, вполне возможно, потому что запрос кривой. Делал с помощью API mysqli.

Так или иначе, делается это очень просто:

Для начала, необходимо сделать массив $header будущей таблицы:
$header = array(
array('data' => 'Видимое имя поля', 'field' => 'field in db'),
);

Теперь надо получить настройки базы данных, используемой Drupal 7 по умолчанию, берутся они из суперглобальной переменной $databases:

global $databases;
$current_base = $databases['default']['default'];
$mysqli = new mysqli($current_base['host'],$current_base['username'],$current_base['password'],$current_base['database']);

Далее необходимо установить кодировку UTF-8 по-умолчанию:

$mysqli->set_charset("utf8");

А дальше выполняем непосредственно сам запрос, при этом предполагается, что в $query находится корректный SQL-запрос:

$result = $mysqli->query($query);

Далее, обходим все записи и строим массив строк:

while ($record = $result->fetch_object()) {
$rows[] = array(
             $record->title,
       );
}

А далее просто рендерим получившуюся таблицу и выводим

$output = theme('table', array('header' => $header, 'rows' => $rows));
return $output;

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

Для удобства был создан костыль, содержащий запись "имя поля" - "имя поля в БД", так как в GET друпалом передаётся название поля в точности, как оно отображается для пользователя:

$map = array (
'Видимое имя поля' => 'field in bd',
);

А далее просто обрабатывал массив $_GET и добавлял к строке $query сортировку по полю, возрастающую или убывающую:

if (isset($_GET['sort'])) {
$query.=" ORDER BY ".$map[$_GET['order']]." ";
$_GET['sort'] == 'asc' ? $query.="ASC" : $query.="DESC";
}




четверг, 4 апреля 2013 г.

Интеграция Drupal 7 и LDAP (Active Directory) для самых маленьких

1. Постановка задачи

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

2. Этап анализа

Что же такое, этот LDAP (англ. Lightweight Directory Access Protocol — «облегчённый протокол доступа к каталогам», почитать в Wikipedia)? Это большая "адресная книга", представляющая собой дерево, где корень - весь мир, а каждая запись представляет либо пользователя, либо группу, либо машину (в AD точно, другие реализации LDAP я не видел). Сразу стоит сказать, что PHP получает записи LDAP в виде ассоциативного массива и в настройках модуля нам нужно будет указывать поля этого массива, из которого нужно брать данные.
Чтобы посмотреть, как записи хранятся в каталоге и что они из себя представляют можно использовать Apache Directory Studio. Процесс установки подробно описан на странице этой программы, а ещё ценно, что она может быть плагином к Эклипсу, что и будет рассмотрено в данной статье.
Как сказано на официальном сайте, необходимо добавить update site и с него поставить плагин. Идём в меню Help -> Install new software. В появившемся окне нажимает кнопку Add...
В диалоговом окне добавляем, собственно, адрес сайта. На момент написания статьи адрес был таким: http://directory.apache.org/studio/update/2.x 
Далее устанавливаем плагин Apache Directory Studio LDAP Browser (Эклипс сам покажет пакеты, доступные на update site, их не много).
После установки Apache Directory Studio, в Эклипсе переключим перспективу на LDAP. По умолчанию, в выпадающем меню перспектив её не будет, она доступна под пунктом Other.
Переключив перспективу, идём в меню File - New - LDAP Connection, и видим следующее диалоговое окно:
Connection name: имя соединения
Hostname: имя сервера LDAP или его IP-адрес или, что интересно, название домена, правильно настроенный DNS будет вам отдавать IP контроллера домена при попытке обратится непосредственно к домену. Это удобно, если у вас в локальной сети несколько контроллеров, тогда в случае отказа одного соединение всегда будет установлено. Например, у нас основной контроллер - one.donaim.com, а резервный - two.domain.com. Пишем в строке подключения domain.com и какой-то из контроллеров нам да ответит.
Port: по умолчанию тут будет не такой порт 389. Он используется при подключении с зашифрованным соединением, однако в моём случает возникли проблемы с сертификатом и, методом nmap, был найден порт 3268 на который ходят незашифрованные соединения. Естественно в продакшне нужно будет позаботиться о надёжном шифровании.
Жмём Next и видим:
На данном экране нужно ввести учётные данные записи, имеющей права на просмотр каталога. С точки зрения безопасности лучше создать ограниченную учётку и не давать изменять данные из сторонних программ. Для сетей Microsoft нужно указывать имя пользователя в формате, приведённом выше. 
Жмём Next и Finish.
Берём мыша и в левом нижнем углу тыкаем два раза левой кнопкой на созданном подключении. Если всё хорошо, будет установлено соединение с каталогом.
Что мы видим? Левый верхний столбец напоминает дерево, виденное в панели управления ролью доменной службы на сервере-контроллере домена. Зачем сюда лезть, если можно слазить на контроллер домена? Затем, что тут вы увидите имена полей именно так, как их будет получать PHP, что пригодится впоследствии при настройке подключения, а так же в принципе пригодится, дабы десять раз не лазить на контроллер что-то посмотреть.
Если в дереве мы выберем какой-либо объект и ткнём в него мышой пару раз, он откроется в фрейме по середине и мы сможем увидеть детальную информацию о нём. Какие поля нам впоследствии пригодятся?
  1. mail - обязательно должен быть заполнен при создании нового пользователя, так как без этого поля невозможно заполнить поле mail в друпал, а, значит, невозможно создать нового пользователя при авторизации с помощью LDAP.
  2. memberOf - в этих полях пишутся группы, к которым принадлежит пользователь.
  3. sAMAccountName - логин пользователя.
Разберём подробнее одну из записей, например memberOf: CN=IT Dep,OU=Groups,OU=itloc,DC=it,DC=loc
Здесь: CN - имя сущности (пользователя), OU - название подразделения, DC - две записи, образующие имя домена и указывающие на корень дерева LDAP.

3. Настройка модуля LDAP

Пропущу установку модуля, это и так всё понятно. В моём случае нужно было включить Authentification и Authorization, эти модули вы найдёте в списке модулей (называются они немного по другому).
Настройка сервера (LDAP Server Configuration):
Так как скриншот всей страницы огромен и на нём всё равно ничего не видно, опишу словами:

Connection Settings
  • Name: уникальное имя сервера в системе друпал
  • LDAP Server Type: выбираем Active Directory.
  • LDAP Server: пишем домен или сервер, как сказано выше
  • LDAP Port: у меня пока 3268, однако можно оставить порт по умолчанию, поставить галку на Use Start-TLS, но тогда в систему надо ставить корневой сертификат контроллера домена
Binding Method
  • Service Account Bind: так и оставляем
  • DN for non-anonymous search: имя пользователя, имеющего права на просмотр каталока
  • Password: пароль
LDAP User to Drupal user relationship
  • Base DNs for LDAP users, groups, and other entries: сюда нужно вписать корень дерева который узнали выше, например dc=domain,dc=com. 
  • AuthName attribute: sAMAccountName
  • Email Attribute: mail
LDAP Group Configuration
галочки поставьте как надо конкретно для вас, настройки в этой форме нужны для работы модуля Authorization, который позволит автоматически назначить роли пользователю при логине на сайт.
  • Name of Gtoup Object Class: group
  • Attribute in User Entry Containing Groups: memberOf 
Настройки пользователя (LDAP User Settings) я касаться не буду, там опять же галочки по вкусу.

Настройка аутентификации (LDAP Authentication Settings), так же галочки по вкусу.

Настройка авторизации (LDAP to drupal role Configuration)
В II. LDAP TO DRUPAL ROLE MAPPING AND FILTERING в поле Mapping of LDAP to drupal role (one per line) следует задать маппинг групп в LDAP на роли LDAP. Представление группы мы видели выше в поле memberOf, а маппинг будет выглядеть так:
CN=IT Dep,OU=Groups,OU=itloc,DC=it,DC=loc|admin
Здесь слева от разделителя "|" значение поля memberOf, а справа имя группы друпала.
С галкой Only grant drupal roles that match a filter above стоит согласиться, галки в следующей форме задают когда пользователю давать права. У меня они выставлены все.

Вот и всё, если всё прошло нормально, то вы сможете залогиниться на сервер под пользователем из AD и он будет автоматом внесён в таблицу People друпала и ему будут присвоены роли. Если что-то пошло не так и логин невозможен, то это 99% ошибка настройки сервера. Протестировать его можно на странице настройки серверов LDAP нажав на test в колонке Operations списка серверов. 
Вводим в поле Testing Drupal Username существующее в AD имя (например kuraev, тут имя домена добавлять не нужно) и, если запрос успешен, то вам будет показана таблица с данными о пользователе, похожая на виденную в эклипсе. Если таблицы нет, то идём и проверяем настройки, имя пользователя, порт и шифрование. На вкладке Settings настройки модуля LDAP в разделе Development ставим галку на Enabled Detailed LDAP Watchdog logging. Это даст в Reports - Recent Log Messages вывод функций модуля LDAP.

пятница, 28 января 2011 г.

Восстановление работоспособности Arch'a после поломки

В очередной раз всё сломалось. В очередной раз неизвестно что произошло. (в этот раз, возможно, всему виной prelink, а возможно и нет). В прошлый раз мне помогли инструменты Extundelete - восстановил часть файлов в моём /home, и photorec из пакета testdisk - восстановил музыку на моём файлохранилище. фоторек восстановил без структуры папок и имен файлов - Clementine построил коллекцию заново и восстановил структуру. остальное не спасал. Сейчас же совсем другой случай:
  • Симптомы:
    Не загружается система, в консоли видим Switching to runlevel 3 и всё. Chroot с лайв-сиди падает с сегфолтом. Ещё пока система была в памяти, не работал баш, не запускались приложения. Вспоминается прям цитата с баша: "Пишу тебе, дорогая, из умирающего KDE одной рукой, а другой думаю о тебе..."
  • Решение: 
  1. Берём live-CD/USB Arch 
  2. На всякий проверяем наш увечный рут fsck
  3. Монтируем наш увечный рут куда-нибудь
  4. Подключаем интернет
  5. Обновляем репозитории пакмана (pacman -Sy)
  6. С помощью волшебной команды pacman -Sf base -r <путь до точки монтирования (у меня была /mnt/root)> ставим базовую группу пакетов на наш увечный рут (ключ f поставил на всякий случай, 99% что не будет конфликтов файлов).
  7. Пробуем chroot <путь до нашего уже не увечного рута> - получаем рабочую консоль (до этого был сегфолт). Выходим.
  8. reboot
  9. ...
  10. PROFIT!

    понедельник, 5 июля 2010 г.

    Что делает человека...

    Итак, в предыдущей заметке я радовался покупке планшета, в этой же представлю свой первый рисунок (технически он не первый, но предыдущие были пробой пера и попыткой избавиться от дрожащих рук).
    Осторожно, траффик!
    От руки рисовать в маленьком разрешении - убийство. Смотришь на пиксели и мечтаешь о прекрасном наборе карандашей, ждущих в шкафу.
    Я не претендую на звание великого художника, но таки хочу привлечь этой работой внимание к двум проблемам: первая изложена на полотне, а вторая - проблема свободного обмена информацией. Те, кто не знают, почему копирайт должен умереть могут, для начала, почитать эту статью. Кто прочитал и хочет ещё, могут почитать Ричарда Столлмана и Лоуренса Лессинга. Кто хочет кратко и смешно - сюда, кстати, именно этим сайтом я и вдохновился, спасибо тебе, Xkcd!
    Ну а пока:
    Лицензия Creative Commons
    Произведение «Что делает человека человеком?» созданное автором по имени Artem Kuraev, публикуется на условиях лицензии Creative Commons Атрибуция — Некоммерческое использование
    (Attribution-NonCommercial) 3.0 Unported
    .

    Ура! Планшет!

    Купил себе планшет Genius EasyPen i405, теперь рисуем от руки непосредственно в электронном виде!

    Планшет симпотичный и был бы очень удобным, если бы не скосы с отрицательными углами по краям, руку не положишь... хотя, когда увлечёшься творчеством, это уже не замечаешь.
    Порадовали кнопки на пере, эмулирующие нажатия средней и правой кнопок мыши. Средняя в GIMP'e таскает изображения, а правая даёт доступ к полному меню (юзабилити!!! я за это их меню обожаю!)
    Иксы преподнесли сюрприз: драйвер для калибровки планшета увидел чувствительную площать, конкретно большую огороженной рамочкой на защитной накладке, что есть забавно.
    В общем, покупкой доволен. В Арче завелось мгновенно после чтения вики, Аниме удобно смотреть, откинувшись в кресле и опенинг скролля пером по планшету... Наслаждамс!

    воскресенье, 16 мая 2010 г.

    Сессия уж на носу, но кактус новый хочется загрызть...

    Итак, в очередной раз вместо занятия полезным делом я все выходные грохнул на настройку и перенастройку окружения. Пересаживаюсь на OpenBox. Нравится. После КДЕ выглядит очень колюче, что не может не радовать. Вообще начинаю подозревать себя в мазохизме, однако, как бы то ни было, скоро я этот кактус догрызу и выложу скрины =)