Temiz Kod: İşlevler (Javascript'te)

Mar 26 2023
Kod tabanınızdaki karmaşık, anlaşılması zor işlevlerle uğraşmaktan bıktınız mı? Daha fazla bakım yapılabilir, yeniden kullanılabilir ve hataya daha az eğilimli işlevler yazmak ister misiniz? Öyleyse, “Temiz Kod: İşlevler” hakkında bilgi edinmeniz gerekir. Robert C.

Kod tabanınızdaki karmaşık, anlaşılması zor işlevlerle uğraşmaktan bıktınız mı? Daha fazla bakım yapılabilir, yeniden kullanılabilir ve hataya daha az eğilimli işlevler yazmak ister misiniz? Öyleyse, “Temiz Kod: İşlevler” hakkında bilgi edinmeniz gerekir. Robert C. Martin'in "Temiz Kod" kitabında özetlenen en iyi uygulamaları izleyerek, okunması, test edilmesi ve bakımı daha kolay işlevler yazmayı öğrenebilirsiniz. Bu blog yazısında, temiz kod fonksiyonlarının temel kavramlarını keşfedeceğiz ve bu kavramları kendi kodunuza uygulamanıza yardımcı olacak pratik ipuçları ve örnekler sağlayacağız. Yardımımızla, kodlama becerilerinizi bir sonraki seviyeye taşıyabilir ve birlikte çalışmaktan keyif alacağınız işlevler yazabilirsiniz. Peki temiz kod fonksiyonlarını öğrenmeye hazır mısınız? Haydi dalalım!

İçerik tablosu

· Küçük Fonksiyonlar Büyük Fonksiyonlardan Daha İyidir
· Fonksiyonlar Bir Şey Yapmalı
· Fonksiyonların Açıklayıcı İsimleri Olmalı
· Fonksiyonların Sınırlı Sayıda Bağımsız Değişkeni Olmalı
· Fonksiyonların Yan Etkileri Olmamalı
· Fonksiyonlar Global Değişkenlere Dayanmamalı
· Fonksiyonlar Çok Olmamalı Derinlemesine İç İçe
· Hata Kodlarını Değil İstisnaları Kullanın
· Sonuç

Küçük İşlevler Büyük İşlevlerden Daha İyidir

Küçük işlevlerin okunması ve anlaşılması daha kolaydır çünkü genellikle tek bir şey yaparlar ve net bir amaçları vardır. Bu aynı zamanda gözden geçirilecek veya değiştirilecek daha az kod olduğu için bunların test edilmesini ve bakımını kolaylaştırır. Öte yandan, büyük işlevler daha karmaşık ve anlaşılması daha zor olabilir, bu da hatalara veya hatalara yol açabilir.

// Large function
function processOrders(orders) {
  const total = orders.reduce((acc, order) => acc + order.price, 0);
  const orderIds = orders.map(order => order.id);
  const orderCount = orders.length;
  const orderSummary = `You have ${orderCount} orders with IDs ${orderIds.join(', ')} for a total of $${total}.`;
  console.log(orderSummary);
  return orderSummary;
}

// --------------------------------------------------------------

// Refactored into smaller functions
function getTotalPrice(orders) {
  return orders.reduce((acc, order) => acc + order.price, 0);
}
function getOrderIds(orders) {
  return orders.map(order => order.id);
}
function getOrderCount(orders) {
  return orders.length;
}
function generateOrderSummary(orders) {
  const total = getTotalPrice(orders);
  const orderIds = getOrderIds(orders);
  const orderCount = getOrderCount(orders);
  return `You have ${orderCount} orders with IDs ${orderIds.join(', ')} for a total of $${total}.`;
}
function logOrderSummary(orders) {
  const orderSummary = generateOrderSummary(orders);
  console.log(orderSummary);
  return orderSummary;
}

İşlev , bir dizi sipariş alır ve her bir siparişin fiyatını toplamak için işlevi getTotalPrice()kullanarak bunların toplam fiyatını döndürür . reduce()İşlev getOrderIds(), bir dizi sipariş alır ve işlevi kullanarak kimliklerinin bir dizisini döndürür map(). İşlev getOrderCount(), bir dizi sipariş alır ve özelliği kullanarak bunların sayısını döndürür length. Son olarak, generateOrderSummary()işlev bir dizi sipariş alır ve bir özet dizesi oluşturmak için üç küçük işlevi kullanır. İşlev logOrderSummary()bir dizi sipariş alır ve özet dizesini konsola kaydeder.

İşlevler Bir Şey Yapmalı

Her işlevin açık ve belirgin bir amacı olmalıdır. Bir işlev birden fazla şey yaptığında anlaşılması, test edilmesi ve sürdürülmesi zorlaşabilir. Daha büyük bir görevi daha küçük işlevlere bölerek daha okunabilir ve korunabilir kodlar oluşturabiliriz.

// Function that performs multiple tasks
function processUserInput(input) {
  const inputLines = input.split('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
  const trimmedLines = inputLines.map(line => line.trim());
  const nonEmptyLines = trimmedLines.filter(line => line !== '');
  const formattedLines = nonEmptyLines.map(line => `> ${line}`);
  return formattedLines.join('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
// --------------------------------------------------------------
// Refactored into smaller functions
function splitInput(input) {
  return input.split('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
function trimLines(lines) {
  return lines.map(line => line.trim());
}
function removeEmptyLines(lines) {
  return lines.filter(line => line !== '');
}
function formatLines(lines) {
  return lines.map(line => `> ${line}`);
}
function joinLines(lines) {
  return lines.join('\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\n');
}
function processUserInput(input) {
  const lines = splitInput(input);
  const trimmedLines = trimLines(lines);
  const nonEmptyLines = removeEmptyLines(trimmedLines);
  const formattedLines = formatLines(nonEmptyLines);
  return joinLines(formattedLines);
}

İşlev splitInput()bir dize alır ve split()onu bir satır dizisine bölmek için yöntemi kullanır. İşlev trimLines()bir satır dizisini alır ve map()her satırın başındaki ve sonundaki boşlukları kaldırmak için yöntemi kullanır. İşlev removeEmptyLines()bir dizi satır alır ve filter()boş satırları kaldırmak için yöntemi kullanır. İşlev formatLines()bir satır dizisini alır ve her satırın başına map()bir karakter eklemek için yöntemi kullanır. >İşlev joinLines()bir dizi satır alır ve join()bunları yeni satırlarla ayrılmış tek bir dizgede birleştirmek için yöntemi kullanır. Son olarak işlev, processUserInput()giriş dizesini işlemek için daha küçük işlevleri kullanır.

İşlevlerin Açıklayıcı Adları Olmalıdır

İşlev adları, işlevin ne yaptığını doğru bir şekilde tanımlamalı ve işlevin uygulanmasını okumak zorunda kalmadan anlaşılması kolay olmalıdır. Açıklayıcı bir işlev adı, kodu daha açıklayıcı hale getirmeye ve yorum ihtiyacını azaltmaya yardımcı olabilir.

// Function with a vague name
function processData(data) {
  // ...
}
// --------------------------------------------------------------
// Refactored with a descriptive name
function processUserData(userData) {
  // ...
}

İşlevlerin Sınırlı Sayıda Argümanı Olmalıdır

Çok sayıda bağımsız değişken alan işlevlerin kullanılması, anlaşılması ve test edilmesi daha zor olabilir. Mümkünse argüman sayısını üç veya dördün altında tutmayı hedefleyin. Argüman sayısını azaltmanın bir yolu, onları tek bir nesne veya veri yapısı olarak iletmektir.

// Function with too many arguments
function createPerson(name, age, address, phone, email) {
  // ...
}

// --------------------------------------------------------------
// Refactored to use an object instead
function createPerson(personData) {
  // ...
}
// Now, we can pass an object with properties for name, age, address, phone, and email:

const personData = {
  name: 'John Doe',
  age: 30,
  address: '123 Main St',
  phone: '555-555-1234',
  email: '[email protected]'
};
const person = createPerson(personData);

İşlevlerin Yan Etkisi Olmamalıdır

Bir işlev, kendi kapsamı dışındaki herhangi bir durumu değiştirdiğinde bir yan etki oluşur. Yan etkiler, işlevin davranışını test etmeyi ve mantık yürütmeyi zorlaştırabilir ve ayrıca beklenmeyen davranışlara yol açabilir. Fonksiyonlar sadece kendi parametreleri ve yerel değişkenleri üzerinde çalışmalı ve kapsamları dışında herhangi bir durumu değiştirmemelidir.

// Example with side effects
let arr = [1, 2, 3];
function popLastElement() {
  arr.pop(); // modifies the external state of `arr`
}
popLastElement();
console.log(arr); // Output: [1, 2]

// --------------------------------------------------------------
// Example without side effects
function getLastElement(arr) {
  return arr[arr.length - 1]; // returns a new value without modifying the input
}
let arr = [1, 2, 3];
let lastElement = getLastElement(arr);
console.log(lastElement); // Output: 3

Fonksiyonlar Global Değişkenlere Dayanmamalıdır

Global değişkenler, fonksiyonları anlamayı ve test etmeyi zorlaştırır ve beklenmeyen davranışlara yol açabilir. İşlevler yalnızca kendi parametreleri ve yerel değişkenleri üzerinde çalışmalı ve genel duruma güvenmemelidir. Bu aynı zamanda işlevi farklı bağlamlarda yeniden kullanmayı kolaylaştırır.

// Example relying on global state
let x = 0;
function increment() {
  x++;
}
increment();
console.log(x); // Output: 1

// --------------------------------------------------------------
// Example without relying on global state
function increment(x) {
  return x + 1;
}
let y = 0;
y = increment(y);
console.log(y); // Output: 1

İşlevler Çok Derin Yuvalanmış Olmamalıdır

Derinlemesine iç içe geçmiş işlevlerin okunması ve anlaşılması daha zor olabileceği gibi karmaşık kontrol yapılarına da yol açabilir. İşlevler, iç içe geçmiş işlevlerin birden çok düzeyini zihinsel olarak takip etmek zorunda kalmadan kontrol akışını anlamayı kolaylaştıracak şekilde yapılandırılmalıdır.

// Example with deeply nested functions
function add(a, b) {
  function increment(x) {
    return x + 1;
  }
  let c = increment(a);
  let d = increment(b);
  return c + d;
}
console.log(add(1, 2)); // Output: 5

// --------------------------------------------------------------
// Example with flatter function structure
function increment(x) {
  return x + 1;
}
function add(a, b) {
  let c = increment(a);
  let d = increment(b);
  return c + d;
}
console.log(add(1, 2)); // Output: 5

Hata Kodlarını Değil İstisnaları Kullanın

Hata kodları, kod hakkında akıl yürütmeyi zorlaştırabilir ve karmaşık kontrol yapılarına yol açabilir. İstisnalar, daha doğal kontrol akışına ve daha kolay hata işlemeye izin verir. İşlevler, hata kodları veya değerleri döndürmek yerine hataları veya beklenmeyen davranışları belirtmek için istisnalar atmalıdır.

// Example with error code
function divide(a, b) {
  if (b === 0) {
    return -1; // error code for divide by zero
  }
  return a / b;
}
let result = divide(4, 0);
if (result === -1) {
  console.log("Error: Divide by zero"); // error handling with error code
}

// --------------------------------------------------------------
// Example with exception
function divide(a, b) {
  if (b === 0) {
    throw new Error("Divide by zero"); // throws an exception
  }
  return a / b;
}
try {
  let result = divide(4, 0);
} catch (e) {
  console.log("Error: " + e.message); // error handling with exception
}

Çözüm

Sonuç olarak, kod tabanımızın genel kalitesini iyileştirmek için işlevler yazarken en iyi uygulamaları takip etmek önemlidir. Bunu yaparak, işlevlerimizin yalnızca okunabilir ve tekrar kullanılabilir olmasını değil, aynı zamanda uzun vadede bakım yapılabilir olmasını da sağlayabiliriz. Bu, uzun vadede zamandan ve kaynaklardan tasarruf sağlayabilecek, kötü yazılmış koddan kaynaklanabilecek hata ve hataların sayısını azaltmaya yardımcı olabilir.

Temiz kodun yalnızca çalışan kod yazmakla ilgili olmadığını belirtmekte fayda var; aynı zamanda kolayca anlaşılabilen, test edilebilen ve zaman içinde değiştirilebilen kod yazmakla ilgilidir. Bu nedenle, kodunuzun kalitesini ve sürdürülebilirliğini optimize etmek için işlevleri yazarken yukarıda özetlenen en iyi uygulamaları dikkatlice değerlendirmek için zaman ayırmanız önerilir.