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
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) andEmailDomain
(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.
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:
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".
For either loading or delivery, we need to update two entities:
Parcel
(to change its status) andSignature
(to add the recipient's signature). When retrieving, we only need to updateParcel
entities (no signature required).So this is our setup:
DAO
ParcelDao
handles updates to the [Parcels] table.SignatureDao
handles updates to the [Signatures] table.Services
LoadingService
depends on both theParcelDao
andSignatureDao
.DeliveryService
depends on both theParcelDao
andSignatureDao
.RetrievalService
depends on theParcelDao
.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.
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.
UI
The customer doesn't care who makes the food or where they make it. They just want to eat what they have ordered.