Przejdź do treści
INF.04 · Dział IV

Inżynieria oprogramowania i projektowanie

Cykl życia oprogramowania, zwinne metodyki (Agile, Scrum), modelowanie systemów z wykorzystaniem UML (diagramy przypadków użycia, klas, sekwencji), wybrane wzorce projektowe (np. Singleton, MVC, Observer).

Wstęp: dział, w którym nie ma czego liczyć — trzeba rozumieć

W INF.04 to jedyny dział bez wzorów i bez składni języka. Egzamin sprawdza tu trzy rzeczy: czy potrafisz nazwać fazę cyklu życia po jej opisie, czy czytasz diagram UML (najczęściej klas albo przypadków użycia) i czy odróżniasz pojęcia, które brzmią podobnie — agregację od kompozycji, test jednostkowy od integracyjnego, Product Ownera od Scrum Mastera. Zadania są krótkie i bardzo konkretne: „na diagramie klas symbol wypełnionego rombu oznacza…", „ile trwa sprint w Scrumie", „który poziom testów wykonuje klient". Nauka tego działu to nauka precyzyjnych rozróżnień, a nie ogólnych opowieści o projektach.

1

Cykl życia oprogramowania i wymagania

Cykl życia (SDLC, Software Development Life Cycle) to sześć faz, przez które przechodzi każdy program — niezależnie od tego, czy jest pisany kaskadowo, czy w sprintach. Zadanie egzaminacyjne zwykle opisuje czynność („programista pisze kod klasy Faktura", „klient sprawdza, czy system spełnia jego oczekiwania") i każe wskazać fazę. Naucz się kolejności i typowego produktu każdej fazy.

Sześć faz i ich produkty
  1. Analiza wymagań — rozmowy z klientem, wywiady, obserwacja obecnego systemu. Produkt: specyfikacja wymagań i najczęściej diagram przypadków użycia. Tu decyduje się, co system ma robić.

  2. Projektowanie — architektura, podział na moduły, model bazy danych, diagramy klas i sekwencji, projekt interfejsu. Produkt: dokumentacja projektowa. Tu decyduje się, jak system ma to robić.

  3. Implementacja — pisanie kodu w wybranym języku, testy jednostkowe pisane przez programistów, praca w repozytorium git.

  4. Testowanie — integracyjne, systemowe i akceptacyjne; raportowanie i poprawianie błędów.

  5. Wdrożenie — instalacja u klienta, migracja danych ze starego systemu, konfiguracja środowiska produkcyjnego, szkolenie użytkowników.

  6. Utrzymanie (konserwacja) — poprawki błędów zgłoszonych przez użytkowników, aktualizacje, dostosowanie do zmian prawa i sprzętu, rozwój o nowe funkcje. To najdłuższa i najdroższa faza całego cyklu.

Wymagania funkcjonalne

Opisują co system ma robić — konkretne funkcje widziane przez użytkownika. Zwykle da się je zapisać zdaniem „system umożliwia…".

  • System umożliwia rejestrację konta przez e-mail.
  • System generuje fakturę w formacie PDF.
  • Administrator może zablokować konto użytkownika.
  • System wysyła powiadomienie o zbliżającym się terminie płatności.
Wymagania niefunkcjonalne

Opisują jak dobrze system ma działać — cechy jakościowe. Najczęściej zawierają liczbę, jednostkę albo nazwę normy.

  • Wydajność — strona ładuje się poniżej 2 sekund przy 500 użytkownikach.
  • Bezpieczeństwo — hasła przechowywane jako skróty, transmisja po HTTPS.
  • Niezawodność — dostępność 99,9% w skali miesiąca.
  • Użyteczność, przenośność, skalowalność — obsługa czytnika ekranu, działanie na Windows i Linux, praca na wielu serwerach.

Test na rozróżnienie wymagań

Zapytaj: „czy da się to wyłączyć i program nadal będzie robił to samo, tylko gorzej?". Jeśli tak — to wymaganie niefunkcjonalne. „Logowanie do systemu" to funkcja (funkcjonalne). „Logowanie ma trwać mniej niż sekundę" to jakość tej funkcji (niefunkcjonalne). Uwaga na słowo „bezpieczeństwo": samo szyfrowanie transmisji jest niefunkcjonalne, ale nadawanie uprawnień przez administratora to już konkretna funkcja systemu.

Dlaczego analiza jest najważniejsza

