Procesy rozwoju standardu aplikacji¶
Rozwój aplikacji Sente Teneum dzielimy na następujące ścieżki rozwojowe:
-
Rozwój starych funkcjonalności. Funkcjonalności "stare", to takie, których kod znajduje się głównie w bazie i w c++, które chcemy aby były rozwijane i poprawiane na wersji standardowej, a więc były dostępne w kolejnych wersjach demo i na przyszłe wdrożenia u nowych klientów. Rezultaty takiego rozwoju możemy dystrybuować do klientów startujących od wersji Teneum 5.4. Przykładem projektu zwykłego jest np. standaryzacja WMS-a, rozwój HID-a, itp.
-
Rozwój projektów przeznaczonych do szybkiej aktualizacji (FK, PER). Projekty przeznaczone do szybkiej aktualizacji to takie, które w krótkim czasie chcemy dystrybuować do dużej ilości klientów, nawet tych którzy pracują na starszych wersjach aplikacji. Przykładem są tu wszelkie zmiany prawne (JPK, e-deklaracje, Split Payment, Biała Lista, itp.) W zasadzie wszelkie zmiany w obszarach FK i Personel można traktować jako przeznaczone do szybkiej aktualizacji u klientów. W innych obszarach będą to raczej wyjątkowe, wybrane zmiany (np. Obowiązkowy Split Payment w obszarze HiD).
-
Rozwój nowych projektów. Projekty nowe to takie, które są w całości napisane w Neosie, a ich struktury bazodanowe są w pełni odseparowane od reszty bazy danych. Ich rozwój jest podobny do projektów zwykłych, przy czym cały kod źródłowy tych projektów jest w pełni zawarty w osobnym folderze ze źródłami. Przykładem nowego projektu są: WORKFLOW i faktury kosztowe (WFFA). Ich projekty neosowe oraz źródła bazodanowe są w całości w folderach "standard/WORKFLOW" i "standard/WFFA". Projekty te nie wymagają żadnych zmian w plikach dbi, rpt, c++, itp. Dzięki odseparowaniu źródeł tych projektów od reszty systemu, ich aktualizacja u klientów jest w miarę łatwa.
-
Rozwój technologii. Jest to rozwój samego neosa, bibliotek klienckich (sdas, neos3) oraz elementów bazodanowych związanych z technologią. Elementy te są dystrybuowane za pomocą tzw. migracji bazodanowych zaszytych w neosie.
Zasady wspólne dla wszystkich ścieżek rozwoju¶
-
Stosujemy spójne zasady nazewnictwa struktur w bazie danych i w neosie, a także standardy do tworzenia interfejsów użytkownika:
b. zasady nazewnictwa struktur w bazie danych
d. nazewnictwo struktur nawet w c# powinno być prefiksowane (np. struktura Package)
-
Dodajemy tylko nowe transferówki, gdyż każdą tylko raz się wgrywa do klienta. W transferówkach nie insertujemy nic do s_appini, bo od tego mamy pliki json. Jedynie usuwanie sekcji z s_appini trzeba napisać jako delete w transferówce.
-
Jeśli stara transferówka wymaga poprawy, to ją poprawiamy i backportujemy do wersji, w której wyszedł oryginał. Jeśli ona mogła już być wgrana do jakichś klientów, to należy niezależnie w nowej wersji zrobić kolejną transferówkę, która poprawi / uzupełni, to czego poprzednia transferówka nie zrobiła lub zrobiła źle. Dzięki temu wgranie kolejnej aktualizacji naprawi dane. Możemy też poprawić starą transferówkę, w sytuacji, gdy jest już bezzasadna, w wyniku późniejszych modyfikacji (np. usunięto kolumnę, którą tamta transferówka uzupełniała).
-
Transferówki piszemy tak, aby można je było bezpiecznie wywoływać wiele razy. Proces automatyczny wgrywa tylko raz, ale ręczne wywołanie transferówki nie jest odnotowane w bazie, więc może się zdarzyć, że ktoś ją wgra kilka razy.. W szczególności nadawanie wartości domyślnych polom powinno je nadawać, tylko wtedy jeśli te pola mają wartość NULL.
-
Rozwój wstążki robimy tylko na poziomie developera - nie na poziomie admina. Jednocześnie należy rozwijać elementy we wstążce starej i neosowej.
-
Staramy się nie usuwać żadnych struktur z BD, zwłaszcza pól i tabel. Po prostu przestańmy używać struktur, które już nie są nam potrzebne. Usuwanie struktur danych, psuje zwłaszcza plik esystem.h i czasami nie da się skompilować aplikacji po aktualizacji.
-
Jeśli musimy zmienić domenę istniejącego pola, to zmieniamy ją tylko tak, w jaki sposób pozwala sam Firebird. Np okazuje się, że zmiany z NUMERIC(14,2) na NUMERIC(14,4) Firebird nie chce przyjąć.
Zasady rozwoju nowych modułów¶
-
Opieramy się na neosie minimum 6.0.
-
Nowy moduł powinien mieć swój symbol, znaleźć swoje miejsce w schemacie i mieć ustaloną z góry zależność od innych modułów. Aby rozstrzygnąć czy dana funkcjonalność mieści się w ramach któregoś z obecnych modułów, czy wymaga dodania nowego modułu, należy zgłosić się do głównego architekta Teneum.
-
Wszystkie struktury BD mają własny prefiks, który nie występuje obecnie w BD. Do tych struktur powinien być na gicie osobny folder z plikiem shfilter.txt
-
Nie piszemy triggerów lub tylko triggery before (blankujące dane), żadnej większej logiki na triggerach.
-
Kod logiki jeszcze piszemy w procedurach SQL w BD póki nie ma Neosa 6.0, procedury powinny być niezależne od globalparamsów, zmiennych kontekstowych, itp - wszystko przekazywane w parametrach do procedury.
-
Do takiej procedury SQL zaleca się stworzyć metodę logiki biznesowej, aby jak najmniej razy wywoływać RunProcedure. W oknach neosowych należy wołać metody logiki.
-
Należy wyodrębnić fasadę modułu i jej metody, aby ludzie po nas wiedzieli jak korzystać z modułu, który napisaliśmy. Minimum stanowi fasada SQL w bazie danych, aby nikt z innego modułu nie musiał grzebać bezpośrednio w strukturach danych modułu, który tworzymy.
-
Okna robimy tylko w neosie, moduł ma własny projekt neosowy.
-
Zaleca się pełną niezależność od struktur danych innych modułów, chyba że jawnie uznamy, że musimy/chcemy czytać struktury danych innego modułu, którego niniejszy moduł jest rozszerzeniem. Najlepiej czytać dane innego modułu przez jego fasadę.
-
Komunikujmy się z innymi modułami (ale tylko tymi które wyróżniliśmy w zależnościach) poprzez ich fasady, a jeśli ich nie mają to przynajmniej nie czytajmy ich tabel bezpośrednio, tylko róbmy sobie ich pseudo-fasady w SQL (widoki, procedury).
-
Jeśli coś w naszym module się wydarzyło, zmieniło stan, to zgłaszajmy zdarzenia na szynę EDA. Może ktoś w przyszłości będzie chciał z tych zdarzeń skorzystać.
-
Akcje do wstążki tylko w neosie. Nie róbmy już akcji we wstążce w s_appini.
Jak rozwijać funkcjonalności przeznaczone do szybkiej aktualizacji u klientów (rozwój FK)?¶
Ten punkt dotyczy rozwoju funkcjonalnego w tym zakresie, który ma być wgrywany do wszystkich klientów, włącznie ze starymi klientami. Chodzi tu o cały rozwój FK oraz o taki zakres innych modułów, które chcemy wgrywać klientom razem z rozwojem FK. Taki rozwój powinien być prowadzony z uwzględnieniem następujących zasad:
-
Powinny zawsze być rozwijane na osobnym branchu per sprint, który to branch jest odbijany od gałęzi master.
-
Na tym branchu powinien być rozwijany tylko ten sprint, nie powinny tam trafiać inne tematy, które mają wejść tylko na standard i nie są przeznaczone do szybkiej aktualizacji u klientów
-
Podczas odbijania brancha do sprintu należy zarejestrować go w rejestrze aktualizacji. Uzupełniamy kolumny od A do F.
-
Sprint może dotyczyć albo pakietu drobnych poprawek, albo jednego dużego projektu rozwojowego. Jeśli do zrobienia są dwa osobne duże projekty, to powinny być rozwijane na dwóch osobnych branchach sprintowych. Chyba, że są bardzo mocno powiązane merytorycznie.
-
Unikajmy refaktoryzacji kodu całych procedur, jeśli potrzebujemy dodać tylko jedną linijkę kodu. Im więcej kodu się zmienia, tym trudniej zmergować rozwój ze zmianami indywidualnymi klienta.
-
Unikajmy dodawania nowego kodu w triggerach wspólnych dla wielu modułów (np. NAGFAK_AU0). Zamiast tego zróbmy trigger specyficzny np dla modułu FK, jeśli to on jest właśnie rozwijany. Łatwiej do starych klientów wgrywać trigger, który ma jedynie zmiany FK.
-
Elementy neosowe rozwijamy w trybie zgodności z wersją 4.6. Chodzi o to aby obiekty biznesowe były starego typu i kompilowały się na wersjach Neosa: 4.3.5, 4.6, 5.0 i nowszych. Pamiętamy o właściwych uprawnieniach do projektów neosowych (albo role publiczne w powstających projektach, albo elementy muszą być przypisane do jakichś modułów).
-
Staramy się nie modyfikować okien c++ wspólnych dla innych modułów, bo utrudnia to przygotowanie zmian izolowanych. Jeśli takie zmiany są konieczne, to trudno. Ale można np zamiast modyfikować na potrzeby FK okna edycji faktury, dodać przycisk na oknie listy faktur, którzy otworzy specyficzne małe okienko z danymi księgowymi faktury. Takie osobne okienko łatwiej rozwijać, wyemitować i wgrać do starych klientów, bez ruszania okna edycji faktury.
-
Jeśli pojawi się potrzeba poprawienia starej transferówki lub zrobienia innej poprawki w już zakończonym sprincie, to należy zmiany docomimtować do tego brancha sprintowego, w którym te zmiany były wykonywane a następnie ponowić proces przygotowania zmian izolowanych dla tego sprintu.
Proces kończenia sprintu jest wykonywany przez rolę GitMastera i odbywa się wg następujących kroków:
-
Ustalenie który w kolejności będzie ten projekt w rejestrze aktualizacji. Kolejność powinna być ściśle określona przez proces kończenia projektu. Projekty zakończone wcześniej muszą mieć wcześniejsze pozycje w rejestrze niż projekty zakończone później
-
Jeśli kolejność została ustalona, to upewniamy się, czy na branchu master, wszystkie wcześniejsze projekty są w pełni zmergowane
-
Robimy rebase brancha projektu branchem master, aby branch projektu zawierał tylko te zmiany, które wynikają z samych prac w tym projekcie. Rebase może wymagać rozwiązania konfliktów. Rozwiązanie konfliktów jest konieczne, aby wszelkie zmiany, które ten projekt wnosi do standardu były rzeczywiście czystymi zmianami tego projektu względem uspójnionej wersji źródeł zawierających wszystkie wcześniej zakończone projekty
-
Proces odbiorów i testów każdy zespół rozwojowy ustala samodzielnie i nie jest to przedmiotem niniejszej instrukcji.
-
Po odbiorze branch projektu należy domergować do gałęzi master i poprosić rolę GitMastera aby wygenerował tzw. zmiany izolowane (specjalny commit, który zawiera wszelkie zmiany całego projektu i może być łatwo przenoszony do aplikacji klientów)
-
W razie potrzeby projekt należy także domergować do gałęzi konkretnej wersji, jeśli projekt ma zostać dodany do utworzonej już wersji (np. branch 5.3, 5.4, itp).
-
Niezwłocznie po mergu należy zaktualizować rejestr aktualizacji (stan, data zakończenia, emisja w wersji) i ew. skorygować finalną kolejność tego projektu w rejestrze aktualizacji.
-
Po zakończeniu nie wolno już nic dodawać do brancha projektowego. Jeśli trzeba koniecznie coś dodać / poprawić, to trzeba powiadomić o tym rolę GitMastera, gdyż proces generowania zmian izolowanych trzeba powtórzyć.
-
Nie wolno robić żadnych hotfixów na masterze, ewentualne poprawki powinny wyjść w kolejnym branchu projektowym - także przeznaczonym do szybkiej aktualizacji.
Każdy projekt powinien działać w sposób kompletny i spójny. Oznacza to, że nie powinniśmy emitować projektów, których nie należy wgrywać do klientów, gdyż aby działały poprawnie będą wymagały jeszcze późniejszych zmian lub wgrania jednocześnie kolejnych projektów. Zatem jeśli do ukończonego projektu są niezbędne poprawki, to należy szybko podjąć decyzję, czy domergowujemy poprawki do tego samego projektu i ponownie wykonujemy kroki procesu kończenia projektu (m.in. ponowne wygenerowanie zmian izolowanych), czy wycofujemy w całości projekt z emisji. Jeśli natomiast projekt może być do klienta wgrany w takiej postaci, w jakiej jest, ale chcemy go w przyszłości rozszerzyć lub uzupełnić pewne niedociągnięcia, należy to zrobić w ramach osobnego projektu, który także będzie projektem przeznaczonym do szybkiej aktualizacji.
Bezpośrednio po zakończeniu projektu rozwojowego, rola GitMastera jest odpowiedzialna za utworzenie zmian izolowanych i przeprowadzenie testowej aktualizacji, a zespół odpowiedzialny za rozwój tego projektu powinien się upewnić, że stan testowej aplikacji po aktualizacji jest poprawny. Do tych czynności wykorzystywana jest specjalna wersja aplikacji Teneum, która jest odzwierciedleniem tzw. "wersji zerowej" z naniesionymi wszystkimi aktualizacjami z rejestru aktualizacji. Wersja zerowa (formalnie 4.0.10), jest to stan aplikacji po wgraniu wszystkich tzw. "starych patchy" (ostatni to 150804 wyemitowany w październiku 2015) oraz naniesieniu tzw. "skryptów pomostowych". Gdybyśmy mieli klienta, który działa na aplikacji, w której nigdy nie wykonano żadnej modyfikacji indywidualnej, to aplikacja ta powinna być identyczna z wersją zerową, do której wgrano wszystkie aktualizacje z rejestru aktualizacji. Kompletne źródła takiej aplikacji znajdują się na gicie na branchu "wersja_zero_plus_aktualizacje". Proces utworzenia zmian izolowanych składa się z następujących kroków:
-
Zidentyfikowanie SHA wszystkich commitów mergujących zmiany z brancha rozwojowego do mastera. Zwykle jest to jeden commit, ale zdarza się kilka.
-
Upewnienie się, że branch "wersja_zero_plus_aktualizacje", zawiera wszystkie poprzednie projekty z rejestru aktualizacji. Jeśli nie, to najpierw należy przeprowadzić niniejszy proces dla poprzednich projektów.
-
Należy nanieść w/w commity na brancha "wersja_zero_plus_aktualizacje" wykonując polecenie "git cherry-pick -m 1 <SHA>". Mogą pojawić się konflikty, gdyż rozwój prowadzony jest na wersji zawierającej wszystkie zmiany rozwojowe, a nanosimy go na wersję aplikacji zawierającą jedynie wszystkie wcześniejsze projekty przeznaczone do szybkiej aktualizacji. Część plików, które są rozwijane w wielu projektach, ma inną postać (np esystem.dbi, esystem.rpt). Po każdym cherry-picku należy rozwiązać konflikty, uważając aby przypadkiem nie zgarnąć za dużo zmian, zwłaszcza w tych wspólnych plikach.
-
Należy użyć SH aby procesem pełnej aktualizacji zaktualizować dotychczasową bazę "zerową" o tą aktualizację. Należy się upewnić, że proces aktualizacji przechodzi bezbłędnie, a źródła się kompilują. Jeśli jest jakiś problem, należy wyjaśnić go z zespołem, który rozwijał projekt, nanieść poprawki i ponowić powyższe kroki.
-
Wyeksportowanie całej bazy po aktualizacji aby mieć pewność że postać wszystkich plików jest identyczna do postaci jaką mamy z eksportu bazy. Jeśli są różnice to je wyjaśnić, ewentualnie zacommitować i zesquashować z poprzednim commitem.
-
Zrobić też gbak i odgbak bazy po aktualizacji.
-
Zbudować środowisko testowe z brancha wersja_zero_plus_aktualizacje, aby zespół, który rozwija aplikację zrobił ponowne testy - zwłaszcza tych elementów, które wygenerowały konflikty w punkcie 2, a więc mają nieco inną postać niż na standardzie. Takim elementem będzie np okno edittowary.cpp/dfm/h.
-
Ostatni commit na branchu wersja_zero_plus_aktualizacje jest oficjalnym commitem zmian izolowanych.
-
Następnie cherrypickujemy ostatni commit na branchu wersja_zero_plus_aktualizacje do brancha wersja_zero_plus_hipersquash i squashujemy, dzięki temu mamy aktualnego hipersquasha.
-
Testowo robimy aktualizację wersji zero hipersquashem, aby sprawdzić czy taka opcja też przechodzi i transferówki przejdą.