React ve Node.js Projelerinde Monorepo Kullanımı: Ölçeklenebilir Geliştirme İçin Modern Yaklaşım

Diagram illustrating a monorepo directory structure with separate applications, packages, and libraries for React and Node.js projects, promoting scalable development.

Modern yazılım geliştirme pratiklerinde, projelerin karmaşıklığı ve ekip büyüklükleri arttıkça, kod tabanlarını yönetmek de giderek zorlaşıyor. Birçok geliştirici, her mikroservis veya frontend uygulaması için ayrı bir Git deposu (polyrepo) kullanma eğilimindedir. Ancak benim geliştirme tecrübelerimde, özellikle birbirine bağlı React frontend ve Node.js backend projeleri üzerinde çalışırken, bu "çoklu depo" yaklaşımının bazı noktalarda yönetimi zorlaştırdığını ve verimliliği düşürdüğünü gözlemledim. İşte tam bu noktada, Monorepo yaklaşımı güçlü bir alternatif olarak devreye giriyor.

Bu yazıda, React ve Node.js projeleriniz için monorepo yapısının ne olduğunu, neden bu yaklaşımı tercih etmeniz gerektiğini, kurulum adımlarını ve yaygın olarak kullanılan araçları detaylı bir şekilde inceleyeceğiz. Amacımız, tek bir Git deposu içinde birden fazla projenizi daha organize, ölçeklenebilir ve bakımı kolay bir şekilde yönetmenizi sağlayacak pratik bilgiler sunmak.

Monorepo Nedir? Polyrepo'dan Farkı

Monorepo (tekli depo), birden fazla projenin veya paketin aynı Git deposu içinde barındırıldığı bir yazılım geliştirme stratejisidir. Bu projeler tamamen bağımsız uygulamalar, paylaşılan kütüphaneler veya farklı mikroservisler olabilir. Öte yandan, polyrepo (çoklu depo) yaklaşımında ise her projenin veya mikroservisin kendine ait ayrı bir Git deposu bulunur.

Monorepo, sanılanın aksine tek bir devasa proje demek değildir; daha ziyade, ilişkili projelerin mantıksal olarak ayrık ama fiziksel olarak birleşik bir yapıda olmasını ifade eder. Google, Meta (eski adıyla Facebook), Microsoft gibi büyük teknoloji şirketleri, yıllardır bu yaklaşımı başarıyla kullanmaktadır.

A visual comparison diagram illustrating the key differences between monorepo and polyrepo project structures for software development.

Neden Monorepo Kullanmalıyız? Avantajları ve Faydaları

React ve Node.js gibi birbirini tamamlayan teknolojilerle geliştirme yaparken monorepo'nun sunduğu avantajlar göz ardı edilemez:

  • Kod Paylaşımı ve Yeniden Kullanılabilirlik: Frontend (React) ve backend (Node.js) arasında veya farklı React uygulamaları arasında ortak tipleri, doğrulama şemalarını, yardımcı fonksiyonları veya UI bileşenlerini kolayca paylaşabilirsiniz. Örneğin, API sözleşmelerinizi tanımlayan bir TypeScript arayüzü, hem Node.js API'nizde hem de React istemcinizde tek bir yerden yönetilebilir. Hatırlarsanız, React'te İleri Seviye Bileşen Desenleri yazımda da kod tekrarını önlemenin önemine değinmiştim.
  • Tutarlı Geliştirme Ortamı: Tüm projeleriniz aynı kodlama standartları, linting kuralları ve test yapılandırmaları ile yönetilebilir. Bu, geliştiriciler arasında tutarlılığı artırır ve yeni ekip üyelerinin projeye adaptasyonunu kolaylaştırır.
  • Basitleştirilmiş Bağımlılık Yönetimi: Projeler arası bağımlılıklar (örneğin, bir React uygulaması tarafından kullanılan paylaşılan bir bileşen kütüphanesi) çok daha kolay yönetilir. Lokal bağımlılıkları yayımlamak veya sembolik bağlar (symlink) oluşturmakla uğraşmanıza gerek kalmaz.
  • Atomik Değişiklikler: Bir özellik geliştirirken, bu özelliğin hem frontend hem de backend kısımlarını tek bir Git commit'i ile değiştirebilirsiniz. Bu, değişikliklerin senkronizasyonunu ve dağıtımını kolaylaştırır. Özellikle mikroservis mimarilerinde (Node.js ile Ölçeklenebilir Mikroservisler yazımda bahsettiğim gibi), atomik commit'ler, ilgili servislerin aynı anda güncellenmesi gerektiğinde büyük kolaylık sağlar.
  • Tekli CI/CD Pipeline'ları: Tek bir depo, genellikle tüm projeler için ortak veya koşullu tetiklenen CI/CD pipeline'ları oluşturmanıza olanak tanır. Bu da altyapı yönetimini basitleştirir.
  • Büyük Resme Hakimiyet: Geliştiriciler, tüm sistemin nasıl çalıştığına dair daha iyi bir genel bakışa sahip olur, bu da daha bilinçli mimari kararlar almalarına yardımcı olur.

