1. Введение
"Чистый код" — не какая-то священная корова, а реальный инструмент выживания программиста. В любом, даже самом прекрасном, ООП-проекте очень быстро накапливается множество классов, полей, методов, хитрых связей… Если нарушить эстетику и структуру, через неделю свой же код становится неразрешимым квестом. Подробнее про "борьбу за выживание" можно почитать у Роберта Мартина, "Чистый код" — как раз о таких битвах.
Стиль в коде — это не про "кому как нравится", а про то, чтобы всем было легче жить:
- Коллега (или вы сами) может быстро понять, что происходит.
- Ошибки (особенно архитектурные) видны сразу.
- Код проще дорабатывать, делая меньше ошибок.
Давайте посмотрим, как сделать ООП-код таким, чтобы его любили проверяющие, коллеги и даже линтеры.
2. Имена: ваша первая линия обороны
Именование классов
Классы в C# принято называть в PascalCase (каждая новая часть слова начинается с большой буквы, например: MyNewClass) и так, чтобы имя чётко отвечало на вопрос "Что это?". Названия должны быть существительными!
public class StudentAccount { /* ... */ }
public class InvoiceGenerator { /* ... */ }
Плохо:
class doMagic { ... } // Плохо: Что за магия? Нарушен PascalCase.
Именование методов
Методы — тоже в PascalCase, но здесь лучше использовать глаголы + объект действия:
public void PrintReport() { ... }
public string GetFormattedName() { ... }
Методы должны отражать действие (Print, Get, Save, Calculate и т.д.), чтобы при чтении было понятно, что произойдет.
Именование полей и свойств
Поля обычно private, называются с маленькой буквы через camelCase, часто с подчеркиванием:
private int _count;
private Student _owner;
Свойства — PascalCase, так как это часть внешнего интерфейса класса:
public int Balance { get; set; }
Переменные
Локальные переменные — camelCase, максимально коротко и понятно к контексту:
string inputName;
int studentCount;
И, пожалуйста, переменные типа a1, result2, something — только если вы хотите создать себе квест на следующий месяц.
3. Организация структуры класса
Правильное расположение членов класса делает навигацию проще и помогает быстро понять, что за чем следует.
Обычно размещают так:
- Конструкторы
- Свойства
- Методы
- Вложенные типы (enum, class и т.д.)
Пример:
public class Student
{
// --- Поля ---
private string _name;
// --- Конструктор ---
public Student(string name)
{
_name = name;
}
// --- Свойства ---
public string Name
{
get => _name;
set => _name = value;
}
// --- Методы ---
public void PrintInfo()
{
Console.WriteLine($"Имя: {_name}");
}
}
Эти "блоки" удобно разделять комментариями (// --- Методы ---), особенно в больших классах. JetBrains Rider, Visual Studio и другие IDE позволяют быстро свернуть/развернуть секции.
4. Комментарии и документация
Комментарии — это хорошо. Но плохо, если ими злоупотреблять или писать "объяснения к непонятному коду", когда можно просто поменять сам код!
Хороший комментарий — тот, который объясняет "почему", а не "что".
// Используем Guid как уникальный идентификатор, т.к. система распределённая
public Guid Id { get; set; }
Документация методов, классов и свойств
Используйте xml-документацию для классов и публичных методов. IDE будут показывать эти описания при наведении курсора.
/// <summary>
/// Представляет студента университета.
/// </summary>
public class Student
{
/// <summary>
/// Имя студента.
/// </summary>
public string Name { get; set; }
}
Что комментировать НЕ надо
- Простые вещи (i++ // увеличиваем i на 1).
- Плохо названные переменные ("// здесь что-то происходит" — ага, но что?).
5. Разделяй и властвуй
Маленькие классы и методы
Золотое правило: один класс — одна ответственность (см. Single Responsibility Principle). Если класс Student делает и учёт оценок, и обработку e-mail, и управление расписанием — что-то тут не так.
- Классы до 300-400 строк — нормально. Больше — повод задуматься.
- Методы до 15-20 строк — читабельно. Исключения бывают, если это метод-обработчик большого кейса.
Пример "раздувшегося" метода:
public void Process()
{
// Уведомление клиента
// Сохраняем изменения
// Отправляем e-mail
// Записываем логи
// ... (15 шагов)
}
Лучше:
public void Process()
{
NotifyClient();
SaveChanges();
SendEmail();
LogActivity();
}
Каждый из методов выделен в отдельный частный метод, код становится компактней и легче для тестирования.
6. Полезные советы
Визуальная структура: форматирование, отступы, пустые строки
IDE умеют красиво форматировать код автоматически (Ctrl+K, D в Visual Studio, Ctrl+Alt+L в Rider), но принципы всё равно надо знать.
- ОТСТУПЫ — 4 пробела. Не табы, не 2 пробела.
- ПУСТЫЕ СТРОКИ — отделяйте методы друг от друга, поля от свойств, свойства от методов.
- СКОБКИ всегда на новой строке для классов и методов (стиль Allman):
public class Test
{
public void Print()
{
Console.WriteLine("Hello");
}
}
"Сильные" и "слабые" члены класса: модификаторы доступа
Всегда старайтесь делать всё максимально закрытым: открывайте только то, что действительно должно быть доступно снаружи. Если поле или метод нужен только внутри класса — делайте его private. Только если должны работать наследники — protected. public — только для контрактов.
Плохо:
public string ConnectionString; // Кто угодно может поменять!
Лучше:
private string _connectionString;
public string ConnectionString
{
get => _connectionString;
private set => _connectionString = value;
}
Использование автоматических свойств
С появлением автоматических свойств и init-only-сеттеров писать "ручные" пропертя стало просто неприлично.
Пример:
public string Name { get; set; } // Отлично!
public int Age { get; init; } // Только для инициализации, безопаснее.
А если нужны вычисляемые свойства:
public string FullName => $"{FirstName} {LastName}";
Инкапсуляция и геттеры/сеттеры
Если у свойства есть некий бизнес-смысл для изменения или контроля, используйте приватное поле + открытый геттер/сеттер с логикой.
private int _grade;
public int Grade
{
get => _grade;
set
{
if (value < 0) _grade = 0;
else if (value > 100) _grade = 100;
else _grade = value;
}
}
Так вы не дадите себе или другим случайно "сломать" объект.
7. Еще полезные советы
Не бойтесь интерфейсов и абстракций
Интерфейсы нужны для удобных контрактов, тестирования и расширения приложения.
Плохо:
- интерфейс с одним методом, который нигде не востребован;
- интерфейс, который реализует только один класс.
- интерфейс, который используют 2+ класса;
- интерфейс для абстракции внешних систем (например, для логгирования, хранения данных).
Пишите код так, чтобы его можно было легко протестировать
Один из признаков хорошего ООП-кода — тестируемость.
- Не делайте методы, в которых всё завязано на глобальные переменные или статические поля.
- Не бойтесь внедрения зависимостей — через параметры конструктора (Dependency Injection).
- Разделяйте вычисления (логику) и взаимодействие с пользователем (ввод/вывод). Это облегчит не только тестирование, но и доработку приложения.
Лайфхаки и анти-паттерны для начинающих
- Не пишите "класс Бога" (God Object), которые делают всё.
- Не делайте "магических чисел" без пояснений (if (status == 42) — почему 42?).
- Не злоупотребляйте наследованием ради наследования — иногда лучше использовать композицию (класс с полями других классов, а не наследник).
- Не пишите сложные методы длиной в 100 строк — их невозможно протестировать и понять.
- Всегда оставляйте место для расширения (open/closed principle).
8. Как выглядят плохой и хороший код
Плохой пример:
class s // Плохо: имя класса с маленькой буквы.
{
public int a; // нет смысла, плохое имя
public void m() // Плохо: метод с именем из одной буквы.
{
Console.WriteLine(a);
// Плохо: непонятно, что делает метод.
}
}
Хороший пример:
// Представляет студента.
public class Student
{
// Возраст студента.
private int _age;
public int Age
{
get => _age;
set => _age = value < 0 ? 0 : value;
}
// Выводит информацию о студенте.
public void PrintInfo()
{
Console.WriteLine($"Возраст студента: {Age}");
}
}
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