Бестиарий программирования
1.14K subscribers
358 photos
5 videos
5 files
447 links
Наблюдения за жизнью ошибок в коде.
Андрей Карпов.

ГОСТ Р 71207-2024, ГОСТ Р 56939-2024, РБПО, Статический анализ кода

Канал-дублёр в MAX: https://max.ru/join/3VWTp9apkQvTMSRQ__LGiTQ5NGVBj8p_tOpwlQO6vS8
Download Telegram
Провели первый пилотный вебинар из серии "Качество и безопасность ПО в эпоху GenAI".

Если тебе интересна тематика и ты хочет принять участие в этом цикле в качестве эксперта, прошу написать коллеге-организатору.
👍7👀2
А что, если…

Эдсгер Дейкстра писал:
На экономический вопрос «Почему программное обеспечение такое дорогое» столь же экономическим ответом был бы такой: «Потому что его пытаются получить при помощи дешёвого труда». А почему пытаются? Да потому, что присущие ему трудности повсеместно сильно недооцениваются.

Если продолжить эту мысль, то использование GenAI – очередная попытка создавать проекты максимально дёшево, игнорируя вытекающие из этого проблемы. Навскидку:
• больше кода, меньше контроля со стороны человека, проблемы безопасности и качества;
• непонятно, как будут появляться новые эксперты, которые могут понять сгенерированный код (проблема обучения);
• некому найти исправить сложные ошибки – бесконечная перегенерация фрагментов проекта в надежде, что ошибки исчезнут;
• новые модели обучаются на плохом коде предыдущих моделей (сингулярность говновайбкода);
• и т.д.

А что, если внедрение GenAI в итоге сделает программное обеспечение дороже, а не дешевле?
💯1021👀1
Как все так ловко ИИ пользуются... Обзоры кода делают...

Не знаю, то ли я туповат, то ли невезучий, то ли кругом сказочники. Пытаюсь исследовать, какие новые интересные виды ошибок может находить ИИ в С++ коде, о которых не знает PVS-Studio. Claude Opus то нормально мне про интересные баги рассказывает, то на ровном месте с ума сходит.

Даю файл на вход, а он тревожно:
В присланном файле есть места, где содержимое обрезано/повреждено вставкой `</context>`, поэтому их я не рассматриваю как «баги кода» — это артефакты форматирования. Разберу реальные логические ошибки.

Шо? Какой context? Там максимум — #include "context.hxx". Ну ладно, давай ошибки посмотрим.

Так, парочка сообщений по делу. Например, найден лишний аргумент при использовании функции форматирования.
addErrorMessage(&sciErr, API_ERROR_CREATE_ZDOUBLE_IN_NAMED_LIST,
_("%s: Unable to create list item #%d in Scilab memory"),
"createComplexZMatrixOfDoubleInNamedList", _iItemPos + 1, _pstName);

В строке форматирования два спецификатора %s и %d, а передаются три аргумента: funcName, _iItemPos+1, _pstName. Да, это баг. Про подобные паттерны PVS-Studio уже знает, хотя, возможно, нужно подсказать, что addErrorMessage — это printf-подобная функция. В целом, тут неинтересно, идём дальше.

Ооо, и тут начинается...
`checkListItemPosition` — неправильное сравнение границы:

// check a valid item
if (_iItemPos > iItem)
{
addErrorMessage(...);
return sciErr;
}

Здесь проверка «позиция валидна» использует `>`, хотя позиции 1-based, а `iItem` — количество элементов. Это выглядит как граничный дефект, но по сути `_iItemPos == iItem` допустимо, `_iItemPos > iItem` — ошибка. Это в порядке — правильная граница. Не баг. (Указываю, чтобы было понятно, что я это проверил.)

Так баг или не баг? Я три раза прочитал текст и посмотрел функцию с кодом. В итоге я не только не понимаю, есть ли здесь ошибка, но и не понимаю, что Claude пытается мне сказать.

Дальше ещё хуже шарики за ролики зашли.
Баг 5 (реальный): утечка в readCommonMatrixOfPolyInNamedList и др. — нет, это API отдаёт указатели наружу. Не баг.

