12 de maio de 2020

Programação Orientada a ob... classes

A história da computação é algo muitas vezes cíclico, onde conceitos com quase 50 anos retornam, às vezes na mesma forma, as vezes em uma nova roupagem. Vamos dar um zoom num dos conceitos mais comuns da programação moderna, a programação orientada a objetos.

A primeira coisa que eu gostaria de falar é que programamos orientado a classes mas os sistemas não rodam orientado a objetos.

Cão-da-pradaria de costas virando dramáticamente e encarando a câmera.
O QUE?


O que fazemos na verdade é estruturação de códigos em classe, o que não é ruim mas no decorrer dos próximos parágrafos vou tentar explicar melhor. Isso inclusive constata a diferença entre como organizamos nosso código e como isso pode ser diferente da organização das estruturas do nosso código em execução.

Se você, que nem eu, começou a programar nos últimos 20 ou até 30 anos com certeza lidou com a programação orientada a objetos, provavelmente com linguagens como C++, Java, C#, Python, Ruby ou qualquer outra linguagem que dê suporte a classes ou até protótipos (no caso de Javascript). Estas linguagens estruturam fortemente o código utilizando classes e a partir dela instanciam estes obetos, porém o ciclo de vida dos objetos tende a ser muito curto e contido no escopo de outros métodos, o que tem benefícios se tratando de concorrência (os objetos vivem tão pouco e num escopo tão restrito que não compartilham nenhum estado), gestão de memória (como os objetos são menores e vivem num escopo restrito, fica fácil controlar seu início e fim) e também manutenção de código, pois a execução do código ainda fica linear em sua execução. Porém é necessário deixar claro que isso não é algo que foi decidido da noite para o dia, durante muito tempo essa abordagem não foi a prioritária para o desenvolvimento Java, que durante muito tempo estruturou de forma diferente suas aplicações com EJBs no framework Java Enterprise Edition (Java EE).

Esta estrutura de código funciona muito bem, porém como já fazemos uma separação mais clara entre procedimentos (ou funções) e estruturas de dados, poderíamos potencializar os benefícios acima espelhando a maneira como nosso programa executa com a maneira que estruturamos nosso código, isso abriu um grande espaço para linguagens funcionais que já lidam bem com programação concorrente, gerenciamento de memória e manutenabilidade, e assim vemos o crescimento de linguagens como Clojure, Elm, F# e até Haskell.

Tabela com duas colunas, uma explicando o que temos de padrões em OO e os FP (que é apenas funções)
Diferenças entre OOP e FP
Fonte: https://blog.cleancoder.com/uncle-bob/2014/11/24/FPvsOO.html

Você pode pensar no motivo de já não termos adotado linguagens funcionais logo de cara, já que a programação orientada a objetos na maneira como fazemos hoje tem uma impedância entre a estrutura de código e a estrutura interna do programa em si, mas como falei acima, isso nem sempre foi assim. No decorrer dos anos 70 uma linguagem muito famosa surgiu, o Smalltalk, sendo uma linguagem orientada a objetos, um dos seus maiores diferenciais era a maneira como ela gerenciava seus objetos. Ao iniciar um programa os objetos eram carregados por sua máquina virtual e começavam a trocar mensagens entre eles, o ciclo de vida desses objetos era mais longo e permitia inclusive tirar uma fotografia do momento atual da máquina virtual e carregá-la novamente no mesmo estado posteriormente. 


Exemplo de diagra de sequência com mensagens UML
Diagra de sequência com mensagens UML
Fonte: https://en.wikipedia.org/wiki/Sequence_diagram
Programadores experientes em Smalltalk e posteriormente em Java inclusive criaram uma forma de documentar toda essa estrutura em uma linguagem bem conhecida, o Unified Model Language, porém como vamos descobrir abaixo, este modelo de execução sofria de alguns problemas e o UML acabou ficando subutilizado, pelo fato de só utilizarmos classes e não orientação a objetos de uma maneira purista, ou já utilizarmos logo uma linguagem funcional.

O modelo se modernizou para o século 21 quando foi adotado pelo Java Enterprise Edition no seu começo, onde estes objetos que ficavam carregados em memória, na forma de pools, eram chamados de Enterprise Java Beans e permitiam coisas como a distribuição entre diversos servidores (um EJB de uma máquina poderiam passar uma mensagens, em forma de invocação de método, para um EJB em outra máquina). 

O modelo orientado a objetos, apesar de muito robusto, era complexo e exigia configurações de máquina bem exigentes (trabalhei em lugares que tinham oito servidores de 32 núcleos e 64 GB de RAM para executar uma única aplicação Java) e isto começou a fazer a estrutura ficar cada vez menos interessante, mesmo o ciclo de vida dos objetos tendo um função de passiva-los (ou seja, eles eram serializados e salvos em um lugar mais econômico da JVM), sendo que depois perceberam que era melhor criar EJBs sem estado (ou seja, a primeira execução do EJB não mantinha nada armazenado que pudesse afetar sua segunda execução) e logo a máquina virtual do Java, por decisões arquiteturais e para facilitar a vida do coletor de lixo (responsável por liberar memória) começou a favorecer objetos que fossem instanciados rapidamente e morriam mais rapidamente ainda, permitindo a execução em máquinas com muito menos memória, favorecido pelo crescimento de frameworks mais simples de desenvolver como o Spring.
Ciclo de vida de um EJB
Fonte: https://examples.javacodegeeks.com/enterprise-java/ejb3/ejb-life-cycle-example/

Hoje em dia, os modelos mais comuns de orientação a objetos favorecem criar o código em forma de classes porém a execução de ocorre muito mais proceduralmente. Isso ajuda no gerenciamento de memória e tira da frente alguns problemas em relação a paralelismo de código, pois quando você tem vários objetos rodando em paralelo é necessário decidir qual é a prioridade e tempo de máquina que cada método de cada objeto deve ter e isto foi uma decisão que os desenvolvedores de linguagens e máquinas virtuais decidiram não priorizar.

Esta é a primeira parte do post e explica um pouco da história da programação orientada a objetos e sua evolução, porém como falei acima, as coisas ocorrem de maneira cíclica e o modelo criado pelo Smalltalk seria retomado mais recentemente de outra forma, que será explicada num próximo post.

Nenhum comentário:

Postar um comentário