Clean architecture czy overengineering?

0

Pisze sobie projekt wzorując się na Clean Architecture i mam tam obecnie taki podział

  1. Configuration
  • wszelkie konfiguracje jak SpringSecurity, połączenie do MongoDB
  1. Domain
  • tutaj realizuje logikę aplikacji, wewnątrz mam podział na konkretne domeny
    screenshot-20190826173801.png
  • każda z nich wystawia publiczną fasadę, dto oraz interfejs który należy zaimplementować w następnej warstwie (zazwyczaj jest to po prostu repozytorium)
public interface ProductRepository {
    List<ProductDto> getProducts();
}
  • packaged-scoped zostają serwisy realizujące logikę oraz encje biznesowe na których ta logika jest wykonywana
  • poza jedną klasą konfiguracyjną, która wrzuca wstrzykuje zależności do mojej fasady, cała reszta jest odseparowana od frameworka
@Configuration
class ProductConfiguration {
    @Bean
    ProductFacade productFacade(ProductRepository repository) {
        return new ProductFacade(repository);
    }
 }
  1. Infrastructure
  • tutaj znajdują się konkretne implementację moich interfejsów domenowych, np. InMemoryProductRepository na czas testów, czy MongoProductRepository na "produkcje", mogę też w prosty sposób zamiast z bazy skorzystać z zewnętrznego API i nie będzie to wymagało wiele zmian w moim kodzie czy testach
  • dodatkowo tutaj implementuję warstwę HTTP aplikacji a także wszelkie styki z światem zewnętrznym

Tak jak wspomniałem, widzę kilka plusów takiego podejścia, łatwo testować moduły domeny które mają 1 punkt wejścia jakim jest fasada, w prosty sposób mogę zmieniać szczegóły jak źródło danych, całość jest całkiem czytelna.
Co mi się jednak nie podoba, to powielanie klas. Przykładowo prosty update wartości na bazie wyglądałby tak
-otrzymanie requestu HTTP z ProductDto, wywołanie metody na fasadzie
-mapowanie ProductDto na ProductEntity (encja biznesowa)
-walidacja/logika
-mapowanie z powrotem na ProductDto
-wywołanie metody z interfejsu updateProduct(productDto)
-wewnątrz implementacji interfejsu mapowanie ProductDto na ProductDBEntity (encja bazodanowa)
-update na bazie
-mapowanie rezultatu na ProductDto

Zastanawiam się wiec, jeżeli moja aplikacja nie ma skomplikowanej logiki biznesowej, czy jest sens tworzenia encji biznesowych?
Obecnie sprowadza się tu u mnie do czegoś takiego

 private DailyConsumptionDto addToDailyConsumption(DailyConsumptionDto daily, ConsumedProductDto consumedProduct) {
     var dailyEntity = converter.toEntity(daily);
     dailyEntity.addProduct(converter.toConsumedProductEntity(consumedProduct));
     return repository.updateDailyConsumption(converter.toDto(dailyEntity));
 }

 @Override
 public DailyConsumptionDto updateDailyConsumption(DailyConsumptionDto productsDto) {
     return converter.toDto(mongoTemplate.save(converter.toEntity(productsDto)));
 }

Równie dobrze całą logikę mógłbym wykonać na Dto. Może nazywanie tego nadal Dto byłoby wtedy błędem, po prostu model danej domeny byłby publiczny, traktowany jako worek na dane, wszelkie walidację i logika zostałyby w package-scoped serwisach.
Trochę gryzie się to z całym podejściem CA, ale - pozbędę się wielu mapowań, które potencjalnie mogą powodować jakieś błędy (NPE przy mapowaniach), odchudzę cały kod, dodatkowo IMO zwiększy się czytelność całego kodu. Czy może widzicie jakieś inne bardziej sensowne rozwiązanie, bądź macie konkretne argumenty by nie iść tą drogą?

0

Przede wszystkim musisz sobie zadać pytanie: Czy taka organizacja kodu Ci pomaga? Główną ideą jest to, żeby łatwo pisać testy i łatwo dodawać nowe rzeczy.

Co do logiki. Jeśli nie masz żadnej logiki bezpośrednio na obiekcie to raczej nie potrzebujesz obiektu domentowego (możesz i będzie to "poprawne", ale wyjdzie lekki overkill), bo wyjdzie Ci CRUD, który udaje, że nie jest CRUDem ;)

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