Yazılım Mühendisliği: Süreç, Gereksinim, Tasarım ve Kalite
Yazılım yaşam döngüsü, proje yönetimi, kalite, test, bakım, gereksinim, tasarım, mimari ve AI/ML sistemlerinde yeniden üretilebilir yapılandırmayı kapsayan ders notları.
Yazılım mühendisliği notlarını süreç modelleri, proje yönetimi, kalite, test, bakım, gereksinim ve tasarım arasında bağ kurmak için tutmuştum. Klasik süreç ve tasarım yöntemleri tarihsel bağlamıyla korunurken DevOps, sürekli teslim ve güncel kalite standartları daha sonraki uygulama katmanını oluşturur. Tarihsel yöntemler ile güncel uygulama biçimleri aynı dönemin pratikleriymiş gibi değerlendirilmemelidir.
Ünite 1: Yazılım Mühendisliğine Giriş
Yazılım ve yazılım mühendisliği
Yazılım yalnız kaynak koddan oluşmaz. Çalışan programın yanında gereksinim tanımları, mimari ve ayrıntılı tasarım, testler, yapılandırma bilgileri, kullanıcı ve işletim belgeleri, bakım bilgileri ve dağıtım için gerekli diğer varlıklar da yazılım ürününün parçasıdır.
Yazılım mühendisliği, yazılım sistemlerinin planlı, ölçülebilir, sınanabilir ve sürdürülebilir biçimde geliştirilmesini amaçlayan mühendislik disiplinidir. Temel hedef yalnız çalışan kod üretmek değildir. Beklenen işlevleri doğru gerçekleştiren, belirlenen kalite özelliklerini sağlayan, ekonomik olarak geliştirilebilen ve yaşam döngüsü boyunca yönetilebilen yazılım üretmektir.
Yazılım mühendisliği şu alanlarla doğrudan ilişkilidir:
- bilgisayar bilimi,
- sistem mühendisliği,
- proje yönetimi,
- kalite yönetimi,
- ekonomi,
- insan-bilgisayar etkileşimi,
- güvenlik,
- işletim ve bakım.
Bir yazılım projesinde teknik olarak doğru çözüm yeterli değildir. Çözümün süre, bütçe, kalite, güvenlik ve bakım kısıtları içinde gerçekleştirilebilmesi gerekir.
Program, yazılım ve donanım
Program, belirli bir işi gerçekleştirmek üzere yazılmış komutlar bütünüdür. Yazılım ise programdan daha geniş bir kavramdır. Kaynak kodun yanında yapılandırma, veri tanımları, testler, gereksinimler, tasarım belgeleri, kullanım ve işletim bilgileri gibi ürünün geliştirilmesi ve yaşatılması için gerekli varlıkları da kapsar.
Donanım fiziksel olarak üretilir ve zamanla aşınabilir. Yazılım fiziksel olarak aşınmaz. Buna karşılık değişiklikler, bağımlılıkların yaşlanması, hatalı bakım ve artan karmaşıklık nedeniyle yazılımın sürdürülebilirliği zamanla bozulabilir.
Bir yazılım kopyasını çoğaltmanın marjinal maliyeti düşük olabilir; mühendislik maliyeti ise gereksinimi anlamada, tasarımda, geliştirmede, doğrulamada, dağıtımda, işletimde ve bakımda oluşur. Bu yüzden yazılım maliyetini kod satırı veya kurulum kopyası gibi tek bir büyüklüğe indirgemek anlamlı değildir.
Yazılım mühendisi ve üretim ortamı
Yazılım mühendisi yalnız program yazan kişi değildir. Yazılım ürününün yaşam döngüsü boyunca teknik kararların, insan ilişkilerinin, kalite hedeflerinin ve proje kısıtlarının birlikte yönetilmesine katkı verir.
Bir yazılım üretim ortamında genellikle şu roller bulunabilir:
- ürün veya iş alanı sorumluları,
- gereksinim ve sistem analistleri,
- yazılım mimarları,
- geliştiriciler,
- test ve kalite uzmanları,
- veri tabanı ve altyapı uzmanları,
- güvenlik uzmanları,
- işletim ve destek ekipleri.
Küçük ekiplerde aynı kişi birden fazla rol üstlenebilir. Büyük sistemlerde ise sorumluluklar daha belirgin biçimde ayrılır. Önemli olan rol adları değil, karar ve sorumluluk sınırlarının açık olmasıdır.
Yazılım sistemlerinin sınıflandırılması
Yazılım sistemleri kullanım alanı ve çalışma biçimine göre farklı sınıflarda incelenebilir:
- sistem yazılımları,
- iş ve bilgi sistemleri,
- gömülü ve gerçek zamanlı sistemler,
- bilimsel ve mühendislik yazılımları,
- web ve dağıtık uygulamalar,
- mobil uygulamalar,
- veri yoğun sistemler,
- yapay zeka ve karar destek sistemleri.
Bir ürün birden fazla sınıfa aynı anda girebilir. Örneğin gerçek zamanlı çalışan bir gömülü sistem aynı zamanda ağ üzerinden dağıtık hizmetlerle haberleşebilir.
Yazılım krizinden günümüze
Yazılım mühendisliğinin bağımsız bir disiplin olarak ortaya çıkmasında 1960'ların sonlarında belirginleşen yazılım krizi önemli rol oynadı. Donanım hızla gelişirken büyük yazılım projeleri:
- bütçeyi aşabiliyor,
- planlanan zamanda tamamlanamıyor,
- beklenen işlevleri eksik karşılıyor,
- çok sayıda hata içeriyor,
- bakım sırasında hızla karmaşıklaşıyordu.
Sorunun yalnız programlama dili veya donanım yetersizliği olmadığı anlaşıldı. Gereksinimlerin yönetilmesi, mimari tasarım, ekip organizasyonu, konfigürasyon yönetimi, test, kalite güvencesi ve bakımın da mühendislik disiplini içinde ele alınması gerekiyordu.
Bugün aynı problem farklı ölçekte devam eder. Modern sistemler dağıtık servisler, mobil istemciler, bulut ve uç altyapıları, güvenlik bileşenleri, yapay zeka modelleri, veri hatları ve üçüncü taraf bağımlılıkları içerebilir. Yazılım mühendisliğinin temel problemi yine aynıdır: karmaşıklığı denetim altında tutmak.
Yazılım sorunlarının temel kaynakları
Yazılım projelerindeki güçlükler genellikle tek bir nedene indirgenemez. Yaygın sorunlar şunlardır:
- gereksinimlerin eksik veya sürekli değişmesi,
- sistem sınırlarının yanlış belirlenmesi,
- tasarım kararlarının belgelenmemesi,
- mimari borcun büyümesi,
- maliyet ve süre tahminlerinin gerçekçi olmaması,
- testin geliştirme sürecinin sonuna bırakılması,
- sürüm ve değişiklik yönetiminin zayıf olması,
- ekip içi iletişim sorunları,
- teknik borcun kontrolsüz büyümesi,
- güvenlik ve işletilebilirliğin sonradan düşünülmesi.
Yazılım mühendisliği bu sorunların hiçbirini tamamen ortadan kaldırmaz. Ama sorunların erken görünür hale gelmesini, ölçülmesini ve yönetilebilir hale gelmesini sağlar.
Hataların yaşam döngüsünde yayılması
Yazılım geliştirme aşamaları birbirine girdi üretir. Gereksinim aşamasındaki bir yanlış tasarıma, kodlamaya, teste ve kullanıcı belgelerine kadar taşınabilir.
Basit zincir şöyledir:
Yanlış gereksinim
↓
Yanlış tasarım
↓
Yanlış gerçekleştirim
↓
Yanlış veya eksik test beklentisi
↓
Üretim hatasıBu nedenle hatanın erken bulunması genellikle daha ucuzdur. Bununla birlikte belirli bir hata için sabit ve evrensel bir maliyet çarpanı yoktur. Etki; sistemin büyüklüğüne, kritikliğine, dağıtım biçimine ve değişikliğin yayıldığı bileşenlere göre değişir.
Bu düşünce modern geliştirmede gereksinim incelemeleri, erken prototipleme, sürekli entegrasyon, otomatik test ve kısa geri bildirim çevrimleriyle desteklenir.
Yazılım geliştirme yaşam döngüsü
Bir yazılım sistemi genel olarak şu etkinliklerden geçer:
- ihtiyaç ve kapsamın belirlenmesi,
- gereksinimlerin çıkarılması ve analizi,
- mimari ve ayrıntılı tasarım,
- gerçekleştirim,
- doğrulama ve test,
- dağıtım,
- işletim,
- bakım ve geliştirme,
- kullanım dışına çıkarma.
Bu sıra her projede doğrusal olmak zorunda değildir. Çevik ve artımlı modellerde aynı etkinlikler küçük çevrimler halinde tekrar edilir.
ISO/IEC/IEEE 12207:2026 yazılım yaşam döngüsünü edinim, tedarik, geliştirme, işletim, bakım ve kullanımdan kaldırmaya kadar uzanan ortak bir süreç çerçevesi içinde ele alır. Modern yaklaşımda yazılım geliştirme, kodlama aşamasından çok daha geniş bir yaşam döngüsüdür.
Yazılım geliştirme planı
Yazılım geliştirme planı projenin nasıl yürütüleceğini belirler.
Plan en az şu sorulara yanıt vermelidir:
- Ne geliştirilecek?
- Neden geliştirilecek?
- Kim geliştirecek?
- Hangi kaynaklar kullanılacak?
- Hangi süreç izlenecek?
- Ne kadar sürecek?
- Ne kadar maliyet oluşturacak?
- Başlıca riskler nelerdir?
- Kalite nasıl ölçülecek?
- Değişiklikler nasıl yönetilecek?
- Ürün ne zaman kabul edilmiş sayılacak?
Plan bir kez hazırlanıp değişmeden kalan belge değildir. Yeni bilgi geldikçe tahminler ve riskler güncellenir.
Gereksinim analizi
Gereksinim analizi, sistemin ne yapması gerektiğini ve hangi kısıtlar altında çalışacağını belirler.
Gereksinimler yalnız işlevleri içermez. Şunlar da gereksinimdir:
- performans,
- güvenlik,
- kullanılabilirlik,
- erişilebilirlik,
- güvenilirlik,
- bakım yapılabilirlik,
- mevzuat uyumu,
- veri bütünlüğü,
- platform ve arabirim kısıtları.
Gereksinim analizi tasarımdan önce "ne" sorusunu netleştirir. Tasarım ise "nasıl" sorusunu yanıtlar.
Tasarım
Tasarım, gereksinimleri gerçekleştirilebilir bir teknik yapıya dönüştürür.
İki düzeyde düşünülebilir:
Mimari tasarım: Sistemin büyük bileşenlerini, sorumluluklarını, veri ve kontrol ilişkilerini belirler.
Ayrıntılı tasarım: Bileşenlerin iç yapısını, sınıfları, veri yapılarını, algoritmaları ve arabirim ayrıntılarını belirler.
Tasarımın amacı yalnız diyagram üretmek değildir. Karmaşıklığı uygun sınırlara bölmek ve değişikliğin etkisini kontrol altında tutmaktır.
Yazılımın sınanması
Test, geliştirilen sistemin beklenen davranışı sağlayıp sağlamadığını araştırır.
Test yalnız sona bırakılan kabul işlemi değildir. Modern geliştirmede test:
- birim düzeyinde,
- bileşenler arasında,
- sistem düzeyinde,
- kabul düzeyinde,
- performans ve güvenlik açısından
yaşam döngüsünün tamamına yayılır.
Test hatanın varlığını gösterebilir. Bütün olası hataların bulunmadığını kanıtlayamaz. Bu nedenle test, inceleme, statik analiz, tip sistemi, kod gözden geçirme ve çalışma zamanı gözlemlenebilirliği gibi başka kalite mekanizmalarıyla birlikte kullanılmalıdır.
Bakım ve geliştirme
Yazılımın teslim edilmesi yaşam döngüsünün sonu değildir.
Kullanım sırasında:
- hatalar düzeltilir,
- çalışma ortamına uyarlamalar yapılır,
- yeni işlevler eklenir,
- performans iyileştirilir,
- güvenlik açıkları giderilir,
- bağımlılıklar güncellenir,
- teknik borç azaltılır.
Bakım maliyeti özellikle uzun ömürlü sistemlerde geliştirme maliyetinin önemli bölümünü oluşturabilir. Bu nedenle bakım yapılabilirlik, ilk tasarım aşamasından itibaren bir kalite hedefidir.
Süreç olgunluğu
Ders notlarında yazılım süreç olgunluğu beş seviyeli klasik Capability Maturity Model, CMM üzerinden ele alınır:
- Başlangıç,
- Tekrarlanabilir,
- Tanımlanmış,
- Yönetilebilir,
- Optimize edilmiş.
Bu model yazılım süreçlerinin kişisel çabadan kurumsal ve ölçülebilir süreçlere doğru olgunlaşmasını açıklamak için önemlidir.
Güncel karşılığı CMMI ailesidir. CMMI V3.0, yalnız yazılım geliştirmeyi değil geliştirme, hizmet, tedarikçi yönetimi, güvenlik, emniyet, veri, insan ve sanal çalışma gibi daha geniş kurumsal yetenek alanlarını bütünleşik biçimde ele alır.
Temel fikir değişmemiştir:
Süreç iyileştirme, tek tek kişilerin kahramanca çabasından tekrarlanabilir ve ölçülebilir kurumsal yeteneğe geçiştir.
Yazılım süreç modelleri
Bir süreç modeli, yaşam döngüsü etkinliklerinin hangi sırayla ve hangi geri besleme mekanizmalarıyla yürütüleceğini tanımlar.
Tek bir süreç modeli bütün projeler için en iyi değildir. Seçim şu özelliklere bağlıdır:
- gereksinimlerin kararlılığı,
- güvenlik ve emniyet kritiklik düzeyi,
- teslim sıklığı,
- ekip büyüklüğü,
- mevzuat yükü,
- müşteri geri bildirimi ihtiyacı,
- teknik belirsizlik,
- risk düzeyi.
Gelişigüzel ve tarihsel doğrusal modeller
Sistematik süreç kullanılmadan kişisel alışkanlıklara göre yapılan geliştirme, tarihsel olarak gelişigüzel model biçiminde açıklanmıştır. Küçük ve geçici programlarda çalışabilir görünse de izlenebilirlik, bakım, ekip çalışması ve tekrar üretilebilirlik açısından zayıftır.
Barok model, yaşam döngüsü aşamalarını doğrusal biçimde ele alan ve belgelemeye ayrı bir aşama gibi ağırlık veren tarihsel yaklaşımdır. Temel sınırlaması, geri dönüş ve değişiklik mekanizmalarını yeterince açık tanımlamamasıdır.
Bu modellerin güncel değeri doğrudan uygulanmalarından çok, yazılım mühendisliğinin neden süreç, izlenebilirlik ve sürekli belge üretimi gerektirdiğini göstermeleridir.
Şelale modeli
Şelale modelinde süreç ana aşamalar halinde ilerler:
Gereksinimler
↓
Tasarım
↓
Gerçekleştirim
↓
Test
↓
Dağıtım
↓
BakımAvantajı aşamaların ve çıktılarının açık olmasıdır.
Zayıf yönü, gereksinimlerin erken ve büyük ölçüde sabitlenmesini varsaymasıdır. Geç bulunan yanlış gereksinim pahalı geri dönüşlere neden olabilir.
Şelale yaklaşımı tamamen geçersiz değildir. Gereksinimleri kararlı, sözleşmeli ve güçlü dokümantasyon gerektiren bazı projelerde halen uygun olabilir.
V modeli
V modeli, doğrulama ve geçerleme faaliyetlerini geliştirme aşamalarıyla eşleştirir.
Kavramsal yapı:
Gereksinimler ---------------- Kabul testi
\ /
Sistem tasarımı ------- Sistem testi
\ /
Mimari ---------- Entegrasyon testi
\ /
Ayrıntılı tasarım
\ /
KodlamaSol taraf tanımlama ve tasarım, sağ taraf karşılık gelen test düzeylerini gösterir. Temel mesaj, test planlamasının kodlama bittikten sonra başlamaması gerektiğidir.
Gereksinimler kabul testinin, mimari tasarım sistem ve entegrasyon testlerinin, ayrıntılı tasarım ise birim testlerinin dayanağını oluşturur.
V modeli özellikle güçlü izlenebilirlik, doğrulama ve düzenleyici kanıt gerektiren projelerde öğretici bir çerçevedir.
Prototip destekli V yaklaşımı
Klasik notlarda VP süreç modeli, V modelinin üretim tarafına farklı düzeylerde prototipleme eklenmiş biçimi olarak ele alınır.
Amaç her aşamada belirsizliği azaltmaktır:
- kullanıcı gereksinimi için arayüz prototipi,
- mimari belirsizlik için teknik prototip,
- gerçekleştirim riski için deneysel kod.
Prototipin hangi soruyu yanıtlamak için geliştirildiği baştan belirlenmelidir. Aksi halde geçici kodun fark edilmeden üretim sistemine dönüşmesi riski vardır.
Prototipleme
Prototipleme, gereksinim veya tasarım belirsizliğini azaltmak için sistemin sınırlı bir modelinin oluşturulmasıdır.
Prototip:
- kullanıcı arabirimini sınamak,
- teknik yapılabilirliği görmek,
- gereksinimleri netleştirmek,
- riskli teknik varsayımları denemek
için kullanılabilir.
Bir prototipin üretim sistemine dönüşeceği varsayılmamalıdır. Hızlı hazırlanan prototipte alınan kısa vadeli tasarım kararları doğrudan kalıcı sisteme taşınırsa teknik borç oluşabilir.
Dördüncü kuşak tekniklerinden kod üretimine
Ders notlarında 4GT, Fourth Generation Techniques yüksek düzeyli tanımlardan kod üretme yaklaşımı olarak ele alınır.
Bu fikir günümüzde farklı biçimlerde yaşamaktadır:
- model güdümlü geliştirme,
- kod üreticiler,
- ORM ve şema üreticileri,
- low-code platformları,
- API tanımından istemci ve sunucu kodu üretimi,
- Infrastructure as Code,
- yapay zeka destekli kod üretimi.
Temel sınır aynıdır. Otomasyon kod yazma maliyetini azaltabilir, ancak doğru gereksinim, mimari ve doğrulama gereksinimini ortadan kaldırmaz.
Evrimsel ve araştırma tabanlı geliştirme
Evrimsel geliştirmede ilk çalışan sürüm belirli kapsamda tam işlev sunar. Sonraki sürümler yeni kullanıcı grupları, sahalar veya gereksinimlerle genişler.
Bu yaklaşım özellikle büyük ve çok birimli yapılarda pilot uygulama ile başlayıp edinilen deneyimin sonraki yayılımlara aktarılmasına uygundur. En önemli gereksinimlerden biri güçlü değişiklik ve konfigürasyon yönetimidir.
Araştırma tabanlı geliştirmede sonuç baştan kesin değildir. Bir deneyin çıktısı sonraki adımı belirler. Bu nedenle klasik sabit kapsam, sabit süre ve sabit maliyet varsayımları zayıflar.
Araştırma prototipi çoğu zaman kalıcı ürün değil, teknik bir soruya cevap veren deneysel varlıktır. Başarısız deney de bilgi üretebilir.
RAD
Rapid Application Development, RAD hızlı geri bildirim, prototipleme ve bileşenlerin yeniden kullanımını öne çıkarır.
RAD'in temel düşüncesi büyük bir ürünü uzun süre kapalı biçimde geliştirmek yerine kısa çevrimlerde çalışan parçalar üretmektir.
Bugünkü çevik geliştirme, sürekli teslim ve low-code yaklaşımında bu düşüncenin farklı izleri görülebilir.
Artımlı model
Artımlı modelde sistem parçalara ayrılır. Her artımda analiz, tasarım, gerçekleştirim ve test yapılır.
Artım 1 -> kullanılabilir ürün
Artım 2 -> daha geniş ürün
Artım 3 -> daha geniş ürünÖnemli avantajı erken çalışan ürün sağlamasıdır. Kullanıcı geri bildirimi sonraki artımlara yansıtılabilir.
Spiral model
Boehm'in spiral modeli iteratif geliştirmeyi risk analizi ile birleştirir.
Her çevrimde genel olarak:
- hedefler ve alternatifler belirlenir,
- riskler analiz edilir,
- çözüm geliştirilir ve doğrulanır,
- sonraki çevrim planlanır.
Spiral modelin ayırt edici özelliği yalnız iteratif olması değil, her iterasyonda riski karar mekanizmasının merkezine koymasıdır.
Çevik geliştirme
Modern yazılım mühendisliğinde çevik yöntemler kısa geri bildirim çevrimlerini, çalışan yazılımı, ekip içi işbirliğini ve değişime uyumu öne çıkarır.
Çeviklik plansızlık değildir. Planlama daha kısa ufuklarda ve daha sık yapılır.
Çevik geliştirmede de:
- mimari kararlar,
- kalite,
- test,
- güvenlik,
- konfigürasyon yönetimi,
- ölçüm
gereklidir.
DevOps ve sürekli teslim
Modern yazılım yaşam döngüsünde geliştirme ile işletim arasındaki sınır önemli ölçüde daralmıştır.
DevOps yaklaşımı:
- sürüm kontrolü,
- otomatik derleme,
- sürekli bütünleme,
- otomatik test,
- sürekli teslim,
- altyapının kodla yönetimi,
- izleme ve gözlemlenebilirlik
gibi pratikleri ortak çalışma modeli altında bütünleştirir.
IEEE SWEBOK V4.0, Agile ve DevOps konularını yazılım mühendisliğinin genel bilgi alanlarına daha belirgin biçimde dahil eder.
CASE araçları
CASE, Computer-Aided Software Engineering, analiz, tasarım, kodlama, test ve dokümantasyon etkinliklerinin yazılım araçlarıyla desteklenmesini ifade eder.
Tarihsel CASE ortamlarında:
- diyagram araçları,
- veri sözlükleri,
- kod üreticileri,
- tasarım depoları
bir arada bulunurdu.
Bugün aynı amaç daha geniş bir araç zinciriyle karşılanır:
Issue Tracker
↓
Git
↓
IDE
↓
Build
↓
Static Analysis
↓
Automated Tests
↓
CI/CD
↓
Artifact Repository
↓
Deployment
↓
MonitoringCASE kavramının kalıcı yönü, yazılım mühendisliği işlemlerinin araçlarla otomatikleştirilmesi ve ortak bilgi tabanı üzerinden izlenebilir hale getirilmesidir.
Ünite 2: Yazılım Proje Yönetimi
Proje yönetiminin amacı
Yazılım proje yönetimi teknik geliştirme faaliyetleriyle insan, süre, bütçe ve risk yönetimini birleştirir.
Başlıca sorular şunlardır:
- kapsam nedir,
- teslimatlar nelerdir,
- kim hangi işten sorumludur,
- süre ne kadardır,
- maliyet ne olacaktır,
- hangi riskler vardır,
- ilerleme nasıl ölçülecektir.
Yazılım projesi yalnız görev listesinden oluşmaz. İşler arasında bağımlılıklar vardır ve belirsizlik yüksektir.
Etkin proje yönetimi
Etkin yönetim üç temel unsuru birlikte ele alır:
İnsan: Ekip yapısı, yetkinlik, iletişim ve sorumluluk.
Problem: Çözülecek sorunun kapsamı, karmaşıklığı ve sınırları.
Süreç: Geliştirmenin hangi yöntem ve denetim mekanizmalarıyla yürütüleceği.
Teknik olarak güçlü bir ekibin yanlış kapsamla çalışması başarısızlığa yol açabilir. İyi tanımlanmış bir projenin kötü iletişimle yürütülmesi de aynı sonucu üretebilir.
Proje kaynakları
Yazılım projesinin kaynakları yalnız geliştiricilerden oluşmaz.
Üç temel kaynak grubu düşünülebilir:
İnsan kaynakları: Analiz, mimari, geliştirme, test, güvenlik, işletim ve alan uzmanlığı.
Donanım kaynakları: Geliştirme makineleri, test ortamları, sunucular, ağ ve özel aygıtlar.
Yazılım kaynakları: İşletim sistemleri, veri tabanları, derleyiciler, geliştirme araçları, lisanslar, test ve izleme araçları.
Kaynak planlaması yalnız sayı belirlemek değildir. Kaynağın ne zaman gerekli olduğu da önemlidir. Test ortamına projenin son haftasında ihtiyaç duyulması ile baştan itibaren ihtiyaç duyulması aynı planlama problemi değildir.
Proje ekiplerinin oluşturulması
Projede iş sahibi ile yüklenici veya geliştiren ekip farklı kuruluşlar olabilir. Bu durumda teknik sorumluluk kadar karar ve kabul sorumluluğu da açık tanımlanmalıdır.
Bir ekip yapısında en az şu görevler görünür olmalıdır:
- ürün ve kapsam kararı,
- teknik mimari kararları,
- geliştirme,
- test ve kalite,
- değişiklik onayı,
- kabul,
- işletim sorumluluğu.
İletişim maliyeti ekip büyüdükçe artar. Bu nedenle yalnız daha fazla kişi eklemek projenin daha kısa sürede tamamlanacağını garanti etmez.
Yazılım ölçümü
Ölçüm proje hakkında nesnel veri sağlar.
Ölçümler şu amaçlarla kullanılabilir:
- tahmin,
- kalite değerlendirmesi,
- verimlilik analizi,
- risk takibi,
- süreç iyileştirme,
- geçmiş projelerle karşılaştırma.
Ölçümün kendisi amaç değildir. Karar vermeyi desteklemeyen metrik gereksizdir.
Doğrudan ölçümler
Doğrudan ölçülebilen değerlere örnekler:
- geliştirme süresi,
- iş gücü,
- maliyet,
- kod satırı,
- hata sayısı,
- test sayısı,
- bellek kullanımı,
- gecikme,
- işlem kapasitesi.
Klasik notlarda LOC ve KLOC önemli ölçülerdir.
Örneğin:
Verimlilik = KLOC / kişi-ay
Hata yoğunluğu = hata / KLOCAncak kod satırı sayısı dil, programlama stili ve kullanılan kütüphanelerden etkilenir. Çok kod üretmek tek başına yüksek verimlilik değildir.
Dolaylı ölçümler
Doğrudan sayılamayan özellikler başka ölçümler üzerinden değerlendirilir.
Örnekler:
- karmaşıklık,
- güvenilirlik,
- bakım yapılabilirlik,
- kalite,
- işlevsel büyüklük.
Fonksiyon noktası
Function Point yaklaşımı yazılım büyüklüğünü kod satırından bağımsız olarak işlevsel özellikler üzerinden tahmin etmeye çalışır.
Klasik yaklaşımda:
- dış girdiler,
- dış çıktılar,
- sorgular,
- iç mantıksal dosyalar,
- dış arabirim dosyaları
sayılır ve ağırlıklandırılır.
Eski ders yaklaşımında düzeltilmiş fonksiyon noktası şu biçimde ifade edilir:
FP = UFP x (0.65 + 0.01 x ΣFi)Burada UFP düzeltilmemiş fonksiyon noktası, Fi ise genel sistem özelliklerinin etki değerleridir.
Fonksiyon noktalarının temel avantajı programlama dilinden bağımsız bir işlev büyüklüğü sağlamaya çalışmasıdır.
LOC ve FP karşılaştırması
LOC:
- kolay sayılabilir,
- gerçekleşmiş ürün üzerinde nettir,
- dile ve kodlama yaklaşımına bağımlıdır,
- erken tahminde zayıftır.
Fonksiyon noktası:
- işlevsel büyüklüğe odaklanır,
- daha erken tahmin edilebilir,
- değerlendirme kurallarında yorum gerektirir,
- algoritmik veya altyapı yoğun projelerde tek başına yeterli değildir.
Hiçbir metrik tek başına proje başarısını ölçmez.
Maliyet tahmini
Yazılım maliyeti tahmini belirsizlik içerir.
Tahmin şu etkenlerden etkilenir:
- ürün büyüklüğü,
- gereksinim belirsizliği,
- ekip deneyimi,
- teknoloji,
- güvenlik ve kalite gereksinimleri,
- entegrasyon sayısı,
- yeniden kullanım,
- zaman baskısı,
- dağıtık ekip yapısı.
Tek bir sayı vermek yerine varsayımlar ve belirsizlik aralığı belirtilmelidir.
Maliyet kestirim metodolojisi
Kestirim tek bir formül çalıştırmak yerine düzenli bir süreç olarak ele alınmalıdır:
- kapsamı ve varsayımları tanımla,
- ürünü veya işleri bölümlere ayır,
- büyüklüğü tahmin et,
- geçmiş proje verilerini kullan,
- ekip ve teknoloji etkilerini değerlendir,
- risk payını belirle,
- sonucu bağımsız yöntemlerle karşılaştır,
- proje ilerledikçe tahmini güncelle.
Function Point, COCOMO, uzman görüşü ve analitik iş kırılımı birbirinin rakibi olmak zorunda değildir. Farklı yöntemlerden elde edilen sonuçlar çapraz kontrol amacıyla birlikte kullanılabilir.
Uzman görüşü
Deneyimli kişilerin benzer projelerden edindikleri bilgiyle tahmin yapması basit ve sık kullanılan yöntemdir.
Avantajı hızdır.
Zayıf yönü kişisel önyargı ve deneyime bağımlılıktır.
Delphi yöntemi
Delphi yönteminde birden fazla uzman birbirinden bağımsız tahmin yapar. Sonuçlar karşılaştırılır ve gerekçeler paylaşıldıktan sonra yeni turlar yapılır.
Amaç tek baskın görüşün diğer katılımcıları etkilemesini azaltmak ve ortak tahmine yaklaşmaktır.
Analitik tahmin
Proje alt işlere bölünür. Her iş için süre ve efor tahmini yapılır.
Toplam efor ≈ alt işlerin eforlarının toplamıBu yaklaşım Work Breakdown Structure düşüncesiyle uyumludur.
En büyük risk, görünmeyen entegrasyon ve koordinasyon işlerinin unutulmasıdır.
COCOMO
COCOMO, Constructive Cost Model, Barry Boehm tarafından yazılım eforunu kod büyüklüğüne göre tahmin etmek için geliştirilmiştir.
Klasik temel biçim:
Efor = a x KLOC^b
Süre = c x Efor^dKlasik COCOMO üç proje sınıfı tanımlar:
- Proje tipi: Organic; a: 2.4; b: 1.05; c: 2.5; d: 0.38
- Proje tipi: Semi-detached; a: 3.0; b: 1.12; c: 2.5; d: 0.35
- Proje tipi: Embedded; a: 3.6; b: 1.20; c: 2.5; d: 0.32
Model tarihsel olarak önemlidir. Modern projelerde doğrudan eski katsayıların kullanılması doğru değildir. COCOMO II daha yeni geliştirme modellerini, yeniden kullanımı ve farklı maliyet sürücülerini ele alan devam modelidir.
COCOMO'nun sınav açısından önemli fikri şudur:
Yazılım büyüklüğü arttıkça efor doğrusal olmak zorunda değildir.
Putnam-Norden-Rayleigh modeli
PNR yaklaşımı proje personel ihtiyacının zamana göre değişimini Rayleigh eğrisiyle ilişkilendirir.
Klasik yaklaşımda yazılım büyüklüğü, teknoloji katsayısı, toplam efor ve teslim süresi arasında güçlü ilişki vardır.
Önemli sonuç şudur:
Takvimi keyfi biçimde kısaltmak için yalnız daha fazla personel eklemek maliyeti orantılı biçimde çözmez.
Bu düşünce büyük yazılım projelerindeki iletişim ve koordinasyon maliyetleriyle birlikte değerlendirilmelidir.
Risk yönetimi
Risk, gerçekleşmesi kesin olmayan ancak gerçekleşirse projeyi etkileyen olay veya koşuldur.
Risk yönetiminin temel çevrimi:
Riskleri belirle
↓
Olasılık ve etkiyi değerlendir
↓
Önceliklendir
↓
Yanıt planla
↓
İzle
↓
Yeniden değerlendirRisk kategorileri
Ders notlarında riskler şu başlıklarda ele alınır:
- ürün büyüklüğü,
- işletme,
- müşteri,
- süreç,
- teknoloji,
- geliştirme ortamı,
- personel.
Bu sınıflandırma bugün de kullanılabilir.
Ürün büyüklüğü riskleri
Risk göstergeleri:
- büyüklüğün tahmin edilenden fazla olması,
- veri hacminin hızlı büyümesi,
- bileşen sayısının artması,
- çok fazla entegrasyon noktası.
İşletme riskleri
Örnekler:
- bütçe değişikliği,
- kurumsal öncelik değişimi,
- mevzuat,
- tedarikçi bağımlılığı,
- ürünün ekonomik değerini kaybetmesi.
Müşteri riskleri
- gereksinim kararlarının gecikmesi,
- paydaşların çelişkili beklentileri,
- kabul kriterlerinin belirsizliği,
- erişilemeyen alan uzmanları.
Süreç riskleri
- süreçlerin tanımlı olmaması,
- kalite kontrolünün zayıflığı,
- test otomasyonunun olmaması,
- değişikliklerin izlenememesi.
Teknoloji riskleri
- olgunlaşmamış teknoloji,
- bilinmeyen performans sınırları,
- üçüncü taraf bağımlılığı,
- donanım veya platform uyumsuzluğu,
- güvenlik açıkları.
Geliştirme ortamı riskleri
- araç zinciri kararsızlığı,
- derleme altyapısının güvenilmezliği,
- test ortamlarının üretimi temsil etmemesi,
- yetersiz CI/CD altyapısı.
Personel riskleri
- kritik bilginin tek kişide toplanması,
- ekip değişimi,
- yetkinlik eksikliği,
- iletişim kopukluğu,
- görev yükünün dengesizliği.
Risk yanıtları
Bir risk için dört temel yaklaşım düşünülebilir:
- önleme,
- azaltma,
- aktarma,
- kabul.
Risk kaydı en az:
- açıklama,
- olasılık,
- etki,
- sorumlu,
- azaltma eylemi,
- tetikleyici,
- durum
bilgilerini içermelidir.
Yazılım proje planı
Proje planı kapsam, kaynak, organizasyon, zaman ve risk bilgisini bir araya getirir.
Başlıca bölümler:
- sorunun tanımı,
- gereksinimler,
- çözüm yaklaşımı,
- geliştirme süreci,
- ekip ve organizasyon,
- iş kırılımı,
- zamanlama,
- maliyet,
- risk,
- kalite ve test,
- konfigürasyon yönetimi.
Proje organizasyonu
Klasik üç yapı:
Fonksiyonel organizasyon: Çalışanlar uzmanlık birimlerinde gruplanır.
Proje organizasyonu: Ekip doğrudan proje için oluşturulur.
Matris organizasyon: Fonksiyonel ve proje yapıları birlikte kullanılır.
Matris yapıda bir kişinin hem teknik birim yöneticisine hem proje yöneticisine karşı sorumluluğu olabilir.
Ekip yapıları
Klasik ders yaklaşımında ekipler demokratik, şef kontrollü veya hiyerarşik yapılarda incelenir.
Modern ekiplerde yapı daha esnektir. Ancak temel problem aynıdır:
- karar yetkisi,
- iletişim yolu,
- teknik liderlik,
- sorumlulukların dağılımı
açık olmalıdır.
Proje zamanlaması
Zamanlama için işler:
- belirlenir,
- süreleri tahmin edilir,
- bağımlılıkları çıkarılır,
- kaynaklara atanır,
- kritik yol belirlenir.
Gantt çizelgesi
Gantt çizelgesi işleri zamana göre gösterir.
Avantajı takvimi okunabilir kılmasıdır.
Tek başına karmaşık bağımlılıkları açıklamakta yetersiz kalabilir.
PERT ve CPM
PERT ve CPM işlerin bağımlılıklarını ağ biçiminde gösterir.
Critical Path Method, toplam proje süresini belirleyen kritik yolu bulmaya odaklanır.
Kritik yoldaki bir iş gecikirse başka telafi yoksa proje de gecikir.
PERT belirsiz süre tahminlerinde klasik olarak üç tahmin kullanabilir:
iyimser
en olası
kötümserÜnite 3: Yazılım Kalite Yönetimi ve Test
Yazılım kalitesi
Kalite yalnız "az hata" anlamına gelmez.
Kaliteli yazılım:
- gereksinimleri karşılar,
- beklenen koşullarda güvenilir çalışır,
- performans hedeflerine uyar,
- güvenli davranır,
- kullanıcı için anlaşılabilir ve kullanılabilir olur,
- bakım ve değişikliğe elverişli olur.
ISO/IEC 25010:2023 ürün kalitesini dokuz ana özellik altında ele alan güncel kalite modelidir. Bu model işlevsel uygunluk, performans verimliliği, uyumluluk, etkileşim yeteneği, güvenilirlik, güvenlik, bakım yapılabilirlik, esneklik ve emniyet gibi kalite boyutlarını sistematik biçimde değerlendirmek için kullanılabilir.
Kalite ölçütleri
Bir kalite özelliği doğrudan ölçülemiyorsa onu temsil eden göstergeler kullanılır.
Örnekler:
- hata yoğunluğu,
- başarısızlık oranı,
- test kapsaması,
- çevrimsel karmaşıklık,
- değişiklik başına etkilenen dosya sayısı,
- ortalama onarım süresi,
- yanıt süresi,
- güvenlik açığı sayısı.
Metrik ile gerçek kalite özelliği aynı şey değildir. Metrik yalnız gösterge olabilir.
Halstead ölçütleri
Halstead ölçütleri kaynak kodun işleç ve işlenen sayılarına dayanır.
Tanımlar:
n1 = farklı işleç sayısı
n2 = farklı işlenen sayısı
N1 = toplam işleç kullanımı
N2 = toplam işlenen kullanımıProgram sözlüğü:
n = n1 + n2Gerçek program uzunluğu:
N = N1 + N2Tahmini uzunluk:
N^ = n1 log2(n1) + n2 log2(n2)Hacim:
V = N log2(n)Zorluk:
D = (n1 / 2) x (N2 / n2)Efor:
E = D x VHalstead ölçütleri program metninin belirli nicel özelliklerini verir. Doğrudan yazılım kalitesinin kesin ölçüsü olarak görülmemelidir.
McCabe çevrimsel karmaşıklığı
McCabe ölçütü kontrol akış grafındaki bağımsız yürütme yollarının sayısıyla ilişkilidir.
Tek bağlı bir kontrol akış grafında:
V(G) = E - N + 2Burada:
E: kenar sayısı,N: düğüm sayısıdır.
Birden fazla bağlı bileşen için genel ifade:
V(G) = E - N + 2Polarak yazılabilir.
Basit programlarda çevrimsel karmaşıklık yaklaşık olarak:
karar noktası sayısı + 1şeklinde de düşünülebilir.
Karmaşıklık arttıkça sınanması gereken bağımsız yollar artar. Bu nedenle metrik test tasarımı ve bakım riski açısından yararlıdır.
Belirli bir eşik bütün projeler için evrensel kalite sınırı değildir. Değer, modülün bağlamıyla birlikte değerlendirilmelidir.
Kalite güvencesi
Quality Assurance, QA, kalitenin süreç boyunca sistematik biçimde güvence altına alınmasıdır.
Kalite güvencesi:
- süreç tanımları,
- standartlar,
- gözden geçirmeler,
- test stratejisi,
- ölçümler,
- konfigürasyon yönetimi,
- denetimler
gibi etkinlikleri kapsar.
Kalite kontrolü
Kalite kontrolü belirli ürün ve çıktıları değerlendirir.
Örneğin:
- gereksinim incelemesi,
- tasarım incelemesi,
- kod incelemesi,
- test sonucu analizi,
- kabul kontrolü.
Kalite güvence daha geniş süreç yaklaşımıdır. Kalite kontrol ise ürün ve çıktı üzerinde doğrulama yapar.
Teknik gözden geçirme
Gözden geçirme, hatayı çalıştırma aşamasından önce bulmayı amaçlar.
İyi bir teknik inceleme:
- belirli kapsamla yapılır,
- kontrol listesi kullanabilir,
- bulguları kaydeder,
- kişiyi değil ürünü değerlendirir,
- düzeltmenin takibini yapar.
Statik inceleme erken hata bulmanın en düşük maliyetli yollarından biri olabilir.
Yazılım testinin amacı
Testin temel soruları:
- Sistem doğru ürünü mü gerçekleştiriyor?
- Ürün doğru biçimde mi gerçekleştirildi?
- Tanımlanan koşullarda hatalı davranış var mı?
- Kalite hedefleri sağlanıyor mu?
Verification daha çok ürünün tanıma ve tasarıma uygunluğunu, validation ise geliştirilen ürünün gerçek kullanıcı ihtiyacını karşılayıp karşılamadığını sorgular.
Test düzeyleri
Modern test sınıflandırması genel olarak:
- birim testi,
- entegrasyon testi,
- sistem testi,
- kabul testi
düzeylerini içerir.
Bunlara performans, güvenlik, kullanılabilirlik, dayanıklılık ve geri dönüş gibi kalite testleri eklenebilir.
ISO/IEC/IEEE 29119 serisi yazılım testi için ortak kavramlar, test süreçleri, test dokümantasyonu ve test teknikleri çerçevesi sunar.
Birim testi
Birim testi en küçük mantıksal yazılım birimini sınar.
İyi bir birim testi:
- hızlı,
- tekrarlanabilir,
- bağımsız,
- deterministik
olmalıdır.
Bağımlılıklar gerektiğinde test double, fake veya mock ile ayrıştırılabilir.
Test sürücüsü ve test desteği
Klasik yapısal testte henüz bulunmayan üst veya alt modüllerin yerine geçici programlar kullanılabilir.
Driver, test edilen modülü çağıran geçici üst bileşendir.
Stub, test edilen modülün çağırdığı fakat henüz bulunmayan alt bileşenin yerine geçer.
Bu kavramlar modern mock ve test double yaklaşımlarının tarihsel temelidir.
Bütünleme testi
Entegrasyon testi bileşenlerin kendi başlarına değil birlikte doğru çalışıp çalışmadığını araştırır.
Başlıca riskler:
- veri biçimi uyuşmazlığı,
- protokol hatası,
- transaction sınırı,
- zaman aşımı,
- hata yayılımı,
- sürüm uyumsuzluğu.
Yukarıdan aşağı bütünleme
Üst seviye modüllerden başlanır. Alt bileşenler başlangıçta stub ile temsil edilir.
Avantajı üst seviye kontrol akışının erken görülmesidir.
Aşağıdan yukarı bütünleme
Alt düzey bileşenlerden başlanır. Üst çağırıcılar için driver kullanılabilir.
Avantajı temel hizmetlerin erken doğrulanmasıdır.
Sistem testi
Sistem testi ürünün bütününü gerçek veya gerçeğe yakın ortamda değerlendirir.
Fonksiyonların yanında:
- performans,
- kapasite,
- güvenlik,
- kurtarma,
- kurulum,
- uyumluluk
gibi özellikler de sınanabilir.
Kabul testi
Kabul testi sistemin kullanıcı veya sözleşme gereksinimlerini karşılayıp karşılamadığını değerlendirir.
Kabul kriterleri gereksinim aşamasında belirlenmelidir.
Hata ayıklama
Test hata olduğunu gösterir. Debugging, hatanın kaynağını bulup düzeltme işlemidir.
Genel çevrim:
Hata gözlenir
↓
Tekrarlanabilir hale getirilir
↓
Kök neden bulunur
↓
Düzeltme yapılır
↓
Test tekrar çalıştırılır
↓
Regresyon denetlenirBeyaz kutu testi
Beyaz kutu testi programın iç yapısını dikkate alır.
Amaç:
- karar yollarını,
- koşulları,
- döngüleri,
- veri akışını
sınamaktır.
Temel yol testi
McCabe çevrimsel karmaşıklığı bağımsız yol sayısının belirlenmesinde kullanılabilir.
Temel yol testi:
- kontrol akış grafını oluşturur,
- karmaşıklığı hesaplar,
- bağımsız yolları belirler,
- bu yolları çalıştıracak testleri tasarlar.
Döngü testi
Döngüler için tipik sınırlar:
- sıfır tekrar,
- bir tekrar,
- normal tekrar,
- üst sınırın hemen altı,
- üst sınır,
- üst sınırın üzeri
gibi durumlarla sınanır.
Kara kutu testi
Kara kutu testinde programın iç yapısından çok giriş ve beklenen çıktı ilişkisi değerlendirilir.
Eşdeğer bölümlere ayırma
Girdi uzayı benzer davranması beklenen sınıflara ayrılır.
Örneğin geçerli yaş aralığı:
0..17
18..65
66+Her sınıftan temsilci değer seçilebilir.
Sınır değer analizi
Hatalar sınıf sınırlarında sık görülür.
Bir aralık:
1 <= x <= 100ise güçlü test adayları:
0, 1, 2, 99, 100, 101değerleridir.
Neden-sonuç grafı ve karar tabloları
Birden fazla mantıksal koşulun birleşimi çok sayıda durum oluşturuyorsa karar tablosu veya neden-sonuç grafı kullanılabilir.
Bu teknik özellikle iş kurallarının kombinasyonlarını sistematik test etmeye yarar.
Test planlama ve test belirtimleri
Test planı hangi kalitenin hangi düzeyde ve hangi kaynaklarla doğrulanacağını belirler.
Temel içerik:
- kapsam,
- test düzeyleri,
- test ortamları,
- giriş ve çıkış kriterleri,
- sorumlular,
- veri hazırlığı,
- bağımlılıklar,
- hata raporlama yöntemi,
- takvim,
- kabul ölçütleri.
Test belirtimi ise belirli test koşullarını ve beklenen sonuçları daha ayrıntılı tanımlar.
Gereksinimden teste izlenebilirlik kurulursa bir gereksinimin doğrulanıp doğrulanmadığı açık biçimde görülebilir.
Yaşam döngüsü boyunca doğrulama ve geçerleme
Doğrulama ve geçerleme yalnız test ekibinin son aşamadaki işi değildir.
Örnek eşleştirme:
Gereksinim -> gereksinim incelemesi + kabul testi tasarımı
Mimari -> mimari inceleme + sistem/entegrasyon test tasarımı
Kod -> statik analiz + birim testi
Paket -> entegrasyon + sistem testi
Ürün -> kabul ve işletim doğrulamasıBu yaklaşım V modelinin temel mantığıyla uyumludur.
Regresyon testi
Bir değişiklik sonrası daha önce çalışan davranışların bozulmadığını doğrulayan testlere regresyon testi denir.
Otomasyonun en yüksek değer sağladığı alanlardan biridir.
Sürekli test
CI/CD sistemlerinde testler kod değişikliğiyle birlikte otomatik çalıştırılabilir.
Tipik hat:
Commit
↓
Build
↓
Static Analysis
↓
Unit Tests
↓
Integration Tests
↓
Package
↓
Deployment TestsBu yapı hatanın değişiklikten kısa süre sonra görünür hale gelmesini sağlar.
Ünite 4: Yazılım Bakımı ve Konfigürasyon Yönetimi
Yazılım bakımı
Yazılım fiziksel olarak aşınmaz. Ancak çevresi ve gereksinimleri değişir.
Bakım dört temel sınıfta ele alınabilir:
Düzeltici bakım: Hataları giderir.
Uyarlayıcı bakım: İşletim sistemi, donanım, API, mevzuat veya dış ortam değişikliklerine uyum sağlar.
İyileştirici bakım: Performans, kullanılabilirlik veya işlevlerde geliştirme yapar.
Önleyici bakım: Gelecekteki hata ve bakım maliyetini azaltmak için iç yapıyı iyileştirir.
Kurulum ve yerinde destek
Kurulum, yalnız yazılım dosyalarını hedef ortama kopyalamak değildir.
Kurulum planı şu konuları kapsayabilir:
- sürüm ve bağımlılıklar,
- veri dönüşümü,
- erişim yetkileri,
- yedekleme,
- geri dönüş planı,
- kullanıcı eğitimi,
- doğrulama testleri,
- izleme ve destek sorumluluğu.
Üretime geçiş sonrası ilk dönem, geliştirme ekibi ile işletim ekibi arasında yoğun bilgi aktarımı gerektirebilir.
Bakım süreç modeli
Bir bakım talebi küçük bir kod değişikliğinden ibaret görülmemelidir. Gerektiğinde yaşam döngüsünün ilgili adımları yeniden çalıştırılır:
Sorun / değişiklik talebi
↓
Çözümleme
↓
Tasarım
↓
Gerçekleştirim
↓
Sistem ve regresyon testi
↓
Kabul
↓
KurulumDeğişiklik büyüdükçe etki analizi ve konfigürasyon yönetiminin önemi artar.
Bakım yapılabilirlik
Bakım yapılabilirlik bir sistemin ne kadar kolay anlaşılabildiği, değiştirilebildiği ve doğrulanabildiğiyle ilgilidir.
Bakımı kolaylaştıran özellikler:
- düşük bağımlılık,
- yüksek iç tutarlılık,
- açık arabirimler,
- modüler tasarım,
- otomatik test,
- anlaşılır kod,
- güncel dokümantasyon,
- izlenebilir gereksinimler,
- gözlemlenebilir çalışma zamanı davranışı.
Bakım maliyetinin azaltılması
Bakım maliyetini yalnız bakım döneminde azaltmak mümkün değildir.
Geliştirme sırasında:
- temiz mimari sınırlar,
- otomatik test,
- kod inceleme,
- teknik borç yönetimi,
- sürüm kontrolü,
- tekrarlanabilir derleme,
- iyi loglama
bakım maliyetini doğrudan etkiler.
Yazılım konfigürasyonu
Bir yazılım ürünü çok sayıda yapılandırma öğesinden oluşur.
Örnekler:
- kaynak kod,
- gereksinim belgeleri,
- tasarım belgeleri,
- testler,
- derleme betikleri,
- bağımlılık tanımları,
- veritabanı şemaları,
- dağıtım manifestoları,
- kullanıcı belgeleri.
Belirli bir sürümü tekrar üretebilmek için bu öğelerin hangi versiyonlarının birlikte kullanıldığı bilinmelidir.
Yazılım konfigürasyon yönetimi
Software Configuration Management, SCM, yazılım ürünündeki değişikliklerin tanımlanması, izlenmesi, denetlenmesi ve doğrulanmasıdır.
Temel etkinlikler:
- konfigürasyon öğelerini belirleme,
- baseline oluşturma,
- sürüm kontrolü,
- değişiklik kontrolü,
- durum muhasebesi,
- konfigürasyon denetimi.
Baseline
Baseline, belirli bir anda kabul edilmiş ve değişiklikleri denetim altına alınmış konfigürasyon durumudur.
Örneğin:
- onaylı gereksinim seti,
- test edilen sürüm,
- üretime çıkan release
baseline olarak ele alınabilir.
Değişiklik kontrolü
Değişiklik şu çevrimle yönetilebilir:
Değişiklik isteği
↓
Etki analizi
↓
Onay / ret
↓
Gerçekleştirim
↓
Test
↓
Sürümleme
↓
KayıtEtki analizi yapılmadan küçük görünen bir değişiklik farklı modülleri ve belgeleri bozabilir.
Konfigürasyon denetimi
Denetim şu soruları yanıtlar:
- Doğru dosyalar mı kullanıldı?
- İstenen değişiklikler gerçekten yapıldı mı?
- Test edilen sürüm ile dağıtılan sürüm aynı mı?
- Belgeler ve kod aynı baseline'a mı ait?
- Onaysız değişiklik var mı?
Durum raporlama
Konfigürasyon durumu:
- hangi sürümlerin bulunduğunu,
- hangi değişikliklerin uygulandığını,
- hangi taleplerin açık olduğunu,
- hangi baseline'ın üretimde olduğunu
gösterebilmelidir.
Sürüm kontrolü
Modern konfigürasyon yönetiminin merkezi araçlarından biri dağıtık sürüm kontrol sistemleridir.
Git gibi sistemler:
- commit geçmişi,
- branch,
- merge,
- tag,
- değişiklik karşılaştırma,
- geri dönüş
işlevleri sunar.
Ancak konfigürasyon yönetimi Git'ten daha geniştir. Derleme araçları, bağımlılıklar, artefakt depoları, ortam ayarları ve dağıtım manifestoları da yönetilmelidir.
Modern konfigürasyon zinciri
Kaynak kod
↓
Sürüm kontrolü
↓
CI derlemesi
↓
Testler
↓
Sürüm numarası
↓
İmzalı / tanımlı artefakt
↓
Artefakt deposu
↓
DağıtımTemel hedef:
Aynı kaynak ve konfigürasyondan aynı ürünün yeniden üretilebilmesi.
Yapay zeka ve makine öğrenmesi sistemlerinde yeniden üretilebilir yapılandırma
Yapay zeka veya makine öğrenmesi içeren bir yazılımda sürüm yalnız kaynak kod commit'iyle tanımlanamaz. Aynı kod, farklı veri, önişleme kuralı, model ağırlığı veya eşikle farklı ürün davranışı üretebilir.
Üretilebilir bir sürümün bağlamı en az şu bileşenleri kapsayabilir:
kaynak kod
+ veri / veri kümesi sürümü
+ önişleme ve özellik kuralları
+ şema / etiket sözleşmesi
+ model veya checkpoint
+ eğitim ve değerlendirme yapılandırması
+ istem / şablon sürümü
+ değerlendirme kümesi
+ karar eşikleri
+ dağıtım yapılandırması
= yeniden üretilebilir çalışma bağlamıHer projede bu öğelerin tamamı bulunmak zorunda değildir. Temel ilke, çalışan davranışı değiştirebilen öğelerin konfigürasyon birimi olarak görünür olmasıdır.
Veri ve model kökeni
Bir modelin hangi veriyle, hangi önişleme sürümüyle ve hangi kod üzerinde üretildiği bilinmiyorsa aynı sonucu yeniden üretmek veya bir regresyonun kaynağını bulmak zorlaşır. Bu ilişki yalnız dosya adlarında tutulmamalı; veri sürümü, model sürümü ve ilgili kaynak commit'i birbirine izlenebilir olmalıdır.
veri sürümü
↓
eğitim yapılandırması
↓
model artefaktı
↓
değerlendirme sonucu
↓
dağıtılan sürümBu zincir “en yüksek doğruluklu model hangisiydi?” sorusundan daha geniştir. Bir modelin neden yayımlandığını ve hangi kanıta dayanarak geri alınabileceğini de açıklar.
Değerlendirme verisi de konfigürasyondur
Değerlendirme kümesi değiştiğinde aynı modelin metriği de değişebilir. Bu nedenle model karşılaştırmalarında test/evaluation verisinin sürümü, filtreleme kuralları ve metrik tanımı kaydedilmelidir. Sürekli aynı test kümesine bakarak hiperparametre seçmek test bilgisini geliştirme sürecine sızdırabilir; bu durumda bağımsız doğrulama özelliği zayıflar.
Bu ayrımın test mühendisliği karşılığı Yazılım Test Mühendisliği notunda daha geniş ele alınır.
Eğitim ve sunum davranışının ayrılması
Eğitim sırasında kullanılan veri hazırlama işlemi ile üretimdeki girdi hazırlama işlemi farklılaşırsa training-serving skew oluşabilir. Aynı normalizasyon, kategori eşleme, tokenization veya özellik üretim sözleşmesinin iki tarafta da izlenebilir olması gerekir.
Model dosyasını sürümlemek bu sorunu tek başına çözmez. Modelin beklediği giriş ve çıktı sözleşmesi de sürümün parçasıdır.
Kademeli dağıtım ve geri dönüş
Yeni model veya karar eşiği doğrudan bütün trafiğe açılmak zorunda değildir. Risk uygun olduğunda küçük kullanıcı/istek oranıyla başlama, gölge değerlendirme veya kontrollü karşılaştırma kullanılabilir. Ancak kademeli dağıtımın anlamlı olması için önceki artefakt ve yapılandırmanın geri yüklenebilir olması gerekir.
yeni sürüm
→ sınırlı doğrulama
→ ölçüm
→ genişletme veya geri dönüşBu süreç model geliştirmeyi klasik konfigürasyon yönetiminden ayırmaz; tersine konfigürasyon yönetiminin kapsamını veri ve model artefaktlarına genişletir. Deney, model seçimi ve üretim gözlemi Yapay Sinir Ağları ve Öğrenme Modelleri notunda model geliştirme açısından ele alınır.
Ünite 5: Yazılım Gereksinim Analizi
Yazılım gereksinimleri
Gereksinim, sistemin sağlaması gereken yetenek, özellik veya kısıttır.
Gereksinimler genel olarak:
- iş gereksinimleri,
- kullanıcı gereksinimleri,
- sistem gereksinimleri,
- yazılım gereksinimleri
düzeylerinde ele alınabilir.
İşlevsel gereksinimler
Sistemin yapacağı işi tanımlar.
Örneğin:
Sistem, yetkili kullanıcının bir siparişi iptal edebilmesini sağlamalıdır.
İşlevsel olmayan gereksinimler
Sistemin çalışma niteliğini veya kısıtlarını tanımlar.
Örnekler:
- sorgu 200 ms altında yanıt vermeli,
- veri aktarımı şifreli olmalı,
- sistem belirli yük altında çalışmalı,
- hizmet belirli erişilebilirlik hedefini sağlamalı.
İşlevsel olmayan gereksinimler ölçülebilir yazılmadığında test edilmesi güçleşir.
Gereksinim spesifikasyonu
Software Requirements Specification, SRS, gereksinimleri düzenli ve doğrulanabilir biçimde tanımlar.
İyi gereksinim:
- açık,
- tek anlamlı,
- gerekli,
- tutarlı,
- gerçekleştirilebilir,
- doğrulanabilir,
- izlenebilir
olmalıdır.
ISO/IEC/IEEE 29148:2018 gereksinim mühendisliği süreçleri ve gereksinim bilgi öğeleri için güncel temel standartlardan biridir.
Gereksinim ile tasarım ayrımı
Gereksinim:
Sistem ne yapmalı?
Tasarım:
Sistem bunu nasıl yapacak?
Gereksiz tasarım kararlarını gereksinim içine gömmek çözüm alanını daraltabilir.
Bazı durumlarda teknoloji seçimi gerçek bir kısıt olduğundan gereksinim olabilir. Ayrım bağlama göre yapılmalıdır.
İzlenebilirlik
Her önemli gereksinim:
- kaynağına,
- tasarım kararına,
- gerçekleştirim bileşenine,
- test durumuna
bağlanabilmelidir.
İş ihtiyacı
↓
Gereksinim
↓
Tasarım
↓
Kod
↓
Testİzlenebilirlik özellikle güvenlik kritik, emniyet kritik ve düzenlemeye tabi sistemlerde önemlidir.
Aviyonik yazılım bu zincirin somut örneklerinden biridir. Gereksinim, tasarım kararı, kaynak kod, doğrulama sonucu, yapılandırma ve problem kaydı arasındaki bağın korunması yazılım güvencesinin temel parçalarındandır. DO-178C bağlamının ders içindeki karşılığı Aviyonik Sistemler ve İnsansız Hava Araçları notunda ele alınmıştır.
Sistem düzeyi güvenlik kısıtları: gereksinimi yalnız özellik olarak yazmamak
Kritik bir sistemde gereksinim yalnız sistemin ne yapacağını söylemez; hangi koşullarda neyi yapmaması gerektiğini de tanımlar. Bileşenlerin tek tek doğru çalışması, aralarındaki etkileşimin güvenli olduğunu garanti etmez. Bu nedenle özellikle siber-fiziksel ve güvenlik-kritik sistemlerde gereksinim analizi sistem düzeyi istenmeyen sonuçlardan geriye doğru yürütülebilir.
istenmeyen sonuç
↓
tehlikeli sistem durumu
↓
ihlal edilmemesi gereken kısıt
↓
tasarım kararı
↓
doğrulanabilir gereksinim
↓
test / gözlem kanıtıBu yaklaşım klasik işlevsel ve işlevsel olmayan gereksinimleri ortadan kaldırmaz. Eksik kalan bir boyutu görünür kılar: doğru bir işlev, yanlış bağlamda veya yanlış zamanda yürütüldüğünde de sistem açısından kabul edilemez sonuç doğurabilir.
Örneğin komut gönder işlevi tek başına yeterli bir gereksinim değildir. Komutun hangi sistem durumlarında geçerli olduğu, hangi geri bildirime dayanacağı, ne kadar eski veriyle verilebileceği, aynı fiziksel süreci başka hangi denetleyicilerin etkilediği ve güvenli duruma geçiş koşulları da gereksinimin parçası olabilir.
Bu bakış, Nancy G. Leveson'ın sistem-teorik güvenlik yaklaşımındaki kontrol ve kısıt düşüncesiyle uyumludur. Buradaki amaç yöntemi bir şablon olarak kopyalamak değil; gereksinim mühendisliğinde özellik listesi ile güvenli sistem davranışı arasındaki farkı açık hale getirmektir.
İzlenebilirlik de bu nedenle yalnız gereksinim -> test bağlantısı değildir. Kritik sistemlerde daha güçlü zincir:
risk / tehlike
-> sistem kısıtı
-> gereksinim
-> mimari öğe
-> uygulama
-> doğrulama kanıtışeklindedir. Gereksinim değiştiğinde yalnız ilgili kod değil, dayandığı kısıt ve onu doğrulayan kanıt da yeniden değerlendirilmelidir.
Mevcut sistemin incelenmesi
Yeni sistem geliştirilecekse mevcut işleyişin anlaşılması gereksinim analizinin önemli parçasıdır.
İnceleme sırasında:
- iş adımları,
- kullanılan belgeler ve kayıtlar,
- girdi ve çıktılar,
- iş kuralları,
- mevzuat ve yönergeler,
- mevcut sorunlar,
- kullanıcıların fiili çalışma biçimleri
araştırılır.
Mevcut sistemin yaptığı her şey yeni sisteme aynen aktarılmak zorunda değildir. Ama mevcut davranış bilinmeden kaldırılan bir işlevin gerçek gereksinim olup olmadığı anlaşılamaz.
Gereksinim çıkarma teknikleri
Gereksinim verisi farklı yöntemlerle toplanabilir.
Görüşme: Alan uzmanıyla doğrudan ve derin bilgi alışverişi sağlar.
Anket: Çok sayıda kullanıcıdan standart biçimde veri toplamayı kolaylaştırır.
Gözlem: Kullanıcının söylediği süreç ile gerçekte uyguladığı süreç arasındaki farkı gösterebilir.
Belge inceleme: Formlar, raporlar, yönergeler, kayıtlar ve mevzuat üzerinden mevcut sistemi açıklar.
Örnekleme ve istatistiksel inceleme: Büyük veri veya belge kümelerinde temsil edici örneklerle çalışma maliyetini azaltır.
Atölye çalışması: Birden fazla paydaşın çelişkili gereksinimlerini aynı ortamda görünür hale getirir.
Belirsiz ve zayıf yapılandırılmış problemlerde senaryo, prototip ve kavramsal model kullanmak soyut beklentileri somutlaştırabilir.
Veri modelleme
Gereksinim analizinde veri modeli sistemin hangi bilgileri tuttuğunu ve bu bilgilerin nasıl ilişkilendiğini gösterir.
Klasik araçlar:
- varlık-ilişki modeli,
- veri sözlüğü.
ER modeli yüksek düzeyde varlık ve ilişkileri gösterir. Veri sözlüğü alanların anlamını, tipini, uzunluğunu, geçerli değerlerini ve kullanım yerlerini ayrıntılandırır.
Güncel projelerde aynı ihtiyaç ilişkisel şema modelleri, domain modelleri, JSON Schema, Protobuf veya API sözleşmeleri gibi farklı tekniklerle karşılanabilir.
Kullanıcı arayüzü prototipleme
Arayüz prototipi gereksinimlerin erken doğrulanmasına yardımcı olur.
Prototip üzerinden kullanıcı:
- hangi bilgiyi göreceğini,
- hangi veriyi gireceğini,
- işlem sırasını,
- hata ve onay davranışını
daha somut biçimde değerlendirebilir.
Prototip görsel tasarım yarışması değildir. Ana amacı belirsiz gereksinimleri erken ortaya çıkarmaktır.
Analiz modelinin değerlendirilmesi
Analiz çıktıları en az şu açılardan gözden geçirilmelidir:
- tamlık,
- tutarlılık,
- olurluluk,
- izlenebilirlik,
- model düzeyleri arasında denge.
DFD ayrıştırmasında üst düzey süreç ile alt düzey diyagramın dış veri akışları uyumlu olmalıdır. Bu özellik klasik terminolojide balancing olarak bilinir.
Formal spesifikasyon
Formal spesifikasyon matematiksel veya kesin tanımlı notasyonlarla sistem davranışını ifade eder.
Avantajları:
- belirsizliği azaltır,
- tutarsızlıkların bulunmasını kolaylaştırır,
- bazı özelliklerin ispatlanmasına izin verir.
Dezavantajı:
- uzmanlık gerektirir,
- maliyetlidir,
- bütün sistemler için aynı ölçüde gerekli değildir.
Formal yöntemler özellikle kritik protokoller, güvenlik mekanizmaları ve doğruluğun yüksek önem taşıdığı bileşenlerde değerlidir.
İlişkisel notasyonlar
Sistemin girdileriyle çıktıları arasındaki ilişkileri matematiksel biçimde tanımlar.
Önkoşul ve sonkoşul yaklaşımı buna örnektir.
Precondition
↓
Operation
↓
PostconditionDurum yönelimli notasyonlar
Sistemin belirli durumlarını ve olaylarla yaptığı geçişleri tanımlar.
Modern karşılığı olarak UML state machine diyagramları kullanılabilir.
Karar tabloları
Çok sayıda koşul ve sonucun bulunduğu iş kurallarını tablo halinde gösterir.
- Koşul A: Evet; Koşul B: Evet; Sonuç: İşlem 1
- Koşul A: Evet; Koşul B: Hayır; Sonuç: İşlem 2
- Koşul A: Hayır; Koşul B: Evet; Sonuç: İşlem 3
- Koşul A: Hayır; Koşul B: Hayır; Sonuç: İşlem 4
Karar tabloları hem gereksinim analizi hem test üretimi için yararlıdır.
Geçiş tabloları
Durum makinesini tablo biçiminde gösterebilir.
- Mevcut durum: Bekliyor; Olay: Başlat; Yeni durum: Çalışıyor
- Mevcut durum: Çalışıyor; Olay: Durdur; Yeni durum: Bekliyor
- Mevcut durum: Çalışıyor; Olay: Hata; Yeni durum: Hata
Petri ağları
Petri ağları eşzamanlı ve olay güdümlü sistemleri modellemekte kullanılabilir.
Temel öğeler:
- yer,
- geçiş,
- token.
Özellikle paralellik, senkronizasyon ve kaynak paylaşımı analizinde kuramsal değer taşır.
Gereksinim analizi ilkeleri
Analiz sırasında:
- problem alanı anlaşılmalı,
- sistem sınırı çizilmeli,
- dış aktörler belirlenmeli,
- veri ve işlevler modellenmeli,
- hata ve istisna durumları düşünülmeli,
- gereksinimler önceliklendirilmeli,
- kabul kriterleri tanımlanmalıdır.
Veri akışına yönelik analiz
Veri akışına yönelik yöntemler sistemde bilginin nereden geldiğine, hangi süreçte dönüştüğüne ve nereye gittiğine odaklanır.
Veri akış diyagramları
Data Flow Diagram, DFD, dört temel öğe kullanır:
- dış varlık,
- süreç,
- veri akışı,
- veri deposu.
Bağlam diyagramında sistem tek süreç olarak gösterilir.
Daha alt düzeylerde süreçler ayrıştırılır.
Önemli ilke balancing'dir. Üst düzeyde görülen dış veri akışları alt düzey ayrıştırmada kaybolmamalı veya gerekçesiz yenileri ortaya çıkmamalıdır.
Veri sözlüğü
Veri sözlüğü sistemdeki veri öğelerinin anlamını tanımlar.
Bir veri öğesi için:
- ad,
- açıklama,
- tür,
- uzunluk,
- format,
- geçerli değerler,
- kaynağı,
- kullanıldığı yerler
tutulabilir.
Modern sistemlerde şema tanımları, API sözleşmeleri ve veri katalogları aynı amacın daha gelişmiş örnekleridir.
İşlevsel betimleme
DFD sürecin ne yaptığını gösterir ancak iç mantığı ayrıntılı açıklamaz.
Bir sürecin iç davranışı:
- yapılandırılmış doğal dil,
- karar tablosu,
- karar ağacı,
- durum modeli,
- pseudocode
ile tanımlanabilir.
Veri yapısına yönelik tarihsel yöntemler
Warnier-Orr ve Jackson System Development yöntemleri program yapısını veri yapısının düzeninden türetmeye çalışan tarihsel yöntemlerdir.
Bu yaklaşımlar günümüzde yaygın geliştirme yöntemi değildir. Ancak kalıcı düşünceleri önemlidir:
- verinin yapısı yazılım yapısını etkiler,
- hiyerarşi açık modellenmelidir,
- sıralama, seçim ve yineleme yapıları sistematik ifade edilmelidir.
Modern projelerde bu ihtiyaçlar daha çok:
- UML sınıf ve nesne modelleri,
- durum ve etkinlik diyagramları,
- domain modeling,
- veri şemaları,
- API sözleşmeleri
ile karşılanır.
Ünite 6: Yazılım Tasarımı
Tasarımın amacı
Tasarım, gereksinimlerden uygulanabilir teknik yapıya geçiştir.
İyi tasarım:
- karmaşıklığı bölümlere ayırır,
- değişiklik etkisini sınırlar,
- bileşen sorumluluklarını netleştirir,
- arabirimleri açık tanımlar,
- kalite hedeflerini mimariye taşır.
Mimari ve veri tasarımı
Mimari tasarım sistemin ana yapı taşlarını ve aralarındaki ilişkileri belirler.
Veri tasarımı ise:
- veri modelleri,
- saklama biçimleri,
- veri sahipliği,
- yaşam döngüsü,
- bütünlük,
- erişim desenleri
üzerinde durur.
Dağıtık sistemlerde "veri kime aittir?" sorusu bileşen sınırlarının önemli belirleyicisidir.
Yazılım mimarisi
Yazılım mimarisi sistemi oluşturan bileşenleri, bunların sorumluluklarını ve etkileşim biçimlerini kapsar.
Mimari kararlar özellikle şu kalite özelliklerini etkiler:
- performans,
- güvenlik,
- ölçeklenebilirlik,
- kullanılabilirlik,
- bakım yapılabilirlik,
- dağıtılabilirlik.
Mimari stil amaç değil, gereksinime verilen cevaptır.
Katmanlı, olay güdümlü, istemci-sunucu, mikroservis veya modüler monolit gibi yapılar doğru bağlamda kullanılmalıdır.
Modülerlik
Sistem yönetilebilir parçalara ayrılır.
İyi modül:
- belirli sorumluluğa sahiptir,
- iç ayrıntısını gizler,
- açık bir arabirim sunar,
- başka modüllere gereksiz bağımlılık kurmaz.
Modülerliğin amacı dosya sayısını artırmak değil, değişikliğin etkisini sınırlamaktır.
Cohesion ve coupling
Cohesion, bir modül içindeki öğelerin aynı amaca ne kadar bağlı olduğunu gösterir. Yüksek olması tercih edilir.
Coupling, modüller arasındaki bağımlılık derecesidir. Gereksiz coupling azaltılmalıdır.
Genel hedef:
yüksek cohesion
düşük couplingolarak özetlenir.
Soyutlama
Soyutlama gereksiz ayrıntıyı gizleyerek probleme uygun seviyede düşünmeyi sağlar.
Örneğin:
dosyayı_oku()işlemini kullanan kodun disk sektörleri veya sistem çağrılarının ayrıntısını bilmesi gerekmez.
Soyutlama karmaşıklığı yok etmez. Karmaşıklığın görülmesi gereken yerde görünmesini sağlar.
Bilginin gizlenmesi
Information hiding, bir bileşenin değişmesi muhtemel iç kararlarını dışarıdan gizlemesidir.
Örneğin bir veri erişim bileşeni verinin hangi fiziksel veri tabanında saklandığını çağıran koddan gizleyebilir.
Bu ilke değişikliğin yayılmasını azaltır.
Yapısal programlama
Yapısal programlama kontrol akışını:
- sıralama,
- seçim,
- yineleme
gibi açık yapılara dayandırır.
Amaç kontrol akışını anlaşılır tutmaktır.
Modern programlama dilleri daha zengin yapılara sahip olsa da bu temel ilke geçerlidir.
Ön tasarım
Ön tasarım gereksinimlerden genel çözüm yapısına geçiştir.
Başlıca çıktılar:
- mimari yapı,
- veri tasarımı,
- temel bileşenler,
- dış arabirimler,
- performans ve güvenlik yaklaşımı.
Ayrıntılı tasarım
Ayrıntılı tasarım bileşenlerin iç gerçekleştirim kararlarını tanımlar.
Örnekler:
- sınıf yapıları,
- algoritmalar,
- veri yapıları,
- API imzaları,
- hata yönetimi,
- transaction sınırları,
- eşzamanlama kuralları.
Tasarım ilkeleri
Kalıcı tasarım ilkeleri şunlardır:
- sorumlulukları ayır,
- gereksiz bağımlılığı azalt,
- değişmesi muhtemel ayrıntıyı gizle,
- arabirimleri küçük ve açık tut,
- tekrarı azalt,
- gereksiz genellemeler üretme,
- test edilebilirliği düşün,
- hata durumlarını normal tasarımın parçası yap.
Fan-in ve fan-out kavramları bağımlılık analizi açısından değerlidir.
Çok yüksek fan-out bir bileşenin çok sayıda başka bileşene bağımlı olduğunu ve değişiklik riskinin büyüyebileceğini gösterebilir.
Yapısal tasarım ve tarihsel akış dönüşümleri
Yapısal tasarım yöntemleri veri akış modelinden modül yapısı çıkarmaya çalışır.
Klasik iki akış türü:
Transform flow: Veri sisteme girer, dönüşüm merkezinden geçer ve çıktı biçimine dönüşür.
Giriş akışı -> Dönüşüm merkezi -> Çıkış akışıTransaction flow: Bir giriş olayı belirli işlem yolunu seçer.
-> İşlem A
Girdi -> seçim -> İşlem B
-> İşlem CBu yöntemler günümüz mimari tasarımında doğrudan standart yöntem değildir. Bununla birlikte veri akışı ile sorumlulukların modüllere ayrılması arasındaki ilişkiyi anlamak açısından değerlidir.
Ayrıntılı tasarım notasyonları
Ayrıntılı tasarımda algoritma ve karar mantığı farklı notasyonlarla ifade edilebilir:
- pseudocode,
- karar tabloları,
- akış diyagramları,
- durum makineleri,
- UML activity ve sequence diyagramları.
Notasyonun amacı kodu ikinci kez yazmak değil, önemli kontrol ve veri ilişkilerini açık hale getirmektir.
Ortak alt sistemler
Kurumsal yazılımlarda bazı teknik işlevler iş alanından bağımsız biçimde tekrar ortaya çıkar:
- kimlik doğrulama ve yetkilendirme,
- güvenlik,
- yedekleme ve kurtarma,
- iletişim,
- arşivleme,
- veri dönüşümü ve göç,
- loglama ve denetim izi,
- yapılandırma yönetimi.
Bu özellikler sonradan eklenen yardımcı kodlar değil, mimari tasarımın parçasıdır.
Tasarımın gözden geçirilmesi
Tasarım incelemesi gerçekleştirim başlamadan önce pahalı hataları bulmayı amaçlar.
Başlangıç tasarım incelemesinde:
- mimari sınırlar,
- ana veri akışları,
- teknoloji kararları,
- kalite gereksinimleri
incelenir.
Ayrıntılı tasarım incelemesinde:
- modül sorumlulukları,
- veri yapıları,
- API sözleşmeleri,
- hata yönetimi,
- eşzamanlama,
- test edilebilirlik
değerlendirilir.
Bağlaşım ve yapışıklık
Klasik Türkçe notlarda bağlaşım coupling, yapışıklık ise cohesion karşılığı olarak kullanılır.
Coupling arttıkça bir modüldeki değişikliğin başka modüllere yayılma olasılığı artar.
Cohesion, aynı modül içindeki öğelerin ortak amaca ne kadar hizmet ettiğini gösterir.
İyi tasarımın genel yönü:
düşük gereksiz coupling
yüksek anlamlı cohesionBu iki özellik tek bir formülle bütün tasarım kalitesini ölçmez. Mimari bağlam ve bağımlılık türü birlikte değerlendirilmelidir.
Tasarım notasyonları
Tarihsel yöntemlerde yapı şemaları ve özel diyagram notasyonları kullanılmıştır.
Günümüzde UML 2.5.1 ortak modelleme standardı olarak kullanılabilir.
Sık kullanılan diyagramlar:
- use case,
- class,
- object,
- sequence,
- state machine,
- activity,
- component,
- dağıtım,
- package.
Her projede bütün UML diyagramlarının çizilmesi gerekmez. Belirsizliği azaltan diyagram kullanılmalıdır.
Kullanıcı arabirimi tasarımı
Arabirim tasarımı yalnız ekranın görsel düzeni değildir.
İyi arayüz:
- kullanıcı görevini destekler,
- tutarlı davranır,
- hatayı önlemeye çalışır,
- hata olduğunda anlaşılır geri bildirim verir,
- gereksiz bilişsel yük oluşturmaz,
- erişilebilirliği gözetir.
Arabirim problemleri
Yaygın sorunlar:
- tutarsız komutlar,
- anlaşılmaz hata mesajları,
- sistem durumunun görünmemesi,
- geri alma olanağının olmaması,
- aşırı bilgi,
- kritik işlemlerde yetersiz doğrulama,
- klavye ve ekran okuyucu erişiminin düşünülmemesi.
Modern kullanıcı deneyimi tasarımında erişilebilirlik temel kalite gereksinimidir.
Ünite 7: Nesne Yönelimli Analiz ve Tasarım
Nesne yönelimli yaklaşım
Nesne yönelimli yaklaşım veri ile bu veri üzerinde çalışan davranışı aynı kavramsal birim altında düzenler.
Temel kavramlar:
- kimlik,
- sınıf,
- nesne,
- kapsülleme,
- kalıtım,
- çok biçimlilik,
- mesajlaşma veya yöntem çağrısı.
Nesne
Nesne:
- kimliğe,
- duruma,
- davranışa
sahiptir.
Aynı değerlere sahip iki nesnenin kimliği farklı olabilir.
Sınıf
Sınıf benzer nesnelerin ortak yapısını ve davranışını tanımlar.
Sınıf
↓
Nesne örnekleriSınıf kavramı gerçek dünya sınıflandırmasını doğrudan kopyalamak zorunda değildir. Yazılım tasarımındaki sorumluluklara göre oluşturulur.
Kapsülleme
Kapsülleme bir nesnenin iç durumunun kontrollü arabirim üzerinden değiştirilmesini sağlar.
Amaç her alan için getter/setter yazmak değildir. Nesnenin geçerli durum kurallarını kendi sınırı içinde korumaktır.
Kalıtım
Kalıtım bir sınıfın başka sınıfın özellik ve davranışlarını genişletmesini sağlar.
Kalıtım güçlü bir yeniden kullanım aracıdır ancak sınıflar arasında sıkı bağ oluşturabilir.
Bu nedenle modern tasarımda yalnız "is-a" ilişkisi açık ve davranışsal olarak doğru olduğunda kullanılmalıdır.
Birçok durumda composition daha esnek olabilir.
Çok biçimlilik
Polymorphism, aynı arabirim üzerinden farklı gerçekleştirimlerin kullanılabilmesidir.
Örneğin:
Depolama
├─ DosyaDepolama
├─ VeritabaniDepolama
└─ NesneDepolamaÇağıran kod somut gerçekleştirim yerine ortak sözleşmeye bağımlı olabilir.
Bu yaklaşım genişletilebilirliği artırır.
Nesne yönelimli analiz
Nesne yönelimli analizde problem alanındaki:
- aktörler,
- varlıklar,
- sorumluluklar,
- ilişkiler,
- olaylar,
- durumlar
belirlenir.
Amaç doğrudan sınıf kodu yazmak değil, problem alanını nesne ve etkileşimler üzerinden anlamaktır.
Coad-Yourdon yaklaşımı
Coad-Yourdon yöntemi nesne yönelimli analizin erken sistematik yöntemlerindendir.
Modeli:
- konu,
- nesne,
- yapı,
- özellik,
- işlev
katmanlarıyla ele alır.
Tarihsel önemi vardır ancak bugün yaygın modelleme dili değildir.
Bu yaklaşımın kalıcı fikri:
Analiz, veri yapısından ayrı olarak nesnelerin kimliğini, ilişkilerini ve davranışını birlikte ele almalıdır.
Booch yaklaşımı ve UML
Booch yöntemi nesne yönelimli tasarımın önemli tarihsel yöntemlerinden biridir.
Booch, Rumbaugh ve Jacobson'ın yaklaşımları daha sonra UML'in oluşumunda birleşmiştir.
Bu nedenle eski Booch diyagramlarını ezberlemek yerine güncel karşılıkları olan UML diyagramlarını bilmek daha değerlidir.
UML sınıf diyagramı
Sınıfları ve aralarındaki yapısal ilişkileri gösterir.
+----------------+
| Siparis |
+----------------+
| id |
| tarih |
+----------------+
| iptalEt() |
+----------------+
|
| 1
|
| *
+----------------+
| SiparisSatiri |
+----------------+Başlıca ilişkiler:
- association,
- aggregation,
- composition,
- inheritance,
- dependency.
Sequence diyagramı
Nesneler arasındaki mesajların zaman sırasını gösterir.
Örneğin:
Kullanici -> SiparisServisi: iptalEt()
SiparisServisi -> Depo: rezervasyonuBirak()
SiparisServisi -> Odeme: iadeEt()
SiparisServisi -> Kullanici: sonucDağıtık sistemlerde çağrı sırası ve sorumlulukları anlamak için yararlıdır.
State machine diyagramı
Bir nesnenin yaşam döngüsünü durumlar üzerinden gösterir.
OLUSTURULDU
↓ onay
ONAYLANDI
↓ sevk
SEVK_EDILDI
↓ teslim
TESLIM_EDILDIGeçiş kuralları karmaşık iş süreçlerinde açık model sağlar.
Activity diyagramı
İş veya kontrol akışını gösterir.
Paralel işler, kararlar ve süreç adımlarını görselleştirmek için kullanılabilir.
Package diyagramı
Kod veya model öğelerinin paketler halinde nasıl gruplandığını ve bağımlılıklarını gösterir.
Paket sınırları mimari bağımlılıkların yönetiminde önemlidir.
Component diyagramı
Sistemin dağıtılabilir veya değiştirilebilir büyük bileşenlerini ve arayüzlerini gösterir.
Modern servis ve modüler uygulama mimarilerinde yararlıdır.
Kullanım durumları
Use case, bir aktörün sistemle belirli hedefe ulaşmak için yaptığı etkileşimi tanımlar.
Bir kullanım durumu tipik olarak:
- aktör,
- önkoşul,
- temel akış,
- alternatif akışlar,
- hata durumları,
- sonkoşul
bilgilerini içerir.
Use case ekran tasarımı değildir. Kullanıcı veya dış sistem açısından gözlenebilir hedefi açıklar.
CRC kartları
Class-Responsibility-Collaborator, CRC yaklaşımı sınıfları erken analiz aşamasında basit kartlarla düşünmeyi sağlar.
Her kart:
Sınıf
- Sorumluluklar
- İşbirliği yaptığı sınıflarbilgisini içerir.
CRC'nin değeri ayrıntılı kod üretmek değil, sorumlulukların doğru nesnelere dağıtılmasını tartışmaktır.
Nesne ilişkileri
Nesne modellerinde başlıca ilişkiler:
- association,
- dependency,
- aggregation,
- composition,
- inheritance.
Composition güçlü yaşam döngüsü sahipliğini, sıradan association ise daha gevşek ilişkiyi ifade edebilir.
Çoklu kalıtım bazı dillerde desteklenir ancak isim çakışması ve karmaşık sınıf hiyerarşileri oluşturabilir. Arayüz ve composition çoğu durumda daha sade alternatif sağlar.
Eşzamanlılık ve alt sistem tasarımı
Nesne yönelimli tasarım yalnız sınıf yapısı değildir. Sistem eşzamanlı çalışıyorsa:
- hangi işlerin ayrı iş parçacığı veya süreçte çalışacağı,
- paylaşılan durumun nerede tutulacağı,
- senkronizasyon sınırlarının ne olacağı,
- mesajlaşma veya kuyrukların nasıl kullanılacağı
belirlenmelidir.
Alt sistem tasarımında ayrıca:
- görev yönetimi,
- veri yönetimi,
- kaynak yönetimi,
- kullanıcı arayüzü,
- dış sistem iletişimi
ayrı sorumluluk alanları olarak ele alınabilir.
Tasarım kalıpları
Design pattern, tekrar eden tasarım problemine bağlama bağlı genel çözüm şablonudur.
Kalıp doğrudan kopyalanacak kod değildir.
Örnekler:
- Strategy,
- Observer,
- Factory Method,
- Adapter,
- Decorator.
Bir kalıp ancak gerçekten çözdüğü problem varsa kullanılmalıdır. Gereksiz pattern kullanımı tasarımı sadeleştirmek yerine karmaşıklaştırabilir.
Tasarımın tamamlanması
Nesne yönelimli tasarım yalnız sınıf diyagramı üretmekle tamamlanmaz.
Tasarım şu sorulara yanıt vermelidir:
- Hangi nesne hangi sorumluluğa sahip?
- Verinin sahibi kim?
- İş kuralları nerede?
- Hangi bağımlılıklar ters çevrilmeli?
- Hangi işlemler transaction sınırı oluşturuyor?
- Hata nasıl yayılıyor?
- Nesneler hangi yaşam döngüsüne sahip?
- Paralel erişim nasıl yönetiliyor?
SOLID ile bağlantı
Modern nesne yönelimli tasarımda SOLID ilkeleri sınıf ve modül sınırlarını değerlendirmek için kullanılabilir:
- Single Responsibility Principle,
- Open/Closed Principle,
- Liskov Substitution Principle,
- Interface Segregation Principle,
- Dependency Inversion Principle.
Bunlar katı kurallar değil, bağımlılık ve değişiklik maliyetini düşünmek için tasarım ilkeleridir.
Composition over inheritance
Kalıtım yalnız kod tekrarını azaltmak için kullanılmamalıdır.
Composition:
Nesne A
|
+--> Hizmet Bile davranış çalışma zamanında daha esnek birleştirilebilir.
Bu nedenle modern tasarımda "composition over inheritance" sık kullanılan bir ilkedir.
Nesne yönelimli tasarımın sınırları
Her problem nesne yönelimli model gerektirmez.
Fonksiyonel, veri yönelimli, olay güdümlü veya veri akışı tabanlı tasarım kimi problemlerde daha doğal olabilir.
Mühendislik yaklaşımı paradigmadan önce probleme bakar.
Ünite 8: Gerçekleştirim ve Kodlama
Gerçekleştirim aşaması
Gerçekleştirim, tasarım kararlarının çalıştırılabilir yazılıma dönüştürülmesidir.
Bu aşamada yalnız kod yazılmaz. Aynı zamanda:
- veri tabanı nesneleri,
- yapılandırma,
- derleme sistemi,
- bağımlılıklar,
- test kodu,
- dağıtım paketleri
üretilir.
Gerçekleştirim tasarımdan kopuk yürütülmemelidir. Kod sırasında yeni teknik bilgi ortaya çıkarsa tasarım da güncellenmelidir.
Yazılım geliştirme ortamları
Geliştirme ortamı şu araçların birlikte çalışmasından oluşur:
- programlama dili ve derleyici,
- IDE veya editör,
- sürüm kontrol sistemi,
- derleme aracı,
- paket ve bağımlılık yöneticisi,
- veri tabanı sistemi,
- test araçları,
- statik analiz araçları,
- hata ayıklayıcı,
- CI/CD sistemi.
Araç seçimi projenin gereksinimine göre yapılmalıdır. Bir aracın popüler olması tek başına teknik gerekçe değildir.
Programlama dilleri
Programlama dili seçimi şu ölçütlerle değerlendirilir:
- problem alanına uygunluk,
- çalışma zamanı performansı,
- bellek ve gerçek zaman gereksinimleri,
- ekosistem,
- güvenlik özellikleri,
- ekip deneyimi,
- hedef platform,
- bakım ve destek süresi.
Tek bir dil bütün yazılım sınıfları için en iyi değildir.
Veri tabanı yönetim sistemleri
VTYS geleneksel dosya kullanımına göre:
- ortak veri modeli,
- veri sözlüğü ve üstveri,
- veri bağımsızlığı,
- eşzamanlı kullanıcı desteği,
- transaction,
- bütünlük sınırlamaları,
- erişim denetimi,
- sorgulama
olanakları sunar.
İlişkisel, belge, anahtar-değer, grafik ve zaman serisi gibi veri modelleri farklı gereksinimlere cevap verir. Veri tabanı seçimi yalnız geliştirme kolaylığına göre değil, veri tutarlılığı ve erişim deseni üzerinden yapılmalıdır.
Hazır kütüphaneler ve bileşenler
Her işlevi yeniden geliştirmek yerine güvenilir kütüphane ve bileşenlerden yararlanmak üretim maliyetini azaltabilir.
Buna karşılık her bağımlılık:
- sürüm,
- güvenlik,
- lisans,
- bakım,
- tedarik zinciri
riski getirir.
Bu nedenle üçüncü taraf kod da ürün konfigürasyonunun parçasıdır.
Kodlama stili
Kodlama stilinin amacı estetik birlikten önce okunabilirlik ve ortak çalışma sağlamaktır.
Temel ilkeler:
- anlamlı isimler,
- tutarlı biçimleme,
- küçük ve belirgin sorumluluklar,
- gereksiz tekrarın azaltılması,
- karmaşık koşulların sadeleştirilmesi,
- hata yollarının görünür olması.
Yorum satırı kodun ne yaptığını tekrar etmemeli; gerekçe, varsayım veya dış kısıt gibi koddan anlaşılamayan bilgiyi açıklamalıdır.
Olağandışı durum yönetimi
Hata yönetimi normal kontrol akışının parçasıdır.
Hatalar kabaca:
- geçersiz girdi,
- beklenen iş kuralı ihlali,
- geçici altyapı hatası,
- kalıcı dış sistem hatası,
- programlama hatası
olarak ayrılabilir.
Her hata için aynı mekanizma uygun değildir. Yeniden deneme yalnız geçici olduğu bilinen hatalarda anlamlıdır.
Bir istisna yakalanıp sessizce yok edilmemelidir. Sistem ya hatayı düzeltebilmeli ya da yeterli bağlamla üst katmana aktarabilmelidir.
Kod gözden geçirme
Code review yalnız biçim hatası aramak için yapılmaz.
İnceleme sırasında:
- doğruluk,
- güvenlik,
- veri ve sınır durumları,
- concurrency,
- hata yönetimi,
- test edilebilirlik,
- gereksiz karmaşıklık,
- API uyumu
kontrol edilir.
Otomatik formatter ve linter ile bulunabilen sorunları insan incelemesine bırakmak verimsizdir. İnsan incelemesi daha çok semantik ve tasarım problemlerine odaklanmalıdır.
Ünite 9: Yazılım Mimarileri
Mimari yaklaşım
Yazılım mimarisi sistemi büyük sorumluluk alanlarına ve iletişim sınırlarına böler.
Mimari seçim:
- performans,
- güvenilirlik,
- güvenlik,
- ölçeklenebilirlik,
- dağıtım,
- ekip yapısı,
- bakım maliyeti
üzerinde uzun süreli etki oluşturur.
İstemci-sunucu mimarisi
İstemci bir hizmet talep eder. Sunucu hizmeti sağlar.
İstemci -> İstek -> Sunucu
İstemci <- Yanıt <- SunucuSunucu farklı hizmet türlerini sağlayabilir:
- dosya,
- veri tabanı,
- uygulama,
- web,
- kimlik,
- mesajlaşma.
Güncel dağıtık sistemlerde aynı uygulama aynı anda hem istemci hem sunucu rolü oynayabilir.
İki katmanlı mimari
İki katmanlı yapıda kullanıcı arayüzü ve uygulama mantığının önemli bölümü istemcide, veri hizmeti sunucuda bulunabilir.
İstemci uygulaması <-> Veri tabanı sunucusuBasit sistemlerde düşük ek katman maliyeti sağlar. Çok sayıda istemci olduğunda dağıtım ve sürüm yönetimi zorlaşabilir.
Üç katmanlı mimari
Üç temel katman:
Sunum
↓
Uygulama / İş mantığı
↓
Veriİstemci veri tabanına doğrudan erişmek yerine uygulama katmanına bağlanır.
Avantajları:
- iş mantığının merkezileştirilmesi,
- güvenlik sınırlarının belirginleşmesi,
- istemci dağıtımının sadeleşmesi,
- yatay ölçeklendirme olanaklarıdır.
N katmanlı ve dağıtık mimariler
Üç katmanlı model daha fazla teknik katmana ayrılabilir:
- API gateway,
- web katmanı,
- uygulama servisleri,
- mesajlaşma,
- önbellek,
- veri katmanı.
Katman sayısı arttıkça dağıtık sistem maliyetleri de artar:
- ağ gecikmesi,
- kısmi arıza,
- gözlemlenebilirlik gereksinimi,
- transaction karmaşıklığı.
Web mimarisi
Klasik web yapısı:
Tarayıcı
↓ HTTP
Web / Uygulama sunucusu
↓
Veri ve dış servislerModern web uygulamalarında:
- REST veya RPC API'leri,
- gerçek zamanlı bağlantılar,
- CDN,
- ters proxy,
- kimlik servisleri,
- istemci tarafı uygulamalar
aynı sistem içinde bulunabilir.
Tarihsel WAP yaklaşımı
WAP, sınırlı yetenekli erken mobil aygıtlar için geliştirilen tarihsel kablosuz uygulama mimarisidir. Mobil tarayıcıların, HTML/CSS/JavaScript desteğinin ve genel IP tabanlı mobil ağların gelişmesiyle temel uygulama modeli olmaktan çıkmıştır.
Kalıcı ders, istemci kapasitesi ve ağ özelliklerinin uygulama protokolü ile kullanıcı arayüzü tasarımını doğrudan etkileyebilmesidir.
Bileşen tabanlı mimari
Bileşen, açık bir sözleşme üzerinden kullanılan ve iç gerçekleştirimini gizleyen yeniden kullanılabilir yazılım parçasıdır.
İyi bir bileşen:
- açık arayüze,
- sınırlı sorumluluğa,
- değiştirilebilir gerçekleştirim yapısına,
- belgelenmiş bağımlılıklara
sahiptir.
Tarihsel COM/DCOM, JavaBeans ve benzeri teknolojiler bileşen yaklaşımının erken örnekleridir. Günümüzde aynı düşünce:
- modüller,
- paketler,
- kütüphaneler,
- servisler,
- plugin sistemleri
üzerinden devam eder.
Servis yönelimli ve mikroservis mimarileri
Servis yönelimli yaklaşım işlevleri ağ üzerinden açık sözleşmelerle sunar.
Mikroservis mimarisi bu fikri daha küçük ve bağımsız dağıtılabilir hizmetlere uygular.
Avantajları bağlama göre:
- bağımsız dağıtım,
- ekip özerkliği,
- farklı ölçeklendirme profilleri
olabilir.
Maliyetleri:
- dağıtık transaction,
- ağ hataları,
- operasyon yükü,
- gözlemlenebilirlik,
- sürüm uyumluluğudur.
Bu nedenle küçük bir sistemin mikroservislere bölünmesi otomatik olarak daha iyi mimari oluşturmaz.
Üretim Davranışı: Mimari Normal Akıştan İbaret Değildir
Bir mimari diyagramı servisleri, veri depolarını ve bağlantıları gösterebilir; fakat üretimde asıl davranış bu bileşenler yavaşladığında, kısmen erişilemez olduğunda veya kapasite sınırına yaklaştığında ortaya çıkar. Bu nedenle mimari değerlendirme yalnız başarılı istek yolunu değil failure path ve recovery path davranışını da kapsamalıdır.
Bir uzak bağımlılık yavaşladığında tipik zincir şöyledir:
bağımlılık gecikmesi
-> çağrının kaynağı daha uzun tutması
-> eşzamanlı iş sayısının artması
-> pool / thread / connection baskısı
-> kuyruk büyümesi
-> tail latency artışı
-> timeout
-> kontrolsüz retry varsa ek trafik
-> başlangıçtaki yerel sorunun sistemik hale gelmesiBu zincirde tek başına hiçbir satır mimari kusur olmak zorunda değildir. Problem, bir katmanın diğer katmanın kapasite ve hata davranışını sınırsız biçimde üzerine almasıyla oluşur. Bu nedenle timeout, bounded kuyruk (queue), concurrency limit, load shedding, circuit breaker veya bulkhead benzeri mekanizmalar yalnız kütüphane seçimi değil hata alanını sınırlayan mimari kararlar olarak düşünülmelidir.
Yavaşlık da bir hata kipidir
Bir bağımlılığın bağlantıyı tamamen reddetmesi çoğu zaman hızlı fark edilir. Daha tehlikeli durum, cevap vermeye devam ederken giderek yavaşlamasıdır. Bu durumda sistem teknik olarak up görünebilir ancak kaynaklar çağrıların üzerinde tutulduğu için kapasite içeriden tüketilir.
Bu nedenle health check yalnız process çalışıyor mu? sorusuna indirgenmemelidir. Gerekli olduğunda:
yanıt doğruluğu
+ gecikme bütçesi
+ bağımlılık doygunluğu
+ kuyruk derinliği
+ toparlanma davranışıbirlikte değerlendirilir.
İzolasyon performans optimizasyonundan farklıdır
İki iş yükünün aynı iş parçacığı (thread), connection veya worker bütçesini paylaşması en yüksek ortalama kullanım oranını sağlayabilir. Buna karşılık düşük öncelikli veya pahalı bir iş yükünün kritik akışı tüketmesine de izin verebilir. Kaynak havuzunu veya eşzamanlılık bütçesini ayırmak bazen toplam teorik verimi azaltır; fakat blast radius küçülür ve kritik yolun öngörülebilirliği artar.
Bu nedenle mimari trade-off yalnız en yüksek throughput değildir:
verim
↔ izolasyon
↔ gecikme öngörülebilirliği
↔ toparlanma süresibirlikte değerlendirilmelidir.
Kararlı durum bir üretim gereksinimidir
Sistem bir saat sorunsuz çalışıp zamanla kuyruk, geçici dosya, log, oturum, önbellek (cache) anahtarı, native buffer veya bağlantı biriktiriyorsa üretim için kararlı değildir. Uzun süreli çalışma sonunda kaynak tüketiminin kabul edilebilir bir çalışma bandına dönmesi ayrıca doğrulanmalıdır.
yük gelir
-> sistem tepki verir
-> yük azalır
-> kuyruk boşalır
-> geçici kaynaklar bırakılır
-> sistem güvenli çalışma bandına dönerBu son adım yoksa başarı yalnız kısa süreli işlem hacmi (işlem hacmi (throughput)) ölçümüdür. Üretime hazır (production-ready) tasarım, başlangıç kapasitesi kadar kaynak yaşam döngüsü ve toparlanma (recovery) davranışını da mimari sözleşmenin parçası kabul eder.
Modüler Monolitten Dağıtık Servislere: Sınır Taşımak Bir Maliyet Transferidir
Monolit ve mikroservis ayrımı yalnız uygulamanın kaç process olarak çalıştırıldığı sorusu değildir.
Asıl mimari karar şudur:
hangi sorumluluk
hangi veri
hangi failure boundary
hangi deployment boundary
içinde yaşayacak?Bir modülü aynı process içinde tutmak ile ayrı servise taşımak iş mantığını ortadan kaldırmaz. Sınırı process dışına taşıyarak farklı maliyetler üretir.
Modülerlik ile dağıtıklık aynı kavram değildir
Bir uygulama tek deployable artifact olduğu halde güçlü modül sınırlarına sahip olabilir:
application
├── identity
├── orders
├── inventory
└── reportingHer modül kendi sorumluluğunu, açık giriş noktalarını, iç implementation detaylarını ve izin verilen bağımlılıklarını tanımlayabilir.
Buna karşılık onlarca ayrı servisten oluşan bir sistemde bütün servisler aynı veritabanı tablolarına doğrudan erişiyor, birlikte deploy edilmek zorunda kalıyor veya senkron çağrı zinciriyle birbirine kilitleniyorsa fiziksel dağıtım gerçek modülerlik sağlamamış olabilir.
Bu nedenle:
çok process ≠ düşük coupling
tek process ≠ yüksek couplingProcess sınırı yeni bir failure boundary üretir
Aynı process içindeki çağrı yaklaşık olarak:
caller
↓
function / method
↓
return / exceptionmodeline sahiptir.
Ağ sınırı eklendiğinde serialization, network, remote kuyruk/worker, remote dependency ve response path gibi yeni aşamalar oluşur.
Artık bağlantı kurulamaması, isteğin ulaşıp cevabın kaybolması, belirsiz sonuçlu yeniden deneme (retry), timeout sahipliği, sürüm uyumluluğu, kısmi hata ve uç gecikme ayrı mühendislik problemleridir.
Bir yöntem çağrısı (method call) ağ çağrısına (network call) dönüştüğünde yalnız gecikme (gecikme (latency)) eklenmez; belirsizlik de eklenir.
Dağıtım bağımsızlığı gerçekten kullanılıyor mu?
Microservice ayrımının güçlü gerekçelerinden biri bağımsız dağıtım (deployment) olabilir.
Ancak bir servis değiştiğinde birkaç başka servisin aynı release train içinde zorunlu olarak deploy edilmesi gerekiyorsa fiziksel ayrım dağıtım bağımsızlığı üretmemiştir.
Gerçek bağımsızlık için contractlerin belirli ölçüde geriye uyumlu evrilebilmesi gerekir.
Bir servisin her değişikliğinde çok sayıda servisin aynı anda release edilmesi gerekiyorsa distributed monolith oluşmuş olabilir.
Veri sahipliği servis sınırının merkezindedir
Kod kolay ayrılır; veri sınırları daha zordur.
İki servis aynı tabloyu doğrudan güncelliyorsa schema, invariant, migration sırası, kilit (lock) davranışı ve alan anlamı üzerindeki sahiplik belirsizleşebilir.
Bu nedenle servis sınırının gerçek anlamı yalnız API uç nokta (endpoint) değildir.
Güçlü bir sınır genellikle:
behavior ownership
+
data ownership
+
change ownershipbileşimini içerir.
Her mikroservisin fiziksel olarak ayrı database sunucusuna sahip olması evrensel zorunluluk değildir. Önemli olan veri değişikliklerinin sahipliği ve başka bileşenlerin bu sınırı nasıl geçtiğinin açık olmasıdır.
Yerel transaction dağıtıldığında problem şekil değiştirir
Tek database içindeki bir transaction birden fazla adımı tek atomic boundary içinde tutabilir.
Bu işlemler ayrı servislere dağıtıldığında aynı ACID transaction doğal olarak bütün ağı kapsamaz.
Artık ikinci adımın başarısız olması, ilk işlemin geri alınabilirliği, mesajın iki kez gelmesi, servisin geçici erişilemezliği ve iş akışının tamamlanıp tamamlanmadığı açık state modeli gerektirir.
Saga, outbox, idempotency veya compensation gibi desenler bu yeni failure modelini yönetir. Bunlar dağıtımın ücretsiz özellikleri değil, dağıtımın doğurduğu problemler için ek mekanizmalardır.
local transaction
↓ dağıtım
distributed workflow
↓
state machine + failure handlingBu dönüşüm mimari maliyet olarak hesaba katılmalıdır.
Ağ çağrısı mimari bağımlılığı daha pahalı yapar
Bir modül diğer modülü gereksiz yere çağırıyorsa monolit içinde bu durum düşük gecikme nedeniyle uzun süre fark edilmeyebilir.
Aynı coupling ağ üzerinden gerçekleştiğinde gecikme, serialization, timeout, yeniden deneme, connection management, observability, versioning ve partial failure maliyetleri görünür hale gelir.
Bu durum microservice mimarisinin kötü olduğu anlamına gelmez. Process sınırı gerçek bir organizasyon, izolasyon, güvenlik veya ölçekleme ihtiyacını karşılıyorsa maliyet kabul edilebilir.
Dağıtım kötü modül sınırlarını otomatik olarak düzeltmez.
Fan-out tail latencyyi büyütebilir
Bir kullanıcı isteği birden fazla senkron servise dağılıyorsa uç yanıt çoğu zaman en yavaş gerekli dependency tamamlanmadan bitmez.
Her dependency nadiren yavaşlasa bile fan-out sayısı arttıkça kullanıcının en az bir yavaş dependency ile karşılaşma olasılığı artar.
Bu nedenle dağıtılmış bir mimaride ortalama servis gecikme tek başına yeterli değildir. End-to-end P95, P99, timeout budget, fan-out ve yeniden deneme amplification birlikte düşünülmelidir.
Performans modeli Java Tabanlı Veri Sistemlerinde Yüksek Başarım notunda daha ayrıntılı ele alınır.
yeniden deneme yeni trafik üreten bir mekanizmadır
Remote call başarısız olduğunda yeniden deneme ilk bakışta güvenilirliği artırır.
Ancak timeout nedeni gerçek overload ise:
overload
↓
timeout
↓
retry
↓
daha fazla load
↓
daha fazla timeoutpozitif geri beslemesi oluşabilir.
Dağıtım kararı bu nedenle yeniden deneme, timeout, backoff, jitter, idempotency ve load shedding politikalarını da mimarinin parçası yapar.
Operasyonel vergi
Her bağımsız servis için yalnız business logic çalıştırılmaz.
Build, artifact, configuration, secret, dağıtım, health, logging, metrics, tracing, alerting, capacity, backup/recovery, security updates ve version compatibility de yönetilir.
On servis yalnız on kod tabanı anlamına gelmez; on ayrı operasyonel yaşam döngüsü anlamına gelebilir.
Bu yük otomasyonla ciddi ölçüde azaltılabilir, ancak sıfıra inmez.
Organizasyon sınırı teknik sınır kadar önemlidir
İki servis sürekli aynı ekip tarafından birlikte değiştiriliyor ve aynı iş kuralının parçalarını taşıyorsa bölünme doğal sınırı temsil etmiyor olabilir.
Buna karşılık farklı ekiplerin farklı değişim hızlarına, ölçekleme gereksinimlerine, güvenlik sınırlarına veya release yaşam döngülerine sahip olduğu alanlarda bağımsız servis sınırı gerçek değer üretebilir.
Mimari yalnız CPU ve RAM topolojisi değildir. İnsanların değişiklik üretme topolojisini de etkiler.
Modüler monolit bir ara aşama olmak zorunda değildir
Modüler monolit bazen mikroservise geçmeden önceki geçici mimari gibi sunulur. Bu zorunlu değildir.
Sistem tek dağıtım ile güvenle yönetilebiliyor, modüller bağımsız anlaşılabiliyor, veri sınırları açık, yük tek process sınırında karşılanabiliyor ve organizasyon bağımsız dağıtım gerektirmiyorsa modüler monolit kalıcı ve güçlü bir mimari olabilir.
Ayrı servis ancak yeni bir gereksinimi çözdüğünde anlam kazanır.
Ayrıştırma için daha güçlü tetikleyiciler
Bir modülü ayrı servise taşımak için daha güçlü gerekçeler şunlardır:
- workloadun gerçekten bağımsız ölçeklenmesi,
- bağımsız dağıtım ihtiyacı,
- fiziksel fault isolation gereksinimi,
- ayrı security/trust boundary gereksinimi,
- gerçekten farklı çalışma zamanı (runtime) veya altyapı gereksinimi,
- doğal ekip sahipliği,
- ayrı veri/invariant yaşam döngüsü.
Buna karşılık mikroservis modern olduğu için, ileride belki büyür diye veya her domain noun için service olsun gibi gerekçeler zayıftır.
Ayrıştırmadan önce mantıksal bağımsızlığı sınamak
Bir modül process dışına taşınmadan önce mantıksal bağımsızlığı test edilebilir.
Package visibility, architecture tests veya modül doğrulama araçlarıyla bir modülün yalnız açık API üzerinden kullanılması sağlanabilir.
Spring ekosisteminde Spring Modulith bu amaçla uygulama modüllerini, dışa açık arayüzlerini ve modüller arası dependency ilişkilerini modelleyip doğrulayabilir.
Buradaki önemli nokta kullanılan araç değildir.
Temel mühendislik sorusu şudur:
network boundary eklemeden önce
logical boundary çalışıyor mu?Kötü bir logical boundary ayrı process içine taşındığında yalnız daha pahalı hale gelir.
Kontrollü ayrıştırma
Çalışan büyük bir sistemi bir defada mikroservislere bölmek hem business behavior hem dağıtım/failure topology değişkenlerini aynı anda değiştirir.
Daha kontrollü yaklaşım:
mevcut davranışı ölç
↓
modül sınırını belirle
↓
iç bağımlılıkları azalt
↓
contract oluştur
↓
gerekliyse sınırı process dışına taşı
↓
aynı davranışı doğrulaşeklindedir.
Bu yaklaşım bakım mühendisliğinin temel kuralıyla aynıdır: modernizasyonun amacı çalışan davranışı yeniden icat etmek değil, gerçek bir problemi kontrollü değişiklikle çözmektir.
Son ilke
Monolit ile mikroservis arasındaki temel soru hangi mimarinin daha modern olduğu değildir.
Daha yararlı soru şudur:
hangi sınırı process dışına taşımak
hangi somut problemi çözüyor
ve bunun karşılığında hangi yeni
failure ve operasyon maliyetlerini kabul ediyoruz?Dağıtık mimari karmaşıklığı ortadan kaldırmaz. Karmaşıklığın yerini değiştirir.
İlgili teknik kaynaklar
- Spring Modulith Reference: https://docs.spring.io/spring-modulith/reference/
- Martin Fowler, Microservices: https://martinfowler.com/articles/microservices.html
- Martin Fowler, MonolithFirst: https://martinfowler.com/bliki/MonolithFirst.html
- Sam Newman, Building Microservices, 2nd ed., O'Reilly Media, 2021
Ünite 10: CASE, Araç Zincirleri ve Değişim Mühendisliği
CASE kavramı
CASE araçları yazılım yaşam döngüsünün mühendislik etkinliklerini bilgisayar desteğiyle yürütmeyi amaçlar.
Tarihsel sınıflandırmada araçlar:
- gereksinim,
- süreç modelleme,
- veri modelleme,
- proje planlama,
- risk analizi,
- tasarım,
- kod üretimi,
- test,
- kalite,
- konfigürasyon,
- belgeleme
işlevlerine göre ayrılır.
CASE araçlarının bütünleştirilmesi
Bütünleşik bir mühendislik ortamında üç tür bütünlük önemlidir.
Veri bütünlüğü: Bir araçta üretilen model veya üstveri diğer araçlar tarafından da kullanılabilir.
Denetim bütünlüğü: Bir araç diğerini iş akışının parçası olarak tetikleyebilir.
Arabirim bütünlüğü: Kullanıcı araçlar arasında benzer etkileşim ve çalışma modeli görür.
Günümüzde bu bütünleşme tek büyük CASE ürünü yerine API'ler, Git, CI/CD ve standart dosya biçimleri üzerinden dağıtık araç zincirleriyle sağlanabilir.
Modern mühendislik araç zinciri
Gereksinim / issue
↓
Sürüm kontrolü
↓
Kod inceleme
↓
Build
↓
Statik analiz
↓
Test
↓
Paket / artefakt
↓
Dağıtım
↓
İzleme
↓
Geri bildirimBu zincirin en önemli özelliği izlenebilirliktir. Bir üretim sürümündeki değişiklik hangi gereksinim, commit, derleme ve test sonucundan geldiğiyle ilişkilendirilebilmelidir.
CASE aracı seçimi
Araç kullanımı kendi başına verimlilik sağlamaz.
Değerlendirme ölçütleri:
- proje büyüklüğü,
- ekip deneyimi,
- öğrenme maliyeti,
- bütünleşme gereksinimi,
- lisans ve işletim maliyeti,
- dışa aktarılabilir veri biçimleri,
- tedarikçi bağımlılığı.
Basit bir projede ağır bir süreç aracı verimi azaltabilir. Büyük ve uzun ömürlü projelerde ise izlenebilirlik ve otomasyon maliyeti kısa sürede geri kazanılabilir.
Tersine ve yeniden mühendislik
Reverse engineering, mevcut sistemden daha üst düzey bilgi çıkarmayı amaçlar.
Örnekler:
- koddan çağrı grafı çıkarma,
- veri tabanından ER modeli üretme,
- binary veya protokolden davranış analizi,
- bağımlılık haritası oluşturma.
Reengineering, mevcut sistemi daha sürdürülebilir yapıya dönüştürür.
Bu süreç:
Mevcut sistem
↓
Analiz / tersine mühendislik
↓
Model ve bilgi kazanımı
↓
Yeniden tasarım
↓
Dönüşüm / modernizasyon
↓
Doğrulamaşeklinde düşünülebilir.
Eski sistemlerde eksik dokümantasyon nedeniyle kod, veri tabanı, çalışma zamanı kayıtları ve kullanıcı davranışı birlikte incelenebilir.
Genel Çerçeve
Yazılım mühendisliği konuları birbirinden bağımsız değildir.
Bir gereksinim değiştiğinde:
Gereksinim
↓
Etki analizi
↓
Mimari / tasarım
↓
Kod
↓
Test
↓
Konfigürasyon
↓
Sürüm
↓
Dağıtım
↓
İşletimzinciri etkilenebilir.
Proje yönetimi bu zincirin süre ve kaynaklarını yönetir.
Kalite yönetimi çıktının beklenen özellikleri sağlamasını gözetir.
Konfigürasyon yönetimi hangi değişikliğin hangi sürümde olduğunu izler.
Test değişikliğin doğruluğunu denetler.
Bakım sistemi yaşam döngüsü boyunca ayakta tutar.
Gereksinim analizi yanlışsa iyi kod yanlış problemi çözer.
Mimari kötü ise doğru gereksinim pahalı ve kırılgan biçimde gerçekleştirilir.
Test zayıfsa hatalar kullanıcıya kadar ulaşır.
Konfigürasyon yönetimi yoksa doğru kodun hangi sürümde olduğu bilinmez.
Bu nedenle yazılım mühendisliği "iyi programlama"dan daha geniştir.
Güvenlik ve Değişebilirlik İçin Ayrı Derinleşme
Süreç, gereksinim, tasarım ve kalite genel yazılım mühendisliği çerçevesinin ana eksenleridir. Tehdit modeli, güven sınırları, güvenli geliştirme ve doğrulama için Güvenli Yazılım Mühendisliği; değişime dayanıklı bağımlılık tasarımı için SOLID ile Değişime Dayanıklı Mimari ayrı derinleşme notlarıdır.
Kendini İspatlamış Büyük Sistemlerde Değişiklik Mühendisliği
Yeni bir sistem tasarlamak ile yıllardır çalışan bir sistemi değiştirmek aynı mühendislik problemi değildir. Sıfırdan geliştirilen projede mimari ideal ön planda olabilir; üretimde kendini ispatlamış sistemde ise gözlenen davranış, kullanıcı alışkanlığı, veri gerçekliği ve işletim süreçleri de kontratın parçasıdır.
Bu nedenle modernizasyonun ilk sorusu “bugün sıfırdan yazsam nasıl tasarlardım?” değil, “hangi davranışı neden korumalıyım ve hangi problemi gerçekten çözmeye çalışıyorum?” olmalıdır. Çalışan sistemi yalnız daha güncel bir çatı, daha kısa kod veya daha simetrik paket yapısı için yeniden kurmak değişiklik riskini artırabilir.
Güvenli değişiklik birkaç ilkeye dayanır:
mevcut davranışı kaynak koddan doğrula
etkilenen akışı sınırla
en küçük tutarlı değişikliği yap
geriye uyumluluğu koru
risk düzeyine göre doğrula
yeni kalıcı kural oluştuysa belgeye taşıBurada “eski” ile “hatalı” kavramları ayrılmalıdır. Şema kısıtı, tarihsel veri tekrarı, alışılmış klavye davranışı veya belirli bir entegrasyon yolu ideal tasarımdan farklı olabilir; fakat üretim kontratı haline gelmişse değiştirilmesi ayrı bir gereksinim ve doğrulama çalışmasıdır. Buna karşılık kanıtlanmış gerçek kusur, sırf legacy olduğu için korunmaz.
Aşamalı modernizasyon bu nedenle büyük yeniden yazımdan daha güçlü olabilir. Önce gözlenebilir ve geri alınabilir sınırlar seçilir; davranış eşdeğerliği gösterilir; sonra bir sonraki aşamaya geçilir. Her aşama kendi kabul ölçütünü ve artık riskini taşır. Yazılım Test Mühendisliği açısından bu, doğrulama kanıtını değişiklikle aynı ritimde üretmek anlamına gelir.
Kullanıcı arayüzü de bu kontratın parçasıdır. Yıllardır yoğun kullanılan bir iş uygulamasında panel sırası, klavye kısayolu veya kayıt seçim davranışı yalnız görsel tercih değildir; kas hafızasına dönüşmüş çalışma biçimidir. Bu tür değişiklikler Web Uygulamalarında UI/UX Mühendisliği kapsamında UX regresyonu olarak değerlendirilmelidir.
Bakım mühendisliğinin amacı bütün tarihsel izleri temizlemek değildir. Amaç, sistemin neden böyle davrandığını görünür kılmak, gereksiz karmaşıklığı azaltmak ve her yeni değişikliğin etki alanını küçültmektir. Bu bakış Temiz Kod ve Bakım Mühendisliği ile süreç mühendisliğini aynı noktada buluşturur.
Davranış envanteri ve değişiklik kanıt zinciri
Kritik bir sistemi değiştirmeden önce gereksinim belgesinin yanında çalışan davranışın da envanteri çıkarılmalıdır. Kod, kullanıcı akışı, veri kaynağı ve işletim kuralı zaman içinde birbirinden uzaklaşmış olabilir. Bu durumda yalnız belgeden veya yalnız kaynaktan hareket etmek eksik kanıt üretir.
Pratik bir değişiklik zinciri şu biçimde kurulabilir:
gözlenen davranış
|
v
korunacak değişmez
|
v
değişiklik sınırı
|
v
doğrulama kanıtı
|
v
yeni kalıcı kuralHer değişiklik için üç küme ayrılmalıdır: aynen korunacak davranış, bilinçli olarak değiştirilecek davranış ve henüz belirsiz davranış. Belirsiz küme kod yazılmadan önce küçültülmelidir. Aksi halde geliştirici farkında olmadan mevcut sözleşmeyi yeniden tanımlar.
Değişiklik sınırı dosya listesi değildir. Bir veri yazma yolu, aynı entity'yi okuyan başka ekranları; bir istemci yaşam döngüsü değişikliği, otomatik yenileme ve klavye odağını; bir concurrency sınırı ise gecikme ve hata davranışını etkileyebilir. Bu nedenle etki analizi çağrı zinciri, veri sahipliği ve kullanıcı görevi üzerinden yapılmalıdır.
Kanıt da riskle orantılı olmalıdır. Salt görsel ve yerel bir düzenlemede dar smoke doğrulaması yeterli olabilir. Veri bütünlüğü, yetkilendirme veya eşzamanlılık değişikliğinde ise derleme, sözleşme testi, negatif senaryo ve uçtan uca akış birlikte gerekir. Yazılım Test Mühendisliği bu kanıt katmanlarını ayrıntılandırır.
Son adım, yalnız gerçekten kalıcı olan bilgiyi proje bağlamına taşımaktır. Her uygulama ayrıntısını kural haline getirmek bağlamı büyütür; buna karşılık tekrar ihlal edilmesi ciddi regresyon doğuracak bir değişmezin kaydedilmemesi aynı araştırmanın yeniden yapılmasına yol açar. Böylece dokümantasyon değişiklikten sonra yazılan özet değil, bir sonraki değişikliğin karar yüzeyini daraltan mühendislik aracı olur.
Yazılım geliştirme yaşam döngüsü
Yazılım geliştirme yaşam döngüsü (Software Development Life Cycle — SDLC), gereksinim ve planlamadan tasarım, gerçekleştirim, doğrulama, dağıtım, işletim ve bakıma uzanan faaliyetleri ortak bir yaşam döngüsü içinde ele alır. Şelale, artımlı, iteratif, çevik veya DevOps odaklı süreçler bu faaliyetleri farklı sırada, geri besleme yoğunluğunda ve teslim ritminde düzenleyebilir. SDLC tek bir süreç modeliyle eş anlamlı değildir; temel amaç değişikliğin ihtiyaçtan çalışan ve sürdürülebilir sisteme kontrollü biçimde taşınmasıdır.
Gereksinimden Dağıtıma İzlenebilirlik
Yazılım mühendisliğinde süreç modellerinden bağımsız kalıcı sorun, bir değişikliğin neden yapıldığını ve hangi teknik sonucu doğurduğunu izleyebilmektir. Gereksinim, tasarım kararı, kod değişikliği, test kanıtı ve dağıtım kaydı arasında izlenebilir bağ kurulması özellikle kritik sistemlerde hata analizi ve kontrollü değişiklik için değerlidir.
Bu bağın her projede ağır bir belge zinciri olması gerekmez. Issue/ticket kimliği, karar kaydı (ADR), commit, test sonucu ve release kaydı gibi mevcut mühendislik artefact'ları yeterli disiplinde ilişkilendirilebilir.
Tasarım kalıplarının doğru yeri
Factory, Strategy, Observer, Adapter, Facade ve Singleton gibi kalıplar tekrar eden tasarım problemlerine isim verir. Kalıp kullanmak başlı başına kalite göstergesi değildir. Problem bulunmadan kalıp eklemek sınıf sayısını, dolaylı çağrıları ve zihinsel yükü artırabilir.
Örneğin Strategy değişebilen algoritmayı bir kontrat arkasında seçilebilir hâle getirebilir; Adapter uyumsuz iki interface arasında çeviri yapabilir; Observer bir olayın birden fazla aboneye bildirilmesini modelleyebilir. Singleton ise global erişimi kolaylaştırsa da test izolasyonu ve gizli bağımlılık bakımından maliyet taşır. Kalıp, maliyet/fayda gerekçesiyle seçilmelidir.
Git ve sürüm kontrolü
Dağıtık sürüm kontrolünde commit yalnız dosya yedeği değildir; değişikliğin kimliği ve tarihçesidir. Küçük, anlamlı ve derlenebilir commit'ler kod inceleme ve geri alma maliyetini düşürür. Branch stratejisi takımın release modeliyle uyumlu olmalıdır; her proje için tek doğru branching modeli yoktur.
Merge conflict, iki kişinin “hatalı” çalıştığını değil aynı bölgenin farklı tarihçelerde değiştiğini gösterir. Çözüm, dosyayı derleyebilen bir hâle getirmekten fazlasıdır; iki tarafın iş anlamını korumalıdır.
Git ile Apache Subversion (SVN) aynı sürüm kontrol problemini farklı depo modelleriyle çözer. Git'te geliştiricinin yerel kopyası commit geçmişini taşıyan dağıtık bir repository iken SVN geleneksel olarak merkezi repository ve working-copy modeli kullanır. Bu ayrım; çevrimdışı commit, branch/merge iş akışı, erişim modeli ve büyük ikili dosya stratejilerini etkileyebilir. Araç seçimi “hangisi daha modern?” sorusundan çok mevcut depo boyutu, takım iş akışı, yetkilendirme ve entegrasyon gereksinimleriyle değerlendirilmelidir.
CI/CD ve otomasyon
Continuous Integration, değişikliklerin sık birleştirilmesi ve otomatik doğrulanması fikridir. Continuous Delivery yazılımın her zaman dağıtılabilir durumda tutulmasını; Continuous Deployment ise başarılı değişikliğin otomatik olarak üretime gönderilmesini ifade eder. Delivery ve deployment eş anlamlı değildir.
Pipeline'ın çok sayıda araç içermesi kalite garantisi değildir. Hızlı ve güvenilir feedback, deterministik build, gerekli testler, güvenlik kontrolleri ve kontrollü artefact üretimi daha önemlidir.
Monolit, modüler monolit ve mikroservis
Monolit “kötü mimari”, mikroservis “iyi mimari” değildir. Mikroservis bağımsız dağıtım ve ölçekleme sağlayabilir; karşılığında ağ hataları, dağıtık transaction, gözlemlenebilirlik, sürümleme ve operasyon yükü getirir. İyi sınırlandırılmış modüler monolit birçok sistemde daha düşük karmaşıklıkla doğru çözüm olabilir.
Servis sınırı teknoloji modasına göre değil domain sınırı, takım sahipliği, bağımsız değişim/ölçek ihtiyacı ve veri sahipliği üzerinden gerekçelendirilmelidir.
Değişiklik riskini sınırlama
Üretimde kendini kanıtlamış sistemde refactoring'in amacı “daha güzel kod” uğruna davranışı yeniden yazmak değildir. Önce mevcut davranış karakterize edilir, değişikliğin sınırı daraltılır, bağımlı sözleşmeler belirlenir ve geri dönüş yolu korunur. Kritik akışlarda küçük, gözlemlenebilir ve geri alınabilir değişiklikler büyük tek seferlik yeniden yazımlardan daha düşük operasyon riski taşır.
Mimari karar kaydı ve değişiklik riski
Mimari yalnız diyagram değildir; belirli bir bağlamda verilmiş kararlar ve bu kararların gerekçeleridir. Kararın neden alındığı kaybolduğunda ekip, aynı tartışmayı tekrar eder veya eski kısıtı bilmeden tersine çevirir. Kısa bir Architecture Decision Record bu hafızayı düşük maliyetle koruyabilir.
Yararlı bir karar kaydı; bağlamı, değerlendirilen seçenekleri, seçilen yolu, beklenen sonucu ve geri dönüş koşulunu içerir. Belgenin amacı geleceği tahmin etmek değil, karar anındaki kanıtı görünür kılmaktır.
Değişiklik riskinde dosya sayısından çok bağımlılık yönü önemlidir. Ortak bir çekirdek sözleşmedeki küçük değişiklik, yüzlerce tüketiciyi etkileyebilir; izole bir modüldeki büyük değişiklik ise sınırlı kalabilir. Bu nedenle code review ve test planı, değişen satır sayısından önce etki alanını değerlendirmelidir.
Mühendislik kararını izlenebilir tutmak
Bir gereksinimin değeri yalnız doğru cümleyle yazılmasında değil, hangi kullanıcı ihtiyacını karşıladığı ve hangi doğrulama kanıtına bağlandığında görülür. Gereksinim, mimari karar, kod değişikliği ve test sonucu arasındaki ilişki izlenebilir olduğunda değişiklik etkisi daha sağlıklı değerlendirilebilir.
Mimari karar kayıtlarında bağlam, değerlendirilen seçenekler, seçilen yaklaşım ve geri dönme koşulu bulunmalıdır. Bu kayıtlar “doğru mimariyi” ilan etmez; kararın hangi varsayımlarla verildiğini görünür kılar.
Kalite metriği de bağlama göre okunmalıdır. Code coverage, defect count veya lead time tek başına kaliteyi kanıtlamaz. Ölçütün hangi karar için kullanıldığı ve hangi yan etkileri teşvik edebileceği açık tutulmalıdır.
Öğrenen Sistemlerde Yazılım Mühendisliği
Yapay zekâ kullanan bir sistemde model, yazılım mimarisinin yalnız bir bileşenidir. Gereksinim, veri, model, çalışma zamanı, servis sınırı ve insan doğrulaması birlikte ele alınmadığında yüksek doğruluklu bir model güvenilir bir ürüne dönüşmez. Bu nedenle yazılım mühendisliği ile yapay zekâ arasındaki bağ model eğitiminden çok değişikliğin ve sorumluluğun yönetilmesinde ortaya çıkar.
Klasik yazılımda davranışın önemli bölümü kaynak kod ve yapılandırma ile belirlenir. Öğrenen sistemde davranışa veri ve model parametreleri de katılır:
çıktı = f(kod, yapılandırma, veri, model, çalışma zamanı)Bu genişleyen durum uzayı sürümlemeyi de değiştirir. Yalnız Git commit'i bilmek aynı sonucu yeniden üretmek için yeterli olmayabilir. Kullanılan veri kesiti, etiket sürümü, özellik üretim hattı, model artifact'i, model çalışma zamanı ve değerlendirme kümesi de izlenmelidir. “Aynı kod” farklı model veya veriyle farklı davranabilir.
Gereksinim tarafında “doğruluk yüksek olsun” yeterli değildir. Sistem düzeyi ölçütler ayrı yazılmalıdır: hangi veri dağılımında hangi performans, kabul edilebilir yanlış pozitif/negatif maliyeti, maksimum gecikme, bellek sınırı, model kullanılamadığında fallback davranışı ve insan onayının hangi durumda zorunlu olduğu açık olmalıdır. Bu ölçütler olmadan model metriği ile iş gereksinimi arasında izlenebilirlik kurulamaz.
Mimari sınır da önemlidir. Model çağrısını uygulamanın her yerine yaymak yerine açık bir sözleşme altında tutmak; girdi doğrulama, timeout, hata politikası ve model sürümünü tek sınırda yönetmeyi kolaylaştırır. Özellikle uzak veya ayrı süreçte çalışan model servislerinde ağ hatası, kapasite aşımı ve kısmi başarısızlık normal sistem durumlarıdır.
iş kuralı
↓
model sözleşmesi
↓
model / inference runtime
↓
ölçülmüş çıktı
↓
uygulama kararıBurada model çıktısı ile iş kararı aynı şey olmak zorunda değildir. Model olasılık veya skor üretirken uygulama, eşik, yetki ve bağlam kurallarına göre karar verebilir. Bu ayrım test edilebilirliği ve değişiklik yönetimini güçlendirir.
Veri hattı da yazılım yaşam döngüsünün parçasıdır. Eğitim ve üretim ön işleme kodlarının ayrışması training-serving skew oluşturabilir. Bir alanın boş değer politikası, ölçekleme biçimi veya kategori kodlaması iki tarafta farklıysa model doğru dosya yüklenmesine rağmen yanlış çalışır. Bu nedenle dönüşüm sözleşmesi kod kadar sürümlenmeli ve test edilmelidir.
Model yükseltmesi bağımsız bir release olayı olarak ele alınmalıdır. Yeni model aynı API'yi korusa bile hata dağılımı değişebilir. Önceki sürümle karşılaştırmalı değerlendirme, shadow/canary yaklaşımı veya kontrollü geçiş gerekebilir. Geri dönüş yalnız binary rollback değil, ilgili model ve veri sözleşmesine dönüş anlamına gelir.
Yapay zekâ destekli kod üretimi de yazılım mühendisliği sorumluluğunu değiştirmez. Üretilen kod gereksinimi, bağımlılığı, lisansı, güvenliği ve regresyon riskini bilen bir doğrulama sürecinden geçmelidir. “Model önerdi” izlenebilir bir mühendislik gerekçesi değildir.
Bu nedenle öğrenen sistemlerde yazılım mühendisliğinin temel ilkesi değişmez: davranışı oluşturan her girdiyi görünür kıl, sınırları açık tanımla, değişikliği izlenebilir yap ve sonucu gereksinime karşı doğrula. Model yeni bir bileşen türüdür; yaşam döngüsü disiplininin yerine geçmez.
Yapay Zekâ Mühendisliği: Olasılıksal Bileşeni Yazılım Sistemine Dönüştürmek
Yapay zekâ mühendisliği, geliştiricinin kod yazarken bir sohbet modelinden yardım almasıyla aynı şey değildir. Bir modelin üretim yazılımında güvenilir bileşen hâline getirilmesi ayrı bir yaşam döngüsü gerektirir.
Problem
|
v
Veri / Bağlam
|
v
Model + İstem + Araç
|
v
Eval
|
v
Serving
|
v
Gözlem
|
v
Geri besleme / RegressionModelin API çağrısının çalışması “özellik tamamlandı” anlamına gelmez.
Olasılıksal Bileşenlerin Testi
Klasik fonksiyonda:
input X -> output Ydeterministik beklenti yazılabilir.
LLM tabanlı bileşende ise kabul ölçütü çoğu zaman:
zorunlu alanlar
yasak iddialar
kaynak kullanımı
şema geçerliliği
kalite eşiğiüzerinden tanımlanmalıdır.
Eval set bir test artefaktıdır
Üretim sisteminde sabitlenmiş değerlendirme kümesi:
- normal örnekler,
- sınır durumları,
- geçmiş hatalar,
- adversarial örnekler,
- no-answer durumları
içermelidir.
feature change
|
v
unit/integration tests
+
AI eval suite
|
v
release gateLLM eval'ı manuel demo'nun yerine geçer; ancak klasik testlerin yerine geçmez.
Model, İstem, Veri ve Araç Sürümü Birlikte Yönetilmeli
Aynı kod, model veya istem değiştiğinde farklı davranabilir.
Bu nedenle konfigürasyon:
AI_RELEASE =
model
+ tokenizer
+ prompt
+ embedding
+ retrieval config
+ tool schema
+ eval datasetolarak düşünülebilir.
İstem metnini uygulama içinde görünmez sabit olarak değiştirmek, kod değişikliği kadar önemli davranış değişimi oluşturabilir.
Provenance
Bir üretim cevabının hangi:
- model,
- istem,
- retrieval sürümü,
- araç çıktısı
ile üretildiği gerektiğinde yeniden bulunabilmelidir.
Bu iz, hata analizi ve geri dönüş için önemlidir.
Deterministik Olmayan Test Sonuçları
Sampling açıkken aynı giriş farklı çıktı üretebilir. Bu durumda test:
exact string equalityyerine yapısal invariants ve dağılımsal ölçülere dayanabilir.
Örneğin:
JSON valid mi?
zorunlu kaynak var mı?
yasak alan üretildi mi?
100 örnekte başarı oranı nedir?gibi.
Ancak mümkün olan yerde deterministik ayar ve sabit seed, regresyon analizini kolaylaştırır.
Canary, Shadow ve Aşamalı Dağıtım
Yeni model sürümü bütün trafiğe bir anda verilmemelidir.
Shadow: Yeni model gerçek girdileri görür ancak kullanıcı cevabını etkilemez.
Canary: Trafiğin küçük bir yüzdesi yeni sürüme gider.
production traffic
|
+--> stable model
|
+--> 5% canaryKarşılaştırılabilecek ölçüler:
- kalite,
- p95/p99,
- hata oranı,
- token / compute maliyeti,
- no-answer oranı,
- güvenlik regresyonları.
Rollback Yalnız Model Dosyasını Geri Almak Değildir
Davranış değişikliği istem, gömme veya erişim ayarından kaynaklanabilir.
Geri alma paketi:
model
prompt
retriever
embedding
tool schema
policyuyumlu sürümlere dönmelidir.
AI Engineering ile AI-Destekli Yazılım Geliştirme
İki kavram ayrılmalıdır.
AI-destekli yazılım geliştirme: geliştirici kod, test, dokümantasyon veya analiz üretirken yapay zekâ aracından yararlanır.
AI engineering: yapay zekâ modelini veri, eval, serving, güvenlik, gözlem ve yaşam döngüsüyle birlikte ürün bileşeni olarak mühendislik eder.
AI ile kod yazmak
!=
AI sistemi mühendisliğiNiyet Odaklı Programlama geliştirici–ajan etkileşimindeki spesifikasyon ve doğrulama sınırını; Büyük Dil Modelleri model katmanını; RAG bilgi erişim katmanını tamamlayıcı biçimde ele alır.
Yapay Zekâ Teknik Borcu
Makine öğrenmesi sistemlerindeki gizli teknik borç düşüncesi üretken yapay zekâda daha da genişler.
Borç kaynakları:
model sağlayıcısına bağımlılık
istem birikimi
değerlendirilmemiş veri değişimi
retrieval index drift
araç şeması uyumsuzluğu
gözlenmeyen kalite regresyonuBu nedenle “modeli değiştirmek bir satır config” gibi görünse bile gerçek sistem değişikliği geniş çaplı olabilir.
Yazılım mühendisliği açısından doğru ilke değişmez: bağımlılıklar, sınırlar, testler ve geri dönüş yolu açık değilse hız, sürdürülebilirlik pahasına satın alınmış olabilir.
Kaynakça
- Apache Software Foundation. Subversion Documentation. https://subversion.apache.org/docs/
- D. Sculley et al. “Hidden Technical Debt in Machine Learning Systems.” Advances in Neural Information Processing Systems, 28, 2015.
- Git Project. Git Documentation. https://git-scm.com/docs
- Ian Sommerville. Software Engineering. Addison-Wesley, 2010.
- IEEE Computer Society. Guide to the Software Engineering Body of Knowledge, Version 3.0. IEEE Computer Society, 2014.
- ISO/IEC. ISO/IEC 25010:2011 Systems and software quality models. International Organization for Standardization, 2011.
- ISO/IEC/IEEE. ISO/IEC/IEEE 29148:2011 Requirements engineering. ISO / IEC / IEEE, 2011.
- Michael T. Nygard. Release It!: Design and Deploy Production-Ready Software. 2nd ed. Pragmatic Bookshelf, 2018.
- Nancy G. Leveson. Engineering a Safer World: Systems Thinking Applied to Safety. MIT Press, 2011.
- National Institute of Standards and Technology. Artificial Intelligence Risk Management Framework: Generative Artificial Intelligence Profile (NIST AI 600-1). 2024. DOI: https://doi.org/10.6028/NIST.AI.600-1