
Thu Sep 03 2026

Merhaba! ☕ Kahven hazır mı? Hadi oturalım, biraz sohbet edelim.
Yazılım mühendisliği sadece kod yazmak değil. Aslında karmaşıklıkla dans etmek. Her satır yazdığımız kod, sistemimize bir miktar daha karmaşıklık katıyor. Ve bu karmaşıklık yönetilmezse... biliyorsunuz ne oluyor 😅
Günümüzde Copilot, Cursor, ChatGPT gibi araçlar kod yazıyor. Harika! Ama...
Hazırsan başlayalım! 🚀
Hazırsan başlayalım 🚀.
Her ikisi de prototip yazıp atıp tekrar yazmak yerine, önceden planlama ve basitlik avantajlarını vurgular. Bugün ML modelleri ve mikro servislerle dolu dünyada bu prensipler hâlâ yol haritamız olabilir.
| İddia | Ne Anlama Gelir? |
|---|---|
| İletişim maliyeti | Ekip büyüdükçe iletişim kanalları O(n²) artar. |
| Ekleme yasası | Yeni kişi eklemek projeyi geciktirir (eğitim, entegrasyon). |
| İkinci sistem etkisi | İlk sistem basit, ikincisi aşırı mühendislik yapar. |
Özetle: Prototip yapıp "sonra düzelteriz" derseniz, karmaşıklık patlar ve teslim tarihi kayar.
"Yavaş giden, sabit giden, en sona kadar gider." – John Ousterhout
# ❌ Kötü: Hızlı prototip, sonra büyüyen "spagetti" kod
def train_and_deploy(data):
model = train(data)
save(model)
deploy(model) # hata yönetimi, loglama, monitoring yok
# ✅ İyi: Ousterhout tarzı, modüler ve tahmin edilebilir
def train(data):
return _train_model(data)
def validate(model, test_set):
return _evaluate(model, test_set)
def deploy(model):
_push_to_registry(model)
_update_serving_infra()
Bu sayede ne oluyor?
train() fonksiyonu, hyperparametreler config dosyasında.Böylece "deney açısından hızlı" (notebook denemeleri) üretimde "verimli" hale gelir.
Brooks ve Ousterhout, yıllar önce yazmış olsalar da, modern yazılım mühendisliğinde (MLOps, mikro servisler, serverless) hâlâ reçete niteliğinde.
Kısaca: Hızlı yaz, yavaş planla demek değil; planla, basit yaz, güvenle teslim et demek.
Bir sonraki bölümde bu prensipleri CI/CD ve otomasyon ile nasıl birleştireceğimize bakalım. 🚀
Yazılım geliştirirken “Bunu nasıl yazarım?” diye düşündüğümüz anlar hepimizde olur. İşte tam o anda GitHub Copilot, Cursor ve hatta Devin gibi araçlar devreye giriyor 🚀.
Bir gün “Python’da faktöriyel hesaplayan bir fonksiyon yaz” dedim. Copilot bana şu kodu sundu:
def calculate_factorial(n: int) -> int:
"""
Faktöriyel hesaplar.
Negatif girdilerde hata fırlatır.
"""
# Girdi kontrolü
if n < 0:
raise ValueError("Negatif sayılar için faktöriyel tanımlı değildir.")
# Sonuç değişkeni
result = 1
# Döngü ile çarpım
for i in range(2, n + 1):
result *= i # Her adımda sonucu güncelle
# Sonucu döndür
return result
Ne oluyor burada?
int) ve docstring ile fonksiyonun ne yaptığı açık.result) kullanımı, basit bir işlem için biraz “aşırı mühendislik” hissi veriyor.Küçük ipucu: Kodunuzu gözden geçirirken “Bu gerçekten gerekli mi?” diye sorun. AI size başlangıç noktası verir, son halini siz verirsiz 🛠.
Cursor, VS Code tabanlı bir editör ama AI sohbet paneli doğrada kodunuzun yanında duruyor.
functools.lru_cache ekleyerek memoization öneriyor.Avantajı: Kodunuzla aynı pencerede konuşuyorsunuz, context switching yok 🎯.
Devin henüz erken erişimde ama tam bir projeyi (repo oluşturma, CI/CD, testler, dokümantasyon) baştan sona yönetebiliyor.
| Araç | Ne Sağlıyor? | Nerede Parlak? |
|---|---|---|
| Copilot | Satır bazlı kod tamamlama | Hızlı prototip, boilerplate |
| Cursor | Editör içi sohbet + çoklu dosya düzenleme | Refactoring, test yazımı |
| Devin | Proje yaşam döngüsünü yöneten ajan | End‑to‑end otomasyon, ekip gibi davranma |
Son söz: AI araçları yardımcı pilot değil, yardımcı mühendis olmaya başlıyor. Onları nasıl sorgularız ve çıktılarını nasıl filtreleriz biliyorsak, kodlama hızımız katlanarak artıyor 🚀.
Hadi şimdi kendi editörünüzde bir deneme yapın: “Basit bir Fibonacci fonksiyonu yaz” deyin ve gelen kodu kendiniz iyileştirin. Göreceksiniz, AI size başlangıç noktasını verir, mükemmel kodu siz yazarsınız ✨.
Hadi pratik bir örnek üzerinden anlayalım.
Çoğu zahmetli işlemi yapay zeka üstlendiğinde, sen artık yüksek seviyeli yönergeler vererek karmaşıklığı denetlemelisin.
# Basit bir yapay zeka yönlendirme snippet'i
guidance = {
"goal": "Kullanıcıları minimum hizmetle buluştur",
"constraints": [
"En fazla 2 hata durumunda başarısız olmalı",
"Artık mevcut verileri kullan"
],
"tools": [
{"name": "Docker", "purpose": "İzolasyon"},
{"name": "Kubernetes", "purpose": "Dağıtım"},
{"name": "OpenAI API", "purpose": "Akıllı süzme"}
]
}
Ne oluyor? ➜ Bu yapı, yapay zeka modeline net bir yol gösteriyor: ne hedeflediğini, nasıl gerçekleştireceğini ve güvenlik kurallarını öğretiyor.
“Üst düzey özerklik, seni sadece bir tekniker olmaktan çıkarıyor; sen, geleceği kurgulayan bir mimar haline geliyorsun.” – AI ile birlikte çalışmanın yeni bir gerçekliği.
Hazırsan başlayalım 🚀
Vibe coding — yani “kodun hissettirdiği iyi hisle yazıp, detayları AI’a bırakmak” — başlangıçta çok cazip görünebilir. Ama dikkat: bu rahatlık, kırıntı kırıntı teknik borç biriktirmeye yol açar. İşte gerçek bir senaryo üzerinden neden sadece AI’ya güvenmenin sizi geride bırakabileceğini görelim.
AI bize şu kodu üretti (ilk versiyon):
+// GET /users
+app.get('/users', async (req, res) => {
+ const users = await User.findAll();
+ res.json(users);
+});
Ne oluyor burada?
+// GET /users
+app.get('/users', async (req, res) => {
+ const users = await User.findAll();
+ // 🎉 AI'nın "güzel" eklemeleri başlıyor
+ const enriched = users.map(u => ({ ...u.toJSON(), fullName: `${u.firstName} ${u.lastName}` }));
+ // loglama için gereksiz bir middleware çağrısı
+ await logService.info('users fetched', { count: enriched.length });
+ // gereksiz bir cache yazması (hiç invalidasyon yok)
+ await cache.set('all_users', enriched, { ttl: 0 });
+ res.json(enriched);
+});
Ne değişti?
fullName hesaplaması her istekte tekrar yapılıyor → performans düşüşü.logService.info her çağrıda async bekliyor → latency artıyor.cache.set TTL sıfır → cache asla temizlenmiyor, bellek sızıntısı riski ⛔.Bu satırlar ilk bakışta “özellik zenginliği” hissi veriyor 🎁, ama production’da şunları getiriyor:
no-unused-vars, no-async-promise-executor).Özet: Vibe coding başlangıçta hız kazandırır 🎯, ama kontrolsüz AI katkıları teknik borcun gizli birikimine dönüşür. Her diff’i insan gözüyle okuyun, “Bu satır gerçekten gerekli mi?” diye sorun. Böylece geliştiriciyi yağmacılığa çalıştıran bu tuzakten kurtulursunuz 🚩.
Hey, hazırsan başlayalım! 🧭 Her gün AI'ya kodumuzu devretmeden önce kontrol etmek istediğimiz birkaç pratik adım var. Uygulayarak yüksek seviyeli düşünmeyi pekiştirebilir, gereksiz detaylardan kurtulabilir ve temiz kod prensiplerine bağlı kalabiliriz.
# Özet
Veri işleme hizmeti, temizlenmiş CSV dosyalarını okumalı, her satırdaki contacts alanını telefon numaralarına ayrıştırmalı ve validasyon sonrası JSON olarak dışa aktarmalıdır.
# Yapısal özet
class DataProcessor {
readCsv() -> List<RawRow>
parseContacts(rawRow) -> List<Phone>
validatePhone(phone) -> boolean
exportJson(parsedData) -> void
}
Aşağıdaki kalıbı kopyalayıp yapıştır ve ihtiyacına göre ayarla:
Lütfen yüksek seviyeli soyutlama gerektiren, temiz ve modüler bir hizmet API'si oluştur, teknik bir açıklama sağlay ve tüm yanlışlıkla oluşan açıklamaları kaldır.
Hızlı ip: Tekrar eden bir desen fark ederseniz, bunu yeniden kullanılabilir bir yardımcı fonksiyon veya bir servis katmanı olarak oluşturabilirsiniz. 🎉
Şimdi bu alıştırmayı uyguladıkça, AI'nin daha az detay ve daha fazla anlam ile çalıştığını göreceksiniz. İsteklerimiz netleşecek, kodumuz daha modüler hale gelecek ve soyutlama becerimiz gelişecek. İyi kodlamalar! 🚀
Eski zamanlarda "soyutlama" derken kod tekrarını azaltmak, interface'ler çıkarmak veya clean code yazmak akla gelirdi. Ama 2024'te? O oyun değişti 🔄
Yeni işe başlayan bir geliştiriciye bugün ne öğretiriz? Syntax mı? Framework'ün API'si mi? Hayır. Onlar zaten 30 saniyede Copilot'tan alırlar. Öğretmemiz gereken: sorunu nasıl çarparak, AI'ya doğru talimatı nasıl veririz?
İşte soyutlama becerisinin yeni dünyadaki rolü:
# Junior: "Şu butona tıklandığında API çağrısı yap" der
# Senior: "Kullanıcı sepetine ürün eklemek istiyor,
# bu durum state'i günceller ve backend'e senkronize eder" der
Fark gördün mü? Birincisi implementation detail, ikincisi business intent. AI'ya ikincisini anlatırsan, doğru kodu üretir. Birincisini anlatırsan, senin yerinde kod yazar — ama sen mantığı kavramamış olursun.
| Seviye | Ne İşe Yarar? | Yeni İki İçin Neden Kritikal? |
|---|---|---|
| Domain | İş kuralını koddan ayırır | AI'ya "ne yapmalı" anlatırken domain dili kullanırsın |
| Architecture | Modüller arası sözleşme kurar | AI'nın ürettiği kodun sisteme sığdırılması |
| Implementation | Detayları gizler | Değişen detaylar AI'ya bırakılır, sen strateji yaparsın |
Bir yeni ekip arkadaşına şunu deneyin:
"Bu fonksiyonu yaz" demek yerine: "Bu kullanıcı hikayesini karşılamak için hangi domain kavramları devreye giriyor? Onları modelleyelim."
Sonra birlikte:
Bunları yaptıktan sonra AI'ya: "Bu interface'i implement eden servis sınıfını yaz, transaction management ekle" dersiniz.
Bu pasif onay değil, aktif yönlendirme. Soyutlama becerisi, senin mimar olmanı sağlar; AI ise inşaatçı. Mimar inşaatçıya "duvarı buraya çek" der, "tuğlayı nasıl yerleştireceğini" anlatmaz — ama duvarın nereye gideceğini bilir.
Özetle: Soyutlama artık kod organizasyonu aracı değil, düşünce organizasyonu aracı. Yeni ikiye "şu kodu yaz" demek yerine "bu problemi şu seviyede çöz, detayları sen hallet" diyebilmek için en güçlü silahın bu 🎯
Technical debt, bir süredir hepimizin üzerinde ilaç gibi etki eden gizli bir sorun. Yalnızca yapay zekaya güvenmek, sizin yerinize bunun farkına varmasını bekleyemez. Kontrol etmekle kalmayıp, araçları, commit grafiklerini ve CI/CD süreçlerini kullanarak sürekli izlemeyi öğrenmeliyiz — böylece borç, bir gün kazıntıya dönüşmeden önce ortaya çıkar 🎯.
Aşağıdaki shell komutu, son 10 commit’arası değişen dosyaları alır ve shellcheck ile basit bir statik analiz yapar. İsterseniz sonar-scanner da ekleyebilirsiniz.
# Son 10 commit'te değişen .sh dosyalarını listele
git diff --name-only HEAD~10..HEAD -- '*.sh' | while read file; do
echo "🔎 Analiz ediliyor: $file"
shellcheck "$file"
done
Ne oluyor burada?
git diff --name-only HEAD~10..HEAD -- '*.sh' → Son 10 commit’te değiştirilen shell script dosyalarını getirir.while read file; do … done → Her dosya için döngüye girer.shellcheck "$file" → Kodda olası hataları, kullanılmayan değişkenleri ve stil ihlallerini raporlar.shellcheck sıfır dışı çıkış kodu verirse pipeline’ı fail edin → PR merge edilmez.sonar-scanner ile daha derin metrikler (cognitive complexity, duplication) toplayın ve Quality Gate tanımlayın.# .github/workflows/tech-debt.yml (örnek)
name: Technical Debt Check
on: [pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 11 # son 10 commit + HEAD
- name: Run shellcheck on changed scripts
run: |
git diff --name-only HEAD~10..HEAD -- '*.sh' | while read f; do
shellcheck "$f"
done
Hazırsan başlayalım! 🚀
Aynı ürün listeleme uç noktasını iki farklı yöntemle yazdık: biri satır satır elle, diğeri ise yapay zeka (AI) ile üretilmiş. Farkları yan yana görelim.
Neden bu şekilde?
# app.py – Manuel yazılmış Flask API
from flask import Flask, jsonify
app = Flask(__name__) # 🎯 Uygulama örneği
# 📦 Örnek veri – Gerçek projede veritabanından gelir
URUNLER = [
{"id": 1, "ad": "Laptop", "fiyat": 15000},
{"id": 2, "ad": "Telefon", "fiyat": 8000},
{"id": 3, "ad": "Kulaklık", "fiyat": 500},
]
@app.route("/api/urunler", methods=["GET"])
def urunleri_listele():
"""
GET /api/urunler → Tüm ürünleri JSON olarak döner.
"""
return jsonify(URUNLER), 200 # ✅ Başarılı yanıt
if __name__ == "__main__":
app.run(debug=True) # 🛠 Geliştirme modunda çalıştır
Ne oldu?
jsonify ve HTTP durum kodu açıkça belirtildi.Prompt (bizim girdimiz):
“Flask ile
/api/urunlerGET endpoint’i yaz. Veriyi bir listeden al, JSON dön. Type hint ekle, docstring yaz.”
AI’nın çıktısı:
# ai_generated.py – AI tarafından üretilen Flask API
from typing import List, Dict
from flask import Flask, Response, json
app = Flask(__name__)
# 📦 Veri katmanı – soyutlanmış
def urunleri_getir() -> List[Dict[str, object]]:
"""Ürün listesini döndürür (örnek veri)."""
return [
{"id": 1, "ad": "Laptop", "fiyat": 15000},
{"id": 2, "ad": "Telefon", "fiyat": 8000},
{"id": 3, "ad": "Kulaklık", "fiyat": 500},
]
@app.route("/api/urunler", methods=["GET"])
def urunleri_listele() -> Response:
"""
GET /api/urunler
Returns:
Response: JSON array of products with 200 OK.
"""
veri = urunleri_getir()
return Response(
json.dumps(veri, ensure_ascii=False),
mimetype="application/json",
status=200,
)
if __name__ == "__main__":
app.run(debug=True)
Ne değişti?
List[Dict[...]]) ve Response dönüş tipi eklendi.urunleri_getir() fonksiyonuna taşındı → tek sorumluluk.jsonify yerine Response + json.dumps kullanıldı → daha kontrollü serialization.| Adım | Sen (Geliştirici) | AI (Model) |
|---|---|---|
| 1. İstek | “Flask GET endpoint, type hint, docstring.” | Prompt’u parse eder, bağlamı anlar. |
| 2. Tasarım | Elle karar verir: jsonify mi, Response mu? |
En yaygın best‑practice kalıbını (type hint + Response) seçer. |
| 3. Kod Üretimi | Satır satır yazar, test eder. | Tek seferde tam dosya üretir, böylece hız kazanır. |
| 4. Doğrulama | pytest ile test yazarsın. |
Kodun syntax hatasız olduğunu varsayar; mantık testi senin görevin. |
| 5. Refactor | Gerekirse urunleri_getir servis katmanına taşırsın. |
Zaten fonksiyon olarak ayırmış; sen sadece taşıma yaparsın. |
Özet:
ensure_ascii=False) olabilir; production’a almadan önce code review şart! ⛔Sonuç:
Her iki yöntemin de yer var. Önemli olan kodun sahibi olman ve üretimden önce gözden geçirmen. 🛠✨
Hazırsan başlayalım 🎯.
Bir süre yoğun kod yazdıktan sonra kontrol listesi ile yolumuza devam edelim. Bu liste, yapay zekayı sadece bir araç değil, ortağın gibi kullanmanı sağlar ve karmaşıklığı devralmana yardımcı olur.
Aşağıdaki dosyayı projenin kök dizinine .github/workflows/next-steps.yml olarak ekleyebilirsin.
Bu pipeline, git init → statik analiz → refactor → test → commit sırasını otomatikleştirir.
name: Next Steps Pipeline
on:
push:
branches: [ main ]
workflow_dispatch: # manuel tetikleme için
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 📦 Git deposu oluştur
run: git init
- name: 🔍 Statik kod analizi
run: |
# örnek: ESLint, SonarQube vb.
./run-static-analysis.sh
- name: ♻️ Refactor
run: |
# otomatik refactor scriptin varsa
./refactor.sh
- name: ✅ Testleri çalıştır
run: |
./run-tests.sh
- name: 📝 Değişiklikleri commit et
run: |
git add .
git commit -m "chore: automate pipeline steps"
git push
Ne oluyor burada?
git init ile yerel depo hazırlanır.Bu yapıyı projenize göre genişletebilirsin (örneğin Docker build, deploy adımları ekleyerek).
Küçük, tekrarlanabilir adımlar = büyük, sürdürülebilir başarı 🚀.
Her araç gibi yapay zeka da bir vasıtadır — onu nasıl kullanırsanız öyle şekillenir.
Unutmayın, en değerli beceriniz şudur:
Bu yolculukta sürekli öğrenme asıl anahtardır.
Her yeni model, her yeni kütüphane size bir fırsat sunar; onları deneyin, sorgulayın, uyarlayın.
Küçük bir hatırlatma:
- Kod yazarken “neden?” sorusunu unutmayın.
- AI önerilerini kritik gözle inceleyin.
- Kendi mimarî kararlarınızı koruyun; AI sadece bir yardımcıdır, patron sizsiniz.
📚 Devam edin, meraklı kalın, yapın.
Başarılar dilerim! ✨
Bu içerik tamamen yapay zeka destekli otomasyon sistemi ile üretilmiştir.
All rights reserved