- Notifications
You must be signed in to change notification settings - Fork45
JavaScript için Uyarlanmış Temiz Kod Kavramları
License
foss-dev/clean-code-javascript-tr
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
- Giriş
- Değişkenler
- Fonksiyonlar
- Nesneler ve Veri Yapıları
- Sınıflar
- SOLID
- Test
- Eşzamanlılık
- Hata Yakalama
- Yazım Şekli
- Yorumlar
- Çeviriler
Yazılım mühendisliği prensipleri, Robert C. Martin'inClean Code isimli kitabından alınmış, JavaScript için uyarlanmıştır. Bu bir stil rehber değildir. Bu JavaScript ilereadable, reusable, ve refactorable yazılımlar üretmek için bir rehberdir..
Burada yazılan prensiplere sıkı bir şekilde uymanız gerekmez belki bazı kurallar herkesçe kabul edilecektir. Burada yazanlar kurallar ve daha fazlası değil. Ancak bu kurallarClean Code yazarlarının uzun yıllara dayanan deneyimleri sonucu ortaya çıktığı için dikkate almanız iyi olabilir.
Yazılım mühendisliği konusundaki çalışmalarımız 50 yılın biraz üzerinde ve hala çok fazla şey öğreniyoruz. Yazılım mimarisi, mimarlığın kendisi kadar eski olduğunda belki de uyulması gereken daha zor kurallara sahip olacağız. Şimdilik, bu kılavuzların sizin ve ekibinizin ürettiği JavaScript kodunun kalitesini değerlendirmek için bir mihenk taşı olarak hizmet etmesine izin verin.
Son bir şey daha: Bunları biliyor olmak sizi hemen mükemmel bir yazılım geliştirici yapmaz ve bu kuralları bilerek geçirdiğiniz yıllar hata yapmayacağınız anlamına da gelmez. Her kod parçası bir taslak olarak başlar, tıpkı ıslak bir kilin son halini alması gibi de devam eder. Son olarak takım arkadaşlarımızla incelemeler yaparken kötü görünen kısımları yok eder. Gelişime ihtiyacı olan kodun ilk hali için kendinize kızmayın. Bunun yerine kodu dövün :)
Kötü:
constyyyymmdstr=moment().format('YYYY/MM/DD');
İyi:
constmevcutTarih=moment().format('YYYY/MM/DD');
Kötü:
kullaniciBilgisiGetir();musteriVerisiGetir();musteriKayitlariGetir();
İyi:
kullaniciGetir();
Yazacağımızdan daha fazla kod okuyacağız. Bu yazdığımız kodun okunabilir ve aranabilir olması açısından önemlidir. Değişkenleri kötü bir şekilde adlandırmayarak programımızı anlamaya çalışan kod okuyucularına zarar vermeyiz. İsimleri aranabilir yapın.buddy.js veESLint gibi araçlar tanımlanmamış sabit değerleri constant olarak tanımlamanıza yardımcı olabilir.
Kötü:
// Bu 86400000 ne olabilir??setTimeout(havalandirmayiCalistir,86400000);
İyi:
// Bu türden tanımlamaları büyük harfler ve alt çizgiler içerecek şekilde belirtin.constBIR_GUNDEKI_MILISANIYELER=86400000;setTimeout(havalandirmayiCalistir,BIR_GUNDEKI_MILISANIYELER);
Kötü:
constadres='Kireç Burnu Sahili, Sarıyer 34400';constsehirPostaKoduRegex=/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;sehirPostaKodunuKaydet(adres.match(sehirPostaKoduRegex)[1],adres.match(sehirPostaKoduRegex)[2]);
İyi:
constadres='Kireç Burnu Sahili, Sarıyer 34400';constsehirPostaKoduRegex=/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;const[,sehir,postaKodu]=adres.match(sehirPostaKoduRegex)||[];sehirPostaKodunuKaydet(sehir,postaKodu);
Açık olan kapalı olandan daha iyidir
Kötü:
constlokasyonlar=['Ankara','İstanbul','İzmir'];lokasyonlar.forEach((l)=>{birSeylerYap();baskaBirSeyYap();// ...// ...// ...// Bekle bi dk.. Bu l nedir?oneCikar(l);});
İyi:
constlokasyonlar=['Ankara','İstanbul','İzmir'];lokasyonlar.forEach((lokasyon)=>{birSeylerYap();baskaBirSeyYap();// ...// ...// ...oneCikar(lokasyon);});
Eğer sınıf ya da nesne adından ne yaptığı anlaşılıyorsa, tekrar olarak değişkenler içinde onu anlatan isimlendirmeler yapmayın.
Kötü:
constAraba={arabaUret:'Honda',arabaModeli:'Accord',arabaRengi:'Mavi'};functionarabayiBoya(araba){araba.arabaRengi='Kırmızı';}
İyi:
constAraba={uret:'Honda',model:'Accord',renk:'Mavi'};functionarabayiBoya(araba){araba.renk='Kırmızı';}
Varsayılan argümanlar çoğunlukla kısa mantıksa ifadelerden daha temiz bir kullanıma sahiptir. Varsayılan argümanların sadece undefined argümanlar geçerliyse çalışacağını unutmayın. Diğer falsy olarak kabul edilen değerler varsayılan argümanı değiştirecektir. Bunlar''
,""
,false
,null
,0
, veNaN
olarak gösterilebilir.
Kötü:
functionfabrikaOlustur(isim){constfabrikaAdi=isim||'Önceki Yazılımcı AŞ';// ...}
İyi:
functionfabrikaOlustur(isim='Önceki Yazılımcı AŞ'){// ...}
Fonksiyonların aldığı argümanları sınırlandırmak fonksiyonun test edilebilirliğiaçısından oldukça önemlidir. Üçten fazla argümana sahip bir fonksiyonu testetmeniz gerektiğinde, her bir durumu her bir argümanla ayrı ayrı testedeceğinizden dolayı tonlarca teste maruz kalabilirsiniz.
Bir veya iki argüman normal olan durumdur, mümkün olduğunca üçüncüden kaçınılmadılır.Bundan daha fazla olanlar iyileştirilmelidir. Eğer fonksiyonunuz ikiden fazlaargüman alıyorsa, muhtemelen yapması gerekenden fazla işi yapmaya çalışıyordur.Daha fazla argümana ihtiyacınız olduğu durumlarda daha kapsamlı bir nesnekullanmak yeterli olacaktır.
Javascript size anında nesne oluşturma kabiliyetini verdiğinden dolayı, daha fazlaargümana ihtiyaç duyduğunuz durumlarda; herhangi bir sınıf üretmeye gerek kalmadannesneler içerisinde argümanlarınızı gönderebilirsiniz.
Fonksiyonun beklediği argümanları garantilemek için ES2015/ES6 ile gelenyıkım işlemi (destructuring) sözdizimini kullanabilirsiniz. Bunun birkaç avantajı var:
- Dışarıdan birisi fonksiyon iskeletine baktığı zaman, fonksiyonun dışarıdan aldığıözellikleri kolayca anlayabilir.
- Yıkım işlemi (destructuring) aynı zamanda nesne içerisinde gönderilen ilkeldeğerleri klonlar. Bu yan etkilerin engellenmesinde yardımcı olur. Not: Argümannesneleri tarafından yıkıma uğratılmış (destruct edilmiş) nesne ve dizi değerleri klonlanmaz.
- Linterlar sizi kullanılmayan değerler için uyarabilir, ki bu durumu yıkım ("destruct") işlemi olmadanyapmanız mümkün değildir.
Kötü:
functionmenuOlustur(baslik,icerik,butonIcerik,iptalEdilebilir){// ...}
İyi:
functionmenuOlustur({ baslik, icerik, butonIcerik, iptalEdilebilir}){// ...}menuOlustur({baslik:'Takip Et',icerik:'Kullanıcı takip edilsin mi?',butonIcerik:'TAKİP ET',iptalEdilebilir:true});
Bu yazılım mühendisliğinde en önemli kuraldır. Fonksiyonlar birden fazla iş yaptığında, onları düzenlemek, test etmek ve hakkında fikir sahibi olmak oldukça zorlaşır. Bir fonksiyonu izole ettiğinizde, daha kolay refactor edilebilir ve daha temiz, okunabilir bir kod haline gelir. Bu kılavuzdan aldığınız tek bilgi bu olsa bile birçok geliştiricinin önünde olacaksınız.
Kötü:
functionmusterilereMailYolla(musteriler){musteriler.forEach((musteri)=>{constmusteriKaydi=database.sorgula(musteri);if(musteriKaydi.aktifMi()){email(musteri);}});}
İyi:
functionaktifMusterilereEmailGonder(musteriler){musteriler.filter(aktifMusteriMi).forEach(email);}functionaktifMusteriMi(musteri){constmusteriKaydi=database.sorgula(musteri);returnmusteriKaydi.aktifMi();}
Kötü:
functiontariheEkle(tarih,ay){// ...}consttarih=newDate();// Fonkisyon adına bakarak neyin eklendiğini anlamak zortariheEkle(tarih,1);
İyi:
functiontariheAyEkle(ay,tarih){// ...}consttarih=newDate();tariheAyEkle(1,tarih);
Fonkiyonunuz bir seviyeden fazla soyutlaşmış ise, gereğinden fazlaiş yapıyor demektir. Fonksiyonlarınızı görevlerine göre küçük parçalarabölmek geri kullanılabilirlik ve kolay test edilebilirlik açısından önemlidir.
Kötü:
functiondahaIyiJSAlternatifineDonustur(kod){constREGEXLER=[// ...];constkodParcaciklari=kod.split(' ');constsimgeler=[];REGEXLER.forEach((REGEX)=>{kodParcaciklari.forEach((kodParcacigi)=>{// ...});});constast=[];simgeler.forEach((simge)=>{// lex...});ast.forEach((node)=>{// dönüstür...});}
İyi:
functiondahaIyiJSAlternatifineDonustur(kod){constsimgeler=simgelestir(kod);constast=analizEt(simgeler);ast.forEach((node)=>{// dönüstür...});}functionsimgelestir(kod){constREGEXLER=[// ...];constkodParcaciklari=kod.split(' ');constsimgeler=[];REGEXLER.forEach((REGEX)=>{kodParcaciklari.forEach((kodParcacigi)=>{simgeler.push(/* ... */);});});returnsimgeler;}functionanalizEt(simgeler){constast=[];simgeler.forEach((simge)=>{ast.push(/* ... */);});returnast;}
Yinelenen kodu kaldırmak için elinizden gelenin en iyisini yapın. Tekrarlanan kodunkötü olma nedeni, kodunuzda mantıksal bir durumu değiştirmeye çalıştığınızdabunu birden fazla yerde yapmanızı gerektirmesidir. Bu da oldukça hataya elverişli bir durumdur.
Bir restoran işlettiğinizi ve içinde domates, soğan, biber, sarımsak vs. olan bir deponuzolduğunu ve deponuzu takip ettiğinizi düşünün. Eğer bu iş için birden fazla listetutarsanız, en ufak bir servisinizde tüm listeleri yeniden güncellemeniz gerekecektir.Eğer tek bir listeniz olursa tek bir noktadan tüm listeyi yönetebilirsiniz
Çoğu zaman kod tekrarına düşersiniz. Çünkü iki veya daha fazla küçük farklılığıolan ama çoğunlukla aynı özellikleri taşıyan iki fonksiyon sizi bu küçük nedenlerdendolayı çoğunlukla aynı özelliklere sahip olan ve temelde aynı işi yapaniki farklı fonksiyon yazmaya zorlar. Tekrarlayan kodu kaldırmak demek; bu farklılıklarıfarklı bir yerde yerine getirebilecek soyut fonksiyonlar, modüller, sınıflar yazmak demektir.
Soyutlamayı doğru yapmak çok kritikdir. Bu yüzden devam eden kısımlardanSınıflarkısmındaki KATI kuralları takip etmelisiniz. Kötü soyutlamalar kod tekrarından da kötüdür.Bu yüzden dikkatli olmalısınız. İyi bir soyutlama yapabilirim diyorsanız bunu yapın.Kendinizi tekrar etmeyin, aksi takdirde kendinizi birden fazla yeri güncellerken bulacaksınız.
Kötü:
functiongelistiriciListesiniGoster(gelistiriciler){gelistiriciler.forEach((gelistirici)=>{constbeklenenMaas=gelistirici.beklenenMaasiHesapla();constdeneyim=gelistirici.deneyimiGetir();constgithubLink=gelistirici.githubLink();constveri={ beklenenMaas, deneyim, githubLink};yazdir(veri);});}functionyoneticiListesiniGoster(yoneticiler){yoneticiler.forEach((yonetici)=>{constbeklenenMaas=yonetici.beklenenMaasiHesapla();constdeneyim=yonetici.deneyimiGetir();constportfolio=yonetici.projeleriniGetir();constveri={ beklenenMaas, deneyim, portfolio};yazdir(veri);});}
İyi:
functionpersonelListesiniGoster(personeller){personeller.forEach((personel)=>{constbeklenenMaas=personel.beklenenMaasiHesapla();constdeneyim=personel.deneyimiGetir();constveri={ beklenenMaas, deneyim};switch(personel.tip){case'yonetici':veri.portfolio=personel.projeleriniGetir();break;case'developer':veri.githubLink=personel.githubLink();break;}yazdir(veri);});}
Kötü:
constmenuAyari={baslik:null,icerik:'Deneme',butonYazisi:null,iptalEdilebilir:true};functionmenuOlustur(ayar){ayar.baslik=ayar.baslik||'Bir Baslik';ayar.icerik=ayar.icerik||'Deneme';ayar.butonYazisi=ayar.butonYazisi||'Kaydet';ayar.iptalEdilebilir=ayar.iptalEdilebilir!==undefined ?ayar.iptalEdilebilir :true;}menuOlustur(menuAyari);
İyi:
constmenuAyari={baslik:'Bir Baslik',// Geliştirici 'icerik' key'ini burada belirtmedibutonYazisi:'Kaydet',iptalEdilebilir:true};functionmenuOlustur(ayar){ayar=Object.assign({baslik:'Bir Baslik',icerik:'Deneme',butonYazisi:'Kaydet',iptalEdilebilir:true},ayar);// ayar simdi: {baslik: "Bir Baslik", icerik: "Deneme", butonYazisi: "Kaydet", iptalEdilebilir: true}// ...}menuOlustur(menuAyari);
Bayraklar geliştiriciye fonksiyonun birden fazla şey yaptığını söyler. Fonksiyonlar sadece bir iş yapmalıdır. Eğer fonksiyonlarınız boolean değere dayalı olarak farklı kodlar çalıştırıyorsa onları bölün.
Kötü:
functiondosyaOlustur(isim,gecici){if(gecici){fs.create(`./gecici/${isim}`);}else{fs.create(isim);}}
İyi:
functiondosyaOlustur(isim){fs.create(isim);}functiongeciciDosyaOlustur(isim){dosyaOlustur(`./temp/${isim}`);}
Bir fonksiyon, değer alıp başka değer veya değerler döndürmek dışındabir şey yapıyorsa yan etki oluşturur. Bu yan etki, dosyalara bir şeyler yazmak,bazı global değişkenleri değiştirmek, güncellemek veya yanlışlıkla bütün paranızı biryabancıya aktarmak olabilir.
Zaman zaman yazdığınız programda yan etkilerin olması gerekir. Mesela, bir öncekiörnekte işlenildiği gibi dosyalara bir şeyler yazmanız gerekebilir. Yapmanız gereken şey iseyan etki oluşturan işlemleri yaptığınız yeri merkezileştirmektir. Örneğin belirli bir dosya üzerindeişlem yapan birkaç fonksiyon veya sınıfınız olmasın. Sadece bir servis bunu yapsın. Evet, sadece bir servis.
Buradaki ana fikir, herhangi bir yapıya sahip olmayan nesneler arasındaki stateleri paylaşmak,herhangi bir şey tarafından değiştirilebilir veri tiplerini kullanmak veya yan etkilerin oluştuğuyerleri merkezileştirmemek gibi yaygın hatalardan kaçınmaktır. Eğer bunları yapabilirseniz,diğer programcıların büyük bir çoğunluğundan daha mutlu olacaksınız.
Kötü:
// Global variable referenced by following function.// If we had another function that used this name, now it'd be an array and it could break it.letisim='Ali Veli';functionisimVeSoyismiAyir(){isim=isim.split(' ');}isimVeSoyismiAyir();console.log(isim);// ['Ali', 'Veli'];
İyi:
functionisimVeSoyismiAyir(isim){returnisim.split(' ');}constisim='Ali Veli';constyeniIsim=isimVeSoyismiAyir(isim);console.log(isim);// 'Ali Veli';console.log(yeniIsim);// ['Ali', 'Veli'];
In JavaScript, primitives are passed by value and objects/arrays are passed byreference. In the case of objects and arrays, if your function makes a changein a shopping cart array, for example, by adding an item to purchase,then any other function that uses thatcart
array will be affected by thisaddition. That may be great, however it can be bad too. Let's imagine a badsituation:
The user clicks the "Purchase", button which calls apurchase
function thatspawns a network request and sends thecart
array to the server. Becauseof a bad network connection, thepurchase
function has to keep retrying therequest. Now, what if in the meantime the user accidentally clicks "Add to Cart"button on an item they don't actually want before the network request begins?If that happens and the network request begins, then that purchase functionwill send the accidentally added item because it has a reference to a shoppingcart array that theaddItemToCart
function modified by adding an unwanteditem.
A great solution would be for theaddItemToCart
to always clone thecart
,edit it, and return the clone. This ensures that no other functions that areholding onto a reference of the shopping cart will be affected by any changes.
Two caveats to mention to this approach:
There might be cases where you actually want to modify the input object,but when you adopt this programming practice you will find that those casesare pretty rare. Most things can be refactored to have no side effects!
Cloning big objects can be very expensive in terms of performance. Luckily,this isn't a big issue in practice because there aregreat libraries that allowthis kind of programming approach to be fast and not as memory intensive asit would be for you to manually clone objects and arrays.
Kötü:
constaddItemToCart=(cart,item)=>{cart.push({ item,date:Date.now()});};
İyi:
constaddItemToCart=(cart,item)=>{return[...cart,{ item,date:Date.now()}];};
Javascript'te globalleri kirletmek kötü bir uygulamadır çünkü diğer bir kütüphaneyle çakışabilirsiniz ve API kullanıcınız uygulamayı canlı ortama sunduğunda alacağı bir hataya kadar bu durumdan haberdar olmayabilir. Bir örnek üzerinden düşünelim: eğer JavaScript'in sahip olduğu Array metodunu, iki dizi arasındaki farkı gösteren birdiff
metoduna sahip olacak şekilde genişletmek isteseydik?Array.prototype
a yeni bir fonksiyon yazabilirsin, ama bu, aynı şeyi yapmaya çalışan başka bir kütüphane ile çakışabilir. Ya başka bir kütüphanediff
metodunu, bir dizinin ilk elemanı ile son elemanı arasındaki farkı bulmak için kullanıyor olsaydı? Bu yüzden ES2015/ES6 sınıflarını kullanmak ve basitçeArray
i kalıtımla almak çok daha iyi olacaktır.
Kötü:
Array.prototype.diff=functiondiff(comparisonArray){consthash=newSet(comparisonArray);returnthis.filter(elem=>!hash.has(elem));};
İyi:
classSuperArrayextendsArray{diff(comparisonArray){consthash=newSet(comparisonArray);returnthis.filter(elem=>!hash.has(elem));}}
JavaScript, Haskell gibi fonksiyonel bir dil değil ama fonksiyonel yönleri de var. Fonksiyonel diller daha temiz ve test edilmesi daha kolay olabilir. Yapabildiğiniz zaman bu programlama stilini tercih edin.
Kötü:
constprogramciCiktisi=[{name:'Uncle Bobby',kodSatirlari:500},{name:'Suzie Q',kodSatirlari:1500},{name:'Jimmy Gosling',kodSatirlari:150},{name:'Gracie Hopper',kodSatirlari:1000}];lettoplamCikti=0;for(leti=0;i<programciCiktisi.length;i++){toplamCikti+=programciCiktisi[i].kodSatirlari;}
İyi:
constprogramciCiktisi=[{name:'Uncle Bobby',kodSatirlari:500},{name:'Suzie Q',kodSatirlari:1500},{name:'Jimmy Gosling',kodSatirlari:150},{name:'Gracie Hopper',kodSatirlari:1000}];consttoplamCikti=programciCiktisi.map(cikti=>cikti.kodSatirlari).reduce((toplamSatirlar,satirlar)=>toplamSatirlar+satirlar);
Kötü:
if(fsm.state==='fetching'&&isEmpty(listNode)){// ...}
İyi:
functionshouldShowSpinner(fsm,listNode){returnfsm.state==='fetching'&&isEmpty(listNode);}if(shouldShowSpinner(fsmInstance,listNodeInstance)){// ...}
Kötü:
functiondomYaratilmadi(node){// ...}if(!domYaratilmadi(node)){// ...}
İyi:
functiondomYaratildi(node){// ...}if(domYaratildi(node)){// ...}
Bu imkansız bir iş gibi güzüküyor. Çoğu insan bunu ilk duyduğu ana kadar, "if
ifadesi olmadan nasıl bir şey yapabilirim? " diyor. Bunun cevabı, birçok durumda aynı işi yapmak için polymorphism kullanabilirsiniz. Genellikle ikinci soru, "iyi güzel ama neden bunu yapmayı isteyeyim ki?" Bunun cevabı ise öğrendiğimiz önceki temiz kod konsepti olan: bir fonksiyon yalnızca bir şey yapmalıdır.if
ifadesine sahip olan sınıflarınız ve fonksiyonlarınız olduğunda, kullanıcılarınıza fonksiyonunuzun birden fazla şey yaptığını söylüyorsunuz. Hatırla, sadece bir şey yap.
Kötü:
classUcak{// ...seyirYuksekliginiGetir(){switch(this.type){case'777':returnthis.maxYuksekligiGetir()-this.yolcuSayisiniGetir();case'Air Force One':returnthis.maxYuksekligiGetir();case'Cessna':returnthis.maxYuksekligiGetir()-this.yakitHarcamasiniGetir();}}}
İyi:
classUcak{// ...}classBoeing777extendsUcak{// ...seyirYuksekliginiGetir(){returnthis.maxYuksekligiGetir()-this.yolcuSayisiniGetir();}}classAirForceOneextendsUcak{// ...seyirYuksekliginiGetir(){returnthis.maxYuksekligiGetir();}}classCessnaextendsUcak{// ...seyirYuksekliginiGetir(){returnthis.maxYuksekligiGetir()-this.yakitHarcamasiniGetir();}}
JavaScript tip güvensiz bir dildir, yani fonksiyonlarınız herhangi bir tipte argüman alabilir.Bazen bu özgürlük can yakıcı olabiliyor haliyle fonksiyonlarınızda tip kontrolü yapmak cazip hale gelebiliyor. Bundan kaçınmanın birçok yolu var.Dikkate alınması gereken ilk şey tutarlı API'lar yazmanız.
Kötü:
functionnigdeyeZiyaret(arac){if(aracinstanceofBisiklet){arac.pedaliCevir(this.mevcutLokasyon,newLokasyon('nigde'));}elseif(aracinstanceofAraba){arac.sur(this.mevcutLokasyon,newLokasyon('nigde'));}}
İyi:
functionnigdeyeZiyaret(arac){arac.hareketEt(this.mevcutLokasyon,newLokasyon('nigde'));}
Eğer strginler ve integerlar gibi temel ilkel değerlerle çalışıyorsanız ve polymorphism kullanamıyorsanız ama hala tip kontrolü yapmanız gerekiyormuş gibi hissediyorsanız TypeScript kullanmayı düşünmelisiniz. TypeScript, normal JavaScript'in mükkemel bir alternatifi, standart Javascript söz diziminin üzerine statik yazmanızı sağlar. Normal JavaScript'te manuel şekilde tip kontrolü yapmanın problemi, tip kontrlünü iyi yapmak ekstra kod kalabalığını gerektiriyor. Yapmaya çalıştığımız sahte "tip kontrolü" kaybolan okunabilirliği telafi etmiyor. JavaScript kodlarınızı temiz tutun, iyi testler yazın ve rahat kod incelemelerine sahip olun. Ayrıca, hepsini yap ama TypeScript ile yap (dediğim gibi, harika bir alternatif).
Kötü:
functionkombin(deger1,deger2){if(typeofdeger1==='number'&&typeofdeger2==='number'||typeofdeger1==='string'&&typeofdeger2==='string'){returnval1+val2;}thrownewError('String veya Number tipinde olmalıdır!');}
İyi:
functionkombin(deger1,deger2){returndeger1+deger2;}
Modern tarayıcılar çalışma anında arkaplanda çok fazla optimizasyon yaparlar.Çoğu zaman yaptığınız optimizasyon, boşa zaman harcamaktır. Optimzasyonun nerede eksik olduğunu görmek içinbu kaynaklar iyidir.
Kötü:
// Eski tarayıcılarda `list.length` için önbelleğe alınmamış her yineleme maliyetlidir.// Çünkü `list.length` her defasında yeniden sayılır. Modern tarayıcılarda bu optimize edilmiştir.for(leti=0,len=liste.length;i<len;i++){// ...}
İyi:
for(leti=0;i<liste.length;i++){// ...}
Ölü kod da tekrarlı kodlar kadar kötüdür. Kodlarınızda ölü kod saklamanız için herhangi bir neden yoktur.Eğer herhangi bir yerde çağrılmıyorlarsa onlardan kurtulun. İhtiyacınız olduğunda, versiyon kontrol sisteminde bulabilirsiniz.
Kötü:
functioneskiHttpRequestModulu(url){// ...}functionyeniHttpRequestModulu(url){// ...}constistek=yeniHttpRequestModulu;envanterTakibi('elmalar',istek,'www.envantertakibi.com');
İyi:
functionyeniHttpRequestModulu(url){// ...}constistek=yeniHttpRequestModulu;envanterTakibi('elmalar',istek,'www.envantertakibi.com');
Nesnelerdeki verilere erişmek için Setter ve Getter kullanmak sadece bir nesnedekiözellikleri aramaktan daha iyi olabilir. "Neden?" diye soracaksınız. Peki, işte buradasebeplerinin bir listesi var:
- Bir nesne özelliğini elde etmekten daha fazla şey yapmak istediğinizde kod tabanınızdakiher erişimciyi aramanız ve değiştirmeniz gerekmez.
set
işlemi yaparken doğrulama eklemeyi kolaylaştırır.- İç temsili kapsüller.
- Set ve Get işlemlerini gerçekleştirirken kayıt tutmayı (log) ve hata yakalamayı eklemek kolaydır.
- Nesnenizin özelliklerini sunucudan alırken Lazy Load kullanabilirsiniz.
Kötü:
functionbankaHesabiOlustur(){// ...return{bakiye:0,// ...};}consthesap=bankaHesabiOlustur();hesap.bakiye=100;
İyi:
functionbankaHesabiOlustur(){// bu privateletbakiye=0;//Getter aşağıda döndürülen nesne aracılığıyla public hale getirildifunctiongetBakiye(){returnbakiye;}// Setter aşağıda döndürülen nesne aracılığıyla public hale getirildifunctionsetBakiye(deger){// ... bakiyeyi güncellemeden önce onaylarbakiye=deger;}return{// ... getBakiye, setBakiye,};}consthesap=bankaHesabiOlustur();hesap.setBakiye(100);
Bu, kapamalarla(closures) gerçekleştirilebilir. (ES5 ve altı için).
Kötü:
constCalisan=function(isim){this.isim=isim;};Calisan.prototype.getIsim=functiongetIsim(){returnthis.isim;};constcalisan=newcalisan('John Doe');console.log(`Calisanin ismi:${calisan.getIsim()}`);// Calisanin ismi: John Doedeletecalisan.isim;console.log(`Calisanin ismi:${calisan.getIsim()}`);// Calisanin ismi: undefined
İyi:
functioncalisanOlustur(isim){return{getIsim(){returnisim;},};}constcalisan=calisanOlustur('John Doe');console.log(`Calisanin ismi:${calisan.getIsim()}`);// Calisanin ismi: John Doedeletecalisan.isim;console.log(`Calisanin ismi:${calisan.getIsim()}`);// Calisanin ismi: John Doe
Klasik ES5 sınıfları için okunabilir sınıf kalıtımları, construction ve metod tanımlarınıalmak çok zordur. Eğer kalıtıma ihtiyacınız varsa (ihtiyacınızın olmayabileceğinin farkında olun),o zaman ES2015/ES6 sınıflarını tercih edin. Ancak, daha büyük ve karmaşık nesnelerle uğraşanakadar sınıflar yerine küçük fonksiyonları kullanın.
Kötü:
constAnimal=function(age){if(!(thisinstanceofAnimal)){thrownewError('Instantiate Animal with `new`');}this.age=age;};Animal.prototype.move=functionmove(){};constMammal=function(age,furColor){if(!(thisinstanceofMammal)){thrownewError('Instantiate Mammal with `new`');}Animal.call(this,age);this.furColor=furColor;};Mammal.prototype=Object.create(Animal.prototype);Mammal.prototype.constructor=Mammal;Mammal.prototype.liveBirth=functionliveBirth(){};constHuman=function(age,furColor,languageSpoken){if(!(thisinstanceofHuman)){thrownewError('Instantiate Human with `new`');}Mammal.call(this,age,furColor);this.languageSpoken=languageSpoken;};Human.prototype=Object.create(Mammal.prototype);Human.prototype.constructor=Human;Human.prototype.speak=functionspeak(){};
İyi:
classAnimal{constructor(age){this.age=age;}move(){/* ... */}}classMammalextendsAnimal{constructor(age,furColor){super(age);this.furColor=furColor;}liveBirth(){/* ... */}}classHumanextendsMammal{constructor(age,furColor,languageSpoken){super(age,furColor);this.languageSpoken=languageSpoken;}speak(){/* ... */}}
Bu yöntem JavaScript'te çok kullanışlıdır ve bunu jQuery ve Lodash gibi birçok kütüphanede görebilirsiniz.Kodunuzun daha anlamlı ve daha az detaylı olmasını sağlar.Bu nedenle, metod zincirleme yöntemini bir kez kullanın ve kodunuzun ne kadar temiz olacağına bir göz atın derim.Sınıf fonksiyonlarında basitçe her fonksiyon sonundathis
döndürün,böylece daha fazla sınıf metodu zincirleyebilirsiniz.
Kötü:
classAraba{constructor(marka,model,renk){this.marka=marka;this.model=model;this.renk=renk;}setMarka(marka){this.marka=marka;}setModel(model){this.model=model;}setRenk(renk){this.renk=renk;}kaydet(){console.log(this.marka,this.model,this.renk);}}constaraba=newAraba('Ford','F-150','kirmizi');araba.setRenk('pembe');araba.kaydet();
İyi:
classAraba{constructor(marka,model,renk){this.marka=marka;this.model=model;this.renk=renk;}setMarka(marka){this.marka=marka;// NOT: Zincirleme için 'this' döndürülüyorreturnthis;}setModel(model){this.model=model;// NOT: Zincirleme için 'this' döndürülüyorreturnthis;}setRenk(renk){this.renk=renk;// NOT: Zincirleme için 'this' döndürülüyorreturnthis;}kaydet(){console.log(this.marka,this.model,this.renk);// NOT: Zincirleme için 'this' döndürülüyorreturnthis;}}constaraba=newAraba('Ford','F-150','kirmizi').setRenk('pembe').kaydet();
Gang of Four tarafındanDesign Patterns da ünlü olarak belirtildiği gibi, yapabildiğiniz yerlerde miras(kalıtım) yerine kompozisyonu tercih etmelisiniz. Miras(kalıtım)ıkullanmak için birçok iyi sebep olduğu gibi kompozisyonu kullanmak içinde birçok iyi sebep var. Bu kural içinasıl nokta, eğer aklınız içgüdüsel olarak miras(kalıtım)ı tercih ediyorsa, kompozisyonun, probleminizi daha iyimodelleyebileceğini düşünmeye çalışın. Bazı durumlarda bu olabilir.
"Miras(kalıtım)ı ne zaman kullanmalıyım?" diye merak ediyor olabilirsiniz. Bu durum elinizdeki soruna bağlı amabu, ne zaman miras(kalıtım)ın kompozisyondan daha anlamlı olduğunun kabul edilebilir bir listesi.
- Miras(kalıtım)ınız, "-dır, -dir" ilişkisini sağlıyor ve "sahiplik" ilişkisinin sağlamıyor.(İnsan->Hayvan vs. Kullanıcı->KullanıcıDetayları)
- Kodu temel sınıflardan yeniden kullanabilirsiniz. (İnsanlar, tüm hayvanlar gibi hareket edebilir)
- Bir temel sınıfı değiştirerek türetilmiş sınıflarda genel değişiklikler yapmak istiyorsunuz.(Hayvanların hareket ettiğinde harcadığı kaloriyi değiştirmek)
Kötü:
classPersonel{constructor(isim,mail){this.isim=isim;this.mail=mail;}// ...}// Kötü çünkü Personeller vergi verisine "sahip". PersonelVergiVerileri, bir Personel türü değil.classPersonelVergiVerileriextendsPersonel{constructor(ssn,maas){super();this.ssn=ssn;// sosyal güvenlik numarasıthis.maas=maas;}// ...}
İyi:
classPersonelVergiVerileri{constructor(ssn,maas){this.ssn=ssn;// sosyal güvenlik numarasıthis.maas=maas;}// ...}classPersonel{constructor(isim,mail){this.isim=isim;this.mail=mail;}vergiVerisiniBelirle(ssn,maas){this.vergiVerisi=newPersonelVergiVerileri(ssn,maas);}// ...}
Temiz Kod'da belirtildiği gibi, "Bir sınıfın değişebilmesi için asla birden fazla sebep olmamalıdır". Birçok işlevsellikle birlikte bir sınıfı sıkıştırmak cezbedicidir, tıpkı bir uçuşda yalnızca bir valiz almak gibi. Bununla ilgili mesele, sınıfınızın kavramsal olarak uyum sağlamayacağı ve değişmesi için birçok neden vereceğidir. Bir sınıfı değiştirmeniz için gereken süreyi en aza indirgemek önemlidir. Çünkü çok fazla işlevsellik bir sınıfta bulunuyorsa ve siz bir kısmını değiştirirseniz, bu değişikliğin kod tabanınızdaki diğer bağımlı modülleri nasıl etkileyeceğini anlamanız zor olabilir.
Kötü:
classUserSettings{constructor(user){this.user=user;}changeSettings(settings){if(this.verifyCredentials()){// ...}}verifyCredentials(){// ...}}
İyi:
classUserAuth{constructor(user){this.user=user;}verifyCredentials(){// ...}}classUserSettings{constructor(user){this.user=user;this.auth=newUserAuth(user);}changeSettings(settings){if(this.auth.verifyCredentials()){// ...}}}
Bertrand Meyer tarafından belirtildiği gibi, "yazılım varlıkları (classlar, modüller, fonksiyonlar vs.) gelişime açık, değişime kapalı olmalıdır." Peki bu ne anlamaya geliyor? Bu ilke temel olarak, kullanıcıların varolan kodu değiştirmeden yeni işlevler ekleyebilmesini sağlamamız gerektiğini belirtir.
Kötü:
classAjaxAdapterextendsAdapter{constructor(){super();this.name='ajaxAdapter';}}classNodeAdapterextendsAdapter{constructor(){super();this.name='nodeAdapter';}}classHttpRequester{constructor(adapter){this.adapter=adapter;}fetch(url){if(this.adapter.name==='ajaxAdapter'){returnmakeAjaxCall(url).then((response)=>{// transform response and return});}elseif(this.adapter.name==='httpNodeAdapter'){returnmakeHttpCall(url).then((response)=>{// transform response and return});}}}functionmakeAjaxCall(url){// request and return promise}functionmakeHttpCall(url){// request and return promise}
İyi:
classAjaxAdapterextendsAdapter{constructor(){super();this.name='ajaxAdapter';}request(url){// request and return promise}}classNodeAdapterextendsAdapter{constructor(){super();this.name='nodeAdapter';}request(url){// request and return promise}}classHttpRequester{constructor(adapter){this.adapter=adapter;}fetch(url){returnthis.adapter.request(url).then((response)=>{// transform response and return});}}
Bu terim bu kadar basit bir konsept için korkutucu. Resmi olarak tanımı şöyle: "Eğer S, T'nin alt türü ise, programın istenilen özelliklerinden herhangi birini değiştirmeden(doğruluğunu, yaptığı işi vb.)T tipindeki nesneler S tipindeki nesneler ile yer değiştirebilir (yani, S tipindeki nesneler T tipindeki nesnelerin yerine geçebilir). Bu daha da korkutucu bir tanım.
Bunun için en iyi açıklama: eğer bir ebeveyn sınıfınız ve alt sınıfınız varsa, temel sınıf ve alt sınıf, yanlış sonuçlar ortaya koymadan birbirlerinin yerine kullanılabilir. Hala kafa karıştırıcı olabilir,o zaman hadi klasik Kare-Dikdörtgen örneğine göz atalım. Matematiksel olarak kare bir dikdörtgendir ama eğer bunu kalıtım yoluyla, "is-a" ilişkisi kullanarak modellerseniz başınızın belaya girmesi çok gecikmeyecektir.
Kötü:
classDikdortgen{constructor(){this.genislik=0;this.yukseklik=0;}renginiBelirle(renk){// ...}olustur(alan){// ...}genisligiBelirle(genislik){this.genislik=genislik;}yuksekligiBelirle(yukseklik){this.yukseklik=yukseklik;}alanHesapla(){returnthis.genislik*this.yukseklik;}}classKareextendsDikdortgen{genisligiBelirle(genislik){this.genislik=genislik;this.yukseklik=genislik;}yuksekligiBelirle(yukseklik){this.genislik=yukseklik;this.yukseklik=yukseklik;}}functiongenisDikdortgenlerOlustur(dikdortgenler){dikdortgenler.forEach((dikdortgen)=>{dikdortgen.genisligiBelirle(4);dikdortgen.yuksekligiBelirle(5);constalan=dikdortgen.alanHesapla();// KÖTÜ: Kare için 25 döner. 20 olmalıydı.dikdortgen.olustur(alan);});}constdikdortgenler=[newDikdortgen(),newDikdortgen(),newKare()];genisDikdortgenlerOlustur(dikdortgenler);
İyi:
classSekil{renginiAyarla(renk){// ...}olustur(alan){// ...}}classDikdortgenextendsSekil{constructor(genislik,yukseklik){super();this.genislik=genislik;this.yukseklik=yukseklik;}alanHesapla(){returnthis.genislik*this.yukseklik;}}classKareextendsSekil{constructor(uzunluk){super();this.uzunluk=uzunluk;}alanHesapla(){returnthis.uzunluk*this.uzunluk;}}functiongenisSekillerOlustur(sekiller){sekiller.forEach((sekil)=>{constalan=sekil.alanHesapla();sekil.olustur(alan);});}constsekiller=[newDikdortgen(4,5),newDikdortgen(4,5),newKare(5)];genisSekillerOlustur(sekiller);
JavaScript doesn't have interfaces so this principle doesn't apply as strictlyas others. However, it's important and relevant even with JavaScript's lack oftype system.
ISP states that "Clients should not be forced to depend upon interfaces thatthey do not use." Interfaces are implicit contracts in JavaScript because ofduck typing.
A good example to look at that demonstrates this principle in JavaScript is forclasses that require large settings objects. Not requiring clients to setuphuge amounts of options is beneficial, because most of the time they won't needall of the settings. Making them optional helps prevent having a"fat interface".
Kötü:
classDOMTraverser{constructor(settings){this.settings=settings;this.setup();}setup(){this.rootNode=this.settings.rootNode;this.animationModule.setup();}traverse(){// ...}}const$=newDOMTraverser({rootNode:document.getElementsByTagName('body'),animationModule(){}// Most of the time, we won't need to animate when traversing.// ...});
İyi:
classDOMTraverser{constructor(settings){this.settings=settings;this.options=settings.options;this.setup();}setup(){this.rootNode=this.settings.rootNode;this.setupOptions();}setupOptions(){if(this.options.animationModule){// ...}}traverse(){// ...}}const$=newDOMTraverser({rootNode:document.getElementsByTagName('body'),options:{animationModule(){}}});
This principle states two essential things:
- High-level modules should not depend on low-level modules. Both shoulddepend on abstractions.
- Abstractions should not depend upon details. Details should depend onabstractions.
This can be hard to understand at first, but if you've worked with AngularJS,you've seen an implementation of this principle in the form of DependencyInjection (DI). While they are not identical concepts, DIP keeps high-levelmodules from knowing the details of its low-level modules and setting them up.It can accomplish this through DI. A huge benefit of this is that it reducesthe coupling between modules. Coupling is a very bad development pattern becauseit makes your code hard to refactor.
As stated previously, JavaScript doesn't have interfaces so the abstractionsthat are depended upon are implicit contracts. That is to say, the methodsand properties that an object/class exposes to another object/class. In theexample below, the implicit contract is that any Request module for anInventoryTracker
will have arequestItems
method.
Kötü:
classInventoryRequester{constructor(){this.REQ_METHODS=['HTTP'];}requestItem(item){// ...}}classInventoryTracker{constructor(items){this.items=items;// BAD: We have created a dependency on a specific request implementation.// We should just have requestItems depend on a request method: `request`this.requester=newInventoryRequester();}requestItems(){this.items.forEach((item)=>{this.requester.requestItem(item);});}}constinventoryTracker=newInventoryTracker(['apples','bananas']);inventoryTracker.requestItems();
İyi:
classInventoryTracker{constructor(items,requester){this.items=items;this.requester=requester;}requestItems(){this.items.forEach((item)=>{this.requester.requestItem(item);});}}classInventoryRequesterV1{constructor(){this.REQ_METHODS=['HTTP'];}requestItem(item){// ...}}classInventoryRequesterV2{constructor(){this.REQ_METHODS=['WS'];}requestItem(item){// ...}}// By constructing our dependencies externally and injecting them, we can easily// substitute our request module for a fancy new one that uses WebSockets.constinventoryTracker=newInventoryTracker(['apples','bananas'],newInventoryRequesterV2());inventoryTracker.requestItems();
Testing is more important than shipping. If you have no tests or aninadequate amount, then every time you ship code you won't be sure that youdidn't break anything. Deciding on what constitutes an adequate amount is upto your team, but having 100% coverage (all statements and branches) is howyou achieve very high confidence and developer peace of mind. This means thatin addition to having a great testing framework, you also need to use agood coverage tool.
There's no excuse to not write tests. There areplenty of good JS test frameworks, so find one that your team prefers.When you find one that works for your team, then aim to always write testsfor every new feature/module you introduce. If your preferred method isTest Driven Development (TDD), that is great, but the main point is to justmake sure you are reaching your coverage goals before launching any feature,or refactoring an existing one.
Kötü:
importassertfrom'assert';describe('MakeMomentJSGreatAgain',()=>{it('handles date boundaries',()=>{letdate;date=newMakeMomentJSGreatAgain('1/1/2015');date.addDays(30);assert.equal('1/31/2015',date);date=newMakeMomentJSGreatAgain('2/1/2016');date.addDays(28);assert.equal('02/29/2016',date);date=newMakeMomentJSGreatAgain('2/1/2015');date.addDays(28);assert.equal('03/01/2015',date);});});
İyi:
importassertfrom'assert';describe('MakeMomentJSGreatAgain',()=>{it('handles 30-day months',()=>{constdate=newMakeMomentJSGreatAgain('1/1/2015');date.addDays(30);assert.equal('1/31/2015',date);});it('handles leap year',()=>{constdate=newMakeMomentJSGreatAgain('2/1/2016');date.addDays(28);assert.equal('02/29/2016',date);});it('handles non-leap year',()=>{constdate=newMakeMomentJSGreatAgain('2/1/2015');date.addDays(28);assert.equal('03/01/2015',date);});});
Callbackler kusursuz değildir , ve aşırı miktarda iç içe geçmeye neden olurlar. ES2015/ES6ile birlikte Promiseler bir yerleşik evrensel tiptir. Onları kullan!
Kötü:
import{get}from'request';import{writeFile}from'fs';get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin',(istekHatasi,cevap)=>{if(requestErr){console.error(istekHatasi);}else{writeFile('makale.html',cevap.body,(yazmaHatasi)=>{if(yazmaHatasi){console.error(yazmaHatasi);}else{console.log('Dosya yazildi');}});}});
İyi:
import{get}from'request';import{writeFile}from'fs';get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin').then((cevap)=>{returnwriteFile('makale.html',cevap);}).then(()=>{console.log('Dosya yazildi');}).catch((hata)=>{console.error(hata);});
Promiseler Callbacklere nazaran daha temizdir, fakat ES2017/ES8 dahatemiz bir çözüm sunan async await'i getirdi. Tek ihtiyacınasync
önekine sahip bir fonksiyon,ve sonrasındathen
li fonksiyonlar zincirini kullanmaksızınmantığını zorunlu olarak yazabilirsin. ES2017 / ES8 özelliklerinden yararlanabiliyorsanız bunubugün kullanın!.
Kötü:
import{get}from'request-promise';import{writeFile}from'fs-promise';get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin').then((cevap)=>{returnwriteFile('makale.html',cevap);}).then(()=>{console.log('Dosya yazildi');}).catch((hata)=>{console.error(hata);});
İyi:
import{get}from'request-promise';import{writeFile}from'fs-promise';asyncfunctiontemizKodMakalesiniAl(){try{constcevap=awaitget('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');awaitwriteFile('makale.html',cevap);console.log('Dosya yazildi');}catch(hata){console.error(hata);}}
Hatalar oluşturmak iyi bir şeydir. Hatalar size programınızda bir şeylerin yolunda olmadığını söylemenin en iyi yoludur.Çalışan bir kod parçacığı ya da çalışmayı durduran bir fonksiyonun, process'in neden durduğuna dair konsol ekranında sizi bilgilendirirler.
Yakalanan bir hata ile hiçbir şey gerçekleştirmemek, size o hatayı tamamen fixlemiş olma imkanı sunmaz.Hataları (console.log
) ile göstermek, tıpkı suya yazı yazmak gibidir. Çoğu zaman yetersizdir.Eğer kod bölümlerinitry/catch
blokları ile oluşturuyorsanız o bölümde bir hatanın oluşabileceğini düşünüyorsunuzdur.Bu durumlar için bir planınız olmalı ya da bu durumları yönetebileceğiniz ayrı kod yapılarınız olmalı.
Kötü:
try{hataFirlatabilecekFonksiyon();}catch(hata){console.log(hata);}
İyi:
try{hataFirlatabilecekFonksiyon();}catch(hata){// İlk seçenek (console.log'dan daha çok bilgilendirici):console.error(hata);// Diğer Seçenek:kullaniciyaHataGoster(hata);// Diğer Seçenek:hatayiServiseBildir(hata);// Ya da üçünü de yapabilirsiniz!!}
Aynı sebepten dolayıtry/catch
'ten kaynaklanan hataları gözardı etmemelisiniz.
Kötü:
verileriGetir().then((veri)=>{fonksiyonHataFirlatabilir(veri);}).catch((hata)=>{console.log(hata);});
İyi:
verileriGetir().then((veri)=>{fonksiyonHataFirlatabilir(veri);}).catch((hata)=>{// İlk seçenek (console.log'dan daha çok bilgilendirici):console.error(hata);// Diğer Seçenek:kullaniciyaHataGoster(hata);// Diğer Seçenek:hatayiServiseBildir(hata);// Ya da üçünü de yapabilirsiniz!!});
Yazım şekli özneldir. Buradaki birçok kural gibi, uymanız gereken zor vesıkı bir kural yoktur. Yazım şekli üzerinde TARTIŞMAYIN.Bunları otomatikleştirmek içinbinlerce araç vardır.Birini kullanın! Mühendisler için, yazım şekli üzerinde tartışmak zaman ve para kaybıdır.
Otomatik formatlama kapsamına girmeyen şeyler(girintileme, tab veya boşluk, çift veya tek tırnak vb.) hakkında rehberlikiçin buraya bakın.
JavaScript'in bir yazım kuralı yoktur, bu yüzden büyük harf kullanımı size değişkenler,fonksiyonlar vb. şeyler hakkında birçok bilgi verir. Bu kurallar özneldir, yani ekibiniz istediğiniseçebilir. Önemli olan neyi seçtiğiniz değildir, seçtiğinizde tutarlı olmanızdır.
Kötü:
constHAFTANIN_GUN_SAYISI=7;constayinGunSayisi=30;constsarkilar=['Back In Black','Stairway to Heaven','Hey Jude'];constSanatcilar=['ACDC','Led Zeppelin','The Beatles'];functionveritabaniniSil(){}functionveritabanini_kurtar(){}classhayvan{}classAlpaka{}
İyi:
constHAFTANIN_GUN_SAYISI=7;constAYIN_GUN_SAYISI=30;constSARKILAR=['Back In Black','Stairway to Heaven','Hey Jude'];constSANATCILAR=['ACDC','Led Zeppelin','The Beatles'];functionveritabaniniSil(){}functionveritabaniniKurtar(){}classHayvan{}classAlpaka{}
Eğer bir fonksiyon diğerini çağırıyorsa, kodda onları dikey olarak birbirine yakın tutun. İdeal olarak, çağıran fonksiyonu çağırılanın hemen üzerinde tutun. Kodları tıpkı gazete okur gibiyukarıdan aşağıya doğru okuruz. Bu nedenle, kodunuzun bu yolda okunabilmesini sağlayın.
Kötü:
classPerformansDegerlendirmesi{constructor(calisan){this.calisan=calisan;}benzerleriniGetir(){returndb.lookup(this.calisan,'benzer');}mudurleriGetir(){returndb.lookup(this.calisan,'mudur');}benzerDegerlendirmeler(){constbenzerler=this.benzerleriniGetir();// ...}performansDegerlendirmesi(){this.benzerDegerlendirmeler();this.mudurDegerlendirmeleri();this.kendiDegerlendirmeleriGetir();}mudurDegerlendirmeleri(){constmudur=this.mudurleriGetir();}kendiDegerlendirmeleriGetir(){// ...}}constdeegrlendirme=newPerformansDegerlendirmesi(calisan);deegrlendirme.performansDegerlendirmesi();
İyi:
classPerformansDegerlendirmesi{constructor(calisan){this.calisan=calisan;}performansDegerlendirmesi(){this.benzerDegerlendirmeler();this.mudurDegerlendirmeleri();this.kendiDegerlendirmeleriGetir();}benzerDegerlendirmeler(){constbenzer=this.benzerleriniGetir();// ...}benzerleriniGetir(){returndb.lookup(this.calisan,'benzer');}mudurDegerlendirmeleri(){constmudur=this.mudurleriGetir();}mudurleriGetir(){returndb.lookup(this.calisan,'mudur');}kendiDegerlendirmeleriGetir(){// ...}}constdegerlendirme=newPerformansDegerlendirmesi(calisan);degerlendirme.performansDegerlendirmesi();
DocBlock sayesinde uygulamalarımızdaki fonksiyonlar, methodlar, sınıflar, modeller ve kontrollerin işlevlerini, değişkenlerini, geri dönüş değerlerini hatırlamamızı ve/veya kullandığımız IDElerde fonksiyonlar hakkında hızlı bilgilendirmeler almak için mutlaka öncelik verilmesi gerekiyor. Ayrıca yorum satırlarında yapılması gereken notlarımızı TODO: şeklinde tanımlamalar yaparsak en son eksik kalan yerleri hızlı hatırlamamıza yardımcı olabilir.
Kötü:
functionFaizHesapla(Anapara,Gun,YillikOran,StopajOrani){faiz=((Anapara*Gun*YillikOran)/36500)*(1-(StopajOrani/100));returnfaiz;}functionFonGetiri(Anapara,Gun,FonOrani){//var Gun=((sonTarih-ilkTarih)/(1000*60*60*24)); hücre içerisinde "01.01.2019" olunca çalışmıyor// tarih olan hücre seçildiğinde bu çalışmaktadır. ilerleyen günlerde google sheets script// araştırma yapılacakfon=(Anapara*(Gun)*(FonOrani/100));returnfon;}
İyi:
/*** Nakit Akışı Sınıfı.**@fileOverview Nakit Akışında Kullanılan Özel Fonksiyonlar Mevcuttur.*@author Sezgin BULUT*@version 1.0.1*//*** Vadeli Hesap Net Faiz Hesaplama**@link https://www.yapikredi.com.tr/bireysel-bankacilik/mevduat-urunleri/mevduat-stopaj-oranlari** Bu formül parametre olarak iletilen tutarın Net Faizini geri döndürür*@param {100.000,00} Anapara Anapara Tutarı Yazılacak*@param {5} Gun Gün Yazılacak*@param {17,25} YillikOran Yıllık Faiz Oranı Yazılacak*@param {15} StopajOrani Mevduat Stopaj Oranı Yazılacak*@return*@customfunction*/functionFaizHesapla(Anapara,Gun,YillikOran,StopajOrani){faiz=((Anapara*Gun*YillikOran)/36500)*(1-(StopajOrani/100));returnfaiz;}/*** Fon Hesaplama**@link https://www.yapikredi.com.tr/yatirimci-kosesi/fon-bilgileri** Bu formül parametre olarak iletilen tutarın Net Fon Gelirini geri döndürür*@param {1.000,00} Anapara Anapara Tutarı Yazılacak*@param {5} Gun Gün Yazılacak*@param {0,04} FonOrani Günlük Fon Getiri Oranı Yazılacak*@return*@customfunction*/functionFonGetiri(Anapara,Gun,FonOrani){// TODO: var Gun=((sonTarih-ilkTarih)/(1000*60*60*24)); hücre içerisinde "01.01.2019" olunca çalışmıyor// TODO: tarih olan hücre seçildiğinde bu çalışmaktadır. ilerleyen günlerde google sheets script araştırma yapılacakfon=(Anapara*(Gun)*(FonOrani/100));returnfon;}
Yorumlar lükstür, zorunlu değildir. İyi kodçoğunlukla kendini belli eder.
Kötü:
functionozetCikar(veri){// Özetletozet=0;// data değişkeninin uzunluğuconstuzunluk=veri.length;// veri değişkeninin her karakterini döngüye sokfor(leti=0;i<uzunluk;i++){// Karakter kodunu getirconstkarakter=veri.charCodeAt(i);// Özetini çıkarozet=((ozet<<5)-ozet)+karakter;// 32-bit'lik sayıya çevirozet&=ozet;}}
İyi:
functionozetCikar(veri){letozet=0;constuzunluk=veri.length;for(leti=0;i<uzunluk;i++){constkarakter=veri.charCodeAt(i);ozet=((ozet<<5)-ozet)+karakter;// 32-bit'lik sayıya çevirozet&=ozet;}}
Sürüm kontrol sistemleri bu nedenle var. Eski kodu geçmişinizde bırakın.
Kötü:
birSeyYap();// baskaBirSeyYap();// birazDahaBirSeyYap();// dahaFazlaBirSeyYap();
İyi:
birSeyYap();
Sürüm kontrol sistemlerini kullanmanız gerektiğini hatırlayın! Ölü koda, yorum satırına alınmış koda veözellikle günlüğe çevrilmiş yorum satırına gerek yok. Önceki yapılanları almak içingit log
komutunu kullanın!
Kötü:
/** * 2016-12-20: Monadları kaldırdım, onları anlamadım (RM) * 2016-10-01: Özel monadları kullanarak geliştirdim (JP) * 2016-02-03: Tip denetimini kaldırdım (LI) * 2015-03-14: Topla fonksiyonunu ekledim (JR) */functiontopla(a,b){returna+b;}
İyi:
functiontopla(a,b){returna+b;}
Onlar sadece kuru gürültüden ibaret. Fonksiyonlar ve değişkenlerin uygun girintilemeler,yoluyla kodunuza görsel şeklini vermesine izin verin.
Kötü:
////////////////////////////////////////////////////////////////////////////////// Scope Model Örneği////////////////////////////////////////////////////////////////////////////////$scope.model={menu:'foo',nav:'bar'};////////////////////////////////////////////////////////////////////////////////// Eylem tanımlanması////////////////////////////////////////////////////////////////////////////////consteylemler=function(){// ...};
İyi:
$scope.model={menu:'foo',nav:'bar'};consteylemler=function(){// ...};
This is also available in other languages:
Brazilian Portuguese:fesnt/clean-code-javascript
Spanish:andersontr15/clean-code-javascript
Chinese:
German:marcbruederlin/clean-code-javascript
Korean:qkraudghgh/clean-code-javascript-ko
Polish:greg-dev/clean-code-javascript-pl
Russian:
Vietnamese:hienvd/clean-code-javascript/
Japanese:mitsuruog/clean-code-javascript/
Indonesia:andirkh/clean-code-javascript/
Italian:frappacchio/clean-code-javascript/
About
JavaScript için Uyarlanmış Temiz Kod Kavramları
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Contributors11
Uh oh!
There was an error while loading.Please reload this page.