OOP está se tornando mais fácil ou mais difícil? [fechadas]

36

Quando os conceitos de Programação Orientada a Objetos foram introduzidos aos programadores anos atrás, parece interessante e a programação foi mais limpa. OOP foi assim

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);

Isso foi mais fácil de entender com nome auto-descritivo.

Mas agora o OOP, com padrões como Objetos de Transferência de Dados, Objetos de Valor, Repositório, Injeção de Dependência etc., tornou-se mais complexo. Para alcançar o que precede, pode ser necessário criar várias classes (por exemplo, resumo, fábrica, DAO etc) e implementar várias interfaces

Nota: Não sou contra as práticas recomendadas que facilitam a colaboração, teste e integração

tunmise fasipe
fonte
23
Criar uma boa arquitetura de software sempre foi difícil e sempre será (provavelmente).
Johannes
6
Eu renomearia addItempara adde removeItempara remove. Porque é mais fácil de ler. stock.add(item)ou stock.remove(item). E mais OOP orientado.
razpeitia
1
OOP original parecia quase nada com o que você mostrou. OOP não é sobre sintaxe , é sobre um tipo de abstração popularizada pelo Smalltalk. Isso não prova necessariamente que seu argumento está errado, nem a premissa é falha; pelo contrário, é ainda mais verdadeiro do que você imagina.
Konrad Rudolph
1
você está comparando maçãs e laranja, pela sua lógica, e a programação imperativa (ou seja, loops e se-condição) é mais simples do que todas as coisas que temos hoje. A programação imperativa é a base para classes / OOP, e classes / OOP é a base para padrões de design. As coisas se tornam mais complexas à medida que você progride porque está resolvendo problemas mais complexos.
Lie Ryan
2
@LieRyan - Eu vi problemas se tornarem complexos só porque ninguém no comando foi capaz de resolvê-los com uma simples programação imperativa e os atacou com padrões de design em cima de OOP e em cima da solução imperativa simples que deveria ter sido implementada sozinha.
Mouviciel 11/06/12

Respostas:

35

OOP em si não mudou muito desde o seu início. Alguns novos ângulos foram explorados, mas os princípios básicos ainda são os mesmos. O conhecimento coletivo reunido ao longo dos anos torna a vida do programador mais fácil do que difícil. Os padrões de design não são um obstáculo; eles fornecem uma caixa de ferramentas de soluções para problemas padrão, destilada por anos e anos de experiência.

Então, por que você percebe o POO hoje como mais complexo do que quando começou a usá-lo?

Um motivo pode ser que o código ao qual você está sendo exposto se torne mais complexo - não porque o OOP se tornou mais complexo, mas porque você avançou na escada de aprendizado e conseguiu ler bases de código maiores e mais complexas.

Outro motivo pode ser que, embora o paradigma da complexidade não tenha mudado, o tamanho e a complexidade de um projeto de software comum podem muito bem ter. Com o poder de processamento disponível em telefones celulares de nível cliente que teria sido o sonho de um desenvolvedor em um servidor há menos de duas décadas, o público em geral esperava basicamente GUI animadas e lisas até mesmo para o aplicativo descartável mais barato, e os PCs de mesa mais potentes sendo mais poderosos do que um "supercomputador" dos anos 80, é natural que a barra tenha aumentado desde os primeiros dias do Smalltalk e C ++.

E há o fato de que, em aplicativos modernos, simultaneidade e paralelismo são a norma e não a exceção, e os aplicativos frequentemente precisam se comunicar entre máquinas diferentes, produzindo e analisando todo um zoológico de protocolos. Embora a OOP seja excelente como paradigma organizacional, ela tem suas limitações, como qualquer outro paradigma: por exemplo, ela não fornece muita abstração para simultaneidade (a maioria das implementações é mais ou menos uma reflexão tardia ou terceirizada inteiramente para bibliotecas) , e não é a melhor abordagem possível para criar analisadores e transformar dados. A programação moderna frequentemente se depara com as limitações do paradigma OOP, e os padrões de design podem levar você até agora. (Pessoalmente, Considero o fato de que precisamos de padrões de design um sinal disso - se o paradigma fornecesse essas soluções prontas para uso, seria mais expressivo para esses problemas e as soluções padrão seriam óbvias. Não há padrão de design para descrever a herança do método, porque é um recurso essencial do OOP; mas existe um padrão de fábrica, porque OOP não fornece uma maneira natural óbvia de construir objetos polimorficamente e de forma transparente.)