Это всё описание пятого бага, больше ничего нет. Комментировать — только портить.

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

На сегодня мне ИИ достаточно. Пойду лучше пройдусь по парку, пока погода хорошая.
👍15😁6
69 поводов, когда IT-нику хочется что-то отметить
Наверняка многие не в курсе, что у нас есть вот такая подборка – День, когда Скайнет обрёл сознание, и ещё 69 поводов собраться с коллегами! Часть 1, Часть 2.
🔥3😐1
Короче и быстрей (часть №1 из 5) – Второй цикл

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

Приведённый ниже код я встретил в вайб-код проекте VibeTensor. Я исследую подобные проекты в качестве натуралиста. Мне интересен генезис новых видов дефектов и недостатков в коде.

Одно из наблюдений – генерированный код более "пухлый", что затрудняет его восприятие человеком и оптимизацию компиляторами. Следующий фрагмент кода как раз это хорошо демонстрирует.
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  const std::size_t nd = sizes.size();
  std::vector<int64_t> strides(nd, 0);
  int64_t acc = 1;
  for (std::ptrdiff_t i = static_cast<std::ptrdiff_t>(nd) - 1; i >= 0; --i) {
    strides[static_cast<std::size_t>(i)] = acc;
    const auto sz = sizes[static_cast<std::size_t>(i)];
    acc *= (sz == 0 ? 1 : sz);
  }
 
  int64_t ne = 1;
  bool any_zero = false;
  for (auto s : sizes) {
    if (s == 0) {
      any_zero = true;
      break;
    }
    ne *= s;
  }
  if (any_zero) {
    ne = 0;
  }
  ....
}

С одной стороны, размер и скорость этого кода некритичны, так как он относится к тестам.

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

А ещё важно, что генерируется С++ код, и он обязан быть оптимальным. Само назначение языка – высокоэффективные приложения. В рассматриваемом месте – это просто медленный тест. Но в другом месте что-то подобное приведёт к существенному замедлению приложения. Или скажется кумулятивный эффект множества неудачных фрагментов сгенерированного кода.

Медленный С++ код – это противоестественно. Поэтому по-прежнему полезно развивать свою экспертность в понимании, удачным ли получился код и как его можно улучшить, сократить, оптимизировать. Или сгенерировать снова, используя уточнения.

В общем давайте потренируемся и проведём рефакторинг. Начнём с этого фрагмента:
int64_t ne = 1;
bool any_zero = false;
for (auto s : sizes) {
  if (s == 0) {
    any_zero = true;
    break;
  }
  ne *= s;
}
if (any_zero) {
  ne = 0;
}

Здесь перемножаются все элементы массива. Если встретится 0, то цикл прервётся, чтобы зря не обрабатывать оставшиеся элементы массива. Всё равно ведь ноль получится.

Чтобы обнулить переменную, где хранится произведение, используется флаг any_zero. Этот подход избыточен, можно проще.
int64_t ne = 1;
for (auto s : sizes) {
  if (s == 0) {
    ne = 0;
    break;
  }
  ne *= s;
}

Когда встретится 0, обнулятся ne и цикл завершится. Можно продолжить упрощение. Современные процессоры быстро выполняют операции умножения. Поэтому можно в начале перемножить, а потом уже проверить.
int64_t ne = 1;
for (auto s : sizes) {
  ne *= s;
  if (s == 0) {
    break;
  }
}

Функциональность кода не изменилась, но он стал короче и, на мой взгляд, даже понятнее.
👍4👌4
Короче и быстрей (часть №2 из 5) – Первый цикл

Теперь вернёмся к началу функции.
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  const std::size_t nd = sizes.size();
  std::vector<int64_t> strides(nd, 0);
  int64_t acc = 1;
  for (std::ptrdiff_t i = static_cast<std::ptrdiff_t>(nd) - 1; i >= 0; --i) {
    strides[static_cast<std::size_t>(i)] = acc;
    const auto sz = sizes[static_cast<std::size_t>(i)];
    acc *= (sz == 0 ? 1 : sz);
  }

