AI verimliliğini ölçmek: 'daha hızlıyız' hissini sayıya dökmek

Ekip daha hızlı olduğunu söylüyor, bütçe sahibi sayı istiyor, vendor paneli acceptance rate gösteriyor. Hangi metriklerin yanılttığını, hangilerinin dayandığını, veriyi kendi Git host'unuzdan nasıl çekeceğinizi ve yönetime abartmadan nasıl raporlayacağınızı anlatıyoruz.

Lisans yenileme dönemi geldiğinde toplantıda iki cümle karşı karşıya gelir. Ekip "çok daha hızlıyız" der, bütçeyi imzalayan kişi "ne kadar" diye sorar. Arada genellikle vendor panelinden alınmış bir ekran görüntüsü vardır: kabul edilen öneri oranı, önerilen satır sayısı, aktif kullanıcı. O ekran görüntüsü soruya cevap vermez, çünkü soru teslimat hakkındadır ve panel editörde olanı sayar.

Bu yazıda "daha hızlıyız" hissini, bir tech lead'in iki hafta içinde kendi Git host'undan çıkarabileceği sayılara çeviriyoruz. Örnek olarak kurgusal bir ekip kullanacağız: Sepet adında bir perakende uygulaması, iOS, Android ve backend'e dağılmış on beş geliştirici, iki haftalık release treni. Yazıdaki bütün Sepet sayıları uydurmadır ve yalnızca tablo biçimini göstermek için vardır.

His ile ölçüm neden ayrışıyor

Bu konuda okuduğumuz en öğretici çalışma METR'in 2025 tarihli randomize deneyi. On altı deneyimli açık kaynak geliştirici, kendi repolarından 246 iş üzerinde çalıştı ve her iş rastgele "AI serbest" ya da "AI yasak" koluna atandı. Sonuç: AI serbest olduğunda işler yüzde 19 daha uzun sürdü. Asıl ilginç kısım algı tarafıdır. Geliştiriciler çalışmadan önce yüzde 24 hızlanma bekliyordu, yavaşlamayı yaşadıktan sonra da yüzde 20 hızlandıklarına inanıyordu.

Bu sonucu "AI yavaşlatır" diye okumak yanlış olur ve yazarlar da öyle okunmasını istemiyor: çalışma, çok iyi bildikleri büyük repolarda çalışan deneyimli kişileri ve 2025 başının araçlarını kapsıyor. METR'in Şubat 2026 güncellemesi tabloyu daha da ilginç hale getiriyor. Deneyi yeni araçlarla tekrarlamaya çalıştıklarında, AI'sız çalışmak istemediği için katılmayan geliştiricilerin sayısı belirgin biçimde arttı. Katılanların yüzde 30 ila 50'si de AI olmadan yapmak istemediği bazı işleri deneye hiç göndermediğini söyledi. Yazarlar bugün hızlanmanın büyük olasılıkla daha yüksek olduğunu düşünüyor, ama veriyi kendi ifadeleriyle çok zayıf kanıt sayıyorlar.

Bu iki yazıdan aldığımız ders hız rakamından bağımsız. Deneyimli geliştiricinin kendi hızı hakkındaki tahmini, ölçümün yerine geçecek kadar güvenilir çıkmıyor ve temiz bir deney kurmak, işi meslek edinmiş araştırmacılar için bile zor. Sizin on beş kişilik ekibinizde bunun kolay olacağını varsaymayın.

Hissin ölçümden sapmasının üç tanıdık nedeni var.

İş yazmaktan okumaya kayıyor. Boş dosyaya bakmak yorucudur, bir taslağı düzeltmek daha az yorucudur. Geliştirici yorgunluğun azaldığını süre kısalması olarak hatırlar. Oysa süre başka yere taşınmıştır: prompt yazmaya, çıktıyı beklemeye, çıktıyı okumaya, makul görünen ama yanlış olan kısmı bulmaya ve PR'ı inceleyen kıdemli geliştiricinin takvimine.

Yenilik etkisi var. Aracın ilk haftaları hem ekip için hem ölçüm için tipik değildir. İnsanlar aracı her işe dener, uygun olmayan işlerde vakit kaybeder, sonra nerede işe yaradığını öğrenir. İlk aydan çıkarılan sayı iki yöne de yanıltır.

Vendor panelleri başka bir soruya cevap verir. GitHub Copilot'ın kullanım metrikleri dokümantasyonu acceptance rate'i kullanıcıların kabul ettiği önerilerin yüzdesi olarak tanımlar, önerilen ve eklenen satırları ayrı ayrı sayar. Bu sayılar "araç kullanılıyor mu" sorusunun cevabıdır ve lisansları kimin açmadığını görmek için işe yarar. Kabul edilen önerinin yarım saat sonra silinip silinmediğini, review'dan geçip geçmediğini ya da kullanıcıya ulaşıp ulaşmadığını söylemez.