Por esse motivo, a maioria das linguagens OOP modernas incorporam recursos de outros paradigmas, o que os torna mais expressivos e mais poderosos, mas também mais complexos. O C # é o principal exemplo disso: possui raízes óbvias de POO, mas recursos como delegados, eventos, inferência de tipos, tipos de dados variantes, atributos, funções anônimas, expressões lambda, genéricos etc. originam-se de outros paradigmas, principalmente a Programação Funcional .

tdammers
fonte
Portanto, os padrões de design adicionaram as complexidades. Os padrões de design de significado não são necessariamente POO, mas são adicionados para aprimorar o POO.
tunmise fasipe
@tunmisefasipe: Não é bem assim. Os padrões de design são apenas soluções comprovadas para problemas padrão; eles não são uma 'adição' ao POO, mas uma conseqüência. A complexidade já estava lá; os padrões de design apenas fornecem estratégias de livros de receitas para enfrentá-lo.
tdammers
17

Não, está se tornando um excesso de engenharia. E você está certo - no bate-papo do SO C ++, frequentemente brincamos sobre o AbstractSingletonFactoryProxyBeanBridgeAdapterManagers que vemos no código Java.

Mas um bom código não exibe essa propriedade. Em bom código, você ainda pode dizer

std::stack<int> s;
s.push(5);
s.pop();
DeadMG
fonte
4
Não está claro em sua postagem, mas acho que o excesso de engenharia é evidente nos códigos Java e C ++. Não é uma propriedade de nenhuma das linguagens por si só, mas da prática dos programadores ... Ambas as linguagens permitem escrever um bom código, embora nenhuma (IMO) seja particularmente adequada para ela :) As estruturas em Java são péssimas, infelizmente.
Andres F.
12
Falando sobre excesso de engenharia, este tópico é obrigatório: discuss.joelonsoftware.com/default.asp?joel.3.219431
Secure
3
@AndresF. true, mas você não parece obter muito disso no código C ++, enquanto no Java e .NET: basta olhar para o padrão de design MVVMVMMD msdn.microsoft.com/en-us/magazine/hh965661.aspx como um exemplo de como você pega 'código simples' e coloca um padrão de design nele para torná-lo 'mais fácil' e depois coloca outro padrão de design no padrão de design porque o padrão original não era tão simples quanto o anunciado. O excesso de engenharia está se tornando cada vez mais comum.
precisa
5
Eu argumentaria com a parte do "devir". O excesso de engenharia é tão antigo quanto a engenharia.
Gort the Robot
4
@AndresF. Somos particularmente anti-Java no bate-papo, mas é verdade que o Java, mais do que o C ++ , incentiva o excesso de engenharia porque o torna mais acessível (GC), e as bibliotecas Java corporativas populares popularizaram esse estilo, como você observou você mesmo.
Konrad Rudolph
10

Eu diria que os problemas com "complexidade" mencionados não têm nada a ver com OOP. Tem mais a ver com separar preocupações.

Há muitos anos, trabalhei em um sistema em que a classe de domínio tinha a responsabilidade de carregar-se do banco de dados, por exemplo,

var userId = Request.QueryString["UserID"].ToInt();
var user = new User(userId);
user.Name = ...;
...
user.Save();

Este é um código muito claro. Não há problema em entender isso. O problema, no entanto, seria na unidade de teste do código. Ou seja, como eu testaria a Userclasse sem ter que carregar uma do banco de dados? E como eu testaria esse código de manipulação de solicitações da Web sem ter acesso ao banco de dados? Simplesmente, não é possível.

É por isso que temos um padrão como um repositório, para separar a responsabilidade de manipular a lógica do domínio de um usuário da funcionalidade de realmente carregar e salvar uma em um repositório de dados. O COI ajuda a reduzir o acoplamento, também tornando o código mais testável, etc.

Então, se voltarmos ao exemplo que você escreve, o que você faria com o material depois de criá-lo? Salve-o no banco de dados

Stock stock = new Stock();
stock.addItem(item);
stock.removeItem(item);
this.StockRepository.Add(stock);

O vermelho! Não há movimento na progressão do POO que sugira que seja mais difícil. Infelizmente, se você optar por usar um mapeador OR para seu código de acesso a dados, poderá encontrar o problema de que o mapeador OR está colocando restrições sobre como você pode escrever seu sistema. Mas isso é outra questão.

Se você é novo nesses padrões, pode precisar aprender um novo estilo de programação. Mas esse estilo de programação não é mais difícil do que a programação OOP da velha escola.

Pete
fonte
Você sabe o esforço que precisa fazer para configurar seu repositório. Embora depois de configurado, ele se torne reutilizável.
tunmise fasipe
talvez o problema esteja no teste de unidade, se tivéssemos ferramentas melhores para testar o todo (como você precisa de qualquer maneira), em vez dos pequenos pedaços, teríamos sistemas com menos bugs?
precisa
2
@gbjbaanb: já temos isso, é chamado de integração / teste funcional. O teste de unidade serve a um propósito diferente, mas igualmente necessária
Kevin
@gbjbaanb - Já temos ótimas ferramentas para testes em todo o sistema / aceitação, como o Pepino na plataforma Rails. Mas as equipes que são realmente boas e escrevem muito poucos bugs, mas também fornecem rápido, escrevem muitos testes de unidade e apenas alguns testes em todo o sistema. Veja sobre o "triângulo de teste", por exemplo, aqui: jonkruger.com/blog/2010/02/08/the-automated-testing-triangle
Pete
4

Nem. Nossos problemas realmente não mudaram; a barra de código aceitável foi aumentada.

Para alcançar o que precede, pode ser necessário criar várias classes (por exemplo, resumo, fábrica, DAO etc) e implementar várias interfaces

Você não precisa fazer isso. Mas se não o fizer, surgem problemas; problemas que sempre estiveram lá. Agora, porém, os programadores têm experiência suficiente para identificar esses problemas e fornecer mecanismos para aliviá-los (se necessário). Aprendemos mais sobre eles e apresentamos soluções melhores (veja - opiniões dos programadores sobre o singleton, por exemplo).

Mas você também deve perceber que a introdução de programadores para OO (ou qualquer outra coisa) tenderá a encobrir as circunstâncias excepcionais. É simplesmente mais fácil explicar o caminho feliz e se preocupar com o resto depois que os iniciantes o seguirem. Não há bala de prata; então sim, acho que as coisas sempre parecerão mais difíceis quando essa ilusão idílica for quebrada ...

Telastyn
fonte
3

Os exemplos de "introdução ao OO" são muito mais simples que um aplicativo do mundo real. Você só precisa de uma classe para alcançar o acima. O problema é que não faz muito. Alguns padrões de design tentam chegar perto (como ActiveRecord.) Mas, em última análise, qualquer exemplo que não seja trivial terá mais de uma classe; está bem.

Jeanne Boyarsky
fonte
Observe também que as estruturas se acumulam com o tempo. Então, sim, a programação requer mais conhecimento. Isso também significa que se pode fazer mais em menos tempo.
precisa
3

As linguagens de programação que usam o OO hoje estão tentando atender a requisitos e ambientes complexos que continuam mudando. OO permite que seus adotantes ocultem diversos níveis de complexidade (entre outros recursos), para que a codificação se torne mais clara e mais fácil de construir e entender. No entanto, esse recurso nem sempre está pronto para uso. No seu exemplo, o OO permitiu que você ocultasse alguns detalhes de mim, fornecendo um método para gerenciar itens em uma coleção e pode até persistir usando o método "AddItem". Gastar esforços para ocultar a complexidade pode resultar em uma estrutura fácil de usar e reutilizável que simplifica a vida. Por exemplo, muitas implementações do ORM permitem a comunicação com bancos de dados sem que o programador grave os detalhes do SQL. Isso é realmente poderoso e torna mais simples para o desenvolvedor.

Os padrões aos quais você se refere são exatamente isso. Eles deveriam facilitar sua vida. Mas depende de você adotá-las e ajustá-las. O fato de que é necessário mais trabalho é apenas porque você obtém mais benefícios. É como pagar mais por uma Ferrari. Se você quiser os extras, pague por eles. Portanto, se você decidir criar uma solução escalável de N Camada que possa ser executada em vários servidores e bancos de dados de back-end diferentes, haverá um custo para isso. Se o seu aplicativo não exigir essa complexidade, ignore as peças extras e volte para a solução mais simples que atenda às suas necessidades (KISS & YAGNI).

Então, para finalizar, não acho que OOP como um conceito em si esteja ficando mais complexo, nós, os usuários do OOP, temos a opção de usá-lo de maneiras diferentes, e isso é uma coisa boa.

NoChance
fonte
Pontos claros. Eu conheço YAGNI. O que é o KISS?
tunmise fasipe
2
@tunmisefasipe, KISS é um nome abreviado para um princípio de design. As palavras originais são "Keep It Simple (Stupid)" (ref: en.wikipedia.org/wiki/KISS_principle ), mas um fraseado mais educado pode ser "Keep It So Simple".
NoChance
3
@tunmisefasipe - KISS = Mantenha as coisas simples, estúpidas. A frase que eu repita a mim mesmo mais, e mais, e mais, e ele ainda não parecem sempre afundar.
Michael Kohne
@MichaelKohne, todos nós fazemos! Eu acho que é uma arte ser capaz de simplificar as coisas. E = M C C diz muito de uma forma muito concisa!
NoChance
3

Resposta curta : Sim, porque você lida com problemas mais difíceis.

Resposta longa (fortemente tendenciosa) : Para mim, os padrões de design geralmente indicam que algum paradigma tem problemas em determinada área. Os padrões OOP lidam com problemas de OOP (no nível inferior, os padrões Java lidam com problemas de Java), os padrões FP lidam com problemas de FP etc.

Durante a programação, você pode ter prioridades diferentes. Você pode querer ter o programa correto, pode reduzir o tempo de colocação no mercado, o programa mais rápido possível, a manutenção a longo prazo ou a manutenção instantânea por uma nova contratação. Dependendo do estado em que você está, você terá uma diferença muito grande - se você estiver programando o controlador da usina, deseja fazê-lo da primeira vez e não corrigir erros de vez em quando ("O colapso ocorre toda vez que você pressiona Ctrl+Alt+Del?"). Se você estiver no HPC, a lógica pode ser relativamente simples, mas você deseja executá-lo o mais rápido possível, etc. etc. Além disso, alguns paradigmas ajustam-se melhor a certos problemas (como IA e programação lógica, dados e bancos de dados relacionais).

OOP é, até certo ponto, estendido 'bom demais' em casos simples e está "modelando a vida real". Por exemplo, no primeiro livro sobre OOP Eu li havia aulas Person, Employeee Managercom is-arelacionamento. Até aí tudo bem, mas e se o funcionário for promovido a gerente?

Por outro lado, outros paradigmas têm lições mais difíceis na primeira vez - por exemplo, FP com variáveis ​​imutáveis ​​(o engraçado é que as pessoas que tiveram experiência com programação geralmente acham mais difícil aprender do que aquelas para quem essa é a primeira língua) - no entanto, no final das contas, elas são não mais difícil do que POO. Testar funções puras é trivial e, em Haskell / Scala / ..., você tem ferramentas que geram testes para você.

PS. Sim - a resposta é tendenciosa contra o POO e admito que, até certo ponto, ela está "em reação" ao POO. OOP tem seus usos, mas não é a única solução final na minha opinião.

PPS. Sim - use padrões de design - eles simplificam a programação de POO.

PPPS. Eu usei OOP como sinônimo de programação imperativa OOP.

Maciej Piechotka
fonte
2

Eu acho que é mais um caso de documentos e exemplos se tornando mais realistas.

Os primeiros livros de POO (particularmente os primeiros livros de Java) apresentavam uma visão absurdamente simplificada da programação de aplicativos. Os exemplos "Débito de uma conta bancária com um programa Java de 10 linhas" sempre foram particularmente irritantes, pois eu vi exemplos da vida real dessa tarefa simples executando 6000 linhas de código COBOL (e a substituição do Java tentando executar 3500 linhas antes de ser abandonada). inviável!).

Felizmente, os livros de OO agora tendem a reconhecer as complexidades da vida real e fornecem exemplos úteis de como lidar com eles.

Mas se você quiser ver como administrar uma conta bancária em apenas 15 linhas de programação funcional de código , é o seu

James Anderson
fonte