Giriş

Büyük projelerde kodun okunabilir, sürdürülebilir ve test edilebilir olması için katmanlı mimari kaçınılmazdır. Bu yapıda üç temel yapı taşına sıkça rastlarız: Servis Katmanı, Repository Katmanı ve DTO (Data Transfer Object).

is-mantigi-katmanli-yapi

1. Katmanlı Mimari – Genel Bakış

Katmanlı mimari, kodun işlevine göre bölünmesini ve sorumlulukların net ayrılmasını sağlar.
En yaygın katmanlar:

  • Controller/UI: Kullanıcıdan gelen isteği alır.
  • Service: İş kurallarını ve iş akışlarını yönetir.
  • Repository: Veri erişimi (DB) ile ilgili tüm işlemleri kapsar.
  • DTO: Katmanlar arası veri transferi için kullanılan sade objedir.

Katmanlar Arası İlişki Diyagramı

  • Controller/UI → Service → Repository → DB
  • DTO: Genellikle Service <-> Controller veya Service <-> Client arasında veri taşır.

2. Repository Katmanı Nedir?

Tanım

Repository, veri erişimi (CRUD işlemleri), sorgular ve ORM işlemlerinden uygulama kodunu ayıran bir katmandır.

Neden Kullanılır?

  • DB ile doğrudan konuşmak yerine, arada soyutlama sağlar.
  • Veritabanı değişirse, üst katman kodu minimum değişir.
  • Testlerde “mock repository” kullanarak bağımsız test imkanı sunar.

C# Repository Örneği

public interface IUserRepository
{
    User GetById(int id);
    IEnumerable<User> GetAll();
    void Add(User user);
    void Update(User user);
    void Delete(int id);
}

public class UserRepository : IUserRepository
{
    // Genelde DbContext veya ORM nesnesi ile çalışır
    private readonly AppDbContext _context;

    public UserRepository(AppDbContext context)
    {
        _context = context;
    }

    public User GetById(int id) => _context.Users.Find(id);
    public IEnumerable<User> GetAll() => _context.Users.ToList();
    public void Add(User user) => _context.Users.Add(user);
    public void Update(User user) => _context.Users.Update(user);
    public void Delete(int id)
    {
        var user = GetById(id);
        if (user != null) _context.Users.Remove(user);
    }
}

Repository Katmanının Avantajları

  • Kodda “DB kodu ile iş kodu” birbirine karışmaz.
  • Tek bir yerden veri erişimi kontrolü.
  • Mocking ve test kolaylığı.
  • ORM/DBMS değişikliğinde minimum iş.

3. Servis Katmanı Nedir?

Tanım

Servis katmanı, iş kurallarını, validasyonları ve uygulama akışlarını barındırır. Repository katmanından aldığı veri ile iş mantığını uygular.

C# Service Örneği

public interface IUserService
{
    UserDto GetUserById(int id);
    IEnumerable<UserDto> GetAllUsers();
    void RegisterUser(UserDto userDto);
}

public class UserService : IUserService
{
    private readonly IUserRepository _userRepository;

    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public UserDto GetUserById(int id)
    {
        var user = _userRepository.GetById(id);
        return new UserDto { Id = user.Id, Name = user.Name, Email = user.Email };
    }

    public IEnumerable<UserDto> GetAllUsers()
    {
        return _userRepository.GetAll()
            .Select(u => new UserDto { Id = u.Id, Name = u.Name, Email = u.Email });
    }

    public void RegisterUser(UserDto userDto)
    {
        // Burada iş kuralları, validasyon vs. yapılır
        var user = new User { Name = userDto.Name, Email = userDto.Email };
        _userRepository.Add(user);
    }
}

Servis Katmanının Avantajları

  • Tüm iş kuralları ve validasyonlar tek yerde toplanır.
  • Controller/UI kodu sadeleşir, sadece yönlendirici olur.
  • Kodun testi ve bakımı kolaylaşır.

4. DTO (Data Transfer Object) Nedir?

Tanım

DTO, iki katman arasında veri taşımak için kullanılan sade nesnedir.
Entity’lerden farkı;

  • DB ile ilgili annotation, navigation property veya ekstra işlevsellik yoktur.
  • UI veya client’a özel “görünüm” ihtiyacını karşılar.

C# DTO Örneği

public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    // Gerekiyorsa ek property’ler (UI veya API'ya özel)
}

DTO Kullanımının Avantajları

  • Katmanlar arası “bağımlılığı” azaltır.
  • UI/Client özelinde veri kısıtlaması sağlar (sadece gerekli alanlar).
  • Kodun güvenliği ve esnekliği artar.

5. Katmanların Sorumlulukları (Madde Madde)

Controller Katmanı

  • Kullanıcı isteğini karşılar.
  • Gerekli servisi çağırır.
  • Sonucu kullanıcıya (UI, API) döner.

