Poglavlje 5: Verzioniranje, testiranje i isporuka

Priča za početak. U petak, 19. jula 2024, u 04:09 po svjetskom vremenu (UTC), firma CrowdStrike poslala je malo ažuriranje svom sigurnosnom programu Falcon, koji štiti računare velikih firmi od napada. Nije to bila nova verzija programa, nego običan fajl s podacima, takozvani Channel File 291, s pravilima za prepoznavanje novih napada. Fajl je imao grešku koju automatska provjera nije uhvatila, a Falcon radi duboko u jezgru Windowsa. Računari koji su ga primili pali su u plavi ekran i nisu se mogli ponovo pokrenuti. CrowdStrike je izmjenu povukao u 05:27, sat i osamnaest minuta kasnije, ali šteta je bila napravljena: Microsoft je procijenio da je pogođeno oko 8,5 miliona Windows uređaja, manje od jedan posto svih, ali među njima su bili računari aviokompanija, aerodroma, bolnica, banaka i televizija. Popravka je išla ručno, računar po računar, često uz fizički pristup mašini. U svom izvještaju CrowdStrike je obećao ono što ovo poglavlje uči: bolje automatsko testiranje i postepeno puštanje izmjena, prvo na malom broju računara, pa tek onda na svim.

U poglavlju 4 napisali smo čist kod i refaktorisali obračun uz 48 testova. Sada pitanje glasi: kako šest ljudi mijenja isti kod svaki dan, a da se izmjene ne sudaraju, i kako izmjena stiže do korisnika brzo, ali bez straha? Prvi dio govori o Gitu u timu, pull requestu i pregledu koda, kontinuiranoj integraciji i statičkoj analizi. Drugi dio govori o osiguranju kvaliteta, automatiziranim testovima, kontinuiranoj isporuci i kontejnerima.

Literatura. Osnovna literatura predmeta:

  1. I. Sommerville: Software Engineering, 10th ed., Pearson, 2016 (poglavlja 8 i 25).
  2. J. Humble, D. Farley: Continuous Delivery, Addison-Wesley, 2010.
  3. N. Forsgren, J. Humble, G. Kim: Accelerate, IT Revolution, 2018.

Riječi ovog poglavlja.

  • Grana (branch) – odvojena linija razvoja u Gitu, u kojoj se radi bez smetanja drugima.
  • Spajanje (merge) – unošenje izmjena iz jedne grane u drugu.
  • Pull request (PR) – zahtjev da se izmjene iz grane spoje u glavnu granu, uz pregled kolega.
  • Pregled koda (code review) – čitanje tuđih izmjena prije spajanja.
  • Kontinuirana integracija (CI) – svaka izmjena se automatski prevodi i testira čim stigne.
  • Statička analiza – provjera koda bez pokretanja (stil, sumnjive konstrukcije, sigurnosni problemi).
  • Osiguranje kvaliteta (QA) – sve aktivnosti kojima se kvalitet planira, ugrađuje i provjerava.
  • Piramida testova – mnogo brzih jediničnih testova, manje integracionih, malo sporih testova cijelog sistema.
  • Kontinuirana isporuka (CD) – svaka izmjena koja prođe provjeru spremna je za puštanje u rad jednim klikom.
  • Postepeno puštanje (kanarinac) – izmjena prvo ide malom dijelu korisnika, pa svima.
  • Kontejner – paket koji sadrži program i sve što mu treba da radi isto na svakom računaru.
  • DORA metrike – četiri mjere brzine i stabilnosti isporuke.

Ciljevi poglavlja. Nakon poglavlja možete: raditi u Gitu s granama i objasniti GitHub flow; napisati dobru commit poruku; otvoriti pull request i pregledati tuđi kod; objasniti kontinuiranu integraciju i napisati jednostavan GitHub Actions tok; protumačiti izlaz lintera; razlikovati osiguranje kvaliteta i testiranje; nacrtati piramidu testova i napisati jedinični test u pytestu i xUnitu; objasniti kontinuiranu isporuku, kanarinca, prekidač funkcije i povratak na staru verziju; objasniti šta je kontejner; nabrojati četiri DORA metrike.

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

