Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

JavaScript için Uyarlanmış Temiz Kod Kavramları

License

NotificationsYou must be signed in to change notification settings

foss-dev/clean-code-javascript-tr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

66 Commits
 
 
 
 

Repository files navigation

İçindekiler

  1. Giriş
  2. Değişkenler
  3. Fonksiyonlar
  4. Nesneler ve Veri Yapıları
  5. Sınıflar
  6. SOLID
  7. Test
  8. Eşzamanlılık
  9. Hata Yakalama
  10. Yazım Şekli
  11. Yorumlar
  12. Çeviriler

Giriş

Yazılım kalitesi hakkında "Bu ne ola ki" sorularından oluşan komik bir görsel.

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 :)

Değişkenler

Anlamlı ve belirli değişken isimleri kullanın

Kötü:

constyyyymmdstr=moment().format('YYYY/MM/DD');

İyi:

constmevcutTarih=moment().format('YYYY/MM/DD');

⬆ en başa dön

Aynı türde değişkenler için aynı kelimeleri kullanın

Kötü:

kullaniciBilgisiGetir();musteriVerisiGetir();musteriKayitlariGetir();

İyi:

kullaniciGetir();

⬆ en başa dön

Aranabilir isimler kullanın

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);

⬆ en başa dön

Açıklayıcı değişkenler kullanın

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);

⬆ en başa dön

Zihinsel Haritalamadan Kaçının

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);});

⬆ en başa dön

Gereksiz içerik eklemeyin

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ı';}

⬆ en başa dön

Kısa Mantıksal İfadeler ya da Koşullar Yerine Varsayılan Argümanlar Kullanın

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Ş'){// ...}

⬆ en başa dön

Fonksiyonlar

Fonksiyon Argümanları (İdeal olanı 2 ya da daha az)

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:

  1. Dışarıdan birisi fonksiyon iskeletine baktığı zaman, fonksiyonun dışarıdan aldığıözellikleri kolayca anlayabilir.
  2. 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.
  3. 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});

⬆ en başa dön

Fonksiyonlar Tek Bir Şey Yapmalı

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();}

⬆ en başa dön

Fonksiyon İsimleri Ne Yaptıklarını Söylemeli

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);

⬆ en başa dön

Fonksiyonlar bir seviye soyutlaştırılmalıdır

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;}

⬆ en başa dön

Yinelenen kodu kaldırın

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);});}

⬆ en başa dön

Varsayılan Nesneleri Object.assign ile Atayın!

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);

⬆ en başa dön

Bayrakları Fonksiyon Argümanları Olarak Kullanmayın

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}`);}

⬆ en başa dön

Yan Etkilerden Kaçının (Kısım 1)

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'];

⬆ en başa dön

Avoid Side Effects (part 2)

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:

  1. 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!

  2. 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()}];};

⬆ en başa dön

Global fonksiyonlar yazma.

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));}}

⬆ en başa dön

Emirli programlama yerine Fonksiyonel programlamayı tercih edin

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);

⬆ en başa dön

Encapsulate conditionals

Kötü:

if(fsm.state==='fetching'&&isEmpty(listNode)){// ...}

İyi:

functionshouldShowSpinner(fsm,listNode){returnfsm.state==='fetching'&&isEmpty(listNode);}if(shouldShowSpinner(fsmInstance,listNodeInstance)){// ...}

⬆ en başa dön

Negatif Koşullardan Kaçının

Kötü:

functiondomYaratilmadi(node){// ...}if(!domYaratilmadi(node)){// ...}

İyi:

functiondomYaratildi(node){// ...}if(domYaratildi(node)){// ...}

⬆ en başa dön

Koşullardan Kaçının

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();}}

⬆ en başa dön

Tip Kontrolünden Kaçının (Bölüm 1)

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'));}

⬆ en başa dön

Tip Kontrolünden Kaçının (Bölüm 2)

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;}

⬆ en başa dön

Aşırı Optimizasyon Yapmayın

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++){// ...}

⬆ en başa dön

Ölü Kodları Silin

Ö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');

⬆ en başa dön

Nesneler ve Veri Yapıları

Setter ve Getter kullanın

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);

⬆ en başa dön

Nesnelerin private üyelere sahip olmasını sağlayın.

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

⬆ en başa dön

Sınıflar

Yalın ES5 fonksiyonları yerine ES2015/ES6 sınıflarını tercih edin

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(){/* ... */}}

⬆ en başa dön

Metod zincirleme yöntemini kullanın

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();

⬆ en başa dön

Miras(Kalıtım) yerine Kompozisyonu tercih edin

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.

  1. 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ı)
  2. Kodu temel sınıflardan yeniden kullanabilirsiniz. (İnsanlar, tüm hayvanlar gibi hareket edebilir)
  3. 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);}// ...}

⬆ en başa dön

SOLID

Tek Sorumluluk Prensibi (TSP)

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()){// ...}}}

⬆ en başa dön

Açık/Kapalı Prensibi

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});}}

⬆ en başa dön

Liskov Yer Değiştirme Prensibi (LSP)

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);

⬆ en başa dön

Interface Segregation Principle (ISP)

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(){}}});

⬆ en başa dön

Dependency Inversion Principle (DIP)

This principle states two essential things:

  1. High-level modules should not depend on low-level modules. Both shoulddepend on abstractions.
  2. 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();

⬆ en başa dön

Testing

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.

Single concept per test

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);});});

⬆ en başa dön

Eşzamanlılık

Promiseleri kullan,Callbackleri değil.

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);});

⬆ en başa dön

Async/Await ,Promise'den daha temizdir.

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ındathenli 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);}}

⬆ en başa dön

Hata Yakalama

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 Hataları Görmezden Gelmeyin

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!!}

Promise Hatalarını Görmezden Gelmeyin

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!!});

⬆ en başa dön

Yazım Şekli

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.

Büyük harf kullanımınız tutarlı olsun

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{}

⬆ en başa dön

Çağırılan ve çağıran fonksiyonlar birbirine yakın olmalıdır.

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();

⬆ en başa dön

Javascript Dökümantasyon Kurallarına uyulmalı.

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;}

⬆ en başa dön

Yorumlar

Sadece iş mantığının karmaşık olduğu durumlarda yorumları kullanın.

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;}}

⬆ en başa dön

Kod tabanınızda yorum satırına alınmış kod bırakmayın.

Sürüm kontrol sistemleri bu nedenle var. Eski kodu geçmişinizde bırakın.

Kötü:

birSeyYap();// baskaBirSeyYap();// birazDahaBirSeyYap();// dahaFazlaBirSeyYap();

İyi:

birSeyYap();

⬆ en başa dön

Yorum satırını günlüğe çevirmeyin

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;}

⬆ en başa dön

Konum işaretleyicilerini kullanmaktan kaçının

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(){// ...};

⬆ en başa dön

Translation

This is also available in other languages:

⬆ en başa dön

About

JavaScript için Uyarlanmış Temiz Kod Kavramları

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors11


[8]ページ先頭

©2009-2025 Movatter.jp