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

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

В вечных словах великого Мартина Фаулера;

Любой дурак может написать код, понятный компьютеру. Хорошие программисты пишут код, понятный людям. — Мартин Фаулер

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

Именование переменных и функций

Мы все были там; вы точно знаете код, который нужно написать, черт возьми, вы его написали, и он прекрасно работает, но теперь вы застряли на том, как назвать эту переменную или эту функцию. В этот момент вы, вероятно, думаете, так ли это важно?? Тогда вы идете вперед и пишете const d и заканчиваете день. (Если вы пишете Golang, это может быть даже желательным, но... я останавливаюсь на достигнутом).

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

Некоторые характеристики правильного именования:

  • Они не расплывчаты и, следовательно, не могут быть истолкованы как что-то другое. Вы, вероятно, не хотите называть переменную hp, даже если она представляет собой гипотенузу треугольника, так как это можно интерпретировать как миллион других вещей.
  • Имена легко произносимы. Программирование часто является социальной деятельностью, и часто возникает необходимость поговорить о коде; подумайте, насколько легче сказать UserAccount, чем сказать UsrAcct.
  • Обычно переменные называются существительными, а функции — глаголами; это имеет смысл, поскольку переменные обычно are вещей, а функции обычно do вещей.
  • Имена доступны для поиска. Проблемы с возможностью поиска — еще одна причина, по которой переменные с одним именем являются проблемой; представьте, что вы пытаетесь найти переменную с именем e в своем коде, что, вероятно, приведет к 2 миллионам обращений, что сделает практически невозможным поиск того, что вам нужно.
  • Это не анаграммы, каламбуры или шутки; да ладно, ребята, это и так достаточно сложно.
  • Они соответствуют утвержденным соглашениям и шаблонам в кодовой базе. Если функции для «получения чего-либо» начинаются с префикса get, постарайтесь не поддаваться желанию использовать префикс fetch, retrieve или acquire.

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

Функции

Характеристики хороших функций включают в себя;

Маленький размер

Функции должны быть МАЛЕНЬКИМИ!!! Извините за крик. Функция — это логическая группа функций (посмотрите, что я там сделал 😉), поэтому имеет смысл, чтобы она была небольшой, потому что это означает, что цель и функция этой функции (последняя, ​​которую я обещаю 😉) легко понять и усвоить, что всегда плюс.

Длинные функции никому не помогают, и их следует избегать как чумы. Напрашивается вопрос, как долго это слишком долго? На этот вопрос сложно ответить, так как жестких правил нет, но я бы сказал, что наилучшее место, вероятно, находится между 4 и 7 строками. Я знаю, что это смехотворно в большинстве реальных условий, но, насколько это возможно, делайте свои функции как можно короче.

Делайте одно дело (принцип единой ответственности)

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

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

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

Совет для профессионалов. Вероятно, вы нарушаете принцип единой ответственности, если имя вашей функции включает конъюнкцию или если ваша функция принимает boolean или то, что мы иногда называем flag.

Мало аргументов

Чем меньше аргументов принимает функция, тем лучше, это верно, потому что чем больше аргументов у функции, тем сложнее становится протестировать эту функцию, поскольку необходимо учитывать множество комбинаций аргументов для достижения полного охвата тестами. эта функция. Если функция должна принимать много аргументов, проверьте, нет ли;

  • Функция не пытается сделать слишком много.
  • Не все аргументы относятся к одному и тому же понятию, и в этом случае функция должна принимать объект.
  • Посмотрим, сможете ли вы нанять Inversion of Control

createUser 1.0 следует преобразовать в createUser 2.0

Чистота

Чистые функции — это функции, которые не имеют побочных эффектов (возвращают один и тот же вывод для одного и того же набора входных данных каждый раз), не имеют доступа и тем более не изменяют общее состояние. К сожалению, не все функции в программе могут быть чистыми, поскольку некоторым функциям неизменно требуется доступ к IO, выполнение сетевых вызовов, вывод журнала в консоль и т. д. Насколько это возможно, предпочитайте чистые функции нечистым и внедрение зависимостей глобальным.

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

В комментариях к коду

Судя по заголовку этого раздела, вы можете подумать, что я рекомендую использовать в комментариях к коду; вы очень ошибаетесь. Я считаю, что, вероятно, 80% комментариев, которые мы добавляем в код, не нужны и даже потенциально опасны.

Правда в коде и больше нигде

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

Эта конкретная часть кричит о том, что переменные, вероятно, могли бы быть названы лучше. Рассматриваемый state относится не только к любому movie; это для фильма, который выбрал пользователь. Я бы реорганизовал это, удалив комментарий и заменив movie и setMovie на selectedMovie и setSelectedMovie.

Вот еще один пример;

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

В конце концов я рекомендовал полностью удалить комментарий и при желании изменить имя переменной на requeryTimeout. Комментарий не добавил ценности и стал дополнительной вещью, которую нужно поддерживать.

Этот последний пример — классический случай doc block, который сильно отстал от реальности. В нем говорится, что функция принимает id и возвращает promise, но на самом деле функция принимает account (что на самом деле довольно неоднозначно) и возвращает object.

Если бы у нас был Typescript, рефакторинг был бы таким же простым, как удаление блока документации и использование аннотаций типов для передачи той же информации; в этом случае, однако, это никогда не будет неправильным. Даже с простым Javascript, используя лучшие имена для функции и аргументов, сохраняя функцию короткой, мы могли бы полностью избавиться от блока документации.

Комментарии в коде проблематичны по ряду причин;

  • Это дополнительная вещь, которую нам нужно поддерживать вместе с кодом, и они часто отстают.
  • Иногда они могут стать шумными и отвлекающими.
  • Они могут стать спасательным люком для плохо написанного кода.
  • Они часто могут вводить в заблуждение и распространять «ложь».

Однако есть несколько хороших комментариев, в том числе; Юридические комментарии, Предупреждение о последствиях, Разъяснения и т. д.

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

Неявный и явный код

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

Рассмотрим фрагмент кода ниже; в form.vue мы хотим получить массив действительных провайдеров.

Код, как он сейчас написан, требует, чтобы вы взглянули наvalidator.js, чтобы понять, почему мы удаляем первый элемент. Кроме того, если порядок массива networkProviders изменится, код сломается. В конечном итоге код был рефакторинг, как показано ниже, где мы можем сразу сказать, что нам нужны все провайдеры, которые не названы DEFAULT;

Глобальные переменные и общее состояние

Вы когда-нибудь слышали поговорку «Любовь к деньгам — корень всех зол»? Что ж, они были неправы. Глобальные переменные и разделяемое состояние являются корнями всех зол.

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

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

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

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

Вывод

Это не рассматривается в этой статье, и я настоятельно рекомендую Clean Code Роберта С. Мартина как хорошее дополнительное чтение.

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

использованная литература