Как вы «держите» в голове функции, переменные и их значения при написании программы, или разборе чужого кода?
1) если речь о своем коде, я стараюсь писать его так что бы не нужно было все это помнить:
 - осмысленные названия функций/методов/переменных
 - локальность, все стремное выносится в отдельные функции/методы в рамках которой все просто и логично, дробить все на маленькие понятные вещи это пожалуй самое простое что можно делать
 - SOLID
2) если речь о чужом коде, дебаггер, листик и ручка, рисую схемки и т.д, плачу... Если могу, опять же начинаю потихонку куски кода выновить в отдельные функции и т.д. если мне это мешает и этот код мне надо не тупо почитать да разобраться а потом еще и править придется.
Самый главный инструмент разработчика - это бумага и ручка. Декомпозиция кода - это следующий главный инструмент. Отладчик ближе к концу списка. Если смотришь в собственный код и не понимаешь, что происходит, значит код слишком большой или слишком сложный или там нет комментариев. Комментарии вообще играют очень важную роль, с одной стороны код сам по себе говорит (как минимум должен говорить), ЧТО делает код, а комментарий говорит о том ЗАЧЕМ это нужно. Можно еще использовать программирование по контракту (assert к примеру) для того, чтобы было более понятно что происходит. Императивное программирование и ООП тяготеют к спагетти коду особенно на этапе прототипирования. Функциональное программирование часто помогает решить часть проблем (иногда правда и новых добавляет).