Dark Mode

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

foss-dev/clean-code-javascript-tr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

66 Commits

Repository files navigation

clean-code-javascript-tr

Icindekiler

  1. Giris
  2. Degiskenler
  3. Fonksiyonlar
  4. Nesneler ve Veri Yapilari
  5. Siniflar
  6. SOLID
  7. Test
  8. Eszamanlilik
  9. Hata Yakalama
  10. Yazim Sekli
  11. Yorumlar
  12. Ceviriler

Giris

Yazilim muhendisligi prensipleri, Robert C. Martin'in Clean Code isimli kitabindan alinmis, JavaScript icin uyarlanmistir. Bu bir stil rehber degildir. Bu JavaScript ile readable, reusable, ve refactorable yazilimlar uretmek icin bir rehberdir..

Burada yazilan prensiplere siki bir sekilde uymaniz gerekmez belki bazi kurallar herkesce kabul edilecektir. Burada yazanlar kurallar ve daha fazlasi degil. Ancak bu kurallar Clean Code yazarlarinin uzun yillara dayanan deneyimleri sonucu ortaya ciktigi icin dikkate almaniz iyi olabilir.

Yazilim muhendisligi konusundaki calismalarimiz 50 yilin biraz uzerinde ve hala cok fazla sey ogreniyoruz. Yazilim mimarisi, mimarligin kendisi kadar eski oldugunda belki de uyulmasi gereken daha zor kurallara sahip olacagiz. Simdilik, bu kilavuzlarin sizin ve ekibinizin urettigi JavaScript kodunun kalitesini degerlendirmek icin bir mihenk tasi olarak hizmet etmesine izin verin.

Son bir sey daha: Bunlari biliyor olmak sizi hemen mukemmel bir yazilim gelistirici yapmaz ve bu kurallari bilerek gecirdiginiz yillar hata yapmayacaginiz anlamina da gelmez. Her kod parcasi bir taslak olarak baslar, tipki islak bir kilin son halini almasi gibi de devam eder. Son olarak takim arkadaslarimizla incelemeler yaparken kotu gorunen kisimlari yok eder. Gelisime ihtiyaci olan kodun ilk hali icin kendinize kizmayin. Bunun yerine kodu dovun :)

Degiskenler

Anlamli ve belirli degisken isimleri kullanin

Kotu:

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

Iyi:

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

en basa don

Ayni turde degiskenler icin ayni kelimeleri kullanin

Kotu:

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

Iyi:

kullaniciGetir();

en basa don

Aranabilir isimler kullanin

Yazacagimizdan daha fazla kod okuyacagiz. Bu yazdigimiz kodun okunabilir ve aranabilir olmasi acisindan onemlidir. Degiskenleri kotu bir sekilde adlandirmayarak programimizi anlamaya calisan kod okuyucularina zarar vermeyiz. Isimleri aranabilir yapin. buddy.js ve ESLint gibi araclar tanimlanmamis sabit degerleri constant olarak tanimlamaniza yardimci olabilir.

Kotu:

// Bu 86400000 ne olabilir??
setTimeout(havalandirmayiCalistir, 86400000);

Iyi:

// Bu turden tanimlamalari buyuk harfler ve alt cizgiler icerecek sekilde belirtin.
const BIR_GUNDEKI_MILISANIYELER = 86400000;

setTimeout(havalandirmayiCalistir, BIR_GUNDEKI_MILISANIYELER);

en basa don

Aciklayici degiskenler kullanin

Kotu:

const adres = 'Kirec Burnu Sahili, Sariyer 34400';
const sehirPostaKoduRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
sehirPostaKodunuKaydet(adres.match(sehirPostaKoduRegex)[1], adres.match(sehirPostaKoduRegex)[2]);

Iyi:

const adres = 'Kirec Burnu Sahili, Sariyer 34400';
const sehirPostaKoduRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
const [, sehir, postaKodu] = adres.match(sehirPostaKoduRegex) || [];
sehirPostaKodunuKaydet(sehir, postaKodu);

en basa don

Zihinsel Haritalamadan Kacinin

Acik olan kapali olandan daha iyidir

Kotu:

