Технологии, которые меняют нас: История одной 1С‑команды. 1С.. 1С. 1с предприятие.. 1С. 1с предприятие. edt.. 1С. 1с предприятие. edt. Git.. 1С. 1с предприятие. edt. Git. Блог компании АльфаСтрахование.. 1С. 1с предприятие. edt. Git. Блог компании АльфаСтрахование. ИИ.

«Чтобы оставаться на месте, нужно бежать со всех ног. А чтобы куда‑то попасть, надо бежать как минимум вдвое быстрее» — Льюис Кэрролл

Пролог. День, когда опять что‑то сломалось

Это было очередное утро после вечернего обновления релиза. В рабочей базе уже несколько часов валилась какая‑то ошибка. Пользователи писали в поддержку, поддержка — нам. В чем оказалась причина? Всего одна строчка кода — мы потеряли ее во время ручного переноса из дева в релизное хранилище.

Далее последовал примерно следующий диалог:

Руководство: «А откуда ошибка? Разве мы вчера всё не протестировали?».
Мы: «Протестировали, но ошибку довнесли позже».
Руководство: «А как нам этого избежать в будущем? Может автотесты какие добавить или ИИ привлечь? Что нужно сделать?».
Мы: (короткое молчание) «Пока точно не знаем, подумаем..».

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

В тот вечер в поисковиках у команды начали появляться следующие запросы: «Как перейти с конфигуратора 1С на EDT», “Git для 1С”, «ИИ в 1С‑разработке» и пр. И пока мы даже не задумывались, что запущен самый сложный, дорогой и одновременно очень нужный проект в нашей команде.

Часть 1. Наше бытие и ловушка комфорта

Мы — довольно большая компания. То, как мы работаем с 1С, должно быть многим будет знакомо. Есть два хранилища — dev и release. Разработчик делает правки, потом вручную, через «сравнение и объединение», переносит их в релизную базу. Получается, наш merge — это частый копипаст из окна в окно, либо сравнение/объединение, и постоянный риск забыть что‑то или перенести не так и не туда.

Code review? Формально он есть. Но найти и посмотреть изменения разработчика в Конфигураторе — довольно муторное занятие. Даже настроен SonarQube, но полностью ему на откуп проверку кода не отдаем, он как дополнительный информатор. На практике ревью сводилось к фразе «Ты посмотрел задачу? Сейчас гляну».

Про CI/CD слышали, что‑то даже есть. Настроен скрипт, который периодически выгружает хранилище в Git. Без веток задач, только теги на них в коммитах. По сути Git используется просто как архив, а не как основной инструмент, и использовать его для развертывания систем не можем.

И знаете, что здесь самое опасное? Все к такой работе привыкли и всех всё устраивало. Зачем что‑то менять, если «и так работает». Да и времени особо на нововведения нет, поток новых задач идет постоянно.

«Если ты не идёшь вперёд, ты откатываешься назад. В стоячей воде неизбежно начинается гниение» — Лао Цзы

Казалось, мы стоим в этой самой воде и она начинает понемногу пахнуть.

Часть 2. Новые надежды и встреча с реальностью

После исследования чужого опыта и погружения в тему, твердо решили: движемся в сторону перехода на EDT. Он хранит конфигурацию в отдельных файлах на диске, а это открывает дверь к Git с отдельными ветками задач, Merge‑requestами и полноценным code‑review. Есть какие‑то альтернативные варианты по синхронизации конфигуратора с Git, но скорее всего это было бы промежуточным переходом, надо сразу ставить разработку на правильные рельсы.

Мы представляли, что наши разработчики, как в Google: пишут код, делают коммиты, еще и ИИ используют на каждом шагу. Наши надежды были наивными и прекрасными. Реальность же оказалась жёстче.

Первая стена — не бюджетное железо

Конфигуратор работает на любом «калькуляторе», а EDT — это тяжелая IDE на Eclipse. На обычном ноутбуке с 8–16 ГБ ОЗУ она грузится и подключает базу неприлично долго. Работать на «стандартном железе» было бы невозможно.

«Гладкая дорога никогда не делает умелого водителя» — Латинская пословица

Мы собрали основные требования: 32 ГБ ОЗУ, быстрый SSD, современный производительный процессор. Для всей команды надо закупить хорошие рабочие станции, а лучше ноутбуки. А ведь это заранее незапланированный бюджет.

Вторая стена — сторонние разработчики

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

Решение ещё ищем, и то что сейчас прорабатываем — не такое красивое: синхронизация через файлы *.cf. Те, кто в EDT, работают в Git. Для внешних разработчиков выгружаем cf‑файл с изменениями. Схема сложная, но кажется позволяет начать двигаться вперед.

