İçeriğe geç
Educora
Üniversite25 dk58 / 59

Yazılım mühendisliği

Yazılım geliştirme yaşam döngüsünü, çevik yöntemleri ve Scrum'ı, Git ile sürüm denetimini, test düzeylerini, SOLID ilkelerini ve kod incelemesini öğren.

Kendini test et
Bu derste öğreneceklerin
  • Şelale ve çevik modelleri karşılaştırmak, Scrum rollerini ve etkinliklerini açıklamak
  • Git'te dallarla çalışmak ve bir değişikliği güvenle geri almak
  • Test düzeylerini seçmek ve döngüsel karmaşıklığı hesaplamak
  • Kodda SOLID ilkelerinin ihlallerini fark etmek

Tek başına 200 satırlık bir betik yazmak programlamadır; 50 kişilik bir ekibin yıllarca milyonlarca satır kod geliştirmesi, test etmesi ve hiçbir şeyi bozmadan her hafta güncelleme yayımlaması ise yazılım mühendisliğidir. Buradaki asıl zorluk algoritmalar değil; karmaşıklık, değişen gereksinimler ve insanlar arası iletişimdir. Bu derste profesyonel ekiplerin bu sorunları nasıl yönettiğini öğreneceğiz.

Yaşam döngüsü: şelaleden çevik yöntemlere

  1. 1
    Gereksinimler

    Sistem ne yapmalı (işlevsel) ve ne kadar iyi yapmalı (hız, güvenlik — işlevsel olmayan)?

  2. 2
    Tasarım

    Mimari, modüller, veri tabanı, arayüzler.

  3. 3
    Gerçekleştirme

    Kod yazma, kod incelemesi, sürüm denetimi.

  4. 4
    Test

    Birim, entegrasyon, sistem ve kabul testleri.

  5. 5
    Dağıtım ve bakım

    Yayın, izleme, hata düzeltme ve yeni gereksinimler; bir sistemin ömrünün en uzun kısmı.

ÖlçütŞelale (waterfall)Çevik (agile)
aşamalarsıralı, bir kezkısa yinelemelerde tekrarlanır
gereksinim değişikliğipahalıbeklenir ve kabul edilir
müşteri çalışan yazılımı görürsonundaher 1–4 haftada bir
uygun olduğu yersabit gereksinimler, sıkı düzenleme (tıp, havacılık)belirsiz pazar, web ve mobil ürünler

2001 tarihli Çevik Manifesto, çalışan yazılımı, müşteriyle iş birliğini ve değişime hazır olmayı öne çıkarır. En popüler çevik çerçeve Scrum'dır. Üç rolü vardır: Product Owner (ürün sahibi; Product Backlog'u ve öncelikleri yönetir), Scrum Master (sürece yardım eder, engelleri kaldırır) ve Developers (işi yapan ekip). İş sprintlerle, yani en fazla bir ay süren sabit dönemlerle yürür: Sprint Planning, her gün 15 dakikalık Daily Scrum, sonunda Sprint Review (sonucun gösterilmesi) ve Retrospective (sürecin iyileştirilmesi).

Örnek 1: hıza göre tahmin

Product Backlog'da 150 hikâye puanı kaldı. Son üç sprintte ekip 16, 20 ve 18 puan tamamladı. Bir sprint 2 hafta sürüyor. Sürüme yaklaşık ne kadar kaldı?

Çözümü göster
Ortalama hız (velocity): (16 + 20 + 18) / 3 = 54 / 3 = sprint başına 18 puan.
Sprint sayısı: ⌈150 / 18⌉ = ⌈8,33⌉ = 9 sprint.
Süre: 9 · 2 = 18 hafta (yaklaşık 4 ay).
Bu bir söz değil, tahmindir: her sprintten sonra güncellenir. Hız ekipler arasında karşılaştırılmamalıdır; puanlar her ekibin kendi ölçeğidir.
C = n(n − 1) / 2C = n(n − 1) / 2
burada:
  • Cekipteki ikili iletişim kanalı sayısı
  • nekip üyesi sayısı

5 kişi → 10 kanal, 10 kişi → 45 kanal. Brooks yasası bununla açıklanır: geciken bir projeye insan eklemek onu çoğu zaman daha da geciktirir. Bu yüzden Scrum ekipleri küçük tutulur (genellikle 10 kişiye kadar).

Git ile sürüm denetimi

Git dağıtık bir sürüm denetim sistemidir: her geliştiricinin bilgisayarında tüm geçmişi içeren eksiksiz bir depo bulunur. Commit, projenin bir “anlık görüntüsüdür” (değişiklikler, yazar, zaman, açıklama); commit'ler bir zincir oluşturur ve her biri bir hash ile adlandırılır. Dal (branch), bir commit'e işaret eden hareketli bir işaretçidir: yeni bir özelliği ayrı bir dalda yapar, hazır olunca pull request ile incelemeye gönderir ve ana dala birleştirirsin (merge).

Terminal
git switch -c feature/login          # create and switch to a new branch
git add login.py
git commit -m 'Validate the login form'
git push -u origin feature/login     # then open a pull request

git switch main
git pull                             # get the reviewed and merged work
git revert 3f2a9c1                   # safely undo a bad pushed commit
Tipik bir iş akışı. git revert, hatalı bir commit'i geri alan yeni bir commit oluşturur; geçmiş yeniden yazılmaz, bu yüzden ortak dallarda güvenlidir.

Test

