Clean Code Nedir ?

Temiz kod, programlayan dışında başka bir geliştirici tarafından okunabilir ve geliştirilebilir olmasıdır.Anlaşılabilirlikle birlikte okunabilirlik, değiştirilebilirlik, genişletilebilirlik ve sürdürülebilirlik gelir.

One difference between a smart programmer and a professional programmer is that the professional understands that clarity is king. Professionals use their powers for good and write code that others can understand.

— Robert C. Martin

Net Açıklayıcı Tanımlar Kullanmak

// Bad variables naming
var i = 10 // user id
var a = 0  // user ages
var w = 0  // user weight
var h = 0  // user height



// Bad functions naming
fun id()
fun age()
fun weight()
fun height()


// Bad classes naming to get user data
class UserInfo()


// Best practices variables naming
var userAge = 0
var userWeight = 0
var userHeight = 0
var userId = 10


// Best practices functions naming
fun setUserAge()
fun setUserWeight()
fun setUserHeight()
fun setUserId()


// Best practices classes naming to get user data
class User()


// Best practices variables naming
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;

// Bad function naming
public List<int[]> getThem() {
     List<int[]> list1 = new ArrayList<int[]>();
     for (int[] x : theList)
       if (x[0] == 4)
         list1.add(x);
     return list1;
}

// Best practices function naming
public List<Cell> getFlaggedCells() {
     List<Cell> flaggedCells = new ArrayList<Cell>();
     for (Cell cell : gameBoard)
       if (cell.isFlagged())
         flaggedCells.add(cell);
     return flaggedCells;
}

Anlam Karmaşasından Kaçının

XYZControllerForEfficientStorageOfString tanımlanmış bir değişken olduğunu düşünelim birde başka bir konumda şöyle değişken XYZControllerForEfficientStorageOfString tanımladığımızı varsayalım. Aynı değişken olup olmadığını anlamanız ne kadar sürdü? Bu tarz anlam çarpıklığı oluşma durumlarından kaçının.

Anlamlı Ayrımlar Yapın

Karekter dizi kopyalama gibi bazı benzeri işlevlerde net açıklayıcı tanımlandırmaya gerek yoktur.

// Best practices parameter of the method naming
public static void copyChars(char a1[], char a2[]) {
     for (int i = 0; i < a1.length; i++) {
       a2[i] = a1[i];
     }
}

//Burada info demeye gerek yok bu tarz bilgilendirici ayrıma gerek yok. Aktif hesaplara erişiyoruz yani onların bilgilerine.

//Best
getActiveAccount()
//Bad
getActiveAccountInfo()

Telafuzu Olmayan Kısaltmalardan Kaçının

//Bad Code
class DtaRcrd102 {
     private Date genymdhms;
     private Date modymdhms;
     private final String pszqint = ”102”;
}

//Best Code
class Customer {
     private Date generationTimestamp;
     private Date modificationTimestamp;;
     private final String recordId = ”102”;
}

Aranabilen Tanımlar Kullanın

Bir değişken veya sabit, bir kod gövdesinde birden çok yerde görülebiliyor veya kullanılıyorsa, ona arama dostu bir ad vermek zorunludur. Aşağıda bulunan sabiti tanımlamadan 5 değerini bir döngüye yazdığımızda bunu aramak oldukça zorlaşır.

const int WORK_DAYS_PER_WEEK = 5;

Arayüzler ve Gerçekleştirimler (Interfaces — Implementations)

Bir arayüz ve onu gerçekleştirecek somut (concrete) bir sınıf yazacağınızı düşünün. Bu iki sınıfa ne isim verirdiniz? IShapeFactory ve ShapeFactory mi? Ben arayüz sınıflarını sade bırakmayı tercih ediyorum. Başa I harfi eklemek yaygın bir pratik, ancak dikkat dağıtmakta bir numara ve bilgi vermek konusunda da sonuncu. Eğer arayüz ya da gerçekleştirim sınıflarından birini belirtmem gerekiyorsa, gerçekleştirim sınıfını seçiyorum; ShapeFactoryImpl şeklinde. Arayüz sınıfını belirtmekten çok daha iyi.

Önekleri Kaldırın

Önekler kodun anlaşılabilirliğini en aza indirmektedir.

//Bad code
public class Part {
     private String m_dsc; // The textual description
     void setName(String name) {
       m_dsc = name;
     }
}

//Best code
public class Part {
     String description;
     void setDescription(String description) {
       this.description = description;
     }
}

