Blog do Urubatan
msgbartop
Desenvolvedor, Palestrante, Escritor, Nerd Assumido e Pai do Marcus :D
msgbarbottom

08 Jun 08 Orientação a objetos é fácil, as pessoas é que complicam

A idéia de escrever este post veio desta discussão no GUJ, que começou falando de testes unitários e terminou sobre orientação a objetos.
Então seguem as minhas opiniões.


As linguagens de programação mais modernas, ou pelo menos as mais utilizadas de hoje em dia são Orientadas a Objeto, as famosas linguagens OO, mas mesmo assim, a grande maior parte dos desenvolvedores parece não conseguir entender direito a tal da Orientação a Objeto.
Resolvi escrever este este post porque do alto do meu ego inflado, acredito conseguir entender corretamente OO e poder ajudar um pouco.
Então, leiam o post até o final, e depois se quiserem tirar dúvidas ou me xingar, é só deixar um comentário …

O primeiro erro que todos cometem ao iniciar em OO é achar que Orientação a Objetos é sobre classes, isto não faz nenhum sentido, Orientação a Objetos como o próprio nome diz, é sobre Objetos, então, qualquer coisa que não seja um objeto não é realmente importante quando se fala em Orientação a Objetos.
OK, mas por que todos caem no mesmo engano então? porque a grande maior parte das linguagens de programação orientadas a objeto, utilizam classes como moldes para objetos, e durante o desenvolvimento se cria os moldes, ja que os objetos só existem em tempo de execução nestas linguagens.
Quais linguagens não funcionam assim? Bom, agora me vem a cabeça SmallTalk, IO e Ruby, mas devem ter outras.
SmallTalk porque não existe realmente distinção entre “tempo de desenvolvimento” e “tempo de execução” em SmallTalk, tudo esta sempre executando.
IO porque não utiliza o conceiro de classes (a não ser que eu tenha entendido a linguagem errado) e sim objetos template.
E Ruby porque as classes em Ruby são objetos também, mas das três é a que mais se aproxima do “padrão” que citei antes.

Outro erro bastante comum, desta vez quando se utiliza alguma tecnologia de mapeamento Objeto/Relacional, é achar que objetos são tabelas, mapeamento Objeto/Relacional serve para salvar o estado de um objeto em um banco de dados relacional, apenas isto, um objeto do tipo Usuario por exemplo, não possui um atributo “grupo_id”, mas pode possuir um relacionamento com um objeto do tipo Grupo. Percebam que eu escrevi atributo e não campo, pois tabelas tem campos e linhas, objetos possuem atributos e métodos.

Uma coisa bastante comum, ainda utilizando mapeamento O/R é achar que um objeto possui os mesmos atributos que a tabela correspondente, mas neste caso até os nomes são diferentes, infelizmente nestes casos, um objeto precisa ter um atributo “id” que mapeia para a chave primária da tabela, mas um objeto não tem uma chave primária, ele tem apenas atributos.

Então, como solucionar estes problemas?
Bom, no geral, um objeto tem comportamento, e alguns atributos também, mas o importante em um objeto é o que ele faz e como ele faz.
Claro que existem objetos que não tem comportamento, objetos em um sistema são a representação binária de alguma coisa do mundo real, e existem coisas no mundo real que não tem comportamento, tem apenas atributos, como por exemplo mesas e cadeiras, mas exceto se você estiver mapeando um destes objetos no seu sistema, todos os objetos tem um comportamento.
Por exemplo, se você criar um objeto do tipo Usuário, se ele não possuir nenhum comportamento, com certeza o seu sistema esta construído de forma errada, pois pelo menos eu, não conheço nenhum usuário que fique parado como uma estátua o tempo todo, e se este for o caso, com certeza ele não é usuário de sistema nenhum, portanto ele não deveria existir no seu sistema.
A mesma coisa se aplica a um carro, você conhece algum carro que não se move? Que não tenha comportamento algum? A única desculpa para um carro que não tem comportamento algum é um sistema para um museu de carros, onde só importa a carcaça do carro e os atributos dele, principalmente o ano de fabricação.

Outra coisa que todos entendem errado é o padrão MVC (Model, View, Controller).
Na definição do padrão, o controlador esta la apenas como ponto de entrada, ele passa parâmetros para um método de um Model, pega o resultado disto e passa para uma View, se ele estiver fazendo mais do que isto, ele possui parte do código que deveria estar dentro do Model, por tanto, o seu Controller esta errado!

Beleza, mas se eu estou dizendo que todos cometem os mesmos erros, como eu posso dizer que OO é fácil então?
Porque a maioria aprende primeiro a programar de forma estrutural, e depois passa para orientação a objetos, e como as pessoas aprendem coisas novas utilizando como base suas experiências anteriores, utilizam os paradigmas procedurais para tentar programar orientado a objetos, esta é basicamente a raiz do problema.
Para tornar a vida de todos mais fácil, o primeiro contato com programação nos cursos e faculdades deveria ser com SmallTalk e não com portugol ou pascal.
Se você aprender primeiro orientação a objetos, conseguira passar para programação procedural com uma facilidade muito maior do que alguem que aprende primeiro programação procedural tentando aprender orientação a objetos.

O pior é que as linguagens de programação que não são 100% OO contribuem ainda mais para aumentar este problema, vamos pegar o Java como exemplo de uma linguagem não 100% OO.
“Mas me disseram que java era uma linguagem de programação OO”
Bom isto também é verdade, eu disse não 100% OO, não disse que não era OO.
Exemplos de coisas que não são OO em Java: tipos primitivos e métodos estáticos
Basicamente eu acho que na linguagem é só isto que não é OO, mas isto ja causa problemas o suficiente confundindo a cabeça de muita gente.
“Perai, métodos estáticos ficam dentro de classes, como podem não ser OO?”
Mérodos estáticos são uma forma porca de programação procedural dentro de uma linguagem OO que teve uma linguagem procedural como origem, como por exemplo o Java e o C++.
Métodos estáticos não fazem parte de uma classe, utilizam a classe apenas como namespace, o que é diferente de fazer parte.
Em um método estático, não é possível nem saber a qual classe ele pertence, como é possível tanto em object pascal quanto em Ruby, ja que estas não possuem métodos estáticos e sim métodos de classe.
E os tipos primitivos estes sim, não tem relação nenhuma com orientação a objetos, só estão la porque quando a linguagem foi criada não era possível fazer uma classe ter a mesma performance do que um tipo mapeado diretamente do processador da máquina, eles existem em Java por problemas de performance e não por serem Orientados a Objeto.

Alguns design patterns foram criados apenas para contornar limitações da pataforma (Exemplo prático, com um banco de dados OO decente não seria necessário criar o pattern DTO), da mesma forma algumas das regras sobre a utilização de OO foram criadas apenas porque a maioria das pessoas não entende OO, como a regra que diz favoreça composição em vez de herança.
Este é um engano terrível cometido por muitas pessoas que eu não consigo entender.
Muita gente acha que estender uma classe é uma forma de compartilhar código, por exemplo:
Existe uma entidade no sistema de nome Cliente, e em algum momento é necessário criar um ClienteDependente que vai possuir todos os mesmos atributos de cliente mais um que aponta para o responsável, não faz sentido algum fazer ClienteDependente estender Cliente para compartilhar este código, porque o comportamento deles não é o mesmo, por exemplo, ClienteDependente não paga a conta, mas Cliente sim, neste caso seria melhor refatorar o sistema e criar uma entidade que pudesse realizar compras (Ou criar objetos do tipo Compra se o sistema foi bem modelado), e fazer com que Cliente e ClienteDependente estendessem desta, pois neste caso elas estariam realmente compartilhando o comportamento e não apenas evitando algum código aparentemente repetido.
Estender uma classe é estender o comportamento, ou seja, só faz sentido estender o comportamento se a classe “filha” tiver todo o comportamento da classe “pai”, ou seja, é um relacionamento o tipo “é um”. Mas como quase ninguém consegue entender que estender uma classe estende o comportamento (não me parece uma coisa tão complexa assim para se entender), foi criada esta regra que diz: Não use herança, use composição. Simplesmente para evitar que pessoas façam porcaria por não entender conceitos que são estupidamente simples, mas que todos tem mania de complicar.

Outro erro bastante comum é tentar colocar em uma classe apenas o comportamento de todo o sistema, se for para fazer isto, utilize programação procedural, pois você vai estar utilizando a classe apenas como namespace mesmo, não vai nem lembrar que em tempo de execução estara trabalhando com diversos objetos criados a partir daquela forma.

Orientação a objetos é simples, é um paradigma de desenvolvimento que modela um sistema transformando conceitos do mundo real como objetos que colaboram entre si para atingir um objetivo.
Acho que o nome Objeto pode ajudar a confundir boa parte das pessoas, pois em um sistema OO, Compra pode ser um tipo de Objetos, mas no mundo real, compra não é um objeto. Mas para resolver isto eu simplesmente assumo que qualquer um que queira ser um programador precisa ter capacidade para trabalhar com abstrações, não tenho uma explicação melhor para alguem que não consegue entender que Compra pode ser um tipo de Objeto em um sistema OO, assim como Viajem também pode ser um tipo de Objeto (estou utilizando “Tipo de Objeto” em vez de classe porque o que importa em um sistema OO são as instâncias e não as classes) dependendo do problema a ser resolvido.

Acho que são estes os erros mais comuns na orientação a objetos, lendo isto você não concorda comigo? OO é simples, as pessoas é que complicam!
Você lembra de algum outro erro muito comum em OO? deixe um comentário.
Se eu lembrar de mais coisas simples que as pessoas tem mania de complicar eu escrevo outro post.

Tags: ,