DüzeyNeyi denetlerHız ve sayı
Birim (unit)tek bir fonksiyon ya da sınıf, yalıtılmışmilisaniyeler, binlerce
Entegrasyonmodüllerin birlikte çalışması (kod + veri tabanı, API)saniyeler, yüzlerce
Sistem (uçtan uca)tüm sistem, bir kullanıcı gibidakikalar, onlarca
Kabulmüşteri gereksinimlerine uygunlukyayından önce
“Test piramidi”: altta çok sayıda hızlı birim testi, üstte az sayıda yavaş sistem testi.
Python
def is_leap(year):
    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)

def buggy_is_leap(year):
    return year % 4 == 0

cases = {2024: True, 2023: False, 1900: False, 2000: True}

def run_tests(func):
    failed = [y for y, expected in cases.items() if func(y) != expected]
    return 'all passed' if not failed else 'FAILED for ' + str(failed)

print('is_leap:', run_tests(is_leap))
print('buggy_is_leap:', run_tests(buggy_is_leap))
▸ Beklenen çıktı
is_leap: all passed
buggy_is_leap: FAILED for [1900]
İyi birim testleri sınır durumlarını da denetler: 1900, 4'e bölünür ama 100'e bölünüp 400'e bölünmediği için artık yıl değildir. Saf sürüm sıradan durumlarda doğru görünür ve hatayı yalnızca bu test yakalar. Gerçek projelerde aynı iş pytest ya da unittest ile otomatikleştirilir ve her commit'te bir CI sunucusunda çalışır.
M = E − N + 2P (= karar sayısı + 1)
burada:
  • MMcCabe'in döngüsel karmaşıklığı: bağımsız yol sayısı
  • E, Ndenetim akışı grafının kenarları ve düğümleri
  • Pbağlı bileşen sayısı (tek fonksiyon için 1)

M, tüm dalları kapsamak için gereken en az test sayısının iyi bir tahminidir. M > 10 olan fonksiyonlar genellikle daha küçük parçalara bölünür.

Örnek 2: döngüsel karmaşıklık

is_leap, A and (B or C) döndürür; burada A = “4'e bölünür”, B = “100'e bölünmez”, C = “400'e bölünür”. Döngüsel karmaşıklığı nedir ve testlerimizde neden 4 durum var?

Çözümü göster
Kısa devreli her mantıksal işleç (and, or) bir karar noktasıdır: 2 karar → M = 2 + 1 = 3.
3 temel yol: A yanlış → 2023; A doğru, B doğru → 2024; A doğru, B yanlış → sonuç C'nin kendisidir.
Üçüncü yol C'yi döndürdüğü için iki değerini de sınarız: 1900 (C yanlış) ve 2000 (C doğru).
Yani M = 3 yol kapsamı için en azdır; 4 test ise tam koşul kapsamı sağlar; bu tam olarak cases sözlüğümüzdür.

SOLID ve kod incelemesi

İlkeAnlamı
S — tek sorumlulukbir sınıfın değişmek için tek bir nedeni olmalı
O — açık/kapalıgenişlemeye açık, değişikliğe kapalı: yeni davranışı yeni kodla ekle
L — Liskov yerine geçmealt sınıf nesnesi, taban sınıfın beklendiği her yerde çalışmalı
I — arayüz ayrımıtek büyük arayüz yerine birkaç küçük, özel arayüz
D — bağımlılığın tersine çevrilmesisomut sınıflara değil, soyutlamalara bağlı ol
Python
from abc import ABC, abstractmethod

class Discount(ABC):
    @abstractmethod
    def apply(self, price): ...

class NoDiscount(Discount):
    def apply(self, price):
        return price

class Percent(Discount):
    def __init__(self, p):
        self.p = p
    def apply(self, price):
        return round(price * (1 - self.p / 100), 2)

class StudentCard(Discount):
    def apply(self, price):
        return max(price - 5, 0)

def checkout(price, discount: Discount):
    return discount.apply(price)

for d in [NoDiscount(), Percent(20), StudentCard()]:
    print(type(d).__name__, checkout(50, d))
▸ Beklenen çıktı
NoDiscount 50
Percent 40.0
StudentCard 45
checkout somut indirimlere değil, Discount soyutlamasına bağlıdır (D). Yeni bir indirim türü eklemek için checkout'u değiştirmek gerekmez; yeni bir sınıf yeter (O). Her alt sınıf, Discount beklenen her yerde çalışır (L).

Kod incelemesi (code review), bir değişikliğin ana dala girmeden önce başka bir geliştirici tarafından denetlenmesidir. İnceleyen kişi doğruluğa, testlere, okunabilirliğe, güvenliğe ve tasarıma bakar; biçim ise otomatik araçlarla (linter, biçimlendirici) denetlenmelidir. İnceleme hataları yakalamanın yanı sıra bilgiyi ekibe yayar: sistemin her parçasını en az iki kişi bilir. Küçük pull request'ler (birkaç yüz satırdan az) daha dikkatli okunur.

Önemli noktalar

  • Yaşam döngüsü: gereksinimler → tasarım → gerçekleştirme → test → dağıtım ve bakım; çevik yöntemler onu kısa yinelemelerle tekrarlar.
  • Scrum: Product Owner, Scrum Master, Developers; bir aya kadar sprintler ve dört etkinlik.
  • Git: commit bir anlık görüntü, dal bir işaretçidir; ortak dalda geçmişi yeniden yazma, revert kullan.
  • Test piramidi: çok sayıda birim, az sayıda sistem testi; döngüsel karmaşıklık M = kararlar + 1.
  • SOLID değişime dayanıklı tasarım sağlar; kod incelemesi hataları yakalar ve bilgiyi yayar; ekip kanalları n(n − 1)/2 büyür.

Kendini test et

10 soru. Her doğru cevap XP kazandırır.

1 / 10
8 kişilik bir ekipte kaç ikili iletişim kanalı vardır?