Robert martin clean code
Robert martin clean code
Стоит прочитать: обзор книги Роберта Мартина «Чистый код. Создание, анализ и рефакторинг»
Одно из самых ярких впечатлений на меня произвела книга консультанта и автора в области разработки ПО Роберта Мартина «Чистый код. Создание, анализ и рефакторинг», написанная в 2012 году. Начиная работу, автор пишет:
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
В своей книге специалист подробно рассказывает о том, как избежать ошибок при написании кода и сделать его чистым.
Книга включает в себя три части. В первой автор описывает основные принципы и приемы создания чистого кода и приводит примеры такого «правильного» кода. Во второй части он демонстрирует сценарии, представляющие собой упражнения по чистке кода или по преобразованию плохого кода в код с меньшим числом ошибок. Последняя часть представляет собой главу, в которой автор описывает путь мышления человека в процессе чтения, написания и чистки кода.
На мой взгляд, книга написана простым языком, поэтому освоить ее сможет даже начинающий программист. Я бы порекомендовала ее людям, только начинающим осваивать профессию, поскольку важно усвоить принципы написания правильного кода в самом начале работы.
Общие правила написания чистого кода
В начале повествования автор сосредотачивает внимание на основных постулатах создания правильного кода. Прочитав эту часть, я поняла, что до того, как код отдан тестировщикам, важно продумать, какие могут возникнуть проблемы и ошибки. Необходимо понять, какой кейс не был учтен. Стоит полностью продумать свою задачу и только после этого приступать к ее выполнению. Ведь если человек начинает писать код, не продумав все заранее, он может столкнуться с ошибками, ему придется возвращаться назад, то есть выполнять двойную работу. Мне кажется, что это очень важный совет. Применяя его, сейчас я экономлю очень много времени и энергии.
Автор сравнивает написание кода с созданием книги. В обоих случаях сначала пишется черновик, в котором заранее продумываются все ходы, и только потом создается чистовик, содержащий лучший вариант. Если специалист хочет стать хорошим программистом, ему всегда нужно продумывать заранее ход работы.
Кроме того, не нужно бояться что-то менять в уже созданном коде. Часто программисты работают с чужим кодом и не меняют какие-то его элементы, поскольку бояться столкнуться с непредсказуемыми ошибками. По мнению автора, такая стратегия ошибочна, потому что она обязательно приведет к еще большему количеству ошибок. Также одним из основных постулатов создания чистого кода является принцип единой ответственности. Согласно ему, любая сущность должна выполнять только одно действие и нести только одну ответственность.
Автор говорит также о том, что код должен читаться сверху вниз. Функции лучше располагать так, чтобы при чтении одной, сразу было видно другую. Если же блоки кода находятся в разных местах, это очень затрудняет чтение.
Наконец, Р. Мартин отмечает важность удаления мертвого кода. Это код, который никогда не сработает или тот код, который уже не используется. По мнению автора, такие коды не приносят никакой пользы и удалять их нужно сразу же, чтобы все было структурировано. Далее я хотела бы рассказать о тезисах книги, которые кажутся мне наиболее важными.
Наименование
При написании кода очень важно задавать верное название, поскольку наименование обеспечивает читаемость кода. Необходимо использовать наиболее понятные и подходящие наименования. Прочитав название метода или сущности, специалист должен сразу понять, за что она ответственна. Стоит также помнить о принципе единой ответственности, и если программист ему следует, то функция вряд ли будет содержать вставки «And» или «With», поскольку функция выполняется лишь одно действие. При описании функции важно всегда использовать глаголы. Также желательно, чтобы в названии было ключевое слово, которое поможет понять, о чем эта функция.
Важно избегать одинаковых наименований. Если в вашем коде имеются функции с одинаковыми названиями, вероятно, они выполняют одно и тоже же действие. Если специалист назвал функции одинаково, а они выполняют разные действия, их нужно переименовать так, чтобы было понятно, что конкретно они делают. Если они выполняют одинаковые действия, но, например, с изменением одного параметра, то важно продумать, как сделать так, чтобы функция не дублировалась. Иными словами, если у двух функций одинаковое наименование, скорее всего, нужно что-то менять.
Наименования лучше не сокращать, а прописывать полностью. Например, если используется слово «product», название «pr» будет не очень понятным для читателя. Важно, чтобы название полностью отражало ответственность сущности.
Функции
По мнению Р. Мартина, функции должны быть максимально короткими. Их длина не должна быть больше двадцати строк, а сами строки не должны быть длиннее ста пятидесяти символов. В противном случае ее лучше делить на части. Кроме того, важно, чтобы функция выполняла только одну операцию. Что касается входных параметров, в идеале их не должно быть. Но если входные параметры требуются, то их должно быть не больше трех. Чем больше входных параметров, тем тяжелее читать функцию.
Комментарии
Слишком большое количество комментариев к коду означает, что написан он плохо. Комментировать код стоит только тогда, когда он может быть непонятен другому разработчику или самому создателю этого когда через какое-то время. Также не нужно комментировать плохой код, его необходимо просто переписать. Например, если специалист начинает работу над проектом другого программиста, и он видит ошибки, эти ошибки нужно сразу же исправлять.
Недописанный или некорректно работающий код всегда нужно комментировать, используя соответственно одно из двух ключевых слов «TODO» или «FIXME». В таком случае программист будет сразу понимать, что код не готов и его нужно дописывать. Также часто разработчики комментируют функции или части кода, чтобы когда-то к ним вернуться, и это переходит из ветки в ветку. Такие комментарии лучше не оставлять. Системы контроля версий хранят все состояния кода, поэтому необходимости переносить закомментированный код из ветки в ветку нет.
Форматирование кода, классы и обработка ошибок
При форматировании кода необходимо придерживаться общей стилистики проекта, его общепринятой архитектуры. Например, если в проекте используется архитектура V.I.P.E.R., то нужно использовать ее, иначе можно испортить код. Если же написание проекта начинается с нуля, то необходимо заранее продумать, какую архитектуру использовать и какой стилистики придерживаться.
Классы обязательно должны быть компактными. Название класса должно отображать его ответственность. И к ним также применяется принцип единой ответственности. Кроме того, Р. Мартин говорит о том, что по отношению к классам, как и по отношению к функциям, важно применять принцип компактности. Не стоит создавать большие классы, лучше разбивать их на подклассы. Важно создавать все новые подклассы до тех пор, пока не получится максимально раздробленная и понятная структура.
Наконец, при обработке ошибок всегда важно использовать exсeptions (исключения) вместо возвращения кода ошибок напрямую. Обработка ошибок всегда должна представлять собой только одну операцию. В функции, которая ответственна за обработку ошибки, ничего другого после произведения обработки выполняться не должно. Хотя на это вам намекнет и сам компилятор.
Книга Р. Мартина является сводом правил по написанию правильного кода, которым каждый программист должен следовать. На мой взгляд, умение писать чистый код – важный навык, помогающий специалисту не только самому понимать свой код лучше, но и работать в команде. Именно поэтому я уверена в том, что, если после этой статьи хоть один разработчик узнает о данной книге и прочтет ее, в мире станет на одного хорошего разработчика больше.
О книге Боба Мартина «Чистый код»
(Картинка без намека, просто уж очень хотелось котика в статью добавить! Ведь это основной залог популярности в интернетах, правда? :))
У меня очень неоднозначное отношение к книгам Роберта Мартина… В них довольно много здравых и интересных мыслей, но иногда они выражаются столь категорично, что неокрепшим программерским мозгом они могут восприниматься неправильно. Если же мозг читателя достаточно окреп, чтобы воспринимать советы прагматично, то есть все шансы, что ничего нового из этих советов он (мозг или программист) не вынесет.
Вот и получается, что идеальной аудиторией для этих книг является продвинутый разработчик, окрепший достаточно, чтобы критически оценивать советы «гуру», но при этом не настолько матерый, чтобы эти советы не звучали из разряда «Спасибо, Кэп!».
Хотя, нужно признать, что если в книге «Принципы, паттерны и методики гибкой разработки» спорных советов с моей точки зрения было очень много, то в «Чистом коде» приводится значительно больше разумных и прагматичных советов.
Но поскольку паранойи в книге тоже достаточно, поэтому я хочу начать именно с неоднозначных моментов, а уже потом перейти к радостям.
Спорные и сомнительные моменты
В «Чистом коде» есть несколько откровенно сомнительных моментов. Во-первых, в ней довольно много кода, читать который на страницах книги очень сложно. В 15-й главе рассматривается улучшение парсера командной строки на 60 страницах, 40 из которых – это сплошной код на Java. Главы 16-17 написаны в том же формате, но они короче, поэтому следовать рассуждениям автора проще.
СОМНИТЕЛЬНЫЙ СОВЕТ
Первое правило: функции должны быть компактными. Второе правило: функции должны быть еще компактнее. … Из сказанного выше следует, что блоки в командах if, else, while и т.д. должны состоять из одной строки, в которой обычно содержится вызов функции. Это не только делает вмещающую функцию более компактной, но и способствует документированию кода, поскольку вызываемой в блоке функции можно присвоить удобное содержательное имя.
Некоторые главы откровенно слабые. Мне вообще не понятна цель главы 13 о параллелизме, в которой даются лишь общие сведения о проблемах многопоточности, а затем в приложении А разбираются те же самые темы, но уже более детально и с необходимыми примерами.
Но больше всего меня смущает неоднозначное отношение автора к состоянию и побочным эффектам.
Побочные эффекты суть ложь. Ваша функция обещает делать что-то одно, но делает что-то другое, скрытое от пользователя. Иногда она вносит неожиданные изменения в переменные своего класса – скажем, присваивает им значения параметров, переданных функции…
Несмотря на этот совет, автор во многих примерах использует код с побочными эффектами и отговаривает всеми силами использовать аргументы, используя вместо этого состояние объекта:
СОМНИТЕЛЬНЫЙ СОВЕТ
… Аргументы создают массу проблем с точки зрения тестирования. Только представьте, как трудно составить все тестовые сценарии, проверяющие правильность работы кода со всеми комбинациями аргументов.
В чем разница с точки зрения тестирования между статическим методом с четырьмя аргументами и экземплярного метода объекта с четырьмя полями? Количество граничных условий в обоих случаях одно и тоже; просто в первом случае мы все входные данные протаскиваем явно, а во втором случае – неявно через this.
Стилю кодирования в книге уделено много внимания, при этом большинство советов вполне разумными. Но встречаются и очень неоднозначные:
СОМНИТЕЛЬНЫЙ СОВЕТ
Стандарт кодирования определяет, где объявляются переменные экземпляров; как именуются классы, методы и переменные; как располагаются фигурные скобки и т.д. Документ с явных описанием этих правил не нужен – сам код служит примером оформления.
Перевод
Перевод, мягко говоря, не порадовал. Иногда он «радовал» настолько, что приходилось лезть в оригинал, чтобы понять, о чем идет речь:
ЦИТАТА
Когда у вас появился полный набор тестов, можно заняться чисткой кода и классов.
Для этого код подвергается последовательной переработке (рефакторингу). Мы добавляем несколько строк кода, делаем паузу и анализируем новую архитектуру.
WTF! Как добавление двух строк может повлиять на архитектуру. Есть два варианта: либо мы имеем дело с очень длинными строками, или же авторы здесь говорят не об архитектуре, а о чем-то ином, например, о дизайне! Вся глава 12 (из которой взята эта цитата) полностью испорчена тем, что термин “design” переведен в ней как «архитектура», что делает многие советы автора спорными.
Как обычно, переводчики не потрудились оставить оригинальные термины, так что приходилось догадываться, что же имеется ввиду под терминами «логическая привязка» или «многопоточность» (оказывается, что это high coupling и concurrency, соответственно).
Поскольку содержимое книги относительно простое, то переводчикам удалось лишь «подпортить» впечатление, но не запороть ее полностью.
Дельные советы
На самом деле, все не настолько плохо и «дядюшка» Боб сотоварищи дают много хороших советов. Вот некоторые из них:
Об именовании
Не используйте имена, передающие информацию о реализации. Имена должны отражать уровень абстракции, на котором работает класс или функция.
О понятности кода
Легко писать код, понятный для нас самих, потому что в момент его написания мы глубоко понимаем решаемую проблему. У других программистов, которые будут заниматься сопровождением этого кода, такого понимания не будет.
О длине и выразительности имен
Длина имени должна быть связана с длиной его области видимости. Переменным с крошечной областью видимости можно присваивать очень короткие имена, но у переменных с большей областью видимости имена должны быть длинными. … Таки образом, чем длиннее область видимости, тем более длинным и точным должно быть ее имя.
О содержимом функций
Все операторы в функции должны находиться на одном уровне абстракции, который должен быть на один уровень ниже операции, описываемой именем функции.
Совет кажется простым, но он очень ценен. Код должен читаться, как хорошая проза, а для этого просто необходимо, чтобы функция содержала операторы одного уровня.
Юнит-тесты в качестве инструмента изучения библиотек
Изучение чужого кода – непростая задача. Интеграция чужого кода тоже сложна. Одновременное решение обоих задач создает двойственные сложности. А что, если пойти по другому пути? Вместо того, чтобы экспериментировать и опробовать новую библиотеку в коде продукта, можно написать тесты. Проверяющие наше понимание стороннего кода. Джим Ньюкирк (JimNewkirk) называет такие тесты «учебными тестами».
Этому совету я следую давно и использую юнит-тесты для изучения новых инструментов и библиотек. Это позволяет лучше разобраться с библиотекой и легко возвращаться к примерам использования, поскольку они всегда под рукой.
Очень повеселил один совет. Давайте так: что вам говорит магическая константа 5280? Ничего? Странно, по словам автора, это одно из значений, которое можно спокойно «хардкодить»!
Некоторые числа так легко узнаются, что их не обязательно скрывать за именованными константами – при условии, что они используются в сочетании с ясным кодом. … Число 5280 – количество футов в миле – настолько хорошо известно и уникально, что читатель сразу узнает его, даже если оно будет располагаться вне какого-либо контекста.
Качество книги можно косвенно оценить по количеству интересных цитат и количеству блог-постов, появившихся в процессе чтения. И если в процессе чтения «Принципов, паттернов и методик» появились критические статьи типа «Контракты, состояние и юнит-тесты», то в результате «Чистого кода» появились «Пять принципов чистых тестов» и «Лучшая метрика для определения качества кода».
Достоинства: приличное количество приличных советов
Недостатки: часть советов весьма спорны; иногда советы непоследовательны; перевод хромает на обе ноги.
Манифест Чистого Программиста или краткий конспект книги «Чистый Код» Роберта Мартина
Данная статья является конспектом книги «Чистый Код» Роберта Мартина и моим пониманием того, каким Чистый Код должен быть. Тут нет разделов о тестировании, TDD, о том какая должна быть архитектура и т.д. Здесь все только о том, каким должен быть Чистый Код.
Да, возможно, тема Чистого Кода уже заезженна, но тем не менее еще не все с ним знакомы и, тем более, я не встретил аналогов контента, который содержится в моей статье.
Общее
Нет истинного пути и решения. Есть тот, который лучше всего подходит для решения конкретной задачи.
При решении задачи попытайся воспроизвести абсолютно все кейсы, которые могут затрагивать эту задачу и реализуй задачу с учетом абсолютно всех кейсов.
Также при решении задачи попробуй пойти от обратного. Пойми какие результаты в итоге ты хочешь получить и составь на этом основании алгоритм, по которому будет выполняться задача.
Перед тем, как отправить задачу в релиз — проверь правильно ли она работает. Нет ли в ней ошибок. Это касается даже тех коммитов, которые отправляются в твою ветку. Самый идеальный сценарий — тот, в котором никто не смог найти ошибки в функционале, который ты разрабатывал.
Всегда задумывайся о том как можно сделать твой код проще, чище и читабельнее.
Чистый Код
Как писать чистый и хороший код? Это похоже на написание книги. Сначала ты делаешь черновик и потом причесываешь его до того состояния, в котором тебе было бы приятно его читать. Всегда помни, что твой код должен рассказывать историю происходящего, чтобы читатель мог ее понять.
Под сущностью понимается — интерфейс, класс, метод, переменная, объект и т.д.
Наименования и разделения
Функции
Комментарии
Форматирование и правила
Объекты и структуры данных
Классы
Обработка ошибок
Границы
Послесловие
В данной статье представлены лишь рекомендации к написанию Чистого Кода. Разумеется, ими можно пренебрегать. Вам лишь стоит понять, что у любого вашего решения должны быть аргументы в пользу него.
«Чистый код» Роберт Мартин. Конспект. Как писать понятный и красивый код?
Я решил написать конспект книги, которая всем известна, а сам автор называет ее «Школой учителей Чистого кода». Пристальный взгляд Мартина как бы говорит:
«Я тебя насквозь вижу. Ты опять не следуешь принципам чистого кода?»
Глава 1. Чистый код
Что же такое этот самый чистый код по версии Мартина в нескольких словах? Это код без дублирования, с минимальным количеством сущностей, удобный для чтения, простой. В качестве девиза можно было бы выбрать: «Ясность превыше всего!».
Глава 2. Содержательные имена
Имена должны передавать намерения программиста
Имя переменной, функции или класса должно сообщить, почему эта переменная существует, что она делает и как используется. Если имя требует дополнительных комментариев, значит, оно не передает намерений программиста. Лучше написать, что именно измеряется и в каких именно единицах.
Пример хорошего названия переменной: daysSinceCreation;
Цель: убрать неочевидность.
Избегайте дезинформации
Не используйте слова со скрытыми значениями, отличными от предполагаемого. Остерегайтесь малозаметных различий в именах. Например, XYZControllerForEfficientHandlingOfStrings и XYZControllerForEfficientStorageOfStrings.
По-настоящему устрашающие примеры дезинформирующих имен встречаются при использовании строчной «L» и прописной «O» в именах переменных, особенно в комбинациях. Естественно, проблемы возникают из-за того, что эти буквы почти не отличаются от констант «1» и «0» соответственно.
Используйте осмысленные различия
Если имена различаются, то они должны обозначать разные понятия.
«Числовые ряды» вида (a1, a2,… aN) являются противоположностью сознательного присваивания имен. Они не несут информации и не дают представления о намерениях автора.
Неинформативные слова избыточны. Слово variable никогда не должно встречаться в именах переменных. Слово table никогда не должно встречаться в именах таблиц. Чем имя NameString лучше Name? Разве имя может быть, скажем, вещественным числом?
Используйте удобопроизносимые имена: generationTimestamp намного лучше genymdhms.
Выбирайте имена, удобные для поиска
Однобуквенные имена могут использоваться только для локальных переменных в коротких методах.
Избегайте схем кодирования имен
Как правило, кодированные имена плохо произносятся и в них легко сделать опечатку.
Интерфейсы и реализации
Я (автор книги) предпочитаю оставлять имена интерфейсов без префиксов. Префикс I, столь распространенный в старом коде, в лучшем случае отвлекает, а в худшем — передает лишнюю информацию. Я не собираюсь сообщать своим пользователям, что они имеют дело с интерфейсом.
Имена классов
Имена классов и объектов должны представлять собой существительные и их комбинации: Customer, WikiPage, Account и AddressParser. Старайтесь не использовать в именах классов такие слова, как Manager, Processor, Data или Info. Имя класса не должно быть глаголом.
Имена методов
Имена методов представляют собой глаголы или глагольные словосочетания: postPayment, deletePage, save и т. д. Методы чтения/записи и предикаты образуются из значения и префикса get, set и is согласно стандарту javabean.
Воздержитесь от каламбуров
Задача автора — сделать свой код как можно более понятным. Код должен восприниматься с первого взгляда, не требуя тщательного изучения. Ориентируйтесь на модель популярной литературы, в которой сам автор должен доступно выразить свои мысли.
Добавьте содержательный контекст
Контекст можно добавить при помощи префиксов: addrFirstName, addrLastName, addrState и т. д. По крайней мере читатель кода поймет, что переменные являются частью более крупной структуры. Конечно, правильнее было бы создать класс с именем Address, чтобы даже компилятор знал, что переменные являются частью чего-то большего.
Переменные с неясным контекстом:
Функция длинновата, а переменные используются на всем ее протяжении. Чтобы разделить функцию на меньшие смысловые фрагменты, следует создать класс GuessStatisticsMessage и сделать три переменные полями этого класса. Тем самым мы предоставим очевидный контекст для трех переменных — теперь абсолютно очевидно, что эти переменные являются частью GuessStatisticsMessage.
Переменные с контекстом:
Не добавляйте избыточный контекст
Короткие имена обычно лучше длинных, если только их смысл понятен читателю кода. Не включайте в имя больше контекста, чем необходимо.
Глава 3. Функции
Компактность!
Первое правило: функции должны быть компактными.
Второе правило: функции должны быть еще компактнее.
Мой практический опыт научил меня (ценой многих проб и ошибок), что функции должны быть очень маленькими. Желательно, чтобы длина функции не превышала 20 строк.
Правило одной операции
Функция должна выполнять только одну операцию. Она должна выполнять ее хорошо. И ничего другого она делать не должна. Если функция выполняет только те действия, которые находятся на одном уровне под объявленным именем функции, то эта функция выполняет одну операцию.
Секции в функциях
Функцию, выполняющую только одну операцию, невозможно осмысленно разделить на секции.
Один уровень абстракции на функцию
Чтобы убедиться в том, что функция выполняет «только одну операцию», необходимо проверить, что все команды функции находятся на одном уровне абстракции.
Смешение уровней абстракции внутри функции всегда создает путаницу.
Чтение кода сверху вниз: правило понижения
Код должен читаться как рассказ — сверху вниз.
За каждой функцией должны следовать функции следующего уровня абстракции. Это позволяет читать код, последовательно спускаясь по уровням абстракции в ходе чтения списка функций. Я называю такой подход «правилом понижения».
Команды switch
Написать компактную команду switch довольно сложно. Даже команда switch всего с двумя условиями занимает больше места, чем в моем представлении должен занимать один блок или функция. Также трудно создать команду switch, которая делает что-то одно — по своей природе команды switch всегда выполняют N операций. К сожалению, обойтись без команд switch удается не всегда, но по крайней мере мы можем позаботиться о том, чтобы эти команды были скрыты в низкоуровневом классе и не дублировались в коде. И конечно, в этом нам может помочь полиморфизм.
В примере представлена всего одна операция, зависящая от типа работника.
Эта функция имеет ряд недостатков. Во-первых, она велика, а при добавлении новых типов работников она будет разрастаться. Во-вторых, она совершенно очевидно выполняет более одной операции. В-третьих, она нарушает принцип единой ответственности (Single responsibility principle), так как у нее существует несколько возможных причин изменения.
В-четвертых, она нарушает принцип открытости/закрытости (The Open Closed Principle), потому что код функции должен изменяться при каждом добавлении новых типов.
Но, пожалуй, самый серьезный недостаток заключается в том, что программа может содержать неограниченное количество других функций с аналогичной структурой, например:
isPayday(Employee e, Date date)
deliverPay(Employee e, Money pay)
Все эти функции будут иметь все ту же ущербную структуру. Решение проблемы заключается в том, чтобы похоронить команду switch в фундаменте абстрактной фабрики и никому ее не показывать. Фабрика использует команду switch для создания соответствующих экземпляров потомков Employee, а вызовы функций calculatePay, isPayDay, deliverPay и т. д. проходят полиморфную передачу через интерфейс Employee.
Мое общее правило в отношении команд switch гласит, что эти команды допустимы, если они встречаются в программе однократно, используются для создания полиморфных объектов и скрываются за отношениями наследования, чтобы оставаться невидимыми для остальных частей системы. Конечно, правил без исключений не бывает и в некоторых ситуациях приходится нарушать одно или несколько условий этого правила.
Используйте содержательные имена
Половина усилий по реализации этого принципа сводится к выбору хороших имен для компактных функций, выполняющих одну операцию. Чем меньше и специализированнее функция, тем проще выбрать для нее содержательное имя.
Не бойтесь использовать длинные имена Длинное содержательное имя лучше короткого невразумительного. Выберите схему, которая позволяет легко прочитать слова в имени функции, а затем составьте из этих слов имя, которое описывает назначение функции.
Аргументы функций
В идеальном случае количество аргументов функции равно нулю. Далее следуют функции с одним аргументом (унарные) и с двумя аргументами (бинарные). Функций с тремя аргументами (тернарных) следует по возможности избегать.
Выходные аргументы запутывают ситуацию еще быстрее, чем входные. Как правило, никто не ожидает, что функция будет возвращать информацию в аргументах. Если уж обойтись без аргументов никак не удается, постарайтесь хотя бы ограничиться одним входным аргументом.
Преобразования, в которых вместо возвращаемого значения используется выходной аргумент, сбивают читателя с толку. Если функция преобразует свой входной аргумент, то результат
должен передаваться в возвращаемом значении.
Аргументы-флаги
Аргументы-флаги уродливы. Передача логического значения функции — воистину ужасная привычка. Она немедленно усложняет сигнатуру метода, громко провозглашая, что функция выполняет более одной операции. При истинном значении флага выполняется одна операция, а при ложном — другая.
Бинарные функции
Функцию с двумя аргументами понять сложнее, чем унарную функцию. Конечно, в некоторых ситуациях форма с двумя аргументами оказывается уместной. Например, вызов Point p = new Point(0,0); абсолютно разумен. Однако два аргумента в нашем случае являются упорядоченными компонентами одного значения.
Объекты как аргументы
Если функция должна получать более двух или трех аргументов, весьма вероятно, что некоторые из этих аргументов стоит упаковать в отдельном классе. Рассмотрим следующие два объявления:
Если переменные передаются совместно как единое целое (как переменные x и y в этом примере), то, скорее всего, вместе они образуют концепцию, заслуживающую собственного имени.
Глаголы и ключевые слова
Выбор хорошего имени для функции способен в значительной мере объяснить смысл функции, а также порядок и смысл ее аргументов. В унарных функциях сама функция и ее аргумент должны образовывать естественную пару «глагол/существительное». Например, вызов вида write(name) смотрится весьма информативно.
Читатель понимает, что чем бы ни было «имя» (name), оно куда-то «записывается» (write). Еще лучше запись writeField(name), которая сообщает, что «имя» записывается в «поле» какой-то структуры.
Последняя запись является примером использования ключевых слов в имени функции. В этой форме имена аргументов кодируются в имени функции. Например, assertEquals можно записать в виде assertExpectedEqualsActual(expected, actual). Это в значительной мере решает проблему запоминания порядка аргументов.
Разделение команд и запросов
Функция должна что-то делать или отвечать на какой-то вопрос, но не одновременно. Либо функция изменяет состояние объекта, либо возвращает информацию об этом объекте. Совмещение двух операций часто создает путаницу.
Изолируйте блоки try/catch
Блоки try/catch выглядят весьма уродливо. Они запутывают структуру кода и смешивают обработку ошибок с нормальной обработкой. По этой причине тела блоков try и catch рекомендуется выделять в отдельные функции.
Обработка ошибок как одна операция
Функции должны выполнять одну операцию. Обработка ошибок — это одна операция. Значит, функция, обрабатывающая ошибки, ничего другого делать не должна. Отсюда следует, что если в функции присутствует ключевое слово try, то оно должно быть первым словом в функции, а после блоков catch/finally ничего другого быть не должно.
Сравнение стандарта PEP8 и «Чистого кода» Роберта Мартина
Предисловие
Привет, Хабр! Признаюсь, честно, за время моего отсутствия я успел по вам соскучиться.
Прежде чем начинать изложение материала, позвольте рассказать небольшую историю, вдохновившую написать эту статью.
Был совершенно обычный день, когда мне в обеденное время написал в ВК знакомый с предложением пройти собеседование на должность разработчика на языке Python. Вакансия очень сильно заинтересовала, поскольку у меня есть большой интерес развиваться в этом языке. Пообщавшись с менеджером, сбросил ему резюме и прикрепил небольшой проект web-серверного приложения.
Главный разработчик провёл ревью и пришёл к выводу, что мне пока рано занимать такую вакантную должность. Вместе с этим HR отправил рекомендации разработчика, как и в каком направлении можно развиваться. Одно из них – чтение книги «Чистый код» под авторством Роберта Мартина
Я сначала не придал особого значения этой книге. За время обучения программированию на Python мне много рекомендовали что почитать. Что-то мне нравилось, что-то нет. Но здесь всё решил один случай.
Через три дня после собеседования я поехал на крупнейшую IT конференцию на Урале DUMP2022. Там познакомился со многими практикующими разработчиками в том числе из этой компании. Какова была моя радость, когда на одной из секций докладчик отметил мой вопрос как лучший, а подарком как раз стала эта книга.
Я понял, что это был знак. Мне действительно надо было прочитать эту книгу. И как оказалось не зря.
Нет, эта статья не очередной обзор, на парадигму автора. Это статья о сравнении двух стандартов PEP8 и «Чистого кода». Вместе с вами я посмотрю чем отличаются эти два стандарта между собой, в чём их сходство. Полученные знания углубят понимание фундаментальных принципов программирования и возможно повлияют на стиль оформления кода.
О «Чистом коде»
Книга Роберта Мартина перевернула мои взгляды о программировании на 180 градусов. До прочтения книги я не задумывался о том, что надо грамотно именовать переменные, грамотно оформлять функции, классы, дизайнерить архитектуру приложения. Про написание юнит тестов вообще промолчу. Всегда считал, что знание юнит тестов больше нужны тестировщику, а не разработчику. Какой же я наивный!
Итогом вышло полное игнорирование архитектуры кода, тестов и так далее. В общем теперь понятно, почему мне отказали в должности.
Когда закончил чтение книги, то понял, что парадигма Чистого Кода является стандартом, к которому стремятся придерживаться крупные IT компании города Екатеринбург (напр. ТОЧКА или СКБ-КОНТУР). И притом совершенно не важно на каком языке я программирую.
Автор пишет код на языке Java. К слову сказать, я не нашёл в интернете какие-либо стандарты (вроде PEP8 в Python), которые могли бы подойти для написания качественного кода на той же Java. Поэтому с осторожностью говорю, что «Чистый код» уже является в какой-то степени набором требований, к которым начинающему разработчику стоит присмотреться. И даже не важно соглашается ли он в полной мере с позицией автора или нет. Тут важно смотреть на альтернативные взгляды о проектировании кода и решать для себя какой подход наиболее подходящий, чтобы читатель кода меня правильно понял.
О стандарте PEP8
Если парадигма Clean Code является стандартом для языка Java, то в Python главным документом, по которому пишется качественный код является PEP8.
За основу написания документа взяты рекомендации создателя языка Python Гвидо ван Россума и дополнения Паула Барри. Программы, написанные по PEP8 читаются в едином стиле и его способен понять каждый Python разработчик. Использование стандарта при разработке программы можно достичь согласованности и единство кода. Я согласен с мнением автора, что согласованность кода со стандартом очень важна. Ведь меня читают другие люди.
Методика сравнения стандартов.
В качестве основного метода сравнения я выделил несколько ключевых слов, встречающиеся в PEP8 и в Чистом коде. Таким образом получился список из 8 пунктов:
“Чистый код”: пять ключевых моментов из обязательной к прочтению книги для программистов
Недавно я написал о «Пять книг, которые изменили мой стиль программирования». В комментариях несколько читателей рекомендовали «Чистый код» Роберта С. Мартина. В результате я прочитал книгу и нашел ее достойной углубленного обзора.
О книге
«Чистый код» был опубликован в 2008 году, и в последние годы он неизменно входит в пятерку самых продаваемых книг на Amazon. Автор, которого ласково называют «Дядя Боб», был одним из первых авторов Agile Manifesto и имеет некоторые серьезные полномочия. Книга получила средний рейтинг 4,4 на Goodreads из более чем 13 000 оценок. Достаточно сказать, что это одна из тех книг, которую должен прочитать каждый программист.
В этом обзоре я собираюсь сжать книгу до пяти основных мыслей.
1. Программирование — это прикладное искусство
Я часто думал, что архитектура и строительство — плохие метафоры для программирования. Мы не создаем полный проект, чтобы потом строить (по нему) от самого фундамента до полностью готового здания.
Скорее мы начнем с эскиза, постепенно добавляя детали. Мы пересматриваем, дорабатываем и расширяем — работаем на разных уровнях абстракции, пока программное обеспечение не заработает так, как нам нужно. Программное обеспечение никогда по-настоящему не закончено.
В этом и есть главная суть «Чистого кода». На протяжении всей книги автор проводит идею о том, что программное обеспечение является искусством и сродни живописи.
Но как перейти от простого написания кода к искусству программирования?
По словам Мартина, основными инструментами, которыми мы располагаем, являются непрерывный рефакторинг и разработка на основе тестирования (TDD). Они неотделимы друг от друга, как две стороны медали. Вот некоторые определения.
Рефакторинг — это процесс реструктуризации существующего программного кода без изменения его внешнего поведения.
Разработка через тестирование — это процесс, в котором требования превращаются в конкретные тестовые сценарии, а затем пишется код и проводится успешное тестирование.
Итак, процесс создания программного обеспечения может выглядеть примерно так.
«Это миф, что мы можем создавать системы «с первого раза». Вместо этого, сегодня мы должны разрабатывать «истории», которые актуальны на текущий момент, затем реорганизовывать и расширять систему для реализации новых историй в будущем. Отсюда и возникает гибкость итеративного и инкрементального подхода».
Таким образом, основная идея, представленная Мартином, заключается в том, что чистый код — это то, что возникает в процессе и практике разработки, а не создается за один раз.
2. Функции должны быть короткими!
«Первое правило функций — они должны быть маленькими. Второе правило функций заключается в том, что они должны быть еще меньше».
По словам Мартина, это означает две вещи.
Краткость функции облегчает чтение кода. Это также приводит к тому, что функция выполняет одну задачу и делает это хорошо.
Автор книги делает аналогичное замечание о классах. По идее класс должен отвечать только за одну вещь. Это известно как принцип единственной ответственности (SRP).
Уменьшение размера сущностей — это стратегия «разделяй и властвуй» для того, чтобы сделать код чище. Если у нас есть большой файл с большим количеством длинного и сложного кода, можно разделить этот файл на модули, разделить модули на функции и разделить функции на подфункции, пока логика и намерение не станут ясными.
3. Делай код самодокументирующимся
«Ясный и выразительный код с небольшим количеством комментариев намного лучше загроможденного и сложного кода с большим количеством комментариев».
В разделах, посвященных комментариям, осмысленным именам и форматированию, Мартин обосновывает необходимость самодокументирования кода. Пример этого приведен ниже:
«Чистый код» включает в себя полную главу о присвоении имени, которая, по сути, является разработкой правил Тима Оттингера.
4. Абстракция важна
Согласно «Чистому коду», если мы хотим убедиться, что наши функции выполняют только одну задачу, нам нужно убедиться, что все команды в каждой функции находятся на одном уровне абстракции.
Мартин иллюстрирует это следующим примером из FitNesse:
Это сочетание как минимум двух уровней абстракции. Первая — это высокоуровневая концепция рендеринга тега hr с заданным размером, вторая — это детали фактического синтаксиса низкоуровневого построения тега. Чтобы проиллюстрировать это, код реорганизован более чисто, как показано ниже:
По словам Мартина:
«Разделение уровней абстракции является одной из важнейших функций рефакторинга и одной из самых сложных для достижения успеха».
Теперь я буду уделять этому большее внимание при написании кода в будущем.
5. Чистый код — это тяжелая работа и соблюдение принципов
Я не хотел, чтобы этот обзор был просто списком пунктов и афоризмов, формирующих правила, которые мы можем просто применить, чтобы получить чистый код. Это было бы плохой услугой для книги, так как сам по себе такой догматический подход далек от истины.
Скорее, у меня складывается впечатление, что Мартин уговаривает нас развить сильное чувство личных принципов и постоянно демонстрирует усилия и добросовестность, необходимые для того, чтобы сделать код из грязного чистым. В книге это называется «смыслом кода», то, что требует «дисциплинированного использования множества маленьких приемов, применяемых через тщательно приобретенное чувство чистоты».
«Чистый код пишется не по правилам. Вы не станете мастером программного обеспечения, изучив список приемов. Профессионализм и мастерство проистекают из ценностей, которые определяют дисциплину».
Лично я, как человек, который страдает от недостатка уверенности, очень оценил этот акцент. Приятно знать, что даже дядя Боб твердо верит, что кодирование — сложное занятие и требует серьезной работы и дисциплины. Чтобы действительно стать профессионалами в написании чистого кода, нам нужно подходить к нашему развитию как программистов итеративно — так же как к написанию кода.
Заключение
Не каждая идея в «Чистом коде» принадлежит дяде Бобу, и он открыто признает это в разных местах книги. Во всяком случае, одна из вещей, которая делает книгу настолько успешной — это квинтэссенция мудрости из различных сообществ программистов, наполненная практическими примерами.
Если для меня и есть один небольшой недочет, так это то, что немного нарушен баланс между главами о деталях и с главами о концепциях более высокого уровня. Глава, посвященная системам, содержит всего 13 страниц, и почти половина посвящена комментариям. Тем не менее, я подозреваю, что автор специально уделил мало внимания системам, чтобы сохранить это обсуждение для его более поздней книги «Чистая архитектура», которая будет в моем списке литературы на 2021 год. Но все же, это одна из лучших книг по программированию.
P.s. Спасибо Zack Shapiro
В ЛАНИТ есть вакансии в области разработки. Те, кто ценит эту книгу, – милости просим к нам.
Robert martin clean code
Роберт Мартин. «Чистый код. Создание, анализ, рефакторинг»
Мелочи важны. 80% работы программиста — поддержка существующего кода. Применение японского принципа 5S к программированию:
Метрика хорошего кода — количество «чертей» в минуту Профессионализм = знания + опыт. Писать чистый код — тяжело. 3 части книги: теория, практика, эвристические правила.
Глава 1. Чистый код
Глава 2. Содержательные имена
Выбор хорошего имени требует усилий и времени, но окупается впоследствии. Несколько правил хорошего именования сущностей.
Имена должны передавать намерения программиста
Не бояться переименовывать переменные, если найден более удачный вариант. Имя несет информацию о том почему переменная существует, что делает, как используется. Если требуется комментарий в коде – имя выбрано неудачно.
Используйте осмысленные различия
Сложное правило. Плохие примеры ясны, а как делать хорошо?
Используте удобопроизносимые имена
Код читают. О коде разговаривают. Имена должны нормально произноситься вслух. Избегать дурацких сокращений, непонятных аббревиатур и кодов.
В другой книжке есть яркий пример, который живет и процветает – аббревиатура SQL. Принятое на Западе произношение: «сиквел»; у нас же я слышал только «эс-кю-эль».
Выбирайте имена, удобные для поиска
Длинные, запоминающиеся имена ищутся редактором легко. Короткие однобуквенные допустимы лишь для локальных переменных, например для итератора цикла.
Избегайте схем кодирования имен
Бывает, что в именах переменных кодируют мета-информацию о типе, области видимости и т.д. Не надо так, придется каждому новому разработчику объяснять схему.
В доисторические времена в названии переменной кодировали как раз мета-инфу, например в Fortran первая буква означала тип. Темные времена прошли, не надо так.
Префиксы членов класса
Интерфейсы и реализации
Это уже наверное про конкретные случаи, особенности языков и парадигм. Для Typescript всё-таки не зашквар, думаю.
Избегайте мысленных преобразований
Локальные мемы вжопу. Сюда же – сленг и просторечия.
Где-то около этого пункта: я бы рекомендовал следить за элементарной орфографией и не лениться заглядывать в переводчик. А то знаю я некоторых транслэйтэров, блеать
Выберите одно слово для каждой концепции
Не использовать одно и то же слово в двух разных смыслах.
Используйте имена из пространства решения
Не стесняться использовать термины CS, названия паттернов, алгоритмов, математические термины. Не забывая при этом про избегание дезинформации.
Используйте имена из пространства задачи
Термины предметной области приложения – тоже ок.
Добавьте содержательный контекст
Не добавлять избыточный контекст
Будет мешать автокомплиту + в принципе засоряет код, лишние префиксы все равно взглядом будут игнорироваться.
Для выбора хороших имен нужен описательный навык и единый культурный фон в команде. Этому можно научиться и выработать. Не бояться переименовывать неудачные места. Хорошие имена помогут именно читать код + чисто технически добавит удобства в разработке (опять же про автокомплит, хотя бы).
Глава 3. Функции
Функции – первый уровень структуризации программы.
Каждая фунция должна быть предельно очевидной и компактной. Предела совершенству здесь нет.
Блоки и отступы
Правило одной операции
Функция должна выполнять только одну операцию, делать это хорошо и не делать ничего другого. Что считать одной операцией: это действие на одном уровне абстракции. Чтобы определить, что в фунции выполняется несколько операций, надо попробовать извлечь из нее другую функцию, которая не являлась бы переформулировкой реализации. Если в функции возможно осмысленное разделение на секции (например: объявления, инициализация, и т.д.) – значит, фунция выполняет несколько операций.
Вторую часть (про определение одной операции) понимаю чуть смутно. Нужно найти пример и вернуться к этому разделу.
Один уровень абстрации на функцию
Ещё раз – все команды функции (может быть несколько этапов, это не противоречит правилу одной операции) лежат в одном уровне абстрации. Например: getHtml – высокий, getName – средний, appendSymbol – низкий.
Примеры операций на разных уровнях абстракции немного изменены. Найти яркий пример из своей работы и добавить.
Чтение кода сверху вниз: правило понижения
Код должен читаться как рассказ – сверху вниз спускаясь по уровням абстрации. Иначе говоря: программа = набор ТО-абзацев, каждый из которых описывает текущий уровень абстрации и ссылается на следующий.
ТО-абзац – дефиниция. Например: renderPageWithSettings – функция, генерирующая код страницы в соответствии с переданными параметрами.
Написать компактный switch или цепочку if/else очень сложно, потому что switch рулит несколькими командами, как правило. Но можно сокрыть эти команды в низкоуровневом классе и не дублировать в коде. Здесь поможет полиморфизм. Переносим switch в абстрактную фабрику, в которой вызовы нужных команд проходят полиморфную передачу через интерфейс.
Здесь тоже не до конца понятен пример и как делать в js. Надо вернуться и разобраться.
Используйте содержательные имена
Имя должны давать понять, что происходит в функции. Не бояться использовать длинные имена, не бояться тратить на это время. Попробовать несколько вариантов. Иногда поиск понятного имени приводит к реструктуризации кода. Ещё нужно быть последовательным в именовании, использовать одинаковую фразеологию. «Функция должна делать примерно то, что вы ожидаете».
Идеал – функция без аргументов(нуль-арная). Допустимы унарные и бинарные функции. Тернарных и пониарных функций нужно избегать. При чтении кода аргументы приходится каждый раз интерпретировать. Часто аргумент и имя функции находятся на разных уровнях абстракции. Большое количество аргументов усложняет тестирование, ведь надо покрыть все кейсы, во всех сочетаниях. Фунции с выходными аргументами – вообще зло.
_Выходные – аргументы, чьи значения изменились после выполнения функции. _
Стандартные унарные формы
Два распространенных случая использования унарной функции: проверить некторое условия, связанное с аргументом, и обработка аргумента с последующим вызвращением. Нужно выбирать имена, четко отражающих эти разлиция. Ещё один частый вариант – событие. Функция принимает аргумент, и производит некоторые изменения состояния системы. Опять же – имя должно давать понять, что перед нами именно событие. Следует избегать иных форм унарных функций (речь опять же про выходные аргументы).
В конце главы описаны варианты игр с ООП, которые я не очень хорошо понял. Вернуться, написать свои примеры.
Разобраться с тремя аргументами ещё сложнее.
Объекты как аргументы
Если есть 2-3-n аргументов – может их упаковать в отдельный класс? Это может показаться жульничеством, но если переменные передаются совместно, и жить друг без друга не могут, значит это отдельная концепция, заслуживающая своего имени.
Если в функцию передается переменное количество аргументов, то есть смысл заключить их в List
Глаголы и ключевые слова
Избавьтесь от побочных эффектов
Побочные эффекты – зло. Функция обещает делать что-то одно, но скрыто совершает что-нибудь дополнительно. Побочные эффекты часто должны быть исполнены в определенный момент времени. За временными привязками следить сложно, особенно когда они скрыты в сайдэффекте. Ну и опять же – правило одной операции нарушается.
Выходные аргументы заставляют обращаться к сигнатуре, а это нарушает ритм чтения кода. Следует их избегать.
Разделение команд и запросов
Используйте исключения вместо возвращения кодов ошибок
Изолируйте блоки try/catch
try/catch смешивает обработку ошибок с нормальным выполнением функции, поэтому из следует выносить в отдельную функцию. Обработка ошибок должна быть одной операцией, и после catch/finally не должно быть ничего другого.
Хороший прием. Посмотреть пример в книге, и написать свой – очень должен пригодится.
Магнит зависимостей Error.java
Обычно создают класс/перечисление всех кодов ошибок, и потом используют во всех остальных классах. Тут есть нюанс (который я не очень уловил, поскольку не знаю Java. Вернуться и проанализировать.)
Не повторяйтесь (DRY)
Дублирование кода увеличивает его объем, делает сложным поддержку/рефакторинг, увеличивет вероятность ошибки. Не надо так.
Как научиться писать такие функции?
Программирование – тоже сочинительство. Сначала излагаешь мысли, потом «причёсываешь». Пытаться сразу писать чисто не надо.
Искусство программирования – это искусство языкового проектирования (где функции – глаголы, а класы – существительные). Средства языка нужно применять для создания более высокоуровневого предметно-ориентированного языка, описывающего вашу систему. Иерархия функций очень поможет. Конечная цель – написать легко читаемый рассказ, «историю системы».
Глава 4. Комментарии
Уместные комментарии – хорошо. Бессодержательные, безапелляционные, устаревшие комментарии – плохо. Комментарии нужны из-за невыразительности языка и нашего неумения им пользоваться. Комментарий компенсирует нашу неудачу в выражении мыслей. Идеально, если код понятен без комментария. Комментарит – зло: ведь обычно сопровождением комментариев никто не занимается, следовательно они устаревают, становятся неверными. Неточный комментарий к коду вреднее, чем его отсутсвие. Истина все равно в коде.
Комментарии не компенсируют плохого кода
Не нужно писать пояснения к запутанно написаному модулю: лучше отрефакторить и сделать проще. Не тратьте время на комментирование, тратьте на исправление.
Объясните свои намерения в коде
Следить за наименованием функций и переменных – они могут избавить от комментирования.
Например, заявление об авторских правах. Чаще всего, достаточно короткого комментария со ссылкой на полный текст.
Некоторая полезная информация о реализации. Например: подсказать, что возвращает функция, или какие параметры принимает.
Раскрывает намерения вашего архитектурного или логического решения. Отвечает на вопрос: «А почему тут так?»
Перевод загодочных аргументов или возвращаемых значений на человеческий язык. Трудно поддерживать, постарайтесь найти иное решение этой проблемы.
Предупреждения о последствиях
Информирование о нежелательных последствиях выполнения того или иного кода.
// TODO как план на будущее: сделать необходимо, но не получится прямо сейчас.
То же самое, что и представление намерений, но там где это незаметно и можно проебать.
Комментарии Javadoc в общедоступных API
Пишешь апишку – напиши комментарии к ней.
О, их будет гораздо больше.
Хочешь написать комментарий – пиши понятно. Не допускайте таких комментариев, для понимания которых придется залезть в другие фукнции/модули.
Комментарии капитана Очевидность. Дублирует название функции.
Ложь в комментарии – устаревшая информация или просто невнимательность.
Бессмысленная херня, когда зачем-то комментируют каждую функцию.
Когда-то программисты дописывали в начале модуля журнал всех изменений. Сейчас есть гит и не надо так.
Это комменты КО и прочий мусор. Это эе тоже придется поддерживать, иначе будет опасненько.
Не используйте комментарии там, где можно использовать фукцию или переменную
В этом заголовке – содержание всей главы
// Actions //////////// Форматирование кода с помощью комментариев-заголовков – только там, где это приносит ощутимую пользу.
Комментарии за закрывающей фигурной скобкой
Ссылки на авторов
Опять же: наследие эпохи до VCS.
Если код не нужен – удоли.
Когда в тексте комментария встречается разметка – это трудно читать.
Комментарий должен описывать тот кусок кода, рядом с которым написан.
Слишком много информации
Иногда в комменты запихивают чуть ли не статьи с Википедии. Не надо так.
Если комментарий нуждается в объяснении – он плохой.
Нужно нормально выбирать имена.
Заголовки Javadoc во внутреннем коде
Не приносит пользы, если это не общедоступный код.
Глава 5. Форматирование
Уважение к деталям – хорошо. Зафиксируйте в своей группе правила оформления кода и седуйте им.
Стиль кодирования и удобочитаемость имеют большое влияние на сопровождаемость и расширяемость кода
Приводится небольшое исследование размера исходных файлов программ на Java (Junit – меньше, Tamcat – больше)
Структура файла должна напоминать газетную статью: заглавие, краткое содержание в первом абзаце, а дальше уже факты, подробности. Чем дальше к концу – тем подробнее и ниже уровень абстрации.
Вертикальное разделение концепций
Строка = выражение, условие. Группа строк = законченная мысль. Мысли следует разделять пустыми строками.
Вертикальное разрежение разделяет концепции, сжатие – наоборот, подчеркивает тесную связь.
По коду трудно навигироваться, приходится постоянно прыгать между кусками кода и файлами. Связанные друг с другом концепции должны распологаться по соседству. Переменные объявлять как можно ближе к месту использования. Переменные экземпляров – в начале класса, так как используются многими методами класса (в С++ поступают наоборот, размещая переменные внизу. Так или иначе, надо их держать вместе и не прятать где-то в середине). Вызывающая функция должна находится над вызываемой. Концептуально родственные участки должны распологаться поблизости (например, группа функций, выполняющих аналогичные операции).
Еще раз: от высоких абстракций к низким, от вызывающих функций к вызываемым.
Исследование длин строк в файлах. Оптимально – до 120 символов.
Горизонтальное разделение и сжатие
Группировки связанных элементов и разделения разнородных. Знаки присваивания окружаются пробелами, аргументы не отделяются от имени функции, сами аргументы разделяются пробелами. В формулах: множители не разделяются пробелами (высокий приоритет операции), слагаемые – разделяются (низкий приоритет). Такой фичи чаще всего нет в инструментах автоматического форматирования, а жаль.
Нет пользы выравнивать группу объвлений переменных а-ля таблица. Более того, выявляется важный дефект: если хочется выровнять длинный список – это признак того, что его нужно сократить.
Отступы создают иерархию: классы > методы > блоки внутри методов. Не стот нарушать систему отступов для коротких блоков, вытягивая их в одну строку.
Вырожденные области видимости
Иногда тело цикла не содержит команд – является вырожденным. Их стоит избегать, но если не получается – правильно отбивать отступами и скобками.
Правила форматирования в группах
Код продукта должен быть оформлен в одном стиле. Потратьте 10 минут и зафиксируйте правила оформления в вашей команде.
Читать “Чистый код. Создание, анализ и рефакторинг”
Создание, анализ и рефакторинг
Библиотека программиста 2019
© Prentice Hall, Inc.
© Перевод на русский язык ООО Издательство «Питер», 2018
© Издание на русском языке, оформление ООО Издательство «Питер», 2019
* * *
Посвящается Анне-Марии — бессмертной любви всей моей жизни
Предисловие
В Дании очень популярны леденцы Ga-Jol. Их сильный лакричный вкус отлично скрашивает нашу сырую и часто холодную погоду. Однако нас, датчан, леденцы Ga-Jol привлекают еще и мудрыми или остроумными высказываниями, напечатанными на крышке каждой коробки. Сегодня утром я купил две коробки леденцов и обнаружил на них старую датскую поговорку:
Ærlighed i små ting er ikke nogen lille ting.
«Честность в мелочах — вовсе не мелочь». Это было хорошим предзнаменованием, которое полностью соответствовало тому, о чем я собирался написать в предисловии. Мелочи важны. Эта книга посвящена вещам простым, но вовсе не малозначительным.
Бог скрывается в мелочах, сказал архитектор Людвиг Мис ван дер Роэ. Эта цитата напоминает о недавних дебатах о роли архитектуры в разработке программного обеспечения и особенно в мире гибких методологий. Мы с Бобом время от времени увлеченно вступаем в этот диалог. Да, Мис ван дер Роэ проявлял внимание и к удобству, и к неподвластным времени строительным формам, лежащим в основе великой архитектуры. С другой стороны, он также лично выбирал каждую дверную ручку для каждого спроектированного им дома. Почему? Да потому, что мелочи важны.
В наших с Бобом непрестанных «дебатах» о TDD выяснилось, что мы согласны с тем, что архитектура играет важную роль при разработке, хотя мы по-разному смотрим на то, какой смысл вкладывается в это утверждение. Впрочем, эти разногласия относительно несущественны, так как мы считаем само собой разумеющимся, что ответственные профессионалы выделяют некоторое время на обдумывание и планирование проекта. Появившиеся в конце 1990-х концепции проектирования, зависящего только от тестов и кода, давно прошли. Тем не менее внимание к мелочам является еще более важным аспектом профессионализма, чем любые грандиозные планы. Во-первых, благодаря практике в мелочах профессионалы приобретают квалификацию и репутацию для серьезных проектов. Во-вторых, даже мельчайшее проявление небрежности при строительстве — дверь, которая неплотно закрывается, или криво положенная плитка на полу, или даже захламленный стол — полностью рассеивает очарование всего сооружения. Чтобы этого не происходило с вашими программами, код должен быть чистым.
Впрочем, архитектура — всего лишь одна из метафор для разработки программных продуктов. Она лучше всего подходит для проектов, в которых продукт «возводится» в том же смысле, в каком архитектор возводит строение. В эпоху Scrum и гибких методологий основное внимание уделяется быстрому выводу продукта на рынок. Фабрики, производящие программные продукты, должны работать на максимальной скорости. Однако этими «фабриками» являются живые люди: мыслящие, чувствующие программисты, работающие над пожеланиями пользователей или историей продукта для создания новых продуктов. Метафора производства сейчас как никогда сильна в их мировоззрениях. Скажем, методология Scrum во многом вдохновлена производственными аспектами японского автостроения с его конвейерами.
Но даже в автостроении основная часть работы связана не с производством, а с сопровождением продуктов — или его отсутствием. В программировании 80% и более того, что мы делаем, тоже изящно называется «сопровождением». На самом деле речь идет о починке. Наша работа ближе к работе домашних мастеров в строительной отрасли или автомехаников в области автостроения. Что японская теория управления говорит по этому поводу?
В 1951 году в японской промышленности появилась методология повышения качества, называвшаяся TPM (Total Productive Maintenance). Она была ориентирована прежде всего на сопровождение, а не на производство. Доктрина TPM базировалась на так называемых «принципах 5S». В сущности, принципы 5S представляют собой набор житейских правил. Кстати говоря, они также заложены в основу методологии Lean — другого модного течения на западной сцене, набирающего обороты и в программных кругах. Как указывает Дядюшка Боб в своем введении, хорошая практика программирования требует таких качеств, как сосредоточенность, присутствие духа и мышление. Проблемы не всегда решаются простым действием, максимальной загрузкой оборудования для производства в оптимальном темпе. Философия 5S состоит из следующих концепций:
• Сэйри, или организация. Абсолютно необходимо знать, где что находится — и в этом помогают такие методы, как грамотный выбор имен. Думаете, выбор имен идентификаторов неважен? Почитайте следующие главы.
• Сэйтон, или аккуратность. Старая американская поговорка гласит: всему свое место, и все оказывается на своих местах. Фрагмент кода должен находиться там, где читатель кода ожидает его найти, — а если он находится где-то в другом месте, переработайте свой код и разместите его там, где ему положено быть.
• Сэйсо, или чистка. Рабочее место должно быть свободно от висящих проводов, грязи, мусора и хлама. Что в этой книге говорят авторы о загромождении кода комментариями и закомментированными строками кода? Они советуют от них избавиться.
• Сэйкэцу, или стандартизация: группа достигает согласия по поводу того, как поддерживать чистоту на рабочем месте. Что в этой книге сказано о наличии единого стиля кодирования и набора правил в группах? Откуда берутся эти стандарты? Прочитайте — узнаете.
• Сюцукэ, или дисциплина. Программист должен быть достаточно дисциплинированным, чтобы следовать правилам, он должен часто размышлять о своей работе и быть готовым к изменениям.
Если вы не пожалеете усилий — да, усилий! — чтобы прочитать и применять эту книгу, вы научитесь понимать последний пункт. Мы наконец-то подошли к корням ответственного профессионализма в профессии, которая должна пристально интересоваться жизненным циклом продукта. В ходе сопровождения автомобилей и других машин по правилам TPM, аварийный ремонт (аналог проявления ошибок) является исключением. Вместо этого мы ежедневно осматриваем машины и заменяем изнашивающиеся части до того, как они сломаются, или выполняем аналоги знаменитой «смены масла каждые 10 000 миль» для предотвращения износа. Безжалостно перерабатывайте свой код. А еще можно сделать следующий шаг, который считался новаторским в движении TPM более 50 лет назад: строить машины, изначально ориентированные на удобство сопровождения. Ваш
Манифест Чистого Программиста или краткий конспект книги «Чистый Код» Роберта Мартина
Данная статья является конспектом книги «Чистый Код» Роберта Мартина и моим пониманием того, каким Чистый Код должен быть. Тут нет разделов о тестировании, TDD, о том какая должна быть архитектура и т.д. Здесь все только о том, каким должен быть Чистый Код.
Да, возможно, тема Чистого Кода уже заезженна, но тем не менее еще не все с ним знакомы и, тем более, я не встретил аналогов контента, который содержится в моей статье.
Общее
Нет истинного пути и решения. Есть тот, который лучше всего подходит для решения конкретной задачи.
При решении задачи попытайся воспроизвести абсолютно все кейсы, которые могут затрагивать эту задачу и реализуй задачу с учетом абсолютно всех кейсов.
Также при решении задачи попробуй пойти от обратного. Пойми какие результаты в итоге ты хочешь получить и составь на этом основании алгоритм, по которому будет выполняться задача.
Перед тем, как отправить задачу в релиз — проверь правильно ли она работает. Нет ли в ней ошибок. Это касается даже тех коммитов, которые отправляются в твою ветку. Самый идеальный сценарий — тот, в котором никто не смог найти ошибки в функционале, который ты разрабатывал.
Всегда задумывайся о том как можно сделать твой код проще, чище и читабельнее.
Чистый Код
Как писать чистый и хороший код? Это похоже на написание книги. Сначала ты делаешь черновик и потом причесываешь его до того состояния, в котором тебе было бы приятно его читать. Всегда помни, что твой код должен рассказывать историю происходящего, чтобы читатель мог ее понять.
Под сущностью понимается — интерфейс, класс, метод, переменная, объект и т.д.
Наименования и разделения
Функции
Комментарии
Форматирование и правила
Объекты и структуры данных
Классы
Обработка ошибок
Границы
Послесловие
В данной статье представлены лишь рекомендации к написанию Чистого Кода. Разумеется, ими можно пренебрегать. Вам лишь стоит понять, что у любого вашего решения должны быть аргументы в пользу него.
Рецензии на книгу « Чистый код. Создание, анализ и рефакторинг » Роберт Мартин
Книга обязательна к прочтению всем, кто так или иначе работает с кодом.
Качество печати отличное.
После первого прочтения книга не рассыпалась, а для мягкой обложки это уже очень хорошо. Лишь немного потрепалась обложка.
Отличная книга, которую в обязательном порядке стоит прочитать новичку в программировании, но и опытному программисту не стоит обходить ее стороной.
Название книги на сто процентов соответствует содержимому. В этой книге почти не будет рекомендаций и шаблонов по грамотному выстраиванию программных систем. Основное внимание здесь уделено именно вопросу написания грамотного, понятного, хорошо читаемого кода.
Материал представлен крайне доходчиво. Вообще дядюшка Боб обладает замечательной способностью доносить мысль крайне лаконично, предельно просто и прозрачно. За счет этого книга читается невероятно легко и быстро, как занимательный художественный роман.
Замечательная книга, от профессионального программиста для программистов, которые рассчитывают стать профессионалами.
SergioMyJava/Clean-Code_Robert_Martin
Use Git or checkout with SVN using the web URL.
Work fast with our official CLI. Learn more.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
Clean Code. Robert Martin
To write a clean code, you must consciously apply a variety of techniques, guided by a sense of «purity» acquired by hard work. A key role here is played by the “code sense”. Some are born with this feeling. Others work to develop it. This feeling not only makes it possible to distinguish good code from bad code, but also demonstrates the strategy of using our skills to transform bad code into clean code.
In short, a clean code programmer is an artist who navigates a blank screen through a series of transformations until he becomes an elegantly programmed system.
Meaningful Names
Watch the names in your programs and change them if you find more successful options. This will simplify the life of everyone who reads your code (including yourself).
Bad:
Good:
Programmers should avoid false associations that obscure the meaning of the code. Do not use words with hidden meanings other than intended.
If the names are different, then they must denote different concepts.
Names should be pronounced normally.
Single-letter names can ONLY be used for local variables in short methods.
We already have enough trouble with coding to look for new difficulties. Encoding information about the type or scope in names only creates new decryption efforts.
Do not force the reader to mentally convert your names to others already known to him.
The names of classes and objects must be nouns and their combinations.
Method names are verbs or verb phrases.
Names should be placed in a specific context for the reader of the code, enclosing them in classes, functions, and namespaces with well-chosen names. Bad:
Good:
Functions
The first rule: functions must be compact. The second rule: functions should be even more compact. HE FUNCTION MUST BE PERFORMED ONLY ONE OPERATION. SHE MUST BE FULFILLED BY IT. AND ANYTHING OTHER SHE MUST NOT DO.
To make sure that the function performs “only one operation,” you need to check that all the function commands are at the same level abstraction.
A long meaningful name is better than a short unintelligible.
In the ideal case, the number of function arguments is zero (a zero-ary function). The following are functions with one argument (unary) and two arguments (binary). Functions with three arguments (ternary) should be avoided whenever possible.
A function must do something or answer a question, but not at the same time.
For this reason, the bodies of try and catch blocks are recommended to be allocated to separate functions.
Good:
Comments
Nothing helps in the proper way to comment. Nothing clutters the module as empty and peremptory comments. Nothing does so much harm, like an old commentary that has lost relevance, spreading lies and misinformation.
The older the commentary, the farther it is from the code it describes, the greater the likelihood that it is simply incorrect.
Sometimes it is useful to leave notes “for the future” in the form of comments // TODO.
Headlines attract attention only if they are not found too often. Use them sparingly and only when they bring tangible benefits.
In programming, rarely habits are more disgusting than commenting off unused code. Never do it!
Do not present system-level information in the context of local commentary.
Formatting
Code formatting is aimed at information transfer, and information transfer is the primary task of a professional developer.
Almost all the code is read from left to right and from top to bottom. Each line represents an expression or condition, and each group of lines represents a complete thought.
Concepts that are closely related to each other should be vertically close to each other.
Variables should be declared as close as possible to the place of use. In some cases, a variable may be declared at the beginning of a block or immediately before a cycle in a long function.
Some code fragments require that they be placed close to other fragments. Such fragments have a certain conceptual relationship. The stronger the relationship, the less should be the vertical distance between them.
The called function must be located below the calling function.
The source file has a hierarchical structure. File-level commands (such as most class declarations) do not indent. Methods in classes are shifted one level to the right of the class level. Implementations of these methods are shifted one level to the right of the class declaration. Block implementations are shifted one level to the right of their outer blocks, and so on.
Bad
Good:
The code of the software product must be issued in the same style.It should not look like it was written by several personalities who disagree about the design. In no case do not complicate the source code, allowing its design in several different styles.
Objects and Data Structures
To find the best way to present the data contained in an object, you need to seriously consider. Thoughtless addition of reading and writing methods is the worst possible option.
Objects hide their data behind abstractions and provide functions that work with this data. Data structures disclose their data and have no meaningful functions.
Procedural code (code using data structures) makes it easy to add new functions without changing existing data structures. Object-oriented code, on the other hand, makes it easy to add new classes without changing existing functions.
Class C method f should be limited to calling methods of the following objects:
objects created by f;
objects passed to f as argument;
objects stored in instance variable C.
Objects provide behavior and hide data. This allows the programmer to easily add new kinds of objects without changing the existing behavior. On the other hand, objects make it difficult to add new behavior to existing objects. Data structures provide data, but do not have any significant behavior. They simplify the addition of new behavior to existing data structures, but make it difficult to add new data structures to existing functions.
Error Handling
Writing code that can trigger exceptions is recommended to start with try-catch-finally.
Use unverifiable exceptions.There are no checked exceptions in C #, and despite all the gallant attempts, they never appeared in C ++. They are also not in Python and Ruby.However, reliable programs can be written in all these languages. The price of checked exceptions is a violation of the principle of openness / closeness.
Each exception that is raised in a program must contain enough contextual information to determine the source and location of the error.
By returning null, we are actually creating extra work for ourselves, and unnecessary problems for the caller. It is worth skipping just one null check, and the application “goes into a corkscrew”.
If you want to return null from a method, consider issuing an exception or returning an “special case” object.
Returning null from methods is bad, but it is even worse to pass null when called.
In most programming languages, there is no good way to handle the random transfer of null from the caller. And if so, it is reasonable to prohibit the transmission of null by default.
Boundaries
We recommend limiting the transmission of the Map (or any other boundary interface) on the system. If you use a interface like Map, keep it inside a class (or a closely related family of classes) in which it is used.
To ensure that borders with third-party code do not create problems in our projects, we minimize the number of calls to them. To do this, you can use wrappers, as in the Map example, or implement the ADAPTER pattern to match our ideal interface with the real one received from the developers.
Unit Tests
The first law. Do not write the product code until you write a failing unit test. The second law. Do not write a unit test in a volume larger than necessary for failure. The impossibility of compiling is a failure. The third law. Do not write the product code in the amount larger than necessary to pass the current failing test.
Tests «in haste» are equivalent to the complete absence of tests, if not worse. The fact is that tests should change as the product code develops. The more primitive the tests, the harder it is to change them. If the test code is heavily entangled, it may be that writing a new product code will take less time than trying to cram new tests into an updated package.
The test code is as important as the product code.
If you do not maintain the purity of your tests, then you lose them. And without tests, all that provides the flexibility of the product code is lost.
Readability in unit tests is even more important than in the product code.
The number of assert directives in the test should be minimized.
Five characteristics for good tests:
Tests must be performed quickly.
Tests should not depend on each other.
Tests should give repeatable results in any environment.
The result of the test should be a logical sign. The test either passed or did not pass.
Tests should be created in a timely manner.
For the «health» of the project tests are no less important than the product code. Or maybe they are even more important because the tests retain and improve the flexibility, maintainability and reusability of the product code.
Classes
The list of variables is usually followed by open functions.
Classes should be compact.
If the class fails to pick a clear one, the short name is probably too large.
Try to separate the variables and methods into two or more classes so that the new classes have higher connectivity.
Systems
The concept of sharing responsibility is one of the oldest and most important techniques.
In software systems, the initialization phase, in which the application objects are constructed and the main dependencies “stick together”, must also be separated from the runtime logic, which receives control after its completion.
This is the most important difference between software systems and physical ones. The architecture of software systems can be developed consistently, if we ensure the correct division of responsibility.
Finally, the most comprehensive tool for separating areas of responsibility through the use of aspects is AspectJ1, a Java extension that provides “full-fledged” support for aspects like modular designs. There are enough pure Java solutions based on Spring and JBoss for 80–90% of situations in which aspects are applied.
If you can write the domain logic of your application in the form of POJO-objects separated from any architectural areas of responsibility at the code level, then you will have the opportunity to conduct full-fledged tests of your architecture.
The optimal system architecture consists of modular areas of responsibility, each of which is implemented on the basis of POJO objects. Areas are integrated with each other through aspects or similar means that minimally interfere with their work. Such architecture can be built on the basis of development methodology through testing, as well as program code.
As you know, it is best to entrust responsible decisions to the most qualified. However, we often forget that decision-making is best postponed until the last moment (at the moment when all the information is known, or almost all of the problems that may arise on the project).
The flexibility of a POJO system with modular areas of responsibility allows you to make optimal, timely decisions based on the latest information. In addition, it helps reduce the complexity of such solutions.
Standards simplify the reuse of ideas and components, attracting people with the necessary experience, translating successful ideas and linking components. However, the process of creating a standard sometimes takes too much time (and the industry does not stand still), with the result that standards lose touch with the real needs of the people they should serve.
Subject-oriented languages allow you to express in the form of POJO-objects all levels of abstraction and all application domains, from high-level policies to low-level technical details.
Clean should be not only the code, but also the system architecture.
Regardless of whether you are designing a whole system or its individual modules, remember: use the simplest solution possible.
Emergence
According to Kent, an architecture can be considered “simple” if it:
ensures that all tests pass (The system, thoroughly tested and passed all tests, is controlled.)
does not contain duplicate code
expresses the intentions of the programmer,
uses the minimum number of classes and methods. The rules are listed in order of importance.
Our goal is to make the system compact, but at the same time preserve the compactness of functions and classes. However, it should be remembered that of the four simple architecture rules, this rule has the lowest priority. Minimizing the number of functions and classes is important, but passing tests, eliminating duplicates and expressive code is still more important.
Concurrency
A multitude of common myths and misconceptions are associated with multithreading:
Multithreading always improves performance. Multithreading improves performance, but only with a relatively large wait time, which could be effectively used by other threads or processors.
Writing a multi-threaded code does not change the architecture of the program. The architecture of a multithreaded algorithm may differ significantly from the architecture of a single-threaded system. Separating the “what” from the “when” usually has a huge impact on the structure of the system.
When working with a container (for example, a web container or an EJB container) it is not necessary to understand the problems of multi-threaded programming. It is advisable to know how the container works and how to protect against problems of simultaneous updating and deadlocks.
Some more objective statements related to writing multi-threaded code:
Proper implementation of multithreading is difficult even for simple tasks.
Errors in multi-threaded code are usually not reproduced, therefore they are often ignored as random deviations1 (and not as systematic defects that they really are).
Multithreading often requires fundamental changes in the design strategy.
Separate code related to multithreading implementation from the rest of the code.Corollary: limit the area data visibility.
Be serious about data encapsulation; severely restrict access to all shared data.
Streams should be as independent as possible.
Logical partitioning patterns of program behavior.
Сonsumer model makers. One or more producer threads create jobs and put them in a buffer or queue. One or more consumer threads retrieve jobs from the queue and execute them
Model «readers-writers» The designer must find a balance between the needs of readers and writers to ensure the correct mode of operation, normal system performance and avoid lag.
Model «dining philosophers problem» Applications compete for resources from a limited set. If you carelessly design such a system, then the competition between threads can lead to interlocks, reversible locks, and a drop in productivity and work efficiency.
Beware of dependencies between synchronized methods. If the generic class contains more than one synchronized method, your system may not be designed correctly.
Synchronized sections must have a minimum size. The code should contain as few synchronized sections as possible.
Testing does not guarantee the correct operation of the code. However, quality testing minimizes risk.
Treat non-periodic failures as signs of potential multithreading problems.
Start by debugging non-threaded core code.
Implement your multithreaded code so that it can be executed in various configurations.
Provide logical isolation for multi-threaded code configurations.
Test the program with the number of threads in excess of the number of processors.
Test the program on different platforms.
Smells and Heuristics
It is inappropriate to post information in comments that is more convenient to store in other sources: in source control systems, in version control systems and in other logging systems.
A comment whose contents have lost relevance is considered obsolete.
Excess is considered to be a comment describing something that is already obvious.
Choose your words carefully. Keep track of spelling and punctuation. Do not write messy. Do not explain the obvious. Be concise.
After seeing the commented out code, delete it! Do not worry, the source control system will not forget it.
Building a project should be one trivial operation. Without sampling numerous fragments from source control. Without a long series of unintelligible commands or context-sensitive scripts to build individual elements. Without searching for additional files in the format of JAR, XML and other artifacts necessary for your system.
All unit tests should be performed with just one command. worst case one simple command is entered on the command line.
Functions should have a small number of arguments. Best of all, when there are no arguments at all; functions with one, two, and three arguments follow.
Output arguments are unnatural.
Eliminate logical arguments from functions.
If the method is never called in the program, then it should be deleted.
Ideally, the source file should contain code in the same language.at the very least, both the amount and amount of code in additional languages in the source files should be minimized.
Any function or class must implement the behavior that the programmer can expect from them.
Disabling security is risky.
All low-level concepts should be concentrated in derived classes, and all high-level concepts are combined in the base class.
In general, base classes should not know anything about their derived classes.
Placing the derived and base classes in different jar files, in which the base jar files do not know anything about the contents of the derived jar files, allows you to organize the deployment of systems in the format of discrete, independent components.
Good developers know how to limit the interfaces of their classes and modules. The less methods a class contains, the better. The fewer variables a function is known, the better. The fewer instance variables the class contains, the better.
In general, give preference to non-static methods over static ones.
If one module depends on another, the dependence must be not only logical, but also physical.
Before using switch, consider using polymorphism.
All function commands must be formulated at the same level of abstraction, which is located one level below the operation described by the function name.
If A interacts with B, and B interacts with C, then modules using A should not be aware of C.
If you use two or more classes from a package, import the entire package.
For each type of choice, the program must not contain more than one switch command. Multiple switch constructions should be replaced with polymorphic objects.
Functions must perform one operation.
The time reference is implemented by creating a “relay race”.
Encapsulate boundary conditions
Make sure the names are meaningful.
Names must reflect the level of abstraction at which the class or function operates.
Names are easier to understand if they are based on existing conventions or standard notation.
The length of the name must match the length of its scope.
Names should describe everything that a function, variable, or class does.
The test package should test everything that might break.
Mistakes are often collected in groups.
Do everything you need to make your tests run fast.
Чистый код. Создание, анализ и рефакторинг
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.
Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги – концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
Примечание верстальщика: книга содержит большой объем исходников (code), так что не рекомендуется применять скрипты «Генеральная уборка», «Обработка кавычек» и т. д.
«В 1951 году в японской промышленности появилась методология повышения качества, называвшаяся TPM (Total Productive Maintenance). Она была ориентирована прежде всего на сопровождение, а не на производство. Доктрина TPM базировалась на так называемых «принципах 5S». В сущности, принципы 5S представляют собой набор житейских правил. Кстати говоря, они также заложены в основу методологии Lean — другого модного течения на западной сцене, набирающего обороты и в программных кругах. Как указывает Дядюшка Боб в своем введении, хорошая практика программирования требует таких качеств, как сосредоточенность, присутствие духа и мышление. Проблемы не всегда решаются простым действием, максимальной загрузкой оборудования для производства в оптимальном темпе. Философия 5S состоит из следующих концепций:»
Чистый код. Создание, анализ и рефакторинг
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.
Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги – концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода. Примечание верстальщика: книга содержит большой объем исходников (code), так что не рекомендуется применять скрипты «Генеральная уборка», «Обработка кавычек» и т. д.
О книге Боба Мартина «Чистый код»
(Картинка без намека, просто уж очень хотелось котика в статью добавить! Ведь это основной залог популярности в интернетах, правда? :))
У меня очень неоднозначное отношение к книгам Роберта Мартина… В них довольно много здравых и интересных мыслей, но иногда они выражаются столь категорично, что неокрепшим программерским мозгом они могут восприниматься неправильно. Если же мозг читателя достаточно окреп, чтобы воспринимать советы прагматично, то есть все шансы, что ничего нового из этих советов он (мозг или программист) не вынесет.
Вот и получается, что идеальной аудиторией для этих книг является продвинутый разработчик, окрепший достаточно, чтобы критически оценивать советы «гуру», но при этом не настолько матерый, чтобы эти советы не звучали из разряда «Спасибо, Кэп!».
Хотя, нужно признать, что если в книге «Принципы, паттерны и методики гибкой разработки» спорных советов с моей точки зрения было очень много, то в «Чистом коде» приводится значительно больше разумных и прагматичных советов.
Но поскольку паранойи в книге тоже достаточно, поэтому я хочу начать именно с неоднозначных моментов, а уже потом перейти к радостям.
Спорные и сомнительные моменты
В «Чистом коде» есть несколько откровенно сомнительных моментов. Во-первых, в ней довольно много кода, читать который на страницах книги очень сложно. В 15-й главе рассматривается улучшение парсера командной строки на 60 страницах, 40 из которых – это сплошной код на Java. Главы 16-17 написаны в том же формате, но они короче, поэтому следовать рассуждениям автора проще.
СОМНИТЕЛЬНЫЙ СОВЕТ
Первое правило: функции должны быть компактными. Второе правило: функции должны быть еще компактнее. … Из сказанного выше следует, что блоки в командах if, else, while и т.д. должны состоять из одной строки, в которой обычно содержится вызов функции. Это не только делает вмещающую функцию более компактной, но и способствует документированию кода, поскольку вызываемой в блоке функции можно присвоить удобное содержательное имя.
Некоторые главы откровенно слабые. Мне вообще не понятна цель главы 13 о параллелизме, в которой даются лишь общие сведения о проблемах многопоточности, а затем в приложении А разбираются те же самые темы, но уже более детально и с необходимыми примерами.
Но больше всего меня смущает неоднозначное отношение автора к состоянию и побочным эффектам.
Побочные эффекты суть ложь. Ваша функция обещает делать что-то одно, но делает что-то другое, скрытое от пользователя. Иногда она вносит неожиданные изменения в переменные своего класса – скажем, присваивает им значения параметров, переданных функции…
Несмотря на этот совет, автор во многих примерах использует код с побочными эффектами и отговаривает всеми силами использовать аргументы, используя вместо этого состояние объекта:
СОМНИТЕЛЬНЫЙ СОВЕТ
… Аргументы создают массу проблем с точки зрения тестирования. Только представьте, как трудно составить все тестовые сценарии, проверяющие правильность работы кода со всеми комбинациями аргументов.
В чем разница с точки зрения тестирования между статическим методом с четырьмя аргументами и экземплярного метода объекта с четырьмя полями? Количество граничных условий в обоих случаях одно и тоже; просто в первом случае мы все входные данные протаскиваем явно, а во втором случае – неявно через this.
Стилю кодирования в книге уделено много внимания, при этом большинство советов вполне разумными. Но встречаются и очень неоднозначные:
СОМНИТЕЛЬНЫЙ СОВЕТ
Стандарт кодирования определяет, где объявляются переменные экземпляров; как именуются классы, методы и переменные; как располагаются фигурные скобки и т.д. Документ с явных описанием этих правил не нужен – сам код служит примером оформления.
Перевод
Перевод, мягко говоря, не порадовал. Иногда он «радовал» настолько, что приходилось лезть в оригинал, чтобы понять, о чем идет речь:
ЦИТАТА
Когда у вас появился полный набор тестов, можно заняться чисткой кода и классов.
Для этого код подвергается последовательной переработке (рефакторингу). Мы добавляем несколько строк кода, делаем паузу и анализируем новую архитектуру.
WTF! Как добавление двух строк может повлиять на архитектуру. Есть два варианта: либо мы имеем дело с очень длинными строками, или же авторы здесь говорят не об архитектуре, а о чем-то ином, например, о дизайне! Вся глава 12 (из которой взята эта цитата) полностью испорчена тем, что термин “design” переведен в ней как «архитектура», что делает многие советы автора спорными.
Как обычно, переводчики не потрудились оставить оригинальные термины, так что приходилось догадываться, что же имеется ввиду под терминами «логическая привязка» или «многопоточность» (оказывается, что это high coupling и concurrency, соответственно).
Поскольку содержимое книги относительно простое, то переводчикам удалось лишь «подпортить» впечатление, но не запороть ее полностью.
Дельные советы
На самом деле, все не настолько плохо и «дядюшка» Боб сотоварищи дают много хороших советов. Вот некоторые из них:
Об именовании
Не используйте имена, передающие информацию о реализации. Имена должны отражать уровень абстракции, на котором работает класс или функция.
О понятности кода
Легко писать код, понятный для нас самих, потому что в момент его написания мы глубоко понимаем решаемую проблему. У других программистов, которые будут заниматься сопровождением этого кода, такого понимания не будет.
О длине и выразительности имен
Длина имени должна быть связана с длиной его области видимости. Переменным с крошечной областью видимости можно присваивать очень короткие имена, но у переменных с большей областью видимости имена должны быть длинными. … Таки образом, чем длиннее область видимости, тем более длинным и точным должно быть ее имя.
О содержимом функций
Все операторы в функции должны находиться на одном уровне абстракции, который должен быть на один уровень ниже операции, описываемой именем функции.
Совет кажется простым, но он очень ценен. Код должен читаться, как хорошая проза, а для этого просто необходимо, чтобы функция содержала операторы одного уровня.
Юнит-тесты в качестве инструмента изучения библиотек
Изучение чужого кода – непростая задача. Интеграция чужого кода тоже сложна. Одновременное решение обоих задач создает двойственные сложности. А что, если пойти по другому пути? Вместо того, чтобы экспериментировать и опробовать новую библиотеку в коде продукта, можно написать тесты. Проверяющие наше понимание стороннего кода. Джим Ньюкирк (JimNewkirk) называет такие тесты «учебными тестами».
Этому совету я следую давно и использую юнит-тесты для изучения новых инструментов и библиотек. Это позволяет лучше разобраться с библиотекой и легко возвращаться к примерам использования, поскольку они всегда под рукой.
Очень повеселил один совет. Давайте так: что вам говорит магическая константа 5280? Ничего? Странно, по словам автора, это одно из значений, которое можно спокойно «хардкодить»!
Некоторые числа так легко узнаются, что их не обязательно скрывать за именованными константами – при условии, что они используются в сочетании с ясным кодом. … Число 5280 – количество футов в миле – настолько хорошо известно и уникально, что читатель сразу узнает его, даже если оно будет располагаться вне какого-либо контекста.
Качество книги можно косвенно оценить по количеству интересных цитат и количеству блог-постов, появившихся в процессе чтения. И если в процессе чтения «Принципов, паттернов и методик» появились критические статьи типа «Контракты, состояние и юнит-тесты», то в результате «Чистого кода» появились «Пять принципов чистых тестов» и «Лучшая метрика для определения качества кода».
Достоинства: приличное количество приличных советов
Недостатки: часть советов весьма спорны; иногда советы непоследовательны; перевод хромает на обе ноги.
Clean Code, Robert Martin, 2009
Clean Code, Robert Martin, 2009.
The mission of this series is to improve the state of the art of software craftsmanship. The books in this series are technical, pragmatic, and substantial. The authors are highly experienced craftsmen and professionals dedicated to writing about what actually works in practice, as opposed to what might work in theory. You will read about what the author has done, not what he thinks you should do. If the book is about programming, there will be lots of code. If the book is about managing, there will be lots of case studies from real projects.
There Will Be Code.
One might argue that a book about code is somehow behind the times—that code is no longer the issue; that we should be concerned about models and requirements instead. Indeed some have suggested that we are close to the end of code. That soon all code will be generated instead of written. That programmers simply won’t be needed because business people will generate programs from specifications.
Nonsense! We will never be rid of code, because code represents the details of the requirements. At some level those details cannot be ignored or abstracted; they have to be specified. And specifying requirements in such detail that a machine can execute them is programming. Such a specification is code.
I expect that the level of abstraction of our languages w ill continue to increase. I also expect that the number of domain-specific languages will continue to grow. This will be a good thing. But it will not eliminate code. Indeed, all the specifications written in these higher level and domain-specific language will be code! It will still need to be rigorous, accurate, and so formal and detailed that a machine can understand and execute it.
CONTENTS.
Foreword.
Introduction.
On the Cover.
Chapter 1: Clean Code.
There Will Be Code.
Bad Code.
The Total Cost of Owning a Mess.
The Grand Redesign in the Sky.
Attitude.
The Primal Conundrum.
The Art of Clean Code?.
What Is Clean Code?.
Schools of Thought.
We Are Authors.
The Boy Scout Rule.
Prequel and Principles.
Conclusion.
Bibliography.
Chapter 2: Meaningful Names.
Introduction.
Use Intention-Revealing Names.
Avoid Disinformation.
Make Meaningful Distinctions.
Use Pronounceable Names.
Use Searchable Names.
Avoid Encodings.
Hungarian Notation.
Member Prefixes.
Interfaces and Implementations.
Avoid Mental Mapping.
Class Names.
Method Names.
Don’t Be Cute.
Pick One Word per Concept.
Don’t Pun.
Use Solution Domain Names.
Use Problem Domain Names.
Add Meaningful Context.
Don’t Add Gratuitous Context.
Final Words.
Chapter 3: Functions.
Small!.
Blocks and Indenting.
Do One Thing.
Sections within Functions.
One Level of Abstraction per Function.
Reading Code from Top to Bottom: The Stepdown Rule.
Switch Statements.
Use Descriptive Names.
Function Arguments.
Common Monadic Forms.
Flag Arguments.
Dyadic Functions.
Triads.
Argument Objects.
Argument Lists.
Verbs and Keywords.
Have No Side Effects.
Output Arguments.
Command Query Separation.
Prefer Exceptions to Returning Error Codes.
Extract Try/Catch Blocks.
Error Handling Is One Thing.
The Error.java Dependency Magnet.
Don’t Repeat Yourself.
Structured Programming.
How Do You Write Functions Like This?.
Conclusion.
SetupTeardownIncluder.
Bibliography.
Chapter 4: Comments.
Comments Do Not Make Up for Bad Code.
Explain Yourself in Code.
Good Comments.
Legal Comments.
Informative Comments.
Explanation of Intent.
Clarification.
Warning of Consequences.
TODO Comments.
Amplification.
Javadocs in Public APIs.
Bad Comments.
Mumbling.
Redundant Comments.
Misleading Comments.
Mandated Comments.
Journal Comments.
Noise Comments.
Scary Noise.
Don’t Use a Comment When You Can Use a Function or a Variable.
Position Markers.
Closing Brace Comments.
Attributions and Bylines.
Commented-Out Code.
HTML Comments.
Nonlocal Information.
Too Much Information.
Inobvious Connection.
Function Headers.
Javadocs in Nonpublic Code.
Example.
Bibliography.
Chapter 5: Formatting.
The Purpose of Formatting.
Vertical Formatting.
The Newspaper Metaphor.
Vertical Openness Between Concepts.
Vertical Density.
Vertical Distance.
Vertical Ordering.
Horizontal Formatting.
Horizontal Openness and Density.
Horizontal Alignment.
Indentation.
Dummy Scopes.
Team Rules.
Uncle Bob’s Formatting Rules.
Chapter 6: Objects and Data Structures.
Data Abstraction.
Data/Object Anti-Symmetry.
The Law of Demeter.
Train Wrecks.
Hybrids.
Hiding Structure.
Data Transfer Objects.
Active Record.
Conclusion.
Bibliography.
No Preemption.
Circular Wait.
Breaking Mutual Exclusion.
Breaking Lock & Wait.
Breaking Preemption.
Breaking Circular Wait.
Testing Multithreaded Code.
Tool Support for Testing Thread-Based Code.
Conclusion.
Tutorial: Full Code Examples.
Client/Server Nonthreaded.
Client/Server Using Threads.
Appendix B: org.jfree.date.SerialDate.
Appendix C: Cross References of Heuristics.
Epilogue.
Index.
Скачать pdf
Ниже можно купить эту книгу по лучшей цене со скидкой с доставкой по всей России. Купить эту книгу
Чистый код: создание, анализ и рефакторинг (pdf+epub)
Посоветуйте книгу друзьям! Друзьям – скидка 10%, вам – рубли
Эта и ещё 2 книги за 399 ₽
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.
Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги – концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
Роберт Мартин: Чистый код. Создание, анализ и рефакторинг
Здесь есть возможность читать онлайн «Роберт Мартин: Чистый код. Создание, анализ и рефакторинг» весь текст электронной книги совершенно бесплатно (целиком полную версию). В некоторых случаях присутствует краткое содержание. Город: СПб., год выпуска: 2019, ISBN: 978-5-4461-0960-9, издательство: Питер, категория: Программирование / на русском языке. Описание произведения, (предисловие) а так же отзывы посетителей доступны на портале. Библиотека «Либ Кат» — LibCat.ru создана для любителей полистать хорошую книжку и предлагает широкий выбор жанров:
Выбрав категорию по душе Вы сможете найти действительно стоящие книги и насладиться погружением в мир воображения, прочувствовать переживания героев или узнать для себя что-то новое, совершить внутреннее открытие. Подробная информация для ознакомления по текущему запросу представлена ниже:
Чистый код. Создание, анализ и рефакторинг: краткое содержание, описание и аннотация
Предлагаем к чтению аннотацию, описание, краткое содержание или предисловие (зависит от того, что написал сам автор книги «Чистый код. Создание, анализ и рефакторинг»). Если вы не нашли необходимую информацию о книге — напишите в комментариях, мы постараемся отыскать её.
Роберт Мартин: другие книги автора
Кто написал Чистый код. Создание, анализ и рефакторинг? Узнайте фамилию, как зовут автора книги и список всех его произведений по сериям.
Возможность размещать книги на на нашем сайте есть у любого зарегистрированного пользователя. Если Ваша книга была опубликована без Вашего на то согласия, пожалуйста, направьте Вашу жалобу на info@libcat.ru или заполните форму обратной связи.
В течение 24 часов мы закроем доступ к нелегально размещенному контенту.
Чистый код. Создание, анализ и рефакторинг — читать онлайн бесплатно полную книгу (весь текст) целиком
Ниже представлен текст книги, разбитый по страницам. Система сохранения места последней прочитанной страницы, позволяет с удобством читать онлайн бесплатно книгу «Чистый код. Создание, анализ и рефакторинг», без необходимости каждый раз заново искать на чём Вы остановились. Поставьте закладку, и сможете в любой момент перейти на страницу, на которой закончили чтение.
Создание, анализ и рефакторинг
© Prentice Hall, Inc.
© Перевод на русский язык ООО Издательство «Питер», 2018
© Издание на русском языке, оформление ООО Издательство «Питер», 2019
Посвящается Анне-Марии — бессмертной любви всей моей жизни
В Дании очень популярны леденцы Ga-Jol. Их сильный лакричный вкус отлично скрашивает нашу сырую и часто холодную погоду. Однако нас, датчан, леденцы Ga-Jol привлекают еще и мудрыми или остроумными высказываниями, напечатанными на крышке каждой коробки. Сегодня утром я купил две коробки леденцов и обнаружил на них старую датскую поговорку:
Ærlighed i små ting er ikke nogen lille ting.
«Честность в мелочах — вовсе не мелочь». Это было хорошим предзнаменованием, которое полностью соответствовало тому, о чем я собирался написать в предисловии. Мелочи важны. Эта книга посвящена вещам простым, но вовсе не малозначительным.
Бог скрывается в мелочах, сказал архитектор Людвиг Мис ван дер Роэ. Эта цитата напоминает о недавних дебатах о роли архитектуры в разработке программного обеспечения и особенно в мире гибких методологий. Мы с Бобом время от времени увлеченно вступаем в этот диалог. Да, Мис ван дер Роэ проявлял внимание и к удобству, и к неподвластным времени строительным формам, лежащим в основе великой архитектуры. С другой стороны, он также лично выбирал каждую дверную ручку для каждого спроектированного им дома. Почему? Да потому, что мелочи важны.
В наших с Бобом непрестанных «дебатах» о TDD выяснилось, что мы согласны с тем, что архитектура играет важную роль при разработке, хотя мы по-разному смотрим на то, какой смысл вкладывается в это утверждение. Впрочем, эти разногласия относительно несущественны, так как мы считаем само собой разумеющимся, что ответственные профессионалы выделяют некоторое время на обдумывание и планирование проекта. Появившиеся в конце 1990-х концепции проектирования, зависящего только от тестов и кода, давно прошли. Тем не менее внимание к мелочам является еще более важным аспектом профессионализма, чем любые грандиозные планы. Во-первых, благодаря практике в мелочах профессионалы приобретают квалификацию и репутацию для серьезных проектов. Во-вторых, даже мельчайшее проявление небрежности при строительстве — дверь, которая неплотно закрывается, или криво положенная плитка на полу, или даже захламленный стол — полностью рассеивает очарование всего сооружения. Чтобы этого не происходило с вашими программами, код должен быть чистым.
Впрочем, архитектура — всего лишь одна из метафор для разработки программных продуктов. Она лучше всего подходит для проектов, в которых продукт «возводится» в том же смысле, в каком архитектор возводит строение. В эпоху Scrum и гибких методологий основное внимание уделяется быстрому выводу продукта на рынок. Фабрики, производящие программные продукты, должны работать на максимальной скорости. Однако этими «фабриками» являются живые люди: мыслящие, чувствующие программисты, работающие над пожеланиями пользователей или историей продукта для создания новых продуктов. Метафора производства сейчас как никогда сильна в их мировоззрениях. Скажем, методология Scrum во многом вдохновлена производственными аспектами японского автостроения с его конвейерами.
Но даже в автостроении основная часть работы связана не с производством, а с сопровождением продуктов — или его отсутствием. В программировании 80% и более того, что мы делаем, тоже изящно называется «сопровождением». На самом деле речь идет о починке. Наша работа ближе к работе домашних мастеров в строительной отрасли или автомехаников в области автостроения. Что японская теория управления говорит по этому поводу?
В 1951 году в японской промышленности появилась методология повышения качества, называвшаяся TPM (Total Productive Maintenance). Она была ориентирована прежде всего на сопровождение, а не на производство. Доктрина TPM базировалась на так называемых «принципах 5S». В сущности, принципы 5S представляют собой набор житейских правил. Кстати говоря, они также заложены в основу методологии Lean — другого модного течения на западной сцене, набирающего обороты и в программных кругах. Как указывает Дядюшка Боб в своем введении, хорошая практика программирования требует таких качеств, как сосредоточенность, присутствие духа и мышление. Проблемы не всегда решаются простым действием, максимальной загрузкой оборудования для производства в оптимальном темпе. Философия 5S состоит из следующих концепций:
Вероятно, хватит рекомендовать «Чистый код»
Возможно, мы никогда не сможем прийти к эмпирическому определению «хорошего кода» или «чистого кода». Это означает, что мнение одного человека о мнении другого человека о «чистом коде» обязательно очень субъективно. Я не могу рассматривать книгу Роберта Мартина «Чистый код» 2008 года с чужой точки зрения, только со своей.
Тем не менее, для меня главная проблема этой книги заключается в том, что многие примеры кода в ней просто ужасны.
В третьей главе «Функции» Мартин даёт различные советы для написания хороших функций. Вероятно, самый сильный совет в этой главе состоит в том, что функции не должны смешивать уровни абстракции; они не должны выполнять задачи как высокого, так и низкого уровня, потому что это сбивает с толку и запутывает ответственность функции. В этой главе есть и другие важные вещи: Мартин говорит, что имена функций должны быть описательными и последовательными, и должны быть глагольными фразами, и должны быть тщательно выбраны. Он говорит, что функции должны делать только одно, и делать это хорошо. Он говорит, что функции не должны иметь побочных эффектов (и он приводит действительно отличный пример), и что следует избегать выходных аргументов в пользу возвращаемых значений. Он говорит, что функции обычно должны быть либо командами, которые что-то делают, либо запросами, которые на что-то отвечают, но не обоими сразу. Он объясняет DRY. Это всё хорошие советы, хотя немного поверхностные и начального уровня.
Но в этой главе есть и более сомнительные утверждения. Мартин говорит, что аргументы логического флага — плохая практика, с чем я согласен, потому что неприкрашенные true или false в исходном коде непрозрачны и неясны по сравнению с явными IS_SUITE или IS_NOT_SUITE … но рассуждения Мартина скорее сводятся к тому, что логический аргумент означает, что функция делает больше, чем одну вещь, чего она не должна делать.
Мартин говорит, что должно быть возможно читать один исходный файл сверху вниз как повествование, причем уровень абстракции в каждой функции снижается по мере чтения, а каждая функция обращается к другим дальше вниз. Это далеко не универсально. Многие исходные файлы, я бы даже сказал, большинство исходных файлов, нельзя аккуратно иерархизировать таким образом. И даже для тех, которые можно, IDE позволяет нам тривиально прыгать от вызова функции к реализации функции и обратно, точно так же, как мы просматриваем веб-сайты. Кроме того, разве мы по-прежнему читаем код сверху вниз? Ну, может быть, некоторые из нас так и делают.
А потом это становится странным. Мартин говорит, что функции не должны быть достаточно большими, чтобы содержать вложенные структуры (условные обозначения и циклы); они не должны иметь отступов более чем на два уровня. Он говорит, что блоки должны быть длиной в одну строку, состоящие, вероятно, из одного вызова функции. Он говорит, что идеальная функция не имеет аргументов (но всё равно никаких побочных эффектов??), и что функция с тремя аргументами запутанна и трудна для тестирования. Самое странное, что Мартин утверждает, что идеальная функция — это две-четыре строки кода. Этот совет фактически помещен в начале главы. Это первое и самое важное правило:
Первое правило: функции должны быть компактными. Второе правило: функции должны быть ещё компактнее. Я не могу научно обосновать своё утверждение. Не ждите от меня ссылок на исследования, доказывающие, что очень маленькие функции лучше больших. Я могу всего лишь сказать, что я почти четыре десятилетия писал функции всевозможных размеров. Мне доводилось создавать кошмарных монстров в 3000 строк. Я написал бесчисленное множество функций длиной от 100 до 300 строк. И я писал функции от 20 до 30 строк. Мой практический опыт научил меня (ценой многих проб и ошибок), что функции должны быть очень маленькими.
Когда Кент показал мне код, меня поразило, насколько компактными были все функции. Многие из моих функций в программах Swing растягивались по вертикали чуть ли не на километры. Однако каждая функция в программе Кента занимала всего две, три или четыре строки. Все функции были предельно очевидными. Каждая функция излагала свою историю, и каждая история естественным образом подводила вас к началу следующей истории. Вот какими короткими должны быть функции!
Весь этот совет завершается листингом исходного кода в конце главы 3. Этот пример кода является предпочтительным рефакторингом Мартина класса Java, происходящего из опенсорсного инструмента тестирования FitNesse.
Повторю ещё раз: это собственный код Мартина, написанный по его личным стандартам. Это идеал, представленный нам в качестве учебного примера.
На этом этапе я признаюсь, что мои навыки Java устарели и заржавели, почти так же устарели и заржавели, как эта книга, которая вышла в 2008 году. Но ведь даже в 2008 году этот код был неразборчивым мусором?
Давайте проигнорируем import с подстановочными знаками.
Но это неправильное предположение! Вот собственное определение Мартина из более ранней части этой главы:
Побочные эффекты суть ложь. Ваша функция обещает делать что-то одно, но делает что-то другое, скрытое от пользователя. Иногда она вносит неожиданные изменения в переменные своего класса — скажем, присваивает им значения параметров, переданных функции, или глобальных переменных системы. В любом случае такая функция является коварной и вредоносной ложью, которая часто приводит к созданию противоестественных временных привязок и других зависимостей.
Мне нравится это определение! Я согласен с этим определением! Это очень полезное определение! Я согласен, что плохо для функции вносить неожиданные изменения в переменные своего собственного класса.
Так почему же собственный код Мартина, «чистый» код, не делает ничего, кроме этого? Невероятно трудно понять, что делает любой из этих кодов, потому что все эти невероятно крошечные методы почти ничего не делают и работают исключительно через побочные эффекты. Давайте просто рассмотрим один приватный метод.
Мартин утверждает в этой самой главе, что имеет смысл разбить функцию на более мелкие функции, «если вы можете извлечь из неё другую функцию с именем, которое не является просто повторением её реализации». Но потом он даёт нам:
Примечание: некоторые плохие аспекты этого кода не являются виной Мартина. Это рефакторинг уже существующего фрагмента кода, который, по-видимому, изначально не был написан им. Этот код уже имел сомнительный API и сомнительное поведение, оба из которых сохраняются в рефакторинге. Во-первых, имя класса SetupTeardownIncluder ужасно. Это, по крайней мере, именная фраза, как и все имена классов, но это классическая фраза с придушенным глаголом. Это такое имя класса, которое вы неизменно получаете, когда работаете в строго объектно-ориентированном коде, где всё должно быть классом, но иногда вам действительно нужна всего лишь одна простая функция.
*
Неужели вся книга такая?
В основном, да. «Чистый код» смешивает обезоруживающую комбинацию сильных, вечных советов и советов, которые очень сомнительны или устарели. Книга фокусируется почти исключительно на объектно-ориентированном коде и призывает к достоинствам SOLID, исключая другие парадигмы программирования. Он фокусируется на коде Java, исключая другие языки программирования, даже другие объектно-ориентированные языки. Есть глава «Запахи и эвристические правила», которая представляет собой не более чем список довольно разумных признаков, которые следует искать в коде. Но есть несколько в основном пустословных глав, где внимание сосредоточено на трудоёмких отработанных примерах рефакторинга Java-кода. Есть целая глава, изучающая внутренние компоненты JUnit (книга написана в 2008 году, так что вы можете себе представить, насколько это актуально сейчас). Общее использование Java в книге очень устарело. Такого рода вещи неизбежны — книги по программированию традиционно быстро устаревают — но даже для того времени предоставленный код плох.
Там есть глава о модульном тестировании. В этой главе много хорошего — хотя и базового — о том, как модульные тесты должны быть быстрыми, независимыми и воспроизводимыми, о том, как модульные тесты позволяют более уверенно производить рефакторинг исходного кода, о том, что модульные тесты должны быть примерно такими же объёмными, как тестируемый код, но гораздо проще для чтения и понимания. Затем автор показывает модульный тест, где, по его словам, слишком много деталей:
и гордо переделывает его:
Это делается как часть общего урока о ценности изобретения нового языка тестирования для конкретной области для ваших тестов. Я был так сбит с толку этим утверждением. Я бы использовал точно такой же код, чтобы продемонстрировать совершенно противоположный совет! Не делайте этого!
*
Автор представляет три закона TDD:
Первый закон. Не пишите код продукта, пока не напишете отказной модульный тест.
Второй закон. Не пишите модульный тест в объёме большем, чем необходимо для отказа. Невозможность компиляции является отказом.
Третий закон. Не пишите код продукта в объёме большем, чем необходимо для прохождения текущего отказного теста.
Эти три закона устанавливают рамки рабочего цикла, длительность которого составляет, вероятно, около 30 секунд. Тесты и код продукта пишутся вместе, а тесты на несколько секунд опережают код продукта.
… но Мартин не обращает внимания на тот факт, что разбиение задач программирования на крошечные тридцатисекундные кусочки в большинстве случаев безумно трудоёмко, часто очевидно бесполезно, а зачастую невозможно.
*
Есть глава «Объекты и структуры данных», где автор приводит такой пример структуры данных:
и такой пример объекта (ну, интерфейс для одного объекта):
Два предыдущих примера показывают, чем объекты отличаются от структур данных. Объекты скрывают свои данные за абстракциями и предоставляют функции, работающие с этими данными. Структуры данных раскрывают свои данные и не имеют осмысленных функций. А теперь ещё раз перечитайте эти определения. Обратите внимание на то, как они дополняют друг друга, фактически являясь противоположностями. Различия могут показаться тривиальными, но они приводят к далеко идущим последствиям.
Да, вы всё правильно поняли. Определение Мартина «структуры данных» расходится с определением, которое используют все остальные! В книге вообще ничего не говорится о чистом кодировании с использованием того, что большинство из нас считает структурами данных. Эта глава намного короче, чем вы ожидаете, и содержит очень мало полезной информации.
*
Я не собираюсь переписывать все остальные мои заметки. У меня их слишком много, и перечислять всё, что я считаю неправильным в этой книге, заняло бы слишком много времени. Я остановлюсь на ещё одном вопиющем примере кода. Это генератор простых чисел из главы 8:
Если таково качество кода, который создаёт этот программист — на досуге, в идеальных условиях, без давления реальной производственной разработки программного обеспечения — тогда зачем вообще обращать внимание на остальную часть его книги? Или другие его книги?
*
Я написал это эссе, потому что постоянно вижу, как люди рекомендуют «Чистый код». Я почувствовал необходимость предложить антирекомендацию.
Первоначально я читал «Чистый код» в группе на работе. Мы читали по главе в неделю в течение тринадцати недель.
Так вот, вы не хотите, чтобы группа к концу каждого сеанса выражала только единодушное согласие. Вы хотите, чтобы книга вызвала какую-то реакцию у читателей, какие-то дополнительные комментарии. И я предполагаю, что в определённой степени это означает, что книга должна либо сказать что-то, с чем вы не согласны, либо не раскрыть тему полностью, как вы считаете должным. Исходя из этого, «Чистый код» оказался годным. У нас состоялись хорошие дискуссии. Мы смогли использовать отдельные главы в качестве отправной точки для более глубокого обсуждения актуальных современных практик. Мы говорили о многом, что не было описано в книге. Мы во многом расходились во мнениях.
Порекомендовал бы я вам эту книгу? Нет. Даже в качестве текста для начинающих, даже со всеми оговорками выше? Нет. Может быть, в 2008 году я рекомендовал бы вам эту книгу? Могу ли я рекомендовать его сейчас как исторический артефакт, образовательный снимок того, как выглядели лучшие практики программирования в далёком 2008 году? Нет, я бы не стал.
*
Итак, главный вопрос заключается в том, какую книгу(и) я бы рекомендовал вместо этого? Я не знаю. Предлагайте в комментариях, если только я их не закрыл.
Чистый код. Создание, анализ и рефакторинг [Роберт Мартин] (fb2)
[url=https://coollib.net/b/486351]
[b]Чистый код. Создание, анализ и рефакторинг (fb2)[/b]
[img]https://coollib.net/i/51/486351/cover.jpg[/img][/url]
QR-код книги
Аннотация
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.
Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги – концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
Примечание верстальщика: книга содержит большой объем исходников (code), так что не рекомендуется применять скрипты «Генеральная уборка», «Обработка кавычек» и т. д.
Рекомендации:
Чистый код — практический подход
После нескольких докладов о чистом коде (Clean Code) я решил обобщить в статье самое важное по этой теме. Поскольку в Интернете и так много постов и информации об этом, то, я думаю, еще одна статья, просто рассказывающая о принципах чистого кода, не будет интересной.
Поэтому я попытаюсь показать вам практический подход к чистому коду. Не вдаваясь в теорию, покажу, как я пишу Чистый Код.
Я хочу, чтобы мой код был чистым!
Что такое «чистый код» и почему вас это должно беспокоить?
История возникновения и определение «чистого кода»
Обязательно стоит упомянуть одноименную книгу, написанную Робертом К. Мартином в 2008 году (Прим. переводчика: издание на русском «Чистый код. Создание, анализ и рефакторинг.»). Но и до выхода этой книги было много других книг и опытных разработчиков, говоривших о подобных концепциях.
Я вывел своего рода определение чистого кода, объединив мнения нескольких авторов и источников:
Чистый код важен. По крайней мере, так же важен, как и другие характеристики, такие как производительность, функциональность, не допускать багов.…
Легко читается любым разработчиком.
Легко модифицируется любым разработчиком.
Автор кода заботится о нем.
Код делает то, что от него ожидается. Код вас не обманет, никаких сюрпризов.
Почему вы должны писать чистый код
Я действительно считаю, написание чистого кода важно, потому что это первый шаг к достижению главной цели любой архитектуры: минимизировать человеческие усилия, необходимые для создания и сопровождения системы.
Программисты тратят больше времени (гораздо больше) на чтение кода, чем на его написание. Мы читаем легаси-код, код библиотек, код коллег по команде, код, написанный вами несколько месяцев назад (которого вы не помните), код, написанный кем-то, кто ушел из компании, код на Stack Overflow… Роберт Мартин резюмирует:
«На самом деле соотношение времени чтения и написания кода превышает 10:1» — Роберт С. Мартин, «Чистый код».
Учитывая это, не стоит ли приложить немного дополнительных усилий при написании кода? Вы окупите это время в дальнейшем несколько раз. Подумайте об этом в следующий раз, когда будете коммитить кусок кода.
Последняя мысль, почему мы должны заботиться о своем коде, заключается в том, что мы, разработчики, пишем код не только для компилятора. Мы пишем код для чтения людьми. Представьте себя в роли журналиста, который пишет статью для газеты или в роли писателя, пишущего роман.
Некоторые принципы
Есть много принципов и идей о том, какой код является чистым, а какой нет. Вы можете найти их в книге, а также в сети. Но поскольку мне нужны некоторые основные принципы, с которыми можно было бы поиграться, я приведу некоторые из них. Если вы уже знакомы с ними, то можете перейти к следующему разделу, если нет, я думаю, они позволят вам получить представление о стиле остальной части теории и, возможно, мотивирует вас на дальнейшее изучение.
Итак, давайте рассмотрим некоторые принципы работы с кодом.
Давайте поэкспериментируем с кодом!
Имена
При написании кода мы повсюду придумываем имена: переменные, функции, классы, пакеты, файлы… Серьезное отношение к именам — первый шаг к чистому коду.
Несколько советов для чистых имен:
Используйте имена, передающие намерения программиста:
Выбирайте произносимые имена:
Используйте имена, доступные для поиска:
Избегайте префиксов, суффиксов и аббревиатур
Что, черт возьми, такое «hp»: гипотенуза (hypotenuse), верхняя точка (high point) …? У испаноговорящих будет еще больше вариантов.
По именованию есть множество других рекомендаций. Вероятно, использование имен, передающих намерения, является наиболее важным, но еще более важно — серьезное отношение к именованию.
Не торопитесь при выборе имен. И не бойтесь переименовывать, если считаете, что после изменения код станет более читабельным.
Функции
Среди всех идей о функциях я выделю три:
Первое правило простое и легко запоминающееся: функции должны делать что-то одно, делать это хорошо и делать только это. Избегайте побочных эффектов, разделяйте функции, если заметите, что они делают несколько вещей одновременно.
Функции должны быть небольшими. Хорошо, но насколько короткими? Как это измерить? Давайте договоримся, что в функциях будет не более двух уровней отступов. Если для вас это сложно, можно начать с более высокого предела (например, с трех уровней), но, пожалуйста, установите ограничение на уровни отступов, которые вы разрешаете.
По поводу аргументов… Чем меньше аргументов у функции, тем она чище. Почему? Аргументы требуют знания контекста. При каждом вызове читатель должен обладать контекстом, чтобы понять все аргументы. Больше аргументов — больше контекста, который вам нужно понять. Также возникают сложности с точки зрения тестирования. Больше аргументов — больше тестов для покрытия всех комбинаций аргументов.
У вас должна быть веская причина для функций с более чем двумя аргументами
Комментарии
Когда я учился программировать в 90-х, мои учителя обычно просили меня писать комментарии везде. Довольно часто приходилось слышать что-то вроде: «Если вы не будете комментировать код, я не приму ваш экзамен…». Целью этих комментариев было облегчить чтение нашего кода. Но мы преследуем эту же цель при написании чистого кода, и комментарии — не лучший способ ее достичь.
«Комментарии должны компенсировать нашу неудачу в выражении своих мыслей в коде. Комментарии — всегда признак неудачи.» — Роберт С. Мартин, «Чистый код»
В этом я согласен с Мартином. Он также говорит, что комментарии врут, и я уверен, что вы встречали в коде устаревшие неактуальные комментарии. Потому что мы вынуждены поддерживать код, но нет ничего, что заставляло бы нас поддерживать комментарии в актуальном состоянии. Есть ли что-нибудь хуже комментария, который лжет?
Правда только в коде. Когда хотите написать комментарий, всегда подумайте, нет ли лучшего способа выразить это с помощью кода.
Основная мысль — стараться избегать комментариев для пояснения кода. Например:
Избегайте комментариев для переменной. Вместо этого выберите хорошее имя для этой переменной, и вам не понадобится комментарий.
Избегайте комментариев для функций. Вместо этого напишите функцию так, чтобы она делала только одну вещь, у нее было небольшое количество аргументов и понятные имена самой функции и аргументов, и вам не понадобятся комментарии.
Давайте рассмотрим пример:
1. У нас есть нетривиальный участок кода. Мы чувствуем, что в будущем будет трудно его понять:
Что здесь происходит? Вам понятно? Круто, но для остальных может быть все не так просто.
Я добавил комментарий. Теперь я могу спать спокойно. Но лучшее ли это решение?
3. Попробуем другой вариант: извлечем этот кусок кода в метод с говорящим названием:
Теперь все чисто!
Подумайте, что будущему читателю кода будет интересно, когда он встретит этот if? Ему нужно понять, что этот if проверяет, является ли год високосным (leap year). Но, вероятнее всего, его не будет волновать, как выполняется эта проверка. Если все-таки это будет интересно, то он может перейти к реализации этого метода. Убрав комментарий, мы невольно также разделили разные уровни абстракции в коде.
В общем, избегайте комментариев для пояснения кода. А, так как вы используете систему управления версиями кода вроде GIT, то избегайте и закомментированного кода (удалите его!), информации об авторах частей кода и т. п.
Комментарии не запрещены, есть ситуации, когда комментарии вполне уместны:
Информация об авторских правах.
Пояснения важности чего-либо или объяснение конкретного решения в коде.
Комментарии публичных API обязательны (JavaDocs, …), но избегайте их в непубличном коде. Не заставляйте команду комментировать все функции всех ваших классов!
Дополнительные принципы
Как говорил ранее, я хотел привести примеры лишь нескольких принципов, чтобы вы получили основы теории «чистого кода». Итак, это всего лишь некоторые из базовых идей о чистом коде. Если они показались вам интересными и вам захотелось узнать больше, поищите дополнительные ресурсы в Интернете или прочитайте книгу Мартина.
Как сделать код чистым? Рефакторинг!
Понятные имена, маленькие функции, отсутствие комментариев для пояснения кода… все ясно. Но как это сделать? Как написать код, следуя этим концепциям?
Наша работа трудна сама по себе. Написать работающий код уже может быть достаточно сложной задачей. И это не беспокоясь о том, чтобы он был чистый.
Написать код уже достаточно сложно, и без раздумий о его чистоте
Таким образом, ключевым здесь может стать Рефакторинг. Хороший подход — первоначальное написание кода без беспокойства о его чистоте, с последующей очисткой уже работающего кода с помощью рефакторинга.
Рефакторинг
Рефакторинг кода — это процесс реструктуризации существующего кода без изменения его внешнего поведения. Это означает, что код до и после рефакторинга должен работать одинаково.
Примеры того, что не является рефакторингом:
Замена одного типа цикла другим.
Повышение производительности фрагмента кода.
Извлечение фрагмента кода в функцию.
Извлечение нескольких функций в новый класс.
Создание константы для хранения жестко заданного значения в коде.
Безопасный рефакторинг
Возможно, вы думаете: «Я не хочу ломать код, он работает нормально!». Да, конечно. Написать работающий код довольно сложно, мы не хотим ломать его при рефакторинге. И это частая причина, из-за которой люди спорят, чтобы не вносить изменения в плохой код. Но не волнуйтесь, есть безопасный способ.
При рефакторинге нас спасут две вещи:
Тестирование. У вас должны быть хорошие автоматизированные тесты по многим причинам. И очевидно, что они помогут провести рефакторинг, ничего не сломав. После каждого рефакторинга вы можете проверить, все ли тесты по-прежнему зеленые. В этом посте я не буду писать о тестировании, возможно, в следующем. Если вы не знакомы с тестированием, вам стоит изучить этот вопрос. В сети есть много информации.
Инструменты рефакторинга. В современных IDE есть инструменты, которые автоматически выполняют некоторые из наиболее распространённых рефакторингов. При их использовании снижается вероятность того, что мы что-то сломаем при внесении изменений в код. Я расскажу о некоторых из них далее в этой статье.
Когда следует проводить рефакторинг кода?
Постоянно. Я имею в виду, что у вас должен быть следующий цикл разработки:
Хотя не обязательно именно в таком порядке. При разработке вы можете использовать TDD, и в этом случае вы будете писать тесты перед кодом. Но в любом случае, вы должны проводить рефакторинг каждый раз, когда напишете кусок рабочего кода. Другими словами, вы должны проводить рефакторинг в конце каждого цикла. И эти циклы должны быть небольшими.
При коротких итерациях проводить рефакторинг гораздо легче, чтобы убедиться, что все чисто, и ничего не ломается. Если вы тратите на написание кода несколько дней и в очередной релиз входит много измененных строк в разных файлах, то, вероятно, это не самая хорошая привычка.
Приложение. Инструменты рефакторинга
Для демонстрации инструментов рефакторинга я выбрал JetBrains IntelliJ. Но вы найдете подобные инструменты и в других IDE. А если не найдете, возможно, вам следует попробовать другую IDE.
Переименование (rename)
Самым простым рефакторингом является переименование (Rename). Например, есть сущность с именем, которое вам не нравится, и вы хотите его изменить. Конечно, можно отредактировать его вручную. но это будет непросто, так как эта сущность может использоваться во многих местах.
Инструмент переименования с различными параметрами для безопасного переименования
IDE сообразило, что есть несколько переменных, которые я хотел бы изменить. Спасибо IDE!
Извлечение метода (Extract method)
Этот рефакторинг я использую чаще всего. Давайте рассмотрим пример:
У меня есть фрагмент кода, являющийся частью очень большой функции, которую я хочу отрефакторить. Я думаю, что часть этих строк делает какую-то законченную операцию и поэтому ее можно вынести в приватную функцию.
Я хочу извлечь создание wordFrequencyList в метод
2. Я использую рефакторинг Extract Method. У этого инструмента также есть ряд параметров:
Инструмент извлечения метода даже осмеливается предложить подходящее имя
3. Теперь код перемещен в метод, а вместо него идет вызов этого метода. Инструмент позаботился о создании метода, перемещении туда кода и изменении всех мест, где был такой же код, на этот один вызов метода (он ищет дубликаты кода).
Стало чище, не так ли?
Другие инструменты
Существует множество инструментов рефакторинга для популярных действий, которые выполняются при реорганизации кода. Говоря об IntelliJ Idea, вы можете взглянуть на ее документацию по рефакторингу, или поискать в документации вашей любимой IDE. Я рекомендую вам изучить все доступные инструменты рефакторинга вашей IDE и поэкспериментировать с ними, чтобы понять, как они работают и насколько они будут вам полезны.
Множество инструментов рефакторинга!
На самом деле, в моей IDE я могу выделить кусок кода и в меню «Refactor This» увидеть все доступные рефакторинги, которые можно применить к этому конкретному случаю:
Скажи мне, добрая IDE, что я могу с этим сделать?
Финальный аргумент
Есть финальный аргумент в пользу поддержания чистоты вашего кода, если я до сих пор вас не убедил:
Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живёте — Джон Ф. Вудс (John F. Woods).
Приглашаем всех на открытое занятие «Элементы формальной логики. Базовые структуры данных в языке Java». На нем познакомимся с основами алгоритмов и булевой алгебры. В процессе мы изучим базовые структуры данных языка Java: массивы, списки и словари. Регистрация по ссылке.
Чистый код. Создание, анализ и рефакторинг
Роберт Мартин
15 сентября 2021 г. 17:49
5 Без комментариев
Определенно могу сказать, что это одна из лучших настольных книг для разработчика. Можно бесконечно спорить насчет целесообразности отдельных стратегий и правил, которые предлагаются здесь, однако человек с прямыми руками и в трезвом рассудке обязательно приобретет массу полезных привычек, когда перевернет последнюю страницу этого томика и поставит его на полку к остальным, которые всегда будут служить ему верой и правдой в такой нелегкой профессии.
14 февраля 2021 г. 00:12
2 Ну так себе
Книга рассказывает о хороших принципах, но наглядность явно не на высоте. Вторая половина книги сопровождается простынёй с кодом на Java, который был актуален лет 10 назад.
23 февраля 2021 г. 16:45
Отличная книга для начинающего разработчика. Изучая программирование в школе/университете вы вряд-ли будете писать большие программы, и учавствовать в разработке ПО, которое пишут несколько людей. Однако при коммерческой разработке возникает множество вопросов, по наименованию разных сущностей организации методов и кода. Эта книга даёт много советов по этим вопросам, и позволяет достаточно сильно поднять свой уровень кода
23 декабря 2020 г. 18:21
5 Качественно
После применения рекомендаций из этой книги, мой код стал существенно понятнее и читаемее. Возможно, со временем я сам сумел бы прийти к похожим правилам, но тут они уже готовые и опробованные. Взял я, конечно, не всё, но имена переменных и функций, разбиение функций на части (да и в целом дробление большого на много маленьких) очень пригодились. Как минимум, теперь я могу лучше предположить, где у меня в коде что лежит, и что для чего сделано.
17 марта 2020 г. 12:53
5 «Единственная надежная метрика качества кода: количество «чертей» в минуту»
Книга крутая. Я много хороших отзывов слышала, но когда начала читать, оказалось, что она даже лучше, чем ожидала: покрывает огромное количество важных тем, в том числе есть немного советов по постороению архитектуры и капелька многопоточности.
А также присутствует ободряющая философия:
Необходимо пытаться и терпеть неудачи. Необходимо наблюдать за тем, как другие пытаются и терпят неудачи. Нобходимо видеть, как они спотыкаются и возвращаются к началу; как мучительно принимаются решения и какую цену приходится платить за неверный выбор.
В моем варианте русского издания (Питер, 2016) есть некоторые недочёты перевода, кривой алфавитный указатель (возможно, страницы остались из оригинальной версии, соответственно указатель ссылается не туда, где понятие действительно упоминается), и как…
18 марта 2019 г. 07:38
4 Не только для джавистов
Читал книжку в оригинале. Конечно те, кто пишет на Java получать максимум из книги, но и тем, кто работает с другими языками, будут очень полезны первые 30% книги – как правильно называть переменные, как организовать класс, сколько аргументов лучше передавать в функцию и т.д. Все эти вещи проходят всколзь при подготовке программистов в ВУЗах, а ведь именно из таких мелочей и складываются хорошие системы. Вообще, стоит прочитать точно всем программистам.
22 сентября 2018 г. 15:19
5 хорошая книга
пс пиши тесты или гори в аду
25 июня 2016 г. 13:02
4.5 «Над кодом необходимо попотеть»
Каждый раз, когда вы пишите комментарий, — поморщитесь и ощутите свою неудачу.
Книга «дядюшки» Боба, как ясно из названия (хотя тут сразу в глаза бросается одна вещь – в оригинале книга имеет название «Clean Code: A Handbook of Agile Software Craftsmanship», а в русском варианте «Чистый код. Создание, анализ и рефакторинг», это как «Lost» и «Остаться в живых»), о том коде, к которому должен стремиться каждый разработчик. Все примеры кода написаны на Java, но даже незнакомым с этим ЯП будет все понятно — ясность мысли, выраженная автором в коде, просто невероятна.
Роберт Мартин с первых страниц «говорит», что все изложенное в книге основано на его личном опыте, и каждое утверждение не будет подкрепляться исследованиями в этой области (как у Макконнелла в «Совершенном коде»), но от этого…
24 мая 2016 г. 11:00
3 Вычищайте код, господа!
Хорошая книга для новичка. Ненавязчиво объясняет необходимость чистки кода, обращает внимание на важные, незаметные, моменты и содержит много практических рекомендаций и примеров.
К сожалению, мои ухищрения ни к чему не привели. Как бы элегантно ни выглядела эта замечательная цепочка рефакторинга, в итоге я понял, что единственными пользователями этой функции были тесты, которые я только что изменил. И я удалил тесты.
Стыдно дважды наступать на одни грабли! Определив, что функция relativeToString (строки 765–781) не вызывается нигде, кроме тестов, я просто удалил функцию вместе с ее тестами.
Наконец-то мы добрались до абстрактных методов абстрактного класса. Первый метод выглядит знакомо: toSerial (строки 838–844). На с. 316 я присвоил ему имя toOrdinal. Рассматривая его в новом контексте, я решил, что его лучше переименовать в getOrdinalDay.
Следующий абстрактный метод, toDate (строки 838–844), преобразует DayDate в java.util.Date. Почему метод объявлен абстрактным? Присмотревшись к его реализации в SpreadsheetDate (строки 198–207, листинг Б.5, с. 428), мы видим, что он не зависит ни от каких подробностей реализации класса [G6]. Поэтому я поднял его на более высокий уровень абстракции.
Методы getYYYY, getMonth и getDayOfMonth абстрактны. Метод getDayOfWeek — еще один метод, который следовало бы извлечь из SpreadSheetDate — тоже не зависит от DayDate. Или все-таки зависит? Присмотревшись внимательно (строка 247, листинг Б.5, с. 428), мы видим, что алгоритм неявно зависит от «точки отсчета» дней недели (иначе говоря, от того, какой день недели считается днем 0). Таким образом, хотя функция не имеет физических зависимостей, которые нельзя было бы переместить в DayDate, у нее имеются логические зависимости.
Подобные логические зависимости беспокоят меня [G22]. Если что-то зависит от реализации на логическом уровне, то что-то должно зависеть и на физическом уровне. Кроме того, мне кажется, что сам алгоритм можно было бы сделать более универсальным, чтобы существенно меньшая его часть зависела от реализации [G6].
Я создал в DayDate абстрактный метод с именем getDayOfWeekForOrdinalZero и реализовал его в SpreadsheetDate так, чтобы он возвращал Day.SATURDAY. Затем я переместил метод getDayOfWeek наверх по цепочке в DayDate и изменил его так, чтобы в нем вызывались методы getOrdinalDay и getDayOfWeekForOrdinalZero.
public Day getDayOfWeek() <
Day startingDay = getDayOfWeekForOrdinalZero();
return Day.make((getOrdinalDay() + startingOffset) % 7 + 1);
Заодно присмотритесь к комментарию в строках с 895 по 899. Так ли необходимо это повторение? Как и в предыдущих случаях, я удалил этот комментарий вместе со всеми остальными.
Переходим к следующему методу compare (строки 902–913). Уровень абстракции этого метода снова выбран неправильно [G6], поэтому я поднял его реализацию в DayDate. Кроме того, его имя недостаточно содержательно [N1]. В действительности этот метод возвращает промежуток в днях, начиная с аргумента, поэтому я переименовал его в daysSince. Также я заметил, что для этого метода нет ни одного теста, и написал их.
Следующие шесть функций (строки 915–980) представляют собой абстрактные методы, которые должны реализовываться в DayDate. Я извлек из SpreadsheetDate.
Последнюю функцию isInRange (строки 982–995) также необходимо извлечь и переработать. Команда switch выглядит некрасиво [G23]; ее можно заменить, переместив условия в перечисление DateInterval.
public enum DateInterval <
public boolean isIn(int d, int left, int right) <
return d > left && d = left && d left && d = left && d
Чистый код. Создание, анализ и рефакторинг [Роберт Мартин] (fb2)
[url=https://coollib.com/b/486351]
[b]Чистый код. Создание, анализ и рефакторинг (fb2)[/b]
[img]https://coollib.com/i/51/486351/cover.jpg[/img][/url]
QR-код книги
Аннотация
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.
Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги – концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
Примечание верстальщика: книга содержит большой объем исходников (code), так что не рекомендуется применять скрипты «Генеральная уборка», «Обработка кавычек» и т. д.
Рекомендации:
Чистый код: создание, анализ и рефакторинг
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.
Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги — концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
Что такое «чистый код» в 2020-м?
«Чистый код» и чистый кот
Разработчиков хлебом не корми, дай поспорить о чистоте кода: например, недавно шумиху навёл пост Дэна Абрамова «Goodbye, Clean Code».
Но при этом у самого понятия «чистый код» нет чёткого определения. Главная книга по этому вопросу — «Clean Code», где Роберт «Дядюшка Боб» Мартин сразу заявляет: «сколько программистов, столько и определений». Впрочем, из этого он делает не вывод «говорить об этом бесполезно», а вывод «стоит сравнить разные определения». Поэтому в книге он привёл мнения нескольких выдающихся программистов о том, что такое чистый код.
Нам стало интересно: в 2020-м представления человечества о чистом коде остались теми же, или с выхода книги как-то изменились? Различаются ли мнения у разных айтишников: может, бэкендеры видят всё с одного ракурса, а тестировщики с другого?
А поскольку тема холиварная, наверняка кто-то из вас окажется не согласен с какими-то из мнений. В таком случае айда спорить в комментариях, это тоже весело!
UPD: Когда мы писали эту статью, Роберт планировал приехать на наши конференции. К сожалению, ситуация изменилась. Также из-за запрета на проведение массовых мероприятий мы перенесли конференции на другие даты. Следите за обновлениями на сайте конференции. 13 марта мы обновили этот пост, чтобы он не содержал некорректную информацию.
DotNext
Джон Скит
Джон — легенда Stack Overflow, автор книги «C# in Depth» и один из самых известных дотнетчиков планеты. Он дал нам такое определение:
«Для меня чистый код — это скучный код, с точки зрения имплементации. Единственный сюрприз в нём — это то, насколько он лишён сюрпризов. Я должен чувствовать „Да, я бы мог такое написать”, даже если бы на самом деле я и не мог — по тому, насколько хорошо он спроектирован.
Когда абстракция выбрана верно, имплементация выводится естественным образом. В идеале эта абстракция также должна ощущаться простой и очевидной — хотя на самом деле доведение её до такого состояния могло занять часы, недели, месяцы размышления и экспериментов.
Упомянутое отсутствие сюрпризов позже переносится и на использование: когда я пишу код, используя хорошо спроектированный API, мой код тоже становится очевидным и скучным».
Андрей Акиньшин
Когда мы спросили, что он думает про чистый код, Андрей сослался на два своих старых хабрапоста: «Совершенный код и реальные проекты» и «Комментировать или не комментировать». И мы выбрали для вас пару абзацев оттуда, с которыми кто-то наверняка захочет поспорить:
«Я люблю совершенный код. Ведь это не только правильный подход к написанию программ, но и настоящее искусство. От чтения хорошего листинга я получаю не меньше удовольствия, чем от чтения хорошей книги. Проектировать архитектуру большого проекта ничуть не легче, чем проектировать архитектуру большого здания, а в случае хорошей работы — результат не менее прекрасен. Порой меня завораживает то, как изящно переплелись паттерны проектирования в создании совершенной программной системы. Меня восхищает внимание к деталям, когда абсолютно каждый метод настолько прост и понятен, что претендует на место классического примера совершенного кода.
Но, увы, всё это великолепие разбивается о суровую действительность и реальные проекты. Если мы говорим о продакшн-проекте, то пользователей не волнует, насколько красив ваш код и насколько хороша архитектура, их волнует, чтобы проект хорошо работал. Но я всё равно считаю, что в любом случае нужно стремиться писать правильно, просто при этом фанатизма быть не должно».
Дилан Битти
Хабрачитатели могут помнить Дилана по его вдумчивому и яркому докладу про работу с легаси-кодом: для Хабра мы делали его расшифровку. И когда мы обратились к Дилану по поводу чистого кода, он написал такой развёрнутый и продуманный текст, что его хоть отдельным постом публикуй:
«Для меня интересно, что понятие «чистый код» распространилось далеко за пределы круга людей, читавших книгу Роберта Мартина. Я общался с многими, многими разработчиками, которые слышали слова «clean code», но не читали книгу. Я даже встречал их в кодревью: «Тут всё довольно хорошо, но можешь немного почистить?» — и такая просьба может быть раздражающе неточной, если неочевидно, что «чистый» означает в данном конкретном контексте.
В английском есть слова, которые часто встречаются вместе — «clean», «tidy», «organised», «neat» — и для меня как носителя английского они все означают немного разные вещи. Я думаю, что полезно рассмотреть некоторые коннотации этих слов применительно к разработке софта.
Представим, например, кухню ресторана. У слова «clean» в этом контексте будут очень конкретные коннотации. Всё вымыто, стерилизовано, нет никакой угрозы заражения из-за сырых продуктов, и тому подобное.
Но это не означает автоматически, что здесь всё хорошо организовано. Если вы когда-нибудь пытались приготовить еду у друга или в квартире, снятой на Airbnb, вы знаете, как раздражает, когда вещи не на своих местах. Средство для мытья посуды стоит в буфете, в котором рассчитываешь увидеть кастрюли, а чеснокодавилка вообще непонятно где. Да, всё чистое — нет угрозы, что кто-то отравится едой, приготовленной на этой кухне — но работать в таких условиях раздражает.
А теперь представим деревообрабатывающий цех. В этом месте грязь тоже может вызывать проблемы, но здесь у вас совсем не такое определение «чистоты», как на кухне. Вы можете начищать зубило, пока оно не начнёт сверкать, но вы всё равно вряд ли стали бы резать им сосиски. Так что слово «clean» может быть очень субъективным.
Но для меня слова вроде «tidy» и «organised» работают и таких контекстах, где «clean» не очень хорошо подходит. «Organised» означает, что кто-то как следует подумал, как расположить элементы конкретного рабочего места, а «tidy» означает, что эти элементы действительно находятся на отведённых им местах. Как говорится в старой поговорке, «всему есть своё место и всё на своём месте».
Возможно, в случае с кодом нам стоит думать о словах «clean», «tidy» и «organised» как о трёх разных понятиях. «Clean» означает, что вы смотрите на составные части кодовой базы — методы, функции, интерфейсы — и не видите никаких причин для беспокойства. В именовании придерживаются конвенций; названия переменных и методов написаны без ошибок; в деталях вроде отступов и скобок придерживаются единого стиля; куда ни посмотри, видишь подтверждения того, что на базовом уровне этим заправляют люди, подходящие к делу серьёзно. Это противоположность «грязного кода» — такого, где в названиях куча опечаток, фигурные скобки и отступы захотичны, несоответствующие названия файлов. Это те вещи, которые магически оказываются исправлены, когда вызываешь инструмент «code cleanup» в чём-то вроде ReSharper.
«Organised» — это про архитектуру. Это о том, что можно нырнуть в незнакомую кодовую базу и найти вещи там, где ожидаешь их увидеть. Интерфейсы и доменные границы помогают, а не мешают; методы и переменные названы не просто корректно названы с точки зрения языка, но и отражают единый язык бизнеса, с которым работаешь.
А «tidy» — это про уважение локальных конвенций… кодовая база, в которой можешь найти нужные вещи в соответствующих им местах, даже если конкретная организационная модель вам в этот момент не слишком понятна.
Я думаю, что когда говорят о борьбе за «чистый код», этим обычно подразумевают все три эти вещи. Но ставить целью полностью «чистый код», особенно когда работаешь со сложным легаси-проектом, может быть довольно устрашающей перспективой. Возможно, нам всем было бы полезно задуматься немного глубже и разобраться, что именно из составляющих «чистого кода» по-настоящему принесёт пользу проекту, над которым мы в данный момент работаем».
Heisenbug
Это «конференция по тестированию не только для тестировщиков»: она на стыке тестирования и разработки. Поэтому многие её спикеры понимают специфику обоих этих миров сразу.
Иван Крутов и Анна Чернышева
Иван и Анна работают в разных компаниях, но кое-что их объединяет: оба много знают про Selenium. Мы общались с ними одновременно, так что получилось совместное определение:
Иван: «Для меня самое простое определение чистого кода — это код, который понятен без комментариев, «самодокументирующийся». Код, который завален комментариями, которые пытаются объяснить, что он делает — это не чистый код».
Анна: «У меня похоже: это код, в котором можно быстро разобраться, исправить баг, легко расширить его, дополнить».
Иван: «Ещё можно сказать, что это «код, за который не стыдно». Вообще говорят, что если ты смотришь код, который написал полгода назад, и не ужасаешься, то ты не развиваешься. Получается, что с каждым годом твой код должен становиться всё чище».
Себастиан Дашнер
Себастиан — Lead Java Developer Advocate в IBM, и его часто можно увидеть на Java-конференциях. Но поскольку сейчас он прилетает на Heisenbug, мы спросили его о чистом коде именно в контексте тестирования, и он ответил:
«По моему опыту, качество кода важно не только в случае продакшн-кода, но и для наших тестов. В тестах чистым кодом, правильными абстракциями и делегацией часто пренебрегают, что приводит к такому коду тестов, который не поддержишь. Когда мы рефакторим продакшн-код и меняем его поведение, становится видно, хорошую работу ли мы проделали над моделированием и имплементацией наших тестов».
Андрей Лушников
Андрей работает над инструментом для браузерной автоматизации Playwright, о котором мы недавно писали. Его определение оказалось самым лаконичным:
«Чистый код — это тупой, очень понятный код. И чем тупее, тем лучше».
Александра Сватикова
Александра — эксперт по информационной безопасности в Одноклассниках, которая «начинала в IT как Java-разработчик, но свернула не туда». Её определение оказалось таким:
«Чистый код обладает тремя свойствами: другой разработчик может легко прочесть и понять его, незначительные доработки требуют соразмерных усилий, и эффект от конкретного изменения может быть предсказан.
На деле это означает, что код структурирован, лаконичен, следует общепринятым практикам для того языка на котором написан, не содержит неявных зависимостей или побочных эффектов и покрыт тестами».
HolyJS
Андрей Мелихов
Андрей известен многим по проекту «Девшахта». Неудивительно, что человек, постоянно формулирующий свои мысли в «Девшахта-подкасте», и свою позицию сформулировал чётко:
«Роберт «Дядя» Мартин тремя своими главными книгами («Clean Code», «The Clean Coder» и «Clean Architecture»), как мне кажется, пытается для себя ответить на вопросы: кто, что и как должен писать. Можно поспорить о корректности некоторых его выводов, но вот что, неоспоримо — эти книги построены на богатом личном опыте и здравом смысле. И в рамках этой идеи я могу сказать, что для меня чистый код — это код, который написал бы человек, споткнувшийся о немалое количество подводных камней в своей жизни и в этом болезненном процессе научившийся идти осторожной походкой, позволяющей этих камней избегать.
Вам может быть неудобен стиль этого человека, но если вы будете ему следовать, вы точно останетесь целы. Вы можете взять этот стиль и переработать его, сделать удобным для себя. Или вы можете отчаянно нырнуть в реку набивать собственные шишки, вырабатывать свой собственный стиль, пока остальные будут смотреть на вас с недоумением, двигаясь под присмотром старших товарищей.
Чистый код — это код, который легко читается, легко поддерживается и легко расширяется. Именно эти три аспекта закладывают прочный фундамент под приложениями, которым предстоит жить годами в условиях изменчивости внешних требований. А именно такие приложения мы пишем в крупных компаниях»
Александра Калинина
Александра состоит в программном комитете HolyJS, у неё большой опыт в программировании — и, хотя она не с Heisenbug, с тестами она тоже знакома не понаслышке (unit, integration, E2E, B2B). Вот её текст:
«Clean code — сейчас это простое понятие, но понять его довольно трудно. Мне кажется, что чистый код может получиться при соблюдении следующих правил:
— каждый отдельный кусочек кода должен иметь возможность масштабироваться или расти/улучшаться независимо от других кусочков, но при этом сохранять изначальную идею/интеграцию с другими кусочками (в этом очень помогает SOLID, а также правило «все решения, которые могут быть приняты позже, должны приниматься позже»).
— код должен читаться как увлекательная книга, с понятными типичными названиями и обозначениями. К примеру, если вы задумаете писать рассказ, то у него, вероятнее всего будет типичная структура вроде вступления, завязки, кульминации и развязки. Даже если только вы один работаете на проекте, код должен читаться легко вами же спустя любое время, независимо от выбранной архитектуры, языка, фреймворков.
— код должен иметь понятную структуру. Т.е. должна быть понятна причина, по которой тот или иной кусочек кода находится в проекте.
— каждая строчка кода должна быть обоснована с точки зрения бизнеса»
Nicolò Ribaudo
Николо, будучи ещё студентом, стал одним из ключевых разработчиков компилятора Babel (об этом мы его уже расспрашивали отдельно). Его вариант оказался таким:
«Чистый код — это код, который можно легко разделить на маленькие атомарные составляющие.
«Атом кода» — это наименьший возможный набор инструкций, обладающий самостоятельным смыслом, не зависящие излишне от окружающего контекста: имена переменных и операций достаточно описательные, чтобы читающему их не требовалось выделять в голове дополнительную память для хранения их значений и возможных модификаций, а также не требовалось смотреть ещё куда-то в коде, чтобы понять, что означает результат этого «атома». Чем меньше атомы, тем проще понять, что делает код.
Код может быть чистым вне зависимости от языка программирования или парадигмы: атомы можно реализовать как маленькие объекты, функции, или даже как маленькие фрагменты кода, не изолированные синтаксически».
Заключение
Наконец, когда мнения были собраны, мы показали их самому Дядюшке Бобу и спросили, хочется ли ему что-то сказать. Ответ оказался таким:
«Я полностью поддерживаю комментаторов выше. Я бы добавил только одну вещь, которую когда-то сказал Майкл Фезерс: “Чистый код всегда выглядит так, будто его писал человек, которому не всё равно”».
Его заключение звучит очень дружелюбно. Но чистый код — такая дискуссионная тема, что пока кто-то из вас согласно кивает, кто-то другой наверняка горит, ощущая что-то такое:
Чистый код. Роберт Мартин
Эту книгу я читал два года назад. Но единственное, что помню из неё, что мне не понравился перевод. Поэтому в этот раз я решил прочесть её в оригинале и заодно собрать годные мысли в заметках. Сегодня рассмотрим первые 4 главы.
Глава 1. Чистый код
В первой главе автор даёт определение чистому коду. Если собрать все описания в один список, то чистый код:
Глава 2. Названия
Используйте названия, объясняющие, что вы хотите сделать.
Избегайте двусмысленных названий. Не стоит называть переменную accountList если это не список. Не используйте названия, которые отличаются одним-двумя символами, чтобы не путать их.
Используйте произносимые имена. Аббревиатур следует избегать.
Глава 3. Функции
Функции не должны быть большими. Лучший размер для функции — 2–3 строки.
Каждая функция должна выполнять только одно действие. Но будьте аккуратнее с определением того, что такое «одно действие». Какие-то части можно вынести в отдельные функции, умейте останавливаться в правильный момент.
Названия должны полно описывать, что функции делают. Они должны быть консистентными, и недвусмысленными.
Больше, чем 3 аргумента использовать не стоит. Флаги лучше заменить на объект с настройками.
Избегайте функций с побочными действиями и дублирования кода.
Глава 4. Комментарии
Комментарии появляются, когда мы не можем выразить что-то прямо в коде. Поэтому по умолчанию стоит считать комментарий недоработкой и стараться передать мысль через переменную или функцию.
В комментариях лучше объяснить, каким образом вы пришли к какому-либо решению. Они должны рассказать то, чего не будет знать человек, который будет работать с вашим кодом. Также стоит в комментариях предупредить об известных проблемах с этой частью кода.
Избавляйтесь от лишних комментариев. Если что-то понятно из прямо кода, не нужно это комментировать. Убирайте устаревшие и вводящие в заблуждение комментарии. Убирайте закомментированный код.
В следующий раз
В главах 5–8 обсудим:
Чистый код. Создание, анализ и рефакторинг
Роберт Мартин
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.
Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги – концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода. Примечание верстальщика: книга содержит большой объем исходников (code), так что не рекомендуется применять скрипты «Генеральная уборка», «Обработка кавычек» и т. д.
Robert martin clean code
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение».
Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший.
Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги – концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
Чистый код: создание, анализ и рефакторинг
Скачать книгу
О книге «Чистый код: создание, анализ и рефакторинг»
В программировании много тонкостей, и, если не учесть некоторые моменты, код может не работать. Однако часто встречаются случаи, что код рабочий, но не слишком «чистый», плохо написанный. В книге «Чистый код: создание, анализ и рефакторинг» Мартин Роберт учит работать с кодом и рассказывает, какие изменения внести, если код нужно доработать. Можно, конечно, и не вносить никаких изменений, но тогда на поддержку кода потребуется гораздо больше ресурсов.
Это учебник для тех программистов, которые хотят стать настоящими профессионалами, а не представителями среднего и низшего уровней. Код здесь рассматривается с разных сторон, изучается так, как только возможно. Автор рассказывает о важных принципах, даёт советы, как написать чистый код. Он приводит большое количество примеров. Затем он предлагает разные сценарии с нарастающей сложностью. Есть упражнения, в которых нужно очистить код или отредактировать так, чтобы при работе возникало меньше проблем. В завершении книги автор говорит обобщённо обо всех правилах и о мышлении, которое должно быть у программиста во время написания и чистки кода.
Книга научит отличать хорошие и плохие коды, изменять их в лучшую сторону. Читатели смогут узнать много нового. Большое количество понятных примеров делают книгу доступной даже для новичков. Всё это легко применимо на практике, как при работе с языком Java, так и при работе с другими языками программирования.
На нашем сайте вы можете скачать книгу «Чистый код: создание, анализ и рефакторинг» Мартин Роберт бесплатно и без регистрации в формате pdf, читать книгу онлайн или купить книгу в интернет-магазине.
Clean Code: A Handbook of Agile Software Craftsmanship
Read it now on the O’Reilly learning platform with a 10-day free trial.
O’Reilly members get unlimited access to live online training experiences, plus books, videos, and digital content from O’Reilly and nearly 200 trusted publishing partners.
Book description
Even bad code can function. But if code isn’t clean, it can bring a development organization to its knees. Every year, countless hours and significant resources are lost because of poorly written code. But it doesn’t have to be that way.
Noted software expert Robert C. Martin presents a revolutionary paradigm with Clean Code: A Handbook of Agile Software Craftsmanship. Martin has teamed up with his colleagues from Object Mentor to distill their best agile practice of cleaning code “on the fly” into a book that will instill within you the values of a software craftsman and make you a better programmer—but only if you work at it.
What kind of work will you be doing? You’ll be reading code—lots of code. And you will be challenged to think about what’s right about that code, and what’s wrong with it. More importantly, you will be challenged to reassess your professional values and your commitment to your craft.
Clean Code is divided into three parts. The first describes the principles, patterns, and practices of writing clean code. The second part consists of several case studies of increasing complexity. Each case study is an exercise in cleaning up code—of transforming a code base that has some problems into one that is sound and efficient. The third part is the payoff: a single chapter containing a list of heuristics and “smells” gathered while creating the case studies. The result is a knowledge base that describes the way we think when we write, read, and clean code.
Readers will come away from this book understanding
How to tell the difference between good and bad code
How to write good code and how to transform bad code into good code
How to create good names, good functions, good objects, and good classes
How to format code for maximum readability
How to implement complete error handling without obscuring code logic
How to unit test and practice test-driven development
This book is a must for any developer, software engineer, project manager, team lead, or systems analyst with an interest in producing better code.
Robert martin clean code
These are the notes I took while reading the book “Clean Code: A Handbook of Agile Software Craftsmanship” (Robert C. Martin)]1, that are supposed to summarize the main concepts presented in the book.
The book has a mission to “improve the state of software craftmanship”. A lot of reasoning and moralizing at the beginning, I’ll skip that (still it is really worth reading!) 🙂 What I liked the most:
We want to use the popular paperback model whereby the author is responsible for making himself clear and not the academic model where it is the scholar’s job to dig the meaning out of the paper.
Just gonna mention that all the advice comes not from guesses but experience (as the author claims).
Table of contents
Dictionary
Because I hate getting stuck on abbreviations:
1. Meaningful Names
It is sometimes a good idea to extract even one-line-if-condition to a separate method, as one can give this method a more descriptive name.
It is important to keep in mind the keywords specific to different areas of IT, and avoid using them when we mean them in a different context. E.g. do not call accountList something which is not a list.
Make your names pronouncable, so that you can later discuss the code without sounding like an idiot.
Class names should have a noun in the name.
Don’t try to be funny when choosing names (someone may not understand).
Don’t be afraid of renaming.
2. Functions
Should be smaller than small. Best 3-4 lines. Max 1-2 indent levels (e.g. if ).
Each function should do only one thing. “One thing” is when you cannot split it to steps anymore.
The code should be read like a top-down narrative. Place the extracted function right below the function that is calling it.
Sometimes it’s worth to use polymorphism rather than a switch. Using switch often breaks the SRP (more than one reason to change) and OCP (must change whenver new types are added), and sometimes even causes duplicating the same switch costructions in several functions. Instead create classes for each switch case, and bury the switch itself deep in an Abstract Factory.
Max number of function input arguments is 2-3, best 0. They increase testing complexity. Make the function harder to understand.
Often if a function takes many arguments it’s a sign that they should be wrapped into a class on their own.
Anything that forces you to look up a function signature is a cognitive break and should be avoided.
Avoid using flag arguments. Boolean passed into a fuction means the fuction does more than one thing! Should be split into two functions then.
Start with writing any fuction and then refactor it, long. It’s not the goal to have them neat and nice from the start.
3. Comments
Comments are evil. The goal of comments is to compensate for our failure or to help express ourselves better. They are always sign of failure.
Comments get outdated as there is no good way of maintaining them. People move the code but forget the comment. People change the code but forget the comment, or no longer remember what it was supposed to mean.
They are reasonable only sometimes (express rationale behind choosing a certain approach, or to stress out some important detail in the implementation), but in general try to minimize using them.
Of course it’s different with Javadocs, Javadocs are useful, but keep them accurate. Misleading comment is worse than no comment.
If you write a comment, write about what is just next to it, not about the whole system around. Only about what the function has control over. Otherwise it will soon become outdated, and therefore misleading.
4. Formatting
Code formatting is important because it is part of communication.
It also makes the reader trust the code more.
Vertical size of a file should be typically 200 lines, with upper limit of 500 (but this is just a rough number, based on a number of open source projects; the author phrases it way more dyplomatically :P).
It’s a good idea to put a blank line between groups of lines that represent single thought. And lines referring to single concept should be kept dense.
Declare local variables on the top of each function (except when it’s just a loop counter, or sth similar).
Keep lines short, less than 80-120 characters. Even if your screen can fit more.
Surround = assignments with whitespaces, to accentuate them.
(some other obvious whitespace usages and antiusages)
Each developer should follow common team rules, even if some of them don’t like some of them.
5. Objects and Data Structures
Don’t automatically add getters and setters to each private variable. Why would we have private variables at all then?
Getters and setters are part of the interface using which the object communicates with the world. Think it through.
OO code makes it easier to add new classes (add new objects), and procedural code makes it easier to add new functions (add new behaviour). Always choose the style appropriate to the task at hand. Everything does not have to be an object.
An example of a procedural code is the following: we have a class Geometry and different Shape subclasses. In Geometry class there is a number of methods that operate on a Shape, in each there is switch to check which subclass of Shape are we dealing with. If we add a new shape type, we need to make changes in every method in Geometry class. If we add a new operation type, we need to only add the new function to Geometry class.
That is why the ctxt.getOptions().getScratchDir().getAbsolutePath() is a candidate of breaking that law. BUT not if the subsequent classes are data structures not objects.
And, if they are objects, there should not be “getSth” functions on them, but “doSth” functions. If we need to get sth, let’s think about what we need it for, and move that logic into that class, under a “doSth” function.
6. Error Handling
Keep error handling separate from the business logic.
Unchecked exceptions are now fine. In the past they were bad practice, now they are not. It’s neccessity. Encouraging checked exceptions in Java was a mistake, as they violate OCP principle. Only use them if you write a critical library and need to force the user to catch an exception.
Don’t return null. This forces you to write a lot of null checks, and of course one day you will forget one.
Don’t pass null (like calculator.xProjection(null, new Point(12, 13)); ).
7. Boundaries
Sometimes it’s a good idea to encapsulate Map into own object, so that the user does not see the generics. Don’t pass Maps or other boundary interfaces (i.e. coming from 3rd party general use library) around your system. They should not be part of your public API.
What happens at boundaries is change. Minimize the number of touch points with 3rd party libraries.
8. Unit Tests
(Some well known rules about TDD)
Use same quality standards for tests as for production code! Otherwise maintenance will become pain in the head. No “quick and dirty” tests! Dirty tests are worse than no tests. Below an illustration of a real life story (the illustration is my own interpretation):
Tests keep the production code flexible.
Readability in tests is even more important than it is in production code. So refactor, remove code duplication, choose descriptive names. Make it clear where the “setup”, “run” and “assert” part is. Design the tests for reading.
Even write a set of utility methods only for your tests, that will use domain language, and provide a testing API to your system.
Keep on refactoring tests, just like you do with the production code.
Test one concept per test. A test should have only one reason to fail.
9. Classes
If a test needs it, it’s fine to change a method from private to protected, if no other solution.
A class should be smaller than small. It should have only one responsibility.
Single Responsibility Principle (SRP) states that a class or module should have one, and only one, reason to change.
Responsibility = reason to change.
Making things work and keeping code clean are two different activities that cannot be done simultaneously. So after you are done with the first, don’t forget the latter!
Don’t be afraid of having many small classes. The complexity comes from number of moving parts not number of classes. You will not change program complexity by dividing it into many classes, but you will increase the ease with which someone else can learn it, and find the piece that is relevant to them at the moment. It’s about organisingthe complexity.
Cohesion of a function is proportional to the number of instance variables it modifies. The number of instance variables of a class should be small and cohesion high. And now listen to that:
Often when you want to minimize number of function arguments and create small functions, the number of instance variables grow, and often also at the same time cohesion decreases. This is often the sign that another class tries to get out of the bigger class. Split them!
10. Systems
Separate system startup code from the rest of the code (initialization, etc.). Even avoid such lazy initialization (it introduces coupling):
Aspects and proxies are an attempt used for separating cross cutting concerns, proxies have some drawbacks though (though Spring makes them transparent enough to be acceptable). Aspect like architecture enables it to be test-driven.
Always postpone architectural decisions to the last possible moment.
Don’t blindly follow emerging standards or hypes.
11. Emergence
Emergent design.
Rules of good design (by Kent Beck):
12. Concurrency
Concurrency is a decoupling strategy: it helps us decouple what gets done from when it gets done.
Concurrency does not always improve performance.
Concurrency requires fundamental change in design strategy.
Correct concurrency is complex even for simple problems. Bugs are often not repeatable, therefore often incorrectly ignored.
Keep your concurrency code separate from other code.
Limit the places where a variable is accessed concurrently to minimum. Eventually you will forget to synchronize the access in one place.
If you can introduce immutable objects instead of synchronizing, do so. It’s worth the garbage collection overhead.
Try to partition your data in such a way that it can be used by independent threads.
Use java.util.concurrent.* collections instead of regular ones. In particular, you should use ConcurrentHashMap instead of HashMap always, as it is more performant in general.
Become familiar with concurrent execution models:
Most concurrency problems are combination of the three above. Learn the three above and their solutions.
Keep number of synchronized sections low, but also keep those sections as small as possible.
Writing correct shut-down is harder than you think. Plan enough time for that.
Testing concurrent code does not assure its correctness. But it can minimize its incorrectness. Write your tests very varied, with different parameters, try to cover extreme cases. Never ignore a situation when a test failed just once. Remember that the number of possibilities of concurrent execution of trivally simple code is huge. Chase every bug.
Make sure your code works outside of threads first.
Make your threaded code pluggable and tunable, so that you can test it independently.
Test your threaded code with more threads than processors. Things happen when the system switches betweent he tasks.
Test your code on different platforms (they have different task switching strategies).
Avoid calling one locked section from another.
13. Successive Refinement
There is a long use case presented. To sum it up: code may be quite nice and clean initially, but once we add new functionality it can become a monster. Always refactor and clean up. But not before you have tests. Use TDD while refactoring.
Programmers who satisfy themselves with merely working code are behaving unprofessionally.
14. JUnit Internals
(Another use case)
15. Refactoring SerialDate
(Another use case)
16. Smells and Heuristics
(Set of numbered checks with explanations. I write only the new things.)
Comments
General bad things
Tests
17. Appendix A: Concurrency II
(I’ll just write some selected stuff)
It’s a common misconception that increment operation ++ is atomic. Assigment is usually also not. Something like 8 steps can be involved in single assignment on the level of byte code, hence so many possible paths of execution in a multithreaded environment.
Nonthread-safe classes:
Example of something not being thread safe even though each method separately is; assume that hasNext() and next() are both synchronized:
Solutions:
Book recommendation: Doug Lea “Concurrent Programming in Java: Design Principles and Patterns”.
18. Appendix B: org.jfree.date.SerialDate
(Just full source code for the SerialDate use case)
How to write clean code? Lessons learnt from “The Clean Code” — Robert C. Martin
There are two things- Programming and Good Programming. Programming is what we have all been doing. Now is the time to do good programming. We all know that even the bad code works. But it takes time and resources to make a program good. Moreover, other developers mock you when they are trying to find what all is happening in your code. But it’s never too late to care for your programs.
This book has given me a lot of knowledge on what are the best practises and how to actually write code. Now I feel ashamed of my coding skills. Though I always strive to better my code, this book has taught a lot more.
Now, you are reading this blog for two reasons. First, you are a programmer. Second, you want to be a better programmer. Good. We need better programmers.
Characteristics of a Clean code:
4. Runs all the tests
5. Contains no duplication
6. Minimize the number of entities such as classes, methods, functions, and the like.
How to write Clean code?
Meaningful Names
Use intention revealing names. Choosing good names takes time but saves more than it takes.The name of a variable, function, or class, should answer all the big questions. It should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name does not reveal its intent.
Eg- int d; // elapsed time in days.
We should choose a name that specifies what is being measured and the unit of that measurement.
A better name would be:- int elapsedTime. (Even though the book says elapsedTimeInDays, I would still prefer the former one. Suppose the elapsed time is changed to milliseconds. Then we would have to change long to int and elapsedTimeInMillis instead of elapsedTimeInDays. And for how long we’ll keep changing both the data type and name.)
Class Names — Classes and objects should have noun or noun phrase names like Customer, WikiPage, Account, and AddressParser. Avoid words like Manager, Processor, Data, or Info in the name of a class. A class name should not be a verb.
Method Names —Methods should have verb or verb phrase names like postPayment, deletePage, or save. Accessors, mutators, and predicates should be named for their value and prefixed with get, set.
When constructors are overloaded, use static factory methods with names that describe the arguments. For example,
Complex fulcrumPoint = Complex.FromRealNumber(23.0); is generally better than Complex fulcrumPoint = new Complex(23.0);
Pick One Word per Concept —Pick one word for one abstract concept and stick with it. For instance, it’s confusing to have fetch, retrieve, and get as equivalent methods of different classes. How do you remember which method name goes with which class? Likewise, it’s confusing to have a controller and a manager and a driver in the same code base. What is the essential difference between a DeviceManager and a Protocol- Controller?
Functions
The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. This implies that the blocks within if statements, else statements, while statements, and so on should be one line long. Probably that line should be a function call. Not only does this keep the enclosing function small, but it also adds documentary value because the function called within the block can have a nicely descriptive name.
Function arguments
A function shouldn’t have more than 3 arguments. Keep it as low as possible. When a function seems to need more than two or three arguments, it is likely that some of those arguments ought to be wrapped into a class of their own. Reducing the number of arguments by creating objects out of them may seem like cheating, but it’s not.
Now when I say to reduce a function size, you would definitely think how to reduce try-catch as it already makes your code so much bigger. My answer is make a function containing just the try-catch-finally statements. And separate the bodies of try/catch/finally block in a separate functions. Eg-
This makes the logic crystal clear. Function names easily describe what we are trying to achieve. Error handling can be ignored. This provides a nice separation that makes the code easier to understand and modify.
Error Handling is one thing — Function should do one thing. Error handling is one another thing. If a function has try keyword then it should be the very first keyword and there should be nothing after the catch/finally blocks.
Comments
If you are writing comments to prove your point, you are doing a blunder. Ideally, comments are not required at all. If your code needs commenting, you are doing something wrong. Our code should explain everything. Modern programming languages are english like through which we can easily explain our point. Correct naming can prevent comments.
Legal comments are not considered here. They are necessary to write. Legal comments means copyright and licenses statements.
Objects and Data Structures
This is a complex topic so pay good attention to it. First we need to clarify the difference between object and Data Structures.
Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions.
These 2 things are completely different. One is just about storing data and other is how to manipulate that data. Consider, for example, the procedural shape example below. The Geometry class operates on the three shape classes. The shape classes are simple data structures without any behavior. All the behavior is in the Geometry class.
Consider what would happen if a perimeter() function were added to Geometry. The shape classes would be unaffected! Any other classes that depended upon the shapes would also be unaffected! On the other hand, if I add a new shape, I must change all the functions in Geometry to deal with it. Again, read that over. Notice that the two conditions are diametrically opposed.
Now consider another approach for the above scenario.
Now we can easily add new Shapes i.e. data structures as compared to previous case. And if we have to add perimeter() function in only one Shape, we are forced to implement that function in all the Shapes as Shape class is an interface containing area() and perimeter() function. This means:
D ata structures makes it easy to add new functions without changing the existing data structures. OO code(using objects), makes it easy to add new classes without changing existing functions.
The complimentary is also true:
Procedural code(using data structures) makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.
So, the things that are hard for OO are easy for procedures, and the things that are hard for procedures are easy for OO!
In any complex system there are going to be times when we want to add new data types rather than new functions. For these cases objects and OO are most appropriate. On the other hand, there will also be times when we’ll want to add new functions as opposed to data types. In that case procedural code and data structures will be more appropriate.
Mature programmers know that the idea that everything is an object is a myth. Sometimes you really do want simple data structures with procedures operating on them. So you have to carefully think what to implement also thinking about the future perspective that what will be easy to update. As for in this example, as any new shape can be added in the future, I will pick OO approach for it.
I understand it’s hard to write good programs given the timeline in which you have to do your tasks. But till how long you’ll delay? Start slow and be consistent. Your code can do wonders for yourself and mostly for others. I’ve started and found so many mistakes I’ve been doing all the time. Though it has taken some extra hours of my daily time limit, it will pay me in the future.
This is not an end to this blog. I will continue to write about new ways to clean your code. Moreover, I will also write about some basic design patterns which are must know for every developer in any technology.
In the mean time, if you like my blog and learnt from it, please applause. It gives me motivation to create a new blog faster 🙂 Comments/Suggestions are welcomed as always. Keep learning and keep sharing.
Манифест Чистого Программиста или краткий конспект книги «Чистый Код» Роберта Мартина
Данная статья является конспектом книги «Чистый Код» Роберта Мартина и моим пониманием того, каким Чистый Код должен быть. Тут нет разделов о тестировании, TDD, о том какая должна быть архитектура и т.д. Здесь все только о том, каким должен быть Чистый Код.
Да, возможно, тема Чистого Кода уже заезженна, но тем не менее еще не все с ним знакомы и, тем более, я не встретил аналогов контента, который содержится в моей статье.
Общее
Нет истинного пути и решения. Есть тот, который лучше всего подходит для решения конкретной задачи.
При решении задачи попытайся воспроизвести абсолютно все кейсы, которые могут затрагивать эту задачу и реализуй задачу с учетом абсолютно всех кейсов.
Также при решении задачи попробуй пойти от обратного. Пойми какие результаты в итоге ты хочешь получить и составь на этом основании алгоритм, по которому будет выполняться задача.
Перед тем, как отправить задачу в релиз — проверь правильно ли она работает. Нет ли в ней ошибок. Это касается даже тех коммитов, которые отправляются в твою ветку. Самый идеальный сценарий — тот, в котором никто не смог найти ошибки в функционале, который ты разрабатывал.
Всегда задумывайся о том как можно сделать твой код проще, чище и читабельнее.
Чистый Код
Как писать чистый и хороший код? Это похоже на написание книги. Сначала ты делаешь черновик и потом причесываешь его до того состояния, в котором тебе было бы приятно его читать. Всегда помни, что твой код должен рассказывать историю происходящего, чтобы читатель мог ее понять.
Под сущностью понимается — интерфейс, класс, метод, переменная, объект и т.д.
Наименования и разделения
Функции
Комментарии
Форматирование и правила
Объекты и структуры данных
Классы
Обработка ошибок
Границы
Послесловие
В данной статье представлены лишь рекомендации к написанию Чистого Кода. Разумеется, ими можно пренебрегать. Вам лишь стоит понять, что у любого вашего решения должны быть аргументы в пользу него.
Check out this breakdown of some of the elements from Robert C. Martin’s acclaimed book, Clean Code.
Join the DZone community and get the full member experience.
Writing good code in accordance with all the best practices is often overrated. But is it really? Writing good and clean code is just like good habits which will come with time and practice.
We always give excuses to continue with our patent non-efficient bad code, reasons like no time for best practices, meeting the deadlines, angry boss, tired of the project, etc. Most of the time we try to procrastinate by saying will make it efficient and clean later but that time never comes.
Bad code is not problematic for us to understand but for the other developers who will handle that after us.
So, let me get you to the points by Robert C. Martin in his captivating book Clean Code.
Meaningful Names
We name our variables, class, directories, packages, jar files, war files, ear files. We name, we name and we name. So, we should name well.
Choosing good names takes time but saves more than it takes. Everyone who reads your code (including you) will be happier if you do.
So while naming anything, we should be able to answer these three questions:
And if we can’t answer them, that means we are not doing it right.
If a name requires a comment, then the name doesn’t reveal its intent. Say for example:
So just by looking at this » d«, no one is going to understand what this d is doing and eventually waste time over it. Our names should be such that says its intention, like,
Avoid Disinformation
Programmers must avoid leaving false clues that obscure the meaning of the code. We shouldn’t use type information in names.
Do not refer to a grouping of accounts as an accountList unless it’s actually a List. The word list means something specific to programmers. If the container holding the accounts is not actually a List, it may lead to false conclusions. So, accountGroup or bunchOfAccounts or just plain accounts would be better.
Don’t be afraid to make a name long. A long descriptive name is better than a short enigmatic name.
A long descriptive name is better than a long descriptive comment.
Just have a look at this snippet. Having a hard time to tell what is it doing? I, too, have few questions:
So a refactored better version of the above snippet could be something like this:
Now, things get clear.
Functions
The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. The smaller and more focused a function is, the easier it is to choose a descriptive name. According to Martin, your functions should be as small as possible, maximum length should be less than 20 lines. If it exceeds this limit, you should segregate the logic into different smaller functions.
Talking about the arguments, the number of arguments should be as minimum as possible. The ideal number of arguments for a function is zero. Such a function doesn’t depend on any input so there’s always going to be some trivial output from it. It will be easy to test. Next comes one (monadic) which is based on functional programming rules, followed closely by two (dyadic). Three arguments (triadic) should be avoided wherever possible. More than three (polyadic) requires very special justification and then shouldn’t be used anyway.
If any in case the number of arguments are more than 3, then we should group them into a meaningful object.
Arguments are even harder from a testing point of view. Imagine the difficulty of writing all the test cases to ensure that all the various combinations of arguments work properly.
Avoid output arguments: Anything that gets modified or mutated but is not returned by the function. An array passed to a function, which changes the body of the array but not returning it, then it is the output argument.
If the name of the function doesn’t tell the developer about all the functionalities implemented by it. Then these hidden functionalities are called side effects. Side effects are lies!
Your function promises to do one thing, but it also does other hidden things. Sometimes it will make unexpected changes to the variables of its own class. Sometimes it will make them to the parameters passed into the function or to system globals. In either case, they are devious and damaging mistruths that often result in strange temporal couplings and order dependencies.
See this example:
So, as you can see that the intent of this function (as its name says) is to just check the password. But it is initializing the session, too. This could be misleading because whosoever calls this function, in fact, will not aware of this hidden functionality and might cause blunder in your code.
Do One Thing!
Your function should do only one thing. If it does two or more, better break them into different functionalities. Keep It Simple, Stupid!
This function is doing two things first it checks the password and then initializing the session. The better way could have been checkPassword and initializeSession would be two separate functions and caller would just call them accordingly.
Data Structures and Objects
Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions. They are virtual opposites. In the case of objects, it is easy to add new objects but harder to add new behavior. Let’s understand this through an example:
As you can see, if I want to add a new type of shape, say for example, rhombus, I can simply add its class extending Shape trait and provide the implementation for the area method. That’s all I need to do. But its hard to add new behavior. Why? If suppose I need to a new method say volume. Then all the subclasses extending this trait need to change.
Now consider data structures example:
Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.
In any complex system, there are going to be times when we want to add new data types rather than new functions. For these cases, objects and OO are most appropriate. On the other hand, there will also be times when we’ll want to add new functions as opposed to data types. In that case, procedural code and data structures will be more appropriate.
The Law of Demeter
It says our function should only access the classes/objects that it has direct access to which are:
i. Objects in class parameter
ii. An object in function parameter
iii. An object in class members
iv. Objects created inside the function body.
In short, the Law of Demeter aims to keep you from doing things like this:
or even worse, this:
It might seem odd to have a section about error handling in a book about clean code. Error handling is just one of those things that we all have to do when we program. Input can be abnormal and devices can fail. In short, things can go wrong, and when they do, we as programmers are responsible for making sure that our code does what it needs to do.
«Error handling is important, but if it obscures logic, it’s wrong. «
A few tips to keep in mind while doing error handling in your code:
So these were just a few topics from the book Clean Code. This book has everything you are looking for. So, go give it a read. For more topics from this book, you can refer to this blog.
I hope this blog helped you!
Opinions expressed by DZone contributors are their own.
Кофе-брейк #103. В защиту “Чистого кода”: 100 вечных советов
Глава 1: Чистый код
Общее количество беспорядка со временем увеличивается.
Восстановить устаревшую систему с нуля очень сложно. Рефакторинг и постепенные улучшения станут лучшим для этого вариантом.
В запутанной кодовой базе на выполнение задач, которые должны занимать всего несколько часов, могут уйти дни или недели.
Найдите время, чтобы действовать быстро.
Чистый код хорошо справляется с одной задачей. Плохой код пытается сделать слишком много.
Чистый код хорошо протестирован.
При чтении хорошо написанного кода каждая функция делает примерно то, что вы ожидали.
Если вы не согласны с принципом, который преподает кто-то с многолетним опытом, вам следует хотя бы рассмотреть его точку зрения, прежде чем игнорировать ее.
Код читают гораздо чаще, чем пишут.
Код, который легче читать, легче изменить.
Оставьте кодовую базу в лучшем виде, чем когда вы ее нашли (Правило бойскаута).
Глава 2: Значение имен
Тщательно выбирайте имена переменных.
Выбирать хорошие имена сложно.
Имя переменной или функции должно указывать на то, что это такое и как используется.
Избегайте использования односимвольных имен переменных, за исключением часто используемых имен, например, i для переменной счетчика в цикле.
Избегайте использовать сокращение в именах переменных.
Имена переменных должны быть произносимыми, чтобы вы могли говорить о них и произносить их вслух.
Используйте имена переменных, которые легко найти.
Классы и объекты должны иметь имена в виде существительных.
Имена методов и функций должны быть глаголами или парами глагол-существительное.
Глава 3: Функции
Функции должны быть небольшими.
Функция должна выполнять одно действие.
Функции должны иметь описательные имена.
Извлеките код в теле if / else или переключите операторы в четко названные функции.
Ограничьте количество аргументов, которые принимает функция.
Если функции требуется много аргументов конфигурации, рассмотрите возможность объединения их в одну переменную параметров конфигурации.
Функции должны быть чистыми, что означает, что они не имеют побочных эффектов и не изменяют свои входные аргументы.
Функция должна быть командой или запросом, но не тем и другим сразу (Command Query Separation — Разделение запросов команд).
Лучше удалить из кода ошибки и исключения, чем оставить ошибки в коде.
Извлеките дублированный код в четко названные функции (Don’t Repeat Yourself).
Модульные тесты упрощают рефакторинг.
Глава 4: Комментарии
Комментарии могут быть неверными. Они могут быть неправильными с самого начала или могут быть изначально точными, а затем со временем устареть по мере изменения кода.
Используйте комментарии, чтобы описать, почему это написано так, как оно есть, а не объяснять, что происходит.
Комментариев часто можно избежать, используя четко названные переменные и извлекая разделы кода в четко названные функции.
Добавляйте к комментариям TODO единообразные префиксы, чтобы упростить их поиск. Периодически просматривайте и очищайте свои TODO-комментарии.
Не используйте Javadocs только ради их использования. Комментарии, описывающие, что делает метод, какие аргументы он принимает и что возвращает, в лучшем случае избыточны, а в худшем — вводят в заблуждение.
Комментарии должны включать всю соответствующую информацию и контекст, который понадобится читателю. Не ленитесь, когда пишете комментарий.
Комментарии журнала и комментарии автора файла не нужны из-за контроля версий и git blame.
Не комментируйте мертвый код. Просто удалите его. Если вы думаете, что код вам понадобится в будущем, то для этого и нужен контроль версий.
Глава 5: Форматирование
В команде выберите набор правил для форматирования кода, а затем последовательно применяйте эти правила. Неважно, с какими правилами вы согласны, вам нужно прийти к соглашению.
Используйте автоматическое форматирование кода и анализатор кода. Не полагайтесь на то, что люди вручную найдут и исправят каждую ошибку форматирования. Это неэффективно, непродуктивно и пустая трата времени при проверке кода.
Добавьте вертикальные пробелы между строками кода, чтобы визуально разделить связанные блоки кода. Все, что вам нужно — это сделать одну новую строку между группами.
Небольшие файлы легче читать, понимать и перемещать, чем крупные файлы.
Переменные следует объявлять рядом с тем, где они используются. Для небольших функций это обычно вверху функции.
Даже для коротких функций или операторов if все равно форматируйте их правильно, а не записывайте в одной строке.
Глава 6: Объекты и структуры данных
Детали реализации в объекте должны быть скрыты за интерфейсом объекта. Предоставляя интерфейс для использования потребителями объекта, вы упрощаете последующий рефакторинг деталей реализации, не вызывая критических изменений. Абстракции упрощают рефакторинг.
Любой данный фрагмент кода не должен знать о внутреннем устройстве объекта, с которым он работает.
При работе с объектом вы должны требовать от него выполнения команды или запроса, а не спрашивать его о его внутреннем устройстве.
Глава 7: Исправление ошибок
Обработка ошибок не должна мешать остальному коду в модуле.
Лучше удалить из кода ошибки и исключения, чем оставить ошибки в коде.
Напишите тесты с ошибками, чтобы убедиться, что ваш код идентифицирует их, а не пропускает.
Сообщения об ошибках должны быть информативными, со всем необходимым контекстом, который может понадобиться кому-то для эффективного устранения неполадок.
Обертывание сторонних API-интерфейсов тонким слоем абстракции упрощает замену одной библиотеки на другую в будущем.
Обертывание сторонних API-интерфейсов тонким слоем абстракции упрощает имитацию библиотеки во время тестирования.
Используйте шаблон Special Case или шаблон Null Object для обработки исключительного поведения, например, когда определенные данные не существуют.
Глава 8: Границы
Сторонние библиотеки помогают ускорить доставку продукта, позволяя передать на аутсорсинг различные задачи.
Напишите тесты, чтобы убедиться, что вы правильно используете стороннюю библиотеку.
Используйте шаблон адаптера, чтобы преодолеть разрыв между API сторонней библиотеки и API, который вы хотели бы иметь.
Обертывание сторонних API-интерфейсов тонким слоем абстракции упрощает замену одной библиотеки на другую в будущем. (Повторяется из главы 7)
Обертывание сторонних API-интерфейсов тонким слоем абстракции упрощает имитацию библиотеки во время тестирования. (Повторяется из главы 7)
Старайтесь не сообщать вашему приложению слишком много информации о деталях какой-либо сторонней библиотеки.
Лучше зависеть от того, что вы контролируете, чем от того, что вы не контролируете.
Глава 9: Модульные тесты
Тестовый код должен быть таким же чистым, как и производственный код (за некоторыми исключениями, обычно связанными с памятью или эффективностью).
По мере изменения производственного кода изменяется и тестовый код.
Тесты помогают сохранить ваш производственный код гибким и поддерживаемым.
Тесты позволяют вносить изменения, позволяя вам уверенно выполнять рефакторинг, не опасаясь, что вы сами этого не заметите.
Структурируйте свои тесты с помощью шаблона Arrange-Act-Assert (также известного как Build-Operate-Check, Setup-Exercise-Verify или Given-When-Then).
Используйте зависящие от предметной области функции, чтобы упростить написание и чтение тестов.
Оцените одну концепцию за тест.
Тесты должны быть быстрыми.
Тесты должны быть независимыми.
Тесты должны быть повторяемыми.
Тесты не должны требовать подтверждений.
Тесты должны быть написаны своевременно, незадолго до или после написания производственного кода, а не через несколько месяцев.
Если ваши тесты будут неправильными, ожидайте, что в вашем коде будут ошибки.
Глава 10: Классы
Классы должны быть небольшими.
Классы должны отвечать только за одну вещь и должны иметь только одну причину для изменения (принцип единой ответственности).
Если вы не можете придумать четкое название для класса, вероятно, он слишком велик.
Ваша работа не заканчивается на том, что вы заставите часть кода работать. Следующим шагом станет рефакторинг и очистка кода.
Использование множества небольших классов вместо нескольких больших классов в вашем приложении сокращает объем информации, которую разработчик должен понимать при работе над любой заданной задачей.
Наличие хорошего набора тестов позволяет с уверенностью выполнять рефакторинг, когда вы разбиваете большие классы на более мелкие.
Классы должны быть открыты для расширения, но закрыты для модификации (принцип открытости-закрытости).
Интерфейсы и абстрактные классы создают стыки (seams), которые упрощают тестирование.
Глава 11: Системы
Используйте внедрение зависимостей, чтобы дать разработчикам гибкость для передачи любого объекта с соответствующим интерфейсом в другой класс.
Используйте внедрение зависимостей для создания стыков объектов в приложении, чтобы упростить тестирование.
Программные системы не похожи на здание, которое нужно проектировать заранее. Они больше похожи на города, которые со временем растут и расширяются, адаптируясь к текущим потребностям.
Отложите принятие решения до последнего ответственного момента.
Используйте предметно-ориентированный язык, чтобы эксперты и разработчики в предметной области использовали одну и ту же терминологию.
Не усложняйте свою систему слишком сильно. Используйте самое простое, что работает.
Глава 12: Развертывание
Системы, которые нельзя тестировать, нельзя проверить, а системы, которые нельзя проверить, никогда не следует развертывать.
Написание тестов приводит к лучшему дизайну, потому что код, который легко тестировать, часто использует внедрение зависимостей, интерфейсы и абстракцию.
Хороший набор тестов избавит вас от страха сломать приложение во время рефакторинга.
Дублирование кода создает больший риск, поскольку в коде есть больше мест, которые можно изменить, и еще больше мест, где ошибки могут быть скрыты.
Код, который вы пишете сейчас, легче понять, потому что вы глубоко вовлечены в его понимание. Другим непросто быстро достичь такого же уровня понимания.
Большая часть стоимости программного проекта связана с долгосрочным обслуживанием.
Тесты служат живой документацией того, как ваше приложение должно (и ведет себя) вести себя.
Не двигайтесь дальше, как только ваш код заработает. Найдите время, чтобы сделать его более понятным и понятным.
Следующим, кто прочитает ваш код в ближайшем будущем, скорее всего, будете вы. Будьте добры к себе в будущем, написав простой для понимания код.
Сопротивляйтесь догмам. Примите прагматизм.
Чтобы стать действительно хорошим специалистом в области разработки программного обеспечения, требуются десятилетия. Вы можете ускорить процесс обучения, изучая опыт окружающих вас экспертов и изучая часто используемые шаблоны проектирования.
Глава 13: Параллелизм
Писать параллельный код сложно.
Случайные ошибки и проблемы, которые трудно воспроизвести, часто являются проблемами параллелизма.
Тестирование не гарантирует отсутствие ошибок в вашем приложении, но минимизирует риск.
Узнайте об общих проблемах параллелизма и их возможных решениях.
Глава 14: Последовательное уточнение
Чистый код обычно не начинается с чистого листа. Сначала вы пишете черновое решение, а затем реорганизуете его, чтобы сделать его более чистым.
Ошибочно прекращать работу над кодом, когда он “заработал”. Найдите время, чтобы сделать его еще лучше после того, как он уже работает.
Беспорядки нарастают постепенно.
Если вы оказались в затруднительном положении, когда добавление функций слишком сложно или занимает слишком много времени, прекратите писать функции и начните рефакторинг.
Постепенные изменения часто лучше, чем восстановление с нуля.
Используйте разработку через тестирование (Test-Driven Development — TDD), чтобы внести большое количество очень мелких изменений.
Хороший дизайн программного обеспечения предполагает разделение проблем в вашем коде и разделение кода на более мелкие модули, классы и файлы.
Легче убрать беспорядок сразу после того, как вы его создали, чем убирать позже.
Глава 15: Внутреннее устройство JUnit
Отрицательные имена переменных или условные выражения немного труднее понять, чем положительные.
Рефакторинг — это итеративный процесс, полный проб и ошибок.
Оставьте кодовую базу в лучшем виде, чем когда вы ее нашли (Правило бойскаута). (Повторяется из главы 1)
Глава 16: Рефакторинг SerialDate
Проверки кода и критика нашего кода делают нас лучше, и мы должны приветствовать это.
Сначала заставьте код работать, затем исправьте.
Не каждую строчку кода требуется тестирование.
Глава 17: Запахи и эвристика
Чистый код — это не набор правил, а скорее система ценностей, определяющих качество вашей работы.
[В этой главе дядя Боб перечисляет еще 66 вариантов своего кода и эвристик, многие из которых были рассмотрены в оставшейся части книги. Воспроизведение их здесь, по сути, было бы копированием и вставкой названия каждого элемента, поэтому я воздержался от этого. Вместо этого я бы посоветовал вам прочитать книгу!]
tl; dr: The Clean Coder by Robert Martin
I just finished reading The Clean Coder: A Code of Conduct for Professional Programmers by Robert C. Martin. Incredible book, brand-spanking new coder, ten out of ten. I recommend it to everyone who writes code on a daily basis.
I decided to make some notes that combine advice from the book with some of my own experience in data science and machine learning. I tried to write these notes in an actionable form so it will be easy to make habits from them.
Let’s look at each in detail.
Professionalism
The thin red line of the book is answering the question, “What does it mean to be a software developer professional?”. Think about it for a second yourself. Could you call yourself a professional? Why? If not, what differentiates you from being a professional?
Take responsibility
My father always told me, “Work as if you own it.” Would you write crappy code, do the minimum work to meet requirements, or produce shallow analysis if the company was your own? Probably not. Make a moral obligation to take responsibility for your actions.
It’s a lot easier to be nonprofessional. Non-professionals don’t have to take responsibility for the job they do.
How could we take responsibility? Robert Martin makes several points:
Be responsible for your career
It’s not your employer’s responsibility to make sure that you are marketable. Work on your career.
Test-Driven Development
Test-driven development (TDD) is a software development process in which a coder repeats small cycles of work: write tests for a function, write the function, make the function pass the tests. There are multiple benefits of this approach; below are just a few:
Use TDD when you are going to re-use code
It’s not that obvious if data scientists should use TDD or not. There are multiple arguments against using TDD for data science and machine learning tasks:
Make your own decision to use TDD or not.
I made a simple rule for myself: If I’m planning to use the piece of code more than once, I’ll write tests first. For tasks when you need to iterate quickly, use eye-ball tests (e.g., check the sanity of the output yourself by printing the output or plotting). If we are talking about production, all code must be tested.
Saying No and Saying Yes
Don’t be afraid to say “No”
— We really love the logo you’ve created for us! But our management has some brilliant ideas…
Management doesn’t have a deep understanding of your field that you do (that’s why they hired you). They often don’t understand how much time a task could take or if it even makes sense to invest resources in some tasks. Your management is counting on you to defend your objectives and not just agree with everything that they say. Be assertive. Both you and your manager need to get to the best possible outcome through negotiation. I’m not saying you should always say “No”, but keep in mind that professionals are expected to disagree.
Define “Done”
It is crucial to understand what you are expected to do, especially in data science, where score improvements might take additional weeks of work. Management expectations might differ from your plan, so to avoid frustration, discuss and define what is meant by “Done”. If you are not sure when you may say “It’s done”, decompose the task into several smaller ones of which you are sure.
Show commitment by giving a time estimate
“I’ll try to do it by the end of next week” — how does that sound to you? The meaning of this phrase might vary from “It would be nice to have; I will do it if I have time” to “This will be done by next week” depending on the person saying it. In some cases, such a phrase might be treated as a commitment to do the task, which might result in a false promise. Be crystal clear about your commitments, give and don’t be afraid to ask for time estimates.
You actually do it
From time to time, you will be hindered by other people or unable to complete the task due to unexpected reasons. That’s fine. Do as much as you can and be professional. If you can’t finish the project in time, notify stakeholders about it as soon as possible.
Time Estimates
“It will take five working days to do the task” — what do you mean by that? Do you mean:
I think it might take five days. Maybe four, maybe six. Maybe even ten. But my final guess is five days.
or do you actually mean something closer to:
I’m committed to making it work in five days or less no matter how much it would cost me. I will work additional time; no family, no friends. Five days, no more.
Provide time estimates, not guesses
Businesses see time estimates as commitments, while developers tend to think of estimates as guesses. Real software developer professionals make commitments and try to achieve them. The problem is that in reality, we don’t know how much time the task will take, thus we need estimates. And people tend to be terrible estimators. However, there are a couple of ways that can help to improve our estimates.
Decompose big task into several small tasks
Imagine you are planning your budget for a vacation in the Bahamas. How much do you need? 1k, 3k, 10k? Could you know for sure?
You may not be perfectly certain, but you can still give a reasonable estimate. All you have to do is to get a price for tickets to the place and back; how much you are planning to spend on food, entertainment, and gifts; and so on and so forth and then sum it up. These estimates are not that hard, are they? The same goes for time planning.
By decomposing the big task into several small ones, you are killing two birds with one stone. First, this breakdown is better for understanding the needed components and the whole architecture of the task. Second, it improves the accuracy of the estimate: it’s much easier to estimate the time needed for a small task than for a big one.
Use PERT methodology
To improve the accuracy of your estimations, start thinking of time estimation not being a single number, but several cases:
● O: Optimistic — the task is done this quickly if absolutely everything goes right.
● N: Normal — this estimate has the greatest chance of success (most probable time). Not everything will be perfect; some errors and blocks will occur.
● P: Pessimistic — everything goes wrong. Worst possible scenario, but still a probable one.
Given these estimations, and assuming the time that is needed for a task can be described with a beta distribution, you may calculate:
Time which is needed for a sequence of tasks with expected duration m_i and standard deviation sigma_i calculated as:
Ask your teammates to estimate the required time
In 1906, Francis Galton, the English statistician, was attending a county fair in Plymouth, a port city located on the south coast of Devon. He came across a weight-guessing lottery wherein participants were asked to guess the weight of the butcher ax. The person that produced the closest guess would win a prize. Galton asked the lottery organizer to write down participants’ guesses.
Based on the notes, Galton found that an average of 800 guesses was within just 500 grams of the actual ax weight, which was far closer than the guess of the winner. This has contributed to the insight in cognitive science that a crowd’s individual judgments can be modeled as a probability distribution of responses, with the median centered near the true value of the quantity to be estimated (see more examples of crowd wisdom in The Wisdom of Crowds).
The simplest and fastest way to get a more accurate estimate of the time required for a task is to independently ask your teammates and then average their answers. You don’t need to ask 800 people as in the ax weight lottery to get a robust prediction. Even with the help of a couple of colleagues, the final estimation would have a much lower variance and thus the estimation would be more accurate (the error of an estimation consists of bias, variance, and noise; reduce one of them and you will get a better prediction).
To improve the prediction even further, you could do the following:
This approach is similar to gradient boosting. In theory, it reduces the bias of the estimation. More information on bias-variance tradeoff, blending, and boosting can be found in An Introduction to Statistical Learning (chapters 2 and 8).
Meetings
The working day is too short, the amount of deep work you could devote to coding even shorter.
Don’t attend every meeting to which you are invited
It is your job to manage your time, not the person who invited you. Sometimes, it’s better to have a short, face-to-face discussion and skip a long meeting.
Provide a clear agenda and set of goals to achieve
This is a simple yet highly effective strategy to improve the efficiency of meetings. Are you going to solve something during the meeting or is it just a random discussion? Write down what points need to be discussed and what decisions should be made. Make it actionable.
Make notes during the meeting
Do you remember what was at the meeting two months ago? Me neither. I don’t know if anyone could. Maybe someone could, but they most likely are counting cards in Vegas.
Take notes yourself or ask someone to take notes during the meeting. Write the most important statements, agreed-upon points, and tasks. Publicly share your notes in Confluence or Google Docs so the people who skipped the meeting can still be updated.
Working as a Team
Do pair programming sessions
Pair programming is a session when two or more (preferably two) people work together on a single task. Usually, one person is writing the code and another talking through the problem and observing the issues, such as syntax, logic, or code style. There are multiple benefits of pair programming:
Start using Pomodoro
I started using the Pomodoro technique about six months ago and I noticed that it became easier to focus on the problem and track daily results (daily standups also help). Besides, it is healthier to break your working sessions into intervals so that you can get up from the computer and warm up.
Clean Code – Robert C. Martin’s Way
Writing good code in accordance with all the best practices is often overrated. But is it really? Writing good and clean code is just like good habits which will come with time and practice.
We always give excuses to continue with our patent non-efficient bad code. Reasons like no time for best practices, meeting the deadlines, angry boss, tired of the project etc. Most of the time we try to procrastinate it by saying will make it efficient and clean later but that time never comes.
Bad code is not problematic for us to understand but for the other developers who will handle that after us.
So, let me get you to the points by Robert C. Martin in his captivating book Clean Code.
Meaningful Names
We name our variables, class, directories, packages, jar files, war files, ear files. We name, we name and we name. So, we should better name them well.
Choosing good names takes time but saves more than it takes. Everyone who reads your code (including you) will be happier if you do.
So while naming anything, we should be able to answer these three questions:
why it exists?
what it does?
how it is used?
And if we can’t answer them, that means we are not doing it right.
If a name requires a comment, then the name doesn’t reveal its intent. Say for example:
int d; // elapsed time In days
So just by looking at this “d“, no one is going to understand what this d is doing and eventually waste time over it. Our names should be such that says its intention.
like, int elapsedTimeInDays;
Avoid Disinformation
Programmers must avoid leaving false clues that obscure the meaning of the code. We shouldn’t use type information in names.
Do not refer to a grouping of accounts as an accountList unless it’s actually a List. The word list means something specific to programmers. If the container holding the accounts is not actually a List, it may lead to false conclusions. So, accountGroup or bunchOfAccounts or just plain accounts would be better.
> Don’t be afraid to make a name long. A long descriptive name is better than a short enigmatic name.
> A long descriptive name is better than a long descriptive comment.
Just have a look at this snippet. Having a hard time to tell what is it doing? I too have few questions:
So a refactored better version of the above snippet could be something like this:
Now, things get clear.
Functions
The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that. The smaller and more focused a function is, the easier it is to choose a descriptive name. According to Martin, your functions should be as small as possible, maximum length should be less than 20 lines. If it exceeds this limit, you should better segregate the logic into different smaller functions.
Talking about the arguments, the number of arguments should be as minimum as possible. The ideal number of arguments for a function is zero. Such function doesn’t depend on any input so there’s always going to be some trivial output from it. It will be easy to test.
Next comes one (monadic) which is based on functional programming rules, followed closely by two (dyadic). Three arguments (triadic) should be avoided wherever possible. More than three (polyadic) requires very special justification and then shouldn’t be used anyway.
If any in case the number of arguments are more than 3, then we should group them into a meaningful object.
Arguments are even harder from a testing point of view. Imagine the difficulty of writing all the test cases to ensure that all the various combinations of arguments work properly.
Avoid output arguments: Anything that gets modified or mutated but is not returned by the function. An array passed to a function, which changes the body of the array but not returning it, then it is the output argument.
Side Effects are lies!
If the name of the function doesn’t tell the developer about all the functionalities implemented by it. Then these hidden functionalities are called side effects.
Your function promises to do one thing, but it also does other hidden things. Sometimes it will make unexpected changes to the variables of its own class. Sometimes it will make them to the parameters passed into the function or to system glo bals. In either case, they are devious and damaging mistruths that often result in strange temporal couplings and order dependencies.
See this example:
So, as you can see that the intent of this function (as its name says) is to just check the password. But it is initializing the session too. This could be misleading because whosoever calls this function, be it you, in fact, will not aware of this hidden functionality and might cause blunder in your code.
Do one thing!
Your function should do only one thing. If it does two or more, better break them into different functionalities. Keep it Simple Silly!
Example,
This function is doing two things first it checks the password and then initializing the session. The better way could have been checkPassword and initializeSession would be two separate functions and caller would just call them accordingly.
Data structures and Objects
Objects hide their data behind abstractions and expose functions that operate on that data. Data structure expose their data and have no meaningful functions.
They are virtual opposites.
In case of objects, it is easy to add new objects but harder to add new behavior. Let’s understand this through an example:
As you can see that if I want to add a new type of shape, say for example Rhombus, I can simply add its class extending Shape trait and provide the implementation for the area method. That’s all I need to do. But its hard to add new behavior. Why? If suppose I need to a new method say volume. Then all the subclasses extending this trait need to change.
Now consider data structures example:
Here I have created a separate class Geometry containing method area(). In this, if I need to add new behavior say volume, then I can easily add that without making any trouble and provide implementations for the different shapes. But in case I need to add new shape (new object) I need to add its implementation in all the methods of the Geometry class.
Procedural code (code using data structures) makes it easy to add new functions without changing the existing data structures. OO code, on the other hand, makes it easy to add new classes without changing existing functions.
In any complex system, there are going to be times when we want to add new data types rather than new functions. For these cases, objects and OO are most appropriate. On the other hand, there will also be times when we’ll want to add new functions as opposed to data types. In that case, procedural code and data structures will be more appropriate.
The Law of Demeter
It says our function should only access the classes/objects that it has direct access to which are:
i. Objects in class parameter
ii. An object in function parameter
iii. An object in class members
iv. Objects created inside the function body.
In short, the Law of Demeter aims to keep you from doing things like this:
or even worse, this:
Error Handling
It might seem odd to have a section about error handling in a book about clean code. Error handling is just one of those things that we all have to do when we program. Input can be abnormal and devices can fail. In short, things can go wrong, and when they do, we as programmers are responsible for making sure that our code does what it needs to do.
“Error handling is important, but if it obscures logic, it’s wrong. ”
Few tips to keep in mind while doing error handling in your code:
So these were just a few topics from the book Clean Code. This book has everything you are looking for. So, go give it a read.
For more topics from this book, you can refer to this blog.
I hope this blog helped you! 🙂
Robert martin clean code
© Prentice Hall, Inc.
© Перевод на русский язык ООО Издательство «Питер», 2018
© Издание на русском языке, оформление ООО Издательство «Питер», 2019
Посвящается Анне-Марии — бессмертной любви всей моей жизни
В Дании очень популярны леденцы Ga-Jol. Их сильный лакричный вкус отлично скрашивает нашу сырую и часто холодную погоду. Однако нас, датчан, леденцы Ga-Jol привлекают еще и мудрыми или остроумными высказываниями, напечатанными на крышке каждой коробки. Сегодня утром я купил две коробки леденцов и обнаружил на них старую датскую поговорку:
Ærlighed i små ting er ikke nogen lille ting.
«Честность в мелочах — вовсе не мелочь». Это было хорошим предзнаменованием, которое полностью соответствовало тому, о чем я собирался написать в предисловии. Мелочи важны. Эта книга посвящена вещам простым, но вовсе не малозначительным.
Бог скрывается в мелочах, сказал архитектор Людвиг Мис ван дер Роэ. Эта цитата напоминает о недавних дебатах о роли архитектуры в разработке программного обеспечения и особенно в мире гибких методологий. Мы с Бобом время от времени увлеченно вступаем в этот диалог. Да, Мис ван дер Роэ проявлял внимание и к удобству, и к неподвластным времени строительным формам, лежащим в основе великой архитектуры. С другой стороны, он также лично выбирал каждую дверную ручку для каждого спроектированного им дома. Почему? Да потому, что мелочи важны.
В наших с Бобом непрестанных «дебатах» о TDD выяснилось, что мы согласны с тем, что архитектура играет важную роль при разработке, хотя мы по-разному смотрим на то, какой смысл вкладывается в это утверждение. Впрочем, эти разногласия относительно несущественны, так как мы считаем само собой разумеющимся, что ответственные профессионалы выделяют некоторое время на обдумывание и планирование проекта. Появившиеся в конце 1990-х концепции проектирования, зависящего только от тестов и кода, давно прошли. Тем не менее внимание к мелочам является еще более важным аспектом профессионализма, чем любые грандиозные планы. Во-первых, благодаря практике в мелочах профессионалы приобретают квалификацию и репутацию для серьезных проектов. Во-вторых, даже мельчайшее проявление небрежности при строительстве — дверь, которая неплотно закрывается, или криво положенная плитка на полу, или даже захламленный стол — полностью рассеивает очарование всего сооружения. Чтобы этого не происходило с вашими программами, код должен быть чистым.
Впрочем, архитектура — всего лишь одна из метафор для разработки программных продуктов. Она лучше всего подходит для проектов, в которых продукт «возводится» в том же смысле, в каком архитектор возводит строение. В эпоху Scrum и гибких методологий основное внимание уделяется быстрому выводу продукта на рынок. Фабрики, производящие программные продукты, должны работать на максимальной скорости. Однако этими «фабриками» являются живые люди: мыслящие, чувствующие программисты, работающие над пожеланиями пользователей или историей продукта для создания новых продуктов. Метафора производства сейчас как никогда сильна в их мировоззрениях. Скажем, методология Scrum во многом вдохновлена производственными аспектами японского автостроения с его конвейерами.
Но даже в автостроении основная часть работы связана не с производством, а с сопровождением продуктов — или его отсутствием. В программировании 80% и более того, что мы делаем, тоже изящно называется «сопровождением». На самом деле речь идет о починке. Наша работа ближе к работе домашних мастеров в строительной отрасли или автомехаников в области автостроения. Что японская теория управления говорит по этому поводу?
В 1951 году в японской промышленности появилась методология повышения качества, называвшаяся TPM (Total Productive Maintenance). Она была ориентирована прежде всего на сопровождение, а не на производство. Доктрина TPM базировалась на так называемых «принципах 5S». В сущности, принципы 5S представляют собой набор житейских правил. Кстати говоря, они также заложены в основу методологии Lean — другого модного течения на западной сцене, набирающего обороты и в программных кругах. Как указывает Дядюшка Боб в своем введении, хорошая практика программирования требует таких качеств, как сосредоточенность, присутствие духа и мышление. Проблемы не всегда решаются простым действием, максимальной загрузкой оборудования для производства в оптимальном темпе. Философия 5S состоит из следующих концепций:
robertkuhar/cleancode
Use Git or checkout with SVN using the web URL.
Work fast with our official CLI. Learn more.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
WingDing studies «Clean Code. A Handbook of Agile Software Craftsmanship» by Robert Martin
Date | Chapter | Moderator |
---|---|---|
Mar 25 | Ch01: Clean Code (16 pages) | George Smith |
Mar 25 | Ch02: Meaningful Names (14 pages) | George Smith |
Apr 08 | spring break | |
Apr 29 | Ch03: Functions (22 pages) | George Smith |
May 13 | Ch04: Comments (22 pages) | Doug |
May 13 | Ch05: Formatting (18 pages) | Doug |
May 27 | Ch06: Data Structures (10 pages) | Stan |
May 27 | Ch07: Error Handling (10 pages) | Stan |
Jun 10 | Ch08: Boundaries (8 pages) | Bob |
Jun 10 | Ch09: Unit Tests (14 pages) | Linus |
Jun 10 | Ch10: Classes (18 pages) | Linus |
Jun 24 | summer break | |
Jul 08 | summer break | |
Jul 22 | summer break | |
Aug 12 | Ch11: Systems (18 pages) | Bob |
Aug 12 | Ch12: Emergence (6 pages) | Bob |
Aug 26 | Ch13: Concurrency (16 pages) | Stewart |
Aug 26 | Ch14: Successive Refinement (58 pages) | Stewart |
Sep 09 | Ch15: JUnit Internals (16 pages) | Piotr |
Sep 09 | Ch16: Refactoring SerialDate (18 pages) | Piotr |
Sep 23 | Ch17: Smells and Heuristics (32 pages) | Bob |
Oct 14 | ApxA: Concurrency II. 317 (32 pages) | Joe Bowbeer |
?? | ApxB: SerialDate. 349 (60 pages) |
About
WingDing studies «Clean Code. A Handbook of Agile Software Craftsmanship» by Robert Martin
Книга «Чистая архитектура. Искусство разработки программного обеспечения»
«Идеальный программист» и «Чистый код» — легендарные бестселлеры Роберта Мартина — рассказывают, как достичь высот профессионализма. «Чистая архитектура» продолжает эту тему, но не предлагает несколько вариантов в стиле «решай сам», а объясняет, что именно следует делать, по какой причине и почему именно такое решение станет принципиально важным для вашего успеха.
Роберт Мартин дает прямые и лаконичные ответы на ключевые вопросы архитектуры и дизайна. «Чистую архитектуру» обязаны прочитать разработчики всех уровней, системные аналитики, архитекторы и каждый программист, который желает подняться по карьерной лестнице или хотя бы повлиять на людей, которые занимаются данной работой. Все архитектуры подчиняются одним и тем же правилам! Роберт Мартин (дядюшка Боб)
Тест на профпригодность
Почему так много программного обеспечения превращается в микропрограммы? Похоже, что основная причина заключается в стремлении получить действующий встраиваемый код и практически не уделяется внимания его структурированию для увеличения срока службы. Кент Бек описывает три шага в создании программного обеспечения (далее в кавычках приводятся слова Кента, а курсивом выделены мои комментарии):
Встраиваемое программное обеспечение ничем не отличается в отношении этих проблем. Многие невстраиваемые приложения доводятся только до стадии «работает», и мало что делается, чтобы код получился правильным и служил долго.
Получение работающего приложения — это то, что я называю тестом на профпригодность для программиста. Программист, разрабатывающий программное обеспечение, встраиваемое или нет, который заботится только о том, чтобы получить работающее приложение, наносит вред своим продуктам и работодателю. Программирование — это нечто большее, чем умение писать работающие приложения.
В качестве примера взгляните на следующие функции, находящиеся в одном файле маленькой встраиваемой системы, написанные в ходе прохождения теста на профпригодность:
В таком порядке функции были объявлены в файле с исходным кодом. А теперь разделим их и сгруппируем по решаемым задачам:
функции, реализующие предметную логику:
• float calc_RPM(void) <… >
• void Do_Average(void) <… >
• void Get_Next_Measurement(void) <… >
• void Zero_Sensor_1(void) <… >
• void Zero_Sensor_2(void)
функции, обслуживающие аппаратную платформу:
• ISR(TIMER1_vect) <… >*
• ISR(INT2_vect) <… >
• void uC_Sleep(void) <… >
функции, реагирующие на нажатия кнопок:
• void btn_Handler(void) <… >
• void Dev_Control(char Activation) <… >
функция, читающая данные из аппаратного аналогово-цифрового преобразователя:
• static char Read_RawData(void) <… >
функции, записывающие значения в долговременное хранилище:
• char Load_FLASH_Setup(void) <… >
• void Save_FLASH_Setup(void) <… >
• void Store_DataSet(void) <… >
• float bytes2float(char bytes[4]) <… >
• void Recall_DataSet(void) <… >
функция, которая не делает того, что подразумевает ее имя:
Заглянув в другие файлы этого приложения, я нашел множество препятствий, мешающих пониманию кода. Также я обнаружил, что организация файлов подразумевает единственный способ тестирования этого кода — непосредственно внутри целевого устройства. Практически каждый бит этого кода знает, что относится к специализированной микропроцессорной архитектуре, используя «расширенные» конструкции языка C1, привязывающие код к конкретному набору инструментов и микропроцессору. У этого кода нет ни малейшего шанса служить долго, если будет решено перенести продукт на другую аппаратную платформу.
Приложение работает: инженер прошел тест на профпригодность. Но нельзя сказать, что оно имеет чистую встраиваемую архитектуру.
Привязка к оборудованию — узкое место
Существует масса особых проблем, с которыми приходится сталкиваться разработчикам встраиваемых систем и не знакомых разработчикам обычного программного обеспечения. Например, ограниченный объем памяти, ограничения по времени выполнения операций, ограниченные возможности ввода/вывода, нетрадиционные пользовательские интерфейсы, а также наличие датчиков и контактов, соединяющих с внешним миром. В большинстве случаев аппаратное обеспечение развивается параллельно с программным обеспечением и микропрограммами. У вас, как инженера, разрабатывающего код для такого рода систем, может не быть места для запуска кода. Но это еще не самое худшее — полученное оборудование может иметь собственные недостатки, что замедляет разработку программного обеспечения больше, чем обычно.
Да, встраиваемое программное обеспечение имеет свои особенности, и инженеры встраиваемых систем — особые люди. Но разработка встраиваемых систем не настолько особенная, чтобы принципы, описываемые в этой книге, нельзя было применить к встраиваемым системам.
Одна из особых проблем встраиваемых систем — тесная зависимость от оборудования. Когда встраиваемый код структурируется без применения принципов и приемов чистой архитектуры, часто приходится сталкиваться со сценарием, когда код можно протестировать только на целевом оборудовании. Если это оборудование — единственное место, где возможно тестирование, такая тесная связь начинает замедлять вас.
Чистая встраиваемая архитектура — архитектура, поддерживающая тестирование
Давайте посмотрим, как применяются некоторые архитектурные принципы к встраиваемому программному обеспечению и микропрограммам и как они помогают избавиться от тесной привязки к оборудованию.
Деление на уровни можно произвести разными способами. Начнем с трехуровневой организации, изображенной на рис. 29.1. Внизу находится уровень оборудования. Как предупреждает Дуг, вследствие совершенствования технологий и согласно закону Мура оборудование будет изменяться. Одни компоненты устаревают, и на смену им приходят новые компоненты, потребляющие меньше электроэнергии, или имеющие более высокую производительность, или стоящие дешевле. Независимо от причин я, как инженер встраиваемых систем, не хотел бы делать больше, чем необходимо, когда неизбежное изменение оборудования наконец произойдет.
Раздел между оборудованием и остальной частью системы — объективная реальность, по крайней мере после определения оборудования (рис. 29.2). Именно здесь часто возникают проблемы при попытке пройти тест на профпригодность. Ничто не мешает знаниям об оборудовании инфицировать весь код. Если не проявить осторожность при структурировании кода и не ограничить просачивание сведений об одном модуле в другой, код будет трудно изменить. Я говорю не только о случае, когда изменяется оборудование, но также о ситуации, когда понадобится исправить ошибку или внести изменение по требованию пользователя.
Смешивание программного обеспечения и микропрограмм — это антишаблон. Код, демонстрирующий этот антишаблон, будет сопротивляться изменениям. Кроме того, изменения сопряжены с опасностями, часто ведущими к непредвиденным последствиям. Даже незначительные изменения требуют полного регрессионного тестирования системы. Если вы не создали тесты с внешним оборудованием, готовьтесь проводить тестирование вручную, а затем ожидать новых сообщений об обнаруженных ошибках.
Оборудование — это деталь
Линия между программным обеспечением и микропрограммами обычно видна не так четко, как линия, разделяющая код и оборудование (рис. 29.3).
Одна из задач разработчика встраиваемого программного обеспечения — укрепить эту линию. Границу между программным обеспечением и микропрограммой (рис. 29.4) называют слоем аппаратных абстракций (Hardware Abstraction Layer; HAL). Это не новая идея: она была реализована в персональных компьютерах еще в эпоху до Windows.
Слой HAL существует для программного обеспечения над ним, и его API должен приспосабливаться под потребности этого программного обеспечения. Например, микропрограмма может хранить байты и массивы байтов во флеш-памяти, а приложению требуется хранить и читать пары имя/значение с использованием некоторого механизма хранения. Программное обеспечение не должно заботиться о деталях хранения пар имя/значение во флеш-памяти, на вращающемся диске, в облаке или в основной памяти. Слой аппаратных абстракций (HAL) предоставляет услугу и не раскрывает программному обеспечению, как она работает. Реализация поддержки флеш-памяти — это деталь, которая должна быть скрыта от программного обеспечения.
Еще один пример: управление светодиодом привязано к биту GPIO. Микропрограмма может предоставлять доступ к битам GPIO, а слой HAL может иметь функцию Led_TurnOn(5). Это довольно низкоуровневый слой аппаратной абстракции. Давайте посмотрим, как повысить уровень абстракции с точки зрения программного обеспечения/продукта. Какую информацию сообщает светодиод? Допустим, что включение светодиода сообщает о низком заряде аккумулятора. На некотором уровне микропрограмма (или пакет поддержки платформы) может предоставлять функцию Led_TurnOn(5), а слой HAL — функцию Indicate_LowBattery(). Таким способом слой HAL выражает назначение услуги для приложения. Кроме того, уровни могут содержать подуровни. Это больше напоминает повторяющийся фрактальный узор, чем ограниченный набор предопределенных уровней. Назначение ввода/выводов GPIO — это детали, которые должны быть скрыты от программного обеспечения.
Для Хаброжителей скидка 20% по купону — Чистая архитектура
Выдержки (цитаты) из книги Чистый код Роберта Мартина
Весь текст сохранен в виде вырезок из книги без каких либо изменений. Примеры коды мои собственные.
Расплата за хаос
Если вы занимались программированием более двух-трех лет, вам наверняка доводилось вязнуть в чужом — или в своем собственном — беспорядочном коде.
Замедление может быть весьма значительным. За какие-нибудь год-два группы, очень быстро двигавшиеся вперед в самом начале проекта, начинают ползти со скоростью улитки. Каждое изменение, вносимое в код, нарушает работу кода в двух-трех местах. Ни одно изменение не проходит тривиально. Для каждого дополнения или модификации системы необходимо «понимать» все хитросплетения кода — чтобы в программе их стало еще больше. Со временем неразбериха разрастается настолько, что справиться с ней уже не удается. Выхода просто нет.
По мере накопления хаоса в коде производительность группы начинает снижаться, асимптотически приближаясь к нулю. В ходе снижения производительности начальство делает единственное, что оно может сделать: подключает к проекту новых работников в надежде повысить производительность. Но новички ничего не понимают в архитектуре системы. Они не знают, какие изменения соответствуют намерениям проектировщика, а какие им противоречат. Более того, они — и все остальные участники группы — находятся под страшным давлением со стороны начальства. В спешке они работают все небрежнее, отчего производительность только продолжает падать.
Основной парадокс
Программисты сталкиваются с основным парадоксом базовых ценностей. Каждый разработчик, имеющий сколько-нибудь значительный опыт работы, знает, что предыдущий беспорядок замедляет его работу. Но при этом все разработчики под давлением творят беспорядок в своем коде для соблюдения графика. Короче, у них нет времени, чтобы работать быстро!
Настоящие профессионалы знают, что вторая половина этого парадокса неверна. Невозможно выдержать график, устроив беспорядок. На самом деле этот беспорядок сразу же замедлит вашу работу, и график будет сорван. Единственный способ выдержать график — и единственный способ работать быстро — заключается в том, чтобы постоянно поддерживать чистоту в коде.
ГРЭДИ БУЧ
Чистый код прост и прямолинеен. Чистый код читается, как хорошо написанная проза. Чистый код никогда не затемняет намерения проектировщика; он полон четких абстракций и простых линий передачи управления.
МАЙКЛ ФИЗЕРС
Чистый код всегда выглядит так, словно его автор над ним тщательно потрудился. Вы не найдете никаких очевидных возможностей для его улучшения. Все они уже были продуманы автором кода.
Правило бойскаута
Хорошо написать код недостаточно. Необходимо поддерживать чистоту кода с течением времени. Все мы видели, как код загнивает и деградирует с течением времени. Значит, мы должны активно поработать над тем, чтобы этого не произошло.
У бойскаутов существует простое правило, которое применимо и к нашей профессии:
Оставь место стоянки чище, чем оно было до твоего прихода
Содержательные имена
Имена должны передавать намерения программиста
Имя переменной, функции или класса должно отвечать на все главные вопросы. Оно должно сообщить, почему эта переменная (и т. д.) существует, что она делает и как используется. Если имя требует дополнительных комментариев, значит, оно не передает намерений программиста.
Избегайте дезинформации
Программисты должны избегать ложных ассоциаций, затемняющих смысл кода.
Не используйте слова со скрытыми значениями, отличными от предполагаемого
Используйте удобопроизносимые имена
Людям удобно работать со словами. Значительная часть нашего мозга специализируется на концепции слов, а слова по определению удобопроизносимы.
Было бы обидно не использовать ту изрядную часть мозга, которая развивалась для разговорной речи. Следовательно, имена должны нормально произноситься.
Выбирайте имена, удобные для поиска
У однобуквенных имен и числовых констант имеется один специфический недостаток: их трудно искать в большом объеме текста.
Избегайте схем кодирования имен
У нас и так хватает хлопот с кодированием, чтобы искать новые сложности. Кодирование информации о типе или области видимости в именах только создает новые хлопоты по расшифровке.
Венгерская запись
В доисторические времена, когда в языках действовали ограничения на длину имен, мы нарушали это правило по необходимости — и не без сожалений. В Fortran первая буква имени переменной обозначала код типа. В ранних версиях BASIC имена могли состоять только из одной буквы и одной цифры. Венгерская запись (HN, Hungarian Notation) подняла эту проблему на новый уровень. Венгерская запись играла важную роль во времена Windows C API, когда программы работали с целочисленными дескрипторами (handle), длинными указателями, указателями на void или различными реализациями «строк» (с разным применением и атрибутами). Компиляторы в те дни не поддерживали проверку типов, поэтому программистам были нужны «подсказки» для запоминания типов.
В современных языках существует куда более развитая система типов, а компиляторы запоминают типы и обеспечивают их соблюдение. Более того, появилась тенденция к использованию меньших классов и более коротких функций, чтобы программисты видели точку объявления каждой используемой переменной. Объекты обладают сильной типизацией, а рабочие среды развились до такой степени, что могут выявить ошибку типа еще до начала компиляции! Таким образом, в наши дни венгерская запись и другие формы кодирования типов в именах превратились в обычные пережитки прошлого. Они усложняют изменение имени или типа переменных, функций и классов. Они затрудняют чтение кода. Наконец, они повышают риск того, что система кодирования собьет с толку читателя кода.
Код должен быть как можно более выразительным. Слишком длинные выражения, венгерская запись, «волшебные числа» — все это скрывает намерения автора.
Имена методов
Имена методов представляют собой глаголы или глагольные словосочетания.
Выберите одно слово для каждой концепции
Если вы используете переменную ЗаказанноеКоличество обозначая количество товара в заказе, придерживайтесь этого названия во всем модуле. Если же будет в одной части кода переменная ЗаказанноеКоличество, в другом просто Количество, в дальше КЗаказу это будет вызывать не доумения и лишнюю трату временя на сопоставления этих названий.
Функции
Компактность!
Первое правило: функции должны быть компактными. Второе правило: функции должны быть еще компактнее.
Желательно, чтобы длина функции не превышала 20 строк.
Блоки и отступы
Из сказанного выше следует, что блоки в командах if, else, while и т. д. должны состоять из одной строки, в которой обычно содержится вызов функции. Это не только делает вмещающую функцию более компактной, но и способствует документированию кода, поскольку вызываемой в блоке функции можно присвоить удобное содержательное имя.
Правило одной операции
Функция должна выполнять только одну операцию. Она должна выполнять ее хорошо. И ничего другого она делать не должна.
Чтение кода сверху вниз: правило понижения
Код должен читаться как рассказ — сверху вниз.
За каждой функцией должны следовать функции следующего уровня абстракции. Это позволяет читать код, последовательно спускаясь по уровням абстракции в ходе чтения списка функций. Я называю такой подход «правилом понижения».
Сказанное можно сформулировать и иначе: программа должна читаться так, словно она является набором абзацев, каждый из которых описывает текущий уровень абстракции и ссылается на последующие абзацы следующего нижнего уровня.
Команды switch
Написать компактную команду switch довольно сложно. Даже команда switch всего с двумя условиями занимает больше места, чем в моем представлении должен занимать один блок или функция.
Аргументы функций
В идеальном случае количество аргументов функции равно нулю (нульарная функция). Далее следуют функции с одним аргументом (унарные) и с двумя аргументами (бинарные). Функций с тремя аргументами (тернарных) следует по возможности избегать. Необходимость функций с большим количеством аргументов (полиарных) должна быть подкреплена очень вескими доводами — и все равно такие функции лучше не использовать.
Аргументы-флаги
Аргументы-флаги уродливы. Передача логического значения функции — воистину ужасная привычка. Она немедленно усложняет сигнатуру метода, громко провозглашая, что функция выполняет более одной операции. При истинном значении флага выполняется одна операция, а при ложном — другая!
Чистый код, создание, анализ и рефакторинг, библиотека программиста, Мартин Р., 2010
К сожалению, на данный момент у нас невозможно бесплатно скачать полный вариант книги.
Но вы можете попробовать скачать полный вариант, купив у наших партнеров электронную книгу здесь, если она у них есть наличии в данный момент.
Также можно купить бумажную версию книги здесь.
Чистый код, создание, анализ и рефакторинг, библиотека программиста, Мартин Р., 2010.
Даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на ею поддержку и «укрощение». та книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший. Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги — концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
Да будет код.
Возможно, кто-то скажет, что книга о коде отстала от времени — код сейчас уже не так актуален; вместо него внимание следует направить на модели и требования. Нам даже доводилось слышать мнение, что код как таковой скоро перестанет существовать. Что скоро весь код будет генерироваться, а не писаться вручную. Что программисты станут попросту не нужны, потому что бизнесмены будут генерировать программы по спецификациям. Ерунда! Код никогда не исчезнет, потому что код представляет подробности требований. На определенном уровне эти подробности невозможно игнорировать или абстрагировать; их приходится определять. А когда требования определяются настолько подробно, чтобы они могли быть выполнены компьютером, это и есть программирование. А их определение есть код.
Содержание.
Предисловие.
Введение.
Глава 1. Чистый код.
Глава 2. Содержательные имена (Тим Оттингер).
Глава 3. Функции.
Глава 4. Комментарии.
Глава 5. Форматирование.
Глава 6. Объекты и структуры данных.
Глава 7. Обработка ошибок (Майк Физерс).
Глава 8. Границы (Джеймс Тренинг).
Глава 9. Модульные тесты
Глава 10. Классы (совместно с Джеффом Лангром).
Глава 11. Системы (Кевин Дин Уомплер).
Глава 12. Формирование архитектуры.
Глава 13. Многопоточность (Бретт Л. Шухерт).
Глава 14. Последовательное очищение.,
Глава 15. Внутреннее строение JUnit
Глава 16. Переработка SerialDate.
Глава 17. Запахи и эвристические правила.
Приложение А. Многопоточность II.
Приложение Б. org.jfree.date.SerialDate.
Приложение В. Перекрестные ссылки.
Эпилог.
Алфавитный указатель.
По кнопкам выше и ниже «Купить бумажную книгу» и по ссылке «Купить» можно купить эту книгу с доставкой по всей России и похожие книги по самой лучшей цене в бумажном виде на сайтах официальных интернет магазинов Лабиринт, Озон, Буквоед, Читай-город, Литрес, My-shop, Book24, Books.ru.
По кнопке «Найти похожие материалы на других сайтах» можно найти похожие материалы на других сайтах.
On the buttons above and below you can buy the book in official online stores Labirint, Ozon and others. Also you can search related and similar materials on other sites.
Robert martin clean code
© Издание на русском языке, оформление ООО Издательство «Питер», 2019
Посвящается Анне-Марии — бессмертной любви всей моей жизни
Предисловие
Ærlighed i små ting er ikke nogen lille ting.
«Честность в мелочах — вовсе не мелочь». Это было хорошим предзнаменованием, которое полностью соответствовало тому, о чем я собирался написать в предисловии. Мелочи важны. Эта книга посвящена вещам простым, но вовсе не малозначительным.
Бог скрывается в мелочах, сказал архитектор Людвиг Мис ван дер Роэ. Эта цитата напоминает о недавних дебатах о роли архитектуры в разработке программного обеспечения и особенно в мире гибких методологий. Мы с Бобом время от времени увлеченно вступаем в этот диалог. Да, Мис ван дер Роэ проявлял внимание и к удобству, и к неподвластным времени строительным формам, лежащим в основе великой архитектуры. С другой стороны, он также лично выбирал каждую дверную ручку для каждого спроектированного им дома. Почему? Да потому, что мелочи важны.
В наших с Бобом непрестанных «дебатах» о TDD выяснилось, что мы согласны с тем, что архитектура играет важную роль при разработке, хотя мы по-разному смотрим на то, какой смысл вкладывается в это утверждение. Впрочем, эти разногласия относительно несущественны, так как мы считаем само собой разумеющимся, что ответственные профессионалы выделяют некоторое время на обдумывание и планирование проекта. Появившиеся в конце 1990-х концепции проектирования, зависящего только от тестов и кода, давно прошли. Тем не менее внимание к мелочам является еще более важным аспектом профессионализма, чем любые грандиозные планы. Во-первых, благодаря практике в мелочах профессионалы приобретают квалификацию и репутацию для серьезных проектов. Во-вторых, даже мельчайшее проявление небрежности при строительстве — дверь, которая неплотно закрывается, или криво положенная плитка на полу, или даже захламленный стол — полностью рассеивает очарование всего сооружения. Чтобы этого не происходило с вашими программами, код должен быть чистым.
Впрочем, архитектура — всего лишь одна из метафор для разработки программных продуктов. Она лучше всего подходит для проектов, в которых продукт «возводится» в том же смысле, в каком архитектор возводит строение. В эпоху Scrum и гибких методологий основное внимание уделяется быстрому выводу продукта на рынок. Фабрики, производящие программные продукты, должны работать на максимальной скорости. Однако этими «фабриками» являются живые люди: мыслящие, чувствующие программисты, работающие над пожеланиями пользователей или историей продукта для создания новых продуктов. Метафора производства сейчас как никогда сильна в их мировоззрениях. Скажем, методология Scrum во многом вдохновлена производственными аспектами японского автостроения с его конвейерами.
Но даже в автостроении основная часть работы связана не с производством, а с сопровождением продуктов — или его отсутствием. В программировании 80% и более того, что мы делаем, тоже изящно называется «сопровождением». На самом деле речь идет о починке. Наша работа ближе к работе домашних мастеров в строительной отрасли или автомехаников в области автостроения. Что японская теория управления говорит по этому поводу?
В 1951 году в японской промышленности появилась методология повышения качества, называвшаяся TPM (Total Productive Maintenance). Она была ориентирована прежде всего на сопровождение, а не на производство. Доктрина TPM базировалась на так называемых «принципах 5S». В сущности, принципы 5S представляют собой набор житейских правил. Кстати говоря, они также заложены в основу методологии Lean — другого модного течения на западной сцене, набирающего обороты и в программных кругах. Как указывает Дядюшка Боб в своем введении, хорошая практика программирования требует таких качеств, как сосредоточенность, присутствие духа и мышление. Проблемы не всегда решаются простым действием, максимальной загрузкой оборудования для производства в оптимальном темпе. Философия 5S состоит из следующих концепций:
• Сэйри, или организация. Абсолютно необходимо знать, где что находится — и в этом помогают такие методы, как грамотный выбор имен. Думаете, выбор имен идентификаторов неважен? Почитайте следующие главы.
• Сэйтон, или аккуратность. Старая американская поговорка гласит: всему свое место, и все оказывается на своих местах. Фрагмент кода должен находиться там, где читатель кода ожидает его найти, — а если он находится где-то в другом месте, переработайте свой код и разместите его там, где ему положено быть.
• Сэйсо, или чистка. Рабочее место должно быть свободно от висящих проводов, грязи, мусора и хлама. Что в этой книге говорят авторы о загромождении кода комментариями и закомментированными строками кода? Они советуют от них избавиться.
• Сэйкэцу, или стандартизация: группа достигает согласия по поводу того, как поддерживать чистоту на рабочем месте. Что в этой книге сказано о наличии единого стиля кодирования и набора правил в группах? Откуда берутся эти стандарты? Прочитайте — узнаете.
• Сюцукэ, или дисциплина. Программист должен быть достаточно дисциплинированным, чтобы следовать правилам, он должен часто размышлять о своей работе и быть готовым к изменениям.
Если вы не пожалеете усилий — да, усилий! — чтобы прочитать и применять эту книгу, вы научитесь понимать последний пункт. Мы наконец-то подошли к корням ответственного профессионализма в профессии, которая должна пристально интересоваться жизненным циклом продукта. В ходе сопровождения автомобилей и других машин по правилам TPM, аварийный ремонт (аналог проявления ошибок) является исключением. Вместо этого мы ежедневно осматриваем машины и заменяем изнашивающиеся части до того, как они сломаются, или выполняем аналоги знаменитой «смены масла каждые 10 000 миль» для предотвращения износа. Безжалостно перерабатывайте свой код. А еще
Глава 17. Запахи и эвристические правила
В своей замечательной книге «Refactoring» [Refactporing] Мартин Фаулер описывает много различных «запахов кода». Следующий список содержит много «запахов», предложенных Мартином, а также ряд моих собственных дополнений. Кроме того, в него были включены некоторые приемы и эвристические правила, которые я часто применяю в своей работе.
Чтобы построить этот список, я просмотрел и переработал несколько разных программ. При внесении каждого изменения я спрашивал себя, почему я это делаю, и записывал результат. Так появился довольно длинный список того, что, на мой взгляд, «дурно пахнет» при чтении кода.
Предполагается, что вы будете читать список от начала к концу, а также использовать его как краткий справочник. Обратитесь к приложению В на с. 455, где собраны перекрестные ссылки, указывающие, где в тексте книги упоминалось то или иное эвристическое правило.
C1: Неуместная информация
В комментариях неуместно размещать информацию, которую удобнее хранить в других источниках: в системах управления исходным кодом, в системах контроля версий и в других системах протоколирования. Например, история изменений только загромождает исходные файлы длинным историческим и малоинтересным текстом. Метаданные (авторы, дата последней модификации и т.д.) в общем случае также неуместны в комментариях. Комментарии должны быть зарезервированы для технической информации о коде и его архитектуре.
C2: Устаревший комментарий
Комментарий, содержимое которого потеряло актуальность, считается устаревшим. Комментарии стареют довольно быстро. Не пишите комментарии, которые с течением времени устареют. Обнаружив устаревший комментарий, обновите его или избавьтесь от него как можно быстрее. Устаревшие комментарии часто «отрываются» от кода, который они когда-то описывали. Так в вашем коде появляются плавучие островки недостоверности и бесполезности.
C3: Избыточный комментарий
Избыточным считается комментарий, описывающий то, что и так очевидно. Например:
i++; // Увеличение переменной i
Или другой пример — комментарий Javadoc, который содержит не больше (а вернее, меньше) полезной информации, чем простая сигнатура функции:
public SellResponse beginSellItem(SellRequest sellRequest)
Комментарии должны говорить то, что не может сказать сам код.
C4: Плохо написанный комментарий
Если уж вы беретесь за написание комментария, напишите его хорошо. Не жалейте времени и позаботьтесь о том, чтобы это был лучший комментарий, который вы способны создать. Тщательно выбирайте слова. Следите за правильностью орфографии и пунктуации. Не пишите сумбурно. Не объясняйте очевидное. Будьте лаконичны.
C5: Закомментированный код
Фрагменты закомментированного кода выводят меня из себя. Кто знает, когда был написан этот код? Кто знает, есть от него какая-нибудь польза или нет? Однако никто не удаляет закомментированный код — все считают, что он понадобится кому-то другому.
Этот код только попусту занимает место, «загнивая» и утрачивая актуальность с каждым днем. В нем вызываются несуществующие функции. В нем используются переменные, имена которых давно изменились. В нем соблюдаются устаревшие конвенции. Он загрязняет модуль, в котором он содержится, и отвлекает людей, которые пытаются его читать. Закомментированный код отвратителен!
Увидев закомментированный код, удалите его! Не беспокойтесь, система управления исходным кодом его не забудет. Если кому-то этот код действительно понадобится, то он сможет вернуться к предыдущей версии. Не позволяйте закомментированному коду портить вам жизнь.
E1: Построение состоит из нескольких этапов
Построение проекта должно быть одной тривиальной операцией. Без выборки многочисленных фрагментов из системы управления исходным кодом. Без длинных серий невразумительных команд или контекстно-зависимых сценариев для построения отдельных элементов. Без поиска дополнительных файлов в формате JAR, XML и других артефактов, необходимых для вашей системы. Сначала вы проверяете систему одной простой командой, а потом вводите другую простую команду для ее построения.
svn get mySystem
E2: Тестирование состоит из нескольких этапов
Все модульные тесты должны выполняться всего одной командой. В лучшем случае все тесты запускаются одной кнопкой в IDE. В худшем случае одна простая команда вводится в командной строке. Запуск всех тестов — настолько важная и фундаментальная операция, что она должна быть быстрой, простой и очевидной.
F1: Слишком много аргументов
Функции должны иметь небольшое количество аргументов. Лучше всего, когда аргументов вообще нет; далее следуют функции с одним, двумя и тремя аргументами. Функции с четырьмя и более аргументами весьма сомнительны; старайтесь не использовать их в своих программах (см. «Аргументы функций» на с. 64).
F2: Выходные аргументы
Выходные аргументы противоестественны. Читатель кода ожидает, что аргументы используются для передачи входной, а не выходной информации. Если ваша функция должна изменять чье-либо состояние, пусть она изменяет состояние объекта, для которого она вызывалась (см. «Выходные аргументы», с. 70).
F3: Флаги в аргументах
Логические аргументы явно указывают на то, что функция выполняет более одной операции. Они сильно запутывают код. Исключите их из своих программ (см. «Аргументы-флаги», с. 66).
F4: Мертвые функции
Если метод ни разу не вызывается в программе, то его следует удалить. Хранить «мертвый код» расточительно. Не бойтесь удалять мертвые функции. Не забудьте, что система управления исходным кодом позволит восстановить их в случае необходимости.
G1: Несколько языков в одном исходном файле
Современные среды программирования позволяют объединять в одном исходном файле код, написанный на разных языках. Например, исходный файл на языке Java может содержать вставки XML, HTML, YAML, JavaDoc, English, JavaScript и т.д. Или, скажем, наряду с кодом HTML в файле JSP может присутствовать код Java, синтаксис библиотеки тегов, комментарии на английском языке, комментарии Javadoc, XML, JavaScript и т.д. В лучшем случае результат получается запутанным, а в худшем — неаккуратным и ненадежным.
Источники:
- http://habr.com/ru/post/189094/
- http://habr.com/ru/post/424051/
- http://habr.com/ru/post/485118/
- http://habr.com/ru/post/683956/
- http://habr.com/ru/company/lanit/blog/516352/
- http://github.com/beardlessman/books/blob/master/Martin_Robert__Clean_Code.md
- http://ruwapa.net/read/33176/
- http://habr.com/en/post/424051/
- http://www.labirint.ru/reviews/goods/642466/
- http://github.com/SergioMyJava/Clean-Code_Robert_Martin
- http://ruwapa.net/book/chistyj-kod-sozdanie-analiz-i-refaktoring/
- http://moreknig.org/kompyuternaya-literatura/programmirovanie/239950-chistyy-kod-sozdanie-analiz-i-refaktoring.html
- http://habr.com/en/post/189094/
- http://obuchalka.org/20210619133424/clean-code-robert-martin-2009.html
- http://www.litres.ru/robert-s-martin/chistyy-kod-sozdanie-analiz-i-refaktoring-6444478/
- http://libcat.ru/knigi/kompyutery-i-internet/programmirovanie/396005-robert-martin-chistyj-kod-sozdanie-analiz-i-refaktoring.html
- http://habr.com/ru/post/508876/
- http://coollib.net/b/486351-robert-sesil-martin-chistyiy-kod-sozdanie-analiz-i-refaktoring
- http://habr.com/ru/company/otus/blog/682922/
- http://www.livelib.ru/book/1000437984/reviews-chistyj-kod-sozdanie-analiz-i-refaktoring-robert-martin
- http://libking.ru/books/comp-programming/1066345-91-robert-martin-chistyj-kod-sozdanie-analiz-i-refaktoring.html
- http://coollib.com/b/486351-robert-sesil-martin-chistyiy-kod-sozdanie-analiz-i-refaktoring
- http://m.chitai-gorod.ru/catalog/book/312177/
- http://habr.com/ru/company/jugru/blog/490718/
- http://bespoyasov.ru/blog/clean-code/
- http://topliba.com/books/747144
- http://www.litmir.me/bd/?b=259244&p=1
- http://avidreaders.ru/book/chistyy-kod-sozdanie-analiz-i-refaktoring.html
- http://www.oreilly.com/library/view/clean-code-a/9780136083238/
- http://monikma.github.io/2016/01/13/clean-code-robert-c-martin-notes.html
- http://medium.com/mindorks/how-to-write-clean-code-lessons-learnt-from-the-clean-code-robert-c-martin-9ffc7aef870c
- http://m.habr.com/en/post/424051/
- http://dzone.com/articles/clean-code-robert-c-martins-way
- http://javarush.ru/groups/posts/3682-kofe-breyk-103-v-zajshitu-chistogo-koda-100-vechnihkh-sovetov
- http://towardsdatascience.com/tl-dr-the-clean-coder-by-robert-martin-d53a77dd228b
- http://blog.knoldus.com/clean-code-robert-c-martins-way/
- http://www.rulit.me/books/chistyj-kod-sozdanie-analiz-i-refaktoring-read-403904-1.html
- http://github.com/robertkuhar/cleancode
- http://habr.com/ru/company/piter/blog/353170/
- http://ut11-web.ru/1C-obshchaya-informatsiya/chistyy-kod/
- http://obuchalka.org/20201113126834/chistii-kod-sozdanie-analiz-i-refaktoring-biblioteka-programmista-martin-r-2010.html
- http://litvek.com/book-read/486351-kniga-robert-sesil-martin-chistyiy-kod-sozdanie-analiz-i-refaktoring-chitat-online
- http://libking.ru/books/comp-programming/1066345-92-robert-martin-chistyj-kod-sozdanie-analiz-i-refaktoring.html