MVC ve ORM

osm4n homek
5 min readMar 6, 2019

Öncelikle, alet çantamıza bir bakalım.

Programlama Dili : GoLang https://golang.org/
Web Framework : Iris Backend Framework https://iris-go.com/
ORM Library : GORM http://gorm.io/
Veritabanı : MySQL https://www.mysql.com/

Neden Iris veya neden Gorm gibi soruların cevabı bu yazıda yeralmayacak. Genel performans, yetenekler ve kullanım kolaylığı gibi özellikleri gözönünde bulundurarak, bu birlikteliği uygun gördüm ;)

Sonrasında, derdimizin MVC kurallarına göre CRUD işlemini yapmak olduğunu belirtelim.

MVC: Model View Controller
Veritabanı işlemleri için, uygulamanın nasıl olması gerektiği ile alakalı çok katmanlı bir yöntem sunan tasarım deseni.

CRUD: Create Read Update Delete
Veritabanı işlemlerinin tamamını kapsayan kısaltma

İlgili örnek kodlarımızın toplu ve çalışır halde olduğu halini bulabilmeniz için

adresini de şuraya koyalım ve başlayalım.

MVC, tasarım deseni isminden de anlaşılacağı üzere 3 katmanlıdır. Katmandan kasıt ilgili katmanlar için birer sayfa açıp sadece ilgili kodu içerisine koymak demek değildir. Burada önemli olan konu, izolasyondur. Yani katmanların sadece kendi işlerini yapabilir halde olmalarıdır.

Katmanlar arası ilişki ve sıralama ile alakalı şu görseli paylaşarak üzerinde konuşmaya başlayalım.

Tam çevrime sahip MVC tasarım deseni

İşin başlangıcı pektabiiki, tarayıcı veya konsol gibi bir kaynaktan bir HTTP talebi oluşturmak. Yani basitçe, Chrome’a gidip google.com yazmak. Böylelikle, GET tipinde bir adet HTTP talebi oluşturmuş olduk.

Bu talep, google.com sunucularına eriştiğinde, onu ilk karşılayan genellikle ROUTER mekanizmasıdır. Router içerisinde elindeki talebi hangi Controller’a ileteceğinin belirtilmiş olduğu bir liste mevcuttur. Böylelikle, talep Controller’ın kucağına düşer.

Kimi durumlarda, Controller’dan önce Before Middleware denen ara bir katmana girer. Bu katmanda genellikle iki ana işlem yapılır.
- Talebi yapmaya yetkili olup olmadığı kontrol edilir
- Cache-ön bellek mekanizması kullanıyorsanız, talebin Service katmanına gönderilmeden doğrudan View katmanına iletilmesini sağlayabilirsiniz

Controller, esasen doğrudan bir işin yapıldığı bir katman değildir. Ana görevi, gelen verinin Service katmanına iletilmesini ve dönen verinin View katmanına iletilmesini sağlar. Eğer bu alma verme sırasında veriler üzerinde bir değişiklik yapılma ihtiyacı mevcut ise Helper gibi bir başka katman ile alışverişte bulunarak bu işlemi tamamlar. Mesela gelen tarih verisinin formatlanması gibi tasarımsal değişiklikler bu katmanda gerçekleşir.

Service katmanı gelen verinin kontrol edildiği, Repository katmanına iletildiği ve gelen cevabın Controller katmanına geri iletildiği katmandır. Mesela kullanıcı adı ve parolanın kontrol edilmesi gereken bir talep için Service katmanında kullanıcı adı ve parola verisinin yeterli özelliklerde olup olmadığı kontrol edilir. Eğer doğru ise, Repository katmanına gönderilir.

Repository katmanı, Service katmanından gelen veriler ile veritabanı, micro-service gibi veri kaynaklarına erişir ve dönen sonucu Service katmanına iletir. Veritabanı namına CRUD işlemlerinin yapıldığı ana katman Repository katmanıdır.

Senaryo yolunu izleyerek After Middleware’a gelen istek, bu katmanda genellikle gelen verinin formatını dönüştürülmesi işlemlerinin yapıldığı katmandır. Mesela, elinize gelen veri JSON formatındadır. Ama sonuç XML isteniyorsa bu katmanda ilgili değişikliği yapabilirsiniz. Yada çok dilli bir uygulama geliştirdiğinizi düşünelim. Dil dönüşümü ekseriyetle bu katman içerisinde yapılır.

Son olarak, View katmanına geliriz. Bu katman genellikle HTML şablonlarımızın Controller katmanından gelen veriler ile “render” edildiği ve salt sonucun talep edene gönderildiği katmandır.

MVC’nin V ve C sinden bahsettik ancak M sinden hiç bahsetmedik. Yani Model katmanı hiç geçmedi. Aslında en uzun Model katmanı geçti. Çoğu zaman tek bir sayfadan oluşan Model katmanını örneğimde, Service ve Repository ara katmanları ile çeşitlendirdik.

Nekadar çok uzattın birader?

Eğer, telefon defteri uygulaması yapıyorsanız bir tane sayfa açar, herşeyi içerisine yazar işi belkide bir tane method içerisinde halledebilirsiniz.

Burada önemli olan konu, her zaman için birbirinde izole olmuş sadece aldığını-vereceğini bilen katmanlar üretmek. Böylelikle ilettiği veya sonuç aldığı katman ile ilişiği kalmayan yapılar üretmiş olursunuz. Bu durum sizin herzaman sağlıklı bir şekilde değiştirilebilir, dönüştürülebilir katmanlar üretmenizi sağlar.

Buraya kadar anlattıklarım MVC tasarım deseni/kalıbı ile alakalı idi diyebiliriz. Bu tasarım kalıbı herhangi bir programlama dilinde herhangi bir framework içerisinde uygulanabilir. Ancak Iris, MVC yi kendi bünyesinde barındırıyor. Benim Iris üzerinde geliştirme yapmamın ana sebeplerinden bir taneside bu.

Gelelim ORM konusuna.

ORM : Object Relating Mapping
Adı üzerinde varolan nesnelerimizi daha doğrusu “Model”imizi veritabanı ile bağlayan mekanizma

Bu tanımdan doğrudan anlaşılacak konu ORM nin yerinin bizim örneğimizde Repository katmanı olduğudur.

Konumunu belirttikten sonra önemli avantajlarını sıralayalım:

  • Nesnelerimiz ile kurduğu köprü nedeniyle (eğer istemez isek) veritabanı ile hiçbir ilişkimiz kalmıyor. Bu durum, arka tarafta çalışan veritabanının ne olduğu önemini ortadan kaldırıyor. Böylelikle, sadece veritabanı bağlantı cümleciğini değiştirerek (eğer kullandığınız ORM izin veriyorsa) RDBMS’den NoSQL’e saniyeler içerisinde geçebilirsiniz.
  • AutoMigration, Polymorphism, Hooks, Transactions, Locking, Concurrency, Cache gibi birçok soruna çok kolay çözümler getirerek işimize odaklanmamızı sağlıyor. Kaldıki, bu maddelerin her birisi kendi başına hatrı sayılır arkadaşlardır.

Devajantajlarına gelince:

  • SQL gibi jenerik bir mekanizması olmaması sebebiyle, her ORM’nin kendince bir öğrenme süreci vardır.
  • ORM’nin yıllar önce popülerliğinin çok yüksek olduğu zamanlarda ciddi performans problemleri vardı. Native bir şekilde veritabanına dokunmadığınız araya bir katman girmesi sebebiyle mutlaka performans kaybı olacaktır. Ancak verim hesabı yapıldığında ORM, ORM sizliği döver :)
Yapıştırın tokadı!

Şimdi biraz kod örnekleri ile havadakini yere indirelim.

book_model.go

type Book struct {
gorm.Model
Title string `gorm:"size:15"`
Author string `gorm:"size:15"`
}

Hemen yeri gelmişken belirtmiş olayım. GORM, Modeli üretirken gorm.Model satırını eklerseniz, ID Primary Key, created_at, updated_at, deleted_at kolonlarını kendisi ekliyor. Böylelikle bu verileri tutmak istiyorsanız hiçbirşey yapmıyorsunuz. Hatta (varsayılan değer olarak) kaydı silerseniz (yani kaydın silinmesi komutunu çalıştırırsanız) kaydı silmiyor, silindi olarak işaretliyor.

book_controller.go

func (c *BookController) GetIdBy(id int64) (results models.Book) {    return c.Service.GetByID(id)
}

Route katmanından GetIdBy fonksiyonuna ilgili ID ile geliyor. ID üzerinde hiçbir işlem yapmadan aldığı veriyi doğrudan Service katmanına gönderiyor.

book_service.go

func (s *bookService) GetByID(id int64) models.Book {    return s.repo.SelectById(id)
}

Service katmanı da elindeki veriyi doğrudan Repository katmanına veriyor.

book_repository.go

import ("github.com/jinzhu/gorm")func (m *bookMysqlRepository) SelectById(id int64) models.Book {    result := models.Book{}
m.DB.Where("id=?",id).First(&result)
return result
}

Repository katmanı Gorm aracılığı ile veritabanına ulaşıp sonucu geriye dönüyor. En son dönen veri Controller katmanına Json formatında geliyor. Ben ilgili kod parçacığında View katmanı kullanmadığım için veri doğrudan talep edene geri dönüyor. Mesela API talebi yada Ajax talebi gibi düşünebilirsiniz.

1990'lardan beri kod geliştiren birisi olarak şunu söyleyebilirimki, yazılımda vaktiyle hiçbirşeylerin olmadığı bir halden, birçok şeyin ortada olduğu vakitlere geldik. Sanıyorum ana problem hiç değişmedi. Dökümantasyon. Bir önceki yazılımcı ile sonraki yazılımcıları bir türlü aynı kefede tutamadık. Dökümantasyon yazmayı sevmeyen yazılımcılar bir taraftan, yazılan dökümanın çok kısa bir süre içerisinde geçerliliğini kaybetmesi hep bir sorun üretti.

En sonunda birileri dediki:

Bizi ortak bir noktada birleştirecek, böylelikle hem kod yazımında hem kod kalitesinin gelişmesinde standartlaştıracak araçlara ihtiyacımız var.

Ben inanıyorumki, çantamızı dolduran aletler (framework ve library) esasen bu motivasyon ile yola çıktı.

Bir slogan ile yazımızı bitirelim.

Yeniden inşa etmek, var olanı onarmaktan daha kolaydır.

Yeniden inşa edilemez durumda iseniz, onarmayı tahammül edilebilir kılmak için, framework/library kullanın!

--

--

osm4n homek

fıkradaki temel gibiyim, kendimden emin ama herşeyin tersineİ dWx0cmEgbG93IGxhdGVuY3kgc3VzdGFpbmFibGUgaGlnaCBlZmZpY2llbmN5