Тема чистого кодирования, вероятно, довольно противоречива, поскольку разные люди по-разному понимают, что это значит. Некоторые люди даже думают, что это просто одна из тех вещей, которые не имеют ничего общего с самим искусством кодирования. По мере того, как я рос как разработчик, пишу и рецензирую много кода, важность чистого, выразительного и легкого для понимания кода стала для меня совершенно очевидной.
Кто-то однажды сказал, что как разработчики мы тратим больше времени на чтение кода, чем на его написание, поэтому очень важно, чтобы код, который мы пишем, был легко читаем и понятен нам самим и другим разработчикам в будущем.
В вечных словах великого Мартина Фаулера;
Любой дурак может написать код, понятный компьютеру. Хорошие программисты пишут код, понятный людям. — Мартин Фаулер
Цель этой статьи — представить методы чистого кодирования интуитивно понятным образом с примерами, которым легко следовать. Прочитав эту статью, вы сможете начать применять многие принципы, выделенные здесь, и увидеть значительное улучшение качества и «чистоты» кода, который вы пишете.
Именование переменных и функций
Мы все были там; вы точно знаете код, который нужно написать, черт возьми, вы его написали, и он прекрасно работает, но теперь вы застряли на том, как назвать эту переменную или эту функцию. В этот момент вы, вероятно, думаете, так ли это важно?? Тогда вы идете вперед и пишете 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
Роберта С. Мартина как хорошее дополнительное чтение.
Верите ли вы в концепцию «чистого кода» или нет, я надеюсь, вы, по крайней мере, согласны с тем, что в коде, который мы пишем, должна быть некоторая структура и здравомыслие. Советы, выделенные выше, могут стать отличным началом.
использованная литература
Clean Code
Роберт С. Мартин- https://medium.com/dailyjs/functional-js-2-functions-duh-70bf22f87bb8