Clean Architecture-1

Harika — bu soruyu sorman, artık mimariyi “kullanmak” değil anlamak istediğini gösteriyor 🔥
Şimdi çok derin ama kalıcı bir şekilde açıklayacağım:
Clean Architecture, katmanların rolleri, bağımlılık yönü, Core’un görevi, Infrastructure’ın yeri, ve modüler monolith ile ilişkisini.
Hazırsan kahveni al ☕ ve başlıyoruz 👇
🧭 1️⃣ Clean Architecture Nedir?
Clean Architecture, bağımlılık yönünü tersine çevirerek iş kurallarını merkezde tutan bir yazılım mimarisidir.
Amaç:
“Uygulamanın kalbinde iş kuralları yaşar.
Framework’ler, veri tabanı, UI ve üçüncü parti servisler sadece ayrılabilir detaylardır.”
🔹 Katmanlar (içten dışa)
+----------------------------+
| Presentation | → UI, API, Web, Console
+----------------------------+
| Infrastructure | → DB, Redis, HTTP, FileSystem, Telegram
+----------------------------+
| Application | → Use Cases, Orchestration
+----------------------------+
| Domain | → Entities, ValueObjects, Rules
+----------------------------+🧩 2️⃣ Katmanların Anlamı
1. Domain (Enterprise Rules)
- Saf iş kuralları ve model (business logic).
- Persistence, logging, HTTP bilmez.
- Framework bağımsız.
- En stabil katman.
İçerik:
EntitiesValueObjectsDomainEventsAggregatesSpecificationsInterfaces (IDomainEventHandler)
Örnek:
public class Quiz : Entity
{
public string Title { get; private set; }
public void Start()
{
if (IsStarted) throw new InvalidOperationException("Quiz already started.");
IsStarted = true;
AddDomainEvent(new QuizStartedEvent(Id));
}
}🟢 Bağımlılığı yok.
Sadece .NET standard kütüphanesine bağlı olabilir.
2. Application (Use Cases + Orchestration)
- “Domain”i kullanarak iş akışını (use case) oluşturur.
- Dış sistemlere erişmek için sadece abstractions kullanır (örneğin
IQuizRepository,IEventBus,IBufferedLogger). - Domain kurallarını uygular ama dış dünyayı bilmez.
- CQRS, Validation, Mediator gibi pattern’ler burada yaşar.
İçerik:
Commands / QueriesHandlersDTOsBehaviors (Pipelines)Interfaces(IRepository, IEventBus, IScheduler)
Örnek:
public class StartQuizCommandHandler : IRequestHandler<StartQuizCommand>
{
private readonly IQuizRepository _repository;
private readonly IEventBus _eventBus;
public StartQuizCommandHandler(IQuizRepository repository, IEventBus eventBus)
{
_repository = repository;
_eventBus = eventBus;
}
public async Task Handle(StartQuizCommand request, CancellationToken ct)
{
var quiz = await _repository.GetByIdAsync(request.QuizId, ct);
quiz.Start();
await _repository.SaveAsync(quiz, ct);
await _eventBus.PublishAsync(new QuizStartedEvent(quiz.Id));
}
}🟢 Application katmanı sadece abstractions’a (interface) bağımlı olmalı.
🛑 Infrastructure’a direkt bağımlı olamaz!
3. Infrastructure (Frameworks + Implementation)
- Dış dünya ile tüm etkileşim burada.
- Veri tabanı, Redis, API çağrıları, dosya sistemi, e-posta, logging, telemetry…
- Bu katman, Application katmanında tanımlı interface’leri uygular.
İçerik:
EFCoreRepositoriesRedisCacheServiceTelegramApiClientBufferedLoggerServiceOutboxProcessorFileStorageService
Örnek:
public class QuizRepository : IQuizRepository
{
private readonly AppDbContext _context;
public QuizRepository(AppDbContext context) => _context = context;
public Task<Quiz?> GetByIdAsync(Guid id, CancellationToken ct)
=> _context.Quizzes.FirstOrDefaultAsync(q => q.Id == id, ct);
public Task SaveAsync(Quiz quiz, CancellationToken ct)
=> _context.SaveChangesAsync(ct);
}🟡 Bu katman dış dünyaya bağımlıdır (EF, Redis, Kafka vs.).
🟢 Ancak bağımlılıklar Application → Interface, Infrastructure → Implementation yönündedir.
🛑 Infrastructure hiçbir zaman Domain veya Application’dan bağımsız olamaz, ama tersine bağımlıdır.
4. Presentation (Interface Adapters / UI Layer)
- Kullanıcıdan (veya başka sistemden) gelen girdiyle Application katmanını çağırır.
- ASP.NET Core Controllers, gRPC Services, CLI, SignalR, WebUI olabilir.
- Request → DTO → Command → Application → Domain → Response akışı.
Örnek:
[ApiController]
[Route("api/quizzes")]
public class QuizController : ControllerBase
{
private readonly IMediator _mediator;
public QuizController(IMediator mediator) => _mediator = mediator;
[HttpPost("{quizId}/start")]
public async Task<IActionResult> Start(Guid quizId)
{
await _mediator.Send(new StartQuizCommand(quizId));
return Ok();
}
}🟢 Presentation sadece Application’a bağımlı olabilir.
🛑 Application veya Domain Presentation’a asla bağımlı olamaz.
🧭 3️⃣ Core Katmanı Nedir?
Core genellikle Domain + Application katmanlarının birleşimidir.
Core/
├── Domain/
│ ├── Entities/
│ ├── ValueObjects/
│ └── Events/
└── Application/
├── Interfaces/
├── Commands/
├── Queries/
└── Services/Core = İşin kalbi.
Yani:
- Uygulamanın iş mantığı burada.
- Framework bağımlılığı yok.
- En stabil kısım.
💡 Bu yüzden:
Core içinde Infrastructure olmamalı,
çünkü Infrastructure dış dünyaya bağımlı, değişken bir detaydır.
🧩 4️⃣ Neden Core içinde Infrastructure olmamalı?
🔴 Sebep 1: Dependency Rule (Bağımlılık Yönü)
“Kod bağımlılığı hep içeriye (Domain’e) doğru olmalı.”
Yanlış yön:
Core → Infrastructure ❌Doğru yön:
Infrastructure → Core ✅Eğer Core içinde Infrastructure varsa:
- Domain veya Application, EF, Redis, Telegram gibi framework’lere bağımlı hale gelir.
- Test edilebilirlik düşer.
- Değişim maliyeti artar.
- SOLID prensipleri (özellikle DIP) bozulur.
🔴 Sebep 2: Değişim Sıklığı
- Infrastructure (örneğin Redis, Kafka, EF) sık değişir.
- Core (iş mantığı) seyrek değişir.
- Farklı değişim frekansına sahip kodlar aynı yerde olursa, stabilite bozulur.
🔴 Sebep 3: Test Edilebilirlik
Core içinde Infrastructure olursa:
- Unit test’ler EF veya Redis’e bağımlı hale gelir.
- Mock edilemez hale gelir.
- Pure business logic testleri zorlaşır.
🔴 Sebep 4: Portability (Taşınabilirlik)
- Core bağımsız olmalı ki aynı iş mantığını başka ortamlara taşıyabilesin.
- Örneğin:
Web API, Worker Service, Azure Function, CLI, Mobile App hepsi aynı Core’u kullanabilir.
🧩 5️⃣ Modüler Monolith ve Core’un Rolü
Modüler Monolith = Tek deployable uygulama, ama bağımsız modüller halinde organize edilmiş.
Her modül, küçük bir “Clean Architecture”’tır.
Örnek:
src/
├── Modules/
│ ├── Quiz/
│ │ ├── Quiz.Domain/
│ │ ├── Quiz.Application/
│ │ ├── Quiz.Infrastructure/
│ │ └── Quiz.API/
│ ├── User/
│ │ ├── User.Domain/
│ │ ├── User.Application/
│ │ ├── User.Infrastructure/
│ │ └── User.API/
│ └── Shared/
│ └── SharedKernel/
└── Host/
└── WebHost/Avantaj:
- Her modül kendi mini-Core’una sahip olur (Domain + Application).
- Tüm modüller Infrastructure katmanını paylaşabilir.
- Tek database ama bağımsız bounded context’ler.
⚙️ 6️⃣ Bağımlılıklar Nasıl Yönetilir?
📌 Proje Referans Yönü
Presentation → Application → Domain
↓ ↑
Infrastructure ←────┘| Katman | Referans verebilir | Referans veremez |
|---|---|---|
| Domain | Hiçbirine | Hepsine ❌ |
| Application | Domain | Infrastructure ❌ |
| Infrastructure | Application, Domain | Presentation ❌ |
| Presentation | Application | Infrastructure ❌ |
📚 7️⃣ Katmanların İsmi Ne Anlama Geliyor?
| Katman | Anlamı | Temel Sorumluluk |
|---|---|---|
| Domain | “Ne iş yapıyorum?” | İş kuralları, entity davranışları |
| Application | “Ne zaman / nasıl yapıyorum?” | İş akışı, orchestration, use-case’ler |
| Infrastructure | “Nerede / hangi araçla yapıyorum?” | DB, API, Redis, Logging |
| Presentation | “Kiminle konuşuyorum?” | Kullanıcı / dış sistem arayüzü |
🧠 8️⃣ Infrastructure Nasıl Olmalıdır?
Infrastructure = “Uygulamanın donanım, framework, teknoloji detaylarını” içerir.
Özellikleri:
- Application’daki interface’leri implemente eder.
- DI (Dependency Injection) ile Application’a bağlanır.
- Kolay değiştirilebilir olmalı (örneğin Redis yerine Kafka).
- Testlerde Mock’lanabilir olmalı.
Alt klasör örneği:
Infrastructure/
├── Persistence/
│ ├── AppDbContext.cs
│ ├── QuizRepository.cs
│ └── UnitOfWork.cs
├── Logging/
│ └── BufferedLoggerService.cs
├── Messaging/
│ └── KafkaEventBus.cs
├── Scheduler/
│ └── RedisScheduler.cs
├── Telegram/
│ └── TelegramApiClient.cs
└── DependencyInjection.cs🧩 9️⃣ Sonuç
| Kural | Açıklama |
|---|---|
| ✅ Core sadece Domain + Application içerir | Core, işin kalbidir; dış dünyayı bilmez |
| ❌ Core içinde Infrastructure olmaz | Bağımlılık yönü ters olur |
| ✅ Application sadece abstraction tanımlar | Dış dünya Application’a değil, interface’lere bağlıdır |
| ✅ Infrastructure bu interface’leri uygular | DB, API, Redis gibi detaylar buradadır |
| ✅ Presentation sadece Application’a bağlıdır | Controller’lar use-case’leri çağırır |
| ✅ Shared, cross-cutting konular içindir | Core’un dışında olabilir |
| ✅ Modüler Monolith = birden fazla küçük Clean Architecture | Her modül kendi Domain + Application setine sahiptir |