Sınıf(Class) ve Nesne(Object) Tanımlamaları

Customer, WikiPage, Account, ve AddressParser gibi tanımlamalar kullanılabilir. Sınıf tanımlamalarında Processor, Data, yada Info gibi genel tanımlamalardan kaçının.

Method Tanımlamaları

Method tanımlarken mutlaka bir fiil(eylem) belirtmek gereklidir. Örneğin ; deletePage , postPayment gibi… Şaka, espri veya tatlılık gerektiren method yazmaktan kaçının.

string name = employee.getName();
   customer.setName(”mike”);
   if (paycheck.isPosted())....

//static methodlar bu şekilde kullanmak yerine
Complex fulcrumPoint = Complex.FromRealNumber(23.0);

// Daha genel kullanımı tercih edebilirsiniz.
Complex fulcrumPoint = new Complex(23.0);

Kavram Başına Tek Kelime

Aynı kelimeyi iki amaç için kullanmaktan kaçının. Aynı terimi iki farklı fikir için kullanmak aslında bir kelime oyunudur.”Kavram başına bir kelime” kuralını izlerseniz, örneğin bir ekleme(add) yöntemine sahip birçok sınıf elde edebilirsiniz.

Örneğin birileri sizden önce add metodu yazmış olsun ve bu metot da iki değeri birbirine birleştiriyor (concat) olsun. Bizim de bir listeye değer ekleyen bir metota ihtiyacımız olsun. Bu metoda add mi demeliyiz? Hayır. Bu durumda yeni metodumuza insert ya da append demeliyiz. Yeni bir add metodu yazmak, kelime oyunu yapmaktır. Add amacı belirsizleşti.

Anlamları Bağlamak

firstName, lastName, street, houseNumber, city, state, ve zipcode değişkenleriniz olduğunu düşünün. Bir nesne elemanı olmadığını düşünelim.

addrFirstName, addrLastName, addrStreet, addrHouseNumber, addrCity, addrState, addrZipCode biçiminde anlamlandırabiliriz. addr bir kısıltma bile olsa onu tanımlayan ögelerden anlaşılabiliyor.

//Bir grup değişken bir grup çatısı altında değil.

val firstName: String? = null
val lastName: String? = null
val street: String? = null
val houseNumber: String? = null
val city: String? = null
val state: String? = null
val zipCode: Int? = null

//adres değişkeni olduğunu anlayabiliyoruz.

val addrFirstName: String? = null
val addrLastName: String? = null
val addrStreet: String? = null
val addrHouseNumber: String? = null
val addrCity: String? = null
val addrState: String? = null
val addrZipCode: Int? = null

Bir başka örnek ;

//belirsiz bağlamı olan değişkenler
private void printGuessStatistics(char candidate, int count)
{   String number;
       String verb;
       String pluralModifier;
       if (count == 0) {
         number = ”no”;
         verb = ”are”;
         pluralModifier = ”s”;
       } else if (count == 1) {
         number = ”1”;
         verb = ”is”;
         pluralModifier = ””;
       } else {
         number = Integer.toString(count);
         verb = ”are”;
         pluralModifier = ”s”;
       }
       String guessMessage = String.format(
         ”There %s %s %s%s”, verb, number, candidate, pluralModifier
       );
       print(guessMessage);
}

//Değişkenler bir bağlama sahiptir.
// Yukarıdaki method kodun geneline baktığımızda anlamakta oldukça güçlük çekiyoruz. Method yazdırma işlemi yapıyor gibi ama içerde bir dizi işlem var ne olduğunu anlamak için tek tek incelemeniz anlam çıkarmanız gerekiyor.

public class GuessStatisticsMessage { 
     private String number;
     private String verb;
     private String pluralModifier;
   
     public String make(char candidate, int count) {
       createPluralDependentMessageParts(count);
        return String.format(
          "There %s %s %s%s", 
          verb, number, candidate, pluralModifier );
     }
   
     private void createPluralDependentMessageParts(int count) {
           if (count == 0) {
              thereAreNoLetters();
           } else if (count == 1) {
              thereIsOneLetter();
           } else {
              thereAreManyLetters(count);
           }
     }
   
     private void thereAreManyLetters(int count) {
       number = Integer.toString(count);
       verb = "are";
       pluralModifier = "s";
     }
   
     private void thereIsOneLetter() {
       number = "1";
       verb = "is";
       pluralModifier = "";
     }
   
     private void thereAreNoLetters() {
       number = "no";
       verb = "are";
       pluralModifier = "s";
     }
}