чистый код или совершенный код

Манифест Чистого Программиста или краткий конспект книги «Чистый Код» Роберта Мартина

Данная статья является конспектом книги «Чистый Код» Роберта Мартина и моим пониманием того, каким Чистый Код должен быть. Тут нет разделов о тестировании, TDD, о том какая должна быть архитектура и т.д. Здесь все только о том, каким должен быть Чистый Код.

чистый код или совершенный код. Смотреть фото чистый код или совершенный код. Смотреть картинку чистый код или совершенный код. Картинка про чистый код или совершенный код. Фото чистый код или совершенный код

Да, возможно, тема Чистого Кода уже заезженна, но тем не менее еще не все с ним знакомы и, тем более, я не встретил аналогов контента, который содержится в моей статье.

Общее

Нет истинного пути и решения. Есть тот, который лучше всего подходит для решения конкретной задачи.

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

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

Перед тем, как отправить задачу в релиз — проверь правильно ли она работает. Нет ли в ней ошибок. Это касается даже тех коммитов, которые отправляются в твою ветку. Самый идеальный сценарий — тот, в котором никто не смог найти ошибки в функционале, который ты разрабатывал.

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

Чистый Код

Как писать чистый и хороший код? Это похоже на написание книги. Сначала ты делаешь черновик и потом причесываешь его до того состояния, в котором тебе было бы приятно его читать. Всегда помни, что твой код должен рассказывать историю происходящего, чтобы читатель мог ее понять.

Под сущностью понимается — интерфейс, класс, метод, переменная, объект и т.д.

Наименования и разделения

Функции

Комментарии

Форматирование и правила

Объекты и структуры данных

Классы

Обработка ошибок

Границы

Послесловие

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

Источник

Чистый код: причины и следствия

чистый код или совершенный код. Смотреть фото чистый код или совершенный код. Смотреть картинку чистый код или совершенный код. Картинка про чистый код или совершенный код. Фото чистый код или совершенный код

Автор: Виктор Свирский, Senior Python Developer / Team Lead, DataArt

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

Первый звоночек, который нам сообщает, что код перестает быть чистым — это рост времени разработки новой функциональности и увеличение регрессионного скоупа при малейшем изменении в системе. Это следствие того, что технический долг накапливается, компоненты в системе очень тесно связаны, автотесты отсутствуют. Причины этого могут быть:

Что такое чистый код?

Получается, чтобы сказать, что код чистый и система спроектирована грамотно, легкого чтения кода недостаточно. Он должен обладать и другими качествами:

Стоит ли писать чистый код?

Однозначно стоит! Но не всегда и не везде стоит уделять чистоте слишком много внимания.

Не стоит забывать о целесообразности и сроке жизни вашего кода. Например, если перед вами стоит задача разработки концепции — PoC (Proof of concept), и вы доказываете, что выбранный стек технологий выполняет поставленную задачу, ваш код станет неактуален уже через неделю или две. Не стоит тратить силы на совершенствование этого функционала.

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

Что поможет улучшить ваш код?

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

чистый код или совершенный код. Смотреть фото чистый код или совершенный код. Смотреть картинку чистый код или совершенный код. Картинка про чистый код или совершенный код. Фото чистый код или совершенный код

Самоорганизация

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

Не спешите решать задачи в лоб. Задавайте вопросы старшим разработчикам и самому себе. Всегда важно понимать причинно-следственную связь тех или иных решений. Хорошо понимая проблему, вы сможете эффективно ее решить.

Любой опыт лучше, чем его отсутствие.

Командная работа

Большинство задач решается в команде. Очень важно разделять ответственность за качество между ее участниками. Чем больше команда, тем сложнее поддерживать продукт в хорошем состоянии. Рассмотрим несколько подходов удержания кода в вышеуказанных условиях.

Во время проверки кода необходимо учитывать несколько вещей:

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

Непрерывная интеграция работает, когда вы следуете двум простым правилам:

Важно иметь список соглашений о кодировании. Но прежде чем вы начнете составлять список, все в команде должны понимать значимость этого соглашения. Не рассчитывайте, что такое соглашение будет принято с первого раза, вас ожидает множество дискуссий.

Составьте список соглашений о кодировании, в которых вы обозначаете то, как переменные должны объявляться, соглашения об именах и т. д. Количество правил, которые вы можете добавить в этот список, не ограничено и может варьироваться. Просто делайте то, что работает для вас и вашей команды. Не стесняйтесь добавлять новые правила в список соглашений, если команде это подходит. Это же касается и удаления соглашений из списка.

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

Чем меньше ошибок в коде, тем выше его качество. Тщательное тестирование отфильтровывает критические ошибки и гарантирует, что код работает так, как задумано.

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

Наличие ошибок в вашем коде, вероятно, неизбежно. Поэтому анализ и способ обработки этих ошибок очень важны. Если вы хотите улучшить свои навыки, важно учиться на собственных ошибках.

Когда возникает ошибка, проанализируйте ее с помощью нескольких вопросов:

Есть несколько метрик, которые вы можете использовать для количественной оценки качества вашего кода. С такой задачей легко справляется SonarQube. Он с легкостью поможет вам собрать все необходимо важные метрики:

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

Ошибки в коде чем-то сродни углеродному следу. Избежать совсем невозможно, а лишний выхлоп сам по себе не убьет ни человечества, ни окружающей его природы. Тем не менее, снизить негативный эффект от своего пребывания на планете сегодня кажется естественной потребностью. Примерно так же и написание чистого кода оказывается ответственностью каждого разработчика. Независимо от того, какой именно путь вы выберете, необходимо стремиться писать работающий и понятный код.

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

Источник

«Чистый код» Роберт Мартин. Конспект. Как писать понятный и красивый код?

Я решил написать конспект книги, которая всем известна, а сам автор называет ее «Школой учителей Чистого кода». Пристальный взгляд Мартина как бы говорит:

«Я тебя насквозь вижу. Ты опять не следуешь принципам чистого кода?»

чистый код или совершенный код. Смотреть фото чистый код или совершенный код. Смотреть картинку чистый код или совершенный код. Картинка про чистый код или совершенный код. Фото чистый код или совершенный код

Глава 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 ничего другого быть не должно.

Источник

Вероятно, хватит рекомендовать «Чистый код»

Возможно, мы никогда не сможем прийти к эмпирическому определению «хорошего кода» или «чистого кода». Это означает, что мнение одного человека о мнении другого человека о «чистом коде» обязательно очень субъективно. Я не могу рассматривать книгу Роберта Мартина «Чистый код» 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 году? Нет, я бы не стал.

*
Итак, главный вопрос заключается в том, какую книгу(и) я бы рекомендовал вместо этого? Я не знаю. Предлагайте в комментариях, если только я их не закрыл.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *