Talvez a maior promessa do uso de paradigma orientado a objetos seja a reutilização de código. Alguns contestam que isso foi alcançado. Por que foi (não) alcançado?
A reutilização de código como OOP define, torna os projetos mais produtivos?
Ou mais gerenciável? Ou mais fácil de manter? Ou com mais qualidade?
Provavelmente todos concordamos que a reutilização de código é uma coisa boa, mas existem várias maneiras de atingir esse objetivo. A questão é sobre o método de reutilização de código oferecido pelo OOP. Foi uma coisa boa? Existem métodos melhores para obter a reutilização de código do que a orientação a objetos, subclassificação, polimorfismo etc.? Que maneiras são melhores? Por que ?
Conte-nos sua experiência com a reutilização de POO ou com a reutilização de outros paradigmas.
Respostas:
A reutilização de código é uma boa idéia. Não é ótimo .
Eu tenho uma perspectiva extraída de cerca de 30 anos de engenharia de software, tentando "reutilizar".
Comecei a investigar a "reutilização de código" como um tópico de pesquisa nos anos 80, depois de descobrir que havia reutilizado o design de um SO que construí no início dos anos 70, para outro SO que construí no final dos anos 70.
A boa parte da reutilização de código é a capacidade de, às vezes, reutilizar código preexistente honesto com Deus. Mas o mundo está cheio de código; como pode encontrar o que você quer? Aqui está o que eu chamo de maldição de reutilização :
Eu sou o Papai Noel (ok Open Source) e tenho um pacote de 1 bilhão de componentes de software. Você pode ter qualquer um deles.
Boa sorte para escolher.
Para resolver bem o problema de reutilização:
Principalmente o que foi descoberto ao longo dos anos é que, para que o código seja reutilizável, ele deve ser projetado para esse fim ou contém muitas suposições implícitas. As bibliotecas de reutilização de código mais bem-sucedidas foram realmente muito pequenas. Indiscutivelmente, bibliotecas e estruturas são códigos "reutilizáveis" e são extremamente bem-sucedidos; Java e C # são bem-sucedidos não porque são boas linguagens de computador, mas porque têm enormes bibliotecas bem projetadas, implementadas e documentadas disponíveis. Mas as pessoas não olham o código fonte nas bibliotecas; eles simplesmente chamam uma API bem documentada (projetada para ser geralmente utilizável).
O que a reutilização de código não fez (OOP também) é fornecer ordens de melhoria de magnitude em nossa capacidade de codificar sistemas.
Eu acho que a principal falha é que qualquer tipo de reutilização de código é fundamentalmente limitado porque o código tem muitas suposições embutidas . Se você reduz o código, minimiza as suposições, mas o custo para construir do zero não é muito grande e os ganhos de reutilização não são eficazes. Se você criar enormes pedaços de código, eles serão praticamente inúteis em um novo contexto. Como Gulliver, eles estão amarrados à praia por um milhão de cordas minúsculas, e você simplesmente não pode se dar ao luxo de cortar todas elas.
O que devemos trabalhar é a reutilização do conhecimento para construir código . Se pudermos fazer isso, podemos aplicar esse conhecimento para construir o código necessário, manipulando o conjunto atual de suposições.
Para fazer isso, ainda é necessário o mesmo recurso de especificação para caracterizar componentes de software (você ainda precisa dizer o que deseja!). Mas você aplica esse conhecimento de "construção" às especificações para gerar o código desejado.
Como comunidade, ainda não somos muito bons nisso. Mas as pessoas fazem isso o tempo todo; por que não podemos automatizar isso? Há muita pesquisa, e isso mostra que isso pode ser feito em muitas circunstâncias.
Uma parte importante do mecanismo necessário para isso são as ferramentas mecânicas para aceitar "descrições de componentes" (esses são apenas documentos formais e podem ser analisados como linguagens de programação) e aplicar transformações de programa a eles.
Os compiladores já fazem isso: -} E eles são realmente bons na classe de problemas que enfrentam.
Modelos UML com geração de código são uma tentativa de fazer isso. Não é uma tentativa muito boa; praticamente o que se diz na maioria dos modelos UML é "Eu tenho dados parecidos com este". Muito difícil gerar um programa real se a funcionalidade for deixada de fora.
Estou tentando criar sistemas práticos de transformação de programas, uma ferramenta chamada DMS . Fiquei bastante distraído com a aplicação de transformações de programa, não tanto para abstrair especificações para gerar código, mas para codificar legado para limpá-lo. (Estes são o mesmo problema no resumo!). (Construir essas ferramentas leva muito tempo; eu faço isso há 15 anos e nesse meio tempo você tem que comer).
Mas o DMS tem as duas propriedades principais que descrevi acima: a capacidade de processar especificações formais arbitrárias e a capacidade de capturar o "conhecimento de geração de código" à medida que se transforma e aplicá-las sob demanda. E notavelmente, nós geramos em alguns casos especiais, algum código bastante interessante a partir das especificações; O DMS é amplamente construído usando-se para gerar sua implementação. Isso alcançou para nós pelo menos parte da promessa de reutilização (conhecimento): ganhos de produtividade extremamente significativos. Eu tenho uma equipe de cerca de 7 pessoas técnicas; nós escrevemos provavelmente 1-2 MSLOC de "especificações" para DMS, mas temos cerca de 10MSLOC de código gerado.
Resumo: a reutilização do conhecimento de geração é a vitória, não a reutilização de código .
fonte
Mostly what has been discovered over the years is that for code to be reusable, it sort of has to be designed for that purpose, or it contains too many implicit assumptions.
Cheguei a uma conclusão semelhante, mas não consegui expressá-la de maneira tão sucinta.A reutilização de código é alcançada no OOP, mas também na programação funcional. Sempre que você pegar um bloco de código e torná-lo exigível pelo resto do seu código, de modo que você possa usar essa funcionalidade em outro lugar, será reutilizado.
Esse tipo de reutilização de código também torna o código mais gerenciável, pois a alteração desse bloco solicitável altera todos os locais para os quais é chamada. Eu diria que esse resultado também aumentou a qualidade e a legibilidade.
Não tenho certeza de que o OOP esteja lá simplesmente para fornecer a reutilização de código. Considero o POO mais uma maneira de interagir com objetos e abstrair os detalhes da estrutura de dados.
Da Wikpedia:
fonte
double sqrt (double x)
? Funções puras são o arquétipo da reutilização.double sqrt(double x)
,float sqrt(float x)
,int sqrt(int x)
você pode definir um monte deles, enquanto que com uma linguagem de programação genérica você teriaNumber sqrt(Number x)
e ser feito com ele.Sim e não
A reutilização de código é um termo genérico para muitas atividades diferentes.
fonte
Eu postaria uma resposta longa, mas por quê? Udi Dahan explica isso muito melhor do que eu.
http://www.udidahan.com/2009/06/07/the-fallacy-of-reuse/
Aqui está o começo do post:
fonte
Concordo com Chris, a programação funcional é uma boa maneira de reutilizar o código.
Muitos programas possuem estruturas de código recorrentes. Para isso, alguns padrões de design são usados no mundo OOP, mas isso pode ser alcançado por funções recursivas e correspondência de padrões em linguagens de programação funcionais. Para mais informações, consulte o primeiro capítulo em Programação Funcional do Mundo Real .
Eu acho que a herança profunda no POO pode ser enganosa em muitos casos. Você tem uma classe e muitos dos métodos intimamente relacionados são implementados em arquivos diferentes. Como Joe Armstrong disse sobre OOP:
As funções de alta ordem também são muito úteis quando se trata de reutilização de código, por exemplo,
map
efoldr
essa é a base do MapReduce do Google .A passagem de mensagens assíncronas também é uma boa maneira de organizar software complexo, e alguns cientistas da computação afirmam que objetos foram assumidos para se comunicar entre si de forma assíncrona como no Tell, não pergunte ao princípio de POO. Veja mais sobre isso em Programação Orientada a Objetos: O Caminho Errado? foram Joe Armstrong é citado:
A passagem assíncrona de mensagens como nos sistemas controlados por eventos e em Erlang também é uma maneira muito boa de desacoplar sistemas e o acoplamento solto é importante em sistemas complexos. Com um sistema suficientemente desacoplado, você pode evoluir o sistema enquanto estiver em execução, talvez em nós diferentes. A Unibet fez uma ótima apresentação sobre isso: Arquitetura Orientada a Eventos de Domínio
No entanto, acho que a maior parte da reutilização de código é feita usando bibliotecas e estruturas.
fonte
O humilde canal unix fez mais pela reutilização de código do que qualquer outra coisa que veio e se foi. Os objetos eram uma maneira intuitiva de estruturar o código quando eles surgiam e, mais tarde, as pessoas começaram a aderir a tudo e qualquer coisa. Em geral, os objetos são para encapsulamento e não para reutilização de código, a reutilização de código exige algo mais e a hierarquia de herança de classe é um substituto inadequado para o que realmente deveria ser um mecanismo de reutilização de código.
fonte
OOP não é especial; você pode criar código reutilizável com ou sem OOP. As funções puras são particularmente reutilizáveis : por exemplo,
java.lang.math.sqrt(double)
insere um número e fornece um número. Sem POO, mas definitivamente mais reutilizável do que a maioria dos códigos existentes.fonte
Do ponto de vista da programação funcional, o POO é principalmente sobre o gerenciamento de estado.
Na programação funcional, você pode facilmente ter centenas de funções úteis para listas: http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/Data-List.html .
Você teria centenas de métodos em uma classe List? Os métodos públicos são considerados uma interface para o estado interno que você deseja manter pequeno.
Infelizmente, em vez de (re) usar muitas funções pequenas, algumas pessoas duplicam a funcionalidade. Para mim, isso ocorre porque o OOP não incentiva a reutilização de código tanto quanto a programação funcional.
fonte
Para mim, sim, mas não o tempo todo, e isso poderia ter sido feito de outras maneiras.
Na maioria das vezes, criando uma classe base abstrata e implementações concretas dessa classe.
Muitas estruturas também usam a herança para fornecer reutilização de código (Delphi, Java, .Net são apenas algumas que vêm à mente instantaneamente).
Isso não quer dizer que muitas bibliotecas de utilitários e trechos de código também não poderiam ter funcionado, mas há algo agradável em uma hierarquia de objetos bem projetada.
fonte
Na minha experiência, tive mais sucesso ao alavancar códigos "reutilizáveis" por meio de recursos de programação genéricos (como modelos C ++) do que usando princípios de OOP, como hierarquias de herança.
fonte
OOP está muito aberto para reutilização efetiva.
Existem muitas maneiras de reutilizar. Cada classe pública pergunta: "faça de mim uma nova instância!" , cada método público diz: "me ligue!" , cada método protegido produz: "substitua-me!" - e todas essas formas de reutilização são diferentes , possuem parâmetros diferentes, aparecem em contextos diferentes, todas têm regras diferentes, como chamar / estender / substituir.
A API é melhor, é um subconjunto estrito de pontos de POO (ou não), mas na vida real, as APIs são excessivamente caras e crescem para sempre, ainda há muitos pontos de conexão. Além disso, uma boa API pode facilitar a vida, é a melhor maneira de fornecer interface para OOP.
O paradigma Datadlow fornece uma interface estrita para componentes, eles têm portas dos seguintes tipos:
Depende do domínio, existem alguns tipos de pacotes, para que consumidores e produtores possam ser conectados, se tiverem as mesmas portas (ou compatíveis). A parte mais bonita, que pode ser feita visualmente, porque não há parâmetros ou outros ajustes nas conexões, eles realmente apenas conectam um consumidor e um produtor.
Eu estava um pouco confuso, você pode dar uma olhada na tag "dataflow" no StackOverflow , ou "programação de fluxo de dados" da Wikipedia ou "programação baseada em fluxo" da Wikipedia .
(Além disso, escrevi um sistema de fluxo de dados em C ++. Portanto, OOP e DF não são inimigos, o DF é uma forma de organização de nível superior.)
fonte
No CommonLisp, existem muitos meios para obter reutilização:
digitação dinâmica, tendo seu código genérico por padrão
abstrações imperativas, ou seja, sub-rotinas
orientação a objeto, com herança múltipla e despacho múltiplo
abstração de sintaxe, a capacidade de definir novas construções sintáticas ou abreviar o código da placa da caldeira
abstrações funcionais, fechamentos e funções de alta ordem
Se você tentar comparar a experiência CommonLisp para outras línguas, você verá que a principal característica que flexibiliza a reutilização de código é a presença de ambas as abstrações orientadas a objetos e funcional. Eles são mais complementares que alternativos: sem um deles, você é forçado a reimplementar os recursos ausentes de uma maneira desajeitada. Veja, por exemplo, classes de functor usadas como fechamentos e correspondência de padrões para obter despacho de método não extensível.
fonte
- Kevlin Henney
fonte
Vou arriscar o ridículo e confessar, só tenho usado o OOP muito recentemente. Não vem automaticamente para mim. A maior parte da minha experiência envolve bancos de dados relacionais, por isso penso em tabelas e junções. Há alegações de que é melhor aprendê-lo desde o início, o que evita a necessidade de religar seu pensamento quando se trata de programação. Não tenho esse luxo e me recuso a abandonar minha carreira por causa de alguma teoria da torre de marfim. Como todo o resto, eu vou descobrir.
No começo, pensei que todo o conceito não fazia sentido. Pareceu-me desnecessário e demais. Eu sei, isso é conversa maluca. Obviamente, é preciso um certo nível de entendimento antes que você possa apreciar os benefícios de qualquer coisa ou descartá-lo por métodos melhores.
A reutilização de código exige uma disposição para não repetir o código, um entendimento de como realizá-lo e um planejamento inicial. Você deve evitar reutilizar o código quando decidir ter um caso em que simplesmente não vale a pena? E nenhuma linguagem é tão estritamente OO que gera um erro quando pensa que você deveria ter herdado o código de outra classe. Na melhor das hipóteses, eles fornecem um ambiente propício à sua implementação.
Eu acho que o maior benefício do OOP é a aceitação geral de como o código deve ser organizado. Tudo o resto é molho. Uma equipe de programadores pode não concordar totalmente sobre como todas as classes devem ser estruturadas, mas eles devem ser capazes de encontrar o código.
Já vi código processual suficiente para saber que poderia estar em qualquer lugar e, às vezes, em todo lugar.
fonte
OOP oferece mais maneiras de reutilizar o código. Isso é tudo.
fonte
Reutilização Horizontal: aspectos, características, enxertos
Às vezes, o OO clássico fica aquém da reutilização de código, especialmente quando você enlouquece toda a herança por falta de uma maneira melhor de compartilhar a funcionalidade real entre as classes. Para esse problema, foram criados mecanismos de reutilização horizontal, como AOP, características e enxertos.
Programação Orientada a Aspectos
Considero AOP como a meia laranja desaparecida da OOP. AOP não é tão conhecido, mas chegou ao código de produção.
Vou tentar explicar em termos simples: imagine que você pode injetar e filtrar funcionalidades com uma estrutura especial chamada aspecto, esses aspectos possuem "métodos" que definem o que e como serão afetados pela reflexão , mas em tempo de compilação , esse processo é chamado de tecelagem .
Um exemplo seria um aspecto que diz "para todos os métodos de determinadas classes que começam com get, o programa gravará em um arquivo de log os dados que foram obtidos e a hora em que foram obtidos".
Assista a essas duas palestras se quiser entender melhor a AOP:
Traços e Enxertos
Os traços são outra construção para definir o código reutilizável que complementa o OOP, eles são semelhantes a mixins , mas mais limpos.
Em vez de explicá-los, há um ótimo RFC PHP que explica os dois . Traços estão chegando ao PHP, já estão comprometidos com o tronco.
Em suma
OOP é fundamental na modularidade, ainda assim, na minha opinião e como normalmente a conhecemos hoje, o OOP ainda está incompleto .
fonte
OOP Fornece um conjunto de ferramentas úteis que permitem escrever código que pode ser usado em mais locais do que você poderia ter sem essas ferramentas. Se você escrever uma
PrintIt
função que pega qualquer objeto antigo e o chama.toString()
, você terá reutilizado esse código assim que o chamar com mais de um tipo de objeto. Com essas ferramentas, cada linha de código faz mais.A programação funcional está muito quente no momento entre os descolados. Fornece-lhe um todo separado de ferramentas para fazer com que cada linha de código faça mais. Provavelmente não é melhor ou funciona, mas fornece outra ferramenta na caixa de ferramentas.
(Havia uma ideia maluca para todo um nível extra de reutilização orientada a objetos: a idéia era que poderíamos definir uma única
Customer
classe e usá-la em todos os aplicativos que escrevemos. Então, os aplicativos seriam apenas um pouco de cola aqui e ali. não funcionou. Mas isso não significa que o OO falhou ou até mesmo a reutilização falhou. Os tipos básicos de código reutilizados nos aplicativos tornaram possível escrever aplicativos que fizeram mais e escrevê-los mais rapidamente.)fonte
Lendo as postagens acima, algumas observações:
fonte
O problema é mais sutil:
Portanto, o POO em si não é ruim do ponto de vista do código reutilizável , mas os tipos de código que são escritos usando o OOP são inerentemente difíceis de reutilizar .
Além disso, a programação funcional pode resultar em código mais reutilizável . Mas obter as abstrações corretamente para escrever um código funcional sensato e cumprir um prazo pode não ser possível. E abstrações "semi-direitas" serão mais fáceis de expressar o estilo OOP. E isso não tenderá a resultar na reutilização mais fácil do código - um nível mais alto de abstrações significa que o entendimento do código exigirá um investimento inicial mais alto da capacidade cognitiva limitada dos programadores.
Como um exemplo prático: o código do jogo envolve muitos estados mutáveis, porque essa é a maneira natural de pensar em codificar um jogo, a menos que seja muito enigmático / algorítmico, portanto, obviamente, acaba sendo estruturado usando OO. E é claro que é difícil reutilizar. Mas o mesmo código, contendo o mesmo conhecimento, seria ainda mais difícil de reutilizar sem OOP . E reescrevê-lo para ser um estilo funcional pode precisar mudar totalmente a maneira como você pensa sobre esse código, o conhecimento por trás dele. Sim, o conhecimento resultante por trás do código seria muito mais claro após a reescrita do OO ao FP, talvez ... mas o custo pode ser enorme e pode sero tipo de custo que também teria que ser pago pelas pessoas que desejam reutilizar o código incrivelmente inteligente e bem abstrato com o qual você acaba, paradoxalmente, as pessoas acabariam não reutilizando o código, mesmo que tecnicamente seja mais reutilizável.
... o que leva à última sutileza: a reutilização do código é sobre a interface People | Code , não apenas sobre o código. OOP faz um trabalho decente ao servir essa interface, porque mapeia bem o número de pessoas que pensam em muitos tipos de código escritos atualmente. O FP pode ser melhor para a reutilização de código, mas não para reutilizar facilmente o tipo de código que as pessoas realmente precisam escrever atualmente.Isso mudará conforme o tipo de código que precisamos escrever.
PS E se alguém quiser dizer que "OO não é sobre estado mutável, você também pode ter OO com estado imutável" ... Eu chamo isso de "FP usando classes como espaços de nome". É ótimo quando funciona para você e evita algumas falhas nos sistemas de módulos de alguns idiomas e pode resultar em código mais reutilizável. Mas isso não é OO;)
fonte