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

Asked

Viewed 108 times

2

I have a problem that seems fairly common to me. The problem, in the specific case, is the following: the user wants to register in the system the services available for sale along with the values. When selling a service, the user wants the service to be 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 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 has a specific property: the number of hours.

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

This clearly conflicts with needing 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 mentioned a concrete case, but we could abstract it as follows: the user wants to register some objects in a personalized way, but 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 I identified was the following: identify the types of service, create a class for each type, and in the registration ask the user to choose the type, opening the possibility of customization. Here it seems that it would fit the use of inheritance, but I know that this is subtle.

Otherwise I thought in bounded contexts of the DDD. I even wondered if the problem would not be the term "Service" being used in two different contexts, representing different things. The problem is that despite identifying the problem, I did not identify how to deal with the issue of "service type".

As this seems to me even common, I thought if there would be a design Pattern that deals with it. Is this type of situation the subject of some design Pattern? There is 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?

  • Without knowing details of the implementation, I believe your last paragraph is the best way.

  • @Renan, I did not give details of implementation, because I thought the question would be better received in a more general way. Do you think she could be better off giving details? Also, regarding the implementation, I only found a problem: how would I let the user choose the type that will be used to create the service at the end? An Enum with possible types and then a mapping of Enum values to classes?

2 answers

1

Modeling of the Code

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. Then, according to the system configuration, you instantiate one of the implementations when performing the calculation.

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

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

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

class Calculohoras { int calcularHoras(int mes, Metodockulohorasapagar metodo) { List servicesDoMes = chargeServicesDoMes(mes); int timesAPagar = method.calculateHorasAPagar(DoMes services); cobrarCliente(horasAPagar); } }

Remarks:

  • 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 only illustrative, use as your case.

General design

Design patterns are interesting, but almost always not a solution on their own, as well as being very low-level.

Thinking about the design of a solution to make functionality flexible involves thinking about various aspects such as:

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

And so it goes. Only then does the code become important.

The first question to be asked in this context is: it is 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 point of view of users, if they try to perform the calculation without selecting a strategy, give a visual answer saying that the result will be unavailable until it defines the strategy.

If the answer is negative, then a possible solution would be to have a set of common strategies and to allow the extension of the rules. This is a tricky point, because 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 is simple, but for many it is a headache. It is not a good solution if the rules vary frequently.
  • You may be able to identify the variables involved in defining new rules and create a configurable rule via screen. This solution allows a little flexibility, but still involves determining all 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 mathematical 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 run such a function on the server. This solution is interesting as its customers are IT 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’s database by some administrative screen or SQL script and have a new function in the system without having to generate a new version.

1

Feature Flags

That’s the name of Pattern what search. You can read more about this in that other Stackoverflow response, or on Wikipedia about Feature Toggle.

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

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

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

There are lots of other reasons you would want to use this feature - one of the main ones is to allow continuous implementation: publishing new features for production having the new feature disabled until it is completed. We often use what we call a 'dev cookie' to show unfinished features to the collaborator team. This way we can test partially completed resources already in production. And when those are ready, just activate the feature to make it public to everyone.

This is a simple package that helps you do this with ASP.NET MVC: https://github.com/cottsak/DevCookie

Fowler also has a old article with much more details.

  • Enable or disable specific features or features doesn’t seem the same concept of choose one of many ways to accomplish a certain process.

  • It depends on your implementation. You can easily make a "Feature" type "Processoqualquer:Enviaemail" and per client you enable or disable. And in the end, this Feature will be just one step away from your flow/process.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.