
Sat Aug 22 2026

Hadi kabul edelim: legacy kod kelimesini duymak bile bazen kan basıncımızı yükseltir 😅. O "kim yazmış bu kodu?" anı, her geliştiricinin en az bir kez yaşadığı bir kabustur. Ben de geçen ay, 10 yıl önce yazılmış, dokümantasyonu yok, testleri hiç olmayan, ama kritik bir ödeme modülünü incelemek zorunda kaldım. Saatlerce grep ve find komutlarıyla boğuştum, yorum satırları bile Türkçe-İngilizce karışık yazılmıştı. Sonunda kafam karıştı, kahve molası verdim ve "Ya buna bir AI asistan olsaydı..." diye düşündüm.
İşte tam o noktada AI ajanları (AI agents) devreye giriyor. Onlar sihirli bir çözüm değil, ama çok güçlü bir asistan olabiliyorlar 🛠.
AI ajanları, sadece kod önermekle kalmıyor; bağlamı anlıyor, dosyalar arası ilişkileri kuruyor ve hatta test senaryoları üretiyor. Düşünün ki:
callback hell'den async/await'e).O ödeme modülünde, AI ajanına "Bu processPayment fonksiyonundaki hata yönetimini anlat" dedim. 3 saniyede bana şunu verdi:
null kart numarasıydı 😱)Sonuç? 2 saatte yapacağım incelemeyi 15 dakikada bitirdim. Ve evet, o null kart numarası bug'ı production'a gitmeden yakaladık ✅.
git blame çekip, o kişinin LinkedIn'ini aradınız mı?Eğer "Evet" dedinyseniz, bu seride doğru yerdesiniz. Gelecek bölümlerde, AI ajanlarını nasıl kuracağımızı, hangi araçları kullanacağımızı ve legacy kod tabanını nasıl "anlayacak" hale getireceğimizi adım adım göreceğiz.
Hazırsan başlayalım 🚀
Hazırsan başlayalım 🎯
Sadece bir prompt yazıp “bunu yap” demek, günlük işlerde sık sık şu çileleri doğurur:
Bağlam eksikliği ❗️
Hallüsinasyon riski 🔁
Dosya / token limitleri 🛠
Tekrar eden iş akışı ⛔
Test edilebilirlik yok ✅
Ne hissediyorsun?
Bu çileler gerçek ve herkesin yaşadığı bir durum.
İşte bu nedenle prompt’un ötesinde bir yapıya — bağlam yönetimi, dosya parçalama, doğrulama adımları — ihtiyacımız var.
Hadi bir sonraki bölümde bu yapıyı nasıl kuracağımızı birlikte keşfedelim 🚀
Statik analiz, kodu çalıştırmadan inceleyip yapısal bilgiler çıkarma sanatıdır 🎯. Derleyici hatalarını yakalamak için değil, büyük picture'ı görmek için kullanırız: hangi dosya nereye bağlı, fonksiyonlar nasıl çağrılıyor, sınıf hiyerarşisi nasıl?
Legacy projelerde dokümantasyon yoksa, statik analiz ilk haritanız olur 🗺️.
| Araç | Ne İşe Yarar? | Legacy'de Ne Zaman? |
|---|---|---|
| ctags | Hızlı sembol (fonksiyon, sınıf, değişken) indeksi üretir | İlk keşif, editörlerde "go to definition" |
| tree-sitter | Artımlı, hata tolérant parse ağaçları verir | Dil bağımsız AST çıkarmak, kendi scriptlerinizde |
| CodeQL | Sorgu diliyle derin semantik analiz (güvenlik, bug pattern) | Güvenlik auditleri, kod kalitesi kuralları |
| SonarQube | Merkezi dashboard, teknik borç metrikleri, quality gate | Süreç içi izleme, CI/CD entegrasyonu |
Benim tavsiyem: Önce ctags ile 5 dakikada bir "fonksiyon envanteri" çıkarın. Sonra ihtiyaca göre CodeQL/tree-sitter'a geçin 🚀.
Hazırsanız terminali açın, proje kök dizinine gidin. Örnek bir Java/Python karışık repo olduğunu varsayalım.
find . -name '*.java' -o -name '*.py' | xargs ctags -R --fields=+n --extras=+f
Ne oluyor burada?
find → .java ve .py dosyalarını bulur (recursive)xargs → bulduğu dosyaları ctags'e besler-R → recursive (alt dizinler de)--fields=+n → satır numarası ekler--extras=+f → dosya adı bilgisini de koyarÇıktı: kök dizinde tags dosyası oluşur. Bu, editörünüz (Vim, VS Code, IDEA) için navigasyon haritasıdır ✅.
ctags -x --c-kinds=f
Çıktı örneği:
main 10 src/Main.java public static void main(String[] args)
calculateTotal 42 src/OrderService.java double calculateTotal(Order o)
processPayment 18 src/Payment.py def process_payment(amount):
Ne kazandık?
method, Python def) tek seferde gördükgrep/awk ile filtreleyip "God class" adaylarını, çok uzun fonksiyonları, test edilmeyen modülleri tespit edebiliriz 🔍ctags varsayılan olarak C/C++ odaklıdır. Java/Python için Exuberant Ctags veya Universal Ctags kurulu olmalı:
# macOS
brew install universal-ctags
# Ubuntu/Debian
apt-get install universal-ctags
Eski exuberant-ctags paketleri Python 3 desteği zayıf olabilir ⚠️.
Bu "ham harita"yı aldıktan sonra:
codeql database create → sorgular yazıp güvenlik açığı/anti-pattern aratree-sitter parse → AST JSON elde edip kendi analiz scriptinizi yazınAma hepsi bu ilk tags dosyasından başlar. Şimdi siz deneyin, tags dosyasını açın, keşfetmeye başlayın 🧭.
Statik analiz bitti, modül ve sınıf bağımlılıklarını görmek istiyorsun.
İşte hızlıca bir yönlü graf (directed graph) çıkarmak için kullanabileceğin iki popüler kütüphane: networkx + pydeps.
pydeps Python kodunu tarayıp import ilişkilerini toplar.networkx ise bu ilişkileri DiGraph nesnesine doldurur; sonra istediğin formatta (GraphML, GEXF, DOT…) kaydedebilirsin.graphviz (DOT → PNG/SVG) veya matplotlib (hızlı bir bakış) yeterli.pydeps’e ver.networkx.DiGraph() ile boş bir yönlü graf oluştur.pydeps.pydeps(..., graph=G) çağrısıyla grafı doldur.import networkx as nx
import pydeps
# 1️⃣ Boş yönlü graf
G = nx.DiGraph()
# 2️⃣ Pydeps ile bağımlılıkları topla ve grafı doldur
pydeps.pydeps('my_project', show_deps=True, graph=G)
# 3️⃣ GraphML olarak kaydet (Graphviz, Gephi, Cytoscape… hepsi okur)
nx.write_graphml(G, 'dependency_graph.graphml')
dependency_graph.graphml dosyası tüm modül/sınıf düğümleri ve import kenarlarını içerir.graphviz ile render edersen (dot -Tpng dependency_graph.graphml -o deps.png) temiz bir PNG elde edersin.matplotlib ile hızlıca nx.draw(G, with_labels=True) deyip plt.show() dersen interaktif bir pencere açarsın.pydeps parametreleri (--max-bacon, --show-deps vb.) ile filtreleme yap, sonra networkx’te nx.subgraph alarak sadece ilgilendiğin paketi çiz.nx.write_dot(G, 'deps.dot') dersen Graphviz doğrudan işler.Hazırsan bir sonraki adımda bu grafı CI/CD içine entegre edip her commit’te otomatik grafik çıkartabilirsin 🚀
Statik analiz kodunuzu derleme zamanında tarar, ama çalışma anında ne olduğunu görmez.
Özellikle mikro servisler, async mesaj kuyrukları ya da legacy monolitlerde hangi servis ne kadar bekliyor, hata nerede patlıyor gibi sorulara cevap vermek için runtime tracing şart 🎯.
| Araç | Ne Sağlar? | Neden Tercih Edilir? |
|---|---|---|
| OpenTelemetry | Vendor‑agnostic API & SDK, otomatik enstrümantasyon | Tek kod bazında birden fazla backend (Jaeger, Zipkin, Tempo…) destekler |
| Jaeger | Dağıtık trace UI, servis haritası, root‑cause analizi | Kubernetes entegrasyonu güçlü, CNCF graduated |
| Zipkin | Basit kurulum, düşük kaynak tüketimi | Hızlı PoC’ler için ideal |
Kısaca: Kodunuza bir kez OpenTelemetry ekleyin, sonradan backend’i değiştirmek sadece config meselesi ✅.
wget https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jarjava -javaagent:opentelemetry-javaagent.jar \
-Dotel.traces.exporter=logging \
-Dotel.service.name=legacy-monolit \
-jar legacy-app.jar
-Dotel.traces.exporter=logging → trace’leri stdout’a basar (geliştirme için yeterli).-Dotel.traces.exporter=otlp + collector adresi verip Jaeger/Zipkin’e yönlendirirsiniz.opentelemetry-instrument Wrapperpip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install
opentelemetry-instrument \
--traces_exporter console \
--metrics_exporter console \
--service_name python-monolit \
python app.py
Ne oluyor? Wrapper,
requests,flask,sqlalchemygibi popüler kütüphaneleri kod değiştirmeden otomatik sarar (auto‑instrumentation) 🔁.
Aşağıda tek bir HTTP isteği için üretilen span hiyerarşisi görüyorsunuz (console exporter çıktısı kısaltılmış):
Span(name="GET /orders", trace_id=abc123, span_id=def456, parent=None)
├─ Span(name="DB SELECT orders", span_id=ghi789, latency=12ms, status=OK)
├─ Span(name="HTTP CALL payment-service", span_id=jkl012, latency=45ms, status=OK)
│ └─ Span(name="payment-service /charge", span_id=mno345, latency=30ms, status=OK)
└─ Span(name="Cache GET user:42", span_id=pqr678, latency=3ms, status=OK)
Yakalanan temel veriler 📦:
| Alan | Açıklama |
|---|---|
| trace_id | Tüm servisleri bağlayan benzersiz kimlik |
| span_id | Her iş birimi (DB call, HTTP call, cache) için unique id |
| parent_span_id | Hangi span’ın child olduğunu gösterir → servis haritası oluşur |
| latency | İşlem süresi (ms) – bottleneck tespiti için kritik |
| status / error | OK / ERROR + exception stack trace (varsa) |
| attributes | http.method, db.statement, messaging.destination gibi semantik etiketler |
Bu veriler sayesinde:
%100 trace prod’da maliyetli → TraceIdRatioBased(0.1) gibi oranlı sampling ayarlayın.service.name, deployment.environment, k8s.pod.name ekleyin → Jaeger’de filtreleme kolaylaşır.otlp + OpenTelemetry Collector → tek noktadan çoklu backend (Jaeger, Tempo, Prometheus) besleyin.opentelemetry-instrument wrapper kod değiştirmeden başlarsınız.trace_id, span_id, latency, status, attributes → bottleneck ve hata kök nedeni anında görünür.Hazırsanız bir sonraki adımda trace verilerini nasıl görselleştirip alarm kuracağımızı (Jaeger UI, Grafana Tempo, alerting) anlatabiliriz 🚀.
Hazırsan başlayalım 🎯
Önceki adımlarda elde ettiğimiz statik analiz çıktılarını (tag dosyası, bağımlılık grafiği) ve tracing verilerini bir AI ajanı üzerinden sorgulamak, mimari keşfi dakikalar içinde özetlemek için harika bir yöntem.
LangChain + LLM kombinasyonu ile bunu bir prompt şablonu ve birkaç satır Python koduyla halledebiliriz.
Sen bir yazılım mimarisin. Aşağıdaki verilerle:
1. Bağımlılık grafiği özeti: {graph_summary}
2. İzleme (trace) özeti: {trace_summary}
Görevlerin:
- Her modülün sorumluluklarını madde madde yaz.
- En kritik yolu (en uzun gecikme zinciri) belirle ve neden kritik olduğunu açıkla.
- İyileştirme önerileri sun.
Cevabı Türkçe, kısa ve net tut.
from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
# Prompt şablonunu tanımla
prompt = PromptTemplate(
input_variables=["graph_summary", "trace_summary"],
template="""
Sen bir yazılım mimarisin. Aşağıdaki verilerle:
1. Bağımlılık grafiği özeti: {graph_summary}
2. İzleme (trace) özeti: {trace_summary}
Görevlerin:
- Her modülün sorumluluklarını madde madde yaz.
- En kritik yolu (en uzun gecikme zinciri) belirle ve neden kritik olduğunu açıkla.
- İyileştirme önerileri sun.
Cevabı Türkçe, kısa ve net tut.
"""
)
# LLM zincirini kur
chain = LLMChain(
llm=OpenAI(temperature=0), # deterministik cevap için sıfır sıcaklık
prompt=prompt
)
# Örnek girdiler (gerçek verilerle değiştirilecek)
graph_txt = "Modül A -> Modül B -> Modül C; Modül D bağımsız."
trace_txt = "Request: A(12ms) → B(45ms) → C(30ms); Toplam 87ms."
# Ajanı çalıştır
result = chain.run(graph_summary=graph_txt, trace_summary=trace_txt)
print(result)
temperature=0 ile tutarlı, tekrarlanabilir cevaplar alıyoruz.networkx veya pydeps çıktısını metne dönüştür.Artık elinizde otomasyonlu bir mimari asistan var. Bir sonraki adımda bu çıktıyı nasıl bir dashboard veya CI/CD adımına entegre edebileceğimize bakalım 🚀
AI ajanı bize üç değerli arteakt verdi:
Bu verileri refactoring yol haritasına (roadmap) nasıl çeviririz? Hadi adım adım bakalım 👇
| Kriter | Ne anlama gelir? | Nasıl skorlanır? |
|---|---|---|
| Risk 🚨 | Değişiklik bozulursa ne kadar zarar verir? | Yüksek (kritik iş akışı), Orta, Düşük |
| Etki 🎯 | Kullanıcı/performans/maliyet üzerindeki etki | Büyük, Orta, Küçük |
| Çaba 🛠 | Geliştirme + test süresi | Büyük (>2 hafta), Orta (1‑2 hafta), Küçük (<1 hafta) |
Basit formül: Öncelik = (Risk × Etki) / Çaba
Yüksek skorlu öğeler ilk sprinte girer 🚀
Bu sayede büyük bang riski ortadan kalkar, her adım geri alınabilir olur ⛔️➡️✅
| Sprint | Odak | Teslim Edilecek |
|---|---|---|
| 1 | Yüksek riskli, yüksek etki, düşük çaba | Auth servisini yeni token yapısına taşı |
| 2 | Orta risk, büyük etki | Order‑service → async messaging (Kafka) |
| 3 | Düşük risk, küçük çaba | Logging formatını merkezi log’a uyarlama |
Her sprint sonunda:
Özetle: AI’nın verdiği haritaları sayısal öncelik matrisine dök, Strangler Fig ile ince ince geçiş yap, test + contract + tracing üçlüsüyle her adımı doğrula. Böylece refactoring kontrollü, geri alınabilir ve ölçülebilir bir sürece dönüşür 🎉
Legacy kod üzerinde her değişiklik bir risk taşır.
Bu riski minimize etmek için CI/CD pipeline’ımıza üç basit ama güçlü adım ekleyebiliriz 🚀
Aşağıdaki workflow dosyası her push/pull‑request’te otomatik çalışır.
Kod bloğunu kopyala, .github/workflows/ci.yml içine yapıştır ve run_static_analysis.sh ile generate_graph.py scriptlerini repo’nuna ekle.
name: CI – Legacy Guard
on:
push:
branches: [ main, develop ]
pull_request:
jobs:
legacy-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Static Analysis
run: ./run_static_analysis.sh
- name: Dependency Graph
run: python generate_graph.py
- name: Upload Graph Artifact
uses: actions/upload-artifact@v3
with:
name: dependency-graph
path: graph_output/
Ne yaptık?
actions/checkout@v3 → Repo’yu runner’a çeker.Static Analysis → Özel scriptin (ör. SonarQube, ESLint, bandit) çalıştırır.Dependency Graph → Python scripti bağımlılık grafiğini üretir (Graphviz, Mermaid vb.).Upload Graph → Oluşan grafiği artifact olarak kaydeder; PR incelemesinde görselleştirme için hazır olur.GitLab’de de aynı mantık geçerli. .gitlab-ci.yml içine script: blokları ekleyip artifacts: ile grafiği yükleyebilirsin. Temel yapı aynı: checkout → analyze → graph → artifact.
Küçük bir yatırım, büyük bir rahatlık.
Bu alışkanlıkları ekibe yay, gelecekteki kendine minnettar olacak ✅
Bu içerik tamamen yapay zeka destekli otomasyon sistemi ile üretilmiştir.
All rights reserved