Im później wykryty błąd, tym droższa poprawka. Błąd w specyfikacji wymagań poprawiasz, zmieniając jedno zdanie w dokumencie. Ten sam błąd wykryty po wdrożeniu oznacza przeprojektowanie modułu, poprawę kodu, ponowne testy, nową wersję u wszystkich klientów i migrację danych. Dlatego w każdym modelu wytwarzania — także zwinnym — nacisk kładzie się na jak najwcześniejsze ustalenie i weryfikację wymagań.

2

Modele wytwarzania oprogramowania

Model wytwarzania mówi, w jakiej kolejności i ile razy wykonuje się fazy cyklu życia. Egzamin pyta o dobór modelu do sytuacji („wymagania są niepewne i będą się zmieniać — który model?") oraz o zalety i wady. Poniższa tabela to minimum, które trzeba znać.

Porównanie modeli
ModelKiedy stosowaćZaletyWady
Kaskadowy (waterfall)wymagania pewne i niezmienne, projekt krótki, silne wymogi formalne i dokumentacyjneprosty i czytelny, łatwo planować budżet i terminy, pełna dokumentacja każdej fazybrak powrotu do poprzedniej fazy, klient widzi produkt dopiero na końcu, kosztowna zmiana wymagań
Iteracyjno-przyrostowyduże systemy, które da się podzielić na moduły dostarczane po koleiklient dostaje działającą część wcześnie, zmiany łatwiejsze, ryzyko rozłożone na iteracjetrudniejsze planowanie całości, wymaga dobrej architektury od początku, ryzyko rozrostu zakresu
Spiralnyprojekty duże, kosztowne i obarczone dużym ryzykiem (systemy bankowe, medyczne)w każdym cyklu jest jawna analiza ryzyka, wcześnie wykrywa kosztowne pomyłkiskomplikowany i drogi, wymaga ekspertów od oceny ryzyka, nieopłacalny w małych projektach
Prototypowyklient nie potrafi określić wymagań, projekt mocno oparty na interfejsie użytkownikaszybkie doprecyzowanie wymagań, klient widzi i klika makietę, mniej nieporozumieńpokusa oddania prototypu jako produktu, prototyp bywa pisany „na skróty", trudno oszacować koszt
V-modelsystemy o wysokich wymogach jakości i certyfikacji, gdzie testy muszą być zaplanowane z górykażdej fazie projektowej odpowiada poziom testów, błędy wykrywane wcześniej niż w kaskadzienadal sztywny jak kaskada, słabo znosi zmiany wymagań, dużo dokumentacji
V-model — dlaczego „V"

Lewe ramię to fazy analizy i projektowania, prawe — odpowiadające im poziomy testów. Wymagania weryfikujesz testami akceptacyjnymi, projekt techniczny — testami jednostkowymi. Zapamiętaj te pary, bo to gotowa odpowiedź na pytanie „który poziom testów sprawdza specyfikację wymagań".

Analiza wymagan  ------------------->  Testy akceptacyjne
 \                                        /
  Specyfikacja systemu  ----------->  Testy systemowe
     \                                  /
      Projekt architektury  ---->  Testy integracyjne
         \                          /
          Projekt szczegolowy  ->  Testy jednostkowe
             \                    /
                  IMPLEMENTACJA

3

Agile, Scrum i Kanban

Manifest zwinnego wytwarzania oprogramowania (Agile, 2001) to cztery pary wartości. Kluczowe zdanie brzmi: doceniamy elementy po prawej, ale bardziej cenimy te po lewej. To nie znaczy „nie robimy dokumentacji", tylko „działający program jest ważniejszy niż jej objętość".

Cztery wartości manifestu Agile
  • Ludzie i interakcje ponad procesy i narzędzia.
  • Działające oprogramowanie ponad obszerną dokumentację.
  • Współpraca z klientem ponad formalne ustalenia umowy.
  • Reagowanie na zmiany ponad realizację ustalonego planu.

Manifest uzupełnia 12 zasad — najczęściej cytowane to: częste dostarczanie działającego oprogramowania, akceptacja zmian wymagań nawet późno w projekcie, codzienna współpraca biznesu z programistami oraz regularna refleksja zespołu nad tym, jak pracować skuteczniej.

Scrum jest najpopularniejszą ramą postępowania zgodną z Agile. Praca dzieli się na sprinty — stałe okresy zwykle od 1 do 4 tygodni (najczęściej 2), zakończone potencjalnie gotowym do wydania przyrostem produktu. Długość sprintu raz ustalona nie zmienia się między sprintami.

Role, artefakty i wydarzenia w Scrumie
ElementRodzajOdpowiada za / czasZapamiętaj
Product Ownerrolawartość produktu, kolejność zadań w backlogu produktureprezentuje klienta, decyduje CO i w jakiej kolejności
Scrum Masterrolaprzestrzeganie zasad Scruma, usuwanie przeszkód zespołunie jest kierownikiem ani szefem — jest opiekunem procesu
Zespół deweloperskirolawytworzenie przyrostu, zwykle kilka osóbsamoorganizujący się i wielofunkcyjny, decyduje JAK
Backlog produktuartefaktuporządkowana lista wszystkiego, co może trafić do produktuwłaścicielem jest Product Owner, lista żyje przez cały projekt
Backlog sprintuartefaktzadania wybrane na bieżący sprint plus plan ich wykonanianależy do zespołu, nie zmienia się dowolnie w trakcie sprintu
Planowanie sprintuwydarzeniena początku sprintu, kilka godzinpowstaje cel sprintu i backlog sprintu
Daily Scrumwydarzeniecodziennie, maksymalnie 15 minutco zrobiłem, co zrobię, co mnie blokuje — to nie raport dla szefa
Przegląd sprintuwydarzeniena końcu sprintu, z udziałem klientapokazujemy działający produkt i zbieramy uwagi
Retrospektywawydarzeniepo przeglądzie, przed kolejnym planowaniemrozmawiamy o sposobie pracy zespołu, nie o produkcie

Przegląd kontra retrospektywa — pewny punkt

Oba wydarzenia są na końcu sprintu i uczniowie je mylą. Różnica jest jedna: przegląd dotyczy produktu (co powstało, czy klient to akceptuje), a retrospektywa dotyczy procesu (co poprawić w sposobie pracy zespołu). Na przeglądzie jest klient, na retrospektywie zwykle tylko zespół.

Kanban i limit WIP

Kanban nie ma sprintów, ról ani stałych wydarzeń. Ma tablicę z kolumnami odpowiadającymi etapom pracy i zadania przesuwane w prawo. Najważniejsze pojęcie to limit WIP (Work In Progress) — maksymalna liczba zadań, które mogą jednocześnie znajdować się w kolumnie. Gdy limit jest osiągnięty, nie wolno wciągnąć nowego zadania; trzeba najpierw dokończyć któreś z trwających. Dzięki temu widać wąskie gardło procesu.

+-------------+---------------+--------------+-------------+
|   DO ZROBIENIA |  W TOKU (3)  |  TESTY (2)   |   GOTOWE    |
+-------------+---------------+--------------+-------------+
| [ Eksport   ] | [ Logowanie ] | [ Koszyk   ] | [ Rejestr. ]|
| [ Raporty   ] | [ Platnosci ] | [ Filtry   ] | [ Menu     ]|
| [ Powiadom. ] | [ Wyszukiw. ] |              | [ Stopka   ]|
| [ Ustawien. ] |               |              |             |
+-------------+---------------+--------------+-------------+
                limit = 3       limit = 2
                ^ pelno!        ^ mozna wciagnac 0 zadan

Liczba w naglowku kolumny to limit WIP.
Kolumna "W toku" jest pelna -> nikt nie zaczyna nowego zadania,
zespol pomaga dokonczyc to, co juz sie zaczelo.

4

UML: przypadki użycia i diagram klas

UML (Unified Modeling Language) to język graficzny do opisu systemów. Na egzaminie liczą się dwa diagramy statyczne: przypadków użycia (powstaje w fazie analizy) i klas (powstaje w fazie projektowania). Pytania są zwykle o odczytanie symbolu albo o wskazanie, który diagram czemu służy.

Diagram przypadków użycia

Pokazuje, kto korzysta z systemu i co może w nim zrobić — nie pokazuje kolejności ani szczegółów technicznych. Aktor (ludzik) to rola użytkownika lub system zewnętrzny, przypadek użycia (elipsa) to funkcja systemu nazwana czasownikiem, a prostokąt to granica systemu.

         SYSTEM SPRZEDAZY BILETOW
 +--------------------------------------------+
 |                                            |
 |        (  Przegladaj repertuar  )          |
 |               ^                            |
 |               |                            |
 |        (  Rezerwuj miejsce  )              |
 |            |        |                      |
 |  <<include>>|        |<<extend>>           |
 |            v        v                      |
 |   ( Zaloguj sie ) ( Wybierz znizke )       |
 |                                            |
 |        (  Generuj raport sprzedazy )       |
 |               ^                            |
 +---------------|----------------------------+
      O          |                    O
     -|-  -------+                   -|-  ------> raport
     / \                             / \
   KLIENT                        PRACOWNIK KASY

Legenda:
O/-|-/ \        aktor (rola uzytkownika lub system zewnetrzny)
( tekst )       przypadek uzycia (funkcja systemu)
------          asocjacja: aktor bierze udzial w przypadku uzycia
<<include>>     przypadek ZAWSZE wlacza inny (obowiazkowy)
<<extend>>      przypadek CZASEM rozszerza inny (opcjonalny)

Kierunek strzałki: przy include strzałka biegnie od przypadku bazowego do włączanego („Rezerwuj miejsce" zawsze wymaga „Zaloguj się"). Przy extend strzałka biegnie od rozszerzenia do przypadku bazowego („Wybierz zniżkę" tylko czasami rozszerza rezerwację). To najczęściej mylona para w całym UML.

Diagram klas

Klasa rysowana jest jako prostokąt podzielony na trzy części: nazwa, atrybuty (pola), operacje (metody). Przed każdym elementem stoi symbol widoczności. Podkreślenie oznacza element statyczny, kursywa — klasę abstrakcyjną lub metodę abstrakcyjną.

         +---------------------------+
       |         Osoba             |   <- nazwa klasy
       +---------------------------+
       | # imie : string           |   <- atrybuty
       | # nazwisko : string       |
       | - pesel : string          |
       +---------------------------+
       | + getImie() : string      |   <- metody (operacje)
       | + setPesel(p:string):void |
       +---------------------------+
                   /_\                 dziedziczenie
                    |                  (pusty trojkat)
       +---------------------------+
       |         Klient            |
       +---------------------------+
       | - idKlienta : int         |
       | - rabat : float           |
       +---------------------------+
       | + zlozZamowienie() : void |
       +---------------------------+
            1 |
              |  posiada
            * |
       +---------------------------+          +------------------+
       |       Zamowienie          |<>-------*|   PozycjaKoszyka |
       +---------------------------+  1       +------------------+
       | - numer : string          | agregacja| - ilosc : int    |
       | - dataZlozenia : date     |          | - cena : float   |
       +---------------------------+          +------------------+
       | + policzWartosc() : float |
       +---------------------------+
            1 |
            <>| KOMPOZYCJA (romb wypelniony)
            1..1
       +---------------------------+
       |        Faktura            |
       +---------------------------+
       | - nrFaktury : string      |
       +---------------------------+

Widocznosc:
  +   public     - dostepny wszedzie
  -   private    - dostepny tylko wewnatrz klasy
  #   protected  - dostepny w klasie i w klasach dziedziczacych
  ~   package    - dostepny w obrebie pakietu
Symbole relacji — tabela do zapamiętania
RelacjaSymbolZnaczenie i przykład
Asocjacjazwykła liniaobiekty po prostu o sobie „wiedzą" i współpracują. Nauczyciel — Uczeń.
Agregacjaromb pusty przy całości„całość — część", ale część przetrwa usunięcie całości. Zespół i Zawodnik: rozwiązujesz zespół, zawodnicy istnieją dalej.
Kompozycjaromb wypełniony przy całościsilna „całość — część": część ginie razem z całością. Faktura i Pozycja faktury; Dom i Pokój.
Dziedziczenie (generalizacja)linia ciągła + pusty trójkąt przy klasie bazowejrelacja „jest rodzajem". Klient jest rodzajem Osoby. Trójkąt zawsze wskazuje klasę nadrzędną.
Realizacja interfejsulinia przerywana + pusty trójkątklasa implementuje interfejs. Klasa PlatnoscKarta realizuje interfejs Platnosc.
Zależnośćlinia przerywana + zwykła strzałkajedna klasa chwilowo używa drugiej, np. jako parametru metody.
Liczebności (krotności)
  • 1 — dokładnie jeden.
  • 0..1 — zero albo jeden (opcjonalny).
  • * lub 0..* — dowolnie wiele, także zero.
  • 1..* — co najmniej jeden.
  • 2..5 — od dwóch do pięciu.

Liczebność czytasz zawsze po przeciwnej stronie linii: „jeden Klient — wiele Zamówień" to zapis 1 przy klasie Klient i * przy klasie Zamówienie.

Agregacja czy kompozycja?

Zadaj jedno pytanie: czy część ma sens bez całości?



Usuwasz Fakturę — jej pozycje przestają mieć jakikolwiek sens, nikt ich nie przypisze gdzie indziej. To kompozycja, romb wypełniony.



Usuwasz Playlistę — utwory zostają w bibliotece i mogą trafić do innej playlisty. To agregacja, romb pusty.



Skrót pamięciowy: wypełniony romb = wspólny los. Romb rysujesz zawsze przy klasie będącej całością.

5

UML: diagram sekwencji i czynności

Diagramy dynamiczne pokazują zachowanie w czasie. Sekwencji — kto do kogo wysyła komunikaty i w jakiej kolejności. Czynności — przepływ kroków algorytmu lub procesu biznesowego, z warunkami i rozgałęzieniami.

Diagram sekwencji

Uczestnicy stoją w rzędzie u góry. Od każdego w dół biegnie linia życia (pionowa linia przerywana). Prostokąt na linii to okres aktywności obiektu. Poziome strzałki to komunikaty: strzałka pełna z pełnym grotem — wywołanie synchroniczne, strzałka przerywana — odpowiedź (return). Czas płynie z góry na dół.

  :Uzytkownik      :FormularzLogowania   :Autoryzacja      :BazaDanych
    |                    |                   |                |
    |  wpiszDane()       |                   |                |
    |------------------->|                   |                |
    |                   [#]                  |                |
    |                    | sprawdz(login,haslo)                |
    |                    |------------------>|                |
    |                    |                  [#] pobierzUzytkownika(login)
    |                    |                   |--------------->|
    |                    |                   |               [#]
    |                    |                   |<- - - - - - - -|
    |                    |                   |   rekord       |
    |                    |<- - - - - - - - - |                |
    |                    |   true / false    |                |
    |<- - - - - - - - - -|                   |                |
    |   komunikat        |                   |                |
    |                    |                   |                |

---->      komunikat synchroniczny (wywolanie metody)
- - >      komunikat zwrotny (odpowiedz, return)
[#]        prostokat aktywnosci - obiekt wykonuje operacje
|          linia zycia obiektu; czas plynie w dol
Diagram czynności

Odpowiednik schematu blokowego w UML. Wypełnione koło to węzeł początkowy, koło z obwódką — końcowy, zaokrąglony prostokąt to czynność, romb to węzeł decyzyjny z warunkiem w nawiasach kwadratowych. Gruba pozioma kreska (rozwidlenie) oznacza czynności wykonywane równolegle.

              (*)   <- wezel poczatkowy
             |
             v
    +--------------------+
    |  Dodaj towar do    |
    |     koszyka        |
    +--------------------+
             |
             v
           /     \
          <  suma  >   [suma > 200 zl]
           \     /--------------------+
             |                        |
    [suma <= 200 zl]                  v
             |             +--------------------+
             v             | Naliczen. rabatu   |
    +--------------------+ +--------------------+
    | Naliczen. wysylki  |          |
    +--------------------+          |
             |                      |
             +----------+-----------+
                        |
                        v
               +------------------+
               | Zlozenie zamow.  |
               +------------------+
                        |
                        v
                      (( ))  <- wezel koncowy

Diagram czynności można podzielić na tory (ang. swimlanes) — pionowe pasy przypisane do konkretnych osób, ról albo systemów. Wtedy od razu widać, kto wykonuje którą czynność.

6

Testowanie oprogramowania i TDD

Poziomy testów układają się od najmniejszego fragmentu do całego systemu u klienta. Egzamin pyta najczęściej o to, kto wykonuje dany poziom testów i co dokładnie sprawdza.

Poziomy testów
PoziomCo sprawdzaKto wykonujePrzykład
Jednostkowepojedynczą funkcję, metodę lub klasę w izolacjiprogramistafunkcja obliczBrutto(100, 23) zwraca 123
Integracyjnewspółpracę modułów i poprawność interfejsów między nimiprogramista lub testermoduł koszyka poprawnie zapisuje zamówienie w bazie danych
Systemowecały system jako całość, zgodność ze specyfikacją, także wydajność i bezpieczeństwozespół testerówpełna ścieżka: rejestracja, zakup, płatność, faktura
Akceptacyjneczy system spełnia oczekiwania zamawiającegoklient / użytkownik końcowyodbiór systemu przez zamawiającego przed podpisaniem protokołu
Regresyjneczy nowa zmiana nie zepsuła tego, co wcześniej działałozwykle automat (CI)po poprawce w module płatności uruchamiamy cały zestaw starych testów
Czarna skrzynka

Tester nie zna kodu. Podaje dane wejściowe i sprawdza wyjście względem specyfikacji. Typowe techniki: klasy równoważności i wartości brzegowe. Dla pola „wiek od 18 do 65" sprawdzasz 17, 18, 65 i 66 — błędy najczęściej siedzą właśnie na granicach.

Biała skrzynka

Tester widzi kod i projektuje przypadki tak, aby przejść wszystkie instrukcje, gałęzie warunków i ścieżki. Miarą jest pokrycie kodu (code coverage) w procentach. Odmiana pośrednia to szara skrzynka — częściowa znajomość wnętrza.

TDD — najpierw test, potem kod

TDD (Test Driven Development) odwraca zwykłą kolejność: najpierw piszesz test, który musi się nie powieść, a dopiero potem kod, który go zaliczy. Cykl nazywa się „red — green — refactor".

1. RED       napisz test dla nieistniejacej jeszcze funkcji
           -> test NIE przechodzi (na czerwono)

2. GREEN     napisz NAJPROSTSZY kod, ktory zalicza test
           -> test przechodzi (na zielono)

3. REFACTOR  popraw strukture kodu (nazwy, powtorzenia),
           nie zmieniajac zachowania
           -> testy nadal przechodza

 -> wroc do punktu 1 dla kolejnej funkcji


Przyklad testu jednostkowego (skladnia w stylu PHPUnit):

class KalkulatorTest extends TestCase
{
  public function testDodawanie()
  {
      $k = new Kalkulator();
      $this->assertEquals(7, $k->dodaj(3, 4));
  }

  public function testDzieleniePrzezZero()
  {
      $this->expectException(DivisionByZeroError::class);
      (new Kalkulator())->podziel(5, 0);
  }
}

Korzyści TDD: kod od początku ma komplet testów, łatwiej o refaktoryzację, a wymagania są doprecyzowane, zanim powstanie implementacja. Koszt: wolniejszy start i konieczność utrzymywania testów razem z kodem.

7

Dokumentacja i kontrola wersji (git)

Dokumentacja dzieli się na trzy rodzaje, a system kontroli wersji jest dziś standardowym narzędziem pracy zespołowej. Egzamin pyta o znaczenie podstawowych pojęć gita i o to, po co w ogóle repozytorium.

Dokumentacja użytkownika

Instrukcja obsługi, opis funkcji krok po kroku, zrzuty ekranu, FAQ. Pisana językiem nietechnicznym, dla osoby, która ma tylko używać programu.

Dokumentacja techniczna

Architektura, diagramy UML, schemat bazy danych, opis API, komentarze w kodzie i dokumentacja generowana z nich (np. narzędziami typu phpDocumentor czy Javadoc). Dla programisty utrzymującego system.

Dokumentacja wdrożeniowa

Wymagania sprzętowe i systemowe, procedura instalacji, konfiguracja serwera, kopie zapasowe, procedura aktualizacji. Dla administratora.

Po co system kontroli wersji
  • Pełna historia zmian — wiadomo, kto, kiedy i co zmienił w każdej linii kodu.
  • Możliwość cofnięcia się do dowolnej wcześniejszej, działającej wersji.
  • Praca równoległa wielu osób na tym samym projekcie bez nadpisywania cudzych plików.
  • Rozwijanie nowych funkcji na gałęziach, bez psucia wersji produkcyjnej.
  • Kopia repozytorium na serwerze (GitHub, GitLab) to jednocześnie zapasowa kopia projektu.

Git jest systemem rozproszonym — każdy programista ma pełną kopię repozytorium z całą historią i może pracować offline. Starsze systemy scentralizowane (np. SVN) trzymały historię wyłącznie na serwerze.

Pojęcia i polecenia, które trzeba znać
REPOZYTORIUM  katalog projektu wraz z pelna historia zmian (folder .git)
COMMIT        zatwierdzona migawka zmian; ma autora, date, opis i skrot SHA
BRANCH        galaz - rownolegla linia rozwoju, np. na jedna nowa funkcje
MERGE         scalenie galezi z powrotem do glownej linii (main / master)
KONFLIKT      dwie osoby zmienily te sama linie - git nie wie, ktora zostawic;
            czlowiek musi recznie wybrac i zatwierdzic wynik

git init                     utworzenie nowego repozytorium
git clone <adres>            pobranie repozytorium zdalnego
git status                   co zostalo zmienione
git add plik.php             dodanie pliku do poczekalni (staging)
git commit -m "opis zmiany"  zatwierdzenie zmian z opisem
git log --oneline            historia commitow
git branch nowa-funkcja      utworzenie galezi
git checkout nowa-funkcja    przelaczenie sie na galaz
git merge nowa-funkcja       scalenie galezi do biezacej
git push                     wyslanie commitow na serwer
git pull                     pobranie zmian z serwera
                       galaz "logowanie"
                        o---o---o
                       /         \   merge
main:  o---o---o---o--o-----------o---o--->
       A   B   C   D               scalenie

Kazde "o" to jeden commit. Praca nad nowa funkcja odbywa sie
na osobnej galezi, wiec main przez caly czas pozostaje sprawny.

8

Wzorce projektowe

Wzorzec projektowy to sprawdzony schemat rozwiązania powtarzalnego problemu projektowego — nie gotowy kod, tylko sposób ułożenia klas. W INF.04 wystarczy znać kilka najpopularniejszych i umieć powiedzieć, jaki problem rozwiązuje każdy z nich.

Singleton (kreacyjny)

Problem: w programie ma istnieć dokładnie jeden obiekt danej klasy — jedno połączenie z bazą danych, jeden obiekt konfiguracji, jeden rejestrator zdarzeń. Gdy każdy moduł tworzy własny obiekt, otwierasz dziesiątki połączeń i marnujesz zasoby.



Rozwiązanie: konstruktor staje się prywatny, więc nikt z zewnątrz nie zrobi „new". Klasa udostępnia statyczną metodę, która przy pierwszym wywołaniu tworzy obiekt, a przy każdym kolejnym zwraca ten sam.

class Baza
{
  private static $instancja = null;
  private $polaczenie;

  private function __construct()          // konstruktor PRYWATNY
  {
      $this->polaczenie = new PDO("mysql:host=localhost;dbname=sklep",
                                  "user", "haslo");
  }

  public static function getInstancja(): Baza
  {
      if (self::$instancja === null) {
          self::$instancja = new Baza();   // tworzone raz
      }
      return self::$instancja;             // potem zawsze to samo
  }
}

$a = Baza::getInstancja();
$b = Baza::getInstancja();     // $a i $b to DOKLADNIE ten sam obiekt
MVC (architektoniczny)

Problem: w jednym pliku mieszają się zapytania SQL, HTML i logika sterująca. Zmiana wyglądu strony wymaga grzebania w zapytaniach, a zmiana bazy — w kodzie widoku. Nie da się tego testować ani rozwijać w zespole.



Rozwiązanie: podział na trzy warstwy o rozdzielonych odpowiedzialnościach. Model — dane i logika biznesowa, dostęp do bazy. Widok — prezentacja, szablon HTML. Kontroler — przyjmuje żądanie użytkownika, prosi model o dane i wybiera widok. Na tym wzorcu opierają się frameworki webowe (Laravel, Symfony, ASP.NET MVC).

   UZYTKOWNIK
     |  1. zadanie: GET /produkty?kategoria=laptopy
     v
+--------------+   2. pobierz dane   +-----------------+
|  KONTROLER   |-------------------->|      MODEL      |
|              |<--------------------|  (baza, logika) |
+--------------+   3. lista obiektow +-----------------+
     |
     |  4. przekaz dane do szablonu
     v
+--------------+
|    WIDOK     |  5. gotowy HTML -> przegladarka
+--------------+

Zasada: WIDOK nie odpytuje bazy, MODEL nie generuje HTML-a.
Wymiana szablonu nie dotyka logiki, wymiana bazy nie dotyka szablonu.
Observer — obserwator (behawioralny)

Problem: gdy zmienia się stan jednego obiektu, kilka innych musi na to zareagować — po złożeniu zamówienia trzeba wysłać e-mail, zapisać log i zaktualizować stan magazynu. Wpisanie tych wywołań na sztywno w klasę Zamówienie oznacza, że przy każdej nowej reakcji trzeba ją modyfikować.



Rozwiązanie: obiekt obserwowany (subject) trzyma listę obserwatorów i przy zmianie stanu powiadamia wszystkich jedną pętlą. Dodanie nowej reakcji to dopisanie obserwatora — bez zmiany klasy obserwowanej. Ten sam mechanizm stoi za obsługą zdarzeń w JavaScripcie (metoda addEventListener).

interface Obserwator {
  public function aktualizuj($zamowienie);
}

class Zamowienie                      // obiekt obserwowany
{
  private $obserwatorzy = [];

  public function dodajObserwatora(Obserwator $o)
  {
      $this->obserwatorzy[] = $o;
  }

  public function zloz()
  {
      // ... zapis zamowienia ...
      foreach ($this->obserwatorzy as $o) {
          $o->aktualizuj($this);     // powiadomienie WSZYSTKICH
      }
  }
}

class WysylkaMaila implements Obserwator { /* wysyla potwierdzenie */ }
class Magazyn      implements Obserwator { /* zdejmuje towar ze stanu */ }
class Logger       implements Obserwator { /* zapisuje wpis do logu */ }
Factory — fabryka (kreacyjny)

Problem: w wielu miejscach programu decydujesz na podstawie parametru, jaki obiekt utworzyć — płatność kartą, przelewem albo BLIK-iem. Rozsiane po kodzie instrukcje warunkowe z „new" trzeba poprawiać w każdym miejscu, gdy dochodzi nowa metoda płatności.



Rozwiązanie: tworzenie obiektów przenosisz do jednej klasy fabryki. Reszta programu prosi fabrykę o obiekt i posługuje się wyłącznie wspólnym interfejsem, nie wiedząc, która konkretna klasa powstała. Nowa metoda płatności to nowa klasa i jedna linia w fabryce.

interface Platnosc {
  public function zaplac(float $kwota): bool;
}

class PlatnoscKarta   implements Platnosc { /* ... */ }
class PlatnoscPrzelew implements Platnosc { /* ... */ }
class PlatnoscBlik    implements Platnosc { /* ... */ }

class FabrykaPlatnosci
{
  public static function utworz(string $typ): Platnosc
  {
      switch ($typ) {
          case "karta":   return new PlatnoscKarta();
          case "przelew": return new PlatnoscPrzelew();
          case "blik":    return new PlatnoscBlik();
          default: throw new InvalidArgumentException("Nieznany typ");
      }
  }
}

// reszta programu nie wie, ktora klasa powstala:
$p = FabrykaPlatnosci::utworz($wyborUzytkownika);
$p->zaplac(199.00);

Podział wzorców — jedno zdanie na kategorię

Kreacyjne odpowiadają za tworzenie obiektów (Singleton, Factory, Builder, Prototype). Strukturalne układają klasy w większe całości (Adapter, Dekorator, Fasada, Kompozyt). Behawioralne opisują komunikację między obiektami (Observer, Strategia, Iterator, Komenda). MVC bywa opisywany osobno jako wzorzec architektoniczny, bo dotyczy struktury całej aplikacji, a nie kilku klas.

Najczęstsze pułapki egzaminacyjne
  • Agregacja i kompozycja rysowane tym samym rombem. Pusty romb — część przeżyje całość (Playlista i Utwór). Wypełniony romb — część ginie z całością (Faktura i jej pozycja). Romb zawsze przy klasie będącej całością.
  • Mylenie include z extend. „Include" to zależność obowiązkowa (zawsze wykonywana), „extend" opcjonalna (czasem rozszerza). Strzałki biegną w przeciwnych kierunkach.
  • Scrum Master traktowany jak kierownik projektu. Nie przydziela zadań i nie rozlicza ludzi — pilnuje zasad Scruma i usuwa przeszkody. Kolejność zadań ustala Product Owner, sposób wykonania — zespół.
  • Przegląd sprintu mylony z retrospektywą. Przegląd = produkt (z klientem), retrospektywa = sposób pracy zespołu.
  • Testy akceptacyjne przypisane programiście. Wykonuje je zamawiający lub użytkownik końcowy. Programista robi testy jednostkowe.
  • Czarna skrzynka pomylona z białą. Czarna — bez znajomości kodu, sprawdzasz wejście i wyjście. Biała — z kodem przed oczami, liczy się pokrycie ścieżek.
  • Wymaganie „system ma być bezpieczny" jako funkcjonalne. To cecha jakościowa, czyli wymaganie niefunkcjonalne, podobnie jak czas odpowiedzi czy dostępność.
  • Model spiralny mylony z iteracyjnym. Oba są cykliczne, ale wyróżnikiem spirali jest jawna analiza ryzyka w każdym obiegu.
Sprawdź, ile z tego zostało w głowie

Ten dział zdaje się na rozróżnieniach: romb pusty czy wypełniony, include czy extend, przegląd czy retrospektywa. Rozwiąż test i sprawdź, które pary nadal ci się zlewają.