Kadir Can kodun şimdiki durumu hakkında ne düşündüğümü sormuştu. Sözümü sakınmadan yazacağım. Amacım hiçbir zaman olmadığı gibi eleştirmek değil. Kod üzerinde böyle düşünmek yararlıdır ve zevklidir. :)
İşlev isimleri: Bazı işlevlerin işleri isimlerine uymuyor
-
saveInFile() dosyaya yazıyor ama aslında "a" modu yüzünden hep dosyanın sonuna ekliyor (bu basit bir hata da olabilir). Ya ismi appendToFile() gibi olmalı ya da "w" kullanılmalı
-
createBody() de aynı şekilde: metnin ana bölümünü oluşturmuyor, onun sonuna ekliyor; programda birden fazla çağrıldığında her iki yerde de metnin oluşturulduğunu sanabiliriz; oysa sonra çağrılan, metnin öncekinden sonrasını oluşturuyor
-
benzer başka işlevler de var
(Biraz ilgisiz olarak, 'functions' da doğru olmamış. createBody()'nin parametre ismi daha doğru olarak 'pieces' olabilirmiş. Ayrıca createHead()'in amacından emin değilim ve o yüzden onun parametre ismi konusunda iyi bir fikrim yok.)
Üye mi olmalı serbest işlev mi: Kabaca iki tür işlev var: HtmlHelper'ın üyelerini değiştirenler ve createTitle() gibi bir string üretip döndürenler. İkinci tür işlevlerin HtmlHelper'ın üye işlevleri olmaları gerekli mi? Bu konu biraz felsefîdir...
Bu konuda uzmanlar da tam olarak anlaşamazlar. Örneğin Bjarne Stroustrup da çoğu nesne yönelimli programcı gibi "herşey bir sınıftır" der. (Aslında yıllardır yakından izlemiyorum; belki de fikri değişmiştir. (?))
İş arkadaşlarımdan birisinin ortalıkta dolaşan işlevlere karşı alerjisi var: o da "herşey sınıfla başlar" fikrindedir.
Ben ise tam tersi görüşteyim: "herşey işlevle başlar." Sanırım bu "herşey algoritmayla başlar" fikrinde olan Alex Stepanov'la uyuşuyor. Ben öncelikle işlevlere iş yaptırırım veya değer ürettiririm.
Sınıf (veya yapı) kavramının ortaya çıkma nedeni ise belirli bir süre yaşaması gereken veya birbirleriyle yakın ilişkisi bulunan verilerdir. Ancak öyle kavramlarla karşılaşıldığında sınıflar oluşur.
Örneğin ben olsam createTitle()'ı hiçbir sınıfa bağlı olmayan serbest bir işlev olarak yazarım. En yararlısı da odur. Çok basit bir işlev olarak etiketi 'title' olan bir HTML elemanı oluşturur ve işi biter.
Bunun yararları:
-
hemen altına unittest bloğu yazılır ve başka işlevlerden bağımsız olarak test edilebilir; test edilebilmesi için nesne gerekmediği test sorunları da azdır; yoksa örneğin bir sınıfın üyesi olsa ve o sınıfın kurucu işlevi bazı özel parametreler gerektirse, işlevin test edilebilmesi için önce öyle bir test ortamı oluşturulması gerekir
-
kolay test edilebilmesine benzer şekilde, kolay da kullanılır: tek başına olduğunda bir HtmlHelper nesnesine gerek olmadan kullanılabilir
-
başka bir grup işlevin parçası olarak görülmediği için kodun anlaşılması daha kolay olur; örneğin HtmlHelper sınıfı da basitleşecektir
Zararı:
- serbest işlev evrensel alana yazıldığında isim kirliliğine neden olabilir; örneğin başka bir modülde de 'foo()' isminde işlev bulunabilir; oysa sınıflar içinde olsalar isimleri çakışmaz. Bu D'de büyük bir sorun değil çünkü zaten modül ismi nedeniyle ayrı isim alanında bulunurlar.
Öte yandan, tasarımı değiştirdiğimizi ve createTitle() yerine addTitle() gibi bir işlev istediğimizi düşünelim. Bu tasarımda addTitle() bir değer üretmesin, bir HTML elemanları dizisine eleman eklesin:
class HtmlHelper
{
string[] elemanlar;
//...
void addTitle(const char[] title)
{
elemanlar ~= "<title>" ~ to!string(title) ~ "</title>\n";
}
// ...
}
İşte şimdi üye işlev olması gerekir; çünkü addTitle() artık 'elemanlar' gibi bir dizi üzerinde işleyen bir grup işlevin bir parçasıdır. Ama dikkat ederseniz bizi sınıf kavramına iten, tasarımımız olmuştur. Yani addTitle()'ı "bir sınıfın üyesi oluversin" diye değil, o sınıfın bir üyesinde ('elemanlar'da) değişiklik yapıyor diye üye işlev yapmak zorunda kalmışızdır.
İşte benim anlayışım o. Ama dediğim gibi, uzmanların bile uyuştukları bir konu değil. O yüzden bu yalnızca "ben olsam öyle yapardım" gibi bir konu. :)
Kod tekrarı: Kadir Can, ben gördüğüm kod tekrarlarını göstermekle yetineceğim; çözümleri senin üretmenin daha yararlı olacağını düşünüyorum.
Öncelikle kod tekrarı konusunu neden tekrar tekrar gündeme getirdiğimi söyleyeyim. (Böyle bir tekrarın zararı yok galiba! :p)
Uzmanların bazı alışkanlıklarının uzman oldukları için olmadığı fikrindeyim. Tersine; bazı alışkanlıklar, uzmanlığı beraberlerinde getirirler. Kod tekrarını araştıran yapıda olmak ve onu azaltmaya çalışmak, kişiyi uzmanlaştırır: soyutlama ve kavramları sınıflandırma yeteneği artar, hata oranı azalır, kod mantıklı olur.
htmlHelper modülünde rastladığım kod tekrarları şunlar:
- Şu yapıyı tekrarlayan çok sayıda işlev var:
string bigger(string text)
{
return "<big>" ~ text ~ "</big>\n";
}
string emphasized(string text)
{
return "<em>" ~ text ~ "</em>\n";
}
Onların tek farkı, kullandıkları eleman etiketi: birisinde 'big', diğerinde 'em'. Onun dışındaki herşey aynı.
Eğer o tekrar bir işleve taşınmış olsa herşey çok daha basit bir hale gelecek. Bir yarar: örneğin herhangi bir nedenle elemanların sonundaki '\n' karakterinin bulunmamasını istesek, bunu tek noktada kaldırmak yetecek. Başka bir yararı: Hatalar azalacak; çünkü o metni oluşturan tek işlevin test edilmiş olması yetecek. (Örneğin createHead() içindeki hâlâ gizli olarak bekleyen hata belki de hiç oluşmamış olacak. ;))
- İşlevler arasındaki o kod tekrarlarının benzerleri bidirectional() ve header() işlevlerinin kendi içlerindeki kodlarda da var.
HTML çıktısı mı üye işlevler mi: Bu sınıfın eninde sonunda bir HTML belgesi (çıktısı) oluşturduğunu biliyoruz. Bütün amacı da zaten o. Peki HtmlHelper sınıfı kullanılırken o belge bir yandan sürekli olarak oluşturulmalı mıdır?
Yoksa HtmlBelgesi türünde bir nesne oluşturulmalı da program kullanıldıkça o nesne mi geliştirilmelidir? Bu, yukarıdaki addTitle() konusuna benziyor. addTitle() gibi bir işlev olsa, HTML belgesini temsil eden nesneye bir 'title' elemanı eklemiş olur. Hepsi odur. Bütün HTML çıktısı en sonunda o nesnenin çıktı() işlevi ile edinilebilir.
Kısaca fark şu:
-
yola devam ettikçe char[] biçiminde HTML çıktısı mı oluşturulsun?
-
HTML sayfasını temsil eden bir nesne mi oluşturulsun, ve sonunda çıktı ondan mı edinilsin?
Bütün bunların felsefî oldukları düşünülebilir; eğer program çalışıyorsa kimsenin fazla bir şey söylemeye hakkı yoktur. Ama kodun sağlığını önemsiyoruz. Her aşamada benzer düşünceler içerisinde ve dikkatle kodlamak gerekiyor. Yukarıda da dediğim gibi, kesin doğru veya yanlış yok. Bunlar üzerinde düşünmek güzel. :)
Ali
--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]