Mert Özen Her Satırda Daha İleri
Proje Yönetimi Kanban — #03

WIP Limit ve Little's Law: Daha Az İşe Başlayıp Daha Çok Bitirmek

Mert Özen 8 Kas 2026 11 dk 4 görüntülenme
WIP Limit ve Little's Law: Daha Az İşe Başlayıp Daha Çok Bitirmek

Throughput sabitken WIP'i artırmak cycle time'ı aynı oranda uzatır; Little's Law bunun aritmetiğidir. C# ile yazdığımız simülasyonda WIP 3'ten 10'a çıkınca ortalama cycle time 2,4 günden 7,9 güne çıkıyor, context switching eklenince throughput da düşüyor. Little's Law'un varsayımlarını, neden tahmin aracı olmadığını, ilk WIP limit'ini belirlemeyi ve kişi başına limit gibi tuzakları konuşuyoruz.

Sürüm notu: Bu yazı The Kanban Guide'ın 2025.5 sürümünü esas alır; simülasyon kodu .NET 10 ile derlenip çalıştırılmıştır.

Önce Tahmin Et

Üç geliştiriciden oluşan bir ekip düşün. Haftada ortalama 6 item bitiriyorlar ve bu sayı aylardır değişmiyor; işin sonsuz bir backlog'dan geldiğini, kimsenin tatile çıkmadığını varsay. Ekip bir dönem aynı anda en fazla 3 iş yürütüyor. Sonra "herkesin elinde bekleyen bir şey olsun, boş kalmasınlar" diye limit'i 10'a çıkarıyorlar. Throughput aynı kalıyor, yani haftada yine 6 item bitiyor.

Bir item'ın başlangıçtan bitişe geçen ortalama süresi ne olur? Aynı mı kalır, biraz mı uzar, yoksa üç katına mı çıkar? Bir de şunu düşün: kişi başına aynı anda açık iş sayısı arttığında throughput'un aynı kalacağı varsayımı ne kadar gerçekçi?

Little's Law: Üç Sayı, Bir Eşitlik

John Little 1961'de Operations Research dergisinde yayımladığı makalede queueing sistemleri için bugün kendi adıyla anılan eşitliğin ispatını verdi: L = λW. Sistemdeki ortalama eleman sayısı (L), ortalama varış hızı (λ) ile bir elemanın sistemde geçirdiği ortalama sürenin (W) çarpımına eşittir. Bir bankadaki ortalama müşteri sayısı, dakikada gelen müşteri sayısı ile bir müşterinin bankada kaldığı ortalama dakikanın çarpımıdır.

Kanban'da bu eşitlik genellikle flow metric'leriyle yazılır:

average cycle time = average WIP / average throughput

Ekip ortalama 10 item'ı aynı anda yürütüyor ve günde ortalama 1,25 item bitiriyorsa, bir item ortalama 8 iş günü sistemde kalır. Formül basit; asıl değeri, üç sayıdan birini değiştirdiğinde diğerlerinin nasıl hareket etmek zorunda olduğunu göstermesidir. Throughput'u değiştirmek zordur: daha çok kişi, daha az iş, daha iyi araç gerekir. WIP'i (Work in Progress) değiştirmek ise ekibin bugün alabileceği bir karardır. Throughput sabitken WIP'i yarıya indirirsen, ortalama cycle time da yarıya iner.

Kod: Aynı Ekip, Farklı WIP Limit'leri

Bunu bir formülle göstermek kolay, ama bir simülasyonla görmek daha ikna edici. Aşağıdaki .NET 10 console uygulaması üç geliştiricili bir ekibi saat saat simüle ediyor. Backlog hiç boşalmıyor; WIP limit'i dolmadıkça yeni iş çekiliyor. Her item'ın gerektirdiği efor, medyanı 2 iş günü olan bir lognormal dağılımdan geliyor; yani çoğu iş 1–3 gün sürerken arada 6–8 günlük büyük işler de çıkıyor. Ekip kapasitesi o an açık olan işler arasında eşit bölünüyor, ama bir item'a aynı anda birden fazla kişi çalışamıyor:

public static class BoardSimulation
{
    const int Developers = 3;
    const int WarmUpDays = 100;
    const int MeasuredDays = 2000;

    public static SimResult Run(int wipLimit, double switchCost, int seed = 7)
    {
        Random rng = new(seed);
        List<(int StartHour, double Remaining)> wip = [];
        List<double> cycleTimes = [];
        long wipHours = 0;

        // Zamanı saat saat ilerletiyoruz: 1 iş günü = 8 saat
        for (int hour = 0; hour < (WarmUpDays + MeasuredDays) * 8; hour++)
        {
            bool measuring = hour >= WarmUpDays * 8;

            // Pull: limit dolana kadar backlog'dan yeni iş çek (backlog hiç boşalmıyor)
            while (wip.Count < wipLimit)
                wip.Add((hour, Effort(rng)));

            if (measuring)
                wipHours += wip.Count;

            // Kişi başına item sayısı arttıkça context switching günün bir kısmını yer
            double itemsPerPerson = (double)wip.Count / Developers;
            double efficiency = Math.Max(0.1, 1 - switchCost * Math.Max(0, itemsPerPerson - 1));
            double share = Math.Min(1.0, Developers * efficiency / wip.Count) / 8;

            for (int i = wip.Count - 1; i >= 0; i--)
            {
                (int start, double remaining) = wip[i];
                remaining -= share;
                if (remaining > 0)
                {
                    wip[i] = (start, remaining);
                    continue;
                }

                wip.RemoveAt(i);
                if (measuring)
                    cycleTimes.Add((hour - start + 1) / 8.0);
            }
        }

        cycleTimes.Sort();
        return new SimResult(
            AvgWip: (double)wipHours / (MeasuredDays * 8),
            ThroughputPerWeek: cycleTimes.Count / (MeasuredDays / 5.0),
            AvgCycleTime: cycleTimes.Average(),
            P85CycleTime: (int)Math.Ceiling(cycleTimes[(int)Math.Ceiling(0.85 * cycleTimes.Count) - 1]));
    }

    // Item eforu: medyanı 2 iş günü olan lognormal dağılım, birkaç büyük item kuyruğu uzatır
    static double Effort(Random rng)
    {
        double u1 = 1.0 - rng.NextDouble(), u2 = rng.NextDouble();
        double normal = Math.Sqrt(-2 * Math.Log(u1)) * Math.Cos(2 * Math.PI * u2);
        return 2.0 * Math.Exp(0.6 * normal);
    }
}

İkinci parametre, switchCost, context switching'in maliyetini modelliyor: kişi başına açık iş sayısı 1'in üstüne çıktıkça her fazladan iş, o kişinin gününün %10'unu yiyor. İlk koşuda bu maliyet sıfır, yani tamamen ideal bir dünya. Programın üst kısmı dört farklı limit'i iki senaryoda deniyor ve son kolonda Little's Law'un tahmin ettiği cycle time'ı yazıyor:

using System.Globalization;

CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;

Console.WriteLine("WIP limit | avg WIP | throughput/week | avg cycle time | p85 cycle time | Little: WIP / TP");
foreach (int limit in new[] { 3, 5, 8, 10 })
    Print(limit, BoardSimulation.Run(wipLimit: limit, switchCost: 0.0));

Console.WriteLine();
Console.WriteLine("Same board, each extra item per person costs 10% of that person's day:");
foreach (int limit in new[] { 3, 5, 8, 10 })
    Print(limit, BoardSimulation.Run(wipLimit: limit, switchCost: 0.10));

static void Print(int limit, SimResult r) =>
    Console.WriteLine($"{limit,9} | {r.AvgWip,7:F1} | {r.ThroughputPerWeek,15:F1} | {r.AvgCycleTime,11:F1} d | " +
        $"{r.P85CycleTime,11} d | {r.AvgWip / (r.ThroughputPerWeek / 5),8:F1} d");

