2006-07-21

Paradigmas de programação

Poliedro Antes de escrever aquele artigo prometido sobre desempenho de algoritmos, vou escrever algo mais light. Este artigo aqui é voltado para meus amigos da faculdade (e o pessoal dos primeiros períodos) que curtem programação e teoria.

Paradigma de programação diz respeito à forma como o programador pensa para desenvolver seus códigos. Há diversos paradigmas (como é possível ver na Wikipédia), mas vou me limitar a falar sobre alguns mais comuns.

Ao contrário do que se pensa – e do que alguns programadores gostam de acreditar –, não é a linguagem de programação que determina o paradigma, mas a forma do programador pensar. Algumas linguagens facilitam o uso deste ou daquele paradigma, tornando-as boas escolhas para tais, mas a recíproca é pura ferramenta de marketing.

Vamos então dissecar alguns conceitos. =)

Programação procedimental



Erroneamente chamada de programação procedural (mal adaptado do inglês procedural programming), há conceitos distintos assim chamados.

Alguns autores usam «programação procedimental» como sinônimo de programação estruturada, o que não está errado, de forma alguma! Estes conceitos são arbitários. Estes autores se baseam no fato de que toda programação estruturada é necessariamente procedimental e, após a criação da programação estruturada, tornou-se raro (entre os bons programadores) a programação não-estruturada.

Já outros autores preferem usar a expressão com sentido justamente contrário: como sinônimo de programação não-estruturada, para contrapor a programação estruturada. E também não estão errados!

Na verdade, programação procedimental é um conceito um tanto mais abrangente do que programação estruturada.

É quando o programa em si é um procedimento – receita de bolo – a ser seguido pelo sistema para realizar uma tarefa.

A programação procedimental começa com o desenho de um fluxograma, que representa o passo-a-passo do procedimento desejado, depois este é traduzido a uma linguagem de programação qualquer.

A programação procedimental é geralmente usada em scripts ou como parte de estruturas de programação (veja a seguir).

Programação estruturada



Este é o paradigma de programação mais usado e já existe há mais de 30 anos. É o «O» da programação. =)

Nesta forma de pensar, o programa é uma estrutura que se subdivide em sub-estruturas mais simples. Então problemas complexos são dividos em problemas mais simples e estes problemas são dividos em problemas ainda mais simples. A combinação das soluções das etapas mais simples acaba solucionando as etapas mais complexas, ou melhor, mais abstratas.

A metodologia adotada pela programação estruturada é chamada top-down: começa definindo o problema de forma abstrata: «enviar um email para Fulano», então são verificados os passos necessários para realizar a tarefa. Cada passo é novamente divido em passos mais simples que frequentemente podem ter seus códigos compartilhados por outros passos, e assim sucessivamente até que o problema tenha sido reduzido a operações triviais.

No final você terá uma série de procedimentos simples, como «ouvir o soquete» e «enviar uma string», que interagindo resolvem o problema maior.

Cada estrutura, desde a mais simples até a mais abstrata, é chamada sub-rotina ou função e internamente aplica a programação procedimental. A diferença é que, como cada estrutura pode ser chamada diversas vezes, o programador salva muito código e tempo de depuração.

Programação funcional



Neste paradigma os problemas são tratados como funções matemáticas e são resolvidos por álgebra.

É usada a programação estruturada para organizar as funções, que recebem ou não argumentos e sempre retornam algum resultado. Estes resultados são combinados na busca de uma solução maior.

Por exemplo: para a solução de Fibonacci, a função fechada consiste na subtração das potências dos autovalores da matriz característica pela ordem do elemento desejado, divida pela subtração dos autovalores. Portanto teremos funções que efetuam as operações aritméticas comuns (subtração, potência, divisão, etc.), funções que retornam os autovalores e uma função mais abstrata que chama as demais funções, retornando o elemento desejado.

— Nossa!

Não se exalte! Este algoritmo estará no próximo artigo. =)

Este artigo aqui tem o objetivo apenas de apresentar os paradigmas enquanto forma de encarar a criação de códigos. Para maiores esclarecimento veja a Wikipédia.

Orientação a objetos



Esta é a menina dos olhos dos pseudo-programadores. Antes que alguém queira me crucificar ou fazer Judas de mim, deixem que eu me explique!

Orientação a objetos é, como qualquer paradigma, uma forma de pensar para criar algorismos – um recurso racional. Há linguagens que saltam o limiar e trazem este recurso para o código em si, o que é muito bom.

Mas não caia no conto do vigário!

