Вопрос: Как перестать говнокодить и принимать неверные архитектурные решения?

Лучший ответ: как писать поддерживаемый код?
Если уж очень коротко, то соблюдать SOLID/GRASP. Мне понравился твит одного из авторов React Router:
https://twitter.com/mjackson/status/1171524189850701825
Most common mistake software developers make: putting stuff in the wrong place. Coupling responsibilities and concepts that should be kept separate.
For me, this is 95% of software development. Just figuring out *where* things belong.Что гуглить, что учить?
Фундаментальные знания, вроде вышеупомянутых SOLID/GRASP, паттерны (не только классические паттерны, но и вообще, общеизвестные решения определённых задач), базовые структуры данных. Фреймворки/библиотеки всегда будут приходить/уходить, что-то будет забываться. А фундаментальные знания всегда актуальны.Может литературу какую почитать посоветуете?
Скажу за себя. Ни одной из этих известных книжек за свою жизнь не прочитал. Писал много говнокода дома, очень много. Удалял, переписывал. Смотрел код других людей, анализировал, пытался перенять то, что считал правильным.Можно ли себя называть миддлом, если твой код говно?
Не пытайтесь себя оценить. В каждой компании свои понятия миддла. А если кто-то 35 лет на лиспе кодил, а потом прыгнет на Angular - кто он, джун или сеньор?
И, да, все мы в какой-то степени пишем говнокод. Если кто-то Вам доказывает, что он пишет супер чистый код - не слушайте. И ответ на главный вопрос.Как перестать говнокодить и принимать неверные архитектурные решения?
Это невозможно. Все проекты, которые чуток сложнее CRUD-ов, рано или поздно обрастают говнокодом. Никто не пишет идеальный код. Код должен работать и решать проблемы бизнеса.

Худший ответ: Программирование — это знания, умения и навыки (можно иногда говорить "искусство", если про талантливых людей) НАХОДИТЬ КОМПРОМИССЫ. Компромиссы между скоростью выполнения задачи (значит стоимостью разработки) и качеством/ясностью вашего кода, между скоростью его исполнения и количеством потребляемой памяти/ресурсов, между наличием/отсутствием тестов и полнотой/качеством их покрытия вашего кода....и множество других  компромиссов. . В конце концов программирование — это такой огромный "конструктор", в котором можно складывать фигурки огромное количество раз и вариантов. Какие то варианты будут оптимальные и изящные, но большая часть далеко не такие. Чем лучше навыки-знания, тем лучше вариант. Чем больше попыток (удачных и не удачных), тем больше ваш опыт конструктора.
Любой, пусть даже (вдруг!) изначально "идеально написанный код" по мере развития проекта (хорошо когда бизнес идёт успешно и развивается) может превращаться в говнокод сам по себе, потому что "он обрастает костылями" при добавлении "фич" (нового функционала). Это нормальный и естественный процесс "эволюции кода/системы". Стараться держать в актуальном состоянии юнит/интеграционные/какие_есть тесты, учиться делать рефакторинг как коду, так и тестам— это навыки, которые надо развивать. Можно на личных проектах также, потому что для вас лично они более интересны и ценны по качеству и вы обычно не жёстко лимитированы по времени. Можно "решать задачки", можно участвовать в open source проектах. "Классические знания/труды" всегда остаются "в силе", про них написали выше, можно для развития ещё читать книги про "искусству создания эволюционирующей архитектуры" ПО. Не для того, чтобы называться сразу "архитектором", а хотя бы просто пробовать заранее планировать разработку, дизайн проекта/модуля/компонента/функции/итд в данном аспекте, оценивать возможные недостатки текущего кода/дизайна/архитектуры. Миддлу это сложно, но в получении новых знаний и навыков нет ничего плохого, если хватает свободного времени (а его всегда крайне мало). Надо понимать, что данная область знаний/профессия продолжает и будет дальше развиваться, новые языки/парадигмы/библиотеки/идеи будут появляться, поэтому самостоятельное развитие (практических) навыков и (теоретических) знаний для практики — залог успеха. Знания без практики и "умесности их применения" в том или другом случае/контексте — тоже могут быть бесполезны и/или вредны. Не надо фанатизма!
Да, иногда сложно "не костылить", да приходится идти с собой на компромисс, да ставить метки todo в коде и заносить в jira задачи "технического долга". Тех долг накапливается и если его не устранять, то рано или поздно проект становится сложно и мучительно поддерживать.
Как разработчик с опытом 18+ в данной профессии — согласен с предыдущими замечаниями. Универсального и единственно работающего рецепта "не говнокодить" нет, приходится развиваться, взрослеть по мере получения практического опыта и знаний.