CodeGym /Kurslar /C# SELF /OOP kodunun stili və oxunaqlılığı üçün məsləhətlər

OOP kodunun stili və oxunaqlılığı üçün məsləhətlər

C# SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

"Təmiz kod" — hansısa müqəddəs inək deyil, proqramçının sağ qalma alətidir. İstənilən, hətta ən gözəl OOP layihəsində belə, çox tez bir zamanda bir yığın sinif, field, metod, hiyləgər əlaqələr yığılır... Əgər estetika və strukturu pozsan, bir həftəyə öz kodun sanki həllolunmaz bir questə çevrilir. "Sağ qalmaq uğrunda mübarizə" barədə daha ətraflı Robert Martin-in "Təmiz kod" kitabında oxuya bilərsən — məhz belə döyüşlərdən bəhs edir.

Kodda stil — "kim necə istəyir" deyil, hamının həyatını asanlaşdırmaq üçündür:

  • Həmkarın (ya da özün) tez başa düşə bilər ki, nə baş verir.
  • Səhvlər (xüsusilə arxitektura səhvləri) dərhal görünür.
  • Kodu inkişaf etdirmək asan olur, daha az səhv edirsən.

Gəlin baxaq, OOP kodunu necə elə yazaq ki, yoxlayanlar, həmkarlar və hətta linter-lər belə onu sevsin.

2. Adlar: sənin ilk müdafiə xəttin

Siniflərin adlandırılması

Siniflər C#-da adətən PascalCase ilə adlandırılır (hər yeni söz böyük hərflə başlayır, məsələn: MyNewClass) və ad elə olmalıdır ki, "Bu nədir?" sualına aydın cavab versin. Adlar mütləq isim olmalıdır!

public class StudentAccount { /* ... */ }
public class InvoiceGenerator { /* ... */ }

Pis nümunə:

class doMagic { ... } // Pis: Nə magiya? PascalCase pozulub.

Metodların adlandırılması

Metodlar da PascalCase ilə yazılır, amma burada daha yaxşıdır ki, fel + obyekt formasında olsun:

public void PrintReport() { ... }
public string GetFormattedName() { ... }

Metodlar hərəkəti əks etdirməlidir (Print, Get, Save, Calculate və s.), ki oxuyanda dərhal başa düşəsən nə olacaq.

Field və property-lərin adlandırılması

Field-lər adətən private olur, kiçik hərflə və camelCase ilə, çox vaxt alt xətt ilə:

private int _count;
private Student _owner;

Property-lər isə PascalCase ilə yazılır, çünki bunlar sinifin xarici interfeysinin bir hissəsidir:

public int Balance { get; set; }

Dəyişənlər

Lokal dəyişənlərcamelCase ilə, maksimum qısa və kontekstə uyğun:

string inputName;
int studentCount;

Və xahiş, a1, result2, something tipli dəyişənlər — ancaq özünə gələn ay üçün quest yaratmaq istəyirsənsə yaz.

3. Sinif strukturunun təşkili

Sinif üzvlərinin düzgün yerləşdirilməsi naviqasiyanı asanlaşdırır və tez başa düşməyə kömək edir ki, nə haradadır.

Adətən belə düzülür:

  1. Konstruktorlar
  2. Property-lər
  3. Metodlar
  4. Daxili tiplər (enum, class və s.)

Nümunə:


public class Student
{
    // --- Field-lər ---
    private string _name;

    // --- Konstruktor ---
    public Student(string name)
    {
        _name = name;
    }

    // --- Property-lər ---
    public string Name
    {
        get => _name;
        set => _name = value;
    }

    // --- Metodlar ---
    public void PrintInfo()
    {
        Console.WriteLine($"Ad: {_name}");
    }
}

