Poglavlje 8: Arhitektura temeljena na komponentama

Priča za početak. Na istoj konferenciji u Garmischu 1968. godine, o kojoj smo čitali u poglavlju 1, programer Douglas McIlroy iz Bell Labsa održao je izlaganje pod naslovom „Masovno proizvedene softverske komponente”. Pitao je zašto softverska industrija nema ono što ima svaka druga industrija: katalog standardnih dijelova. Proizvođač automobila ne pravi sam svaki vijak; kupi ga, po standardu, iz kataloga. McIlroy je zamišljao da će programeri birati gotove rutine iz porodica, prema preciznosti, robusnosti i brzini, i od njih sklapati programe. Skoro pola vijeka kasnije, 22. marta 2016, ta vizija se ostvarila na način koji niko nije očekivao. Programer Azer Koçulu povukao je sve svoje pakete iz registra npm, u kojem programeri JavaScripta dijele komponente. Među njima je bio i left-pad, funkcija od jedanaest redova koja dopunjava tekst razmacima s lijeve strane. Ispostavilo se da od nje, preko lanca drugih paketa, zavise popularni alati, i gradnja hiljada projekata širom svijeta odjednom je počela padati. Registar je paket vratio za nekoliko sati i promijenio pravila povlačenja. Katalog dijelova je stvaran, ali je donio i novo pitanje: koliko zaista znamo o dijelovima od kojih je naš proizvod sastavljen?

U poglavlju 7 izabrali smo arhitekturu DeliveryApp 2.0: modularni monolit s jasnim granicama između narudžbi, dostave, plaćanja i obavještenja. Ovo poglavlje uzima te dijelove ozbiljno i pravi od njih komponente: dijelove s ugovorom, verzijom i vlastitim životom. Prvi dio objašnjava ideju programskog inženjerstva temeljenog na komponentama, odlike komponente, interfejse, koheziju i povezanost. Drugi dio daje principe i smjernice za dizajn komponenata, pokazuje kako se komponenta pravi kao paket sa semantičkom verzijom, i govori o rizicima ponovne upotrebe, od Ariane 5 do left-pada.

Literatura. Osnovna literatura predmeta:

  1. I. Sommerville: Software Engineering, 10th ed., Pearson, 2016 (poglavlje 16).
  2. C. Szyperski: Component Software, 2nd ed., Addison-Wesley, 2002.
  3. R. C. Martin: Clean Architecture, Prentice Hall, 2017 (dio o principima komponenata).

Riječi ovog poglavlja.

  • Komponenta – samostalna jedinica softvera s jasnim interfejsom, koja se isporučuje nezavisno i sklapa s drugim komponentama.
  • CBSE (component-based software engineering) – razvoj softvera sklapanjem gotovih i vlastitih komponenata.
  • Ponuđeni interfejs – operacije koje komponenta nudi drugima.
  • Zahtijevani interfejs – operacije koje komponenta traži od okoline da bi radila.
  • Ugovor – precizan opis interfejsa: ulazi, izlazi, greške, uslovi.
  • Kohezija – koliko dijelovi unutar komponente pripadaju zajedno.
  • Povezanost (coupling) – koliko komponenta zavisi od drugih.
  • Paket – komponenta spremna za instalaciju iz registra (pip/PyPI, NuGet, npm).
  • Semantičko verzioniranje – verzija oblika glavna.sporedna.zakrpa s tačno određenim značenjem.
  • Tranzitivna zavisnost – zavisnost moje zavisnosti.
  • SBOM (software bill of materials) – spisak svih komponenata od kojih je proizvod sastavljen.

Ciljevi poglavlja. Nakon poglavlja možete: objasniti ideju CBSE i njene koristi; navesti odlike komponente po Szyperskom; razlikovati ponuđeni i zahtijevani interfejs i nacrtati UML dijagram komponenti; objasniti koheziju i povezanost; objasniti principe REP, CCP, CRP, ADP, SDP i SAP prostim riječima; primijeniti smjernice za dizajn komponente; napraviti Python paket sa semantičkom verzijom i reći kad se mijenja koji broj; objasniti rizike ponovne upotrebe i šta je SBOM.

Plan poglavlja – Predavanje 8: dva časa teorije i jedan čas dopunske prakse

