Takip et

Node.js Modülü Oluşturma Rehberi: Temellerden İleri Seviyeye

Node.js Modülü Oluşturma Rehberi: Temellerden İleri Seviyeye Node.js, sunucu tarafı uygulamalar geliştirmek için tasarlanmış, olay tabanlı,

Node.js Modülü Oluşturma Rehberi: Temellerden İleri Seviyeye

Node.js, sunucu tarafı uygulamalar geliştirmek için tasarlanmış, olay tabanlı, asenkron bir JavaScript çalışma zamanı ortamıdır. Node.js’in gücünün önemli bir kısmı, kodun yeniden kullanılabilirliğini, bakımını ve ölçeklenebilirliğini artıran modül sisteminden gelir. Modüller, kodunuzu mantıksal olarak izole edilmiş, küçük ve yönetilebilir parçalara ayırmanıza olanak tanır. Bu sayede, büyük ve karmaşık uygulamaları daha kolay geliştirebilir, işbirliği yapabilir ve hata ayıklayabilirsiniz. Bu kapsamlı rehberde, Node.js modüllerinin temel prensiplerinden başlayarak, CommonJS ve ES Modülleri arasındaki farkları, modül oluşturma ve kullanma yöntemlerini, ileri düzey konuları ve en iyi uygulamaları derinlemesine inceleyeceğiz. Amacımız, Node.js ekosisteminde kendi modüllerinizi etkin bir şekilde oluşturma ve yönetme konusunda size sağlam bir temel sağlamaktır.

Node.js Modüllerine Genel Bakış

Modüller, Node.js uygulamalarının yapı taşlarıdır. Her bir JavaScript dosyası, varsayılan olarak kendi kapsamına (scope) sahiptir ve bu dosya içerisinde tanımlanan değişkenler, fonksiyonlar veya sınıflar, dışarıdan doğrudan erişilemez. Bir dosyadan diğerine kod paylaşımı yapmak için, belirli öğelerin dışa aktarılması (export) ve başka bir dosyada içe aktarılması (import) gerekir. Bu mekanizma, global değişken karmaşasını önler ve kodun daha düzenli olmasını sağlar.

Neden Modüller Kullanmalıyız?

Modüler programlamanın birçok avantajı vardır:

* Yeniden Kullanılabilirlik: Bir kez yazılan bir modül, uygulamanın farklı yerlerinde veya hatta farklı projelerde tekrar kullanılabilir. Bu, geliştirme süresini kısaltır ve kod tekrarını azaltır.
* Bakım Kolaylığı: Kod parçalarını modüllere ayırmak, hataları bulmayı ve düzeltmeyi kolaylaştırır. Bir modüldeki değişiklikler, uygulamanın diğer bölümlerini doğrudan etkilemez, bu da yan etki riskini azaltır.
* Okunabilirlik: Modüller, kodunuzu daha organize ve anlaşılır hale getirir. Her modül belirli bir görevi yerine getirdiği için, kodun ne iş yaptığını anlamak daha kolaydır.
* Ad Alanı Çakışmalarını Önleme: Her modülün kendi özel kapsamı olduğundan, farklı modüllerde aynı isimde değişkenler veya fonksiyonlar tanımlamak ad çakışmalarına yol açmaz.
* Bağımlılık Yönetimi: Modüller, bir dosyanın hangi diğer dosyalara veya kütüphanelere bağımlı olduğunu açıkça belirtir. Bu, bağımlılık grafiğini anlamayı ve yönetmeyi kolaylaştırır.
* Ölçeklenebilirlik: Büyük uygulamalar, küçük, bağımsız modüllerden oluşturulduğunda daha kolay ölçeklenebilir ve yönetilebilir hale gelir.

Modül Tipleri: CommonJS ve ES Modülleri

Node.js, tarihsel olarak CommonJS modül sistemini kullanmıştır. Ancak, JavaScript dilinin kendisi, ECMAScript 2015 (ES6) ile birlikte kendi standart modül sistemini (ES Modülleri veya ESM) tanıttı. Node.js, bu iki sistemi de desteklemektedir, ancak aralarında önemli farklar ve kullanım senaryoları bulunmaktadır.

