Temiz Kod — İsimler, Fonksiyonlar, Yorumlar
30 saniyede özet
Temiz kod bir zevk meselesi değil, bir zaman meselesi. Kod bir kez yazılır, onlarca kez okunur, ve okuyan çoğu zaman altı ay sonraki sensin.
Birinin yazdığı kodu açtın ve ne yaptığını anlamak yarım saatini aldı. “Temiz kod” dediğimiz şeyin ölçüsü tam olarak bu: anlamak ne kadar sürüyor?
Adım adım oku
- Kod bir kez yazılır.
- Ama ekipteki herkes tarafından, aylar boyunca defalarca okunur.
- d, x, getData gibi belirsiz isimler her okuyanı tanıma geri döndürür; her okuma uzar.
- daysSinceLastLogin, findUsersActiveSince gibi isimler ne yaptığını söyler; kod bir bakışta anlaşılır.
-
Bayt: Bir arkadaşımın kodunu açtım, ne yaptığını anlamak yarım saatimi aldı.
-
Sen: Kod çalışıyor muydu peki?
-
Bayt: Kusursuz çalışıyordu. Sorun okumaktı: d, x, getData...
-
Bayt: Temiz kodun ölçüsü güzellik değil, anlamanın ne kadar sürdüğü!
İsim, en ucuz dokümantasyondur
Bir isim iki soruya cevap verebilir: ne yapıyor, ve nasıl yapıyor. İkincisini söyleyen isimler, uygulamayı değiştirdiğin anda yalana dönüşür.
// ne anlattığı belirsizList<User> getData(int x)
// nasıl yaptığını anlatıyor — uygulama değişince yalan olurList<User> getUsersWithHashMapCache(int days)
// ne yaptığını anlatıyorList<User> findUsersActiveSince(int days)Kısalık bir erdem değil. d yazmak daysSinceLastLogin yazmaktan hızlıdır ama okuyan her seferinde tanıma geri dönmek zorunda kalır.
Kafam karıştı, daha basit anlat
İyi bir isim, kutunun üstündeki etiket gibidir: içini açmadan ne olduğunu söyler. “Nasıl” yapıldığını anlatan etiket ise tarif değişince yalan söylemeye başlar.
Hangi isim daha iyidir ve neden?
Satır satır: bir fonksiyonu okunur hâle getirmek
Aşağıdaki fonksiyon çalışıyor. Sorun doğruluğu değil, bir şeyi anlamak için tamamını okumak zorunda olman.
Bu fonksiyonun ne yaptığını anlaman kaç saniye sürüyor? Hangi satırda kaybettin? Cevabı göster
Çoğu okuyucu üçüncü if’te kaybeder. Sebep karmaşıklık değil — üç farklı soyutlama seviyesiKodun ne kadar "ne yapılacak" ne kadar "nasıl yapılacak" anlattığı. Bir fonksiyonda ikisi karışırsa okuyucu iki düzeyi aynı anda takip etmek zorunda kalır.Sözlükte gör →nin (döngü, iş kuralı, biçimlendirme) aynı fonksiyonda olması.
Üç seviye, tek fonksiyon
String rapor(List<Order> orders) { StringBuilder sb = new StringBuilder(); for (Order o : orders) { if (o.getStatus() == Status.CANCELLED) continue; if (o.getTotal() > 1000) { sb.append("VIP "); } sb.append(o.getId()).append(": ") .append(String.format("%.2f", o.getTotal())) .append("\n"); } return sb.toString();}Debug
okuyucu Birinci seviye: bir koleksiyon üzerinde geziliyor. Buraya kadar sorun yok.
- seviye
- = yineleme
Sol/sağ ok tuşlarıyla da gezebilirsin.
Buradaki kural tek soyutlama seviyesi: bir fonksiyon ya ne yapılacağını anlatır (“raporu hazırla”), ya da nasıl yapılacağını (“şu listeyi dön”), ikisini birden değil.
Bu kuralı bir bankanın ay sonu hesap işletim ücretinde görelim. Kimden ücret alınacağı, ne kadar alınacağı ve ekstreye nasıl yazılacağı burada ayrı, adı olan parçalarda duruyor.
Derinleş · Ay sonu hesap işletim ücreti: okunur hâle getirmek 4 dosya · ~78 satır · ilk okumada atlayabilirsin
Kafam karıştı, daha basit anlat
Bir fonksiyonda hem döngü, hem iş kuralı, hem de biçimlendirme varsa okuyan kaybolur. Her birini adı olan ayrı bir küçük fonksiyona ayır.
"Tek soyutlama seviyesi" kuralı ne demek?
Koddaki `if (o.getTotal() > 1000)` satırının sorunu nedir?
Kendin gör
Simülatör bir fonksiyonu adım adım refactor ediyor ve her adımda iki şeyi ölçüyor: iç içe geçme derinliği ve en uzun fonksiyonun satır sayısı.
Aynı fonksiyon, dört refactor
Tohum 3- Başlangıç
- Guard clause
- Fonksiyon çıkarıldı
- Aşırıya kaçırıldı
- Fonksiyon
- 1
- En uzun fonksiyon
- 14 / 20
- İç içe derinlik
- 3 / 2
- Akışı izlemek için bakılacak yer
- 0
Lint sınırlarına takılıyor
Şu an ne oldu?
Tek fonksiyon, üç seviye iç içe
14 satır ve 3 seviye derinlik. Okuyucu neyi elediğini, neyi işaretlediğini ve nasıl yazdığını aynı anda takip etmek zorunda. Lint sınırlarına takılıyor.
Aklında kalsın: Sorun satır sayısı değil, tek fonksiyonda birden çok soyutlama seviyesinin olması.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Baştan adımla. Tek fonksiyon, derinlik 3, 14 satır.
Guard clause'a çevir. guard clauseİstisnai durumu başta eleyip erken dönen koşul. `else` merdivenini siler; satır kazandırmaz ama iç içe geçmeyi kaldırır.Sözlükte gör →,elsemerdivenini siliyor — derinlik düşüyor, satır sayısı neredeyse aynı.Fonksiyon çıkar. Satır sayısı bölünüyor ama toplam kod artıyor. Takas bu: daha çok isim, daha az anda tutulacak şey.Aşırıya kaçır. Her şeyi tek satırlık fonksiyonlara böl. Ölçüler “iyi” görünüyor ama akışı takip etmek zorlaştı — temizlik de abartılabilir.
Statik analiz aracı bir fonksiyona "karmaşıklık: 3, iyi" diyor. Bu kod temiz midir?
Yorum, çoğu zaman bir özürdür
Yorumların büyük kısmı, yazılamamış bir ismin yerine geçer:
// kullanıcı son 30 gündür giriş yapmadıysa pasif sayılırif (u.getLastLogin().isBefore(now.minusDays(30))) { ... }
// yorum artık gereksiz — isim onu söylüyorif (pasifSayilir(u)) { ... }Ama bazı yorumlar silinemez, çünkü kodda olmayan bir bilgi taşırlar:
| Yorum türü | Kalmalı mı | Neden |
|---|---|---|
| Neden böyle yapıldı | ✅ | “Bu sıra önemli: API başlığı gövdeden önce okumak zorunda.” Koda yazılamaz. |
| Dış dünyaya referans | ✅ | “Bkz. RFC 9457 §3” veya “Satıcı API’si burada 200 ile hata dönüyor.” |
| Uyarı | ✅ | “Bu metot thread-safe değildir.” |
| Ne yaptığını anlatan | ❌ | İsim düzeltilmeli. |
| Kapalı kod | ❌ | Git zaten hatırlıyor. |
Kafam karıştı, daha basit anlat
Bir yorum “bu kod şunu yapıyor” diyorsa, çoğu zaman kodun kendisi daha iyi bir isimle aynı şeyi söyleyebilir. Yorumu, kodun anlatamadığı “neden” için sakla.
Her yorumu, kalması mı yoksa kodun kendisiyle değiştirilmesi mi gerektiğine göre ayır.
Tuzaklar
Temizlik de abartılabilir. Üç satırlık bir fonksiyonu üç fonksiyona bölmek okuma maliyetini düşürmez, artırır: artık akışı takip etmek için dosyada zıplaman gerekiyor. Ölçüt her zaman aynı — anlamak kolaylaştı mı?
Sayı kuralları körü körüne uygulanmaz. “Fonksiyonlar 20 satırı geçmesin” gibi sayılar bir hedef değil, “buraya bir bak” diyen bir alarmdır. 30 satırlık düz bir switch, 8 satırlık üç seviye iç içe koşuldan okunaklıdır.
erken soyutlamaHenüz bilinmeyen bir gereksinime göre genelleştirme yapmak. Yanlış eksende açılmış bir soyutlama, hiç açılmamış olmasından pahalıdır.Sözlükte gör →. Tek kullanımı olan bir şeyi genelleştirmek, henüz bilmediğin bir gereksinime göre tasarlamaktır. İkinci kullanım geldiğinde soyutlama neredeyse her zaman yanlış yerden çıkar.
Kendini sına
İyi bir isim, bir şeyin nasıl yapıldığını değil ne yaptığını söyler.
Bu kod ne yazdırır?
Aklında kalacak üç şey
- 1 Temiz kodun ölçüsü güzellik değil, okuma süresidir: kod bir kez yazılır, onlarca kez okunur.
- 2 İyi bir isim ne yaptığını söyler, nasıl yaptığını değil. getUserData bir şey anlatmaz; findActiveUsersByEmail anlatır.
- 3 Yorumların çoğu, bulunamamış iyi bir ismin özrüdür. Kodun ne yaptığını isimle anlat; yorumu neden öyle yaptığın için sakla.
5 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.