Čas Sadržaj Na času
Teorija 1 5.1–5.4 Git u timu, pull request, CI, statička analiza Šta ruff kaže o staroj funkciji obracun
Teorija 2 5.5–5.8 Kvalitet, testovi, isporuka, kontejneri Da je CrowdStrike imao kanarinca…
Dopunska praksa GitHub Actions: ruff + pytest na svaki pull request Zelena kvačica na PR-u

Dio 1 – Od izmjene do spajanja

5.1 Git u timu

Git pamti svaku izmjenu koda: ko je promijenio, šta, kada i zašto. To već znate iz ranijih predmeta. Ono što se mijenja u timu je kako šest ljudi radi istovremeno.

Odgovor su grane. Glavna grana (main) uvijek sadrži kod koji radi. Ko počinje novi posao, napravi svoju granu (tarife-po-gradu), radi u njoj koliko treba, i kad je gotov, traži da se grana spoji u main. Dok radi, ne smeta nikome, i niko ne smeta njemu.

git switch -c tarife-po-gradu        # nova grana
# ... izmjene ...
git add dostava.py test_dostava.py
git commit -m "Tarifa kao podatak; dodati Grad B i C"
git push -u origin tarife-po-gradu   # grana ide na GitHub

Tim DeliveryApp koristi jednostavan dogovor zvani GitHub flow: main je uvijek ispravan; svaki posao je kratka grana; spajanje samo preko pull requesta; nakon spajanja grana se briše. Neki timovi idu i dalje i rade trunk-based development: grane žive najviše dan-dva, a nedovršene funkcije se sakrivaju prekidačima (5.7). Što grana duže živi, to je teže spajanje.

Slika 5.1 – Dvije grane DeliveryApp 2.0 i spajanje u glavnu granu

Dobra commit poruka je kratka rečenica u zapovjednom načinu koja kaže šta i, ako nije očito, zašto: „Dodaj tarifu za Grad B”, a ne „izmjene” ili „fix”. Za godinu dana, kad neko traži zašto je dostava u Gradu B 0,60 € po kilometru, istorija Gita mora odgovoriti.

Konflikt nastaje kad dvoje promijeni istu liniju u različitim granama. Git tada ne pogađa, nego pita čovjeka. Konflikata je manje kad su grane kratke i kad se često spaja.

Ukratko.

  • U timu svako radi u svojoj grani, a main je uvijek ispravan.
  • GitHub flow: kratka grana, pull request, pregled, spajanje, brisanje grane.
  • Commit poruka kaže šta i zašto; konflikti su rjeđi kad su grane kratke.

5.2 Pull request i pregled koda

Pull request je zahtjev: „Ovdje su moje izmjene, molim pregled prije spajanja u main.” Na GitHubu se vidi tačno šta je promijenjeno (crveno obrisano, zeleno dodato), i kolege mogu komentarisati svaku liniju.

Pregled koda ima tri cilja: naći greške dok su jeftine, širiti znanje (sada dvoje zna kako radi tarifa, a ne jedan; sjetite se rizika RZ-2), i držati kod dosljednim. Pravila koja tim DeliveryApp koristi:

  1. Mali PR-ovi. Do oko 400 linija izmjena. PR od 3.000 linija niko ne pregleda pažljivo, nego klikne „odobri”.
  2. Opis kaže zašto. Šta je cilj, kako je testirano, šta pregledač treba posebno pogledati.
  3. Mašina prva. Stil, format i testove provjerava CI (5.3); čovjek gleda logiku, imena, dizajn i sigurnost.
  4. Komentar o kodu, ne o osobi. „Ova funkcija radi dvije stvari” umjesto „opet si napravio dugu funkciju”. Psihološka sigurnost iz poglavlja 2 važi i ovdje.
  5. Bar jedno odobrenje. GitHub se može podesiti da ne dozvoli spajanje bez odobrenja i bez zelenih testova (branch protection).

Na času. Sara je poslala PR „Dodaj tarifu Grada B” sa 12 linija koda i bez ijednog testa. Šta biste napisali u komentaru, da bude korisno i ljubazno?

Ukratko.

  • Pull request traži pregled prije spajanja u main.
  • Pregled koda hvata greške, širi znanje i drži kod dosljednim.
  • PR-ovi su mali, opis kaže zašto, stil provjerava mašina, a komentari su o kodu, ne o osobi.

5.3 Kontinuirana integracija

U starim projektima programeri su mjesecima radili odvojeno, pa su na kraju danima „integrisali”: spajali kod koji se nije slagao. Kontinuirana integracija (CI) okreće priču: integriše se stalno, više puta dnevno, i svaka integracija se automatski provjerava. Pojam je uveo Grady Booch 1991, a proširio ga Extreme Programming krajem devedesetih.

Analogija: CI je kao vaga i kontrola na ulazu u skladište. Svaka pošiljka (izmjena) prolazi kontrolu odmah po dolasku, a ne jednom godišnje na inventuri.

Svaki put kad neko pošalje izmjenu ili otvori pull request, server za CI:

  1. preuzme kod,
  2. instalira zavisnosti,
  3. provjeri stil i sumnjive konstrukcije (linter),
  4. pokrene sve testove,
  5. javi rezultat: zelena kvačica ili crveni krstić na pull requestu.

Za DeliveryApp 2.0 to radi GitHub Actions. Tok se opisuje u YAML fajlu u repozitoriju (primjeri/ci/ci.yml):

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  python:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
      - run: pip install pytest ruff
      - run: ruff check .
      - run: pytest -q

  csharp:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: "10.0.x"
      - run: dotnet test DeliveryAppTestovi

Dva posla (python i csharp) rade paralelno, svaki na svom virtuelnom računaru. Ako bilo koji korak padne, pull request dobija crveni krstić i, uz zaštitu grane, ne može se spojiti.

Slika 5.2 – Kontinuirana integracija i isporuka: put izmjene do korisnika

Česta zabluda. „Imamo CI server, znači da radimo kontinuiranu integraciju.” CI je navika, a ne alat: svi spajaju u main bar jednom dnevno, i kad provjera padne, popravka je prvi posao tima. Server koji svaki dan prijavljuje crveno, a niko ne reaguje, samo troši struju.

Ukratko.

  • CI znači integrisati stalno i provjeriti svaku izmjenu automatski.
  • Tok: preuzmi kod, instaliraj, linter, testovi, javi rezultat.
  • GitHub Actions opisuje tok u YAML fajlu; crveni rezultat blokira spajanje.
  • CI je navika tima, a ne samo server.

5.4 Statička analiza i stil

Statička analiza pregleda kod bez pokretanja. Najjednostavniji alati (linteri) traže sumnjive konstrukcije i kršenje stila; ozbiljniji traže sigurnosne propuste i zavisnosti s poznatim ranjivostima.

Kad se linter ruff pokrene nad starom funkcijom obracun iz poglavlja 4, prijavi:

PLR1730 [*] Replace `if` statement with `p = min(p, 500)`
  --> primjeri\python\obracun_prije.py:44:9
   |
42 |       if k == "STUDENT10":
43 |           p = round(t * 10 / 100)
44 | /         if p > 500:
45 | |             p = 500
   | |___________________^

Ruff je uočio isto što i mi u refaktoringu: ograničenje popusta se jednostavnije piše kao min(...). Zvjezdica [*] znači da alat može sam popraviti (ruff check --fix). Nad refaktorisanim kodom ruff ne prijavljuje ništa.

Alat Jezik Šta provjerava
ruff, pylint, mypy Python stil, sumnjiv kod, tipovi
Roslyn analizatori, dotnet format C# stil, sumnjiv kod (ugrađeno u prevodilac)
SonarQube / SonarCloud više jezika kvalitet, dupliran kod, složenost, „vrata kvaliteta”
CodeQL, Dependabot više jezika sigurnosni propusti, ranjive zavisnosti
radon Python ciklomatska složenost (poglavlje 4)

Vrata kvaliteta (quality gate) su pravilo u CI-ju: PR se ne spaja ako, na primjer, novi kod nema testove ili ima funkciju složenosti veće od 10.

Ukratko.

  • Statička analiza provjerava kod bez pokretanja: stil, sumnjive konstrukcije, sigurnost.
  • Ruff je u staroj funkciji obracun našao isto što i refaktoring.
  • Vrata kvaliteta u CI-ju blokiraju spajanje koda koji ne zadovoljava pravila.

Provjeri se.

  1. Šta se nalazi u grani main u GitHub flowu? – Kod koji uvijek radi.
  2. Koji su koraci CI-ja za DeliveryApp? – Preuzmi kod, instaliraj, ruff, pytest (i dotnet test), javi rezultat.
  3. Šta znači [*] u izlazu ruffa? – Da alat može sam popraviti problem.

Dio 2 – Od provjere do korisnika

5.5 Osiguranje kvaliteta i testiranje

Osiguranje kvaliteta (QA, quality assurance) nije isto što i testiranje. Testiranje je jedna aktivnost: pokrenemo program i provjerimo rezultat. QA je sve što tim radi da bi kvalitet bio ugrađen: jasni zahtjevi s kriterijima prihvatanja, pregled dizajna, pregled koda, statička analiza, testovi, mjerenje grešaka u produkciji i retrospektive.

Dva pitanja treba razlikovati:

  • Verifikacija – pravimo li proizvod ispravno? (Da li kod radi prema specifikaciji? Da li N-1001 u Gradu B daje 25,30 €?)
  • Validacija – pravimo li ispravan proizvod? (Da li kupci uopšte žele „Ponovi narudžbu”? Da li je razumiju?)

Testovi uglavnom verifikuju; validaciju rade prototipi i razgovor s korisnicima (poglavlje 3). Detaljno o testiranju govori udžbenik Testiranje softvera; ovdje gledamo kako se testovi uklapaju u proces isporuke.

Ukratko.

  • QA je sve što ugrađuje kvalitet; testiranje je samo jedan dio.
  • Verifikacija pita da li proizvod pravimo ispravno, a validacija da li pravimo ispravan proizvod.

5.6 Automatizirani testovi i piramida testova

Testovi se razlikuju po tome koliko sistema obuhvataju:

Nivo Šta provjerava Brzina Primjer u DeliveryApp
jedinični jednu funkciju ili klasu milisekunde Tarifa.dostava(4.2, 2150) == 380
integracioni više dijelova zajedno (kod + baza, kod + API) sekunde narudžba se sačuva u bazu i pročita isto
sistemski / E2E cijeli sistem kroz sučelje sekunde do minute robot u pregledniku naruči i vidi „Potvrdi 24,50 €”

Mike Cohn je 2009. predložio piramidu testova: mnogo brzih jediničnih testova u osnovi, manje integracionih u sredini, i samo nekoliko sporih testova cijelog sistema na vrhu. Razlog je jednostavan: brzi testovi se pokreću na svaku izmjenu i odmah pokazuju gdje je greška, a spori testovi kroz sučelje su krhki i dugo traju.

Slika 5.3 – Piramida testova DeliveryApp 2.0

Jedinični test u Pythonu (pytest, primjeri/python/test_obracun.py):

@pytest.mark.parametrize("grad, ocekivano", [("A", 2450), ("B", 2530), ("C", 2500)])
def test_n1001_u_tri_grada(grad, ocekivano):
    assert ukupno_za_naplatu(N1001, 4.2, grad) == ocekivano


def test_izvan_zone_u_gradu_b():
    with pytest.raises(ValueError):
        ukupno_za_naplatu(N1001, 8.1, "B")

Isto u C# (xUnit, primjeri/csharp/DeliveryAppTestovi/TarifaTestovi.cs):

public class TarifaTestovi
{
    static readonly Tarifa GradB = new("B", Osnovna: 200, UkljucenoKm: 2, PoKm: 60, MaxKm: 8);

    [Theory]
    [InlineData(2.0, 200)]   // tačno uključeni kilometri
    [InlineData(2.1, 260)]   // započet jedan km
    [InlineData(4.2, 380)]   // N-1001
    [InlineData(8.0, 560)]   // najdalje
    public void DostavaUGraduB(double km, int ocekivano)
    {
        Assert.Equal(ocekivano, GradB.Dostava(km, 2150));
    }

    [Fact]
    public void IzvanZoneSeOdbija()
    {
        Assert.Throws<ArgumentException>(() => GradB.Dostava(8.1, 2150));
    }
}

pytest u folderu primjeri/python pokrene 48 testova, a dotnet test u projektu DeliveryAppTestovi 5 testova; svi prolaze za manje od sekunde. Primijetite izbor podataka: granice (2,0 km i 2,1 km; 8,0 km i 8,1 km) i poznati primjer (N-1001). Greške najčešće žive na granicama.

Razvoj vođen testovima (TDD, test-driven development) okreće redoslijed: prvo se napiše test koji pada, pa najmanje koda da prođe, pa refaktoring. Tako svaki red koda ima razlog i test.

Ukratko.

  • Testovi su jedinični, integracioni i sistemski; razlikuju se po obuhvatu i brzini.
  • Piramida: mnogo brzih jediničnih, manje integracionih, malo sporih sistemskih.
  • Dobri testovi provjeravaju granice i poznate primjere; pytest i xUnit izgledaju slično.
  • TDD: prvo test koji pada, pa kod, pa refaktoring.

5.7 Kontinuirana isporuka i postepeno puštanje

Kontinuirana isporuka (CD, continuous delivery) znači da je svaka izmjena koja prođe CI spremna za puštanje u rad, jednim klikom. Kontinuirano puštanje (continuous deployment) ide korak dalje: izmjena koja prođe sve provjere ide korisnicima automatski, bez klika.

Najvažnija lekcija iz priče o CrowdStrikeu nije „testirajte više”, nego „ne puštajte sve odjednom”. Tehnike koje ograničavaju štetu:

  • Kanarinac (canary release). Rudari su nekad nosili kanarinca u rudnik: ako ptica klone, ima plina, i ljudi izlaze. Nova verzija prvo ide malom dijelu korisnika (npr. 5 % kupaca u Gradu A). Ako se broj grešaka ne poveća za sat vremena, ide na 25 %, pa na sve.
  • Plavo-zeleno puštanje (blue–green). Dvije iste produkcije: stara (plava) radi, nova (zelena) se pripremi pored nje. Prebacivanje je jedno podešavanje, a povratak isto tako.
  • Prekidač funkcije (feature flag). Kod za „Praćenje dostavljača uživo” je u produkciji, ali isključen. Lana ga uključi prvo za tim, pa za Grad C, pa za sve. Ako nešto ne valja, isključi se bez nove isporuke.
  • Povratak (rollback). Svaka isporuka mora imati plan povratka na prethodnu verziju, isproban prije nego što zatreba.

Slika 5.4 – Kanarinac: nova verzija ide postepeno, uz praćenje grešaka

Iz stvarnog svijeta. U izvještaju nakon incidenta od 19. jula 2024. CrowdStrike je naveo da su ažuriranja sadržaja (kao Channel File 291) do tada išla svim korisnicima istovremeno, i najavio postepeno puštanje, s praćenjem i mogućnošću da kupci sami biraju kada primaju ažuriranja. Jedan fajl s podacima, a ne program, srušio je milione računara: i podaci i podešavanja su dio isporuke i zaslužuju istu pažnju kao kod.

Ukratko.

  • Kontinuirana isporuka: svaka provjerena izmjena spremna je za rad jednim klikom.
  • Kanarinac, plavo-zeleno puštanje, prekidači funkcija i povratak ograničavaju štetu greške.
  • I podaci i podešavanja su dio isporuke i provjeravaju se kao kod.

5.8 Kontejneri i metrike isporuke

„Kod mene radi” je najpoznatija rečenica u softveru. Program radi na Sarinom računaru, ali ne na serveru, jer server ima drugu verziju Pythona ili nema neku biblioteku. Kontejner rješava problem tako što zapakuje program zajedno sa svim što mu treba: verzijom jezika, bibliotekama i podešavanjima. Analogija je brodski kontejner: luka ne mora znati šta je unutra, svi kontejneri imaju iste dimenzije i isto se prenose.

Najpoznatiji alat je Docker (od 2013). Recept za kontejner je Dockerfile (primjeri/ci/Dockerfile):

FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY deliveryapp/ deliveryapp/
EXPOSE 8000
CMD ["uvicorn", "deliveryapp.api:app", "--host", "0.0.0.0", "--port", "8000"]

CI nakon uspješnih testova napravi sliku kontejnera (docker build), označi je verzijom (npr. deliveryapp-api:2.0.0) i pošalje u registar. Ista slika ide na test, pa na kanarinca, pa svima. Za mnogo kontejnera na mnogo servera koristi se orkestrator, najčešće Kubernetes (poglavlje 6, skaliranje).

Kako znati da li tim isporučuje dobro? Istraživanje opisano u knjizi Accelerate (2018) predlaže četiri DORA metrike:

Metrika Pitanje DeliveryApp 1.x Cilj za 2.0
učestalost isporuke koliko često puštamo u rad? jednom mjesečno više puta sedmično
vrijeme od izmjene do produkcije koliko traje put izmjene? dvije sedmice manje od jednog dana
procenat neuspjelih izmjena koliko isporuka izazove problem? oko 20 % ispod 10 %
vrijeme oporavka koliko brzo popravimo kvar? pola dana ispod jednog sata

Važan nalaz istraživanja: najbolji timovi su i brži i stabilniji. Brzina i stabilnost ne isključuju jedna drugu, jer male, česte i automatski provjerene izmjene manje kvare i lakše se vraćaju.

Ukratko.

  • Kontejner pakuje program sa svim zavisnostima, pa radi isto svuda; recept je Dockerfile.
  • Ista slika kontejnera ide kroz sva okruženja, od testa do produkcije.
  • DORA metrike: učestalost isporuke, vrijeme izmjene do produkcije, procenat neuspjelih izmjena, vrijeme oporavka.
  • Najbolji timovi su i brži i stabilniji.

Provjeri se.

  1. Koja je razlika između verifikacije i validacije? – Verifikacija: radimo li ispravno; validacija: radimo li ispravnu stvar.
  2. Zašto u piramidi ima najviše jediničnih testova? – Jer su najbrži, pokreću se na svaku izmjenu i tačno pokazuju gdje je greška.
  3. Šta je kanarinac u isporuci? – Puštanje nove verzije prvo malom dijelu korisnika, uz praćenje grešaka, prije puštanja svima.

Dopunska praksa – GitHub Actions za DeliveryApp

Cilj je da svaki pull request u repozitoriju deliveryapp-2 automatski prođe linter i testove. Trajanje: jedan čas.

Korak 1 – Kod i testovi

U repozitorij kopirajte dostava.py, obracun_poslije.py, obracun_prije.py i test_obracun.py iz primjeri/python. Lokalno pokrenite:

python -m pytest -q
python -m ruff check .

Ruff će prijaviti obracun_prije.py. Ispravite ga sa ruff check --fix ili ga obrišite (više nam ne treba, jer testovi već pokrivaju novu funkciju).

Korak 2 – Tok rada

Napravite fajl .github/workflows/ci.yml s dijelom python iz odjeljka 5.3 (dio csharp dodajte ako ste kopirali i projekat DeliveryAppTestovi). Commit i push u main. Na kartici Actions pratite izvršavanje.

Korak 3 – Pull request koji pada

  1. Napravite granu pokvari-tarifu.
  2. U dostava.py promijenite po_km=60 za Grad B u po_km=50.
  3. Commit, push, otvorite pull request.
  4. Posmatrajte kako CI pada i koji test javlja grešku (test_n1001_u_tri_grada[B]).

Korak 4 – Zaštita grane

U Settings → Branches (ili Rulesets) uključite pravilo za main: spajanje samo preko PR-a, uz uspješnu provjeru CI. Pokušajte spojiti pokvareni PR. Zatim vratite ispravku i posmatrajte zelenu kvačicu.

Korak 5 – Pregled koda u paru

Razmijenite PR s kolegom i ostavite bar dva komentara po pravilima iz 5.2.

Rezultat: link na PR koji je pao pa prošao CI, s komentarima pregleda.

Vježbe

Vježba za studenta 1 – commit poruke.