* CommonJS (CJS): Node.js’in geleneksel modül sistemidir. require() fonksiyonu ile modüller içe aktarılır ve module.exports veya exports nesnesi ile dışa aktarılır. Senkron bir yükleme mekanizmasına sahiptir, yani bir modül tamamen yüklenmeden önce kodun geri kalanı yürütülmez. Çoğu eski Node.js projesi ve npm paketi CommonJS kullanır.
* ES Modülleri (ESM): JavaScript dilinin standart modül sistemidir. import ve export anahtar kelimeleri ile modüller içe ve dışa aktarılır. Asenkron yüklemeyi destekler ve tarayıcı ortamında da kullanılan standarttır. Node.js’te ES Modüllerini kullanmak için genellikle package.json dosyasında "type": "module" belirtilmesi veya .mjs uzantısı kullanılması gerekir.

Bu iki modül sistemi arasındaki geçiş ve birlikte çalışma, Node.js geliştiricileri için önemli bir konudur.

Basit Bir CommonJS Modülü Oluşturma

CommonJS, Node.js’in varsayılan modül sistemidir ve hala birçok projede yaygın olarak kullanılmaktadır. Temel bir CommonJS modülü oluşturmak oldukça basittir.

Öncelikle, bir fonksiyon veya değeri dışa aktarmak istediğiniz bir JavaScript dosyası oluşturun. Örneğin, matematik.js adında bir dosya oluşturalım:

// matematik.js
function topla(a, b) {
  return a + b;
}

function cikar(a, b) {
  return a - b;
}

// Bu fonksiyonları dışa aktarmanın yolları

module.exports ve exports Kullanımı

CommonJS’te dışa aktarma için iki ana yöntem vardır: module.exports ve exports.

* module.exports: Bu, bir modülün dışa aktardığı gerçek nesnedir. Bir modülden tek bir şey (bir fonksiyon, bir obje, bir sınıf vb.) dışa aktarmak istediğinizde idealdir. module.exports‘a bir değer atadığınızda, bu değer modülün kendisi olur.

// matematik.js (module.exports ile tek bir nesne dışa aktarma)
    function topla(a, b) {
      return a + b;
    }

    function cikar(a, b) {
      return a - b;
    }

    const islemler = {
      topla: topla,
      cikar: cikar
    };

    module.exports = islemler;

Bu durumda, matematik.js modülünü içe aktardığınızda, islemler nesnesini alırsınız.

* exports: Bu, module.exports‘a bir referanstır (exports = module.exports = {} başlangıçta). Genellikle, birden fazla öğeyi dışa aktarmak için kullanılır. exports nesnesine özellikler ekleyerek (örneğin, exports.topla = topla;) dışa aktarma yaparsınız.

// matematik.js (exports ile birden fazla öğe dışa aktarma)
    function topla(a, b) {
      return a + b;
    }

    function cikar(a, b) {
      return a - b;
    }

    exports.topla = topla;
    exports.cikar = cikar;
    // exports.carp = (a, b) => a * b; // Doğrudan da eklenebilir

Önemli Not: exports doğrudan module.exports‘a bir referans olduğu için, exports = yeniDeger; gibi bir atama yapmak, exports referansını keser ve beklenen dışa aktarmayı yapmaz. Her zaman module.exports = yeniDeger; kullanın veya exports.ozellik = deger; şeklinde özellik ekleyin.

Genellikle, tek bir değer dışa aktarılacaksa module.exports = ... kullanılırken, birden fazla adlandırılmış değer dışa aktarılacaksa exports.ad = ... kullanılır.

Modülü Başka Bir Dosyada Kullanma

Bir CommonJS modülünü başka bir dosyada kullanmak için require() fonksiyonunu kullanırız.

// app.js
const matematik = require('./matematik.js'); // .js uzantısı isteğe bağlıdır

