Makaron kodu (spagetti kodu, əriştə) — proqramın qarışıq, xaotik strukturudur, burada məntiqi bloklar heç bir nizam olmadan bir-birinə qarışıb. TIOBE Index (2024) araşdırmasına görə, yüksək səviyyəli spagetti kodu olan layihələr yeni funksiyaların tətbiqi üçün 2,5 dəfə çox vaxt tələb edir. Bu termin erkən proqramlaşdırma dövründə yaranıb, o zaman goto operatoru proqramın istənilən nöqtələri arasında sıçramağa imkan verərək oxunmaz konstruksiyalar yaradırdı.
Əsas məqamlar
Makaron kodu (spaghetti code) — kodu təsvir edən metaforadır, strukturuna görə bir boşqab spagettini xatırladır: ayrı-ayrı saplar (məntiqi bloklar) bir-birinə qarışıb, yapışıb və ayrılmazdır. Belə kodu layları, modulları və ya komponentləri ayırmaq mümkün deyil — hər şey bir böyük kütlədə qarışıb.
Pis koddan fərqli olaraq, makaron kodu fundamental memarlıq problemidir. Hətta mükəmməl formatlaşdırılmış kod yaxşı dəyişən adları ilə spagetti kodu ola bilər, əgər onun memarlığı xaotikdirsə. Problem proqramın struktur səviyyəsindədir, yazı tərzində deyil.
IEEE məlumatına görə (2022), böyük layihələrdə bütün səhvlərin təxminən 35%-i məhz kodun qarışıq strukturundan qaynaqlanır, proqramçının məntiqi səhvlərindən deyil. Proqramçı səhv edir, çünki tapşırığı səhv başa düşməyib, spagetti kodunda icra axınını izləyə bilmədiyi üçün.
Əgər pis kod bir funksiya və ya fayl miqyasında pis koddursa, makaron kodu bütün tətbiq miqyasında pis memarlıqdır. Əriştə ayrı-ayrı yaxşı yazılmış funksiyalardan ibarət ola bilər, lakin onların qarşılıqlı əlaqəsi xaotik və gözlənilməzdir.
Termin "spaghetti code" 1970-ci illərdə goto operatorunun tənqidi ilə birlikdə ortaya çıxdı. Erkən proqramlaşdırma dillərində (BASIC, FORTRAN, COBOL) goto icra axınını idarə etməyin əsas üsulu idi. Proqram nömrələnmiş sətirlər ardıcıllığından ibarət idi və goto onlardan hər hansı birinə keçməyə imkan verirdi. Bu, açılması mümkün olmayan keçidlər "dolaşıqlığı" yaradırdı.
1968-ci ildə Edsger Dijkstra "Go To Statement Considered Harmful" adlı məşhur məktubu dərc etdi və bu, strukturlaşdırılmış proqramlaşdırma dövrünün başlanğıcını qoydu. Dijkstra sübut etdi ki, istənilən alqoritm goto olmadan yalnız üç konstruksiyadan istifadə etməklə reallaşdırıla bilər: ardıcıllıq, budaqlanma (if) və dövr (while). Bu, müasir proqramlaşdırmanın təməli oldu.
Strukturlaşdırılmış proqramlaşdırma problemi tamamilə aradan qaldırmadı. Makaron kodu yeni səviyyəyə keçdi — fiziki goto əvəzinə proqramçılar məntiqi "goto" yaratmağa başladılar: qlobal dəyişənlər, JavaScript-də callback hell, mürəkkəb çağırış zəncirləri və komponentlər arasında gizli asılılıqlar. Problem qaldı, yalnız forması dəyişdi.
Callback hell JavaScript-də, dərin yuvalanmış Promise, xəta idarəetməsi olmayan async/await, kimin və nə vaxt işə saldığı bəlli olmayan hadisələr — bunların hamısı spagetti kodunun müasir növləridir. Anti-pattern yaşayır və inkişaf edir, sadəcə indi goto operatorundan istifadə etmir.
Layların olmaması — ilk və əsas əlamət. Makaron kodunda biznes məntiqi, verilənlər bazası ilə iş, HTML səhifəsi və şəbəkə əlaqəsi bir faylda, hətta bir metoddda qarışıb. Verilənlər bazası sorğusunun dəyişdirilməsi UI-nin göstərilməsini poza bilər, çünki bu layların kodu ayrılmayıb.
Qlobal dəyişənlər və sinqletonlar — ikinci aşkar əlamət. Tətbiqin vəziyyəti qlobal obyektlərdə saxlanıldıqda, icra axını gözlənilməz olur. İstənilən funksiya qlobal vəziyyəti dəyişə bilər və bunun harada və nə vaxt baş verdiyini izləmək praktiki olaraq mümkünsüzdür.
God-klaslar və god-funksiyalar — üçüncü əlamət. 2000+ sətirlik klas, həm biznes məntiqinə, həm göstərilməyə, həm də verilənlərlə işə cavabdehdir — bu tipik spagetti kodudur. 10 parametr qəbul edən və 5 müxtəlif şey edən funksiya da.
| Əlamət | Təsvir | Nümunə |
|---|---|---|
| Layların qarışması | SQL sorğuları UI kodu daxilində | Birbaşa verilənlər bazasına yazan nəzarətçi |
| Qlobal dəyişənlər | Hər yerdən əlçatan vəziyyət | Hər klasda static SessionManager |
| God-klaslar | Bir klas hər şeyi edir | 3000 sətirlik OrderManager |
| Uzun metodlar | Bölünməmiş funksiyalar | 5 məsuliyyətli 200 sətirlik metod |
| Callback hell | Sonsuz yuvalanmış callbacklər | JavaScript-də 6 yuvalanma səviyyəsi |
Əgər 15 mock-obyekt yaratmadan funksiya üçün vahid test yaza bilmirsinizsə — bu makaron kodudur. Əgər bir modulun test edilməsi bütün tətbiq infrastrukturunun qaldırılmasını tələb edirsə — bu makaron kodudur. Test edilə bilməmək — qarışıq memarlığın obyektiv göstəricisidir.
Memarlıq layihələndirilməsinin olmaması — ən tez-tez rast gəlinən səbəb. Komanda plansız kod yazmağa başlayanda, memarlığı "yol boyu" seçəndə, nəticə qaçılmaz olaraq spagettiyə çevrilir. Hər yeni funksiya "hazırda rahat olduğu" yerə əlavə olunur, məntiqə görə yeri olan yerə yox.
Təkamül inkişafı — ikinci səbəb. Layihə kiçik bir skript kimi başlayır, sonra funksiyalarla böyüyür, sonra tətbiqə, daha sonra monolitə çevrilir. Bu zaman memarlıq yenidən nəzərdən keçirilmir. 100 sətir kod üçün işləyən şey 100 000 sətir üçün fəlakətə çevrilir.
SOLID prinsiplərinin pozulması — üçüncü səbəb. Xüsusilə tək məsuliyyət prinsipi (S) və asılılıqların inversiyası (D). Klas hər şeyə cavabdeh olduqda, asılılıqlar sərt olduqda və modullar möhkəm bağlandıqda — makaron kodu alınır.
Son tarixlər və hotfix mədəniyyəti — spagetti kodunun katalizatorları. "Dünən lazım idi" deyəndə, proqramçılar kodu memarlıq haqqında düşünmədən ilk rast gələn yerə daxil edirlər. On belə hotfix — və tətbiqin memarlığı məhv olur.
Əsas nəticə — kod bazası üzərində nəzarətin itirilməsi. Proqramçılar tətbiqin bütövlükdə necə işlədiyini başa düşməyi dayandırırlar. Bir yerdə dəyişiklik digər, zahirən əlaqəsi olmayan yeri sındırır. Hər yama iki yeni səhv yaradır. Komanda "dəyişiklik qorxusu" vəziyyətinə düşür.
Komandanın məhsuldarlığı eksponensial şəkildə düşür. Microsoft Research (2023) tədqiqatı göstərdi ki, spagetti kodunda yeni funksiyanın əlavə edilmə vaxtı kod bazasının ölçüsünə nisbətən kvadratik qanunla artır. Təmiz memarlıq üçün bu artım xəttidir. Fərq 50 000+ sətir kodda kritik olur.
Təhlükəsizlik — daha bir qurban. Makaron kodunda idarə olunmayan istisnanı, səhv giriş validasiyasını və ya məlumat sızmasını qaçırmaq asandır. Qarışıq memarlıqlı layihədə təhlükəsizlik auditi praktiki olaraq mümkünsüzdür — istifadəçi girişinin istifadə olunduğu bütün yerləri tapmaq qeyri-realdır.
Kadr dəyişikliyi spagetti kodlu layihələrdə orta səviyyədən yüksəkdir. Təcrübəli proqramçılar "əriştə" ilə işləmək istəmədikləri üçün gedirlər. Yeni işçilər kodu başa düşə bilmir və ilk aylarda ayrılırlar. Layihə ekspertizasını itirir, bu da kod keyfiyyətini daha da pisləşdirir — qısır dairə.
Birinci — layların ayrılması ilə başlayın. Kodu üç səviyyəyə bölün: presentation (UI, nəzarətçilər), business logic (xidmətlər, use cases) və data access (repozitorilər, DAO). Hətta qismən ayrılma dərhal strukturu yaxşılaşdırır və kodu test edilə bilən edir.
İkinci — dependency injection tətbiq edin. Asılılıqların birbaşa yaradılmasını konstruktor və ya parametrlər vasitəsilə ötürülməsi ilə əvəz edin. Bu, komponentlər arasında sərt əlaqələri qırır və hər modulu təcrid olunmuş şəkildə test etməyə imkan verir.
Üçüncü — god-klasları və god-funksiyaları ayırın. Onları kiçik klaslara və tək məsuliyyətli metodlara bölün. Mürəkkəb alt sistemləri sadələşdirmək üçün Facade patternindən istifadə edin. Unutmayın: 20 sətirlik klas 2000 sətirlik klasdan daha başa düşüləndir.
// spaghetti — hər şey bir metoddadır
function handleRequest(req, res) {
const db = new Database("mysql://...");
const user = db.query("SELECT * FROM users WHERE id =" + req.params.id);
let html = "";
html += ""
+ user.name + "";
html += "Balance: "
+ user.balance + "";
html += "";
res.send(html);
}
// təmiz memarlıq — ayrılmış laylar
class UserController {
constructor(userService) {
this.userService = userService;
}
async getUser(req, res) {
const user = await this.userService.findById(req.params.id);
res.json(new UserResponse(user));
}
}
class UserService {
constructor(userRepository) {
this.userRepository = userRepository;
}
async findById(id) {
return await this.userRepository.findById(id);
}
}
Bütün kod bazasını bir anda yenidən yazmağa çalışmayın — bu zəmanətli uğursuzluqdur. Bir modul seçin, onun üçün cari davranışı təsbit edən testlər (characterization tests) yazın və yalnız bundan sonra refaktor edin. Tədricən, modul-modul, spagettini açacaqsınız.
Memarlıq planlaması — profilaktikanın əsası. İnkişafa başlamazdan əvvəl memarlıq üslubunu təsdiqləyin: MVC, MVVM, Clean Architecture, VIPER və ya digər. Seçimin əsaslandırılması ilə ADR (Architecture Decision Record) yazın. Code review-də memarlığa riayət olunmasını tələb edin.
Asılılıqların inversiyası prinsipi (DIP) — spagetti kodu ilə mübarizənin güclü alətidir. Yüksək səviyyəli modullar aşağı səviyyəli modullardan asılı olmamalıdır. Hər ikisi abstraksiyalardan asılı olmalıdır. Dependency Injection — bu prinsipin praktiki reallaşdırılmasıdır.
Test etmə — ən yaxşı profilaktika. Əgər koddan əvvəl testlər yazırsınızsa (TDD), qaçılmaz olaraq zəif bağlı komponentlər layihələndirirsiniz. Test edilə bilən kod — yaxşı strukturlaşdırılmış koddur. Test edilə bilməyən kod — demək olar ki, həmişə spagetti kodudur.
SonarQube — siklotomik mürəkkəbliyi, miras dərinliyini, metod ölçüsünü izləyir. JDepend (Java) — paketlər arası asılılıqları ölçür. PhpMetrics — PHP layihələri üçün maintainability indeksi verir. CI/CD-də metrikləri izləyin — əriştənin yaranmasının qarşısını alın, onunla sonradan mübarizə aparmayın.
Tez-tez verilən suallar
Bəli, tədricən refaktorinq üstünlük təşkil edir. Strangler Fig metodundan istifadə edin — tətbiqin işini dayandırmadan köhnə komponentləri tədricən yeniləri ilə əvəz edin. Məlumat layını və ya biznes məntiqini ayırmaqla başlayın. Dəyişikliklərdən əvvəl köhnə kodu testlərlə əhatə edin ki, funksionallığı itirməyəsiniz.
Spagetti kodu — tətbiqin bütün laylarının xaotik qarışmasıdır. Lasanya kodu — sərt çoxlaylı memarlıqdır, lakin hər lay o qədər təcrid olunub ki, onlar arasında məlumat ötürülməsi bürokratiyaya çevrilir. Hər iki anti-pattern zərərlidir, lakin spagetti kodu daha təhlükəlidir — kodu gözlənilməz edir.
Asılılıqlara baxın: əgər modul tətbiqin bütün laylarından modulları idxal edirsə — bu şübəlidir. Metodların ölçüsünə diqqət edin — 30 sətirdən çox adətən pisdir. Funksiyanın UI işini, biznes məntiqini və məlumatları qarışdırıb-qarışdırmadığını yoxlayın. Əgər bəli — bu makaron kodudur.
Clean Architecture Robert Martin və Hexagonal Architecture (Ports & Adapters) — iki ən yaxşı yanaşma. Hər ikisi layların ayrılmasını, biznes məntiqinin freymvorklardan müstəqilliyini və test edilə bilməni təmin edir. Mobil inkişaf üçün — Repository patterni ilə MVVM.
Qismən. Siklotomik mürəkkəblik (McCabe), modulların bağlanması (Coupling) və miras dərinliyi (DIT) kimi metrikalar potensial spagetti kodunu göstərir. SonarQube, CodeClimate və PhpMetrics bu metrikaları avtomatik hesablayır. Lakin tam diaqnostika memarlığın insan analizini tələb edir.
Xülasə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun