Go’da KISS, DRY ve LOD Prensipleri: Uygulama Rehberi
Karmaşık Go projelerinde verimliliği ve sürdürülebilirliği nasıl sağlayacağınız konusunda mı sıkıntı yaşıyorsunuz? Bu makalede, yazılım geliştirmenin temel prensipleri olan KISS (Keep It Simple, Stupid), DRY (Don’t Repeat Yourself) ve LOD (Law of Demeter) prensiplerini Go dilinde nasıl uygulayacağınızı adım adım öğreneceksiniz. KISS, DRY ve LOD’u anlamak ve uygulamak, kodunuzun okunabilirliğini, bakımını ve ölçeklenebilirliğini önemli ölçüde artıracaktır. Hazırsanız, Go kodunuzda bu güçlü prensipleri kullanmanın yollarına dalalım!
Go’da KISS Prensibini Uygulama: Basitliğin Gücü
KISS prensibi, yazılımın gereksiz karmaşıklıktan arındırılarak basit tutulması gerektiğini savunur. Go’nun özlü ve okunabilir sözdizimi, KISS prensibine doğal olarak uygundur. Ancak, karmaşık iş mantığını basit fonksiyonlara ve modüllere ayırmak için bilinçli bir çaba göstermek gerekir. Fonksiyonlarınızın tek bir görevi yerine getirmesine odaklanın. Uzun ve karmaşık fonksiyonlar yerine, daha küçük, daha yönetilebilir fonksiyonlara bölün. Bu, kodun okunabilirliğini ve hata ayıklama sürecini kolaylaştıracaktır.
Örneğin, bir veritabanından veri çekme, işleme ve sunma işlemlerini tek bir büyük fonksiyonda toplamak yerine, her bir işlemi ayrı bir fonksiyonda gerçekleştirmek daha KISS uygundur. Bu, kodun daha modüler, daha test edilebilir ve daha kolay bakımı yapılmasını sağlar.
// Kötü örnek: Tek fonksiyonda her şey yapılıyor.
func processDatabaseData(db *sql.DB) (string, error) {
rows, err := db.Query("SELECT * FROM users")
if err != nil { return "", err }
defer rows.Close()
// Veri işleme ve sunma işlemleri burada...
// Çok uzun ve karmaşık kod burada olabilir.
return result, nil
}
// İyi örnek: Görevler ayrı fonksiyonlara ayrılmış.
func fetchData(db *sql.DB) ([]User, error) {
// Veri çekme işlemi
return users, nil
}
func processData(users []User) []User {
// Veri işleme işlemi
return processedUsers
}
func presentData(users []User) string {
// Veri sunma işlemi
return output
}
func main(){
//Daha temiz ve okunaklı
}
Bu yaklaşım, kodun anlaşılırlığını ve bakımını kolaylaştırır. Her fonksiyonun tek bir görevi olduğundan, hata ayıklama ve test etme daha kolay hale gelir. Ayrıca, gelecekte kodun genişletilmesi veya değiştirilmesi de daha kolay olacaktır.
Go'da DRY Prensibini Uygulama: Kod Tekrarını Önleme
DRY prensibi, kodunuzda tekrar eden kısımları ortadan kaldırmanızı önerir. Go'da bu, fonksiyonlar, yapıları ve döngüler kullanarak gerçekleştirilebilir. Aynı kod bloğunu birden çok yerde tekrarlamak yerine, bir fonksiyon veya yapı içinde tanımlayarak tekrar kullanımını sağlayabilirsiniz. Bu, kodun boyutunu küçültür, tutarlılığını artırır ve bakımı kolaylaştırır.
Örneğin, bir veritabanı bağlantısı kurma işlemini her yerde tekrarlamak yerine, bir fonksiyon içinde tanımlayıp, ihtiyaç duyulduğunda bu fonksiyonu çağırabilirsiniz:
// Kötü örnek: Veritabanı bağlantısı her yerde tekrarlanıyor.
func function1() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database")
// ...
}
func function2() {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database")
// ...
}
// İyi örnek: Veritabanı bağlantısı tek bir fonksiyonda tanımlanmış.
func getDatabaseConnection() (*sql.DB, error) {
db, err := sql.Open("mysql", "user:password@tcp(127.0.0.1:3306)/database")
if err != nil {
return nil, err
}
return db, nil
}
func function1() {
db, err := getDatabaseConnection()
// ...
}
func function2() {
db, err := getDatabaseConnection()
// ...
}
Go'nun güçlü yapıları ve fonksiyonel yetenekleri ile kod tekrarını önlemek ve DRY prensibine bağlı kalmak oldukça kolaydır.
Go'da LOD (Law of Demeter) Prensibini Uygulama: Bağımlılıkları Azaltma
LOD prensibi, bir nesnenin yalnızca doğrudan ilişkili olduğu nesnelerle etkileşim kurması gerektiğini belirtir. Bu, nesneler arasındaki bağımlılıkları azaltır ve kodun daha modüler ve bakımı kolay olmasını sağlar. Go'da, bu prensibi uygulamak için, uzun zincirleme çağrıları (method chaining) yerine, daha kısa ve daha doğrudan çağrılar kullanmalısınız.
Örneğin, bir User nesnesinin Address nesnesinin City nesnesinin adını almak istiyorsanız, aşağıdaki gibi bir zincirleme çağrı yerine:
city := user.getAddress().getCity().getName() // LOD'ye uymuyor
daha doğrudan bir yaklaşım kullanmanız daha iyidir:
city := user.getCityName() // LOD'ye uyuyor
Bu yaklaşımda User nesnesi, Address ve City nesneleriyle doğrudan etkileşim kurmak yerine, getCityName() fonksiyonunu kullanarak gerekli bilgiyi alır. Bu, kodun daha okunaklı, daha az bağımlı ve daha kolay test edilebilir olmasını sağlar.
LOD'ye Uymayan Bir Örnek ve Düzeltmesi
Diyelim ki bir e-ticaret sisteminde ürünlerin stok bilgilerini güncellemek istiyoruz. LOD prensibine uymayan bir yaklaşım şu şekilde olabilir:
//LOD'ye uymayan örnek
func updateProductStock(order *Order){
product := order.getCustomer().getAddress().getProduct().updateStock(1)
}
Bu örnekte, updateProductStock fonksiyonu, Order nesnesiyle başlayarak, bir dizi nesneyi çağırıp, stok bilgilerini güncelliyor. Bu, yüksek bağımlılık ve düşük okunabilirlik anlamına gelir.
LOD prensibine uygun bir yaklaşım şu şekilde olabilir:
//LOD'ye uyan örnek
func updateProductStock(order *Order, productId int, quantity int) {
product, err := getProductById(productId) //Servis kullanarak ürünü alıyoruz
if err != nil {
//Hata yönetimi
}
product.updateStock(quantity)
}
Bu örnekte, updateProductStock fonksiyonu, Order nesnesinden bağımsız olarak çalışır ve sadece getProductById servisini kullanarak ürüne ulaşır.
Go'da KISS, DRY ve LOD Prensiplerini Birlikte Uygulama: Gerçek Dünya Senaryosu
Şimdi, bu üç prensibi birlikte uygulayan gerçek bir dünya senaryosunu ele alalım. Bir blog platformu için yorum ekleme fonksiyonu yazacağımızı varsayalım. KISS prensibine göre, bu fonksiyon mümkün olduğunca basit olmalıdır. DRY prensibi gereği, kod tekrarını önlemek için yardımcı fonksiyonlar kullanılmalıdır. Son olarak, LOD prensibine göre, yorum nesnesinin yalnızca doğrudan ilişkili olduğu nesnelerle etkileşim kurması sağlanmalıdır.
package main
import (
"fmt"
"time"
)
type Comment struct {
ID int
Text string
Author string
Posted time.Time
PostID int
}
type Post struct {
ID int
}
//Yorum ekleme fonksiyonu
func addComment(post *Post, author string, text string) (Comment, error) {
comment := Comment{
ID: generateCommentID(), // DRY prensibi burada sağlanıyor
Text: text,
Author: author,
Posted: time.Now(),
PostID: post.ID,
}
//veri tabanına kaydetme işlemi
return comment, nil
}
func generateCommentID() int {
//ID üretme mantığı buraya gelecek
return 1
}
func main() {
post := &Post{ID: 1}
comment, err := addComment(post, "Fatih Soysal", "Harika bir makale!")
if err != nil {
fmt.Println("Hata:", err)
} else {
fmt.Printf("Yorum eklendi: %+v\n", comment)
}
}
Bu örnekte, addComment fonksiyonu basit ve okunabilirdir. generateCommentID fonksiyonu kod tekrarını önler. Ayrıca, yorum nesnesi sadece Post nesnesiyle doğrudan etkileşim kurar.
Öğrenme Yol Haritası
[Yeni Başlayan]: Go'nun temel sözdizimini öğrenin. Küçük, basit programlar yazın. KISS prensibini anlayıp uygulayın. Tek bir görevi yerine getiren fonksiyonlar yazmaya odaklanın.
[Orta]: Fonksiyonlar, yapılar ve döngüler kullanarak daha karmaşık programlar yazın. DRY prensibini uygulayarak kod tekrarını önleyin. Yardımcı fonksiyonlar ve yapıları kullanarak kodunuzu düzenleyin.
[İleri Düzey]: LOD prensibini inceleyin ve uygulamalarını geliştirin. Nesneler arası bağımlılıkları azaltın. Karmaşık projelerde bu üç prensibi birlikte uygulayın. Go'nun paket yönetim sistemini kullanarak modüler projeler geliştirin. Daha fazla bilgi için (https://fatihsoysal.com) inceleyebilirsiniz.
Performans Karşılaştırması: Tablo vs. Liste vs. Özel Çözüm
| Yöntem | Performans (Ortalama) | Bellek Kullanımı | Okunabilirlik | Bakım Kolaylığı |
|--------------|-----------------------|--------------------|-----------------|-------------------|
| Basit Tablo | Yüksek | Orta | Yüksek | Orta |
| Liste | Orta | Düşük | Orta | Düşük |
| Özel Çözüm | Çok Yüksek | Orta | Düşük | Düşük |
Uzman İpucu: Veri yapısı seçiminde, performans ve okunabilirlik arasında denge kurmanız önemlidir.
Güvenlik Uyarıları
Sonuç
KISS, DRY ve LOD prensipleri, Go'da temiz, sürdürülebilir ve ölçeklenebilir kod yazmak için olmazsa olmaz prensiplerdir. Bu makalede ele aldığımız örnekler ve açıklamalar, Go projelerinizde bu prensipleri uygulama konusunda size yardımcı olacaktır. Daha fazla ipucu ve örnek için (https://fatihsoysal.com) adresini ziyaret edebilirsiniz.
Sıkça Sorulan Sorular
1. KISS, DRY ve LOD prensipleri arasında nasıl bir ilişki vardır? Bu üç prensip birbirini destekler. KISS, genel bir yaklaşım belirlerken, DRY ve LOD, bu yaklaşımı uygulamak için spesifik teknikler sunar.
2. LOD prensibini ihlal etmek neden kötüdür? Bağımlılıkları artırır, kodun okunabilirliğini azaltır ve bakımı zorlaştırır. Test etme ve hata ayıklama sürecini de karmaşıklaştırır.
3. Go'da DRY prensibini uygulamanın en etkili yolları nelerdir? Fonksiyonlar, yapılar, arayüzler ve generics (Go 1.18 ve üzeri) kullanımı.
4. KISS prensibine uymak performansı nasıl etkiler? Genellikle performansı olumsuz etkilemez, aksine, daha temiz kod daha kolay optimize edilebilir.
5. LOD prensibine uymanın performans üzerinde bir etkisi var mıdır? Genellikle performans üzerinde çok az etkisi olur, ancak kodun okunabilirliği ve sürdürülebilirliği açısından büyük faydalar sağlar.
Yazar: Fatih Soysal
