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 і облік оцінок веде, і електронну пошту обробляє, і розкладом керує — щось тут не так.
- Класи до 300–400 рядків — це нормально. Більше — привід замислитися.
- Методи до 15–20 рядків — читабельно. Винятки бувають, якщо це метод-обробник великого кейсу.
Приклад «роздутого» методу:
public void Process()
{
// Сповіщаємо клієнта
// Зберігаємо зміни
// Надсилаємо електронний лист
// Записуємо журнали
// ... (15 кроків)
}
Краще:
public void Process()
{
NotifyClient();
SaveChanges();
SendEmail();
LogActivity();
}
Кожен із кроків винесено в окремий приватний метод — код стає компактнішим і легшим для тестування.
6. Корисні поради
Візуальна структура: форматування, відступи, порожні рядки
IDE можуть акуратно форматувати код автоматично (Ctrl+K, D у Visual Studio, Ctrl+Alt+L у Rider), але принципи все одно треба знати.
- Відступи — 4 пробіли. Не табуляції, не два пробіли.
- Порожні рядки — відділяйте методи один від одного, поля від властивостей, властивості від методів.
- Дужки — завжди на новому рядку для класів і методів (стиль Allman):
public class Test
{
public void Print()
{
Console.WriteLine("Привіт");
}
}
«Сильні» і «слабкі» члени класу: модифікатори доступу
Завжди намагайтеся робити все максимально закритим: відкривайте лише те, що справді має бути доступне ззовні. Якщо поле чи метод потрібен лише всередині класу — робіть його 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. Ще корисні поради
Не бійтеся інтерфейсів і абстракцій
Інтерфейси потрібні для зручних контрактів, тестування і розширення застосунку.
Погано:
- інтерфейс з одним методом, що ніде не потрібен;
- інтерфейс, який реалізує лише один клас.
- інтерфейс, який використовують два й більше класи;
- інтерфейс для абстракції зовнішніх систем (наприклад, для логування, зберігання даних).
Пишіть код так, щоб його можна було легко протестувати
Одна з ознак якісного ООП-коду — тестованість.
- Не робіть методи, у яких усе зав’язано на глобальні змінні чи статичні поля.
- Не бійтеся впроваджувати залежності — через параметри конструктора (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}");
}
}
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