Você acha que a programação orientada a objetos é uma solução para a complexidade. Por quê? Este tópico pode ser um pouco controverso, mas minhas intenções de saber a resposta de Por que dos especialistas aqui!
18
Você acha que a programação orientada a objetos é uma solução para a complexidade. Por quê? Este tópico pode ser um pouco controverso, mas minhas intenções de saber a resposta de Por que dos especialistas aqui!
Respostas:
Não há solução para a complexidade.
Em "The Mythical Man-Month", Fred Brooks discute a diferença entre complexidade acidental e essencial na programação. A complexidade acidental é causada por nossas ferramentas e métodos, como ter que escrever e testar código adicional em um idioma, porque não podemos expressar nossas idéias diretamente, e coisas assim. Novos métodos e técnicas podem reduzir a complexidade acidental. Posso escrever programas mais rápido e melhor do que há vinte e cinco anos, porque tenho melhores linguagens e ferramentas.
A complexidade essencial vem do fato de que o que tentamos fazer com a programação é inerentemente complicado e que há uma complexidade irredutível. "Essencial", neste contexto, significa "relacionar-se com a essência da coisa" em vez de "muito necessário".
Portanto, ele alegou que não haveria bala de prata, que o software de escrita continuaria sendo difícil.
Eu recomendo fortemente que você leia o livro dele: especificamente, recomendo a edição do Silver Anniversary, com um ensaio adicional "No Silver Bullet". Nisso, ele analisa as soluções propostas para a complexidade e considera seu impacto. (O que ele considera mais eficaz é o software de encolhimento - escreva algo complexo uma vez e venda milhares ou milhões de cópias.)
Agora, a programação orientada a objetos ajuda, quando bem feita, criando abstrações e ocultando a complexidade. Um objeto de uma classe tem um determinado comportamento definido, do qual podemos raciocinar, sem se preocupar com a complexidade da implementação. As aulas escritas corretamente têm um baixo acoplamento entre si e a divisão e conquista é uma excelente maneira de lidar com a complexidade, se você conseguir se safar. Eles também têm alta coesão, pois são um conjunto de funções e dados que se relacionam muito próximos entre si.
fonte
Espero que você obtenha respostas melhores em breve, mas aqui está uma simples:
OOP ajuda * com a complexidade, modelando o software de maneira muito mais próxima da maneira como modelamos todo o resto do mundo. Geralmente, é mais fácil imaginar um objeto bola interagindo com um objeto de parede do que imaginar uma série de rotinas e estruturas de dados para fazer a mesma coisa, pois é mais próximo de como interagimos com o mundo real.
* Porque nada pode 'resolver' a complexidade
fonte
Eu acho que a atual definição mainstream de OOP não é uma boa solução para gerenciar a complexidade.
Se você voltar às suas raízes, acredito que Alan Kay foi influenciado muito pelo "lisp".
Como o Lisp não foi corrompido pela adoção convencional, provavelmente conseguiu conservar seus valores principais. Então, acho que observar como o ceceio lida com esse problema de complexidade pode nos dar algumas dicas, e podemos usá-lo como base para avaliar como é útil a OOP para lidar com a complexidade.
Se você examinar o final da "Aula 3a: Exemplo de Henderson Escher" do SICP , Hal Abelson propõe que a complexidade é gerenciada não dividindo a tarefa em subtarefas menores, mas criando camadas de abstração. No nível mais alto, você expressa a solução para o problema complicado em termos da solução para o nível mais baixo de abstração.
Eu acho que OOP foi originalmente concebido como um mecanismo para criar essas camadas de abstrações.
Infelizmente hoje em dia, OOP é (ab) usado para escrever estruturas / códigos de espaguete.
Vou fazer um exemplo: um jogo multiplayer de FPS.
No nível mais alto, o jogo funciona com um monte de jogadores correndo pelo mapa e atirando um no outro usando armas.
No próximo nível mais baixo, temos que falar sobre mapas, armas e jogadores. Talvez possamos falar sobre eles como objetos físicos que interagem dentro do mundo do jogo.
No próximo nível inferior, podemos falar sobre como os objetos interagem fisicamente (movimento, colisões, etc.).
E assim por diante.
O que isso significa (e estou citando o SICP ..) é que, em cada camada, não apenas resolvemos um problema específico específico, mas uma classe de problemas que meio que caem na vizinhança do problema que estamos ' está tentando resolver. Portanto, se houver uma pequena alteração na descrição do problema, provavelmente exigiria apenas uma pequena alteração na solução.
Portanto, a maneira mais inteligente de usar OOP é criar camadas de abstrações, em cada nível de abstração, você resolve o problema em questão usando os "objetos" do nível diretamente abaixo.
Aqui está a parte que eu estava citando da palestra: http://www.youtube.com/watch?v=CYtrfncMqHQ
fonte
Como sempre, eu discordo de todos. Longe de fornecer ferramentas para gerenciar a complexidade, o OOP cria uma enorme quantidade de complexidade porque é um paradigma inadequado e matematicamente falso. Confunde os programadores sem fim, tentando modelar coisas com OOP que não podem ser modeladas com OOP.
Na minha opinião, o trabalho seminal aqui é Construção de Software Orientado a Objetos de Meyer. Ele detalha um conjunto de requisitos, incluindo um que considero crucial: o Princípio Aberto-Fechado. Isso diz que algo deve estar aberto para extensão, mas fechado para uso, ao mesmo tempo.
Meyer procede à derivação de Orientação a Objetos a partir desses requisitos, conforme incorporado em Eiffel. O encapsulamento fornece fechamento, abertura de herança e a "coisa" mencionada é a classe.
Considero esse trabalho uma boa ciência, porque Meyer estava comprovadamente errado, e é possível, devido à qualidade de seu trabalho, identificar o erro e corrigi-lo.
O erro é tornar a classe ou o tipo a unidade de modularidade. Isso está errado, e provavelmente está. Mesmo Meyer reconheceu o problema (chamado problema de covariância), que OOP não pode lidar com relações de aridade mais altas que uma (isto é, OOP funciona bem para propriedades, mas falha em relações binárias). Em Eiffel, esse problema resultou em um problema no sistema de tipos!
A solução é bastante clara. A unidade de modularidade deve ser maior que um único tipo. Ele deve consistir em vários tipos e nos métodos que os relacionam.
Não é de surpreender que esse modelo de abstração seja respaldado pela teoria matemática da abstração, a teoria das categorias: tipos são objetos de uma categoria e métodos (funções) são setas.
Com este modelo, as representações de vários tipos são conhecidas por um conjunto de funções. A representação está oculta ao público, então isso é uma encapulsação, mas usamos módulos, não classes.
A Meta-linguagem padrão (SML) e a Ocaml são baseadas diretamente nesse modelo. O Ocaml também possui classes e OOP: não é inútil porque o OOP permite que você despache propriedades, também conhecidas como ligação dinâmica. No entanto, a maioria dos problemas do mundo real envolve relações e não surpreende que as classes não sejam muito usadas em Ocaml.
Não é de surpreender que a herança dificilmente seja usada na biblioteca de modelos C ++ Standard.
O simples fato é que o OOP não fornece as ferramentas certas para lidar com a complexidade, nem mesmo as ferramentas para lidar com problemas realmente simples; em vez disso, enganou e confundiu duas gerações de programadores. Longe de ajudar, OOP é a coisa mais ruim e ruim que acontece com a programação desde C, Fortran e Cobol começaram a se cansar.
fonte
A programação orientada a objetos tem raízes que podem ser encontradas nos anos 60. À medida que o hardware e o software se tornaram cada vez mais complexos, a capacidade de gerenciamento tornou-se uma preocupação. Os pesquisadores estudaram maneiras de manter a qualidade do software e desenvolveram a programação orientada a objetos, em parte para resolver problemas comuns, enfatizando fortemente unidades discretas e reutilizáveis da lógica de programação.
Um programa orientado a objetos pode, portanto, ser visto como uma coleção de objetos em interação, em oposição ao modelo convencional, no qual um programa é visto como uma lista de tarefas (sub-rotinas) a serem executadas. No OOP, cada objeto é capaz de receber mensagens, processar dados e enviar mensagens para outros objetos. Cada objeto pode ser visto como uma "máquina" independente, com uma função ou responsabilidade distinta. As ações (ou "métodos") nesses objetos estão intimamente associadas ao próprio objeto.
http://en.wikipedia.org/wiki/Object-oriented_programming
Essa separação de preocupações, juntamente com outros recursos da Orientação a Objetos, como polimorfismo, herança, passagem de mensagens, desacoplamento e encapsulamento, fornecem uma estrutura lógica e conceitual pela qual a complexidade de grandes programas pode ser gerenciada de maneira altamente eficaz.
fonte
Existem muitos tipos de complexidade no desenvolvimento de software. No nível de programação, o OOP procura abordar a complexidade usando objetos e classes para modelar o domínio do problema. Um guru conhecido disse que a solução de problemas está apenas representando o problema, de modo que a solução é a própria representação. Portanto, por abstração usando classes, encapsulamento usando modificadores e métodos de acesso, herança para especificar relacionamento e reutilização, composição para estabelecer relacionamento e colaboração entre classes, polimorfismo como um meio de simplificar a determinação de diferentes comportamentos em objetos semelhantes, a complexidade pode ser gerenciada.
Também existem outras maneiras de gerenciar a complexidade do software, por exemplo, programação lógica (Prolog) e funcional (Haskell).
Em um nível superior à programação, precisamos de Padrões e Princípios de Design para orientar o POO. Portanto, o OOP está gerenciando a complexidade em um nível baixo (de codificação), enquanto essas metodologias, como Padrões e Princípios de Design, orientam o design da solução em um nível mais alto (sistema e aplicativo) e tornam mais complexas o gerenciamento e o desenvolvimento de software.
Para responder sua pergunta, sim, OOP é apenas uma solução para lidar com a complexidade entre muitas outras soluções. É uma solução em um nível baixo. Precisamos de padrões e princípios de design para guiar a OOP em um nível superior.
fonte
A programação orientada a objetos gerencia a complexidade essencial e opcional, mas também não reduz.
Prefiro a definição fornecida por Eric Steven Raymond em The Art of Unix Programming , porque delineia entre complexidade essencial, opcional e acidental. http://www.faqs.org/docs/artu/ch13s01.html#id2964646
OOP não faz nada pela complexidade essencial ou opcional, eles são uma função dos requisitos do programa. Isso pode afetar a complexidade acidental, pois você pode criar um design mais elegante às vezes com o OOP. Às vezes, no entanto, o design é pior ao usar o OOP.
fonte
Problemas complexos não podem ser simplificados por meio da tecnologia, apenas podem ser gerenciados por meio da tecnologia.
OOP é uma tecnologia, um conceito e uma maneira de abordar um problema.
OOP oferece as ferramentas para impor um design que pode facilitar o gerenciamento da complexidade, mas você também pode ter um design ruim que aumenta sua complexidade. Em outras palavras, se não for usado corretamente, você poderá ter complexidade induzida pela tecnologia em seus problemas.
Lembre-se de que existem muitos outros aspectos que determinam o êxito do seu projeto (por exemplo, estilo de gerenciamento de projetos, definição de problemas, gerenciamento de mudanças, etc ...). A tecnologia que você usa é relevante apenas em quanto ela ajudará a gerenciar o problema.
No final, a programação orientada a objetos não pode ser uma solução para a complexidade; é apenas uma ferramenta para gerenciá-lo. (se usado corretamente)
fonte
A Orientação a Objetos (como convencionalmente usada) é uma ferramenta útil em muitas circunstâncias, mas não é uma solução suficiente para a complexidade.
Em particular, muitas vezes adiciona muita " complexidade incidental ". Exemplos são a complexidade em torno da herança de implementação, a necessidade de fornecer muitas "funcionalidades padrão", como equals () e hashCode () etc. Uma boa apresentação de Stuart Halloway sobre este tópico: " Simplicidade não é fácil "
Os objetos na maioria dos idiomas também tendem a encapsular muitos estados mutáveis - que em um mundo simultâneo estão cada vez mais começando a parecer uma má decisão de design. Novamente, um vídeo interessante de Rich Hickey analisa a distinção entre identidade de objeto e estado, e como pode ser um erro confundir os dois.
fonte
A programação orientada a objetos é uma maneira de representar um problema, nada mais, nada menos. É, por si só, não menos complexo do que qualquer outro paradigma de programação. Um sistema OOP bem projetado gerencia e reduz a complexidade, mas também é muito fácil projetar um sistema muito mais complexo do que o necessário e que atrapalha tudo.
Como já foi dito em C ++, o OOP fornece corda suficiente para você se enforcar.
fonte
Acho que sim , apenas porque permite dividir a complexidade em pequenos "blocos de construção" autocontidos que ocultam detalhes e depois usá-los para criar a funcionalidade necessária, passo a passo, camada por camada.
Dividir e conquistar.
fonte
OOP é uma tentativa de solução.
A melhor maneira de gerenciar a complexidade é criar abstrações. Se eu puder transformar meus dados em coleções úteis, com funções reconhecíveis que operam nessas coleções, posso começar a pensar nas coleções como "coisas" discretas. Essa é a base para classes e métodos. Nesse aspecto, o POO corretamente projetado pode ajudar a gerenciar a complexidade.
Em algum lugar ao longo do caminho, alguém decidiu que poderíamos usar o OOP para ajudar a resolver o problema da reutilização de código. Quero dizer, por que reinventar a roda? Se alguém tiver feito muito trabalho para solucionar esse problema, aproveite o que eles fizeram, adicione os ajustes que seu projeto em particular exige e pronto! Você criou um aplicativo poderoso e sofisticado com relativamente pouco trabalho da sua parte. Programadores OO podem ser programadores muito produtivos.
O resultado final é que os programadores modernos de OO acabam sendo "aprendizes de feiticeiros", onde juntam várias bibliotecas grandes e pesadas com algumas linhas de "cola" e conseguem algo que funciona. Sorta. Meio. A maior parte do tempo. Existem possíveis efeitos colaterais do uso desta biblioteca com essa? Talvez. Mas quem tem tempo para realmente descobrir o código contido nessas bibliotecas? Especialmente quando as bibliotecas estão evoluindo. O resultado é que acabamos com aplicativos inchados, onde um programador precisava de um punhado de classes e métodos dessa biblioteca, mas o aplicativo precisa suportar o peso de todas as OUTRAS coisas que eles não precisavam.
O resultado final é que você acaba com muito mais complexidade do que precisa.
Outro mecanismo para lidar com a complexidade que você deseja separar funcionalidade. Você deseja todas as suas funções de acesso a dados em um só lugar. Você deseja todas as funcionalidades da interface do usuário em um só lugar. Você deseja todos os seus controladores em um só lugar. Então você cria classes diferentes que gerenciam partes diferentes da funcionalidade. Por enquanto, tudo bem. E isso é escalável, até certo ponto; seus desenvolvedores habilitados com acesso a dados podem escrever essas classes, seu pessoal da interface do usuário pode escrever as classes da interface do usuário etc. Tudo está bem.
Até você ter que manter algo escrito por outra pessoa.
Sim, é bom saber que todas as funções de acesso a dados estão localizadas aqui. Mas o que os chama?
Este método está chamando esse método nessa classe. Mas quando olho para a definição de classe, não há método com esse nome. Oh, isso é herdado de outra coisa, uma ou duas camadas na cadeia de herança. Espere um minuto; essa classe implementou uma interface? Quantas classes diferentes implementam essa interface? E estamos usando um sistema de tempo de execução complicado (estou olhando para você, Spring) para "conectar" instâncias de classes em tempo de execução? Onde QUALQUER classe que implementa essa interface pode ser usada?
Você acaba com muitos métodos pequenos e discretos que fazem coisas precisas. Mas este chama isso, em outra classe. O que chama isso de mais uma classe. O que chama esse, ainda em outra classe. O que chama esse, em uma classe adicional. O que retorna um resultado de um tipo específico. No qual você deve chamar um método para fazer uma determinada coisa. O que retorna um resultado de outro tipo. Etc.
Existe um termo para isso: código de espaguete.
Você acaba com um sistema muito complexo, necessário apenas para compor o código. Portanto, IDEs como Visual Studio, Eclipse e NetBeans. Todos com uma curva de aprendizado significativa. De fato, muitos deles são capazes de encapsular / agregar várias ferramentas, desenvolvidas por diferentes grupos, cada um com suas próprias curvas de aprendizado.
Isso está gerenciando a complexidade?
O código de depuração é duas vezes mais difícil do que escrevê-lo. Boa sorte na depuração de algumas dessas coisas. Especialmente se estiver usando várias bibliotecas, "conectadas" em tempo de execução usando algum tipo de sistema de injeção de dependência.
Em resumo: OOP fornece o que parece ser uma ferramenta promissora para ajudar a gerenciar a complexidade. A realidade é que o código resultante tende a ficar terrivelmente inchado (porque você não pode extrair apenas as partes necessárias de todas as bibliotecas vinculadas) e precisa de ferramentas sofisticadas apenas para navegar no código. Torna-se rapidamente um pesadelo de manutenção.
IMHO, é uma perda líquida; adiciona mais complexidade do que elimina. Ele permite que você faça coisas que seriam extremamente difíceis, possivelmente até impossíveis, sem ela. Mas qualquer grande projeto evolui rapidamente para uma bagunça insustentável.
Se você já sabe como ele funciona e se lembra, pode ter uma chance de mantê-lo.
Lembre-se de aplicar a Lei de Eagleson: qualquer código seu, que você não veja há seis meses, também pode ser escrito por outra pessoa.
fonte
Até certo ponto...
Por quê? Porque facilita a modularidade muito lógica. Pelo menos em comparação com a programação processual, em que é tentador escrever apenas enormes pilhas de código espaguete.
fonte
A razão pela qual a programação orientada a objetos parece nos ajudar a lidar com a complexidade é porque ela nos força a escrever código de uma maneira específica, em vez de uma variedade enorme de maneiras. A programação orientada a tarefas é muito mais intuitiva, e é por isso que a programação começou dessa maneira. A orientação a objetos requer treinamento e prática para entender e usar efetivamente, mas restringindo a programação a um determinado caminho, permite que os treinados mantenham efetivamente o código que foi escrito.
Não é mais lógico ou real do que qualquer outro método, é apenas uma maneira de focar nossa solução de problemas através de lentes semelhantes. Muitas especialidades técnicas usam o paradigma de uma metodologia rígida não intuitiva para lidar com a complexidade de suas tarefas.
Um terceiro método para lidar com a complexidade seria a programação funcional, e provavelmente haverá outros novos métodos no futuro também.
fonte
Eu acho que é mais uma solução para a manutenção, porque, como programador, você deve colocar métodos onde você tem os dados, criando assim um modelo de objeto do seu aplicativo.
sim, também é uma solução para a complexidade, fornecendo um modelo para você "ver" seu código de maneira natural, como objetos que possuem propriedades e possíveis ações
fonte