Mert Özen Her Satırda Daha İleri
Yazılım Tasarımı UML ve Modeling — #02

Requirement'tan Diyagrama: Hangi Soru Hangi Diyagramla Cevaplanır?

Mert Özen 7 Kas 2026 12 dk 4 görüntülenme
Requirement'tan Diyagrama: Hangi Soru Hangi Diyagramla Cevaplanır?

Her diyagram bir soruyu cevaplar: kim ne yapar sorusunu use case, hangi kavramlar sorusunu class, kim kimi çağırır sorusunu sequence, object hangi durumlardan geçer sorusunu state machine diagram'ı cevaplar. İK Portalı İzin Talebi modülünün requirement metni, isim, fiil ve koşullardan aday class, use case ve guard çıkarmak, hedef kitleye göre detay seviyesi ve serinin haritası.

Sürüm notu: Bu yazıdaki diyagramlar UML 2.5.1 notasyonuyla çizilmiştir; C# örnekleri .NET 10 ile denenmiştir.

Önce Tahmin Et

İK (İnsan Kaynakları) direktörlüğünün gönderdiği ilk requirement metninde şu cümle var: "3 günü aşan izinler direktör onayına gider." İki geliştirici bu cümleyi ayrı ayrı koda döküyor. Ada cuma günü başlayıp salı günü biten bir izin istiyor. Aşağıdaki iki satırdan hangisi doğru, direktör bu talebi görecek mi?

DateOnly start = new(2026, 11, 27);   // Cuma
DateOnly end = new(2026, 12, 1);      // Salı

int calendarDays = end.DayNumber - start.DayNumber + 1;
int workingDays = CountWorkingDays(start, end);

Console.WriteLine($"Calendar days: {calendarDays}, needs director: {calendarDays > 3}");
Console.WriteLine($"Working days:  {workingDays}, needs director: {workingDays > 3}");

static int CountWorkingDays(DateOnly start, DateOnly end)
{
    int count = 0;
    for (DateOnly day = start; day <= end; day = day.AddDays(1))
    {
        if (day.DayOfWeek is not (DayOfWeek.Saturday or DayOfWeek.Sunday))
            count++;
    }
    return count;
}

"Gün" Kelimesi İki Farklı Kod Üretti

Calendar days: 5, needs director: True
Working days:  3, needs director: False

İkisi de cümleye sadık. Takvim günü sayan geliştirici talebi direktöre gönderiyor, iş günü sayan göndermiyor. Hangisinin doğru olduğunu kod söyleyemez; bunu ancak cümleyi yazan kişi söyleyebilir. Bizim vakada İK direktörlüğüne sorduk, cevap "iş günü" oldu ve metnin 1.0 sürümüne öyle girdi.

Bu soruyu kim, ne zaman sordu? Requirement metninden model çıkarırken. Metni okuyup LeaveRequest diye bir class çizmeye ve üzerine "kaç gün sürüyor" bilgisini koymaya kalktığında, attribute'a bir isim ve bir tip vermen gerekiyor: calendarDays mı, workingDays mı? Düz metinde rahatça geçiştirilen belirsizlik, modelde bir karar ister. Modellemenin en az konuşulan faydası budur: çizdiğin diyagram, cevabını bilmediğin soruları yüzüne vurur. Bu yazıda İzin Talebi modülünün requirement metnini yazıyoruz, ondan sistematik olarak model çıkarıyoruz ve hangi sorunun hangi diyagramla cevaplandığını eşliyoruz. Requirement toplamanın kendisi (elicitation, mülakatlar, user story yazmak) ilerideki Requirements Analysis serisinin konusu; burada metin elimizde hazır.

Vaka: İzin Talebi Modülünün Requirement Metni

