Architecture – How should the service layer be done

Architecturedaodesign-patternsservices

so I have this android app at work, if I understand it right the DAO/services/UI layers is to "decouple" the UI from the database.
I have 2 problems with that :

1/ Decoupling

Like this if things changes in the DAO layer/database schema I just have to touch the service layer and the UI stays untouched.

Allright, why? I still have to change stuff in 1 layer to adapt to the DAO layer change, why does it matter that I don't have to change the UI layer? in the end I still have to rewrite the services layer.

2/we are making one service per DAO

Client Info Screen : display info about the client

So I'm in a screen, the only information I currently have is the "current intervention ID"

to get the client address I need to get the InterventionEntity in order to know the client, then I need the ClientDao in order to retrieve the ClientEntity with it's address.

so I need access to 2 DAO, but I will call 1 service. choosing in which service to implement that is confusing.

Wouldn't it be better to have 1 service per screen?

I would have a ClientInfosScreenService that would have "getClientAdress" using both the InterventionDAO and ClientDAO.

Thanks.

Best Answer

1/ Decoupling

Like this if things changes in the DAO layer/database schema I just have to touch the service layer and the UI stays untouched.

Allright, why? I still have to change stuff in 1 layer to adapt to the DAO layer change, why does it matter that I don't have to change the UI layer?

Consider that each layer abstracts the next layer, and therefore often centralizes usage.

Consider an example of where you have 4 views which can all update the person's email address (person@example.com). All four of them contain logic to update the person's email address.

Suppose you want to introduce a change, where you now save an email as two separate fields: EmailIdentity (person) and EmailDomain (example.com). You have to change the update logic of the person's email address. There are 4 views, which means you have to change four things.

If you had had a DAO layer, there would've been one UpdateEmailAddress(int personId, string emailAddress) method. Therefore, if you wanted to implement the same change, you would only have to change one thing.

In the example I used, when you only do 3 changes and you didn't know the 4th location existed, you would run into compiler issues, so you'd quickly see that you forgot something. However, if the applied change is not breaking, it will lead to a successful compilation and you will not be reminded that you forget any other updates.

Tangentially, while different layers are often represented as different projects, that is not inherently required. If your UI project already has a separate PersonUpdateHelper class, you could arguably call that the DAO layer. A class can be a layer too, as long as it is inbetween the database and the UI (so those two never interact directly).
I would suggest using projects as your layers for other reasons (library dependencies, the ability to meaningfully use access modifiers to prevent circumventing the layer, ...) but it is not technically a requirement for it to be considered a layer.


2/we are making one service per DAO

Wouldn't it be better to have 1 service per screen?

No. As per the previous example, the updating of a person's email address occurs on 4 separate views, and therefore you'd be forced to create the same logic in 4 services (one per view).

However, there is some merit to the underlying foundation of your issue:

so I need access to 2 DAO, but I will call 1 service. choosing in which service to implement that is confusing.

I completely agree with this. But I do want to point out here that there is no requirement for the dao and service to work on the same scope.

When your service only depends on one DAO (FooDao), then it usually makes sense for the service to take the same name (FooService). But when the service relies on more than one DAO (FooDao, BarDao), then the service should be named based on the purpose it serves.

I'll give you a real world example. I work on an application used for delivery truck drivers, to track which parcels they have delivered.

Delivery drivers have three distinct jobs. These jobs are what I mean when I say "the purpose a service serves".

  • Loading the parcels into their truck.
  • Delivering the parcels at the recipient.
  • Retrieving parcels from a sender (to later be delivered).

For either loading or delivery, we need to update two entities: Parcel (to change its status) and Signature (to add the recipient's signature). When retrieving, we only need to update Parcel entities (no signature required).

So this is our setup:

DAO

  • The ParcelDao handles updates to the [Parcels] table.
  • The SignatureDao handles updates to the [Signatures] table.

Services

  • The LoadingService depends on both the ParcelDao and SignatureDao.
  • The DeliveryService depends on both the ParcelDao and SignatureDao.
  • The RetrievalService depends on the ParcelDao.

The driver doesn't care about which entities are affected. The driver (and his mobile application) simply calls FinishLoading() and doesn't care if this updates one or more entities.

This is why layer separation is so useful. To an external caller, it looks like the application has functional features (load/deliver/retrieve). But internal to the application, there is a more complicated data logic at play, which the external caller doesn't need to know about.

As a second example, restaurants similarly separate their cooks (DAO), their waiters (services) and their UI (customers).

The room where customers eat is quiet and calm, even if the kitchen is hectic and busy. If the cooks and the customers sat in the same room, they would get in each other's way. But by separating them into their own separate rooms, each can have what they need (peace and quiet for the customers, the ability to work fast for the cooks), and neither the cooks nor the customers need to worry about what happens in the other room.

DAO

Separating the kitchens means that every kitchen can be tailored to a specific cuisine.

  • The sushi chef has his own kitchen.
  • The grill chef has his own kitchen.
  • The salads are made in a separate kitchen.
  • The wine is stored in the wine cellar.

I'm aware that real life restaurants often only have one kitchen. But if you look at large-scale kitchens, like the ones you find on a massive cruise ship, you'll see that there are several kitchens each with their own cuisine and staff.

Services

The waiters serve as the layer between the cooks and the customers. Because the waiters are there, the cooks and the customers never interact with each other. The waiters know what the customers have ordered. The waiters will figure out where they need to get the meals from.

  • The waiters will fetch the meals from the appropriate kitchens. They do not fetch wine.
  • The sommelier (wine advisor) will fetch the wine from the wine cellar. They do not fetch meals.

UI

The customer doesn't care who makes the food or where they make it. They just want to eat what they have ordered.

  • The customers expect their waiter to bring the food to their table.
  • The customers expect the sommelier to bring the wine they asked for.
  • The customers don't care where the waiter got the food from. Whether they picked it up in one location, or picked it up from multiple locations, it really doesn't matter to the customer.