Search code examples
javadesign-patternsmicroservicessoftware-design

Should I always have a separate "DataService" that make invokes another service?


I am building a new RESTful service that interacts with other microservices.

The routine task is to fetch some data from another RESTful service, filter it, match it against existing data and return a response.

My question is is it a good design pattern to always separate steps "get data" and "filter it" in two different classes and name one is as EntityDataService and the second one is simply EntityService?

For instance, I can make a call to a service that returns a list of countries that has to be filtered against some conditions as inclusion in EU or date of creation, etc.

In this case, which option is better:

  • separate CountryDataService class that only have one method getAllCountries and EUCountryService that filters them
  • make one class CountryService with public methods getEUCountries and getCountriesCreatedInDateRange and private getAllCountries

Which one is better?

I'm trying to follow KISS pattern but also want to make my solution maintainable and extensible.


Solution

  • In systems with lots of data, having a method getAllSomething is not that good of an idea.

    If you don't have lots of data, it's ok to have it, but still be careful.

    If you have 50 records, it's not that bad, but if you have millions of records that whould be a problem.

    Having a Service or Repository with methods getBySomeCriteria is the better way to go.

    If you have lots of different queries that you want to perform, so you may end up with lots of methods: getByCriteria1, getByCriteria2,..., getByCriteria50. Also, each time you need a different query you will have to add a new method to the Service.

    In this case you can use the Specification Pattern. Here's an example:

    public enum Continent { None, Europe, Africa, NorthAmerica, SouthAmerica, Asia }
    
    public class CountrySpecification {
    
        public DateRange CreatedInRange { get; set; }
        public Continent Location { get; set; }
    }
    
    public class CountryService {
    
        public IEnumerable<Country> Find(CountrySpecification spec) {
    
            var url = "https://api.myapp.com/countries";
            url = AddQueryParametersFromSpec(url, spec);
            var results = SendGetRequest(url);
            return CreateCountryFromApiResults(results);
        }
    }