Prepravite poruke: „izmjene”, „fix”, „radi sad”, „Sara-final-final2”.

Rješenje. Na primjer: „Dodaj tarifu za Grad C”; „Ispravi zaokruživanje kilometara u Gradu B (ceil umjesto int)”; „Vrati 404 kad narudžba ne postoji”; „Dodaj ekran Moje narudžbe s dugmetom Ponovi”. Poruka kaže šta je urađeno i, gdje nije očito, zašto.

Vježba za studenta 2 – granice.

Napišite tri testa za tarifu Grada C (2,50 € do 3 km, 0,50 € po započetom km, najdalje 12 km) koji provjeravaju granice.

Rješenje. 3,0 km → 250 centi; 3,1 km → 300 centi; 12,0 km → 250 + 9 × 50 = 700 centi; 12,1 km → greška „izvan zone”. Uz to iznos 30,00 € na bilo kojoj udaljenosti → 0.

Vježba za studenta 3 – piramida.

Tim DeliveryApp ima 10 jediničnih, 20 integracionih i 60 testova kroz preglednik, i CI traje 40 minuta. Šta nije u redu i šta predlažete?

Rješenje. Piramida je naopako (sladoled-kornet): najviše je sporih i krhkih testova kroz preglednik. Prijedlog: pravila (dostava, popust, stanja) pokriti jediničnim testovima (stotine, ukupno nekoliko sekundi), zadržati integracione za bazu i API, a testove kroz preglednik svesti na nekoliko glavnih tokova (naruči, ponovi, otkaži).

Vježba za studenta 4 – isporuka.

Opišite plan puštanja funkcije „Praćenje dostavljača uživo” u rad, koristeći prekidač funkcije i kanarinca. Šta pratite i kada odustajete?

Rješenje. (1) Kod ide u produkciju isključen. (2) Prekidač se uključi za tim i nekoliko dostavljača (interni test). (3) Uključi se za 5 % kupaca Grada C na dva dana; prate se greške aplikacije, vrijeme odziva i potrošnja baterije na mobitelu. (4) Ako je sve u granicama (npr. bez rasta grešaka, odziv do 2 s), 25 %, pa 100 % i drugi gradovi. (5) Ako greške porastu ili odziv pređe 2 s, prekidač se isključuje odmah, bez nove isporuke.

Sažetak u pet rečenica

  1. CrowdStrikeovo ažuriranje od 19. jula 2024. srušilo je oko 8,5 miliona Windows uređaja jer je jedan neispravan fajl s podacima pušten svima istovremeno.
  2. Tim radi u kratkim Git granama, a izmjene ulaze u main samo preko pull requesta s pregledom koda, malim izmjenama i komentarima o kodu, ne o osobi.
  3. Kontinuirana integracija automatski provjerava svaku izmjenu (linter, testovi), a statička analiza i vrata kvaliteta zaustavljaju loš kod prije spajanja.
  4. Osiguranje kvaliteta je šire od testiranja, a piramida testova traži mnogo brzih jediničnih testova (pytest, xUnit) koji provjeravaju granice, i malo sporih testova cijelog sistema.
  5. Kontinuirana isporuka, kanarinac, prekidači funkcija, povratak i kontejneri čine isporuku brzom i bez straha, a DORA metrike pokazuju da najbolji timovi isporučuju i brže i stabilnije.

Pitanja za ponavljanje

  1. Šta se desilo 19. jula 2024. i koje su pouke za isporuku softvera?
  2. Šta je grana i kako izgleda GitHub flow?
  3. Kako izgleda dobra commit poruka? Kada nastaje konflikt?
  4. Šta je pull request i koja su tri cilja pregleda koda? Navedite tri pravila dobrog pregleda.
  5. Šta je kontinuirana integracija i koje korake izvršava? Zašto je CI navika, a ne samo alat?
  6. Šta je statička analiza? Navedite dva alata za Python i jedan za C#. Šta su vrata kvaliteta?
  7. Koja je razlika između osiguranja kvaliteta i testiranja, i između verifikacije i validacije?
  8. Opišite tri nivoa testova i piramidu testova.
  9. Zašto testovi tarife provjeravaju 2,0 i 2,1 km, i 8,0 i 8,1 km?
  10. Šta je razlika između kontinuirane isporuke i kontinuiranog puštanja?
  11. Objasnite kanarinca, plavo-zeleno puštanje, prekidač funkcije i povratak.
  12. Šta je kontejner i čemu služi Dockerfile? Nabrojte četiri DORA metrike.

