- Şəlalə və çevik modelləri müqayisə etmək, Scrum rollarını və tədbirlərini izah etmək
- Git-də budaqlarla işləmək və dəyişikliyi təhlükəsiz ləğv etmək
- Test səviyyələrini seçmək və tsiklomatik mürəkkəbliyi hesablamaq
- Kodda SOLID prinsiplərinin pozulmasını tanımaq
Tək başına 200 sətirlik skript yazmaq proqramlaşdırmadır; 50 nəfərlik komandanın illərlə milyonlarla sətir kodu inkişaf etdirməsi, sınaması və heç nəyi sındırmadan hər həftə yeniləməsi isə proqram təminatı mühəndisliyidir. Burada əsas çətinlik alqoritm deyil, mürəkkəblik, dəyişən tələblər və insanlar arasında ünsiyyətdir. Bu dərsdə peşəkar komandaların bu problemləri necə idarə etdiyini öyrənəcəyik.
Həyat dövrü: şəlalədən çevik üsullara
- 1Tələblər
Sistem nə etməlidir (funksional) və necə yaxşı etməlidir (sürət, təhlükəsizlik — qeyri-funksional)?
- 2Layihələndirmə
Arxitektura, modullar, verilənlər bazası, interfeyslər.
- 3Reallaşdırma
Kodun yazılması, kod icmalı, versiyalara nəzarət.
- 4Testləşdirmə
Vahid, inteqrasiya, sistem və qəbul testləri.
- 5Yerləşdirmə və dəstək
Buraxılış, monitorinq, səhvlərin düzəldilməsi və yeni tələblər — sistemin ömrünün ən uzun hissəsi.
| Meyar | Şəlalə (waterfall) | Çevik (agile) |
|---|---|---|
| mərhələlər | ardıcıl, bir dəfə | qısa iterasiyalarda təkrarlanır |
| tələblərin dəyişməsi | bahalı | gözlənilir və qəbul olunur |
| müştəri işləyən proqramı görür | sonda | hər 1–4 həftədən bir |
| uyğun olduğu yer | sabit tələblər, ciddi tənzimləmə (tibb, aviasiya) | qeyri-müəyyən bazar, veb və mobil məhsullar |
2001-ci ildə qəbul edilmiş Çevik manifest işləyən proqramı, müştəri ilə əməkdaşlığı və dəyişikliyə hazır olmağı ön plana çəkir. Ən populyar çevik çərçivə Scrum-dır. Onun üç rolu var: Product Owner (məhsul sahibi — Product Backlog-u və prioritetləri idarə edir), Scrum Master (prosesə kömək edir, maneələri aradan qaldırır) və Developers (işi görən komanda). İş sprintlərlə — bir aya qədər sabit müddətli dövrlərlə aparılır: Sprint Planning, hər gün 15 dəqiqəlik Daily Scrum, sonda Sprint Review (nəticənin nümayişi) və Retrospective (prosesin təkmilləşdirilməsi).
Product Backlog-da 150 hekayə xalı (story point) qalıb. Son üç sprintdə komanda 16, 20 və 18 xal tamamlayıb. Sprint 2 həftədir. Buraxılışa təxminən nə qədər qalıb?
Həllini göstərHəllini gizlət
Sprintlərin sayı: ⌈150 / 18⌉ = ⌈8,33⌉ = 9 sprint.
Vaxt: 9 · 2 = 18 həftə (təxminən 4 ay).
Bu, vəd deyil, proqnozdur: hər sprintdən sonra yenilənir. Sürəti komandalar arasında müqayisə etmək olmaz — xallar hər komandanın öz şkalasıdır.
- Ckomandada cüt-cüt ünsiyyət kanallarının sayı
- nkomanda üzvlərinin sayı
5 nəfər → 10 kanal, 10 nəfər → 45 kanal. Bu, Bruks qanununun izahıdır: gecikən layihəyə yeni insanlar əlavə etmək onu çox vaxt daha da gecikdirir. Scrum komandaları ona görə kiçik saxlanılır (adətən 10 nəfərə qədər).
Git ilə versiyalara nəzarət
Git paylanmış versiyalara nəzarət sistemidir: hər tərtibatçının kompüterində bütün tarixçə ilə tam repozitoriya var. Commit — layihənin «fotoşəkli»dir (dəyişikliklər, müəllif, vaxt, izah); commitlər zəncir əmələ gətirir və hər biri heş ilə adlanır. Budaq (branch) — commitə istinad edən hərəkətli göstəricidir: yeni funksiyanı ayrıca budaqda edib, hazır olanda pull request vasitəsilə yoxlamaya göndərir və əsas budağa birləşdirirsən (merge).
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 commitgit revert səhv commiti ləğv edən yeni commit yaradır — tarixçə dəyişmir, ona görə ortaq budaqlar üçün təhlükəsizdir.Testləşdirmə
| Səviyyə | Nəyi yoxlayır | Sürət və say |
|---|---|---|
| Vahid (unit) | bir funksiya və ya sinif, təcrid olunmuş | millisaniyələr, minlərlə |
| İnteqrasiya | modulların birgə işi (kod + verilənlər bazası, API) | saniyələr, yüzlərlə |
| Sistem (end-to-end) | bütün sistem istifadəçi kimi | dəqiqələr, onlarla |
| Qəbul | müştərinin tələblərinə uyğunluq | buraxılışdan əvvəl |
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))▸ Gözlənilən nəticə
is_leap: all passed buggy_is_leap: FAILED for [1900]
pytest və ya unittest ilə avtomatlaşdırılır və hər commitdə CI serverində işə düşür.- MMakkeybin tsiklomatik mürəkkəbliyi: müstəqil yolların sayı
- E, Nidarəetmə axını qrafının tilləri və düyünləri
- Pəlaqəli komponentlərin sayı (bir funksiya üçün 1)
M — bütün budaqları əhatə etmək üçün lazım olan testlərin minimal sayının yaxşı təxminidir. M > 10 olan funksiyanı adətən kiçik hissələrə bölürlər.
is_leap funksiyası A and (B or C) qaytarır: A — «4-ə bölünür», B — «100-ə bölünmür», C — «400-ə bölünür». Onun tsiklomatik mürəkkəbliyi nədir və testlərimizdə nə üçün 4 hal var?
Həllini göstərHəllini gizlət
and, or) bir qərar nöqtəsidir: 2 qərar → M = 2 + 1 = 3.3 baza yolu: A yalan → 2023; A doğru, B doğru → 2024; A doğru, B yalan → nəticə C-nin özüdür.
Üçüncü yol C-ni qaytardığı üçün onun hər iki qiymətini yoxlayırıq: 1900 (C yalan) və 2000 (C doğru).
Deməli, M = 3 yolların əhatəsi üçün minimumdur, 4 test isə tam şərt əhatəsi verir — məhz bizim
cases lüğətimiz.SOLID və kod icmalı
| Prinsip | Mənası |
|---|---|
| S — tək məsuliyyət | sinfin dəyişməsi üçün yalnız bir səbəb olmalıdır |
| O — açıq/qapalı | genişlənməyə açıq, dəyişikliyə qapalı: yeni davranışı yeni kodla əlavə et |
| L — Liskov əvəzetməsi | alt sinfin obyekti baza sinfin yerində problemsiz işləməlidir |
| I — interfeysin ayrılması | böyük interfeys əvəzinə bir neçə kiçik, konkret interfeys |
| D — asılılığın inversiyası | konkret sinifdən yox, abstraksiyadan asılı ol |
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))▸ Gözlənilən nəticə
NoDiscount 50 Percent 40.0 StudentCard 45
checkout konkret endirimlərdən deyil, Discount abstraksiyasından asılıdır (D). Yeni endirim növü əlavə etmək üçün checkout-u dəyişmək lazım deyil — yeni sinif yazmaq kifayətdir (O). Hər alt sinif Discount gözlənilən yerdə işləyir (L).Kod icmalı (code review) — dəyişikliyin əsas budağa düşməzdən əvvəl başqa tərtibatçı tərəfindən yoxlanmasıdır. Rəyçi düzgünlüyə, testlərə, oxunaqlılığa, təhlükəsizliyə və dizayna baxır; üslubu isə avtomatik alətlər (linter, formatlayıcı) yoxlamalıdır. İcmal səhvləri tutmaqla yanaşı, biliyi komandaya yayır: sistemin hər hissəsini ən azı iki nəfər tanıyır. Kiçik pull request-lər (bir neçə yüz sətirdən az) daha diqqətlə oxunur.
Əsas fikirlər
- Həyat dövrü: tələblər → layihələndirmə → reallaşdırma → test → yerləşdirmə və dəstək; çevik üsullar onu qısa iterasiyalarda təkrarlayır.
- Scrum: Product Owner, Scrum Master, Developers; bir aya qədər sprintlər və dörd tədbir.
- Git: commit — fotoşəkil, budaq — göstərici; ortaq budaqda tarixçəni yenidən yazma,
revertişlət. - Test piramidası: çoxlu vahid, az sistem testi; tsiklomatik mürəkkəblik M = qərarlar + 1.
- SOLID dəyişikliyə davamlı dizayn verir; kod icmalı səhvləri tutur və biliyi yayır; komanda kanalları n(n − 1)/2 kimi artır.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.