Третья стена — человеческий фактор

Люди боятся нового и не хотят ничего менять, это не новость.

«Зачем мне EDT? У меня куча задач и в Конфигураторе я всё успеваю» — высказались некоторые разработчики. «Это всё сложно, долго и не работает» — вторили им другие.

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

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

«Трудности — это не преграды на пути, они и есть путь» — Райан Холидей

Главный вывод этой части: EDT при серьезной разработке в 1С — это уже не дань моде, а необходимость. Но этот путь требует мощных компьютеров, терпения и готовности от всех меняться.

Часть 3. Следующий уровень в работе

Здесь еще раз проговорим, зачем нам все это? Когда мы освоим EDT и Git, перед нами откроются горизонты, о которых мы раньше даже не мечтали:

Настоящий code review

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

В нашем светлом будущем нас ждет merge‑request. Каждая ветка‑задача проходит ревью. Мы сразу видим строки, которые изменились, всё в одном месте.

А ещё можно начать использовать Git‑хуки. Подключить скрипты, которые автоматически проверяют код перед коммитом или пушем, с помощью различных сервисов, в том числе на основе ИИ.

Автоматизация тестирования с Vanessa Automation

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

Сейчас активно развиваем Vanessa Automation — полноценный фреймворк для автоматизированного тестирования в 1С. А тут еще в последних версиях у нее появилась поддержка ИИ и MCP‑серверов, что кажется может дать огромную выгоду в генерацию тестовых данных. Vanessa сможет сама подготовить данные для теста: создать документы, заполнить справочники. ИИ поможет написать и сами тесты.

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

Сборка и выпуск приложения

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

Технологии, которые меняют нас: История одной 1С‑команды - 1

Часть 4. ИИ — не игрушка, а пропуск в будущее

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

И после этого задаешься вопросом: «Почему у нас этого нет?». Ответ обычно таков: потому что Конфигуратор, а совместное использование ИИ с ним трудно совместимо. Решим проблему с Конфигуратором — решим проблему с полноценным внедрением и использованием ИИ.

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

Проблема: ИИ слепой

ИИ вполне себе знает синтаксис 1С и даже может написать красивый код. Но он не знает про ваш справочник «Номенклатура» или «Товары», не знает реквизиты ваших документов и тому подобное. Пытается что‑то «правдоподобно угадать» и как результат — генерирует мёртвый код. Ему нужен ваш контекст!

Решение: MCP (Model Context Protocol) — “USB‑порт” для нейросети. Стандарт, который позволяет ИИ подключиться к вашей конфигурации и «увидеть» её. Сейчас активно тестируем некоторые из них, благо подобные инструменты для 1С начали активно появляться. Будем тестировать их как в отдельных средах так и внутри EDT, посмотрим что понравится больше. О конечных результатах пока говорить рано, и кажется это отдельная тема для новой статьи.

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

Выбор ИИ

Сейчас нам доступно 3 инструмента для работы:

Yandex Code Assist — “Универсальный солдат”

Ассистент Яндекса на базе модели Qwen. Работа строится через Visual Studio, то есть сбоку от EDT, конечно это не плюс. Зато обладает множеством дополнительных настроек (MCP, навыки, плагины и пр.), что может повышать качество работы и результата. Говорит по‑русски — это тоже важно. Без дополнительных знаний в языке 1С еще многое додумывает.

Результат: Код пишет качественно. Учитывает много нюансов. На вопросы отвечает полнее и зависаний практически нет.

Вердикт: Неплох, особенно для отдельных небольших алгоритмов или задач.

1С:Напарник — «Домашний питомец»

Раз есть EDT, значит есть и официальный ИИ‑помощник от 1С, который пока бесплатен. Сразу видно: он знает платформу, код пишет хорошо, а комментарии к нему еще лучше.

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

Вердикт: для чего‑то не сложного, разработки с нуля, шаблонов и комментариев — очень даже. Если нужно большее — кажется пока слабоват, но будем пробовать.

Claude Code — “Профессиональный наемник”

Сам по себе Claude Code — мощный агент. Хорошо анализирует конфигурацию и код, удачно предлагает и принимает решения. НО! Стоит больших денег( Непонятна его дальнейшая судьба в РФ и нашей компании в частности. Пока пользуемся им осторожно)

Результат: Код пишет красиво (правда, пока не идеально), с учётом нашей структуры и стандартов. Ещё и объясняет, почему сделал так, а не иначе. С каждым обновлением про 1С знает все больше.

