Чтобы стать отличным рецензентом, нужна практика, начните здесь!

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

Предоставление обратной связи для CR может быть сложным поначалу. Младшие инженеры могут бояться критиковать код старшего инженера, но такое мышление мешает обучению! Старший инженер не научился предлагать полезные и конструктивные комментарии к CR за ночь — вероятно, ему потребовались годы проверки кода, чтобы достичь своих текущих навыков.

Практика делает совершенным, так что давайте погрузимся в 10 примеров CR и как вы могли бы улучшить их самостоятельно!

#1 — Дублирование кода

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

Пример:

public int calculateTotal(List<Integer> prices) {
    int total = 0;
    for (int price : prices) {
        total += price;
    }
    return total;
}

public double calculateAverage(List<Integer> prices) {
    int total = 0;
    for (int price : prices) {
        total += price;
    }
    return total / prices.size();
}

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

public int calculateTotal(List<Integer> prices) {
    int total = 0;
    for (int price : prices) {
        total += price;
    }
    return total;
}

public double calculateAverage(List<Integer> prices) {
    int total = calculateTotal(prices);
    return total / prices.size();
}

# 2 — Непоследовательные соглашения об именах

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

Пример:

public void getUserData() {
    ...
}

public void retrieveCustomerInfo() {
    ...
}

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

public void getUserData() {
    ...
}

public void getCustomerInfo() {
    ...
}

№3 — Отсутствие комментариев

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

Пример:

public String encryptData(String data, String key) {
    // encrypt data
    return encryptedData;
}

В приведенном выше примере показан метод, который шифрует данные, но не поясняется, как выполняется шифрование. Чтобы исправить эту проблему, метод должен быть прокомментирован, чтобы объяснить, как работает шифрование.

public String encryptData(String data, String key) {
    /*
    This method uses the AES encryption algorithm to encrypt the data.
    The key parameter is used as the encryption key.
    */
    // encrypt data using AES algorithm
    return encryptedData;
}

#4 — Отсутствие обработки ошибок

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

Пример:

public int divide(int a, int b) {
    return a / b;
}

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

public int divide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Cannot divide by zero");
    }
    return a / b;
}

№5 — Излишняя сложность

Слишком сложная кодовая база может затруднить ее понимание и поддержку. Важно, чтобы код был максимально простым, но при этом соответствовал требованиям.

Пример:

public boolean isValid(String input) {
    if (input == null) return false;
    if (input.length() < 6) return false;
    if (input.contains(" ")) return false;
    if (!input.matches("[a-zA-Z0-9]+")) return false;
    return true;
}

В приведенном выше примере показан метод, который проверяет допустимость строки, но использует несколько операторов if. Это можно упростить, используя регулярное выражение.

public boolean isValid(String input) {
    return input != null && input.matches("^\\S{6,}$");
}

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

№ 6 — Игнорирование лучших практик

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

Пример:

public String formatAddress(String street, String city, String state, String zip) {
    return street + ", " + city + ", " + state + " " + zip;
}

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

public String formatAddress(String street, String city, String state, String zip) {
    StringBuilder address = new StringBuilder();
    address.append(street);
    address.append(", ");
    address.append(city);
    address.append(", ");
    address.append(state);
    address.append(" ");
    address.append(zip);
    return address.toString();
}

Или еще лучше:

public String formatAddress(String street, String city, String state, String zip) {
    return String.format("%s, %s, %s %s", street, city, state, zip);
}

#7 — Игнорирование безопасности

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

Пример:

public void storePassword(String password) {
    String sql = "INSERT INTO users (password) VALUES ('" + password + "')";
    statement.executeUpdate(sql);
}

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

public void storePassword(String password) {
    String sql = "INSERT INTO users (password) VALUES (?)";
    PreparedStatement statement = connection.prepareStatement(sql);
    statement.setString(1, password);
    statement.executeUpdate();
}

О, и убедитесь, что вы передаете этот пароль в виде зашифрованной строки. ;)

#8 — Жестко закодированные значения конфигурации

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

Пример:

public void connectToDatabase() {
    String connectionString = "jdbc:mysql://localhost:3306/mydb";
    String username = "root";
    String password = "password";
    Connection connection = DriverManager.getConnection(connectionString, username, password);
}

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

public void connectToDatabase() {
    Properties prop = new Properties();
    InputStream input = new FileInputStream("config.properties");
    prop.load(input);
    String connectionString = prop.getProperty("db.connectionString");
    String username = prop.getProperty("db.username");
    String password = prop.getProperty("db.password");
    Connection connection = DriverManager.getConnection(connectionString, username, password);
}

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

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