Modeling my Android domain layer

  2 mins read

Since my last post about why I don’t use a pure repository pattern in Android I received some feedback and I want to explain how I organize my domain layer.

What should be my domain layer

Everything. No, seriously, everything that are decissions that your app makes in order to request data must be in this layer. If your domain layer is rich your controllers/presenters should be so simple like directly calls to your domain. For example, domain logic are form validations, algorithm calculations, etc..

Deconstruction of a domain layer

In an application based on use cases I have the domain separated in Outter domain and Inner domain. This two concepts are pretty simple to understand:

  • Outter domain are your interactors, those pieces of code don’t have domain rules, it only coordinates actions and makes your domain logic “Public” to the rest of your layers by using those actions.
  • Inner domain is composed of Domain Services and Infrastructure services. Basically an Interactor calls a Domain Service and this Domain Service communicates with your Network, Database, makes calculations, provides rules for your form validations etc… If you need something from your infrastructure (find your current location, send an email…) you can call an Infrastructure service. This doesn’t mean that your inner domain can only contain those 2 figures, your domain can have Objects that help your logic to be organized.

We can define an interactor as the implementation of a use case that makes only one action. It does not contain the domain logic directly because it coordinates various calls in order to make the action. It’s named with a Verb + Noun and it’s Public to the outter layers of your architecture.

Anatomy of inner domain

My Interactor communicates with inner services in order to perform those actions, but it can call various domain services if needed. Here is a sample interactor that modelates the creation of a product in the Selltag app flow:

InteractorFlow

As you can see it coordinates various actions, first it calls a Login domain service to get the current user status, if it’s logged in, then it calls a Validator that is a simple object with some rules that decides if this product is a valid one, it can be rules like if it has title, the price is greater than zero, etc.. With these 2 preconditions then it decides to call the Product Creator domain service that talks with an infrastructure service in order to get the current user GPS coordinates. When it has all the data to create the product the Product Creator domain service calls some boundaries in order to complete this action.

Abstracting

The way to communicate with the network and data layers is with an interface that defines the boundary between your domain and the outside world. This allows us to keep our domain decoupled from the concrete implementation of the data retrieval objects.

Error handling

This action makes some complex things in the middle and maybe you want to keep the user informed with exact data to let the user decide what to do in case of a failure in some of the middle actions. You can throw some custom Exceptions and return those exceptions to your controller/presenter to present different messages or customized actions to recover from a problem.

References and further info

I’m working on an example that demonstrates this concepts but I wanted to post this to receive feedback, so if you have to tell something you are very welcome!

Written by:

