Data Vinci 20 : Code Smells

Tahmini Okuma Süresi: 9 dakika

Bu yazıda camiada “Code Smells” olarak bilinen bir kod davranışından söz etmek istiyorum. Mecazi olarak anlamlandırıldığında “kötü kokan kod” gibi bir anlam çıkabilir. Kötü pratiklerden birisidir. İyi kod yazma pratikleri verilirken genişletilebilir, okuması kolay, gramer olarak düzgün, isimlendirmelerin doğru yapıldığı, her operasyonun sadece kendi görevini icra ettiği, gevşek bağlı pırıl pırıl bir kod öneriyor. Kıyısı köşesi tuz ruhuyla iyice yıkanmış kodlar, gız pencereleri de iyice ovala…

İşte bunları yapamayan, eksik yapan kodlar başkaları tarafından okunması zorlaşan kodlar oluyor.

İyi kod yazma pratikleri geniş bir alana hitap eden, içerisinde hem teknik hem de pratik bir takım yöntemler barındıran bir liste. Kodun kalitesine etki eden onlarca etken var. Bunların bazıları kritik iken bazılarına da “nice to have” denebilir. Yani uygulanmasa da çalışan bir kod üretmeye engel olmayan yazılım dünyasının cefakâr abileri sayesinde bizlere sunulan listeler. Object oriented bir yazılım dili kullanılırsa, bu konseptin öne sürdüğü yöntemler kullanılmalı. Listenin ne kadar uzun olduğuna şöyle bir bakalım. Tüm bu yöntemlerin her biri bir yazıya konu olabilecek kapsama sahipler. Hazırsanız varoşlardan çıkıyor, temiz kod dünyasına doğru yelken açıyoruz. Kötü kokan kodlar taksonomi olarak 5 sınıfa ayrılmakta. The Bloaters, The Object-Orientation Abusers, Change Preventers, Dispensables, The Couplers sınıfları karşımıza çıkmaktadır. Bu sınıflar altında yer alan “kokuları” kurcalayalım.

The Bloaters

Genel olarak kontrolsüz büyüyen objeler, methodlar, sınıfların sonunda çalışalamaz hale gelmesi ile ilgili kokular olarak bahsetmek mümkün.

Long Method : Aslında adı üstünde çok uzun methodları konu alır. İyi kodlama pratiği olarak bir metotun 10 satırı geçmemesi önerilmektedir.

Problem
Uzayan metotlar, okunması zor kodlar ortaya döküyor hâkim bey.
Çözüm
Yaz kızım, uzayan metotları parçalara ayır, ayrılamayan ve hâlâ büyük boyutlarda ise bir sınıfa taşımanın vakti gelmiş olabilir. 

Large Class : Başlangıçta yazmış olduğumuz tüm sınıflar, “minnoş”, “ponçik”, “şapşik” olabilir. Fakat gereksinimler değiştikçe sınıf içerisinde yer alan alanlar(fields), metotlar(methods) artabilir, yani bir maliyet birimi olarak “line of code” şişebilir. Eğer böyle bir ölçüm kriteriniz varsa da sizden kan alırlar.

Problem
Bir sınıfın büyüklüğü ve işlevselliğinin fazlalığı karmaşıklığı artırır.
Çözüm
  • Sınıf içerisinde ayrılabilen kısımlar başka bir sınıfa taşınabilir.
  • Sınıf interface’lere ayrılabilir. Böylelikle bizzat kendinde bulunması zorunlu olmayan özellikleri arayüz objelerinden miras alabilir.

Long Parameter List : 3-4 parametreden fazla parametre içeren metotları tanımlar.

Problem
Metotların aldığı parametre sayısının fazla olması hem kodun okunabilirliğini azaltır hem de bağımlılık yönetimini zorlaştırır.
Çözüm
  • Çok fazla sayıda argüman parametre olarak kullanılıyorsa bunlardan bir sınıf yapılabilir.
  • Metot sonucunda bir başka değişkenin değeri belirlenebiliyorsa paremetre kullanmak yerine bir metot yazmak mümkün olabilir. Yani nihayi hedefimiz bir şeyi hedeflemekse ne var ne yok parametre geçip sonuç dönmek yerine, oluşacak sonuca etki eden işlemleri ayrı ayrı metotlar halinde elde edebiliriz.

Data Clumps: Belli başlı fonksiyonlar bir metotun veya sınıfın içerisinde tekrar tekrar kullanılıyor olabilir. Copy-Paste programming konseptinde sıklıkla rastlanır. Bu gibi gruplar kodu gereksiz yere uzatır, okunabilirliği düşürür.

Problem
Aynı işi yapan kod bloklarının tekrar tekrar kullanılması.
Çözüm
  • Tekrar eden kısımlar bir metota alınabilir veya sınıfa da alınabilir.

Primitive Obsession: 

Basit görevler için küçük objeler yerine primitive tiplerin kullanılması, bunun sürekli olarak eklenmesi ile de karmaşık bir yapı oluşmaktadır.

Problem
Data tipleri kullanırken objeler ile çalışabilecek iken primitif tiplerin kullanılması
Çözüm
  • Primitif tiplerden oluşan bir veri seti var ise bunun bir sınıf ile temsil edilmesi.
  • Birbiriyle ilişkili objeler arasındaki bağlar Strateji tasarım deseniyle ifade edilebilir.

The Object-Orientation Abusers

Switch Statements: Kompleks karar mekanizmalarında switch veya if operatörlerinin kullanılmasıyla spagettiye ön ayak olacak kodlar ortaya konulabilir.

Problem
Switch ve if gibi yapıların iş mantıklarında kullanılması kodun okunurluğunu azaltmaktadır.
Çözüm
  • Bu gibi yapıların izole edilmesi gerekir.
  • Çok biçimlilik(Polymorphism) kullanılabilir.

Refused Bequest: Kalıtım kavramının yanlış kullanımdan kaynaklanan bir kokudur. Türeyen sınıflar ana sınıf içerisindeki metotların çok azını kullanıyorsa bu kokuya işaret eder.

Problem
Çocuk sınıfların Ebeveyn sınıfın sağladığı metotlarından sadece birini kullanması.
Çözüm
  • Bu gibi yapıların izole edilmesi gerekir.
  • Çok biçimlilik(Polymorphism) kullanılabilir.

Temporary Field: Sadece belirli koşullar sağlandığında değer atanan alanlar. Bu tarz alanlar koşul sağlanmadığında boş olarak duracaktır.

Problem
Gereksiz field alanlarının kod içerisinde yer alması
Çözüm
  • Null object kullanılabilir.

Alternative Classes with different interfaces: Farklı sınıflar içerisinde aynı işi yapan fakat farklı isimleri olan objelerin bulunması.

Problem
Benzer işi yapan objelerin isimlerinin farklı olmasından kaynaklanan iş mantığı ve kod tekrarı.
Çözüm
  • İsimlendirmeler gözden geçirilebilir.
  • Eğer bir işi yapan belirli bir model var ise ve bu bir metot veye metotlardan oluşan blok ise yardımcı bir sınıfın içerisine taşınabilir.
  • Silme, referansları kontrol edilerek benzer işlerin yapan benzer blokların silinmesi gerekir. Silin denilince gaza gelip başka bir noktaya referans veren şeyleri silmeyin. Silme işi önerilir fakat sildiğimiz şeylerin etki analizlerinin iyi yapılmış olması gerekir. Sonra varoşları alır bir telaş…

Change Preventers

Divergent Change: Bu koku genellikle kötü dizayn edilmiş yapılardan ve copy-paste programming alışkanlıklarından kaynaklanır. Temel olarak bir sınıf içerisinde sürekli değişiklikler yapılması ile ilgilidir.

Problem
Bir sınıf içerisinde sıklıkla değişiklik yapılması
Çözüm
  • Kod hiyerarşisi gözden geçirilmelidir.
  • Kod tekrarı azaltılmalıdır.
  • Kurgulanan senaryolar basitleştirilmeye çalışılmalıdır.

Shotgun Surgery: Divergent Change’e benzer fakat tam tersini ifade etmektedir. Yani bir sınıf içerisinde yapılan tek bir değişikliğin bir çok yere etki ediyor olmasıdır.

Problem
Tek bir değişiklik ile bir sürü gol yemek. Yapılan tek bir değişikliğin bir çok yeri etkiliyor olması
Çözüm
  • Aslında çözümü kod yazarken farketmek en güzelidir, yaygınlaşmış bir kod içerisinde bu kokuyu temizlemek gerçekten zor bir iş. Yapının baştan bu kokuya sebep olmayacak şekilde tasarlanması en iyi yöntemdir. Uygulanan “workaround”(günü kurtarma diyelim)  daha da işin içinden çıkılmaz durumlara yol açabilir.
  • Parallel Inheritance: Sınıf hiyerarşisi ile ilgili bir durumdur. Bir sınıfa alt bir sınıf oluşturduğumuzda başka bir sınıfa da aynı sınıfı oluşturma zorunluluğu oluşuyor ise paralel kalıtım kokusu oluşur. Cümle de spagetti oldu, daha anlatırken bile spagetti yaşanıyorsa bu durum gerçekten kötü kokudur. 🙂

Dispensables

Comments: Koda eklenen yorum satırları gerektiğinden fazla bol buldun saç şekilden kullanılır ise kodun okunabilirliğini düşürür.

Problem
Yorum satırlarının fazlalığı ve anlamsızlığı
Çözüm
  • The best comment is a good name for a method or class.

Duplicate Code: Kod tekrarı, çok sık rastlanabilecek ve farkedebilecek bir koku. Copy-paste programming alışkanlıklarından kaynaklanır.

Problem
Kod tekrarı.
Çözüm
  • Aynı işi yapan kod blokları metot haline getirebilir.
  • Aynı işi yapan birden çok metot var ise hangisi daha iyi yapıyorsa onu kullanın.
  • Birden çok sınıf içerisinde yer alan ve aynı işi yapan metotlar, ana sınıfa taşınmalı ve kalıtım özelliği kullanılmalıdır.

Lazy Class: İşe yaramayan sınıfların kaldırılması ile ilgili bir kokudur. Bazen bir sınıf refactor edile edile, kırbacı yiye yiye o kadar küçülür ki artık gerek bile kalmayabilir.

Problem
Gereksiz sınıflar
Çözüm
  • Boş sınıflar, hiç bir iş mantığı barındırmayan, hatta bomboş terkedilmiş sınıflar kod içerisinden temizlenmelidir.

Data Class: Bir sınıf sadece fields(alan) veya bu alanlara get-set işlemi yapan metotlardan oluşuyor ise bu tarz sınıflara Data Class adı verilmektedir. İyi bir pratik olarak bir sınıfın belirli operasyonları da içermesi gerekir.

Problem
Data class kullanımı.
Çözüm
  • Encapsulation işlemi. (Kapsülleme)

Dead Code :  Adı üstünde ölü kod. Kömün gitsin.

Speculative Generality: Geleceğe dönük tahminleme yaparak, henüz kullanılmayan sınıfların oluşturulması.

Problem
Kod içerisinde ileride kullanılacağı düşünülerek oluşturulan yapılar
Çözüm
  • Sil geç.

The Couplers

Feature Envy: Bir metotun veriye sahibinden daha fazla erişmesi ve kullanmasını ifade eder.

Problem
Metot ve verinin gereksiz samimiyeti
Çözüm
  • Kod gözden geçirmelerin dikkatli yapılması, birbirleriyle ilişkili yapıların taşıması esnasında bütünlüğü bozmadan taşıma işleminin yapılması gerekir.

Incomplete library class: Kütüphaneler eninde sonunda değişecektir. Böyle bir ihtiyaç oluştuğunda eğer kütüphane read-only bir davranışta ise değişim neredeyse imkansızdır.

Problem
Kullanılan kütüphanenin ihtiyacı karşılamaması.
Çözüm
  • Extension metotlar kullanılarak, kütüphane genişletilmeye çalışılabilir.

Inappropriate Intimacy: Bir sınıfın diğer bir sınıfın internal alanlarını erişmesi ve kullanmasını ifade eder.

Problem
İzolasyon eksikliği
Çözüm
  • İlişkilerin(relations) gözden geçirilmesi.
  • Hiding delegate yöntemi.

