Ваш код может пахнуть! Как это исправить

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

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

В этой статье мы выделим 10 наиболее распространенных запахов кода, что искать и как их дезодорировать. Если вы новый программист

, избегайте этого, и ваш код будет заметно лучше!

1. Плотная муфта

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

Например:

class Worker {
Bike bike = new Bike();
public void commute() {
bike.drive();
}
}

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

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

class Worker {
Vehicle vehicle;
public void changeVehicle(Vehicle v) {
vehicle = v;
}
public void commute() {
vehicle.drive();
}
}
interface Vehicle {
void drive();
}
class Bike implements Vehicle {
public void drive() {
}
}
class Car implements Vehicle {
public void drive() {
}
}

2. Объекты Бога

Эта проблема
Объект God — это массивный класс / модуль, который содержит слишком много переменных и функций. Он «знает слишком много» и «делает слишком много», что проблематично по двум причинам. Во-первых, другие классы / модули становятся слишком зависимыми от этого для данных (тесная связь). Во-вторых, общая структура программы становится грязной, так как все забивается в одно и то же место.

Решение
Возьмите объект Бога, разделите его данные и функции в соответствии с проблемами, которые они существуют для решения, затем превратите эти группировки в объекты. Если у вас есть объект Бога, он может быть лучше в виде композиции из более мелких объектов.

Например, предположим, у вас есть чудовищный класс User:

class User {
public String username;
public String password;
public String address;
public String zipcode;
public int age;
...
public String getUsername() {
return username;
}
public void setUsername(String u) {
username = u;
}
}

Вы могли бы преобразовать это в состав следующего:

class User {
Credentials credentials;
Profile profile;
...
}
class Credentials {
public String username;
public String password;
...
public String getUsername() {
return username;
}
public void setUsername(String u) {
username = u;
}
}

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

3. Длинные функции

Эта проблема
Длинная функция — это то, на что она похожа: функция, которая стала слишком длинной. Хотя не существует определенного числа для того, сколько строк кода является «слишком длинным» для функции, это одна из тех вещей, когда вы это знаете, когда видите это. Это в значительной степени более узкая версия проблемы объекта Бога — длинная функция имеет слишком много обязанностей.

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

4. Чрезмерные параметры

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

Решение
Хотя «слишком много» является субъективным для списка параметров, мы рекомендуем с осторожностью относиться к любой функции, имеющей более 3 параметров. Конечно, иногда имеет смысл иметь одну функцию с 5 или даже 6 параметрами, но только если для этого есть действительно веская причина.

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

5. Плохо названные идентификаторы

Эта проблема
Одно- или двухбуквенные имена переменных. Непонятные имена функций. Чрезмерно украшенные имена классов. Маркировка имен переменных их типом (например, b_isCounting для логической переменной). И что хуже всего, смешивая разные схемы именования в одной кодовой базе. Все это приводит к сложному для чтения, сложному для понимания и сложному в обслуживании коду.

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

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

6. Волшебные числа

Эта проблема
Вы просматриваете какой-то код, который (надеюсь) кто-то написал, и обнаруживаете некоторые жестко закодированные числа. Может быть, они являются частью оператора if, или, может быть, частью некоторых тайных вычислений, которые, кажется, не имеют смысла. Вам нужно изменить функцию, но вы просто не можете понять, что означают цифры. Кий царапает голову.

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

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

7. Глубокое вложение

Эта проблема
Есть два основных способа получить глубоко вложенный код: циклы и условные операторы. Глубоко вложенный код не всегда плох, но может быть проблематичным, потому что его сложно проанализировать (особенно если переменные не названы правильно) и еще сложнее изменить.

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

С другой стороны, глубоко вложенные условные операторы часто являются признаком того, что вы пытаетесь обрабатывать слишком много логики в одной функции или классе. На самом деле глубокая вложенность и длинные функции имеют тенденцию идти рука об руку. Если в вашем коде имеются массивные операторы switch или вложенные операторы if-then-else, вы можете вместо этого реализовать шаблон State Machine или Strategy.

Глубокое вложение особенно распространено среди неопытных программистов игр

!

8. Необработанные исключения

Эта проблема
Исключения являются мощными, но легко злоупотребляют. Ленивые программисты, которые неправильно используют операторы throw-catch, могут значительно усложнить отладку, если не сделать невозможным. Например, игнорирование или скрытие пойманных исключений.

Решение
Вместо того, чтобы игнорировать или скрывать перехваченные исключения, по крайней мере распечатайте трассировку стека исключений, чтобы отладчикам было с чем работать. Разрешение вашей программы молча проваливаться — это гарантированный рецепт будущих головных болей! Кроме того, предпочитайте ловить определенные исключения по сравнению с общими исключениями. Узнайте больше в нашей статье о том, как правильно обрабатывать исключения

,

9. Дубликат Код

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

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

String queryUsername = getSomeUsername();
boolean isUserOnline = false;
for (String username : onlineUsers) {
if (username.equals(queryUsername)) {
isUserOnline = true;
}
}
if (isUserOnline) {
...
}

Где-то еще в коде вы понимаете, что вам нужно выполнить ту же самую проверку «этот пользователь онлайн?». Вместо копирования цикла, вы можете извлечь его в функцию:

public boolean isUserOnline(String queryUsername) {
for (String username : onlineUsers) {
if (username.equals(queryUsername)) {
return true;
}
}
return false;
}

Теперь в любом месте вашего кода вы можете использовать проверку isUserOnline (). Если вам когда-либо понадобится изменить эту логику, вы можете настроить метод, и он будет применяться везде, где он вызывается.

10. Отсутствие комментариев

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

Решение
Целью простой в обслуживании кодовой базы должен быть код, который написан достаточно хорошо, чтобы он не нуждался в комментариях, но все еще имел их. И при написании комментариев стремитесь к комментариям, которые объясняют, почему существует фрагмент кода, а не объясняют, что он делает. Комментарии хороши для души и здравомыслия. Не пренебрегайте ими.

Как написать код, который не пахнет

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

, Например, строгое соблюдение принципа СУХОЙ устраняет большинство дублирования кода, в то время как мастерство принципа единой ответственности делает почти невозможным создание чудовищных объектов Бога.

Мы также рекомендуем прочитать нашу статью о том, как писать более чистый код

, который смотрит на более практическую сторону программирования. Если вы не можете прочитать свой собственный код и понять его с первого взгляда, как кто-нибудь еще? Чистый код — это код без запаха.

С чем вы боретесь больше всего, когда дело касается программирования? Поделитесь с нами в комментариях ниже!

Кредит изображения: SIphotography / Depositphotos

Ссылка на основную публикацию
Adblock
detector