Vocês ouvirão – ou lerão – muito que programar em Java é programar orientado a objetos. Quantas vezes vi códigos em Java que na verdade consistem de uma classe e, dentro dela, um procedimento que nem estruturado foi. Programação procedimental não-estruturada! Mas só porque o cara fez em Java ele acredita que esteja orientando a objetos.

Vamos lá... mito #1: «se a linguagem é orientada a objetos, o programa automaticamente também será».

Orientação a objetos é uma forma de pensar. Se você não consegue pensar orientado a objetos, você não consegue programar orientado a objetos. A linguagem de programação não vai fazer isso pra você.

Mito #2: «orientação a objetos e programação estruturada são exclusivas entre si».

Besteira. Orientação a objetos é dependente de programação estruturada. Se o código não for estruturado, ele automaticamente também não é orientado a objetos. Neste caso (como em outros) cada o paradigma é complementar ao anterior.

Mito #3: «não é possível usar orientação a objetos se a linguagem não for orientada a objetos».

Minha nossa! É tão difícil assim entender que orientação a objetos é um paradigma, ou seja, uma forma de pensar?! Você pode elaborar seu programa orientado a objetos e implementá-lo até mesmo em Assembly, se for bom o suficiente pra isso. Se não fosse assim, não seria possível existir linguagens orientadas a objetos, visto que, no final das contas, quem executa o programa é a máquina e os objetos executáveis são códigos em linguagem de máquina, uma sequência procedimental de comandos do microprograma do processador.

É claro, se você for esperto o bastante, vai escolher uma linguagem que possua nativamente os recursos de que precisa. =P


Esclarecidos os mitos, vamos à definição de orientação a objetos:

É quando o programador implementa não procedimentos, mas objetos que solucionem os problemas. Estes objetos possuem características que os definem e podem executar procedimentos simples chamados métodos. Os métodos de uso exclusivo de cada objeto são chamados privados, os de comunicação são chamados interfaces ou métodos públicos.

Da interação entre os objetos nasce a solução para o problema.

No entanto, na orientação a objetos o programador não define cada objeto. Ele cria as classes dos objetos e se preocupa com elas. Os objetos criados a partir de uma classe são chamados instâncias.

Na implementação dos métodos, o programador deve necessariamente usar programação estruturada, ou sua orientação a objetos vai pras cucuias.

Orientação a eventos



Um paradigma interessante: aqui há um ciclo principal (tradicionamente chamado mainloop) que se repete indefinidamente. Dentro deste ciclo, o programa fica aguardando a ocorrência de eventos e executa funções relacionadas a cada evento.

(Quem estiver prestando atenção verá que a orientação a eventos também pressupõe a programação estruturada.)

Um evento pode ser a pressão de uma tecla (ou sua soltura), um clique do mouse, uma conexão em um soquete ou a resposta da interface de um objeto. É interessante combinar orientação a eventos e orientação a objetos. O fim do ciclo principal – e consequentemente do programa – também é indicado por um evento.

A orientação a eventos é muito usada em daemons (serviços), jogos e na simples criação e manipulação de janelas.

Metaprogramação



Há duas definições de metaprogramação: a mais simples é chamada metacódigo, que nem é tanto um paradigma.

Metacódigo é um programa que gera como saída o código para outro programa. Nada de mais e não requer o uso de nenhum outros paradigmas.

Mas a metaprogramação de verdade pressupõe a orientação a objetos.

Metaprogramação é basicamente – mas não somente – o uso de metafunções e metaclasses.

Metafunções são funções que retornam outras funções (e muitas vezes também recebem funções como parâmetro). Com metafunções é possível criar funções dinamicamente, em tempo de execução.

Metaclasses são classes cujas instâncias também são classes, portanto com metaclasses é possível criar classes em tempo de execução.

Outras linguagens com paradigmas próprios também implementam metaprogramação de acordo com seu próprio funcionamento. Por exemplo, Lua usa metatabelas: tabelas que podem ser instanciadas como se fossem classes. As instâncias das metatabelas são tabelas (Walter me corrija se eu estiver errado!).

Programação extrema



Vou ser o mais sincero possível: não entendo lhufas de programação extrema. Ou quase nada...

Conheço algumas coisinhas. Por exemplo, sei que foi criada pelos programadores de Smalltalk (valeu pela dica, Walter!).

Uma coisa curiosa da programação extrema é a forma de fazer testes.

Tradicionalmente, o programador faz seus códigos e vai testando aos poucos, corrigindo eventuais falhas, e no final testa tudo, depurando inconsistências. Em programação extrema os testes são desenvolvidos antes do código (!!!). Depois o programador vai desenvolvendo o código de forma a que satisfaça os testes.

Quem estiver interessado em programação extrema, veja na Wikipédia. =)