Architektura projektu
Goat rozdziela definicję aplikacji, szablony generatora, kod źródłowy oraz automatyzację projektu od kodu powstającego w wyniku generowania.
Generator ma przyspieszać pracę, a nie zamykać użytkownika w narzuconym modelu generowania.
Dlatego kod utworzony przez Goat pozostaje zwykłym kodem źródłowym projektu. Możesz go swobodnie edytować, rozszerzać i refaktoryzować. Generator automatyzuje przede wszystkim elementy powtarzalne, ale nie odbiera kontroli nad końcową implementacją.
W praktyce możesz łączyć dwa sposoby pracy:
- korzystać z modelu i generatora tam, gdzie oszczędza to czas i zapewnia spójność,
- edytować kod bezpośrednio tam, gdzie projekt wymaga niestandardowej logiki lub rozwiązania.
Dzięki temu Goat może wspierać projekt również po jego początkowym wygenerowaniu, zamiast wymuszać ciągłą pracę wyłącznie przez generator.
Najważniejsze elementy projektu
| Element | Przeznaczenie |
herd/_model.goat | Główna definicja aplikacji: encje, właściwości, relacje, role i inne elementy modelu. |
herd/ | Skrypty automatyzacji, migracji, testów, generowania oraz dane fixture. |
herd/gen/templates/ | Szablony określające sposób generowania kodu. |
scripts/ | Narzędzia CLI wspierające generowanie, uruchamianie skryptów i proces developerski. |
| kod źródłowy aplikacji | Ręcznie utrzymywane elementy backendu i frontendu wykorzystywane przez generator. |
| główny katalog projektu | Końcowa aplikacja po wygenerowaniu, gotowa do dalszej ręcznej pracy. |
Model aplikacji
Plik:
herd/_model.goatopisuje strukturę domeny aplikacji.
Może zawierać między innymi:
- encje,
- pola,
- typy danych,
- relacje,
- role,
- wspólne właściwości,
- informacje wykorzystywane przez backend i frontend.
Model powinien opisywać przede wszystkim intencję i strukturę aplikacji, zamiast szczegółów implementacyjnych każdego pliku.
Na jego podstawie Goat może generować spójne elementy wielu warstw systemu, na przykład:
- modele,
- DAO i repozytoria,
- DTO,
- endpointy API,
- komendy CRUD,
- migracje SQL,
- formularze,
- tabele,
- widoki administracyjne,
- elementy interfejsu użytkownika.
Największą korzyścią nie jest samo tworzenie plików, ale możliwość utrzymania spójności pomiędzy wieloma reprezentacjami tej samej encji.
Zmiana modelu może zostać przełożona jednocześnie na backend, bazę danych i frontend.
Generator kodu
Generator łączy kilka źródeł:
model aplikacji
+
szablony
+
kod źródłowy
↓
kod aplikacjiRezultatem jest kompletna aplikacja znajdująca się w głównym katalogu projektu.
Wygenerowany kod nie jest jednak traktowany jako kod tylko do odczytu.
Możesz go:
- edytować,
- rozszerzać,
- refaktoryzować,
- dostosowywać do specyficznych wymagań,
- uzupełniać o własną logikę,
- commitować razem z pozostałymi zmianami projektu.
Goat ma automatyzować pracę tam, gdzie generowanie daje realną korzyść. Nie wymusza jednak, aby każda późniejsza zmiana była wykonywana wyłącznie przez model lub szablony.
Edycja wygenerowanego kodu
Po wygenerowaniu aplikacji otrzymujesz normalny kod źródłowy, nad którym zachowujesz pełną kontrolę.
Generator może na przykład utworzyć:
- encję,
- podstawowe API,
- DAO,
- formularz,
- widok listy,
- podstawowe operacje CRUD.
Następnie możesz ręcznie dodać:
- dodatkową logikę biznesową,
- nietypową walidację,
- bardziej złożone zapytania,
- dodatkowe endpointy,
- niestandardowe akcje,
- własne komponenty interfejsu,
- integracje z zewnętrznymi systemami.
Nie każda ręczna zmiana musi zostać przeniesiona do generatora.
Jeżeli dana modyfikacja jest specyficzna dla jednego miejsca w aplikacji, często bardziej opłacalne jest zmienić kod bezpośrednio.
Jeżeli natomiast ta sama zmiana powinna obowiązywać w wielu podobnych miejscach, warto przenieść ją do modelu lub szablonu generatora.
Dobrym kryterium jest pytanie:
Czy ta zmiana opisuje specyfikę konkretnej funkcjonalności, czy regułę, która powinna być powtarzana przez generator?
Regenerowanie aplikacji
Po zmianie modelu możesz uruchomić:
goat reGenerator analizuje aktualną definicję aplikacji i wprowadza wynikające z niej zmiany.
Typowy workflow może wyglądać tak:
zmiana modelu
↓
goat re
↓
aktualizacja kodu
↓
ręczne dopracowanie
↓
git diff
↓
testyPo regeneracji warto zawsze sprawdzić:
git diffDzięki temu dokładnie widzisz, które fragmenty projektu zostały zmienione przez generator i możesz zdecydować, które zmiany powinny znaleźć się w commicie.
Git pozostaje ważnym elementem pracy z Goat: generator proponuje konkretne zmiany w kodzie, natomiast to programista kontroluje ich finalny zakres.
Model, szablon czy bezpośrednia edycja?
Goat nie narzuca jednego sposobu wprowadzania zmian.
W zależności od charakteru zadania możesz pracować na różnych poziomach.
Zmiana modelu
Jeżeli zmiana dotyczy struktury domeny, zacznij od:
herd/_model.goatPrzykłady:
- dodanie encji,
- dodanie pola,
- zmiana typu danych,
- zmiana relacji,
- dodanie roli,
- zmiana wspólnej właściwości.
W takim przypadku model jest najlepszym miejscem, ponieważ pozwala generatorowi zachować spójność pomiędzy różnymi warstwami aplikacji.
Zmiana szablonu
Jeżeli chcesz zmienić sposób generowania całej klasy podobnych elementów, odpowiednim miejscem może być:
herd/gen/templates/Przykłady:
- zmiana struktury wszystkich endpointów,
- dodanie wspólnej adnotacji,
- zmiana sposobu generowania formularzy,
- zmiana domyślnego komponentu CRUD,
- wprowadzenie nowej konwencji w generowanym kodzie.
Model określa wtedy co powinno powstać, a szablon definiuje jak ma wyglądać domyślna implementacja.
Bezpośrednia edycja kodu
Jeżeli zmiana dotyczy konkretnego przypadku i nie ma sensu rozszerzać nią generatora, możesz po prostu zmodyfikować wygenerowany kod.
Przykłady:
- specjalna reguła biznesowa,
- jednorazowy wyjątek,
- niestandardowy endpoint,
- dodatkowa integracja,
- specyficzny komponent frontendowy.
To świadoma część filozofii Goat.
Generator ma usuwać powtarzalną pracę, a nie zmuszać projekt do dopasowania się do ograniczeń generatora.
Warstwy aplikacji
main.go uruchamia rdzeń aplikacji.
Rdzeń odpowiada między innymi za:
- załadowanie konfiguracji,
- inicjalizację zależności,
- rejestrację usług,
- przygotowanie infrastruktury aplikacji,
- obsługę terminala poleceń.
Dzięki temu różne operacje korzystają z tego samego środowiska aplikacji.
Przykładowe komendy:
serve
db:migrate
crud:doc:persistnie muszą być implementowane jako osobne narzędzia.
Mogą współdzielić:
- konfigurację,
- dostęp do bazy danych,
- usługi,
- logowanie,
- mechanizmy autoryzacji,
- pozostałą infrastrukturę projektu.
Ułatwia to zarówno rozwój aplikacji, jak i tworzenie narzędzi administracyjnych oraz procesów automatyzacji.
Model domeny a generowany kod
Encje zdefiniowane w:
herd/_model.goatmogą być wykorzystywane do generowania elementów różnych warstw aplikacji.
Przykładowy przepływ:
encja
↓
model backendu
↓
DAO / repozytorium
↓
DTO
↓
API
↓
formularz
↓
widok listyPozwala to ograniczyć konieczność wielokrotnego opisywania tej samej struktury danych.
Zamiast ręcznie synchronizować kilka warstw aplikacji, podstawowe informacje mogą pochodzić ze wspólnej definicji.
Nie oznacza to jednak, że wszystkie warstwy muszą pozostać identyczne lub w pełni generowane. Każdy z wygenerowanych elementów może być dalej dostosowany do potrzeb aplikacji.
Skrypty .goat
Katalog herd/ pełni również rolę warstwy automatyzacji projektu.
Skrypty .goat mogą opisywać całe procesy developerskie, między innymi:
- uruchamianie środowiska,
- generowanie aplikacji,
- migracje,
- inicjalizację bazy danych,
- ładowanie danych fixture,
- budowanie frontendu,
- synchronizację tłumaczeń,
- uruchamianie testów.
Przykładowo:
goat run:script --path=herd/dev.goatmoże uruchomić kompletny workflow wymagany do rozpoczęcia pracy nad projektem.
Dzięki temu sposób budowania, testowania i uruchamiania aplikacji pozostaje częścią repozytorium.
Nie trzeba utrzymywać osobnego zestawu ręcznych instrukcji dla każdego systemu operacyjnego lub stanowiska developerskiego.
Izolacja wykonywania skryptów
Jednym z ważnych założeń Goat jest ograniczenie wpływu wykonywanych skryptów na system hosta.
Narzędzia wykorzystywane podczas budowania i testowania mogą być uruchamiane w izolowanym środowisku opartym o Docker.
Dotyczy to między innymi:
- Go,
- Node.js,
- npm,
- PostgreSQL,
- Playwright,
- narzędzi buildowych,
- dodatkowych zależności wymaganych przez projekt.
Pozwala to ograniczyć zależność od lokalnej konfiguracji komputera programisty oraz ujednolicić środowisko pomiędzy zespołem i CI.
Izolacja ogranicza również zakres zasobów dostępnych dla wykonywanych skryptów.
W typowym przypadku mogą one pracować na bieżącym projekcie bez swobodnego dostępu do pozostałych danych hosta.
Jest to szczególnie istotne podczas wykonywania kodu pochodzącego z zewnętrznych zależności, na przykład skryptów instalacyjnych uruchamianych przez npm install.
Architektura a praca z AI
Architektura Goat została zaprojektowana tak, aby dobrze współpracowała również z narzędziami AI.
W tradycyjnym projekcie nawet niewielka zmiana wymagania może oznaczać analizę wielu plików:
model
DTO
DAO
API
migracja
formularz
widok
frontendW projekcie opartym na Goat część takich zmian może zostać opisana znacznie wyżej:
zmiana wymagania
↓
zmiana modelu
↓
goat re
↓
aktualizacja wielu warstwAI może wtedy pracować na mniejszym kontekście i skoncentrować się na intencji zmiany, zamiast analizować całą wygenerowaną implementację.
Pozwala to:
- ograniczyć ilość kodu przekazywanego do modelu,
- zmniejszyć koszt analizy,
- skrócić czas potrzebny na zrozumienie zmiany,
- ograniczyć liczbę modyfikowanych plików,
- zmniejszyć ryzyko niespójności pomiędzy warstwami.
Jednocześnie Goat nie wymusza pracy wyłącznie na wysokim poziomie.
Jeżeli zmiana dotyczy jednego konkretnego fragmentu kodu, AI lub programista może zmodyfikować go bezpośrednio.
Daje to dwa uzupełniające się poziomy pracy:
wysokopoziomowy — zmiana modelu, konfiguracji lub szablonu i regeneracja,
niskopoziomowy — bezpośrednia edycja kodu aplikacji.
Dobór poziomu zależy od tego, który sposób jest prostszy, bardziej czytelny i tańszy w utrzymaniu.
Typowy workflow
Praca nad zmianą modelu może wyglądać następująco:
# zmień model aplikacji
vim herd/_model.goat
# wygeneruj wynikające z niego zmiany
goat re
# sprawdź rezultat
git diff
# w razie potrzeby dopracuj kod ręcznie
# uruchom testy
goat run:script --path=herd/test.goat
# sprawdź finalny zakres zmian
git statusW przypadku zmiany czysto biznesowej lub implementacyjnej regeneracja może nie być potrzebna. Możesz zmienić odpowiedni fragment kodu bezpośrednio i uruchomić testy.
Najważniejsza zasada
Goat nie próbuje być właścicielem wygenerowanego kodu.
Jego zadaniem jest wygenerowanie powtarzalnych elementów szybciej i bardziej konsekwentnie niż ręczna implementacja.
Po wygenerowaniu kod należy do projektu.
Możesz go zmieniać, rozszerzać i dostosowywać dokładnie tak, jak wymaga tego aplikacja.
Generator ma przyspieszać pracę, a nie zamykać użytkownika w swoim modelu generowania.