Kodlama Yaparken Dikkat Edilmesi Gereken Bazı Performans ve Optimizasyon Teknikleri

Bunlar da hoşunuza gidebilir...

15 Cevaplar

  1. CA dedi ki:

    Bahsi geçen önerilerin hiç biri performansı etkileyecek bir durum oluşturmaz. En fazla performansa yakınlığı olan konu, switch ve boş default durumudur ki bu bile göz ardı edilebilir. Konu yönetilebilirlik olsaydı tamamdı ama performans adına sonuna kadar anlamsız bir başlık olmuş. Bence kodlamaya bakış açınızı değiştirip alıntı yazıları sorgulamadan kabullenmekten kaçının.

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhabalar, yorumunuz ve önerileriniz için teşekkür ederim. Buradaki maddelere kapalı bir boru içerisinden bakmamalıyız. Örneğin 1. madde olan “Bir method sadece bir sorumluluğu yerine getirmelidir” maddesinde, mail gönderim işlemi farklı bir method’a ayrıldığından dolayı buradaki işlem asenkron olarak gerçekleştirilebilir. Buda performans etkenini etkilemektedir. Switch-Case durumları da göz ardı edilmemelidir eğer clean bir code geliştiriyorsak. Bir diğeri 12. maddeye baktığımızda ise sayın Çağatay Doğan bey, string birleştirme ile StringBuilder arasındaki ciddi performans farklarının da olduğunu sizin iyi bilmeniz gerekir. 14. maddeye hemen geldiğimizde ise “External kaynaklara erişecek bir class varsa IDisposable pattern’ini implemente edilmelidir” uygun bir bellek yönetimi gerçekleştirmediğimiz de ilgili application farm’ı git gide yavaşlayıp, allocate olacaktır. Bunu takiben 16. maddeye baktığımızda ise, “Unmanaged kaynaklar için using statement’ı kullanılmalıdır” yine bir bellek yönetimi pratiği görüyoruz. Diğer kalanlar ise optimize bir şekilde temiz kod yazabilmek için olması gereken önerilerdir. Ben burada performansa ve optimizasyona, yönetilebilirliğe vb. alt maddelere yönelik bir kod yazarken nelere dikkat edebiliriz gibi coding standartlarını aktarmaya çalıştım. Bunun haricinde konumuz ORM kullanımı/seçimi, Distributed cache/session kullanımları, Javascript Framework seçimleri gibi architectural konular değil. Yinede yorumunuz için teşekkür ederim.

  2. Ekrem ÖZER dedi ki:

    Hocam sabah sabah ufkumuzu açtın 🙂 Eline sağlık çok faydalı bir makale.

  3. CA dedi ki:

    Merhaba Gökhan Bey,

    Yazınıza eleştirim, uzun yıllardır performans konusuna oldukça takıntılı bir insan olarak yapıcı bir eleştiri niteliğindir, kişisel algılamamanızı rica ederim. Mikro performans oldukça hassas bir konu. Yıllardır compiler üzerindeki geliştirmelerin etkisi ile her .Net versiyonunda bir öncekinde d, bir sonrakindeğişmekte, geçersiz kılınmakta veya ters etki yaratabilmekte. Adım adım takip etmediğimiz durumda, konu “doğru bildiğimiz yanlışlar” kategorisine girivermekte. Örnek verecek olursam; string.concat olayı yanlış bilmiyorsam .Net 2.0’dan bu tarafa bahsettiğiniz gibi çalışmıyor. Compiler’ı geliştiren arkadaşlar developer alışkanlıklarını da göz önünde bulundurarak bu durumları konu özelinde ele alıp performans arttıracak önlemleri alıyorlar. Aşağıdaki kod örneği bahsettiğiniz konuya çok derinlemesine olmasa da detaylı bakan bir örnek.
    using System;

    namespace ConsoleApplication51
    {
    class Program
    {
    public static string Foo1()
    {
    return “a” + “1” + “b” + “2” + “c” + “3”;
    }

    public static string Foo2()
    {
    return “a” + 1.ToString() + “b” + 2.ToString() + “c” + 3.ToString();
    }

    public static string Foo3()
    {
    var s = “a”;
    s += “1”;
    s += “b”;
    s += “2”;
    s += “c”;
    s += “3”;

    return s;
    }

    public static string Foo4()
    {
    var s = “a”;
    s += 1.ToString();
    s += “b”;
    s += 2.ToString();
    s += “c”;
    s += 3.ToString();

    return s;
    }

    public static string Foo5()
    {
    return String.Concat(“a”, “1”, “b”, “2”, “c”, “3”);
    }

    public static string Foo6()
    {
    return String.Concat(“a”, 1.ToString(), “b”, 2.ToString(), “c”, 3.ToString());
    }

    public static string Foo7()
    {
    var s = “a”;
    s = String.Concat(“1”, s);
    s = String.Concat(“b”, s);
    s = String.Concat(“2”, s);
    s = String.Concat(“c”, s);
    s = String.Concat(“3”, s);

    return s;
    }

    public static string Foo8()
    {
    var s = “a”;
    s = String.Concat(1.ToString(), s);
    s = String.Concat(“b”, s);
    s = String.Concat(2.ToString(), s);
    s = String.Concat(“c”, s);
    s = String.Concat(3.ToString(), s);

    return s;
    }

    static void Main(string[] args)
    {
    Foo1();
    Foo2();
    Foo3();
    Foo4();
    Foo5();
    Foo6();
    Foo7();
    Foo8();

    Console.ReadKey();
    }
    }
    }

    Burada 4 örnek göstermek istedim. Bu örneklerin IL kodlarına bakarsanız aşağıdaki kod örgülerini görürsünüz. Bu açıdan bakarsanız en performanslı kod bloğunun Foo1 metodu tarafından sağlandığını görürsünüz çünkü IL optimizasyonu ile “a” + “1” + “b” + “2” + “c” + “3” kodunu optimize edip “a1b2c3” haline dönüştürmüştür. Diğer Foo2 metoduna da dikkat ederseniz zaten compiler sizin yerinize buradaki işlemi string.concat işlemine dönüştürür. Compiler’ın optimize edemediği Foo3 ve Foo4 metodlarındaki durumdur. Bu durum tam da StringBuilder’a ihtiyacımızın olduğu yerdir. Foo1 metodunun kötü tarafı ise okunaklı olmamasıdır. Email adresim sizde mevcut, arzu ederseniz makalede geçen diğer öneriler hakkındaki görüşlerimi de email üzerinden iletişime geçerseniz ayrıca paylaşabilirim. Yorumumda yazım hatalarım varsa da lütfen kusuruma bakmayın.

    .namespace ConsoleApplication51
    {
    .class private auto ansi beforefieldinit ConsoleApplication51.Program
    extends [mscorlib]System.Object
    {
    // Methods
    .method public hidebysig static
    string Foo1 () cil managed
    {
    // Method begins at RVA 0x2050
    // Code size 11 (0xb)
    .maxstack 1
    .locals init (
    [0] string CS$1$0000
    )

    IL_0000: nop
    IL_0001: ldstr “a1b2c3”
    IL_0006: stloc.0
    IL_0007: br.s IL_0009

    IL_0009: ldloc.0
    IL_000a: ret
    } // end of method Program::Foo1

    .method public hidebysig static
    string Foo2 () cil managed
    {
    // Method begins at RVA 0x2068
    // Code size 79 (0x4f)
    .maxstack 3
    .locals init (
    [0] string CS$1$0000,
    [1] string[] CS$0$0001,
    [2] int32 CS$0$0002
    )

    IL_0000: nop
    IL_0001: ldc.i4.6
    IL_0002: newarr [mscorlib]System.String
    IL_0007: stloc.1
    IL_0008: ldloc.1
    IL_0009: ldc.i4.0
    IL_000a: ldstr “a”
    IL_000f: stelem.ref
    IL_0010: ldloc.1
    IL_0011: ldc.i4.1
    IL_0012: ldc.i4.1
    IL_0013: stloc.2
    IL_0014: ldloca.s CS$0$0002
    IL_0016: call instance string [mscorlib]System.Int32::ToString()
    IL_001b: stelem.ref
    IL_001c: ldloc.1
    IL_001d: ldc.i4.2
    IL_001e: ldstr “b”
    IL_0023: stelem.ref
    IL_0024: ldloc.1
    IL_0025: ldc.i4.3
    IL_0026: ldc.i4.2
    IL_0027: stloc.2
    IL_0028: ldloca.s CS$0$0002
    IL_002a: call instance string [mscorlib]System.Int32::ToString()
    IL_002f: stelem.ref
    IL_0030: ldloc.1
    IL_0031: ldc.i4.4
    IL_0032: ldstr “c”
    IL_0037: stelem.ref
    IL_0038: ldloc.1
    IL_0039: ldc.i4.5
    IL_003a: ldc.i4.3
    IL_003b: stloc.2
    IL_003c: ldloca.s CS$0$0002
    IL_003e: call instance string [mscorlib]System.Int32::ToString()
    IL_0043: stelem.ref
    IL_0044: ldloc.1
    IL_0045: call string [mscorlib]System.String::Concat(string[])
    IL_004a: stloc.0
    IL_004b: br.s IL_004d

    IL_004d: ldloc.0
    IL_004e: ret
    } // end of method Program::Foo2

    .method public hidebysig static
    string Foo3 () cil managed
    {
    // Method begins at RVA 0x20c4
    // Code size 73 (0x49)
    .maxstack 2
    .locals init (
    [0] string s,
    [1] string CS$1$0000
    )

    IL_0000: nop
    IL_0001: ldstr “a”
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: ldstr “1”
    IL_000d: call string [mscorlib]System.String::Concat(string, string)
    IL_0012: stloc.0
    IL_0013: ldloc.0
    IL_0014: ldstr “b”
    IL_0019: call string [mscorlib]System.String::Concat(string, string)
    IL_001e: stloc.0
    IL_001f: ldloc.0
    IL_0020: ldstr “2”
    IL_0025: call string [mscorlib]System.String::Concat(string, string)
    IL_002a: stloc.0
    IL_002b: ldloc.0
    IL_002c: ldstr “c”
    IL_0031: call string [mscorlib]System.String::Concat(string, string)
    IL_0036: stloc.0
    IL_0037: ldloc.0
    IL_0038: ldstr “3”
    IL_003d: call string [mscorlib]System.String::Concat(string, string)
    IL_0042: stloc.0
    IL_0043: ldloc.0
    IL_0044: stloc.1
    IL_0045: br.s IL_0047

    IL_0047: ldloc.1
    IL_0048: ret
    } // end of method Program::Foo3

    .method public hidebysig static
    string Foo4 () cil managed
    {
    // Method begins at RVA 0x211c
    // Code size 85 (0x55)
    .maxstack 2
    .locals init (
    [0] string s,
    [1] string CS$1$0000,
    [2] int32 CS$0$0001
    )

    IL_0000: nop
    IL_0001: ldstr “a”
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: ldc.i4.1
    IL_0009: stloc.2
    IL_000a: ldloca.s CS$0$0001
    IL_000c: call instance string [mscorlib]System.Int32::ToString()
    IL_0011: call string [mscorlib]System.String::Concat(string, string)
    IL_0016: stloc.0
    IL_0017: ldloc.0
    IL_0018: ldstr “b”
    IL_001d: call string [mscorlib]System.String::Concat(string, string)
    IL_0022: stloc.0
    IL_0023: ldloc.0
    IL_0024: ldc.i4.2
    IL_0025: stloc.2
    IL_0026: ldloca.s CS$0$0001
    IL_0028: call instance string [mscorlib]System.Int32::ToString()
    IL_002d: call string [mscorlib]System.String::Concat(string, string)
    IL_0032: stloc.0
    IL_0033: ldloc.0
    IL_0034: ldstr “c”
    IL_0039: call string [mscorlib]System.String::Concat(string, string)
    IL_003e: stloc.0
    IL_003f: ldloc.0
    IL_0040: ldc.i4.3
    IL_0041: stloc.2
    IL_0042: ldloca.s CS$0$0001
    IL_0044: call instance string [mscorlib]System.Int32::ToString()
    IL_0049: call string [mscorlib]System.String::Concat(string, string)
    IL_004e: stloc.0
    IL_004f: ldloc.0
    IL_0050: stloc.1
    IL_0051: br.s IL_0053

    IL_0053: ldloc.1
    IL_0054: ret
    } // end of method Program::Foo4

    .method public hidebysig static
    string Foo5 () cil managed
    {
    // Method begins at RVA 0x2180
    // Code size 67 (0x43)
    .maxstack 3
    .locals init (
    [0] string CS$1$0000,
    [1] string[] CS$0$0001
    )

    IL_0000: nop
    IL_0001: ldc.i4.6
    IL_0002: newarr [mscorlib]System.String
    IL_0007: stloc.1
    IL_0008: ldloc.1
    IL_0009: ldc.i4.0
    IL_000a: ldstr “a”
    IL_000f: stelem.ref
    IL_0010: ldloc.1
    IL_0011: ldc.i4.1
    IL_0012: ldstr “1”
    IL_0017: stelem.ref
    IL_0018: ldloc.1
    IL_0019: ldc.i4.2
    IL_001a: ldstr “b”
    IL_001f: stelem.ref
    IL_0020: ldloc.1
    IL_0021: ldc.i4.3
    IL_0022: ldstr “2”
    IL_0027: stelem.ref
    IL_0028: ldloc.1
    IL_0029: ldc.i4.4
    IL_002a: ldstr “c”
    IL_002f: stelem.ref
    IL_0030: ldloc.1
    IL_0031: ldc.i4.5
    IL_0032: ldstr “3”
    IL_0037: stelem.ref
    IL_0038: ldloc.1
    IL_0039: call string [mscorlib]System.String::Concat(string[])
    IL_003e: stloc.0
    IL_003f: br.s IL_0041

    IL_0041: ldloc.0
    IL_0042: ret
    } // end of method Program::Foo5

    .method public hidebysig static
    string Foo6 () cil managed
    {
    // Method begins at RVA 0x21d0
    // Code size 79 (0x4f)
    .maxstack 3
    .locals init (
    [0] string CS$1$0000,
    [1] string[] CS$0$0001,
    [2] int32 CS$0$0002
    )

    IL_0000: nop
    IL_0001: ldc.i4.6
    IL_0002: newarr [mscorlib]System.String
    IL_0007: stloc.1
    IL_0008: ldloc.1
    IL_0009: ldc.i4.0
    IL_000a: ldstr “a”
    IL_000f: stelem.ref
    IL_0010: ldloc.1
    IL_0011: ldc.i4.1
    IL_0012: ldc.i4.1
    IL_0013: stloc.2
    IL_0014: ldloca.s CS$0$0002
    IL_0016: call instance string [mscorlib]System.Int32::ToString()
    IL_001b: stelem.ref
    IL_001c: ldloc.1
    IL_001d: ldc.i4.2
    IL_001e: ldstr “b”
    IL_0023: stelem.ref
    IL_0024: ldloc.1
    IL_0025: ldc.i4.3
    IL_0026: ldc.i4.2
    IL_0027: stloc.2
    IL_0028: ldloca.s CS$0$0002
    IL_002a: call instance string [mscorlib]System.Int32::ToString()
    IL_002f: stelem.ref
    IL_0030: ldloc.1
    IL_0031: ldc.i4.4
    IL_0032: ldstr “c”
    IL_0037: stelem.ref
    IL_0038: ldloc.1
    IL_0039: ldc.i4.5
    IL_003a: ldc.i4.3
    IL_003b: stloc.2
    IL_003c: ldloca.s CS$0$0002
    IL_003e: call instance string [mscorlib]System.Int32::ToString()
    IL_0043: stelem.ref
    IL_0044: ldloc.1
    IL_0045: call string [mscorlib]System.String::Concat(string[])
    IL_004a: stloc.0
    IL_004b: br.s IL_004d

    IL_004d: ldloc.0
    IL_004e: ret
    } // end of method Program::Foo6

    .method public hidebysig static
    string Foo7 () cil managed
    {
    // Method begins at RVA 0x222c
    // Code size 73 (0x49)
    .maxstack 2
    .locals init (
    [0] string s,
    [1] string CS$1$0000
    )

    IL_0000: nop
    IL_0001: ldstr “a”
    IL_0006: stloc.0
    IL_0007: ldstr “1”
    IL_000c: ldloc.0
    IL_000d: call string [mscorlib]System.String::Concat(string, string)
    IL_0012: stloc.0
    IL_0013: ldstr “b”
    IL_0018: ldloc.0
    IL_0019: call string [mscorlib]System.String::Concat(string, string)
    IL_001e: stloc.0
    IL_001f: ldstr “2”
    IL_0024: ldloc.0
    IL_0025: call string [mscorlib]System.String::Concat(string, string)
    IL_002a: stloc.0
    IL_002b: ldstr “c”
    IL_0030: ldloc.0
    IL_0031: call string [mscorlib]System.String::Concat(string, string)
    IL_0036: stloc.0
    IL_0037: ldstr “3”
    IL_003c: ldloc.0
    IL_003d: call string [mscorlib]System.String::Concat(string, string)
    IL_0042: stloc.0
    IL_0043: ldloc.0
    IL_0044: stloc.1
    IL_0045: br.s IL_0047

    IL_0047: ldloc.1
    IL_0048: ret
    } // end of method Program::Foo7

    .method public hidebysig static
    string Foo8 () cil managed
    {
    // Method begins at RVA 0x2284
    // Code size 85 (0x55)
    .maxstack 2
    .locals init (
    [0] string s,
    [1] string CS$1$0000,
    [2] int32 CS$0$0001
    )

    IL_0000: nop
    IL_0001: ldstr “a”
    IL_0006: stloc.0
    IL_0007: ldc.i4.1
    IL_0008: stloc.2
    IL_0009: ldloca.s CS$0$0001
    IL_000b: call instance string [mscorlib]System.Int32::ToString()
    IL_0010: ldloc.0
    IL_0011: call string [mscorlib]System.String::Concat(string, string)
    IL_0016: stloc.0
    IL_0017: ldstr “b”
    IL_001c: ldloc.0
    IL_001d: call string [mscorlib]System.String::Concat(string, string)
    IL_0022: stloc.0
    IL_0023: ldc.i4.2
    IL_0024: stloc.2
    IL_0025: ldloca.s CS$0$0001
    IL_0027: call instance string [mscorlib]System.Int32::ToString()
    IL_002c: ldloc.0
    IL_002d: call string [mscorlib]System.String::Concat(string, string)
    IL_0032: stloc.0
    IL_0033: ldstr “c”
    IL_0038: ldloc.0
    IL_0039: call string [mscorlib]System.String::Concat(string, string)
    IL_003e: stloc.0
    IL_003f: ldc.i4.3
    IL_0040: stloc.2
    IL_0041: ldloca.s CS$0$0001
    IL_0043: call instance string [mscorlib]System.Int32::ToString()
    IL_0048: ldloc.0
    IL_0049: call string [mscorlib]System.String::Concat(string, string)
    IL_004e: stloc.0
    IL_004f: ldloc.0
    IL_0050: stloc.1
    IL_0051: br.s IL_0053

    IL_0053: ldloc.1
    IL_0054: ret
    } // end of method Program::Foo8

    .method private hidebysig static
    void Main (
    string[] args
    ) cil managed
    {
    // Method begins at RVA 0x22e5
    // Code size 56 (0x38)
    .maxstack 8
    .entrypoint

    IL_0000: nop
    IL_0001: call string ConsoleApplication51.Program::Foo1()
    IL_0006: pop
    IL_0007: call string ConsoleApplication51.Program::Foo2()
    IL_000c: pop
    IL_000d: call string ConsoleApplication51.Program::Foo3()
    IL_0012: pop
    IL_0013: call string ConsoleApplication51.Program::Foo4()
    IL_0018: pop
    IL_0019: call string ConsoleApplication51.Program::Foo5()
    IL_001e: pop
    IL_001f: call string ConsoleApplication51.Program::Foo6()
    IL_0024: pop
    IL_0025: call string ConsoleApplication51.Program::Foo7()
    IL_002a: pop
    IL_002b: call string ConsoleApplication51.Program::Foo8()
    IL_0030: pop
    IL_0031: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_0036: pop
    IL_0037: ret
    } // end of method Program::Main

    .method public hidebysig specialname rtspecialname
    instance void .ctor () cil managed
    {
    // Method begins at RVA 0x231e
    // Code size 7 (0x7)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void [mscorlib]System.Object::.ctor()
    IL_0006: ret
    } // end of method Program::.ctor

    } // end of class ConsoleApplication51.Program
    }

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Merhaba Çağatay Bey tekrardan. Kişisel olarak algılamadım sadece alıntı yazıları kabullenmekten kaçının kısmı biraz fazla yapıcı oldu. Onun dışında gelecek olursak, sizin yaptığınız her öneri benim gerek kendimi geliştirmede gerekse farklı boyutlarını görme konusunda önemlidir. Sonuç olarak aramızda çok fazla yaş ve deneyimler bulunmakta. O yüzden size saygım sonsuz. Göstermiş olduğunuz string concatenation örnekleri gayet açıklayıcı. Benimde bir üst yorumda belirtmek istediğimde/çalıştığımda bu idi en basitinden string ile StringBuilder kullanım yeri/farkı. Bunun üzerine zaten bir çok performans testleri bulunmakta. Örneklerinize ek olarak bende bir loop içerisinde özellikle sürekli string initialazing yerine StringBuilder kullanımının da efektif olacağını eklemek isterim. Makale konusunda ise, bende eğer bir kaç string concatenation işlemi varsa problem olmayacağını belirtmeye çalıştım. Belkide dediğiniz gibi burada biraz daha konuyu açarak, bu concatenation işlemlerinin kullanım boyutlarına göre sizin örneklerinizde de olduğu gibi farklılık göstereceğini de eklemem gerekirdi. Tekrardan güzel yorumlarınız için teşekkür ederim ve diğer örnekler için fikirlerinizi almak adına e-posta ile iletişime geçeceğim.

  4. CA dedi ki:

    Gökhan Bey,

    Yazınıza eleştirimi yanlış anlamış olabilirsiniz diye belirtmek istedim, bir çok yazınızı zaman buldukça, rastgeldikçe, severek ve beğenerek okuyorum.

    Performans konusuna gelecek olursak da nacizane önerim, Linq ve performans konusuna detaylı bir şekilde değinen bir yazı ele almanız olurdu.

    Uzun zamandır bu konuyu hakkıyla becerenler gördüm ama gördüğüm becemeyenlerin sayısı o kadar fazla ki, bu konudaki düşüncem; “Functional Programming” bilhassa özel ilgi alanınız değilse, Linq ve Lamda expression’a da arka planda neler döndüğünü anlayabilecek kadar hakim değilseniz veya anlamaya çalışmıyorsanız, mümkün olduğunca uzak durulması gerektiği. Nedeni ise çok basit, Linq ve Lamda expression hayatı kolaylaştırıyor gibi görünmesine rağmen bilinçsiz ve tecrübesiz kullanımlarla, doğru işi yaptığı sanılarak yazılan kodların bilhassa çok sık kullanılan yerlerde performansın yerlerde sürünmesine sebep olması.

    Tabiki hangi konuya değineceğiniz size kalmış bir durum. Buna müdahil olmak da haddime değil ama bu konudaki detaylı bir yazıyla, bir çok açıdan değinilmesi gereken ama pek fazla da değinilmeyen bir konuda, yazınız çok faydalı olabilir diye düşünüyorum.

    Saygılar,

    Çağatay DOĞAN

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Çağatay Bey tekrardan teşekkür ederim belirtmeniz için. Özelikle Linq ve EntityFramework performansı konusunda çok haklısınız. Çoğu zaman yazılımcı arkadaşların yazdıkları kodu farklı profiler tool’ları ile profiling etmekteyiz. En basitinden sizinde bildiğiniz üzere, tracking change’ler yüzünden gereksiz alanlarında update’e gitmesi, kullanması gereken property’ler yerine tüm entity’i çekmesi gibi vb. Bunun dışında zaten kaç kişi arka planda Linq provider’ının ilgili expression’ları nasıl evulate ettiğini, oradaki Visitor Pattern yapısını biliyor ve araştırma gereği duyuyor. Güzel öneriniz için çok teşekkür ederim daha önce de aklıma gelmişti fakat dediğiniz gibi micro performans konuları derinlemesine bir konu ve gerçekten zaman ve araştırma gerektiriyor yazıya dökebilmek için. Herhangi bir saygısızlığım oldu ise daha önceki yazımımda affola.

      Saygılarımla.

  5. veysi dedi ki:

    Kesinlikle 11’inci kurala katilmiyorum, mimariyi belirten seyler koda katmak kesinlikle yanlistir. Editorler bunun icin vardir.

    • Gökhan Gökalp Gökhan Gökalp dedi ki:

      Koda katmak kesinlikle yanlıştır, editörler bunun için vardır cümlenizi anlayamadım fakat, mimariyi belirten bir case değil bu sadece naming convention. Katılıp katılmamak size kalmış. 🙂

  6. akif yanbak dedi ki:

    Performanstan ziyade kod okunurluğu işlenmiş. Elinize sağlık

  7. Efe ÖZYER dedi ki:

    Meyve veren ağaç taşlanır hocam :))

  8. Emre dedi ki:

    Emeğinize sağlık hocam, kitapınızıda bitirdim harika bilgiler veriyorsunuz

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*