Clean Code на C#: принципы и примеры на практике

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

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

Начать курс

Clean Code на C#: принципы и примеры на практике

Чистый код (Clean Code) — это не просто модный тренд в разработке, а фундаментальный подход, который определяет успех любого программного проекта на C#. Писать код, который легко читать, поддерживать и расширять, — навык, отличающий профессионала от новичка. В этой статье мы разберем ключевые принципы Clean Code на практических примерах для .NET-разработчиков.

Почему Clean Code важен для C# проектов

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

  • Сократить время на отладку и рефакторинг
  • Уменьшить количество багов за счет ясной логики
  • Улучшить командную работу и код-ревью
  • Повысить производительность разработки в долгосрочной перспективе

Принцип 1: Говорящие имена и единый стиль

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

Плохой пример

public class Data
{
    public int a { get; set; }
    public string b { get; set; }
    public void Do()
    {
        // какая-то логика
    }
}

Хороший пример

public class Customer
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public void SendWelcomeEmail()
    {
        // логика отправки приветственного письма
    }
}

Используйте camelCase для локальных переменных, PascalCase для классов и методов. Избегайте сокращений, если они не общеприняты (например, Id вместо Identifier).

Принцип 2: Маленькие методы с одной ответственностью

Каждый метод должен выполнять ровно одну задачу. Это делает код тестируемым и переиспользуемым. Если метод занимает больше 15-20 строк — пора его разбивать.

Плохой пример

public void ProcessOrder(Order order)
{
    // Валидация
    if (order.Total <= 0) throw new Exception("Invalid order");
    // Сохранение в БД
    _context.Orders.Add(order);
    _context.SaveChanges();
    // Отправка email
    var emailService = new EmailService();
    emailService.Send(order.CustomerEmail, "Order confirmed");
}

Хороший пример

public void ProcessOrder(Order order)
{
    ValidateOrder(order);
    SaveOrder(order);
    SendConfirmationEmail(order);
}

private void ValidateOrder(Order order)
{
    if (order.Total <= 0)
        throw new ArgumentException("Order total must be positive");
}

private void SaveOrder(Order order)
{
    _context.Orders.Add(order);
    _context.SaveChanges();
}

private void SendConfirmationEmail(Order order)
{
    var emailService = new EmailService();
    emailService.Send(order.CustomerEmail, "Order confirmed");
}

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

Принцип 3: Избегайте магических чисел и строк

Магические числа и строки — одна из главных причин трудночитаемого кода. Выносите их в константы или конфигурационные файлы.

Плохой пример

if (user.Role == 3)
{
    // логика для администратора
}
if (DateTime.Now.Hour > 18)
{
    // вечерняя скидка
}

Хороший пример

private const int AdminRoleId = 3;
private const int EveningDiscountStartHour = 18;

if (user.RoleId == AdminRoleId)
{
    // логика для администратора
}
if (DateTime.Now.Hour > EveningDiscountStartHour)
{
    // вечерняя скидка
}

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

Принцип 4: Принцип DRY (Don't Repeat Yourself)

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

Плохой пример

public decimal CalculateDiscount(Order order)
{
    if (order.Total > 1000) return order.Total * 0.1m;
    if (order.Total > 500) return order.Total * 0.05m;
    return 0;
}

public decimal CalculateBonus(Order order)
{
    if (order.Total > 1000) return order.Total * 0.15m;
    if (order.Total > 500) return order.Total * 0.07m;
    return 0;
}

Хороший пример

private const decimal HighThreshold = 1000;
private const decimal MediumThreshold = 500;

public decimal CalculateDiscount(Order order) => 
    CalculatePercentage(order.Total, 0.1m, 0.05m, 0);

public decimal CalculateBonus(Order order) => 
    CalculatePercentage(order.Total, 0.15m, 0.07m, 0);

private decimal CalculatePercentage(decimal amount, decimal highRate, 
    decimal mediumRate, decimal lowRate)
{
    if (amount > HighThreshold) return amount * highRate;
    if (amount > MediumThreshold) return amount * mediumRate;
    return amount * lowRate;
}

Обратите внимание: мы не только убрали дублирование, но и сделали логику гибкой для изменений.

Принцип 5: Работа с исключениями

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

Плохой пример

try
{
    var data = _repository.GetData();
    ProcessData(data);
}
catch (Exception ex)
{
    // Пустой блок — ошибка проглатывается
}

Хороший пример

try
{
    var data = _repository.GetData();
    ProcessData(data);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("not found"))
{
    _logger.LogWarning("Data not found, returning default");
    return GetDefaultData();
}
catch (SqlException ex)
{
    _logger.LogError(ex, "Database error occurred");
    throw; // Пробрасываем дальше
}

Используйте when для фильтрации исключений и всегда логируйте ошибки на соответствующем уровне.

Заключение

Clean Code в C# — это не

Блоги

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