İK Portalı, Çözüm Desenleri serisinde de kullandığımız kurgusal İK yazılımı. Seri boyunca onun izin modülünü modelleyeceğiz. İK direktörlüğünün onayladığı metin aşağıda. Maddelerin başındaki R, requirement'ın kısaltması; seri boyunca bir kurala "R7" diye atıf yapacağız.

  • R1. Çalışan, portal üzerinden izin talebi oluşturur: izin türü, başlangıç ve bitiş tarihi, isteğe bağlı açıklama. Talep önce taslak olarak kaydedilebilir; çalışan hazır olduğunda talebi gönderir.
  • R2. Gönderimde sistem talebin kaç iş günü tuttuğunu hesaplar. Hafta sonları ve İK'nın tanımladığı resmi tatiller sayılmaz. İzin türleri: Yıllık İzin, Mazeret İzni, Hastalık İzni, Ücretsiz İzin.
  • R3. Yıllık izinde çalışanın o yılki kalan bakiyesi talep edilen iş günü sayısından azsa talep gönderilemez.
  • R4. Aynı çalışanın tarihleri çakışan iki aktif (iptal edilmemiş, reddedilmemiş) talebi olamaz.
  • R5. Hastalık izni talebine rapor dosyası (PDF) eklenebilir.
  • R6. Gönderilen talep çalışanın bağlı olduğu yöneticinin onayına düşer. Yönetici talebi onaylar ya da reddeder; reddederken gerekçe yazmak zorunludur.
  • R7. 3 iş gününü aşan talepler, yönetici onayından sonra çalışanın departman direktörünün onayına gider. Direktör de onaylar ya da gerekçeyle reddeder.
  • R8. Onay anında bakiye yeniden kontrol edilir (gönderimden bu yana başka bir izin onaylanmış olabilir).
  • R9. Son onayla talep "Onaylandı" olur; yıllık izinse iş günü sayısı bakiyeden düşülür ve izin kurumsal takvim sistemine işlenir.
  • R10. Her durum değişikliğinde talep sahibine, onay bekleyen taleplerde onaycıya e-posta bildirimi gider. Onaycı 2 iş günü içinde karar vermezse kendisine hatırlatma gönderilir.
  • R11. Çalışan onay bekleyen talebini her zaman iptal edebilir. Onaylanmış talebini ancak izin başlamadan önce iptal edebilir; bu durumda düşülen gün bakiyeye iade edilir ve takvim kaydı silinir. İzin başladıktan sonra iptali yalnız İK uzmanı yapabilir.
  • R12. İK uzmanı izin türlerini ve resmi tatilleri tanımlar, çalışan bakiyelerini görüntüler ve gerekçe yazarak düzeltebilir.

Sıradan bir metin: on iki madde, iki sayfa bile değil. Ama içinde beş farklı kişi ya da sistem, dört izin türü, altı durum, iki onay basamağı, bir zaman aşımı ve bir dış sistem var. Bunları metinden tek tek çıkaralım.

İsimlerden Aday Class'lara

Metinden class çıkarmanın en eski sistematik yolu dilbilgisine bakmaktır. Russell Abbott'un 1983'te Communications of the ACM (Association for Computing Machinery) dergisinde yayımlanan "Program Design by Informal English Descriptions" makalesi, düz metindeki isimlerin tiplere ve object'lere, fiillerin operation'lara karşılık geldiğini önerir. Craig Larman'ın "Applying UML and Patterns" kitabı bu tekniği "noun phrase identification" adıyla anlatır ve hemen ardından uyarır: isimden class'a mekanik bir eşleme yoktur, doğal dil belirsizdir ve aynı kavram farklı kelimelerle geçer. Yani teknik bir başlangıç noktasıdır, cevap değil.

02-text-to-model-tr.png

R1–R12'deki isimleri toplayınca uzun bir liste çıkıyor: çalışan, portal, izin talebi, izin türü, tarih, açıklama, taslak, sistem, iş günü, hafta sonu, resmi tatil, bakiye, yıl, rapor dosyası, yönetici, onay, gerekçe, direktör, departman, takvim sistemi, e-posta, hatırlatma, İK uzmanı. Bu listeyi şu sorularla eliyoruz:

Kendi kimliği ve yaşam döngüsü var mı? Bakiye bir sayı gibi görünür, ama "Ada'nın 2026 yılı yıllık izin bakiyesi" ayrı bir şeydir: yılı, hak edilen günü, kullanılan günü var ve İK onu gerekçeyle düzeltebiliyor. Bu yüzden LeaveBalance bir class. Onay da öyle: kim onayladı, ne zaman, hangi basamakta, hangi yorumla; bunlar Approval class'ını doğuruyor.

Başka bir şeyin özelliği mi? Başlangıç tarihi, bitiş tarihi, açıklama ve gerekçe kendi başına yaşamaz; talebin ya da onayın attribute'larıdır. "Taslak" bir class değil, talebin durumudur (state). "Yıl" bakiyenin attribute'u.

Belirsiz ya da sistemin kendisi mi? "Portal" ve "sistem" modellediğimiz şeyin adıdır, içindeki bir kavram değil. "E-posta" ve "hatırlatma" bir davranışın sonucudur; ilk kesitte class yapmıyoruz.