Вердикт: для сложного рефакторинга легаси, тестирования и анализа — кажется лучший. Но дорогой, зараза.

Небольшой ИИ‑батл

Еще в начале работы удалось устроить короткое сравнение между всеми тремя. Задача была сделать одну и ту же, срочную и не сложную задачку. Промт звучал примерно так:

«Нужен пример кода для базы УХ: сначала запросом отобрать документы ВерсияСоглашенияКоммерческийДоговор с Номером ПОДОБНО „%‑%-%“; потом обойти эту выборку и изменить номер на „000071959“ увеличивая на единицу. Документы записывать в режиме загрузка. Добавить комментарии у процедуры и основных действий»

Вот что из этого получилось:

  • Yandex Code Assist

    • Написал работоспособную процедуру на 55 строк с обширным комментарием к процедуре.

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

    • Про режим загрузки ничего не понял и придумал такую конструкцию: «ДокументОбъект.Записать(РежимЗаписиДокумента.Загрузка)»

    • В конце выдал некие рекомендации, по мне — не особо полезные.

Пример кода
// Процедура выполняет изменение номеров документов "Версия соглашения коммерческий договор".
//
// Логика работы:
//   1. Запросом отбираются документы "ВерсияСоглашенияКоммерческийДоговор",
//      у которых номер документа содержит подстроку вида "ЧЧЧ-ЧЧЧ-ЧЧЧ" (маска "%-%-%").
//   2. Выборка обходится в цикле, и каждому документу присваивается новый номер,
//      начиная с базового значения "000071959" и увеличиваясь на единицу
//      для каждого следующего документа.
//   3. Документы записываются в режиме записи "Обмен данными.Загрузка",
//      что позволяет изменять номера без срабатывания проверок уникальности номера.
//
// ВАЖНО: процедура модифицирует данные в базе. Перед выполнением убедитесь в наличии
// резервной копии базы данных и в корректности выбранных документов.