public sealed record SimResult(double AvgWip, double ThroughputPerWeek, double AvgCycleTime, int P85CycleTime);

Gerçek çıktı:

WIP limit | avg WIP | throughput/week | avg cycle time | p85 cycle time | Little: WIP / TP
        3 |     3.0 |             6.2 |         2.4 d |           4 d |      2.4 d
        5 |     5.0 |             6.3 |         4.0 d |           6 d |      4.0 d
        8 |     8.0 |             6.3 |         6.3 d |          10 d |      6.3 d
       10 |    10.0 |             6.3 |         7.9 d |          12 d |      7.9 d

Same board, each extra item per person costs 10% of that person's day:
        3 |     3.0 |             6.2 |         2.4 d |           4 d |      2.4 d
        5 |     5.0 |             5.9 |         4.3 d |           7 d |      4.3 d
        8 |     8.0 |             5.3 |         7.5 d |          12 d |      7.5 d
       10 |    10.0 |             4.9 |        10.2 d |          16 d |     10.2 d

Çıktıyı Okumak

İlk tabloda throughput neredeyse hiç değişmiyor: haftada 6,2 ile 6,3 item arası. Kapasite aynı, iş aynı; yalnız aynı anda açık tutulan iş sayısı değişiyor. Ama ortalama cycle time 2,4 günden 7,9 güne çıkıyor; WIP'i 3,3 katına çıkarınca cycle time da yaklaşık 3,3 katına çıkıyor. Müşteri açısından anlamlı olan 85. percentile ise 4 günden 12 güne fırlıyor. Son kolondaki Little's Law tahmini simülasyonun ölçtüğü ortalamayla birebir aynı, çünkü bu sistem Little's Law'un varsayımlarını tam olarak sağlıyor: başlayan her iş bitiyor ve sistem uzun süre aynı koşullarda çalışıyor.

Bu tablonun söylediği şey sezgiye ters: limit 10'ken kimse boş durmuyor, herkesin önünde bekleyen bir iş var, ama hiçbir şey daha hızlı bitmiyor. Ekip daha meşgul görünüyor, müşteri daha uzun bekliyor. Herkesin elinde iş olması ile işin akması aynı şey değil.

İkinci tablo ideal dünyadan çıkıyor. Kişi başına her fazladan açık işin günün %10'unu yediğini varsayınca, limit 10'da throughput haftada 4,9 item'a düşüyor ve ortalama cycle time 10,2 güne çıkıyor. Yani yüksek WIP iki yerden vuruyor: hem her iş daha uzun bekliyor hem de toplam iş daha yavaş bitiyor. %10 bizim seçtiğimiz bir varsayım, ölçülmüş bir sabit değil. Gerald Weinberg'in 1992 tarihli "Quality Software Management: Systems Thinking" kitabındaki meşhur tablo, ikinci bir projenin kişinin zamanının yaklaşık %20'sini context switching'e harcattığını öne sürer; bizim sayımız bunun yarısı, yani iyimser.

Little's Law Neden Hesap Makinesi Değil

Simülasyonda Little's Law kusursuz çalıştı. Gerçek bir board'da bu kadar temiz çalışmaz, çünkü varsayımları bozulur. Daniel Vacanti, flow metric'leri üzerine yazdığı "Actionable Agile Metrics for Predictability" (2015) kitabında bu varsayımları ekip diliyle şöyle sıralar; farklı kaynaklarda küçük farklarla geçer:

  • Ölçülen dönemde ortalama giriş hızı ile ortalama çıkış hızı aynı olmalı.
  • Başlayan her iş eninde sonunda bitmeli ve sistemden çıkmalı; yarıda bırakılıp unutulmamalı.
  • Dönemin başındaki ve sonundaki WIP aşağı yukarı aynı olmalı.
  • WIP'teki işlerin ortalama yaşı sürekli artmamalı ya da azalmamalı.
  • Üç metric aynı birimle ölçülmeli: WIP item ise throughput da item/gün, cycle time da gün olmalı.

Bu varsayımlar bozulduğunda formül yanlış sayı üretir. Bu yüzden Little's Law'u ileriye dönük tahmin için kullanmak, yani "WIP 12, throughput günde 1,2, demek ki yeni başlayan iş 10 günde biter" demek tehlikelidir. Vacanti de Little's Law'un bir tahmin aracı olarak değil, sistemin nasıl davrandığını anlamak için kullanılması gerektiğini vurgular. Tahmin için 05. yazıdaki Monte Carlo simülasyonunu kullanacağız. Little's Law'un sana söylediği şey yöndür: WIP artarsa ve throughput aynı kalırsa, cycle time artmak zorundadır. Bu bir görüş değil, aritmetik.

Bir de ters kullanımı var: kendi verinle Little's Law'u kontrol etmek. Board'undan ortalama WIP'i, throughput'u ve cycle time'ı ayrı ayrı hesapla. WIP / throughput ile ölçtüğün ortalama cycle time arasında büyük bir fark varsa, ya sistem stabil değildir (WIP sürekli büyüyordur) ya da verinde bir sorun vardır: yarıda bırakılmış ama board'da duran işler, yanlış kaydedilmiş geçiş tarihleri gibi.

Stop Starting, Start Finishing

Kanban topluluğunda çok tekrarlanan bir slogan var: "Stop starting, start finishing", yani başlamayı bırak, bitirmeye başla. Little's Law bu sloganın matematiğidir. Bir geliştirici elindeki iş code review'da beklediği için yeni bir iş çektiğinde WIP'i bir artırır. Bunu her gün herkes yaptığında WIP büyür, throughput aynı kalır ve cycle time uzar.

WIP limit'i bu davranışa bir fren koyar. Limit dolduğunda geliştiricinin önünde iki seçenek kalır: ya bekleyen bir işe yardım eder (bir PR'ı (pull request) review eder, tester'la birlikte bir senaryoyu dener, blocked bir işin önündeki engeli kaldırmaya çalışır) ya da gerçekten yapacak bir şey yoksa boş durur. İkincisi kulağa kötü gelir, ama çoğu ekipte limit doldurulduğunda yapılacak çok iş vardır; sadece kimse onlara bakmıyordur çünkü yeni iş başlatmak daha keyiflidir.

İlk WIP Limit'ini Belirlemek

Hangi sayıyla başlamalı? İdeal bir formül yok, ama işe yarayan bir yöntem var:

Önce bugünü ölç. İki üç hafta boyunca board'daki started ile finished arasındaki item sayısını her gün not et ve ortalamasını al. Bookstore ekibinin eski board'unda bu sayı 13–14'tü; ekip ilk limit'i 14 koydu, yani hiçbir şeyi değiştirmeden mevcut durumu yazıya döktü. Bu limit pratikte neredeyse hiç devreye girmedi, ama ekibe sayıyı görünür kıldı.

Sonra yavaşça düşür. Limit'i birer ikişer azalt ve birkaç hafta bekle. Cycle time'a, throughput'a ve "limit doldu, ne yapıyoruz?" anlarına bak. Throughput düşmeden cycle time kısalıyorsa doğru yöndesin. Ekip sık sık boş kalıyorsa ve throughput düşüyorsa, limit'i fazla düşürmüşsündür. Bookstore ekibi Eylül'de toplam limit'i 12'ye indirdi ve kolon bazlı limit'ler ekledi; bunun sonucunu 06. yazıda verisiyle göreceğiz.

Son olarak, limit'in aşıldığı anı bir sinyal olarak kullan. Limit bir kural değil, bir konuşma başlatıcıdır; aşıldığında "neden?" sorusunu sormak, limit'in kendisinden daha değerlidir.

Üretimde Dikkat

Birimleri karıştırma. Simülasyonumuz iş günüyle çalışıyor; gerçek board verisi takvim günüyle. Throughput'u "haftada item" olarak, cycle time'ı "takvim günü" olarak hesaplayıp Little's Law'a sokarsan, hafta sonları yüzünden %40'a varan bir fark görürsün. Hepsini aynı birime çevir: item/takvim günü ve takvim günü.

Ortalamaya güvenme. Simülasyonda ortalama cycle time ile 85. percentile arasında 1,5–2 kat fark vardı ve gerçek veride bu fark daha büyük olur. Little's Law ortalamalarla çalışır, ama müşterine "ortalama 8 günde" dersen işlerin yaklaşık yarısında sözünü tutamazsın. Percentile'lar ve dağılım 04. yazının konusu.

Limit'i aracın uygulamasına bırakma. Jira'nın kolon limit'i aşıldığında kolonu kırmızıya boyar ama kimseyi durdurmaz. Limit'in işe yaraması aracın değil ekibin davranışına bağlı; DoW'daki (Definition of Workflow) policy "limit doluysa yeni iş çekme, sağdaki işlere yardım et" diyorsa, bunu Daily toplantısında ya da board önünde her gün sormak gerekir.

Sık Düşülen Tuzaklar

Kişi başına WIP limit'i en yaygın tuzak. "Herkes aynı anda en fazla 2 iş" kuralı adil görünür, ama ekibi bireysel kuyruklara böler. Herkes kendi iki işine odaklanır, kimse code review'da bekleyen başkasının işine yardım etmez ve limit'in amacı olan işbirliği kaybolur. Limit'i kolon ya da ekip seviyesinde koy; kişi başına limit gerekiyorsa bile ekip limit'inin yanına koy, onun yerine değil.

İkinci tuzak limit'in aşıldığı anda kimsenin bir şey yapmaması. Limit 12, board'da 15 kart var ve hayat devam ediyor. Bu durumda limit bir süs olmuştur. Ya limit'i gerçekçi bir sayıya çek ya da limit aşıldığında ne olacağını policy olarak yaz ve uygula.

Üçüncüsü blocked işleri WIP'ten düşürmek. Dış bir API (Application Programming Interface) sağlayıcısını bekleyen bir item'ı "zaten üzerinde çalışmıyoruz" diye WIP'ten saymazsan, ekip onun yerine yeni bir iş başlatır ve WIP sessizce büyür. Blocked iş de sistemde yer kaplar ve yaşlanmaya devam eder.

Dördüncüsü Little's Law'u tek bir item için kullanmak. Formül ortalamalarla çalışır; "bu item ne zaman biter?" sorusunu cevaplamaz. Tek item için cevap SLE (Service Level Expectation) ve Work Item Age'dir.

Küçük Bir Deneme

★☆☆ Simülasyonu Developers = 5 ile çalıştır ve limit'leri 5, 8, 12, 16 yap. Throughput ne kadar değişiyor, cycle time nasıl büyüyor? Little's Law kolonu hâlâ ölçülen ortalamayla aynı mı?

★★☆ Effort method'undaki lognormal'in sigma değerini 0.6'dan 1.0'a çıkar. Ortalama cycle time ile 85. percentile arasındaki fark nasıl değişiyor? Bu, item boyutlarının çok farklı olduğu bir ekip için ne anlama geliyor?

★★★ Simülasyona bir "blocked" olasılığı ekle: her item'ın %8 ihtimalle 2–9 gün boyunca hiç ilerlemediği bir dönem olsun ve blocked item WIP'e sayılmaya devam etsin. Sonra blocked item'ı WIP'ten düşüren ikinci bir versiyon yaz ve iki versiyondaki WIP, throughput ve cycle time'ı karşılaştır.

Little's Law ortalamalarla konuştu. Bir sonraki yazıda ortalamayı bırakıp dağılıma bakacağız: Bookstore ekibinin altı aylık board verisinden dört flow metric'ini bir .NET 10 console uygulamasıyla hesaplayacak, percentile'ları ve Work Item Age'i okumayı öğreneceğiz.