Spring clean architecture

Odpowiedz Nowy wątek
2019-08-10 21:10
3

Cześć,
Zacząłem ostatnio tworzyć projekt którego głównym celem jest zapoznanie się z architekturą heksagonalna, separacją logiki domenowej od frameworka (Spring) oraz poznanie biblioteki Vavr
Funkcjonalnie ma to być Internetowy dziennik treningowy, czyli układanie treningów / diety, śledzenie swoich postępów, itp. Póki co jednak nic z tego nie jest ruszone, zacząłem od modułu użytkownika który obecnie umożliwia rejestracje i potwierdzenie założenia konta.
Po stronie infrastruktury, skonfigurowane jest security na podstawie JWT oraz połączenie do MongoDB.
Obecnie siadam do frontendu (Angular) i bardzo zależałoby mi na review tego co obecnie napisałem.

https://gitlab.com/angryprogrammer01/springcleanarchitecture

Pozostało 580 znaków

2019-08-13 20:01
1

Wygląda to naprawdę nieźle! :) z plusów:

  1. klasy package scope
  2. podział na pakiety per feature
  3. zastosowanie dependency inversion principle.
  4. kod jest czytelny
  5. testy jednostkowe przez fasadę, a nie na wszędobylskich mockach

Nad czym bym się zastanowił:

  1. Brak testów integracyjnych - skąd wiesz, że Twoja aplikacja zadziała na produkcji?
  2. Klasa ResponseResolver - użyj @ControllerAdvice
  3. Jest kilka „worków”, które mogą się rozrastać - np. ten ObjectCreator w testach, czy pakiet „common” - tutaj możesz zrobić podpakiet „vavr” na extensiony stricte dotyczące Vavra
  4. Brak struktury given/when/then testów (lub arrange/act/assert), przez co są nieczytelne i sprawdzają za dużo. Brakuje mi tez testów na ścieżki alternatywne - widać, że nie robisz TDD.
  5. Kolizja nazwy klasy ObjectMapper. Wiem, że to domena i nie wie o Springu, natomiast jest to i tak mylące. Poza tym nazwa aby ogólna, proponuję UserConverter.
  6. Nie podoba mi się, że fasadę do testów tworzysz inaczej niż produkcyjną - testowa metoda powinna wołać produkcyjna, abyś testował kod, który będzie odpalany na prodzie.
  7. Jeden kontroler i fasada zarówno do pobierania zasobu Usera, jak i do jego rejestracji i linków aktywacyjnych - te ostatnie nie są raczej zasobami w rozumieniu REST oraz będą miały pewnie inne reguły security. Rozważyłbym rozwód kontrolerów, moduł może zostać jeden.

Na zakończenie powtórzę - jest nieźle! :)

edytowany 3x, ostatnio: Charles_Ray, 2019-08-13 20:09

Pozostało 580 znaków

2019-08-13 23:52
0

@Charles_Ray: co do punktu 6, czyli tworzymy Fasadę tą samą metodą w Configuration, ale po prostu przekazujemy tam w parametrach nasze implementacje InMemory?

Pozostało 580 znaków

2019-08-13 23:55
0

@weiss: w testach możesz od razu zrobić new XFacade(cosInMemory, cosInMemory) bez potrzeby konfiguracji itp. Klasy Configuration są zazwyczaj tylko na potrzeby spięcia całości frameworkiem itp


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.
edytowany 1x, ostatnio: danek, 2019-08-13 23:55

Pozostało 580 znaków

2019-08-14 00:02
0

Czyli klasa Configuration przyda się nam jeśli będziemy z Fasady musieli zrobić Bean żeby mógł on tam podpiąć swoje adnotacje potrzebne do działania. Czyli np. przekazujemy Springowej DAO?

mniej więcej - danek 2019-08-14 00:13

Pozostało 580 znaków

2019-08-30 17:55
0

Bardzo fajny kod. Mi też się podoba :).
Tylko, mam pytanie: Czy na pewno dobrym pomysłem jest transformacja z Dto -> Obiekt domenowy -> Dto -> encja? Czy to nie jest już trochę overengineering? :)

Pozostało 580 znaków

2019-08-30 17:59
0

Czyżbym widział pewną inspiracje? ;) Z rzeczy które teraz na szybko znalazłem

User userToEntity(UserDto user) {
        if(user == null) return null;
//uciete
    }

Nie ładnie zwracać nulle ;)

   private Success deactivate(ActivationTokenDto tokenDto) throws RuntimeException {
        var deactivatedToken = ActivationTokenDto.builder()
                .tokenID(tokenDto.getTokenID())
                .username(tokenDto.getUsername())
                .activated(true)
                .expirationDateTime(LocalDateTime.now())
                .build();
        tokenRepository.updateToken(deactivatedToken);
        return new Success();
    }

Czemu RuntimeException?

private Either<Error, Success> activateUser(UserDto userDto) {
        var user = mapper.userToEntity(userDto);
        user.activate();
        return Try.of(() -> activate(mapper.userToDto(user)))
                .onFailure(e -> log.severe(e.getMessage()))
                .toEither(UserError.PERSISTENCE_FAILED);
    }

Jeśli activate(mapper.userToDto(user)) sie wysypie to nie jest problem ze user.activate() się wykonało?

@Charles_Ray: ResponseResolver jest po to, żeby nie używać wyjątków ;)


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.
edytowany 5x, ostatnio: danek, 2019-08-30 18:04

Pozostało 580 znaków

2019-09-01 09:04
0

Tylko, mam pytanie: Czy na pewno dobrym pomysłem jest transformacja z Dto -> Obiekt domenowy -> Dto -> encja? Czy to nie jest już trochę overengineering? :)

Doszedłem do wniosku że nie, przynajmniej nie w projekcie tego kalibru. Pozbyłem się obiektów domenowych, model==dto jest teraz publiczny, a cała logika przeniesiona jest do serwisów realizujących use case.

Nie ładnie zwracać nulle ;)

To już poprawione ;)

Czemu RuntimeException?

Zastanawiam się właśnie co robić w przypadku błędów jakie mogą lecieć z bazy?

Jeśli activate(mapper.userToDto(user)) sie wysypie to nie jest problem ze user.activate() się wykonało?

@Transactional po stronie repozytorium?

Pozostało 580 znaków

2019-09-01 14:24
0

Zastanawiam się właśnie co robić w przypadku błędów jakie mogą lecieć z bazy?

Zazwyczaj wtedy connector do bazy rzuca wyjątkiem (i nawet wtedy powinien)


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.

Pozostało 580 znaków

2019-09-01 20:00
1

Dlaczego plik UserConfiguration znajduje się z w katalogu z domeną? Z tego co widzę ma on adnotacje ze Springa (@Configuration, @Configuration), czy nie lepiej byłoby go przenieść do jakiegoś innego pakietu, w którym konfigurujesz sobie rzeczy związane ze Springiem? Np. pakiet configuration.

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 0, botów: 1

Robot: Yandex