Čas Sadržaj Na času
Teorija 1 8.1–8.4 CBSE, odlike, interfejsi, kohezija i povezanost Lego kocka i utičnica; dijagram komponenti DeliveryApp
Teorija 2 8.5–8.8 Principi, smjernice, provođenje, rizici Koja je sljedeća verzija: 1.1.0 ili 2.0.0?
Dopunska praksa Paket deliveryapp-dostava sa semantičkom verzijom pip install . i tri testa

Dio 1 – Šta je komponenta

8.1 Ideja programskog inženjerstva temeljenog na komponentama

Lego kocke su najbolja slika komponente. Svaka kocka ima standardne čepiće (interfejs), pa se svaka može spojiti sa svakom, bez obzira na to ko ju je napravio i kada. Iz istih kocki prave se kuća, auto i svemirski brod. Niko ne pravi kocke iznova za svaku igračku.

Programsko inženjerstvo temeljeno na komponentama (CBSE) prenosi tu ideju u softver: proizvod se sklapa od komponenata, a ne piše od nule. Dio komponenata tim pravi sam (komponenta za obračun dostave), a dio uzima gotove (biblioteka za heširanje lozinki, okvir za web, klijent za sistem plaćanja).

Koristi:

  1. Brži razvoj – ne piše se ono što već postoji i radi.
  2. Pouzdanost – komponenta koju koriste hiljade projekata već je „istestirana” u praksi.
  3. Zamjenjivost – komponenta s istim interfejsom može se zamijeniti boljom.
  4. Podjela rada – svaki tim odgovara za svoje komponente.

Danas je CBSE svakodnevica: tipična web aplikacija sadrži više stotina paketa iz registara, a vlastitog koda je često manje od tuđeg.

Ukratko.

  • CBSE sklapa proizvod od vlastitih i gotovih komponenata, kao igračku od Lego kocki.
  • Koristi su brzina, pouzdanost, zamjenjivost i podjela rada.
  • Tipičan proizvod danas sadrži više tuđeg nego vlastitog koda.

8.2 Odlike komponente

Clemens Szyperski je u knjizi Component Software dao definiciju koja se najčešće navodi: komponenta je jedinica sastavljanja s ugovorom definisanim interfejsima i samo eksplicitnim zavisnostima od okoline; može se isporučiti nezavisno i sklapati s drugim komponentama, i to od strane trećih lica.

Prevedeno na pet odlika:

Odlika Šta znači deliveryapp-dostava
standardizovana prati dogovoren model (npr. Python paket, .NET biblioteka) Python paket s pyproject.toml
nezavisna ne traži skrivene stvari od okoline; sve zavisnosti su zapisane nema zavisnosti osim Pythona
sastavljiva sav pristup ide kroz javni interfejs obracunaj(grad, km, iznos)
isporučiva može se instalirati i nadograditi posebno pip install deliveryapp-dostava==2.0.0
dokumentovana interfejs je opisan tako da ga koristi neko ko ne vidi kod opis u modulu i README

Komponenta nije isto što i klasa. Klasa je jedinica koda; komponenta je jedinica isporuke. Komponenta obično sadrži više klasa, od kojih je većina skrivena, a vani se vidi samo interfejs.

Ukratko.

  • Po Szyperskom, komponenta je jedinica sastavljanja s ugovorom i eksplicitnim zavisnostima, koja se isporučuje nezavisno.
  • Odlike: standardizovana, nezavisna, sastavljiva, isporučiva, dokumentovana.
  • Klasa je jedinica koda, a komponenta jedinica isporuke.

8.3 Interfejsi i ugovor

Komponenta ima dvije vrste interfejsa. Analogija je električni aparat:

  • Ponuđeni interfejs je ono što aparat nudi: fen nudi topao zrak, dugme i dva stepena brzine.
  • Zahtijevani interfejs je ono što aparat traži: utičnicu od 230 V.

Fen radi u bilo kojoj kući koja ima tu utičnicu; kući je svejedno koji fen je uključen. Tako i komponenta deliveryapp-narudzbe zahtijeva interfejse obracunaj(), naplati(), posalji() i udaljenost(), a ne zna i ne zanima je ko ih pruža.

