Devido à correria, faz muito tempo que não atualizo o blog. Atualmente tenho aprendido bastante sobre a linguagem Python e tenho gostado muito.
Durante o desenvolvimento do Revelação Virtual, desenvolvi um framework para facilitar a minha vida na infra do Google App Engine. Logo no início, comecei a pensar como seria um bom modelo de segurança. Já tive contato com Spring Security em minha época de Javeiro.
Contudo, buscava uma solução sucinta, sem depender de frameworks e suas documentações. Por não ter paciência de ler, fico muito ansioso por ver as coisas funcionar. Se houver mais que uma página de documentação para ler antes de ver a um exemplo concreto funcionando, fico frustrado. Justo nessa época um amigo me falou sobre os decorators de Python (não confundir com o padrão Decorator, veja esse artigo sobre o assunto).
Programação Funcional
Para utilizar os decorators, você precisa conhecer um conceito simples de programação funcional: função é uma variável. Para quem conhece o conceito, isso pode parecer simples, mas para quem não está acostumado, como era meu caso quando só conhecia Java, função ser uma variável pode soar bem estranho.
Para clarificar:
def funcao(arg):
print "Sou uma funcao e meu argumento eh: %s"%arg
variavel=funcao
variavel("argumento")
print type(variavel)
Na primeira linha é criada uma função em Python. Contudo, o que realmente acontece é a criação de um Objeto do tipo função cujo identificador é "funcao". Tanto isso é verdade que após a implementação do corpo, o objeto função é é atribuído à "variavel".
Depois dessa atribuição, a função é executada através da referência "variavel". Para finalizar, o programa imprime o tipo de "variavel": function. Esse é apenas um exemplo simples, mas suficiente, para entender as próximas explicações. Se quiser saber mais, leia a documentação do próprio Python.
Segurança
Depois de entender que função é variável, é possível expandir os horizontes e utilizar funções de uma nova maneira. Com esse "novo" conceito, agora você pode passar funções como argumento e retornar funções como resultado de uma função. Suponha então que você queira executar uma função somente se for passado um valor positivo como argumento único, sem saber qual é essa funcao a princípio. O código poderia ser algo como:
def permitir_valor_positivo(regra_negocio):
def f(valor):
if valor>0:
return regra_negocio(valor)
return "Somente valor positivo permitido"
f.__name__=regra_negocio.__name__
return
f
Vamos entender o código:
- É criada uma função permitir_valor_positivo que ira receber uma outra como argumento
- É criada uma função f que executa a função regra_de_negocio, passada como argumento, somente se o valor passado para f como argumento for positivo. Caso contrário, imprime uma mensagem de erro.
- O nome da função é alterado de "f" para o nome da função "regra_de_negocio"
- f é retornada como resultado de permitir_valor_positivo
Construida nossa funcao , podemos agora apenas ter a preocupação de escrever a "regra de negócio", e depois aplicar a "segurança":
def deposito(valor):
return "Deposito no valor de: %s"%valor
deposito=permitir_valor_positivo(deposito)
print deposito(1)
print deposito(0)
Nossa regra de negócio é realizar um depósito em conta. Depois de implementado o negócio, podemos fazer sua segurança utilizando nossa função permitir_valor_positivo. Depois de aplicada a segurança, tentamos fazer depósitos com valores 1 e 0 recebendo como resposta, respectivamente, "Deposito no valor de: 1" e "Somente valor positivo permitido".
Decorator
Depois de entendido o conceito acima, poderia-se utilizar a programação funcional para fazer nosso lógica de segurança em pseudo-código:
seguranca(negócio):
se (cumpre requisitos de segurança):
execute negocio
se não:
Exiba mensagem de erro
Com a função de segurança escrita, bastaria utilizar o esquema da seção anterior para "segurar" os métodos de negócio. Contudo, o Python apresenta uma açúcar sintático bem interessante chamado Decorator. Talvez inspirado pela notação de Annotation em de Java, podemos substituir as linhas abaixo:
def deposito(valor):
return "Deposito no valor de: %s"%valor
deposito=permitir_valor_positivo(deposito)
por apenas:
@permitir_valor_positivo
def deposito(valor):
return "Deposito no valor de: %s"%valor
Dessa maneira, o código fica menor e muito mais elegante atingindo alguns objetivos que busco em frameworks:
- Documentação curta e simples (esse blog apenas)
- Sem necessidade de configuração, apenas conhecimento da própria linguagem
- Lógica de Segurança separada da Lógica de Negócio
- Granular ao nível de função
Conclusões
Para fazer algo análogo em Java, seria necessário criar uma Annotation personalizada, configurar algum tipo de processamento (como o Spring no Bean Processor) e aplicar a API de Reflection. Como trabalhei justamente com Annotation e Reflection no projeto de meu TCC (JColtrane) sei que esse processo seria muito mais trabalhoso e bem menos elegante que a solução Python, além de obrigar o usuário a ter mais uma dependência em seu projeto. Como já ouvi inúmeras vezes: "para quem só conhece martelo, tudo é prego" ;)
Se você gostou do exemplo e quer saber mais sobre Python, confira o curso Python Pro.
Abs e até o próximo post,
Renzo Nuccitelli
PS:Gostaria de explicar o título do post. Não gostos de flames, cada um tem o direito de preferir trabalhar com a linguagem que quiser. Contudo, um ponto positivo do flame é gerar discussão e consequente tráfego no blog ;)