Yanıltan dört metrik

Sepet ekibinin ilk çeyrek raporu şöyle görünüyordu. Tanıdık gelecektir:

AI pilot sonuçları, Q2
- Acceptance rate: %31
- AI ile önerilen satır: 48.000
- Haftalık PR sayısı: 38 → 52
- Sprint velocity: 61 → 74 story point
Sonuç: ekip yaklaşık %35 daha verimli.

Dört satırın dördü de doğru ölçülmüş olabilir, sonuç cümlesi yine de bunlardan çıkmaz.

Satır sayısı bir çıktı ölçüsüdür ve AI'ın en ucuza ürettiği şey satırdır. Aynı işi 40 satırda çözen PR ile 400 satırda çözen PR arasında ikincisi daha "verimli" görünür, bakım maliyeti ise tersidir. Satır sayısına yalnızca PR boyutu olarak, review yükünü açıklamak için bakarız.

PR sayısı, PR'ın tanımı değiştiğinde anlamını kaybeder. Agent'lar işi küçük parçalara böler, küçük parçalar çok PR eder. Sayı artarken teslim edilen özellik sayısı sabit kalabilir.

Acceptance rate bir kullanım metriğidir. Üstelik yüksek olması her zaman iyi haber sayılmaz: öneriyi okumadan kabul eden bir ekipte oran tavan yapar.

Story point ekibin kendi tahmin birimidir ve ekip aracın varlığını bilerek tahmin yapar. Velocity artışı çoğu zaman puanların şiştiğini gösterir. Ayrıca story point'i hedef haline getirdiğiniz gün ölçü olmaktan çıkar.

Editörde sayılan her şey kullanımı ölçer. Verimlilik, değişikliğin kullanıcıya ulaştığı ve orada kaldığı yerde ölçülür.

Dayanan metrikler ve AI hakkında ne söyledikleri

Elimizdeki en sağlam çerçeve DORA'nın teslimat metrikleri. Güncel rehber beş metrik tanımlıyor ve bizim için ikisi merkezde duruyor: change lead time (değişikliğin version control'e girmesinden production'a çıkmasına kadar geçen süre) ve change fail rate (deployment'ların ne kadarının acil müdahale gerektirdiği). Bunlara AI'ın etkisini ayırt etmeye yarayan birkaç metrik ekliyoruz.

Metrik Nereden gelir AI hakkında ne söyler
Lead time, aşamalarıyla PR timeline, CI, release tag'leri Kazancın hangi aşamada olduğunu ve darboğazın nereye taşındığını
Change failure rate Hotfix release'leri, rollback'ler, durdurulan phased rollout Hızın kaliteden ödenip ödenmediğini
N gün içinde rework git log, fix ve revert commit'leri Makul görünen ama yanlış kodun review'dan geçip geçmediğini
Kıdemli başına review yükü PR review kayıtları Yazma hızının inceleme kapasitesini aşıp aşmadığını
Kaçan hatalar Issue tracker, production'da bulunan bug'lar Test ve review'un AI çıktısını yakalayıp yakalamadığını
Bug'ı yeniden üretme ve düzeltme süresi Issue açılış, ilk repro, fix merge zamanları AI'ın teşhis işinde işe yarayıp yaramadığını
Onboarding süresi Yeni gelenin ilk ve onuncu merge edilmiş PR'ı Kod tabanını öğrenmeyi hızlandırıp hızlandırmadığını

Lead time'ı tek sayı olarak raporlamak işe yaramaz, çünkü AI yalnızca bir aşamasına dokunur. Beş aşamaya bölün: kodlama (ilk commit'ten review'a hazır olana kadar), review bekleme, review ve düzeltme turları, CI, release (merge'den kullanıcıya çıkan sürüme kadar). Büyük projelerde sık gördüğümüz tablo şudur: kodlama aşaması kısalır, review bekleme uzar, toplam değişmez. Bu tablonun söylediği, darboğazın artık kodlama olmadığıdır. Mobilde release aşaması ayrıca dikkat ister: iki haftalık release treni olan bir ekipte kodlama süresini yarıya indirmek kullanıcıya ulaşma süresini neredeyse hiç değiştirmez.

Change failure rate ve rework, hızın faturasıdır. İkisini ayrı tutuyoruz çünkü farklı şeyleri yakalarlar: failure rate kullanıcıya ulaşan kazayı, rework ise kullanıcıya ulaşmadan ekip içinde düzeltilen yanlışı sayar. AI çıktısının tipik hatası olan "derleniyor, testleri geçiyor, ama yanlış şeyi yapıyor" durumu önce rework'te görünür.

Kıdemli başına review yükü, AI geçişlerinde en çok ihmal edilen sayıdır. On beş kişilik bir ekipte review'ların çoğu üç dört kişiden geçer. Yazma tarafı hızlandığında o üç dört kişinin haftası dolar, review'lar yüzeyselleşir ve bunu kimse bir metrik olarak görmez. Haftalık review sayısını ve review edilen satırı kişi bazında değil rol bazında izleyin. Bu yükü azaltmanın yollarını AI ile code review yazımızda anlatıyoruz.

Bug teşhis süresi, AI'ın çoğu zaman sessizce en çok işe yaradığı yerdir: log okumak, crash'i yeniden üreten testi yazmak, şüpheli commit'i bulmak. Feature lead time'ında görünmez, o yüzden ayrı ölçün. Onboarding süresi için de aynısı geçerli, ama yılda iki üç kişi işe alan bir ekipte bu bir istatistik olmaz, yalnızca not düşülecek bir gözlemdir.

Veriyi platform satın almadan toplamak

Mühendislik analitiği platformları bu sayıların çoğunu hazır verir. On beş kişilik bir ekip için ilk ölçümü yapmak üzere platform almayı önermiyoruz: önce hangi soruyu sorduğunuzu öğrenin, platformu sonra seçin. Gereken veri Git host'unuzda ve repoda zaten duruyor.

Önce etiket: AI katkısını dürüstçe işaretlemek

Segmentasyon için her PR'da üç değerli bir etiket yeterli: ai:none, ai:assisted (tamamlama ya da sohbetle yazılmış, geliştirici sürmüş), ai:agent (değişikliğin çoğunu agent üretmiş, geliştirici incelemiş). Etiketi zorunlu tutan küçük bir kontrol, unutulmayı engeller:

# .github/workflows/ai-label.yml
name: ai-label
on:
  pull_request:
    types: [opened, reopened, labeled, unlabeled, synchronize, ready_for_review]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - env:
          LABELS: ${{ toJson(github.event.pull_request.labels.*.name) }}
        run: |
          count=$(echo "$LABELS" | jq '[.[] | select(startswith("ai:"))] | length')
          if [ "$count" -ne 1 ]; then
            echo "::error::Tam olarak bir ai:* etiketi seçin (ai:none, ai:assisted, ai:agent)."
            exit 1
          fi

PR etiketi olmayan ortamlarda aynı bilgiyi commit trailer'ı taşır. Git bunu doğrudan destekler ve git log trailer'ı anahtarına göre okuyabilir:

git commit -m "Sepet toplamında kampanya indirimini uygula" --trailer "AI-Assisted: agent"

# Okuma: her commit için trailer değeri
git log --first-parent --format='%h %(trailers:key=AI-Assisted,valueonly,separator=%x2C) %s' main

Bunun emsali var: Linux kernel dokümantasyonu AI yardımıyla yazılan katkılar için Assisted-by trailer'ını tanımlıyor ve sorumluluğun insanda kaldığını açıkça yazıyor. Biz araç adı yerine katkı düzeyini kaydetmeyi tercih ediyoruz, çünkü segmentasyonda işe yarayan bilgi o. Squash merge kullanıyorsanız trailer'ın squash commit'ine taşınıp taşınmadığını kendi merge ayarınızda bir kere kontrol edin. Emin değilseniz PR etiketini esas alın.

Etiketin dürüst kalması iki koşula bağlı. Birincisi, etiket hiçbir zaman kişisel değerlendirmeye girmez ve bunu yazılı olarak söylersiniz. ai:none seçenin geri kaldığı, ai:agent seçenin tembel sayıldığı bir ekipte etiket bir ayda anlamsızlaşır. İkincisi, raporlar kişi bazında üretilmez. Bu kuralları ekibin diğer AI kurallarıyla aynı yere, AI kullanım politikanıza yazın.

PR aşama sürelerini API'den çekmek

Aşağıdaki script GitHub REST API'sinin iki endpoint'ini kullanır: PR listesi (created_at, merged_at, labels, user) ve her PR'ın timeline'ı. Timeline'daki committed olayı commit'in yazar tarihini, ready_for_review olayı draft'tan çıkış anını, reviewed olayı review'un submitted_at ve state alanlarını verir. Yalnızca standart kütüphane gerekir, token'ın repoyu okuma yetkisi olması yeterlidir.

#!/usr/bin/env python3
"""Birleşmiş PR'ların aşama sürelerini CSV olarak yazar.
Kullanım: GITHUB_TOKEN=... python3 pr_timings.py owner/repo 2026-06-01 > prs.csv
"""
import csv, json, os, sys, urllib.request
from datetime import datetime

API = "https://api.github.com"
REPO, SINCE = sys.argv[1], sys.argv[2]
HEADERS = {"Accept": "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28"}
if os.environ.get("GITHUB_TOKEN"):
    HEADERS["Authorization"] = f"Bearer {os.environ['GITHUB_TOKEN']}"

def get(url):
    with urllib.request.urlopen(urllib.request.Request(url, headers=HEADERS)) as r:
        return json.load(r)

def pages(path):
    page = 1
    while True:
        sep = "&" if "?" in path else "?"
        batch = get(f"{API}{path}{sep}per_page=100&page={page}")
        yield from batch
        if len(batch) < 100:
            return
        page += 1

def ts(value):
    return datetime.fromisoformat(value.replace("Z", "+00:00")) if value else None

def hours(start, end):
    return round((end - start).total_seconds() / 3600, 1) if start and end else ""

out = csv.writer(sys.stdout)
out.writerow(["pr", "author", "ai", "labels", "merged_at", "coding_h", "wait_review_h",
              "review_h", "total_h", "review_rounds", "reviewers"])

for pr in pages(f"/repos/{REPO}/pulls?state=closed&sort=updated&direction=desc"):
    if pr["updated_at"] < SINCE:
        break                               # güncellenme tarihine göre sıralı, gerisi daha eski
    if not pr["merged_at"] or pr["merged_at"] < SINCE or pr["user"]["type"] == "Bot":
        continue

    first_commit = ready = first_review = None
    rounds, reviewers = 0, set()
    for ev in pages(f"/repos/{REPO}/issues/{pr['number']}/timeline"):
        kind = ev.get("event")
        if kind == "committed":
            when = ts(ev["author"]["date"])
            first_commit = min(first_commit or when, when)
        elif kind == "ready_for_review":
            ready = ts(ev["created_at"])    # draft'tan son çıkış
        elif kind == "reviewed":
            user = ev.get("user") or {}
            if user.get("type") != "User" or user.get("login") == pr["user"]["login"]:
                continue                    # bot review'ları ve yazarın kendi yorumları sayılmaz
            reviewers.add(user["login"])
            when = ts(ev["submitted_at"])
            first_review = min(first_review or when, when)
            if ev["state"] == "changes_requested":
                rounds += 1

    created, merged = ts(pr["created_at"]), ts(pr["merged_at"])
    ready = ready or created
    if first_review and first_review < ready:
        ready = created                     # draft iken review almış PR
    labels = [label["name"] for label in pr["labels"]]
    ai = next((name for name in labels if name.startswith("ai:")), "untagged")
    out.writerow([
        pr["number"], pr["user"]["login"], ai, "|".join(labels), pr["merged_at"],
        hours(min(first_commit or ready, ready), ready),   # kodlama: ilk commit -> review'a hazır
        hours(ready, first_review),                        # review bekleme
        hours(first_review, merged),                       # review ve düzeltme turları
        hours(min(first_commit or created, created), merged),
        rounds, "|".join(sorted(reviewers)),
    ])

Script'i herkese açık bir repoda çalıştırıp alanların gerçekten böyle döndüğünü doğruladık. Bilmeniz gereken sınırları var. Kodlama aşaması ilk commit'le başlar, ondan önceki düşünme ve prompt yazma süresi görünmez. Geliştirici commit'leri amend ya da rebase ederse yazar tarihi korunur, ama tek commit'e sıkıştırılmış bir dalda "ilk commit" son halin tarihidir. Süreler takvim saatidir, hafta sonlarını içerir. Bu yüzden ortalama yerine medyan ve yüzdelik kullanacağız. AI review bot'ları user.type alanı Bot olarak geldiği için "ilk review" sayılmaz. Sayılırsa review bekleme süreniz bir gecede iki dakikaya düşer ve yanlış bir başarı hikâyesi elde edersiniz.

GitLab kullanıyorsanız karşılığı GET /projects/:id/merge_requests endpoint'idir. Yanıtta created_at, merged_at, draft, labels ve MR'ın hazırlık adımlarının bittiği anı veren prepared_at alanları bulunur.

Rework'ü git log ile saymak

Rework için kullandığımız tanım bilerek kabadır: main'e giren bir değişikliğin dokunduğu dosyalardan en az birine, N gün içinde başlığı fix, revert ya da hotfix ile başlayan bir commit dokunduysa o değişiklik "yeniden işlendi" sayılır. Squash merge ve tutarlı commit başlıkları (örneğin Conventional Commits) varsayar.

#!/usr/bin/env python3
"""main'e giren her değişiklik için: N gün içinde aynı dosyalara fix/revert geldi mi?
Kullanım (repo kökünde): python3 rework.py 2026-06-01 21 > rework.csv
"""
import re, subprocess, sys
from datetime import datetime, timedelta

SINCE, DAYS = sys.argv[1], int(sys.argv[2])
BRANCH = sys.argv[3] if len(sys.argv) > 3 else "HEAD"
FIX = re.compile(r"^(revert|fix|hotfix)\b|\bhotfix\b", re.IGNORECASE)
IGNORE = re.compile(r"(\.lock$|\.md$|^docs/|\.xcstrings$|/strings\.xml$)")

log = subprocess.run(
    ["git", "log", "--first-parent", "--name-only", f"--since={SINCE}",
     "--format=%x1e%H%x1f%cI%x1f%s%x1f%(trailers:key=AI-Assisted,valueonly,separator=%x2C)%x1f",
     BRANCH],
    capture_output=True, text=True, check=True).stdout

commits = []
for record in log.split("\x1e")[1:]:
    sha, date, subject, ai, files = record.split("\x1f")
    paths = {f for f in files.split("\n") if f and not IGNORE.search(f)}
    when = datetime.fromisoformat(date.replace("Z", "+00:00"))
    commits.append((sha, when, subject, ai.strip() or "untagged", paths))
commits.reverse()                                  # eskiden yeniye

newest = commits[-1][1]
print("sha,merged_at,ai,files,reworked,days_to_fix,fix_sha")
for i, (sha, date, subject, ai, paths) in enumerate(commits):
    if not paths or FIX.search(subject):
        continue                                   # düzeltmenin kendisi ölçülen değişiklik sayılmaz
    if newest - date < timedelta(days=DAYS):
        continue                                   # gözlem penceresi dolmamış, dahil etme
    hit = next(((s, d) for s, d, subj, _, p in commits[i + 1:]
                if d - date <= timedelta(days=DAYS) and FIX.search(subj) and p & paths), None)
    print(sha[:10], date.date(), ai, len(paths), int(bool(hit)),
          (hit[1] - date).days if hit else "", hit[0][:10] if hit else "", sep=",")

Dosya düzeyinde eşleşme yanlış pozitif üretir: herkesin dokunduğu bir router dosyası her fix'te sayılır. Mutlak değere güvenmeyin, aynı tanımla ölçülmüş iki dönemin farkına bakın. Gözlem penceresi dolmamış değişiklikleri dışarıda bırakan satır önemlidir. Onsuz son üç haftanın rework oranı her zaman düşük görünür ve rollout'tan hemen sonra alınan ölçüm AI lehine çıkar.

Release ve CI aşamaları

Merge'den release'e geçen süre için her commit'i içeren ilk tag'i bulmak yeter:

git log --first-parent --since=2026-06-01 --format='%H %cI' main | while read -r sha merged; do
  tag=$(git tag --contains "$sha" --sort=creatordate | head -n 1)
  [ -n "$tag" ] && echo "${sha:0:10},$merged,$tag,$(git log -1 --format=%cI "$tag")"
done > release_lag.csv

Tag tarihi mağazaya gönderim tarihidir, kullanıcıya ulaşma tarihi sayılmaz. Mağaza incelemesi ve phased rollout süresini biliyorsanız üstüne ekleyin. CI için GitHub Actions'ın workflow run listesi her koşunun run_started_at, updated_at ve conclusion alanlarını verir:

curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \
  "https://api.github.com/repos/sepet/app/actions/runs?event=pull_request&status=completed&created=%3E%3D2026-09-01&per_page=100" |
jq -r '[.workflow_runs[] | {name, conclusion,
         min: (((.updated_at | fromdate) - (.run_started_at | fromdate)) / 60)}]
       | group_by(.name)[]
       | "\(.[0].name)\t\(length) koşu\t\(map(.min) | add | round) dk\t\(map(select(.conclusion == "failure")) | length) başarısız"'

Bu, koşunun duvar saati süresidir. Paralel job'ların toplamı olan faturalanan dakika için host'unuzun fatura raporuna bakın. Yüzden fazla koşu varsa sayfalamanız gerekir.

Karşılaştırmayı tasarlamak

Baseline, rollout'tan önce alınır. Araç zaten kullanılıyorsa iyi haber şu ki Git geçmişi geriye dönük okunabilir: script'leri rollout tarihinden önceki üç ay için çalıştırın. Geriye dönük alınamayan tek şey etiket ve ankettir.

İki tasarım seçeneğiniz var. Aynı ekibi önce ve sonra karşılaştırmak ucuzdur ve herkesi kapsar, zayıflığı o arada değişen her şeyin sonuca karışmasıdır: yeni işe alımlar, büyük bir refactor, CI geçişi, tatil dönemi. Pilot ve kontrol ekibi karşılaştırması bu gürültünün bir kısmını ayıklar, ama on beş kişilik bir organizasyonda iki "ekip" yedişer kişidir ve farklı işler yapar. METR'in güncellemesinde anlattığı sorun burada da çıkar: aracı kullanmak isteyenler pilot ekibe gönüllü olur ve karşılaştırma baştan yanlıdır.

On beş kişilik ekipte bizim tercihimiz, tüm ekip için önce ve sonra karşılaştırması ve bunu iş tipine göre bölmektir. Aynı dönem içinde ai:agent etiketli PR'ları ai:none etiketlilerle karşılaştırmak cazip görünür, ama geliştirici AI'ı uygun gördüğü işte kullanır. O karşılaştırmada ölçtüğünüz şey geliştiricinin iş seçimidir. Etiketi nedensellik için kullanmayın, "kazanç hangi iş tipinde yoğunlaşıyor" sorusu için kullanın.

İş tipi segmentasyonu şart, çünkü AI'ın etkisi işe göre çok değişir. Dört beş kova yeter: yeni feature, bug fix, refactor ya da migration, test, bağımlılık ve yapılandırma. Bunu da PR etiketiyle ya da başlık önekiyle alırsınız.

Beklenecek süre için önerimiz şu: rollout'un ilk dört haftasını ölçüme katmayın, ardından en az sekiz ila on iki hafta toplayın. Change failure rate gibi release'e bağlı metrikler için en az dört beş release döngüsü gerekir. İki haftalık trende bu zaten iki üç ay eder. Baseline dönemini mümkünse takvim olarak benzer seçin: yaz tatiliyle kasım kampanya dönemini karşılaştırmak araç hakkında bir şey söylemez.

On beş kişide örneklem sorunu neye benzer

Sepet haftada kırk civarı PR birleştiriyorsa on iki haftada yaklaşık beş yüz PR eder. Kulağa yeterli gelir. Beş iş tipine ve üç AI etiketine böldüğünüzde hücre başına otuz kırk PR kalır ve PR süreleri uzun kuyrukludur: tek bir on günlük PR ortalamayı kaydırır. Bu yüzden medyan ve yetmiş beşinci yüzdelik raporlayın ve farkın gürültüden ayrılıp ayrılmadığına bakın. Bootstrap bunun için yeterli ve istatistik kütüphanesi gerektirmez:

#!/usr/bin/env python3
"""İki dönemin (ya da iki grubun) medyan farkı ve bootstrap aralığı.
Kullanım: python3 compare.py baseline.csv after.csv total_h
"""
import csv, random, statistics, sys

def column(path, name):
    with open(path, newline="") as f:
        return [float(row[name]) for row in csv.DictReader(f) if row[name]]

def p75(values):
    return statistics.quantiles(values, n=4)[2]

before, after = column(sys.argv[1], sys.argv[3]), column(sys.argv[2], sys.argv[3])
random.seed(7)
diffs = sorted(
    statistics.median(random.choices(after, k=len(after)))
    - statistics.median(random.choices(before, k=len(before)))
    for _ in range(5000))
low, high = diffs[int(0.025 * len(diffs))], diffs[int(0.975 * len(diffs))]

print(f"önce : n={len(before):4d}  medyan={statistics.median(before):6.1f}  p75={p75(before):6.1f}")
print(f"sonra: n={len(after):4d}  medyan={statistics.median(after):6.1f}  p75={p75(after):6.1f}")
print(f"medyan farkı: {statistics.median(after) - statistics.median(before):+.1f}  "
      f"(%95 aralık: {low:+.1f} .. {high:+.1f})")
print("aralık sıfırı içeriyor: fark gürültüden ayırt edilemiyor" if low <= 0 <= high
      else "aralık sıfırı içermiyor: fark büyük olasılıkla gerçek")

Sorunun neye benzediğini görmek için script'i rastgele üretilmiş, uzun kuyruklu iki sentetik veri setiyle çalıştırdık (60 ve 55 PR, gerçek bir ekipten gelmiyor):

önce : n=  60  medyan=  20.5  p75=  39.2
sonra: n=  55  medyan=  11.6  p75=  42.7
medyan farkı: -8.9  (%95 aralık: -15.9 .. +5.6)
aralık sıfırı içeriyor: fark gürültüden ayırt edilemiyor

Medyan 20 saatten 12 saate inmiş görünüyor, slayta "lead time yüzde 43 düştü" yazmak için yeterli. Aralık ise artı beş saate kadar uzanıyor ve yetmiş beşinci yüzdelik kötüleşmiş. Altmış PR'lık bir hücrede bu büyüklükte farklar tesadüfen oluşur. On beş kişilik ekipte dürüst sonuç çoğu zaman şu biçimdedir: "tüm PR'larda fark belirgin, bug fix kovasında belirgin, diğer kovalarda veri yetersiz". Bunu yazmaktan çekinmeyin.

Kişi bazında kırılım yapmayın. Örneklem daha da küçülür, etiketin dürüstlüğü biter ve ölçtüğünüz şey ölçüldüğünü bilen insanların davranışı olur.

Anket: kısa, tekrarlı ve belirli sorularla

Sayılar neyin değiştiğini söyler, nedenini söylemez. Bunun için dört haftada bir, iki dakikada biten, anonim bir anket kullanıyoruz. "AI'dan memnun musunuz" gibi sorular işe yaramaz, çünkü METR'in gösterdiği algı sapmasını doğrudan ölçersiniz. Sorular son haftaya ve somut olaylara bakmalı:

1. Geçen hafta AI çıktısını düzeltmek ya da atmak için yaklaşık kaç saat harcadınız?
   (0 / 1'den az / 1-3 / 3'ten fazla)
2. Geçen hafta AI'ın en çok işe yaradığı iş hangisiydi? (tek cümle)
3. Geçen hafta AI ile başlayıp elle bitirdiğiniz bir iş oldu mu? Neden bıraktınız?
4. Review ettiğiniz PR'larda, tam anlamadan onayladığınız bir bölüm oldu mu?
   (hiç / bir kez / birden fazla)
5. Review bekleyen PR'ınız geçen hafta sizi kaç kez engelledi? (0 / 1-2 / 3 ve üzeri)

Dördüncü soru rahatsız edicidir ve en değerli sinyali verir: bu oran artıyorsa kaçan hatalar bir iki release sonra artar. Anketin yeri, metrikleri açıklamak ve bir sonraki ölçümde neye bakılacağını seçmektir. Anket sonucunu tek başına kazanç kanıtı olarak raporlamayın.

Maliyet tarafını aynı sayfaya koymak

Kazanç saat cinsinden ölçülüyorsa maliyeti de aynı aya ve aynı birime getirin. Dört kalem var.

Lisans ve kullanım: koltuk başına ücret ile kullanıma göre faturalanan kısım (token, agent koşuları, premium istekler). İkincisi aydan aya oynar ve agent kullanımı arttıkça büyür. Tahmin yürütmeyin, faturadan okuyun.

Review süresi: prs.csv içindeki review turu sayısı ve reviewer listesi size haftalık review adedini verir. Bir review'un kaç dakika sürdüğünü Git'ten çıkaramazsınız. Kıdemlilerden iki hafta boyunca kaba bir kayıt tutmalarını isteyin ya da ankete bir soru ekleyin.

CI dakikaları: agent'lar çok push eder, her push pipeline çalıştırır. Yukarıdaki sorguyu baseline ve sonrası için çalıştırın. macOS runner kullanan mobil ekiplerde bu kalem lisansı geçebilir.

Bakım: kural dosyaları, prompt'lar, agent ortamı, etiket ve ölçüm script'leri. Küçük ama sıfır değil ve genellikle tek bir kişinin üstünde kalır.

Kazancı "tasarruf edilen kişi" birimine çevirmeyin. Kısalan lead time kimsenin maaşını bütçeden çıkarmaz. Yan yana koyacağınız şey şudur: aylık toplam maliyet, hangi aşamada kaç saat kısaldığı, kalite metriklerinin ne yaptığı.

Yönetime tek sayfa

Rapor tek sayfa ve hep aynı biçimde olsun. Sepet için kurgusal bir örnek:

Metrik Baseline (Mar-May) Şimdi (Tem-Eyl) Belirsizlik Yorum
Lead time medyanı (ilk commit → merge) 26 sa 21 sa Aralık sıfırı içermiyor Kazanç kodlama aşamasında
Review bekleme medyanı 5 sa 9 sa Aralık sıfırı içermiyor Darboğaz buraya taşındı
Merge → release 6 gün 6 gün Değişmedi Release treni belirliyor
Change failure rate 6 release'te 1 hotfix 6 release'te 1 hotfix Örneklem çok küçük Yorum yapılamaz
21 günde rework %9 %12 Aralık sıfırı içeriyor İzlemede
Kıdemli başına haftalık review 11 17 Sürdürülemez, önlem gerekli
Aylık maliyet (lisans + kullanım + CI farkı) Faturadan
Karar Devam, review kapasitesi için öneri ekte

"Belirsizlik" sütunu pazarlık konusu olmamalı. O sütun olmadan tablo bir satış broşürüne dönüşür.

Kaçınmanızı önerdiğimiz cümleler ve yerlerine yazdıklarımız:

Yazmayın Yazın
"Yüzde 40 daha hızlıyız." "Merge'e kadar geçen sürenin medyanı 26 saatten 21 saate indi, release süresi değişmedi."
"Dört kişilik iş tasarrufu sağladık." "Kodlama aşaması haftada toplam şu kadar saat kısaldı, review yükü şu kadar arttı."
"Kodun yüzde 60'ını AI yazıyor." "PR'ların şu kadarı ai:agent etiketli ve bunların rework oranı şu."
"Acceptance rate yükseldi." "Lisansların şu kadarı aktif kullanılıyor."
"Kalite etkilenmedi." "Altı release'te hotfix sayısı aynı. Bu örneklem bir fark gösteremeyecek kadar küçük."

Bir kere abartılmış bir rapor, sonraki her raporun inandırıcılığını tüketir. İlk çeyrekte "yüzde 40" yazan ekip, ikinci çeyrekte neden yüzde 80 olmadığını açıklamak zorunda kalır.

Sayılar kıpırdamadığında

Üç ay sonra tablo düz çıkabilir. Bu geçerli bir sonuçtur ve bir şeyler söyler. Sırasıyla baktığımız yerler:

Aşama kırılımı. Toplam lead time sabit, kodlama kısalmış, review bekleme uzamışsa araç çalışıyor ve kazanç kuyrukta eriyor. Çözüm AI tarafında aranmaz: review kapasitesi, PR boyutu sınırı, ön inceleme için otomatik review. Release aşaması toplam sürenin büyük kısmıysa kodlama hızını artırmak kullanıcıya hiçbir şey kazandırmaz, release sıklığını konuşun.

İş tipi kırılımı. Kazanç test ve migration kovalarında toplanmış, feature işinde görünmüyorsa bu aracın sizin kod tabanınızdaki gerçek profilidir. Kullanımı işe yaradığı yere yönlendirin, herkese her iş için önermeyi bırakın.

PR boyutu. Medyan PR boyutu rollout'tan sonra büyüdüyse kodlama kazancını review'da geri ödüyorsunuz. Agent'a verilen işin kapsamını küçültün.

Kullanımın kendisi. Vendor panelinin işe yaradığı tek yer burasıdır: lisansların yarısı açılmıyorsa ölçtüğünüz şey yarım ekibin etkisidir. Kullanmayanlara nedenini sorun. Cevap çoğu zaman "bizim modülde işe yaramıyor" olur ve bu, kural dosyalarınız ve proje bağlamınız hakkında bir bilgidir.

Bunlara baktıktan sonra hâlâ hareket yoksa kapsamı daraltmak meşru bir karardır: lisansları fayda görülen rollerle sınırlayın, bir çeyrek sonra yeniden ölçün. Geçişin bütününü nasıl sıraladığımızı AI ile SDLC dönüşümü yazımızda anlatıyoruz. Ölçüm o sıranın ilk adımıdır.

Kontrol listesi

  • Rollout tarihinden önceki üç ay için PR aşama süreleri, rework ve CI dakikaları çıkarıldı ve saklandı.
  • Her PR tam olarak bir ai:* etiketi ve bir iş tipi etiketi taşıyor, CI bunu kontrol ediyor.
  • Etiketin ve metriklerin kişisel değerlendirmede kullanılmayacağı yazılı olarak duyuruldu.
  • Lead time beş aşamaya bölünerek raporlanıyor: kodlama, review bekleme, review, CI, release.
  • AI review bot'ları "ilk review" hesabından çıkarıldı.
  • Rework tanımı yazıldı ve gözlem penceresi dolmamış değişiklikler hesaba katılmıyor.
  • Kıdemli başına haftalık review sayısı izleniyor.
  • Rollout'un ilk dört haftası ölçüm dışında, karşılaştırma dönemleri takvim olarak benzer.
  • Medyan ve yetmiş beşinci yüzdelik raporlanıyor, her fark için bootstrap aralığına bakıldı.
  • Etiketler arası karşılaştırma nedensellik kanıtı olarak sunulmuyor.
  • Dört haftada bir beş soruluk anket yapılıyor ve yalnızca metrikleri açıklamak için kullanılıyor.
  • Lisans, kullanım, CI ve review maliyeti aynı ay için aynı sayfada.
  • Yönetim raporu tek sayfa, belirsizlik sütunu dolu, "kişi tasarrufu" ve tek yüzdelik başlık yok.
  • Sayılar kıpırdamazsa bakılacak dört yer (aşama, iş tipi, PR boyutu, kullanım) rapora eklendi.
Seviye 23 tamamlandıİlerlemen bu tarayıcıda saklanıyor.
Sıradaki: n8n ile ilk üretim otomasyonu: form, sınıflandırma, CRM, Slack (uçtan uca)

Bu konuda desteğe mi ihtiyacınız var?

Uygulamanızda bu kontrollerin doğru kurulup kurulmadığını birlikte inceleyelim. Güvenlik denetimi ya da danışmanlıkla buradayız.

Yorumlar ve sorular

Katılmadığınız bir nokta ya da projenizde takıldığınız bir yer mi var? Yazın, konuşalım.