Для начала нужно определиться что вообще такое «хороший» и «плохой» код, так как эти категории оценочны.
Разработчики между собой условно договорились, что хороший код — это код быстрый и хорошо масштабируемый. При этом он не может одновременно достичь обеих этих целей в пределе, это всегда определенный баланс и компромисс, так что идеального кода не может быть, в принципе. Профессионализм разработчика во многом связан с умением найти и удержать этот баланс.
Хороший код должен быть легко читаем и понятен. При увеличении кодовой базы проекта должна сохраняться ясность архитектуры, новые фичи должны добавляться легко, а разработчики не должны мешать друг другу при параллельной работе на разных участках. Код должен быть «развязан», то есть не иметь жёсткой связности внутри и взаимного влияния. Лучше всего в этом помогает следование принципам SOLID и использование паттернов проектирования. Соответственно, мы приходим к определённым требованиям в работе команд по части архитектуры и взаимодействия.
Как проверить качество кода?
Обычно в командах из двух и более разработчиков есть роль мейнтейнера, который отвечает за репозиторий. Ему присылают запросы на принятие изменений в проект. На этом этапе обычно проводится код-ревью — технический анализ кода на соответствие качеству. Здесь могут быть выявлены грубые ошибки и проведены тесты, таким образом плохой код не попадёт в продакшн.
Также полезно будет следовать гайдам и спецификациям конкретного языка или фреймворка — это унифицирует код и сократит итерации по его отладке. Также существуют линтеры, инструменты для автоматизации контроля когда на соответствие этим спецификациям, с их помощью можно разгрузить мейнтейнера от рутинной части. Линтеры можно интегрировать в IDE и в CI/CD при сборке проекта.
И если для разработчика хороший код — это элемент профессионального роста и способ выполнять работу в срок и с удовольствием, то для компании или заказчика — напрямую время и деньги. Это короткий time-to-market, частые релизы, возможность наращивать команду, ровная стоимость внесения изменений и удержание энтропии проекта — не превращение его в тяжело поддерживаемого монстра.
Плохой код — это обратное от хорошего. Типичным признаком является многословность, шумность, неочевидность и тяжёлая отладка. Такой код обычно медленно работает, его тяжело развивать, в нём есть уязвимости безопасности и архитектурные тупики. Классической историей с плохим кодом является монолитное приложение, которое писали несколько человек, каждый со своей колокольни и в меру своих знаний и навыков. В итоге мы имеем очень сложно поддерживаемый продукт.
Всегда ли нужно писать только хороший код?
На самом деле нет. Когда разработчик только начинает свой путь, непросто писать сложноустроенный и выверенный код, это не должно смущать и сбивать с цели. У молодого специалиста ещё нет необходимых знаний и опыта, нет коллег, которые будут вместе с вами работать на одном проекте.
В начале обучения программированию писать плохой код совершенно не зазорно. Тем, кто только учится или начинает стажировку вообще не стоит на себя примерять какие-то оценочные категории. На данном этапе стоит задача понять предметную область, научиться использовать конструкции языка и познакомиться с основами, а дальше уже будет работа в командах. Хороший код там довольно быстро заставит себя писать просто потому, что без него невозможно будет работать в команде над большим продуктом.
Плохой код может выдерживать только небольшой участок. Это очень важно понимать. В какой-то момент развивать продукт просто не получится, цена изменений будет непомерной, конструкция будет хрупкой и неповоротливой, поэтому придётся проводить рефакторинг, переписывать участки.
Тем не менее есть кейсы, когда плохой код оправдан даже у опытного разработчика. Если мы делаем какой-то очень маленький и очень быстрый проект, который нужно запустить за минимальное время с минимальными ресурсами, то почему нет? Если он не претендует ни на какую важность: не работает ни с какими персональными данными, не рассчитаны ни на какую нагрузку, а его главная задача быстро проверить какую-то гипотезу, то тратить ресурсы на сложные конструкции не обязательно. Если проект выстрелит, всегда можно будет провести рефакторинг.