flowchart LR
    N["«komponenta»<br/>deliveryapp-narudzbe"]
    D["«komponenta»<br/>deliveryapp-dostava 2.0.0"]
    iD(("obracunaj()"))
    D --- iD
    N -.->|"zahtijeva"| iD

Slika 8.1 – Komponente DeliveryApp 2.0: ponuđeni i zahtijevani interfejsi

Ugovor je precizan opis interfejsa. Za obracunaj(grad, km, iznos) ugovor kaže:

  • ulazi: oznaka grada (A, B, C), udaljenost u kilometrima, iznos artikala u centima;
  • izlaz: objekat Obracun s gradom, iznosom dostave u centima i kratkim opisom;
  • greške: nepoznat grad → KeyError; udaljenost izvan zone ili iznos ispod 5,00 € → ValueError;
  • garancije: od 30,00 € dostava je 0; rezultat ne zavisi od vremena ni od stanja baze.

Ugovor se ne mijenja „usput”. Ako se mora promijeniti, mijenja se glavna verzija (8.6).

Ukratko.

  • Ponuđeni interfejs je ono što komponenta nudi, zahtijevani ono što traži, kao aparat i utičnica.
  • UML dijagram komponenti crta komponente, interfejse (kružići) i zavisnosti (isprekidane strelice).
  • Ugovor opisuje ulaze, izlaze, greške i garancije.

8.4 Kohezija i povezanost

Dva pojma odlučuju da li je podjela na komponente dobra:

  • Kohezija – koliko dijelovi unutar komponente pripadaju zajedno. Visoka kohezija: komponenta radi jednu stvar (obračun dostave). Niska kohezija: komponenta razno u kojoj su obračun dostave, slanje SMS-a i izvoz u Excel.
  • Povezanost – koliko komponenta zavisi od drugih. Niska povezanost: dostava ne zna ništa o plaćanju. Visoka povezanost: promjena u plaćanju ruši dostavu.

Cilj je uvijek isti: visoka kohezija, niska povezanost. Analogija: dobro organizovana kuhinja ima ladicu za pribor i ladicu za začine (visoka kohezija), a da biste uzeli kašiku ne morate izvaditi začine (niska povezanost).

Slika 8.2 – Visoka kohezija i niska povezanost naspram suprotnog

Na času. Tim predlaže komponentu deliveryapp-alati u kojoj bi bili formatiranje cijene (24,50 €), provjera e-mail adrese, računanje udaljenosti i slanje push obavještenja. Šta nije u redu i kako biste je razdvojili?

Ukratko.

  • Kohezija je koliko dijelovi unutar komponente pripadaju zajedno; povezanost koliko komponenta zavisi od drugih.
  • Cilj: visoka kohezija, niska povezanost.
  • Komponenta „razno” ili „alati” je znak niske kohezije.

Provjeri se.

  1. Koja je razlika između klase i komponente? – Klasa je jedinica koda, a komponenta jedinica isporuke koja obično sadrži više klasa.
  2. Šta je zahtijevani interfejs? – Operacije koje komponenta traži od okoline da bi radila.
  3. Kakvu koheziju i povezanost želimo? – Visoku koheziju i nisku povezanost.

Dio 2 – Dizajn i provođenje

8.5 Principi dizajna temeljenog na komponentama

Robert C. Martin je opisao šest principa za komponente. Tri govore šta ide zajedno u komponentu, a tri kako komponente zavise jedna od druge.

Šta ide zajedno (kohezija):

Princip Prostim riječima U DeliveryApp
REP – ponovna upotreba = izdanje ono što se ponovo koristi mora imati verziju i izdanje deliveryapp-dostava ima verziju 2.0.0 i bilješke o izdanju
CCP – zajedničko zatvaranje u istu komponentu ide ono što se mijenja iz istog razloga i u isto vrijeme tarife i obračun dostave mijenjaju se zajedno, pa su zajedno
CRP – zajednička ponovna upotreba ne tjeraj korisnika da zavisi od onoga što ne koristi dostava ne nosi kod za SMS, pa ko koristi dostavu ne mora instalirati SMS

Kako zavise (povezanost):

