12.1 Mimari Prensipler: SOLID ve Temiz Kod
Büyük ölçekli sistemlerde kodun "çalışması" yeterli değildir; kodun Sürdürülebilir (Maintainable) ve Genişletilebilir (Extensible) olması gerekir. Robert C. Martin tarafından popülerleşen SOLID prensipleri, C++'ın statik tipleme ve şablon yapısıyla harmanlandığında devasa sistemlerin yönetilmesini sağlar.
Bağımlılıkların Tersine Çevrilmesi (DIP)
Üst seviye modüller, alt seviye modüllere doğrudan bağımlı olmamalıdır. Her ikisi de soyutlamalara (Arayüzler/Abstract Classes) bağımlı olmalıdır. C++'da bu, saf sanal fonksiyonlar (Pure Virtual Functions) kullanılarak gerçekleştirilir.
Açık/Kapalı Prensibi (OCP)
Yazılım birimleri gelişime açık, değişime kapalı olmalıdır. Yeni bir özellik eklemek için mevcut kodun değiştirilmesine gerek kalmamalı, yeni kod eklenerek sistem genişletilmelidir.
12.2 Modern Proje Yapılandırması (CMake)
Modern C++ dünyasında standart CMake'dir. CMake bir derleyici değil, derleyici dosyalarını (Makefile, Ninja, MSVC Solution) üreten bir Meta-Derleme Sistemi (Meta-Build System)dir.
Şema 12.1: Profesyonel C++ Proje Klasör Hiyerarşisi
12.3 Tasarım Kalıpları: Strateji (Strategy) Mimari Örneği
Aşağıdaki örnek, çalışma zamanında algoritma değiştirmeyi sağlayan profesyonel bir mimari yapıyı simgeler.
#include <iostream>
#include <memory>
#include <vector>
/**
* @brief Akademik Arayüz: Strateji (Strategy)
* @details SOLID: Bağımlılıkların Tersine Çevrilmesi (DIP) uygulanmıştır.
*/
class ISiralamaStratejisi {
public:
virtual ~ISiralamaStratejisi() = default;
virtual void sirala(std::vector<int>& veri) const = 0;
};
// Somut Strateji A
class HizliSirala : public ISiralamaStratejisi {
public:
void sirala(std::vector<int>& veri) const override {
std::cout << "Hizli Siralama (Quick Sort) Algoritmasi Calistirildi.\n";
}
};
// Bağlam (Context) Sınıfı
class VeriYonetici {
private:
std::unique_ptr<ISiralamaStratejisi> m_strateji;
public:
void strateji_set(std::unique_ptr<ISiralamaStratejisi> yeni_strateji) {
m_strateji = std::move(yeni_strateji);
}
void islem_yap(std::vector<int>& veri) {
if (m_strateji) m_strateji->sirala(veri);
}
};
int main() {
VeriYonetici yonetici;
std::vector<int> veri = {5, 2, 9, 1};
// Dinamik olarak strateji değiştirme (Runtime Polymorphism)
yonetici.strateji_set(std::make_unique<HizliSirala>());
yonetici.islem_yap(veri);
return 0;
}
Polimorfizm ve Soyutlama
Yukarıdaki yapıda `VeriYonetici` sınıfı, hangi sıralama algoritmasının kullanıldığını bilmez. Sadece `ISiralamaStratejisi` arayüzünü (Interface) tanır. Bu, sisteme yeni bir sıralama algoritması (örn: BubbleSort) eklerken mevcut sınıfları değiştirmenize gerek kalmadığı anlamına gelir (OCP).
Birim Testleri (Unit Testing):
Büyük projelerde Google Test (GTest) veya Catch2 kullanımı kaçınılmazdır. Her mimari bileşen, diğerlerinden bağımsız olarak test edilmelidir. Mocking kütüphaneleri (örn: gMock) kullanılarak dış bağımlılıklar taklit edilir.
⚠️ Mimari Yanılgılar ve Teknik Borç (Technical Debt)
Tanrı Nesnesi (God Object) Anti-Pattern
Her şeyi yapan, binlerce satırlık, tüm bağımlılıkları üzerinde toplayan devasa sınıflar. Bu durum, sistemin test edilebilirliğini ve esnekliğini yok eder.
Çözüm: Tek Sorumluluk Prensibi (Single Responsibility - SRP) uygulayarak sınıfları parçalayın.
Sıkı Bağımlılık (Tight Coupling)
Sınıfların birbirlerinin iç işleyişini bilmesi ve doğrudan birbirlerini `new` ile oluşturması.
Çözüm: Bağımlılık Enjeksiyonu (Dependency Injection) kullanarak nesneleri dışarıdan verin.
MEZUNİYET SINAVI
Soru: Bir C++ projesinde 'CMakeLists.txt' dosyasının temel görevi nedir?
Final Mühendislik Görevi:
"trcpp-telegram topluluğunda 'Senior Interview' sorusu olarak sorulmuş bir senaryo: Bir Logger (Günlük Kaydı) sistemi tasarlamanız isteniyor. Sistem hem Dosyaya (File) hem Konsola (Console) yazabilmeli. SOLID prensiplerine ve Strategy Pattern'e uygun olarak bu sistemin sınıf hiyerarşisini (Interface ve Implementation) kurgulayın."