{ birSeylerYap(); baskaBirSeyYap(); // ... // ... // ... // Bekle bi dk.. Bu l nedir? oneCikar(l); });">const lokasyonlar = ['Ankara', 'Istanbul', 'Izmir'];
lokasyonlar.forEach((l) => {
birSeylerYap();
baskaBirSeyYap();
// ...
// ...
// ...
// Bekle bi dk.. Bu l nedir?
oneCikar(l);
});

Iyi:

{ birSeylerYap(); baskaBirSeyYap(); // ... // ... // ... oneCikar(lokasyon); });">const lokasyonlar = ['Ankara', 'Istanbul', 'Izmir'];
lokasyonlar.forEach((lokasyon) => {
birSeylerYap();
baskaBirSeyYap();
// ...
// ...
// ...
oneCikar(lokasyon);
});

en basa don

Gereksiz icerik eklemeyin

Eger sinif ya da nesne adindan ne yaptigi anlasiliyorsa, tekrar olarak degiskenler icinde onu anlatan isimlendirmeler yapmayin.

Kotu:

const Araba = {
arabaUret: 'Honda',
arabaModeli: 'Accord',
arabaRengi: 'Mavi'
};

function arabayiBoya(araba) {
araba.arabaRengi = 'Kirmizi';
}

Iyi:

const Araba = {
uret: 'Honda',
model: 'Accord',
renk: 'Mavi'
};

function arabayiBoya(araba) {
araba.renk = 'Kirmizi';
}

en basa don

Kisa Mantiksal Ifadeler ya da Kosullar Yerine Varsayilan Argumanlar Kullanin

Varsayilan argumanlar cogunlukla kisa mantiksa ifadelerden daha temiz bir kullanima sahiptir. Varsayilan argumanlarin sadece undefined argumanlar gecerliyse calisacagini unutmayin. Diger falsy olarak kabul edilen degerler varsayilan argumani degistirecektir. Bunlar '', "", false, null, 0, ve NaN olarak gosterilebilir.

Kotu:

function fabrikaOlustur(isim) {
const fabrikaAdi = isim || 'Onceki Yazilimci AS';
// ...
}

Iyi:

function fabrikaOlustur(isim = 'Onceki Yazilimci AS') {
// ...
}

en basa don

Fonksiyonlar

Fonksiyon Argumanlari (Ideal olani 2 ya da daha az)

Fonksiyonlarin aldigi argumanlari sinirlandirmak fonksiyonun test edilebilirligi acisindan oldukca onemlidir. Ucten fazla argumana sahip bir fonksiyonu test etmeniz gerektiginde, her bir durumu her bir argumanla ayri ayri test edeceginizden dolayi tonlarca teste maruz kalabilirsiniz.

Bir veya iki arguman normal olan durumdur, mumkun oldugunca ucuncuden kacinilmadilir. Bundan daha fazla olanlar iyilestirilmelidir. Eger fonksiyonunuz ikiden fazla arguman aliyorsa, muhtemelen yapmasi gerekenden fazla isi yapmaya calisiyordur. Daha fazla argumana ihtiyaciniz oldugu durumlarda daha kapsamli bir nesne kullanmak yeterli olacaktir.

Javascript size aninda nesne olusturma kabiliyetini verdiginden dolayi, daha fazla argumana ihtiyac duydugunuz durumlarda; herhangi bir sinif uretmeye gerek kalmadan nesneler icerisinde argumanlarinizi gonderebilirsiniz.

Fonksiyonun bekledigi argumanlari garantilemek icin ES2015/ES6 ile gelen yikim islemi (destructuring) sozdizimini kullanabilirsiniz. Bunun birkac avantaji var:

  1. Disaridan birisi fonksiyon iskeletine baktigi zaman, fonksiyonun disaridan aldigi ozellikleri kolayca anlayabilir.
  2. Yikim islemi (destructuring) ayni zamanda nesne icerisinde gonderilen ilkel degerleri klonlar. Bu yan etkilerin engellenmesinde yardimci olur. Not: Arguman nesneleri tarafindan yikima ugratilmis (destruct edilmis) nesne ve dizi degerleri klonlanmaz.
  3. Linterlar sizi kullanilmayan degerler icin uyarabilir, ki bu durumu yikim ("destruct") islemi olmadan yapmaniz mumkun degildir.

Kotu:

function menuOlustur(baslik, icerik, butonIcerik, iptalEdilebilir) {
// ...
}

Iyi:

function menuOlustur({ baslik, icerik, butonIcerik, iptalEdilebilir }) {
// ...
}

menuOlustur({
baslik: 'Takip Et',
icerik: 'Kullanici takip edilsin mi?',
butonIcerik: 'TAKIP ET',
iptalEdilebilir: true
});

en basa don

Fonksiyonlar Tek Bir Sey Yapmali

Bu yazilim muhendisliginde en onemli kuraldir. Fonksiyonlar birden fazla is yaptiginda, onlari duzenlemek, test etmek ve hakkinda fikir sahibi olmak oldukca zorlasir. Bir fonksiyonu izole ettiginizde, daha kolay refactor edilebilir ve daha temiz, okunabilir bir kod haline gelir. Bu kilavuzdan aldiginiz tek bilgi bu olsa bile bircok gelistiricinin onunde olacaksiniz.

Kotu:

function musterilereMailYolla(musteriler) {
musteriler.forEach((musteri) => {
const musteriKaydi = database.sorgula(musteri);
if (musteriKaydi.aktifMi()) {
email(musteri);
}
});
}

Iyi:

function aktifMusterilereEmailGonder(musteriler) {
musteriler
.filter(aktifMusteriMi)
.forEach(email);
}

function aktifMusteriMi(musteri) {
const musteriKaydi = database.sorgula(musteri);
return musteriKaydi.aktifMi();
}

en basa don

Fonksiyon Isimleri Ne Yaptiklarini Soylemeli

Kotu:

function tariheEkle(tarih, ay) {
// ...
}

const tarih = new Date();

// Fonkisyon adina bakarak neyin eklendigini anlamak zor
tariheEkle(tarih, 1);

Iyi:

function tariheAyEkle(ay, tarih) {
// ...
}

const tarih = new Date();
tariheAyEkle(1, tarih);

en basa don

Fonksiyonlar bir seviye soyutlastirilmalidir

Fonkiyonunuz bir seviyeden fazla soyutlasmis ise, gereginden fazla is yapiyor demektir. Fonksiyonlarinizi gorevlerine gore kucuk parcalara bolmek geri kullanilabilirlik ve kolay test edilebilirlik acisindan onemlidir.

Kotu:

{ kodParcaciklari.forEach((kodParcacigi) => { // ... }); }); const ast = []; simgeler.forEach((simge) => { // lex... }); ast.forEach((node) => { // donustur... }); }">function dahaIyiJSAlternatifineDonustur(kod) {
const REGEXLER = [
// ...
];

const kodParcaciklari = kod.split(' ');
const simgeler = [];
REGEXLER.forEach((REGEX) => {
kodParcaciklari.forEach((kodParcacigi) => {
// ...
});
});

const ast = [];
simgeler.forEach((simge) => {
// lex...
});

ast.forEach((node) => {
// donustur...
});
}

Iyi:

{ kodParcaciklari.forEach((kodParcacigi) => { simgeler.push( /* ... */ ); }); }); return simgeler; } function analizEt(simgeler) { const ast = []; simgeler.forEach((simge) => { ast.push( /* ... */ ); }); return ast; }">function dahaIyiJSAlternatifineDonustur(kod) {
const simgeler = simgelestir(kod);
const ast = analizEt(simgeler);
ast.forEach((node) => {
// donustur...
});
}

function simgelestir(kod) {
const REGEXLER = [
// ...
];

const kodParcaciklari = kod.split(' ');
const simgeler = [];
REGEXLER.forEach((REGEX) => {
kodParcaciklari.forEach((kodParcacigi) => {
simgeler.push( /* ... */ );
});
});

return simgeler;
}

function analizEt(simgeler) {
const ast = [];
simgeler.forEach((simge) => {
ast.push( /* ... */ );
});

return ast;
}

en basa don

Yinelenen kodu kaldirin

Yinelenen kodu kaldirmak icin elinizden gelenin en iyisini yapin. Tekrarlanan kodun kotu olma nedeni, kodunuzda mantiksal bir durumu degistirmeye calistiginizda bunu birden fazla yerde yapmanizi gerektirmesidir. Bu da oldukca hataya elverisli bir durumdur.

Bir restoran islettiginizi ve icinde domates, sogan, biber, sarimsak vs. olan bir deponuz oldugunu ve deponuzu takip ettiginizi dusunun. Eger bu is icin birden fazla liste tutarsaniz, en ufak bir servisinizde tum listeleri yeniden guncellemeniz gerekecektir. Eger tek bir listeniz olursa tek bir noktadan tum listeyi yonetebilirsiniz

Cogu zaman kod tekrarina dusersiniz. Cunku iki veya daha fazla kucuk farkliligi olan ama cogunlukla ayni ozellikleri tasiyan iki fonksiyon sizi bu kucuk nedenlerden dolayi cogunlukla ayni ozelliklere sahip olan ve temelde ayni isi yapan iki farkli fonksiyon yazmaya zorlar. Tekrarlayan kodu kaldirmak demek; bu farkliliklari farkli bir yerde yerine getirebilecek soyut fonksiyonlar, moduller, siniflar yazmak demektir.

Soyutlamayi dogru yapmak cok kritikdir. Bu yuzden devam eden kisimlardan Siniflar kismindaki KATI kurallari takip etmelisiniz. Kotu soyutlamalar kod tekrarindan da kotudur. Bu yuzden dikkatli olmalisiniz. Iyi bir soyutlama yapabilirim diyorsaniz bunu yapin. Kendinizi tekrar etmeyin, aksi takdirde kendinizi birden fazla yeri guncellerken bulacaksiniz.

Kotu:

function gelistiriciListesiniGoster(gelistiriciler) {
gelistiriciler.forEach((gelistirici) => {
const beklenenMaas = gelistirici.beklenenMaasiHesapla();
const deneyim = gelistirici.deneyimiGetir();
const githubLink = gelistirici.githubLink();
const veri = {
beklenenMaas,
deneyim,
githubLink
};

yazdir(veri);
});
}

function yoneticiListesiniGoster(yoneticiler) {
yoneticiler.forEach((yonetici) => {
const beklenenMaas = yonetici.beklenenMaasiHesapla();
const deneyim = yonetici.deneyimiGetir();
const portfolio = yonetici.projeleriniGetir();
const veri = {
beklenenMaas,
deneyim,
portfolio
};

yazdir(veri);
});
}

Iyi:

function personelListesiniGoster(personeller) {
personeller.forEach((personel) => {
const beklenenMaas = personel.beklenenMaasiHesapla();
const deneyim = personel.deneyimiGetir();

const veri = {
beklenenMaas,
deneyim
};

switch (personel.tip) {
case 'yonetici':
veri.portfolio = personel.projeleriniGetir();
break;
case 'developer':
veri.githubLink = personel.githubLink();
break;
}

yazdir(veri);
});
}

en basa don

Varsayilan Nesneleri Object.assign ile Atayin!

Kotu:

const menuAyari = {
baslik: null,
icerik: 'Deneme',
butonYazisi: null,
iptalEdilebilir: true
};

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

Iyi:

const menuAyari = {
baslik: 'Bir Baslik',
// Gelistirici 'icerik' key'ini burada belirtmedi
butonYazisi: 'Kaydet',
iptalEdilebilir: true
};

function menuOlustur(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 basa don

Bayraklari Fonksiyon Argumanlari Olarak Kullanmayin

Bayraklar gelistiriciye fonksiyonun birden fazla sey yaptigini soyler. Fonksiyonlar sadece bir is yapmalidir. Eger fonksiyonlariniz boolean degere dayali olarak farkli kodlar calistiriyorsa onlari bolun.

Kotu:

function dosyaOlustur(isim, gecici) {
if (gecici) {
fs.create(`./gecici/${isim}`);
} else {
fs.create(isim);
}
}

Iyi:

function dosyaOlustur(isim) {
fs.create(isim);
}

function geciciDosyaOlustur(isim) {
dosyaOlustur(`./temp/${isim}`);
}

en basa don

Yan Etkilerden Kacinin (Kisim 1)

Bir fonksiyon, deger alip baska deger veya degerler dondurmek disinda bir sey yapiyorsa yan etki olusturur. Bu yan etki, dosyalara bir seyler yazmak, bazi global degiskenleri degistirmek, guncellemek veya yanlislikla butun paranizi bir yabanciya aktarmak olabilir.

Zaman zaman yazdiginiz programda yan etkilerin olmasi gerekir. Mesela, bir onceki ornekte islenildigi gibi dosyalara bir seyler yazmaniz gerekebilir. Yapmaniz gereken sey ise yan etki olusturan islemleri yaptiginiz yeri merkezilestirmektir. Ornegin belirli bir dosya uzerinde islem yapan birkac fonksiyon veya sinifiniz olmasin. Sadece bir servis bunu yapsin. Evet, sadece bir servis.

Buradaki ana fikir, herhangi bir yapiya sahip olmayan nesneler arasindaki stateleri paylasmak, herhangi bir sey tarafindan degistirilebilir veri tiplerini kullanmak veya yan etkilerin olustugu yerleri merkezilestirmemek gibi yaygin hatalardan kacinmaktir. Eger bunlari yapabilirseniz, diger programcilarin buyuk bir cogunlugundan daha mutlu olacaksiniz.

Kotu:

// 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.
let isim = 'Ali Veli';

function isimVeSoyismiAyir() {
isim = isim.split(' ');
}

isimVeSoyismiAyir();

console.log(isim); // ['Ali', 'Veli'];

Iyi:

function isimVeSoyismiAyir(isim) {
return isim.split(' ');
}

const isim = 'Ali Veli';
const yeniIsim = isimVeSoyismiAyir(isim);

console.log(isim); // 'Ali Veli';
console.log(yeniIsim); // ['Ali', 'Veli'];

en basa don

Avoid Side Effects (part 2)

In JavaScript, primitives are passed by value and objects/arrays are passed by reference. In the case of objects and arrays, if your function makes a change in a shopping cart array, for example, by adding an item to purchase, then any other function that uses that cart array will be affected by this addition. That may be great, however it can be bad too. Let's imagine a bad situation:

The user clicks the "Purchase", button which calls a purchase function that spawns a network request and sends the cart array to the server. Because of a bad network connection, the purchase function has to keep retrying the request. 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 function will send the accidentally added item because it has a reference to a shopping cart array that the addItemToCart function modified by adding an unwanted item.

A great solution would be for the addItemToCart to always clone the cart, edit it, and return the clone. This ensures that no other functions that are holding 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 cases are 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 are great libraries that allow this kind of programming approach to be fast and not as memory intensive as it would be for you to manually clone objects and arrays.

Kotu:

const addItemToCart = (cart, item) => {
cart.push({ item, date: Date.now() });
};

Iyi:

const addItemToCart = (cart, item) => {
return [...cart, { item, date: Date.now() }];
};

en basa don

Global fonksiyonlar yazma.

Javascript'te globalleri kirletmek kotu bir uygulamadir cunku diger bir kutuphaneyle cakisabilirsiniz ve API kullaniciniz uygulamayi canli ortama sundugunda alacagi bir hataya kadar bu durumdan haberdar olmayabilir. Bir ornek uzerinden dusunelim: eger JavaScript'in sahip oldugu Array metodunu, iki dizi arasindaki farki gosteren bir diff metoduna sahip olacak sekilde genisletmek isteseydik? Array.prototype a yeni bir fonksiyon yazabilirsin, ama bu, ayni seyi yapmaya calisan baska bir kutuphane ile cakisabilir. Ya baska bir kutuphane diff metodunu, bir dizinin ilk elemani ile son elemani arasindaki farki bulmak icin kullaniyor olsaydi? Bu yuzden ES2015/ES6 siniflarini kullanmak ve basitce Array i kalitimla almak cok daha iyi olacaktir.

Kotu:

Array.prototype.diff = function diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
};

Iyi:

class SuperArray extends Array {
diff(comparisonArray) {
const hash = new Set(comparisonArray);
return this.filter(elem => !hash.has(elem));
}
}

en basa don

Emirli programlama yerine Fonksiyonel programlamayi tercih edin

JavaScript, Haskell gibi fonksiyonel bir dil degil ama fonksiyonel yonleri de var. Fonksiyonel diller daha temiz ve test edilmesi daha kolay olabilir. Yapabildiginiz zaman bu programlama stilini tercih edin.

Kotu:

const programciCiktisi = [
{
name: 'Uncle Bobby',
kodSatirlari: 500
}, {
name: 'Suzie Q',
kodSatirlari: 1500
}, {
name: 'Jimmy Gosling',
kodSatirlari: 150
}, {
name: 'Gracie Hopper',
kodSatirlari: 1000
}
];

let toplamCikti = 0;

for (let i = 0; i < programciCiktisi.length; i++) {
toplamCikti += programciCiktisi[i].kodSatirlari;
}

Iyi:

cikti.kodSatirlari) .reduce((toplamSatirlar, satirlar) => toplamSatirlar + satirlar);">const programciCiktisi = [
{
name: 'Uncle Bobby',
kodSatirlari: 500
}, {
name: 'Suzie Q',
kodSatirlari: 1500
}, {
name: 'Jimmy Gosling',
kodSatirlari: 150
}, {
name: 'Gracie Hopper',
kodSatirlari: 1000
}
];

const toplamCikti = programciCiktisi
.map(cikti => cikti.kodSatirlari)
.reduce((toplamSatirlar, satirlar) => toplamSatirlar + satirlar);

en basa don

Encapsulate conditionals

Kotu:

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

Iyi:

function shouldShowSpinner(fsm, listNode) {
return fsm.state === 'fetching' && isEmpty(listNode);
}

if (shouldShowSpinner(fsmInstance, listNodeInstance)) {
// ...
}

en basa don

Negatif Kosullardan Kacinin

Kotu:

function domYaratilmadi(node) {
// ...
}

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

Iyi:

function domYaratildi(node) {
// ...
}

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

en basa don

Kosullardan Kacinin

Bu imkansiz bir is gibi guzukuyor. Cogu insan bunu ilk duydugu ana kadar, " if ifadesi olmadan nasil bir sey yapabilirim? " diyor. Bunun cevabi, bircok durumda ayni isi yapmak icin polymorphism kullanabilirsiniz. Genellikle ikinci soru, "iyi guzel ama neden bunu yapmayi isteyeyim ki?" Bunun cevabi ise ogrendigimiz onceki temiz kod konsepti olan: bir fonksiyon yalnizca bir sey yapmalidir. if ifadesine sahip olan siniflariniz ve fonksiyonlariniz oldugunda, kullanicilariniza fonksiyonunuzun birden fazla sey yaptigini soyluyorsunuz. Hatirla, sadece bir sey yap.

Kotu:

class Ucak {
// ...
seyirYuksekliginiGetir() {
switch (this.type) {
case '777':
return this.maxYuksekligiGetir() - this.yolcuSayisiniGetir();
case 'Air Force One':
return this.maxYuksekligiGetir();
case 'Cessna':
return this.maxYuksekligiGetir() - this.yakitHarcamasiniGetir();
}
}
}

Iyi:

class Ucak {
// ...
}

class Boeing777 extends Ucak {
// ...
seyirYuksekliginiGetir() {
return this.maxYuksekligiGetir() - this.yolcuSayisiniGetir();
}
}

class AirForceOne extends Ucak {
// ...
seyirYuksekliginiGetir() {
return this.maxYuksekligiGetir();
}
}

class Cessna extends Ucak {
// ...
seyirYuksekliginiGetir() {
return this.maxYuksekligiGetir() - this.yakitHarcamasiniGetir();
}
}

en basa don

Tip Kontrolunden Kacinin (Bolum 1)

JavaScript tip guvensiz bir dildir, yani fonksiyonlariniz herhangi bir tipte arguman alabilir. Bazen bu ozgurluk can yakici olabiliyor haliyle fonksiyonlarinizda tip kontrolu yapmak cazip hale gelebiliyor. Bundan kacinmanin bircok yolu var. Dikkate alinmasi gereken ilk sey tutarli API'lar yazmaniz.

Kotu:

function nigdeyeZiyaret(arac) {
if (arac instanceof Bisiklet) {
arac.pedaliCevir(this.mevcutLokasyon, new Lokasyon('nigde'));
} else if (arac instanceof Araba) {
arac.sur(this.mevcutLokasyon, new Lokasyon('nigde'));
}
}

Iyi:

function nigdeyeZiyaret(arac) {
arac.hareketEt(this.mevcutLokasyon, new Lokasyon('nigde'));
}

en basa don

Tip Kontrolunden Kacinin (Bolum 2)

Eger strginler ve integerlar gibi temel ilkel degerlerle calisiyorsaniz ve polymorphism kullanamiyorsaniz ama hala tip kontrolu yapmaniz gerekiyormus gibi hissediyorsaniz TypeScript kullanmayi dusunmelisiniz. TypeScript, normal JavaScript'in mukkemel bir alternatifi, standart Javascript soz diziminin uzerine statik yazmanizi saglar. Normal JavaScript'te manuel sekilde tip kontrolu yapmanin problemi, tip kontrlunu iyi yapmak ekstra kod kalabaligini gerektiriyor. Yapmaya calistigimiz sahte "tip kontrolu" kaybolan okunabilirligi telafi etmiyor. JavaScript kodlarinizi temiz tutun, iyi testler yazin ve rahat kod incelemelerine sahip olun. Ayrica, hepsini yap ama TypeScript ile yap (dedigim gibi, harika bir alternatif).

Kotu:

function kombin(deger1, deger2) {
if (typeof deger1 === 'number' && typeof deger2 === 'number' ||
typeof deger1 === 'string' && typeof deger2 === 'string') {
return val1 + val2;
}

throw new Error('String veya Number tipinde olmalidir!');
}

Iyi:

function kombin(deger1, deger2) {
return deger1 + deger2;
}

en basa don

Asiri Optimizasyon Yapmayin

Modern tarayicilar calisma aninda arkaplanda cok fazla optimizasyon yaparlar. Cogu zaman yaptiginiz optimizasyon, bosa zaman harcamaktir. Optimzasyonun nerede eksik oldugunu gormek icin bu kaynaklar iyidir.

Kotu:

// Eski tarayicilarda `list.length` icin onbellege alinmamis her yineleme maliyetlidir.
// Cunku `list.length` her defasinda yeniden sayilir. Modern tarayicilarda bu optimize edilmistir.
for (let i = 0, len = liste.length; i < len; i++) {
// ...
}

Iyi:

for (let i = 0; i < liste.length; i++) {
// ...
}

en basa don

Olu Kodlari Silin

Olu kod da tekrarli kodlar kadar kotudur. Kodlarinizda olu kod saklamaniz icin herhangi bir neden yoktur. Eger herhangi bir yerde cagrilmiyorlarsa onlardan kurtulun. Ihtiyaciniz oldugunda, versiyon kontrol sisteminde bulabilirsiniz.

Kotu:

function eskiHttpRequestModulu(url) {
// ...
}

function yeniHttpRequestModulu(url) {
// ...
}

const istek = yeniHttpRequestModulu;
envanterTakibi('elmalar', istek, 'www.envantertakibi.com');

Iyi:

function yeniHttpRequestModulu(url) {
// ...
}

const istek = yeniHttpRequestModulu;
envanterTakibi('elmalar', istek, 'www.envantertakibi.com');

en basa don

Nesneler ve Veri Yapilari

Setter ve Getter kullanin

Nesnelerdeki verilere erismek icin Setter ve Getter kullanmak sadece bir nesnedeki ozellikleri aramaktan daha iyi olabilir. "Neden?" diye soracaksiniz. Peki, iste burada sebeplerinin bir listesi var:

  • Bir nesne ozelligini elde etmekten daha fazla sey yapmak istediginizde kod tabaninizdaki her erisimciyi aramaniz ve degistirmeniz gerekmez.
  • set islemi yaparken dogrulama eklemeyi kolaylastirir.
  • Ic temsili kapsuller.
  • Set ve Get islemlerini gerceklestirirken kayit tutmayi (log) ve hata yakalamayi eklemek kolaydir.
  • Nesnenizin ozelliklerini sunucudan alirken Lazy Load kullanabilirsiniz.

Kotu:

function bankaHesabiOlustur() {
// ...

return {
bakiye: 0,
// ...
};
}

const hesap = bankaHesabiOlustur();
hesap.bakiye = 100;

Iyi:

function bankaHesabiOlustur() {
// bu private
let bakiye = 0;

//Getter asagida dondurulen nesne araciligiyla public hale getirildi
function getBakiye() {
return bakiye;
}

// Setter asagida dondurulen nesne araciligiyla public hale getirildi
function setBakiye(deger) {
// ... bakiyeyi guncellemeden once onaylar
bakiye = deger;
}

return {
// ...
getBakiye,
setBakiye,
};
}

const hesap = bankaHesabiOlustur();
hesap.setBakiye(100);

en basa don

Nesnelerin private uyelere sahip olmasini saglayin.

Bu, kapamalarla(closures) gerceklestirilebilir. (ES5 ve alti icin).

Kotu:

const Calisan = function(isim) {
this.isim = isim;
};

Calisan.prototype.getIsim = function getIsim() {
return this.isim;
};

const calisan = new calisan('John Doe');
console.log(`Calisanin ismi: ${calisan.getIsim()}`); // Calisanin ismi: John Doe
delete calisan.isim;
console.log(`Calisanin ismi: ${calisan.getIsim()}`); // Calisanin ismi: undefined

Iyi:

function calisanOlustur(isim) {
return {
getIsim() {
return isim;
},
};
}

const calisan = calisanOlustur('John Doe');
console.log(`Calisanin ismi: ${calisan.getIsim()}`); // Calisanin ismi: John Doe
delete calisan.isim;
console.log(`Calisanin ismi: ${calisan.getIsim()}`); // Calisanin ismi: John Doe

en basa don

Siniflar

Yalin ES5 fonksiyonlari yerine ES2015/ES6 siniflarini tercih edin

Klasik ES5 siniflari icin okunabilir sinif kalitimlari, construction ve metod tanimlarini almak cok zordur. Eger kalitima ihtiyaciniz varsa (ihtiyacinizin olmayabileceginin farkinda olun), o zaman ES2015/ES6 siniflarini tercih edin. Ancak, daha buyuk ve karmasik nesnelerle ugrasana kadar siniflar yerine kucuk fonksiyonlari kullanin.

Kotu:

const Animal = function(age) {
if (!(this instanceof Animal)) {
throw new Error('Instantiate Animal with `new`');
}

this.age = age;
};

Animal.prototype.move = function move() {};

const Mammal = function(age, furColor) {
if (!(this instanceof Mammal)) {
throw new Error('Instantiate Mammal with `new`');
}

Animal.call(this, age);
this.furColor = furColor;
};

Mammal.prototype = Object.create(Animal.prototype);
Mammal.prototype.constructor = Mammal;
Mammal.prototype.liveBirth = function liveBirth() {};

const Human = function(age, furColor, languageSpoken) {
if (!(this instanceof Human)) {
throw new Error('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 = function speak() {};

Iyi:

class Animal {
constructor(age) {
this.age = age;
}

move() { /* ... */ }
}

class Mammal extends Animal {
constructor(age, furColor) {
super(age);
this.furColor = furColor;
}

liveBirth() { /* ... */ }
}

class Human extends Mammal {
constructor(age, furColor, languageSpoken) {
super(age, furColor);
this.languageSpoken = languageSpoken;
}

speak() { /* ... */ }
}

en basa don

Metod zincirleme yontemini kullanin

Bu yontem JavaScript'te cok kullanislidir ve bunu jQuery ve Lodash gibi bircok kutuphanede gorebilirsiniz. Kodunuzun daha anlamli ve daha az detayli olmasini saglar. Bu nedenle, metod zincirleme yontemini bir kez kullanin ve kodunuzun ne kadar temiz olacagina bir goz atin derim. Sinif fonksiyonlarinda basitce her fonksiyon sonunda this dondurun, boylece daha fazla sinif metodu zincirleyebilirsiniz.

Kotu:

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

const araba = new Araba('Ford','F-150','kirmizi');
araba.setRenk('pembe');
araba.kaydet();

Iyi:

class Araba {
constructor(marka, model, renk) {
this.marka = marka;
this.model = model;
this.renk = renk;
}

setMarka(marka) {
this.marka = marka;
// NOT: Zincirleme icin 'this' donduruluyor
return this;
}

setModel(model) {
this.model = model;
// NOT: Zincirleme icin 'this' donduruluyor
return this;
}

setRenk(renk) {
this.renk = renk;
// NOT: Zincirleme icin 'this' donduruluyor
return this;
}

kaydet() {
console.log(this.marka, this.model, this.renk);
// NOT: Zincirleme icin 'this' donduruluyor
return this;
}
}

const araba = new Araba('Ford','F-150','kirmizi')
.setRenk('pembe')
.kaydet();

en basa don

Miras(Kalitim) yerine Kompozisyonu tercih edin

Gang of Four tarafindan Design Patterns da unlu olarak belirtildigi gibi, yapabildiginiz yerlerde miras(kalitim) yerine kompozisyonu tercih etmelisiniz. Miras(kalitim)i kullanmak icin bircok iyi sebep oldugu gibi kompozisyonu kullanmak icinde bircok iyi sebep var. Bu kural icin asil nokta, eger akliniz icgudusel olarak miras(kalitim)i tercih ediyorsa, kompozisyonun, probleminizi daha iyi modelleyebilecegini dusunmeye calisin. Bazi durumlarda bu olabilir.

"Miras(kalitim)i ne zaman kullanmaliyim?" diye merak ediyor olabilirsiniz. Bu durum elinizdeki soruna bagli ama bu, ne zaman miras(kalitim)in kompozisyondan daha anlamli oldugunun kabul edilebilir bir listesi.

  1. Miras(kalitim)iniz, "-dir, -dir" iliskisini sagliyor ve "sahiplik" iliskisinin saglamiyor. (Insan->Hayvan vs. Kullanici->KullaniciDetaylari)
  2. Kodu temel siniflardan yeniden kullanabilirsiniz. (Insanlar, tum hayvanlar gibi hareket edebilir)
  3. Bir temel sinifi degistirerek turetilmis siniflarda genel degisiklikler yapmak istiyorsunuz. (Hayvanlarin hareket ettiginde harcadigi kaloriyi degistirmek)

Kotu:

class Personel {
constructor(isim, mail) {
this.isim = isim;
this.mail = mail;
}

// ...
}

// Kotu cunku Personeller vergi verisine "sahip". PersonelVergiVerileri, bir Personel turu degil.
class PersonelVergiVerileri extends Personel {
constructor(ssn, maas) {
super();
this.ssn = ssn; // sosyal guvenlik numarasi
this.maas = maas;
}

// ...
}

Iyi:

class PersonelVergiVerileri {
constructor(ssn, maas) {
this.ssn = ssn; // sosyal guvenlik numarasi
this.maas = maas;
}

// ...
}

class Personel {
constructor(isim, mail) {
this.isim = isim;
this.mail = mail;
}

vergiVerisiniBelirle(ssn, maas) {
this.vergiVerisi = new PersonelVergiVerileri(ssn, maas);
}
// ...
}

en basa don

SOLID

Tek Sorumluluk Prensibi (TSP)

Temiz Kod'da belirtildigi gibi, "Bir sinifin degisebilmesi icin asla birden fazla sebep olmamalidir". Bircok islevsellikle birlikte bir sinifi sikistirmak cezbedicidir, tipki bir ucusda yalnizca bir valiz almak gibi. Bununla ilgili mesele, sinifinizin kavramsal olarak uyum saglamayacagi ve degismesi icin bircok neden verecegidir. Bir sinifi degistirmeniz icin gereken sureyi en aza indirgemek onemlidir. Cunku cok fazla islevsellik bir sinifta bulunuyorsa ve siz bir kismini degistirirseniz, bu degisikligin kod tabaninizdaki diger bagimli modulleri nasil etkileyecegini anlamaniz zor olabilir.

Kotu:

class UserSettings {
constructor(user) {
this.user = user;
}

changeSettings(settings) {
if (this.verifyCredentials()) {
// ...
}
}

verifyCredentials() {
// ...
}
}

Iyi:

class UserAuth {
constructor(user) {
this.user = user;
}

verifyCredentials() {
// ...
}
}


class UserSettings {
constructor(user) {
this.user = user;
this.auth = new UserAuth(user);
}

changeSettings(settings) {
if (this.auth.verifyCredentials()) {
// ...
}
}
}

en basa don

Acik/Kapali Prensibi

Bertrand Meyer tarafindan belirtildigi gibi, "yazilim varliklari (classlar, moduller, fonksiyonlar vs.) gelisime acik, degisime kapali olmalidir." Peki bu ne anlamaya geliyor? Bu ilke temel olarak, kullanicilarin varolan kodu degistirmeden yeni islevler ekleyebilmesini saglamamiz gerektigini belirtir.

Kotu:

{ // transform response and return }); } else if (this.adapter.name === 'httpNodeAdapter') { return makeHttpCall(url).then((response) => { // transform response and return }); } } } function makeAjaxCall(url) { // request and return promise } function makeHttpCall(url) { // request and return promise }">class AjaxAdapter extends Adapter {
constructor() {
super();
this.name = 'ajaxAdapter';
}
}

class NodeAdapter extends Adapter {
constructor() {
super();
this.name = 'nodeAdapter';
}
}

class HttpRequester {
constructor(adapter) {
this.adapter = adapter;
}

fetch(url) {
if (this.adapter.name === 'ajaxAdapter') {
return makeAjaxCall(url).then((response) => {
// transform response and return
});
} else if (this.adapter.name === 'httpNodeAdapter') {
return makeHttpCall(url).then((response) => {
// transform response and return
});
}
}
}

function makeAjaxCall(url) {
// request and return promise
}

function makeHttpCall(url) {
// request and return promise
}

Iyi:

{ // transform response and return }); } }">class AjaxAdapter extends Adapter {
constructor() {
super();
this.name = 'ajaxAdapter';
}

request(url) {
// request and return promise
}
}

class NodeAdapter extends Adapter {
constructor() {
super();
this.name = 'nodeAdapter';
}

request(url) {
// request and return promise
}
}

class HttpRequester {
constructor(adapter) {
this.adapter = adapter;
}

fetch(url) {
return this.adapter.request(url).then((response) => {
// transform response and return
});
}
}

en basa don

Liskov Yer Degistirme Prensibi (LSP)

Bu terim bu kadar basit bir konsept icin korkutucu. Resmi olarak tanimi soyle: "Eger S, T'nin alt turu ise, programin istenilen ozelliklerinden herhangi birini degistirmeden(dogrulugunu, yaptigi isi vb.) T tipindeki nesneler S tipindeki nesneler ile yer degistirebilir (yani, S tipindeki nesneler T tipindeki nesnelerin yerine gecebilir). Bu daha da korkutucu bir tanim.

Bunun icin en iyi aciklama: eger bir ebeveyn sinifiniz ve alt sinifiniz varsa, temel sinif ve alt sinif, yanlis sonuclar ortaya koymadan birbirlerinin yerine kullanilabilir. Hala kafa karistirici olabilir, o zaman hadi klasik Kare-Dikdortgen ornegine goz atalim. Matematiksel olarak kare bir dikdortgendir ama eger bunu kalitim yoluyla, "is-a" iliskisi kullanarak modellerseniz basinizin belaya girmesi cok gecikmeyecektir.

Kotu:

class Dikdortgen {
constructor() {
this.genislik = 0;
this.yukseklik = 0;
}

renginiBelirle(renk) {
// ...
}

olustur(alan) {
// ...
}

genisligiBelirle(genislik) {
this.genislik = genislik;
}

yuksekligiBelirle(yukseklik) {
this.yukseklik = yukseklik;
}

alanHesapla() {
return this.genislik * this.yukseklik;
}
}

class Kare extends Dikdortgen {
genisligiBelirle(genislik) {
this.genislik = genislik;
this.yukseklik = genislik;
}

yuksekligiBelirle(yukseklik) {
this.genislik = yukseklik;
this.yukseklik = yukseklik;
}
}

function genisDikdortgenlerOlustur(dikdortgenler) {
dikdortgenler.forEach((dikdortgen) => {
dikdortgen.genisligiBelirle(4);
dikdortgen.yuksekligiBelirle(5);
const alan = dikdortgen.alanHesapla(); // KOTU: Kare icin 25 doner. 20 olmaliydi.
dikdortgen.olustur(alan);
});
}

const dikdortgenler = [new Dikdortgen(), new Dikdortgen(), new Kare()];
genisDikdortgenlerOlustur(dikdortgenler);

Iyi:

class Sekil {
renginiAyarla(renk) {
// ...
}

olustur(alan) {
// ...
}
}

class Dikdortgen extends Sekil {
constructor(genislik, yukseklik) {
super();
this.genislik = genislik;
this.yukseklik = yukseklik;
}

alanHesapla() {
return this.genislik * this.yukseklik;
}
}

class Kare extends Sekil {
constructor(uzunluk) {
super();
this.uzunluk = uzunluk;
}

alanHesapla() {
return this.uzunluk * this.uzunluk;
}
}

function genisSekillerOlustur(sekiller) {
sekiller.forEach((sekil) => {
const alan = sekil.alanHesapla();
sekil.olustur(alan);
});
}

const sekiller = [new Dikdortgen(4, 5), new Dikdortgen(4, 5), new Kare(5)];
genisSekillerOlustur(sekiller);

en basa don

Interface Segregation Principle (ISP)

JavaScript doesn't have interfaces so this principle doesn't apply as strictly as others. However, it's important and relevant even with JavaScript's lack of type system.

ISP states that "Clients should not be forced to depend upon interfaces that they do not use." Interfaces are implicit contracts in JavaScript because of duck typing.

A good example to look at that demonstrates this principle in JavaScript is for classes that require large settings objects. Not requiring clients to setup huge amounts of options is beneficial, because most of the time they won't need all of the settings. Making them optional helps prevent having a "fat interface".

Kotu:

class DOMTraverser {
constructor(settings) {
this.settings = settings;
this.setup();
}

setup() {
this.rootNode = this.settings.rootNode;
this.animationModule.setup();
}

traverse() {
// ...
}
}

const $ = new DOMTraverser({
rootNode: document.getElementsByTagName('body'),
animationModule() {} // Most of the time, we won't need to animate when traversing.
// ...
});

Iyi:

class DOMTraverser {
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 $ = new DOMTraverser({
rootNode: document.getElementsByTagName('body'),
options: {
animationModule() {}
}
});

en basa don

Dependency Inversion Principle (DIP)

This principle states two essential things:

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  2. Abstractions should not depend upon details. Details should depend on abstractions.

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 Dependency Injection (DI). While they are not identical concepts, DIP keeps high-level modules 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 reduces the coupling between modules. Coupling is a very bad development pattern because it makes your code hard to refactor.

As stated previously, JavaScript doesn't have interfaces so the abstractions that are depended upon are implicit contracts. That is to say, the methods and properties that an object/class exposes to another object/class. In the example below, the implicit contract is that any Request module for an InventoryTracker will have a requestItems method.

Kotu:

{ this.requester.requestItem(item); }); } } const inventoryTracker = new InventoryTracker(['apples', 'bananas']); inventoryTracker.requestItems();">class InventoryRequester {
constructor() {
this.REQ_METHODS = ['HTTP'];
}

requestItem(item) {
// ...
}
}

class InventoryTracker {
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 = new InventoryRequester();
}

requestItems() {
this.items.forEach((item) => {
this.requester.requestItem(item);
});
}
}

const inventoryTracker = new InventoryTracker(['apples', 'bananas']);
inventoryTracker.requestItems();

Iyi:

class InventoryTracker {
constructor(items, requester) {
this.items = items;
this.requester = requester;
}

requestItems() {
this.items.forEach((item) => {
this.requester.requestItem(item);
});
}
}

class InventoryRequesterV1 {
constructor() {
this.REQ_METHODS = ['HTTP'];
}

requestItem(item) {
// ...
}
}

class InventoryRequesterV2 {
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.
const inventoryTracker = new InventoryTracker(['apples', 'bananas'], new InventoryRequesterV2());
inventoryTracker.requestItems();

en basa don

Testing

Testing is more important than shipping. If you have no tests or an inadequate amount, then every time you ship code you won't be sure that you didn't break anything. Deciding on what constitutes an adequate amount is up to your team, but having 100% coverage (all statements and branches) is how you achieve very high confidence and developer peace of mind. This means that in addition to having a great testing framework, you also need to use a good coverage tool.

There's no excuse to not write tests. There are plenty 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 tests for every new feature/module you introduce. If your preferred method is Test Driven Development (TDD), that is great, but the main point is to just make sure you are reaching your coverage goals before launching any feature, or refactoring an existing one.

Single concept per test

Kotu:

{ it('handles date boundaries', () => { let date; date = new MakeMomentJSGreatAgain('1/1/2015'); date.addDays(30); assert.equal('1/31/2015', date); date = new MakeMomentJSGreatAgain('2/1/2016'); date.addDays(28); assert.equal('02/29/2016', date); date = new MakeMomentJSGreatAgain('2/1/2015'); date.addDays(28); assert.equal('03/01/2015', date); }); });">import assert from 'assert';

describe('MakeMomentJSGreatAgain', () => {
it('handles date boundaries', () => {
let date;

date = new MakeMomentJSGreatAgain('1/1/2015');
date.addDays(30);
assert.equal('1/31/2015', date);

date = new MakeMomentJSGreatAgain('2/1/2016');
date.addDays(28);
assert.equal('02/29/2016', date);

date = new MakeMomentJSGreatAgain('2/1/2015');
date.addDays(28);
assert.equal('03/01/2015', date);
});
});

Iyi:

{ it('handles 30-day months', () => { const date = new MakeMomentJSGreatAgain('1/1/2015'); date.addDays(30); assert.equal('1/31/2015', date); }); it('handles leap year', () => { const date = new MakeMomentJSGreatAgain('2/1/2016'); date.addDays(28); assert.equal('02/29/2016', date); }); it('handles non-leap year', () => { const date = new MakeMomentJSGreatAgain('2/1/2015'); date.addDays(28); assert.equal('03/01/2015', date); }); });">import assert from 'assert';

describe('MakeMomentJSGreatAgain', () => {
it('handles 30-day months', () => {
const date = new MakeMomentJSGreatAgain('1/1/2015');
date.addDays(30);
assert.equal('1/31/2015', date);
});

it('handles leap year', () => {
const date = new MakeMomentJSGreatAgain('2/1/2016');
date.addDays(28);
assert.equal('02/29/2016', date);
});

it('handles non-leap year', () => {
const date = new MakeMomentJSGreatAgain('2/1/2015');
date.addDays(28);
assert.equal('03/01/2015', date);
});
});

en basa don

Eszamanlilik

Promiseleri kullan,Callbackleri degil.

Callbackler kusursuz degildir , ve asiri miktarda ic ice gecmeye neden olurlar. ES2015/ES6 ile birlikte Promiseler bir yerlesik evrensel tiptir. Onlari kullan!

Kotu:

{ if (requestErr) { console.error(istekHatasi); } else { writeFile('makale.html', cevap.body, (yazmaHatasi) => { if (yazmaHatasi) { console.error(yazmaHatasi); } else { console.log('Dosya yazildi'); } }); } }); ">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');
}
});
}
});

Iyi:

{ return writeFile('makale.html', cevap); }) .then(() => { console.log('Dosya yazildi'); }) .catch((hata) => { console.error(hata); }); ">import { get } from 'request';
import { writeFile } from 'fs';

get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
.then((cevap) => {
return writeFile('makale.html', cevap);
})
.then(() => {
console.log('Dosya yazildi');
})
.catch((hata) => {
console.error(hata);
});

en basa don

Async/Await ,Promise'den daha temizdir.

Promiseler Callbacklere nazaran daha temizdir, fakat ES2017/ES8 daha temiz bir cozum sunan async await'i getirdi. Tek ihtiyacin async onekine sahip bir fonksiyon, ve sonrasinda thenli fonksiyonlar zincirini kullanmaksizin mantigini zorunlu olarak yazabilirsin. ES2017 / ES8 ozelliklerinden yararlanabiliyorsaniz bunu bugun kullanin!.

Kotu:

{ return writeFile('makale.html', cevap); }) .then(() => { console.log('Dosya yazildi'); }) .catch((hata) => { console.error(hata); }); ">import { get } from 'request-promise';
import { writeFile } from 'fs-promise';

get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin')
.then((cevap) => {
return writeFile('makale.html', cevap);
})
.then(() => {
console.log('Dosya yazildi');
})
.catch((hata) => {
console.error(hata);
});

Iyi:

import { get } from 'request-promise';
import { writeFile } from 'fs-promise';

async function temizKodMakalesiniAl() {
try {
const cevap = await get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');
await writeFile('makale.html', cevap);
console.log('Dosya yazildi');
} catch(hata) {
console.error(hata);
}
}

en basa don

Hata Yakalama

Hatalar olusturmak iyi bir seydir. Hatalar size programinizda bir seylerin yolunda olmadigini soylemenin en iyi yoludur. Calisan bir kod parcacigi ya da calismayi durduran bir fonksiyonun, process'in neden durduguna dair konsol ekraninda sizi bilgilendirirler.

Yakalanan Hatalari Gormezden Gelmeyin

Yakalanan bir hata ile hicbir sey gerceklestirmemek, size o hatayi tamamen fixlemis olma imkani sunmaz. Hatalari (console.log) ile gostermek, tipki suya yazi yazmak gibidir. Cogu zaman yetersizdir. Eger kod bolumlerini try/catch bloklari ile olusturuyorsaniz o bolumde bir hatanin olusabilecegini dusunuyorsunuzdur. Bu durumlar icin bir planiniz olmali ya da bu durumlari yonetebileceginiz ayri kod yapilariniz olmali.

Kotu:

try {
hataFirlatabilecekFonksiyon();
} catch (hata) {
console.log(hata);
}

Iyi:

try {
hataFirlatabilecekFonksiyon();
} catch (hata) {
// Ilk secenek (console.log'dan daha cok bilgilendirici):
console.error(hata);
// Diger Secenek:
kullaniciyaHataGoster(hata);
// Diger Secenek:
hatayiServiseBildir(hata);
// Ya da ucunu de yapabilirsiniz!!
}

Promise Hatalarini Gormezden Gelmeyin

Ayni sebepten dolayi try/catch'ten kaynaklanan hatalari gozardi etmemelisiniz.

Kotu:

verileriGetir()
.then((veri) => {
fonksiyonHataFirlatabilir(veri);
})
.catch((hata) => {
console.log(hata);
});

Iyi:

verileriGetir()
.then((veri) => {
fonksiyonHataFirlatabilir(veri);
})
.catch((hata) => {
// Ilk secenek (console.log'dan daha cok bilgilendirici):
console.error(hata);
// Diger Secenek:
kullaniciyaHataGoster(hata);
// Diger Secenek:
hatayiServiseBildir(hata);
// Ya da ucunu de yapabilirsiniz!!
});

en basa don

Yazim Sekli

Yazim sekli ozneldir. Buradaki bircok kural gibi, uymaniz gereken zor ve siki bir kural yoktur. Yazim sekli uzerinde TARTISMAYIN. Bunlari otomatiklestirmek icin binlerce arac vardir. Birini kullanin! Muhendisler icin, yazim sekli uzerinde tartismak zaman ve para kaybidir.

Otomatik formatlama kapsamina girmeyen seyler (girintileme, tab veya bosluk, cift veya tek tirnak vb.) hakkinda rehberlik icin buraya bakin.

Buyuk harf kullaniminiz tutarli olsun

JavaScript'in bir yazim kurali yoktur, bu yuzden buyuk harf kullanimi size degiskenler, fonksiyonlar vb. seyler hakkinda bircok bilgi verir. Bu kurallar ozneldir, yani ekibiniz istedigini secebilir. Onemli olan neyi sectiginiz degildir, sectiginizde tutarli olmanizdir.

Kotu:

const HAFTANIN_GUN_SAYISI = 7;
const ayinGunSayisi = 30;

const sarkilar = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
const Sanatcilar = ['ACDC', 'Led Zeppelin', 'The Beatles'];

function veritabaniniSil() {}
function veritabanini_kurtar() {}

class hayvan {}
class Alpaka {}

Iyi:

const HAFTANIN_GUN_SAYISI = 7;
const AYIN_GUN_SAYISI = 30;

const SARKILAR = ['Back In Black', 'Stairway to Heaven', 'Hey Jude'];
const SANATCILAR = ['ACDC', 'Led Zeppelin', 'The Beatles'];

function veritabaniniSil() {}
function veritabaniniKurtar() {}

class Hayvan {}
class Alpaka {}

en basa don

Cagirilan ve cagiran fonksiyonlar birbirine yakin olmalidir.

Eger bir fonksiyon digerini cagiriyorsa, kodda onlari dikey olarak birbirine yakin tutun. Ideal olarak, cagiran fonksiyonu cagirilanin hemen uzerinde tutun. Kodlari tipki gazete okur gibi yukaridan asagiya dogru okuruz. Bu nedenle, kodunuzun bu yolda okunabilmesini saglayin.

Kotu:

class PerformansDegerlendirmesi {
constructor(calisan) {
this.calisan = calisan;
}

benzerleriniGetir() {
return db.lookup(this.calisan, 'benzer');
}

mudurleriGetir() {
return db.lookup(this.calisan, 'mudur');
}

benzerDegerlendirmeler() {
const benzerler = this.benzerleriniGetir();
// ...
}

performansDegerlendirmesi() {
this.benzerDegerlendirmeler();
this.mudurDegerlendirmeleri();
this.kendiDegerlendirmeleriGetir();
}

mudurDegerlendirmeleri() {
const mudur = this.mudurleriGetir();
}

kendiDegerlendirmeleriGetir() {
// ...
}
}

const deegrlendirme = new PerformansDegerlendirmesi(calisan);
deegrlendirme.performansDegerlendirmesi();

Iyi:

class PerformansDegerlendirmesi {
constructor(calisan) {
this.calisan = calisan;
}

performansDegerlendirmesi() {
this.benzerDegerlendirmeler();
this.mudurDegerlendirmeleri();
this.kendiDegerlendirmeleriGetir();
}

benzerDegerlendirmeler() {
const benzer = this.benzerleriniGetir();
// ...
}

benzerleriniGetir() {
return db.lookup(this.calisan, 'benzer');
}

mudurDegerlendirmeleri() {
const mudur = this.mudurleriGetir();
}

mudurleriGetir() {
return db.lookup(this.calisan, 'mudur');
}

kendiDegerlendirmeleriGetir() {
// ...
}
}

const degerlendirme = new PerformansDegerlendirmesi(calisan);
degerlendirme.performansDegerlendirmesi();

en basa don

Javascript Dokumantasyon Kurallarina uyulmali.

DocBlock sayesinde uygulamalarimizdaki fonksiyonlar, methodlar, siniflar, modeller ve kontrollerin islevlerini, degiskenlerini, geri donus degerlerini hatirlamamizi ve/veya kullandigimiz IDElerde fonksiyonlar hakkinda hizli bilgilendirmeler almak icin mutlaka oncelik verilmesi gerekiyor. Ayrica yorum satirlarinda yapilmasi gereken notlarimizi TODO: seklinde tanimlamalar yaparsak en son eksik kalan yerleri hizli hatirlamamiza yardimci olabilir.

Kotu:

function FaizHesapla(Anapara,Gun,YillikOran,StopajOrani){
faiz=((Anapara*Gun*YillikOran)/36500)*(1-(StopajOrani/100));
return faiz;
}
function FonGetiri(Anapara,Gun,FonOrani){
//var Gun=((sonTarih-ilkTarih)/(1000*60*60*24)); hucre icerisinde "01.01.2019" olunca calismiyor
// tarih olan hucre secildiginde bu calismaktadir. ilerleyen gunlerde google sheets script
// arastirma yapilacak
fon=(Anapara*(Gun)*(FonOrani/100));
return fon;
}

Iyi:

/**
* Nakit Akisi Sinifi.
*
* @fileOverview Nakit Akisinda Kullanilan Ozel 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 formul parametre olarak iletilen tutarin Net Faizini geri dondurur
* @param {100.000,00} Anapara Anapara Tutari Yazilacak
* @param {5} Gun Gun Yazilacak
* @param {17,25} YillikOran Yillik Faiz Orani Yazilacak
* @param {15} StopajOrani Mevduat Stopaj Orani Yazilacak
* @return
* @customfunction
*/

function FaizHesapla(Anapara,Gun,YillikOran,StopajOrani){
faiz=((Anapara*Gun*YillikOran)/36500)*(1-(StopajOrani/100));
return faiz;
}

/**
* Fon Hesaplama
*
* @link https://www.yapikredi.com.tr/yatirimci-kosesi/fon-bilgileri
*
* Bu formul parametre olarak iletilen tutarin Net Fon Gelirini geri dondurur
* @param {1.000,00} Anapara Anapara Tutari Yazilacak
* @param {5} Gun Gun Yazilacak
* @param {0,04} FonOrani Gunluk Fon Getiri Orani Yazilacak
* @return
* @customfunction
*/

function FonGetiri(Anapara,Gun,FonOrani){
// TODO: var Gun=((sonTarih-ilkTarih)/(1000*60*60*24)); hucre icerisinde "01.01.2019" olunca calismiyor
// TODO: tarih olan hucre secildiginde bu calismaktadir. ilerleyen gunlerde google sheets script arastirma yapilacak
fon=(Anapara*(Gun)*(FonOrani/100));
return fon;
}

en basa don

Yorumlar

Sadece is mantiginin karmasik oldugu durumlarda yorumlari kullanin.

Yorumlar lukstur, zorunlu degildir. Iyi kod cogunlukla kendini belli eder.

Kotu:

function ozetCikar(veri) {
// Ozet
let ozet = 0;

// data degiskeninin uzunlugu
const uzunluk = veri.length;

// veri degiskeninin her karakterini donguye sok
for (let i = 0; i < uzunluk; i++) {

// Karakter kodunu getir
const karakter = veri.charCodeAt(i);

// Ozetini cikar
ozet = ((ozet << 5) - ozet) + karakter;

// 32-bit'lik sayiya cevir
ozet &= ozet;

}
}

Iyi:

function ozetCikar(veri) {
let ozet = 0;
const uzunluk = veri.length;

for (let i = 0; i < uzunluk; i++) {
const karakter = veri.charCodeAt(i);
ozet = ((ozet << 5) - ozet) + karakter;

// 32-bit'lik sayiya cevir
ozet &= ozet;
}
}

en basa don

Kod tabaninizda yorum satirina alinmis kod birakmayin.

Surum kontrol sistemleri bu nedenle var. Eski kodu gecmisinizde birakin.

Kotu:

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

Iyi:

birSeyYap();

en basa don

Yorum satirini gunluge cevirmeyin

Surum kontrol sistemlerini kullanmaniz gerektigini hatirlayin! Olu koda, yorum satirina alinmis koda ve ozellikle gunluge cevrilmis yorum satirina gerek yok. Onceki yapilanlari almak icin git log komutunu kullanin!

Kotu:

/**
* 2016-12-20: Monadlari kaldirdim, onlari anlamadim (RM)
* 2016-10-01: Ozel monadlari kullanarak gelistirdim (JP)
* 2016-02-03: Tip denetimini kaldirdim (LI)
* 2015-03-14: Topla fonksiyonunu ekledim (JR)
*/
function topla(a, b) {
return a + b;
}

Iyi:

function topla(a, b) {
return a + b;
}

en basa don

Konum isaretleyicilerini kullanmaktan kacinin

Onlar sadece kuru gurultuden ibaret. Fonksiyonlar ve degiskenlerin uygun girintilemeler, yoluyla kodunuza gorsel seklini vermesine izin verin.

Kotu:

////////////////////////////////////////////////////////////////////////////////
// Scope Model Ornegi
////////////////////////////////////////////////////////////////////////////////
$scope.model = {
menu: 'foo',
nav: 'bar'
};

////////////////////////////////////////////////////////////////////////////////
// Eylem tanimlanmasi
////////////////////////////////////////////////////////////////////////////////
const eylemler = function() {
// ...
};

Iyi:

$scope.model = {
menu: 'foo',
nav: 'bar'
};

const eylemler = function() {
// ...
};

en basa don

Translation

This is also available in other languages:

en basa don

About

JavaScript icin Uyarlanmis Temiz Kod Kavramlari

Topics

Resources

Readme

License

MIT license

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 11