Azure Boards to narzędzie pozwalające planować pracę podobnie jak w Kanban. Boards może być połączony także z GitHub. Zwykle praca jest dzielona co najmniej na 3 etapy: „to do”, „in progres” i „done”. Zadania dodatkowo klasyfikuje się do odpowiedniej kategorii, jak np. „bug”.
Zadania są zdefiniowane raz, ale mogą być wyświetlane z punktu widzenia jednego użytkownika, całej firmy albo jednego repozytorium. Zdefiniowane zadania mogą być aktualizowane w mniej lub bardziej automatyczny sposób przy pomocy szablonów. Dobra klasyfikacja zadań pozwala w kolejnym kroku na dobre raportowanie, a to z kolei pozwala na ustalenie czy są osiągane KPI.
Azure Board może być połączone z kontem GitHub pozwalając prezentować na Azure Boards postęp prac nad projektem publikowanym na GitHub.
Odpowiednikiem Azure Board na GitHub jest Git Project Board. Cel obu tych narzędzi jest podobny – śledzenie postępu prac nad projektem programistycznym.
Zmiany wprowadzane przez programistów powinny koniec końców zostać opublikowane w postaci kodu. Ten kod jest umieszczany w systemie kontroli wersji, którym może być Azure Boards lub GitHub. Co warto zauważyć można korzystać z Azure Boards, ale swój kod publikować na GitHub. W systemie kontroli wersji zachowywana jest cała historia wykonywanych zmian przez wszystkich programistów. Dzięki temu można w dowolnej chwili sprawdzić stan określonej linii kodu w dowolnym pliku. W razie potrzeby można więc wrócić do wcześniejszej wersji.
Dobrą praktyką w tworzeniu kodu jest:
Tworzenie małych zmian
Publikowaniw tylko plików, które budują projekt (żadnych plików personalnych)
Częsta aktualizacja kodu (push/pull)
Weryfikacja kodu przed wyslaniem do repozytorium
Czytanie (!!!) komunikatów zwracanych przez git
Łączenie wykonywanych zmian z przypisanymi zadaniami (Azure Boards)
Współpraca – niezależnie od pozycji w zespole
Kod źródłowy jest utrzymywany w centralnej lokalizacji i wykorzystywany przez wielu programistów jednocześnie. Z drugiej strony kod przechowywany może być w postaci dystrybuowanej. Dystrybucja polega na tym, że cały kod aplikacji jest w pierwszej kolejności ściągany lokalnie na komputer użytkownika i tam programista zarządza kodem tworząc np. nowe branch, czy commitując swoje zmiany. Dopiero w pewnym momencie wysyła te zmiany do centralnej lokalizacji, którą jest GitHub Repo lub Azure Repo.
Każdy projekt zaczyna się tak samo: od potrzeby klienta. Sama potrzeba jest zwykle na początku bardzo słabo opisana. Dzięki pracy architekta można jednak zdefiniować wymagania klienta, które da się przenieść do postaci funkcjonalności aplikacji, tzw. functional & non-functional requirements.
W oparciu o requirements i dokładniej opisane rozwiązanie (Low Level Design), do pracy przystępują programiści. Właściwie to właśnie w tym miejscu najczęściej zaczynamy dostrzegać różnice w rónych sposobach podejścia do tematu.
W Waterfall, programiści zbudują w oparciu o wymagania aplikacje, która zostanie przekazana do klienta. Jeśli po drodze czy to architekt, czy programista popełnił błąd, to na tym etapie będzie go trudno odkręcić. Na dodatek żadne zmiany w requirements na tym etapie nie są dopuszczalne.
Co innego w Agile. Tutaj programiści będą skupiać się na małych zadaniach, które są stale dostarczane do klienta. Klient może wcześnie zareagować na niepoprawne decyzje, ale co ważniejsze – również architekt może wprowadzić pewne zmiany do rozwiązania. To podejście jest zdecydowanie bardziej elastyczne. Zasady pracy w zespole Agile są spisane w postaci manifestu:
Czy Waterfall jest zawsze zły? Pewnie nie. Dobrze sprawdzi sie tam, gdzie jako twórca oprogramowania doskonale wiesz, co chcesz osiagnąć. Jeśli jednak takiej pewności nie masz, a tak chyba aktualnie jest w większości przypadków, to metoda Agile wydaje sie lepsza.
Istotna jest też budowa zespołów pracujacych nad danym rozwiązaniem. Chcociaż w DevOps uciekamy od podziału zespołów ze względu na umiejętności, to nadal jest możliwe budowanie zespołu w strukturze poziomej „horizontal”. Tak utworzone zespoły mogą wspierać i budować rozwiązania w tylko ściśle określonej technologii – tylko user interface, tylko backend, tylko bazy danych. Wydaje sie jednak, że organizacja w strukturze pionowej „vertical” lepiej sprawdza się w modelu DevOps. Jeden zespół będzie tu odpowiadał za całą pracę jednej wybranej aplikacji od A do Z, od interfejsu użytkownika po backend i bazę danych.
Struktura horizontal będzie częściej wybierana przez organizaję migrującą się z modelu silosów. Do istniejących zespołów można dodać mentorów, którzy będą wpływać na zmianę modelu pracy całego zespołu oraz modyfikować blokujące ten zespół istniejące procesy.
Agile charakteryzuje się również specyficznym zestawem narzędzi, jak np. Kanban, dashboards itp.
Green Field – projekty budowane w zupełnie nowym środowisku. Te projekty wydają się prostsze, bo wszystko można zrobić „jak się chce”. Wyzwaniem w takim projekcie może być brak doświadczenia z nowymi rozwiązaniami i brak potwierdzenia sprawności danej technologii w praktyce. Dużo czasu musi być poświęcone na sprawdzenie możliwych opcji i wybór tej najlepszej.
Brown Field – projekty budowane w istniejącym środowisku z istniejącymi innymi aplikacjami, systemami, zależnościami. Ten typ projektu łączy się z często z bieżącym utrzymaniem istniejących aplikacji. Inny problem to opór stawiany przez administratorów istniejącego systemu, których głównym zadaniem jest utrzymanie aplikacji „as is”. Czasami ryzyko związane z modyfikacją istniejącego systemu jest tak duże, że zamiast pracować nad „brown project”, praca zostanie przekształcona w „green project” polegający na zbudowaniu zupełnie nowego systemu.
Oba typy projektów charakteryzują się też różnego rodzaju narzędziami pozwalającymi kontrolować, co się dzieje:
System of record – są to systemy, których głównym zadaniem jest dokładne śledzenie stanu systemu, co może być osiągnięte przez dokładne opisanie wszystkich zmian. Ten typ systemu jest ważniejszy w brown field project, bo tam trzeba pilnować tego co już jest.
System of engagement – jest budowany zazwyczaj z myślą o kliencie, pozwala priorytetyzować pracę z punktu widzenia klienta. Jest on bardziej specyficzny dla DevOps, ale nie wyklucza się z system of record. Systemy te pozwalają też zespołowi śledzić kto i za co jest odpowiedzialny.
W pracy DevOps trzeba (oczywiście) pracować z użytkownikami, których można podzielić na kilka kategorii:
Canary – użytkownicy, którzy bez powiadomienia o tym – pracują z nowymi rozwiązaniami i niestety jeśli coś jest nie tak, to praca tego człowieka jest najbardziej narażona na problemy. Ten typ użytkownika może nie wiedzieć o tym, że coś jest „na nim testowane”, całkiem jak kanarki przebywające z górnikami pod ziemią. Ich rola była brutalna – jeśli ulatniał się gaz, kanarek umierał pierwszy ostrzegając w ten sposób górników
Early adopter – użytkownicy, którzy na ochotnika świadomie zgadzają się na testowanie oprogramowania.
Użytkownicy (standardowi) – uzyskują dostęp do aplikacji na koniec, kiedy dana funkcjonalność jest już przetestowana przez canary i early adopters.
Nie stronimy też od pomiaru postępu projektu poprzez KPI. Pozwalają one śledzić, jak dobrze, albo jak źle jest realizowana dana usługa, albo dane rozwiązanie. Część z KPI będzie powiązana z wartościami wyliczanymi, ale inne mogą pochodzić z subiektywnej oceny użytkownika. Zwykle ocenie podlega:
prędkość uzyskiwania zmian (liczba release, build itp.),
efektywność – jak np. liczba serwerów na jednego administratora, wydajność systemu,
jakość i bezpieczeństwo – ile razy coś się nie udało, np. nie udało się dostarczenie nowej wersji aplikacji, albo aplikacja była niedostępna, ile luk (bug) w oprogramowaniu zostało znalezionych, jakie jest pokrycie kodu przez testy, czy SLA jest osiągnięte, ile czasu zajmuje rozwiązanie incydentu,
kultura – czy programiści są zadowoleni ze swojej pracy, czy odchodzą z firmy itp.
DevOps – może mieć różne definicje, bo jest różnie rozumiany. Zwykle rozumiemy przez niego połączenie pracy człowieka, procesów i produktów, które umożliwiają dostarczanie wartości klientowi w procesie Continous Delivery. Czasami łatwiej jest powiedzieć, co nie jest DevOps. Przykładami takich czynności są tworzenie dokumentacji, modyfikacja ustawień firewall. Te czynności nie przynoszą klientowi bezpośrednich korzyści. Co innego utworzenie nowej funkcjonalności w aplikacji.
Observe, Orient, Decide, Act – pętla OODA – każdorazowo, przy każdej iteracji należy obserwować skutki poprzednich zmian, określać czy są one pożądane, decydować o kolejnych krokach i wykonywać je. Dzięki częstej ocenie pracy, można uniknąć błądzenia po niepoprawnych rozwiązaniach, na bieżąco korygować błędy i w efekcie szybciej dostarczyć wyniki dla klienta.
Continous Integration – proces ma na celu upewnienie się, że wprowadzone zmiany działają z innymi zmianami, wykonywanymi przez innych programistów, w tym również że są zgodne z wymogami security itp. Programista wysyłając swój kod może powodować konflikty, które powinny być szybko wykryte. Łatwiej je wykrywać, gdy często są wykonywane testy. Programista wykonuje małą zmianę, oprogramowanie jest budowane i testowane w automatyczny sposób.
Continous Delivery – Jest to implementacja logiki „Fail Fast” – jeśli coś ma się nie udać, albo ma nie dać wartości dla klienta, to lepiej jeśli zostanie to wykryte wcześniej. Zmiany wykonane w rozwiązaniu, dostarczamy klientowi tak szybko jak się da. Z jednej strony, klient nie musi długo czekać na rezultaty, z drugiej strony może szybko zareagować, jeśli coś jest nie tak.
Version Control – utrzymywanie jednego prawdziwego miejsca gdzie utrzymywany jest kod aplikacji. Ten kod może być podzielony na różne etapy pracy (branch), ale jeśli szukasz odpowiedniego miejsca skąd można pobrać kod źródłowy – idziesz tam. Version Control wspiera zachowanie historii wszystkich zmian, możliwość przeglądu wysyłanego kodu itp.
Agile – metodologia dzieląca pracę na mniejsze fragmenty „sprinty”, co pozwala na dopasowanie pracy do możliwości zespołu i śledzenie postępu
Monitoring – pozwala na zbieranie i analizę danych w Azure, która nastęnie może być wykorzystana do podejmowania dalszych decyzji w rozwoju oprogramowania, a operacyjnie pomaga w utrzymaniu dostępności usługi.
Cloud – umieszczanie usług w chmurze: prywatnej, publicznej lub hybrydowej.
IaaC – tworzenie i zarządzanie infrastruktury za pomocą kodu
Microservice – podział aplikacji na wiele małych usług, z których każda jest odpowiedzialna za niewielki fragment funkcjonalności. Jest to przeciwieństwo architektury monolitycznej
Containers – technika uruchamiania aplikacji wyizolowanej z systemu operacyjnego do postaci tzw. kontenera. Kontener powołuje się na konfigurację utworzoną wcześniej w innym kontenerze i dodaje do niego swoją warstwę funkcjonalności, np. funkcjonalności specyficznej aplikacji.
Migracja w stronę DevOps wymaga stworzenia wyspecjalizowanych zespołów, dopasowania procesów, stąd właśnie taka a nie inna definicja tego czym jest DevOps. Konflikty z istniejącymi procesami są jednak nieuniknione.
DevOps team musi definiować swoje cele, a do tego są potrzebne metryki: ile czasu spędza się na naprawie błędów, ile czasu spędza się na wykonaniu powtarzalnych czynności, ile czasu trwa stworzenie określonej funkcjonalności.
SERIAL generuje kolejne wartości, zazwyczaj używane jako identyfikator w tabelach. Np. tutaj kolumna id ma automatycznie nadawaną wartość:
CREATE TABLE t1
(id SERIAL,
name TEXT
);
a tutaj id trzeba podawać samodzielnie:
CREATE TABLE t2
(id INT,
name TEXT
);
Co zrobić, jeśli chcielibyśmy w zapytaniu SQL wykorzystać wartość, która została wygenerowana w kolejnym zapytaniu? Oto propozycja nr 1
Polecenie INSERT wstawia nowy rekord. Podczas tego wstawiania generowana jest nowa wartość id. Ta wartość jest zwracana przez klauzulę RETURNING. Żeby z tej wartości dalej skorzystać budujemy wyrażeni CTE (Common Table Expression), które wartości zwracane przez INSERT z RETURNING udostępnia w wirtualnej tablicy r. Idąc dalej można wykonać zapytanie do tabeli r, a wynik np. wykorzystać do wstawienia go do kolejnej tabeli t2:
WITH r AS
(INSERT INTO t1(name) VALUES('x323') RETURNING id, name)
INSERT INTO t2(id, name)
SELECT * FROM r;
A oto propozycja nr 2.
Polecenie insert generuje nową wartość w oparciu o sekwencję (tak właśnie działa typ SERIAL). Możemy wiec w kolejnym zapytaniu pobrać wartość z tej sekwencji poleceniem currval. Co istotne zadziała to nawet wtedy, jeśli w międzyczasie w innej sesji ktoś też wstawił rekord do tabeli t1 i wygenerował nową wartość:
INSERT INTO t1(name) VALUES('c');
SELECT * FROM t1 WHERE id = currval('t1_id_seq');
W PG Admin, po wybraniu polecenia „Restore database” pojawia się czasami komunikat o błędzie „Utility not found”
Co wtedy zrobić?
Należy w menu PGAdmin wybrać polecenie File >> Preferences
Dalej poszukaj w drzewku po lewej stronie odszukaj Paths >> Binary Paths
Teraz po prawej stronie okna, w dolnej części zatytyłowanej „PostgreSQL Binary Path” odszukaj numeru wersji, którą masz na swoim komputerze. (Uwaga – nie pomyl się. Jest tam też podobna tabelka zatytułowana „EDB Advanced Server Binary Path” – ale ta nas nie interesuje.
Teraz kliknij ikonę folderka i wskaż na katalog bin, w którym masz zainstalowany PostgreSQL. Najprawdopodobniej będzie to coś w tym stylu (uważaj zwłaszcza na numer wersji):
C:\Program Files\PostgreSQL\15\bin
Po wybraniu foldera, powyższy ekran powinien wyglądać tak:
Teraz zapisz zmiany „Save” i problem powinien być rozwiązany 🙂
A o co chodziło w tych krokach? W katalogu, który wskazaliśmy znajdują się programy narzędziowe PostgreSQL. Jeden z nich to program pg_restore, który służy do odtwarzania bazy danych. Z jakiegoś powodu ten parametr nie ustawia się automatycznie i wtedy… trzeba trochę pomóc. Teraz już wiesz co, jak i dlaczego 🙂
Od czasu do czasu dostaję pytanie o to, jak formatować napisy w Pythonie. Lubię w takim przypadku odsyłać do dokumentacji Pythona, dlatego, ku pamięci…