Christian Panadero Martinez

  • Pedro Vicente Gómez Sánchez

    Thanks for this post Christian! Really interesting to read 🙂

    When you talk about “Everything. No, seriously, everything that are decisions that your app makes in order to request data must be in this layer.” I think you are adding a quite strong rule to the game. If you are not going to reuse your domain with other applications (like a library or framework you are going to share) you can move your validation rules out of your domain and move them to your presenters or even to your views implementations (if you are using a library to create forms most of the validation rules will be in the view implementation because you are using the library there). Doing this, your domain code will be focused in your business logic and not in this repetitive details related to data validation (most of the time null/empty checks or regular expressions).

    If you are going to share your domain your validation rules should be implemented there 🙂 There is no doubt.

    What do you think?

  • Hi Pedro,

    I was wondering if the validation rules are domain or not and I conclude that in this case for me they are. Why? Because a product cannot be created if you don’t have a valid title, valid description, a formatted price and at least 1 photo of the article you are going to sell. So If you want to reuse this interactor in the app, for ex if you have a functionality to “sell one of those” when you are viewing a seller profile (ebay has this) you don’t need to re-check the validations because you have those validations in the same interactor.

    In resume, for me I can’t create an article without having X rules so this rules belong to my domain layer.

    Thanks for your comment!

  • Renan Ferrari

    Hey Christian, really good post, thanks for sharing 🙂

    I have a question: where would you fit SharedPreferences in your structure?

    The way I see it, you may have to access some preference from your product validator object (let’s say the product validation depends on some user’s preference being enabled or not), but at the same time I could see you accessing it from a domain service (let’s say you only get the product coordinates if the user allows it). Are those scenarios really possible, or am I missing something here? And in the case you need to access some preference from a Domain Service, would you “hide it” behind a boundary or would you consider it to be an Infrastructure Service?

    Hope it makes sense to you.

    Thanks again.

    • Hey Renan,

      For me SharedPreferences on the Android delivery mechanism is only a way to store persistent data in an easy way, your application (domain) doesn’t care about the way you store data, in the case you thought, your application should care about this dependant data, and the object that provides this data should be a concept of your model. If you choose SharedPreferences as your storage, you can use a Boundary like I’ve done with the Network in the example.

      I hope I’ve explained myself well.
      Thanks for your comment!

      • Renan Ferrari

        Great, that’s how I’m currently doing in my project 🙂

        Thanks again for your post and your explanation Christian.

      • Renan Ferrari

        Christian, another question: in your architecture, is the outter domain equivalent to Eric Evan’s application layer from the DDD book?

        I’m asking this because I believe your interactors fit that definition pretty well: they are thin, they define the actions your app is supposed to do, they coordinate the tasks between the domain objects and have no business logic inside them.

        If they really are equivalent, it would be correct to say the interactor can directly call an infrastructure service, do you agree? I mean, just like this use case from the book: http://i.imgur.com/oF6MuKN.png

        The thing is that in your project, you put the interactor’s implementation inside the domain module. Shouldn’t it just be an interface there?

        I’m thinking that different applications could interact with the domain services and the infrastructure services in very different ways in some cases, so it would make more sense if the application could implement the interactors accordingly to its own infrastructure needs.

        Does that make sense for you?

        • Is totally that Renan, the outter layer is just the public part of my domain layer. And yes, it fits the use case that you are linking 🙂

  • Shot for the awesome post Christian, really learned something!

  • Pa Po

    For example where would you fit setting a flag for the first start of the app in your structure? Are you creating an use case for setting and getting that flag or are you directly accessing that flag thru the shared prefs in your “presentation layer”?

    • We are talking about flags and technical things, but we have to speak about concepts, semantics. So, let’s say you have to check thtat flag to do an action in your model, you don’t have any Presenter and you should create an Interactor with this concept related with your domain and call it when the application starts, this interactor maybe will talk with a boundary that eventually can read from SharedPreferences or database or whatever. The key concept is abstract your application from the implementation, the app should know about the domain but not what it does.

  • Saúl Molinero Malvido

    Nice article! looking forward that example 😀

  • Pingback: Modeling my presentation layer - Christian Panadero()

  • Pingback: Modeling my presentation layer - IT大道()

  • J.K.

    I can see a lot of Evans/Martin/Jacobson here and I’m proud to say I’m also adopting this technique. It worked wonders for my last app. More than halved the amount of bugs and the ease of maintenance! I hope more people catch on to this

  • J.K.

    Can you please post an article about the methodologies of grouping classes in packages? I’m still confused about that.

  • eoin

    is there any code available for this?

      • eoin

        i find that code pretty hard to understand unfortunately

          • eoin

            further study is required on my part. what are you using for DI? maybe i need to read the book on DDD and look at the slides. I just cant follow exactly how its working at present

          • If you can make a list with the things that you don’t understand, we can discuss it, here or in the clean-contacts repository as issues

          • eoin

            cool. Thanks Christian, I appreciate your help.

          • eoin

            i was wondering if i sent you on a gist link could you take a look at it for me?

          • eoin

            i studied fernando cejas implemetation and i understand a lot better now. lookig forward to revisiting this example

          • eoin

            actually there’s still too much going on here for me. lol

          • eoin

            i usually use dagger 2 also. I think you are using dagger 1? I think this is part of my confusion.

          • Dagger 2 is more or less the same than dagger 1. The thing is to apply Inversion of control, it does not matter the framework that you are using, you can read more here: https://www.google.com/search?q=Ioc+vs+Di