🔥

Тред (Михаил Куренков)


Давай поговорим о комфорте при работе с кодом.

Мы с вами большую часть рабочего дня работаем с кодом. И на самом деле мы больше читаем код чем пишем.

Важно чтоб код был понятный.

Так получилось что мы с вами люди. 
Даниэль Канеман описывает мышление человека как работу 2х систем.

Система 1 срабатывает автоматически и очень быстро, не тратит ресурсы. Система 1 распознает текст на родном языке, классифицирует знакомые объекты, как яблоко или стул и достает из памяти понимание паттерна, когда вы видите слово singleton или метод sharedInstance().

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

Рядом с 2мя системами у человека есть 2 памяти: быстрая и долгосрочная.

Быстрая память похожа на дырявый стек. В этом стеке от 4х до 7ми слотов. Когда стек переполняется нижняя мысль просто выпадает на пол.

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

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

Потом переходит к следующему кусочку. Так большая структура может поместится в 4–7ми мыслях.

Читает код Система 1. Прочитанный код выражается в категориях знакомых Системе 1, она на достаточно низком уровне, это информация о переменных, методах, классах и их названиях, о том какие операции производятся с переменными, какие методы вызываются.

Примерно так я читал код одного из своих старых тестовых заданий.
notion image

После прочтения Система 1 передает прочитанную информацию Системе 2. Система 2 сжимает переданную информацию в одну мысль. Мысль описывает то что делает прочитанный кусок кода.

Система 1 может сопоставить кусок кода с мыслью уже содержащийся в рабочей памяти, но не может самостоятельно сжать похожий кусок в похожую мысль, это уже работа Системы 2. Эта работа расходует ресурсы.

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

Что может пойти не так?
notion image

Быстрая память — дырявый стек. Если ее переполнить, старые мысли вывалятся на пол. Их придется думать заново.

Запутанный код будет прочитан кусочками слишком маленькими для формирования понимания того что он делает. Тогда в быструю память будут складываться промежуточные этапы сжатия информации о том что код делает. Это расходует ресурсы.

Код может быть написан таким образом, что Система 1 будет отдавать ошибочные оценки, категории и опыт. Тогда Система 2 потратит больше ресурсов на изменение информации которую переделал Система 1.

Заботливый код помогает подготовить сложную и массивную логику программы к сжатию в понятные программисту идеи и категории, и складыванию в маленькую быструю память.

Как это сделать? Уменьшить количество операция сжатия. Уменьшить стоимость каждой операции сжатия.

И тут в чат врываются книжки Дядюшки Боба, Макконнелла и других прекрасных авторов.

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

Если не на долго выключить зануду, то с некоторыми допущениями можно сказать что все полезные практики про одно и то-же. Это разные способы уменьшить количество операция сжатия и стоимость каждой операции сжатия, во время чтения кода.

Огромный набор паттернов проектирования - должны стать набором мыслей которыми может оперировать Система 1. Если ты видишь в коде FooBarFactory, то не задумываясь понимаешь, что эта фигня умеет порождать какие-то FooBar-ы.

Все эти бесчисленные архитектуры преследуют ту-же цель. Если ты видишь классы, имена которых заканчиваются на View и ViewModel, то непроизвольно сделаешь вывод что тут MVVM и сделаешь несколько предположений о том как эти классы взаимодействуют не читая их код.

Легкий для чтения код: - Содержит названия, по которым Система 1 бесплатно достает нужные понятия и опыт. - Структурирован понятным читателю образом. Избавляет от необходимости сначала разобраться в структуре. - Соотносится 1к1 с предметной областью.

Тяжелый для чтения код: - Содержит названия по которым Система 1 достает ошибочные понятия. - Содержит слишком много состояний, которое вываливаются из быстрой памяти.

Тяжелый для чтения код: - Содержит неявные и ненужные зависимости. Зависимости нужно отдельно вычитывать, сжимать и упаковывать в быструю память. - Содержит незнакомую структуру. На чтение и понимание структуры расходуются операции сжатия и дорогая быстрая память.

Знакомая архитектура лучше незнакомой.

Программист читая код работает с понятиями из 3х предметных областей. - Предметная область приложения. - Термины и понятия языка программирования, используемых фреймворков. - Термины и понятия архитектуры программы и конструкций используемых на прикладном уровне.

Предметная область приложения — самая важная и интересная часть. Ради нее пишется программа. Язык и фреймворки — уже знакомы программисту. С опытом эта часть расходует все меньше и меньше ресурсов. Архитектура приложения каждый раз отличается. В ней нужно разбираться.

Обман в коде — несоответствие названия содержанию. Встретив такой кусок читатель тратит дополнительные слоты в быстрой памяти на согласование названия с содержанием. Так происходит каждый раз, когда встречается обманывающее название.

Самый распространенный пример обмана в коде - это когда класс называется так как компонент из какой-то популярной архитектуры, но при этом делает что-то что не связанно с его зоной ответственности в той самой архитектуре, из которой заимствовано название.

Например ViewModel, который ходит в сеть. Тот кто знаком с MVVM в подлёдную очередь пойдет искать сетевой запрос в ViewModel. Или сингтон, для которого оставили возможность создать несколько инстансов.

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

Если зависимость или состояние неявные, не задекларированы в интерфейсе, то ресурс каждый раз тратится еще и на поиск.

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

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

Михаил КуренковМихаил Куренков