← Назад к вопросам

Каким должен быть хорошо написанный код?

1.0 Junior🔥 191 комментариев
#Soft Skills и карьера#Тестирование

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Характеристики хорошо написанного кода

Хорошо написанный код — это не просто код, который работает. Это код, который легко понять, поддерживать, расширять и тестировать. За 10+ лет я сформулировал ясные критерии качества.

1. Читаемость (Readability)

Читаемость — это самое важное. Код читается в 10 раз чаще, чем пишется.

// Плохо - трудно понять
public int c(int[] a) {
    int r = 0;
    for (int x : a) r += x;
    return r;
}

// Хорошо - ясная цель
public int sumArray(int[] numbers) {
    int sum = 0;
    for (int number : numbers) {
        sum += number;
    }
    return sum;
}

// Или ещё лучше
public int sumArray(int[] numbers) {
    return Arrays.stream(numbers).sum();
}

Правила читаемости:

  • Осмысленные имена переменных, методов, классов
  • Коротко функции (максимум 50 строк)
  • Понятная логика без nested conditions
  • Комментарии только для ПОЧЕМУ, не для ЧТО

2. Простота (Simplicity)

KISS (Keep It Simple, Stupid) — не усложняй без необходимости.

// Переусложнено
public Optional<User> findUser(String email) {
    try {
        return Optional.ofNullable(
            userRepository.findByEmail(email)
                .orElseThrow(NoSuchElementException::new)
        );
    } catch (Exception e) {
        logger.error("Error finding user", e);
        return Optional.empty();
    }
}

// Просто и ясно
public Optional<User> findUser(String email) {
    return userRepository.findByEmail(email);
}

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

3. Тестируемость (Testability)

Хорошо написанный код легко тестировать.

// Сложно тестировать
public class OrderService {
    public void processOrder(Order order) {
        Database.save(order);
        EmailClient.send("Order confirmed");
        PaymentGateway.charge(order.getTotal());
    }
}

// Легко тестировать
public class OrderService {
    private final OrderRepository orderRepository;
    private final EmailService emailService;
    private final PaymentService paymentService;
    
    public void processOrder(Order order) {
        orderRepository.save(order);
        emailService.sendConfirmation(order);
        paymentService.charge(order);
    }
}

4. SOLID принципы

S - Single Responsibility — одна ответственность:

// Плохо
public class User {
    public void save() { /* DB */ }
    public void sendEmail() { /* Email */ }
    public void generateReport() { /* Report */ }
}

// Правильно
public class User { /* только данные */ }
public class UserRepository { /* сохранение */ }
public class EmailService { /* email */ }
public class UserReportGenerator { /* отчёты */ }

O - Open/Closed — открыт для расширения, закрыт для модификации:

// Плохо - много условий
public class PaymentProcessor {
    public void process(String type, Payment payment) {
        if ("credit_card".equals(type)) {
            // логика Visa
        } else if ("paypal".equals(type)) {
            // логика PayPal
        }
    }
}

// Правильно
public interface PaymentGateway {
    void process(Payment payment);
}

public class CreditCardGateway implements PaymentGateway {
    public void process(Payment payment) { /* Visa */ }
}

L - Liskov Substitution — полиморфизм работает правильно

I - Interface Segregation — узкие интерфейсы:

// Плохо - большой интерфейс
public interface UserService {
    void createUser(User user);
    void updateUser(User user);
    void deleteUser(String id);
    void sendEmail(String email);
    void generateReport();
}

// Правильно - узкие интерфейсы
public interface UserRepository {
    void save(User user);
    void update(User user);
    void delete(String id);
}

D - Dependency Inversion — зависит от абстракций:

// Плохо
public class OrderService {
    private PostgresDatabase db = new PostgresDatabase();
}

// Правильно
public class OrderService {
    private final Database db;
    
    public OrderService(Database db) {
        this.db = db;
    }
}

5. Отсутствие дублирования (DRY)

Don't Repeat Yourself — не копируй код.

// Дублирование
public void processOrder() {
    if (order == null) throw new IllegalArgumentException();
    if (order.getTotal() <= 0) throw new IllegalArgumentException();
}

public void processPayment() {
    if (payment == null) throw new IllegalArgumentException();
    if (payment.getAmount() <= 0) throw new IllegalArgumentException();
}

// Правильно - общая валидация
private <T> void validateNotNull(T value) {
    if (value == null) throw new IllegalArgumentException();
}

private void validatePositive(BigDecimal amount) {
    if (amount.compareTo(BigDecimal.ZERO) <= 0) {
        throw new IllegalArgumentException();
    }
}

6. Обработка ошибок

// Плохо - скрываешь ошибку
try {
    database.save(user);
} catch (Exception e) {
    // Молча игнорируем
}

// Правильно
try {
    database.save(user);
} catch (DatabaseException e) {
    logger.error("Failed to save user: {}", user.getId(), e);
    throw new ApplicationException("Could not save user", e);
}

7. Производительность

Хороший код должен быть эффективным:

// Неэффективно - N+1 query problem
for (Order order : orders) {
    customer = database.findCustomer(order.getCustomerId());
    process(order, customer);
}

// Правильно
Map<String, Customer> customers = database.findAllCustomers();
for (Order order : orders) {
    Customer customer = customers.get(order.getCustomerId());
    process(order, customer);
}

8. Документация

/**
 * Обрабатывает заказ и отправляет подтверждение.
 * Если платёж не прошёл, выбрасывает PaymentException.
 * 
 * @param order заказ для обработки
 * @throws PaymentException если платёж не удался
 * @throws DatabaseException если ошибка БД
 */
public void processOrder(Order order) throws PaymentException, DatabaseException {
    // ...
}

Чеклист хорошего кода

  • Читаемо — любой разработчик поймёт
  • Просто — нет ненужной сложности
  • Тестируемо — есть unit тесты (80%+ coverage)
  • SOLID — следует принципам
  • DRY — нет дублирования
  • Обработаны ошибки — нет молчаливого игнорирования
  • Производительно — нет очевидных bottleneck'ов
  • Документировано — сложная логика объяснена
  • Поддерживаемо — можно изменять без страха

Золотое правило

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