Odgovori na pitanja za ponavljanje.

  1. CrowdStrike je poslao neispravan fajl s podacima (Channel File 291) za svoj program Falcon; računari s Windowsom su pali u plavi ekran, oko 8,5 miliona uređaja, uključujući aerodrome, bolnice i banke, a popravka je išla ručno. Pouke: i podaci i podešavanja su dio isporuke i moraju se testirati, a izmjene se puštaju postepeno, ne svima odjednom.
  2. Grana je odvojena linija razvoja u Gitu. GitHub flow: main je uvijek ispravan; svaki posao je kratka grana; spajanje samo preko pull requesta s pregledom; nakon spajanja grana se briše.
  3. Kratka rečenica u zapovjednom načinu koja kaže šta je urađeno i, ako nije očito, zašto (npr. „Dodaj tarifu za Grad B”). Konflikt nastaje kad dvoje u različitim granama promijeni istu liniju; Git tada traži od čovjeka da odluči.
  4. Pull request je zahtjev da se izmjene iz grane spoje u main, uz pregled kolega. Ciljevi pregleda: naći greške dok su jeftine, širiti znanje u timu, držati kod dosljednim. Pravila: mali PR-ovi, opis kaže zašto, stil provjerava mašina, komentar o kodu a ne o osobi, bar jedno odobrenje.
  5. CI znači integrisati izmjene stalno i automatski ih provjeravati. Koraci: preuzmi kod, instaliraj zavisnosti, linter, testovi, javi rezultat (zeleno ili crveno). Navika je jer ima smisla samo ako svi spajaju često i ako je popravka crvenog rezultata prvi posao tima.
  6. Statička analiza provjerava kod bez pokretanja: stil, sumnjive konstrukcije, sigurnost, ranjive zavisnosti. Python: ruff, pylint, mypy; C#: Roslyn analizatori ili dotnet format. Vrata kvaliteta su pravilo u CI-ju koje blokira spajanje koda koji ne zadovoljava uslove (npr. bez testova ili prevelika složenost).
  7. Testiranje je jedna aktivnost provjere; osiguranje kvaliteta je sve što tim radi da ugradi kvalitet (zahtjevi, pregledi, analiza, testovi, mjerenje). Verifikacija pita „pravimo li proizvod ispravno”, a validacija „pravimo li ispravan proizvod”.
  8. Jedinični testovi provjeravaju jednu funkciju (milisekunde), integracioni više dijelova zajedno (sekunde), sistemski cijeli sistem kroz sučelje (sekunde do minute). Piramida: mnogo jediničnih u osnovi, manje integracionih, malo sistemskih na vrhu.
  9. Zato što greške najčešće žive na granicama: 2,0 km je posljednja vrijednost bez doplate, 2,1 km prva s doplatom; 8,0 km je najdalja dozvoljena adresa, 8,1 km prva koja se odbija.
  10. Kontinuirana isporuka: svaka provjerena izmjena je spremna za puštanje jednim klikom. Kontinuirano puštanje: provjerena izmjena ide korisnicima automatski, bez klika.
  11. Kanarinac: nova verzija prvo ide malom dijelu korisnika uz praćenje, pa postepeno svima. Plavo-zeleno: dvije iste produkcije, prebacivanje i povratak su jedno podešavanje. Prekidač funkcije: kod je u produkciji, a funkcija se uključuje ili isključuje podešavanjem. Povratak: unaprijed isproban plan vraćanja prethodne verzije.
  12. Kontejner je paket programa sa svim zavisnostima, koji radi isto na svakom računaru. Dockerfile je recept po kojem se pravi slika kontejnera. DORA metrike: učestalost isporuke, vrijeme od izmjene do produkcije, procenat neuspjelih izmjena, vrijeme oporavka.