MVC
Çalıştığım bir proje gereği kısa sürede mvc hakkında bilgi sahibi olmam gerekti. Tıpkı diğer yazılarımda olduğu gibi bu yazımda da neler öğrendiğimi görme adına ve sanki bir arkadaşıma mvc nin ne olduğunu anlatıyormuş gibi bu yazıyı yazdım. Bu yüzden eğer projende bir hata aldıysan ve hatayı araştırırken kendini burada bulduysan bu yazı senin için yeterli olmayabilir!
MVC ye neden ihtiyaç duyduk?
Bilim ve teknolojideki tüm gelişmeler gibi MVC de bir ihtiyaç sonucu ortaya çıktı. Eskiden geliştirilen projelerde tüm yazılım tek bir sayfada yazılırmış. Örneğin bir butonun tetiklediği fonksiyon sunucu isteklerini ve veri tabanına kayıt işlemlerini de yaparmış. Yani tüm iş mantığı tek bir yerde toplanırmış. Bu durumda geliştirci projede bir butonun görünümüyle alakalı küçük bir değişiklik yapacak olsa bile tüm proje bu değişiklikten etkilenirdi. Haliyle kodun yönetimi ve bakımı oldukça zorlayıcı olurdu. Test kısmından bahsetmek dahi istemiyorum.
İşte bu noktada Seperation of Concerns ilkesine uygun bir arayışa gidildi ve Norveçli bir yazılım mühendisi MVC yi ortaya attı. Sonuç olarak MVC iş mantığını ayırma ihtiyacı sebebiyle ortaya çıktı ve kullanılmaya başlandı.
Seperation of Concerns (SoC)
Seperation of Concerns birebir çeviride “Endişelerin Ayrımı” anlamına gelir. İlk başta bu çeviri mantıksız gelebilir ancak burda Concerns kelimesi, sorumluluk, görev alanı kavramlarını karşılar. Ancak illa endişe kavramıyla ilişkilendirme gerekirse “SoC herkesin kendi derdiyle ilgilenmesidir.” şeklinde bir tanım yapabiliriz :)
SoC en temelde her bir bileşenin tek bir işten sorumlu olduğu bir tasarım ilkesidir. Yazılım jargonuna hakim olmayan biri SoC yi tanımlamak isteseydi bence şöyle tanımlardı: “Benzer işlerin aynı dizin altında yapılması işlemidir. Yani razor dosyalarının view klasörü altında, http isteklerinin controller altında ve modellerin model klasörü altında toplanmasıdır.” Bu tanım oldukça doğru ama biraz eksik bir tanımdır. Çünkü SoC prensibi sadece dosya yapısıyla sınırlı değildir, SoC kodun her katmanında sorumlulukların net sınırlarla ayrılmasını sağlar.
İşte MVC de bu prensibi somutlaştıran en bilinen örneklerden biridir. Model, View ve Controller birbirinden farklı “endişeleri” (sorumluluk alanlarını) üstlenir.
MVC bazı kaynaklarda mimari, bazı kaynaklardaysa tasarım örüntüsü (design pattern) olarak tanımlanıyor ancak MVC için en doğru tanım, bir “Tasarım Mimarisi” olacaktır. Çünkü MVC en basit tanımıyla işlerin ayrıştırılması prensibine dayanır. Dolayısıyla projenin mimarisini belirler ancak bu yapısıyla tekrarlanabilir bir çözüm sunduğu için bir pattern de oluşturmuş olur. Bu yüzden en doğru tanım: Architectural Pattern olacaktır.
Mvc çoğunlukla web uygulamalarında kullanılır ancak controller ın web uygulamaları dışında da kullanımına denk gelebilirsiniz. Öyleyse MVC yi detaylıca inceleyelim.
MVC 3 kısımdan oluşur: Model, View ve Controller.
Model: Tüm iş mantığını barındıran ve veri yönetimini sağlayan kısımdır.
View: Kullanıcıya çıktının gösterildiği kısımdır. View dosyalarında html, java script ve c# gibi bir çok teknoloji aynı anda kullanılabilir. .Net de view dosyaları “.cshtml” uzantılı olur ve bunlara “Razor” dosyası denir.
Controller: Model ile view arasındaki iletişimi sağlayan köprüdür. İstekleri alır, bu isteklere göre gerekli modelleri çağırır ve sonucu view e gönderir.
İlk bakışta bu kavramların soyut kaldığını tahmin edebiliyorum. Çünkü bende öyle olmuştu :) Bu yüzden çok ünlü bir örnek olan Restorant metaforundan bahsedeceğim.
Herhangi bir restoranda yemek siparişi veren bir müşteri olduğunuzu düşünün. Bu senaryoda sipariş verdiğiniz yemeğin ne olduğunu biliyor olduğunuzu varsayacağım. Siparişiniz getirildiğinde tabakta ne olacağını biliyor olmanız Model kavramına, tabakta gördükleriniz View kavramına ve garsonun mutfakla siz (müşteri/client) arasındaki iletişimi sağlamasıysa Controller kavramına denk gelir. Garson müşterinin siparişini alır ancak müşteriyi siparişinin nasıl hazırlanacağı ya da siparişi kimlerin hazırlayacağı gibi detaylarla meşgul etmez. Zaten müşteri de bu detayları bilmek istemez :) Ancak garson mutfağa gittiğinde siparişi kime iletmesi ve kimden teslim alması gerektiğini bilir. Çünkü garson mutfaktaki tüm görev dağılımı bilgisine sahiptir.
Bir isteğin yol akışı
MVC projesindeki bir isteğin yol akışını basit bir örnekle gösterelim.
Kullanıcı, https://restorant.com/musteriler adresine istek atsın.
Bu adresin Model sınıfı şöyle olsun:
public class Musteri
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}Modelimiz id, name ve email alanlarına sahip. Yani herhangi bir istek yapıldığında bu isteğin id, name ve email bilgilerini içereceğini biliyoruz.
Controller sınıfı:
public class MusteriController : Controller
{
public IActionResult Index()
{
// Normalde veri veritabanından çekilir, ama basit tutalım:
var musteriler = new List<User>
{
new Musteri { Id = 1, Name = "Dilara", Email = "dilara@deneme.com" },
new Musteri { Id = 2, Name = "Derya", Email = "derya@deneme.com" }
};
return View(musteriler); // View'e veriyi gönderir
}
}.Net MVC projelerinde controller oluşturmak için Controller sınıfını miras almanız gerekir. Bu sınıf içerisinde gerekli tüm metodları bulundurur. MusteriController sınıfı ilk olarak Model sınıfımıza istekte bulunur ve sonrasında aldığı bilgileri View a döndürür. Yani ilk olarak mutfağa siparişi iletir ve sonra mutfaktan aldığı tabağı (veriyi) müşteriye götürür (view).
View dosyası:
@model List<User>
<h2>Müşteri Listesi</h2>
<ul>
@foreach (var musteri in Model)
{
<li>@musteri.Name - @musteri.Email</li>
}
</ul>En son aşamada view dosyasında değişiklikler kullanıcının göreceği şekilde yapılır. Örneğin yukardaki kodda müşteri listesi ekrana yazdırılır. View in işi sadece görsellik ve sunumdur.
Get Dilara Kardaş’s stories in your inbox
Join Medium for free to get updates from this writer.
Bu akışı özetlemek gerekirse iş akışı şu şekilde olur:
Kullanıcı /musteriler adresine gider ->
Tarayıcı bu isteği UserController a iletir ->
Controller, modelden (ya da veritabanından) veriyi alır ve view a yollar ->
View, veriyi kullanıcıya gösterir.
MVVM (Model–View–ViewModel)
MVC mimarisine benzer şekilde MVVM de yazılım bileşenlerini birbirinden ayırmayı amaçlar. Ancak bu desende Controller yerine ViewModel bulunur. ViewModel, bir yandan View ile Model arasında veri akışını yönetirken, diğer yandan kullanıcı arayüzünün ihtiyaçlarını karşılar.
Başka kaynaklarda viewModel için çok daha detaylı ve formal tanımlar bulabilirsiniz ancak benim tanımımla ViewModel, kullanıcının göreceği datayı filtreler. Örneğin Musteri modelinde müşterinin TC kimlik numarası gibi hassas bir bilgi olabilir. Ancak bu veriyi doğrudan arayüze taşımak, kişisel verilerin korunması açısından doğru olmaz. Bu durumda, MusteriViewModel isimli ayrı bir sınıf tanımlanır ve sadece gerekli alanlar (örneğin ad, soyad, sipariş no gibi) bu sınıfa map edilir.
Böylelikle viewModel bir nevi “ara katman” görevi görür; View’ın ihtiyaç duyduğu veriyi şekillendirir, fazlasını gizler, bazen de kullanıcı etkileşimlerine uygun ek veriler üretir.
DTO (Data Transfer Object)
DTO ve MVVM kavramlarını ilk öğrendiğimde bu iki kavramı sürekli birbirine karıştırıyor ve hatta bir süre aynı şey olduklarını sanıyordum. Aslında her ikisi de veriyi düzenli ve güvenli bir şekilde taşımayı amaçlar, ancak farklı soyutlama seviyelerinde yer alırlar. MVVM bir mimari pattern iken DTO sadece bir veri nesnesidir ve genellikle katmanlar arası veri taşımak için kullanılır. Örneğin, backend’deki bir Musteri nesnesini API üzerinden frontend’e göndermek istiyorsan, doğrudan Musteri modelini dışarı açmak güvenli veya pratik olmayabilir. Bu durumda bir MusteriDto oluşturur, sadece gerekli alanları bu sınıfa eklersin. DTO’lar genellikle taşıyıcı nesnelerdir; içinde iş mantığı barındırmazlar.
Bir API projesinde de gelen veriyi özelleştirmek için de DTO (Data Transfer Object) kullanılabilir. Veri çekilecek bir projede model, endpoint’ten gelecek veri tipine göre oluşturulur. Örneğin, endpoint yalnızca müşterinin adı, maili ve telefonunu döndürüyorsa, model sınıfında da yalnızca bu alanlar tanımlanmalıdır. Ancak birçok senaryoda veriler veritabanına kaydedilirken primary key (id) alanına ihtiyaç duyulur. Bu durumda veriler doğrudan model nesnesi üzerinden kaydedilemez, çünkü modelde id alanı bulunmamaktadır. İşte burada DTO devreye girer.
DTO sınıfı, modelin bir kopyası gibi davranır ama üzerine id gibi ek alanlar tanımlanabilir. Böylece, verileri API’den çekerken model nesnesi, verileri veritabanına kaydederken DTO nesnesini kullanılır.
Yazdıklarımızı kodla gösterelim:
// API'den veri çekerken kullanılan model
public class MusteriModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] //id nin db tarafından otomatik arttırılmasını sağlar.
public int Id { get; set; } //primary key
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
// Veritabanına kaydederken kullanılan DTO (model kopyalaıp id ekleniyor)
public class MusteriDTO
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}// API'den veri çekiyoruz
var apiMusteri = new MusteriModel { Name = "Dilara", Email = "dilara@deneme.com", Phone = "05555555555" };
// Veritabanına kaydetmek için DTO oluşturuyoruz
var dbMusteri = new MusteriDTO
{
//id otomatik oluşturulacağı için değer atamamıza gerek yok
Name = apiMusteri.Name,
Email = apiMusteri.Email,
Phone = apiMusteri.Phone
};MVC nin Avantajları
MVC kullanmanın bir çok avantajı var ancak ben bu yazımda en temel 5 sebepten bahsedeceğim.
1. Kodun bakımının kolaylaştırır Herkes sadece kendi işinden sorumlu olduğu için projede bir değişiklik yapmak istediğinizde sadece ilgili yeri değiştirmeniz yeterli olur ve yapılan değişiklik kodun diğer kısımlarını etkilemez.
2. Test edilebilirliği artırır Kodun sorumluluklara göre bölünmesi her bileşenin ayrı ayrı test edilmesini sağlar. Bu sayede herhangi bir controller metodunuzun sağlıklı çalışıp çalışmadığını kodun diğer kısımlarını etkilemeden test edebilirsiniz.
3. Ekip çalışmasını kolaylaştırır Frontend ekibi view kısmında geliştirme yaparken backend ekibi controller da geliştirme yapabilir. Çünkü bileşenler bağımsız olduğu için ekipler birbirinin koduna müdahale etme derdi yaşamaz.
4. Kodun yeniden kullanılabilirliğinini sağlar Model ve Controller mantıkları farklı projelerde veya farklı View’larla tekrar kullanılabilir. Örneğin aynı Model’i hem bir web uygulamasında hem de bir API’de kullanmak mümkündür.
5. Genişlemeye ve değişime açık bir yapı sunar Hızla değişien teknolojiye ayak uydurur. Örneğin view tarafında react kullanılmak istendiğinde proje yapısında sadece View katmanının değiştirilmesi yeterli olur. Model ve Controller büyük oranda aynı kalır.
MVC nin Dezavantajları
Şu ana kadar MVC den mükemmel bir mimariymiş gibi bahsetsek de tabi ki bazı dezavantajalrı var. Özellikle yeni başlayanlar için bu yapı ilk başta hem karmaşık hem de “fazla katmanlı” olabilir. Ancak bir kez anlandı mı kullanımı oldukça kolay bir hale gelir. Kullanımı dışında başka dezavantajları da var tabi ki.
1. Controller’ların zamanla şişmesi (Fat Controller Problemi)
Küçük bir projede Controller’lar genellikle basittir. Ancak proje büyüdükçe tüm iş mantığının kontrol katmanına taşınması, Controller’ları oldukça büyük hale getirir. Ancak bu sorun servis katmanları kullanılarak çözülebilir. Örneğin küçük bir projede controller hem modele istek atıp hem de veritabanına kayıt yapabilir ancak proje büyüdükçe servis katmanı oluşturulup veri tabanına kayıt işlemi bu kısımda yapılabilir. Bu sayede controller en temelde tanımlandığı gibi sadece modelle view arasındaki iletişimden sorumlu olur.
2. Yeni başlayanlar için dosya karmaşası
MVC düzenli bir yapı sunsa da, ilk kez gören biri “neden bu kadar kalasör var?” diyebilir (ben de ilk gördüğümde klasörler gözümü inanılmaz korkutmuştu.). Model, View ve Controller’ların ayrı klasörlerde bulunması başta karışık gelse de, proje büyüdükçe bunun aslında önemli bir düzen olduğu kavranır.
3. Küçük projeler için fazla katmanlı hissettirebilir9
Basit bir uygulama için bile üç farklı dosyada değişiklik yapmak bazen fazla gelir. Bu yüzden MVC, her projede kullanılacak “tek doğru” çözüm değildir. Ufak projelerde daha sade yapılar kullanmak mantıklı olabilir.
4. “MVC = sadece web için” yanılgısı
MVC genellikle web uygulamalarıyla özdeşleştirilir. Oysa MVC, bir düşünme biçimidir. Web dışında, masaüstü uygulamalarında, mobil geliştirmede hatta oyun motorlarında bile aynı prensip uygulanabilir. Yani MVC bir framework değil, bir yaklaşım biçimidir. MVC mantığını bir kere kaptınız mı artık bir çok projeye uyarlayabilirsiniz.
5. Katı yapının öğrenme eşiği
MVC, temiz bir mimari sunsa da bu temizlik belli bir disiplin gerektirir. Kodun nereye yazılacağı, hangi katmanın hangi işi üstleneceği gibi kurallara dikkat edilmezse yapı hızla dağılır. Kısacası MVC’yi anlamak kolay, doğru uygulamak sabır ister.
Yazının sonuna geldik. Genel olarak MVC ve birkaç kavram hakkında bilgi vermeye çalıştım. Yazının başında bahsettiğim gibi aslında bu yazıları kendi öğrenme sürecimi somutlaştırma adına yazıyorum. Yanlış ya da eksik anlatılmış bilgiler görürseniz lütfen düzeltmekten çekinmeyin. Bu yazıda anlattığım teknolojileri kullandığım projelerimi görmek için github hesabımı, bana ulaşmak içinse linkedin hesabımı ziyaret edebilirsiniz.








