Is there a design pattern that can help with this problem?

2

I have a problem that seems to me to be fairly common. The problem, in this case, is this: the user wants to register in the system the services available for sale together with the values. When you sell a service, you want the service to become active for the customer.

Finally, for some services there are specific rules and properties that the system needs to consult. An example would be support service, which has the hours that the customer pays per month. This service has a specific rule: it can only be performed if the hours have not yet been spent in the month, and have a specific property: the number of hours.

Now let's see the problem: if the user registers the services manually, there is no way in the system to know for example which service is the support service. In fact, for the system they will all be the same. This is because in theory there will be a single class with general properties, whose instances are services registered for sale.

This clearly conflicts with having to specify rules and details for specific types of service.

As I said, I think this may be more common than it seems at first. I quoted a concrete case, but we could abstract it as follows: the user wants to register some objects in a personalized way, however these objects need to have specific behaviors, with specific properties and specific rules, which conflicts with the user wanting to register them at will .

In this sense, the solution that I identified was the following: identify the service types, create a class for each type, and in the registry ask the user to choose the type, opening possibility of customization. Here it seems that would fit the use of inheritance, but I know that this is subtle.

Other than that I thought of the bounded contexts of the DDD. I wondered if the problem was not the term "Service" being used in two different contexts, representing different things. The problem is that despite identifying the problem, I have not identified how to deal with the "service type" issue.

As this seems to me common, I thought if there was a design pattern that deals with this. Is this kind of a design pattern issue? Is there a known and tested solution that addresses this type of problem?

Or the solution I proposed to create a class for each type of service, abstracting its main characteristics, allowing the user to choose the type in the register would be the best solution?

    
asked by anonymous 19.04.2017 / 16:37

2 answers

1

Feature Flags

This is the name of the pattern you are looking for. You can read more about this on this other StackOverflow answer , or Wikipedia on Feature Toggle .

A Feature Flag (or Feature Toggle ) is the ability to easily enable / disable features (sub-sections) of your application:

  • Through a rebuild , or
  • internal area where pages / features / features can be switched with immediate effect.

It is convenient to have the control of cutting or activating a feature set, in case you need to, for example, reduce the number of queries in the DB if the load is too high.

There are lots of other reasons you would want to use this feature - one of the key is to enable continuous deployment: publish news to production having the new feature disabled until it is complete. We often use what we call a 'cookie dev' to show incomplete features to the collaborator's team. In this way we can test partially completed features already in production. And when those are ready, just enable the feature to make it public.

This is a simple package that helps you do this with ASP.NET MVC: link

Fowler also has an old article with much more detail .

    
20.04.2017 / 09:09
1

Code Modeling

From a code point of view, the problem sounds exactly like the Strategy Pattern .

Example:

abstract class CalculoHoras {
  int calcularHoras(int mes) {
    List<Servico> servicosDoMes = carregarServicosDoMes(mes);
    int horasAPagar = calcularHorasAPagar(servicosDoMes);
    cobrarCliente(horasAPagar);
  }
  abstract int calcularHorasAPagar(List<Servico> servicosDoMes);
}

From there, you can create any strategies to calculate the hours extending the class. So, depending on your system configuration, you instantiate one of the implementations at the time of the calculation.

Another way, without using inheritance, would be to create an interface:

interface MetodoCalculoHorasAPagar { 
  int calcularHorasAPagar(List<Servico> servicosDoMes);
}

Then you create the deployments you want and consume one each time you perform the calculation:

class CalculationHours {       int computeHours (int month, MethodCalculateHoursApply method) {         List servicosDoMes = loadServicesDoMes (month);         int hoursApply = method.calculateHoursApply (servicosDoMes);         charge Customer (hours);       }     }

Comments:

  • Using delegation and interfaces is generally a better practice than using inheritance, although in general the original design pattern uses inheritance.
  • The names and methods used above are illustrative only, use as appropriate.

General design

Project patterns are interesting, but almost always are not a solution by themselves, as well as being of very low level.

Thinking about the design of a solution to make a feature flexible involves thinking about a number of things, such as:

  • Who will use such functionality
  • How it will be used
  • Flexibility vs. Complexity
  • Security

And so on. Only then will the code become important.

The first question to be asked in this context is: Is it possible to identify a finite, limited set of possible calculation strategies?

If the answer is yes, then it is enough to identify and implement such strategies. From the users' point of view, if he tries to perform the calculation without selecting a strategy, give a visual answer saying that the result will be unavailable until he defines the strategy.

If the answer is negative, then a possible solution would be to have a set of common strategies and allow the rules to be extended. This is a tricky point as there are several ways to do this:

  • The most basic and manual is to offer a service where the customer sends a specification and you implement as he wants. For few customers it's simple, but for many it's a headache. This is not a good solution if the rules change frequently.
  • It may be possible to identify the variables involved in defining new rules and create a configurable rule via the screen. This solution allows a bit of flexibility, but still involves determining everything that can vary.
  • If the problem can be solved with a mathematical or financial formula and some input variables, it would be possible to allow the user to enter such a formula using some math expression interpreter.
  • Finally, you can allow users to contribute rules via code. You can take advantage of the fact that there are several dynamic languages that run within the JVM securely and allow the user to write, for example, a JavaScript function in a system field and you perform that function on the server. This solution is interesting whether your customers are from the IT area or have IT sectors managing the company's systems. In fact, you can implement this solution for yourself, because in this way you could write the rule, put the script in the client database by some administrative screen or SQL script and have a new function in the system without having to generate a new version.
21.04.2017 / 04:29