Princip Prostim riječima U DeliveryApp
ADP – bez ciklusa zavisnosti ne smiju praviti krug narudžbe → dostava, ali dostava ne zavisi od narudžbi
SDP – zavisi od stabilnog zavisi od onoga što se rjeđe mijenja od tebe ekran zavisi od narudžbi, narudžbe od tarife
SAP – stabilno je apstraktno komponente od kojih mnogi zavise neka budu apstraktne (interfejsi) ServisMapa je interfejs, a konkretna firma je zamjenjiva

Zašto je ciklus opasan? Ako narudžbe zavise od dostave, a dostava od narudžbi, nijedna se ne može izgraditi, testirati ni isporučiti bez druge: dvije komponente su zapravo jedna, samo s dva imena. Ciklus se prekida tako što se zajednički dio izdvoji ili se uvede interfejs (inverzija zavisnosti).

Slika 8.3 – Zavisnosti bez ciklusa, prema stabilnim komponentama

Ukratko.

  • REP, CCP i CRP odlučuju šta ide u komponentu: ono što se izdaje, mijenja i koristi zajedno.
  • ADP, SDP i SAP odlučuju o zavisnostima: bez ciklusa, prema stabilnom, a stabilno neka bude apstraktno.
  • Ciklus pretvara dvije komponente u jednu i prekida se izdvajanjem ili interfejsom.

8.6 Smjernice za dizajn komponenata

Praktične smjernice koje tim DeliveryApp koristi:

  1. Mali, jasan interfejs. Što manje javnih funkcija, to manje obećanja koja se moraju čuvati. deliveryapp-dostava izvozi tri imena: Obracun, obracunaj, gradovi. Sve ostalo (npr. _Tarifa, _TARIFE) počinje donjom crtom i nije dio ugovora.
  2. Nepromjenjivi objekti na granici. Komponenta vraća objekat koji se ne može mijenjati (frozen=True), da pozivalac ne pokvari stanje komponente.
  3. Jasne greške. Svaka greška ugovora ima svoj tip i poruku.
  4. Bez skrivenih zavisnosti. Ništa iz globalnih varijabli, okruženja ili baze, osim ako to piše u ugovoru.
  5. Dokumentacija i primjer. README s primjerom poziva od tri reda.
  6. Testovi uz komponentu. Komponenta se isporučuje sa svojim testovima.
  7. Semantička verzija. Verzija glavna.sporedna.zakrpa ima tačno značenje:
Promjena Koji broj raste Primjer za deliveryapp-dostava
ispravka greške, ugovor isti zakrpa 1.1.0 → 1.1.1: ispravljeno zaokruživanje na 8,0 km
nova mogućnost, stari pozivi i dalje rade sporedna 1.0.0 → 1.1.0: dodane tarife po gradu, stari poziv dostava(km, iznos) radi za Grad A
promjena koja kvari stare pozive glavna 1.1.0 → 2.0.0: obracunaj() vraća Obracun umjesto broja; stari poziv uklonjen

Kad DeliveryApp kaže da zavisi od deliveryapp-dostava>=2.0,<3, zna da će dobiti sve ispravke i nove mogućnosti verzije 2, a da ga ništa neće pokvariti bez upozorenja. Pravila semantičkog verzioniranja zapisana su na stranici semver.org.

Česta zabluda. „Verzija je samo broj za marketing.” U svijetu komponenata verzija je obećanje. Ako komponenta u zakrpi promijeni ugovor, hiljade projekata koji su vjerovali obećanju mogu se pokvariti preko noći.

Ukratko.

  • Smjernice: mali interfejs, nepromjenjivi objekti na granici, jasne greške, bez skrivenih zavisnosti, dokumentacija, testovi.
  • Semantička verzija: zakrpa za ispravku, sporedna za kompatibilnu novost, glavna za promjenu koja kvari stare pozive.
  • Verzija je obećanje korisnicima komponente.

8.7 Provođenje dizajna komponenata

Kako tim DeliveryApp od dijela koda pravi komponentu, korak po korak:

  1. Prepoznati kandidata. Dio s visokom kohezijom koji se mijenja iz jednog razloga i koji bi mogao trebati i drugima: obračun dostave (trebaće ga i budući proizvod za dostavu iz apoteka).
  2. Definisati ugovor. Ponuđeni interfejs (obracunaj), zahtijevani (nijedan), greške, garancije.
  3. Izdvojiti kod. Premjestiti kod iza interfejsa, sakriti sve ostalo.
  4. Napisati testove komponente. Prije nego što je drugi počnu koristiti.
  5. Spakovati. Python: pyproject.toml s imenom i verzijom; C#: projekat biblioteke (.csproj) i NuGet paket.
  6. Objaviti. U javni registar (PyPI, NuGet, npm) ili u interni registar firme.
  7. Održavati. Bilješke o izdanju, semantičke verzije, ispravke sigurnosnih problema.

Paket deliveryapp-dostava (primjeri/paket/deliveryapp-dostava) ima ovu strukturu:

deliveryapp-dostava/
├── pyproject.toml
├── src/deliveryapp_dostava/__init__.py
└── tests/test_komponenta.py

pyproject.toml opisuje paket:

[project]
name = "deliveryapp-dostava"
version = "2.0.0"
description = "Obračun dostave po tarifi grada (komponenta proizvoda DeliveryApp 2.0)"
requires-python = ">=3.10"

A ponuđeni interfejs izgleda ovako:

@dataclass(frozen=True)
class Obracun:
    grad: str
    dostava: int      # centi
    opis: str


def obracunaj(grad: str, km: float, iznos: int) -> Obracun:
    t = _TARIFE.get(grad)
    if t is None:
        raise KeyError(f"nepoznat grad: {grad}")
    if km < 0 or km > t.max_km:
        raise ValueError("adresa je izvan zone dostave")
    if iznos < MIN_NARUDZBA:
        raise ValueError("iznos je manji od najmanje narudžbe")
    if iznos >= BESPLATNA_OD:
        return Obracun(grad, 0, "besplatna dostava od 30,00 €")
    dodatni = math.ceil(max(0, km - t.ukljuceno_km))
    return Obracun(grad, t.osnovna + t.po_km * dodatni, f"osnovna + {dodatni} km")

Nakon pip install . u čistom virtuelnom okruženju, poziv obracunaj("B", 4.2, 2150) vraća Obracun(grad='B', dostava=380, opis='osnovna + 3 km'), a tri testa komponente prolaze.

U C# isti posao radi projekat biblioteke: dotnet new classlib -n DeliveryApp.Dostava, verzija u .csproj (<Version>2.0.0</Version>), pakovanje sa dotnet pack i objava u NuGet registar. Javne su samo klase i metode označene sa public; ostalo je internal i ne vidi se izvan komponente.

