O Princípio Aberto Fechado

Open Closed Principle — OCP

Ricardo Dias
Contexto Delimitado
7 min readOct 14, 2019

--

Na engenharia de software, este é considerado por muitos como um dos mais importantes princípios. Definido em 1988 por Bertrand Meyer e publicado em 1994 em seu livro “Object Oriented Software Construction”, o Princípio Aberto Fechado é importantíssimo para a construção de softwares que visam a longevidade, ou seja, que objetivem ter longos anos de operação sem necessidade de serem totalmente refeitos.

Um paradigma modular

No artigo anterior tentei fazer um explicação sobre o que é um módulo, usando uma citação de CONSTANTINE (1974). Para fixar o assunto, é importante entender que um módulo é qualquer conjunto de código, agrupado por um motivo comum. Não importa se o conjunto de código está dentro do núcleo do software (ao lado de regras de negócio, por exemplo) ou separados na forma de pacotes avulsos. Os módulos são agrupamentos de código que fazem parte de um contexto próprio.

Por exemplo, pode-se ter um módulo responsável pelo gerenciamento de Funcionários. Nele, podem existir várias classes, cada uma com sua responsabilidade (falamos disso no artigo anterior):

  • classe para exibir dados de funcionários;
  • classe para salvar e obter dados no banco;
  • classe para gerar relatórios etc.

O desafio de qualquer projetista de software é produzir módulos, pois eles geram economia e lucratividade para a empresa. Módulos bem feitos podem ser reutilizados e, consequentemente, reduzir o tempo de entrega das novas demandas da empresa.

Shotgun Surgery

Todos os programadores, em especial os mais veteranos, já se depararam com o estilo de programação chamado Shotgun Surgery, ou Cirurgia de Espingarda, que é exatamente o contrário de uma programação modular sadia.

Cirurgia de Espingarda: um módulo tem sua regra de negócio espalhada em diversos outros módulos

O estilo tem esse nome porque, ao invés de uma funcionalidade estar toda agrupada (em um módulo independente), a mesma é espalhada em vários lugares do sistema, sem um contexto definido. Quando é necessário fazer uma correção, por menor que seja, o programador é forçado a ficar “procurando alfinete no palheiro” e seguindo pistas até chegar na fonte do problema. Como acontece em uma cirurgia onde o paciente levou um tiro de espingarda, pois os estilhaços se alojam em várias partes do corpo.

Decompondo o design do software em módulos

Com a finalidade de evitar a proliferação do efeito Shotgun Surgery, existe o design modular. Segundo MEYER (1994), “uma técnica de decomposição modular satisfatória deve atender a mais um requisito: deve produzir módulos abertos e fechados”. Neste sentido, a base do Princípio Aberto Fechado regulamenta que:

Um módulo deve estar aberto para extensão mas fechado para modificação.

Olhando para essa afirmação, parece que estamos diante de um paradoxo. O mesmo acontece quando lemos o nome do princípio: “Aberto Fechado”. Como uma coisa pode ser aberta e fechada ao mesmo tempo? É como dizer que vamos subir para baixo! À primeira vista parece estranho, mas vai fazer todo o sentido no decorrer deste artigo.

Um módulo, continua MEYER (1994), será considerado aberto se estiver disponível para extensão. Por exemplo, deve ser possível adicionar campos às estruturas de dados que ele contém ou novos elementos ao conjunto de funções que ele executa”.

O módulo também “será considerado fechado, se estiver disponível para uso por outros módulos… um módulo fechado é aquele que pode ser armazenado em uma biblioteca, para uso de outros … publicando sua interface para o beneficiar os designers de outros módulos(MEYER 1994). Outrossim, o Princípio Aberto Fechado afirma que:

Você deve poder estender o comportamento de um sistema sem precisar modificá-lo.

Isso significa que precisamos escrever um módulo, de forma que sua funcionalidade possa ser estendida, sem precisar modificar esse módulo. Em outras palavras, queremos poder alterar o que os módulos fazem, sem alterar o código-fonte dos módulos.

Observe abaixo, o seguinte código de exemplo escrito em PHP:

A classe Financeiro é responsável pela escolha de qual salário calcular, enquanto a classe Salários é responsável pelo cálculo de cada cargo disponível na empresa, no caso, Operários e Gerentes.

Qual é o problema dessa abordagem?

Se forem adicionados novos cargos na classe Salário, isso obrigará uma adaptação relacionada na classe Financeiro, adicionando novos “ifs” para suportar os novos cargos.

Em outras palavras, a classe Financeiro fere o Princípio Aberto Fechado pois:

  • Não é “fechada para modificação” quando para estendê-la é necessário modificar seu conteúdo, adicionando “ifs”;
  • Não é “aberta para extensão”, pois para que ela calcule o salário é passada uma chave simples (‘operário’, ‘gerente’ ou ‘vendedor’) que não agrega nenhuma funcionalidade nova ao Funcionário sem alterar seu conteúdo com “ifs”.

Outro problema, que pode ser percebido, é que a classe Salários fere o Princípio da Responsabilidade Única, pois possui três responsabilidades diferentes, enquanto lida com três tipos distintos de cargos.

Resumindo, esta implementação está altamente acoplada e fere os dois princípios mais básicos.

Melhorando o design com SOLID

A primeira medida para melhorar essa abordagem é separar as responsabilidades da classe Salários para cumprir o Princípio da Responsabilidade Única. Para isso precisamos desmembrar as rotinas de cálculo de salários em classes específicas, de acordo com cada contexto.

Nesta nova abordagem, cada classe possui sua própria implementação para calcular o salário, cumprindo a exigência da interface IFuncionário. Os objetos Operário, Gerente e Vendedor estarão “disponíveis para uso” no módulo Financeiro, como prega o Princípio Aberto Fechado:

será considerado fechado, se estiver disponível para uso por outros módulos… publicando sua interface para o beneficiar … outros módulos(MEYER 1994)

Para identificar qual funcionalidade está “disponível para uso”, basta consultar a interface IFuncionário para descobrir, neste caso, o método calcularSalário.

A segunda medida é oferecer flexibilidade ao novo design. A classe Financeiro deverá estar “disponível para extensão”, permitindo agregar funcionalidades a ela sem modificá-la. Isso pode ser conseguido usando composição de objetos.

Nesta abordagem, o objeto Financeiro será capaz de receber qualquer instância do tipo IFuncionário através do método pagarFuncionário(). Para entender melhor, observe o trecho de código PHP a seguir:

Note que a partir de agora, não será mais necessário mudar a classe Financeiro para adicionar novos cargos, pois ela pode prever que o método calcularSalário() irá sempre retornar um número flutuante (float) graças à exigência de IFuncionário.

Dessa maneira o método calcularSalário() “adiciona um novo elemento ao conjunto de funções” que a classe Funcionário executa, como pede o Princípio Aberto Fechado:

será considerado aberto se estiver disponível para extensão … deve ser possível adicionar campos … ou novos elementos ao conjunto de funções que ele executa (MEYER 1994)

Arquitetura de plugins

MARTIN (2014) afirma que “ouviu dizer que o Princípio Aberto Fechado é errado, inviável, impraticável e não é para programadores reais com trabalho real”.

Para refutar essa opinião, Martin usa como exemplo a utilização de Plug-ins, por vários softwares do mercado. Os Plug-ins nada mais são que módulos abertos e fechados, que oferecem novas funcionalidades ao software sem modificá-lo.

“E se o comportamento do seu sistema fosse amplamente controlado pela configuração de seus plugins? Que poder isso lhe daria? Quão fácil seria adicionar novos recursos, novas interfaces de usuário? … Quão fácil seria adicionar ou remover o REST? Quão fácil seria adicionar ou remover Spring, ou Rails, ou Hibernate, ou Oracle…” MARTIN (2014)

No VSCode, os Plug-ins permitem codificar em qualquer linguagem de programação.

Conclusão

Um design modular é muito interessante para adicionar flexibilidade a aplicações, ao mesmo tempo que pode facilitar a manutenção concorrente por parte de vários membros de um mesmo time de programadores. Como os contextos são separados, uma alteração no código dificilmente irá afetar outras áreas, como acontece com softwares que não seguem o Princípio Aberto Fechado.

Por enquanto é isso. Espero que o conteúdo esteja sendo útil. Até a próxima!

Leia também o próximo artigo sobre o assunto:

Leia todos os artigos desta série:

Referências para Aprofundamento

CONSTANTINE, Larry L. Structured design. IBM Systems Journal, VOL13, NO 2, 1974.

MARTIN, Robert C. The Open Closed Principle. 2014. Disponível em <https://blog.cleancoder.com/uncle-bob/2014/05/12/TheOpenClosedPrinciple.html>. Acesso em 14/09/2019

MEYER, Bertrand. Object-Oriented Software Construction. Prentice-Hall International series in computer science. Prentice Hall, Nova Jersey, US, 1994.

--

--

Ricardo Dias
Contexto Delimitado

Apaixonado por padrões, programação clara, elegante e principalmente manutenível. Trabalha como desenvolvedor deste 2000, incrementando a cada ano este loop…