JavaScript* Patterns - Básico

Tweet Like

Eu sei que estou falando de mim mais do que deveria quando eu digo que me lembro quando "Programação Estruturada" era uma grande novidade. Na época em ouvi sobre isso em minha aula de Pascal, eu estava programando em Basic há algum tempo. Eu fiquei psicótico com a clareza e a beleza de coisas tão maravilhosas como o while loops e if-then-else. Mesmo que parece engraçado agora, eu levei algum tempo para realmente apreciar o significado de um "else" em um if-then-else. Acho que isso é o que acontece quando você foi criado na base de Basic e Fortan IV (que isso sirva de alerta :-)

Enquanto isso, em casa programando por diversão, eu ainda estava preso ao Basic como a minha única opção computacional. Era muito frustrante aprender sobre todas essas coisas novas e divertidas, mas não ser capaz de utilizá-las. Em algum ponto, me ocorreu que mesmo sem ter um if-then-else no Basic, eu poderia programar como se tivesse. Isso significava que eu podia me forçar a usar uma forma particular para os meus if-goto que correspondessem de forma previsível ao que poderia ser escrito se eu tivesse um if-then-else.

Por exemplo, se eu quisesse escrever

if a=b then
  x:=0
else
  x:=1;
. . .

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Eu poderia escrever

100 if a=b goto
110   x=1
120 goto 140
130   x=0
140 . . .

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Este padrão é direto, mas ele acaba com as partes do 'then' e 'else' lexicalmente invertidas (ex. ele olha para trás). Se eu quisesse que as sub cláusulas aparecessem na ordem correta, eu poderia ajustar o código um pouco, assim:

100 if a=b goto 120
110 goto 140
120   x=0
130 goto 150
140   x=1
150 . . .

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Apesar de parecer mais confuso, visualmente é mais fácil de entender. Eu posso pensar o primeiro goto como um "Then" e o segundo goto como um "Else". Uma outra abordagem seria usar a primeira opção, mas sempre negar a condição, para que a parte do 'then' viesse antes da parte do 'else':

100 if not a=b goto 130
110   x=0
120 goto 140
130   x=1
140 . . .

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Existem diversas soluções possíveis, mas a chave é que, uma vez que eu escolhi uma solução e a usei de forma consistente, o resultado final é algo mais parecido com o if-then-else do Pascal, e menos parecido com goto's aleatórios bagunçando meu código. Queimei um pouco de fosfato para entender isso na primeira vez, mas depois disso, eu simplesmente reconhecia o padrão e o tratava como código estruturado. Ainda não era o mesmo que programar em Pascal, mas me trouxe diversos dos benefícios de código mais fácil de manter e depurar, sem o custo de pagar por um compilador Pascal, ou naquela época, por um computador que tivesse a capacidade de executar um compilador Pascal.

Hoje em dia, a programação "Estruturada" é trivial, e o Javascript não tem falta do if-then-else. Mas atualmente, todo mundo quer funcionalidades de Orientação a Objetos, que em sua maioria não existem no Javascript. Ele não tem Classes ou Hierarquia. Ele não tem Módulos ou mesmo variáveis estáticas. Pior, ele não tem Inteiros. Como alguém pode escrever alguma coisa útil nesta linguagem ?

Bem, mesmo sem todas as funcionalidades desejadas por muita gente, o Javascript é uma linguagem de programação extremamente flexível. Prova disso é que podemos combinar esta flexibilidade com maneiras específicas de programar que nos permitirão emular as funcionalidades que não estão necessariamente na linguagem. O que acabou acontecendo, é que desenvolvedores bem espertinhos acabaram criando uma variedade de padrões que podem ser usados para suprir as funcionalidades que não existem

Considere as boas e velhas variáveis estáticas, comuns aos programadores C. Variáveis estáticas podem ser utilizadas (ou mal utilizadas) para manter dados dentro de uma função (ou outro escopo), de forma que os dados sobrevivam entre uma chamada e outra, assim:

int f(x) {
    static int i = 0;
    return ++i+x;
}

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

A linha "static" especifica o valor inicial de 'i', mas não atribui zero a cada chamada da função. Neste caso, o valor de i usado no retorno da função corresponde ao número de vezes que a função f() foi chamada, mas não está visível de fora da função, o que a torna diferente (e mais segura) do que uma variável global.

Fazer isso em Javascript pode ser um pouco complicado. Você pode fazer assim:

i = 0
function f(x) {
    return ++i+x;
}

See the Pen %= penName %> by Intel IDZ (@intelidz) on CodePen

Mas isso não é exatamente a mesma coisa. Ele aparenta funcionar do mesmo modo, mas agora o 'i' é uma variável global, visível a qualquer um. Se mais alguém atribuir um valor diferente a 'i' (acidentalmente ou de propósito), você pode acabar com um comportamento anormal, difícil de resolver. Então este pode ser um padrão, mas não um padrão muito bom para emular variáveis estáticas. Como seria um padrão bom ? Bem, você poderia usar uma variável de escopo local (para evitar sua super exposição) e você poderia inicializa-la apenas uma vez. Ela pode ser atualizada, mas a mesma variável deve ser mantida para chamadas posteriores, preservando seu valor entre as chamadas.

Este post está ficando longo, portanto eu vou deixar a implementação disso como um exercício ao leitor, mas eu mostrarei alguns exemplos no próximo artigo.