Ukratko.

  • Provođenje: prepoznati kandidata, definisati ugovor, izdvojiti kod, testovi, spakovati, objaviti, održavati.
  • Python komponenta je paket s pyproject.toml; C# komponenta je biblioteka i NuGet paket.
  • Sve osim ponuđenog interfejsa je sakriveno (donja crta u Pythonu, internal u C#).

8.8 Ponovna upotreba i njeni rizici

Ponovna upotreba štedi vrijeme, ali komponenta koja je radila u jednom okruženju ne mora raditi u drugom, a svaka tuđa komponenta je i tuđi rizik.

Iz stvarnog svijeta. Raketa Ariane 5 eksplodirala je na prvom letu, 4. juna 1996, oko četrdeset sekundi nakon polijetanja. Softver za inercijalni navigacioni sistem preuzet je s rakete Ariane 4, gdje je godinama radio bez greške. Ariane 5 je, međutim, brža, pa je jedna vrijednost horizontalne brzine postala prevelika za pretvaranje iz 64-bitnog decimalnog broja u 16-bitni cijeli broj. Pretvaranje nije bilo zaštićeno, sistem je prijavio grešku, i raketa je skrenula s putanje i raspala se. Istražna komisija je utvrdila da funkcija koja je izazvala grešku Ariani 5 nakon polijetanja nije ni bila potrebna. Komponenta je bila ispravna za svoj stari ugovor, a niko nije provjerio da li taj ugovor važi u novom okruženju.

Rizici ponovne upotrebe i odgovori:

Rizik Primjer Odgovor
komponenta ne odgovara novom okruženju Ariane 5 provjeriti ugovor i granice u novom okruženju; testovi s novim vrijednostima
komponenta nestane left-pad, 2016 interni registar ili keš paketa; zaključane verzije
ranjivost u komponenti ranjivost u biblioteci Log4j otkrivena u decembru 2021, koja je pogodila ogroman broj Java sistema praćenje ranjivosti (npr. Dependabot), brza nadogradnja
zlonamjerna komponenta paket s imenom sličnim popularnom, s ubačenim kodom provjera izvora i imena, potpisani paketi
tranzitivne zavisnosti moja zavisnost zavisi od stotinu drugih spisak svih zavisnosti, redovna provjera
licenca biblioteka s licencom koja traži objavu vlastitog koda provjera licenci prije uključivanja

Zaključavanje verzija. Fajl s tačnim verzijama svih zavisnosti, uključujući tranzitivne (npr. requirements.txt s ==, poetry.lock, packages.lock.json u .NET-u), garantuje da se proizvod sutra gradi od istih dijelova kao danas.

SBOM (software bill of materials) je deklaracija sastava proizvoda, kao spisak sastojaka na pakovanju hrane: sve komponente, njihove verzije i licence. Kad se objavi nova ranjivost, firma sa SBOM-om za minut zna da li je pogođena. Zakoni o sajber sigurnosti (npr. evropski Akt o sajber otpornosti) sve češće traže takav spisak za proizvode koji se prodaju.

Ukratko.

  • Komponenta ispravna u jednom okruženju može biti pogrešna u drugom, kao kod Ariane 5.
  • Rizici: drugo okruženje, nestanak, ranjivost, zlonamjerni paket, tranzitivne zavisnosti, licence.
  • Odgovori: provjera ugovora, zaključane verzije, interni registar, praćenje ranjivosti, provjera licenci.
  • SBOM je deklaracija sastava proizvoda.

Provjeri se.

  1. Šta kaže princip ADP? – Zavisnosti između komponenata ne smiju praviti ciklus.
  2. Komponenta dobija novu funkciju, a stari pozivi rade. Koja verzija slijedi nakon 1.1.0? – 1.2.0.
  3. Šta je SBOM? – Spisak svih komponenata, verzija i licenci od kojih je proizvod sastavljen.

Dopunska praksa – paket deliveryapp-dostava

Cilj je napraviti komponentu kao Python paket, instalirati je i promijeniti verziju po pravilima. Trajanje: jedan čas.

Korak 1 – Paket

Kopirajte folder primjeri/paket/deliveryapp-dostava u svoj repozitorij. Napravite virtuelno okruženje i instalirajte paket:

python -m venv .venv
.venv\Scripts\activate          (Linux/macOS: source .venv/bin/activate)
pip install -e .
python -c "import deliveryapp_dostava as z; print(z.__version__, z.obracunaj('B', 4.2, 2150))"
pip install pytest
pytest tests

Korak 2 – Zakrpa

Pronađite ili zamislite ispravku koja ne mijenja ugovor (npr. bolja poruka greške). Napravite je, promijenite verziju u pyproject.toml i __init__.py na 2.0.1 i dopišite stavku u CHANGELOG.md.

Korak 3 – Sporedna verzija

Dodajte Grad D (2,00 € do 4 km, 0,40 € po km, najdalje 15 km) i test za njega. Stari pozivi rade, pa je nova verzija 2.1.0. Provjerite: koliko je dostava za N-1001 (21,50 €, 4,2 km) u Gradu D?

Korak 4 – Glavna verzija (samo zapis)

U CHANGELOG.md opišite promjenu koja bi tražila 3.0.0 (npr. iznos se vraća kao Decimal u eurima umjesto int u centima) i šta korisnici komponente moraju promijeniti.

Korak 5 – SBOM (opcionalno)

Pokrenite pip list --format=freeze u virtuelnom okruženju i sačuvajte izlaz kao docs/sastav.txt. To je najjednostavniji spisak sastava; profesionalni alati prave SBOM u standardnim formatima (CycloneDX, SPDX).

Rezultat: paket koji se instalira, testovi koji prolaze, verzija 2.1.0 i CHANGELOG.md s tri stavke.

Vježbe

Vježba za studenta 1 – verzije.

Komponenta deliveryapp-placanje je u verziji 3.4.2. Koja je sljedeća verzija za: a) ispravku greške u zaokruživanju; b) novi način plaćanja (stari rade); c) uklanjanje starog načina plaćanja „pouzećem”; d) ispravku pravopisne greške u poruci?

Rješenje. a) 3.4.3; b) 3.5.0; c) 4.0.0 (stari pozivi prestaju raditi); d) 3.4.3 ako se poruka ne smatra dijelom ugovora (ako je pozivaoci porede kao tekst, sigurnije je smatrati je promjenom ugovora).

Vježba za studenta 2 – kohezija i povezanost.

Komponenta deliveryapp-narudzbe direktno čita tabelu tarifa iz baze da bi izračunala dostavu, umjesto da pozove deliveryapp-dostava. Šta je loše i šta predlažete?

Rješenje. Povezanost je visoka i skrivena: narudžbe zavise od unutrašnje strukture podataka dostave, pa svaka promjena tabele kvari narudžbe, a pravilo obračuna postoji na dva mjesta (krši DRY i CCP). Prijedlog: narudžbe pozivaju samo ponuđeni interfejs obracunaj(); tabela tarifa je privatna stvar komponente dostave.

Vježba za studenta 3 – ciklus.

deliveryapp-narudzbe zavisi od deliveryapp-obavjestenja (šalje poruku o promjeni stanja), a deliveryapp-obavjestenja zavisi od deliveryapp-narudzbe (čita detalje narudžbe za tekst poruke). Kako prekinuti ciklus?

Rješenje. Npr. narudžbe objavljuju događaj „stanje promijenjeno” sa svim podacima potrebnim za poruku (broj, novo stanje, telefon), preko reda poruka ili interfejsa koji pripada narudžbama. Obavještenja reaguju na događaj i više ne zovu narudžbe. Zavisnost ide samo u jednom smjeru (ADP).

Vježba za studenta 4 – ponovna upotreba.

Tim želi u DeliveryApp uključiti besplatnu biblioteku za crtanje mape koju je napisao jedan programer i koja nije ažurirana tri godine. Napišite pet pitanja koja tim treba postaviti prije odluke.

Rješenje. 1) Kakva je licenca i da li dozvoljava upotrebu u komercijalnom proizvodu? 2) Ima li poznatih ranjivosti i ko ih ispravlja? 3) Od čega ona zavisi (tranzitivne zavisnosti)? 4) Šta radimo ako nestane ili prestane raditi – možemo li je držati u internom registru ili zamijeniti? 5) Da li njen ugovor odgovara našim uslovima (broj tačaka na mapi, mobilni uređaji, brzina)?

Sažetak u pet rečenica

  1. McIlroy je 1968. sanjao katalog softverskih komponenata, a left-pad 2016. pokazao je da taj katalog postoji, ali i da od jedanaest redova tuđeg koda mogu zavisiti hiljade projekata.
  2. Komponenta je jedinica sastavljanja i isporuke s ugovorom, ponuđenim i zahtijevanim interfejsom i eksplicitnim zavisnostima, a dobra podjela ima visoku koheziju i nisku povezanost.
  3. Principi REP, CCP i CRP odlučuju šta ide zajedno u komponentu, a ADP, SDP i SAP traže zavisnosti bez ciklusa, prema stabilnim i apstraktnim komponentama.
  4. Komponenta se pravi kao paket (pip, NuGet) s malim interfejsom, testovima i semantičkom verzijom, gdje zakrpa znači ispravku, sporedna verzija kompatibilnu novost, a glavna promjenu koja kvari stare pozive.
  5. Ponovna upotreba nosi rizike, od drugog okruženja (Ariane 5) do nestanka, ranjivosti i licenci, pa se verzije zaključavaju, zavisnosti prate, a sastav proizvoda vodi u SBOM-u.

Pitanja za ponavljanje

  1. Šta je McIlroy predložio 1968. i šta se desilo s left-padom 2016?
  2. Šta je CBSE i koje su njegove koristi?
  3. Navedite Szyperskijevu definiciju komponente i pet odlika komponente.
  4. Koja je razlika između komponente i klase?
  5. Šta su ponuđeni i zahtijevani interfejs? Objasnite analogijom s aparatom i utičnicom.
  6. Šta sadrži ugovor komponente? Napišite ugovor za obracunaj.
  7. Šta su kohezija i povezanost i kakve ih želimo?
  8. Objasnite principe REP, CCP i CRP.
  9. Objasnite principe ADP, SDP i SAP. Zašto je ciklus zavisnosti opasan?
  10. Navedite smjernice za dizajn komponente. Šta znače tri broja semantičke verzije?
  11. Opišite korake provođenja dizajna komponente i kako se komponenta pakuje u Pythonu i C#.
  12. Šta se desilo s Ariane 5 i koji su rizici ponovne upotrebe? Šta je SBOM?

Odgovori na pitanja za ponavljanje.

  1. McIlroy je na konferenciji u Garmischu 1968. predložio masovno proizvedene softverske komponente: kataloge standardnih rutina iz kojih se sklapaju programi. Dana 22. marta 2016. autor je povukao paket left-pad (11 redova) i druge pakete iz registra npm; gradnja hiljada projekata koji su preko lanca zavisnosti koristili left-pad počela je padati, dok registar nije vratio paket i promijenio pravila.
  2. CBSE je razvoj softvera sklapanjem vlastitih i gotovih komponenata. Koristi: brži razvoj, veća pouzdanost provjerenih komponenata, zamjenjivost i podjela rada među timovima.
  3. Komponenta je jedinica sastavljanja s ugovorom definisanim interfejsima i samo eksplicitnim zavisnostima od okoline, koja se isporučuje nezavisno i može je sklapati treće lice. Odlike: standardizovana, nezavisna, sastavljiva, isporučiva, dokumentovana.
  4. Klasa je jedinica koda, a komponenta jedinica isporuke; komponenta obično sadrži više klasa, od kojih je većina skrivena iza interfejsa.
  5. Ponuđeni interfejs su operacije koje komponenta nudi (fen nudi topao zrak), a zahtijevani one koje traži od okoline (fen traži utičnicu od 230 V). Komponenta radi svuda gdje okolina pruža zahtijevani interfejs.
  6. Ulaze, izlaze, greške i garancije. obracunaj(grad, km, iznos): ulazi su oznaka grada, kilometri i iznos u centima; izlaz je Obracun s gradom, dostavom u centima i opisom; greške su KeyError za nepoznat grad i ValueError za adresu izvan zone ili iznos ispod 5,00 €; garancija je da je od 30,00 € dostava 0 i da rezultat ne zavisi od vremena ni baze.
  7. Kohezija je koliko dijelovi unutar komponente pripadaju zajedno, a povezanost koliko komponenta zavisi od drugih. Želimo visoku koheziju i nisku povezanost.
  8. REP: ono što se ponovo koristi mora imati verziju i izdanje. CCP: zajedno ide ono što se mijenja iz istog razloga i u isto vrijeme. CRP: korisnik ne treba zavisiti od onoga što ne koristi.
  9. ADP: zavisnosti bez ciklusa. SDP: zavisi od onoga što je stabilnije od tebe. SAP: stabilne komponente trebaju biti apstraktne. Ciklus je opasan jer komponente u njemu ne mogu biti građene, testirane ni isporučene odvojeno, pa su zapravo jedna komponenta.
  10. Mali i jasan interfejs, nepromjenjivi objekti na granici, jasne greške, bez skrivenih zavisnosti, dokumentacija s primjerom, testovi uz komponentu, semantička verzija. Zakrpa (treći broj) za ispravku bez promjene ugovora, sporedna (drugi) za novu mogućnost uz rad starih poziva, glavna (prvi) za promjenu koja kvari stare pozive.
  11. Prepoznati kandidata, definisati ugovor, izdvojiti kod, napisati testove, spakovati, objaviti, održavati. Python: paket s pyproject.toml (ime, verzija), registar PyPI ili interni. C#: projekat biblioteke s verzijom u .csproj, dotnet pack, registar NuGet; javne su samo public klase.
  12. Ariane 5 je 4. juna 1996. eksplodirala oko 40 sekundi nakon starta jer je softver preuzet s Ariane 4 pri pretvaranju prevelike vrijednosti brzine iz 64-bitnog u 16-bitni broj izazvao grešku; funkcija Ariani 5 nije ni trebala. Rizici: drugo okruženje, nestanak komponente, ranjivosti, zlonamjerni paketi, tranzitivne zavisnosti, licence. SBOM je spisak svih komponenata, verzija i licenci od kojih je proizvod sastavljen.