How far should we follow OCP?

Asked

Viewed 123 times

4

When developing a screen for a certain part of a system, I come across a classic situation of owning some ifs to determine what action should be taken. I then linked this case to examples of OCP infringement.

However, I saw that the screen is very cohesive and with a defined scope, where I do not see, and neither does the team see at some point, a possible change in actions. In other words, new conditions will not be added in theory.

In cases like this, you must follow OCP faithfully, create the base class and its extensions, or maintain the ifs? taking into consideration that new demands should not appear?

This is the current code that theoretically violates OCP.

Controller:


        [HttpPost]
        public ActionResult InserirOrcamento(OrcamentoViewModel orcamento, string acao)
        {

            if (acao == "consultaCPF")
            {
                var retornoConsultaCPF = OrcamentoService.consultaCPF(orcamento);

                return Json(retornoConsultaCPF, JsonRequestBehavior.AllowGet);
            }

            if (acao == "listaTipoProduto")
            {
                var retornoTipoProduto = orcamento.lstTipoProduto = OrcamentoService.listaTipoProduto(orcamento);

                return Json(retornoTipoProduto, JsonRequestBehavior.AllowGet);
            }
        }

Service

 public class OrcamentoService
    {
        public static OrcamentoViewModel consultaCPF(OrcamentoViewModel orcamento)
        {
            using(ToqueEntities db = new ToqueEntities()){ 

                var retorno = db.PESSOA_FISICA
                                        .Where(x => x.PESF_CPF == orcamento.cpfPessoa)
                                        // .Join(db.CONTATOS, x => x.PES_CDID, c => c.PES_CDID, (x,c) => new { x, c })
                                        .Select(x => new OrcamentoViewModel
                                        {
                                            cpfPessoa = x.PESF_CPF,
                                            nomeClienteOrcamento = x.PESF_NOME,
                                            sobrenomeClienteOrcamento = x.PESF_SOBRENOME,
                                            PES_CDID = x.PES_CDID
                                        }).FirstOrDefault();

                    if (!retorno.Equals(null))
                    {
                        var lstContatos = db.CONTATOS.Where(x => x.PES_CDID == retorno.PES_CDID && x.CON_TIPOCONTATO != "EMAIL")
                        .Select(x => x.CON_CONTEUDO)
                        .ToList();

                            if (!lstContatos.Count().Equals(0))
                            {
                                foreach (var item in lstContatos)
                                {
                                    retorno.Contatos += item + ";";
                                }
                            }
                            else
                            {
                                retorno.Contatos = "";
                            }
                    }

                orcamento.nomeClienteOrcamento = retorno.nomeClienteOrcamento;
                orcamento.sobrenomeClienteOrcamento = retorno.sobrenomeClienteOrcamento;
                orcamento.cpfPessoa = retorno.cpfPessoa;
                orcamento.Contatos = retorno.Contatos;

                return orcamento;
           }
        }

2 answers

5


Open Close Principle

In my vision the OCP is the most complicated principle to follow within the SOLID. And often it is adopted as cake recipe. Luckily you are questioning it.

I don’t know if you’re considering that writing a class can no longer touch it at all, if that’s how the principle preached it would be the most bizarre thing ever invented. You can touch it, you just have to be careful with the contracts.

Note that what you are talking about is not even touching the class, just changing the method, and as far as I understand changes the implementation without touching the final result.

You always have to wonder why you should do something you were told to do. It needs to have a justification, it needs to have a gain put something in a code, especially if it complicates the code and the value is not very apparent.

The code

I think that segregating responsibilities is much more important, and in a way shows to be doing at one point (creating the service I do not know if it should be one, but anyway, isolates). If you do this you isolate where you should make modification.

You seem to be aware that it’s necessary to give cohesion. I will not go into the merits if you are completely united in this case even because you do not know all the details of the problem, and there is no magic formula that determines whether or not it is cohesive. Cohesion is important, follow principles are not, at least not in the same proportion.

I can’t even say that there is OCP violation there, but it is true that there are weird things like dealing with an action within a method that should be an action, I think the problem there is hurting the SRP because this action does various actions. Clearly there are 2 actions different, then you are concerned about a problem that comes after another more important one. And then it may become more obvious the violation of OCP.

The correct understanding of OCP is that if someone is going to do something other than what they are doing, that is, that same object should be created in a different context from this one, then they should not treat everything in the same object, should create a class inherited from this by adding the new functionality, thus giving flexibility without touching what exists. But that has its problem, creates coupling, dependency, hinders some flexibility. So it has a form of function delegation (maybe using lambda).

I don’t see that need in this code.

Why Use OCP?

Why should you keep something open for extension? If you don’t have a reason you shouldn’t. For example String is a type that is not open to extension under normal conditions (all types in C# are open to extension through extension methods, when they created this principle or considered that a language could have such a mechanism). There are many people who argue that classes should be sealed by default so important that is not leave open what you do not need. Extension is problematic, should only have this if it is very useful.

Why your case needs to stay open for extension?

And why this class should be closed for modification?

This idea was created to give a certain stability, to ensure that whenever someone calls it will happen the same. It’s a good idea, but you’ve seen established engineers go out doing it everywhere?

They are pragmatic, they know that trying to do this is complicated, in many cases it is better to have to do other things and make the current obsolete in some extreme cases than complicate something to give a possible stability and flexibility that may never be needed.

OCP in the MVC

To my understanding the way MVC is done does not usually cause these problems that are said to keep the class open for modification. Of course you have to be careful, but it’s not complicated, and in fact people move a lot of these classes that are actions, extending the capacity of the controller right there. The mechanism was not even thought to be closed for modification and open for extension.

If someone presents a possible problem I can change my mind.

Other problems

I won’t even mention those Equals() which are horrible, although it works. But this can be a clue that they are not thinking clearly about what to do. It may just be bad style chosen and have been thought out. I’m more afraid of this acao.executarAcao() in a data that is of the type String that seems wrong to me too. So there are much more serious concerns. I also did not mention the problem of concatenation of strings which is more basic. And I haven’t looked if other parties have no problems, or if the ToList() is needed there or is used improperly as almost everyone does. Also it does not seem very suitable a method called ConsultaCPF() modify the content of orcamento, or even if he should be changed, that’s much worse than violating OCP. It seems that the code has many other problems more basic than following the modinha of SOLID.

  • thank you for commenting on this point of action.executarAcao(), had not seen that it has placed, it is not part of the code in question, is part of my attempt to implement the OCP, I will even edit.

  • I placed a string acao because they are actions executed via Ajax. For example, the CPF query is for when the user enters the CPF and takes the focus of the input, then the query is made and returns that person’s data in the respective inputs, such as the name and the surname. In other words, everything has to be in this Inserting View so that I can submit the form and give the proper processing. But I will try to break into 3 different actions, I appreciate the remark.

  • 2

    That’s not a view, that’s a action of a controller. Since you don’t know how to use MVC correctly you need to fix it, you shouldn’t put a action inside of another action, need to recast from that controller, even though I don’t sell the rest.

  • Yes, I just refactored this Controller, I separated the 2 actions that were inside it. Much more organized and better maintenance. Actually the problem of SRP was much more latent and could hinder maintenance in the future. I ended up expressing myself wrong in the placement above when I said "view", I was referring to view linked to that controller . Separating better, I saw that I could return only JSON and let JS handle the fields.

  • How you are using as Webapi, nor view has.

  • Actually no, it’s ASP.NET MVC same hahaha, just didn’t put the view and Javascript because I did not find pertinent to the question.

Show 1 more comment

0

I suggest to study a little about the difference between Any(), All(), Count() and Count, so you don’t have problems of code performance and readability.

For example, exchange "! lstContacts.Count(). Equals(0)" by lstContacts.Any() or if the variable is a List (as in this case, even though it is not required to be) lstContacts.Count > 0.

In my opinion "! return.Equals(null)" is quite unreadable, perhaps exchange for "return != null" is more interesting.

Another problem is string concatenation, study the amount of concatenations that will be made, and depending on it, check the need to use Stringbuilder (more performative for large amounts of concatenations).

Browser other questions tagged

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