console.log('2 + 3 =', matematik.topla(2, 3)); // Çıktı: 2 + 3 = 5
console.log('5 - 2 =', matematik.cikar(5, 2)); // Çıktı: 5 - 2 = 3

// Eğer matematik.js dosyasında sadece topla fonksiyonunu dışa aktarmış olsaydık:
// module.exports = topla;
// O zaman içe aktarma şöyle olurdu:
// const topla = require('./matematik.js');
// console.log(topla(2,3));

require() fonksiyonuna verdiğimiz yol, içe aktarılacak modülün bulunduğu dizine göreceli olmalıdır (örn. ./ veya ../). Eğer bir npm paketi içe aktarıyorsak (örn. express), sadece paket adını belirtiriz ve Node.js bunu node_modules dizininde arar.

ES Modüllerine Geçiş

ES Modülleri, modern JavaScript geliştirmenin geleceğidir ve hem tarayıcılar hem de Node.js tarafından desteklenmektedir. CommonJS’e göre daha statik analiz dostu, asenkron ve daha esnek bir yapı sunarlar.

package.json‘da "type": "module" Ayarı

Node.js’te bir dizindeki tüm .js dosyalarını varsayılan olarak ES Modülü olarak ele almak için, projenizin package.json dosyasına "type": "module" eklemeniz gerekir:

// package.json
{
  "name": "es-module-ornek",
  "version": "1.0.0",
  "description": "ES Modülleri ile Node.js uygulaması",
  "main": "app.js",
  "type": "module", // Bu satır önemlidir
  "scripts": {
    "start": "node app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Eğer "type": "module" ayarını yapmazsanız, .js uzantılı dosyalar CommonJS olarak kabul edilir. Alternatif olarak, tek tek dosyaları ES Modülü olarak işaretlemek için .mjs uzantısını kullanabilirsiniz (örn. matematik.mjs). CommonJS modülleri için ise .cjs uzantısı kullanılır.

import ve export Sözdizimi

ES Modüllerinde dışa ve içe aktarma için export ve import anahtar kelimeleri kullanılır.

* Adlandırılmış Dışa Aktarmalar (Named Exports): Birden fazla öğeyi dışa aktarmak için kullanılır.

// matematik.js (ES Modülü)
    export function topla(a, b) {
      return a + b;
    }

    export function cikar(a, b) {
      return a - b;
    }

    export const PI = 3.14159;

İçe aktarma:

// app.js (ES Modülü)
    import { topla, cikar, PI } from './matematik.js';

    console.log('2 + 3 =', topla(2, 3));
    console.log('5 - 2 =', cikar(5, 2));
    console.log('PI değeri:', PI);

    // Farklı bir isimle içe aktarma
    // import { topla as add } from './matematik.js';
    // console.log(add(1,1));

    // Tüm adlandırılmış dışa aktarmaları bir obje olarak içe aktarma
    // import * as matematikIslemleri from './matematik.js';
    // console.log(matematikIslemleri.topla(10, 20));

* Varsayılan Dışa Aktarmalar (Default Exports): Bir modülden tek bir birincil öğeyi dışa aktarmak için kullanılır. Her modülde yalnızca bir varsayılan dışa aktarma olabilir.

// kullanici.js (ES Modülü)
    class Kullanici {
      constructor(ad, soyad) {
        this.ad = ad;
        this.soyad = soyad;
      }

      tamAd() {
        return ${this.ad} ${this.soyad};
      }
    }

    export default Kullanici; // Sadece bir tane default export olabilir

İçe aktarma:

// app.js (ES Modülü)
    import Kullanici from './kullanici.js'; // Süslü parantez olmadan, herhangi bir isimle içe aktarılabilir

    const user = new Kullanici('Ayşe', 'Yılmaz');
    console.log(user.tamAd()); // Çıktı: Ayşe Yılmaz

Varsayılan ve adlandırılmış dışa aktarmaları aynı modülde birleştirmek de mümkündür:

// servis.js
    export const API_URL = 'https://api.example.com';

    class Servis {
      constructor() { / ... / }
      fetchData() { / ... / }
    }

    export default Servis;
// app.js
    import Servis, { API_URL } from './servis.js';

    console.log(API_URL);
    const myService = new Servis();

CommonJS ve ES Modüllerini Birlikte Kullanma

Node.js, farklı modül sistemleri arasında bir miktar birlikte çalışabilirlik sunar.

* ES Modülünden CommonJS Modülünü İçe Aktarma: Bir ES Modülü, import sözdizimi ile bir CommonJS modülünü içe aktarabilir. CommonJS modülünün module.exports değeri, ES Modülünün varsayılan dışa aktarması olarak ele alınır. Adlandırılmış dışa aktarmalar için ise CommonJS modülünün dışa aktardığı nesnenin özellikleri kullanılır.

// commonjs-modul.cjs (veya .js ve package.json'da "type": "commonjs" varsayımıyla)
    module.exports = {
      selamla: (isim) => Merhaba, ${isim}!,
      versiyon: '1.0.0'
    };
// es-modul.mjs (veya .js ve package.json'da "type": "module" varsayımıyla)
    import commonModule from './commonjs-modul.cjs'; // Varsayılan içe aktarma
    // Veya adlandırılmış olarak:
    // import { selamla, versiyon } from './commonjs-modul.cjs';

    console.log(commonModule.selamla('Dünya'));
    console.log('Versiyon:', commonModule.versiyon);

* CommonJS Modülünden ES Modülünü İçe Aktarma: Bu durum biraz daha karmaşıktır çünkü CommonJS senkron, ES Modülleri ise asenkrondur. CommonJS modülleri, doğrudan import anahtar kelimesini kullanamaz. Bunun yerine, dinamik import() fonksiyonunu kullanmaları gerekir. Bu, bir Promise döndürür ve asenkron bir bağlamda ele alınmalıdır.

// es-modul.mjs
    export const mesaj = 'Bu bir ES Modülü mesajıdır.';
    export default 'Varsayılan ES Modülü';
// commonjs-app.js
    async function main() {
      const esModule = await import('./es-modul.mjs');
      console.log(esModule.default); // Çıktı: Varsayılan ES Modülü
      console.log(esModule.mesaj);   // Çıktı: Bu bir ES Modülü mesajıdır.
    }

    main();

Bu durum, top-level await özelliğinin Node.js 14 ve sonrası sürümlerinde ES modüllerinde doğrudan kullanılabilmesiyle daha da kolaylaşmıştır, ancak CommonJS modüllerinde hala async fonksiyonlar içinde await import() kullanmak gereklidir.

Modülleri Daha Kapsamlı Hale Getirme

Modüller sadece basit fonksiyonları dışa aktarmakla kalmaz, aynı zamanda daha karmaşık veri yapılarını ve davranışları da içerebilir.

Birden Fazla Fonksiyon ve Değişken Dışa Aktarma

Yukarıdaki örneklerde gördüğümüz gibi, hem CommonJS hem de ES Modüllerinde birden fazla fonksiyon, değişken veya sabit dışa aktarılabilir.

CommonJS:

// util.js
exports.sayHello = (name) => Hello, ${name}!;
exports.addNumbers = (a, b) => a + b;
exports.APP_VERSION = '1.0.0';

ES Modülleri:

// util.mjs
export const sayHello = (name) => Hello, ${name}!;
export const addNumbers = (a, b) => a + b;
export const APP_VERSION = '1.0.0';

Varsayılan Dışa Aktarma (Default Exports)

ES Modüllerine özgü olan varsayılan dışa aktarma, bir modülün ana işlevini veya ana nesnesini belirtmek için kullanılır. Modülü içe aktarırken süslü parantez kullanmadan doğrudan bir isimle erişilebilir.

// database.mjs
class Database {
  constructor(connectionString) {
    this.connectionString = connectionString;
  }

  connect() {
    console.log(Connecting to ${this.connectionString}...);
    // Bağlantı mantığı
  }

  query(sql) {
    console.log(Executing query: ${sql});
    // Sorgu mantığı
    return [];
  }
}

export default Database;
// app.mjs
import DB from './database.mjs'; // İstediğimiz bir isimle içe aktarabiliriz

const myDb = new DB('mongodb://localhost:27017/mydb');
myDb.connect();
myDb.query('SELECT * FROM users');

Sınıfları ve Nesneleri Dışa Aktarma

Modüller, JavaScript sınıflarını veya doğrudan nesne değişmezlerini (object literals) dışa aktarmak için de kullanılabilir. Bu, nesne tabanlı programlama prensiplerini uygularken oldukça faydalıdır.

CommonJS ile Sınıf Dışa Aktarma:

// user.js
class User {
  constructor(id, name) {
    this.id = id;
    this.name = name;
  }

  greet() {
    return Hello, my name is ${this.name}.;
  }
}

module.exports = User;
// app.js
const User = require('./user.js');
const user1 = new User(1, 'Alice');
console.log(user1.greet());

ES Modülleri ile Sınıf Dışa Aktarma:

// product.mjs
export class Product {
  constructor(id, name, price) {
    this.id = id;
    this.name = name; name;
    this.price = price;
  }

  getPriceWithTax(taxRate) {
    return this.price * (1 + taxRate);
  }
}
// app.mjs
import { Product } from './product.mjs';
const item = new Product(101, 'Laptop', 1200);
console.log(Laptop price with 18% tax: $${item.getPriceWithTax(0.18).toFixed(2)});

Nesne Dışa Aktarma (Hem CommonJS hem de ES Modülleri):

// config.js (CommonJS)
module.exports = {
  dbHost: 'localhost',
  dbPort: 5432,
  apiTimeout: 5000
};
// config.mjs (ES Modülü)
const config = {
  dbHost: 'localhost',
  dbPort: 5432,
  apiTimeout: 5000
};
export default config;
// veya
// export const dbHost = 'localhost';
// export const dbPort = 5432;

Bu esneklik, modüllerinizi uygulamanızın ihtiyaçlarına göre şekillendirmenizi sağlar.

Modül Yolları ve Çözümleme

Node.js, require() ve import ifadelerindeki modül yollarını nasıl çözdüğünü belirleyen karmaşık bir mekanizmaya sahiptir. Bu mekanizmayı anlamak, modüllerinizi doğru bir şekilde içe aktarmanız için kritik öneme sahiptir.

Göreceli Yollar (Relative Paths)

./, ../ veya / ile başlayan yollar göreceli yollardır. Bu yollar, içe aktarma işlemini yapan dosyanın konumuna göre modülün yerini belirtir.

* ./modul.js: Aynı dizindeki modul.js dosyasını arar.
* ../lib/util.js: Bir üst dizindeki lib klasöründeki util.js dosyasını arar.
* /src/data.js: Projenin kök dizininden (veya geçerli çalışma dizininden) başlayan mutlak bir yol gibi yorumlanır, ancak genellikle . veya .. ile başlayan göreceli yollar daha güvenlidir.

Örnek:

// proje-kök/
// ├── src/
// │   ├── components/
// │   │   └── Button.js
// │   └── utils/
// │       └── helper.js
// └── app.js

* app.js içinden Button.js‘i içe aktarmak için: require('./src/components/Button.js')
* Button.js içinden helper.js‘i içe aktarmak için: require('../utils/helper.js')

Mutlak Yollar (Absolute Paths)

Mutlak yollar, dosya sisteminin kökünden başlar (örn. /home/user/project/src/module.js veya C:\Users\user\project\src\module.js). Genellikle, __dirname veya path modülü ile oluşturulurlar.

// app.js
const path = require('path');
const myModule = require(path.join(__dirname, 'src', 'myModule.js'));

Bu yöntem, dosyanın nerede çalıştırıldığına bakılmaksızın modülü doğru bir şekilde bulmayı sağlar.

node_modules ve Dizine Dayalı Çözümleme

Eğer require() veya import ifadesinde bir yol yerine sadece bir modül adı (örn. express, lodash) belirtilirse, Node.js bu modülü node_modules dizininde arar. Arama süreci şöyledir:

1. Node.js, geçerli dosyanın bulunduğu dizinden başlayarak node_modules dizinini arar.
2. Bulamazsa, bir üst dizine çıkar ve orada node_modules‘u arar.
3. Bu işlem, dosya sisteminin kök dizinine ulaşana kadar devam eder.

Modülün içinde bir package.json dosyası varsa, Node.js bu dosyadaki "main" (CommonJS için) veya "exports" (ES Modülleri için) alanlarını kontrol ederek hangi dosyanın dışa aktarılması gerektiğini belirler. Eğer package.json yoksa veya "main" alanı belirtilmemişse, varsayılan olarak index.js dosyasını arar.

Örnek:

// app.js
const express = require('express'); // node_modules'tan express paketini bulur
const _ = require('lodash');       // node_modules'tan lodash paketini bulur

NODE_PATH ve Ortam Değişkenleri

NODE_PATH ortam değişkeni, Node.js’in modülleri arayacağı ek dizinleri belirtmek için kullanılabilir. Bu, global olarak yüklü modüllere veya belirli bir projeye özgü olmayan modüllere erişmek için faydalı olabilir. Ancak, genellikle NODE_PATH kullanımı önerilmez çünkü bu, modül çözümlemesini daha az tahmin edilebilir hale getirir ve bağımlılık yönetimini zorlaştırabilir. Bağımlılıkları genellikle package.json üzerinden yönetmek ve node_modules kullanmak en iyi uygulamadır.

Asenkron Modüller ve Gelişmiş Konular

Node.js, asenkron işlemleri yoğun bir şekilde kullanır ve modül sistemi de bu paradigmayı destekler.

Top-Level await (Üst Düzey await)

Node.js 14 ile birlikte, ES Modüllerinde artık async fonksiyonu içine almadan doğrudan await anahtar kelimesini kullanmak mümkündür. Bu, modülün başlangıcında asenkron kaynakları (veritabanı bağlantısı, API çağrısı vb.) yüklemeyi veya yapılandırmayı kolaylaştırır.

// config.mjs
import { fetchData } from './api.mjs';

console.log('Modül yükleniyor...');
const initialConfig = await fetchData('/settings'); // Modül seviyesinde await

export const appConfig = {
  ...initialConfig,
  port: process.env.PORT || 3000
};

console.log('Modül yüklendi ve yapılandırıldı.');

Bu özellik yalnızca ES Modülleri için geçerlidir. CommonJS modüllerinde hala async fonksiyonlar içinde await kullanmak gerekir.

Dinamik İçe Aktarma (import())

import() fonksiyonu, bir modülü çalışma zamanında (runtime) koşullu olarak veya isteğe bağlı olarak yüklemek için kullanılır. Bir Promise döndürür ve modülün yüklenmesi tamamlandığında çözülür. Bu, uygulamanızın başlangıç yükleme süresini optimize etmek veya sadece belirli koşullar altında ihtiyaç duyulan modülleri yüklemek için faydalıdır.

// app.js (CommonJS veya ES Modülü olabilir)
const userRole = 'admin'; // Bu bir veritabanı sorgusundan gelebilir

async function loadAdminModule() {
  if (userRole === 'admin') {
    const adminModule = await import('./admin-panel.mjs'); // Dinamik içe aktarma
    adminModule.showAdminDashboard();
  } else {
    console.log('Yönetici erişimi yok.');
  }
}

loadAdminModule();

Dinamik import() hem CommonJS hem de ES Modüllerinde kullanılabilir.

Modül Önbellekleme (Module Caching)

Node.js, bir modülü ilk kez require() veya import ettiğinde, modülü bellekte önbelleğe alır. Sonraki içe aktarma istekleri, aynı modülün önbelleğe alınmış kopyasını döndürür. Bu, modül kodunun her seferinde yeniden yürütülmesini önler ve performansı artırır.

// sayac.js
let count = 0;
console.log('Sayac modülü yüklendi.'); // Bu sadece bir kez yazdırılır

exports.increment = () => {
  count++;
  return count;
};

exports.getCount = () => count;
// app.js
const sayac1 = require('./sayac.js');
const sayac2 = require('./sayac.js'); // Önbellekten gelir

console.log(sayac1.increment()); // Çıktı: 1
console.log(sayac2.increment()); // Çıktı: 2 (aynı örnek üzerinde çalışıyorlar)
console.log(sayac1.getCount());  // Çıktı: 2

Modül önbelleğini manuel olarak temizlemek mümkündür (delete require.cache[modulePath]), ancak genellikle bu önerilmez ve sadece çok özel durumlarda (örn. test senaryoları) kullanılır.

Modül Yükleyici Kancaları (Module Loader Hooks)

Node.js’in modül yükleme sürecini daha derinlemesine kontrol etmek isteyen ileri düzey kullanıcılar için modül yükleyici kancaları mevcuttur. Bu kancalar, modüllerin nasıl çözüldüğünü, yüklendiğini ve dönüştürüldüğünü özelleştirmeye olanak tanır. Genellikle özel durumlar, örneğin TypeScript veya başka bir dilin doğrudan Node.js’te dönüştürülerek çalıştırılması gibi senaryolar için kullanılır. Bu, loader mekanizması aracılığıyla node --experimental-loader ./my-loader.js gibi komutlarla etkinleştirilebilir. Bu, özellikle transpiler’lar veya özel dosya türlerini işlemek için güçlü bir araçtır ancak kullanımı karmaşıktır ve genellikle özel kütüphaneler tarafından soyutlanır (örn. ts-node).

Modül Testi ve Dokümantasyonu

Güvenilir ve sürdürülebilir modüller oluşturmak için test ve dokümantasyon vazgeçilmezdir.

Unit Testleri Yazma

Her bir modülün beklenen şekilde çalıştığından emin olmak için unit testleri yazılmalıdır. Popüler test çerçeveleri arasında Jest, Mocha ve Chai bulunur.

Jest ile Örnek Test:

// matematik.js
exports.topla = (a, b) => a + b;
exports.carp = (a, b) => a * b;
// matematik.test.js
const matematik = require('./matematik');

test('iki sayıyı doğru bir şekilde toplar', () => {
  expect(matematik.topla(1, 2)).toBe(3);
});

test('iki sayıyı doğru bir şekilde çarpar', () => {
  expect(matematik.carp(2, 3)).toBe(6);
});

test('sıfır ile çarpım sıfır olmalı', () => {
  expect(matematik.carp(5, 0)).toBe(0);
});

Testler, modülün her bir fonksiyonunun veya metodunun izole bir şekilde doğru çalıştığını doğrular. Bu, kodda değişiklik yapıldığında regresyon hatalarını önlemeye yardımcı olur.

Dokümantasyon Oluşturma

Modülünüzün nasıl kullanılacağını, hangi fonksiyonları sunduğunu, parametrelerini ve dönüş değerlerini açıklayan iyi bir dokümantasyon, diğer geliştiricilerin (ve gelecekteki sizin) modülü anlamasını ve kullanmasını kolaylaştırır. JSDoc gibi araçlar, kodunuzdaki yorumlardan otomatik olarak dokümantasyon oluşturabilir.

JSDoc Örneği:

/
 * İki sayıyı toplar.
 * @param {number} a - İlk sayı.
 * @param {number} b - İkinci sayı.
 * @returns {number} İki sayının toplamı.
 */
function topla(a, b) {
  return a + b;
}

/
 * Kullanıcı nesnesi.
 * @typedef {object} User
 * @property {number} id - Kullanıcının ID'si.
 * @property {string} name - Kullanıcının adı.
 */

/
 * Yeni bir kullanıcı oluşturur.
 * @param {number} id - Kullanıcının benzersiz ID'si.
 * @param {string} name - Kullanıcının adı.
 * @returns {User} Yeni oluşturulan kullanıcı nesnesi.
 */
function createUser(id, name) {
  return { id, name };
}

module.exports = { topla, createUser };

Bu yorumlar, JSDoc aracı tarafından işlenerek HTML, Markdown veya başka formatlarda okunabilir bir dokümantasyon haline getirilebilir.

En İyi Uygulamalar ve İpuçları

Node.js modülleri geliştirirken göz önünde bulundurmanız gereken bazı en iyi uygulamalar ve ipuçları:

Modül Sorumluluğu

Her modülün tek bir sorumluluğu olmalıdır (Single Responsibility Principle – SRP). Bir modül, belirli bir görevi veya bir dizi ilişkili görevi yerine getirmelidir. Örneğin, bir modül sadece veritabanı işlemleriyle ilgilenmeli, başka bir modül ise kullanıcı kimlik doğrulamasını yönetmelidir. Bu, modüllerin daha küçük, daha yönetilebilir ve daha az hata yapmaya eğilimli olmasını sağlar.

Bağımlılık Yönetimi

Modüllerinizin bağımlılıklarını açıkça belirtin ve yönetin. package.json dosyasındaki dependencies ve devDependencies alanlarını doğru bir şekilde kullanın. Mümkün olduğunca, modüllerin iç bağımlılıklarını azaltın veya bunları soyutlayın. Bağımlılık enjeksiyonu (Dependency Injection) gibi desenler, modüller arası sıkı bağımlılıkları gevşetmek için kullanılabilir.

Hata Yönetimi

Modüllerinizin içindeki hataları uygun şekilde ele alın. Bir modül bir hata durumuna düştüğünde, bu hatayı çağıran koda bildirmeli veya uygun bir şekilde loglamalıdır. Callback’lerde hata objesini ilk parametre olarak döndürmek (Node.js geleneği), Promise’leri reddetmek veya try-catch blokları kullanmak yaygın yaklaşımlardır.

Performans İpuçları

* Gereksiz Yüklemelerden Kaçının: Yalnızca ihtiyacınız olan modülleri içe aktarın. Modülün tamamını içe aktarmak yerine, sadece belirli fonksiyonları veya sınıfları içe aktarabilirsiniz (ES Modüllerinde import { func } from './module.mjs'; gibi).
* Modül Önbelleğini Anlayın: Node.js modül önbelleklemesini otomatik olarak yapar. Bu, bir modülü birden fazla kez require veya import etmenin ek bir maliyeti olmadığı anlamına gelir. Ancak, modülün ilk yüklenmesinde yapılan pahalı işlemlerin (örn. büyük dosyaları okuma, karmaşık hesaplamalar) yalnızca bir kez gerçekleştiğinden emin olun.
* Dinamik İçe Aktarmayı Kullanın: Uygulamanızın başlangıç süresini kısaltmak için, kritik olmayan veya nadiren kullanılan modülleri dinamik olarak içe aktarmayı düşünebilirsiniz.

Sonuç

Node.js modül sistemi, modern ve ölçeklenebilir uygulamalar geliştirmenin temelini oluşturur. CommonJS’in geleneksel gücünden, ES Modüllerinin modern esnekliğine kadar, Node.js geliştiricilerine geniş bir araç yelpazesi sunulmaktadır. Bu rehberde ele aldığımız konular – modül tipleri, dışa ve içe aktarma yöntemleri, modül yolları, ileri düzey asenkron konular, test ve dokümantasyon – kendi Node.js modüllerinizi oluşturmanız ve bunları projelerinizde etkin bir şekilde kullanmanız için size kapsamlı bir bilgi birikimi sağlamıştır.

Modüler programlama prensiplerini benimseyerek, kodunuzu daha okunabilir, bakımı daha kolay, yeniden kullanılabilir ve işbirliğine daha açık hale getirebilirsiniz. Unutmayın ki iyi tasarlanmış bir modül, sadece bir kod parçası değil, aynı zamanda uygulamanızın genel sağlığına ve sürdürülebilirliğine katkıda bulunan değerli bir varlıktır. Kendi modüllerinizi yazarken bu prensipleri göz önünde bulundurarak, daha sağlam ve başarılı Node.js uygulamaları geliştireceksiniz.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Exit mobile version