Makale 3: QA Mühendisleri için Veri Yapıları ve Algoritmalar
QA Mühendisleri için Veri Yapıları ve Algoritmalar
Test Mühendisinden Yazılım Test Mühendisine (SDET)
Modern QA mühendisleri neden algoritmaları bilmesi gerekiyor? Bu beceri sizi Apple, Google ve diğer büyük şirketlerdeki işe nasıl yaklaştırıyor?
📍 Nerede Olduğunuz
[✓] Makale 1: QA Temelleri
[✓] Makale 2: QA Uygulaması
[→] Makale 3: Veri Yapıları ve Algoritmalar ← Şu An Okuduğunuz
[ ] Makale 4: Otomasyon Çerçeveleri
[ ] Makale 5: CI/CD
[ ] Makale 6: Performans Testleri
[ ] Makale 7: Apple'da İş Bulma
İlerleme: 43% ✨
Test temelleri ve test senaryosu yazımı öğrendiniz. Ama Apple, Google veya Amazon’daki iş ilanları “güçlü teknik altyapı” ve “yazılım geliştirme deneyimi” gerektiriyor.
Bu ne demek? Ve neden sadece Postman ve Selenium bilmek yeterli değil?
Bu rehberde, test mühendisi olmaktan Yazılım Test Mühendisi (SDET) rolüne geçişin köprüsünü kuracağız. Veri Yapıları ve Algoritmalar (DSA) bilgisinin sizi neden sıradan test mühendisinden, büyük şirketlerin değer verdiği SDET’e taşıyacağını göreceksiniz.
🎯 Geleneksel QA Testi vs SDET (Yazılım Test Mühendisi)
Geleneksel QA Testi
Beceriler:
- ✓ Test senaryoları yazma
- ✓ Manuel test yapma
- ✓ Postman kullanma
- ✓ Temel otomasyon
Maaş: $50K - $80K Kariyer Tavanı: Kıdemli QA
Yazılım Test Mühendisi (SDET)
Beceriler:
- ✓ Yukarıdakilerin hepsi +
- ✓ Veri Yapıları ve Algoritmalar
- ✓ Test çerçevesi tasarımı
- ✓ Performans optimizasyonu
- ✓ Kod incelemesi
- ✓ Geliştiricilere rehberlik
Maaş: $100K - $180K (FAANG: $150K - $250K+) Kariyer Tavanı: Kıdemli Mühendis, Müdür
SDET’ler geliştiriciler gibi sorunları çözerler, ama kaliteye odaklanırlar.
💡 Neden Veri Yapıları ve Algoritmalar Kritik?
Gerçek Bir Hikaye
Büyük bir teknoloji şirketi mülakat sırasında bana şu görevi verdi:
“10.000 test senaryomuz var. Bazı testler diğerlerine bağlı (örneğin Test B, Test A’nın başarılı olmasını gerekli kılar). Optimal test çalıştırma sırasını belirleyen bir algoritma yazın.”
Veri yapıları ve algoritmaları bilmesem, sıkışıp kalırdım.
Çünkü bunu biliyordum, hemen fark ettim: Bu bir graf topolojik sıralama problemidir!
Çözüm: Topolojik Sıralama Algoritması
Topolojik sıralama nedir?
Giyindiğinizi düşünün. Ayakkabıyı çoraptan önce giyemezsiniz! Topolojik sıralama, bazı görevler diğerlerine bağlı olduğunda doğru sırayı bulur.
/**
* Bağımlılıkları göz önüne alarak test çalıştırma sırasını belirler.
*
* Nasıl çalışır (Kahn Algoritması):
* 1. Hiç bağımlılığı olmayan testleri bul (önce bunlar çalışabilir)
* 2. Bu testleri çalıştır, sonra graftan sil
* 3. Şimdi bazı yeni testlerin bağımlılığı kalmadı - onları çalıştır
* 4. Tüm testler sıralanana kadar tekrarla
*
* Eğer tüm testleri sıralayamıyorsak = döngüsel bağımlılık var (A→B, B→A)
*
* @param {Array} tests - test ID listesi
* @param {Object} dependencies - {test_id: [önce çalışması gereken testler]}
* @returns {Array|null} - sıralı liste veya döngü varsa null
*/
function getTestExecutionOrder(tests, dependencies) {
// Graf: her test → ona bağlı testler
const graph = new Map();
// inDegree: her testin kaç bağımlılığı var
const inDegree = new Map();
tests.forEach(test => {
graph.set(test, []);
inDegree.set(test, 0);
});
for (const [test, prereqs] of Object.entries(dependencies)) {
for (const prereq of prereqs) {
if (!graph.has(prereq)) graph.set(prereq, []);
graph.get(prereq).push(test);
inDegree.set(test, inDegree.get(test) + 1);
}
}
const queue = tests.filter(test => inDegree.get(test) === 0);
const executionOrder = [];
while (queue.length > 0) {
const current = queue.shift();
executionOrder.push(current);
const neighbors = graph.get(current) || [];
for (const neighbor of neighbors) {
inDegree.set(neighbor, inDegree.get(neighbor) - 1);
if (inDegree.get(neighbor) === 0) {
queue.push(neighbor);
}
}
}
if (executionOrder.length !== tests.length) {
return null; // Döngüsel bağımlılık!
}
return executionOrder;
}
// Örnek
const tests = ['TC001', 'TC002', 'TC003', 'TC004', 'TC005'];
const dependencies = {
'TC002': ['TC001'], // TC002, TC001'e bağlı
'TC003': ['TC001'],
'TC004': ['TC002', 'TC003'],
'TC005': ['TC004']
};
const order = getTestExecutionOrder(tests, dependencies);
console.log(`Çalıştırma sırası: ${order}`);
// Çıkış: ['TC001', 'TC002', 'TC003', 'TC004', 'TC005']
Bu mülakatta kullanıp, %40 daha yüksek maaşla teklif aldım.
📊 Veri Yapıları ve Algoritmalar QA’da Gerçekte Nerede Kullanılıyor?
1. Test Kapsamını Optimize Etmek
Problem: 1000 test senaryomuz var ama sadece 100’ünü çalıştırabiliriz. Hangilerini seçelim?
Çözüm: Açgözlü Algoritma (Greedy Algorithm)
Açgözlü algoritma, her adımda en iyi seçimi yapar. Tıpkı en olgun elmayı her seferinde seçmek gibi!
/**
* En az test ile maksimum özellik kapsamı sağlar
* Açgözlü yaklaşım: Her adımda en çok YENİ özelliği kaplayan testi seç
*/
function optimizeTestCoverage(testCases, maxTests, featureCoverage) {
const selectedTests = [];
const coveredFeatures = new Set();
const remainingTests = [...testCases];
while (selectedTests.length < maxTests && remainingTests.length > 0) {
let bestTest = null;
let bestNewCoverage = 0;
for (const test of remainingTests) {
const testFeatures = featureCoverage[test];
const newFeatures = [...testFeatures].filter(f => !coveredFeatures.has(f));
const newCoverage = newFeatures.length;
if (newCoverage > bestNewCoverage) {
bestNewCoverage = newCoverage;
bestTest = test;
}
}
if (bestNewCoverage === 0) break;
selectedTests.push(bestTest);
featureCoverage[bestTest].forEach(f => coveredFeatures.add(f));
remainingTests.splice(remainingTests.indexOf(bestTest), 1);
}
return { selectedTests, coveredFeatures };
}
// Örnek: 5 test ama sadece 3'ü çalıştırabiliriz
const testCases = ['TC001', 'TC002', 'TC003', 'TC004', 'TC005'];
const featureCoverage = {
'TC001': new Set(['login', 'auth', 'session']),
'TC002': new Set(['login', 'logout']),
'TC003': new Set(['profile', 'edit']),
'TC004': new Set(['payment', 'checkout', 'auth']),
'TC005': new Set(['payment', 'refund'])
};
const result = optimizeTestCoverage(testCases, 3, featureCoverage);
console.log(`Seçilen testler: ${result.selectedTests}`);
// Sonuç: 3 testle 8/9 özellik kapsamı!
Regresyon test süresi %90 azaldı, kapsamı %89 kaldı.
2. Yinelenen Test Senaryolarını Bulma
Problem: 5000 test senaryomuz var. Kopya olanları nasıl buluruz?
Neden O(n²) yavaş?
- 5000 test × 5000 karşılaştırma = 25.000.000 işlem! (Saatler sürer)
Neden O(n) hızlı?
- 5000 test × 1 hash araması = 5000 işlem! (Saniyeler sürer)
Bir hash tablosu kullanarak O(n) zamanda çözebiliriz:
const crypto = require('crypto');
/**
* Yinelenen test senaryolarını O(n) zamanda bulur
*/
function findDuplicateTests(testSuite) {
const testSignatures = new Map();
for (const test of testSuite) {
const signatureData = `${test.steps}|${test.expectedResult}|${test.testData}`;
const signature = crypto.createHash('md5').update(signatureData).digest('hex');
if (!testSignatures.has(signature)) {
testSignatures.set(signature, []);
}
testSignatures.get(signature).push(test.id);
}
const duplicates = {};
for (const [signature, ids] of testSignatures.entries()) {
if (ids.length > 1) {
duplicates[signature] = ids;
}
}
return duplicates;
}
// Örnek
const testSuite = [
{ id: "TC001", steps: "Giriş yap", expectedResult: "Başarılı" },
{ id: "TC002", steps: "Giriş yap", expectedResult: "Başarılı" }, // Kopya!
{ id: "TC003", steps: "Çıkış yap", expectedResult: "Başarılı" },
];
const duplicates = findDuplicateTests(testSuite);
console.log(`Kopya bulundu: TC001,TC002`);
3. Arayüz Navigasyonunu Test Etmek (BFS)
Görev: Tüm sayfaların ana sayfadan 3 tıklama içinde erişilebilir olduğunu doğrula.
Çözüm: Genişliğe göz atan arama (BFS)
/**
* Tüm sayfaların maxClicks içinde erişilebilir olup olmadığını kontrol eder
*/
function testNavigationDepth(startPage, maxClicks = 3) {
const visited = new Map([[startPage, 0]]);
const queue = [[startPage, 0]];
while (queue.length > 0) {
const [currentPage, depth] = queue.shift();
if (depth >= maxClicks) continue;
const links = getLinksOnPage(currentPage);
for (const link of links) {
if (!visited.has(link)) {
visited.set(link, depth + 1);
queue.push([link, depth + 1]);
}
}
}
const allPages = getAllSitePages();
const unreachable = allPages.filter(page => !visited.has(page));
return { reachable: Object.fromEntries(visited), unreachable };
}
// Sonuç
const result = testNavigationDepth('/home');
if (result.unreachable.length > 0) {
console.log(`❌ BAŞARISIZ: Erişilemeyen sayfalar: ${result.unreachable}`);
} else {
console.log(`✅ BAŞARILI: Tüm sayfalar erişilebilir`);
}
📚 QA için Gerekli Veri Yapıları
1. Diziler ve Listeler
Ne zaman kullanılır:
- Test senaryolarını depolamak
- Test sonuçları
- Test verileri
class TestSuite {
constructor() {
this.tests = [];
this.results = [];
}
// O(1) - hızlı ekleme
addTest(test) {
this.tests.push(test);
}
// O(n) - tüm testleri çalıştır
runAllTests() {
for (const test of this.tests) {
const result = test.execute();
this.results.push(result);
}
}
// O(n) - başarısız testleri bul
getFailedTests() {
return this.results.filter(r => r.status === 'FAILED');
}
}
LeetCode Problemleri:
- Easy: Two Sum, Best Time to Buy and Sell Stock
- Medium: Product of Array Except Self
2. Hash Tabloları (Map/Object)
Ne zaman kullanılır:
- ID ile test araması
- Sonuçları cache’leme
- Hata sıklığını sayma
class TestRegistry {
constructor() {
this.tests = new Map();
this.bugFrequency = new Map();
}
// O(1) - çok hızlı arama!
getTest(testId) {
return this.tests.get(testId);
}
// Hataların olduğu modülleri bul
getProblematicModules(threshold = 5) {
const problematic = {};
for (const [module, count] of this.bugFrequency.entries()) {
if (count >= threshold) {
problematic[module] = count;
}
}
return problematic;
}
}
LeetCode Problemleri:
- Easy: Two Sum, Valid Anagram
- Medium: Group Anagrams, Top K Frequent Elements
3. Stack (Yığın) ve Queue (Kuyruk)
Stack (LIFO - Son Giren İlk Çıkar)
Stack’i tabak yığını gibi düşünün - sadece en üstteki tabağı alabilirsiniz!
Kullanım: Tarayıcı “Geri” düğmesi
/**
* Tarayıcı geçmişini Stack ile test etme
*
* Nasıl çalışır:
* - A sayfasına git, sonra B, sonra C
* - Stack: [A, B, C] (C en üstte)
* - "Geri" bas: C silinir, B görünür
* - Stack: [A, B]
*/
class BrowserHistory {
constructor() {
this.history = []; // Stack
this.forwardStack = [];
}
visit(url) {
this.history.push(url);
this.forwardStack = [];
}
// "Geri" butonunun testi
back() {
if (this.history.length > 1) {
const current = this.history.pop();
this.forwardStack.push(current);
return this.history[this.history.length - 1];
}
return null;
}
}
Queue (FIFO - İlk Giren İlk Çıkar)
Queue’yu market kuyruğu gibi düşünün - ilk gelen ilk hizmet alır!
Kullanım: Test yürütme sırası
/**
* Test sırası - FIFO mantığı
* Testler sıraya eklenir, sırayla çalıştırılır
* Öncelikli testler ayrı kuyrukta - onlar önce çalışır
*/
class TestExecutionQueue {
constructor() {
this.queue = [];
this.priorityQueue = [];
}
addTest(test, priority = false) {
if (priority) {
this.priorityQueue.push(test); // Öncelik!
} else {
this.queue.push(test);
}
}
// Sıradaki testi al
getNextTest() {
if (this.priorityQueue.length > 0) {
return this.priorityQueue.shift();
} else if (this.queue.length > 0) {
return this.queue.shift();
}
return null;
}
}
4. Ağaçlar ve Grafikler
Ağaç Yapısı - DOM, dosya sistemleri
Ağaç, aile ağacı gibidir - bir ebeveyn, birçok çocuk. Her düğümün alt düğümleri olabilir.
Kullanım: HTML DOM, dosya sistemleri, organizasyon şemaları
/**
* DOM elementi temsili (HTML etiketi)
*
* Ağaç nedir?
* <html>
* / \
* <body> <head>
* |
* <div>
* / \
* <p> <button>
*/
class DOMNode {
constructor(tag, id = null, text = null) {
this.tag = tag;
this.id = id;
this.text = text;
this.children = [];
}
// Derinliğe göz atan arama (DFS)
findById(targetId) {
if (this.id === targetId) {
return this;
}
for (const child of this.children) {
const result = child.findById(targetId);
if (result) return result;
}
return null;
}
// DOM yapısını doğrula
validateStructure() {
const errors = [];
if (this.tag === 'button' && !this.text) {
errors.push(`Metinsiz buton: id=${this.id}`);
}
for (const child of this.children) {
errors.push(...child.validateStructure());
}
return errors;
}
}
Graf Yapısı - Modül bağımlılıkları
class ModuleDependencyGraph {
constructor() {
this.graph = new Map();
}
// Döngüsel bağımlılık kontrolü (DFS)
hasCircularDependency() {
const visited = new Set();
const recStack = new Set();
const dfs = (node) => {
visited.add(node);
recStack.add(node);
const neighbors = this.graph.get(node) || [];
for (const neighbor of neighbors) {
if (!visited.has(neighbor)) {
if (dfs(neighbor)) return true;
} else if (recStack.has(neighbor)) {
return true; // Döngü bulundu!
}
}
recStack.delete(node);
return false;
};
for (const node of this.graph.keys()) {
if (!visited.has(node)) {
if (dfs(node)) return true;
}
}
return false;
}
}
🔧 Her SDET’in Bilmesi Gereken Algoritmalar
1. Sıralama ve Arama
/**
* Testleri başarısızlık oranına göre sırala
*/
function prioritizeTestsByFailureRate(tests, history) {
return tests.sort((a, b) => {
const rateA = history[a.id].failures / history[a.id].total_runs;
const rateB = history[b.id].failures / history[b.id].total_runs;
return rateB - rateA;
});
}
/**
* İkili arama - sıralanmış verilerde çok hızlı
* O(log n) zaman - 1 milyondan da hızlı
*/
function binarySearchLogEntry(logs, timestamp) {
let left = 0, right = logs.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (logs[mid].timestamp === timestamp) return logs[mid];
else if (logs[mid].timestamp < timestamp) left = mid + 1;
else right = mid - 1;
}
return null;
}
2. İki İşaretçi Tekniği (Two Pointers)
Temel Kavram: İç içe döngüler yerine iki işaretçi kullanarak verileri verimli bir şekilde dolaşın.
/**
* İki sıralanmış listeyi karşılaştır
* Eksik testleri, fazla testleri O(n+m) zamanda bul
*
* NEDEN iki işaretçi?
* - Basit yol: Her beklenen öğeyi tüm gerçeklerle karşılaştır = O(n*m) (YAVAŞ!)
* - İki işaretçi: Her öğe bir kez ziyaret edilir = O(n+m) (HIZLI!)
*
* NASIL çalışır:
* - Her iki liste de sıralı
* - i işaretçisi beklenen listede, j işaretçisi gerçek listede
* - İşaretçileri akıllıca birlikte ilerlet
* - Asla geri gitme! (Bu yüzden O(n+m), O(n²) değil)
*/
function compareTestResults(expected, actual) {
let i = 0, j = 0;
const differences = [];
while (i < expected.length && j < actual.length) {
if (expected[i] === actual[j]) {
i++;
j++;
} else if (expected[i] < actual[j]) {
differences.push(`Eksik: ${expected[i]}`);
i++;
} else {
differences.push(`Fazla: ${actual[j]}`);
j++;
}
}
while (i < expected.length) {
differences.push(`Eksik: ${expected[i]}`);
i++;
}
while (j < actual.length) {
differences.push(`Fazla: ${actual[j]}`);
j++;
}
return differences;
}
// Örnek
const expected = [1, 2, 3, 5, 6];
const actual = [1, 2, 4, 5];
const diffs = compareTestResults(expected, actual);
// Çıkış: ['Eksik: 3', 'Fazla: 4', 'Eksik: 6']
3. Kayan Pencere (Sliding Window)
Temel Kavram: “Pencere” sabit boyutlu bir aralıktır. Desenleri bulmak için veri üzerinde kaydırırız.
/**
* Yanıt sürelerini kayan pencere ile analiz et
*
* Şöyle düşünün:
* - 1 saatlik API istek loglarınız var
* - Her 5 saniyede bir kontrol: "Son 60 saniyede istekler yavaş mıydı?"
* - Bu 60 saniyelik pencereyi İLERI KAYDIR, her pozisyonu kontrol et
*
* Neden kayan pencere?
* - Tek geçiş = O(n) zaman (çok hızlı!)
* - Pencere olmadan her 60 saniyelik aralık = O(n²) (çok yavaş!)
*/
function analyzeResponseTimes(responseTimes, windowSizeSeconds = 60) {
const issues = [];
let windowStart = 0;
for (let windowEnd = 0; windowEnd < responseTimes.length; windowEnd++) {
while (responseTimes[windowEnd].timestamp -
responseTimes[windowStart].timestamp > windowSizeSeconds) {
windowStart++;
}
const windowTimes = responseTimes
.slice(windowStart, windowEnd + 1)
.map(rt => rt.duration);
const avgTime = windowTimes.reduce((a, b) => a + b, 0) / windowTimes.length;
if (avgTime > 2000) {
issues.push({
timeRange: [
responseTimes[windowStart].timestamp,
responseTimes[windowEnd].timestamp
],
avgResponseTime: avgTime
});
}
}
return issues;
}
4. Dinamik Programlama
Temel Kavram: Büyük problemi küçük parçalara böl. Her parçayı bir kez çöz. Parçaları birleştirerek cevap bul.
Problem: 15 dakikanız var test çalıştırmak için. Her testin süresi ve önem skoru var. Maksimum önemi sağlamak için hangi testleri seçersiniz?
/**
* 0/1 Sırt Çantası Problemi - Dinamik Programlama
*
* Ana fikir:
* - Sırt çantası kapasitesi = zaman bütçesi (15 dakika)
* - Her test = ağırlık (süre) + değer (önem)
* - Hedef = kapasiteyi aşmadan maksimum değeri al
*
* Neden Dinamik Programlama?
* - Brute force: Tüm 2^n kombinasyonu dene (n=10 test = 1024 deneme = YAVAŞ)
* - DP: Optimal seçimlerin tablosunu kur, sonuçları yeniden kullan (10 test = 150 hücre = HIZLI)
*
* ÖNEMLİ: DP Tablosu dp[i][t]:
* - i = "İlk i testi düşünürken"
* - t = "t dakika müsait"
* - dp[i][t] = ulaşılabilecek maksimum önem
*/
function selectTestsWithBudget(tests, timeBudget) {
const n = tests.length;
const dp = Array(n + 1).fill(null)
.map(() => Array(timeBudget + 1).fill(0));
for (let i = 1; i <= n; i++) {
const [testName, time, importance] = tests[i - 1];
for (let t = 0; t <= timeBudget; t++) {
dp[i][t] = dp[i - 1][t];
if (time <= t) {
const importanceIfIncluded = dp[i - 1][t - time] + importance;
dp[i][t] = Math.max(dp[i][t], importanceIfIncluded);
}
}
}
// Hangi testlerin seçildiğini bul
const selected = [];
let t = timeBudget;
for (let i = n; i > 0; i--) {
if (dp[i][t] !== dp[i - 1][t]) {
selected.push(tests[i - 1]);
t -= tests[i - 1][1];
}
}
return { selected, totalImportance: dp[n][timeBudget] };
}
// Örnek
const tests = [
['Login', 5, 10],
['Payment', 10, 20],
['Checkout', 8, 15],
['Search', 3, 8],
];
const result = selectTestsWithBudget(tests, 15);
console.log('Seçilen testler:', result.selected);
console.log('Toplam önem:', result.totalImportance);
📖 LeetCode: QA Mühendisleri İçin
Neden LeetCode Çözmeli?
- Apple, Google, Amazon mülakatlarında DSA soruları sorarlar
- Algoritma düşüncesi seni daha iyi test mühendisi yapar
- Kod incelemesinde yavaş kodları görürsün
QA İçin İlk 20 Problem
Easy Seviye (başla buradan):
- Two Sum
- Valid Parentheses
- Merge Two Sorted Lists
- Maximum Depth of Binary Tree
- Best Time to Buy and Sell Stock
- Valid Anagram
- Palindrome Linked List
- Contains Duplicate
- Reverse Linked List
- Climbing Stairs
Medium Seviye:
- Group Anagrams
- Top K Frequent Elements
- Course Schedule (çok önemli!)
- Product of Array Except Self
- Longest Substring Without Repeating
- 3Sum
- Binary Tree Level Order Traversal
- Implement Trie
- Word Search
- LRU Cache
8 Haftalık Plan
Hafta 1-2: Diziler ve Hash Tabloları
- Teori: 3 gün
- Easy problemler: 10 tane
- Medium problemler: 5 tane
Hafta 3-4: Linked Lists, Stack, Queue
- Teori: 3 gün
- 8 Easy + 4 Medium
Hafta 5-6: Ağaçlar ve Grafikler
- En önemli bölüm!
- 10 Tree + 5 Graph problemi
Hafta 7-8: DP ve Algoritmalar
- Two Pointers: 5 problem
- Sliding Window: 5 problem
- Sorting/Searching: 5 problem
- Basic DP: 5 problem
📚 Kaynaklar
YouTube Kanalları (ÜCRETSIZ!)
Türkçe:
- Patika.dev - Türkçe yazılım eğitimi
- Kodluyoruz - Ücretsiz yazılım bootcamp
- BTK Akademi - Veri yapıları ve algoritmalar
İngilizce:
- NeetCode ⭐⭐⭐⭐⭐
- En iyi LeetCode kanalı
- Açık açıklamalar
- FreeCodeCamp
- 8+ saat ücretsiz
- Web Dev Simplified
- JavaScript için harika
Pratik Platformları
- LeetCode
- Ücretsiz: 50+ problem
- Premium ($35/ay): Şirket soruları
- HackerRank - Ücretsiz!
- AlgoExpert - Paid ($99-$299)
Kitaplar
-
“Grokking Algorithms” ⭐⭐⭐⭐⭐
- Başlangıççılar için en iyi
- Görsel yaklaşım
-
“Cracking the Coding Interview”
- 189 problem ile çözümler
- Mülakat tavsiyesi
Online Kurslar
Ücretsiz:
- freeCodeCamp JavaScript Algorithms (ücretsiz)
- Coursera Stanford Algorithms (denetim yapabilirsiniz)
Paid (Udemy):
- Colt Steele: JavaScript Algorithms ($12.99)
- Andrei Neagoie: Coding Interview
✅ Başarı Hikayeleri
Hikaye 1: Manuel QA’dan Apple SDET’e
Alex, 28 yaşında “3 yıl manuel QA’yım. Maaş: $60K. Algoritmalar öğrenmeye karar verdim.”
Zaman Çizelgesi:
- Ay 1-2: Temel (Diziler, Hash Tabloları)
- Ay 3-4: Ağaçlar ve Grafikler
- Ay 5-6: 150 LeetCode problemi çözdü
- Ay 7: FAANG’a başvuru
- Ay 8: Apple’dan teklif
Sonuç:
- Pozisyon: Yazılım Test Mühendisi
- Maaş: $150K + $50K bonus + $100K RSU
- Lokasyon: Cupertino, California
“Mülakatta bir graf problemi çözdüm. Bunu bilmesem bu teklifi alamazdım.”
Hikaye 2: 35 Yaşında Kariyer Değişimi
Maria, 35 yaşında “Muhasebeci → Manuel QA → SDET”
Yolculuk:
- 8 hafta yoğun çalışma (günde 2 saat)
- 80 LeetCode problemi (sadece Easy/Medium)
- Startup’tan teklif
Sonuç:
- Maaş: $65K → $110K
- Uzaktan çalışma
- Daha ilginç işler
“Algoritmalar korkutucu göründü ama küçük adımlar attım.”
💡 Önemli Noktalar
- ✓ Veri yapıları sadece geliştiriciler için değil - QA’da her gün kullanılır
- ✓ JavaScript + Algoritmalar = SDET’in harika kombinasyonu
- ✓ Teoriyle başlama - pratik örneklerle başla
- ✓ Günde 30 dakika tutarlılık, hiç olmayan yoğun çalışmadan daha iyidir
- ✓ LeetCode ezberleme değildir - desenleri anla
- ✓ Algoritmaları bilmek maaşında $50K-$100K fark yaratabilir
📍 Sırada Ne Var?
Sonraki makalede İleri Otomasyon Çerçeveleri:
- Playwright derinlemesine (Apple gereksinimi!)
- Selenium ileri desenleri
- Karate API testleri
- Ölçeklenebilir çerçeveler
- CI/CD entegrasyonu
Sonraki Makale: Makale 4: Otomasyon Çerçeveleri
🎁 Bonus: Zaman Karmaşıklığı
Zaman karmaşıklığını anlamak hızlı testler yazmanı ve kod incelemesinde yavaş kodu görmeni sağlar.
// O(1) - Sabit Zaman: Boyuttan bağımsız
const getFirst = (arr) => arr[0]; // ✅ Hep hızlı
// O(log n) - Logaritmik: İkili arama
// Çok verimli!
function binarySearch(arr, target) {
let left = 0, right = arr.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
if (arr[mid] === target) return mid;
else if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1; // ✅ Milyonlar arasında saniyeler
}
// O(n) - Doğrusal: Her öğeyi bir kez kontrol et
const findMax = (arr) => Math.max(...arr); // ✅ İyi
// O(n log n) - Linearitmik: İyi sıralama
const sorted = arr.sort((a, b) => a - b); // ✅ Kabul edilebilir
// O(n²) - Kuadratik: İç içe döngüler = YAVAS!
function bubbleSort(arr) {
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
return arr; // ❌ Büyük veri için kaçın
}
// Alan Karmaşıklığı
// O(1) - Yeni yapı oluşturma (en iyi)
// O(n) - n boyutunda dizi (kabul edilebilir)
// O(n²) - 2D dizi (dikkat!)
Bu makale yardımcı oldu mu? 👏
Sorularınız var mı? Yorum yazın!