Чистый код на C#: как писать так, чтобы не стыдно было показать коллегам

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему чистый код — это не про эстетику, а про деньги

Представьте, что вы приходите на новую работу, открываете проект на C# и видите метод длиной в 500 строк, переменные a, b, temp, а комментарии написаны на смеси русского и английского. Знакомо? Скорее всего, да. Такой код работает, но его поддержка превращается в ад. Чистый код на C# — это не прихоть перфекциониста, а инструмент, который экономит часы, нервы и деньги команды.

В этой статье мы не будем читать морали. Вместо этого разберем конкретные приёмы, которые помогут вам писать на C# так, чтобы код был понятен новичку и радовал опытного разработчика. Поехали!

1. Имена имеют значение: как называть переменные, методы и классы

Самый простой способ сделать код чище — давать осмысленные имена. C# строг к регистру, но это не оправдание для int x или string d.

Переменные: говорите, что храните

Плохо:

int d; // что это? дата? дистанция? деньги?
string n; // имя? номер? ноутбук?

Хорошо:

int daysUntilDeadline;
string userName;

Правило простое: если через месяц вы не сможете понять, что хранит переменная без комментария — имя плохое. Избегайте сокращений вроде usr или cnt — они экономят секунду при наборе, но отнимают минуты при чтении.

Методы: глагол + существительное

Метод — это действие. Называйте его так, чтобы было ясно, что он делает:

  • CalculateTotalPrice() — считает общую цену;
  • SendEmailNotification() — отправляет уведомление;
  • ValidateUserInput() — проверяет ввод пользователя.

Плохой пример: ProcessData() — слишком абстрактно. Что значит "обработать"? Удалить? Преобразовать? Сохранить?

Классы: существительные во множественном или единственном числе

Класс — это сущность. User, Order, PaymentProcessor. Избегайте суффиксов вроде Manager или Helper, если это не оправдано архитектурой. Часто такие классы становятся "свалкой" для всего подряд.

2. Методы должны быть маленькими и делать одну вещь

Золотое правило чистого кода: метод должен решать одну задачу и решать её хорошо. Если метод занимает больше 20–30 строк — скорее всего, его нужно разбить.

Пример: рефакторинг монстра

Представьте метод, который регистрирует пользователя:

public void RegisterUser(string name, string email)
{
    // валидация
    if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException();
    if (!email.Contains("@")) throw new ArgumentException();
    // сохранение в БД
    using var db = new AppDbContext();
    var user = new User { Name = name, Email = email };
    db.Users.Add(user);
    db.SaveChanges();
    // отправка письма
    var smtp = new SmtpClient();
    smtp.Send("admin@site.com", email, "Welcome", "Hello!");
}

Что здесь не так? Три ответственности: валидация, работа с БД, отправка email. Если изменится логика отправки, придётся трогать метод регистрации. Разобьём:

public void RegisterUser(string name, string email)
{
    ValidateUser(name, email);
    var user = CreateUser(name, email);
    SaveUser(user);
    SendWelcomeEmail(email);
}

private void ValidateUser(string name, string email)
{
    if (string.IsNullOrWhiteSpace(name)) 
        throw new ArgumentException("Name is required", nameof(name));
    if (!email.Contains("@")) 
        throw new ArgumentException("Invalid email", nameof(email));
}

private User CreateUser(string name, string email)
{
    return new User { Name = name, Email = email };
}

private void SaveUser(User user)
{
    using var db = new AppDbContext();
    db.Users.Add(user);
    db.SaveChanges();
}

private void SendWelcomeEmail(string email)
{
    var smtp = new SmtpClient();
    smtp.Send("admin@site.com", email, "Welcome", "Hello!");
}

Теперь каждый метод делает ровно одно. Код стал длиннее, но читать и тестировать его в разы проще. Это и есть чистый код на C# — жертвуем краткостью ради ясности.

3. Комментарии: меньше — лучше, но без фанатизма

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

Когда комментарии полезны

  • Объяснение бизнес-логики: "// скидка 10% для новых клиентов";
  • Предупреждения о сложных алгоритмах: "// O(n^2), но данные редко превышают 100 записей";
  • Ссылки на внешние требования: "// согласно спецификации ISO 12345".

Когда комментарии — зло

  • Очевидные вещи: // увеличиваем счётчик на 1 (и так понятно);
  • Закомментированный код: если код не нужен — удалите его, он в Git;
  • Комментарии-оправдания: "// не трогать, иначе всё сломается".

4. Работа с исключениями: не глотайте ошибки

Одна из самых частых проблем в C# — пустые блоки catch. Они превращают отладку в квест.

Плохо:

try
{
    // опасный код
}
catch (Exception ex)
{
    // ничего не делаем — ошибка проглочена
}

Хорошо:

try
{
    // опасный код
}
catch (SpecificException ex) when (ex.ErrorCode == 42)
{
    _logger.LogError(ex, "Ошибка при обработке заказа {OrderId}", orderId);
    throw; // пробрасываем дальше, если не можем обработать
}

Правила простые:

  • Ловите только те исключения, которые можете обработать;
  • Используйте фильтры (when) для уточнения условий;
  • Всегда логируйте ошибки — это спасёт вас в продакшене;
  • Не используйте catch (Exception) без крайней необходимости.

5. LINQ: мощь и опасность в одном флаконе

LINQ делает код на C# лаконичным, но злоупотребление им может привести к нечитаемым конструкциям.

Плохой пример: "однострочник-монстр"

var result = orders.Where(o => o.Status == "Active")
    .SelectMany(o => o.Items)
    .GroupBy(i => i.Category)
    .Select(g => new { Category = g.Key, Total = g.Sum(i => i.Price * i.Quantity) })
    .Where(x => x.Total > 1000)                

Блоги

Рекомендаций по книгам