Mimari Prensipler ve Desenler Terimler Sözlüğü
Architectural Principles and Patterns Glossary
Bu bölümde ki terimleri ezberlemenize gerek yoktur.
Konular içerisinde ki terimlerdir, sadece
konuyu daha iyi anlamanıza yardımcı olması
için eklenmiştir.
Bir sistemin genel topolojisini ve yönünü belirleyen, yapısal problemlere kanıtlanmış çözümler
sunan üst
seviye desenler. MVC, Microservices, EDA gibi örnekleri
vardır.
Yazılım tasarımında beş temel prensip: Single Responsibility,
Open/Closed,
Liskov Substitution, Interface Segregation,
Dependency Inversion.
Kodun bakımını ve genişletilmesini kolaylaştırır.
Mimarinin fonksiyonel olmayan gereksinimlerini belirleyen nitelikler: Performans, Ölçeklenebilirlik, Güvenlik, Dayanıklılık, Bakım Kolaylığı. Sistemin kalitesini ölçen metrikler.
Uygulama mantığını üç bileşene ayıran mimari desen: Model (veri), View
(kullanıcı arayüzü), Controller (iş mantığı). View güncellemesi imperatif (manuel)
yapılır.
View'in durumunu hazırlayan ViewModel katmanı içeren mimari desen. İki yönlü veri
bağlama
(two-way binding) ile View güncellemesi otomatik olur. Vue.js,
Knockout.js
kullanır.
Uygulamayı bağımsız, küçük servislere bölen mimari desen. Her servis kendi veritabanına sahiptir ve API Gateway üzerinden iletişim kurar. Yatay ölçeklenebilirlik sağlar.
Bileşenlerin olaylar (events) aracılığıyla gevşek bağlı şekilde iletişim kurduğu mimari. Olay veriyolu (Event Bus) veya mesaj kuyrukları (Queue) kullanır. Yüksek ölçeklenebilirlik sağlar.
Tek yönlü veri akışı (unidirectional data flow) sağlayan mimari desen. Action →
Dispatcher → Store → View döngüsü ile durum yönetimini
merkezileştirir.
Uygulamayı bağımsız, yeniden kullanılabilir bileşenlere (components) ayıran mimari.
React,
Vue gibi framework'ler bu yaklaşımı kullanır. SRP'nin UI düzeyinde uygulanmasıdır.
Sistemin sorumluluklara göre katmanlara ayrıldığı mimari: Sunum (Presentation), İş Mantığı (Business), Veri Erişim (Data Access). Her katman yalnızca altındaki katmana bağımlıdır.
Sunucunun kullanıcı oturumu gibi verileri kendi belleğinde tutmadığı tasarım. Durum harici, paylaşılan depolamada (Redis gibi) tutulur. Yatay ölçeklenebilirlik için kritiktir.
Tüm dış trafiğin geçtiği merkezi giriş noktası. Kimlik doğrulama (AuthN), yetkilendirme (AuthZ), hız sınırlama (rate limiting) gibi görevleri üstlenir. Mikroservis mimarisinde zorunludur.
Sürekli başarısız olan bir servise yapılan çağrıları geçici olarak durduran desen. Arızalı servise iyileşme zamanı tanır ve kaynak tüketimini önler. Dayanıklılık (Resilience) için kritiktir.
Kriptografik olarak imzalanmış, kullanıcı kimliğini taşıyan token formatı. Stateless kimlik doğrulama sağlar. API Gateway veya servisler token'ı yerel olarak doğrulayabilir.
Sistemi aynı uygulamanın yeni kopyalarını (instance) ekleyerek ölçekleme. Stateless tasarım gerektirir. Teorik olarak sonsuz ölçeklenebilirlik sağlar ve arızaya karşı dayanıklıdır.
Mevcut tek bir sunucunun kaynaklarını (CPU, RAM) artırarak ölçekleme. Başlangıçta kolaydır ancak donanım limitleri nedeniyle sınırlıdır. Tek Arıza Noktası (SPOF) riskini artırır.
Sistem içindeki hiçbir bileşene veya kullanıcıya varsayılan olarak güvenilmeyen güvenlik modeli. Her istek, kaynağı ne olursa olsun doğrulanmalıdır. Dağıtık sistemlerde kritiktir.
Verinin sistemde sadece bir yönde (Action → Dispatcher → Store → View) akmasını sağlayan
prensip.
Durumun öngörülebilirliğini garanti eder. Flux ve Redux bu prensibi
kullanır.
Gelen trafiği yatay ölçeklenen sunucu kopyalarına eşit ve verimli şekilde dağıtan bileşen. Hizmet kesintisi olmadan kaynak yönetimi sağlar. Mikroservis mimarisinde zorunludur.
Verinin mantıksal olarak birden fazla veritabanı sunucusuna bölünmesi. Veri hacmi yüksek sistemler için hayati öneme sahiptir. Tek bir veritabanının kapasite limitine ulaşmasını engeller.
Mimari Prensipleri ve Desenleri ( Ana Konu Giriş )
Mimari prensipleri ve desenleri, JavaScript'te kod yapısını daha modüler,
okunaklı
ve bakımı kolay hale getirmek için kullanılan prensipler ve desenlerdir.
Bu bölümde, mimari
prensipleri ve desenlerinin detaylarını inceleyeceğiz.
Ana Konuya Giriş ve Detaylı Açıklama Mimari Prensipler ve Desenler
Mimari, bir yazılım sisteminin sadece ne yaptığını ( fonksiyonel gereksinimler ) değil, aynı zamanda bu işi ne kadar performanslı, güvenli ve sürdürülebilir yaptığını belirleyen yüksek seviyeli tasarım kararları kümesidir.
Bu yapısal omurgayı kurarken mühendislik dünyası iki temel rehberi pusula kabul eder: Mimari Desenler ve Mimari Prensipler.
Mimari Desenler (Architectural Patterns)Mimari desenler, sistem düzeyindeki yaygın ve karmaşık yapısal sorunlara yönelik, doğruluğu binlerce projede kanıtlanmış
makro çözümlerdir.
Sistem Topolojisi: Bir projenin ana haritasını ( topolojisini ) belirlerler.
Bir uygulamanın Katmanlı Mimari ( Layered ) ile mi, yoksa bağımsız parçalardan oluşan Mikroservis ( Microservices ) tabanlı mı inşa edileceği kararı, doğrudan bir mimari desen seçimidir.
Tasarım desenleri bu yapıların içindeki odaları düzenlerken, mimari desenler binanın genel projesini çizer.
Mimari Prensipler (Architectural Principles)Mimari prensipler, desenler uygulanırken veya yeni kod blokları sisteme dahil edilirken uyulması gereken evrensel kılavuz ilkelerdir.
Sürdürülebilirlik Garantisi: Gevşek Bağlılık , Yüksek Uyum ve SOLID gibi prensipler, sistemin parçalarının birbirinden bağımsız, anlaşılır ve esnek kalmasını sağlar.
Bu ilkeler, yazılımın zaman içinde bir "kod yığınına" dönüşmesini engelleyerek uzun vadeli hayatta kalma kabiliyetini garanti eder.
Sonuç olarak; Mimari Desenler bize "şablonu" sunarken, Mimari Prensipler bu şablonu doldururken kullanacağımız "etik ve teknik disiplini" temsil eder.
Temel Mimari Prensiplerin Odak Noktası Mimari Prensipleri ve Desenleri
Mimari desenler bir sistemin yapısal haritasını ve fiziksel sınırlarını çizerken; mimari prensipler, o sistemin içindeki tüm bileşenlerin istisnasız uyması gereken yüksek seviyeli davranış kurallarını ve felsefi ilkeleri belirler.
Bu prensipler, sadece bir yazılımın "doğru çıktı" üretmesiyle ilgilenmez.
Nihai ürünün sürdürülebilir, esnek ve hataya dayanıklı olmasını garanti altına alan mimari birer yol göstericidir.
Karmaşıklık Yönetimi ve Uzun ÖmürlülükÖzellikle JavaScript gibi ekosistemi ve kütüphaneleri hızla değişen dillerde, bu prensiplere sadık kalmak projenin yaşam süresini belirleyen en kritik etkendir.
Teknolojiler değişse bile, sağlam prensipler üzerine kurulu bir mimari, iş mantığını ( business logic ) korumayı başarır.
Sonuç olarak mimari prensipler; bir sistemin sadece teknik başarısını değil, aynı zamanda mühendislik kalitesini ve gelecekteki değişim rüzgarlarına karşı sergileyeceği direnci belirleyen temel değerlerdir.
SOLID Prensipleri JavaScript Mimarisi İçin Kritik Bir Temel
SOLID, yazılım dünyasının duayenlerinden Robert C. Martin ( Uncle Bob ) tarafından popülerleştirilen ve Nesne Yönelimli Tasarımın ( OOD ) beş temel direğini temsil eden bir akronimdir.
Bu prensipler, geleneksel olarak Java veya C# gibi kesin tiplemeli ( statically-typed ) dillerin tekelinde görülse de; modern JavaScript'in gelişmiş sınıf yapıları, modüler sistemleri
ve devasa ölçekli uygulama ekosistemleri ( Node.js , React, , Angular ) için hayati bir mimari pusula haline gelmiştir.
Felsefi Amaç: Esneklik ve Yeniden KullanılabilirlikSOLID'in temel varoluş amacı, kod tabanının değişime karşı direncini kırmak ve sistemi anlaşılır, esnek ve modüler bir yapıya kavuşturmaktır.
Sürdürülebilirlik: Tasarım desenleri genellikle belirli bir problemi çözmek için "nasıl" sorusuna cevap verirken; SOLID prensipleri, bu desenleri uygularken "hangi etik ve teknik kurallara" uymamız gerektiğini belirler.
Bu disiplin, projenin aylar hatta yıllar sonra bile teknik borç altında ezilmeden büyümesini sağlar.
Bileşenlerin AnotomisiSOLID, beş temel kuralın birleşiminden oluşur:
S (Single Responsibility): Her bileşenin sadece tek bir işi ve sorumluluğu olmalıdır.
O (Open/Closed): Kodlar genişlemeye açık, ancak mevcut yapıyı değiştirmeye kapalı olmalıdır.
L (Liskov Substitution): Alt sınıflar, üst sınıfların yerine hiçbir sorun çıkarmadan geçebilmelidir.
I (Interface Segregation): Kullanılmayan metotlar içeren devasa arayüzler yerine, özelleşmiş küçük yapılar tercih edilmelidir.
D (Dependency Inversion): Yüksek seviyeli modüller, düşük seviyeli detaylara değil; soyutlamalara bağımlı olmalıdır.
Sonuç olarak SOLID, yazılım mimarisini "yaz-geç" mantığından kurtarıp, her parçanın neden-sonuç ilişkisiyle birbirine bağlandığı profesyonel bir mühendislik sanatına dönüştürür.
Single Responsibility Principle Tek Sorumluluk Prensibi
Tek Sorumluluk Prensibi , bir sınıfın, modülün veya fonksiyonun değişmesi için yalnızca tek bir nedeninin olması gerektiğini savunur.
Basitçe ifade etmek gerekirse; her yapı taşı, sistem içinde yalnızca tek bir sorumluluğu üstlenmelidir.
Sınırları Belirlemek: Bir bileşeni, farklı paydaş gruplarının ( bir veritabanı yöneticisi ile bir iş analisti gibi ) talepleriyle ayrı ayrı değiştirmek zorunda kalıyorsanız, o bileşen muhtemelen birden fazla sorumluluk yüklenmiştir.
JavaScript ve Modülerlik UygulamasıModern JavaScript mimarisinde, özellikle ES Modülleri kullanılırken bu prensip hayati önem taşır.
Bir Node.js modülü veya bir React bileşeni, hem veri erişimini yönetip hem de karmaşık iş mantığını barındırmamalıdır.
Pratik Örnek: Bir UserService.js dosyası düşünün; Bu dosya hem veritabanına sorgu atıyor hem de kullanıcıya hoş geldin e-postası gönderiyorsa, SRP ihlal edilmiş demektir ve bu iki işlem birbirinden ayrılmalı, servis sadece iş mantığına odaklanmalıdır.
Prensibin Derinlemesine FelsefesiDomino Etkisini Engellemek: SRP'nin ana amacı, kod tabanında oluşabilecek "zincirleme hata" riskini ortadan kaldırmaktır.
Bir modül birden fazla iş yapıyorsa, bir özelliği güncellerken ilgisiz bir diğer özelliği kazara bozma riskiniz her zaman yüksektir.
Yüksek Uyum (High Cohesion): SRP'yi uygulamak, Yüksek Uyum ve Gevşek Bağlılık hedeflerine ulaşmanın ilk adımıdır.
Sorumlulukları ayrılmış bileşenler, çok daha kolay test edilebilir, hata ayıklanabilir ve farklı projelerde yeniden kullanılabilir hale gelir.
Sonuç olarak SRP, yazılım bileşenlerine "tek bir işi mükemmel yapma" disiplini getirerek, sistemin karmaşıklık karşısında direncini artıran mimari bir zırh görevi görür.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mimari Analiz Aracı Örneği</title>
<link rel="stylesheet" href="srp-mimari.css?v=1.0.150">
</head>
<body>
<div class="srp-container">
<div class="header">
<h2>Byteomi Architecture Lab: SRP Analizi</h2>
</div>
<div class="action-bar">
<button id="registerBtn" class="btn-register">Kullanıcı Kaydet (registerUser)</button>
</div>
<div class="architecture-grid">
<div id="card-service" class="module-card">
<h4>User Service</h4>
<div class="module-icon">⚙️</div>
<p style="font-size: 11px;">Orkestrasyon & Mantık</p>
</div>
<div id="card-repository" class="module-card">
<h4>User Repository</h4>
<div class="module-icon">📂</div>
<p style="font-size: 11px;">Veri Erişimi (DB)</p>
</div>
<div id="card-email" class="module-card">
<h4>Email Service</h4>
<div class="module-icon">📧</div>
<p style="font-size: 11px;">Bildirim Servisi</p>
</div>
</div>
<div id="terminal" class="terminal-output">
<div class="log-entry">> Sistem hazır. İşlem bekleniyor...</div>
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--blueprint-bg: #0f172a;
--module-card: #1e293b;
--accent-blue: #38bdf8;
--accent-green: #4ade80;
--text-white: #f8fafc;
--border-color: #334155;
}
body {
background-color: var(--blueprint-bg);
color: var(--text-white);
font-family: 'Fira Code', monospace;
/* Teknik bir hava için */
padding: 40px;
}
.srp-container {
max-width: 900px;
margin: 0 auto;
}
.header {
border-bottom: 2px solid var(--accent-blue);
margin-bottom: 30px;
padding-bottom: 10px;
}
/* Modüllerin Izgarası */
.architecture-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
margin-bottom: 40px;
position: relative;
}
.module-card {
background: var(--module-card);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 15px;
text-align: center;
transition: all 0.3s ease;
}
.module-card.active {
border-color: var(--accent-green);
box-shadow: 0 0 15px rgba(74, 222, 128, 0.2);
}
.module-card h4 {
color: var(--accent-blue);
margin-top: 0;
font-size: 0.9rem;
}
.module-icon {
font-size: 2rem;
margin: 10px 0;
}
/* Konsol Çıktısı Alanı */
.terminal-output {
background: #000;
border-radius: 6px;
padding: 20px;
height: 200px;
overflow-y: auto;
font-size: 13px;
line-height: 1.6;
border-left: 4px solid var(--accent-blue);
}
.log-entry {
margin-bottom: 5px;
}
.log-repo {
color: #fbbf24;
}
/* Amber */
.log-email {
color: #a78bfa;
}
/* Violet */
.log-success {
color: var(--accent-green);
font-weight: bold;
}
.action-bar {
text-align: center;
margin-bottom: 30px;
}
.btn-register {
background: var(--accent-blue);
color: var(--blueprint-bg);
border: none;
padding: 12px 30px;
font-weight: bold;
border-radius: 4px;
cursor: pointer;
font-family: inherit;
}
.btn-register:hover {
opacity: 0.9;
transform: translateY(-2px);
}
import { UserRepository } from './user-repository.js';
import { EmailService } from './email-service.js';
import { UserService } from './user-service.js';
const terminal = document.getElementById('terminal');
const registerBtn = document.getElementById('registerBtn');
// Terminale yazdırma yardımcı fonksiyonu
function logToTerminal(msg, className = '') {
const div = document.createElement('div');
div.className = `log-entry ${className}`;
div.innerText = `> ${msg}`;
terminal.appendChild(div);
terminal.scrollTop = terminal.scrollHeight;
}
// Modül kartını parlatma
function highlightCard(id) {
document.querySelectorAll('.module-card').forEach(c => c.classList.remove('active'));
document.getElementById(id).classList.add('active');
}
// Örneğini Başlatma
const userRepository = new UserRepository();
const emailService = new EmailService();
const userService = new UserService(userRepository, emailService);
registerBtn.addEventListener('click', () => {
terminal.innerHTML = ''; // Temizle
const userData = { username: "byteomi_user", password: "secure_pass" };
try {
logToTerminal("UserService.registerUser() çağrıldı.", "log-success");
highlightCard('card-service');
setTimeout(() => {
logToTerminal("[Repository] Kayıt yapılıyor...", "log-repo");
highlightCard('card-repository');
const user = userRepository.save(userData);
setTimeout(() => {
logToTerminal("[EmailService] Hoş geldin e-postası tetiklendi.", "log-email");
highlightCard('card-email');
emailService.sendWelcome(user);
setTimeout(() => {
logToTerminal(`Kayıt Başarılı! ID: ${user.id}`, "log-success");
document.querySelectorAll('.module-card').forEach(c => c.classList.add('active'));
}, 600);
}, 600);
}, 600);
} catch (error) {
logToTerminal(`Hata: ${error.message}`, "log-repo");
}
});
// user-repository.js (Sadece Veri Erişimi)
export class UserRepository {
save(userData) {
console.log(
`[Repository] Kullanıcı ${userData.username} veritabanına kaydedildi.`,
);
// Veritabanı sürücüsü (MongoDB/PostgreSQL) ile konuşur.
return { id: Math.random().toString(36).substring(2, 9), ...userData };
}
}
// email-service.js (Sadece Bildirim)
export class EmailService {
sendWelcome(user) {
console.log(
`[EmailService] ${user.username} adresine hoş geldiniz e-postası gönderildi.`,
);
// SMTP veya mail API ile konuşur.
}
}
// user-service.js (Sadece İş Akışı Mantığı)
import { UserRepository } from "./user-repository.js";
import { EmailService } from "./email-service.js";
export class UserService {
constructor(userRepository, emailService) {
// Bağımlılıklar dışarıdan enjekte edilir (DIP ilkesine de uyum).
this.userRepository = userRepository;
this.emailService = emailService;
}
registerUser(userData) {
if (!this.validate(userData)) {
throw new Error("Geçersiz kullanıcı verisi.");
}
// Sorumluluklar delege edilir:
const user = this.userRepository.save(userData);
this.emailService.sendWelcome(user);
console.log(`[UserService] Kayıt işlemi başarıyla tamamlandı.`);
return user;
}
validate(data) {
return data.username && data.password && data.username.length > 3;
}
}
Open/Closed Principle Açık/Kapalı Prensibi
Açık/Kapalı Prensibi, yazılım varlıklarının genişletilmeye açık, ancak mevcut kodun değiştirilmesine kapalı olması gerektiğini savunur.
Temel Mantık: Yeni bir özellik eklemek istediğinizde, halihazırda çalışan, test edilmiş ve canlı ortamda güvenle hizmet veren kod bloklarına dokunmamalısınız. Bunun yerine, sistemi bu yeni özelliği kabul edecek şekilde "genişletmelisiniz".
JavaScript ve Strateji Odaklı UygulamaJavaScript'te bu prensibi uygulamanın en etkili yolu, devasa if/else veya switch/case bloklarından kaçınmaktır.
Pratik Örnek: Bir raporlama modülünüz olduğunu düşünün ve sisteme "PDF Raporu" özelliğinden sonra "Excel Raporu" eklemek istediğinizde, ana raporlama sınıfının içine girip yeni bir if (tip === 'excel') satırı yazıyorsanız OCP'yi ihlal ediyorsunuz demektir.
Doğru Yaklaşım: Strateji Deseni kullanarak her rapor formatını ayrı bir nesne olarak tanımlamak ve ana sınıfa bu nesneyi dışarıdan enjekte etmektir.
Böylece ana kod sabit kalırken, siz sınırsız sayıda yeni format ekleyebilirsiniz.
Prensibin Derinlemesine Mimari AnaliziStabilite ve Hız Dengesi: OCP, sistemin yeni isteklere hızla cevap verebilmesi ile mevcut kararlılığını koruması arasındaki hassas dengeyi kurar.
Bir mimarın, binaya yeni bir kat çıkmak için ana taşıyıcı kolonları ve duvarları yıkmak yerine, en baştan hazır bir kolon sistemi bırakması tam olarak bu prensibi yansıtır.
Hantallaşmayı Önleme: OCP'nin ihlal edildiği sistemlerde, merkezi modüller zamanla "tanrı nesnelere" dönüşür.
Her yeni özellik bu merkezi modülü daha hantal, daha zor anlaşılan ve en küçük bir dokunuşta her yeri bozulan ( brittle ) bir yapıya sürükler.
Sonuç olarak OCP, yazılımı "yama yapılan bir örtü" olmaktan çıkarıp, üzerine sürekli yeni ve sağlam modüller eklenebilen
"evrensel bir platform" haline getirir.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Open/Closed Principle (OCP)</title>
<link rel="stylesheet" href="ocp-style.css?v=1.0.150">
</head>
<body>
<div class="ocp-lab">
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi OCP Strategy Pattern Lab
<span class="lang-icon"><i class="fab fa-html5"></i></span>
<span class="lang-icon"><i class="fab fa-css3-alt"></i></span>
<span class="lang-icon"><i class="fab fa-js"></i></span>
</div>
</div>
</div>
<div class="terminal-ui">
<div class="payment-options">
<h3>Ödeme Yöntemi</h3>
<p style="font-size: 12px; color: #666;">Mevcut kodu bozmadan yeni strateji seçin:</p>
<button class="btn-pay active" data-type="credit">Kredi Kartı (Mevcut)</button>
<button class="btn-pay" data-type="eft">EFT/Havale (Yeni Genişletme)</button>
<div style="margin-top: 20px;">
<strong>Tutar: 250.75 TL</strong>
<button id="executePay" style="margin-top:10px; background: var(--success-green); color:white;"
class="btn-pay">Ödemeyi İşle</button>
</div>
</div>
<div class="pos-screen">
<div id="pos-display" class="display">
> POS Hazır...
</div>
<div class="ocp-badge">
<strong>Mimari Durum:</strong> OdemeYoneticisi kaynak kodu değiştirilmeden davranış genişletiliyor.
</div>
</div>
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
/* byteomi.com - OCP Architecture Lab Styles */
:root {
--pos-bg: #2d3436;
--screen-bg: #dfe6e9;
--accent-orange: #e67e22;
--accent-blue: #0984e3;
--success-green: #27ae60;
--text-dark: #2d3436;
--bg-light: #f1f2f6;
}
body {
background-color: #f8fafc;
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
margin: 0;
padding: 20px;
}
/* Üst Başlık Etiketi Tasarımı */
.code-type-label {
background: #fff;
border-radius: 8px 8px 0 0;
border: 1px solid #e2e8f0;
border-bottom: none;
padding: 12px 20px;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Courier New', monospace;
font-weight: bold;
color: var(--accent-blue);
background: #e0f2fe;
padding: 5px 10px;
border-radius: 4px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
color: #475569;
display: flex;
align-items: center;
gap: 10px;
}
.lang-icon {
font-size: 16px;
opacity: 0.7;
}
/* Ana Konteyner */
.ocp-lab {
max-width: 900px;
margin: 40px auto;
background: white;
border-radius: 12px;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
overflow: hidden;
border: 1px solid #e2e8f0;
}
.terminal-ui {
display: grid;
grid-template-columns: 350px 1fr;
gap: 0;
border-top: 1px solid #e2e8f0;
}
/* Sol Panel: Ödeme Seçenekleri */
.payment-options {
padding: 30px;
border-right: 1px solid #e2e8f0;
background: #ffffff;
}
.payment-options h3 {
margin-top: 0;
font-size: 1.25rem;
color: var(--text-dark);
}
.btn-pay {
width: 100%;
padding: 14px;
margin: 8px 0;
border: 2px solid #e2e8f0;
border-radius: 10px;
background: #fff;
cursor: pointer;
font-weight: 600;
font-size: 14px;
transition: all 0.2s ease;
text-align: center;
}
.btn-pay:hover {
border-color: var(--accent-blue);
background: #f0f9ff;
}
.btn-pay.active {
background: var(--accent-blue);
color: white;
border-color: var(--accent-blue);
box-shadow: 0 4px 6px -1px rgba(9, 132, 227, 0.3);
}
#executePay {
background: var(--success-green);
color: white;
border: none;
margin-top: 15px;
}
#executePay:hover {
background: #219150;
transform: translateY(-1px);
}
/* Sağ Panel: POS Ekranı */
.pos-screen {
background: #1e293b;
/* Koyu Dashboard rengi */
padding: 30px;
display: flex;
flex-direction: column;
justify-content: center;
}
.display {
background: var(--screen-bg);
height: 220px;
border-radius: 8px;
padding: 20px;
font-family: 'Fira Code', 'Courier New', monospace;
font-size: 13px;
color: var(--text-dark);
overflow-y: auto;
border: 6px solid #334155;
line-height: 1.6;
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
}
.ocp-badge {
margin-top: 20px;
padding: 12px;
background: rgba(230, 126, 34, 0.1);
border: 1px dashed var(--accent-orange);
border-radius: 6px;
color: #ff9f43;
font-size: 11px;
text-align: center;
line-height: 1.4;
}
/* Mobil Uyumluluk */
@media (max-width: 850px) {
.terminal-ui {
grid-template-columns: 1fr;
}
.payment-options {
border-right: none;
border-bottom: 1px solid #e2e8f0;
}
.ocp-lab {
margin: 10px;
}
}
import { OdemeStratejisi } from "./odeme-stratejisi.js";
import { OdemeYoneticisi } from "./odeme-yoneticisi.js";
import { KrediKartiStratejisi } from "./kredi-karti-stratejisi.js";
// OCP uyarınca sistemi GENİŞLETİYORUZ (Yeni dosya gibi düşün)
class EFTStratejisi extends OdemeStratejisi {
odemeYap(tutar) {
return `[EFT/HAVALE] ${tutar} TL için banka onayı bekleniyor...`;
}
}
const display = document.getElementById("pos-display");
const executeBtn = document.getElementById("executePay");
let selectedStrateji = new KrediKartiStratejisi();
const yonetici = new OdemeYoneticisi(selectedStrateji);
// Görsel seçim mantığı
document.querySelectorAll(".btn-pay[data-type]").forEach((btn) => {
btn.addEventListener("click", (e) => {
document
.querySelectorAll(".btn-pay")
.forEach((b) => b.classList.remove("active"));
e.target.classList.add("active");
if (e.target.dataset.type === "eft") {
selectedStrateji = new EFTStratejisi();
yonetici.setOdemeStratejisi(selectedStrateji);
} else {
selectedStrateji = new KrediKartiStratejisi();
yonetici.setOdemeStratejisi(selectedStrateji);
}
});
});
executeBtn.addEventListener("click", () => {
const tutar = 250.75;
const log = (msg) => {
display.innerHTML += `<div> > ${msg} </div>`;
display.scrollTop = display.scrollHeight;
};
display.innerHTML = "> İşlem Başlatıldı...<br>";
// OdemeYoneticisi içindeki if/else yapısına dokunmadan çalışır!
const resultMsg = yonetici.strateji.odemeYap(tutar);
log(resultMsg);
setTimeout(() => {
log("İşlem Başarılı.");
log("Fatura Kesildi.");
}, 800);
});
// odeme-stratejisi.js
export class OdemeStratejisi {
// Tüm somut stratejilerin uygulaması gereken metot.
odemeYap(tutar) {
throw new Error("odemeYap metodu alt sınıflarda uygulanmalıdır.");
}
}
// odeme-yoneticisi.js
// Dikkat: Bu sınıf, somut stratejilerin (KrediKartiStratejisi) iç detaylarını bilmez.
export class OdemeYoneticisi {
constructor(odemeStratejisi) {
// Strateji dışarıdan enjekte edilir (Bileşim).
this.strateji = odemeStratejisi;
}
// 💡 GENİŞLETİLMEYE AÇIK: Yeni strateji ile davranış değiştirilebilir.
setOdemeStratejisi(yeniStrateji) {
this.strateji = yeniStrateji;
}
// 💡 DEĞİŞTİRMEYE KAPALI: Kaynak kodu if/else içermez.
odemeIsle(tutar) {
if (this.strateji.odemeYap(tutar)) {
console.log("-> İşlem başarılı. Fatura kesiliyor.");
return true;
}
console.error("-> İşlem başarısız.");
return false;
}
}
// kredi-karti-stratejisi.js
import { OdemeStratejisi } from "./odeme-stratejisi.js";
export class KrediKartiStratejisi extends OdemeStratejisi {
odemeYap(tutar) {
console.log(`[KREDİ KARTI] ${tutar} TL tutar, kart ile işleniyor.`);
return true;
}
}
Liskov Substitution Principle Liskov Değiştirme Prensibi
Liskov Değiştirme Prensibi , bir üst sınıfın ( parent ) kullanıldığı her yerde, ondan türeyen alt sınıfların ( child ) sistemin işleyişini ve davranışsal bütünlüğünü bozmadan kullanılabilmesi gerektiğini savunur.
Davranışsal Sözleşme: Alt sınıflar, sadece üst sınıfın metot isimlerini değil, aynı zamanda o metotların vaat ettiği mantıksal sonuçları ve işleyiş kurallarını da korumalıdır.
JavaScript ve Mantıksal TutarlılıkJavaScript'in dinamik yapısı, sınıflar arası geçişleri kolaylaştırsa da LSP ihlallerine de kapı aralar.
Bir üst sınıftan devralınan bir metodun, alt sınıfta "içinin boşaltılması" veya "hata fırlatacak şekilde değiştirilmesi" bu prensibin en büyük düşmanıdır.
Pratik Örnek: Bir Hayvan sınıfının yemekYe() metodu olduğunu varsayalım.
Bu sınıftan türeyen bir OyuncakKedi sınıfı, "ben gerçek bir kedi değilim, yemek yiyemem" diyerek bu metot içinde bir Error fırlatıyorsa, bu net bir LSP ihlalidir.
Çünkü Hayvan tipinde bir nesne bekleyen ve yemekYe() metodunu çağıran bir kod bloğu, OyuncakKedi ile karşılaştığında beklenmedik şekilde çökecektir.
Prensibin Derinlemesine Teknik KriterleriLSP, kalıtımın sadece "şekilsel" değil, "mantıksal" bir uyum içinde olmasını şu kriterlerle sağlar:
Önkoşulların Güçlendirilmemesi: Alt sınıf, üst sınıfa göre daha katı kurallar veya parametreler talep etmemelidir.
Eğer üst sınıf her sayıyı kabul ediyorsa, alt sınıf "sadece pozitif sayıları kabul ederim" diyemez.
Sonkoşulların Zayıflatılmamasını: Üst sınıfın garanti ettiği çıktıları alt sınıf da sağlamalıdır.
Üst sınıf bir "obje" döndüreceğini vaat ediyorsa, alt sınıf "null" döndürerek bu sözü bozmamalıdır.
İstisna Yönetimi: Üst sınıfın sözleşmesinde yer almayan, tamamen yeni ve yabancı hata türleri alt sınıfta fırlatılmamalıdır.
Sonuç olarak LSP, kalıtım hiyerarşisini "mantıksal bir mayın tarlası" olmaktan çıkarıp, modüllerin birbirinin yerine güvenle geçebildiği sağlam bir mimari zincire dönüştürür.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LSP Behavior & Compatibility Lab</title>
<link rel="stylesheet" href="lsp-style.css?v=1.0.150">
</head>
<body>
<div class="lsp-lab">
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi LSP Behavior & Compatibility Lab
<span class="lang-icon"><i class="fab fa-html5"></i></span>
<span class="lang-icon"><i class="fab fa-css3-alt"></i></span>
<span class="lang-icon"><i class="fab fa-js"></i></span>
</div>
</div>
</div>
<div class="hierarchy-viz">
<div class="node parent-node">BildirimGonderici<br>(Parent/Base)</div>
<div class="connector-arrow">←</div>
<div class="node child-node">EmailGonderici<br>(LSP Uyumlu)</div>
<div class="connector-arrow">←</div>
<div class="node child-node violation">SmsGonderici<br>(LSP İhlali)</div>
</div>
<div class="test-controls">
<h4>Simülasyonu Başlat</h4>
<p class="test-description">Aynı fonksiyonu farklı nesnelerle çalıştırın:</p>
<div class="control-btns">
<button id="btn-base" class="btn-test btn-base">Base Class Test</button>
<button id="btn-email" class="btn-test btn-email">Email Class Test (OK)</button>
<button id="btn-sms" class="btn-test btn-sms">SMS Class Test (VIOLATION)</button>
</div>
</div>
<div id="lsp-console" class="lsp-terminal">
> Sistem analizi için bir test seçin...
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
/* byteomi.com - LSP Architecture Lab Styles */
:root {
--lsp-parent: #2980b9;
--lsp-child-ok: #27ae60;
--lsp-child-fail: #e74c3c;
--terminal-bg: #1e293b;
--text-light: #d2dae2;
--accent-blue: #38bdf8;
--bg-main: #f8fafc;
}
body {
background-color: var(--bg-main);
font-family: 'Inter', -apple-system, sans-serif;
margin: 0;
padding: 20px;
}
/* Üst Başlık Etiketi Tasarımı */
.code-type-label {
background: #fff;
border-radius: 12px 12px 0 0;
border: 1px solid #e2e8f0;
border-bottom: none;
padding: 15px 20px;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
/* Mobilde taşmayı önler */
}
.code-type-icon {
font-family: 'Courier New', monospace;
font-weight: bold;
color: var(--lsp-parent);
background: #e0f2fe;
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
color: #475569;
display: flex;
align-items: center;
gap: 10px;
}
.lang-icon {
font-size: 18px;
color: #94a3b8;
}
/* Ana Konteyner */
.lsp-lab {
max-width: 900px;
margin: 40px auto;
background: white;
border-radius: 15px;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
overflow: hidden;
border: 1px solid #e2e8f0;
}
/* Mimari Şema Alanı */
.hierarchy-viz {
display: flex;
justify-content: center;
align-items: center;
padding: 40px 20px;
background: #f1f5f9;
border-bottom: 1px solid #e2e8f0;
gap: 20px;
}
.node {
padding: 18px 25px;
border-radius: 10px;
color: white;
font-size: 13px;
font-weight: 700;
text-align: center;
min-width: 140px;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
.parent-node {
background: var(--lsp-parent);
}
.child-node {
background: var(--lsp-child-ok);
}
.child-node.violation {
background: var(--lsp-child-fail);
}
.connector-arrow {
color: #94a3b8;
font-size: 24px;
font-weight: bold;
}
/* Kontrol Paneli */
.test-controls {
padding: 35px 20px;
text-align: center;
background: #fff;
}
.test-controls h4 {
margin-top: 0;
font-size: 1.25rem;
color: #1e293b;
}
.control-btns {
display: flex;
justify-content: center;
gap: 12px;
flex-wrap: wrap;
margin-top: 20px;
}
.control-btns button {
padding: 12px 24px;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
font-size: 14px;
transition: all 0.2s ease;
min-width: 160px;
}
.control-btns button:hover {
transform: translateY(-2px);
filter: brightness(1.1);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
/* Terminal Görünümü */
.lsp-terminal {
background: var(--terminal-bg);
color: #f1f5f9;
padding: 25px;
height: 250px;
overflow-y: auto;
font-family: 'Fira Code', 'Courier New', monospace;
font-size: 13px;
border-top: 8px solid #334155;
line-height: 1.6;
}
.error-text {
color: #ff6b6b;
font-weight: bold;
}
.success-text {
color: #51cf66;
}
/* Satır içi stillerin taşındığı yeni sınıflar */
.test-description {
font-size: 12px;
color: #666;
margin-bottom: 15px;
}
.btn-test {
color: white;
border: none;
padding: 10px 18px;
border-radius: 6px;
cursor: pointer;
font-weight: 500;
transition: 0.3s ease;
}
.btn-test:hover {
filter: brightness(1.1);
transform: translateY(-1px);
}
.btn-base {
background-color: #3498db;
}
.btn-email {
background-color: #27ae60;
}
.btn-sms {
background-color: #e74c3c;
}
/* Modül kartlarındaki parlamayı yönetmek için ek bir stil */
.node.highlight {
box-shadow: 0 0 15px rgba(255, 255, 255, 0.4);
transform: scale(1.05);
}
/* --- Mobil Uyumluluk --- */
@media (max-width: 768px) {
.hierarchy-viz {
flex-direction: column;
/* Mobilde alt alta diz */
gap: 15px;
}
.connector-arrow {
transform: rotate(90deg);
/* Okları aşağı çevir */
font-size: 18px;
}
.node {
width: 80%;
min-width: unset;
}
.control-btns {
flex-direction: column;
align-items: center;
}
.control-btns button {
width: 100%;
max-width: 300px;
}
.lsp-lab {
margin: 10px;
}
}
import { BildirimGonderici } from "./bildirim-gonderici.js";
import { EmailGonderici } from "./email-gonderici.js";
import { SmsGondericiIhlali } from "./sms-gonderici.js";
const terminal = document.getElementById("lsp-console");
// Olay dinleyicilerini tanımla
document
.getElementById("btn-base")
.addEventListener("click", () => runTest("base"));
document
.getElementById("btn-email")
.addEventListener("click", () => runTest("email"));
document
.getElementById("btn-sms")
.addEventListener("click", () => runTest("sms"));
function runTest(type) {
let gonderici;
const mesaj =
"Liskov Substitution Principle testi için hazırlanan, 160 karakterden uzun bir deneme mesajıdır...";
terminal.innerHTML = "";
if (type === "base") gonderici = new BildirimGonderici();
else if (type === "email") gonderici = new EmailGonderici();
else if (type === "sms") gonderici = new SmsGondericiIhlali();
bildirimGonderSim(gonderici, mesaj);
}
// ... geri kalan bildirimGonderSim fonksiyonun aynı kalabilir.
function bildirimGonderSim(gonderici, mesaj) {
const log = (text, isError = false) => {
const div = document.createElement('div');
div.className = isError ? 'error-text' : 'success-text';
div.innerHTML = `> ${text}`;
terminal.appendChild(div);
};
log(`${gonderici.constructor.name} test ediliyor...`);
try {
const sonuc = gonderici.gonder(mesaj);
log(`İşlem Başarılı. Çıktı: ${sonuc}`);
} catch (e) {
log(`❌ KRİTİK HATA: ${e.message}`, true);
log("Analiz: Alt sınıf, üst sınıfın 'hata fırlatmama' sözleşmesini bozdu.", true);
}
}
// bildirim-gonderici.js
export class BildirimGonderici {
// 💡 Sözleşme: Mesaj alır, başarı durumunu (boolean) döndürür.
gonder(mesaj) {
console.log(`[TEMEL] Mesaj başarıyla işlendi: "${mesaj}"`);
return true;
}
}
// email-gonderici.js (LSP'ye Uyumlu)
import { BildirimGonderici } from "./bildirim-gonderici.js";
export class EmailGonderici extends BildirimGonderici {
gonder(mesaj) {
if (mesaj.length > 500) {
console.warn("[EMAIL] Mesaj çok uzun, kısaltılıyor...");
// Davranışsal sözleşmeyi (başarılı bitiş) bozmaz, sadece içerideki mantığı değiştirir.
}
console.log(`[EMAIL] Gönderildi: "${mesaj.substring(0, 50)}..."`);
return true; // Sözleşmeye uygun olarak true döner.
}
}
// sms-gonderici.js (LSP İhlali Yapan Alt Sınıf)
import { BildirimGonderici } from "./bildirim-gonderici.js";
export class SmsGondericiIhlali extends BildirimGonderici {
gonder(mesaj) {
if (mesaj.length > 160) {
// ❌ İHLAL: Üst sınıfın sözleşmesinde olmayan bir kısıtlama getiriyor.
// Üst sınıf true/false beklerken bu, beklenmedik bir Error fırlatıyor.
throw new Error("[SMS İHLALİ] SMS 160 karakterden uzun olamaz!");
}
console.log(`[SMS] Gönderildi: ${mesaj}`);
return true;
}
}
Interface Segragation Principle Arayüz Ayırma Prensibi
Arayüz Ayırma Prensibi , istemcilerin asla kullanmadıkları metotlara bağımlı olmaya zorlanmaması gerektiğini savunur.
Bu prensip; her şeyi kapsayan devasa ve şişkin yapılar yerine, küçük, parçalanmış ve amaca özel yapıların tercih edilmesini emreder.
Şişkin Arayüz (Fat Interface): Eğer bir sınıf, ihtiyaç duymadığı bir fonksiyonu sadece bağlı olduğu üst yapı gerektirdiği için bünyesinde barındırıyorsa, orada bir mimari kirlilik ve ISP ihlali vardır.
JavaScript ve Tip Sözleşmelerinde ISPJavaScript'te yerleşik bir interface anahtar kelimesi olmasa da; bu prensip sınıflar, nesne protokolleri ve TypeScript kullanılıyorsa type/interface tanımları için tamamen geçerlidir.
Pratik Örnek: Tüm veri işlemlerini yöneten devasa bir CRUDManager sınıfı düşünün.
Sadece veri okuması gereken bir bileşen, bu sınıfa bağlandığında aslında kullanmadığı "silme" ve "güncelleme" metotlarına da bağımlı hale gelir.
Doğru Yaklaşım: Bu yapıyı DataReader ve DataWriter olarak ikiye ayırmaktır. Böylece sadece okuma yapan bir istemci, yazma tarafında yapılan hiçbir değişiklikten etkilenmez.
Prensibin Derinlemesine Modülerlik EtkisiBağımlılık Minimüzasyonu: ISP'ye uyum, sistemdeki gereksiz bağları keser.
Bir metodun değişmesi, sadece o metodu gerçekten kullanan sınıfları etkilemelidir.
İlgisiz modüllerin bu değişimden etkilenerek "yanlışlıkla" bozulma riski ortadan kalkar.
Mantıksal Gruplama: JavaScript'te bu prensip, sınıfları tasarlarken metotları mantıksal görevlerine göre mikro modüllere ayırmak anlamına gelir.
Her bileşen, sistemin devasa bir parçasına değil, sadece gerçekten ihtiyaç duyduğu o küçük ve "odaklanmış" parçaya bağlanmalıdır.
Özet olarak ISP, yazılım mimarisini "hantal ve her işi yapan" hiyerarşilerden kurtarıp; parçaları bağımsızca büyüyebilen, hafif ve çevik bir organizmaya dönüştürür.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Arayüz Ayırma Prensibi (ISP) | Byteomi</title>
<link rel="stylesheet" href="isp-style.css?v=1.0.150">
</head>
<body>
<div class="isp-lab">
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi ISP Interface Segregation Lab
<span class="lang-icon"><i class="fab fa-html5"></i></span>
<span class="lang-icon"><i class="fab fa-css3-alt"></i></span>
<span class="lang-icon"><i class="fab fa-js"></i></span>
</div>
</div>
</div>
<div class="interface-viz">
<div class="interface-card reader-card">
<h5>VeriOkuyucu</h5>
<ul>
<li>• al(id)</li>
<li>• listele()</li>
</ul>
</div>
<div class="interface-divider">+</div>
<div class="interface-card writer-card">
<h5>VeriYazici</h5>
<ul>
<li>• kaydet(veri)</li>
<li>• sil(id)</li>
</ul>
</div>
</div>
<div class="isp-controls">
<h4>Modüler Erişim Simülasyonu</h4>
<p class="isp-description">Hangi modülün hangi yeteneklere eriştiğini test edin:</p>
<div class="btn-group">
<button id="btn-write-test" class="btn-isp btn-write">Yazma İşlemi (Mongo)</button>
<button id="btn-read-test" class="btn-isp btn-read">Raporlama (Sadece Okuma)</button>
</div>
</div>
<div id="isp-console" class="isp-terminal">
> Sistem analizi için bir işlem seçin...
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
/* byteomi.com - ISP Dark Mode Lab Styles */
:root {
--bg-dark: #0f172a;
--card-dark: #1e293b;
--accent-blue: #38bdf8;
--accent-purple: #a78bfa;
--text-main: #f8fafc;
--text-dim: #94a3b8;
--terminal-bg: #000000;
--success: #4ade80;
--divider: #334155;
}
body {
background-color: var(--bg-dark);
font-family: 'Inter', -apple-system, sans-serif;
margin: 0;
padding: 20px;
color: var(--text-main);
}
/* Üst Başlık Etiketi Tasarımı */
.code-type-label {
background: var(--card-dark);
border-radius: 12px 12px 0 0;
border: 1px solid var(--divider);
border-bottom: none;
padding: 15px 20px;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
flex-wrap: wrap;
}
.code-type-icon {
font-family: 'Courier New', monospace;
font-weight: bold;
color: var(--accent-blue);
background: rgba(56, 189, 248, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
color: var(--text-main);
display: flex;
align-items: center;
gap: 10px;
}
.lang-icon {
font-size: 18px;
color: var(--text-dim);
}
/* Ana Konteyner */
.isp-lab {
max-width: 900px;
margin: 40px auto;
background: var(--card-dark);
border-radius: 15px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
border: 1px solid var(--divider);
}
/* Modüler Şema */
.interface-viz {
display: flex;
justify-content: center;
align-items: center;
padding: 40px 20px;
background: rgba(15, 23, 42, 0.5);
border-bottom: 1px solid var(--divider);
gap: 20px;
}
.interface-divider {
font-size: 24px;
color: var(--divider);
font-weight: bold;
}
.interface-card {
padding: 20px;
border-radius: 10px;
width: 200px;
text-align: center;
border: 2px solid transparent;
}
.reader-card {
border-color: var(--accent-blue);
background: rgba(56, 189, 248, 0.05);
}
.writer-card {
border-color: var(--accent-purple);
background: rgba(167, 139, 250, 0.05);
}
.interface-card h5 {
margin: 0 0 10px 0;
font-size: 14px;
color: var(--text-main);
}
.interface-card ul {
list-style: none;
padding: 0;
margin: 0;
font-size: 12px;
color: var(--text-dim);
text-align: left;
}
/* Kontrol Paneli */
.isp-controls {
padding: 35px 20px;
text-align: center;
}
.isp-description {
font-size: 12px;
color: var(--text-dim);
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
margin-top: 20px;
flex-wrap: wrap;
}
.btn-isp {
padding: 12px 24px;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: all 0.2s ease;
min-width: 200px;
color: white;
}
.btn-read {
background: var(--accent-blue);
}
.btn-write {
background: var(--accent-purple);
}
.btn-isp:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
/* Terminal */
.isp-terminal {
background: var(--terminal-bg);
color: var(--success);
padding: 25px;
height: 250px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 13px;
border-top: 4px solid var(--divider);
line-height: 1.6;
}
/* Responsive */
@media (max-width: 768px) {
.interface-viz {
flex-direction: column;
gap: 15px;
}
.btn-isp {
width: 100%;
}
}
import { MongoDeposu } from "./mongo-deposu.js";
import { RaporlamaModulu } from "./raporlama-modulu.js";
const terminal = document.getElementById("isp-console");
const mongoDeposuInstance = new MongoDeposu();
// Yazma Testi
document.getElementById("btn-write-test").addEventListener("click", () => {
terminal.innerHTML = "";
log("--- Yazma Modülü Erişimi Başlatıldı ---");
// MongoDeposu tüm metotlara sahip (Yazıcı + Okuyucu)
mongoDeposuInstance.kaydet({ ad: "Sistem Raporu v2" });
log("[MONGO] Veri başarıyla kaydedildi.");
mongoDeposuInstance.sil(101);
log("[MONGO] ID 101 verisi sistemden temizlendi.");
});
// Okuma/Raporlama Testi
document.getElementById("btn-read-test").addEventListener("click", () => {
terminal.innerHTML = "";
log("--- Raporlama Modülü (Okuma) Erişimi Başlatıldı ---");
try {
const raporlamaModulu = new RaporlamaModulu(mongoDeposuInstance);
raporlamaModulu.raporOlustur();
log(
"\n[ANALİZ] Raporlama modülü sadece listele() ve al() metotlarını kullandı.",
);
log(
"[ANALİZ] İstemci, kullanmadığı kaydet() ve sil() metotlarından izole edildi.",
);
} catch (e) {
log(`Hata: ${e.message}`);
}
});
function log(text) {
terminal.innerHTML += `<div> > ${text} </div>`;
terminal.scrollTop = terminal.scrollHeight;
}
// veri-arayuzleri.js
// 💡 Küçük ve amaca özel arayüzler
export class VeriOkuyucu {
al(id) {
throw new Error("Uygulanmalı.");
}
listele() {
throw new Error("Uygulanmalı.");
}
}
export class VeriYazici {
kaydet(veri) {
throw new Error("Uygulanmalı.");
}
sil(id) {
throw new Error("Uygulanmalı.");
}
}
// raporlama-modulu.js (Sadece VeriOkuyucu'ya bağımlıdır)
import { VeriOkuyucu } from "./veri-arayuzleri.js";
// 💡 İstemci, sadece VeriOkuyucu arayüzünü bekler. VeriYazici metotlarını bilmez.
export class RaporlamaModulu {
constructor(okuyucu) {
// Kontrolsüz bir şekilde VeriYazici'ya bağımlı olmaktan kaçınılır.
if (!(okuyucu instanceof VeriOkuyucu)) {
throw new Error(
"Raporlama Modülü sadece VeriOkuyucu arayüzüne ihtiyaç duyar.",
);
}
this.okuyucu = okuyucu;
}
raporOlustur() {
console.log("\n[RAPORLAMA] Rapor oluşturma başlatıldı.");
const veriler = this.okuyucu.listele();
veriler.forEach((d) => this.okuyucu.al(d.id));
console.log("[RAPORLAMA] Rapor verileri başarıyla çekildi.");
}
}
// mongo-deposu.js (Hem Okuyucu hem de Yazıcı arayüzlerini uygular)
import { VeriOkuyucu, VeriYazici } from "./veri-arayuzleri.js";
export class MongoDeposu extends VeriOkuyucu {
al(id) {
console.log(`[MONGO] ID ${id} verisi okundu.`);
return { id, ad: "Test Verisi" };
}
listele() {
console.log("[MONGO] Tüm veriler listeleniyor.");
return [{ id: 1 }, { id: 2 }];
}
kaydet(veri) {
console.log(`[MONGO] Veri kaydedildi: ${veri.ad}`);
return veri;
}
sil(id) {
console.log(`[MONGO] ID ${id} verisi silindi.`);
}
}
Dependency Inversion Principle Bağımlılık Tersine Çevrilmesi Prensibi
Bağımlılıkların Tersine Çevrilmesi Prensibi, yüksek seviyeli modüllerin düşük seviyeli modüllere doğrudan bağımlı olmamasını savunur.
Temel Kural: Hem yüksek seviyeli hem de düşük seviyeli modüller, soyutlamalara ( arayüzler veya protokoller ) bağımlı olmalıdır.
Bu, sistemin parçalarını birbirine kaynak yapmak yerine, araya esnek bir "sözleşme katmanı" koymak demektir.
JavaScript ve Bağımlılık Enjeksiyonu (DI)JavaScript dünyasında bu prensip genellikle Bağımlılık Enjeksiyonu tekniği ile hayat bulur.
Pratik Örnek: Bir UserService sınıfı, kendi içinde doğrudan new MongoDBDriver() diyerek somut bir araca bağlanmamalıdır.
Bunun yerine, "verileri kaydedebilen herhangi bir araç" beklediğini belirtmeli ve bu araç ( MongoDB, PostgreSQL veya MockDB) sınıfa dışarıdan, genellikle constructor aracılığıyla verilmelidir.
Prensibin Derinlemesine Mimari AnaliziGeleneksel vs. Modern Yaklaşım: Geleneksel yapıda iş kuralları, veritabanı veya dosya sistemi gibi düşük seviyeli araçları doğrudan çağırır.
Bu durum, araç değiştiğinde tüm sistemin sarsılmasına neden olur.
DIP, bu akışı tersine çevirerek iş kurallarını ( Yüksek Seviye ) merkeze alır ve araçları ( Düşük Seviye ) bu kurallara hizmet eden figüranlara dönüştürür.
Değişim Kolaylığı ve Test Edilebilirlik: DIP, sistemi adeta bir "LEGO" setine dönüştürür.
Veritabanınızı değiştirmek istediğinizde iş mantığınızın tek bir satırına bile dokunmazsınız; sadece enjekte ettiğiniz somut uygulamayı değiştirirsiniz.
Aynı şekilde, test yaparken gerçek bir veritabanı yerine kolayca bir "Sahte" ( Mock) nesne enjekte ederek sistemi izole bir şekilde test edebilirsiniz.
Sonuç olarak DIP, yazılım mimarisini "katı ve kırılgan" bağımlılıklardan kurtarıp; parçaları birbirinin yerine geçebilen, test edilebilir ve
geleceğin değişimlerine hazır profesyonel bir platforma taşır.
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DIP Dependency Inversion & Bridge</title>
<link rel="stylesheet" href="dip-style.css?v=1.0.150">
</head>
<body>
<div class="dip-lab">
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi DIP Dependency Inversion & Bridge Lab
<span class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</span>
</div>
</div>
</div>
<div class="bridge-viz">
<div class="node high-node">RaporlamaServisi<br>(High-Level)</div>
<div class="connector-line"></div>
<div class="node abstract-node">IDepolama<br>(Abstraction / Contract)</div>
<div class="connector-line"></div>
<div class="low-node-container">
<div class="node low-node sql-width">SQLDeposu<br>(Detail)</div>
<div class="node low-node mongo-bg mongo-width">MongoDeposu<br>(Detail)</div>
</div>
</div>
<div class="dip-controls">
<h4>Bağımlılık Enjeksiyonu Testi</h4>
<p class="control-text">Yüksek seviyeli servis kodunu değiştirmeden veri kaynağını enjekte edin:</p>
<div class="btn-group">
<button id="btn-sql" class="btn-dip btn-sql">SQL Enjekte Et</button>
<button id="btn-mongo" class="btn-dip btn-mongo">Mongo Enjekte Et</button>
</div>
</div>
<div id="dip-console" class="dip-terminal">
> Modül bağımsızlığı analizi için bir enjeksiyon seçin...
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
/* byteomi.com - DIP Bridge Lab Styles */
:root {
--dip-high: #3498db;
--dip-abstract: #f1c40f;
--dip-low: #e67e22;
--terminal-bg: #1e1e1e;
--text-white: #ffffff;
--border-color: #ddd;
--label-bg: #ffffff;
--label-text: #475569;
}
body {
background-color: #f0f2f5;
font-family: 'Segoe UI', system-ui, sans-serif;
padding: 20px;
}
/* --- Başlık Etiketi (Code Type Label) --- */
.code-type-label {
background: var(--label-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Courier New', monospace;
font-weight: bold;
color: var(--dip-high);
background: #e0f2fe;
padding: 5px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
color: var(--label-text);
display: flex;
align-items: center;
gap: 12px;
}
.lang-icons {
display: flex;
gap: 8px;
opacity: 0.6;
}
/* --- Ana Konteynır --- */
.dip-lab {
max-width: 850px;
margin: 40px auto;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
}
/* --- Mimari Köprü Şeması --- */
.bridge-viz {
display: flex;
flex-direction: column;
align-items: center;
padding: 30px;
background: #fff;
border-top: 1px solid #eee;
/* Başlıktan sonra ince çizgi */
gap: 15px;
}
.low-node-container {
display: flex;
gap: 20px;
}
.node {
padding: 12px 20px;
border-radius: 6px;
color: white;
font-weight: bold;
font-size: 14px;
text-align: center;
width: 200px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.high-node {
background: var(--dip-high);
}
.abstract-node {
background: var(--dip-abstract);
color: #2d3436;
border: 2px dashed #d35400;
}
.low-node {
background: var(--dip-low);
}
/* Genişlik ve Arka Plan Yardımcı Sınıfları */
.sql-width {
width: 120px;
}
.mongo-width {
width: 120px;
}
.mongo-bg {
background: #27ae60;
}
.connector-line {
width: 2px;
height: 30px;
background: #bdc3c7;
}
/* --- Terminal & Controls --- */
.dip-controls {
background: #fff;
padding: 25px;
text-align: center;
border-top: 1px solid #eee;
}
.control-text {
font-size: 12px;
color: #666;
}
.btn-group {
display: flex;
justify-content: center;
gap: 10px;
margin-top: 15px;
}
.btn-dip {
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: 600;
transition: 0.3s;
color: white;
}
.btn-sql {
background: #2980b9;
}
.btn-mongo {
background: #27ae60;
}
.dip-terminal {
background: var(--terminal-bg);
color: #00ff00;
padding: 20px;
height: 220px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 13px;
border-top: 5px solid #34495e;
}
import { RaporlamaServisi } from "./raporlama-servisi.js";
import { SQLDeposu } from "./sql-deposu.js";
import { MongoDeposu } from "./mongo-deposu.js";
const terminal = document.getElementById("dip-console");
// Güvenli Event Listener'lar
document.getElementById("btn-sql").addEventListener("click", () => {
runInversionTest("sql");
});
document.getElementById("btn-mongo").addEventListener("click", () => {
runInversionTest("mongo");
});
function runInversionTest(dbType) {
terminal.innerHTML = "";
log(`--- ${dbType.toUpperCase()} Enjeksiyonu Başlatıldı ---`, "system");
// 💡 Bağımlılık dışarıdan yaratılır (Inversion)
const depo = dbType === "sql" ? new SQLDeposu() : new MongoDeposu();
// 💡 RaporlamaServisi (High-level), somut depoyu constructor üzerinden alır (Injection)
const servis = new RaporlamaServisi(depo);
try {
servis.raporOlustur(dbType === "sql" ? "Aylık" : "Günlük");
log(
`\n[ANALİZ] RaporlamaServisi kodu DEĞİŞMEDEN veri kaynağı ${dbType} olarak güncellendi.`,
);
log(
"[ANALİZ] Bağımlılıklar soyut IDepolama arayüzü üzerinden tersine çevrildi.",
);
} catch (e) {
log(`Hata: ${e.message}`, "error");
}
}
function log(text, type = "normal") {
const color =
type === "system" ? "#f1c40f" : type === "error" ? "#ff4757" : "#00ff00";
terminal.innerHTML += `<div style="color: ${color}">> ${text}</div>`;
terminal.scrollTop = terminal.scrollHeight;
}
// i-depolama.js
export class IDepolama {
// 💡 Soyutlama: Yüksek ve düşük seviyeli modüllerin uyması gereken sözleşme.
veriyiGetir(sorgu) {
throw new Error("veriyiGetir metodu alt sınıflarda uygulanmalıdır.");
}
}
// mongo-deposu.js (Somut Uygulama)
import { IDepolama } from "./i-depolama.js";
export class MongoDeposu extends IDepolama {
veriyiGetir(sorgu) {
console.log(`[MONGO DEPOSU] NoSQL sorgusu yapıldı: ${sorgu}`);
return [{ rapor_id: 1, veri: "Mongo Verisi" }];
}
}
// raporlama-servisi.js (Yüksek Seviye Modül)
// 💡 SADECE soyutlamaya bağımlıdır. Somut SQLDeposu'nu BİLMEZ.
import { IDepolama } from "./i-depolama.js";
export class RaporlamaServisi {
constructor(depolama) {
// ❌ Burası kritik: Somut bir depo nesnesi (SQL/Mongo) new ile YARATILMAZ.
// Dışarıdan (index.js'ten) enjekte edilir.
if (!(depolama instanceof IDepolama)) {
throw new Error("Depolama nesnesi IDepolama arayüzünü uygulamalıdır.");
}
this.depolama = depolama;
}
raporOlustur(tip) {
console.log(`\n[RAPOR SERVİSİ] ${tip} raporu hazırlanıyor...`);
// 💡 İstek, soyut arayüz üzerinden delege edilir.
const veriler = this.depolama.veriyiGetir(`Rapor Sorgusu ${tip}`);
console.log(`[RAPOR SERVİSİ] Rapor Veri Kaynağı: ${veriler[0].veri}`);
return veriler;
}
}
// sql-deposu.js (Somut Uygulama)
import { IDepolama } from "./i-depolama.js";
export class SQLDeposu extends IDepolama {
veriyiGetir(sorgu) {
console.log(`[SQL DEPOSU] SQL ile sorgu çalıştırıldı: ${sorgu}`);
return [{ rapor_id: 1, veri: "SQL Verisi" }];
}
}
|
Prensip
|
Odak Noktası
|
JavaScript'te Önemi
|
|---|---|---|
|
SRP
Single Responsibility |
Bir sınıf, modül veya fonksiyonun değişmesi için yalnızca
tek bir
neden
olmalıdır.
Her bileşen tek bir sorumluluğu üstlenmelidir. |
ES Modülleri ve Node.js mimarisinde kritik öneme sahiptir.
Bir modül hem veri erişimi hem de iş mantığını barındırmamalıdır. Sorumluluklar UserService.js ve UserRepository.js gibi ayrı modüllere bölünmelidir. |
|
OCP
Open/Closed |
Yazılım varlıkları genişletilmeye açık, ancak mevcut kodun
değiştirilmesine
kapalı olmalıdır.
Yeni özellikler eklemek için kalıtım veya bileşim kullanılmalıdır. |
Büyük if/else veya
switch/case bloklarından kaçınmak gerekir.
Strateji Deseni veya Dekoratör Deseni gibi kompozisyon desenleriyle uygulanır. Yeni ödeme yöntemi eklemek için ana fonksiyona dokunmak yerine yeni bir strateji sınıfı oluşturulur. |
|
LSP
Liskov Substitution |
Bir üst sınıfın kullanıldığı her yerde, alt sınıfları
davranışı
bozmadan
kullanılabilmelidir.
Sadece metot imzaları değil, davranışsal sözleşme de korunmalıdır. |
JavaScript'in dinamik yapısı LSP ihlallerine kapı
aralayabilir.
Alt sınıfta bir metodun "içinin boşaltılması" veya beklenmedik hata fırlatması bu prensibi bozar. Bir Logger sınıfından türeyen ErrorLogger sınıfı, temel log() metodunu beklenmedik şekilde değiştirmemelidir. |
|
ISP
Interface Segregation |
İstemciler kullanmadıkları metotlara bağımlı olmaya
zorlanmamalıdır.
Büyük, genel arayüzler yerine küçük ve amaca özel arayüzler tercih edilmelidir. |
JavaScript'te bu, nesnelerin gereksiz metotlar taşımaması
gerektiği
anlamına gelir.
Bir UserManager nesnesi hem okuma hem silme metotlarını içeriyorsa ve bir bileşen sadece okuma yapıyorsa, gereksiz bağımlılık oluşur. Bunun yerine DataReader ve DataWriter gibi ayrı arayüzler oluşturulmalıdır. |
|
DIP
Dependency Inversion |
Yüksek seviyeli modüller düşük seviyeli modüllere bağımlı
olmamalıdır.
Her ikisi de soyutlamalara ( interfaceler/protokoller ) bağımlı olmalıdır. Bağımlılıklar somut implementasyonlardan soyutlamalara doğru yönlendirilmelidir. |
Modern JavaScript ve Node.js mimarilerinde Bağımlılık Enjeksiyonu ile sağlanır.
Bir OrderService doğrudan new PostgresDriver() çağırmak yerine, bir DBClient arayüzüne bağımlı olmalı ve somut nesneyi dışarıdan almalıdır. Bu, test edilebilirliği ve esnekliği artırır. |
Nitelik Gereksinimleri Architectural Quality Attributes - AQC
Nitelik Gereksinimleri, bir yazılımın sadece çalışmasını değil, "nasıl" bir performansla ayakta kalacağını belirleyen; ölçülebilir ve test edilebilir mimari kısıtlamalardır.
Fonksiyonel vs. Fonksiyonel Olmayan: Bir uygulamanın "kullanıcı giriş yapabilsin" demesi fonksiyonel bir gereksinimken bir sonraki çıktı bir nitelik gereksinimidir; "giriş işlemi 200ms altında gerçekleşsin ve 1 milyon eşzamanlı kullanıcıyı desteklesin"
Bu alan; yüksek performans, güvenlik, kullanılabilirlik ve geliştirme hızı gibi kritik değerlerle ilgilenir.
Mimari Kararların Rasyonel TemeliBir yazılım mimarı için AQC, teknik kararları yönlendiren en önemli öncelikler listesidir.
Mimari desenlerin ( Katmanlı Mimari, Mikroservisler, Olay Güdümlü Tasarım ) veya prensiplerin ( SOLID ) neden seçildiğinin temel gerekçesi AQC'dir.
Stratejik Yönlendirme: Eğer bir sistemin "yüksek ölçeklenebilirlik" gereksinimi varsa, mimar doğal olarak mikroservis desenine yönelir.
Eğer sistemin "kolay bakım" önceliği varsa, SOLID prensipleri ve katı bir modüler yapı tercih edilir.
Teknik Borca Karşı Erken TeşhisUzun Ömürlü Sistemler: AQC, projenin henüz ilk satırı yazılmadan netleştirilmelidir.
Geliştirme döngüsünün başında belirlenmeyen nitelik hedefleri, projenin ilerleyen safhalarında devasa bir teknik borç olarak geri döner.
AQC'yi doğru analiz etmek, kodun sadece "doğru çıktı" üretmesini değil; aynı zamanda hızlı , güvenli , esnek ve on yıl sonra bile yönetilebilir kalmasını sağlar.
Sonuç olarak Nitelik Gereksinimleri, bir yazılımın ticari başarısı ile mühendislik mükemmelliği arasındaki köprüyü kuran görünmez mimari iskelettir.
Giriş ve Tanım Fonksiyonel vs. Fonksiyonel Olmayan Gereksinimler
Yazılım mimarisinin en kritik başlangıç noktası, sistemden beklenen tüm taleplerin doğru bir şekilde sınıflandırılmasıdır.
Bir projenin başarısı, sistemin sadece istenen işi yapmasına değil, bu işi hangi şartlar altında ve nasıl bir kalitede yapacağına bağlıdır.
Bu talepler iki ana kategoriye ayrılır: Fonksiyonel ve Fonksiyonel Olmayan gereksinimler.
Fonksiyonel Gereksinimler (Sistem Ne Yapmalı?)Fonksiyonel gereksinimler, sistemin varlık sebebidir ve kullanıcıya sunduğu temel özellikleri tanımlar.
Eğer bu gereksinimlerden biri eksikse, uygulama vaat ettiği işi yapma yeteneğini kaybeder.
Tanım ve Davranış: Sistemin belirli girdilere karşı üretmesi gereken çıktıları ve takip etmesi gereken iş kurallarını belirler.
Örneğin: Bir uygulama için; "Kullanıcının sepete ürün ekleyebilmesi", "Ödeme sonrası onay e-postası gönderilmesi" veya
"Yöneticinin kullanıcıları filtreleyebilmesi" doğrudan fonksiyonel gereksinimlerdir.
Nitelik Gereksinimleri (Sistem Nasıl Çalışmalı?)Fonksiyonel Olmayan Gereksinimler veya Mimari Nitelik Gereksinimleri, sistemin operasyonel kalitesini ve kısıtlamalarını belirler.
Bu gereksinimler, uygulamanın "yaşam kalitesini" ve mimarın stratejik tasarım kararlarını doğrudan kontrol eder.
Tanım ve Mimari Etki: Sistemin hızı, güvenliği , ölçeklenebilirliği ve bakım Kolaylığı gibi kalite özniteliklerini tanımlar.
Stratejik Ayrım: Fonksiyonel gereksinimler genellikle kodun "İş Mantığı" katmanında çözülürken; AQC, mimarinin en üst düzey seçimlerini yönlendirir.
Bir sistemin mikroservis mi yoksa katmanlı mı olacağına "ne yapıldığı" değil, "ne kadar hızlı ve ölçeklenebilir olması gerektiği" (AQC) karar verir.
Mimari Denge ve Teknik BorçBir mimar için asıl ustalık, bu iki gereksinim türünü doğru dengelemek ve AQC'ye projenin en başında öncelik vermektir.
AQC'nin ihmal edilmesi, fonksiyonel olarak çalışan ancak yavaş, güvensiz ve genişletilemez bir sistem ortaya çıkarır; bu da kaçınılmaz olarak devasa bir teknik borç birikimine yol açar.
Tüm bunların sonucu olarak, AQC'yi doğru anlamak ve prensiplerle desteklemek, kodun sadece bugünü kurtarmasını değil, gelecekteki değişimlere karşı dimdik durmasını sağlar.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AQC Balance & Trade-off Lab</title>
<link rel="stylesheet" href="aqc-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi AQC Balance & Trade-off Lab
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container aqc-dark-theme">
<div class="lab-viz status-panel">
<div class="stat-item">
<label>Sistem Hızı (Performance)</label>
<div class="progress-bar">
<div id="bar-speed" class="bar bg-blue" style="width: 80%"></div>
</div>
</div>
<div class="stat-item">
<label>Teknik Borç (Technical Debt)</label>
<div class="progress-bar">
<div id="bar-debt" class="bar bg-red" style="width: 10%"></div>
</div>
</div>
<div class="stat-item">
<label>Güvenlik Skoru (Security)</label>
<div class="progress-bar">
<div id="bar-security" class="bar bg-green" style="width: 50%"></div>
</div>
</div>
</div>
<div class="lab-controls">
<h4>Mimari Karar Simülasyonu</h4>
<p class="lab-description">
Özellik eklemek fonksiyonel bir ihtiyaçtır; ancak AQC yatırımı yapılmazsa teknik borç artar.
</p>
<div class="btn-group">
<button id="btn-add-feature" class="btn-lab btn-functional">
Yeni Özellik Ekle (Functional)
</button>
<button id="btn-optimize" class="btn-lab btn-aqc">
Refactoring & AQC Yatırımı
</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">
> Mimar: Sistem analizi bekleniyor. İlk kararı verin...
</div>
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--blue-glow: #38bdf8;
--red-alert: #ef4444;
--green-safe: #10b981;
--btn-purple: #6366f1;
--btn-pink: #ec4899;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--blue-glow);
background: rgba(56, 189, 248, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.status-panel {
display: flex;
flex-direction: column;
gap: 18px;
padding: 30px;
background: rgba(15, 23, 42, 0.4);
}
.stat-item label {
display: block;
font-size: 11px;
margin-bottom: 8px;
color: var(--text-dim);
text-transform: uppercase;
}
.progress-bar {
height: 8px;
background: #020617;
border-radius: 4px;
overflow: hidden;
border: 1px solid var(--border-color);
}
.bar {
height: 100%;
transition: width 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.bg-blue {
background: var(--blue-glow);
box-shadow: 0 0 15px rgba(56, 189, 248, 0.3);
}
.bg-red {
background: var(--red-alert);
box-shadow: 0 0 15px rgba(239, 68, 68, 0.3);
}
.bg-green {
background: var(--green-safe);
box-shadow: 0 0 15px rgba(16, 185, 129, 0.3);
}
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 24px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 180px;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
.btn-functional {
background: var(--btn-purple);
color: white;
}
.btn-aqc {
background: var(--btn-pink);
color: white;
}
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
gap: 12px;
}
.btn-lab {
width: 100%;
max-width: 300px;
min-width: unset;
padding: 14px 10px;
font-size: 13px;
}
.status-panel,
.lab-controls {
padding: 20px 15px;
}
.code-type-description {
font-size: 12px;
}
}
let speed = 80;
let debt = 10;
let security = 50;
const updateUI = () => {
document.getElementById("bar-speed").style.width = `${speed}%`;
document.getElementById("bar-debt").style.width = `${debt}%`;
document.getElementById("bar-security").style.width = `${security}%`;
};
const log = (msg, type) => {
const terminal = document.getElementById("lab-console");
const div = document.createElement("div");
div.className = type === "warn" ? "log-error" : "log-success";
div.innerText = `> ${msg}`;
terminal.prepend(div);
};
// Fonksiyonel İstek: Yeni Özellik
document.getElementById("btn-add-feature").addEventListener("click", () => {
speed -= 10; // Her yeni özellik sistemi biraz hantallaştırır
debt += 15; // Refactoring yapılmadığı için teknik borç artar
security -= 5;
log("Fonksiyonel Gereksinim: Sepete Ekleme özelliği eklendi.", "normal");
if (debt > 50)
log("UYARI: Teknik borç kritik seviyede! Sistem yavaşlıyor.", "warn");
updateUI();
});
// Nitelik Gereksinimi: Optimizasyon
document.getElementById("btn-optimize").addEventListener("click", () => {
speed += 15;
debt -= 20;
security += 10;
if (speed > 100) speed = 100;
if (debt < 0) debt = 0;
log(
"AQC Yatırımı: Kod refactoring ve index optimizasyonu yapıldı.",
"success",
);
updateUI();
});
Temel AQC Türleri Performans, Ölçeklenebilirlik, Güvenlik, Bakım
Temel AQC Türleri, bir yazılım mimarisini tasarlarken teknik kararları en çok yönlendiren ve sistemin karakterini belirleyen kritik kalite alanlarını temsil eder.
Bu kategoriler, uygulamanın sadece vaat ettiği işi yapmasının ötesinde; sistemin operasyonel dayanıklılığını, kullanıcı sadakatini ve toplam sahip olma maliyetini belirleyen ana kısıtlamalardır.
Denge Sanatı: Trade-Off (Ödünleşim) YönetimiMimari tasarımın en büyük zorluğu, bu AQC türleri arasındaki karmaşık dengeyi kurmaktır.
Genellikle bir alanda elde edilen kazanç, başka bir alanda kayba neden olabilir.
Örnek Çatışma: Bir sisteme eklenen aşırı yüksek Güvenlik katmanları ( karmaşık şifreleme ve doğrulama süreçleri ), kaçınılmaz olarak sistemin Performans değerlerinde bir düşüşe yol açabilir.
Bir mimar olarak görevimiz, projenin önceliklerine göre bu denge noktasını en rasyonel şekilde belirlemektir.
Dört Ana Sütun ve EtkileriPerformans (Performance): Sistemin belirli bir iş yükü altındaki tepki süresi ve kaynak kullanımıdır. Kullanıcının "hız" algısını doğrudan yönetir.
Ölçeklenebilirlik (Scalability): Sistem yükü ( kullanıcı veya veri sayısı ) arttığında, sistemin bu yükü karşılayabilme ve kaynaklarını genişletebilme yeteneğidir.
Güvenlik (Security): Verilerin gizliliği, bütünlüğü ve erişilebilirliğinin korunmasıdır. Sistemin saldırılara karşı direncini ve yasal uyumluluğunu belirler.
Bakım Kolaylığı (Maintainability): Sistemin hatalardan arındırılma, güncellenme ve yeni özelliklerle genişletilme hızıdır. Yazılımın uzun vadeli maliyetini ve hayatta kalma süresini kontrol eder.
Sonuç olarak bu AQC türlerini derinlemesine analiz etmek, bir uygulamayı sadece "çalışan bir kod" olmaktan çıkarıp; kullanıcı deneyimi ile mühendislik sürdürülebilirliği arasında kusursuz bir denge kuran "iyi bir mimariye" dönüştürmenin anahtarıdır.
Performans ve Ölçeklenebilirlik Konu Girişi İçeriği
Performans ve Ölçeklenebilirlik, günümüz yazılım dünyasında bir uygulamanın hem ticari başarısını hem de teknik ayakta kalma kapasitesini belirleyen en kritik iki parametredir.
Bu iki nitelik gereksinimi, sistemin sadece bugünkü kullanıcı kitlesiyle hızlı bir etkileşim kurmasını değil; aynı zamanda gelecekteki büyüme dalgaları ve beklenmedik talep patlamaları karşısında da hizmet kalitesinden ödün vermemesini garanti altına alır.
Anlık Memnuniyet vs. Uzun Vadeli MaliyetPerformans (Anlık Hız): Bir sistemin tek bir işlem birimi için harcadığı zaman ve kaynak verimliliğidir.
Kullanıcı bir butona bastığında sonucun ne kadar sürede döneceğiyle ( latency/gecikme ) ilgilenir. Yüksek performans, doğrudan anlık kullanıcı memnuniyetini sağlar.
Ölçeklenebilirlik (Büyüme Kapasitesi): Sistemin toplam iş yükü kapasitesini artırabilme yeteneğidir. Kullanıcı sayısı 100’den 1 milyona çıktığında, sistemin çökmeden bu yükü karşılayabilmesiyle ilgilenir.
Başarılı bir ölçeklenebilirlik stratejisi, uygulamanın yaşam ömrü boyunca operasyonel maliyetleri ( infrastructure cost ) kontrol edilebilir bir seviyede tutar.
Mimari Kararlar ve Dağıtık DesenlerBu AQC'ler, bir mimarı her zaman iki yol arasında seçim yapmaya zorlar: Verimlilik için Lokal Optimizasyonlar mı, yoksa esneklik için
Dağıtık Mimari Desenleri mi?
Mühendislik Vizyonu: Bir sistemin sadece "hızlı" olması modern standartlarda yeterli kabul edilmez.
Gerçek mimari başarı; sistemin o yüksek hızını korurken, kaynak ekleyerek ( horizontal/vertical scaling ) binlerce kat büyüyebilmesidir.
Sonuç olarak Performans ve Ölçeklenebilirlik, yazılımı "çalışan bir prototip" olmaktan çıkarıp, küresel ölçekte hizmet verebilen "endüstriyel bir platforma" dönüştüren temel mühendislik gücüdür.
Performans Gecikme, Yanıt Süresi ve Protokoller
Performans, bir yazılım sisteminin kendisine verilen görevi ne kadar sürede tamamladığını ve bu süreçte donanım kaynaklarını ne kadar verimli kullandığını ölçen zaman odaklı bir kalite kriteridir.
İş Riski: Düşük performans sadece teknik bir sorun değil; kullanıcı kaybına, dönüşüm oranlarının düşmesine ve arkasından gelen
operasyonel maliyetlerin artmasına neden olan doğrudan bir ticari risktir.
Mimaride performans, sistemin "akıcılığını" garanti altına alan temel unsurdur.
Temel Metrikler: Gecikme ve Yanıt SüresiKullanıcı deneyimini optimize etmek için performans iki ana metrik üzerinden takip edilir:
Gecikme (Latency): Bir isteğin istemciden isteğin istemciden çıkıp sunucuya varması ve ilk yanıtın geri dönmesi arasında geçen toplam ağ süresidir.
Yüksek gecikme, internet bağlantısı ne kadar hızlı olursa olsun kullanıcının sistemi "hantal" algılamasına neden olur.
Yanıt Süresi (Response Time): Ağ gecikmesine ek olarak, sunucunun veriyi işlemek, veritabanına erişmek ve cevabı hazırlamak için harcadığı süreyi de kapsar.
Mimari Tercihler ve Protokollerin GücüPerformans hedefleri, mimarın hangi iletişim dilini seçeceğini doğrudan belirler:
HTTP/REST ve JSON: Metin tabanlı olduğu için okunması kolaydır ancak veriyi paketleme maliyeti yüksektir, bant genişliğini daha fazla tüketir.
gRPC ve Binary Format: Veriyi ikili formatta kodlar.
Bu sayede aktarım hızı REST'e göre çok daha yüksektir ve veri boyutu küçüktür.
Özellikle mikroservisler arası düşük gecikmeli iletişim için standart tercihtir.
Stratejik Optimizasyon KatmanlarıÖnbellekleme (Caching): Veritabanına her seferinde gitmek yerine, sık kullanılan verileri Redis veya CDN gibi hızlı erişim katmanlarında tutarak yanıt süresini dramatik şekilde düşürür.
Asenkron İşleme: Rapor oluşturma veya e-posta gönderme gibi uzun süren görevlerin kullanıcıyı bekletmeden arka plan çalışanlarına devredilmesidir.
Bu, ön uçta hissedilen yanıt süresini anında iyileştiren mimari bir manevradır.
Sonuç olarak performans; doğru algoritma, doğru protokol ve akıllı bir asenkron yönetim stratejisinin birleşimiyle inşa edilen mimari bir disiplindir.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Latency Analyzer</title>
<link rel="stylesheet" href="latency-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Performance & Latency Analyzer
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container performance-theme">
<div class="lab-viz track-area">
<div class="latency-track">
<div class="track-info">
<span>HTTP/1.1 REST (JSON)</span>
<span id="rest-timer" class="timer">0 ms</span>
</div>
<div class="track-line">
<div id="rest-packet" class="packet json-packet">JSON</div>
</div>
</div>
<div class="latency-track">
<div class="track-info">
<span>HTTP/2 gRPC (Binary)</span>
<span id="grpc-timer" class="timer">0 ms</span>
</div>
<div class="track-line">
<div id="grpc-packet" class="packet binary-packet">0101</div>
</div>
</div>
</div>
<div class="lab-controls">
<h4>Protokol Hız Testi</h4>
<p class="lab-description">
Aynı boyuttaki verinin farklı protokollerle iletim süresini (TTFB) analiz edin.
</p>
<div class="btn-group">
<button id="btn-start-race" class="btn-lab btn-run">Testi Başlat</button>
<button id="btn-reset-race" class="btn-lab btn-reset">Sıfırla</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">
> Analizör hazır. Veri paketlerini göndermek için teste başlayın...
</div>
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--blue-glow: #38bdf8;
--json-color: #f59e0b;
--grpc-color: #10b981;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--blue-glow);
background: rgba(56, 189, 248, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.track-area {
padding: 40px 30px;
display: flex;
flex-direction: column;
gap: 35px;
background: rgba(15, 23, 42, 0.4);
}
.latency-track {
width: 100%;
}
.track-info {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
font-size: 12px;
font-weight: 600;
color: var(--text-dim);
}
.timer {
font-family: 'Fira Code', monospace;
color: #fff;
background: #020617;
padding: 2px 8px;
border-radius: 4px;
}
.track-line {
height: 44px;
background: #020617;
border: 1px solid var(--border-color);
border-radius: 22px;
position: relative;
overflow: hidden;
}
.packet {
position: absolute;
top: 50%;
left: 10px;
transform: translateY(-50%);
padding: 5px 15px;
border-radius: 15px;
font-size: 10px;
font-weight: 800;
text-transform: uppercase;
}
.json-packet {
background: var(--json-color);
box-shadow: 0 0 15px rgba(245, 158, 11, 0.4);
color: #000;
}
.binary-packet {
background: var(--grpc-color);
box-shadow: 0 0 15px rgba(16, 185, 129, 0.4);
color: #000;
}
/* --- Kontroller --- */
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 160px;
font-size: 14px;
}
.btn-run {
background: #3b82f6;
color: white;
}
.btn-reset {
background: #475569;
color: white;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
color: #51cf66;
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
}
const restPacket = document.getElementById("rest-packet");
const grpcPacket = document.getElementById("grpc-packet");
const restTimer = document.getElementById("rest-timer");
const grpcTimer = document.getElementById("grpc-timer");
const terminal = document.getElementById("lab-console");
let racing = false;
function log(msg, colorClass = "log-dim") {
const div = document.createElement("div");
div.className = colorClass;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
document.getElementById("btn-start-race").addEventListener("click", () => {
if (racing) return;
racing = true;
log("Test Başlatıldı: 10KB veri paketleniyor...", "log-system");
// gRPC Yarışı (Hızlı - 1.2 saniye)
startSim(grpcPacket, grpcTimer, 1200, "gRPC (Binary) veriyi iletti.");
// REST Yarışı (Yavaş - 4 saniye)
setTimeout(() => {
startSim(restPacket, restTimer, 4000, "REST (JSON) veriyi iletti.");
}, 200); // Paketleme gecikmesi simülasyonu
});
function startSim(element, timerElement, duration, completionMsg) {
let start = Date.now();
element.style.transition = `left ${duration}ms linear`;
element.style.left = "calc(100% - 60px)";
const interval = setInterval(() => {
let elapsed = Date.now() - start;
if (elapsed >= duration) {
elapsed = duration;
clearInterval(interval);
log(completionMsg, duration < 2000 ? "log-success" : "log-dim");
if (duration > 3000) racing = false;
}
timerElement.innerText = `${elapsed} ms`;
}, 10);
}
document.getElementById("btn-reset-race").addEventListener("click", () => {
restPacket.style.transition = "none";
grpcPacket.style.transition = "none";
restPacket.style.left = "10px";
grpcPacket.style.left = "10px";
restTimer.innerText = "0 ms";
grpcTimer.innerText = "0 ms";
racing = false;
log("Sistem sıfırlandı.");
});
Ölçeklenebilirlik Yatay vs. Dikey Ölçekleme ve Mimari Etkisi
Ölçeklenebilirlik, bir sistemin artan iş yükü ( kullanıcı sayısı, veri hacmi , trafik ) karşısında performans kaybı yaşamadan, kaynaklarını artırarak hizmet kalitesini koruyabilme yeteneğidir.
Gelecek Projeksiyonu: Ölçeklenebilirlik sadece bugünün trafiğini yönetmekle ilgili değildir; uygulamanın gelecekteki büyüme potansiyelini ve bu büyüme gerçekleşirken operasyonel maliyetlerin ne kadar verimli yönetileceğini de belirler.
Yatay Ölçeklemenin Mimari ZorunluluklarıModern bulut tabanlı sistemlerde tercih edilen Yatay Ölçekleme, sisteme daha fazla sunucu kopyası eklemeyi ifade eder, ancak bu esnekliğe ulaşmak için mimarinin belirli kurallara uyması şarttır:
Durumsuz Tasarım (Statelessness): Herhangi bir isteğin, sistemdeki herhangi bir sunucu kopyası tarafından işlenebilmesi için sunucuların kullanıcı oturumu gibi verileri kendi yerel belleklerinde tutmaması gerekir.
Veriler Redis gibi merkezi bir depoda tutulmalıdır.
JavaScript ( Node.js ) ekosistemi, asenkron ve modüler yapısıyla bu durumsuz çalışma modeline mükemmel uyum sağlar.
Yük Dengeleme (Load Balancing): Gelen trafiğin, sistemdeki sunucu kopyalarına adil ve verimli bir şekilde dağıtılmasıdır.
Bu bileşen, sistemin Dayanıklılığını sağlar; bir sunucu çökerse trafik otomatik olarak diğerlerine yönlendirilir.
Veri ve Mimari Darboğazların YönetimiVeri Bölümlenmesi (Sharding): Ölçeklenebilirliğin önündeki en büyük engel genellikle veritabanıdır.
Tek bir veritabanı sunucusunun kapasite limitlerini aşmak için verilerin mantıksal olarak farklı sunuculara dağıtılması ( Sharding ) zorunludur.
Mimari Desen SeçimiBir sistemin ölçeklenebilirliği, dayanıklılığı ve operasyonel verimliliği yalnızca altyapı yatırımlarıyla değil, seçilen mimari desenle doğrudan ilişkilidir.
Mimari desen; bileşenlerin nasıl organize edildiğini, sorumlulukların nasıl ayrıldığını ve sistemin değişime nasıl tepki verdiğini belirleyen yapısal bir çerçevedir.
Doğru desen seçimi, artan iş yükü karşısında sistemin hangi bileşenlerinin ölçekleneceğini, hangi noktaların darboğaz oluşturabileceğini ve ekiplerin geliştirme sürecinde nasıl bir modülerlik seviyesinde çalışacağını belirler.
Katmanlı Mimari: Genellikle merkezi bir veritabanına bağlı olduğu için yatay ölçekleme limitlerine daha çabuk takılır.
Mikroservisler ve EDA: Her servisin bağımsız ölçeklenmesine izin verir.
Örneğin: Kampanya döneminde sadece "Sipariş Servisi"nin kapasitesini artırarak kaynakları verimli kullanmanızı sağlar.
Özetlemek gerekirse yüksek ölçeklenebilirlik, sadece sistemin büyümesini sağlamaz; aynı zamanda hatalara karşı bağışıklık kazandırarak operasyonel maliyetleri minimize eden stratejik bir mimari yatırımdır.
Yatay vs. Dikey Ölçekleme Basit Diagram Gösterimi
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Scaling & Statelessness Lab</title>
<link rel="stylesheet" href="scaling-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Scaling & Statelessness Lab
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container scaling-theme">
<div class="lab-viz scaling-area">
<div id="load-balancer" class="lb-node">Load Balancer</div>
<div id="server-cluster" class="cluster">
<div class="server active">Node Server 1</div>
</div>
<div class="redis-layer">
<div class="redis-node">Shared Redis Session Store</div>
</div>
</div>
<div class="lab-controls">
<h4>Yük ve Kapasite Yönetimi</h4>
<p class="lab-description">
Sistem yükü arttığında yeni sunucular ekleyerek performansı koruyun.
</p>
<div class="btn-group">
<button id="btn-add-server" class="btn-lab btn-scale">
Sunucu Ekle (Scale Out)
</button>
<button id="btn-increase-load" class="btn-lab btn-load">
Trafik Gönder
</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">
> Sistem stabil. 1 sunucu aktif...
</div>
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--primary-blue: #38bdf8;
--redis-red: #ef4444;
--success-green: #10b981;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--primary-blue);
background: rgba(56, 189, 248, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.scaling-area {
padding: 40px 30px;
display: flex;
flex-direction: column;
align-items: center;
gap: 30px;
background: rgba(15, 23, 42, 0.4);
}
.lb-node {
padding: 10px 30px;
background: var(--primary-blue);
border-radius: 20px;
font-weight: bold;
color: #000;
font-size: 13px;
box-shadow: 0 0 15px rgba(56, 189, 248, 0.3);
}
.cluster {
display: flex;
gap: 15px;
flex-wrap: wrap;
justify-content: center;
min-height: 80px;
}
.server {
padding: 15px 20px;
background: #020617;
border: 2px solid var(--primary-blue);
border-radius: 8px;
font-size: 11px;
color: #fff;
font-family: 'Fira Code', monospace;
transition: border-color 0.3s ease;
}
.redis-layer {
width: 100%;
display: flex;
justify-content: center;
border-top: 2px dashed var(--border-color);
padding-top: 25px;
}
.redis-node {
padding: 12px 40px;
background: var(--redis-red);
border-radius: 8px;
font-size: 13px;
font-weight: 600;
color: #fff;
box-shadow: 0 0 15px rgba(239, 68, 68, 0.3);
}
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 160px;
font-size: 14px;
}
.btn-scale {
background: var(--success-green);
color: white;
}
.btn-load {
background: var(--primary-blue);
color: #000;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
color: #51cf66;
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
.cluster {
gap: 10px;
}
}
const cluster = document.getElementById("server-cluster");
const terminal = document.getElementById("lab-console");
let serverCount = 1;
function log(msg, type = "dim") {
const div = document.createElement("div");
div.style.color =
type === "success" ? "#10b981" : type === "info" ? "#38bdf8" : "#94a3b8";
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
// Sunucu Ekleme (Scale Out)
document.getElementById("btn-add-server").addEventListener("click", () => {
if (serverCount >= 4) {
log("Maksimum ölçekleme sınırına ulaşıldı.", "info");
return;
}
serverCount++;
const newServer = document.createElement("div");
newServer.className = "server";
newServer.innerText = `Node Server ${serverCount}`;
cluster.appendChild(newServer);
log(`Yatay Ölçekleme: Node Server ${serverCount} kümeye eklendi.`, "success");
log(
"Durumsuz Mimari: Yeni sunucu Redis üzerinden oturumları okumaya hazır.",
"dim",
);
});
// Trafik Simülasyonu
document.getElementById("btn-increase-load").addEventListener("click", () => {
log(
`Gelen Trafik: İstekler ${serverCount} sunucuya dengeli dağıtılıyor...`,
"info",
);
const servers = document.querySelectorAll(".server");
servers.forEach((s) => {
s.style.borderColor = "#4ade80";
setTimeout(() => (s.style.borderColor = "#38bdf8"), 500);
});
});
Güvenlik ve Dayanıklılık Konu Girişi İçeriği
Güvenlik ve Dayanıklılık, bir yazılım mimarisinin sadece kod düzeyinde doğru çalışmasını değil, aynı zamanda ekstrem koşullar altında dahi hizmet sürekliliğini garanti eden en hayati nitelik gereksinimleridir.
Bu iki nitelik, mimari bir madalyonun iki yüzü gibidir: Sistemin bütünlüğü; hem kötü niyetli dış müdahalelere karşı bir zırh giymesini, hem de beklenmedik sistem arızalarına karşı esneklik kazanmasını gerektirir.
Güvenlik: Veriyi ve Yetkiyi KorumakMimari Güvenlik, sistemin yetkisiz erişimden, veri sızıntılarından ve kötü niyetli manipülasyonlardan korunmasıdır.
Bu sadece bir kod satırı değil, tüm katmanları kapsayan bir disiplindir.
Stratejik Savunma: Kullanıcı verilerinin şifrelenmesi ( Encryption ), kimlik doğrulama ( Authentication ) ve yetki kontrolü ( Authorization ) mekanizmaları, mimarinin en başında tasarlanmalıdır.
Güvenliği sonradan eklemeye çalışmak, bir binanın temeli atıldıktan sonra gizli geçitler eklemeye benzer; her zaman zayıf noktalar bırakır.
Dayanıklılık (Resilience): Hata ile Yaşama SanatıHata Kaçınılmazdır: Dayanıklılık felsefesi, hatanın ( bir sunucunun çökmesi, ağın kopması veya veritabanının yavaşlaması ) er ya da geç gerçekleşeceğini kabul eder.
Amacı, hata anında tüm sistemin domino taşı gibi devrilmesini engellemek ve sistemin hızla toparlanmasını sağlamaktır.
Mimari Tepki: Dayanıklı bir mimari, hata izolasyonu ( bulkheading ) ve otomatik yeniden deneme ( retry patterns ) gibi stratejiler kullanarak sistemin kısmi olarak çalışmaya devam etmesini sağlar.
Bir mikroservis çöktüğünde diğerlerinin etkilenmemesi, dayanıklılığın en temel başarısıdır.
Güvenilirlik (Reliability) HedefleriGüvenlik ve Dayanıklılık el ele verdiğinde, sistemin Güvenilirlik hedefleri gerçekleşir.
Bu durum, kullanıcıların sisteme olan bağlılığını artırırken, gece yarısı gelen "sistem çöktü" alarmlarını ve operasyonel maliyetleri minimuma indirir.
Sonuç olarak bu iki AQC, yazılımı "kırılgan bir yapı" olmaktan çıkarıp; saldırılara karşı uyanık, hatalara karşı ise hazırlıklı olan endüstriyel bir kaleye dönüştürür.
Güvenlik (Security) Mimari Düzeyde Savunma
Güvenlik, bir sistemin veriyi ve işlevselliği yetkisiz erişime, manipülasyona veya sızıntılara karşı ne kadar dirençli olduğunu belirleyen temel nitelik gereksinimidir.
Mimari düzeyde güvenlik, basit bir şifreleme işleminin ötesine geçerek, sistemin tüm zayıf noktalarını önceden belirleyen Tehdit Modellemesine dayanır.
Felsefe: Derinlemesine Savunma ve Sıfır GüvenDerinlemesine Savunma (Defense in Depth): Modern mimariler, tek bir koruma duvarına güvenmek yerine, birbirini destekleyen çoklu güvenlik katmanları oluşturur.
Bir katman aşılsa bile ( firewall geçilse bile ), iç katmandaki şifreleme veya yetkilendirme mekanizmaları korumayı sürdürür.
Sıfır Güven (Zero Trust): Dağıtık sistemlerde benimsenen bu modelde, ağ içindeki hiçbir kullanıcıya veya servise varsayılan olarak güvenilmez.
"Asla güvenme, her zaman doğrula" ilkesiyle, her istek kaynağına bakılmaksızın kimlik doğrulamasına ve yetki kontrolüne tabi tutulur.
Kimlik, Yetki ve Veri BütünlüğüAuthN & AuthZ İzolasyonu: Mimari, kimlik doğrulama ve yetkilendirme süreçlerini genellikle merkezi bir Kimlik Servisine devreder.
Bu sayede güvenlik mantığı, uygulamanın iş kodundan ayrıştırılarak SRP (Single Responsibility) prensibine uyum sağlanır.
Şifreleme ve mTLS: Veri sadece depolanırken değil, ağ üzerinde akarken de ( in-transit ) korunmalıdır.
Mikroservis ortamlarında kullanılan mTLS (Mutual TLS), servislerin birbirini çift taraflı doğrulamasını sağlayarak gizlilik ve bütünlüğü ağ katmanında garanti altına alır.
Mimari Kontrol Noktaları: Gateway ve VaultAPI Ağ Geçidi (API Gateway): Sistemin kapı görevlisidir.
Tüm dış trafiği karşılar ve yetkisiz istekleri arkadaki servislere ulaşmadan engeller. Bu "Security Offloading" işlemi sayesinde iç servisler sadece kendi iş mantıklarına odaklanabilir.
Gizli Bilgi Yönetimi (Secrets Management): Veritabanı şifreleri veya API anahtarları asla kodun içinde ( hardcoded ) tutulmamalıdır.
Vault veya Cloud Secrets gibi altyapı bileşenleri, bu hassas bilgileri güvenli bir kasada saklayarak kodun ve güvenliğin sınırlarını kesin olarak ayırır.
Sonuç olarak mimari güvenlik; rastgele önlemler dizisi değil, sistemin her hücresine sızmış, proaktif ve katmanlı bir disiplinler bütünüdür.
Dayanıklılık / Hata Toleransı (Resilience / Fault Tolerance) Genel Bilgi
Dayanıklılık, bir sistemin bir veya daha fazla bileşeni arızalansa dahi, kullanıcıya hizmet vermeye devam edebilme yeteneğidir.
Bu AQC'nin temel felsefesi; hatanın sistemin doğasında var olduğunu ve kaçınılmaz olduğunu kabul etmektir.
Hızlı Geri Kazanım (Fast Recovery): Asıl amaç hatayı sıfıra indirmek değil, hata oluştuğunda sistemin bu durumdan ne kadar hızlı kurtulacağını ve normale döneceğini garanti etmektir.
Hata İzolasyonu ve Kendi Kendini OnarmaDayanıklılığın mimari odağı, hata izolasyonudur.
Geleneksel monolitik yapılarda küçük bir hata tüm sistemi çökertebilirken; dayanıklı bir mimari, arızalı bileşenin etkisini sınırlar ve bu arızanın bir "domino etkisi" yaratarak tüm sistemi aşağı çekmesini engeller.
Ölçülebilir Dayanıklılık: Bir mimarın başarısı, Ortalama Onarım Süresi metrikleriyle ölçülür.
Başarılı bir mimari, sistemin bir arıza sonrası müdahale gerektirmeden otomatik olarak kendi kendini iyileştirmesini ( self-healing ) hedefler.
Kritik Dayanıklılık Desenleri ve Mimari EtkisiÖzellikle dağıtık Node.js ve mikroservis ortamlarında, sistemin sürekliliğini sağlamak için şu desenler mimariye zorunlu olarak entegre edilir:
Devre Kesici (Circuit Breaker): Bir servise yapılan çağrılar üst üste başarısız oluyorsa, devre "açılır" ve o servise giden istekler geçici olarak durdurulur.
Bu, arızalı servisin iyileşmesi için zaman yaratırken, çağıran sistemin kaynaklarının boşa harcanmasını önler.
Tekrar Deneme (Retry) & Zaman Aşımı (Timeout): Geçici ağ hataları için istekler artan aralıklarla otomatik olarak tekrar denenir.
Zaman Aşımı ise bir servisin sonsuza kadar beklenmesini engelleyerek kaynak tüketimini sınırlar.
Yedeklilik (Redundancy): Sistemin tek bir başarısızlık noktasına sahip olmaması için kritik bileşenlerin birden fazla kopyasının çalıştırılmasıdır , bir kopya çöktüğünde trafik anında sağlam olanlara yönlendirilir.
Sonuç olarak dayanıklılık; yazılımı sadece güneşli günlerde çalışan bir yapı olmaktan çıkarıp, fırtınalı koşullarda dahi yönünü kaybetmeyen sarsılmaz bir gemiye dönüştürür.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Resilience & Circuit Breaker Lab</title>
<link rel="stylesheet" href="resilience-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Resilience & Circuit Breaker Lab
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container resilience-theme">
<div class="lab-viz resilience-area">
<div class="circuit-viz">
<div id="status-light" class="status-light closed"></div>
<div class="circuit-path">
<div class="circuit-label">
Sistem Durumu:
<span id="circuit-state-text">CLOSED</span>
</div>
<div id="breaker-line" class="breaker-line"></div>
</div>
</div>
<div class="service-cluster">
<div id="main-service" class="service-node">
Payment Service
</div>
</div>
</div>
<div class="lab-controls">
<h4>Hata İzolasyonu Simülasyonu</h4>
<p class="lab-description">
Ödeme servisini bozarak devrenin sistemi nasıl koruduğunu izleyin.
</p>
<div class="btn-group">
<button id="btn-fail-service" class="btn-lab btn-fail">
Servisi Boz (Fail)
</button>
<button id="btn-send-request" class="btn-lab btn-request">
İstek Gönder
</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">
> Sistem stabil. Hata oranı: %0...
</div>
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
/* Byteomi Resilience & Circuit Breaker - Modern Lab Styles */
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--valid-green: #10b981;
--error-red: #ef4444;
--warning-orange: #f59e0b;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
/* --- Başlık Etiketi (Header) --- */
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--valid-green);
background: rgba(16, 185, 129, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
/* --- Ana Laboratuvar Konteynırı --- */
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
/* --- Dayanıklılık Şeması (Viz) --- */
.resilience-area {
padding: 50px 30px;
display: flex;
flex-direction: column;
align-items: center;
gap: 40px;
background: rgba(15, 23, 42, 0.4);
}
.circuit-viz {
display: flex;
align-items: center;
gap: 25px;
background: #020617;
padding: 20px 40px;
border-radius: 50px;
border: 1px solid var(--border-color);
}
.status-light {
width: 24px;
height: 24px;
border-radius: 50%;
transition: all 0.4s ease;
}
.closed {
background: var(--valid-green);
box-shadow: 0 0 20px var(--valid-green);
}
.open {
background: var(--error-red);
box-shadow: 0 0 20px var(--error-red);
}
.halfopen {
background: var(--warning-orange);
box-shadow: 0 0 20px var(--warning-orange);
}
.circuit-path {
text-align: left;
}
.circuit-label {
font-size: 11px;
font-weight: 800;
margin-bottom: 8px;
color: var(--text-dim);
letter-spacing: 1.5px;
}
.breaker-line {
width: 180px;
height: 4px;
background: var(--valid-green);
border-radius: 2px;
transition: all 0.5s cubic-bezier(0.68, -0.55, 0.27, 1.55);
}
.breaker-line.broken {
background: var(--error-red);
transform: rotate(-35deg) translateY(-12px) translateX(5px);
}
.service-node {
padding: 20px 50px;
background: #020617;
border: 2px solid var(--border-color);
border-radius: 12px;
font-weight: bold;
font-family: 'Fira Code', monospace;
transition: all 0.3s ease;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
}
.service-node.failed {
border-color: var(--error-red);
color: var(--error-red);
box-shadow: 0 0 20px rgba(239, 68, 68, 0.2);
}
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 180px;
font-size: 14px;
}
.btn-fail {
background: var(--error-red);
color: white;
}
.btn-request {
background: var(--valid-green);
color: white;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
/* --- Terminal --- */
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
.circuit-viz {
padding: 15px 25px;
}
.breaker-line {
width: 120px;
}
}
const light = document.getElementById("status-light");
const breaker = document.getElementById("breaker-line");
const stateText = document.getElementById("circuit-state-text");
const service = document.getElementById("main-service");
const terminal = document.getElementById("lab-console");
let state = "CLOSED"; // CLOSED, OPEN, HALF-OPEN
let failureCount = 0;
let isServiceDown = false;
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
function updateCircuit(newState) {
state = newState;
stateText.innerText = newState;
light.className = `status-light ${newState.toLowerCase().replace("-", "")}`;
if (newState === "OPEN") {
breaker.classList.add("broken");
log(
`DİKKAT: Devre AÇILDI (OPEN). İstekler servise gitmeden engelleniyor.`,
"#ef4444",
);
} else {
breaker.classList.remove("broken");
breaker.style.background = newState === "HALF-OPEN" ? "#f59e0b" : "#10b981";
}
}
document.getElementById("btn-fail-service").addEventListener("click", () => {
isServiceDown = true;
service.classList.add("failed");
log("Sistem Hatası: Ödeme servisi yanıt vermeyi kesti!", "#ef4444");
});
document.getElementById("btn-send-request").addEventListener("click", () => {
if (state === "OPEN") {
log("Circuit Breaker: İstek reddedildi. Hata izolasyonu aktif.", "#f59e0b");
return;
}
log("İstek gönderiliyor...");
if (isServiceDown) {
failureCount++;
log(
`HATA: Servis başarısız oldu. (Başarısızlık: ${failureCount})`,
"#ef4444",
);
if (failureCount >= 3) {
updateCircuit("OPEN");
// 5 saniye sonra Half-Open durumuna geçiş simülasyonu
setTimeout(() => {
updateCircuit("HALF-OPEN");
log(
"Sistem Kontrolü: Devre YARI-AÇIK. Servis test ediliyor...",
"#f59e0b",
);
failureCount = 0;
}, 5000);
}
} else {
log("BAŞARI: İstek tamamlandı.", "#10b981");
}
});
Kimlik ve Yetkilendirme Mekanizması Genel Bilgi
Modern dağıtık mimarilerde Kimlik Doğrulama ( AuthN ) ve Yetkilendirme ( AuthZ ) süreçleri, genellikle merkezi bir Kimlik Servisine devredilir.
Bu mimari tercih, SRP (Single Responsibility Principle) uyarınca, güvenlik karmaşıklığının uygulamanın ana iş kurallarından tamamen izole edilmesini sağlar.
Bağımlılıkların Tersine Çevrilmesi (DIP): Merkeziyetçi yaklaşım, iş mantığı servislerinin parola hash'leme veya karmaşık oturum yönetimi gibi süreçlere bağımlı olmasını engeller.
Servisler sadece kimlik bilgisinin "doğruluğu" ile ilgilenir; bu bilginin nasıl üretildiğiyle ilgilenmez.
AuthN (Kimlik Doğrulama) ve Durumsuzluk (Statelessness)JWT'nin Stratejik Rolü: Node.js ve mikroservis ekosisteminde AuthN, genellikle kriptografik olarak imzalanmış JWT (JSON Web Tokens) üzerinden yürütülür.
Bu teknoloji, mimariye Durumsuzluk kazandırır.
Performans AQC'si: Token'lar imzalı olduğu için, API Ağ Geçidi veya servisler her istekte veritabanına gidip oturum kontrolü yapmak zorunda kalmaz.
İmzayı yerel olarak doğrulamak yeterlidir ve bu, veritabanı üzerindeki yükü kaldırarak sistemin yatayda ışık hızında ölçeklenmesini sağlar.
AuthZ (Yetkilendirme): Erişim Kontrol ModelleriKimlik doğrulandıktan sonra, bu kimliğin hangi kaynaklara dokunabileceğini belirleyen süreç Yetkilendirmedir, mimari tasarımda iki ana model öne çıkar:
Rol Tabanlı Erişim Kontrolü (RBAC): Kullanıcılara "Admin", "Editor" gibi roller atanır.
En yaygın ve yönetimi basit modeldir, izinler doğrudan rollere göre şekillenir.
Nitelik Tabanlı Erişim Kontrolü (ABAC): Daha dinamik bir modeldir.
Yetki; kullanıcının konumu, departmanı, hatta mesai saati gibi niteliklere göre anlık belirlenir.
Örneğin: "Sadece Pazarlama yöneticileri, hafta içi saat 18:00'den önce kendi bölge raporlarını görebilir." mesajı gibi bir yetki kontrolü yapılabilir.
Servis İçi Güvenlik Akışı ve Veri GüvenliğiToken, API Ağ Geçidi tarafından doğrulanıp sisteme girse bile, her mikroservis kendi kaynakları için son bir kontrol yapmalıdır.
Bu, Hata İzolasyonu açısından kritiktir.
Örneğin: Bir OrderService, gelen JWT içindeki kullanıcı ID'sini alır ve veritabanı seviyesinde "Bu sipariş gerçekten bu kullanıcıya mı ait?" kontrolünü yapar.
Bu, hem veri güvenliğini sağlar hem de yetkisiz bir erişim denemesi olduğunda bu hatanın diğer servisleri etkilemeden o noktada sönümlenmesini garanti eder.
Sonuç olarak Kimlik ve Yetkilendirme; yazılımı rastgele erişimlerden koruyan bir kabuk değil, sistemin her hücresinde
kimin, neyi, ne zaman yapabileceğine karar veren merkezi bir akıl ve disiplindir.
API Ağ Geçidi (API Gateway) Rolü Genel Bilgi
API Ağ Geçidi, modern mikroservis mimarilerinde dış dünya ile sistemin iç işleyişi arasındaki tek zorunlu uygulama noktasıdır.
Mimari açıdan tüm harici trafiğin bu merkezden geçmesi, Sıfır Güven felsefesinin sistemin en dış sınırında katı bir şekilde uygulanmasını sağlar.
Güvenlik Yükünü Hafifletme (Security Offloading)Merkezi Doğrulama: Ağ Geçidi; token geçerliliği ve temel yetki kontrolleri gibi ağır güvenlik süreçlerini üstlenir.
Bu durum, SRP (Single Responsibility Principle) uyarınca iç servislerin bu karmaşık ve tekrarlayan mantığı barındırmasına gerek bırakmaz.
Sınır Koruması: Yetkisiz veya hatalı istekler daha sistemin iç katmanlarına sızmadan Ağ Geçidi tarafından engellenir.
İç trafik ise genellikle mTLS gibi protokollerle daha derin katmanlarda korunmaya devam eder; bu da katmanlı bir Güvenlik AQC'si sunar.
Operasyonel Orkestrasyon ve VerimlilikAğ Geçidi, güvenliğin ötesinde sistemin operasyonel akışını yöneten bir orkestra şefi gibi çalışır:
Trafik Yönlendirme (Reverse Proxy): İstemciden gelen basit istekleri, içerideki dinamik Servis Keşfi mekanizması üzerinden doğru mikroservis kopyalarına iletir.
Bu, istemcinin karmaşık iç ağ yapısını bilmesine gerek bırakmaz ( Gevşek Bağlılık ).
API Kompozisyonu (Aggregation): Tek bir kullanıcı isteği için arkada çalışan beş farklı servisten veri toplayıp bunları tek bir paket halinde istemciye sunabilir.
Bu, ağ üzerindeki gidiş-dönüş trafiğini azaltarak Performans AQC'sini doğrudan yukarı çeker.
Yatay Kesen Sorumlulukların (Cross-Cutting Concerns) YönetimiGüvenlik dışında; Hız Sınırlama, İzleme ve Günlükleme gibi her serviste ortak olan sorumluluklar bu merkezi noktada çözülür.
Bu sayede tüm sistemde operasyonel bir tutarlılık sağlanırken, geliştirme ekiplerinin sadece "iş değerine" odaklanması mümkün kılınır.
Sonuç olarak API Ağ Geçidi, yazılım mimarisini "kontrolsüz bir kaos" olmaktan çıkarıp; güvenli, performanslı ve tek bir noktadan yönetilebilen disiplinli bir platforma dönüştürür.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Gateway & Auth Flow Lab</title>
<link rel="stylesheet" href="gateway-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Gateway & Auth Flow Lab
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container gateway-theme">
<div class="lab-viz gateway-area">
<div id="client-node" class="node client">
İstemci (Browser)
</div>
<div class="arrow">→</div>
<div id="gateway-node" class="node gateway">
API Gateway (Auth Check)
</div>
<div class="arrow">→</div>
<div id="service-node" class="node service">
Microservice (Order/User)
</div>
</div>
<div class="lab-controls">
<h4>Sıfır Güven Sınır Hattı</h4>
<p class="lab-description">
Token doğrulaması başarılı olursa Gateway isteği iç servislere iletir.
</p>
<div class="btn-group">
<button id="btn-valid-token" class="btn-lab btn-valid">
Geçerli Token Gönder
</button>
<button id="btn-invalid-token" class="btn-lab btn-invalid">
Hatalı Token Gönder
</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">
> Sınır hattı aktif. İzleme bekleniyor...
</div>
</div>
</div>
<script type="module" src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--gateway-blue: #38bdf8;
--valid-green: #10b981;
--error-red: #ef4444;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--gateway-blue);
background: rgba(56, 189, 248, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.gateway-area {
padding: 50px 30px;
display: flex;
justify-content: center;
align-items: center;
gap: 15px;
background: rgba(15, 23, 42, 0.4);
}
.node {
padding: 15px 20px;
border-radius: 8px;
font-size: 12px;
font-weight: 600;
text-align: center;
border: 2px solid #475569;
transition: all 0.3s ease;
min-width: 150px;
background: #334155;
color: #fff;
}
.gateway {
background: #020617;
border-color: var(--gateway-blue);
color: var(--gateway-blue);
box-shadow: 0 0 15px rgba(56, 189, 248, 0.1);
}
.arrow {
color: var(--border-color);
font-weight: bold;
font-size: 20px;
}
.active-pulse {
box-shadow: 0 0 20px var(--gateway-blue);
transform: scale(1.05);
}
.success-flash {
border-color: var(--valid-green) !important;
color: var(--valid-green) !important;
box-shadow: 0 0 15px rgba(16, 185, 129, 0.3);
}
.error-flash {
border-color: var(--error-red) !important;
color: var(--error-red) !important;
box-shadow: 0 0 15px rgba(239, 68, 68, 0.3);
}
/* --- Kontroller --- */
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 180px;
font-size: 14px;
}
.btn-valid {
background: var(--valid-green);
color: white;
}
.btn-invalid {
background: var(--error-red);
color: white;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
/* --- Terminal --- */
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
.gateway-area {
flex-direction: column;
padding: 30px;
}
.arrow {
transform: rotate(90deg);
margin: 5px 0;
}
}
const gatewayNode = document.getElementById("gateway-node");
const serviceNode = document.getElementById("service-node");
const terminal = document.getElementById("lab-console");
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
function resetNodes() {
gatewayNode.classList.remove("active-pulse", "success-flash", "error-flash");
serviceNode.classList.remove("success-flash");
}
// Geçerli Token Simülasyonu
document.getElementById("btn-valid-token").addEventListener("click", () => {
resetNodes();
log("İstemci: İstek gönderildi (JWT: Valid)...", "#38bdf8");
gatewayNode.classList.add("active-pulse");
setTimeout(() => {
gatewayNode.classList.add("success-flash");
log("Gateway: Token doğrulandı. İstek yönlendiriliyor...", "#10b981");
setTimeout(() => {
serviceNode.classList.add("success-flash");
log("Sipariş Servisi: İşlem başarıyla tamamlandı.", "#10b981");
}, 600);
}, 800);
});
// Hatalı Token Simülasyonu
document.getElementById("btn-invalid-token").addEventListener("click", () => {
resetNodes();
log("İstemci: İstek gönderildi (JWT: Invalid)...", "#38bdf8");
gatewayNode.classList.add("active-pulse");
setTimeout(() => {
gatewayNode.classList.add("error-flash");
log(
"Gateway: 401 Unauthorized - Hatalı Token! İstek engellendi.",
"#ef4444",
);
log("Analiz: İç servislere hiçbir veri sızmadı.", "#f1c40f");
}, 800);
});
Mikroservis Mimari Şeması Basit Diagram Gösterimi
Sol Bölüm: Dış bileşenler ve servisler (UI bileşenleri, dış API'ler, üçüncü parti servisler)
Sağ Bölüm: Bağımsız nano servisler, her biri kendi veritabanı ve kaynaklarına sahip
Bu Diagram: Mikroservis mimarisinde merkezi API Gateway'in, dış bileşenler ile backend nano servisler arasındaki yönlendirme ve yönetim rolünü gösterir.
Bakım ve Geliştirilebilirlik (Maintainability and Evolvability) Konu İçeriği
Bakım ve Geliştirilebilirlik, bir yazılım sisteminin ilk yayınlanmasından sonraki aylar ve yıllar boyunca ne kadar kolay güncellenebileceğini, hatalardan nasıl arındırılacağını ve yeni taleplere ne kadar hızlı cevap verebileceğini belirleyen en temel mimari hedeflerdir.
Bu iki nitelik gereksinimi, yazılım dünyasının en büyük maliyet kalemi olan Teknik Borcun birikmesini engelleyen en güçlü bariyerlerdir.
Bakım Kolaylığı (Maintainability): Mevcut Durumu KorumakBakım kolaylığı, sistemde bir hata tespit edildiğinde bu hatanın ne kadar düşük maliyetle ve ne kadar hızlı düzeltilebileceğini ölçer.
Sistemin iç kalitesini temsil eden üç ana sütun üzerine inşa edilir:
Anlaşılırlık (Understandability): Kod tabanına yeni katılan bir geliştiricinin mimariyi ne kadar sürede kavradığıdır.
SOLID prensipleri ve Katmanlı Mimari kullanımı burada anahtar rol oynar.
Test Edilebilirlik (Testability): Modüllerin birbirini bozmadan, izole bir şekilde test edilebilme kapasitesidir ve test edilemeyen kod, bakımı imkansız koddur.
Hata Ayıklama (Debuggability): Bir sorun anında kaynağın hızla bulunabilmesidir.
Bu, sistemin Gözlemlenebilirlik kabiliyetiyle doğrudan ilişkilidir.
Geliştirilebilirlik ve Esneklik (Evolvability): Geleceği İnşa EtmekGeliştirilebilirlik, sistemin henüz öngörülmeyen gelecekteki gereksinimlere ( yeni teknolojiler, farklı veritabanları veya
yeni iş modelleri ) uyum sağlama yeteneğidir:
Uyum Yeteneği (Adaptability): Teknoloji yığını değiştiğinde ( SQL'den NoSQL'e geçiş gibi ) sistemin sergilediği dirençtir.
DIP bu noktada hayati bir kalkan görevi görür.
Genişletilebilirlik (Extensibility): Yeni özelliklerin, mevcut çalışan yapıya zarar vermeden entegre edilmesidir.
OCP bu yeteneğin matematiksel temelini oluşturur.
Mimari Kararlar ve Stratejik DesenlerYüksek geliştirilebilirlik hedefleri, mimarları iş mantığını altyapı detaylarından keskin bir şekilde ayıran Temiz Mimari veya Altıgen Mimari gibi modellere yönlendirir.
Sonuç olarak Bakım ve Geliştirilebilirlik; kodun sadece "bugün" çalışmasını değil, on yıl sonra bile taze, anlaşılır ve değişime hevesli kalmasını sağlayan profesyonel bir mimari mirastır.
Mimari Desenler Yapısal Çözümler ve Karar Verme Araçları
Mimari Desenler, bir yazılım sisteminin genel yapısını, organizasyonunu ve bileşenleri arasındaki temel iletişim kurallarını şekillendiren üst düzey şablonlardır.
Tasarım Desenlerinden (GoF) Farkı: Kod seviyesindeki mikro sorunlara çözüm sunan tasarım desenlerinin aksine; mimari desenler tüm sistemin ölçeklenebilirlik, esneklik ve güvenlik gibi nitelik gereksinimlerini garanti altına alan "büyük resmi" çizer.
Mimari Desenlerin Temel RolüMimari desenler, geliştirme ekiplerine ortak bir dil ve çözüm çerçevesi sunarak karmaşıklığı şu üç ana eksende yönetir:
Sorumlulukların Bölünmesi (Partitioning): Karmaşık işlevleri yönetilebilir parçalara ayırır.
Örneğin: Katmanlı Mimari sorumlulukları dikey olarak bölerken, Mikroservis Mimarisi iş alanlarına göre yatay olarak böler.
Bağımlılık Yönünü Belirleme: Hangi bileşenin kime bağlı olabileceğine dair katı kurallar koyar.
Bu, DIP prensibini büyük ölçekte uygulamanın temel yoludur ve bir parçadaki değişimin tüm sistemi çökertmesini ( domino etkisi ) engeller.
Kanıtlanmış Stratejiler: Her desen, belirli bir problem kümesine karşı defalarca başarılı olmuş bir mühendislik mirasıdır ve tekerleği yeniden icat etme riskini ortadan kaldırır.
Modern JS ve Node.js Ekosistemindeki Kritik ÖnemiHızla büyüyen JavaScript dünyasında mimari desenler, projenin "kontrolsüz bir kod yığınına" dönüşmesini engelleyen anahtar faktördür:
Ölçeklenebilirlik Kararı: Bir Node.js uygulamasının tek bir sunucuda mı ( Monolitik/Katmanlı ) yoksa yüzlerce konteynerda mı ( Mikroservis ) çalışacağı kararı mimari desen seçimiyle kristalleşir.
Sorumluluk Ayrımı: MVC veya MVVM gibi desenler, ön uç ( React/Vue ) ve arka uç ( Node/Express ) sorumluluklarını netleştirerek ekiplerin birbirine ayak bağı olmadan çalışmasını sağlar.
Özetle, mimari desenler; yazılımı rastgele bir araya getirilmiş parçalar bütünü olmaktan çıkarıp, kararlı, öngörülebilir ve teknoloji değişimine hazır profesyonel bir yapıya dönüştürür.
Katmanlı Mimari (Layered Architecture) Dört Katmanlı Yapı
Katmanlı Mimari, bir yazılım sisteminin sorumluluklarını dikey olarak birbirinden bağımsız katmanlara bölen geleneksel ve son derece etkili bir tasarım desenidir.
Bu yapı, her katmanın sadece kendi görevine odaklanmasını sağlayarak sistem genelinde Tek Sorumluluk Prensibi'ni en üst düzeyde uygular.
Hiyerarşik İzolasyon: Bu mimarinin temel kuralı, üst katmanların alt katmanların iç işleyişi hakkında minimum bilgiye sahip olmasıdır.
Bu sayede, alt katmanlarda yapılan teknik bir değişiklik ( veritabanı şemasının güncellenmesi gibi ), tüm sistemi sarsmadan sadece doğrudan üstündeki katmanı etkiler.
Dört Katmanlı Standart YapıGeleneksel olarak sistem, belirli sınırlarla ( boundaries ) ayrılmış dört ana katmandan oluşur:
1. Sunum Katmanı (Presentation Layer): Kullanıcı arayüzü ve istemci ile etkileşimin yönetildiği yerdir.
2. İş Mantığı Katmanı (Business/Service Layer): Sistemin asıl "aklını" temsil eder; tüm iş kuralları ve hesaplamalar burada gerçekleşir.
3. Kalıcılık Katmanı (Persistence Layer): Verinin veritabanına nasıl yazılacağı ve okunacağıyla ilgilenen teknik detayları barındırır.
4. Veritabanı Katmanı (Database Layer): Verinin fiziksel olarak saklandığı en alt katmandır.
Modern Node.js Uygulamalarında SadeleşmeGünümüzün çevik Node.js ekosisteminde, bu dörtlü yapı genellikle daha esnek bir formata evrilir.
Veri erişim ve kaynak yönetimi katmanları, Altyapı/Depo adı verilen tek bir yapıda birleştirilir.
DIP ve Bakım Kolaylığı: Bu sadeleştirme, Bağımlılıkların Tersine Çevrilmesi Prensibi için ideal bir zemin hazırlar.
İş mantığı katmanı, somut veritabanı sürücülerine değil, soyut bir depo arayüzüne bağımlı hale gelir. Bu stratejik ayrım, sistemin Bakım Kolaylığı ve Test Edilebilirlik değerlerini maksimize eder.
Sonuç olarak Katmanlı Mimari; onlarca yıldır kurumsal uygulamalarda başarısını kanıtlamış, sistemin her parçasının görevini kusursuz yapmasını sağlayan "Yüksek Uyumlu" bir güven modelidir.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Layered Architecture Flow Lab</title>
<link rel="stylesheet" href="layered-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Layered Architecture Flow Simulator
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container layered-theme">
<div class="lab-viz layered-viz">
<div id="layer-pres" class="layer-node">
1. Sunum Katmanı (Controller)
</div>
<div class="layer-arrow">↓</div>
<div id="layer-biz" class="layer-node">
2. İş Mantığı Katmanı (Service)
</div>
<div class="layer-arrow">↓</div>
<div id="layer-pers" class="layer-node">
3. Veri Erişim Katmanı (Repository)
</div>
<div class="layer-arrow">↓</div>
<div id="layer-db" class="layer-node db-node">
4. Veritabanı (Physical Storage)
</div>
</div>
<div class="lab-controls">
<h4>Katmanlar Arası İletişim</h4>
<p class="lab-description">
Bir "Sipariş" isteğinin katman hiyerarşisinde nasıl delege edildiğini izleyin.
</p>
<div class="btn-group">
<button id="btn-process-order" class="btn-lab btn-primary">
Siparişi İşle
</button>
<button id="btn-reset-flow" class="btn-lab btn-reset">
Sıfırla
</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">
> Sistem hazır. İsteği başlatın...
</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--layer-pres: #38bdf8;
--layer-biz: #a78bfa;
--layer-pers: #fbbf24;
--layer-db: #f87171;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--layer-pres);
background: rgba(56, 189, 248, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.layered-viz {
padding: 40px 30px;
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
background: rgba(15, 23, 42, 0.4);
}
.layer-node {
width: 320px;
padding: 15px;
border-radius: 10px;
text-align: center;
font-weight: 700;
font-size: 13px;
color: #fff;
border: 2px solid transparent;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
background: #020617;
cursor: default;
}
#layer-pres {
border-color: var(--layer-pres);
}
#layer-biz {
border-color: var(--layer-biz);
}
#layer-pers {
border-color: var(--layer-pers);
}
#layer-db {
border-color: var(--layer-db);
border-radius: 15px 15px 25px 25px;
}
/* Aktif Durum Parlamaları */
.layer-node.active {
transform: scale(1.05);
}
#layer-pres.active {
background: var(--layer-pres);
color: #000;
box-shadow: 0 0 25px rgba(56, 189, 248, 0.5);
}
#layer-biz.active {
background: var(--layer-biz);
color: #000;
box-shadow: 0 0 25px rgba(167, 139, 250, 0.5);
}
#layer-pers.active {
background: var(--layer-pers);
color: #000;
box-shadow: 0 0 25px rgba(251, 191, 36, 0.5);
}
#layer-db.active {
background: var(--layer-db);
color: #000;
box-shadow: 0 0 25px rgba(248, 113, 113, 0.5);
}
.layer-arrow {
color: var(--border-color);
font-weight: bold;
font-size: 20px;
height: 25px;
display: flex;
align-items: center;
}
/* --- Kontroller --- */
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 160px;
font-size: 14px;
}
.btn-primary {
background: var(--layer-pres);
color: #000;
}
.btn-reset {
background: #475569;
color: white;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
.lab-terminal {
background: #000;
padding: 20px;
height: 160px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
line-height: 1.6;
}
/* --- Mobil Duyarlılık --- */
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
.layer-node {
width: 100%;
max-width: 280px;
}
}
const layers = ["layer-pres", "layer-biz", "layer-pers", "layer-db"];
const terminal = document.getElementById("lab-console");
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
document
.getElementById("btn-process-order")
.addEventListener("click", async () => {
// Adım 1: Sunum Katmanı
activateLayer(0);
log(
"Sunum Katmanı: HTTP POST /orders isteği alındı. Veri formatı doğrulanıyor...",
"#38bdf8",
);
await wait(1000);
// Adım 2: İş Mantığı Katmanı
activateLayer(1);
log(
"İş Mantığı: Sipariş kuralları (stok kontrol, bakiye) işletiliyor...",
"#a78bfa",
);
await wait(1000);
// Adım 3: Veri Erişim Katmanı
activateLayer(2);
log(
"Veri Erişimi: Sipariş nesnesi SQL INSERT komutuna dönüştürülüyor...",
"#fbbf24",
);
await wait(1000);
// Adım 4: Veritabanı
activateLayer(3);
log("Veritabanı: Fiziksel kayıt başarıyla tamamlandı. (Commit)", "#f87171");
log("İşlem Başarılı: Yanıt yukarı katmanlara iletiliyor.", "#10b981");
});
function activateLayer(index) {
layers.forEach((id) =>
document.getElementById(id).classList.remove("active"),
);
document.getElementById(layers[index]).classList.add("active");
}
function wait(ms) {
return new Promise((res) => setTimeout(res, ms));
}
Sunum Katmanı Detaylı Analizi Presentation Layer
Sunum Katmanı, sistemin dış dünya ile temas kurduğu en üst düzey arayüzdür.
Tek sorumluluğu, kullanıcıdan veya harici sistemlerden gelen talepleri kabul etmek ve bu taleplerin işlenmesi sonucunda oluşan verileri, istemcinin anlayabileceği uygun formata dönüştürerek geri iletmektir.
İş Mantığından Arındırılmış Yapı: Bu katmanın temel felsefesi sadece koordinasyon yapmaktır.
Sunum katmanı, verinin ne anlama geldiğiyle ( İş Mantığı ) veya nasıl saklandığıyla ( Veri Erişimi ) ilgilenmez; sadece "gelen isteği doğru yere iletme" ve "sonucu doğru formatta sunma" görevine odaklanır.
Kritik Sorumluluklar: Doğrulama ve YönlendirmeSunum katmanı, sistemin güvenliğini ve veri kalitesini korumak için şu kritik görevleri üstlenir:
İstek Ayrıştırma ve Yönlendirme (Routing): Gelen HTTP isteklerini veya mesaj kuyruğu bildirimlerini analiz ederek, hangi bileşenin bu isteği karşılayacağına karar verir.
Temel Veri Doğrulama (Input Validation): Gelen verinin beklenen yapıda olup olmadığını ( bir e-posta alanının boş olup olmadığı kontrolü gibi ) kontrol eder. Ancak iş kurallarına dayalı derin kontrolleri bir alt katmana bırakır.
Modern JavaScript Ekosisteminde UygulamaJavaScript dünyasında Sunum Katmanı, hem istemci (Frontend) hem de sunucu (Backend) tarafında net rollere sahiptir:
Frontend (React, Vue, Angular): Kullanıcı etkileşimlerini yakalayan bileşenler ( Components ) bu katmandadır.
Bir butona tıklandığında yapılacak işlem, bileşenin içinde değil, ona bağlı bir servis veya store içinde tanımlıdır.
Backend (Node.js - Express, NestJS): Controller sınıfları bu katmanın merkezindedir ve Controller'lar asla doğrudan veritabanı sorgusu yazmamalı; tüm talepleri bir alt katmandaki Servis nesnelerine delege etmelidir.
Teknolojik Bağımsızlık ve EsneklikSunum katmanının bu keskin izolasyonu, sistemin kullanıcı arayüzü teknolojisi değiştiğinde ( React'ten Vue'ye geçişte ) veya bir API'dan CLI
( Komut Satırı ) uygulamasına dönüştüğünde, sistemin çekirdek iş mantığının hiç bozulmadan korunmasını garanti eder.
Sonuç olarak Sunum Katmanı; sistemi karmaşadan koruyan, dış dünyadan gelen gürültüyü temizleyen ve çekirdek mantığı izole eden
profesyonel bir iletişim kalkanıdır.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Presentation Shield Lab</title>
<link rel="stylesheet" href="shield-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Presentation Shield (Input Validation)
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container shield-theme">
<div class="lab-viz shield-viz">
<div class="input-data-box">
<div id="data-packet" class="data-packet">User Data</div>
</div>
<div id="shield-gate" class="shield-gate">Presentation Layer (Shield)</div>
<div class="internal-system">
<div id="biz-core" class="core-node">Business Logic Core</div>
</div>
</div>
<div class="lab-controls">
<h4>Giriş Filtreleme Simülasyonu</h4>
<p class="lab-description">Sunum katmanının, geçersiz veriyi çekirdek sisteme ulaşmadan nasıl elediğini
izleyin.
</p>
<div class="btn-group">
<button id="btn-send-clean" class="btn-lab btn-clean">Temiz Veri Gönder</button>
<button id="btn-send-dirty" class="btn-lab btn-dirty">Kirli Veri Gönder</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">> Kalkan aktif. Veri girişi bekleniyor...</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--shield-blue: #38bdf8;
--clean-green: #10b981;
--dirty-red: #ef4444;
--core-purple: #a78bfa;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--shield-blue);
background: rgba(56, 189, 248, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.shield-viz {
padding: 60px 30px;
display: flex;
flex-direction: column;
align-items: center;
gap: 30px;
background: rgba(15, 23, 42, 0.4);
position: relative;
border-top: 1px solid #eee;
}
.shield-gate {
width: 100%;
max-width: 500px;
padding: 20px;
background: #020617;
border: 3px solid var(--shield-blue);
border-radius: 15px;
text-align: center;
font-weight: 800;
color: var(--shield-blue);
z-index: 2;
transition: all 0.3s ease;
box-shadow: 0 0 15px rgba(56, 189, 248, 0.2);
}
.core-node {
padding: 20px 40px;
background: rgba(167, 139, 250, 0.1);
border: 2px dashed var(--core-purple);
border-radius: 10px;
color: var(--core-purple);
font-weight: bold;
box-shadow: 0 0 15px rgba(167, 139, 250, 0.1);
}
.data-packet {
padding: 8px 16px;
background: #fff;
color: #000;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
position: absolute;
top: 0;
opacity: 0;
}
.shield-gate.reject {
border-color: var(--dirty-red);
color: var(--dirty-red);
box-shadow: 0 0 25px var(--dirty-red);
}
.shield-gate.pass {
border-color: var(--clean-green);
color: var(--clean-green);
box-shadow: 0 0 25px var(--clean-green);
}
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 180px;
font-size: 14px;
}
.btn-clean {
background: var(--clean-green);
color: white;
}
.btn-dirty {
background: var(--dirty-red);
color: white;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
}
const gate = document.getElementById("shield-gate");
const packet = document.getElementById("data-packet");
const terminal = document.getElementById("lab-console");
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
function runSimulation(isDirty) {
gate.className = "shield-gate";
packet.style.opacity = "1";
packet.style.top = "0";
packet.innerText = isDirty ? "MALFORMED DATA" : "CLEAN DATA";
packet.style.background = isDirty ? "#ef4444" : "#10b981";
log(
`İstek Alındı: ${isDirty ? "Kirli" : "Temiz"} veri paketi sunum katmanına ulaştı...`,
);
// Paket hareketi
setTimeout(() => {
packet.style.transition = "all 0.8s ease-in";
packet.style.top = "100px";
setTimeout(() => {
if (isDirty) {
gate.classList.add("reject");
log(
"DOĞRULAMA HATASI: Sunum katmanı veriyi reddetti! (400 Bad Request)",
"#ef4444",
);
log("İş mantığı katmanı güvende, kirli veri sızmadı.", "#f59e0b");
packet.style.opacity = "0";
} else {
gate.classList.add("pass");
log("DOĞRULAMA BAŞARILI: Veri formatı uygun.", "#10b981");
setTimeout(() => {
packet.style.top = "250px";
log(
"YÖNLENDİRME: İstek İş Mantığı (Service) katmanına delege ediliyor.",
"#a78bfa",
);
}, 400);
}
}, 800);
}, 100);
}
document
.getElementById("btn-send-clean")
.addEventListener("click", () => runSimulation(false));
document
.getElementById("btn-send-dirty")
.addEventListener("click", () => runSimulation(true));
İş Mantığı Katmanı Detaylı Analizi Business Layer
İş Mantığı Katmanı, uygulamanın temel değerini yaratan ve tüm sistemin nasıl davranması gerektiğini belirleyen merkezdir.
Bu katman, sistemin asıl "beyni" olarak iş kurallarını, süreç akışlarını ve uygulama durumunu yönetir.
Mimari Orkestra Şefi: Sunum ve Veri katmanları arasındaki koordinasyondan sorumludur.
Bir isteğin yerine getirilmesi için hangi verinin, hangi sırayla ve hangi şartlar altında işleneceğine bu katman karar verir.
Örneğin: "Bir transfer işleminde gönderici bakiyesi kontrol edilmeli, ardından her iki hesap eşzamanlı güncellenmelidir" kuralı bu katmanın asli görevidir.
Teknolojiden Bağımsızlık (Technology-Agnostic)İş Mantığı Katmanı, mimarideki en soyut ve en değerli bölgedir.
En büyük özelliği teknolojik detaylara kör olmasıdır. Verinin hangi veritabanında saklandığı veya isteğin hangi arayüzden geldiği bu katmanı ilgilendirmez.
DIP ile Koruma: Bu katman asla HTTP protokol kodları, HTML etiketleri veya ham SQL sorguları içermemelidir.
Bağımlılıkların Tersine Çevrilmesi Prensibi sayesinde altyapı detaylarından izole edilir, böylece teknoloji yığını değişse bile işin özü
( business logic ) sarsılmaz.
JavaScript Bağlamı: Servisler ve Domain ModelleriModern JavaScript ve Node.js mimarilerinde bu katman genellikle Service sınıfları veya Domain modelleri üzerinden temsil edilir:
Sorumluluk Dağılımı: UserService.register() veya OrderService.placeOrder() gibi metotlar bu katmanda yer alır.
Bu servisler, veriye ulaşmak için alt katmandaki Repository arayüzlerini kullanır.
Atomik İşlemler: Karmaşık süreçlerin ve işlem yönetiminin ( transaction management ) merkezi burasıdır.
Hata izolasyonunu sağlayarak verinin tutarlı kalmasını garanti eder.
Sürdürülebilirlik ve Yeniden Kullanılabilirlikİş mantığının bu şekilde izole edilmesi, uygulamanın uzun ömürlü olmasını sağlar.
Bir gün veritabanı sağlayıcınızı değiştirmek isterseniz, sadece alt katmandaki "detayı" güncellersiniz; uygulamanın kalbi olan iş kuralları dokunulmazlığını korur.
Sonuç olarak İş Mantığı Katmanı; yazılımı teknik bir araç olmaktan çıkarıp, gerçek dünyadaki bir iş problemini çözen akıllı bir sisteme dönüştüren mimari çekirdektir.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Business Core Lab</title>
<link rel="stylesheet" href="business-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Business Core Engine (Logic Isolation)
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container business-theme">
<div class="lab-viz business-area">
<div id="logic-core" class="logic-core">
<div class="core-label">BUSINESS LOGIC CORE</div>
<div class="rule-box">Kural: Bakiye >= Transfer Miktarı</div>
</div>
<div class="adapter-zone">
<div id="db-adapter" class="db-adapter">SQL Repository (Active)</div>
</div>
</div>
<div class="lab-controls">
<h4>Teknolojiden Bağımsız İş Kuralları</h4>
<p class="lab-description">Veritabanı teknolojisini değiştirin; iş mantığının etkilenmediğini izleyin.</p>
<div class="btn-group">
<button id="btn-switch-db" class="btn-lab btn-switch">Altyapıyı Değiştir (DIP)</button>
<button id="btn-run-logic" class="btn-lab btn-run">İşlemi Başlat</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">> Çekirdek motor hazır. Altyapı: SQL...</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--core-purple: #a78bfa;
--adapter-blue: #38bdf8;
--adapter-amber: #fbbf24;
--success-green: #10b981;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--core-purple);
background: rgba(167, 139, 250, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.business-area {
padding: 60px 30px;
display: flex;
flex-direction: column;
align-items: center;
gap: 40px;
background: rgba(15, 23, 42, 0.4);
}
.logic-core {
width: 100%;
max-width: 400px;
padding: 30px;
background: #020617;
border: 3px solid var(--core-purple);
border-radius: 20px;
text-align: center;
box-shadow: 0 0 25px rgba(167, 139, 250, 0.3);
z-index: 2;
transition: all 0.3s ease;
}
.core-label {
font-weight: 800;
font-size: 15px;
color: var(--core-purple);
margin-bottom: 15px;
letter-spacing: 1px;
}
.rule-box {
font-size: 12px;
color: #fff;
opacity: 0.9;
font-family: 'Fira Code', monospace;
background: rgba(255, 255, 255, 0.05);
padding: 8px;
border-radius: 6px;
}
.adapter-zone {
width: 100%;
display: flex;
justify-content: center;
position: relative;
}
.adapter-zone::before {
content: '';
position: absolute;
top: -20px;
left: 50%;
transform: translateX(-50%);
width: 2px;
height: 20px;
background-image: linear-gradient(var(--border-color) 50%, rgba(255, 255, 255, 0) 0%);
background-size: 2px 8px;
background-repeat: y;
}
.db-adapter {
padding: 15px 40px;
background: #020617;
border: 2px solid var(--adapter-blue);
border-radius: 12px;
color: var(--adapter-blue);
font-weight: 700;
font-size: 13px;
transition: all 0.5s ease;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 180px;
font-size: 14px;
}
.btn-switch {
background: var(--adapter-blue);
color: #000;
}
.btn-run {
background: var(--core-purple);
color: #fff;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
/* --- Terminal --- */
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
line-height: 1.6;
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
.logic-core {
width: 100%;
max-width: 300px;
}
}
const dbAdapter = document.getElementById("db-adapter");
const terminal = document.getElementById("lab-console");
let currentDB = "SQL";
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
document.getElementById("btn-switch-db").addEventListener("click", () => {
currentDB = currentDB === "SQL" ? "NoSQL (MongoDB)" : "SQL";
dbAdapter.innerText = `${currentDB} Repository (Active)`;
dbAdapter.style.borderColor = currentDB === "SQL" ? "#38bdf8" : "#fbbf24";
dbAdapter.style.color = currentDB === "SQL" ? "#38bdf8" : "#fbbf24";
log(
`ALTYAPI DEĞİŞTİ: Artık ${currentDB} kullanılıyor. İş mantığı sabit kaldı.`,
"#f59e0b",
);
});
document.getElementById("btn-run-logic").addEventListener("click", () => {
log("İşlem Başladı: Para transferi talebi alındı...");
setTimeout(() => {
log(
"BUSINESS CORE: Bakiye kontrol ediliyor... (Kural Çalışıyor)",
"#a78bfa",
);
setTimeout(() => {
log(
`ALTYAPI ÇAĞRISI: ${currentDB} üzerinden veri güncelleniyor...`,
"#38bdf8",
);
log(
"SONUÇ: İşlem başarıyla tamamlandı. İş mantığı hiç değişmedi!",
"#10b981",
);
}, 800);
}, 600);
});
Veri Erişim Katmanı Detaylı Analizi Persistence/Data Access Layer
Veri Erişim Katmanı, uygulamanın ürettiği bilgilerin kalıcı olmasını sağlayan depolama sistemleriyle ( veritabanları, dosya sistemleri, harici API'ler ) doğrudan iletişim kuran katmandır.
Ana amacı, üst katmanları veritabanı teknolojilerinin teknik karmaşıklığından tamamen izole etmektir.
Tercüme Görevi: Bu katman, İş Mantığı Katmanından gelen soyut talepleri ( "Kullanıcıyı ID ile getir" ) alır ve bunları veritabanının anlayacağı somut sorgu dillerine çevirir.
Gelen ham veriyi ise tekrar uygulama nesnelerine dönüştürerek yukarı iletir.
Kritik Sorumluluklar: CRUD ve Eşleme (Mapping)Veri Erişim Katmanı, sistemin veri bütünlüğünü ve performansını korumak için şu teknik sorumlulukları üstlenir:
Temel CRUD Operasyonları: Verinin yaratılması, okunması, güncellenmesi ve silinmesi işlemlerini en optimize şekilde yürütür.
Bağlantı Yönetimi (Connection Pooling): Veritabanı bağlantılarının verimli kullanılmasını sağlar ve ağ kaynaklarını yönetir.
ORM / ODM Kullanımı: Nesne-İlişkisel Haritalama araçlarını ( Prisma, Sequelize, Mongoose ) kullanarak, veritabanındaki tabloları veya dokümanları yazılım dünyasındaki nesne modelleriyle eşleştirir.
DIP ve Katmanlı GüvenlikMimaride bu katman "Düşük Seviyeli Modül" olarak kabul edilse de, Bağımlılıkların Tersine Çevrilmesi Prensibi gereği üst katmana asla hükmedemez.
İş Mantığı Katmanı, bu katmanın somut sınıflarına değil, bir Arayüze bağımlı kalır.
Böylece veritabanını değiştirmek, iş kurallarını etkilemeyen basit bir "fiş-priz" değişimi haline gelir.
JavaScript Bağlamı: Repository DeseniModern JavaScript ve Node.js projelerinde bu katman genellikle Repository sınıfları üzerinden hayat bulur:
Soyutlama Örneği: Bir UserRepository.findById() metodu, içinde ister karmaşık SQL Join'leri ister MongoDB agregasyonları barındırsın; üst katman sadece kendisine bir "User" objesi döneceğini bilir ve iç detaylar tamamen bu katmana gömülüdür.
Sonuç olarak Veri Erişim Katmanı; iş kurallarını teknik detayların gürültüsünden koruyan, veriyi güvenli ve düzenli bir şekilde depolayan
mimari bir arşiv yöneticisidir.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Persistence Bridge Lab</title>
<link rel="stylesheet" href="persistence-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Persistence Bridge (Data Abstraction)
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container persistence-theme">
<div class="lab-viz persistence-area">
<div class="interface-node">IUserRepository (Interface)</div>
<div class="bridge-line"></div>
<div class="tech-stack">
<div id="repo-impl" class="repo-node">SQLRepository.js</div>
<div class="arrow">→</div>
<div id="db-storage" class="db-storage-node">PostgreSQL</div>
</div>
</div>
<div class="lab-controls">
<h4>Teknik Detay İzolasyonu</h4>
<p class="lab-description">Veritabanı motorunu değiştirin; üst katmanın sadece "User" nesnesi aldığını
görün.
</p>
<div class="btn-group">
<button id="btn-toggle-tech" class="btn-lab btn-toggle">Teknolojiyi Değiştir</button>
<button id="btn-fetch-user" class="btn-lab btn-fetch">Kullanıcıyı Getir</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">> Arşiv yöneticisi hazır. Mevcut: SQL...</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--interface-gold: #fbbf24;
--repo-blue: #38bdf8;
--db-red: #f87171;
--db-green: #10b981;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--interface-gold);
background: rgba(251, 191, 36, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.persistence-area {
padding: 50px 30px;
display: flex;
flex-direction: column;
align-items: center;
gap: 0;
background: rgba(15, 23, 42, 0.4);
}
.interface-node {
padding: 15px 35px;
background: #020617;
border: 2px solid var(--interface-gold);
color: var(--interface-gold);
border-radius: 10px;
font-weight: 800;
font-size: 13px;
box-shadow: 0 0 15px rgba(251, 191, 36, 0.15);
z-index: 2;
}
.bridge-line {
width: 2px;
height: 40px;
background: repeating-linear-gradient(to bottom, var(--border-color), var(--border-color) 4px, transparent 4px, transparent 8px);
}
.tech-stack {
display: flex;
align-items: center;
gap: 20px;
}
.repo-node {
padding: 18px 25px;
background: #020617;
border: 2px solid var(--repo-blue);
color: var(--repo-blue);
border-radius: 8px;
font-family: 'Fira Code', monospace;
font-size: 12px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
transition: all 0.5s ease;
}
.arrow {
color: var(--text-dim);
font-weight: bold;
font-size: 20px;
}
.db-storage-node {
padding: 18px 30px;
background: #020617;
border: 2px solid var(--db-red);
color: var(--db-red);
border-radius: 12px 12px 25px 25px;
font-weight: bold;
font-size: 13px;
transition: all 0.5s ease;
}
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 170px;
font-size: 14px;
}
.btn-toggle {
background: var(--repo-blue);
color: #000;
}
.btn-fetch {
background: var(--interface-gold);
color: #000;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
.tech-stack {
flex-direction: column;
gap: 10px;
}
.arrow {
transform: rotate(90deg);
}
}
const repoImpl = document.getElementById("repo-impl");
const dbStorage = document.getElementById("db-storage");
const terminal = document.getElementById("lab-console");
let isSQL = true;
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
document.getElementById("btn-toggle-tech").addEventListener("click", () => {
isSQL = !isSQL;
repoImpl.innerText = isSQL ? "SQLRepository.js" : "MongoRepository.js";
dbStorage.innerText = isSQL ? "PostgreSQL" : "MongoDB";
repoImpl.style.borderColor = isSQL ? "#38bdf8" : "#a78bfa";
repoImpl.style.color = isSQL ? "#38bdf8" : "#a78bfa";
dbStorage.style.borderColor = isSQL ? "#f87171" : "#4ade80";
dbStorage.style.color = isSQL ? "#f87171" : "#4ade80";
log(
`TEKNOLOJİ DEĞİŞTİ: Altyapı artık ${isSQL ? "SQL" : "NoSQL"}.`,
"#fbbf24",
);
});
document.getElementById("btn-fetch-user").addEventListener("click", () => {
log("ÜST KATMAN: findById(101) çağrısı yapıldı...");
setTimeout(() => {
const query = isSQL
? "SELECT * FROM users WHERE id=101"
: "db.users.find({_id: 101})";
log(`REPO KATMANI: ${query} yürütülüyor...`, isSQL ? "#38bdf8" : "#a78bfa");
setTimeout(() => {
log("MAPPING: Ham veri 'User' nesnesine dönüştürüldü.", "#10b981");
log(
"SONUÇ: Üst katman teknolojiyi bilmeden 'User' objesini aldı.",
"#fff",
);
}, 800);
}, 600);
});
Altyapı Katmanı Detaylı Analizi Infrastructure Layer
Altyapı Katmanı, bir uygulamanın temel iş kurallarını değil, bu kuralların hayata geçmesi için gereken harici ve operasyonel hizmetleri yöneten katmandır.
Uygulamanın çalışma ortamıyla doğrudan ilişkili olup, temel amacı teknolojik bağımlılıkları sistemin çekirdek mantığından tamamen izole etmektir.
Hizmet Odaklı Yapı: Altyapı katmanı, İş Mantığı Katmanına hizmet sunar ancak ondan somut olarak etkilenmez.
İş mantığı sadece "bir e-posta gönderilmeli" der; ancak bu e-postanın SendGrid ile mi yoksa yerel bir SMTP sunucusuyla mı gönderileceği tamamen Altyapı katmanının teknik kararıdır.
Kritik Sorumluluklar: I/O ve Harici ServislerAltyapı katmanı, yazılımın kendi iş mantığı dışında kalan tüm operasyonel yükleri omuzlar:
Günlükleme ve İzleme (Logging & Monitoring): Sistemin çalışma anındaki durumunu kaydeden Winston veya Morgan gibi kütüphanelerin yönetimi.
Önbellekleme (Caching): Redis veya Memcached gibi araçlarla sistem performansını artıran entegrasyonlar.
Dış API Entegrasyonları: Ödeme ağ geçitleri ( Stripe, Iyzico ), SMS servisleri veya bulut tabanlı dosya sistemleri ( AWS S3 ) ile kurulan iletişimler.
DIP ve Bağımlılık Enjeksiyonu (DI)Bu katman, Bağımlılıkların Tersine Çevrilmesi Prensibi için en kritik bölgedir.
Altyapı servisleri somut sınıflar olarak burada yaratılır, ancak üst katmanlara soyut arayüzler üzerinden enjekte edilir.
Bu strateji sayesinde, loglama kütüphanesini değiştirdiğinizde iş kurallarını içeren servislerin tek bir satırını bile değiştirmenize gerek kalmaz.
JavaScript Bağlamı: Harici İstemciler ve AdaptörlerModern JavaScript ve Node.js projelerinde Altyapı Katmanı, dış dünyaya açılan "adaptörler" gibi çalışır:
Köprü Görevi: S3StorageClient veya RedisCacheManager gibi sınıflar burada yer alır.
Bu sınıflar, İş Mantığı Katmanında tanımlanan genel "Depolama" veya "Önbellek" arayüzlerini uygulayarak, uygulama çekirdeği ile dış dünya arasında güvenilir ve değiştirilebilir bir köprü oluşturur.
Sonuç olarak Altyapı Katmanı; iş mantığını teknik detayların gürültüsünden, kütüphane bağımlılıklarından ve dış servis değişimlerinden koruyan mimari bir koruma kalkanıdır.
Mekanizma Detayları Bağımlılık Akışı
Katmanlı Mimari, sistemin kararlılığını korumak için katı bir tek yönlü bağımlılık akışını zorunlu kılar.
Bu kurala göre; bir katman yalnızca doğrudan altındaki katmana hizmet çağrısı yapabilir ve onun sunduğu yetenekleri kullanabilir.
Aşağıya Doğru Akış: Bağımlılık yönü her zaman yukarıdan aşağıya ( Sunum → İş Mantığı → Veri/Altyapı ) doğrudur.
Bu hiyerarşide hiçbir alt katman, kendisini çağıran üst katmanın varlığından, teknolojisinden veya o anki durumundan haberdar olmamalıdır.
Gevşek Bağlılık (Loose Coupling) MekanizmasıBu katı bağımlılık hiyerarşisi, sistemi "gevşek bağlı" tutmanın ana mekanizmasıdır.
Eğer alt katmanlar üst katmanları tanımaya başlarsa ( circular dependency / dairesel bağımlılık ), sistem bir "spagetti koda" dönüşür ve bir parçayı değiştirmek tüm yapının çökmesine neden olur.
Değişim İzolasyonu: Tek yönlü akış sayesinde, alt katmanlarda yapılan bir iyileştirme veya teknoloji değişikliği yukarıya doğru bir yıkım yaratmaz.
Sadece o katmanın sunduğu arayüzün sabit kalması yeterlidir.
DIP ile Güçlendirilmiş AkışBağımlılık akışı, Bağımlılıkların Tersine Çevrilmesi Prensibi ile birleştiğinde gerçek gücüne kavuşur.
Yüksek seviyeli bir modül olan İş Mantığı Katmanı, somut ve düşük seviyeli olan Veri Erişim Katmanına doğrudan göbekten bağlı olmak yerine, aradaki bir "sözleşmeye" bağımlı hale gelir.
Yazılımın Özgürlüğü: Bu yaklaşım, iş kurallarını içeren çekirdek kodun, altyapı detaylarına esir düşmesini engeller.
Bağımlılık yönü teknik olarak aşağıya baksa da, kontrol her zaman iş kurallarının elindedir.
JavaScript ve Node.js Uygulama PratiğiNode.js projelerinde bu akış, require veya import yönleriyle somutlaşır.
Bir Service dosyası bir Repository dosyasını içe aktarabilir, ancak bir Repository asla bir Service'i içe aktarmamalıdır.
Bu disiplin, uygulamanın test edilebilirliğini ve modülerliğini en üst seviyeye taşır.
Sonuç olarak Bağımlılık Akışı; katmanlar arasındaki sınırları koruyan, karmaşıklığı dikeyde izole eden ve yazılım mimarisini
kaostan düzene taşıyan bir trafik yönetimidir.
Bağımlılık Akışının Vurgulanması Genel Açıklama
Katmanlı Mimari içerisinde bağımlılıklar rastgele değil, belirli bir disiplin çerçevesinde aşağıya doğru akar.
Bu akış, bir üst katmanın görevi tanımlayıp alt katmana delege etmesi prensibiyle çalışır.
Her katman, bir altındakine güvenir ancak onun teknik detaylarına karışmaz.
Sunum ➔ İş Mantığı: "Ne İstendi?"Sunum Katmanı, kullanıcıdan gelen ham isteği anlamlı bir komuta dönüştürür ve İş Mantığı Katmanındaki ilgili servisi çağırır.
İzolasyon Noktası: Sunum katmanı, iş kuralının içeriğini sorgulamaz.
Örneğin: "Kullanıcıyı kaydet" der ve gerisini servise bırakır. Kayıt sırasında hangi kontrollerin yapıldığı Sunum katmanının sorumluluğu dışındadır.
İş Mantığı ➔ Veri Erişimi: "Veri Nereden Gelecek?"İş Mantığı Katmanı, kararlarını vermek için veriye ihtiyaç duyduğunda asla doğrudan bir veritabanı sürücüsünü çağırmaz.
Bunun yerine, bir Repository Interface üzerinden talepte bulunur.
DIP'nin Uygulanması: Bu nokta, Bağımlılıkların Tersine Çevrilmesi Prensibi'nin (DIP) kalbidir.
İş mantığı, verinin MySQL'den mi yoksa bir bulut servisininden mi geldiğini bilmek zorunda kalmadan sadece "veriyi bana getir" sözleşmesine odaklanır.
Veri Erişimi: Hiyerarşinin TemeliVeri Erişim Katmanı, hiyerarşinin en altında yer alır ve kendi üzerinde başka bir uygulama katmanına bağımlılığı yoktur.
Tek görevi, İş Mantığı katmanından gelen soyut talepleri, harici veritabanı sistemlerinin anlayacağı dile çevirmektir.
Katmanlı Mimari Örneği (Layered Architecture Example)Bu disiplinli akış sayesinde; kullanıcı arayüzünü tamamen değiştirseniz bile iş kurallarınız korunur veya veritabanınızı değiştirseniz bile uygulamanın sunum ve iş katmanları bu değişimden etkilenmez.
Katmanlı mimari, sistemin her bir parçasını bağımsızca geliştirilebilir ve test edilebilir kılan profesyonel bir koruma kalkanıdır.
Mikroservis Mimarisi (Microservices Architecture) Genel Açıklama
Mikroservis Mimarisi, bir uygulamayı tek bir monolitik blok olarak inşa etmek yerine, her biri kendi iş sürecinden sorumlu olan, bağımsız olarak geliştirilebilen ve ölçeklenebilen küçük hizmetler koleksiyonu olarak yapılandırma yaklaşımıdır.
Modern Standart: Bulut bilişim ve DevOps süreçleriyle mükemmel bir uyum sergileyen bu desen, özellikle hızlı çeviklik gerektiren büyük ölçekli Node.js projeleri için modern mimarinin altın standardı kabul edilir.
Derinlemesine Analiz: Neden Monolitten Ayrılıyoruz?Katmanlı Mimari gibi geleneksel monolitik yapılar büyüdükçe hantallaşır.
Mikroservisler, bu hantallığa üç ana eksende çözüm sunar:
Bağımsız Ölçekleme (Selective Scalability): Monolitte sistemin bir parçası yoğun trafik alsa bile tüm yapıyı kopyalamanız gerekir.
Mikroservislerde ise sadece yük altındaki servisi ( sadece Ödeme Servisi gibi ) yatayda ölçekleyerek kaynak verimliliği sağlarsınız.
Teknoloji Özgürlüğü (Polyglot Persistence): Tüm uygulamayı tek bir dile hapsetmek yerine, ihtiyaca göre bir servisi Node.js, bir diğerini yüksek performans için Go veya veri işleme için Python ile yazabilirsiniz.
Hata İzolasyonu (Resilience): Monolitte küçük bir bellek sızıntısı tüm gemiyi batırabilirken; mikroservislerde arızalanan bir hizmet izole kalır ve sistemin geri kalanı kesintisiz hizmet vermeye devam eder.
Yapısal ve Davranışsal KarakteristiklerMikroservisleri başarılı kılan temel yapı taşları şunlardır:
Hizmet Boyutu ve SRP: Her servis tek bir "İş Alanına" ( Bounded Context ) odaklanır. Bu, Tek Sorumluluk Prensibi'nin (SRP) mimari düzeydeki karşılığıdır.
Bağımsız Dağıtım (CI/CD): Her servisin kendi yaşam döngüsü vardır. Bir servisteki güncelleme için tüm sistemi kapatıp açmanıza gerek kalmaz; her parça kendi başına canlıya alınabilir.
Veri Bağımsızlığı: Mikroservislerin "olmazsa olmaz" kuralı, her servisin kendi özel veritabanına sahip olmasıdır.
Bu, servisler arasındaki sıkı bağı keser ve veri şeması değişikliklerinin diğer servisleri bozmasını engeller.
İletişim Katmanı: Senkron ve Asenkron AğlarHizmetler arası iletişim, mimarinin sinir sistemidir. Anlık yanıtlar için HTTP/REST veya gRPC gibi senkron protokoller tercih edilirken; sistemin esnekliğini ve performansını artırmak için RabbitMQ veya Kafka üzerinden asenkron mesajlaşma kullanılır.
Sonuç olarak Mikroservis Mimarisi; yazılımı tek bir kırılgan dev olmaktan çıkarıp, her bir hücresi bağımsızca yaşayan, gelişen ve büyüyen
akıllı bir organizmaya dönüştürür.
Mekanizma Detayları Bağımsızlık ve İletişim
Mikroservis Mekanizması, dikey katmanlar yerine yatay bölümleme prensibiyle çalışır.
Katmanlı mimarideki bellek içi fonksiyon çağrılarının yerini, burada ağ üzerinden gerçekleşen iletişim protokolleri alır.
Mini-Katmanlar: İlginç bir mimari detay olarak; her bir mikroservis kendi içinde küçük bir "Katmanlı Mimari" ( Controller, Service, Repository ) barındırabilir.
Ancak bu servisler birbirine kapalı kutulardır; aralarındaki tek bağ ağ üzerindeki protokollerdir, bu da onlara tam bir özerklik tanır.
Bağımsızlığın Dört BoyutuMikroservislerin başarısı, sistemin her hücresinin şu dört boyutta özgür kalmasına bağlıdır:
Veri Bağımsızlığı: "Her servise özel veritabanı" kuralı, veri şeması değişikliklerinin diğer servisleri bozmasını engeller.
Bu, SRP prensibinin veri katmanındaki nihai zaferidir.
Dağıtım Bağımsızlığı: Bir ekip, "Sepet Servisi"'ni güncellerken "Ödeme Servisi"'nin çalışmasını durdurmak zorunda kalmaz.
Her servis kendi CI/CD hattı üzerinden özgürce canlıya çıkar.
Teknoloji Bağımsızlığı (Polyglot): Performans gereken bir servis Go ile yazılırken, hızlı geliştirme gereken bir diğeri Node.js ile inşa edilebilir.
Hata İzolasyonu: Bir servisteki çökme, sistemin geneline yayılmaz.
Arızalı parça izole edilir ve sistemin geri kalanı ( graceful degradation ) ile çalışmaya devam eder.
İletişim Modları: Sistemin Sinir SistemiMikroservisler, veri alışverişi için senaryoya göre iki ana iletişim modunu kullanır:
Senkron İletişim (Anlık Yanıt): Genellikle HTTP/REST veya gRPC ile sağlanır.
İstemci bir istek gönderir ve yanıt gelene kadar bekler.
API Gateway üzerinden yönlendirilen trafik genellikle bu moddadır.
Asenkron İletişim (Olay Güdümlü): İstemci yanıt beklemez.
Bir servis bir "olay" ( event ) fırlatır ve ilgili diğer servisler bu mesajı kendi zamanlarında işler.
RabbitMQ veya Kafka gibi mesaj kuyrukları bu modelin merkezindedir.
Mimari Esneklik ve ÖlçeklenebilirlikAsenkron iletişim, sistemin daha hızlı tepki vermesini sağlar çünkü servisler birbirini beklemek zorunda kalmaz.
Bu model, sistemin Ölçeklenebilirlik AQC'sini maksimize ederken, servisler arasındaki bağı en düşük seviyeye indirir.
Sonuç olarak Mikroservis Mekanizması; her bir parçanın kendi hızında büyüdüğü, kendi diliyle konuştuğu ve kendi verisini yönettiği
demokratik ve dayanıklı bir sistem düzenidir.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Selective Scalability Simulator</title>
<link rel="stylesheet" href="scaler-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Selective Scalability Simulator
<div class="lang-icons">
<i class="fab fa-html5"></i>
<i class="fab fa-css3-alt"></i>
<i class="fab fa-js"></i>
</div>
</div>
</div>
</div>
<div class="lab-container scaler-theme">
<div class="lab-viz scaler-area">
<div class="arch-box">
<span class="arch-title">Monolithic (Hantal)</span>
<div id="monolith-cluster" class="instance-group">
<div class="instance monolit">All-in-One App</div>
</div>
</div>
<div class="divider">VS</div>
<div class="arch-box">
<span class="arch-title">Microservices (Esnek)</span>
<div class="micro-services">
<div id="auth-service" class="instance-group service-mini">
<span class="label">Auth</span>
<div class="instance micro">S</div>
</div>
<div id="payment-service" class="instance-group service-mini">
<span class="label">Payment</span>
<div class="instance micro">S</div>
</div>
</div>
</div>
</div>
<div class="lab-controls">
<h4>Bağımsız Ölçekleme Kararı</h4>
<p class="lab-description">Sadece "Ödeme Servisi" yük aldığında ne yaparsınız? İki mimariyi karşılaştırın.
</p>
<div class="btn-group">
<button id="btn-scale-monolith" class="btn-lab btn-monolith">Monoliti Çoğalt</button>
<button id="btn-scale-payment" class="btn-lab btn-micro">Sadece Ödemeyi Ölçekle</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">> Sistem stabil. Kaynak kullanımı: %20...</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--monolith-gray: #64748b;
--micro-green: #10b981;
--payment-red: #f43f5e;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
}
body {
background-color: var(--bg-deep);
font-family: 'Inter', system-ui, sans-serif;
margin: 0;
padding: 40px 20px;
color: #f8fafc;
display: flex;
flex-direction: column;
align-items: center;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 12px 12px 0 0;
padding: 15px 20px;
box-sizing: border-box;
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--micro-green);
background: rgba(16, 185, 129, 0.1);
padding: 6px 12px;
border-radius: 6px;
}
.code-type-description {
font-size: 14px;
font-weight: 600;
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-radius: 0 0 12px 12px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
overflow: hidden;
box-sizing: border-box;
}
.scaler-area {
padding: 60px 30px;
display: flex;
justify-content: center;
align-items: flex-start;
gap: 30px;
background: rgba(15, 23, 42, 0.4);
}
.arch-box {
flex: 1;
text-align: center;
}
.arch-title {
font-size: 11px;
font-weight: 800;
text-transform: uppercase;
color: var(--text-dim);
margin-bottom: 25px;
display: block;
letter-spacing: 1.5px;
}
.instance-group {
display: flex;
flex-wrap: wrap;
gap: 12px;
justify-content: center;
}
.instance {
padding: 12px 16px;
border-radius: 8px;
font-size: 11px;
font-weight: bold;
border: 2px solid transparent;
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
animation: scaleIn 0.3s ease;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
}
.monolit {
background: var(--monolith-gray);
color: #fff;
border-color: #94a3b8;
width: 120px;
box-shadow: 0 5px 15px rgba(100, 116, 139, 0.3);
}
.micro {
background: var(--micro-green);
color: #fff;
width: 35px;
box-shadow: 0 5px 15px rgba(16, 185, 129, 0.3);
}
#payment-service .micro {
background: var(--payment-red);
box-shadow: 0 5px 15px rgba(244, 63, 94, 0.3);
}
.service-mini {
border: 1px dashed var(--border-color);
padding: 15px;
border-radius: 12px;
background: rgba(15, 23, 42, 0.2);
}
.label {
font-size: 10px;
font-weight: 700;
display: block;
margin-bottom: 10px;
color: var(--text-dim);
}
.divider {
align-self: center;
font-weight: 900;
color: var(--border-color);
font-size: 20px;
z-index: 2;
}
@keyframes scaleIn {
from {
transform: scale(0);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
.lab-controls {
padding: 30px;
text-align: center;
border-top: 1px solid var(--border-color);
}
.lab-description {
font-size: 13px;
color: var(--text-dim);
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 15px;
}
.btn-lab {
padding: 12px 28px;
border: none;
border-radius: 8px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
min-width: 180px;
font-size: 14px;
}
.btn-monolith {
background: #475569;
color: white;
}
.btn-micro {
background: var(--payment-red);
color: white;
}
.btn-lab:hover {
transform: translateY(-2px);
filter: brightness(1.2);
}
.lab-terminal {
background: #000;
padding: 20px;
height: 150px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 12px;
border-top: 1px solid var(--border-color);
line-height: 1.6;
}
.lab-terminal::-webkit-scrollbar {
width: 6px;
}
.lab-terminal::-webkit-scrollbar-track {
background: #020617;
}
.lab-terminal::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 10px;
}
.lab-terminal::-webkit-scrollbar-thumb:hover {
background: var(--repo-blue);
}
.lab-terminal {
scrollbar-width: thin;
scrollbar-color: var(--border-color) #020617;
}
@media (max-width: 600px) {
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
.scaler-area {
flex-direction: column;
align-items: center;
}
.instance monolit {
width: 100%;
max-width: 200px;
}
}
const monCluster = document.getElementById("monolith-cluster");
const payCluster = document.getElementById("payment-service");
const terminal = document.getElementById("lab-console");
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
document.getElementById("btn-scale-monolith").addEventListener("click", () => {
const clone = document.createElement("div");
clone.className = "instance monolit";
clone.innerText = "All-in-One App";
monCluster.appendChild(clone);
log(
"MONOLİT ÖLÇEKLENDİ: Tüm uygulama kopyalandı. Kaynak israfı yüksek!",
"#f43f5e",
);
});
document.getElementById("btn-scale-payment").addEventListener("click", () => {
const clone = document.createElement("div");
clone.className = "instance micro";
clone.innerText = "S";
payCluster.appendChild(clone);
log(
"MİKROSERVİS ÖLÇEKLENDİ: Sadece 'Payment Service' çoğaltıldı. Verimlilik sağlandı.",
"#10b981",
);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Resilience Isolator</title>
<link rel="stylesheet" href="resilience-isolator-style.css?v=1.0.150">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Resilience Isolatör (Fault Tolerance)
<span class="lang-icon"><i class="fab fa-html5"></i></span>
<span class="lang-icon"><i class="fab fa-css3-alt"></i></span>
<span class="lang-icon"><i class="fab fa-js"></i></span>
</div>
</div>
</div>
<div class="lab-container resilience-theme">
<div class="lab-viz resilience-area">
<div class="service-net">
<div id="srv-auth" class="srv-box active">
<i class="fas fa-lock"></i>
<span>Auth Service</span>
</div>
<div id="srv-order" class="srv-box active">
<i class="fas fa-shopping-cart"></i>
<span>Order Service</span>
</div>
<div id="srv-inventory" class="srv-box active">
<i class="fas fa-boxes"></i>
<span>Stock Service</span>
</div>
</div>
<div class="status-radar">
<div id="system-health" class="health-indicator healthy">Sistem Durumu: Kararlı</div>
</div>
</div>
<div class="lab-controls">
<h4>Hata İzolasyon Simülasyonu</h4>
<p class="lab-description">Bir servisi bozarak sistemin geri kalanının nasıl ayakta kaldığını izleyin.</p>
<div class="btn-group">
<button id="btn-break-stock" class="btn-lab btn-break">Stok Servisini Boz</button>
<button id="btn-check-system" class="btn-lab btn-check">Sistemi Sorgula</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">> Küme izleniyor. Tüm servisler çevrimiçi...</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--srv-active: #10b981;
--srv-broken: #f43f5e;
--srv-warning: #fbbf24;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
--glass-effect: rgba(30, 41, 59, 0.7);
}
body {
background-color: var(--bg-deep);
background-image:
linear-gradient(rgba(16, 185, 129, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(16, 185, 129, 0.03) 1px, transparent 1px);
background-size: 30px 30px;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 20px;
margin: 0;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 16px 16px 0 0;
padding: 18px 24px;
box-sizing: border-box;
backdrop-filter: blur(10px);
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--srv-active);
background: rgba(16, 185, 129, 0.1);
padding: 6px 12px;
border-radius: 6px;
font-size: 16px;
}
.code-type-description {
display: flex;
align-items: center;
gap: 12px;
font-size: 14px;
font-weight: 600;
color: #f1f5f9;
}
.lang-icon {
font-size: 16px;
color: var(--text-dim);
transition: color 0.3s ease;
}
.lang-icon:hover {
color: var(--srv-active);
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--glass-effect);
border: 1px solid var(--border-color);
border-radius: 0 0 16px 16px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.7);
overflow: hidden;
backdrop-filter: blur(12px);
box-sizing: border-box;
}
/* --- Görselleştirme Alanı --- */
.resilience-area {
padding: 80px 40px;
background: radial-gradient(circle at center, rgba(16, 185, 129, 0.08) 0%, transparent 75%);
display: flex;
flex-direction: column;
align-items: center;
gap: 50px;
position: relative;
}
.service-net {
display: flex;
gap: 40px;
justify-content: center;
z-index: 2;
position: relative;
}
.service-net::after {
content: '';
position: absolute;
top: 50%;
left: 10%;
right: 10%;
height: 2px;
background: linear-gradient(90deg, transparent, var(--border-color), transparent);
z-index: -1;
}
.srv-box {
width: 140px;
padding: 30px 20px;
background: #020617;
border: 2px solid var(--srv-active);
border-radius: 20px;
text-align: center;
transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
color: var(--srv-active);
box-shadow: 0 10px 30px -10px rgba(16, 185, 129, 0.4);
}
.srv-box i {
font-size: 32px;
filter: drop-shadow(0 0 8px currentColor);
}
.srv-box span {
font-size: 11px;
font-weight: 800;
letter-spacing: 1px;
}
.srv-box.broken {
border-color: var(--srv-broken);
color: var(--srv-broken);
transform: scale(0.92) translateY(15px);
box-shadow: 0 0 40px rgba(244, 63, 92, 0.4);
background: #0f172a;
}
.status-radar {
display: flex;
justify-content: center;
}
.health-indicator {
padding: 12px 30px;
border-radius: 40px;
font-size: 12px;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 1.5px;
transition: all 0.4s ease;
border: 2px solid transparent;
}
.healthy {
background: rgba(16, 185, 129, 0.1);
color: var(--srv-active);
border-color: var(--srv-active);
box-shadow: 0 0 20px rgba(16, 185, 129, 0.2);
}
.degraded {
background: rgba(251, 191, 36, 0.1);
color: var(--srv-warning);
border-color: var(--srv-warning);
box-shadow: 0 0 20px rgba(251, 191, 36, 0.2);
}
.lab-terminal {
background: #000;
padding: 24px;
height: 180px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 13px;
border-top: 1px solid var(--border-color);
line-height: 1.7;
color: #e2e8f0;
}
.lab-terminal::-webkit-scrollbar {
width: 8px;
}
.lab-terminal::-webkit-scrollbar-track {
background: #000;
}
.lab-terminal::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 4px;
border: 2px solid #000;
}
.lab-terminal::-webkit-scrollbar-thumb:hover {
background: var(--srv-active);
}
.lab-controls {
padding: 40px 30px;
text-align: center;
border-top: 1px solid var(--border-color);
background: rgba(15, 23, 42, 0.3);
}
.lab-controls h4 {
color: #f1f5f9;
font-size: 18px;
margin-bottom: 10px;
font-weight: 700;
}
.lab-description {
color: var(--text-dim);
font-size: 14px;
line-height: 1.6;
margin-bottom: 25px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 20px;
}
.btn-lab {
padding: 14px 32px;
border: none;
border-radius: 12px;
font-weight: 800;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
min-width: 200px;
text-transform: uppercase;
font-size: 13px;
letter-spacing: 0.5px;
}
.btn-break {
background: var(--srv-broken);
color: white;
box-shadow: 0 4px 14px rgba(244, 63, 92, 0.3);
}
.btn-check {
background: var(--srv-active);
color: white;
box-shadow: 0 4px 14px rgba(16, 185, 129, 0.3);
}
.btn-lab:hover {
transform: translateY(-3px) scale(1.02);
filter: brightness(1.15);
}
const stockSrv = document.getElementById("srv-inventory");
const healthStatus = document.getElementById("system-health");
const terminal = document.getElementById("lab-console");
let isStockDown = false;
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
document.getElementById("btn-break-stock").addEventListener("click", () => {
isStockDown = true;
stockSrv.className = "srv-box broken";
healthStatus.className = "health-indicator degraded";
healthStatus.innerText = "Sistem Durumu: Kısmi Hata (Degraded)";
log("KRİTİK HATA: Stok Servisi yanıt vermeyi kesti!", "#ef4444");
log("İzolasyon Aktif: Hata diğer servislere yayılmıyor.", "#f59e0b");
});
document.getElementById("btn-check-system").addEventListener("click", () => {
log("Sistem denetleniyor...");
setTimeout(() => {
log("Auth Service: [OK]", "#10b981");
log("Order Service: [OK]", "#10b981");
if (isStockDown) {
log("Stock Service: [FAILED] - Geçici olarak devre dışı.", "#ef4444");
log(
"ANALİZ: Monolitte sistem çökerdi, Mikroserviste sadece stok özelliği kapalı.",
"#fff",
);
} else {
log("Stock Service: [OK]", "#10b981");
}
}, 500);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Polyglot Deck Lab</title>
<link rel="stylesheet" href="polyglot-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Polyglot Deck (Multi-Lang Ecosystem)
<span class="lang-icon"><i class="fab fa-html5"></i></span>
<span class="lang-icon"><i class="fab fa-css3-alt"></i></span>
<span class="lang-icon"><i class="fab fa-js"></i></span>
</div>
</div>
</div>
<div class="lab-container polyglot-theme">
<div class="lab-viz polyglot-area">
<div class="deck-grid">
<div id="srv-node" class="lang-card nodejs">
<div class="lang-badge">Node.js</div>
<i class="fab fa-node-js"></i>
<span>API Gateway</span>
</div>
<div id="srv-go" class="lang-card golang">
<div class="lang-badge">Go</div>
<i class="fas fa-bolt"></i>
<span>High-Perf Engine</span>
</div>
<div id="srv-py" class="lang-card python">
<div class="lang-badge">Python</div>
<i class="fab fa-python"></i>
<span>AI Data Processor</span>
</div>
</div>
<div class="network-mesh">
<div class="mesh-label">Common Network (gRPC / REST)</div>
</div>
</div>
<div class="lab-controls">
<h4>Teknoloji Özgürlüğü Simülasyonu</h4>
<p class="lab-description">Farklı dillerle yazılmış servislerin, ortak bir dilde (JSON/Protobuf) nasıl
anlaştığını izleyin.</p>
<div class="btn-group">
<button id="btn-ping-all" class="btn-lab btn-ping">Ekosistemi Sorgula</button>
<button id="btn-process-data" class="btn-lab btn-process">Karmaşık İşlem Başlat</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">> Çok dilli ekosistem hazır. Tüm çalışma ortamları (Runtimes) aktif...</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--node-green: #68a063;
--go-cyan: #00add8;
--py-blue: #3776ab;
--text-main: #f1f5f9;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
--glass-effect: rgba(30, 41, 59, 0.7);
}
body {
background-color: var(--bg-deep);
background-image: radial-gradient(circle at center, rgba(56, 189, 248, 0.03) 0%, transparent 70%);
font-family: 'Inter', system-ui, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 20px;
margin: 0;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 16px 16px 0 0;
padding: 18px 24px;
box-sizing: border-box;
backdrop-filter: blur(10px);
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--go-cyan);
background: rgba(0, 173, 216, 0.1);
padding: 6px 12px;
border-radius: 6px;
font-size: 16px;
}
.code-type-description {
display: flex;
align-items: center;
gap: 12px;
font-size: 14px;
font-weight: 600;
color: var(--text-main);
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--glass-effect);
border: 1px solid var(--border-color);
border-radius: 0 0 16px 16px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.7);
backdrop-filter: blur(12px);
overflow: hidden;
box-sizing: border-box;
}
.polyglot-area {
padding: 80px 40px;
background: rgba(15, 23, 42, 0.4);
}
.deck-grid {
display: flex;
justify-content: center;
gap: 30px;
margin-bottom: 50px;
}
.lang-card {
width: 160px;
padding: 35px 20px;
background: #020617;
border: 2px solid var(--border-color);
border-radius: 20px;
text-align: center;
position: relative;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
color: var(--text-main);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
}
.lang-badge {
position: absolute;
top: -12px;
left: 50%;
transform: translateX(-50%);
padding: 4px 14px;
border-radius: 20px;
font-size: 10px;
font-weight: 900;
color: #000;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.nodejs .lang-badge {
background: var(--node-green);
box-shadow: 0 0 15px rgba(104, 160, 99, 0.4);
}
.golang .lang-badge {
background: var(--go-cyan);
box-shadow: 0 0 15px rgba(0, 173, 216, 0.4);
}
.python .lang-badge {
background: var(--py-blue);
box-shadow: 0 0 15px rgba(55, 118, 171, 0.4);
}
.lang-card i {
font-size: 42px;
margin-bottom: 18px;
display: block;
filter: drop-shadow(0 0 8px currentColor);
}
.nodejs i {
color: var(--node-green);
}
.golang i {
color: var(--go-cyan);
}
.python i {
color: var(--py-blue);
}
.lang-card span {
font-size: 11px;
font-weight: 800;
opacity: 0.9;
text-transform: uppercase;
}
/* Aktif Servis Animasyonu */
.lang-card.active {
transform: translateY(-12px);
border-color: currentColor;
box-shadow: 0 15px 35px -10px rgba(255, 255, 255, 0.2);
}
.network-mesh {
width: 100%;
height: 50px;
border: 2px dashed var(--border-color);
border-radius: 25px;
display: flex;
justify-content: center;
align-items: center;
color: var(--text-dim);
font-size: 11px;
font-weight: 700;
letter-spacing: 2.5px;
text-transform: uppercase;
background: rgba(2, 6, 23, 0.4);
}
.lab-controls {
padding: 40px 30px;
text-align: center;
border-top: 1px solid var(--border-color);
background: rgba(15, 23, 42, 0.3);
}
.lab-controls h4 {
color: var(--text-main);
font-size: 18px;
margin-bottom: 10px;
font-weight: 700;
}
.lab-description {
color: var(--text-dim);
font-size: 14px;
line-height: 1.6;
margin-bottom: 30px;
}
.btn-group {
display: flex;
justify-content: center;
gap: 20px;
}
.btn-lab {
padding: 14px 32px;
border: none;
border-radius: 12px;
font-weight: 800;
cursor: pointer;
transition: all 0.3s ease;
min-width: 200px;
text-transform: uppercase;
font-size: 13px;
letter-spacing: 0.5px;
}
.btn-ping {
background: var(--text-main);
color: #000;
}
.btn-process {
background: var(--go-cyan);
color: #000;
box-shadow: 0 4px 14px rgba(0, 173, 216, 0.3);
}
.btn-lab:hover {
transform: translateY(-3px) scale(1.02);
filter: brightness(1.1);
}
.lab-terminal {
background: #000;
padding: 24px;
height: 180px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 13px;
border-top: 1px solid var(--border-color);
line-height: 1.7;
color: #e2e8f0;
}
.lab-terminal::-webkit-scrollbar {
width: 8px;
}
.lab-terminal::-webkit-scrollbar-track {
background: #000;
}
.lab-terminal::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 4px;
border: 2px solid #000;
}
.lab-terminal::-webkit-scrollbar-thumb:hover {
background: var(--go-cyan);
}
const cards = document.querySelectorAll(".lang-card");
const terminal = document.getElementById("lab-console");
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
document.getElementById("btn-ping-all").addEventListener("click", () => {
log("Ağ Taraması Başlatıldı: Tüm servisler sorgulanıyor...");
cards.forEach((card, index) => {
setTimeout(() => {
card.classList.add("active");
log(
`${card.querySelector(".lang-badge").innerText} Servisi: [ONLINE] - Uptime: 99.9%`,
"#10b981",
);
setTimeout(() => card.classList.remove("active"), 1000);
}, index * 400);
});
});
document.getElementById("btn-process-data").addEventListener("click", () => {
log("İşlem Başladı: Karmaşık veri analizi talebi alındı.");
setTimeout(() => {
log("NODE.JS: İstek karşılandı, Auth kontrolü yapıldı.", "#68a063");
document.getElementById("srv-node").classList.add("active");
setTimeout(() => {
log("PYTHON: Büyük veri seti AI modelleriyle işleniyor...", "#3776ab");
document.getElementById("srv-py").classList.add("active");
setTimeout(() => {
log(
"GO: İşlenmiş veri yüksek hızla veritabanına yazılıyor.",
"#00add8",
);
document.getElementById("srv-go").classList.add("active");
setTimeout(() => {
cards.forEach((c) => c.classList.remove("active"));
log(
"BAŞARI: 3 farklı dil, tek bir iş akışında kusursuz çalıştı!",
"#fff",
);
}, 800);
}, 1000);
}, 1000);
}, 600);
});
Olay Güdümlü Mimari (Event-Driven Architecture - EDA) Genel Açıklama
Olay Güdümlü Mimari (EDA), bir sistemdeki bileşenlerin birbirleriyle doğrudan konuşmak yerine, sistemde meydana gelen durum değişikliklerini kullanarak haberleştiği merkezi olmayan bir yaklaşımdır.
Asenkron Felsefe: Katmanlı mimarinin "şimdi yap ve bana sonucu söyle" diyen senkron yapısının aksine EDA,
"şu olay gerçekleşti, ilgilenen baksın" diyen tamamen asenkron bir iletişime dayanır.
Yayıncı ( Publisher ), olayı duyurduktan sonra işine devam eder; kimin ne tepki vereceğiyle ilgilenmez.
Derinlemesine Analiz: Maksimum Gevşek BağlılıkEDA, sistemin parçaları arasındaki bağı kopararak ulaşılabilecek en yüksek esnekliği sağlar:
Zaman ve Mekan Ayrımı (Decoupling): Olayı yayımlayan bileşen, tüketicinin o an çalışıp çalışmadığını veya hangi sunucuda olduğunu bilmez.
İletişim bir Olay Veriyolu veya mesaj kuyruğu üzerinden yürütüldüğü için servisler birbirinden tamamen bağımsızdır.
Genişletilmeye Açıklık (OCP): Mevcut sistemi bozmadan yeni özellikler eklemek çok kolaydır.
Örneğin: "Kullanıcı kaydolduğunda hoş geldin hediyesi ver" özelliğini eklemek için kayıt kodunu değiştirmezsiniz; sadece "KullanıcıKaydoldu" olayını dinleyen yeni bir bağımsız servis eklersiniz.
Hata Dayanıklılığı ve İşlem GarantisiDayanıklılık (Resilience): Senkron bir yapıda bir servis çöktüğünde tüm akış durur.
EDA'da ise bir tüketici geçici olarak çevrimdışı olsa bile olaylar kuyrukta ( RabbitMQ, Kafka ) güvenle bekler.
Servis ayağa kalktığı anda kaldığı yerden devam eder.
Temel Bileşenler ve JavaScript EkosistemiOlay (Event): "Sipariş Ödendi" gibi geçmiş zamanlı bir gerçeği temsil eden veri paketidir.
Aracı (Broker): Olayları yayıncıdan alıp abonelere ileten merkezi sinir sistemidir.
Node.js projelerinde genellikle Redis Pub/Sub, RabbitMQ veya Apache Kafka bu görevi üstlenir.
Sonuç olarak Olay Güdümlü Mimari; yazılımı katı ve birbirine bağımlı bir zincir olmaktan çıkarıp, her bir parçasının özgürce hareket ettiği ama ortak olaylarla uyum sağladığı çevik bir ağa dönüştürür.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Event Flow Lab</title>
<link rel="stylesheet" href="event-flow-style.css?v=1.0.150">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Event Flow Lab (Sync vs Async)
<span class="lang-icon"><i class="fab fa-html5"></i></span>
<span class="lang-icon"><i class="fab fa-css3-alt"></i></span>
<span class="lang-icon"><i class="fab fa-js"></i></span>
</div>
</div>
</div>
<div class="lab-container event-theme">
<div class="lab-viz event-area">
<div class="actor publisher">
<i class="fas fa-broadcast-tower"></i>
<span>Order Service</span>
</div>
<div class="event-line">
<div id="event-pulse" class="pulse">Event: Created</div>
</div>
<div class="actor consumer">
<i class="fas fa-envelope-open-text"></i>
<span>Email Service</span>
</div>
</div>
<div class="lab-controls">
<h4>Asenkron İletişim Felsefesi</h4>
<p class="lab-description">"Hemen yap" yerine "Bu olay oldu" demenin sistem performansına etkisini izleyin.
</p>
<div class="btn-group">
<button id="btn-sync" class="btn-lab btn-sync">Senkron (Bekletmeli)</button>
<button id="btn-async" class="btn-lab btn-async">Asenkron (Fırlat & Unut)</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">> Olay veriyolu (Event Bus) dinleniyor...</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--sync-blue: #38bdf8;
--async-purple: #a78bfa;
--success-green: #10b981;
--text-main: #f1f5f9;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
--glass-effect: rgba(30, 41, 59, 0.7);
}
body {
background-color: var(--bg-deep);
background-image:
radial-gradient(circle at center, rgba(167, 139, 250, 0.05) 0%, transparent 70%),
linear-gradient(rgba(167, 139, 250, 0.02) 1px, transparent 1px),
linear-gradient(90deg, rgba(167, 139, 250, 0.02) 1px, transparent 1px);
background-size: 100% 100%, 30px 30px, 30px 30px;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 20px;
margin: 0;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 16px 16px 0 0;
padding: 18px 24px;
box-sizing: border-box;
backdrop-filter: blur(10px);
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--async-purple);
background: rgba(167, 139, 250, 0.1);
padding: 6px 12px;
border-radius: 6px;
font-size: 16px;
}
.code-type-description {
display: flex;
align-items: center;
gap: 12px;
font-size: 14px;
font-weight: 600;
color: var(--text-main);
}
.lang-icon {
font-size: 16px;
color: var(--text-dim);
transition: color 0.3s ease;
}
.lang-icon:hover {
color: var(--async-purple);
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--glass-effect);
border: 1px solid var(--border-color);
border-radius: 0 0 16px 16px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.7);
overflow: hidden;
backdrop-filter: blur(12px);
box-sizing: border-box;
}
.event-area {
padding: 80px 40px;
display: flex;
justify-content: space-between;
align-items: center;
background: rgba(15, 23, 42, 0.4);
position: relative;
}
.actor {
width: 130px;
padding: 25px 20px;
background: #020617;
border: 2px solid var(--border-color);
border-radius: 16px;
text-align: center;
color: var(--text-main);
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
z-index: 2;
}
.actor i {
font-size: 32px;
color: var(--async-purple);
filter: drop-shadow(0 0 8px currentColor);
}
.actor span {
font-size: 11px;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.actor:hover {
border-color: var(--async-purple);
transform: translateY(-3px);
}
/* Olay Taşıyıcı Çizgi */
.event-line {
flex-grow: 1;
height: 2px;
background: var(--border-color);
margin: 0 30px;
position: relative;
z-index: 1;
}
.pulse {
position: absolute;
top: -40px;
left: 0;
padding: 6px 16px;
background: var(--async-purple);
color: #000;
border-radius: 20px;
font-size: 11px;
font-weight: 900;
opacity: 0;
white-space: nowrap;
box-shadow: 0 0 20px var(--async-purple);
transition: left 1.5s linear, opacity 0.3s ease;
}
.lab-controls {
padding: 40px 30px;
text-align: center;
border-top: 1px solid var(--border-color);
background: rgba(15, 23, 42, 0.3);
}
.lab-controls h4 {
color: var(--text-main);
font-size: 18px;
margin-bottom: 10px;
font-weight: 700;
}
.lab-description {
color: var(--text-dim);
font-size: 14px;
line-height: 1.6;
margin-bottom: 30px;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.btn-group {
display: flex;
justify-content: center;
gap: 20px;
}
.btn-lab {
padding: 14px 32px;
border: none;
border-radius: 12px;
font-weight: 800;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
min-width: 210px;
text-transform: uppercase;
font-size: 13px;
letter-spacing: 0.5px;
}
.btn-sync {
background: var(--sync-blue);
color: #000;
box-shadow: 0 4px 14px rgba(56, 189, 248, 0.3);
}
.btn-async {
background: var(--async-purple);
color: #000;
box-shadow: 0 4px 14px rgba(167, 139, 250, 0.3);
}
.btn-lab:hover {
transform: translateY(-3px) scale(1.02);
filter: brightness(1.1);
}
.btn-lab:active {
transform: translateY(0);
}
.lab-terminal {
background: #000;
padding: 24px;
height: 180px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 13px;
border-top: 1px solid var(--border-color);
line-height: 1.7;
color: #e2e8f0;
}
.lab-terminal::-webkit-scrollbar {
width: 8px;
}
.lab-terminal::-webkit-scrollbar-track {
background: #000;
}
.lab-terminal::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 4px;
border: 2px solid #000;
}
.lab-terminal::-webkit-scrollbar-thumb:hover {
background: var(--async-purple);
}
.lab-terminal {
scrollbar-width: thin;
scrollbar-color: var(--border-color) #000;
}
.pulse {
position: absolute;
top: -40px;
left: 0;
transform: translateX(-50%);
padding: 6px 16px;
background: var(--async-purple);
color: #000;
border-radius: 20px;
font-size: 11px;
font-weight: 900;
opacity: 0;
white-space: nowrap;
box-shadow: 0 0 20px var(--async-purple);
z-index: 3;
transition: left 1.5s linear, opacity 0.3s ease;
}
@media (max-width: 600px) {
.event-area {
flex-direction: column;
gap: 30px;
padding: 40px 20px;
}
.event-line {
width: 2px;
height: 100px;
margin: 0;
}
.pulse {
top: 0;
left: -50px;
transform: translateY(-50%);
}
.btn-group {
flex-direction: column;
align-items: center;
}
.btn-lab {
width: 100%;
max-width: 300px;
}
}
// DOM Elementlerini yakala
const publisher = document.querySelector(".publisher");
const consumer = document.querySelector(".consumer");
const eventLine = document.querySelector(".event-line");
const pulse = document.getElementById("event-pulse");
const terminal = document.getElementById("lab-console");
/**
* Terminale log düşer ve en son gelen en üstte görünür.
*/
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
/**
* Aktörlerin (Publisher/Consumer) orta noktalarını hesaplar.
* Animasyonun tam merkezden merkeze gitmesini sağlar.
*/
function getActorCenter(actor) {
const rect = actor.getBoundingClientRect();
return rect.left + rect.width / 2;
}
/**
* Pulse (Olay Paketi) hareket simülasyonu.
* Her iki modda da 1.5 saniye sürer.
*/
function movePulse(toX) {
return new Promise((res) => {
// Tarayıcının stil değişikliğini algılaması için 50ms gecikme
setTimeout(() => {
// Hız Sabitlendi: 1500ms (1.5s)
pulse.style.transition = "left 1500ms linear, opacity 0.3s ease";
pulse.style.left = `${toX}px`;
}, 50);
// Animasyon (1.5s) + küçük bir buffer ile promise'ı tamamla
setTimeout(res, 1550);
});
}
/**
* Ana Simülasyon Fonksiyonu
*/
async function simulate(isAsync) {
// 1. Başlangıç hazırlıkları
const pubCenter = getActorCenter(publisher);
const lineRect = eventLine.getBoundingClientRect();
const startX = pubCenter - lineRect.left;
const conCenter = getActorCenter(consumer);
const endX = conCenter - lineRect.left;
// Pulse'ı Publisher'ın ortasına ışınla ve görünür yap
pulse.style.transition = "none";
pulse.style.left = `${startX}px`;
pulse.style.opacity = "1";
log(`İşlem Başladı: Sipariş oluşturuluyor...`);
if (!isAsync) {
// --- SENKRON AKIŞ (Blocking) ---
log(
"SENKRON MOD: Email servisinden yanıt bekleniyor (Bloklama)...",
"#38bdf8",
);
// Pulse hareket ederken 'await' ile kod burada durur.
await movePulse(endX);
log("BAŞARI: Email gönderildi. Sipariş akışı tamamlandı.", "#10b981");
pulse.style.opacity = "0";
} else {
// --- ASENKRON AKIŞ (Non-Blocking) ---
log("ASENKRON MOD: Olay fırlatıldı! Sipariş servisi özgür.", "#a78bfa");
// movePulse çağrılır ama 'await' kullanılmadığı için kod hemen alt satıra geçer.
movePulse(endX).then(() => {
log(
"DURUM: Email servisi olayı arka planda başarıyla işledi.",
"#94a3b8",
);
pulse.style.opacity = "0";
});
// Paket yoldayken bu log anında düşer; EDA'nın hızını temsil eder.
log("HIZ: Sipariş servisi bir sonraki müşteriye hazır.", "#10b981");
}
}
// Event Listener'lar
document
.getElementById("btn-sync")
.addEventListener("click", () => simulate(false));
document
.getElementById("btn-async")
.addEventListener("click", () => simulate(true));
Temel Bileşenler ve Roller Mekanizma Detayları
Olay Güdümlü Mimari'nin çalışma mekanizması, birbirini doğrudan tanımayan üç ana rolün kusursuz işbirliğine dayanır.
Bu roller arasındaki iletişim, geleneksel metot çağrılarının aksine "fırlat ve unut" ( fire-and-forget ) prensibiyle gerçekleşir.
1. Olay Üreticisi (Producer / Publisher)Görevi: Sistemde önemli bir durum değişikliğini tespit eden ve bunu bir "olay" olarak dünyaya duyuran bileşendir.
Sorumluluk Sınırı: Üreticinin tek sorumluluğu, olayın gerçekleştiğini bildirmektir.
Olayı kimin tüketeceği, kaç servisin bu bilgiyle ilgilendiği veya tüketicilerin o an çalışıp çalışmadığı üreticiyi ilgilendirmeyen teknik detaylardır.
Örneğin: Bir OrderService, ödeme onaylandığı anda SiparisOlusturuldu olayını sisteme fırlatır ve kendi işine devam eder.
2. Olay Yöneticisi (Event Bus / Broker)Görevi: Sistemin merkezi sinir sistemidir, üreticilerden gelen olayları teslim alır, güvenli bir şekilde sıralar ve bu olaylara abone olmuş olan doğru tüketicilere iletir.
Teknoloji Katmanı: Bu rol genellikle RabbitMQ, Apache Kafka veya Redis Pub/Sub gibi mesaj kuyruğu teknolojileri tarafından üstlenilir.
Aracılar, sistemin Dayanıklılığını sağlar; tüketici kapalı olsa bile mesajı saklar.
3. Olay Tüketicisi (Consumer / Subscriber)Görevi: Belirli olay türlerini dinleyen ve bir olay geldiğinde kendi iş mantığını çalıştıran bileşendir.
Reaktif Davranış: Tüketiciler pasif beklerler; kendilerine ilgili olay iletildiğinde uyanırlar ve bir olayın birden fazla tüketicisi olabilir.
Örneğin: SiparisOlusturuldu olayını aynı anda; müşteriye mail atan bir BildirimServisi, stokları güncelleyen bir StokServisi ve faturayı hazırlayan bir MuhasebeServisi dinleyebilir.
Mimari Fayda: Esnek GenişlemeBu mekanizma sayesinde sisteme yeni bir tüketici eklemek, mevcut üretici koduna dokunmayı gerektirmez.
Bu, sistemin Geliştirilebilirlik AQC'sini maksimize ederken, servisler arasındaki bağı tamamen koparır.
Sonuç olarak EDA mekanizması; bileşenleri birbirine kelepçelemek yerine, onları ortak bir "olay dili" ile konuşan bağımsız ve çevik birimlere dönüştürür.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Byteomi Pub/Sub Broker Lab</title>
<link rel="stylesheet" href="broker-style.css?v=1.0.150">
</head>
<body>
<div class="code-type-label">
<div class="code-type-label-content">
<div class="code-type-icon"></></div>
<div class="code-type-description">
Byteomi Pub/Sub Broker (Message Orchestration)
<span class="lang-icon"><i class="fab fa-html5"></i></span>
<span class="lang-icon"><i class="fab fa-css3-alt"></i></span>
<span class="lang-icon"><i class="fab fa-js"></i></span>
</div>
</div>
</div>
<div class="lab-container broker-theme">
<div class="lab-viz broker-area">
<div class="actor-group">
<div class="actor publisher-node">
<i class="fas fa-plus-circle"></i>
<span>Order Service</span>
</div>
</div>
<div id="message-broker" class="broker-node">
<div class="broker-label">MESSAGE BROKER</div>
<div id="queue-stack" class="queue-visual"></div>
</div>
<div class="subscribers-group">
<div id="sub-mail" class="actor subscriber-node">
<i class="fas fa-envelope"></i>
<span>Mail Srv</span>
</div>
<div id="sub-stock" class="actor subscriber-node">
<i class="fas fa-warehouse"></i>
<span>Stock Srv</span>
</div>
<div id="sub-invoice" class="actor subscriber-node">
<i class="fas fa-file-invoice-dollar"></i>
<span>Bill Srv</span>
</div>
</div>
</div>
<div class="lab-controls">
<h4>Olay Güdümlü Dağıtım Mekanizması</h4>
<p class="lab-description">Bir olay yayınlandığında, aracının (Broker) bu mesajı tüm abonelere nasıl
eşzamanlı
dağıttığını izleyin.</p>
<div class="btn-group">
<button id="btn-publish" class="btn-lab btn-pub">Olayı Yayınla (Publish)</button>
</div>
</div>
<div id="lab-console" class="lab-terminal">
<div class="log-dim">> Broker dinlemede. Aboneler aktif: 3...</div>
</div>
</div>
<script src="index.js?v=1.0.150"></script>
</body>
</html>
:root {
--bg-deep: #0f172a;
--card-bg: #1e293b;
--broker-gold: #fbbf24;
--pub-blue: #38bdf8;
--sub-purple: #a78bfa;
--success-green: #10b981;
--text-main: #f1f5f9;
--text-dim: #94a3b8;
--border-color: #334155;
--lab-max-width: 900px;
--glass-effect: rgba(30, 41, 59, 0.7);
}
body {
background-color: var(--bg-deep);
background-image:
radial-gradient(circle at center, rgba(251, 191, 36, 0.05) 0%, transparent 75%),
linear-gradient(rgba(251, 191, 36, 0.02) 1px, transparent 1px),
linear-gradient(90deg, rgba(251, 191, 36, 0.02) 1px, transparent 1px);
background-size: 100% 100%, 30px 30px, 30px 30px;
font-family: 'Inter', system-ui, -apple-system, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 20px;
margin: 0;
}
.code-type-label {
width: 100%;
max-width: var(--lab-max-width);
background: var(--card-bg);
border: 1px solid var(--border-color);
border-bottom: none;
border-radius: 16px 16px 0 0;
padding: 18px 24px;
box-sizing: border-box;
backdrop-filter: blur(10px);
}
.code-type-label-content {
display: flex;
align-items: center;
gap: 15px;
}
.code-type-icon {
font-family: 'Fira Code', monospace;
font-weight: bold;
color: var(--broker-gold);
background: rgba(251, 191, 36, 0.1);
padding: 6px 12px;
border-radius: 6px;
font-size: 16px;
}
.code-type-description {
display: flex;
align-items: center;
gap: 12px;
font-size: 14px;
font-weight: 600;
color: var(--text-main);
}
.lang-icon {
font-size: 16px;
color: var(--text-dim);
transition: color 0.3s ease;
}
.lang-icon:hover {
color: var(--broker-gold);
}
.lab-container {
width: 100%;
max-width: var(--lab-max-width);
background: var(--glass-effect);
border: 1px solid var(--border-color);
border-radius: 0 0 16px 16px;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.7);
overflow: hidden;
backdrop-filter: blur(12px);
box-sizing: border-box;
}
.broker-area {
padding: 80px 40px;
display: flex;
justify-content: space-around;
align-items: center;
background: rgba(15, 23, 42, 0.4);
min-height: 320px;
position: relative;
gap: 30px;
}
.broker-node {
width: 190px;
height: 190px;
border: 4px solid var(--broker-gold);
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
background: #020617;
box-shadow: 0 0 30px rgba(251, 191, 36, 0.2);
z-index: 2;
transition: all 0.3s ease;
}
.broker-node:hover {
box-shadow: 0 0 40px rgba(251, 191, 36, 0.3);
transform: scale(1.02);
}
.broker-label {
font-size: 11px;
font-weight: 900;
color: var(--broker-gold);
margin-bottom: 15px;
letter-spacing: 1px;
}
.queue-visual {
width: 70px;
height: 70px;
display: flex;
flex-direction: column-reverse;
gap: 5px;
overflow: hidden;
background: rgba(15, 23, 42, 0.5);
border-radius: 10px;
padding: 5px;
box-sizing: border-box;
}
.msg-packet {
height: 12px;
background: var(--broker-gold);
border-radius: 4px;
animation: slideIn 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
.broker-area::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 250px;
height: 250px;
border: 2px dashed var(--border-color);
border-radius: 50%;
z-index: 1;
}
.actor {
width: 110px;
padding: 20px 15px;
background: #020617;
border: 2px solid var(--border-color);
border-radius: 16px;
text-align: center;
color: var(--text-main);
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
font-size: 11px;
font-weight: bold;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
z-index: 2;
}
.actor i {
font-size: 30px;
filter: drop-shadow(0 0 8px currentColor);
}
.actor span {
font-size: 10px;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.publisher-node {
border-color: var(--pub-blue);
color: var(--pub-blue);
}
.subscriber-node {
border-color: var(--sub-purple);
color: var(--sub-purple);
}
.subscribers-group {
display: flex;
flex-direction: column;
gap: 20px;
}
.actor.active-node {
transform: scale(1.1);
border-color: var(--success-green);
color: var(--success-green);
box-shadow: 0 0 25px rgba(16, 185, 129, 0.3);
}
.lab-controls {
padding: 40px 30px;
text-align: center;
border-top: 1px solid var(--border-color);
background: rgba(15, 23, 42, 0.3);
}
.lab-controls h4 {
color: var(--text-main);
font-size: 18px;
margin-bottom: 10px;
font-weight: 700;
}
.lab-description {
color: var(--text-dim);
font-size: 14px;
line-height: 1.6;
margin-bottom: 30px;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.btn-group {
display: flex;
justify-content: center;
gap: 20px;
}
.btn-lab {
padding: 14px 32px;
border: none;
border-radius: 12px;
font-weight: 800;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
min-width: 250px;
text-transform: uppercase;
font-size: 13px;
letter-spacing: 1px;
}
.btn-pub {
background: var(--broker-gold);
color: #000;
box-shadow: 0 4px 14px rgba(251, 191, 36, 0.3);
}
.btn-lab:hover {
transform: translateY(-3px) scale(1.02);
filter: brightness(1.1);
}
.btn-lab:active {
transform: translateY(0);
}
.lab-terminal {
background: #000;
padding: 24px;
height: 180px;
overflow-y: auto;
font-family: 'Fira Code', monospace;
font-size: 13px;
border-top: 1px solid var(--border-color);
line-height: 1.7;
color: #e2e8f0;
}
.lab-terminal::-webkit-scrollbar {
width: 8px;
}
.lab-terminal::-webkit-scrollbar-track {
background: #000;
}
.lab-terminal::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 4px;
border: 2px solid #000;
}
.lab-terminal::-webkit-scrollbar-thumb:hover {
background: var(--broker-gold);
}
.lab-terminal {
scrollbar-width: thin;
scrollbar-color: var(--border-color) #000;
}
@media (max-width: 768px) {
.broker-area {
flex-direction: column;
gap: 40px;
padding: 60px 20px;
}
.broker-area::before {
width: 100%;
height: 2px;
border-radius: 0;
}
.subscribers-group {
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
gap: 15px;
}
.actor {
width: 100px;
padding: 15px;
}
}
@keyframes slideIn {
from {
transform: translateY(-30px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
const queue = document.getElementById("queue-stack");
const terminal = document.getElementById("lab-console");
const subs = document.querySelectorAll(".subscriber-node");
function log(msg, color = "#94a3b8") {
const div = document.createElement("div");
div.style.color = color;
div.innerText = `> ${msg}`;
terminal.prepend(div);
}
document.getElementById("btn-publish").addEventListener("click", () => {
log("PUBLISHER: 'OrderCreated' olayı yayınlandı.", "#38bdf8");
// Mesajın Broker'a girişi
const pkt = document.createElement("div");
pkt.className = "msg-packet";
queue.appendChild(pkt);
log("BROKER: Olay kuyruğa alındı ve abonelere iletiliyor...", "#fbbf24");
setTimeout(() => {
pkt.remove();
subs.forEach((sub, index) => {
setTimeout(() => {
sub.style.transform = "scale(1.1)";
sub.style.borderColor = "#10b981";
const subName = sub.querySelector("span").innerText;
log(`CONSUMER: ${subName} olayı aldı ve işliyor.`, "#a78bfa");
setTimeout(() => {
sub.style.transform = "scale(1)";
sub.style.borderColor = "#a78bfa";
}, 500);
}, index * 300);
});
log(
"BAŞARI: Tüm aboneler (Mail, Stok, Fatura) olaydan haberdar edildi.",
"#10b981",
);
}, 800);
});
Frontend Mimari Desenleri MVC/MVVM
Frontend Mimari Desenleri, istemci tarafında çalışan uygulamaların artık sadece basit etkileşimler değil, devasa iş kuralları ve durum yönetimi barındıran tam teşekküllü sistemlere dönüşmesiyle hayati önem kazanmıştır.
Temel Mücadele: Buradaki asıl zorluk, kullanıcıya görünen yüz ( Presentation Logic ) ile arka planda dönen veri kurallarını ( Business Logic ) birbirinden ayırmaktır.
Bu ayrım sağlanmadığında, küçük bir görsel değişiklik bile tüm sistemi bozabilen hantal bir yapıya dönüşür.
Felsefi Amaç: "Aptal" Görünüm (Dumb View)Bu desenlerin ana felsefesi, Görünüm katmanını mümkün olduğunca teknik detaydan ve karar verme mekanizmasından arındırmaktır.
View, sadece kendisine verilen veriyi göstermeli ve kullanıcı etkileşimlerini üst katmanlara haber vermelidir.
Test Edilebilirlik (Testability): DOM manipülasyonları içeren bir arayüzü test etmek oldukça zordur.
Ancak sunum mantığını ( Controller veya ViewModel ) arayüzden kopardığımızda, iş mantığının büyük bir kısmını tarayıcıya bile ihtiyaç duymadan ( Unit Test ) hızla test edebiliriz.
Mimari Kazançlar ve Geliştirici VerimliliğiFrontend mimarisi uygulandığında, projenin yaşam ömrü boyunca şu avantajlar elde edilir:
Yeniden Kullanılabilirlik: Veri yönetimi mantığı, spesifik bir UI teknolojisinden bağımsız hale gelir.
Bugün React ile yazdığınız iş mantığını, yarın Vue veya mobil React Native ) tarafında çok daha az maliyetle kullanabilirsiniz.
Geliştirici Odaklanması: Desenler, ekipleri sorumluluk alanlarına böler.
Bir geliştirici sadece estetik ve kullanıcı deneyimine ( UX/UI ) odaklanırken, diğeri verinin nasıl akacağına ve işleneceğine ( Data Flow ) yoğunlaşabilir.
Sonuç olarak Frontend mimari desenleri; istemci tarafındaki kodun "rastgele yazılmış scriptler" olmaktan çıkıp, profesyonel, sürdürülebilir ve teknoloji değişimlerine dirençli bir mühendislik yapısına dönüşmesini sağlar.
Model-View-Controller (MVC) MVC Mimari Deseni
MVC, kullanıcı arayüzü tasarımını, uygulamanın çekirdek verisinden ve iş mantığından ayırmak amacıyla geliştirilmiş klasik bir mimari desendir.
Bu ayrım, büyük ölçekli projelerin bakımını kolaylaştırırken, her bir parçanın kendi uzmanlık alanına odaklanmasını sağlar.
Desenin Akış Dinamiği: Etkileşimden SunumaMVC'nin çalışma felsefesi, dairesel bir sorumluluk zincirine dayanır. Bu döngü, sistemin her parçasının bağımsızca test edilebilir ve geliştirilebilir kalmasını garanti eder:
1. Kullanıcı Etkileşimi (Giriş): Kullanıcı bir düğmeye tıkladığında veya bir form doldurduğunda, View bu girdiyi yakalar ancak kendisi işlemez.
2. Veri İşleme (Kontrol): View, girdiyi Controller'a iletir.
Controller, isteği yorumlayarak hangi iş kuralının çalışması gerektiğine karar verir.
3. Durum Değişikliği (Veri): Controller, Model'i çağırarak veriyi güncellemesini ister. Model iş kurallarını uygular ve yeni durumu hazırlar.
4. Sunum Güncellemesi (Çıkış): Model güncellendiğinde, bu değişiklik View'e bildirilir ( Observer deseni ). View, Model'deki güncel veriyi alarak arayüzü yeniler.
Bileşenlerin Derinlemesine RolleriModel (Veri ve İş Kuralları): Uygulamanın en "akıllı" ama dış dünyadan en izole katmanıdır.
Verinin doğrulanması ve işlenmesinden sorumludur. Model, View veya Controller'ın varlığından haberdar değildir; sadece veriyi yönetir.
View (Görünüm): Sistemin "aptal" ( dumb ) kısmıdır.
Sadece Model'den gelen veriyi ekrana basar. Kendi içinde hiçbir mantıksal karar vermez, sadece kullanıcı girdilerini Controller'a postalar.
Controller (Kontrolcü): Sistemin "trafik polisi" ve köprüsüdür.
Kullanıcı girdilerini Model'in anlayacağı komutlara çevirir.
Uygulama akışını koordine eder ancak ağır iş kurallarını Model'e bırakarak "hafif" kalmalıdır.
MVC sayesinde, arayüz tasarımınızı (View) tamamen değiştirseniz bile iş mantığınız sarsılmaz.
Bu Gevşek Bağlılık, modern yazılım mühendisliğinde kodun çürümesini engelleyen ve ekiplerin paralel çalışmasına olanak tanıyan en temel disiplindir.
Saf JavaScript (Vanilla JavaScript) ile MVC Simülasyonu Model, View, Controller
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>MVC Basit Simülasyonu</title>
</head>
<body>
<h1>MVC Sayaç Örneği</h1>
<div style="font-size: 3em; margin-bottom: 20px;">
Sayaç Değeri: <span id="counter-display"></span>
</div>
<button id="increment-button">Artır</button>
<p style="margin-top: 20px;">Akışı görmek için konsolu (F12) açın.</p>
<script type="module">
import { CounterModel } from './model.js';
import { CounterController } from './controller.js';
import { CounterView } from './view.js';
// 1. Model'i Yaratma
const model = new CounterModel();
// 2. Controller'ı Yaratma ve Model'i Enjekte Etme
const controller = new CounterController(model);
// 3. View'i Yaratma ve Controller'ı Enjekte Etme
const view = new CounterView(controller);
// 4. View'i Model'e abone etme (Model -> View iletişimi)
model.subscribe(view);
// Başlangıç durumunu View'e bildir
model.notify();
</script>
</body>
</html>
// model.js (Veri ve Durum Yönetimi)
export class CounterModel {
constructor() {
this.count = 0;
this.views = []; // Gözlemciler (View'ler) listesi
}
// View'i abone etme
subscribe(view) {
this.views.push(view);
}
// Değişikliği tüm View'lere bildirme
notify() {
this.views.forEach(view => view.update(this.count));
}
// İş Mantığı: Sayacı artırma
increment() {
this.count++;
// Durum değişti, View'leri güncelle
this.notify();
}
}
// controller.js (İstek Yönetimi)
export class CounterController {
constructor(model) {
// Model'e bağımlılık enjekte edilir
this.model = model;
}
// View'den gelen tıklama isteğini işler
handleIncrementClick() {
console.log("[Controller] Tıklama isteği alındı, Model güncelleniyor...");
// İşlem Model'e delege edilir
this.model.increment();
}
}
Model-View-ViewModel (MVVM) MVVM Mimari Deseni
MVVM, kullanıcı arayüzü mantığını klasik MVC modelinden daha ileri bir seviyeye taşıyarak, ViewModel adında güçlü bir soyutlama katmanı ekler.
Bu desen, modern web uygulamalarındaki karmaşık durum yönetimini ve arayüz güncellemelerini otomatize etmek için tasarlanmıştır.
Desenin Amacı: Veri Bağlama (Data Binding) GücüMVVM'nin temel felsefesi, geliştiriciyi zahmetli ve hata yapmaya müsait olan manuel DOM manipülasyonundan ( eleman seçme, değer atama vb. ) kurtarmaktır.
İki Yönlü Veri Bağlama (Two-Way Data Binding): ViewModel'deki bir veri değiştiğinde View otomatik olarak güncellenir; aynı şekilde kullanıcı arayüzde bir veri değiştirdiğinde ( bir input alanına yazı yazıldığında ) ViewModel'deki karşılığı anında güncellenir.
Bu, sistemin her iki tarafının da her zaman senkronize kalmasını sağlar.
Bileşenlerin Stratejik RolleriModel (Veri Çekirdeği): MVC ile aynı sorumluluğa sahiptir ve iş kurallarını ve saf veriyi saklar.
View veya ViewModel'in nasıl göründüğüyle ilgilenmez, sadece veri bütünlüğünü garanti eder.
View (Sunum Katmanı): Kullanıcının etkileşime girdiği görsel katmandır.
MVVM'de View, ViewModel'deki verilere ve komutlara "abone" (bind) olur.
Kendi içinde iş mantığı barındırmaz; sadece ViewModel'in yansıttığı durumu gösterir.
ViewModel (Görünüm Modeli): Desenin kalbidir, view için veriyi hazırlar, biçimlendirir ve aksiyonları yönetir.
Model'deki ham veriyi ( bir tarih objesini gibi ) View'in anlayacağı bir formata ( "24 Aralık 2025" yazısı gibi ) dönüştürür.
Geliştirici Odaklanması ve Test EdilebilirlikMVVM sayesinde geliştiriciler, "arayüzü nasıl güncelleyeceğim?" sorusuyla değil, "uygulamanın durumu nasıl olmalı?" sorusuyla ilgilenirler.
ViewModel, hiçbir UI kütüphanesine veya tarayıcı DOM'una bağımlı olmadığı için, tüm arayüz mantığı birim testler ile kolayca doğrulanabilir hale gelir.
Sonuç olarak MVVM; yazılımı manuel ve yavaş süreçlerden kurtarıp, veri ve arayüzü kesintisiz bir döngüde birleştiren modern ve dinamik bir mühendislik çözümüdür.
MVVM Mekanizması İki Yönlü Veri Bağlama
MVVM Mekanizması'nı klasik MVC'den ayıran en kritik fark, View ve ViewModel arasındaki senkronizasyonun tamamen otomatik olmasıdır.
Geleneksel yaklaşımlarda Controller, "Şu butona basılınca şu elementin metnini değiştir" gibi manuel emirler verirken; MVVM'de bu süreç
Bağlama Sistemi tarafından sessizce yürütülür.
, Veri Akışı: İki Yönlü Kesintisiz DöngüBu mekanizma, veriyi sistemin iki ucu arasında sürekli akan canlı bir nehre dönüştürür:
1. View'den ViewModel'e (Giriş): Kullanıcı bir metin kutusuna bir karakter yazdığında, Bağlama Sistemi bu değişikliği anında yakalar ve ViewModel'deki ilgili özelliği günceller.
Geliştiricinin her tuş vuruşu için bir olay dinleyici (event listener) yazmasına gerek kalmaz.
2. ViewModel'den View'e (Çıkış): Arka planda bir API çağrısı bittiğinde veya bir hesaplama sonucunda ViewModel'deki bir veri değiştiğinde, bu değişiklik otomatik olarak arayüzdeki ( DOM ) ilgili elemente yansıtılır.
Bu işlem, genellikle modern kütüphanelerin Reaktivite Sistemi veya Sanal DOM algoritmalarıyla milisaniyeler içinde gerçekleşir.
Mimari Kazanç: Durum Odaklı GeliştirmeBu otomasyon sayesinde geliştirici artık "arayüzün hangi parçasını nasıl güncelleyeceğim?" sorusuyla boğuşmaz.
Bunun yerine, uygulamanın durumuna odaklanır, eğer veri doğruysa, arayüzün de doğru olacağı garantilenmiş olur.
Deklaratif Yaklaşım: Geliştirici sadece "Bu başlık, ViewModel'deki userName özelliğine bağlıdır" diyerek niyetini beyan eder; sistem geri kalan tüm ağır işçiliği üstlenir.
Sonuç olarak MVVM Mekanizması; kod kalabalığını azaltan, hata payını minimize eden ve kullanıcı etkileşimlerini veri ile doğrudan eşleyen son derece verimli bir mühendislik otomasyonudur.
Saf JavaScript (Vanilla JavaScript) ile MVVM Simülasyonu MVVM Simülasyonu (Gözlemci Deseni Kullanımı)
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>MVVM Basit Simülasyonu</title>
</head>
<body>
<h1>MVVM Veri Bağlama Örneği</h1>
<label for="username-input">Kullanıcı Adı:</label>
<input type="text" id="username-input" placeholder="Adınızı yazın...">
<p style="margin-top: 20px;">
Görüntülenen Veri (ViewModel'den):
<strong id="display-output">Henüz Girilmedi</strong>
</p>
<p style="margin-top: 20px;">Akışı ve otomatik güncellemeyi konsolda (F12) inceleyin.</p>
<script type="module">
import { UserModel } from './model.js';
import { UserViewModel } from './viewmodel.js';
const model = new UserModel();
const viewModel = new UserViewModel(model);
// View'i ViewModel'e bağlama (Manuel Data Binding Simülasyonu)
const inputElement = document.getElementById('username-input');
// Kullanıcı girdisi otomatik olarak ViewModel'i günceller (2 Yönlü Bağlamanın 1. yönü)
inputElement.addEventListener('input', (e) => {
viewModel.handleInput(e.target.value);
});
// Başlangıç render'ı
viewModel.renderView();
</script>
</body>
</html>
// model.js (Uygulama Durumu ve İş Kuralları)
export class UserModel {
constructor() {
this.username = '';
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
notify() {
this.observers.forEach(observer => observer.update(this.username));
}
// Model işlevi: Veriyi güncelle ve bildirim yap
setUsername(name) {
// İş Kuralı: Boş olamaz
if (!name) return console.error("[Model] Kullanıcı adı boş olamaz.");
this.username = name;
this.notify(); // View/ViewModel'e haber ver
}
}
// viewmodel.js (View için durum yöneticisi)
export class UserViewModel {
constructor(model) {
this.model = model;
// ViewModel, Model'e abone olur (Observer Deseni)
model.subscribe(this);
// View'de gösterilecek durumu hazırlar
this.viewData = {
usernameDisplay: model.username || "Henüz Girilmedi"
};
}
// Model'den gelen güncellemeyi ViewModel durumuna yansıtır
update(modelUsername) {
// Model verisini View formatına dönüştürme mantığı
this.viewData.usernameDisplay = modelUsername.toUpperCase();
// 💡 Otomatik Veri Bağlama Simülasyonu
// Normalde framework otomatik yapar, biz manuel tetikliyoruz.
this.renderView();
}
// View'den gelen kullanıcı girdisini işler (Komut)
handleInput(name) {
this.model.setUsername(name);
}
// View'i güncelleme (Simülasyon)
renderView() {
document.getElementById('display-output').textContent = this.viewData.usernameDisplay;
console.log(`[ViewModel] View Güncellendi: ${this.viewData.usernameDisplay}`);
}
}
MVC ve MVVM Karşılaştırması ve Sınırlamaları Genel Bilgi
MVC ve MVVM, frontend mimarisinde en çok uygulanan iki temel kalıptır.
Her ikisi de Görünüm ile Veri Yönetimini ayırmayı hedeflerken, bu ayrımı gerçekleştirme biçimleri sistemin genel performansını ve bakım maliyetini doğrudan etkiler.
Temel Çatışma: Bu iki desen arasındaki farkın merkezinde; arayüzün nasıl güncelleneceği ve veri akışının kimin sorumluluğunda olduğu yatar.
Bu farklılık, uygulamanın ölçeği büyüdükçe birinin avantajının diğerinin dezavantajına dönüşmesine neden olur.
MVC'de Kontrol: Controller'ın YüküKlasik MVC yapısında, Controller tüm sürecin merkezindeki trafik polisidir.
Kullanıcıdan gelen girdiyi alır, Model'i günceller ve ardından View'i manuel olarak güncelleme yükünü sırtlar.
Şişen Controller'lar: Uygulama karmaşıklaştıkça, Controller'lar yüzlerce satırlık "şu elementi bul, şu değeri yaz" kodlarıyla dolar.
Bu durum, veri ve arayüz arasındaki güncellenme sırasını takip etmeyi zorlaştırır ve hata payını artırır.
MVVM'de Otomasyon ve Gizli MaliyetlerMVVM, bu manuel güncellenme yükünü İki Yönlü Veri Bağlama ile çözer.
Geliştirici sadece veriyi değiştirir, arayüz kendiliğinden güncellenir.
Öngörülemezlik Sorunu: Bu otomasyon küçük projelerde mucizevi bir hız sağlasa da, devasa uygulamalarda büyük bir "takip edilebilirlik" sorununa yol açar.
Verinin hangi bileşen tarafından, hangi anda değiştirildiğini kestirmek güçleşir.
Bir input alanındaki değişim, zincirleme bir reaksiyonla sistemin hiç alakasız yerlerini tetikleyebilir.
Modern Reaktif Sistemlere GeçişMVVM'in sunduğu "iki yönlü bağlama" mekanizması, özellikle büyük ölçekli ve yüksek performans gerektiren modern uygulamalarda yetersiz kalmaya başlamıştır.
Bu öngörülemezlik, Redux veya Vuex gibi "Tek Yönlü Veri Akışı" prensiplerine dayalı daha sağlam mimarilerin doğmasına zemin hazırlamıştır.
Sonuç olarak; MVC manuel kontrolün güvenini verirken, MVVM otomasyonun hızını sunar.
Ancak her ikisi de, sistem büyüdüğünde karmaşıklık yönetimi ve hata ayıklama süreçlerinde kendine has zorluklar yaratır.
MVC ve MVVM'nin Ortak Sınırlamaları Genel Açıklama
MVC ve MVVM, orta ölçekli projelerde mükemmel çözümler sunsa da, devasa frontend uygulamalarında ciddi yapısal zorluklar yaratır.
Bu sınırlamalar genellikle desenlerin temel tasarım tercihlerinden, özellikle de bileşenler arasındaki karmaşık etkileşim ağından kaynaklanır.
Kontrol Kaybı: Bir sistem büyüdükçe, bu mimarilerin sağladığı esneklik yerini "öngörülemezliğe" bırakır.
Bakım maliyetleri artar ve bir noktada geliştiriciler, yaptıkları bir değişikliğin sistemin başka hangi noktasında yan etki yaratacağını kestiremez hale gelirler.
Öngörülemez Veri Akışı (Unpredictable Data Flow)Takip Edilebilirlik Sorunu: MVVM'deki "İki Yönlü Veri Bağlama" veya MVC'deki Controller-View döngüsü, verinin tam olarak nereden gelip nereye gittiğini izlemeyi zorlaştırır.
Domino Etkisi: Bir görünümdeki basit bir değişiklik, bir modeli güncelleyebilir; o model başka bir view'i tetikleyebilir ve o view de tekrar başka bir modeli güncelleyerek sonsuz veya yönetilemez bir güncelleme döngüsü yaratabilir.
Bu durum, hata ayıklama süreçlerini bir kabusa dönüştürür.
State (Durum) KarmaşasıGeleneksel desenlerde "Gerçeğin Tek Kaynağı" ( Single Source of Truth ) ilkesini korumak zordur. Uygulama durumu (state), farklı modellerin ve view'lerin içine dağılmış durumdadır.
Senkronizasyon Kaybı: Farklı UI bileşenlerinin aynı veriyi farklı şekillerde göstermesi gerektiğinde, bu parçaların her zaman senkron kalmasını sağlamak için yazılan "yapıştırma kodları" mimariyi hantallaştırır.
Yeni Paradigmaya Geçiş: Neden Tek Yönlü Akış?Bu yapısal zayıflıklar, modern frontend dünyasında Redux, Flux ve Zustand gibi sistemlerin doğmasına neden olmuştur.
Bu yeni yaklaşımlar, verinin her zaman tek bir yönde akmasını zorunlu kılarak; sistemin her anında "ne olduğunu" ve "neden olduğunu" tamamen öngörülebilir hale getirir.
Sonuç olarak; MVC ve MVVM'nin sınırlamaları, yazılım mühendisliğini daha katı ama daha güvenilir ve izlenebilir veri yönetimi modellerine yönlendirmiştir.
Veri Akışı Karmaşası (Two-Way Flow Sorunu) Konu Açıklaması
Geleneksel MVC ve MVVM modelleri, özellikle büyük ölçekli ve yoğun veri akışı olan uygulamalarda, View ile ViewModel arasındaki çift yönlü iletişimden kaynaklanan yapısal bir krizle karşılaşır.
Bu durum, ilk bakışta kolaylık gibi görünse de sistem büyüdükçe bir "veri kaosu" yaratır.
Sorun: İzlenebilirlik ve ÖngörülemezlikTakip Zorluğu: Uygulama içindeki bileşen sayısı arttıkça, verinin tam olarak hangi noktadan tetiklendiğini ve hangi sırayla değiştiğini izlemek imkansız hale gelir.
Çift yönlü bağlama, verinin hem aşağıdan yukarı hem yukarıdan aşağı aynı anda akmasına izin verdiği için merkezi kontrolü zayıflatır.
Çapraz Etkileşimler: Özellikle bir "A" bileşeni, dolaylı yoldan bir "B" bileşeninin modeline bağımlı olduğunda tehlike başlar.
Kullanıcının "A" bileşenindeki basit bir tıklaması, "B" ve "C" bileşenlerini beklenmedik şekilde güncelleyebilir.
Bu durum, geliştiricinin kontrolü dışında gerçekleşen istenmeyen yan etkilere yol açar.
Hata Ayıklama (Debugging) KabusuÖngörülemez Durum (Unpredictable State): Sistemde "şu anki veri durumu nedir?" sorusuna net bir cevap vermek zorlaşır.
Bir hata meydana geldiğinde, bu hatanın kaynağını bulmak için tüm bileşenler arasındaki görünmez veri bağlarını tek tek incelemek gerekir.
Domino Etkisi: Bir güncelleme, zincirleme bir reaksiyon başlatarak sistemin alakasız bir yerinde tutarsızlığa neden olabilir.
Bu karmaşa, modern frontend geliştiricilerini "gerçeğin tek kaynağına" ihtiyaç duymaya iten ana nedendir.
Sonuç: Paradigma Değişimine DoğruBu veri akışı karmaşası, yazılım mimarlarını daha katı ama daha güvenilir bir modele yönlendirmiştir.
Facebook gibi devlerin bu sorunu çözmek için geliştirdiği Flux ve ardından gelen Redux gibi yapılar, verinin sadece tek bir yönde akmasını zorunlu kılarak bu "spagetti etkisini" tamamen ortadan kaldırmayı hedefler.
Test Edilebilirlik Zorluğu (MVC'ye Özgü) Konu Açıklaması
MVC Deseni, bileşen rollerini teoride ayırsa da, pratikte bu ayrımı Controller üzerine aşırı yük bindirerek yapar.
Controller, hem kullanıcıdan gelen girdiyi yorumlamak, hem Model'e talimat vermek, hem de Model'den gelen sonuçla View'i güncellemek gibi çoklu sorumlulukları üstlenir.
Sorumluluk Karmaşası: Zamanla Controller'lar, iş mantığı ile sunum mantığının birbirine girdiği, yönetilemez ve "şişman" bir yapıya dönüşür.
Bu durum, Single Responsibility Principle ilkesinin ihlal edilmesine ve dolayısıyla birim testlerin ( unit tests ) yazılmasının imkansızlaşmasına neden olur.
Sorun: DOM Bağımlılığı ve Manuel GüncellemeMVC'nin test edilebilirliğini zorlaştıran asıl faktör, Controller'ın View'i manuel olarak güncelleme kısmıdır.
Bir Controller metodunu test etmek istediğinizde, o metodun bir HTML elementini ( bir div içeriği ) değiştirip değiştirmediğini kontrol etmeniz gerekir.
Sanal Ortam İhtiyacı: Saf JavaScript ile bu testi yapmak zordur; çünkü Controller'ı test etmek için sistemde gerçek veya sanal bir DOM ( JSDOM gibi ) ortamı kurmanız şarttır.
Bu bağımlılık, testlerin yavaşlamasına, kırılgan hale gelmesine ve kodun "saf mantığının" arayüzden izole edilememesine yol açar.
MVVM'in Çözümü: Otomasyon ile İzolasyonMVVM Farkı: MVVM bu sorunu, güncellemeyi tamamen otomasyona bırakarak çözer.
ViewModel'de hiçbir DOM kodu vseya element seçicisi bulunmaz. ViewModel sadece "veri durumunu" yönetir.
Saf Mantık Testi: ViewModel'i test ederken sadece "X fonksiyonu çağrıldığında veri Y oldu mu?" diye bakarsınız.
Arayüzün nasıl güncellendiği kütüphanenin sorumluluğundadır.
Bu, mimarinin Test Edilebilirlik AQC'sini devasa boyutta artırır.
Sonuç olarak MVC'deki test zorlukları, modern frontend geliştiricilerini daha test dostu ve arayüz bağımsız yapılara yönlendirmiştir.
Kodun güvenilirliğini sağlamak için, iş mantığını "arayüz gürültüsünden" tamamen arındırmak profesyonel bir zorunluluktur.
Ölçeklenebilirlik Engeli (Her İkisi İçin) Konu Açıklaması
MVC ve MVVM desenleri, orta ölçekli projelerde düzen sağlasa da, uygulama devasa boyutlara ulaştığında veri durumunu yönetme biçimleri nedeniyle ciddi ölçeklenebilirlik engelleri yaratır.
Bu engel, sistemin sadece performansını değil, geliştirme hızını da yavaşlatır.
Sorun: Merkezi Model DarboğazıTekil Model Riski: Geleneksel yaklaşımlarda uygulama durumu genellikle merkezi ve devasa bir Model yapısında tutulur.
Farklı iş alanlarına ait tüm mantıklar bu merkezi yapıya bağlandığında, Tek Sorumluluk Prensibi sistem düzeyinde ihlal edilmeye başlar.
Bağımlılık Zinciri: Sepet üzerindeki küçük bir değişiklik, aynı merkezi modeli kullanan Ödeme bileşenini veya Profil bileşenini etkileyebilir.
Bu durum, bileşenlerin birbirine "sıkı sıkıya bağlı" kalmasına ve bir modülü geliştirirken diğerini bozma riskine yol açar.
Yatay Ölçeklenme ve Performans SıkıntılarıDoğrudan Müdahale: Farklı bileşenlerin aynı veri kümesine doğrudan ve eşzamanlı müdahale etmeye çalışması, veri tutarsızlıklarına neden olur.
Bu karmaşa, uygulamanın farklı parçalarının bağımsız olarak ölçeklenmesini ve izole edilmesini zorlaştırır.
Geliştirme Hızı: Mimarideki bu hantallık, ekiplerin birbirine ayak bağı olmasına neden olur.
Bir özelliğin eklenmesi için devasa merkezi modelin karmaşık kuralları arasında kaybolmak, Bakım Kolaylığı AQC düşürür.
Çözüm Yolu: Modüler Durum YönetimiBu ölçeklenebilirlik engelleri, modern frontend dünyasını veriyi merkezi ama "modüler" yöneten yapılara itmiştir.
Redux veya Zustand gibi sistemlerin sunduğu "durumu dilimleme" teknikleri, her iş alanının kendi verisini bağımsız yönetmesini sağlayarak bu darboğazı aşmayı hedefler.
Sonuç olarak; MVC ve MVVM'nin yarattığı bu engel, yazılımı "yekpare bir blok" olmaktan çıkarıp, her bir parçası bağımsızca büyüyebilen "modüler bir platforma" dönüştürme ihtiyacını doğurmuştur.
Tek Yönlü Veri Akışı (One-Way Data Flow) Flux Deseni Konu Girişi
Tek Yönlü Veri Akışı, özellikle React ekosistemiyle hayatımıza giren ve MVC/MVVM modellerindeki çift yönlü veri bağlamanın yarattığı kontrol kaybına karşı bir devrim niteliğindedir.
Bu mimari felsefe, büyük ölçekli uygulamalarda uygulama durumunun nasıl ve ne zaman değiştiğini tamamen şeffaf hale getirmeyi hedefler.
Flux: Disiplinli ve Öngörülebilir AkışFlux, Facebook tarafından geliştirilen ve tek yönlü akış prensibini katı kurallara bağlayan bir mimari desendir.
Flux'ta veri asla geriye doğru akmaz; bu durum, sistemin herhangi bir anındaki durumunu öngörülebilir kılar.
Bir hata oluştuğunda, verinin hangi yollardan geçerek o noktaya ulaştığını izlemek artık bir tahmin oyunu değil, net bir veri takibidir.
Felsefi Temeller ve Merkezi YönetimGerçeğin Tek Kaynağı (Store): Uygulamanın tüm verisi, sistemin farklı köşelerine dağılmak yerine merkezi bir Store içinde tutulur.
Bu, veritabanı benzeri bir güven sağlar; tüm bileşenler aynı güncel veriye bakar.
Değişimin Açık Niyeti (Action): Veri değişimi asla "tesadüfen" veya doğrudan gerçekleşmez.
Her değişiklik bir Eylem ile başlar. "Kullanıcı sepete ürün ekledi" gibi açık bir niyet olmadan veri yerinden oynamaz.
Merkezi Dağıtıcı (Dispatcher): Tüm eylemler bu merkezden geçer.
Dispatcher, eylemleri Store'lara ileten bir trafik kontrol merkezidir.
Bu zorunlu durak, sistemdeki tüm hareketlerin günlüklenmesini ve hata ayıklanmasını radikal bir şekilde kolaylaştırır.
Gevşek Bağlılık ve Reaktif Güçİzolasyon: View ( arayüz ) bileşenleri artık Model'leri doğrudan güncellemez; sadece bir "istek" (Action) yayınlar.
Store'lar ise View'leri tanımaz, sadece veriyi güncelleyip ilgilenenlere duyurur.
Bu yüksek izolasyon, parçaların birbirinden bağımsız test edilmesini ve geliştirilmesini sağlar.
Sonuç olarak Tek Yönlü Veri Akışı; Redux ve Vuex gibi modern kütüphanelerin temelini oluşturan, yazılımı rastgele değişimlerden koruyup disiplinli ve sağlam bir veri hattına dönüştüren vazgeçilmez bir prensiptir.
Flux Deseni Temel Mekanizma Dairesel Veri Akışı
Flux Mimarisinde veri akışı, hiçbir bileşenin atlanmadığı ve asla geriye dönülmediği katı bir döngü şeklinde ilerler.
Bu zorunlu dairesel yapı, MVVM veya MVC modellerinde karşılaşılan "durum öngörülemezliğini" ortadan kaldıran en radikal çözümdür.
İzlenebilir Değişim: Veri akışı tek bir yöne kilitlendiği için, bir hata oluştuğunda sistemin hangi aşamada tıkandığı veya verinin kim tarafından bozulduğu saniyeler içinde tespit edilebilir.
Adım 1: Action ➔ Dispatcher (Niyetin Bildirilmesi) Döngü, kullanıcının arayüzdeki bir etkileşimiyle başlar.
View, doğrudan veriyi değiştirmek yerine bir Action oluşturur.
Bu eylem, "Sepete Ekle" gibi net bir niyet ve bu niyetle ilgili veriyi taşır ve bu paket, merkezi otorite olan Dispatcher'a gönderilir.
Adım 2: Dispatcher ➔ Store (Trafik Kontrolü) Dispatcher, sistemin trafik polisidir. Gelen eylemi alır ve bu eylemi dinleyen tüm Store birimlerine dağıtır.
Dispatcher, hiçbir deponun eylemi atlamamasını ve değişimin tüm sistemde aynı anda, tutarlı bir şekilde işlenmesini garanti eder.
Adım 3: Store ➔ View (Durum Güncelleme) Store, eylemi işler ve uygulama durumunu ( state ) günceller.
Değişim tamamlandığında Store, "veri değişti" haberini sisteme yayınlar.
View, bu bildirimi alır almaz Store'dan güncel veriyi çeker ve arayüzünü bu yeni gerçekliğe göre yeniden çizer.
Döngünün Tamamlanması: Şeffaf ve Güvenli SistemView güncellendikten sonra kullanıcı yeni arayüzle tekrar etkileşime girdiğinde döngü en baştan başlar.
Bu kapalı döngü sayesinde, sistemde verinin girdiği tek bir kapı (Action) ve çıktığı tek bir sonuç noktası (Updated View) bulunur.
Özet olarak Flux mekanizması; yazılımı öngörülemez sürprizlerden koruyan, her bir veri değişimini kayıtlı ve izlenebilir kılan profesyonel bir kontrol hattıdır.
Saf JavaScript (Vanilla JavaScript) ile Flux Simülasyonu Flux Simülasyonu
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flux Deseni (Tek Yönlü Akış) Simülasyonu</title>
</head>
<body>
<h1>Flux ToDo Örneği</h1>
<input type="text" id="todo-input" placeholder="Yeni görev ekle">
<button id="add-button">Ekle</button>
<ul id="todo-list" style="margin-top: 15px; list-style-type: circle;"></ul>
<p style="margin-top: 20px;">
Akışı ve tek yönlü veri akışını görmek için konsolu (F12) açın.
</p>
<script type="module">
import { TodoView } from './view.js';
// Uygulama başlatılır
const app = new TodoView();
</script>
</body>
</html>
// dispatcher.js (Merkezi Yönlendirici)
class Dispatcher {
constructor() {
// Store'ların callback fonksiyonlarını tutar.
this.callbacks = [];
}
// Store'ları kaydetme
register(callback) {
this.callbacks.push(callback);
}
// Eylemi tüm kayıtlı Store'lara yayınlama
dispatch(action) {
console.log(`\n[DISPATCHER] Eylem Alındı: ${action.type}`);
// 💡 Akış: Tüm Store'ları sırayla tetikler.
this.callbacks.forEach(callback => callback(action));
}
}
// Uygulama genelinde tek bir Dispatcher kullanılır.
export const dispatcher = new Dispatcher();
// store.js (Durum Deposu ve Durum Değişim Mantığı)
import { dispatcher } from './dispatcher.js';
class TodoStore {
constructor() {
this.todos = [];
this.viewCallbacks = []; // View'leri bilgilendirme listesi
// Dispatcher'a abone ol, gelen eylemleri dinle
dispatcher.register(this.handleAction.bind(this));
}
// View'in Store'daki değişikliklere abone olması
subscribe(callback) {
this.viewCallbacks.push(callback);
}
// View'lere yeni durumu bildir (Gözlemci Deseni)
notify() {
this.viewCallbacks.forEach(callback => callback(this.todos));
}
// 💡 Akış: Eylemi işleme ve durumu değiştirme mantığı
handleAction(action) {
switch (action.type) {
case 'ADD_TODO':
this.todos.push({ id: Date.now(), text: action.payload.text, completed: false });
this.notify(); // View'i güncelle
break;
case 'TOGGLE_TODO':
const todo = this.todos.find(t => t.id === action.payload.id);
if (todo) {
todo.completed = !todo.completed;
this.notify(); // View'i güncelle
}
break;
}
}
}
export const todoStore = new TodoStore();
// view.js (View ve Action Yaratıcı)
import { dispatcher } from './dispatcher.js';
import { todoStore } from './store.js';
// Action Creator (Eylem Yaratıcı Fonksiyonlar)
export const TodoActions = {
addTodo: (text) => {
// 💡 Akış: Action nesnesi yaratılır ve Dispatcher'a gönderilir.
dispatcher.dispatch({ type: 'ADD_TODO', payload: { text } });
},
toggleTodo: (id) => {
dispatcher.dispatch({ type: 'TOGGLE_TODO', payload: { id } });
}
};
export class TodoView {
constructor() {
this.list = document.getElementById('todo-list');
this.input = document.getElementById('todo-input');
// Kullanıcı girdisi yakalanır (View sorumluluğu)
document.getElementById('add-button').addEventListener('click', () => {
const text = this.input.value.trim();
if (text) {
TodoActions.addTodo(text); // Controller rolünü üstlenen Action Creator çağrılır.
this.input.value = '';
}
});
this.list.addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
const id = parseInt(e.target.dataset.id);
TodoActions.toggleTodo(id);
}
});
// Store'daki değişikliklere abone ol (Observer)
todoStore.subscribe(this.render.bind(this));
console.log("[View] Flux'a abone oldu.");
}
// 💡 Akış: Store'dan gelen veriyle arayüzü günceller.
render(todos) {
this.list.innerHTML = '';
todos.forEach(todo => {
const li = document.createElement('li');
li.textContent = todo.text;
li.dataset.id = todo.id;
li.style.textDecoration = todo.completed ? 'line-through' : 'none';
li.style.cursor = 'pointer';
this.list.appendChild(li);
});
console.log(`[VIEW] Arayüz güncellendi. Toplam görev: ${todos.length}`);
}
}
Bileşen Tabanlı Mimari Component-Based Architecture - CBA
Bileşen Tabanlı Mimari, bir yazılım sisteminin kullanıcı arayüzünü veya işlevselliğini, birbirinden bağımsız, yeniden kullanılabilir ve kolayca değiştirilebilir parçalar olarak inşa etme prensibidir.
Monolitten Modülere: Sayfaların bütünleşik ve devasa HTML/JS blokları olarak tasarlandığı eski yaklaşımların aksine CBA, uygulamayı hiyerarşik bir ağaç yapısı oluşturan küçük ve izole edilmiş birimlere ayırır ve bu, karmaşıklığı yönetmenin en etkili yoludur.
Felsefi Amaç: İzolasyon ve KapsüllemeCBA'nın temel felsefesi, Tek Sorumluluk Prensibi'ni görsel katmana taşımaktır.
Her bileşen, kendi HTML yapısını, davranış mantığını ve stilini kendi içinde hapseder ( Encapsulation ).
Güvenli Değişim: Bir bileşenin iç kodunda yapılan düzenleme, sınırları iyi çizildiği sürece sistemin geri kalanını etkilemez.
Bu izolasyon, büyük projelerde "yan etki" riskini minimize eder.
Yeniden Kullanılabilirlik ve Hiyerarşik DüzenDRY (Don't Repeat Yourself) Prensibi: Bir kez tasarlanan kaliteli bir bileşen ( Button, Input veya Card gibi UI bileşenleri ), uygulamanın her yerinde veya farklı projelerde tekrar kullanılabilir.
Bu, hem geliştirme hızını artırır hem de tasarım tutarlılığı sağlar.
Bileşen Ağacı (Component Tree): Uygulama, "Ebeveyn-Çocuk" ( Parent-Child ) ilişkisiyle örülür.
Büyük bileşenler, daha küçük bileşenlerin birleşimiyle oluşur( App ➔ Page ➔ List ➔ Item ).
Bu hiyerarşi, sistemin her bir parçasının kolayca izlenebilmesini ve yönetilmesini sağlar.
Modern Sentez: CBA ve Veri AkışıDesenlerin Buluşması: MVC ve MVVM gibi desenler "verinin nasıl akacağını" belirlerken; CBA, "görünümün nasıl organize edileceğini" belirler.
React ve Vue gibi modern araçlar bu iki dünyayı birleştirir: Bileşen tabanlı bir yapı kurarken, bu yapı içindeki veri trafiğini Tek Yönlü Veri Akışı ile yönetirler.
Sonuç olarak Bileşen Tabanlı Mimari; kullanıcı arayüzlerini kırılgan bir cam kule olmaktan çıkarıp, parçaları istenildiğinde değiştirilebilen esnek ve endüstriyel bir platforma dönüştürür.
Bileşen Türleri ve Sorumluluk Ayrımı Genel Bakış
Bileşen Tabanlı Mimari içerisinde kaosun önlenmesi, bileşenlerin yüklendiği sorumlulukların keskin bir şekilde ayrılmasına bağlıdır.
Tek Sorumluluk Prensibi'ni UI düzeyinde uygulamak için bileşenler, üstlendikleri temel göreve göre iki ana kategoriye ayrılır: Akıllı ve Aptal bileşenler.
İzolasyonun Gücü: Bir bileşenin hem "veriyi nereden alacağını" hem de "verinin nasıl görüneceğini" aynı anda bilmesi, o bileşeni hantal ve test edilemez kılar.
Görevlerin ayrıştırılması, UI/UX değişikliklerinin veri akışını bozmadan hızla uygulanmasına olanak tanır.
1. Sunum Bileşenleri (Presentational / Dumb Components)Görevi: Sadece "nasıl görüneceği" ile ilgilenir.
Bu bileşenler veriyi kendi başlarına çekmezler; sadece kendilerine dışarıdan verilen veriyi ekrana basarlar.
Karakteristiği: Kendi durumları yoktur veya sadece görsel durumları ( menü açık mı kapalı mı? gibi ) yönetirler.
Uygulamanın geri kalanından tamamen izole oldukları için yeniden kullanılabilirlik oranları en yüksek olan parçalardır.
2. Konteyner Bileşenleri (Container / Smart Components)Görevi: "Nasıl çalışacağı" ile ilgilenir. Veri çekme ( API çağrıları ), durum yönetimi ve iş mantığı bu bileşenlerin sorumluluğundadır.
Köprü Rolü: Bu bileşenler genellikle görsel bir yapı içermezler ( HTML/CSS barındırmazlar ).
Bunun yerine, aldıkları veriyi Sunum Bileşenlerine paslayarak sistemi koordine ederler.
Uygulamanın "beyni" gibi davranarak veri akışını ( Redux/Flux döngüsü gibi ) yönetirler.
Mimari Kazanç: Test Edilebilirlik ve BakımBu ayrım sayesinde, bir arayüz elemanının biçimine odaklanan bir tasarımcı, veri akışını bozma korkusu olmadan çalışabilir.
Aynı şekilde, bir geliştirici de veri mantığını tarayıcıya veya spesifik bir tasarıma bağımlı kalmadan Node.js ortamında bile kolayca test edebilir.
Sonuç olarak Bileşen Türleri ve Sorumluluk Ayrımı; yazılımı rastgele bir arayüz yığını olmaktan çıkarıp, her bir parçası öngörülebilir ve yönetilebilir bir mühendislik sistemine dönüştürür.
Sunum Bileşenleri (Presentational Components) Sadece Görünümü Yönetir
Sunum Bileşenleri, uygulamanın kullanıcıyla temas eden yüzüdür.
Temel sorumlulukları; arayüzün nasıl görüneceğini, stilini ( CSS ) ve DOM üzerindeki yerleşim düzenini belirlemektir.
Bu bileşenler, sistemin saf işlevselliğini temsil ederler.
Sadece Render: Bir sunum bileşeni veriyi sadece "alır ve gösterir".
Verinin nereden geldiği, hangi API'den çekildiği veya veritabanında nasıl saklandığı gibi teknik detaylar bu bileşenin ilgi alanı dışındadır.
O, sadece kendisine verilen paketi en estetik şekilde ekrana yansıtmakla görevlidir.
Teknik Özellik: Durumsuz (Stateless) YapıSunum bileşenlerini güçlü kılan en önemli özellik, genellikle kendi iç durumlarını yönetmemeleridir.
Props Aracılığıyla İletişim: Bu bileşenler tüm veriyi ebeveynlerinden ( Parent Component ) özellikler ( props ) aracılığıyla kabul eder.
Bu yapı, bileşenin deterministik olmasını sağlar; yani aynı "prop" değerleri verildiğinde her zaman aynı görsel sonucu üretir.
Aptal (Dumb) ve Saf (Pure) KavramıLiteratürde bu bileşenlere "Aptal" denmesinin sebebi, çevrelerinde olup biten karmaşık iş kurallarından habersiz olmalarıdır.
Ancak bu "aptallık" bir tasarım harikasıdır; çünkü bileşeni çevresel faktörlerden izole ederek yeniden kullanılabilirlik oranını en üst seviyeye çıkarır.
Tasarım Sistemi Birimi: Bir "Button" veya "UserCard" bileşeni, bu saflığı sayesinde projenin onlarca farklı yerinde, farklı verilerle ama aynı görsel tutarlılıkla kullanılabilir.
Mimari Kazanç: Birim Test KolaylığıSunum bileşenleri, veri çekme veya asenkron işlemler gibi "gürültülü" kodlar barındırmadıkları için Birim Test süreçleri için idealdir.
Test yazarken sadece "İsim verisi verildiğinde ekranda isim yazıyor mu?" sorusuna yanıt aramak yeterlidir; bu da uygulamanın
Güvenilirlik AQC'sini artırır.
Sonuç olarak Sunum Bileşenleri; uygulamanın görsel dilini oluşturan, karmaşık mantıktan arındırılmış, estetik ve güvenilir yapı taşlarıdır.
Konteyner Bileşenleri (Container Components) Veri ve Durum Yönetimi
Konteyner Bileşenleri, kullanıcı arayüzünün estetiğiyle değil, bu arayüzün nasıl çalışacağı ve gerekli verinin nereden temin edileceğiyle ilgilenen stratejik katmandır.
Bu bileşenler, karmaşık veri kaynakları ile saf görsel yapılar arasında bir "lojistik merkezi" görevi görürler.
Veri Köprüsü: Bir konteyner bileşeni; uygulamanın merkezi veri deposuna bağlanır, harici API çağrılarını yönetir ve elde edilen bu ham veriyi işleyerek altındaki bileşenlere aktarır.
İş Mantığı Katmanı ile View arasındaki en kritik bağlantı noktasıdır.
Teknik Özellik: Sarmalama (Wrapping) ve Props DağıtımıKonteyner bileşenlerini fiziksel olarak ayırt eden en büyük özellik, genellikle kendi başlarına yoğun bir HTML / CSS üretmemeleridir.
Orkestra Şefi: Bu bileşenler, Sunum Bileşenlerini sarmalar ve onlara ihtiyaç duydukları verileri "özellikler" olarak dağıtırlar.
Sunum bileşeni sahnede şarkı söyleyen sanatçı ise, Konteyner bileşeni tüm teknik altyapıyı ve müziği koordine eden orkestra şefidir.
Akıllı (Smart) ve Kapsayıcı (Wrapper) KavramıLiteratürde bu bileşenlere "Akıllı" denmesinin sebebi, uygulamanın durumundan haberdar olmaları ve verilere müdahale edebilmeleridir.
Bir kullanıcının butona tıklama eylemi sonucunda veritabanında neyin güncelleneceğine veya hangi yönlendirme işleminin yapılacağına
bu akıllı katman karar verir.
Mimari Kazanç: Esneklik ve Bakım KolaylığıKonteyner yapısının kullanılması, veri yönetimini görsel tasarımdan izole eder.
Örneğin: Veriyi çektiğiniz API değiştiğinde veya Redux'tan Zustand'a geçiş yaptığınızda, uygulamanın görsel tasarımına dokunmanıza gerek kalmaz.
Sadece ilgili Konteyner bileşenini güncellemek yeterlidir; bu da sistemin Bakım Kolaylığı AQC'sini maksimize eder.
Sonuç olarak Konteyner Bileşenleri; veriyi ham halinden alıp anlamlı bilgilere dönüştüren ve bu bilgileri kullanıcıya sunulması için görsel katmana ileten stratejik karar mekanizmalarıdır.
Bileşenler Arası İletişim Inter-Component Communication
Bileşen Tabanlı Mimari'nin (CBA) gerçek gücü, birbirinden bağımsız parçaların ne kadar temiz ve disiplinli bir şekilde haberleştiğinde yatar.
Bu iletişim, uygulamanın karmaşıklığı artsa dahi sistemin öngörülebilir izlenebilir kalmasını sağlayan temel bir yaşam hattıdır.
İki Temel Akış: Veri ve OlaylarModern frontend sistemlerinde iletişim, Tek Yönlü Veri Akışı prensibine sadık kalarak iki ana yönde gerçekleşir:
1. Verinin Aşağı Akışı (Props): Bilgi, ebeveyn bileşenden çocuk bileşene doğru özellikler aracılığıyla akar.
Çocuk bileşen, bu verinin nereden geldiğini veya kaynağını bilmez; sadece kendisine sunulan veriyi kullanır.
2. Olayların Yukarı Akışı (Callbacks/Events): Bir çocuk bileşende bir etkileşim olduğunda ( örneğin bir tıklama ), bu durumu ebeveynine bildirmek için geri çağırma fonksiyonlarını ( callbacks ) tetikler, böylece kontrol ve karar yetkisi her zaman hiyerarşinin üst katmanlarında kalır.
Gevşek Bağlılık ve Yan Etki KontrolüBu modelin temel felsefesi, bileşenler arasındaki gevşek bağlılığı maksimize etmektir.
Bir bileşen, başka bir bileşenin iç yapısına müdahale edemez.
Bu katı sınırlar, bir bileşendeki değişikliğin sistemin geri kalanında "domino etkisi" yaratarak beklenmedik hatalara yol açmasını kesin olarak engeller.
Mimari Kazanç: İzlenebilirlik ve İzolasyonVerinin sistem içindeki seyahat yönünün net olması, bir hata oluştuğunda kaynağını bulma süresini radikal bir şekilde azaltır.
Ayrıca, iletişim kuralları sabit kaldığı sürece bir bileşeni tamamen söküp yenisiyle değiştirebilir veya o bileşeni tek başına ( isolated ) test edebilirsiniz.
Sonuç olarak Bileşenler Arası İletişim; yazılımın parçalarını birbirine kelepçelemek yerine, onları ortak bir protokol ile anlaşan özgür birimler haline getiren bir mühendislik disiplinidir.
Props (Özellikler) Verinin Aşağı Akışı
Props, bileşenler arasında veri ve yapılandırma bilgilerini iletmek için kullanılan birincil ve "yasal" araçtır.
Bu kanal, Tek Yönlü Veri Akışı felsefesinin temel taşıdır; çünkü verinin her zaman ebeveynden çocuğa doğru akmasını zorunlu kılarak sistemde bir otorite hiyerarşisi kurar.
Felsefe: Değişmezlik (Immutability) ve GüvenProps'un en kritik kuralı Değişmezlik ilkesidir, bir çocuk bileşen, kendisine iletilen props değerini asla doğrudan modifiye edemez.
Bu kısıtlama, veri akışını basit, izlenebilir ve güvenilir hale getirir.
Bütünlük Garantisi: Bir bileşenin görsel çıktısı, yalnızca kendi iç durumu ve dışarıdan gelen props'un birleşimiyle oluşur.
Eğer bir değişiklik gerekiyorsa, çocuk bileşen ebeveynine bir "geri çağırma" fonksiyonu ile sinyal gönderir; veriyi güncelleme yetkisi yine ebeveyndedir.
Props'un Fonksiyonel KapsamıProps sadece metin veya sayı gibi ham verileri taşımaz; bileşenin tüm kimliğini ve iletişim yeteneğini yapılandırır:
Callback Fonksiyonları: Çocuğun ebeveyniyle haberleşmesini sağlayan metodları taşır.
Bu, "Olayların Yukarı Akışı" mekanizmasını çalıştıran anahtar teslimidir.
Bileşen Enjeksiyonu (Children): Bir bileşenin içine başka bileşen yapılarını yerleştirmek için kullanılır.
Bu, mimaride esnek bir kompozisyon yeteneği sağlar.
JavaScript ve Reaktivite OtomasyonuModern JavaScript kütüphanelerinde props, reaktivite motorunun bir parçasıdır.
Ebeveyn bileşen yeni verilerle güncellendiğinde, bu güncel props değerleri otomatik olarak çocuklara aktarılır.
Çocuk bileşen, hiçbir manuel müdahale gerektirmeden bu yeni gerçeğe göre kendini yeniden çizer.
Sonuç olarak Props; bileşenleri bir araya getiren bir sözleşme gibi çalışarak, veri trafiğini düzenli, izlenebilir ve hatasız kılan mimari bir disiplindir.
Olayların Yukarı Akışı Callbacks/Events
Olayların Yukarı Akışı, verinin sadece yukarıdan aşağıya aktığı bir sistemde, çocuk bileşenlerin kendi dünyalarında gerçekleşen önemli etkileşimleri ebeveynlerine iletmek için kullandıkları resmi kanaldır.
Bu mekanizma, Tek Yönlü Veri Akışı disiplinini bozmadan sistemin dinamik kalmasını sağlar.
Yetki Hiyerarşisi: Çocuk bileşen, kendisine gelen veriyi değiştirecek yetkiye sahip değildir.
Bu nedenle, bir değişiklik gerektiğinde bu sorumluluğu hiyerarşideki yetkili noktaya geri devreder.
Mekanizma: Callback Fonksiyonlarının İşleyişiYukarı doğru iletişim, ebeveynin çocuğa bir "iletişim teli" uzatması gibidir ve bu süreç iki aşamada gerçekleşir:
1. Ebeveynin Rolü: Ebeveyn, durum değişikliğini yapacak olan fonksiyonu ( updateUserName ) tanımlar ve bu fonksiyonu çocuğa bir prop olarak paslar.
2. Çocuğun Rolü: Çocuk bileşen, bir olay gerçekleştiğinde ( handleInput ) kendisine gelen bu fonksiyonu tetikler.
Çocuk, bu fonksiyonun arka planda veritabanını mı güncellediğini yoksa sadece bir uyarı mı verdiğini bilmez; sadece niyetini sisteme bildirmiş olur.
Fonksiyonel Fark: Veri (Aşağı) vs. Olay (Yukarı)İletişim ağındaki dengeyi şu iki ayrım kurar:
Props (Aşağı Akış): "Ne Gösterilecek?" bilgisini, yani ham veriyi taşır.
Callbacks (Yukarı Akış): "Ne Yapılacak?" isteğini, yani olay sinyalini taşır.
Mimari Kazanç: İzolasyon ve Yeniden KullanılabilirlikBu yapı, çocuk bileşeni ebeveynin iç mantığından tamamen koparır.
Çocuk bileşen sadece "Bende bu olay oldu!" diye bağırır; kimin dinlediğini umursamaz.
Bu sayede aynı çocuk bileşen, farklı ebeveynlerde farklı amaçlar için tekrar tekrar kullanılabilir.
Sonuç olarak Olayların Yukarı Akışı; modern React/Flux mimarilerinin en güçlü yanıdır ve durum değişikliklerini öngörülebilir kılan, hata ayıklamayı basitleştiren profesyonel bir iletişim disiplinidir.
Sunum ve Konteyner Bileşenleri Presentational vs. Container Components
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CBA - Sunum ve Konteyner Ayrımı</title>
</head>
<body>
<h1>Bileşen Tabanlı Mimari: Props ve State Akışı</h1>
<div id="app-root"></div>
<p style="margin-top: 20px;">
Akışı ve bileşenler arası iletişimi (Props & Callbacks) görmek için konsolu (F12) açın.
</p>
<script type="module">
import { UserListContainer } from './konteyner-bileseni.js';
// Uygulama başlatılır ve ilk render yapılır.
const app = new UserListContainer();
app.render();
</script>
</body>
</html>
// sunum-bileseni.js
export const UserCard = (props) => {
const { name, status } = props;
// 💡 ÖNEMLİ: onclick KALDIRILDI. Olayı Konteyner yakalayacak.
return `
<div class="user-card" data-user-name="${name}" style="border: 1px solid #ccc; padding: 10px; margin-bottom: 5px;">
<strong>Ad: ${name}</strong><br>
Durum: <span style="color: ${status === "Aktif" ? "green" : "red"};">${status}</span>
<button class="status-toggle-btn" data-user="${name}"
style="margin-left: 10px; cursor: pointer;">
Durum Değiştir
</button>
</div>
`;
};
// konteyner-bileseni.js (Veri Yönetimi, Mantık)
import { UserCard } from "./sunum-bileseni.js";
export class UserListContainer {
constructor() {
this.state = {
users: [
{ name: "Ayşe", status: "Aktif" },
{ name: "Burak", status: "Pasif" },
{ name: "Cem", status: "Aktif" },
],
};
this.rootElement = document.getElementById("app-root");
this.handleStatusChange = this.handleStatusChange.bind(this);
// 💡 EKLENEN KISIM: Olay Delegasyonu Kurulumu
// Tüm tıklamaları kök elementten dinler ve butona özel işlemi tetikler.
this.rootElement.addEventListener('click', (e) => {
if (e.target.classList.contains('status-toggle-btn')) {
const userName = e.target.dataset.user;
this.handleStatusChange(userName); // Callback'i tetikle
}
});
}
// 💡 Yukarı Akış Fonksiyonu: Çocuktan gelen isteği işler ve State'i günceller.
handleStatusChange(userName) {
console.log(
`[KONTEYNER] Eylem alındı: ${userName} durumunu değiştirme isteği.`
);
const newUsers = this.state.users.map((u) =>
u.name === userName
? { ...u, status: u.status === "Aktif" ? "Pasif" : "Aktif" }
: u
);
this.state.users = newUsers;
this.render(); // Durum değişti, View'i yeniden çiz.
}
// 💡 Aşağı Akış: Veriyi Sunum Bileşenine Props olarak iletir.
render() {
this.rootElement.innerHTML = this.state.users
.map((user) => {
// Sadece veri Props olarak iletilir. Callback artık HTML'de değil, burada yakalanır.
return UserCard({
name: user.name,
status: user.status,
});
})
.join("");
console.log("[KONTEYNER] Tüm bileşenler Props ile yeniden çizildi.");
}
}
🧭 Opsiyonel Okuma Notu
Bilgilendirme: Bu bölüm, konuların arka planına ve düşünsel temellerine daha derin bir bakış sunmak amacıyla hazırlanmıştır.
- Matematiksel, tarihsel ve felsefî içerikler isteğe bağlı olarak okunabilir.
- Her bölümün içerik seviyesi ve yoğunluğu farklılık gösterebilir.
- Temel düzey kullanıcılar için zorunlu değildir, ileri düzey okuma niteliğindedir.
Mimari Prensipleri ve Desenleri ( Felsefi ve Tarihsel Açıklama )
Mimari prensipleri ve desenleri, JavaScript'te kod yapısını daha modüler,
okunaklı
ve bakımı kolay hale getirmek için kullanılan prensipler ve desenlerdir.
Bu bölümde, mimari
prensipleri ve desenlerinin felsefi ve tarihsel detaylarını inceleyeceğiz.
Programlamadaki Tarihi ve Evrimi Mimari Prensipleri ve Desenleri
Yazılım Mimarisi, bir sistemin sadece kodundan ibaret olmadığını, onun soyut ve yüksek seviyeli organizasyonunu ifade eder.
Tıpkı bir gökdelenin inşasından önce hazırlanan statik planlar gibi; mimari de sistemin ana bileşenlerini, bu parçaların birbirleriyle kurduğu derin ilişkileri ve dış dünya ile etkileşimini yöneten temel kılavuzdur.
Mimari Desen Nedir? Yapısal Çözüm ŞablonlarıMimari Desenler, yazılım tarihinde defalarca karşılaşılan karmaşık ve geniş kapsamlı problemlere sunulan, başarısı kanıtlanmış çözüm şablonlarıdır.
Tasarım desenlerinden farklı olarak; mimari desenler kodun mikro detaylarıyla değil, sistemin genel topolojisi ve ana yönüyle ilgilenir.
Odak ve Kapsam: Mimari bir desen; verinin nasıl akacağını, sorumlulukların hangi sınırlarda bölüneceğini ( Mikroservisler ) veya bileşenlerin hiyerarşik dizilimini ( Katmanlı Mimari ) belirleyerek sistemin omurgasını kurar.
Nitelik Gereksinimleri (Quality Attributes)Mimari desenlerin nihai amacı, sadece işlevsellik sunmak değil; Ölçeklenebilirlik, Güvenilirlik, Güvenlik ve Sürdürülebilirlik gibi sistemin kalitesini belirleyen "Nitelik Gereksinimlerini" karşılamaktır.
Doğru deseni seçmek, projenin teknik ömrünü belirleyen en kritik karardır.
Mimari Prensiplerin RehberliğiMimari Prensipler (Architectural Principles) ise, bu desenlerin uygulanması sırasında ekiplere yol gösteren yüksek seviyeli pusulalardır.
Bu kurallar, teknik kararlar alınırken ödün verilmemesi gereken temel değerleri yansıtır.
Evrensel Kılavuzlar: Kodun tekrarını önleyen DRY, sistemin parçalarının bağımsızlığını sağlayan Gevşek Bağlılık ( Loose Coupling ) ve her parçanın tek bir göreve odaklanmasını sağlayan Yüksek Uyum ( High Cohesion ) gibi prensipler; mimariyi sağlam, esnek ve her türlü değişime dirençli kılar.
Sonuç olarak Yazılım Mimarisi; teknik bir zorunluluktan öte, karmaşıklığı düzene çeviren ve yazılımın geleceğini garanti altına alan stratejik bir düşünce sistemidir.
Tarihsel Köken ve Evrim Yazılım Mimarisinin Doğuşu ve GoF Sonrası Gelişmeler
Yazılım Mimarisinin Doğuşu, teknik bir tercihten ziyade bir zorunluluk olarak ortaya çıkmıştır.
1960'lı yıllarda projelerin ölçekleri büyüdükçe, kontrol edilemeyen hatalar ve başarısızlıkla sonuçlanan devasa bütçeli işler "Yazılım Krizi"ni tetikledi.
Bu dönemde Edsger W. Dijkstra gibi öncüler, yazılımı rastgele bir kod yığını olmaktan çıkarıp, modüler ve hiyerarşik Katmanlı Mimari önerileriyle sistemleştirmeye başladılar.
1990’lar: GoF ve Desenlerin Formalleşmesi1990'lar, yazılım dünyasında bir dönüm noktasıdır. Christopher Alexander'ın fiziksel mimari ( bina inşası ) için geliştirdiği "desen" felsefesi, Gang of Four tarafından yazılımdaki tasarım desenlerine aktarıldı.
Ancak bu dönemde asıl devrim, kodun mikro detaylarından ziyade sistemin tüm topolojisini ele alan Mimari Desenlerin ayrı bir disiplin olarak tanınmasıyla gerçekleşti.
Standartlaşma Dönemi: Mary Shaw ve David Garlan'ın çalışmalarıyla; bugün hala temel aldığımız Model-View-Controller ve
İstemci-Sunucu gibi yapılar akademik ve endüstriyel olarak standart hale getirildi.
Bu, yazılım mühendisliğini bir zanaattan gerçek bir bilim dalına taşıyan adımdı.
Modern Çağ: Dağıtık Yapılar ve JavaScript DevrimiGünümüzde mimari desenler, bulut bilişim ve modern JavaScript ekosisteminin etkisiyle yeni bir faza geçmiştir.
Artık odak noktası sadece kodu bölmek değil, sistemin Ölçeklenebilirliğini ve Esnekliğini küresel çapta yönetmektir.
Paradigma Değişimi: Yekpare yapılar yerini; bağımsız hizmetlerin konuştuğu Mikroservisler ve gerçek zamanlı reaksiyonlar üzerine kurulu
Olay Güdümlü Mimari gibi dağıtık sistemlere bırakmıştır.
Bu evrim, yazılımın artık sadece çalışan bir araç değil, sürekli nefes alan ve büyüyen dijital bir ekosistem olduğunu kanıtlamaktadır.
Sonuç olarak Yazılım Mimarisi; geçmişin hatalarından ders çıkararak inşa edilen, her yeni teknolojiyle birlikte daha dayanıklı ve modüler hale gelen bir mühendislik mirasıdır.
Mimari Prensipleri ve Desenleri Programlamadaki Tarihi ve Evrimi
Yazılım Mimarisinin Kökenleri, "Yazılım Krizi" olarak adlandırılan, projelerin karmaşıklık nedeniyle yönetilemez hale geldiği bir dönemde atılmıştır.
Özellikle havacılık ve askeri savunma gibi hataya yer olmayan alanlarda, yazılımın rastgele bir komut dizisi değil, yapılandırılmış bileşenler olması gerektiği anlaşıldı.
İlk Katmanlaşma: 1968 yılında Edsger W. Dijkstra, karmaşıklığı dikeyde bölmeyi hedefleyen Katmanlı Yapı önerisini sundu.
Bu, yazılım dünyasında "alt sistem" kavramının ve sorumluluk ayrımının ilk büyük zaferiydi.
Mimari Dönüm Noktası: Disiplinin Formalleşmesi (1990’lar)1990'lı yıllarda, Christopher Alexander'ın fiziksel mimari felsefesi yazılıma uyarlandı. Gamma Grubu, nesne yönelimli tasarım desenlerini popülerleştirirken; 1996 yılında Mary Shaw ve David Garlan, "Software Architecture" adlı eserleriyle mimariyi kod düzeyinden sistem düzeyine taşıdılar.
Standart Desenlerin Doğuşu: Bu dönemde MVC, İstemci-Sunucu ve Boru-Filtre gibi yapılar akademik birer kavram olmaktan çıkıp endüstri standardı haline geldi.
Yazılım, artık bir zanaattan çok, mühendislik disiplini olarak kabul görmeye başladı.
Modern Dönem: Dağıtık ve Esnek Sistemler (2000’ler Sonrası)İnternetin küreselleşmesi ve bulut teknolojilerinin yükselişiyle birlikte mimari, "tek bir makinede çalışan yapı" vizyonundan
"birbirine bağlı bağımsız servisler" vizyonuna evrildi.
Modern çağın odağı artık sadece kod düzeni değil; hız, sınırsız ölçeklenebilirlik ve hata dayanıklılığıdır.
Yeni Nesil Paradigmalar: Modern JavaScript ekosisteminde (özellikle Node.js) hayat bulan Mikroservisler, Olay Güdümlü Mimari ve Sunucusuz yapılar, günümüzün devasa dijital platformlarının omurgasını oluşturmaktadır.
Sonuç olarak yazılım mimarisinin tarihi; insanlığın karmaşıklığı yönetme becerisinin, saf mantığı modüler ve dayanıklı sistemlere dönüştürme yolculuğudur.
Mimari Prensipleri ve Desenleri Mimari Desenlerin Matematiksel Yapısı ve Davranışı
Mimari Desenler, matematiksel olarak en temelde Graf Teorisi üzerine inşa edilir.
Bu teoride, her bir yazılım bileşeni birer Düğüm; bu bileşenler arasındaki iletişim ve bağımlılık yolları ise birer Kenar olarak temsil edilir.
Topolojik Analiz: Graf teorisi, bir mimarinin karmaşıklığını ve kırılganlığını ölçmemizi sağlar.
Mimarların en büyük hedefi, sistemde Döngüsel Bağımlılıkları yok ederek, verinin ve bağımlılığın net bir yönde aktığı (
Directed Acyclic Graph - DAG ) optimize edilmiş yapılar kurmaktır.
Kuyruk Teorisi: Performans ve Davranış DenklemiDağıtık mimarilerde, sistemin çalışma anındaki davranışı Kuyruk Teorisi ile analiz edilir.
Gelen her bir kullanıcı isteği bir "görev" olarak kuyruğa girer ve işlemci kaynakları tarafından işlenir.
Ölçeklenebilirlik Tahmini: Kuyruk teorisi; sistemin yoğun yük altında ne kadar sürede cevap verebileceğini ve hangi noktada tıkanacağını ( bottleneck ) matematiksel olarak hesaplamamıza yarar.
Bu, Node.js gibi olay döngüsü tabanlı sistemlerde kaynakların ne kadar verimli kullanıldığını anlamanın temelidir.
Olasılık ve Güvenilirlik MatematiğiBir mimarinin başarısı, sistemin ayakta kalma Olasılığı ile ölçülür.
Mimari desenler, "tek hata noktası" riskini matematiksel olarak minimize etmek için tasarlanır.
Yedeklilik (Redundancy): Bir bileşenin arızalanma olasılığı P ise, sisteme eklenen yedekli yapılar ve yük dengeleyicilerle bu olasılık katlanarak düşürülür.
Mimari kararlar, sistemin Güvenilirlik katsayısını en üst seviyeye çıkarmayı hedefleyen matematiksel birer optimizasyon hamlesidir.
Sonuç: Bilimsel Temelli TasarımSonuç olarak mimari desenler; sadece estetik bir düzen değil, graf teorisinin kararlılığı ve kuyruk teorisinin hızı ile yoğrulmuş, bilimsel temelli mühendislik çözümleridir.
Mimari Prensipleri ve Desenleri Yazılım Dünyasında Tasarım Mimarı (Software Architect) Kimdir ?
Yazılım Mimarı, bir yazılım projesinin yüksek seviyeli tasarım kararlarını alan ve projenin teknik geleceğini inşa eden kişidir.
Sadece kodun "nasıl yazılacağı" ile değil, sistemin parçalarının "nasıl birleşeceği" ve "nasıl ayakta kalacağı" ile ilgilenir.
O, geliştirme ekiplerinin takip edeceği teknik haritayı çizen baş stratejisttir.
Temel Sorumluluklar: Nitelik ve Uyum YönetimiTeknik Yol Haritası: Yazılım mimarı, kullanılacak mimari desenleri, teknoloji yığınlarını ve temel tasarım prensiplerini belirler.
Amacı, projenin sadece "çalışması" değil, uzun vadede sürdürülebilir olmasıdır.
Nitelik Bekçiliği: Sistemin Ölçeklenebilirlik, Güvenlik, Performans ve Güvenilirlik gibi nitelik gereksinimlerini karşılayıp karşılamadığını denetler.
İş dünyasının taleplerini, mühendislik diline ve uygulanabilir bir yapıya dönüştürür.
Sorumluluk Kapsamına Göre Mimari RollerYazılım dünyasında mimari roller, odaklandıkları alanın genişliğine göre farklı unvanlar alırlar:
1. Çözüm Mimarı (Solution Architect): Odak noktası belirli bir projedir.
İş gereksinimlerini teknik bir çözüme dönüştürmekle ve o projenin başarısıyla ilgilenir.
2. Teknik Mimar (Technical Architect): Belirli bir uzmanlık alanında derin teknik bilgiye sahiptir.
O alanın standartlarını ve en iyi uygulamalarını belirler.
3. Kurumsal Mimar (Enterprise Architect): En geniş perspektife sahiptir.
Tüm şirketin teknoloji stratejisini, departmanlar arası standartları ve uzun vadeli teknoloji yol haritasını yönetir.
Sonuç: Kaostan Düzene Geçişin MimarıYazılım mimarı, karmaşık iş problemlerini parçalara ayıran ve bu parçaları disiplinli bir sistem içinde birleştiren kişidir.
Onun çizdiği doğru harita, projenin sadece başarısını değil, geliştirme ekibinin huzurunu ve yazılımın ömrünü de belirler.
Öğrenme Yolu
JavaScript öğrenme yolculuğunuzda neredesiniz?
Bu bölüm, JavaScript öğrenme yolculuğunuzdaki ilerlemenizi görselleştirir. Aşağıda göreceğiniz adımlar, konular arasındaki mantıksal sıralamayı ve öğrenme akışını temsil eder. Tamamlanan konular mavi tonlarda gösterilir ve üzerinde bir onay işareti bulunur. Aktif konu, şu anda üzerinde çalıştığınız bölümdür ve parlak mavi renkle vurgulanır. Sonraki adımlar ise henüz tamamlanmamış konuları gösterir ve daha soluk tonlarda görüntülenir.
Her adım arasındaki oklar, öğrenme sırasını ve konular arasındaki bağlantıyı gösterir. Bu yapı, hangi konuları tamamladığınızı, hangi konuda olduğunuzu ve sıradaki adımlarınızı net bir şekilde görmenizi sağlar.
Modülerlik ve Kod Organizasyonu
ES Modülleri, Bağımlılık Enjeksiyonu ve IoC Konteynerleri
Mimari Prensipler ve Desenler
Yazılım mimarisi prensipleri ve desenleri