Monorepo'nun Zorlukları ve Nasıl Üstesinden Gelinir?

Her mimari yaklaşımda olduğu gibi, monorepo'nun da kendi zorlukları vardır:

  • Öğrenme Eğrisi ve Araç Seçimi: Monorepo'ları yönetmek için Lerna, Nx, Turborepo gibi özel araçlara ihtiyaç duyulur. Bu araçların öğrenilmesi ve doğru şekilde yapılandırılması başlangıçta zaman alabilir.
  • Derleme ve Test Süreleri: Büyük monorepo'larda, tüm projeleri derlemek veya test etmek uzun sürebilir. Akıllı araçlar (Nx gibi) sadece değişen projeleri ve onlara bağımlı olanları test ederek bu sorunu azaltır.
  • Depo Büyüklüğü: Zamanla depo boyutu artabilir, bu da `git clone` sürelerini uzatabilir. Ancak modern Git versiyonları ve araçları (Sparse Checkout gibi) bu sorunu yönetilebilir kılar.
  • Erişim Kontrolü ve Güvenlik: Tüm kod tabanının tek bir yerde olması, erişim kontrolü stratejilerini daha kritik hale getirir. Tüm ekibin her şeye erişimi olması istenmeyebilir. Bu durum, organizasyonel politikalar ve Git sağlayıcınızın özellikleri ile yönetilebilir.
Diagram illustrating common monorepo challenges (blue boxes) and their effective solutions (green boxes).

Monorepo Araçları: Lerna ve Nx

Monorepo'ları yönetmek için birçok araç mevcuttur. En popüler ikisi Lerna ve Nx'tir:

Lerna

Lerna, npm veya yarn kullanarak birden fazla JavaScript/TypeScript projesini (paketini) yönetmeye yardımcı olan bir araçtır. Özellikle paylaşılan kütüphaneler ve bağımsız dağıtılabilir paketler için idealdir. Komutları ile bağımlılıkları yönetebilir, tüm paketlerde script çalıştırabilir ve versiyonlama/yayınlama süreçlerini kolaylaştırır.

Nx (Nrwl Extensible)

Nx, bir üst seviye monorepo aracıdır. Sadece paket yönetimi değil, aynı zamanda kod üretimi (schematics), etkilenen dosyaların tespiti (affected commands), akıllı önbellekleme ve dağıtılmış görev yürütme gibi gelişmiş özellikler sunar. React, Angular, Node.js, Next.js gibi birçok framework ve teknolojiyle entegre olabilir. Büyük ölçekli ve çok teknolojili monorepo'lar için daha güçlü bir çözümdür.

Lerna ile Basit Bir React ve Node.js Monorepo Kurulumu

Şimdi Lerna kullanarak basit bir monorepo yapısı oluşturalım. Bu örnekte bir React frontend uygulaması, bir Node.js API'si ve bu iki proje arasında paylaşılan bir `utils` kütüphanesi olacak.

Adım 1: Monorepo Oluşturma

mkdir my-monorepo
cd my-monorepo
npm init -y
npm install lerna --save-dev
npx lerna init

Bu komutlar, `lerna.json` ve `packages` klasörünü oluşturacak.

Adım 2: Paketleri Oluşturma

Şimdi `packages` klasörü içinde projelerimizi oluşturalım:

# React uygulaması (frontend)
npx create-react-app packages/frontend --template typescript

# Node.js API (backend)
mkdir packages/backend
cd packages/backend
npm init -y
npm install express --save
touch index.js

# Paylaşılan Utilities (shared)
mkdir packages/shared
cd packages/shared
npm init -y
touch index.ts # TypeScript kullanıyoruz diyelim

Örnek `packages/backend/index.js` içeriği:

const express = require('express');
const app = express();
const PORT = process.env.PORT || 4000;

app.get('/api/data', (req, res) => {
  res.json({ message: 'Merhaba, Monorepo Backend!' });
});

app.listen(PORT, () => {
  console.log(`Backend ${PORT} portunda çalışıyor.`);
});

Örnek `packages/shared/index.ts` içeriği:

export const greet = (name: string): string => {
  return `Merhaba, ${name}!`;
};

export interface ApiResponse {
  message: string;
}

Adım 3: Paketler Arası Bağımlılık Kurulumu

Şimdi `frontend` paketinin `shared` paketine bağımlılığını ekleyelim. Lerna ile bu çok kolaydır:

cd my-monorepo
npx lerna add shared packages/frontend

Bu komut, `packages/frontend/package.json` dosyasına `shared` paketini lokal bir bağımlılık olarak ekleyecektir. Şimdi `frontend` uygulamanızda `shared` paketini kullanabilirsiniz:

// packages/frontend/src/App.tsx
import React from 'react';
import { greet, ApiResponse } from 'shared'; // shared paketini import et

function App() {
  const [message, setMessage] = React.useState('');

  React.useEffect(() => {
    fetch('/api/data')
      .then(res => res.json())
      .then((data: ApiResponse) => setMessage(data.message));
  }, []);

  return (
    <div>
      <h1>{greet('React Uygulaması')} </h1> {/* shared paketini kullan */}
      <p>Backend Mesajı: {message}</p>
    </div>
  );
}

export default App;

Adım 4: Lerna Komutlarını Kullanma

Lerna, tüm paketlerde komut çalıştırmanıza olanak tanır:

  • Tüm paketlerin bağımlılıklarını kurmak: lerna bootstrap (Zaten lerna add sırasında bağımlılıklar kurulur.)
  • Tüm paketlerde `build` script'ini çalıştırmak: lerna run build
  • Tüm paketlerde `test` script'ini çalıştırmak: lerna run test

Özellikle `shared` paketi gibi TypeScript tabanlı kütüphaneler için `build` script'i önemlidir. `packages/shared/package.json` dosyanıza bir `build` script'i eklemeyi unutmayın (örneğin, `"build": "tsc"`).

Monorepo'da CI/CD ve Test Stratejileri

Monorepo'ların belki de en karmaşık görünen, ama doğru araçlarla en verimli hale getirilebilecek yönlerinden biri CI/CD ve test süreçleridir.

  • Akıllı Testler: Nx gibi araçlar, sadece son commit'ten etkilenen projeleri test etmenize olanak tanır. Örneğin, sadece `backend` klasöründeki bir değişiklik olduğunda `backend` testlerini çalıştırır, `frontend` testlerini es geçer. Bu, CI pipeline'larının süresini önemli ölçüde kısaltır.
  • Kademeli Dağıtım: Her paketin kendi dağıtım sürecine sahip olması mümkündür. Bir `backend` değişikliği sadece `backend` servisini yeniden dağıtırken, `frontend` değişikliği bir ön uç dağıtımını tetikleyebilir.
  • Versiyonlama ve Yayımlama: Lerna, monorepo içindeki paketlerin versiyonlarını yönetmek ve bunları npm'e veya özel bir depoya yayımlamak için güçlü araçlar sunar (`lerna publish`).

Bu konularda daha derinlemesine bilgi almak için Node.js ve Express.js'te Güçlü Hata Yönetimi veya React Native Uygulamalarında Performans Optimizasyonu gibi yazılarımda bahsettiğim gibi, sürekli entegrasyon ve dağıtımın (CI/CD) bir projenin başarısı için ne kadar kritik olduğunu hatırlatmak isterim. Monorepo yapısı, bu süreçleri tek bir çatı altında daha tutarlı hale getirme potansiyeli taşır.

Conceptual diagram illustrating Continuous Integration and Continuous Delivery (CI/CD) strategies optimized for monorepo projects and effective testing.

Sonuç

React ve Node.js projelerinde monorepo kullanımı, geliştirme sürecinizi dönüştürebilecek güçlü bir yaklaşımdır. Kod paylaşımını artırarak, bağımlılık yönetimini basitleştirerek ve takım içi işbirliğini güçlendirerek hem verimliliği hem de kod kalitesini önemli ölçüde artırabilir. Başlangıçta bir öğrenme eğrisi olsa da, Lerna veya Nx gibi doğru araçlarla bu zorlukların üstesinden gelmek mümkündür.

Eğer siz de projelerinizin büyümesiyle artan karmaşıklıktan şikayetçiyseniz veya birden fazla ilişkili projeyi daha entegre bir şekilde yönetmek istiyorsanız, monorepo yaklaşımına mutlaka bir şans vermelisiniz. Unutmayın, en iyi mimari, projenizin mevcut ve gelecekteki ihtiyaçlarına en iyi cevap veren mimaridir.

Eğer aklınıza takılan sorular olursa veya bu konularda daha derinlemesine bilgi almak isterseniz, bana ismailyagci371@gmail.com adresinden veya sosyal medya kanallarından benimle (İsmail YAĞCI) iletişime geçebilirsiniz. Sağlıklı ve başarılı kodlamalar dilerim!

Orijinal yazı: https://ismailyagci.com/articles/react-ve-nodejs-projelerinde-monorepo-kullanimi-olceklenebilir-gelistirme-icin-modern-yaklasim

Yorumlar

Bu blogdaki popüler yayınlar

Node.js ile Ölçeklenebilir Mikroservisler: Adım Adım Bir Mimari Kılavuzu

JavaScript ve Node.js'te Tasarım Desenleri: Uygulamanızı Güçlendirin ve Ölçeklendirin

Anlık Etkileşim: Node.js, WebSockets ve Socket.IO ile Gerçek Zamanlı Uygulama Geliştirme Rehberi