Becoming a software developer – episode X

Becoming a software developer – episode X

Welcome to the tenth episode of my course “Becoming a software developer” in which we will start designing our domain and services.

All of the materials including videos and sample projects can be downloaded from here.
The source code repository is being hosted on GitHub.


 

Scope

  • Domain
  • Services
  • Controllers

Abstract

Domain

As I mentioned already before, we will incorporate the Domain Driven Design (DDD) approach (at least in its light version) into our solution. Our domain models are the root of the Core project. They will have to be rich classes (that we will be continuously refactoring throughout the whole course), containing both properties and methods that will ensure that the internal of such object is valid. Otherwise, our domain model might throw an exception in order to let the user know that something went wrong. We can split our domain models into the following types:

  • Value Object – has no unique identifier, is immutable, can represent address, geolocation etc. Both Value Objects are usually equal if all of their properties have the same values.
  • Entity – has the unique identifier, which means that both entities are equal only if they possess the same id. This is a rich model that may contain additional methods in order to manipulate its state.
  • Aggregate – it’s an entity that may contain other entities and is a root model that we will have access to via the repository. It can be constructed by using one or more entities. Think about the Trip which can be an entity and have it’s unique identifier, but without a Driver (aggregate) the Trip on it’s own doesn’t make much sense – this is what the aggregates are for, to set the boundaries and ensure the valid state of the other entities that are a part of it.

Our repository will also contain the repositories, but only the interfaces. The actual implementation of such repository interface is the concern of the Infrastructure layer, as it could be either in memory, database or even some external storage being used to save our data.

Later on, we may also include e.g. events in order to build a more sophisticated application.

Services

Our infrastructure will have to deal with a lot of different tasks related either to implementation of the domain interfaces, handling the database connections and so on.
One of such requirements will be to provide the so-called application services. They will be defined as interfaces and implemented using the domain repositories and models in order to manipulate them and perform the actual business logic (e.g. registering user, creating a new trip etc.). The important part here is that we will never expose the domain itself to the higher layer which would be API in our solution (or the UI). We want to ensure the consumer of the application services that the models he will receive will be safe to use, which means that they will be just a set of public properties with no robust methods whatsoever. By doing so, we can be certain that we will never modify our domain model (even unwillingly) via our API without ensuring it’s proper validation and the overall flow. In order to achieve such goal, we will be returning DTO (Data Transfer Objects) from our infrastructural services to the other layers (being API in that scenario).

Controllers

This is where we can actually deal with our application from the end user point of view. For now, we can only do the very trivial things such as fetch the User account, but later on we will be able to do much, much more. Our controllers define the set of distinct operations (GET, PUT, POST, DELETE) and each one of them will have its unique endpoint called the URI (Unique Resource Identifier) e.g. /users or /drivers/{id}/vehicle that will allow to either get or modify the underlying data.

Next

In the next episode, we’ll make use of some external libraries to help us with handling the DTO mapping, take a look at the HTTP POST method and refactor our services to be fully asynchronous.

12 Comments Becoming a software developer – episode X

  1. Pingback: Becoming a software developer – episode X – Patryk Huzarski | Personal Blog

  2. Pingback: Dew Drop - March 30, 2017 (#2451) - Morning Dew

  3. Johny

    Hej!
    Mam szybkie pytanie jeśli to możliwe? W trakcie kursu piszę swoją apkę tak by na bieżąco wdrażać wiedzę i natrafiłem na gwoździa. Mam issues powiązane z moim userem ale które pobieram z zewnętrznego serwisu i nie będę ich przechowywał w mojej bazie danych – gdzie w onnion architecture powinny być klasy odpowiedzialne za te issues?

    Pozdrawiam.

    Reply
    1. Piotr Gankiewicz

      Cześć,
      Po prostu w warstwie infrastruktury stwórz np. nowy serwis aplikacji oczywiście opakowany odpowiednim interfejsem, który będzie pobierał w tym przypadku dane z zewnętrznego źródła, najprostsze rozwiązanie.
      Pozdrawiam

      Reply
  4. Johny

    Aha!! Rozszerzam wtedy po prostu Users w UsersDTO o listę Issues pobranych z zewnętrznego Api których definicja (klasa z propertisami) jest w infrastrukturze. Super bardzo to elastyczne. Dzięki za odpowiedz!!

    Reply
  5. Tomasz

    Hej!

    Mam pytanie według wytycznych od ms który zaleca clean architecture dla aplikacji web warstwa UI ma referencje do CORE i INFRA natomiast w architekturze zaproponowanej przez ciebie tylko do INFRA. Podobna różnica jest odnośnie miejsca przechowywania klas DTO według ms w CORE a w passenger w INFRA. Możesz pokrótce odnieść się do tych różnic?

    Reply
    1. Piotr Gankiewicz

      Cześć,
      Ja się stosuję do Onion Architecture. Warstwa taka jak API/UI nie powinna nic wiedzieć o Core (czyli głównie o domenie). Przykładowo API jedyne co musi wiedzieć, to w jaki sposób wykonać logikę biznesową oraz pobrać ewentualne dane. W tym celu wykorzystuje się DTO, które podobnie jak serwisy aplikacji wchodzą w skład tzw. anti-corruption layer.

      Reply
      1. paweł

        Witam.
        A skąd w Startup wziął się:
        using Passenger.Core.Repositories;
        W końcu Api nie powinno widzieć Core?

        Reply
          1. paweł

            Ok. Ale dlaczego w ogóle można w API dodać using do Core?
            Spowodowane jest to tym że skoro API zależy od Infrastructure to pomimo iż nie jest zależne bezpośrednio to i tak ma dostęp do jego ‘wnętrza’?
            Bo przeczy to założeniu że API nic nie wie o Core 🙁

            A tak na marginesie to kurs genialny, bardzo mi pomógł. Dzięki wielkie.
            Pozdrawiam

  6. Konrad

    Hi! I have a question regarding the GUIDs in CQS. Having non sequential GUID in DB could be problematic in the future. So this is a good idea to use Id as an int. When we need to insert new object into the DB what is the best practice to send inserted ID back to our UI and still using CQS pattern? As you said command shouldn’t return any value.

    Reply

Leave a Reply to Konrad Cancel reply

Your email address will not be published. Required fields are marked *