что такое чистый код в программировании
Разбираемся с Clean Code в Android
Вы читаете эту статью по двум причинам. Первая — Вы программист, вторая — Вы хотите быть лучшим программистом.
Представьте, что Вы находитесь в библиотеке и ищете какие-то книги. Если библиотека сортирована, имеет категории книг, то вы быстро отыщите нужную Вам. Кроме того, крутой дизайн интерьера и архитектура сделает пребывание в этой библиотеке довольно комфортным для Вас.
Как и при написании книг, если вы хотите создать что-то великое, то вы должны знать как писать и как организовывать свой код. Если у вас есть члены команды или кто-то еще, у кого есть Ваш (устаревший) код, им просто нужно увидеть имена переменных или пакеты или классы, и они сразу поймут. Им не нужно говорить «Е**л» я этот код и начинать его снова с нуля.
Что такое «Чистый Код»?
Когда я писал этот код, только Бог и я знал как он работает!
Теперь только Бог знает это!
Перед тем как ты попытаешься оптимизировать эту рутину и это не приведет к успеху (наиболее вероятно), пожалуйста увеличь счетчик затраченного времени для предостережения следующего разработчика
Всего потрачено часов: 567
Как Вы можете видеть, недостаточно закончить разработку быстрее. Если в будущем в этом коде не смогут разобраться, то это так же станет техническим долгом.
Ваш код имеет состояние «Чистый», если его может понять каждый член Вашей команды. Чистый код может быть прочитан и улучшен любым разработчиком, отличным от первоначального автора. С пониманием приходит читаемость, изменяемость, расширяемость и ремонтопригодность.
Я должен заботиться об этом?
Причина, по которой Вы должны заботиться о чистоте своего кода, заключается в том, что Вы описываете ход своих мыслей другим разработчикам. Именно поэтому Вы должны заботиться о том, что Ваш код был более элегантным, простым и читаемым.
Признаки Чистого кода
Отличие между хорошим программистом и профессионалом в том, что профессиональный программист понимает, что понятность кода первостепенна. Профессионал использует эту силу для написания кода, который понятен всем — Robert C. Martin
Пишите осознанные имена
Выбор хорошего имени, может занять много времени, но в последствии оно сэкономит больше. Имя переменной, функции, класса должно отвечать на все значимые вопросы. Оно должно рассказать Вам, почему оно существует, зачем оно нужно и как его использовать. Если имя требует комментария, то имя не раскрывает своего предназначения
Имена классов
Классы и объекты должны быть существительными, например Сustomer, WikiPage, Account, and AddressParser. Избегайте таких слов как Manager, Processor, Data, или Info. Помните так же, что имя класса не должно быть глаголом.
Имена методов
Имена методов же должны быть глаголами, например postPayment, deletePage или save. Модификаторы доступа, предикаты должны быть названы по их значению и с префиксом get, set и согласно стандарту JavaBean.
Перед тем, как мы продолжим сделайте небольшой перерыв, запаситесь кофе и печеньками
Окей, теперь перейдем к SOLID принципам
Пишите код, придерживаясь SOLID принципов
Эти принципы были разработаны дядюшкой Бобом, SOLID это аббревиатура, описывающая набор принципов, предназначенных для написания хорошего кода.
Принцип единственную ответственности (S)
Это означает, что каждый класс должен нести только одну ответственность. Никогда не должно быть более одной причины для изменения класса. Не надо добавлять все в свой класс, просто потому что Вы можете это сделать. Разбивайте большие классы на более маленькие и избегайте God Classes.
У нас есть RecyclerView.Adapter с бизнес логикой внутри onBindViewHolder
Это делает RecyclerView.Adapter не имеющим единственную ответственность, потому что он содержит бизнес логику внутри onBindViewHolder. Этот метод отвечает только за вставку данных во view.
Принцип открытости/закрытости (О)
Программные сущности должны быть открыты для расширения, но закрыты для модификации. Это означает, что если Вы разрабатываете класс А и ваши коллеги захотят изменить функцию внутри этого класса. Они смогут легко это сделать, расширив этот класс без изменения самого класса.
Простой пример класс RecyclerView.Adapter. Вы можете с легкостью расширить его и создать свой собственный адаптер с нестандартным поведением без модификации самого RecyclerView.Adapter.
Принцип подстановки Барбары Лисков (L)
Дочерний класс должен дополнять родительский, а не изменять его. Это означает, что подкласс должен переопределять методы родительского, которые не нарушают функциональность этого родительского класса. Например мы создаем интерфейс класса, который имеет onClick() слушатель а затем вы применяете слушатель в MyActivity и даете ему действие Toast, когда вызывается onClick ().
Принцип разделения интерфейса
Этот принцип гласит, что клиент не должен быть зависим от методов, которые он не использует.
Это означает, что если Вы хотите написать класс А и добавить в него функциональность другого класса В. Нет необходимости переопределять все классы А внутри класса В.
Пример: в нашей активити, нам нужно реализовать SearchView.OnQueryTextListener(), но нам нужен только onQuerySubmit() метод.
Как мы это сделаем? Легко! Просто создадим callback и класс, расширяющий SearchView.OnQueryTextListener()
И вот так мы добавим это к нашей view
Или так, используя Extension Function в Kotlin
Принцип инверсии зависимостей
Зависимость на абстракциях, без зависимости на что-то конкретное.
Определение инверсии зависимостей от дядюшки Боба состоит из двух понятий.
Модули верхних уровней не должны зависеть от модулей нижних уровней. Оба должны быть завязаны на абстракциях. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций. Модули высоких уровней, которые реализуют комплексную логику, должны быть легко переиспользуемы без изменений в модулях нижнего уровня. Для этого Вам нужно ввести абстракцию, которая отделяет модули верхнего и нижнего уровней друг от друга.
Простой пример этого MVP паттерн. У Вас есть объект интерфейсов, который помогает Вам общаться с конкретными классами. Что имеется ввиду — классам UI (Activity/Fragment) не нужно знать фактическую реализацию методов презентера. Таким образом, если Вы делаете изменения внутри презентера, UI классы не должны волновать эти изменения
Давайте взглянем на пример
А теперь на активити
Таким образом мы создаем интерфейс, который абстрагирует реализацию презентатора, и наш класс view сохраняет ссылку на PresenterInterface.
Чистый код: причины и следствия
Сколько программистов, столько и определений, что такое чистый код. Часто, проводя собеседование, я слышу, что хороший код — это такой, который легко читается. Согласен, но как подсказывает мой личный опыт, это только вершина айсберга.
Первый звоночек, который нам сообщает, что код перестает быть чистым — это рост времени разработки новой функциональности и увеличение регрессионного скоупа при малейшем изменении в системе. Это следствие того, что технический долг накапливается, компоненты в системе очень тесно связаны, автотесты отсутствуют. Причины этого могут быть:
Не стоит откладывать работу над качеством кода и архитектуры в долгий ящик. Во время спринта важно уметь разделять задачи, которые имеют прямую ценность для бизнеса (задачи с новой функциональностью), и технические задачи, которые имеют для бизнеса лишь косвенный эффект. Пропорция разделения зависит от текущего состояния проекта, временных рамок и количества свободных рук.
Что такое чистый код?
Получается, чтобы сказать, что код чистый и система спроектирована грамотно, легкого чтения кода недостаточно. Он должен обладать и другими качествами:
Чтобы уйти от субъективной оценки качества своего кода, с 1961 года введен термин «запахи кода» или «код с запашком». Это группа правил и рекомендаций, которые четко определяют, пора ли делать рефакторинг. «Запашок» ведет к распаду кода, и разработчики всегда должны стремиться его устранить. Необходимость рефакторинга напрямую следует из наличия запаха кода, и предотвращая причину, мы сможем избежать и следствия. Более подробно о ключевых признаках того, что вам пора заняться рефакторингом можно прочесть в книге Мартина Фаулера «Рефакторинг. Улучшение существующего кода».
Стоит ли писать чистый код?
Однозначно стоит! Но не всегда и не везде стоит уделять чистоте слишком много внимания.Не стоит забывать о целесообразности и сроке жизни вашего кода. Например, если перед вами стоит задача разработки концепции — PoC (Proof of concept), и вы доказываете, что выбранный стек технологий выполняет поставленную задачу, ваш код станет неактуален уже через неделю или две. Не стоит тратить силы на совершенствование этого функционала.Бытует мнение, что не нужно следить за качеством кода или части системы, которые в скором времени будут заменены. И это неверно по нескольким причинам. Высокое качество исполнения сделает переход или интеграцию с новыми частями более простыми, бесшовными и быстрыми. Оно наверняка упростит жизнь в тех случаях, когда несколько версий кода придется поддерживать одновременно. Количество регрессионных ошибок с чистым кодом будет в разы меньше. Также не стоит забывать, что нет ничего более постоянного, чем временное. Возможно, задачи по улучшению этой части кода еще несколько месяцев будут лежать в бэклоге.
Что поможет улучшить ваш код?
Большинство программистов мечтают писать код быстро и максимально красиво, причем так, чтобы все идеально работало с первого раза. Но далеко не каждому удается сделать код не просто работающим, но и понятным. Как же добиться успеха в написании чистого кода? Есть два пути — самоорганизация и командная работа.
Самоорганизация
Рассмотрим несколько возможных способов улучшить индивидуальное качество кода. Эти рекомендации подойдут разработчику любого уровня.
Командная работа
Большинство задач решается в команде. Очень важно разделять ответственность за качество между ее участниками. Чем больше команда, тем сложнее поддерживать продукт в хорошем состоянии. Рассмотрим несколько подходов удержания кода в вышеуказанных условиях.
Ошибки в коде чем-то сродни углеродному следу. Избежать совсем невозможно, а лишний выхлоп сам по себе не убьет ни человечества, ни окружающей его природы. Тем не менее, снизить негативный эффект от своего пребывания на планете сегодня кажется естественной потребностью. Примерно так же и написание чистого кода оказывается ответственностью каждого разработчика. Независимо от того, какой именно путь вы выберете, необходимо стремиться писать работающий и понятный код.
Хорошо, если удастся не превращать чистоту в фетиш, учитывая срок жизни нашего кода и оценивая целесообразность дальнейших улучшений. Главное помнить о людях: пользователях, которых может подвести внезапный отказ даже небольшой части разработанной нами системы, и инженерах, которым предстоит эту систему поддерживать.
Вероятно, хватит рекомендовать «Чистый код»
Возможно, мы никогда не сможем прийти к эмпирическому определению «хорошего кода» или «чистого кода». Это означает, что мнение одного человека о мнении другого человека о «чистом коде» обязательно очень субъективно. Я не могу рассматривать книгу Роберта Мартина «Чистый код» 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 году? Нет, я бы не стал.
*
Итак, главный вопрос заключается в том, какую книгу(и) я бы рекомендовал вместо этого? Я не знаю. Предлагайте в комментариях, если только я их не закрыл.
Чистый код на PHP
Это принципы разработки ПО, взятые из книги Clean Code Роберта Мартина и адаптированные для PHP. Это руководство не по стилям программирования, а по созданию читабельного, многократно используемого и пригодного для рефакторинга кода на PHP.
Не каждый из этих принципов должен строго соблюдаться, и ещё с меньшим количеством все будут согласны. Это лишь рекомендации, не более, но все они кодифицированы в многолетнем коллективном опыте автора Clean Code.
Содержание
Переменные
Используйте значимые и произносимые имена переменных
Плохо:
Хорошо:
Для одного типа переменных используйте единый словарь
Плохо:
Хорошо:
Используйте имена, по которым удобно искать
Мы прочитаем больше кода, чем когда-либо напишем. Поэтому важно писать такой код, который будет читабелен и удобен для поиска. Но давая переменным имена, бесполезные для понимания нашей программы, мы мешаем будущим читателям. Используйте такие имена, по которым удобно искать.
Плохо:
Хорошо:
Используйте пояснительные переменные
Плохо:
Неплохо:
Так лучше, но мы всё ещё сильно зависим от регулярного выражения.
Хорошо:
С помощью именования подпаттернов снижаем зависимость от регулярного выражения.
Избегайте ментального сопоставления
Не заставляйте тех, кто будет читать ваш код, переводить значения переменных. Лучше писать явно, чем неявно.
Плохо:
Хорошо:
Не добавляйте ненужный контекст
Если имя вашего класса/объекта с чем-то у вас ассоциируется, не проецируйте эту ассоциацию на имя переменной.
Плохо:
Хорошо:
Вместо сокращённых или условных используйте аргументы по умолчанию
Плохо:
Хорошо:
Функции
Аргументы функций (в идеале два или меньше)
Крайне важно ограничивать количество параметров функций, потому что это упрощает тестирование. Больше трёх аргументов ведёт к «комбинаторному взрыву», когда вам нужно протестировать кучу разных случаев применительно к каждому аргументу.
Идеальный вариант — вообще без аргументов. Один-два тоже нормально, но трёх нужно избегать. Если их получается больше, то нужно объединять, чтобы уменьшить количество. Обычно если у вас больше двух аргументов, то функция делает слишком много. В тех случаях, когда это не так, чаще всего в качестве аргумента достаточно использовать более высокоуровневый объект.
Плохо:
Хорошо:
Функции должны делать что-то одно
Это, безусловно, самое важное правило в разработке ПО. Когда функции делают больше одной вещи, их труднее составлять, тестировать и обосновывать. А если вы можете наделить функции только какими-то одиночными действиями, то их будет легче рефакторить, а ваш код станет гораздо чище. Даже если вы не будете следовать никакой другой рекомендации, кроме этой, то всё равно опередите многих других разработчиков.
Плохо:
Хорошо:
Имена функций должны быть говорящими
Плохо:
Хорошо:
Функции должны быть лишь одним уровнем абстракции
Если у вас несколько уровней абстракции, то на функцию возложено слишком много задач. Разбиение функций позволяет многократно использовать код и облегчает тестирование.
Плохо:
Хорошо:
Уберите дублирующий код
Старайтесь полностью избавиться от дублирующего кода. Он плох тем, что если вам нужно менять логику, то это придётся делать в нескольких местах.
Представьте, что вы владеете ресторанчиком и отслеживаете, есть ли продукты: помидоры, лук, чеснок, специи и т. д. Если у вас несколько списков с содержимым холодильников, то вам придётся обновлять их все, когда вы готовите какое-то блюдо. А если список один, то и вносить изменения придётся только в него.
Зачастую дублирующий код возникает потому, что вы делаете две и более вещи, у которых много общего. Но небольшая разница между ними заставляет вас писать несколько функций, и те по большей части делают одно и то же. Удаление дублирующего кода означает, что вы создаёте абстракцию, которая может обрабатывать все различия с помощью единственной функции/модуля/класса.
Правильный выбор абстракции критически важен, поэтому нужно следовать принципам SOLID, описанным в разделе «Классы». Плохие абстракции могут оказаться хуже дублирующего кода, так что будьте осторожны! Но если можете написать хорошие, то делайте это! Не повторяйтесь, иначе окажется, что при каждом изменении вам нужно обновлять код в нескольких местах.
Плохо:
Хорошо:
Не используйте флаги в качестве параметров функций
Флаги говорят вашим пользователям, что функции делают больше одной вещи. А они должны делать что-то одно. Разделяйте свои функции, если они идут по разным ветвям кода в соответствии с булевой логикой.
Плохо:
Хорошо:
Избегайте побочных эффектов
Функция может привносить побочные эффекты, если она не только получает значение и возвращает другое значение/значения, но и делает что-то ещё. Побочным эффектом может быть запись в файл, изменение глобальной переменной или случайная отправка всех ваших денег незнакомому человеку.
Но иногда побочные эффекты бывают нужны. Например, та же запись в файл. Лучше делать это централизованно. Не выбирайте несколько функций и классов, которые пишут в какой-то один файл, используйте для этого единый сервис. Единственный.
Главная задача — избежать распространённых ошибок вроде общего состояния для нескольких объектов без какой-либо структуры; использования изменяемых типов данных, которые могут быть чем-то перезаписаны; отсутствия централизованной обработки побочных эффектов. Если вы сможете это сделать, то будете счастливее подавляющего большинства других программистов.
Плохо:
Хорошо: