Etiket Arşivi refactoring türkçe

Refactoring 5: Açıklayıcı Değişken Kullanımı (Introduce Explaining Variable)

Merhabalar.

Bu yazıda Açıklayıcı Değişken Kullanımı – Introduce Explaining Variable yöntemini anlatmaya çalışacağım.
(Çeviri için arkadaşım Mesut Fatih Elevli’ye sevgiler..)

Nedir?

if ((platform.toUpperCase().indexOf("MAC") > -1) &&
(browser.toUpperCase().indexOf("IE") > -1) &&
wasInitialized() && resize > 0 ) {
// do something
}

extractmethod

final boolean isMacOs = platform.toUpperCase().indexOf("MAC") > -1;
final boolean isIEBrowser = browser.toUpperCase().indexOf("IE") > -1;
final boolean wasResized = resize > 0;

if (isMacOs && isIEBrowser && wasInitialized() && wasResized) {
// do something
}

Neden?

Kimi zaman kod içerisinde -belki de- zamanla koda yeni caseler eklenmesiyle okunması zor kompleks ifadeler oluşur.

Bu ifadeler okunurluğunu ve yönetilebilirliğini artırmak için parçalanıp, değişkenlere atanabilir.

Elbette oluşturulan bu değişkenlerin güzel isimlendirilmesi(yukarıdaki örnekte isMacOs, wasResized kullanımları gibi) ziyadesiyle önem arz eder.

Bazı durumlarda bu yöntem yerine Extract Method yöntemini kullanmak daha efektif olabilir. Mesela bu ifadeler yerel değişkenler içerip, tamamı tek bir yerde kullanılıyorsa veya buradaki değişkenlerin tamamı global değişkense Extract Method kullanımı tavsiye edilebilir.

Nasıl?

  • Öncelikle anlaşılır şekilde isimlendirilmiş bir değişken oluşturulur ve sözkonusu kompleks ifade bu değişkene atanır.
  • Daha sonra ifadelerin yerine değişkenler yazılır.
  • Derleme ve test.

Örnek

Yöntemimizi şöyle basit bir fiyat hesaplamasıyla inceleyebiliriz. 500 adet üzerindeki siparişlere %5 indirim yapılan bir ürün için toplam fiyatı hesaplıyoruz:

double fiyat() {
    // fiyat = taban fiyat - indirim + nakliye
     return _miktar * _adetFiyati -
        Math.max(0, _miktar - 500) * _adetFiyati * 0.05 +
        Math.min(_miktar * _adetFiyati * 0.1, 100.0);
}

İlk etapta taban fiyat hesaplamasını ayırıyoruz.

double fiyat() {
     // fiyat = taban fiyat - indirim + nakliye
     final double tabanFiyat = _miktar * _adetFiyati;

     return tabanFiyat -
         Math.max(0, _miktar - 500) * _adetFiyati * 0.05 +
         Math.min(_miktar * _adetFiyati * 0.1, 100.0);
}

Nakliye masrafının hesaplamasında da taban fiyat üzerinden hesaplama yapılıyor. Dolayısıyla yeni değişkenimizi oraya da koyabiliriz.

double fiyat() {
    // fiyat = taban fiyat - indirim + nakliye
    final double tabanFiyat = _miktar * _adetFiyati;

    return tabanFiyat -
        Math.max(0, _miktar - 500) * _adetFiyati * 0.05 +
        Math.min(tabanFiyat * 0.1, 100.0);
}

Şimdi toplam indirimi de değişkene alalım:

double fiyat() {
    // fiyat = taban fiyat - indirim + nakliye
    final double tabanFiyat = _miktar * _adetFiyati;
    final double miktaraGoreIndirim = Math.max(0, _miktar - 500) * _adetFiyati * 0.05;

    return tabanFiyat - miktaraGoreIndirim + Math.min(tabanFiyat * 0.1, 100.0);
}

Nakliyeyi de ayırdık mı gayet okunur ve temiz bir kodumuz oluşuyor.

double fiyat() {
    final double tabanFiyat = _miktar * _adetFiyati;
    final double miktaraGoreIndirim = Math.max(0, _miktar - 500) * _adetFiyati * 0.05;
    final double nakliye = Math.min(tabanFiyat * 0.1, 100.0);

    return tabanFiyat - miktaraGoreIndirim + nakliye;
}

Bu örnekte tüm değişkenler global değişken olduğu için Extract Method yöntemi de kullanılabilir. Şimdi üstadın tavsiyesi üzerine bu yöntemi uygulayalım.

Örneği başa sarıyoruz.

double fiyat() {
    // fiyat = taban fiyat - indirim + nakliye
     return _miktar * _adetFiyati -
        Math.max(0, _miktar - 500) * _adetFiyati * 0.05 +
        Math.min(_miktar * _adetFiyati * 0.1, 100.0);
}

Taban fiyatı bu defa değişkene değil metoda çıkartıyoruz:

double fiyat() {
    // fiyat = taban fiyat - indirim + nakliye
    return tabanFiyat() -
        Math.max(0, _miktar - 500) * _adetFiyat * 0.05 +
        Math.min(tabanFiyat() * 0.1, 100.0);
}
private double tabanFiyat() {
    return _miktar * _adetFiyat;
}

Daha sonra tüm ifadeleri metodlara çıkarıyoruz:

double fiyat() {
    return tabanFiyat() - miktaraGoreIndirim () + nakliye();
}
 
private double miktaraGoreIndirim () {
    return Math.max(0, _miktar - 500) * _adetFiyat * 0.05;
}
 
private double nakliye() {
    return Math.min(tabanFiyat() * 0.1, 100.0);
}
 
private double tabanFiyat() {
    return _miktar * _adetFiyat;
}

Extract Method kullanımı, düzenlediğimiz ifadenin programın farklı yerlerinde de kullanımına imkan sağlayacağı için daha esnek bir yapı oluşturabilir. Bu yüzden ekstradan çaba gerektirmeyen durumlarda daha faydalı bir yöntem olabilir. Ama bolca lokal değişkenlerin olduğu ifadeler için Introduce Explaining Variable yöntemi kullanılabilir.

Kaynak: https://sourcemaking.com/refactoring/introduce-explaining-variable

Kendinize çook iyi davranın.

Bu sayfa 808 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr

Refactoring 4: Geçici Değişkenlerin Sorguya Dönüştürülmesi (Replace Temp with Query)

Merhabalar.

Bu yazıda “replace temp with query”(geçici değişkenlerin sorguya dönüştürülmesi) yönteminden bahsetmeye çalışacağım.

Nedir?

double basePrice = _quantity * _itemPrice;

if (basePrice > 1000)

     return basePrice * 0.95;

else

     return basePrice * 0.98;

extractmethod

if (basePrice() > 1000)

     return basePrice() * 0.95;

else

     return basePrice() * 0.98;

...
double basePrice() {

     return _quantity * _itemPrice; }

Neden?

  • Global olmayan değişkenler geçici ve lokaldir. Bu zaman zaman kullanımı zorlaştırabilir. Örneğin tanımlandığı blok dışında kullanılamazlar.
  • Bilhassa uzun metodlarda değişkenleri sorgusal metodlara çevirmek faydalı bir yöntemdir.
  • Extract Method yöntemi öncesi, önemli bir adımdır.
  • Bu yöntemi değişkene tek bir değer(global değişkenler, hardcoded değerler vb.) tahsis edildiği durumlarda kullanmak gerekir. Değeri devamlı güncellenen bir değişkene uygulamak mümkün olsa bile uğraştırıcıdır.

Nasıl?

  • Bir kez atama yapılan değişkenlere bakılır. Java’da çalışıyorsanız bir kez atandığını garanti etmek için değişkenleri final yapabilirsiniz.
  • Değişkene atanan kısım alınır ve private bir metod tanımlanıp içine atılır.
  • Değişkenin kullanıldığı yerlerde yeni metod çağırılır ve değişken remove edilir.
  • Derleme ve test.

Örnek

Bir ürünün paket/koli fiyatını getiren bir metodumuz olsun. Paket fiyatına göre de indirimli fiyatı hesaplıyor.

Buradaki _miktar ve _adetFiyati global değişkenler.

double ucretGetir()
 {
      int paketFiyat = _miktar * _adetFiyati;
      double indirimOrani;

      if (paketFiyat > 1000) indirimOrani = 0.95;
      else indirimOrani = 0.98;

      return paketFiyat * indirimOrani;
 }

İlk etapta değişkenlerimizi final yaparak bir kez atama yapıldığını test edelim.

double ucretGetir()
 {
      final int paketFiyat = _miktar * _adetFiyati;
      final double indirimOrani;

      if (paketFiyat > 1000) indirimOrani = 0.95;
      else indirimOrani = 0.98;

      return paketFiyat * indirimOrani;
 }

paketFiyat hesaplamasını yeni bir metoda çıkarıyorum:

private int paketFiyat()
{
     return _miktar * _adetFiyati;
}

Değişkeni artık bu metoda eşitleyebilirim.

double ucretGetir()
 {
      final int paketFiyat = paketFiyat();
      final double indirimOrani;

      if (paketFiyat > 1000) indirimOrani = 0.95;
      else indirimOrani = 0.98;

      return paketFiyat * indirimOrani;
 }

Derleyip, test ediyoruz. Sonra asıl konumuz olan yöntemi uygulamaya başlıyoruz. Değişkeni kullandığım yerde direkt metodu çağırıyorum.

double ucretGetir()
 {
      final int paketFiyat = paketFiyat();
      final double indirimOrani;

      if (paketFiyat() > 1000) indirimOrani = 0.95;
      else indirimOrani = 0.98;

      return paketFiyat * indirimOrani;
 }

Derleyip, test ediyoruz. Daha sonra yerel değişkenimizi tamamen imha ediyoruz:

double ucretGetir()
 {
      final double indirimOrani;

      if (paketFiyat() > 1000) indirimOrani = 0.95;
      else indirimOrani = 0.98;

      return paketFiyat() * indirimOrani;
 }

Derleyip, test ediyoruz. Koda dikkatli baktığımızda indirimOrani için de aynı işlemleri uygulayabiliriz gibi gözüküyor. Bu defa biraz kestirmeden gidelim:

double ucretGetir()
 {
      final double indirimOrani = indirimOrani();

      return paketFiyat * indirimOrani;
 }

private int indirimOrani()
{
      if (paketFiyat() > 1000) return 0.95;
      else return 0.98;
}

..ve son yerel değişkenimizi de ortadan kaldırıyoruz:

double ucretGetir()
{
      return paketFiyat() * indirimOrani();
}

private int indirimOrani()
{
     if (paketFiyat() > 1000) return 0.95;
     else return 0.98;
}

private int paketFiyat()
{
     return paketFiyat * indirimOrani;
}

 

Kendinize çook iyi davranın.

Kaynak: http://sourcemaking.com/refactoring/replace-temp-with-query

 Bu sayfa 1093 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr

Refactoring 3: Inline Method & Inline Temp

Merhabalar.

Refactoring yaparken, amaçlardan biri koddaki karmaşıklığı gidermek ve okunabilirliği sağlamaktır. Mesela bir önceki yöntemde tekrar eden veya okunurluğu zorlaştıran scriptleri ayrı metod haline getirmiştik.Ama metoda çevirme işinin, hatta değişken oluşturma işinin de abartılmamasında fayda var. Gereksiz yere bunların kullanımı da yine okunurluğu zorlaştırabilir. Buradaki 2 yöntem bu sıkıntıları gidermeye matuftur.

a – Inline Method

Nedir?

int getRating()
 {
      return (moreThanFiveLateDeliveries()) ? 2 : 1;
 }

boolean moreThanFiveLateDeliveries()
 {
      return _numberOfLateDeliveries > 5;
 }

extractmethod

int getRating()
 {
      return (_numberOfLateDeliveries > 5) ? 2 : 1;
 }

 

Neden?

  • Bir önceki yöntemde, kodun anlaşılmasının zor olduğu parçalar yerine; anlaşılır isimde, kısa metodlar yazılması öneriliyordu.
  • Ama herşeyin olduğu gibi metodun da gereksizi ve fazlası zarardır. Bu yüzden değişken kullanılabilecekken ve işi karmaşıklaştırmayacaksa, gereksiz yere metod kullanmak tavsiye edilmez.

Nasıl?

  • Metodun polimorfik olup olmadığı kontrol edilir.
  • Metodun çağrıldığı bütün yerler bulunur.
  • Metodun gövde kısmıyla, metodun çağırıldığı script değiştirilir.
  • Derleme ve test.
  • Metod remove edilir.

 

b – Inline Temp

Nedir?


double basePrice = anOrder.basePrice();
 return (basePrice > 1000);

extractmethod

return (anOrder.basePrice() > 1000);

 

Neden?

  • Inline Method yöntemiyle benzer nedenden ötürü bu yöntem kullanılır.
  • Üstteki örnekteki gibi değişkenin eşitlendiği kısım sabitse(hard coded bir değer, global bir değişken veya bir değer dönen bir metod vb.) ve değişken tek bir yerde kullanılacaksa değişkene gerek olmadığını söyleyebiliriz.

Nasıl?

  • “Değişkene atanan kısım sabit mi” ve “değişken tek yerde mi kullanılıyor” kontrol edilir.
  • Değişkenin kullanıldığı yere değişkenin eşitlendiği değer yazılır
  • Derleme ve test.
  • Değişkenin tanımlanma ve eşitlenme kısımları silinir.

Kendinize çook iyi davranın.

Kaynak:

http://sourcemaking.com/refactoring/inline-method

http://sourcemaking.com/refactoring/inline-temp

 Bu sayfa 1061 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr

Refactoring 2: Yeni Metod Oluşturma(Extract Method) Yöntemi

Merhabalar.
Refactoring yöntemlerini incelemeye başlıyoruz. İlk olarak Extract Method yöntemi:

Nedir?

void printOwing(double amount) {
    printBanner();

    //print details
    System.out.println ("name:" + _name);
    System.out.println ("amount" + amount);
}

graphics/arrow.gif

void printOwing(double amount)
{
     printBanner();
     printDetails(amount);
}
void printDetails(double amount)
{
     System.out.println ("name:" + _name);
     System.out.println ("amount" + amount);
}

 

Neden?

* Mümkün olduğunca uzun ve commente(yorum satırı) ihtiyaç duyan kod parçalarından kaçınmak lazım.
* Bunun yerine kısa ve güzel isimlendirilmiş metodlar kullanılmalı. Çünkü:
– Küçük(core sayılabilecek) metodlar ihtiyaç duyulan başka yerlerde de kullanılabilir.
– Küçük metodları(kodu) okumak commenti okumaktan daha kolaydır.

Nasıl?

* Yeni bir metod oluşturulup(create), ne yaptığını(nasıl yaptığını değil) anlatan güzel bir isim verilir.
– Ayıklanacak kod kısaysa ve anlamlı bir isim konulamayacaksa ayıklanmaması daha iyidir.
* İlgili kod yeni metoda kopyalanır.
* Kodun içinde değişken olup olmadığına bakılır.
– Daha önceden tanımlanmış, alınacak kodun sonrasında da kullanılan değişkenler parametre olarak verilebilir.
– Sadece seçilen kısımda kullanılan değişkenler, oluşturulan metodun içinde tanımlanır.
– Seçilen kodda değişkenin değeri değişiyorsa, metodda return edilebilir.
* Kullanılan tüm değişkenler tarandıktan sonra, kod silinip, söz konusu bçlümde yeni metod çağırılır.
* Derleme ve test.

Örnek

Aşağıdaki java konsol uygulaması üzerinden mevzuyu örneklemeye çalışayım:

“Refactoring” adında bir adet sınıf oluşturuyorum. “Main” metodunda, bir kitapçıdaki kitapların isim ve fiyatlarını konsolda listeliyor:


public class Refactoring {

 public static void main(String[] args) {

 ArrayList kitapListe=new ArrayList();

 double[] satisFiyat=new double[3];
 double kar = 0.25;

 // başlığı yaz
 System.out.println ("**************************");
 System.out.println ("******** Kitaplar ********");
 System.out.println ("**************************");

 // kitaplar ekleniyor
 kitapListe.add(new Kitaplar( "Dublörün Dilemması",10.0));
 kitapListe.add(new Kitaplar( "Aşkın Gözyaşları",5.0));
 kitapListe.add(new Kitaplar( "Kime Emanet",6.0));

 // kitapların fiyatları hesaplanıyor
 for(int i=0;i<3;i++)
 {
 satisFiyat[i]=kitapListe.get(i).gelisFiyat*(1+kar);
 }

 // Kitap listesi yazdırılıyor
 for(int i=0;i<3;i++)
 {
 System.out.println(kitapListe.get(i).isim+" "+satisFiyat[i]+" TL");
 }
 }
}

Bir tane de “Kitaplar” sınıfı oluşturuyorum. Kitabın ismi ve kitapçıya geliş fiyatını barındırıyor.

public class Kitaplar
{
 String isim;
 Double gelisFiyat=0.0;

 public Kitaplar(String isim, double gelisFiyat)
 {
 this.isim=isim;
 this.gelisFiyat=gelisFiyat;
 }

 public String getIsim() {
 return isim;
 }

public void setIsim(String isim) {
 this.isim = isim;
 }

public Double getGelisFiyat() {
 return gelisFiyat;
 }

public void setGelisFiyat(Double gelisFiyat) {
 this.gelisFiyat = gelisFiyat;
 }

}

 

Şimdi adım adım Extract Method yöntemimizi uygulayalım:
1-) Yukarıda belirtildiği gibi, yorum satırına(comment) ihtiyaç bırakmayacak şekilde başlık kısmını güzel isimlendirilmiş bir metoda çıkarıyorum(main metodum static olduğu için diğer metodları da static oluşturuyorum):

static void basligiYazdir()
	{
	    System.out.println ("**************************");
        System.out.println ("******** Kitaplar ********");
        System.out.println ("**************************");
	}

2-) Sonra kitapları ArrayList‘e eklemek için bir metod oluşturuyorum.. ama ArrayList kodun devamında da kullanılacağı için “return” etmem gerekiyor:

static ArrayList kitaplariListeyeEkle()
	{
		ArrayList kitapListe=new ArrayList();

		kitapListe.add(new Kitaplar( "Dublörün Dilemması",10.0));
        kitapListe.add(new Kitaplar( "Aşkın Gözyaşları",5.0));
        kitapListe.add(new Kitaplar( "Kime Emanet",6.0));

        return kitapListe;
	}

Kodları çıkardığım yerlerden bu metodları çağırınca main metodu aşağıdaki gibi oldu:

public static void main(String[] args) {

 ArrayList kitapListe=new ArrayList();

 double[] satisFiyat=new double[3];
 double kar = 0.25;

 basligiYazdir();

 kitapListe=kitaplariListeyeEkle();

 // kitapların fiyatları hesaplanıyor
 for(int i=0;i<3;i++)
 {
 satisFiyat[i]=kitapListe.get(i).gelisFiyat*(1+kar);
 }

 // Kitap listesi yazdırılıyor
 for(int i=0;i<3;i++)
 {
 System.out.println(kitapListe.get(i).isim+" "+satisFiyat[i]+" TL");
 }
 }

3-) Fiyat hesaplamaları için de bir metod oluşturabilirim. Main kısmı olduğu için ne kadar “extract method” yapsam kardır.
Fiyat hesaplama kısmında kitapListe ArrayList’i kullanılıyor ve herhangi bir değişikliğe uğramıyor. O zaman bunu parametre olarak gönderebilirim.
satisFiyat dizisinin ise hem burada içeriği oluşturuluyor, hem de kodun devamında kullanılıyor. O halde “return” edebilirim bu değeri.
Son olarak ise kar değişkenine baktığımda sadece bu kısımda kullanıldığını görüyorum. O halde bu değişkeni yeni metodun içinde de tanımlasam olur. Yani:

static double[] fiyatlariHesapla(ArrayList kitapListe)
	{
		double[] satisFiyat=new double[3];
		double kar = 0.25;

		for(int i=0;i<3;i++)
        {
        	satisFiyat[i]=kitapListe.get(i).gelisFiyat*(1+kar);
        }

		return satisFiyat;
	}

4-) Son olarak listeyi konsola yazdırma kısmını da metoda çıkaralım. Bu kısımda kitapListe ArrayList‘imiz ve satisFiyat dizimiz kullanılıyor ve sadece değerleri görüntüleniyor. O zaman bunları parametre olarak göndermem yeterli:

static void kitapListesiniYazdir(ArrayList kitapListe, double[] satisFiyat)
	{
		for(int i=0;i<3;i++)
        {
        	System.out.println(kitapListe.get(i).isim+"   "+satisFiyat[i]+" TL");
        }
	}

..ve işte sınıfımızın son hali:

public class Refactoring {

	public static void main(String[] args) {

        ArrayList kitapListe=new ArrayList();
        double[] satisFiyat=new double[3];

        basligiYazdir();

        kitapListe=kitaplariListeyeEkle();

        satisFiyat=fiyatlariHesapla(kitapListe);

        kitapListesiniYazdir(kitapListe, satisFiyat);

    }

	static void basligiYazdir()
	{
		System.out.println ("**************************");
        System.out.println ("******** Kitaplar ********");
        System.out.println ("**************************");
	}

	static ArrayList kitaplariListeyeEkle()
	{
		ArrayList kitapListe=new ArrayList();

		kitapListe.add(new Kitaplar( "Dublörün Dilemması",10.0));
        kitapListe.add(new Kitaplar( "Aşkın Gözyaşları",5.0));
        kitapListe.add(new Kitaplar( "Kime Emanet",6.0));

        return kitapListe;
	}

	static double[] fiyatlariHesapla(ArrayList kitapListe)
	{
		double[] satisFiyat=new double[3];
		double kar = 0.25;

		for(int i=0;i<3;i++)
        {
        	satisFiyat[i]=kitapListe.get(i).gelisFiyat*(1+kar);
        }

		return satisFiyat;
	}

	static void kitapListesiniYazdir(ArrayList kitapListe, double[] satisFiyat)
	{
		for(int i=0;i<3;i++)
        {
        	System.out.println(kitapListe.get(i).isim+"   "+satisFiyat[i]+" TL");
        }
	}
}

Kendinize çook iyi davranın.

Kaynak: http://sourcemaking.com/refactoring/extract-method

 

Bu sayfa 1375 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr

Refactoring 1: Refactoring Nedir?

Merhabalar.
Refactoring, Türkçe’ye genelde “kod düzenleme” diye çeviriliyor.

Yazılan bir kodun zamanla değiştirilerek optimize edilmesi, kodu daha anlaşılır hale getirme, kodu adam etme vs. pek çok tanım yapılabilir.

Yazılan kodların üzerinden zaman geçtikten sonra(mesela 6-7 ay), hangi kodun ne ifade ettiği unutulabilir. Dolayısıyla anlamak için kodu okumak gerekir. Kod ne kadar karışıksa, yapılan işi anlamak da o kadar zorlaşır-velev ki kendi yaptığımız iş olsun- ve dolayısıyla o kadar zaman alır. Dahası bir kurumda çalışıyorsak, başkasının kodlarını okumamız da gerekecektir ve kodlar karışıksa bu durumun içinden çıkmak iyice zorlaşacaktır.

Peki yapılması gereken nedir?

Kodlamayı yaptıktan sonra veya başkasının yaptığı kötü bir kodlamayı gördükten sonra (kötü kodlamayı %95 başkaları yapar zaten:)), refactoring yapmak. Yani kodu elden geçirip kullanım yanlışlıklarını ve karışıklıkları gidermek. Mesela 3 satırlık bir kod 2-3 yerde tekrar ediyorsa o scripti, metod haline getirmek.  Veya 3 satırlık bir kodun ne yaptığını anlamak için comment(yorum satırı) yazmak gerekiyorsa, scripti metod haline getirip, ne yaptığını anlatan güzel bir isim vermek vs.

Tabi yaptığımızın refactoring olduğunu bilmeden, refactoring yaptığımız olmuştur. Refactoring yöntemlerini incelerken, siz de “aa ben refactoring yapıyormuşum” diyebilirsiniz.

Ayrıca şurada hangi durumlarda ve ne tür yöntemlerle refactoring yapılacağı güzel bir tabloyla gösterilmiş.

Ben peyderpey sourcemaking sitesindeki refactoring yöntemlerini, oradan çıkardığım notlarla(bi nevi özetler) yazmaya çalışacağım. Hem benim daha iyi kavramam hem de varsa burayı okuyan birileri, onların yararlanması açısından faydalı olacağını düşünüyorum.

Kendinize çook iyi davranın.

 Bu sayfa 1918 kez görüntülendi

It's only fair to share...Share on LinkedInShare on FacebookShare on Google+Tweet about this on TwitterShare on Tumblr