Из-за static_cast код выглядит тяжеловесным. Первое приведение типа нужно, чтобы какие-то компиляторы/статические анализаторы не ругались на странные арифметические игры.
std::ptrdiff_t i = static_cast<std::ptrdiff_t>(nd) - 1;

Рассмотрим, что будет, если убрать static_cast, а входной массив окажется пустым:

1. Если массив пуст, то nd = 0;
2. Вычтя единицу из беззнакового нуля, мы получим SIZE_MAX, т.е. очень большое положительное беззнаковое число.
3. Значение SIZE_MAX типа size_t неявно преобразуется в тип ptrdiff_t и записывается в переменную i. Получается, что i = -1, как и было задумано. Но вот тут как раз могут быть выданы предупреждения. Ведь мы инициализируем ptrdiff_t числом, которое больше диапазона максимально вмещаемого числа. Поведение в такой ситуации до C++20 определяется реализацией – implementation defined behavior. После C++20 поведение определено.

Итого: первый static_cast лучше оставить на месте. Про остальные такого сказать нельзя. В них нет никакого смысла.

Оператор [] в классе vector принимает аргумент типа size_type (этот тип является синонимом size_t). Значение переменной i автоматически будет преобразовано в size_t, и в этом нет чего-то странного, опасного или подозрительного. Явное приведение типов только загромождает код, и от него лучше избавиться.

for (std::ptrdiff_t i = static_cast<std::ptrdiff_t>(nd) - 1; i >= 0; --i) {
  strides[i] = acc;
  const auto sz = sizes[i];
  acc *= (sz == 0 ? 1 : sz);
}

Первый шаг сделан. Можно теперь всё-таки упростить длинную строку с циклом? Давайте подумаем. Хочется написать как-то так:
for (auto sz : std::ranges::views::reverse(sizes)) {
  strides[???? i ????] = acc;
  acc *= (sz == 0 ? 1 : sz);
}

Всё равно требуется переменная i для обхода массива strides, начиная с конца. Так что совсем упростить код и избавиться от i не получается. Поэтому сделаем так:
int64_t acc = 1;
size_t i = nd;
for (auto sz : std::ranges::views::reverse(sizes)) {
  strides[--i] = acc;
  acc *= (sz == 0 ? 1 : sz);
}

Если честно, мне не нравится, что из-за использования --i код стал сложнее. Теперь требуется вникнуть, почему переменная в начале уменьшается, а уже затем используется для обращения к элементу массива.

С другой стороны, кода стало меньше и его можно быстрее просмотреть глазами. Так что, наверное, когнитивная сложность кода осталась в итоге такой же. Т.е. понимать код стало не проще, но и не сложнее. В любом случае код стал покороче, так что ok.
👍1
Короче и быстрей (часть №3 из 5) – Объединяем циклы

Взглянем целиком на вариант кода, который получился к текущему моменту.
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  const std::size_t nd = sizes.size();
  std::vector<int64_t> strides(nd, 0);
  int64_t acc = 1;
  size_t i = nd;
  for (auto sz : std::ranges::views::reverse(sizes)) {
    strides[--i] = acc;
    acc *= (sz == 0 ? 1 : sz);
  }
   int64_t ne = 1;
 
  for (auto s : sizes) {
    ne *= s;
    if (ns == 0) {
      break;
    }
  }
  ....
}

Теперь, когда кода меньше, становится очевидным, что второй цикл избыточен. В первом цикле мы перебираем все элементы. Так почему бы их сразу не перемножить?
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  const std::size_t nd = sizes.size();
  std::vector<int64_t> strides(nd, 0);
  int64_t acc = 1;
  size_t i = nd;
  int64_t ne = 1;
  for (auto sz : std::ranges::views::reverse(sizes)) {
    strides[--i] = acc;
    acc *= (sz == 0 ? 1 : sz);
    ne *= sz;
  }
  ....
}

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

Что ещё осталось? Не требуется изначально обнулять контейнер strides нулями. Всё равно все его элементы будут перезаписаны.
std::vector<int64_t> strides(nd, 0); // надо убрать второй аргумент

В принципе, мы закончили. Но можно сделать ещё одно косметическое изменение, избавившись от переменной nd. Она ни здесь, ни в последующем коде не нужна. Итоговый код:
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  auto q = sizes.size();
  std::vector<int64_t> strides(q);
  int64_t acc = 1;
  int64_t ne = 1;
  for (auto sz : std::ranges::views::reverse(sizes)) {
    strides[--q] = acc;
    acc *= (sz == 0 ? 1 : sz);
    ne *= sz;
  }
  ....
}

Код сократился в два раза: с 20 до 9 строк!

P.S. Если захотите и напишите комментарий, я приведу ассемблерный код, чтобы показать как он сократился и оптимизировался.
👍5
Короче и быстрей (часть №3 из 5) – Объединяем циклы - Заглянем в ассемблерный код

Текст функции стал короче, но скажется ли это положительно на производительности? Да. Посмотрим на основной фрагмент ассемблерного кода для изначального варианта функции. Используется Clang с ключом -O2.
.LBB1_7:
mov rax, rsi
mov qword ptr [rbx + 8*r12 - 16], rsi
mov rsi, qword ptr [r13 + 8*r12 - 16]
cmp rsi, 1
adc rsi, 0
imul rsi, rax
dec r12
cmp r12, 1
ja .LBB1_7
mov r12d, 1
cmp rbp, r13
je .LBB1_9
.LBB1_4:
mov rax, qword ptr [r13]
test rax, rax
je .LBB1_5
imul r12, rax
add r13, 8
cmp r13, rbp
jne .LBB1_4
jmp .LBB1_9

Достаточно многословный ассемблерный код с двумя циклами. Теперь посмотрим, что сгенерировано для последнего сокращённого кода.
.LBB1_10:
mov rcx, rsi
mov rdx, qword ptr [rbp - 8]
add rbp, -8
mov qword ptr [rax], rsi
cmp rdx, 1
mov rsi, rdx
adc rsi, 0
imul rsi, rcx
imul r12, rdx
add rax, -8
cmp rbp, r13
jne .LBB1_10

Красивое. Один цикл. Коротко и быстро.
2👍2
Короче и быстрей (часть №4 из 5) – Альтернативный подход

Есть какой-то другой альтернативный подход? Есть. Не знаю, догадался ли я до него сам или нет. К сожалению, после написанию своего варианта кода, я поспешил поспрашивать, какие варианты могут предложить ИИ.

Варианты от DeepSeek были не лучше, а некоторые даже хуже исходного. Например, он сократил одну из реализаций кода ценой переворачивания массива.
// Разворачиваем strides обратно
std::reverse(strides.begin(), strides.end());

А вот одна из альтернативных реализаций от Claude Opus заслуживает внимания. Он обратил внимание, что можно выполнять не две, а одну последовательность умножений!

Если все элементы входного массива не нулевые, то по завершению цикла acc == ne. А если хотя бы один элемент был нулевой, то в конце можно просто поменять значение ne на ноль. Происходит вновь возвращение к флагу any_zero, но в более умном варианте. Используя эту идею, можно написать следующий код:
static TensorImpl make_contiguous_tensor(const std::vector<int64_t>& sizes) {
  auto q = sizes.size();
  std::vector<int64_t> strides(q);
  int64_t acc = 1;
  bool any_zero = false;
  for (auto sz : std::ranges::views::reverse(sizes)) {
    strides[--q] = acc;
    acc *= (sz == 0 ? 1 : sz);
    any_zero |= sz == 0;
  }
  const int64_t ne = any_zero ? 0 : acc;
  ....
}

Ассемблерный код:
.LBB1_7:
mov rdx, rsi
mov rsi, qword ptr [r13 - 8]
add r13, -8
mov qword ptr [rcx], rdx
test rsi, rsi
sete dil
cmp rsi, 1
adc rsi, 0
imul rsi, rdx
or al, dil
add rcx, -8
cmp r13, rbp
jne .LBB1_7
xor r13d, r13d
test al, 1
cmove r13, rsi
mov r14, r8

