brianegan / new_flutter_template

Test ideas for a new flutter template
140 stars 23 forks source link

"Service" or "Repository" -- Naming is hard! #14

Open brianegan opened 3 years ago

brianegan commented 3 years ago

Many apps talk to external data sources via some kind of "Data Layer." Some folks call these Data Layer objects "Repositories," while others call these same type of objects "Services."

Which makes the most sense or feels the most universal?

orestesgaolin commented 3 years ago

This is just my opinion, but together with some folks we've recently found that it seems more common (at least in our social bubble) to have distinct service and repositories layers. It helps with testability, maintenance and splitting work across team members. It can be considered a derivative of service-repository pattern from the enterprise world, but there seems to be some confusion about the order and responsibilities of layers.

What I mean is that state management layer (bloc, cubit, provider etc.) has dependency on a repository layer. The repository layer has dependency on a service layer. They specialize in a given set of tasks:

This kind of approach works both in smaller projects with single feature (e.g. in my personal side projects) but also scales robustly to bigger apps where each repository or service can be a different package with several implementations (e.g. one using REST, other using cloud_firestore).

escamoteur commented 3 years ago

I second this although I prefer the name Manger over repository because there is more possible business logic than just transfering data. Services are the really outer limit of my app to the environment.

brianegan commented 3 years ago

That is very interesting indeed! This is where it get's tricky. For a larger app, you'll almost always have an additional "domain layer" for business logic, but that feels like overkill for a template aimed a beginner-to-intermediate devs. I've usually seen this organized in the following ways:

  1. "Domain Services" handle business logic and make use of Repositories or Data Services for data storage.
  2. "Use Cases" are often single-functionality Domain Services that contain business logic and make use of Data Services or Repositories to perform a specific action

But I haven't seen Repositories making use of Services! Do you happen to have some articles that discuss that organization a bit more?

escamoteur commented 3 years ago

You are talking here about Domain Services, which I would call business logic. A service coming from Operating system chargon means something providing infrastructure services.

chimon2000 commented 3 years ago

A few articles for inspiration

https://verygood.ventures/blog/boring-code-part-1 https://medium.com/flutter-community/the-software-engineering-approach-in-cross-platform-programming-with-flutter-part-1-efcdc8a8fc26

chimon2000 commented 3 years ago

A better explainer of the repository-services pattern

https://exceptionnotfound.net/the-repository-service-pattern-with-dependency-injection-and-asp-net-core/amp

escamoteur commented 3 years ago

I don't think that this fits to an app architecure. that describes a Web API that offers business services to client applictions

MisterJimson commented 3 years ago

I typically use this naming scheme:

Manager: A domain service that your app is in charge of and owns. Service: An adapter to something you app is not in charge of and does not own (webapi, local database, third party SDKs, etc)

chimon2000 commented 3 years ago

I don't think that this fits to an app architecure. that describes a Web API that offers business services to client applictions

I agree. I generally don't use services because the term is too generic and has too many meanings compared to something like Manager.

If I wanted to describe an outer limit (local database, remote API) I would call it a Datasource.

brianegan commented 3 years ago

Thanks all -- really interesting stuff -- appreciate the extra links for info!

Ok, so I think we're all using or describing a very similar setup, yet using the word "Service" to mean different things :)

This is the catalog of names I have so far and how each approach uses these terms -- please lemme know if I got something wrong!

  1. Android Style: View - ViewModel - Repository - Data Source
  2. VGV Style: Widget - Bloc / Cubit - Repository - Service
  3. Clean Architecture: View - Controller/Presenter - Use Case / Domain Service - Repository - Gateway/Interface Adapter/Database
  4. DDD: View - Controller - Application Service - Repository - Not sure what the "Edge" is called here
escamoteur commented 3 years ago

May I add:

  1. RVMS: View-Manager-Service
brianegan commented 3 years ago

@escamoteur Sure, np. Question for you: If you had an offline-first weather app and you want to check if you've got the data locally stored in SQLIte before making a Web API call for the data, how would you coordinate that?

Would the Manager use two services: A SQLWeatherService and WebApiWeatherService and be responsible for coordinating multiple data sources, or would the service coordinate those objects? If so, what are those objects called?

escamoteur commented 3 years ago

I think both would be legit solutions. If its really just checking if its available before reaching out to the API I probably would put it in the service. Probably the WebApiService would use a CacheService If the logic to determine if the data in cache is the correct one, I would put it in the Manager.

chimon2000 commented 3 years ago

Thanks all -- really interesting stuff -- appreciate the extra links for info!

Ok, so I think we're all using or describing a very similar setup, yet using the word "Service" to mean different things :)

This is the catalog of names I have so far and how each approach uses these terms -- please lemme know if I got something wrong!

  1. Android Style: View - ViewModel - Repository - Data Source
  2. VGV Style: Widget - Bloc / Cubit - Repository - Service
  3. Clean Architecture: View - Controller/Presenter - Use Case / Domain Service - Repository - Gateway/Interface Adapter/Database
  4. DDD: View - Controller - Application Service - Repository - Not sure what the "Edge" is called here

I couldn't find an official for DDD but this comes from @resocoder's primer:

Data sources operate at the lowest level. Remote data sources fit JSON response strings gotten from a server into DTOs, and also perform server requests with DTOs converted to JSON. Similarly, local data sources fetch data from a local database or from the device sensors.

Arkangel12 commented 3 years ago

I think that more like it to trying to define a naming convention for a specific part of the code I would like to add definitions and comments about what this does and how you can find this represented in another architecture, use this more like guidance that uses it like a specific named oriented.

I have found that many times for beginners find it more confusing to get the idea of what each thing does and not how to implement it. what you are talking about is pretty important but also you have to think this throw also think that not all your readers (devs) are going to be native English speakers or even they will not have good English.

This needs to be a full answer for understanding not just aiming to create a starting point without really now what is it happening under the hood.

RobertBrunhage commented 3 years ago

This is a really interesting topic and I think it depends quite a lot.

I personally follow DDD: View - Controller - Application Service - Repository

To me this has made most sense and has made my code the most decoupled. The reason I've gone with this is because in my experience a lot of people coming from other technologies has a base understanding that a Repository handles crud operations while Service handles the business request. I.e I need x from x repository but also y from y repository, put these together and we have that value xy in the service.

The controller would then take the combined value (xy) from the service.

Now there are also times when a Repository is not needed or a Service is not needed but would only clutter. But I think we should be careful when going for the Android style or VGV style as there are not only people coming from an Android background and to them a Repository calling a Service does not make sense to the definitions of the words. But to others this make a complete sense.

I just want to add that I don't think any of the approaches are bad but just wanted to give an additional opinion 😊

EDIT: The thing I am mostly talking about in my example is the repository-service pattern which is widly used in .net.

filiph commented 3 years ago

This is fantastic discussion! At some point we'll need to apply pressure to simplify (we don't want the template to be totally overwhelming with new concepts) but, at this point, the breadth of approaches is enlightening.

I do think that it will be useful for intermediate devs to get a simple, approachable and practical explanation of these terms, like @RobertBrunhage's

a Repository handles crud operations while Service handles the business request. I.e I need x from x repository but also y from y repository, put these together and we have that value xy in the service.

asidt commented 3 years ago

I think I need to clarify this ambiguity of the word 'service' in the context. I follow an architecture which is inspired by the Android Architecture Components. With that approach, a Repository is an abstraction which needs to handle the data access from the db and from the server. At the same time, the ViewModel needs to have access to the Repository, and this is done with Dependency Injection. I decided to use the service locator pattern to provide the ViewModel access to the Repository. In this context, the Repository is a 'service' of the service locator pattern, that you register in the registry. Now if you look closely at the first picture of the link, or at the code, you'll see that the access to the remote data coming from the server is done with a WebService. In this context, service means something completely different. So, as I see it, the Repository is a clear name for the abstraction layer, and it's also a service (in the service locator pattern context). Repository is a specialized service, still in this context, and you could have many other services provided by the service locator pattern which are not repositories at all. A (Web) Service on the other hand is a clear name for the part communicating to the server. So usually I use the word 'repository' for some service locator pattern's specialized services which represent the abstraction layer which handles access to db and web, while I use the word 'service' for all the web services which communicate to the server.

johnpryan commented 3 years ago

This is just how I think about it, but objects tend to fall into a few main buckets:

  1. Models (aka Data objects, or just objects) - plain old dart objects that store data and other objects (e.g. User, Todo). These usually don't depend on other packages or libraries and are bespoke for the app I'm writing.
  2. Services (aka APIs, Data Sources) - classes for interacting with a backend or database with methods like get(), delete(), insert(), etc.
  3. Controllers (aka Cache / Manager / Bloc / Store) etc - objects that store state for the entire app or part of an app. This is where the bulk of the complexity goes. Controllers can depend on services or other controllers. I prefer to make these classes expose Streams as opposed to using ValueNotifier, which introduces a dependency on flutter:foundation

Dependency injection is a separate issue IMO - how widgets get access to any of these three types of objects is solved separately by packages like Provider or InheritedWidget patterns. I tend to prefer manual dependency injection most of the time – Widgets and Controllers put the objects they require in their constructors. Otherwise it's hard to figure out my app's dependencies.

It sounds like Repositories don't fall into the Service of Controller buckets but sound useful for apps that deal with multiple backend services.

MisterJimson commented 3 years ago

I think about things in a pretty similar way to @johnpryan. Although I believe Services should also be used to interact with anything you don’t control. Data Sources are the most comment example, but in my opinion they should be used for third party SDK integration, native API calls, etc. Ensuring you abstract access to these it critical to not mixing dependancies all over your app, making it very difficult to test.

quetool commented 3 years ago

I didn't read any of the comments on this issue but we should have both... One or more "Repositories" makes one or more "Services"... Is about the abstraction's levels we are talking about here...

neiljaywarner commented 3 years ago

I hope the template creates multiple files like android studio fragment with viewmodel, and ideally creating a test would be nice. Maybe look to sunflower for inspiration as well, better yet with api element of course.

but specifically 1) repository makes it easier to have the cache/refresh logic with api call and db or similar, so the naming repository is helpful 2) It might be reasonable to have 1:1 viewmodel+repository,but definitely not 1:1 viewmodel to service

also - what is the %age of developers coming from android vs ios, web, etc? if Android is highest that might be a nod towards the direction of jetpack guide naming (Repository)