Введение: почему чистый код — это не про эстетику, а про деньги
Представьте, что вы приходите на новую работу, открываете проект на 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)