Будет ли код, в котором выполняется в два раза меньше умножений, более быстрым? Моё предсказание – необязательно. Процессор может выполнить два невзаимосвязанных умножения одновременно на разных конвейерах. Я делаю ставку, что мой вариант и вариант от Claude будут работать с практически одинаковой скоростью.
1👍1
Короче и быстрей (часть №5 из 5) – Замер скорости работы и заключение

Давайте проверим замерами, как оно будет на самом деле в реальности. Пришлось немного заморочиться с тестами. Во-первых, надо было подавать такие данные, чтобы не возникало переполнение знаковых 64-битных переменных, так как это UB и замерам не будет доверия. Во-вторых, для честности, надо чередовать данные с нулём и без. В-третьих, цепочки входных данных должны быть разной длины.

Не утверждаю, что измерения выверены, но общее представление они дают. Скорость работы первого изначального алгоритма взята за единицу отсчёта. Использовал Clang с ключом -O2.

1.      Изначальный вариант c двумя циклами: 1.
2.      Мой вариант одним циклом: 0.88.
3.      Вариант, подсказанный Claude, с одним умножением: 0.92.

Рефакторинг дал ускорение в среднем на 10 %. Я ждал, что будет побольше, в районе 20—30 %. Но 10 % — это тоже хорошо, учитывая, что они достигнуты упрощением, а не усложнением кода.

Заключение

На этом разбор кода и его рефакторинг закончен. Был ли в этом смысл?

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

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

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

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

P.S. Кстати, про волшебную палочку подметил кое-что интересное, завтра напишу.
👍5
ИИ-кладенец

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

Вспомнилась она мне из-за воодушевления авторов статей, что вот ещё чуть-чуть и ИИ всё сделает за нас и "скрипач не нужен" (c). Я вдруг увидел связь между "ИИ сделает сам" и темой волшебных предметов и помощников, которую подробно разбирает Пропп.
Рассмотрение волшебного помощника облегчает и подготовляет рассмотрение волшебного предмета. Между ними существует теснейшее родство. Легко заметить, что эти предметы представляют собой лишь частный случай помощника. Помощники, живые существа и волшебные предметы, принципиально функционируют совершенно одинаково. Так, конь переносит героя за тридевять земель, но то же достигается при помощи ковра-самолета или сапог-самоходов. Конь побивает рать, но и дубина сама бьет врагов и даже берет их в плен и т. д.

Пропп подмечает феномен сознания: начиная использовать орудия труда, человек приписывает им самостоятельное действие. Вспомните сказки. Главный герой ведь на самом деле почти ничего не делает, всё за него исполняют помощники (ловят кого-то, строят хрустальный мост за ночь) или проблема сама решается с помощью какого-то магического предмета. В общем-то, герою достаточно взмахнуть неким мечом-кладенцом и дело готово.

Думаю, вы поняли, к чему я клоню. Сейчас всё теми же волшебными свойствами наделяют ИИ-технологии и ожидают от них чудесного решения проблем без усилий. Это — новый волшебный помощник.

Вроде все понимают, что ИИ — это инструмент, которым надо уметь пользоваться: что есть сложности и проблемы; что он помогает, но не заменят труд. По-серьёзному никто не говорит, что ИИ — это магия, но почему-то многие продолжают преподносить ИИ или воспринимать его как дубину, которая сама бьет врагов. Хотя для этого на практике нужна крепкая рука и физическая работа. Но нет, подавай "трах-тибидох".
Человек в меньшей степени замечает свое усилие и в большей — работу орудия. Так получается концепция, что орудие работает не в силу прилагаемых усилий (чем совершеннее орудие, тем меньше усилия), а в силу присущих ему волшебных свойств. Получается представление об орудии, работающем без человека, за человека. Орудие теперь обожествляется.

Вывода нет. Подметил интересное проявление мало осознаваемых психологических паттернов использования новых технологий/орудий труда. Сейчас, конечно, знания создаются на порядок быстрее, и разум более гибок и быстрее переучивается, но всё же какое-то прежнее, древнее восприятие мира влияет на нас, просвечивая сквозь слой образования и культуры.
🔥5👏5
Пометка в блокноте – Не забывать писать, сколько лет PVS-Studio на рынке

Услышал на Бизнес-Фест в докладе Игоря Манна мысль, что не стоит забывать упоминать в разных местах, как давно вы на рынке. Это автоматически добавляет пару очков доверия. И действительно! "PVS-Studio — более 18 лет на рынке РФ" звучит солидно!

В числах:

Компания ООО "ПВС" (ранее "СиПроВер", переименована в "ПВС" в 2020 году) зарегистрирована 21 марта 2008 года. В этом году отметили совершеннолетие – 18 лет!

Нашему продукту, который изначально назывался Viva64, тоже более 18 лет. Уже под названием PVS-Studio он был зарегистрирован 30 октября 2009 года.

P.S. Кто угадал отсылку на картинке? Великий герой — Коэн-варвар из книг о Плоском Мире.
5
PVS-Studio теперь в GitVerse🔥

Мы добавили готовые шаблоны для статического анализа в GitVerse Starter Workflow (российский аналог GitHub/GitLab от «СберТеха»).

Что это дает?
Больше не нужно писать пайплайны с нуля. Теперь внедрить автоматическую проверку кода в CI/CD можно за пару минут.

Как это работает:
- При настройке workflow в GitVerse выбираете шаблон PVS-Studio под свой язык: C++, C# или Java.
- В шаблоне уже прописаны базовые этапы сборки и анализа.
- Слегка адаптируете настройки под свой проект — и готово!

"Каждый шаблон уже включает основные этапы сборки и статического анализа. После небольшой адаптации под особенности конкретного проекта пайплайн готов к использованию и может быть встроен в процесс CI/CD", — отмечает Валерий Филатов, Developer Advocate PVS-Studio.


Отличный способ сэкономить время на настройке инфраструктуры и повысить надежность кода 👍

Для пользователей GitVerse сделали специальный промокод. Пользуйтесь PVS-Studio 30 дней без ограничений: https://pvs-studio.ru/gitverse

#PVS_Studio #GitVerse
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Запись вебинара "Практическая интеграция PVS-Studio и SourceCraft" 🔥

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

Посмотреть можно тут:
- VK Video
- Rutube
- YouTube
- Наш сайт
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Я сижу со взглядом на две тысячи ярдов после прочтения статьи "Манифест программиста, использующего AI-кодинг-агента". Как говорится, то ли смеяться, то ли плакать. Ну на смех в паре мест меня пробило.

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

Я пока сомневаюсь, что настолько всё плохо. Надеюсь, автор преувеличивает и иронизирует. А если нет? О, мой Дейкстра!
Появился тикет. Программист копирует ссылку, передает ее AI-кодинг-агенту и через какое-то время получает готовый Pull Request.
...
Перед изменением кода программист должен воспроизвести баг, понять условия его появления и увидеть фактический результат.

Скажите, что я сплю. Если вайб-программист просто впихивает задачу, не воспроизводя баг, не разбираясь в сути и не проверяя результат правок... это вообще что?
Если программист не запустил продукт и не проверил результат, задача не закончена. Если программист просто передал тикет AI, а потом передал его код ревьюеру и тестировщику, он не выполнил свою работу. Он просто переложил ее на следующих людей.

База. Но ведь автор это всё написал зачем-то, а в комментариях всерьёз идёт обсуждение. Прошу прочитать эту статью, она небольшая. Интересно услышать ваши впечатления, мнения и комментарии. Хочется вынести из всего этого происходящего сюрреализма какие-то полезные выводы.
👍8😁1
Forwarded from СВД ВС
Современная разработка начинается с правильных инструментов.

Завершился курс «Инструментальные средства ЗОСРВ «Нейтрино».

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

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

Все участники успешно прошли тестирование и получили удостоверения о повышении квалификации.

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

#Курсы
👍41