Esclarecer o Princípio Aberto / Fechado

25

Como já expliquei, o princípio de aberto / fechado afirma que uma vez que o código escrito não deve ser modificado (além das correções). Mas se minhas regras de negócios mudarem, não devo modificar o código que implementa essas mudanças? Eu suspeito que não estou entendendo algo sobre como o princípio porque não faz sentido para mim.

Winston Ewert
fonte

Respostas:

22

Este é provavelmente o mais difícil dos princípios sólidos de explicar. Deixe-me tentar. Imagine que você escreveu uma classe de fatura que funciona perfeitamente e não possui bugs. Faz um PDF de uma fatura.

Então alguém diz que quer uma fatura HTML com links nela. Você não altera nenhum código na fatura para atender a essa solicitação. Em vez disso, você cria outra classe, HTMLInvoice, que faz o que deseja agora. Você aproveita a herança para não precisar escrever muito código duplicado no HTMLInvoice.

O código antigo que estava usando a fatura antiga não é quebrado ou realmente afetado de forma alguma. O novo código pode usar HTMLInvoice. (Se você também usar a Substitutability Liskov , o L sólido, poderá fornecer instâncias HTMLInvoice ao código existente que espera instâncias de Invoice.) Todo mundo vive feliz para sempre.

A fatura é fechada para modificação, aberta para extensão. E você deve escrever a fatura corretamente com antecedência para que isso funcione.

Kate Gregory
fonte
11
Se as regras de negócios mudarem, não há suposição de que funcione perfeitamente, sem erros, portanto o princípio de abrir / fechar não se aplica?
Jeffo
Lutei com essa regra e o que Kate sugere é basicamente o que concluí sobre ela. Nos negócios, você tenta programar classes menores e mais flexíveis para poder reutilizá-las. Se você os conseguiu funcionar corretamente, não deseja modificá-los. Mas eles raramente são totalmente "concluídos", portanto algumas modificações são inevitáveis. Observe que o texto diz "módulo", porém não objeto. Costumo aplicar com êxito o OCP no nível da função, com funções restritas que fazem uma coisa perfeitamente e nunca precisam ser alteradas.
CodexArcanum
11
@ Jeff OI distingue entre a correção de um bug (onde o código não atendia ao requisito original e ninguém o quer como ele é) e a alteração dos requisitos. Se eu exigir PDFs eo código faz PDFs, não há erro, mesmo que eu agora quero HTML (e, geralmente, as pessoas querem HTML, bem como, não em vez de.)
Kate Gregory
2
@ Winston - é isso que eu quis dizer quando disse que você deve escrever a fatura corretamente. Idealmente, já havia uma fatura bastante abstrata e você herdou a PDFInvoice esperando isso. Caso contrário, você deve violar a regra uma vez para se preparar para não quebrá-la no futuro. De qualquer forma, prever mudanças futuras é uma parte enorme de tudo isso - e essa é a parte "pegar e cortar um elefante" da receita.
Kate Gregory #
11
Sua última declaração é a mais importante. Aberto / fechado é um design ideal - e você deve obtê-lo com antecedência para alcançá-lo. Nem tudo também precisa satisfazer o aberto / fechado, mas é uma ferramenta poderosa se você pode chegar lá.
Alex Feinman
13

Você já leu o artigo The Open-Closed Principle, dos amigos do tio Bob no ObjectMentor? Eu acho que é uma das melhores explicações por aí.

Existem muitas heurísticas associadas ao design orientado a objetos. Por exemplo, “todas as variáveis ​​de membro devem ser privadas” ou “variáveis ​​globais devem ser evitadas” ou “o uso da identificação do tipo de tempo de execução (RTTI) é perigoso”. Qual é a fonte dessas heurísticas? O que os torna verdadeiros? Eles sempre são verdadeiros? Esta coluna investiga o princípio de design subjacente a essas heurísticas - o princípio aberto-fechado.

Como disse Ivar Jacobson: “Todos os sistemas mudam durante seus ciclos de vida. Isso deve ser lembrado ao desenvolver sistemas que duram mais que a primeira versão. ”Como podemos criar designs estáveis ​​diante das mudanças e que durarão mais que a primeira versão? Bertrand Meyer nos deu orientação desde 1988, quando cunhou o agora famoso princípio de aberto-fechado. Parafraseando-o:

ENTIDADES DE SOFTWARE (CLASSES, MÓDULOS, FUNÇÕES, ETC.) DEVEM SER ABERTAS PARA EXTENSÃO, MAS FECHADAS PARA MODIFICAÇÃO.

Quando uma única alteração em um programa resulta em uma cascata de alterações nos módulos dependentes, esse programa exibe os atributos indesejáveis ​​que passamos a associar ao design “ruim”. O programa se torna frágil, rígido, imprevisível e irrecusável. O princípio aberto-fechado ataca isso de uma maneira muito direta. Diz que você deve projetar módulos que nunca mudam . Quando os requisitos mudam, você amplia o comportamento de tais módulos adicionando novo código, não alterando o código antigo que já funciona.

Descrição

Módulos que estão em conformidade com o princípio aberto-fechado têm dois atributos principais.

  1. Eles são "abertos para extensão".
    Isso significa que o comportamento do módulo pode ser estendido. Que possamos fazer com que o módulo se comporte de maneiras novas e diferentes conforme os requisitos do aplicativo mudam, ou para atender às necessidades de novos aplicativos.
  2. Eles estão "fechados para modificação".
    O código fonte desse módulo é inviolável. Ninguém tem permissão para fazer alterações no código fonte.

Parece que esses dois atributos estão em desacordo. A maneira normal de estender o comportamento de um módulo é fazer alterações nesse módulo. Pensa-se que um módulo que não pode ser alterado tenha um comportamento fixo. Como esses dois atributos opostos podem ser resolvidos?

A abstração é a chave ...

Martijn Verburg
fonte
3
Este é um bom artigo explicando a abstração. Há um ponto fundamental a ser considerado, porém, e esse foi um bom desenho abstrato estabelecido em primeiro lugar? Muitas lojas têm muito código legado que a única maneira de alterá-lo é "modificação", não "extensão". Se for esse o caso, provavelmente deve-se trabalhar para mudar isso, mas até isso acontecer, você está travando a modificação do código.
Michael K
@ Chris, legal - eu também recomendo o livro "Código limpo" do tio Bob, se você gosta desse tipo de coisa.
Martijn Verburg
@ Michael - Concordo totalmente, é quase como ter que refatorar o código para torná-lo ideal para teste.
Martijn Verburg
O artigo demonstra a importância da abstração muito bem. Mas não estou entendendo a conexão entre abstrações e tentando nunca modificar os módulos depois de escrevê-los. A abstração significa que eu posso modificar o módulo X sem fazer as modificações no módulo Y. Mas não é o objetivo de fazê-lo, para que eu possa modificar o módulo X ou o módulo Y, se necessário?
Winston Ewert
11
Uau. O código é inviolável? Eu nunca fui um grande fã do tio Bob. Esse princípio é pedante, extremamente não pragmático e tem conexão limitada à realidade.
user949300
12

A resposta de Kate Gregory é muito boa, mas considere uma situação diferente em que um novo requisito pode ser atendido por uma mudança relativamente pequena na Invoiceclasse existente . Por exemplo, digamos que um novo campo deve ser adicionado ao PDF da fatura. De acordo com o OCP, ainda devemos criar uma nova subclasse, mesmo que o novo campo possa ser adicionado na implementação existente, alterando algumas linhas de código.

No meu entender, o OCP reflete a realidade dos anos 80 e início dos anos 90, onde os projetos nem sequer usavam controle de versão, muito menos tinham testes de regressão automatizados ou o benefício de ferramentas sofisticadas de refatoração. OCP foi uma tentativa de evitar o risco de quebra de código que havia sido testado e colocado manualmente em produção. Hoje, temos melhores maneiras de gerenciar o risco de quebrar o software de trabalho (sistemas de controle de versão, TDD e testes automatizados e ferramentas de refatoração).

Rogério
fonte
2
Sim, porque, na prática, não é possível criar uma classe que possa ser estendida para se adequar a todos os futuros possíveis, a menos que você proteja todos os métodos (o que é péssimo e também viola o princípio YAGNI, que é muito mais importante do que o O / C aqui).
Martin Wickman
"De acordo com o OCP, ainda devemos criar uma nova subclasse, mesmo que o novo campo possa ser adicionado à implementação existente alterando algumas linhas de código.": Sério? Por que não adicionar novos campos ou novos métodos? O ponto importante é que você está apenas adicionando (estendendo) e não alterando o que já está lá.
Giorgio
Eu acho que o princípio faz sentido quando se lida com bibliotecas / estruturas padrão. Você não deseja abrir e modificar trechos de código bem estabelecidos. Caso contrário, é tudo sobre refatoração constante e teste, teste, teste.
MasdBlasta #
@Giorgio Claro, adicionar novos campos ou métodos é o que eu recomendaria, na maioria dos casos. Mas isso não é extensão , é "modificação"; o ponto principal do OCP é que o código deve ser "fechado para modificação" (ou seja, nenhuma alteração no arquivo de origem pré-existente) enquanto está "aberto para extensão"; e a extensão no OCP é alcançada através da herança de implementação.
Rogério
@ Rogério: Por que você define a fronteira entre extensão e modificação no nível da classe? Existe uma razão específica para isso? Prefiro defini-lo no nível do método: alterar um método altera o comportamento do seu aplicativo, adicionar um método (público) estende sua interface.
Giorgio
6

Pessoalmente, acho que esse princípio deve ser tomado com uma pitada de sal. O código é orgânico, as empresas mudam e o código muda de acordo com as necessidades de uma empresa à medida que o tempo passa.

Acho muito difícil entender o fato de que a abstração é fundamental. E se a abstração estivesse originalmente errada? E se a função comercial tiver mudado significativamente?

Esse princípio garante essencialmente que as intenções e o comportamento ORIGINAL de um design nunca devem mudar. Isso provavelmente funciona para aqueles que têm APIs públicas e seus clientes têm problemas para acompanhar os novos lançamentos e alguns outros casos extremos. No entanto, se uma empresa possui TODO o código, desafio esse princípio.

Ter uma boa cobertura de teste do seu código deve facilitar a refatoração da sua base de códigos. Isso significa que não há problema em fazer as coisas erradas - seus testes ajudarão a guiá-lo para um design melhor.

Dizendo que, se não houver nenhum teste, esse princípio é válido.

user126776
fonte