7 способов сделать ваш код чище
Перевод статьи Али Спиттел «Extreme Makeover: Code Edition».
Я немного одержима идеей написания чистого кода. Код должен быть читабельным для тех разработчиков, которые будут заниматься им в будущем (включая вас). Также он должен иметь возможность расширения. Добавлять новые свойства в ваше приложение и поддерживать код должно быть легко. Если бы мы писали код только для компьютеров, то можно было бы обойтись бинарным кодом! Вот несколько моих советов для написания чистого кода:
1. Используйте понятные имена переменных и функций
Если вы будете писать полные, описательные имена переменных и функций, то ваш код будет гораздо легче читать. Вот этот код не вполне понятен:
[python]function avg (a) let s = a.reduce((x, y) => x + y)
return s / a.length
>[/python]
Но он становится гораздо более читабельным, если написать полные имена переменных!
[python]function averageArray (array) let sum = array.reduce((number, currentSum) => number + currentSum)
return sum / array.length
>[/python]
Не минифицируйте свой код; используйте полные имена переменных, чтобы следующему разработчику они были понятны.
2. Пишите короткие функции, выполняющие только одно действие
Функции становятся гораздо понятнее, читабельнее и проще в обслуживании, если они выполняют лишь одно действие. Если мы пишем короткие функции и у нас проявляется баг, обычно бывает довольно легко найти источник проблемы. Также в таком случае наш код больше подходит для повторного использования.
Например, приведенную выше функцию можно было бы переименовать в «sumAndAverageArray», потому что мы вычисляем сумму, используя сокращения, а затем вычисляем среднее значение этой суммы.
[python]function sumAndAverageArray(array) let sum = array.reduce((number, currentSum) => number + currentSum)
return sum / array.length
>[/python]
Мы можем разбить эту функцию на две отдельные, и тогда станет гораздо яснее, что делает каждая часть кода. Также, если мы создаем большую программу, такая функция как sumArray вполне может пригодиться.
[python]function sumArray(array) return array.reduce((number, currentSum) => number + currentSum)
>
function averageArray(array) return sumArray(array) / array.length
>[/python]
Если вы пишете функцию, в имени которой можно вставить союз «и», – ее точно стоит разделить на две разные функции.
3. Документация
Пишите для своего кода хорошую документацию, чтобы разработчики, которые будут иметь дело с вашим кодом в будущем, понимали, что именно делает этот код и почему.
В следующем коде содержатся незадокументированные «магические числа».
[python]function areaOfCircle (radius) return 3.14 * radius ** 2
>[/python]
Мы можем добавить комментарий к этому коду. Таким образом он станет более понятен для кого-то, кто не знает математической формулы вычисления площади круга.
[python]const PI = 3.14 // PI rounded to two decimal places
function areaOfCircle (radius) // Implements the mathematical equation for the area of a circle:
// Pi times the radius of the circle squared.
return PI * radius ** 2
>[/python]
Примечание: указанный код это лишь пример! В своем коде вы наверняка бы использовали Math.PI вместо собственноручного присвоения значения PI.
Ваши комментарии должны отвечать на вопрос «Почему?» относительно вашего кода.
Бонус: используйте определенный стиль для документации вашего кода. Для Python мне нравится пользоваться Google Style Docstrings, а для JavaScript отлично подходит JSDoc.
4. Правила Сэнди Мец
Сэнди Мец (Sandi Metz) – отличный разработчик на языке Ruby, докладчик и писательница. У нее есть четыре правила для написания чистого кода в объектно-ориентированных языках.
- Классы должны содержать меньше 100 строк кода.
- Методы и функции не могут быть длиннее 5 строк кода.
- Передавать в метод не больше 4 параметров.
- Контроллеры могут обрабатывать только один объект.
Я настоятельно рекомендую посмотреть полную запись ее речи относительно этих правил!
Сама я последовательно придерживаюсь этих правил последние два года, и это стало настолько привычным, что я делаю это не задумываясь! Мне эти правила очень нравятся; я считаю, что они делают код более простым в поддержке.
Указанные выше правила – лишь рекомендации, но благодаря им ваш код может стать заметно чище.
5. Будьте последовательны
При написании кода последовательность очень важна. Не должно быть такого, что человеку стоит только глянуть на код, и он без всякого git blame уже знает, кто это писал! Если вы используете точку с запятой в JavaScript – ставьте их в конце каждого предложения. Также будьте последовательны в использовании определенного типа кавычек!
Я бы рекомендовала пользоваться руководством по стилю и линтером, чтобы обеспечить выполнение этого стандарта. Например, мне нравится Standard JS для JavaScript и PEP8 для Python. И мой текстовый редактор настроен таким образом, чтобы при сохранении код подгонялся под эти стандарты.
Выберите стиль кода и придерживайтесь его.
6. Избавляйтесь от «воды»
Одна из первых вещей, которым учат новых программистов, это «не повторяться». Если вы замечаете в своем коде повторы, используйте код для уменьшения числа таких дубликатов. Я часто поощряю своих студентов играть в SET для развития навыков распознавания шаблонов.
Однако, если вы «пересушите»* свой код, избрав неправильные шаблоны для абстрагирования, он может стать нечитаемым и вам придется дублировать его в дальнейшем. У Сэнди Мец есть отличная статья о том, что «дублирование обходится гораздо дешевле, чем неправильное абстрагирование».
Не повторяйтесь, но также и не абстрагируйте свой код до состояния нечитабельности.
*В оригинале используется игра слов: DRY как аббревиатура «don’t repeat yourself» и dry — «сухой».
7. Инкапсуляция + модуляризация
Группируйте подобные переменные и функции, чтобы сделать ваш код более понятным и подходящим для повторного использования.
[python]let name = ‘Ali’
let age = 24
let job = ‘Software Engineer’
let getBio = (name, age, job) => `$ is a $ year-old $` [/python]
Если в вашей программе много людей, то следующий код будет более понятным:
[python]class Person constructor (name, age, job) this.name = name
this.age = age
this.job = job
>
Или, если в вашем сценарии только один человек, то можно так:
[python]const ali = name: ‘Ali’,
age: 24,
job: ‘Software Engineer’,
getBio: function () return `$ is a $ year-old $`
>
>[/python]
Аналогично, разбивайте длинные программы на разные файлы, чтобы ваш код был более модульным и удобоваримым. Длинные файлы зачастую трудно анализировать, к тому же небольшие отрывки кода можно использовать повторно в других проектах.
Группируйте подобные вещи в вашем коде, чтобы он стал более подходящим для повторного использования.
В общем…
Это хорошие советы относительно того, как сделать код чище, но они не высечены на скрижалях! Я сама не пользуюсь ими всеми постоянно (это заметно, если глянуть на мои личные проекты), и никакой код не совершенен. Это лишь подсказки, как писать код, чтобы его было легче использовать повторно, проще читать и расширять.
Помогите сделать код читабельным
Подскажите как можно сделать данный код более читабельным. А то код новичка будто)). Если есть другой сайт для подобных вещей. То дайте плиз ссылку.
Отслеживать
80.6k 9 9 золотых знаков 78 78 серебряных знаков 134 134 бронзовых знака
задан 13 мая 2016 в 13:02
3,471 14 14 серебряных знаков 49 49 бронзовых знаков
3 ответа 3
Сортировка: Сброс на вариант по умолчанию
switch(position) < case 1: Toast.makeText(Home.this, "Акции временно не работают", Toast.LENGTH_LONG).show(); break; case 2: if (strTotalPrice<500) Toast.makeText(Home.this, "Минимальная сумма заказа 500 руб.", Toast.LENGTH_SHORT).show(); else viewPager.setCurrentItem(position,false); break; default: viewPager.setCurrentItem(position,false); break; >drawerLayout.closeDrawers();
Отслеживать
ответ дан 13 мая 2016 в 13:07
69.8k 9 9 золотых знаков 66 66 серебряных знаков 122 122 бронзовых знака
Спасибо Юрий. Я код чуток изменил. Можете измененный код через свитч еще раз?
13 мая 2016 в 13:12
@xTIGRx, так просто же копирнуть и всё. А вообще менять ТЗ после его исполнения — плохо. Вы ж, вроде, фрилансер, а таким занимаетесь(
13 мая 2016 в 13:14
Все спасибо)). Копирнуть это дело школьников, а я хочу разобраться в этом. Благодаря вашему коду и чуток погулив в инете. Я понял как работает default. Спасибо большое))
13 мая 2016 в 13:15
Для начала, чтобы повысить читабельность кода, советую обратиться к документу
В конвенции есть правила которых стоит придерживаться при написании Java библиотек, правила стиля оформления кода, правила языка Java и т.д. Этих правил стоит придерживаться, чтобы ваш код был лаконичен, понятен и, самое главное, «привычен» всем программистам. Во многих компаниях есть свои соглашения по написанию кода, но это уже другая история.
Есть множество переводов Java Code Conventions на русский, но лучше, по возможности, все-таки прочитать в оригинале. Тем более сделать это надо всего лишь один раз.
Конкретно в вашем примере, следующие нарушения конвенции:
-
операторы необходимо отделять пробелами
if (position != 1 && position != 2)
viewPager.setCurrentItem(position, false);
if (strTotalPrice < 500) < Toast.makeText(Home.this, "Минимальная сумма заказа 500 руб.", Toast.LENGTH_SHORT).show(); >else
Я не обращаю внимания на структуру кода (ввести взаимоисключающие if. else, либо перейти на switch. case), я сделал пост о нарушении конвенции Java для написания кода, надеюсь это будет полезно
Пять способов улучшить читабельность кода
Для тех, кто ищет быстрые ответы, не желая читать весь текст, вот краткое содержание:
- Повторно используйте код, который повторяется более одного раза.
- Читабельность и простота поддержки важнее универсальности.
- Делайте модули, классы и компоненты как можно меньше.
- Используйте правила и стандарты для кода.
- Пишите код, как будто вы в команде, даже если работаете один.
Повторно используйте код, который повторяется более одного раза
Большинство разработчиков знакомы с принципом DRY (Don’t Repeat Yourself). Он позволяет избежать дублирования кода.
Зачем писать функцию снова и снова? Напишите ее один раз и используйте в нескольких местах. И, когда вам понадобится изменить этот кусок кода, сделать это придется только в одном месте, не занимаясь копипастой багфикса в кучу мест.
Но имейте в виду, что использование принципа DRY увеличивает сложность кода, потому что, в конце концов, количество повторно используемого кода будет расти.
А про важность написания тестов при повторном использовании частей кода вы узнаете, когда вы начнете изменять этот код.
Читабельность и простота поддержки важнее универсальности
Повторное использование, читабельность, и простота поддержки друзья и враги одновременно.
Когда вы начинаете придерживаться принципа DRY, сложность вашего кода начинает расти. Когда растет сложность - страдает читабельность.
Поэтому не начинайте написание кода с громоздких универсальных решений. Начинайте с простых! Не надо пытаться сделать идеально с первого раза.
Используя итеративный подход, вы сможете повторно использовать некоторые части своего кода, сохраняя при этом его читабельность и простоту поддержки.
Когда вы работаете в компании с несколькими командами разработчиков, в вашей команде скорее всего будут еще и внешние исполнители (фрилансеры или консультанты). Таким людям, как правило, приходится намного чаще переключаться с одного проекта на другой.
В этом случае, читабельность кода и простота его поддержки - ключ к успеху проекта. Громоздкий непонятный код, написанный человеком, который может покинуть команду в любой момент - не самое лучшее решение.
Правда иногда вам могут требоваться именно такие решения, но помните, что важно сделать их код как можно более читабельным и простым в поддержке.
Делайте модули, классы и компоненты как можно меньше
Разрабатывая новые функции для проекта, вы, скорее всего, стараетесь тщательно их продумать.
Помните, что лучшие решения — это те, которые можно разделить на небольшие модули, классы или компоненты. А знаете почему?
Маленькие куски кода проще тестировать и поддерживать.
Вспомните, что дома строятся путем перемещения более мелких компонентов в нужное место, и никто не пытается сначала построить дом, а потом переместить его туда, где он должен находиться. Хотя, конечно, бывают и исключения.
Большинство современных библиотек и фреймворков разбиты на маленькие строительных блоки, а не представлены в виде одного файла. JavaScript библиотеки и фреймворки такие, как Angular, React и Vue используют концепцию компонентов. Вряд ли они делают это случайно.
Используйте правила и стандарты для кода
Одна из составляющих написания читабельного и легко поддерживаемого кода - его архитектура. Другая - его стиль.
Я думаю, любому из вас хорошо известны эти бесконечные споры о том, что лучше использовать для выравнивания: табы или пробелы. Не хочу занимать ни чью сторону в этом споре, ведь на самом деле не важно, что использует ваша команда. Гораздо важнее, что это каждый член команды понимает и принимает эти правила.
И лучшим решением в данной ситуации будет автоматическое форматирования кода. Большинство IDE имеют для этого встроенные или устанавливаемые в виде плагинов инструменты.
Самый простой из таких инструментов, подходящий для большинства языков программирования и редакторов — editorconfig. Вы можете применять правила форматирования кода просто добавляя файл .editorconfig в свой проект.
В этот файл можно добавить различные настройки форматирования, как глобальные, так и специфичные для конкретного языка программирования. Например:
- Использование табов или пробелов для отступов
- Тип кавычек: двойные или одинарные
- Максимальную длину строки
- Набор символов
- и т.д.
Вот пример такого файла:
root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = tab insert_final_newline = false max_line_length = 120 tab_width = 4 [*.md] max_line_length = off trim_trailing_whitespace = false
Подробнее про формат файла можно почитать на editorconfig.org
Кроме того, существуют более специализированные решения для конкретных языков программирования. Например, Prettier для JavaScript. Возможно, вы используете что-то другое. На самом деле не важно какие инструменты используются в вашей команде, самое главное — это использование единых правил и стандартов.
Пишите код, как будто вы в команде, даже если работаете один
Последний, но не менее важный пункт: пишите, как будто вы в команде!
Я могу представить, что людям, которые никогда не писали код в команде, очень трудно понять каково это.
Но если вы пишите проект в одиночку, есть большой соблазн начать писать код, который поймете только вы (например, использовать непонятные имена переменных или имена из 2–3 символов и т.д.).
Вместо этого попробуйте писать так, как будто вы в команде. Представьте, что ваш код настолько понятен, что кто-то другой сможет без труда в нем разобраться.
Вы можете легко проверить это, попросив друга или кого-нибудь из сообщества разработчиков проверить читабельность вашего кода. Обещаю, что вы получите такую обратную связь, о которой не могли и подумать.
Не паникуйте из-за негативного фидбека! Сфокусируйтесь на отзывах, которые сделают ваш код более читабельным.
Запомните, что грань между хорошо читаемым и плохо читаемым кодом очень тонка. И чаще всего субъективна.
Не расстраивайтесь, если кто-то скажет, что ваш код не читаем! Вместо этого поблагодарите человека за обратную связь.
Как сделать код читабельным
Когда-нибудь мы все писали (а некоторые и пишут) плохой код, и, надеюсь, мы все работаем над улучшением наших навыков, а не просто чтением статей вроде этой.
Зачем нам писать хороший код, а не просто производительный код?
Хотя производительность вашего продукта или сайта важна, также важно и то, как выглядит ваш код. Причиной этого является то, что не только машина читает ваш код.
Во-первых, рано или поздно вам придется перечитывать собственный код, и когда это время наступит, только хорошо написанный код поможет вам понять, что вы написали, или выяснить, как это исправить.
Во-вторых, если вы работаете в команде или сотрудничаете с другими разработчиками, то все члены команды будут читать ваш код и пытаться интерпретировать его так, как они понимают. Чтобы сделать это проще для них, важно соблюдать некие правила при названии переменных и функций, ограничивать длину каждой строки и сохранять структуру вашего кода.
Наконец, давайте рассмотрим конкретный пример.
Часть 1: Как определить плохой код?
Самый простой способ определить плохой код, на мой взгляд, — попытаться прочитать код так, как если бы это было предложение или фраза.
Например, взглянем на этот код:
Скриншот плохой версии функции «traverseUpUntil»
Представленная выше функция принимает некий элемент и условную функцию и возвращает ближайший родительский узел, который удовлетворяет условной функции.
const traverseUpUntil = (el, f) =>
Исходя из того, что код должен читаться, как обычный текст, первая строка имеет три грубейших недостатка.
- Параметры функции не читаются, как слова.
- Допустим, el можно понять, поскольку такое имя обычно используется для обозначения элемента, но имя параметра f не объясняет ровным счётом ничего.
- Название функции можно прочитать так так: «переходить до тех пор, пока el не пройдет f», которое, вероятно, лучше читать как «переходить до тех пор, пока f не пройдет для el». Конечно, лучший способ сделать это — позволить функции вызываться как el.traverseUpUntil(f) , но это другая проблема.
let p = el.parentNode
Это вторая строка. Снова проблема с именами, на этот раз с переменной. Если бы кто-то посмотрел на код, то, скорее всего, понял бы, что такое p . Это parentNode параметра el . Однако, что происходит, когда мы смотрим на p , используемое где-либо еще, у нас больше нет контекста, который объясняет, что это такое.
while (p.parentNode && !f(p))
В следующей строке основная проблема, с которой мы сталкиваемся — это непонимание того, что означает или делает !f(p) , потому что «f» может означать всё, что угодно. Предполагается, что человек, читающий код, должен понимать, что !f(p) — это проверка текущего узла на удовлетворение определённому условию. Если она проходит, то цикл прерывается.
p = p.parentNode
Здесь всё понятно.
return p
Не совсем очевидно, что возвращается из-за неправильного имени переменной.
Часть 2: Давайте отрефакторим
Скриншот хорошей версии функции «traverseUpUntil»
Сначала мы изменяем имена параметров и их порядок: (el, f) => в (condition, node) => .
Возможно, вам интересно, почему вместо «element (рус. элемент) я использовал «node» (рус. узел). Я использовал его по следующим причинам:
- Мы пишем код в терминах узлов, например .parentNode , поэтому почему бы не сделать его консистентным.
- «Node» короче, чем «element», и при этом смысл не теряется.
Затем мы переходим к именам переменных:
let parent = node
Очень важно полностью раскрыть значение вашей переменной в её имени, поэтому «p» теперь «parent» (рус. родитель). Возможно, вы также заметили, что теперь мы не начинаем с получения родительского узла node.parentNode , вместо этого получаем только узел.
do < parent = parent.parentNode >while (parent.parentNode && !condition(parent))
Вместо обычного цикла while я выбрал цикл do . while . Это означает, что нам нужно каждый раз перед проверкой условия получать родительский узел, а не наоборот. Использование цикла do . while также способствует тому, чтобы читать код, как обычный текст.
Давайте попробуем прочитать: «Присвоить родительский узел родителя родителю, пока у родителя есть родительский узел, а функция условия не возвращает true». Уже гораздо понятнее.
return parent
Часто разработчики предпочитают использовать какую-то общую переменную ret (или returnValue ), но это довольно плохая практика. Если вы правильно назовёте свои возвращаемые переменные, становится очевидным то, что возвращается. Однако иногда функции могут быть длинными и сложными, что приводит к большой путанице. В этом случае я бы предложил разделить вашу функцию на несколько функций, и если она всё ещё слишком сложна, то, возможно, добавление комментариев может помочь.
Часть 3: Упрощение кода
Теперь, когда вы сделали код читабельным, пришло время убрать ненужный код. Я уверен, что некоторые из вас уже заметили, что нам вообще не нужна переменная parent .
const traverseUpUntil = (condition, node) => < do < node = node.parentNode >while (node.parentNode && !condition(node)) return node >
Я просто убрал первую строку и заменил «parent» на «node». Таким образом, я пропустил ненужный шаг создания «parent» и перешёл прямо в цикл.
Но что насчёт имени переменной?
Хотя «node» не лучшее описание для этой переменной, оно удовлетворительное. Но давайте не будем останавливаться на этом, давайте переименуем её. Как насчёт «currentNode»?
const traverseUpUntil = (condition, currentNode) => < do < currentNode = currentNode.parentNode >while (currentNode.parentNode && !condition(currentNode)) return currentNode >
Так-то лучше! Теперь, когда мы читаем метод, мы знаем, что currentNode всегда представляет собой узел, в котором мы сейчас находимся, вместо того, чтобы быть «каким-то» узлом.
- читабельность
- совершенный код
- перевод с английского
- программирование
- разработка
- devcolibri
- никто не читает теги
- Программирование
- Совершенный код