UML Nedir? Kısa Tarih, UML 2.5.1'in 14 Diyagramı ve Gerçekte Hangilerini Kullanırsın
UML, kodun içine dağılmış modeli herkesin aynı okuduğu bir notasyonla ortaya koyan, OMG'nin standart modelleme dilidir; güncel sürümü 2017 tarihli UML 2.5.1'dir ve 7 structure, 7 behavior olmak üzere 14 diyagram tanımlar. Method savaşlarından bugüne kısa tarih, sahada gerçekten kullanılan diyagramlar, model ile diyagram farkı ve Fowler'ın sketch, blueprint, programming language modları.
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ı) portalının izin modülünde bir talep var: 5 iş günü sürüyor, yani önce yönetici, sonra direktör onaylamalı. Çalışan talebi gönderiyor, yönetici onaylıyor, çalışan fikrini değiştirip iptal ediyor. Bir gün sonra direktör, eski bildirim e-postasındaki onay linkine tıklıyor. Son satır ne yazdırır?
LeaveRequest request = new(id: 42, workingDays: 5);
request.Submit();
request.Approve(); // yönetici onaylar
request.Cancel(); // çalışan vazgeçer
request.Approve(); // direktör, eski e-postadaki linke tıklar
Console.WriteLine(request.Status);
public enum LeaveStatus { Draft, PendingManagerApproval, PendingDirectorApproval, Approved, Rejected, Cancelled }
public sealed class LeaveRequest(int id, int workingDays)
{
public int Id { get; } = id;
public int WorkingDays { get; } = workingDays;
public LeaveStatus Status { get; private set; } = LeaveStatus.Draft;
public void Submit() => Status = LeaveStatus.PendingManagerApproval;
public void Approve() =>
Status = Status == LeaveStatus.PendingManagerApproval && WorkingDays > 3
? LeaveStatus.PendingDirectorApproval
: LeaveStatus.Approved;
public void Cancel()
{
if (Status != LeaveStatus.Approved)
Status = LeaveStatus.Cancelled;
}
}
Cevabı aşağıda; önce koda bakarak, talebin hangi durumdan hangisine geçebildiğini kafanda çizmeye çalış.
Koddaki Gizli Model
Approved
İptal edilmiş talep onaylandı. Bordro bu izni düşecek, takvime işlenecek ve çalışan izne çıkmadığı hâlde bakiyesi azalacak. Kodda derleyici hatası yok, uyarı yok; Approve() yalnızca "yönetici onayı bekliyorsa ve 3 günden uzunsa direktöre gönder" diye düşünüyor, geri kalan her durumda talebi onaylıyor. Cancel() da talep taslak bile olsa onu iptal ediyor.
Burada ilginç olan hata değil, hatanın neden gözden kaçtığı. Bu 30 satırın içinde bir model var: altı durum ve aralarındaki geçişler. Ama model kodun içine dağılmış hâlde. "Hangi durumdan hangisine geçilebilir?" sorusunun cevabı hiçbir satırda yazmıyor; her method'u okuyup kafanda birleştirmen gerekiyor. Aynı bilgiyi bir state machine diagram'ı olarak çizseydin, Cancelled kutusundan çıkan bir "approve" oku olmadığını ilk bakışta görürdün. Kod review'da "bu ok nerede?" sorusu sorulurdu.
Diyagramdaki her oku bir case'e çeviren düzeltilmiş sürüm şöyle:
LeaveRequest request = new(id: 42, workingDays: 5);
request.Submit();
request.Approve();
request.Cancel();
try
{
request.Approve();
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine(request.Status);
public enum LeaveStatus { Draft, PendingManagerApproval, PendingDirectorApproval, Approved, Rejected, Cancelled }
public sealed class LeaveRequest(int id, int workingDays)
{
public int Id { get; } = id;
public int WorkingDays { get; } = workingDays;
public LeaveStatus Status { get; private set; } = LeaveStatus.Draft;
public void Submit() => Status = Status == LeaveStatus.Draft
? LeaveStatus.PendingManagerApproval
: throw Invalid(nameof(Submit));
// Diyagramdaki her ok bir case; ok yoksa exception
public void Approve() => Status = Status switch
{
LeaveStatus.PendingManagerApproval when WorkingDays > 3 => LeaveStatus.PendingDirectorApproval,
LeaveStatus.PendingManagerApproval => LeaveStatus.Approved,
LeaveStatus.PendingDirectorApproval => LeaveStatus.Approved,
_ => throw Invalid(nameof(Approve))
};
public void Cancel() => Status = Status switch
{
LeaveStatus.PendingManagerApproval or LeaveStatus.PendingDirectorApproval => LeaveStatus.Cancelled,
_ => throw Invalid(nameof(Cancel))
};
private InvalidOperationException Invalid(string action) =>
new($"Request {Id}: '{action}' is not allowed in status {Status}.");
}
Request 42: 'Approve' is not allowed in status Cancelled.
Cancelled
Bu sürüm de eksik: requirement'a göre onaylanmış bir izin, izin başlamadan önce iptal edilebilmeli ve bunun için tarih kontrolü gerekiyor. O ayrıntıya State Machine yazısında döneceğiz. Bu yazının konusu şu: kodun içinde her zaman bir model vardır; UML (Unified Modeling Language) o modeli koddan ayrı, herkesin aynı şekilde okuyabildiği bir notasyonla ortaya koymanın yoludur. Status field'ının neden her yerden güncellenmemesi gerektiğini veritabanı tarafından merak ediyorsan, Çözüm Desenleri serisinin "Status Field'ı Her Yerden Güncelleniyorsa" yazısı aynı problemi transition table ile çözüyor.
UML Nedir, Ne Değildir
UML, yazılım sistemlerini belirtmek, görselleştirmek ve belgelemek için kullanılan, OMG (Object Management Group) tarafından yönetilen standart bir modelleme dilidir. "Dil" kelimesi önemli: UML'in bir notasyonu (kutu, ok, elmas, çubuk adam) ve bu notasyonun arkasında her öğenin ne anlama geldiğini tanımlayan bir metamodel'i vardır. Bir class kutusundaki - startDate: DateOnly [1] satırı keyfi bir yazım değildir; spesifikasyonda bir property'nin visibility'si, adı, tipi ve multiplicity'si olarak tanımlanmıştır. Bu yüzden iki farklı ekip aynı diyagramı aynı şekilde okuyabilir.
UML bir süreç ya da metodoloji değildir. Hangi diyagramı ne zaman çizeceğini, kimin onaylayacağını ya da kaç tane çizeceğini söylemez. 2000'lerde UML ile birlikte anılan RUP (Rational Unified Process) ayrı bir süreç önerisiydi; ikisini karıştırmak, UML'in "ağır ve bürokratik" diye anılmasının nedenlerinden biri oldu. UML ayrıca bir araç da değildir: kâğıt kalemle, beyaz tahtada, PlantUML gibi metin tabanlı bir araçla ya da büyük bir modelleme aracıyla aynı notasyonu kullanabilirsin.
Güncel formal sürüm UML 2.5.1'dir; OMG Aralık 2017'de yayımladı (belge numarası formal/17-12-05) ve o tarihten bu yana yeni bir formal sürüm çıkmadı. Spesifikasyon yaklaşık 800 sayfa. Kimse onu baştan sona okuyarak UML öğrenmez; ama bir notasyon tartışmasında son sözü o söyler. Bu seride "UML böyle der" dediğim her yerde kaynak bu belge.
Kısa Bir Tarih: Method Savaşlarından UML 2.5.1'e
1990'ların başında object-oriented analiz ve tasarım için onlarca yöntem vardı ve her birinin kendi notasyonu vardı. En yaygın üçü şunlardı: Grady Booch'un Booch method'u, James Rumbaugh ve ekibinin 1991'de yayımladığı OMT (Object Modeling Technique) ve Ivar Jacobson'ın use case kavramını merkeze koyan OOSE (Object-Oriented Software Engineering). Bir class'ı Booch bulut şeklinde, OMT dikdörtgen olarak çiziyordu; aynı ekipte iki notasyon kullanan iki kişi birbirinin diyagramını okuyamıyordu. Dönemin bu hâli sonradan "method savaşları" diye anıldı.
Ekim 1994'te Rumbaugh, Booch'un çalıştığı Rational Software'e katıldı ve ikisi yöntemlerini birleştirmeye başladı. 1995'te Jacobson da katıldı; üçü bu yüzden "üç amigo" diye anılır. Haziran 1996'da UML 0.9 yayımlandı, Ocak 1997'de UML 1.0 OMG'ye standart önerisi olarak sunuldu ve diğer şirketlerin katkılarıyla genişleyen UML 1.1, Kasım 1997'de OMG tarafından standart olarak kabul edildi. Sonraki adımlarda iki kez de ISO (International Organization for Standardization) ile IEC'nin (International Electrotechnical Commission) ortak standardı oldu:
| Sürüm | Yıl | Ne değişti |
|---|---|---|
| UML 1.1 | 1997 | İlk OMG standardı; 9 diyagram türü |
| UML 1.4.2 | 2005 | ISO/IEC 19501:2005 olarak uluslararası standart oldu |
| UML 2.0 | 2005 | Büyük revizyon: sequence diagram'a combined fragment'ler, yeni diyagram türleri, 13 diyagram |
| UML 2.2 | 2009 | Profile diagram ayrı bir tür oldu; toplam 14 |
| UML 2.4.1 | 2011 | ISO/IEC 19505-1 ve 19505-2:2012 olarak yayımlandı |
| UML 2.5 | 2015 | Infrastructure ve Superstructure tek belgede birleşti, metin sadeleşti; metamodel 2.4.1 ile teknik olarak eşdeğer |
| UML 2.5.1 | 2017 | Hata düzeltmeleri; bugün hâlâ güncel formal sürüm |
ISO/IEC numaraları kurumsal ihalelerde ve sözleşmelerde karşına çıkabilir; günlük işte "UML 2.5.1 notasyonuyla" demek yeterli. Tablodan çıkarılacak pratik ders şu: internette gördüğün UML örneklerinin önemli bir kısmı UML 1.x döneminden kalma. Sequence diagram'da alt ve loop kutuları yerine dallanan oklar görüyorsan ya da "collaboration diagram" adını okuyorsan, eski bir kaynağa bakıyorsun. UML 2.0'da collaboration diagram'ın adı communication diagram oldu.
14 Diyagram: Structure ve Behavior
UML 2.5.1 spesifikasyonunun Annex A'sı diyagramları bir taxonomy ile gruplar. İlk ayrım basit: structure diyagramları sistemin zamandan bağımsız yapısını (ne var, neyle bağlı), behavior diyagramları zaman içinde ne olduğunu (kim ne yapar, hangi sırayla, hangi duruma geçer) gösterir. Behavior'un içinde, object'ler arasındaki mesajlaşmaya odaklanan dört diyagram ayrıca "interaction diagram" diye gruplanır.

Figürdeki oklar da UML: içi boş üçgen generalization demek, yani "Class Diagram bir Structure Diagram'dır". İtalik yazılan dört kutu abstract kategoridir; "bir structure diagram çizdim" diyemezsin, ancak onun bir türünü çizersin. Her diyagramın cevapladığı soruyu bir cümleyle söylersek:
- Class: hangi kavramlar var, hangi bilgiyi taşıyorlar, birbirleriyle nasıl ilişkili? Object: belirli bir anda bu kavramların somut örnekleri neler? Package: kod hangi gruplara ayrılmış ve gruplar birbirine nasıl bağımlı?
- Component ve Composite Structure: sistem hangi değiştirilebilir parçalardan oluşuyor ve parçalar hangi interface'ler üzerinden konuşuyor? Deployment: hangi parça hangi makinede ya da container'da çalışıyor? Profile: UML'i kendi alanına göre nasıl genişlettin?
- Use Case: sistemi kim, hangi amaçla kullanıyor? Activity: bir iş akışı hangi adımlardan, hangi kararlardan ve paralel kollardan geçiyor? State Machine: bir object hangi durumlardan geçer, hangi event onu hangi duruma taşır?
- Sequence: bir senaryoda kim kimi hangi sırayla çağırıyor? Communication: aynı etkileşimde kim kiminle bağlantılı? Interaction Overview: birden fazla etkileşim hangi akışla birleşiyor? Timing: durum değişiklikleri zaman ekseninde ne zaman oluyor?
Taxonomy katı bir kural değildir; spesifikasyon da farklı türlerin öğelerini aynı diyagramda karıştırmayı yasaklamaz. Ayrıca serinin iki önemli konuğu bu ağaçta yok: C4 (Context, Container, Component, Code: Simon Brown'ın yazılım mimarisini dört zoom seviyesinde anlatan yaklaşımı) model ve ER (Entity-Relationship) diagram UML'in parçası değildir, ama mimari ve veri modelinde UML'den daha sık kullanılırlar. Seride ikisine de ayrı yazı ayırdık.
Gerçekte Hangilerini Kullanırsın?
14 diyagramın hepsini aktif kullanan bir ekiple karşılaşma ihtimalin düşük. Bunun en iyi belgelenmiş kanıtı Marian Petre'nin ICSE (International Conference on Software Engineering) 2013'te sunduğu "UML in Practice" çalışması. Petre 50 farklı şirketten 50 profesyonel yazılımcıyla görüştü: 35'i UML kullanmıyordu, hiçbiri UML'i "eksiksiz" kullanmıyordu, 11'i ise seçici kullanıyordu. Bu seçici kullanıcıların en çok başvurduğu diyagramlar sırasıyla class, sequence ve activity diagram'lardı; state machine ve use case diagram'lar listenin sonundaydı. Bu bir anket değil, nitel bir görüşme çalışması; yüzdeleri genelleştirmek doğru olmaz. Ama verdiği tablo sahada gördüğümle örtüşüyor: UML işe yaradığı yerde, parça parça ve hedef kitleye göre uyarlanarak kullanılıyor.
Bu seride ağırlık verdiğimiz yedi diyagram şunlar: use case, class, object/package, sequence, activity, state machine, component/deployment. Seçim ölçütü, "bir .NET ekibinin gerçek bir projede hangi soruyu sorduğunda bu diyagrama ihtiyaç duyduğu". Class diagram domain modelini ve Entity Framework Core (EF Core) entity'lerini tartışırken, sequence diagram bir API (Application Programming Interface) isteğinin hangi katmanlardan geçtiğini konuşurken, state machine bir status field'ının kurallarını belirlerken, deployment ve C4 yeni gelen birine sistemi anlatırken işe yarıyor. Timing ve interaction overview diagram'lar kendi nişlerinde (gömülü sistemler, protokol tasarımı) değerli, ama bir İK portalında onlara ihtiyaç duyacağın an nadir; onları sequence diagram yazısında kısaca tanıyacağız.
Model ve Diyagram Aynı Şey Değil
UML'de en sık gözden kaçan ayrım bu. Model, sistemin bütün öğelerini (class'lar, ilişkiler, state'ler, mesajlar) içeren tek bir yapıdır. Diyagram ise o modelin bir kısmına açılan penceredir.

LeaveRequest class'ı modelde bir kez tanımlıdır. Class diagram'da kutu olarak, state machine diagram'da yaşam döngüsünün sahibi olarak, sequence diagram'da bir lifeline olarak görünür; üçü de aynı öğeye bakar. Spesifikasyon her diyagramın bir çerçevesi (frame) olabileceğini ve sol üst köşedeki başlığın diyagramın türünü ve neyi gösterdiğini söyleyeceğini tanımlar: stm LeaveRequest state machine, sd SubmitLeaveRequest sequence diagram, uc use case, act activity. Figürdeki çerçeve başlıkları bu yazımı kullanıyor.
Bu ayrımın pratik sonuçları var. Birincisi, bir diyagramda bir öğeyi göstermemek onu modelden silmek değildir. Sequence diagram'ında IBalanceService'i çizmediysen, sistemde bakiye kontrolü yok demek değil; o senaryoda konuşmak istemediğin bir ayrıntı demek. İkincisi, model tabanlı bir araçta (Enterprise Architect, MagicDraw gibi) bir class'ın adını değiştirdiğinde onu gösteren bütün diyagramlar güncellenir; çizim aracında (draw.io gibi) ise her diyagram bağımsız bir resimdir ve tutarlılık senin sorumluluğundur. Üçüncüsü, bu seride yapacağımız gibi kodu "asıl model" kabul edip diyagramları koddan türetilmiş ya da koda bakan pencereler olarak tutmak da meşru bir seçim. O zaman koddaki LeaveStatus enum'ı modelin kendisidir ve diyagram onun okunabilir bir görünümüdür.
Fowler'ın Üç Modu ve Bu Serinin Çizgisi
Martin Fowler 2003'te yazdığı "UmlMode" yazısında, insanların UML hakkında anlaşamamasının nedenini UML'i üç farklı amaçla kullanmalarına bağlar. Steve Mellor'ın da bağımsız olarak aynı ayrıma vardığını not eder.
Sketch modunda diyagram düşünmek ve anlatmak içindir. Seçicidir: yalnızca o konuşmada önemli olan kısım çizilir. Beyaz tahtada on dakikalık bir tasarım tartışmasında (forward sketching) ya da mevcut bir kodu yeni gelene anlatırken (reverse sketching) kullanılır. Fowler'ın bu mod için kullandığı cümle akılda kalıcıdır: "comprehensiveness is the enemy of comprehensibility", yani her şeyi göstermeye çalışmak anlaşılırlığın düşmanıdır. Notasyonun her kuralına uyulmayabilir; amaç iletişimdir.
Blueprint modunda diyagram eksiksiz bir tasarım belgesidir: bir tasarımcı çizer, bir programcı fazla düşünmeden koda çevirebilir. Bu mod araç desteğine ve notasyon doğruluğuna ihtiyaç duyar, ama modelin kodla senkron kalması ciddi bir emek ister. Programming language modunda ise UML'in kendisi çalıştırılabilir koddur; MDA (Model Driven Architecture) ve fUML (Foundational UML) bu çizginin örnekleridir. Fowler bu moda hep şüpheyle baktı ve bu seri de onu kapsam dışında bırakıyor.
Bu seri sketch ile "koda yakın blueprint" arasında duruyor. Diyagramları notasyonu doğru, ama yalnızca bir soruyu cevaplayacak kadar detaylı çiziyoruz; her diyagram öğesinin C# ve .NET 10 kodunda neye karşılık geldiğini gösteriyoruz; diyagramların metin olarak repo'da tutulmasını (PlantUML ve Mermaid) son yazılarda işliyoruz. Bütün seri boyunca tek bir vaka kullanacağız: kurgusal bir İK portalının "İzin Talebi" modülü. Çalışan izin talebi açar, yöneticisi onaylar ya da reddeder, 3 iş gününü aşan talepler direktöre gider, onaylanan yıllık izin bakiyeden düşer ve takvime işlenir, iptalin de kendi kuralları vardır. Bir sonraki yazıda bu requirement metnini madde madde yazıp ondan model çıkaracağız; sonra aynı vakayı use case'ten class'a, sequence'tan state machine'e, deployment'tan C4'e kadar taşıyacağız.
Sık Düşülen Tuzaklar
UML'i "hepsi ya da hiçbiri" diye görmek. Birçok ekip UML'i 14 diyagramın hepsini eksiksiz çizmek olarak algıladığı için hiç kullanmıyor. Oysa tek bir state machine diagram'ı, yukarıdaki iptal edilmiş talebin onaylanması gibi bir hatayı review'da yakalatabilir. Bir diyagramın değeri, cevapladığı sorunun değeri kadardır.
Eski notasyonla çizmek. Booch bulutları, UML 1.x'in dallanan sequence okları ya da "collaboration diagram" terimi bugün okuyanı yanıltır. Bir kaynağın ne zaman yazıldığına bak; emin olmadığın bir notasyonu UML 2.5.1 spesifikasyonunda ya da uml-diagrams.org gibi spesifikasyona dayanan bir referansta doğrula.
Diyagramı modelin kendisi sanmak. Bir diyagramdaki eksik ilişki, sistemde o ilişkinin olmadığını göstermez. Okurken her zaman "bu diyagram hangi soruyu cevaplamak için çizilmiş?" diye sor; çizerken de bu soruyu başlığa ya da açıklamaya yaz.
Modu karıştırmak. Sketch olarak çizilmiş bir diyagramı blueprint gibi okumak ("burada Employee'nin Email'i yok, demek ki tutmayacağız") ya da blueprint beklenen bir yerde beyaz tahta fotoğrafı paylaşmak, iki tarafı da hayal kırıklığına uğratır. Diyagramı paylaşırken hangi modda çizdiğini söyle.
Notasyonu "nasılsa sketch" diye önemsememek. Sketch modu esneklik tanır, ama içi boş elmas ile dolu elmas, düz ok ile kesik ok farklı şeyler söyler. Yanlış ok, yanlış kod demektir. Bu serinin class diagram yazılarında her okun C# karşılığını bu yüzden tek tek göstereceğiz.
Küçük Bir Deneme
★☆☆ İlk koddaki LeaveRequest için kâğıda altı kutu (her LeaveStatus değeri için bir tane) çiz ve kodun izin verdiği her geçişi bir okla göster. Kaç ok çıktı? Hangileri requirement'a göre hiç olmamalı?
★★☆ Düzeltilmiş koda Reject(string reason) method'unu ekle: yalnızca iki pending durumdan Rejected'a geçilebilsin ve boş gerekçe reddedilsin. Önce okları çiz, sonra switch'i yaz ve iptal edilmiş bir talebi reddetmeye çalışan bir satırla dene.
★★★ Çalıştığın projede son altı ayda yazılmış bir tasarım dokümanı ya da wiki sayfası bul. İçindeki diyagramların türünü bu yazıdaki taxonomy'ye göre adlandır ve her biri için Fowler'ın üç modundan hangisinde çizildiğini, hâlâ kodla uyumlu olup olmadığını not et.
Sonraki yazıda İK portalının izin modülü için requirement metnini yazıyoruz ve ondan model çıkarmayı deniyoruz: isimlerden aday class'lara, fiillerden use case ve operation'lara, "ise" ile başlayan cümlelerden activity ve state machine'e. Ardından her diyagram türünü cevapladığı soruyla eşleştiren bir tablo ve serinin haritası gelecek.