Refactoring Nedir?

     Merhaba, programlama dünyasının vazgeçilmezlerinden biridir, refactoring. Peki ne demektir, ne işe yarar, nasıl yapılır, ne zaman yapılır, başlıca kuralları nelerdir? Bu ve benzer soruların cevaplarını içeren bir makale yazmaya karar verdim. Aslında bu makaleden önce “İyi kod nasıl yazılır?” şeklinde bir makale yazmam gerekirdi; ancak onu bir sonraki makalemde ele alacağım. Öncelikle refactoring konu başlıklarını makalemde kullanmama izin verdiği için Steve McConnell‘e teşekkür ederim. Refactoring konusuyla alakalı detaylı bilgi için Steve McConnell’ın yazmış olduğu Code Complete 2 kitabının 24. bölümünü okuyabilirsiniz.

Refactoring nedir?

     Refactoring birkaç bölüme ayrılmakla beraber bizim inceleyeceğimiz kısım olan kod refactoring: programın veya kod bloğunun çalışmasını değiştirmeyecek şekilde gözden geçirilip ilgili kısımlarda düzenleme yapılması demektir. Bu ilgili kısım bazen sadece bir metot iken bazen de programın büyük bir bölümünü içerebilir. Kısacası refactoring, düzenleme demektir.

Refactoring neden gereklidir?

     Refactoring, bir çok durumda gerekli olabilir. Örnekler vermek gerekirse; eğer büyük bir projede çalışıyorsanız ve projenin bitiş tarihi yakınsa bazen, “kod çalışsın da nasıl çalışırsa çalışsın” denilen zamanlar olabilir. Bu şekilde yazılmış kodların daha sonra mutlaka refactor edilmesi gerekir. Başka bir örnekte ise, program ilk seferde gayet düzgün yazılmıştır; ancak yapılan ufak tefek değişiklikler, bakımlar, bug fix’ler zamanla kodu çok değiştirmiştir. Bu durumda da refactor yapmak gereklidir. Refactoring’in temel amacı aslında kodun okunabilirliğini arttırmak ve karmaşıklığını azaltmaktır. Bunun sebebi de ileride yapılacak ekstra geliştirmelerin veya bakımların daha kolay bir şekilde halledilebilmesidir.

Refactoring ne zaman yapılmalı?

     Zaman olarak refactoring her an yapılabilir; ancak bazen refactor yapmak için belirtiler görmeye başlarsınız. Bu belirtiler sıklaştığı zaman, gerekirse yeni geliştirmelere ara verip refactor yapmak gereklidir. Peki nedir bu belirtiler? Bu belirtilerden bazılarını aşağıda madde madde açıklamaya çalıştım.

  • Çoklanmış kod: Programınızda aynı işi yapan veya %99 oranında aynı işi yapıp çok ufak farklılık olan kodları refactor etmeniz gerekir. Mümkün olduğunca çoklanmış kod yazılmamalıdır.
  • Uzun metotlar: Çok uzun metotların hem okunması hem de bakımı zor olur. Dolayısıyla metotlar mümkün olduğunca kısa yazılmalıdır. Ben çoğunlukla C# dilini kullandığım için ordan örnek vereyim: ortalama bir metot 20 – 25 satırı geçmemelidir. Daha düşük seviyeli bir dil kullanıyorsanız elbette ki satır sayısı biraz daha artabilir. Refactoring yaparken gözünüze uzun görünen ve parçalanabilir metotları mutlaka parçalayın.
  • Çok uzun veya iç içe döngüler: Her programda for, foreach veya while döngüsü mevcuttur. Bu döngülerin iç kısmındaki kod bloğunu mümkün olduğunca kısa tutmak gerekir. Örneğin değişken tanımlarını döngünün dışında yapabilirsiniz. Uzun kod bloklarının haricinde iç içe yazılan döngüler de refactor alanına girmektedir. İç içe 3 – 4 tane döngü yazdığınızda kodun okunabilirliği çok çok azalmış olur ve özellikle debug yaparken takip etmek çok zorlaşır. Bakım maliyetinden bahsetmiyorum bile.
  • Sınırları belli olmayan sınıflar: Oluşturmuş olduğunuz bir sınıf, kendinden beklenen başka işleri de yapıyorsa orda bir sıkıntı var demektir. Bu durumda ilgili alakasız işler için ayrı bir sınıf oluşturmalı veya daha alakalı bir sınıfa taşımalıdır.
  • Aşırı parametre alan metotlar: Metotlara geçilen parametre sayısı yerine göre iyi bir refactoring alanı olabilir. C# için maksimum parametre sayısı 5 – 6’dır. Eğer metodunuz çok fazla parametre alıyorsa muhtemelen birden fazla iş yapıyor demektir. Bu durumda metodu bölmek, dolayısıyla da parametrelerini azaltmak gerekir.
  • Birden çok sınıfta paralel değişiklikler: Bir sınıfta kullandığınız bir şeyi benzer bir şekilde başka bir sınıfta da kullanıyorsanız, herhangi bir değişiklikte iki sınıfı da değiştirmeniz gerekecektir. Hatta aynı şeyi 3 – 4 sınıfta kullanıyorsanız epey bir değişiklik yapmanız gerekecek. Dolayısıyla bu ortak noktaları ayrı bir sınıfa taşımakta fayda var. Basit bir örnek verelim, telefon numarası uzunluğunu 10 olarak belirlediniz ve bunu A sınıfının içerisine constant olacak şekilde tanımladınız. Aynı şekilde B ve C sınıflarına da tanımladınız. Yarın bir gün yurt dışı telefon numaraları için de destek geldiğinde 10 olan sabiti 15 olarak değiştirmeniz gerekecek ve dolayısıyla 3 sınıfta da bu değişikliği yapacaksınız. Eğer bu değişken tek bir yerde olsaydı kolayca değiştirilebilir olacaktı.
  • Ait olduğu sınıftan çok başka bir sınıftan özellik kullanan metotlar: Öyle bir metot düşünün ki, içinde bulunduğu sınıfın elemanlarından çok başka bir sınıfın elemanlarını kullanıyor. Sizce bu normal bir durum mudur? Böyle bir durumda metodu diğer sınıfın içine taşıyarak mevcut sınıf içerisinden çağırabilirsiniz.
  • Basit veri tiplerinin aşırı yüklenmesi: Eğer programınızda basit veri tiplerini çokça kullanıyorsanız dikkatli olmalısınız. Örneğin tutar için integer veri tipi kullanmak yerine Amount şeklinde bir sınıf oluşturabilirsiniz. Böylece yanlış atamaların önüne geçebilirsiniz.
  • İşe yaramayan sınıflar: Kodunuzu refactor ettiğinizde bazen bazı sınıflarda çok az şey kalabilir. Bu durumda kendinize sormalı ve gerekliyse sınıf içerisinde kalan işleri diğer sınıflara dağıtarak ilgili sınıfı komple silebilirsiniz.
  • İsmi anlamsız olan metotlar: Bir metodun ismi size anlamsız geliyorsa veya ismi ile yaptığı iş birbirinden farklıysa metodun ismini değiştirmeniz gerekir. Bu iş bazı ortamlarda zahmetli olabilir; ancak eğer Visual Studio kullanıyorsanız, imleci metot isminin üzerine getirin ve F2 tuşuna basın veya metot ismine sağ tıklayarak Refactor > Rename menüsünü izleyin. Açılan pencereye metodun yeni ismini yazıp onayladıktan sonra, metot ismi ve metoda referans veren tüm yerlerde ilgili değişiklik yapılacaktır. Böylece tek tek metodun nerden çağrıldığını aramanıza gerek kalmayacak.
  • İleride lazım olabilecek kodlar: Bunu birçok programcının yaptığını düşünüyorum. Bir kod bloğu yazıyorsunuz, daha sonra akış değişiyor ve farklı bir kod yazmanız gerekiyor. Bu durumda eskisini silmeyip “ileride lazım olur” dediğiniz an hata yapıyorsunuz demektir. Çoğu durumda o kod bir daha kullanılmayacak ve sadece orda duruyor olacaktır. Benzer şekilde ilgili kodu yoruma alıp bırakmak da pek mantıklı değildir. Birçok büyük proje TFS gibi dosya yönetimini kolaylaştıran uygulamalar kullanır. Dolayısıyla, eğer lazım olur dediğiniz kod ilerde gerçekten lazım olursa, sadece dosyanın geçmişine bakıp ilgili kod bloğunu edinebilirsiniz.
Belirli Refactoring’ler

Aşağıda, çeşitli seviyelerde refactoring tipleri mevcut. Tamamını uygulayacaksınız diye bir şey yok. Aklınızın bir köşesinde bulunması açısından yazıyorum.

Veri seviyesinde refactoring
  • Magic number denilen sayılara isim vererek sabit yapın: Program genelinde her yerde 3.14 yazmaktansa PI isminde bir sabit oluşturun ve değerini 3.14 olarak atayın.
  • Değişken ismini daha anlamlı ve bilgi verici yapın: Benzer şekilde metot ve sınıf isimlerini de anlamlı vermeye çalışın. x, y, sayi1, sayi2 gibi değişken isimleri vermeyin.
  • İfadeleri satır içi kullanın: Eğer bir if koşulu yazıyorsanız ve bu koşulu başka yerde kullanmayacaksanız direkt olarak if içerisine yazın. Yani bool tipinde bir ara değişken tanımlamayın.
  • İfadeyi metot ile değiştirin: Sıklıkla kullanacağınız bir ifadeyi metot haline getirip onu kullanın, böylece kodu çoklamamış olursunuz.
  • Ara değişken tanımlayın: Eğer if koşulunda kullanacağınız ifadeyi başka yerlerde de kullanacaksanız bir ara değişken tanımlamak faydalı olacaktır.
  • Enum kullanın: Kodun sağına soluna constant tanımlamak yerine, benzer işi yapan ifadeleri gruplayıp enum veya sınıf oluşturun.
Komut seviyesinde refactoring
  • Bool ifadeyi parçalayın: Eğer bir if koşulu için uzun bir and/or kombinasyonunuz varsa bunu anlamlı birkaç ifadeye bölüp değişkenlere atayın ve if içerisinde bu değişkenleri kullanın.
  • Karmaşık bool ifadeleri metotlara taşıyın: If koşulu içerisinde yazdığınız ifadeler çok karmaşıksa bu işi bir metot içerisine taşıyın.
  • Hem if hem de else koşullarında yapılması gerekenleri if – else bloğu dışına taşıyın: Aynı kod parçasını hem if hem de else içerisine yazmaktansa bu kod parçasını if-else bloğundan sonraya yazın.
Metot seviyesinde refactoring
  • Metot oluşturun: Bir metot içerisinde ayrı bir metot olabilecek bir kod bloğu varsa bu bloğu ayrı bir metot olarak tanımlayın.
  • Metotları sınıfa çevirin: Eğer çok uzun bir metodunuz varsa bu metodu sınıfa çevirmeyi düşünün.
  • Benzer iki metodu parametre yardımıyla birleştirin: Eğer iki metodunuz birbirine çok benzeyen işler yapıyorsa, kodu çoklamamak adına bu iki metodu tek metotta birleştirin ve parametreye göre ilgili kısmın çalışmasını sağlayın.
  • Parametreye göre farklı iki iş yapan metodu bölün: Eğer bir metot aldığı parametreye göre birbirinden alakasız iki iş yapıyorsa, bu metodu ikiye bölün.
  • Bir objenin alanlarını metoda tek tek geçmek yerine tüm objeyi parmetre olarak geçin: Bir metoda, bir objenin alanlarını tek tek geçmektense tüm objeyi tek parametre olarak geçmek daha sağlıklıdır.
  • Bir objeyi metoda geçmektense ihtiyacınız olan alanları geçin: Eğer metot içerisinde, bir objenin sadece 1 veya 2 alanını kullanacaksanız sadece o alanları metoda geçin.
Sınıf seviyesinde refactoring
  • Değer ve referans nesnelerini iyi yönetin: Kullancağınız duruma bağlı olarak büyük nesneleri değer veya referans yöntemiyle metotlara gönderin.
  • Alt sınıf oluşturun: Eğer bir sınıftan oluşan nesnelerin sadece bazılarının kullandığı metotlar vs. olacaksa bu kısmı ayrı bir alt sınıf oluşturarak halledin.
Güvenli şekilde refactoring nasıl yapılır?
  • Başlamadan önce kodu yedekleyin: Refactor işine başlamadan önce kodunuzu yedeklemeniz sağlıklı olacaktır. Eğer zaten TFS gibi bir sistem kullanıyorsanız herhangi bir yedekleme yapmanıza gerek yok.
  • Unit Test yazın: Refactor işleminin en önemli adımlarından biri olan unit test yazmayı sakın unutmayın. Refactor etmeden önce unit test yazın ve test sonuçlarının refactor işleminden sonra değişmediğini kontrol edin.
  • Küçük değişiklikler yapın: Komple bir sınıfı refactor edip test etmekten sakının. Daha ziyade ufak tefek değişiklikler yaparak kodun çalışma mantığını değiştirmediğinizden emin olun.
  • Yapacağınız değişikliklerin listesini çıkarın: Refactor yapmaya başlamadan önce neleri refactor edeceğinizin listesini çıkarın.
  • Daldan dala atlamayın: Bir sınıf üzerinde refactor yaparken başka bir sınıftaki metoda yönlendiğinizde ve o metodun da refactor edilmesi gerektiğini gördüğünüzde hemen refactor etmeye çalışmayın. Bir yere not alın, önce asıl işinizi bitirin.

     Gördüğünüz gibi refactoring üzerine yazılacak çok şey var aslında. Ben sadece önemli ve basit olanlarını yazmaya çalıştım. Refactoring hakkında daha detaylı bilgi için aşağıdaki kitapları okuyabilirsiniz. Bir sonraki makalede görüşmek ümidiyle…

Steve McConnell – Code Complete 2 (Chapter 24: Refactoring) (Bu yazıyı yazarken bir çok yerde alıntı yaptığım kitap)
Martin Fowler – Refactoring: Improving the Design of Existing Code (Baştan sona refactoring anlatan kitap)

Bu makaleye henüz yorum yapılmamış

Yorum Yapın

*

warning
www.kemalkefeli.com.tr üzerindeki herhangi bir yazının veya kodun izinsiz olarak başka bir yerde kullanılması yasaktır.