Service Katmanı

  • İş kurallarını ve validasyonları yönetir.
  • Transaction, logging gibi “iş mantığı” işlemlerini kapsar.
  • DTO <-> Entity dönüşümünü yapar.

Repository Katmanı

  • DB erişimi, sorgular ve CRUD işlemlerini kapsar.
  • DB’yi soyutlar ve kodu merkezi yönetir.

DTO

  • Veri transferi için sade nesne.
  • Katman bağımlılığı olmadan sadece veri taşır.

6. Uygulama Akışı – Katmanlar Arası İlişki

  1. Kullanıcı bir istek gönderir (ör: kayıt ol).
  2. Controller, ilgili Service’i çağırır ve DTO’yu iletir.
  3. Service, iş kuralı ve validasyonları uygular, DTO’dan Entity oluşturur.
  4. Repository, veritabanı işlemlerini yapar (ekle, güncelle, sil, oku).
  5. Service, sonucu Controller’a döner, gerekirse DTO oluşturur.
  6. Controller yanıtı (JSON, View, vs.) olarak kullanıcıya iletir.

katmanli-yapi-akis-diagrami

7. C# ile Katmanlı Mimari: Komple Mini Uygulama

Entity

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

DTO

public class UserDto
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

Repository

public interface IUserRepository
{
    User GetById(int id);
    IEnumerable<User> GetAll();
    void Add(User user);
}

public class UserRepository : IUserRepository
{
    private readonly List<User> _users = new List<User>();

    public User GetById(int id) => _users.FirstOrDefault(u => u.Id == id);
    public IEnumerable<User> GetAll() => _users;
    public void Add(User user) => _users.Add(user);
}

Service

public interface IUserService
{
    UserDto GetUserById(int id);
    IEnumerable<UserDto> GetAllUsers();
    void RegisterUser(UserDto userDto);
}

public class UserService : IUserService
{
    private readonly IUserRepository _repository;
    public UserService(IUserRepository repository)
    {
        _repository = repository;
    }

    public UserDto GetUserById(int id)
    {
        var user = _repository.GetById(id);
        if (user == null) return null;
        return new UserDto { Id = user.Id, Name = user.Name, Email = user.Email };
    }

    public IEnumerable<UserDto> GetAllUsers()
    {
        return _repository.GetAll()
            .Select(u => new UserDto { Id = u.Id, Name = u.Name, Email = u.Email });
    }

    public void RegisterUser(UserDto dto)
    {
        var user = new User { Name = dto.Name, Email = dto.Email };
        _repository.Add(user);
    }
}

Controller (Minimal Örnek)

public class UserController
{
    private readonly IUserService _service;
    public UserController(IUserService service)
    {
        _service = service;
    }

    public void Register(string name, string email)
    {
        var dto = new UserDto { Name = name, Email = email };
        _service.RegisterUser(dto);
        Console.WriteLine("Kullanıcı kaydedildi.");
    }

    public void ListUsers()
    {
        var users = _service.GetAllUsers();
        foreach (var user in users)
            Console.WriteLine($"{user.Id} - {user.Name} - {user.Email}");
    }
}

8. Katmanlı Mimaride Sıkça Sorulanlar

Repository ile Service arasındaki temel fark nedir?
Repository veriyi işler, Service iş mantığını yönetir. Service, Repository’e doğrudan erişir, Controller ise Service’e.

DTO ile Entity neden ayrı tutulmalı?
DTO, UI ve API ile iletişim için sadeleştirilmiş objedir. Entity, veritabanı ile birebir ilişkilidir ve fazla veri taşır. Her katmanda “gerektiği kadar bilgi” taşınır.

Her projede DTO zorunlu mu?
Küçük projelerde Entity doğrudan kullanılabilir, ancak büyüyen projede DTO büyük avantaj sağlar.

9. Tasarımda En Sık Yapılan Hatalar

  • Repository içinde iş kuralı barındırmak (ör: validasyon, logik).
  • Serviste doğrudan DB işlemleri yapmak.
  • Controller’dan doğrudan Repository’ye erişmek.
  • DTO ve Entity’yi karıştırmak, veritabanı modelini doğrudan UI’a açmak.
  • Katmanlar arası bağımlılığı artırmak.

10. Sonuç ve Pratik İpuçları

  • Katmanlı mimari, kodun sürdürülebilir ve genişletilebilir olması için en güvenli yoldur.
  • Her katmanı sadece kendi sorumluluğunda kodla.
  • DTO kullanarak dış dünyaya açık veri formatını kontrol et.
  • Bağımlılıkları constructor ile inject et, gevşek bağla.
  • Her katmanda test yazmak daha kolay olur.

11. Kaynaklar

By tanju.bozok

Software Architect, Developer, and Entrepreneur

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir