POO e Padrões de Projetos são lixo
Nota:
Infelizmente a regra de negócio do TabNews não me deixa responder todos os comentários. Por isso vou responder por aqui. Mais abaixo você encontrará o post original.
Como o post tem limite de caracteres, coloquei os comentários aqui
smiley
POO e padrões de projetos muitas vezes não são a melhor solução para um problema.
Surge a pergunta: em que situação POO é a melhor solução? E para qual problema?
Simula é considerada a primeira linguagem orientada a objetos e muitas linguagens OO foram influenciadas por essa linguagem, incluindo Java. Mas não entendi o que tem a ver com o post em si?
É lixo para uns, luxo para outros.
Concordo. Escrevi esse post para gerar essa discussão, porque na cultura de programação tem essa ideia de que POO é útil para alguns casos. Mas na minha opinião e experiência não vejo utilidade. E outros programadores, que coloquei alguns links no post, também compartilham dessa opinião.
kht
São ferramentas que têm sua utilidade.
Surge a pergunta: em que situação POO é útil?
POO, definida por Alan Kay, não é o foco da minha argumentação. Como ele mesmo já disse, o foco são mensagens e não objetos, então deveria se chamar Message Oriented Programming.
uriel
Obrigado por concordar. Realmente, o objetivo do título era chamar a atenção mesmo e tentar gerar uma discussão interessante sobre o tema. Visto que é tão comum pessoas defenderem POO, resolvi mostrar um ponto de vista diferente. Mas pelos downvotes percebi que as pessoas não têm interesse nisso.
POO nem padrão tem. Ninguém sabe a definição dela!
Verdade. Quando pesquisei sobre POO para escrever este post, vi isso também. Muitos não conseguem definir ou acham que tem várias definições de POO. Na minha opinião, o que faz mais sentido é a agregação de dados e operações na mesma estrutura, ou seja, objeto.
RecursiveError
desempenho depende da implementação.
tem seus próprios pontos fracos e fortes, nenhum dos links critica OO em si, apenas apresenta soluções mais adequadas para um problema específico.
Os três links que eu coloquei no post mostram que a implementação OO tem pior desempenho que DOD. O terceiro link é mais sutil, mas ele menciona no vídeo.
OO não é bala de prata, obviamente não serve para tudo.
Então para que serve OO? Quando ela é útil? Qual problema ela resolve?
DoD não substitui OO, na verdade eles são ótimos juntos.
Os dois conceitos são completamente opostos. OO junta dado e operação em uma estrutura. DoD separa os dois.
onde isso?
Nos livros que mencionei. Eles escreveram heurísticas para escrever código OO melhor.
problemas de 1994 não são os mesmos de hoje.
Os livros são de 1996, 2004, 2016 e 2017. Afinal, quais problemas não são mais os mesmos de hoje?
não existe explicitamente OO, imagino que você esteja falando de Java/C#/C++
Estou falando da OO mais comum, que está presente em Java e C++. É o que menciona várias vezes no post.
Erlang usa a definição de Alan Kay
Exatamente, mas não é essa definição que estou argumentando contra.
Não é o OO que deixa complexo, porque não é o OO que resolve o problema, quem resolve é você, desenvolvedor, é sua função como Dev de levantar requisitos, é sua função como Dev colocar os trade-offs de cada implementação na balança, é sua função como Dev ser um Dev.
Exatamente, e qual é a vantagem de usar POO?
os códigos "Não-OO" que você citou são ótimos exemplos do bom uso de OO, eles usam conceitos desse paradigma, porque têm utilidade e são simples se usados de forma correta, que nem qualquer coisa. (link)
Não, eles não usam OO. O link que você colocou mostra que na versão 2 do kernel do Linux teve alguns conceitos de OO no passado, há mais de 10 anos. O artigo apenas cita que encontrou esses conceitos no kernel mas não explica em detalhes quais as vantagens. Mas hoje o kernel está na versão 6 e o código já está bem diferente do que era.
código que refatorou é um código feito para aprendizado desses conceitos
Então porque não foi usado um problema que realmente precisasse de Design Patterns? Mesmo que seja de aprendizado, eu espero que seja algo relevante para a solução do problema. E esse é um problema em geral com vários posts e vídeos na internet, eles dão exemplos muito simples, como: Cachorro herda de Animal. Seria mais vantajoso mostrar exemplos reais em projetos grandes de como foi implementada a solução e analisar os trade-offs de outras soluções. Na minha versão o código ficou mais simples sem a necessidade do Design Pattern.
isso aqui é só meteção de loko, porque que Java e C++ é popular, ent? meter esse papo em TI não cola, C++ com quase 4 décadas de história .... se não tivesse vantagem Java taria morto já.
Em uma palavra: Marketing
Se fosse tão bom não haveria necessidade de criar outras linguagens de programação.
os "não-OO" aí de cima que diga né
Não entendi.
Segue o post original:
Quando comecei minha carreira em programação, aprendi que POO é uma ferramenta e, como toda ferramenta, tem seu lugar para resolver um problema.
A princípio parecia fazer sentido, mas à medida que fui adquirindo mais experiência em programação, percebi que POO não traz nenhum benefício. É por isso que escrevi para ignorar POO.
A primeira razão para ignorar OOP é que isso leva a um desempenho ruim:
- Sistemas de componentes de entidades e design orientado a dados
- POO está morto, vida longa ao design orientado a dados
- Design Orientado a Dados e C++
Outra razão é que vários livros tentam corrigir POO:
Esses livros mostram que POO é falho visto que
eles fornecem diretrizes para escrever melhor código OO.
Todos os três livros combinados têm cerca de 1.200 páginas de heurísticas!
Tente se lembrar de tudo isso!
Michael Feathers escreveu em seu blog dizendo que seu livro "Trabalho Eficaz com Código Legado"
deveria se chamar "Trabalho Eficaz com Código Orientado a Objetos".
Eu me pergunto por que não existe um livro para trabalhar com código funcional ou procedural legado.
Provavelmente porque não existe uma técnica secreta, é muito simples de lidar, então não precisa de um livro para isso.
Outra razão é que linguagens modernas, como Zig, Go e Erlang, não adotam explicitamente a POO e não a incentivam. Algumas linguagens mais antigas, como Java, C# e C++, estão se afastando da POO através da implementação de recursos funcionais.
No meu primeiro post, mencionei que Rust não adota POO explicitamente, mas a documentação oficial mostra que sim. No entanto, parece que não é muito divulgado.
Alguns defensores da POO afirmam que a POO é mais adequada para softwares grandes e complexos. Esta afirmação é um absurdo completo. Existem muitos projetos não-OO grandes, complexos e bem-sucedidos: Git, Linux, Redis, Nginx, Postgres e SQLite. Você pode escrever software grande, complexo e bem-sucedido em qualquer paradigma, até mesmo assembly!
Outros defensores afirmam que POO é melhor para código de interface gráfica.
Mas esta não é a única abordagem para escrever código de interface gráfica, como
interface gráfica de modo imediato.
Uma das afirmações mais irritantes é quando alguém critica um código OO e diz que o desenvolvedor
fez mais complicado do que precisa e não é culpa da POO.
Os desenvolvedores podem projetar soluções excessivamente complicadas, mas acredito firmemente
que POO leva a soluções excessivamente complicadas.
Para finalizar esta seção, gostaria de dar um exemplo onde o código procedural é muito mais simples que o código OO. Martin Fowler, que escreveu o livro Refactoring, reescreveu o exemplo da Loja de Vídeo em JavaScript, onde calcula a fatura do cliente e imprime o extrato.
Na primeira versão, ele escreveu em Java. O código inicial tem três classes e 88 linhas de código. Tudo isso cabe facilmente em 42 linhas de JavaScript. Se você adicionar tipagem, aumenta para 57, mas ainda menos que Java.
Você pode até traduzi-lo para C, que, apesar de ser mais antigo que Java, tem uma certa simplicidade que falta ao Java.
Já que já discuti que POO é lixo. Vamos para Padrões de Projeto. Como o título diz: “Padrões de Projetos: Soluções Reutilizáveis de Software Orientados a Objetos” é específico para POO.
O único propósito dos padrões de projeto é corrigir deficiências na linguagem, especialmente C++ e Java.
Os autores concordam que alguns padrões não fazem sentido em outra linguagem porque possuem mecanismos melhores para resolver um problema.
O trecho do livro:
...alguns de nossos padrões são suportados diretamente pelas linguagens orientadas a objetos menos comuns. O CLOS possui vários métodos, por exemplo, que diminuem a necessidade de um padrão como Visitor (página 331). Na verdade, existem diferenças suficientes entre Smalltalk e C++ para significar que alguns padrões podem ser expressos mais facilmente em uma linguagem do que em outra.
e a maioria dessas linguagens existia antes de Java e C++, que são as linguagens alvo do livro.
Além disso, Peter Norvig apontou que
"16 dos 23 padrões têm uma implementação qualitativamente mais simples em Lisp ou Dylan".
Outra postagem interessante mostra como Clojure simplifica esses padrões.
Se C++ ou Java tivessem sido baseados em Lisp, então o livro de padrões nunca existiria.
A escolha da linguagem de programação é importante porque influencia o ponto de vista de cada um. Nossos padrões assumem recursos de linguagem de nível Smalltalk/C++, e essa escolha determina o que pode e o que não pode ser implementado facilmente. Se assumissemos linguagens procedurais, poderíamos ter incluído padrões de design chamados “Herança”, “Encapsulação” e “Polimorfismo”.
Herança, encapsulamento e polimorfismo não são padrões!
Eles são simplesmente recursos de linguagem. Eles não resolvem um problema recorrente.
Eu também acredito
que Padrões de Projeto não descrevem problemas reais
mas problemas fictícios da mentalidade de design da POO.
Algumas citações do livro explicam um pouco sobre o design da POO em geral.
A parte difícil do design orientado a objetos é decompor um sistema em objetos. A tarefa é difícil porque muitos fatores entram em jogo: encapsulamento, granularidade, dependência, flexibilidade, desempenho, evolução, capacidade de reutilização e assim por diante. Todos eles influenciam a decomposição, muitas vezes de formas conflitantes.
As metodologias de design orientadas a objetos favorecem muitas abordagens diferentes. Você pode escrever uma declaração de problema, destacar os substantivos e verbos e criar classes e operações correspondentes. Ou você pode se concentrar nas colaborações e responsabilidades do seu sistema. Ou você pode modelar o mundo real e traduzir os objetos encontrados durante a análise em design. Sempre haverá desacordo sobre qual abordagem é a melhor.
Esta é a falha fundamental do POO. Supõe que devemos
projetar o código em torno de objetos, não da solução.
Isso leva a um design estranho e a uma estrutura complexa, semelhante a este projeto satírico
FizzBuzzEnterpriseEdition.
Os padrões de projeto resolvem muitos dos problemas diários enfrentados pelos designers orientados a objetos.
Eles enfrentam esses problemas porque POO é lixo.
A estrutura de tempo de execução de um programa orientado a objetos geralmente tem pouca semelhança com sua estrutura de código. A estrutura do código é congelada em tempo de compilação; consiste em classes em relacionamentos de herança fixa. A estrutura de tempo de execução de um programa consiste em redes de objetos em comunicação que mudam rapidamente. Na verdade, as duas estruturas são em grande parte independentes.
Com tanta disparidade entre as estruturas de tempo de execução e de compilação de um programa, fica claro que o código não revelará tudo sobre como um sistema funcionará. A estrutura de tempo de execução do sistema deve ser imposta mais pelo designer do que pela linguagem. Os relacionamentos entre objetos e seus tipos devem ser projetados com muito cuidado, pois determinam quão boa ou ruim é a estrutura de tempo de execução.
Esta é outra razão pela qual a OOP leva a um design ruim. Torna mais difícil entender o programa lendo-o porque é uma rede de objetos comunicantes.
Não consideramos esta coleção de padrões de projeto completa e estática; é mais uma gravação de nossos pensamentos atuais sobre design.
Então, por que não há uma segunda edição depois de 30 anos?
Para finalizar esta seção, refatorei um jogo simples.
O jogo fez uso intenso do padrão observer. Então, como demonstração, removi as camadas indiretas e simplifiquei o código geral. No final, o padrão observer era desnecessário.
Você pode comparar você mesmo, o código original e minha versão refatorada. Então, veja qual é mais fácil de ler e entender.
Conclusão
POO tornou-se amplamente utilizado devido à popularidade de C++ e Java, não porque seja inerentemente bom. POO não oferece nenhum benefício que as pessoas dizem. O código procedural é tão flexível, modular e reutilizável quanto OO. A ideia de que POO é de alguma forma melhor nisso é um absurdo completo.
Tenha cuidado com qualquer pessoa que esteja “vendendo” padrões para você. Certifique-se de que eles sirvam a um propósito e resolvam seu problema. Não se esqueça de que as estruturas de dados e os algoritmos são muito mais fundamentais do que qualquer padrão de design.
A principal lição desta postagem é:
Se você ignorar POO, seu código ficará mais simples.
Para finalizar meu caso contra POO, selecionei uma lista de links que discutem um pouco sobre como a POO é ruim:
- OOP é lixo: exemplo de 3.800 linhas de código
- Dados privados e getters/setters
- Santo Graal da POO
- Discutindo Roc e sistemas funcionais
- Pare de escrever classes
- O que nunca é programação (palestra informal)
- "você pode falar sobre arquitetura de objetos e padrões para sempre sem ensinar nenhuma programação"
- "Então POO é uma porcaria?"
- Design Patterns são lixo - Versão estendida