Процедура ИзменитьНомераДоговоров() Экспорт

    // Формируем и выполняем запрос для отбора документов с номером, содержащим дефисы.
    Запрос = Новый Запрос;
    Запрос.Текст =
    "ВЫБРАТЬ
    |    ВерсияСоглашенияКоммерческийДоговор.Ссылка КАК Ссылка
    |ИЗ
    |    Документ.ВерсияСоглашенияКоммерческийДоговор КАК ВерсияСоглашенияКоммерческийДоговор
    |ГДЕ
    |    ВерсияСоглашенияКоммерческийДоговор.Номер ПОДОБНО ""%-%-%""";
    // Условие "%-%-%" отбирает документы, у которых номер состоит минимум
    // из трёх частей, разделённых дефисом (например, "123-456-789").

    Выборка = Запрос.Выполнить().Выбрать();

    // Начальное значение номера, с которого начинается перенумерация.
    БазовыйНомер = "000071959";

    // Обходим отобранные документы в цикле.
    Пока Выборка.Следующий() Цикл

        // Открываем объект документа для изменения его номера.
        ДокументОбъект = Выборка.Ссылка.ПолучитьОбъект();

        // Присваиваем документу новый номер.
        ДокументОбъект.Номер = БазовыйНомер;

        // Записываем документ в режиме "Обмен данными.Загрузка".
        // Такой режим записи позволяет изменить номер документа в обход
        // стандартных проверок уникальности и правил нумерации.
        ДокументОбъект.Записать(РежимЗаписиДокумента.Загрузка);

        // Увеличиваем базовый номер на единицу для следующего документа.
        // Число в строке прибавляется как целочисленное значение,
        // результат преобразуется обратно в строку.
        БазовыйНомер = Строка(Число(БазовыйНомер) + 1);

    КонецЦикла;

КонецПроцедуры
  • 1С‑Напарник

    • Написал работоспособную процедуру на 57 строк с адекватными комментариями к процедуре и основным действиям.

    • Оказался единственным, кто еще при рассуждении понял про «ДокументОбъект.ОбменДанными.Загрузка = Истина» и указал это в коде.

    • Выдал добротные и полезные рекомендации для запуска.

Пример кода
// Перенумерация документов "Версия соглашения (коммерческий договор)".
// Для всех документов с номером вида "<x>-<y>-<z>" устанавливает
// последовательные числовые номера, начиная с "000071959".
//
Процедура ПеренумероватьВерсииСоглашений() Экспорт

    // Начальное значение новой нумерации.
    НачальныйНомер = 71959;

    // Шаблон отбора: документы, в номере которых присутствуют дефисы.
    ШаблонНомера = "%-%-%";

    // Формируем запрос для отбора документов со "старыми" номерами.
    Запрос = Новый Запрос;
    Запрос.Текст =
        "ВЫБРАТЬ
        |    ВерсияСоглашенияКоммерческийДоговор.Ссылка КАК Ссылка
        |ИЗ
        |    Документ.ВерсияСоглашенияКоммерческийДоговор КАК ВерсияСоглашенияКоммерческийДоговор
        |ГДЕ
        |    ВерсияСоглашенияКоммерческийДоговор.Номер ПОДОБНО &ШаблонНомера
        |УПОРЯДОЧИТЬ ПО
        |    ВерсияСоглашенияКоммерческийДоговор.Дата,
        |    ВерсияСоглашенияКоммерческийДоговор.Ссылка";

    Запрос.УстановитьПараметр("ШаблонНомера", ШаблонНомера);

    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать();

    // Счетчик новых номеров - увеличивается на единицу для каждого документа.
    ТекущийНомер = НачальныйНомер;

    Пока Выборка.Следующий() Цикл

        // Получаем объект документа для изменения реквизита Номер.
        ДокументОбъект = Выборка.Ссылка.ПолучитьОбъект();
        Если ДокументОбъект = Неопределено Тогда
            // Документ мог быть удален другой транзакцией - пропускаем.
            Продолжить;
        КонецЕсли;

        // Присваиваем номер в формате 9-значного числа с лидирующими нулями.
        ДокументОбъект.Номер = Формат(ТекущийНомер, "ЧЦ=9; ЧВН=; ЧГ=0");

        // Записываем документ в режиме загрузки:
        //   - РежимЗаписиДокумента.Запись - простая запись без проведения;
        //   - ОбменДанными.Загрузка = Истина - отключает проверки заполнения
        //     и подписки на события, выполняемые при интерактивной записи.
        ДокументОбъект.ОбменДанными.Загрузка = Истина;
        ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);

        ТекущийНомер = ТекущийНомер + 1;

    КонецЦикла;

КонецПроцедуры
  • Claude Code

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

    • Даже использовал блоки Попытка‑Исключение, а также Сообщить для вывода информации пользователю.

    • Все комментарии разумных размеров.

    • Тоже ничего не понял про загрузку и откуда‑то придумал метод «УстановитьРежимЗагрузкиДанных(Истина)».

Пример кода
// Процедура для обновления номеров документов ВерсияСоглашенияКоммерческийДоговор
// Находит документы с номерами по шаблону "%-%-%", изменяет их номера начиная с "000071959"
// и записывает в режиме загрузки для повышения производительности
Процедура ОбновитьНомераВерсийСоглашений() Экспорт

// Начальный номер для присвоения документам
НачальныйНомер = 71959;
ТекущийНомер = НачальныйНомер;

// Создаем запрос для отбора документов с номерами по шаблону "%-%-%"
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВерсияСоглашенияКоммерческийДоговор.Ссылка КАК Ссылка,
| ВерсияСоглашенияКоммерческийДоговор.Номер КАК СтарыйНомер,
| ВерсияСоглашенияКоммерческийДоговор.Дата КАК Дата
|ИЗ
| Документ.ВерсияСоглашенияКоммерческийДоговор КАК ВерсияСоглашенияКоммерческийДоговор
|ГДЕ
| ВерсияСоглашенияКоммерческийДоговор.Номер ПОДОБНО ""%-%-%""
|УПОРЯДОЧИТЬ ПО
| ВерсияСоглашенияКоммерческийДоговор.Дата,
| ВерсияСоглашенияКоммерческийДоговор.Номер";

// Выполняем запрос и получаем результат
РезультатЗапроса = Запрос.Выполнить();

// Проверяем, есть ли найденные документы
Если РезультатЗапроса.Пустой() Тогда
Сообщить("Документы с номерами по шаблону '%-%-%' не найдены.");
Возврат;
КонецЕсли;

// Получаем выборку документов для обработки
ВыборкаДокументов = РезультатЗапроса.Выбрать();

// Счетчики для отчета о выполнении
КоличествоОбработанных = 0;
КоличествоОшибок = 0;

// Включаем режим загрузки данных для повышения производительности
УстановитьРежимЗагрузкиДанных(Истина);

Попытка
// Обходим все найденные документы
Пока ВыборкаДокументов.Следующий() Цикл

Попытка
// Получаем объект документа для изменения
ДокументОбъект = ВыборкаДокументов.Ссылка.ПолучитьОбъект();

// Сохраняем старый номер для логирования
СтарыйНомер = ДокументОбъект.Номер;

// Формируем новый номер с ведущими нулями (9 знаков)
НовыйНомер = Формат(ТекущийНомер, "ЧЦ=9; ЧВН=");

// Присваиваем новый номер документу
ДокументОбъект.Номер = НовыйНомер;

// Записываем документ (в режиме загрузки)
ДокументОбъект.Записать();

// Выводим информацию о изменении
Сообщить(СтрШаблон("Документ %1: номер изменен с '%2' на '%3'",
ВыборкаДокументов.Ссылка,
СтарыйНомер,
НовыйНомер));

// Увеличиваем номер для следующего документа
ТекущийНомер = ТекущийНомер + 1;
КоличествоОбработанных = КоличествоОбработанных + 1;

Исключение
// Обрабатываем ошибки записи отдельных документов
КоличествоОшибок = КоличествоОшибок + 1;
ТекстОшибки = ОписаниеОшибки();
Сообщить(СтрШаблон("Ошибка при обработке документа %1: %2",
ВыборкаДокументов.Ссылка,
ТекстОшибки),
СтатусСообщения.Важное);

// Продолжаем обработку следующих документов
Продолжить;
КонецПопытки;

КонецЦикла;

Исключение
// Обрабатываем критические ошибки
ТекстОшибки = ОписаниеОшибки();
Сообщить("Критическая ошибка при выполнении процедуры: " + ТекстОшибки, СтатусСообщения.ОченьВажное);

// Обязательно отключаем режим загрузки данных
УстановитьРежимЗагрузкиДанных(Ложь);

КонецПопытки;

// Выводим итоговую информацию о выполнении процедуры
Сообщить("");
Сообщить("=== РЕЗУЛЬТАТЫ ВЫПОЛНЕНИЯ ===");
Сообщить(СтрШаблон("Обработано документов: %1", КоличествоОбработанных));
Сообщить(СтрШаблон("Ошибок при обработке: %1", КоличествоОшибок));
Сообщить(СтрШаблон("Следующий доступный номер: %1", Формат(ТекущийНомер, "ЧЦ=9; ЧВН=")));

КонецПроцедуры

// Вспомогательная процедура для запуска обновления с подтверждением
// Рекомендуется использовать эту процедуру для безопасного выполнения
Процедура ЗапуститьОбновлениеНомеровСПодтверждением() Экспорт

// Запрашиваем подтверждение у пользователя
Ответ = Вопрос("Выполнить обновление номеров документов ВерсияСоглашенияКоммерческийДоговор?" + Символы.ПС +
"Будут изменены все документы с номерами вида '%-%-%'" + Символы.ПС +
"Операция необратима!",
РежимДиалогаВопрос.ДаНет,
0,
КодВозвратаДиалога.Нет);

Если Ответ = КодВозвратаДиалога.Да Тогда
// Выполняем обновление только после подтверждения
ОбновитьНомераВерсийСоглашений();
Иначе
Сообщить("Операция отменена пользователем.");
КонецЕсли;

КонецПроцедуры
Технологии, которые меняют нас: История одной 1С‑команды - 2

Итоговый вывод: пока мы еще в поисках нашего идеального инструмента. Каждый чем‑то хорош и удобен. Отдельные инструменты еще требуют донастройки. Пользуемся всеми тремя для наработки опыта.

Эпилог. Есть только путь

Мы только в самом начале нашего пути. EDT в процессе освоения: разработчики привыкают к новым процессам работы, а некоторые коллеги даже еще не перешли. Но выбор сделан и свернуть назад не получится.

Теперь у нас впереди освоение: полноценного Git‑инструментария, для проверки кода и развертывания приложений; полные автотесты с выявлением багов до релиза; ИИ, который не заменяет программиста, но реально помогает и ускоряет его работу.

«Идти вперёд — значит прорываться через стены, которые кажутся непреодолимыми, с верой, что за ними — свет» — Нельсон Мандела

«Есть только путь» — не просто громкая фраза, а правда. Да, путь труден. Да, он требует денег на железо, времени на настройку и смелости, чтобы сказать коллегам: «Мы это сделаем. Идёте с нами?». Но каждый пройденный километр этого тернистого пути даёт нам новый опыт. Опыт, который закаляет команду. Опыт, который подготовит нас к следующим вызовам. А они обязательно будут.

Мы движемся вперед. Медленно, с матами и перезагрузками. Но движемся — и это радует!

Автор: abandrey

Источник