Message Chains: Zincirleme metot çağrılarına işaret eder. Kredi borcunu başka krediyle ödemek gibi düşünelim:)

Problem
Bir request’in ardı ardına başka metotları çağırması
Çözüm
  • Sınıflar arası bağımlılığın azaltılması

Middle Man: Bir sınıf sadece başka sınıfların yapacağı işleri tetikliyorsa ne gerek var mottosu ile ifade edilebilir. Bulky Code denilen kodlarda sık rastlanır. Kafasına sık.

TL;DR

En yaygın kullanılan anti-pattern sanırım duplicate code-copy-paste çok yapılıyorsa bu kötü pratiğin uygulandığı anlaşılabilir. Kod yazarken daha sonra bu kodu okuyacak, kullanacak kişiler olduğu hatta bu kişinin kendimiz bile olabileceği göz önüne alınarak, elimizden geldiğince kötü pratiklerden kaçınmamız gerekir. Tüm bu pratikleri kazanmak belki yazılımcıya zaman kaybettirecek, zor gelecektir. Fakat bir kez öğrenilip davranış haline dönüştürüldüğünde artık ne zor gelecektir ne de zaman kaybına dönüşecektir. Zen programming yöntemleri ile ilgili olarak verilen öğütlerden birisi de bu yönde,  başta kaybettiğiniz zamana bakarak vazgeçerseniz, ilerde bu disiplinin getireceği kazançlardan yoksun kalırsınız. O yüzden bir gayret gösterip bu konulara eğilerek mümkün mertebe uygulamaya çalışmakta fayda var diye düşünüyorum. İnternet’te araştırarak kendi “Code Smells” yapılacaklar listenizi oluşturabilirsiniz. Böylece aşama aşama bu listedeki yapılacakları tamamlayarak daha “temiz” kodlar yazan birine dönüşebiliriz. Denemeye değer ne dersiniz?

Faydalı Linkler:

Coding Horror – Code Smells

Mikrofonlarımız Martin Fowler’da

Reek – Code Smells

2 Replies to “Data Vinci 20 : Code Smells”

  1. Data class kullanımında ne gibi bir sakınca var? Çok pratik ve mantıklı bir kullanımını şu anda iş projelerimde uyguluyorum. Bir class operasyon içermek zorunda değildir.

    1. Merhaba Ahmet Bey, yazıda iyi bir pratik olmadığından bahsettim, tabii ki class operasyon içermek zorunda değildir, hatta hiçbir şey bile içermeyebilir. Burada bahsedilen tüm maddeler, “Code Smells” konsepti içerisinde tanımlanmış kod pratikleridir. Buradaki pratiklerin uygulanmaması kodun çalışabilirliğine engel değildir. Zaten yazıda bundan bahsetmiştim o kısmı atlamışsınız sanırım. Best practices denen yıllar içerisinde birikmiş deneyimlerden yola çıkılarak hazırlanan bu listeler, dikkat edilmesi ve uygulanması “zorunlu” olmayan davranışları işaret eder. Burada bahsedilen tüm pratikler için “önerilen” alternatifler var. İnformIT sitesinde DataClass kullanımı ile ilgili olarak şu şekilde bir yorum yapılmış.
      “Data classes are like children. They are okay as a starting point, but to participate as a grownup object, they need to take some responsibility.”
      Sakıncası büyüyen projelerde DataClass’lardan türeyen sınıflar arttıkça kod gevşek bağlılıktan uzaklaşacaktır. Bunun yerine önerilen refactoring yöntemi ise Encapsulete Collection işlemidir. Encapsulate Collection bu linkte nasıl yapılacağından bahsedilmiş.
      Şunu da belirtmekte fayda görüyorum eğer büyüyen bir yapı yok ise kod içerisinde, bu durumda data class kullanımında sakınca olmayacaktır, internette okuduğum bir yazıda bu code smell’in farkedilmesinin de zor olduğu belirtilmiş. Data Class Code Smells ilgili yazıyı gözden geçirebilrsiniz.

      Yorumunuz ve katkınız için teşekkür ederim. Selamlar.

Leave a Reply

Your email address will not be published. Required fields are marked *