Bu "blokları" şərhlərlə ayırmaq rahatdır (// --- Metodlar ---), xüsusilə böyük siniflərdə. JetBrains Rider, Visual Studio və digər IDE-lər bu bölmələri tez qatlamağa/açmağa imkan verir.

4. Şərhlər və sənədləşmə

Şərhlər — yaxşıdır. Amma pisdir, əgər onlardan həddindən artıq istifadə edirsənsə və ya "anlaşılmaz kodu izah edən" şərhlər yazırsansa, halbuki kodun özünü dəyişmək olar!

Yaxşı şərh — "niyə" sualını izah edən şərhdir, "nə" deyil.

// Guid istifadə edirik unikal identifikator kimi, çünki sistem paylanmışdır
public Guid Id { get; set; }

Metodların, siniflərin və property-lərin sənədləşməsi

Siniflər və public metodlar üçün xml-dokumentasiya istifadə et. IDE-lər bu təsvirləri kursoru gətirəndə göstərir.


/// <summary>
/// Universitet tələbəsini təmsil edir.
/// </summary>
public class Student
{
    /// <summary>
    /// Tələbənin adı.
/// </summary>
    public string Name { get; set; }
}

NƏYİ şərh etməyə ehtiyac yoxdur

  • Sadə şeylər (i++ // i-ni 1 artırırıq).
  • Pis adlandırılmış dəyişənlər ("// burada nəsə baş verir" — hə, amma nə?).

5. Böl və hökm sür

Kiçik siniflər və metodlar

Qızıl qayda: bir sinif — bir məsuliyyət (bax: Single Responsibility Principle). Əgər Student sinifi həm qiymətləri aparır, həm e-mail işləyir, həm də cədvəli idarə edir — burada nəsə düz deyil.

  • Siniflər 300-400 sətrə qədər — normaldır. Daha çox — düşünməyə səbəbdir.
  • Metodlar 15-20 sətrə qədər — oxunaqlıdır. İstisnalar ola bilər, əgər böyük case-in handler-metodudursa.

"Şişmiş" metod nümunəsi:


public void Process()
{
    // Müştəriyə bildiriş
    // Dəyişiklikləri saxla
    // E-mail göndər
    // Log yaz
    // ... (15 addım)
}

Daha yaxşı:


public void Process()
{
    NotifyClient();
    SaveChanges();
    SendEmail();
    LogActivity();
}

Hər bir addım ayrıca private metoda çıxarılıb, kod daha yığcam və test üçün rahat olur.

6. Faydalı məsləhətlər

Vizual struktur: formatlama, boşluqlar, boş sətirlər

IDE-lər kodu avtomatik gözəl formatlaya bilir (Ctrl+K, D Visual Studio-da, Ctrl+Alt+L Rider-də), amma prinsipləri bilmək yenə də lazımdır.

  • BOŞLUQLAR — 4 boşluq. Tab yox, 2 boşluq yox.
  • BOŞ SƏTİRLƏR — metodları bir-birindən, field-ləri property-lərdən, property-ləri metodlardan ayır.
  • MÖTƏRİZƏLƏR həmişə yeni sətrdə olsun (Allman stili):

public class Test
{
    public void Print()
    {
        Console.WriteLine("Salam");
    }
}

"Güclü" və "zəif" sinif üzvləri: access modifier-lər

Həmişə çalış hər şeyi maksimum qapalı saxla: yalnız həqiqətən xaricdən lazım olanı aç. Əgər field və ya metod yalnız sinif daxilində lazımdırsa — private et. Yalnız mirasçılar üçün lazımdırsa — protected. public — yalnız kontraktlar üçün.

Pis nümunə:

public string ConnectionString; // İstənilən dəyişə bilər!

Daha yaxşı:


private string _connectionString;
public string ConnectionString
{
    get => _connectionString;
    private set => _connectionString = value;
}

Avtomatik property-lərdən istifadə

Avtomatik property-lər və init-only setter-lər gələndən "əl ilə" property yazmaq artıq ayıbdır.

Nümunə:


public string Name { get; set; } // Əla!
public int Age { get; init; }    // Yalnız init üçün, daha təhlükəsiz.

Əgər hesablama property-si lazımdırsa:


public string FullName => $"{FirstName} {LastName}";

Encapsulation və getter/setter-lər

Əgər property-də dəyişiklik və ya nəzarət üçün biznes-məna varsa, private field + açıq getter/setter ilə yaz.


private int _grade;
public int Grade
{
    get => _grade;
    set
    {
        if (value < 0) _grade = 0;
        else if (value > 100) _grade = 100;
        else _grade = value;
    }
}

Beləliklə, özün və ya başqası təsadüfən obyekti "sındıra" bilməz.

7. Daha bir neçə faydalı məsləhət

İnterfeyslərdən və abstraksiyalardan qorxma

İnterfeyslər rahat kontraktlar, test və tətbiqin genişlənməsi üçündür.

Pis:

  • bir metodlu interfeys, heç yerdə istifadə olunmur;
  • yalnız bir sinifin implement etdiyi interfeys.
Yaxşı:
  • 2+ sinifin istifadə etdiyi interfeys;
  • xarici sistemlərin abstraksiyası üçün interfeys (məsələn, logging, data storage üçün).

Kodu elə yaz ki, asan test olunsun

Yaxşı OOP kodunun əlamətlərindən biri — test oluna bilməsidir.

  • Metodları elə yazma ki, hər şey global dəyişənlərə və ya static field-lərə bağlı olsun.
  • Dependency Injection-dan qorxma — konstruktor parametrləri ilə ötür (Dependency Injection).
  • Hesablamaları (logika) və istifadəçi ilə əlaqəni (input/output) ayır. Bu, təkcə test yox, həm də tətbiqin inkişafını asanlaşdıracaq.

Yeni başlayanlar üçün lifehack-lər və anti-pattern-lər

  • "God Object" (God Object) yazma, hər şeyi edən siniflərdən uzaq dur.
  • İzahı olmayan "sehrli ədədlər" yazma (if (status == 42) — niyə 42?).
  • Sadəcə miras üçün mirasdan istifadə etmə — bəzən composition daha yaxşıdır (başqa siniflərin field-ləri olan sinif, yoxsa mirasçı).
  • 100 sətrlik mürəkkəb metodlar yazma — onları nə test etmək, nə başa düşmək olur.
  • Həmişə genişlənmə üçün yer saxla (open/closed principle).

8. Pis və yaxşı kod necə görünür

Pis nümunə:


class s // Pis: sinif adı kiçik hərflə.
{
    public int a; // mənası yoxdur, pis ad
    public void m() // Pis: metodun adı bir hərf.
    {
        Console.WriteLine(a);
        // Pis: metodun nə etdiyi aydın deyil.
    }
}

Yaxşı nümunə:


// Tələbəni təmsil edir.
public class Student
{
    // Tələbənin yaşı.    
    private int _age;
    public int Age
    {
        get => _age;
        set => _age = value < 0 ? 0 : value;
    }

    // Tələbə haqqında məlumatı çıxarır.
    public void PrintInfo()
    {
        Console.WriteLine($"Tələbənin yaşı: {Age}");
    }
}
1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
İrsi əlaqədə səhvlər
Sinif və obyekt elanında tez-tez rast gəlinən səhvlər
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION