Как стать автором
Поиск
Написать публикацию
Обновить

Архитектура ошибочного мышления: как баги рождаются в голове, а не в коде

Уровень сложностиСложный
Время на прочтение4 мин
Количество просмотров2.7K

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

Введение: баг, которого не было

Были ли у вас баги, которые исчезли, когда вы начали их кому-то объяснять? Или, наоборот, баги, которые вы не видели часами, пока не посмотрели на них с совершенно другой стороны? Я хочу поговорить не о коде. И даже не о компиляторах, алгоритмах или архитектуре. А о той странной штуке, в которой всё это происходит — о мозге разработчика.

Большинство багов начинается не с if, а с «я точно всё понял». Не с null, а с «не может такого быть». И не с segfault, а с «я же так делал сто раз». То есть — с багов мышления.

1. Раздел первый: баг как симптом мышления

Код — это манифестация наших мыслей. Баг — это симптом ошибочной логики, прошедшей через компилятор. Компиляторы не догадываются, что вы имели в виду. Они работают строго по инструкции. А инструкция — это и есть следствие вашего мышления.

Пример

# Я уверен, что переменная всегда инициализирована до вызова
def calculate_discount(price):
    if has_discount:
        return price * 0.9
    return price

Ошибка очевидна? Только если вы привыкли думать о переменных как о сущностях, которым надо дать значение до использования. А если вы переучились с языка, где has_discount глобальная или имеет дефолт — вы можете и не заметить.

Это не ошибка кода. Это ошибка в предположениях.

3. Мышление — не поток, а сеть

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

Мы редко задумываемся, что значат слова «всё работает». Работает как? В каких условиях? А почему ты считаешь, что оно работает? Потому что прошёл тест? А тест написан в том же багнутом контексте мышления.

4. Когнитивные искажения: чем багат наш мозг

Некоторые классические баги в коде — это просто отражения стандартных когнитивных искажений:

  • Иллюзия прозрачности — «ясно же, как работает этот метод»;

  • Предвзятость подтверждения — мы читаем код, чтобы доказать, что он работает, а не искать, где он не работает;

  • Эффект Даннинга-Крюгера — чем меньше мы понимаем, тем увереннее пишем код;

  • Слепое пятно предвзятости — «ну я-то объективен».

Каждое из этих искажений находит свой способ сломать ваш прод.

5. Язык как ловушка мышления

Языки программирования задают каркас мышления. Например:

let isAdmin = false;

if (isAdmin = true) {
    // always runs
}

JavaScript позволяет такую конструкцию, потому что = возвращает значение. Вы думаете, что проверяете, а на самом деле присваиваете. И это баг не в языке. Это баг в том, как мозг ожидает работу конструкции. Язык формирует эти ожидания. А потом ломает их.

6. Архитектура «невидимого бага»

Самые сложные баги — это не сломанный for и не неправильный index. Это баги, встроенные в архитектуру, в саму модель системы. Они сидят на фундаментальном предположении. На чём-то вроде:

  • «Событие не может произойти дважды подряд»;

  • «Состояние X всегда следует за состоянием Y»;

  • «Пользователь не нажмёт эту кнопку три раза за секунду».

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

7. Диалог как способ дебага головы

Когда объясняешь кому-то свой баг, часто ловишь себя: «блин, а что если тут…» — и ты находишь ошибку. Это называется «эффект резиновой уточки». Но он работает не из-за уточки, а потому, что ты пересобираешь свою модель мышления, когда вербализуешь её.

8. Как баги проходят ревью и тесты

Классика: «пропустили баг на ревью». Почему?

  • Читали глазами, а не умом;

  • Имеют ту же ментальную модель, что и автор кода;

  • Проверяют «соответствие стандартам», а не «подразумеваемую логику».

Ревью, в сущности, не проверка кода. Это попытка сравнить мышление автора и ревьюера. Если оно одинаково кривое — баг пройдет.

9. Можно ли тестировать мышление?

Да. Это называется «деструктивное мышление». В программировании мы тестируем код. А вот в инженерии высокого уровня тестируют гипотезы и предпосылки.

Пример:

# Python: проверим предположение о порядке вызовов
calls = []

def a():
    calls.append('a')

def b():
    calls.append('b')

def c():
    a()
    b()
    return calls

print(c())  # ['a', 'b']

Теперь предположим, что a() вызывает b() внутри. Если ты об этом не знаешь, поведение сломается. Проблема не в коде. Проблема в том, что ты думал иначе.

10. Как не попасть в мышленческий баг

Никак. Мы все люди. Но можно:

  • Обсуждать логику с людьми, которые мыслят по-другому;

  • Вводить практики тестирования предпосылок;

  • Добавлять в код комментарии не только «что делает», но и «почему так»;

  • Развивать паранойю: «а что если всё не так, как я думаю?»;

  • Писать код, будто тебе будет его объяснять враг на суде.

11. (Немного личного) Почему я пишу об этом

Потому что у меня был баг. Странный, непонятный, абсолютно неуловимый. И когда я его нашёл — я понял, что всё это время думал не так. Не кодил, не проектировал, а просто думал криво. Я уверен, у каждого был такой баг.

И может быть, если мы научимся замечать свои баги мышления, багов в коде станет чуть меньше.


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

Теги:
Хабы:
+8
Комментарии7

Публикации

Ближайшие события