Aynı kavramın başka adı mı? Metinde "talep", "izin talebi" ve bazen yalnızca "izin" geçiyor. "İzin" kelimesi iki ayrı şeye işaret ediyor: çalışanın talep ettiği şey (request) ve onaylandıktan sonra gerçekten kullanılan izin dönemi. Bu modülde ikisini tek LeaveRequest class'ında tutuyoruz, ama bu bir karardır ve bir sözlüğe (glossary) yazılmalıdır. Aynı kavram için tek bir kelime seçip her yerde onu kullanmak, ilerideki Domain-Driven Design serisinde konuşacağımız "ubiquitous language" fikrinin özüdür.

Elimizde kalanlar: Employee, Department, LeaveType, LeaveRequest, LeaveBalance, Approval, PublicHoliday ve rapor dosyası için LeaveAttachment. Çalışan, yönetici ve direktör ayrı class'lar değil; hepsi Employee, yalnızca bir talep karşısındaki rolleri farklı. Bu ayrım bir sonraki yazıda önemli olacak: use case diagram'ında Çalışan ve Yönetici ayrı actor'lardır, çünkü actor bir rolü temsil eder, bir veritabanı kaydını değil.

Bu ilk kesiti hemen koda dökmek, eksikleri görmenin en hızlı yolu. Her tipin üstüne hangi requirement maddesinden geldiğini yazdım:

Employee ada = new(1001, "E-1001", "Ada Lovelace", ManagerId: 420, DepartmentId: 10);
LeaveType annual = new("ANNUAL", "Annual Leave", DeductsFromBalance: true);
LeaveBalance balance = new(ada.Id, annual.Code, Year: 2026, EntitledDays: 14, UsedDays: 6);
LeaveRequest request = new(42, ada.Id, annual.Code, new DateOnly(2026, 12, 21), new DateOnly(2026, 12, 25), WorkingDays: 5);

Console.WriteLine($"Remaining: {balance.RemainingDays}, requested: {request.WorkingDays}");
Console.WriteLine($"Enough balance (R3): {balance.RemainingDays >= request.WorkingDays}");
Console.WriteLine($"Needs director (R7): {request.RequiresDirectorApproval}");

// R1, R6, R7: çalışan, yöneticisi ve departmanı
public sealed record Employee(int Id, string EmployeeNumber, string FullName, int? ManagerId, int DepartmentId);

// R2: izin türü; yalnız yıllık izin bakiyeden düşer
public sealed record LeaveType(string Code, string Name, bool DeductsFromBalance);

// R3, R9, R12: yıllık bakiye; kalan gün saklanmaz, hesaplanır
public sealed record LeaveBalance(int EmployeeId, string LeaveTypeCode, int Year, int EntitledDays, int UsedDays)
{
    public int RemainingDays => EntitledDays - UsedDays;
}

// R1, R2, R7: talep; eşik requirement'taki "3 iş günü"
public sealed record LeaveRequest(int Id, int EmployeeId, string LeaveTypeCode, DateOnly Start, DateOnly End, int WorkingDays)
{
    public const int DirectorApprovalThreshold = 3;
    public bool RequiresDirectorApproval => WorkingDays > DirectorApprovalThreshold;
}
Remaining: 8, requested: 5
Enough balance (R3): True
Needs director (R7): True

Ada'nın 21–25 Aralık talebi 5 iş günü; bakiyesi 8 olduğu için gönderilebilir ve 3'ü aştığı için direktör Grace Hopper'ın onayına gidecek. Bu kod bilerek kaba: Status yok, Approval yok, değişmez record'lar var. İlk kesitin amacı doğru kavramları ve doğru isimleri bulmak; sorumlulukları, durumları ve ilişkileri sonraki yazılarda diyagramlarla ekleyeceğiz. Ama şimdiden bir şey kazandık: DirectorApprovalThreshold adlı sabit, requirement'taki "3" rakamının kodda nerede yaşadığını tek satırda söylüyor.

Fiillerden Use Case'lere ve Operation'lara

Fiiller iki farklı yere gider ve hangisine gideceğini "fiili kim yapıyor?" sorusu belirler.

Fiili bir insan ya da dış sistem kendi amacı için yapıyorsa, aday bir use case'tir: çalışan izin talep eder, yönetici talebi karara bağlar, çalışan talebi iptal eder, İK uzmanı bakiyeyi düzeltir. Alistair Cockburn'ün ölçütüyle iyi bir use case, actor'ın bir oturuşta tamamlayıp "işimi hallettim" diyebileceği bir hedeftir (user goal level). "Tarih seç" ya da "Kaydet'e bas" bu seviyenin altında kalır; "izin süreçlerini yönet" ise üstünde.

Fiili sistemin kendisi yapıyorsa, aday bir operation ya da bir service sorumluluğudur: "sistem iş günü sayısını hesaplar" bir IWorkingDayCalculator'a, "bakiyeden düşülür" LeaveBalance.Deduct()'a, "takvime işlenir" dış sisteme konuşan bir ICalendarGateway'e işaret eder. Edilgen cümleler ("düşülür", "işlenir", "gönderilir") burada ipucudur: işi kimin yaptığını söylemezler ve o sorumluluğu bir class'a vermek senin işin.

"İse", "Sonra", "Ancak": Davranışın İzleri

Metindeki üçüncü tür ipucu koşul ve zaman bildiren kelimeler. Bunlar class diagram'a sığmaz; davranış diyagramlarına gider.

Koşullar guard olur. "3 iş gününü aşan talepler" bir transition'ın ya da bir karar noktasının koşuludur: [workingDays > 3]. "Kalan bakiye azsa gönderilemez" bir ön koşul ya da reddedilen bir transition'dır.

Durum bildiren sıfatlar state olur. "Onay bekleyen", "onaylanmış", "iptal edilmemiş, reddedilmemiş" ifadeleri, talebin bir yaşam döngüsü olduğunu söylüyor. Bir object için metinde bu kadar çok durum sıfatı geçiyorsa, o object bir state machine diagram'ı hak ediyor demektir. R11'deki "onaylanmış talebini ancak izin başlamadan önce" cümlesi aynı anda bir state (Approved) ve bir guard ([today < period.start]) içeriyor.

Sıralama kelimeleri ("önce", "sonra", "onay anında") activity ya da sequence diagram'a işaret eder. R7 bir iş akışı tarifi: önce yönetici, sonra koşullu olarak direktör. Hangi rolün hangi adımı yaptığı activity diagram'ın swimlane'lerine, hangi object'in hangisini çağırdığı sequence diagram'a gider.

Süre bildiren ifadeler ("2 iş günü içinde karar vermezse") zamanla tetiklenen bir event'tir. State machine'de bir time event, sequence diagram'da bir zaman kısıtı, kodda bir background job olarak karşına çıkacak.

Hangi Soru Hangi Diyagramla Cevaplanır?

Bir diyagram çizmeden önce sorulacak soru "hangi diyagramı çizeyim?" değil, "hangi soruyu cevaplamak istiyorum?" olmalı. İzin modülü için soru ve diyagram eşlemesi şöyle:

SoruDiyagramİzin modülündeki cevap
Sistemi kim, hangi amaçla kullanıyor?Use caseÇalışan talep eder, yönetici karara bağlar, İK düzeltir
Hangi kavramlar var, nasıl ilişkili?ClassLeaveRequest, Employee, LeaveBalance, Approval
Belirli bir anda veriler nasıl görünüyor?ObjectAda'nın 42 numaralı talebi ve iki onayı
Bir senaryoda kim kimi hangi sırayla çağırıyor?SequencePOST /leave-requests isteğinin katmanlardan geçişi
İş akışı hangi adımlardan ve kararlardan geçiyor?ActivityYönetici ve direktör onayı, swimlane'lerle
Object hangi durumlardan geçiyor?State machineTaslak, onayda, onaylandı, reddedildi, iptal edildi
Kod hangi modüllere ayrılmış?Component, packageİzin, Bordro, Bildirim modülleri
Nerede çalışıyor?Deployment, C4 (Context, Container, Component, Code)Angular SPA (Single Page Application), API (Application Programming Interface) container'ı, SQL Server
Veritabanında nasıl saklanıyor?ER (Entity-Relationship)Tablolar, foreign key'ler, cardinality

Tablonun her satırı bu serinin bir ya da iki yazısına denk geliyor. Bazı sorular birden fazla diyagramla cevaplanabilir; örneğin onay akışını hem activity hem sequence ile çizebilirsin. Seçimi hedef kitle belirler.

Kime Çiziyoruz? Hedef Kitle ve Detay Seviyesi

Aynı LeaveRequest'i üç farklı kişiye üç farklı detayda çizersin. İK direktörlüğüyle requirement'ı doğrularken use case diagram'ı ve Türkçe adımlı bir activity diagram'ı yeterlidir; tip adı, visibility işareti, DateOnly gibi teknik ayrıntılar orada gürültüdür. Ekip içinde tasarım konuşurken class, sequence ve state machine diagram'ları gerçek class ve method adlarıyla çizilir, çünkü konuşma doğrudan koda dönüşecek. Operasyon ekibiyle konuşurken deployment ve C4 diyagramlarında class yoktur; container, port, protokol ve ortam vardır.

Class diagram'ın kendi içinde de üç seviye konuşulur: conceptual (yalnızca kavram adları ve ilişkiler), analysis (attribute'lar eklenir, tipler kabaca) ve design (tipler, visibility, operation imzaları, interface'ler). Yukarıdaki C# kodu conceptual ile analysis arasında bir yerde. Analysis ile design ayrımını Class Diagram yazılarının sonunda, aynı vakanın iki seviyesini yan yana koyarak işleyeceğiz.

Detay seviyesini seçmek için pratik bir test var: diyagramı gösterdiğin kişi bir öğeye bakıp "bu ne?" diye soruyorsa ve cevap onun işine yaramıyorsa, o öğe o diyagramda fazladır.

Serinin Haritası

Bu tablo ve detay seviyeleri bir araya gelince serinin yolu ortaya çıkıyor. Requirement metninden başlayıp üç soru grubundan geçiyoruz ve sonunda çalışan koda varıyoruz:

02-series-map-tr.png

Her kutu bir sonrakine bilgi taşıyor. Use case'ler sequence diagram'larının senaryolarını, class diagram'ı lifeline'ların tiplerini, state machine diagram'ı switch expression'larını ve unit test senaryolarını, deployment ve C4 diyagramları docker compose dosyasını besliyor. Son yazıda aynı modülü baştan sona bir kez daha geçeceğiz ve "yarım gün izin" gibi yeni bir requirement geldiğinde hangi diyagramların değiştiğini izleyeceğiz.

Sık Düşülen Tuzaklar

Her ismi class yapmak. "Portal", "sistem", "bilgi", "tarih" gibi isimleri class yapan bir model hem büyür hem anlamsızlaşır. Kimliği ve yaşam döngüsü olmayan isimler attribute'tur, belirsiz isimler ise metinden atılır.

Rolü class sanmak. Yönetici ve direktör ayrı class değil; aynı Employee'nin bir talep karşısındaki rolleri. Manager : Employee diye bir inheritance kurmak, bir yönetici başka bir yöneticiye bağlıyken ya da bir direktör kendi izin talebini açarken hemen çöker.

Belirsizliği diyagrama taşımak. "3 gün" ifadesini diyagrama aynen yazmak soruyu çözmez, yalnızca erteler. Modelde bir isme ve tipe dönüşmeyen her ifade, metnin sahibine sorulacak bir sorudur; o soruları bir listede topla.

Her şeyi çizmek. Requirement'taki her cümle için bir diyagram çizen ekip, bir ay sonra hangisinin güncel olduğunu bilmez. Diyagram, cevapladığı soru sorulmaya devam ettiği sürece yaşar; soru sorulmayan diyagram bayatlar ve yanlış bilgi vermeye başlar.

Soruyu yazmamak. Bir diyagramın başlığı "İzin Modülü" ise neyi cevapladığını kimse bilmez. "Bir talep onaylanınca hangi object'ler hangi sırayla çağrılır?" gibi bir başlık, diyagramın kapsamını ve ne zaman eskiyeceğini de söyler.

Küçük Bir Deneme

★☆☆ R10'u (bildirimler ve 2 iş günlük hatırlatma) isim, fiil ve koşul olarak renklendir. Hangi isimler class olmayı hak ediyor, hangileri attribute? Çıkan listeyi yazıdaki aday class'larla karşılaştır.

★★☆ Önce Tahmin Et'teki CountWorkingDays'e R2'deki resmi tatilleri ekle: IReadOnlySet<DateOnly> tipinde bir tatil listesi alsın. 2026'da 29 Ekim Perşembe; 28 Ekim–2 Kasım talebi kaç iş günü tutuyor? Sonuç direktör onayını değiştiriyor mu?

★★★ Kendi projendeki bir requirement metnini ya da issue açıklamasını al ve bu yazıdaki dört soruyla aday class listesi çıkar. Metnin sahibine sormanı gerektiren kaç belirsizlik buldun? Bunları "karar" ve "soru" diye iki listeye ayır.

Bir sonraki yazıda use case diagram'ıyla başlıyoruz: actor, system boundary, use case ve en çok karıştırılan ikili <<include>> ile <<extend>>. Diyagramın tek başına az şey söylediğini görüp "İzin Talep Et" use case'ini Cockburn'ün fully dressed şablonuyla yazacağız.