2025-12-26
JavaScript'te SOLID Prensipleri: TypeScript ve React ile Pratik Rehber
SOLID prensiplerininin modern JavaScript geliştirmede nasıl uygulanacağını öğrenin. TypeScript, React hooks ve fonksiyonel pattern'ler ile pratik örnekler - ayrıca ne zaman kullanmalı, ne zaman gereksiz.
SOLID prensipleri object-oriented programming için formüle edilmişti, ama modern JavaScript geliştirme farklı görünüyor - functional pattern’ler, React hooks, dynamic typing. Bu prensipler hala önemli mi? Cevap evet, ama önemli adaptasyonlarla.
Bu prensipler JavaScript’te değerli olmaya devam ediyor, ama çeviri gerekiyor. Sorun bunları kullanıp kullanmamak değil, inheritance yerine composition’ı ve katı interface’ler yerine duck typing’i tercih eden bir dilde nasıl uygulayacağımız.
Özet
Bu yazı SOLID’in beş prensibinin - Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation ve Dependency Inversion - JavaScript ve TypeScript geliştirmede nasıl adapte olduğunu inceliyor. React, Node.js ve TypeScript ile pratik örnekler üzerinden, bu prensiplerin kod kalitesini ne zaman geliştirdiğini ve ne zaman over-engineering’e yol açtığını keşfedeceğiz. Her prensip çalışan kod örnekleri, kaçınılması gereken anti-pattern’ler ve JavaScript’in fonksiyonel ve dinamik doğası için spesifik rehberlik içeriyor.
JavaScript Context’inde SOLID’i Anlamak
Zorluk
SOLID prensipleri Java ve C# gibi statik tipli, class tabanlı diller için tasarlandı. JavaScript farklı özellikler getiriyor:
- Dynamic typing - TypeScript olmadan compile-time type checking yok
- Functional pattern’ler - Function’lar first-class citizen
- Composition odaklı - Inheritance’a daha az vurgu
- Duck typing - Objeler explicit interface’lerle değil, davranışla validate ediliyor
- React pattern’leri - Hook’lar ve component’ler farklı kısıtlamalara sahip
Soru SOLID’in JavaScript’e uygulanıp uygulanmayacağı değil, bu prensipleri nasıl etkili bir şekilde çevireceğimiz.
Single Responsibility Principle (SRP)
Tanım: Bir modülün değişmek için tek bir nedeni olmalı.
Bu en doğrudan JavaScript’e çevrilir. Class, function veya React component yazıyor olun, her biri bir concern ile ilgilenmelidir.
React Component Örneği
İşte yaygın bir ihlal - birden fazla sorumluluğu olan component:
// BAD: SRP'yi ihlal ediyor: Component data fetching, state ve rendering yapıyor
function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(data => {
setUser(data);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});
}, [userId]);
if (loading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
if (!user) return null;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
<img src={user.avatar} alt={user.name} />
</div>
);
}
Bu component’in değişmek için üç nedeni var: data fetching logic, state management veya rendering gereksinimleri. Her concern’i ayır:
// SRP'yi takip ediyor: Data fetching sorumluluğu
function useUser(userId: string) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetch(`/api/users/${userId}`)
.then(res => res.json())
.then(setUser)
.catch(setError)
.finally(() => setLoading(false));
}, [userId]);
return { user, loading, error };
}
// Presentation sorumluluğu
function UserProfile({ userId }: { userId: string }) {
const { user, loading, error } = useUser(userId);
if (loading) return <Spinner />;
if (error) return <ErrorMessage error={error} />;
if (!user) return null;
return <UserCard user={user} />;
}
// Rendering sorumluluğu
function UserCard({ user }: { user: User }) {
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
<img src={user.avatar} alt={user.name} />
</div>
);
}
Şimdi her parçanın tek sorumluluğu var. useUser hook’u bağımsız test edilebilir ve diğer component’lerde yeniden kullanılabilir. UserCard user data’sını nereden geldiğini bilmeden render ediyor. API’deki değişiklikler sadece useUser’ı etkiliyor, presentation logic’i değil.
Yaygın SRP Anti-pattern’i: God Object’ler
// BAD: İlgisiz concern'leri olan modül
// utils/user.js
export function validateEmail(email) { /* ... */ }
export function formatCurrency(amount) { /* ... */ }
export function fetchWeatherData(city) { /* ... */ }
export function compressImage(file) { /* ... */ }
Bu function’ların ortak hiçbir yanı yok. Bunları odaklanmış modüllere böl:
// Cohesive modüller
// utils/validation.js
export function validateEmail(email) { /* ... */ }
export function validatePassword(password) { /* ... */ }
// utils/formatting.js
export function formatCurrency(amount) { /* ... */ }
export function formatDate(date) { /* ... */ }
// services/weather.js
export function fetchWeatherData(city) { /* ... */ }
Open/Closed Principle (OCP)
Tanım: Software entity’leri extension’a açık, modification’a kapalı olmalı.
JavaScript’te bu, mevcut kodu değiştirmeden yeni functionality ekleme demek. Strategy pattern burada iyi çalışıyor.
Payment Processing Örneği
İşte ihlal - yeni payment method’ları eklemek mevcut kodu değiştirmeyi gerektiriyor:
// BAD: OCP'yi ihlal ediyor: Her yeni payment method için function'ı değiştirmeli
function processPayment(amount: number, method: string) {
if (method === 'credit-card') {
validateCreditCard();
chargeCreditCard(amount);
} else if (method === 'paypal') {
validatePayPalAccount();
chargePayPal(amount);
} else if (method === 'crypto') {
validateWallet();
transferCrypto(amount);
}
// Yeni method eklemek bu function'ı değiştirmeyi gerektiriyor
}
Strategy pattern kullanarak functional yaklaşım:
// OCP'yi takip ediyor: Modification olmadan extend ediliyor
type PaymentProcessor = {
validate: () => Promise<boolean>;
charge: (amount: number) => Promise<PaymentResult>;
};
const createCreditCardProcessor = (cardDetails: CardDetails): PaymentProcessor => ({
validate: () => validateCreditCard(cardDetails),
charge: (amount) => chargeCreditCard(cardDetails, amount),
});
const createPayPalProcessor = (email: string): PaymentProcessor => ({
validate: () => validatePayPalAccount(email),
charge: (amount) => chargePayPal(email, amount),
});
const processPayment = async (
processor: PaymentProcessor,
amount: number
): Promise<PaymentResult> => {
const isValid = await processor.validate();
if (!isValid) throw new Error('Payment validation failed');
return processor.charge(amount);
};
// Kullanım - yeni processor eklemek processPayment'ta değişiklik gerektirmiyor
await processPayment(createCreditCardProcessor(cardDetails), 100);
await processPayment(createPayPalProcessor('[email protected]'), 100);
// Mevcut kodu değiştirmeden crypto ekle
const createCryptoProcessor = (wallet: string): PaymentProcessor => ({
validate: () => validateWallet(wallet),
charge: (amount) => transferCrypto(wallet, amount),
});
await processPayment(createCryptoProcessor(walletAddress), 100);
Bu TypeScript’in structural typing’i ile çalışıyor. Yeni processor’lar sadece shape’e uymalı - JavaScript’te explicit interface declaration gerekmiyor, TypeScript compile-time safety’de yardımcı oluyor.
Higher-Order Function’lar ile OCP
// Composition ile OCP
type Middleware = (data: any) => any;
const compose = (...fns: Middleware[]) => (data: any) =>
fns.reduce((result, fn) => fn(result), data);
// Base transformation'lar
const toLowerCase = (str: string) => str.toLowerCase();
const trim = (str: string) => str.trim();
const removeSpaces = (str: string) => str.replace(/\s/g, '');
// Composing ile extend et - modification gerektirmez
const normalizeEmail = compose(trim, toLowerCase);
const normalizeUsername = compose(trim, toLowerCase, removeSpaces);
// Yeni transformation ekle
const removeDashes = (str: string) => str.replace(/-/g, '');
const normalizePhoneNumber = compose(trim, removeSpaces, removeDashes);
Liskov Substitution Principle (LSP)
Tanım: Object’ler program’ı bozmadan subtype’ları ile değiştirilebilir olmalı.
LSP ihlalleri inheritance ile yaygın. Klasik örnek:
// BAD: LSP'yi ihlal ediyor: Square, Rectangle'ın contract'ını bozuyor
class Rectangle {
constructor(
protected width: number,
protected height: number
) {}
setWidth(width: number) {
this.width = width;
}
setHeight(height: number) {
this.height = height;
}
getArea(): number {
return this.width * this.height;
}
}
class Square extends Rectangle {
setWidth(width: number) {
this.width = width;
this.height = width; // Beklenmeyen davranış
}
setHeight(height: number) {
this.width = height;
this.height = height; // Beklenmeyen davranış
}
}
// Bu Square ile bozuluyor
function resizeRectangle(rectangle: Rectangle) {
rectangle.setWidth(10);
rectangle.setHeight(5);
console.assert(rectangle.getArea() === 50); // Square ile başarısız (area = 25)
}
Çözüm inheritance yerine composition:
// LSP'yi takip ediyor: Composition kullan
interface Shape {
getArea(): number;
}
class Rectangle implements Shape {
constructor(
private width: number,
private height: number
) {}
setWidth(width: number) {
this.width = width;
}
setHeight(height: number) {
this.height = height;
}
getArea(): number {
return this.width * this.height;
}
}
class Square implements Shape {
constructor(private size: number) {}
setSize(size: number) {
this.size = size;
}
getArea(): number {
return this.size * this.size;
}
}
// Function'lar Shape interface ile çalışıyor - substitution sorunu yok
function printArea(shape: Shape) {
console.log(`Area: ${shape.getArea()}`);
}
printArea(new Rectangle(10, 5)); // Çalışıyor
printArea(new Square(5)); // Çalışıyor
React Component’lerinde LSP
// BAD: LSP'yi ihlal ediyor: Enhanced button ek prop gerektiriyor
interface ButtonProps {
onClick: () => void;
label: string;
}
function IconButton({ onClick, label, icon }: ButtonProps & { icon: string }) {
if (!icon) {
throw new Error('IconButton requires icon prop'); // BAD: Substitution'ı bozuyor
}
return (
<button onClick={onClick}>
<Icon name={icon} />
{label}
</button>
);
}
// LSP'yi takip ediyor: Optional enhancement
interface IconButtonProps extends ButtonProps {
icon?: string; // Optional - substitution'ı bozmuyor
}
function IconButton({ onClick, label, icon }: IconButtonProps) {
return (
<button onClick={onClick}>
{icon && <Icon name={icon} />}
{label}
</button>
);
}
// Button kullanılan her yerde IconButton kullanılabilir
function Form() {
const handleSubmit = () => console.log('Submitted');
return (
<>
<Button onClick={handleSubmit} label="Submit" />
<IconButton onClick={handleSubmit} label="Submit" icon="check" />
</>
);
}
Interface Segregation Principle (ISP)
Tanım: Client’lar kullanmadıkları interface’lere depend etmemeli.
JavaScript’in duck typing’i bunu doğal olarak destekliyor, ama TypeScript interface’leri ve React prop’ları explicit segregation’dan faydalanıyor.
Fat Interface Problemi
// BAD: ISP'yi ihlal ediyor: Fat interface kullanılmayan method implementasyonlarını zorluyor
interface Worker {
work(): void;
eat(): void;
sleep(): void;
getMaintenance(): void;
}
class HumanWorker implements Worker {
work() { console.log('Working...'); }
eat() { console.log('Eating lunch...'); }
sleep() { console.log('Sleeping...'); }
getMaintenance() {
throw new Error('Humans do not need maintenance'); // BAD: Implement etmeye zorlanıyor
}
}
class RobotWorker implements Worker {
work() { console.log('Working...'); }
getMaintenance() { console.log('Getting maintenance...'); }
eat() {
throw new Error('Robots do not eat'); // BAD: Implement etmeye zorlanıyor
}
sleep() {
throw new Error('Robots do not sleep'); // BAD: Implement etmeye zorlanıyor
}
}
Odaklanmış interface’lere böl:
// ISP'yi takip ediyor: Segregated interface'ler
interface Workable {
work(): void;
}
interface Eatable {
eat(): void;
}
interface Sleepable {
sleep(): void;
}
interface Maintainable {
getMaintenance(): void;
}
// Sadece gerekli interface'leri implement et
class HumanWorker implements Workable, Eatable, Sleepable {
work() { console.log('Working...'); }
eat() { console.log('Eating lunch...'); }
sleep() { console.log('Sleeping...'); }
}
class RobotWorker implements Workable, Maintainable {
work() { console.log('Working...'); }
getMaintenance() { console.log('Getting maintenance...'); }
}
// Function'lar sadece ihtiyaç duydukları şeye depend ediyor
function makeWork(worker: Workable) {
worker.work();
}
function feedWorker(worker: Eatable) {
worker.eat();
}
const human = new HumanWorker();
const robot = new RobotWorker();
makeWork(human); // Çalışıyor
makeWork(robot); // Çalışıyor
feedWorker(human); // Çalışıyor
// feedWorker(robot); // BAD: Compile error - Robot Eatable implement etmiyor
React Component’lerinde ISP
// BAD: ISP'yi ihlal ediyor: Component tüm User type'a depend ediyor
interface User {
id: string;
name: string;
email: string;
address: Address;
phoneNumber: string;
preferences: UserPreferences;
billingInfo: BillingInfo;
// ... 20+ property daha
}
function UserGreeting({ user }: { user: User }) {
return <h1>Hello, {user.name}!</h1>; // Sadece name kullanıyor
}
// ISP'yi takip ediyor: Component sadece kullandığına depend ediyor
interface UserGreetingProps {
name: string;
}
function UserGreeting({ name }: UserGreetingProps) {
return <h1>Hello, {name}!</h1>;
}
// Kullanım: Sadece gerekli data'yı geç
function App() {
const user: User = fetchUser();
return <UserGreeting name={user.name} />;
}
ISP için TypeScript Utility Type’ları
// Büyük interface
interface User {
id: string;
email: string;
password: string;
firstName: string;
lastName: string;
address: Address;
phoneNumber: string;
createdAt: Date;
}
// Utility type'lar kullanarak focused type'lar oluştur
type UserCredentials = Pick<User, 'email' | 'password'>;
type UserProfile = Pick<User, 'id' | 'firstName' | 'lastName' | 'email'>;
type UserContactInfo = Pick<User, 'email' | 'phoneNumber' | 'address'>;
type PublicUser = Omit<User, 'password'>;
// Component'ler sadece gerekli property'leri alıyor
function UserContactForm({ email, phoneNumber, address }: UserContactInfo) {
// Component logic
}
Dependency Inversion Principle (DIP)
Tanım: High-level modüller low-level modüllere depend etmemeli. İkisi de abstraction’lara depend etmeli.
Bu testability ve flexibility için kritik.
Problem: Direct Dependency’ler
// BAD: DIP'yi ihlal ediyor: UserService doğrudan concrete implementation'lara depend ediyor
class MySQLDatabase {
connect() { /* ... */ }
query(sql: string) { /* ... */ }
}
class EmailService {
sendEmail(to: string, subject: string, body: string) {
// Doğrudan Gmail SMTP kullanıyor
}
}
class UserService {
private db = new MySQLDatabase(); // BAD: Tight coupling
private emailService = new EmailService(); // BAD: Tight coupling
async createUser(userData: UserData) {
await this.db.connect();
const user = await this.db.query('INSERT INTO users...');
await this.emailService.sendEmail(user.email, 'Welcome', 'Welcome!');
return user;
}
}
// Gerçek MySQL ve email service olmadan test edilemiyor
// Implementation'ları değiştirilemiyor
Abstraction’lar ile constructor injection kullan:
// DIP'yi takip ediyor: Abstraction'lara depend et
interface Database {
connect(): Promise<void>;
query<T>(sql: string, params?: any[]): Promise<T>;
}
interface EmailProvider {
send(to: string, subject: string, body: string): Promise<void>;
}
// Concrete implementation'lar
class MySQLDatabase implements Database {
async connect() { /* MySQL connection */ }
async query<T>(sql: string, params?: any[]): Promise<T> {
/* MySQL query */
return {} as T;
}
}
class PostgreSQLDatabase implements Database {
async connect() { /* PostgreSQL connection */ }
async query<T>(sql: string, params?: any[]): Promise<T> {
/* PostgreSQL query */
return {} as T;
}
}
// High-level modül abstraction'lara depend ediyor
class UserService {
constructor(
private db: Database,
private emailProvider: EmailProvider
) {}
async createUser(userData: UserData) {
await this.db.connect();
const user = await this.db.query<User>('INSERT INTO users...', [userData]);
await this.emailProvider.send(user.email, 'Welcome', 'Welcome!');
return user;
}
}
// Production: Gerçek implementation'ları inject et
const userService = new UserService(
new MySQLDatabase(),
new GmailEmailProvider()
);
// Testing: Mock'ları inject et
const testUserService = new UserService(
new MockDatabase(),
new MockEmailProvider()
);
// Implementation'ları kolayca değiştir
const productionUserService = new UserService(
new PostgreSQLDatabase(),
new SendGridEmailProvider()
);
React’te Context API ile DIP
// React Context ile dependency injection
interface ApiClient {
get<T>(url: string): Promise<T>;
post<T>(url: string, data: any): Promise<T>;
}
interface Logger {
log(message: string): void;
error(message: string, error: Error): void;
}
// Context'leri oluştur
const ApiClientContext = React.createContext<ApiClient | null>(null);
const LoggerContext = React.createContext<Logger | null>(null);
// Dependency'ler için custom hook'lar
function useApiClient() {
const client = useContext(ApiClientContext);
if (!client) throw new Error('ApiClient not provided');
return client;
}
function useLogger() {
const logger = useContext(LoggerContext);
if (!logger) throw new Error('Logger not provided');
return logger;
}
// Component abstraction'lara depend ediyor
function UserList() {
const apiClient = useApiClient();
const logger = useLogger();
const [users, setUsers] = useState<User[]>([]);
useEffect(() => {
apiClient.get<User[]>('/users')
.then(setUsers)
.catch(error => logger.error('Failed to fetch users', error));
}, [apiClient, logger]);
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
);
}
// Root'ta dependency'leri provide et
function App() {
const apiClient = useMemo(() => new FetchApiClient(), []);
const logger = useMemo(() => new ConsoleLogger(), []);
return (
<ApiClientContext.Provider value={apiClient}>
<LoggerContext.Provider value={logger}>
<UserList />
</LoggerContext.Provider>
</ApiClientContext.Provider>
);
}
// Testing: Mock'ları provide et
function TestApp() {
const mockApiClient = useMemo(() => new MockApiClient(), []);
const mockLogger = useMemo(() => new MockLogger(), []);
return (
<ApiClientContext.Provider value={mockApiClient}>
<LoggerContext.Provider value={mockLogger}>
<UserList />
</LoggerContext.Provider>
</ApiClientContext.Provider>
);
}
SOLID Ne Zaman Overkill Oluyor
Tüm kod strict SOLID’den faydalanmıyor. Premature abstraction gereksiz complexity yaratıyor.
Overkill Örneği: Basit String Formatting
// BAD: Basit utility için overkill
interface StringFormatter {
format(input: string): string;
}
class UpperCaseFormatter implements StringFormatter {
format(input: string): string {
return input.toUpperCase();
}
}
class FormatterFactory {
static create(type: string): StringFormatter {
switch (type) {
case 'uppercase':
return new UpperCaseFormatter();
default:
throw new Error('Unknown formatter');
}
}
}
// Basit function yeterli
const toUpperCase = (str: string) => str.toUpperCase();
SOLID’i Ne Zaman Strict Uygula
- Büyük codebase’ler ile birden fazla takım
- Kütüphaneler ve framework’ler public API’lar ile
- Uzun ömürlü enterprise uygulamalar
- Kompleks business logic yüksek testability gerektiren
- Esneklik gerektiren sistemler implementation değişiminde
SOLID’i Ne Zaman Rahatlatmalı
- Prototype’lar ve MVP’ler hızın architecture’dan önemli olduğu
- Küçük utility function’lar abstraction overhead’inin faydaları aştığı
- Stabil CRUD uygulamaları requirement değişikliklerinin düşük olduğu
- One-off script’ler ve tool’lar kısa ömürlü
- Pattern’ler henüz belirmediğinde - abstract etmeden önce duplication bekle
TypeScript’in Rolü
TypeScript JavaScript’te SOLID’i önemli ölçüde geliştiriyor:
// ISP ve DIP için explicit interface'ler
interface PaymentProcessor {
process(amount: number): Promise<void>;
}
class CreditCardProcessor implements PaymentProcessor {
async process(amount: number): Promise<void> {
// Implement etmeli yoksa compile error
}
}
// Type checking LSP ihlallerini önlüyor
interface Bird {
fly(): void;
}
class Penguin implements Bird {
fly() {
throw new Error('Cannot fly'); // TypeScript bunu yakalıyor
}
}
// Daha iyi: Farklı interface'ler
interface FlyingBird {
fly(): void;
}
interface SwimmingBird {
swim(): void;
}
class Sparrow implements FlyingBird {
fly() { console.log('Flying'); }
}
class Penguin implements SwimmingBird {
swim() { console.log('Swimming'); }
}
// Type-safe abstraction için generic'ler (DIP ve LSP)
interface Repository<T> {
findById(id: string): Promise<T | null>;
save(entity: T): Promise<T>;
delete(id: string): Promise<void>;
}
class UserRepository implements Repository<User> {
async findById(id: string): Promise<User | null> {
return null;
}
async save(user: User): Promise<User> {
return user;
}
async delete(id: string): Promise<void> {}
}
// Class hierarchy'lere alternatif union type'lar
type Shape =
| { type: 'circle'; radius: number }
| { type: 'rectangle'; width: number; height: number }
| { type: 'triangle'; base: number; height: number };
function calculateArea(shape: Shape): number {
switch (shape.type) {
case 'circle':
return Math.PI * shape.radius ** 2;
case 'rectangle':
return shape.width * shape.height;
case 'triangle':
return (shape.base * shape.height) / 2;
}
}
Önemli Çıkarımlar
SOLID prensipleri JavaScript’te değerli olmaya devam ediyor ama adaptasyon gerektiriyor:
- SRP doğrudan çevrilir function’lara, modüllere, component’lere ve hook’lara
- OCP composition ile çalışır ve higher-order function’lar, derin inheritance değil
- LSP TypeScript ile daha önemli - dynamic typing duck typing’e izin veriyor
- ISP doğal olarak destekleniyor JavaScript’in esnekliği ile - TypeScript bunu explicit yapıyor
- DIP testability için essential - constructor injection ve Context API iyi çalışıyor
React hook’ları doğal olarak SOLID ile uyumlu:
- Custom hook’lar SRP’yi enforce ediyor
- Hook’lar modification olmadan compose oluyor (OCP)
- Hook interface’leri minimal olmalı (ISP)
- Dependency’ler parameter veya Context ile inject ediliyor (DIP)
Pragmatizm ile prensipleri dengele:
- Küçük utility’ler abstraction layer’a ihtiyaç duymuyor
- Abstract etmeden önce pattern’lerin belirmesini bekle
- Prototype’lar hız için architecture’ı atlayabilir
- Büyük codebase’ler strict SOLID’den faydalanıyor
TypeScript SOLID’i geliştiriyor:
- Interface’ler ISP ve DIP’yi explicit yapıyor
- Type checking LSP ihlallerini önlüyor
- Generic’ler type-safe abstraction sağlıyor
- Utility type’lar focused interface’ler oluşturmaya yardımcı oluyor
Hedef SOLID prensiplerine dogmatik bağlılık değil, kod kalitesini ne zaman geliştirdiklerini ve ne zaman gereksiz complexity getirdiklerini anlamak. JavaScript’in dinamik, fonksiyonel ortamında, bu prensipler dilin güçlü yönlerine düşünceli bir şekilde adapte edildiğinde değerli rehberlik sağlıyor.
İlgili yazılar
Decorator, Adapter, Facade, Composite ve Proxy patternlerinin React ve TypeScript'te nasıl evrildiğini keşfedin. HOC'ların ne zaman hook'lara yol verdiğini, adapterlerin third-party API'ları nasıl izole ettiğini ve facade'ların karmaşıklığı nasıl basitleştirdiğini öğrenin.
Kural tabanlı chatbot'lardan otonom AI agent'larına mimari evrimi keşfet. ReAct, Plan-and-Execute ve çoklu-agent desenleri TypeScript implementasyonları ve pratik geçiş stratejileriyle öğren.
Singleton, Factory, Builder ve Prototype pattern'lerinin TypeScript'te nasıl evrildiğini keşfet. ES modüllerinin singleton'ları ne zaman değiştirdiğini, factory function'ların ne zaman class'lardan daha iyi olduğunu ve TypeScript'in type sisteminin oyunu nasıl değiştirdiğini öğren.
JavaScript ve TypeScript ekosistemlerinden doğan modern kalıpları keşfedelim - hooks, compound components, render props ve GoF'un hiç karşılaşmadığı problemleri çözen repository pattern'leri.
Claude Code konfigürasyonlarını kopyalamak context window şişmesine, araç seçim kalitesinin düşmesine ve uyumsuz iş akışlarına yol açar. Token bütçesi hesapları ve kademeli iyileştirme yaklaşımıyla desteklenen, bilinçli yapay zeka aracı konfigürasyonu rehberi.