Codemountain, Paulo Suzart's Blog

Archive for the ‘coding’ Category

Basic Authentication no GAE com Tornado

with 2 comments

Olá! Pra quem já usou o Tornado, vai perceber que o framework permite autenticação via cookie criptografado. O exemplo original da documentação usa uma autenticação por formulário, o que é ótimo para visitantes que desejem utilizar as funcionalidades da nossa aplicação via página web, mas o que fazer para proteger uma API rest construída no GAE com o Tornado?

Uma possibilidade simples é o uso da autenticação no nível do transporte, o HTTP Basic Authentication, que não é lá estas coisas, mas tem seu lugar. Outro ponto importante é que na minha API, eu gostaria de usar um esquema de Decorator em Python (explicar o funcionamento dos decorators está fora do escopo deste post, mas o link anterior oferece bastante info) para facilitar a minha vida. Isto é, eu gostaria de usar algo semelhante a interceptors ou filters em Java. O uso deveria ficar mais ou menos assim:

MyRequestHandler(tornado.web.RequestHandler):
	@authenticated(authenticator)
	def post(self, username):
		#alguma protegida aqui

def authenticator(user,pass):
	#Nossa logica de auth aqui, seja acessar o DataStore
        #ou qualquer coisa para verificar a autenticidade da informação

@authenticated é uma função de decoração que receberá nosso autenticador como parâmetro, que por sua vez será utilizado dentro do código que irá iterceptar a invocação da função post em MyRequestHandler.

Agora a parte mais interessante, o nosso Decorator propriamente dito. Este cara precisa fazer o seguinte: verificar se o usuário tem um cookie criptografado, se não tiver, verificar os cabeçalhos http referentes a Basic Authentication, que por sua vez fornecerão usuário e senha para passarmos para a função authenticator. Naturalmente, se existe um cookie criptografado e válido, pulamos a validação do cabeçalho HTTP e permitimos a invocação do da função post do MyRequestHandler. Abaixo o código inteiro do Decorator e depois os comentários:

def authenticated(auth):
	"""Decorate a function to request user authentication before processing.
		Just uses Basic HTTP Authentication.
	"""
	def decore(f):

		def _request_auth(handler):
			"""Responds 401 to the client, that may prompts the user for auth data."""
			handler.set_header('WWW-Authenticate', 'Basic realm=tmr')
			handler.set_status(401)
			handler.finish()
			return False

		@functools.wraps(f)
		def new_f(*args):
			"""The actual wrapper of the function. Check if auth data is present, if so, invokes
				the auth (authenticated argument) for credential check, if ok, the wrapper function is invoked
				with an aditional argument, the username."""
			handler = args[0]

			auth_header = handler.request.headers.get('Authorization')

			if (not handler.get_secure_cookie("user") and (auth_header is None or not auth_header.startswith('Basic '))):
				return _request_auth(handler)
			elif handler.get_secure_cookie("user"):
				logging.info("####Login by cookie")
				user = handler.get_secure_cookie("user")
			else:
				logging.info("###First login by http")
				auth_decoded = base64.decodestring(auth_header[6:])
				user, password = auth_decoded.split(':', 2)
				if not auth(user, password):
					_request_auth(handler)
				handler.set_secure_cookie("user", user)
			f(username=user, *args)
			return

		return new_f
	return decore

O código poderia ter sido escrito de alguma outra fora, sei lá, organizar e encadear os ifs de outra maneira, enfim. Acho que aqui fica suficiente pra representar o que falei logo acima, que é a lógica de execução da coisa.

Veja que authenticated na verdade é uma função definida como outra qualquer. Ela recebe uma função que recebe dois argumentos (usuário e senha), que por sua vez retornará True ou False, indicando sucesso na autenticação. authenticated de fato retorna outra função, a função decore. decore é uma função qure retorna uma função decorada (a new_f) com @functools.wraps, que nada mais é permitir que new_f fique com a mesma “cara” que a nossa função post do MyRequestHandler. Estranho? Veja detalhes aqui.

Pois bem, nossa decore recebe f como parâmetro, que na verdade é a função post do Request Handler e retorna new_f, que por sua vez recebe os mesmos parâmetros que post na forma de *args. *args é o jeito python de uma função receber um número de argumentos variável, dado que quando decoramos uma função, não sabemos exatamente quantos parâmetros aquela função receberá. Mais detalhes sobre *args e **kwargs aqui.

Quem mantém a lógica de verificação da presença das credenciais (seja por cookie, seja por http) é new_f, que delega para _request_auth os casos onde a credencial não está presente e para auth os casos onde existem as credenciais http. _request_auth só envia um status code 401 para o client, para que este envie as informações do usuário e senha.

A execução de post fica no final de new_f onde ela invoca f (username=user, *args). Aqui podemos ver uma pseudo injeção de dependência, dado que username poderia ser um objeto do tipo user retornado da base ou qualquer outra coisa. Por que injeção? Por que o Tornado não conhece este parâmetro, quer ficaria nulo caso a função post não tivesse sido anotada com @authenticated.

O código aqui está em funcionamento em uma aplicação que estou fazendo. Mas não postei aqui a aplicação completa. Ao usar este decorator, meu log mostra (considerando usuário jordan e uma senha qualquer):

INFO     2010-11-06 13:30:27,448 utils.py:37] ###First login by http
INFO     2010-11-06 13:30:27,448 api.py:34] ########jordan######
INFO     2010-11-06 13:30:27,461 dev_appserver.py:3283] "GET /api/track/twitter/mentions HTTP/1.1" 200 -
INFO     2010-11-06 13:30:31,903 utils.py:34] ####Login by cookie
INFO     2010-11-06 13:30:31,904 api.py:34] ########jordan######

Meu autenticador passado para @authenticated, por enquanto é um lambda que retorna True para qualquer usuário e senha.

@authenticated(lambda x,y: True)
def post(self, username): #...

Acho que é só. A intenção aqui é de orientação e mostrar alguns dos desafios que podemos enfrentar usando o Google App Engine (GAE) e o Tornado.
Não mostro aqui os detalhes gerais de se usar o Tornado no GAE, mas é possível encontrar muito material bom na internet. Espero que tenham gostado e não esqueçam, follow me on twitter: @paulosuzart

Post UPDATE: por algum motivo sobrenatural eu escrevi *Basich* e não Basic. Por isto a URL contem um erro que ficará para a posteridade. Mereço um #Fail!

Written by paulosuzart

novembro 6, 2010 at 2:12 pm

Publicado em python

Tagged with ,

Clojure macros

leave a comment »

É um pouco contraditório falar do básico de uma linguagem e já envolver um framework tão rebuscado quanto o Enlive. Não vou falar muito deste framewok, só o suficiente para deixarmos nosso exemplo mais interessante.

Um amigo me perguntou qual era o meu público alvo depois de ler o último post. Ele falou sobre ter feito uma série de posts sobre scala de forma suave, e de repente cheguei como um trem falando de clojure.

Pra compensar, neste post vamos ver uma pequeníssima introdução a algo muito poderoso da linguagem: Macros. Vejamos uma enxuta definição do Eric Rochester:

“A macro is a function that accepts Clojure code—represented as lists, vectors, symbols, strings, numbers, and other Clojure data types—and returns another list, vector, etc., that represents Clojure code.”

O que passa é que o código clojure é exatamente composto por suas próprias estruturas de dados como vetors, listas, mapas, conjuntos, etc. Esta é uma característica das linguagens de programação Homoiconicas. No fim das contas o que temos é a possibilidade de manipular o código (literalmente) antes que este seja compilado e executado. Pode ser absurdo, mas em *algumas situações* uma macro age como um wrapper ou decorador de uma função lembrando até mesmo o padrão de projeto – guardadas as devidas proporções – do GOF, Decorator.

Mas com macros, não criamos um objeto, extendemos aquele outro ou implementamos alguma interface. O que fazemos é alterar o código inserindo antes, depois ou ao redor dele, algum outro código. O uso de macro pode ser tão complexo ou alto nível quanto queiramos. Mas acho que pra as minhas possibilidades, um exemplo simples é o adequado.

Enquanto estudava a linguagem me perguntava quando usar uma macro, e acredito ter arrumado um bom exemplo. Os nossos amigo da Caelum fizeram um site legal apoiando uma iniciativa que apoio há algum tempo: seja um programador poliglota. E pra os que pensam que programar é coisa de peão, vejam este excelente artigo intitulado: LA RAÍZ DE LA PRECARIEDAD EN LA INFORMÁTICA, onde o autor descreve um cenário que se aplica perfeitamente ao brasil e certamente a muitas partes do mundo: o descaso com o desenvolvimento de software por parte das consultorias, dos pseudo-engenheiros de software, etc.

Vamos ao ponto! O script a seguir usa o poder do Enlive para pesquisar nas tags HTML retornada pela requisição ao site programadorpoliglota, o conteúdo onde aparecem as citações lá listadas. Examinando o fonte HTML, vemos que os tweets são colocados num span de classe tweet_text (isso significa que este script será válido enquanto este for o css usado no site).

O Gist http://gist.github.com/617497 mostra a evolução desta ideia até chegarmos no código abaixo:

(ns enlive
   (:use [net.cgrand.enlive-html])
   (import java.net.URL))

(def target "http://www.programadorpoliglota.com.br")

(defn citations    "check if the given twitter user u was cited."
    [u]
    (let [tweets (-> target URL. html-resource
                    (select [:span.tweet_text]))
          progs (select tweets [:a content])]
        (count (filter #(= % u) progs))))

(defmacro every
    "wraps a serie of functions f to be called every t seconds."
    [t & f]
    `(let [t# (* 1000 ~t)]
         (loop []
             (do ~@f)
             (. Thread (sleep t#)))
             (recur)))

(defn run []
    (future
        (every 10
            (println "Number of citations is: " (citations "your-user-here")))))

Colei o código completo, mas vamos analisar por partes. O foco aqui é a macro every. Ela recebe como parâmetro 2 argumentos t e f. O & é semelhante ao varargs java, com a diferença de receber qualquer tipo de argumento.
Como você deve ter notado, para definir funções em clojure, usamos defn e para macros, defmacro. o argumento t representa o tempo que precisamos colocar nossa thread para dormir entre cada execução de f. E f são todas as funções passadas como parâmetro para every.

Começamos nossa macro pedindo que ela gere o código de let, que vai avaliar a multiplicação de 1000 por ~t e atribuir a t#. Aqui a coisa pode começar a ficar estranha enquanto você não se acostuma.

~t pede ao reader para fazer um evaluate do argumento t da macro, retornando (para o exemplo) o valor 10. O resultado será atribuído a uma variável cujo nome único gerado não sabemos, mas usamos t# para referenciá-la no restante do código (veja o sleep t#).

Outro ítem novo é o ~@, que não tem segredo, podemos ver esta forma especial como um ~ para cada elemento dentro do vetor (do varagrs) que f é.

Por último temos uma função auxiliar de nome run. Usei um future para liberar a thread do REPL clojure e permitir o recarregamento do código enquanto fazia os testes. Ela não é mandatória na linguagem e é uma função como outra qualquer.

O que ganhamos até aqui? Ao de fixar que a função citations (definida mais acima) possua no seu código o comportamento de executar a cada 10 segundos, ou até mesmo usar uma função auxiliar pra isso, o que fizemos foi mudar o nosso próprio código a ser gerado “inserindo” (println “Number of …) onde você vê ~@f. Essa é uma visão simplificada de macros, um instrumento poderoso que permite você construir programas que modifiquem ou mesmo produzam outros completamente diferentes. E se quiser vermos o resultado de código gerado ao executar a macro? basta fazer um:

user=> (macroexpand-1 '(every 10 (println "Number of citations is: " (citations "your-user-here")))

(clojure.core/let [t__1790__auto__ (clojure.core/* 1000 10)]
     (clojure.core/loop []
        (do (println "Number of citations is: " (citations "your-user-here")))
        (. java.lang.Thread (enlive/sleep t__1790__auto__)))
        (recur))

Num código de uma aplicação não há diferença entre invocar uma macro ou uma função, as duas tem a mesma estrutura e o Clojure Reader vai se preocupar em fazer iso por você. Acima, o macroexpand-1 vai retornar a nossa função depois de passar pela macro. Note que o código gerado foi exatamente o que descervemos acima e a variável t# que assume o nome t__1790__auto__.

O que acabamos empacotando numa execução a cada 10 segundos não foi exatamente a função citations, foi a invocação desta função que acontece dentro da função print. Assim podemos manter “a lógica” de imprimir a consulta fora da função citations e da nossa belíssima macro every.

E é só. O uso do Envile fica como apoio para permitir fazermos alguns selectors no HTML retornado pelo site. Espero ter ajudado a fundamentar a linguagem e é claro não esqueça de me seguir no twitter: @paulosuzart.

Written by paulosuzart

outubro 9, 2010 at 3:30 pm

Publicado em clojure

Tagged with ,

Clojure na web – Compojure/Hiccup/Sandbar/Leiningen

with one comment

Quanta coisa aconteceu desde o último post! Umas boas, outras ruins. Uma das boas é que agora você pode ler artigos meus em scala-br.org. O primeiro post na verdade é um repost de um texto já publicado aqui no Codemountain.

Desde o último post fiquei bastante ocupado com a pós, até passei a estudar menos as coisas que gosto por conta disso. ¬¬ Mas arrumei um tempo pra parar de apenas dar RT no twitter sobre clojure e resolvi fazer uma micro app para web usando esta fabulosa linguagem e alguns dos frameworks disponíveis.

O post não contém nada extraordinário ou que não seja possível encontrar nas documentações dos frameworks, a intenção mesmo é fazer uma introdução – em português – do que pode ser seu ferramental de amanhã.

Anote a receita:

  • Um pouco de Ring. Algo com WSGI para Clojure, abstraindo o HTTP numa DSL concisa. Aqui vamos usar seu adaptador para Jetty.
  • Uma pitada de  Compojure. Um webframework simples onde o foco aqui  é o uso dos seus routes para construir o que o Ring chama de handlers.
  • Uma boa dose de Hiccup. Isto é, vamos representar nosso html em Clojure. Não é fantástico?
  • Uma forma em Sandbar. Na verdade é possível construir html forms com Compojure + Hiccup. Mas acredite, construção de forms com Sandbar é mais sexy.
  • E pra selar tudo, nossa ferramenta de build expressa na linguagem: o Leiningen. Este nome vem de um personagem que luta contra formigas na Amazônia. As formigas que esta ferramenta luta contra são os antigos builds.xml usando Ant. Nome criativo.

Me referi a receita, por que criar software é uma arte como cozinhar, já dizia Terrence Parr, ele é só o autor do ANTLR.

A aplicação: Moyure

Muito simples. Uma página principal – sem autenticação ou belezas visuais – com um link para a página de criação de um registro do seus Meet Ups! O nome Moyure não tem uma história tão interessante quanto a do Leiningen :(

Após incluir o registro, a aplicação deve voltar à página principal e mostrar a listagem do registro existentes com um link para edição em cada um deles.

O Banco de Dados: STM

STM (Software Transactional Memory) é, a grosso modo, transações em memória. Isso mesmo, sem uso de locks explícitos podemos efetuar transações em memória usando Clojure Refs. A linguagem oferece outras formas de isolamento/concorrência, mas me pareceu suficiente usar Refs. O objetivo de ter feito um pequeno conjunto de funções é permitir que você faça um clone da aplicação no git (link mais abaixo) e possa executa-la sem se preocupar em gerar schemas/massa de dados ou mesmo instalar uma base. Nosso banco se resume a:

(ns moyure.db)
(def id (ref 0))

(def db (ref {}))

(defn nextval [] (dosync (alter id inc)))

(defn insert-meet
    "Insert a new meet."
    [d] (dosync  (let [nid (nextval)]
          (alter db assoc nid (assoc d :id nid))  nid)))

(defn find
    "If id present, returns the given entry.  Otherwise, returnts all
    entries (the actual map of db)"
    ([] @db)
    ([id] (get @db id)))

Não desanime. O post está só começando. Resumindo, temos aqui duas Refs. Veja id e db sendo definidas com (ref), isto é, para “alterar estes valores” precisamos faze-lo dentro de uma transação. Para isso usamos (dosync) para estabelecer um escopo transacional e (alter) para efetuar a alteração. É possível envolver mais de uma variável em uma transação, e é o que temos aqui. As variáveis id e db estão envolvidas na mesma transação e serão alteradas com sucesso juntas, ou retornarão ao seu estado original se necessário.

Dito isto, precisei garantir que esse banco de dados de última geração :) se comportaria como desenhei. Pra isso usei o pacote clojure.test disponível na própria linguagem. Os testes são simples e autodescritivos. Eles tem mesmo a cara do RSpec. Veja:

(ns moyure.test.db
    (:use [moyure.db])
    (:use [clojure.test]))

(deftest db-t
    (testing "db"

         (testing "should return 1 in the first insertion and 2 in the second."
            (is (= (inc @id) (insert-meet {:title "test" :when "today"})))
            (is (= (inc @id) (insert-meet {:title "doc" :when "saturday"})))

            (testing "And and then nextval should return 2."
                (is (= (inc @id) (nextval)))))

         (testing "Should return all entries (2) with unspecified id."
            (is (not= 0 (count (find))))
         (testing "But should return one entry using id as argument."
            (is (not= nil (find (dec @id))))))))

Testes desse tipo fazem a diferença, numa linguagem dinãmica, ainda mais. Por que basta você ficar sem mexer numa parte do código por uma semana e já não vai lembrar tão bem das coisas. Os testes vão garantir a evolução do seu código sem medos.

Existem libs mais apropriadas para BDD como o Lazytest apontada pelo @alandipert. Vale conferir.

O Projeto

Quase esqueço! Precisamos configurar o nosso novo projeto (sei que você vai fazer um clone do github, mas fica a dica). Para criar um novo projeto com o Leiningen, precisamos de um project.clj com a descrição do projeto. Uma versão simples seria:


(defproject moyure "1.0.0-SNAPSHOT"  :description "Save your meet ups in the speed of clojure"
    :dependencies [[org.clojure/clojure "1.2.0"]
                            [org.clojure/clojure-contrib "1.2.0"]
                            [compojure "0.5.2"]
                            [ring/ring-jetty-adapter "0.3.1"]
                            [hiccup "0.2.7"]
                            [sandbar/sandbar "0.3.0-SNAPSHOT"]])

A aplicação foi construída com este super Banco de dados em db.clj (acima) e core.clj que contém tudo: layout, forms, rotas de requisição http, etc. Mas sempre será boa prática separar melhor as coisas. Pra efeito de exemplo, acho que é suficiente.

A primeira coisa a definir na nossa aplicação pode ser o conjunto de rotas, isto é, quais urls serão acessíveis pelo usuário e para que função cada url será mapeada. defroutes é a macro responsável por gerar nossas rotas:

 (defroutes app-routes
     (GET "/" [] (home))
     (meetup-form (fn [request form] (layout form)))
     (route/not-found (layout [:h2 "Page not found dude!"])))
 

Observe a macro GET, ela mapeia o verbo GET Http na url / sem parâmetros para a invocação da função home. Em seguida vemos meetup-form, não necessitamos gerar explicitamente uma rota com verbo e url pois estes dois elementos definidos no próprio form com a macro defform. Esta macro é quem faz toda mágica do Sandbar, e entender vai demandar um pouco de intimidade com clojure e macros.

Nossa última rota é a rota para tudo que não seja “/” nem “/meetup” – a url para a página de cadastro. Usamos not-found, uma rota que retorna 404 para o browser.

Parece um monte de coisa até aqui pra fazer algo tão simples assim. É, parece, mas é questão de costume.

Agora vamos à função home ela é quem vai fazer a consulta por todos os registros no banco de dados e exibir uma tabela com os resultados.

(defn show-all
    "Generates a html snipet for entries"
    [a]
    (for [[k v] a]
        (let [id (:id v)
             title (:title v)]
             [:tr
                [:td id] [:td title]
                [:td (link-to (str "/meetup/" id) "Edit")]])))

(defn home
    "The welcome screen"
     []
     (layout [:div
                    [:b "Hello Visitor"]
                    [:p (link-to "/meetup" "New MeetUp")]
                    (if-let [a (db/find)]
                       [:table (show-all a)])]))

Aqui entra o Hiccup, de fato as tags aqui não passam de vetores com uma :chave e um valor nativos Clojure, o tratamento disso acontece na função layout (a seguir). É possível passar atributos para o elemento html em quesão, css, eventos js, etc. Tudo direto do clojure. Note a função find do nosso banco sendo invocada. E pra facilitar a modularização, a geração das tr/td html é feita a função show-all. Esta última recebe algo como {1 {:id 1 :title “Consulting” :when “Saturday” :subject “Check some code!”}}. Note o link para a página de edição, que é: /meetup/{id}. Simples! Ah, outra coisa fabulosa é que você abre a tag e o fechamento do vetor dela já basta, o Hiccup faz a geração correta para você. Me lembra até HAML ou SCAML.

Agora vamos para a melhor parte. O form com Sandbar. Eu espero algum dia construir algo assim. Vejam:


(def m-label
      {:title "Title"
       :when "When"
       :subject "Subject"})

(forms/defform meetup-form "/meetup"
:fields [(forms/hidden :id)
                (forms/textfield :title)
                (forms/textfield :when {:size 10})
                (forms/textarea :subject)]
:load #(db/find %)
: on-cancel "/"
: on-success #(do (db/insert-meet  % )
                 (flash-put! :user-message [:p "Meet up saved, go tell your friends!"])
                 "/")
:properties m-label)

A grande sacada do Sandbar é através de :chaves fazer a definição do que o nosso form precisa. Vale a pena ver esta macro. Nosso forme de nome meetup-form é bem explicativo, creio. Basta ressaltar as chaves :load  e :on-sucess, que são quase intuitivas, você só precisa saber o que é este % nelas.

Estas chaves representarão funções que recebem um argumento. :load representa uma função anônima (lembre-se do #) contendo o id da requisição em caso de edição. Ou seja, o valor de % é mapeado automaticamente para 1 na url “/meetup/1″ . Então, passamos este valor para a função find do nosso banco. Esta função retorna um map com chaves de mesmo nome dos campos, permitindo que o formulário seja preenchido automaticamente. WOW!

E quanto a : on-success? Neste caso o % representa o mapa de campos preenchidos (estes campos podem ser validados com o próprio Sandbar, mas acho que já deu no post). Veja que a função anônima de : on-success  invoca a função de inseção com o mapa de valores, em seguida salva no scopo flash da requisição uma mensagem, e por último retorna para onde a navegação deve seguir após o dado ser persistido. Isso mesmo, tão simples quanto isso.

Não tem nada de ocultismo no %, esta á a forma curta de referenciar o primeiro argumento de uma função anônima em clojure. E o valor que ele recebe pode ser facilmente verificável na documentação da lib Sandbar.

Se você chegou até aqui, obrigado. Confesso que as vezes me sinto só nessa mundo Scala, Clojure, etc. Então não deixe de me seguir no twitter (@paulosuzart).

Por último, e tão importante quanto tudo. Está nossa função layout, ela é quem invoca a função html do Hiccup e gera o nosso correto HTML


(defn layout
    "Acts as a template wrapping all the content (cont) in the
base structure"
    [con]
    (html [:html
             [:head
                 [:title "Organize your meet ups with Moyure"]
                 (stylesheet "sandbar-forms.css")
                 (stylesheet "sandbar.css")]
             [:body
                 [:h2 "MOYURE"]
                 (if-let [m (flash-get :user-message)]
                     [:div m])
                  con]]))

Sempre que alguém invocar layout aqueles vectors contendo :chaves serão passados como parâmetro, e aqui acontece a mágica do HTML. Nesta função vemos o uso de .css – que peguei emprestado do pessoal do Sandbar (Não foram alterados e os créditos são deles). Existe uma pasta chamada public/css no projeto, e lá estão os css usados.

E como testar isso tudo? Vá até o meu repositório no GitHub e faça um clone: http://github.com/paulosuzart/moyure. Supondo que você tem o Leiningen instalado, basta fazer:


lein repl
#Deve aparecer algo como:
"REPL started; server listening on localhost:54837."
user=>
# e você faz uso do moyure.core:
user=> (use 'moyure.core)
user=> (run)

Basta acessar http://localhost:8080 e pronto. Jetty rodando com sua aplicação Web em Clojure. Você pode baixar a aplicação e modificar ela para deployar no Google App Engine como exercício, ou mesmo corrigir a função db/insert que insere duas vezes um registro ao invés de atualizá-lo.

A aplicação no GitHub tem algumas coisas não comentadas no post para tentar simplificar. Pretendo explorar mais Clojure na Web e quem sabe mostrar mais detalhes e ir mais a fundo em cada um destes frameworks/libs separadamente. Vamos ver o que consigo.

Conclusão

Clojure é uma linguagem que já ganhou espaço. Só que fora do Brasil. Existem empresas muito focadas nela para os mais variados tipos de problema como a Relevance. A insatisfação razoável com – a linguagem e não a plataforma java – para internet é algo que pode ser observado nos últimos anos, e boas alternativas já existem como Rails, Grails, Play, Django, etc. Mas nenhuma delas tem Clojure, uma linguagem puramente funcional que permite construir soluções elegantes e concisas. Esta virou sem dúvida primeira opção pra mim junto com Scala e Python. Espero ver um pouco de Clojure nos próximos grandes eventos no Brasil.

Pra matar a curiosidade de alguns e preguiça de outros, segue o print das telas (observe as urls no browser):

Update: Os testes sofreram uma pequena modificação para funcionar com a JVM persistente do Cake. Ao invés de identificadores hard coded, passei a usar o último valor do id do banco para a escrita dos testes (veja @id nos testes).

Written by paulosuzart

outubro 8, 2010 at 5:49 am

Publicado em clojure

Tagged with ,

Clojure e seus “Incantos”

with 3 comments

Ta bom, eu sei que é encantos, mas resolvi escrever “Incantos” por postar aqui muito rapidamente sobre uma lib clojure chamada Incanter.

Durante a construção do JTornado, resolvi fazer um exemplo de utilização em clojure. A sensação que eu tive foi a mesma que você vai ter quando olhar o código abaixo. Algo do tipo: “c@#, esse negócio é impossível!”. Me senti exatamente como Brenton Ashworth se sentiu ao descrever seus primeiros contatos com a linguagem em uma entrevista a Fogus.

Mas não aceitei o desaforo de me sentir assim e encarei o aprendizado da linguagem com mais seriedade. Para a minha supresa, a linguagem é tão concisa e tras consigo uma ideologia tão profunda, que tudo é naturalmente compreendido. Imediatamente fiz uma conexão Os ensinamentos do Budha, principalmente no tocante a impermanência de todas as coisas.

Ok, não vamos gastar as poucas linhas que pretendo escrever. :) Mas a ideia trazida por Rich Hickey é – guardadas as proporções – muitíssimo semelhante.

Por algum motivo achei um post do Michael Kohl (que inclusive me deu  boas dicas de como melhorar a primeira versão deste exemplo), onde ele usa o Incanter para analisar – inclusive graficamente –  a utilização de linguagens de programação em projetos hospedados no GitHub. Aquilo me saltou aos olhos de imediato.

Vamos chamar o Incanter de uma poderosa construção em clojure que integra elegantemente diversas libs java (veja a descrição no site) matemáticas, estatísticas e de plotagem. O resultado não poderia ter sido melhor. E nada como um bom motivo (ainda que você force a barra um pouco :p) pra usar algo que você quer aprender.

Na pós-graduação, a professora de Gestão de Pessoas passou um questionário para que pudéssemos visualizar nosso Estilo Motivacional. O teste se chama LEMO e visa detectar se você é uma pessoa de estilo Ação, Participação, Conciliação ou Manutenção. Sem entrar em detalhes, o teste consiste em anotar as respostas do questionário e efetuar somas simples por quesito, o resultado é categorizado em estilos dentro de uma situação normal de trabalho e numa situação de pressão.

Ok, não precisava desenvolver nada pra calcular, a professora até entregou uma planilha com tudo arrumado, era só preencher. Mas se eu preenchesse não seria eu. E aí vem:

(ns lemo
 (:use (incanter core io charts stats)))

(def lemo (read-dataset "lemo.txt"
 :header true
 :delim \;))

(defn bar [data title]
 (bar-chart ["p" "a" "m" "c"]
 data
 :title title
 : x-label "Motivational Style"
 :y-label "Degree"))

(defn line [n p]
 (doto (line-chart ["Normal" "Pressure"]
 [(sd n) (sd p)]
 :title "Standard Deviation"
 :y-label "Deviation"
 : x-label "Condition")

 (add-subtitle "From Normal to Pressure Conditions")))

(let [[norm press] (->> lemo
 to-matrix
 (partition-all 9)
 (map trans)
 (map #(map sum %)))]
 (view (bar norm "Normal Conditions"))
 (view (bar press "Under Pressure"))
 (view (line norm press)))

;;lemo test can be loaded from http://gist.github.com/526089

Susto? Provavelmente sim. Onde está o método main? Qual é o nome da classe? Bom, esquece tudo isso! Clojure nem é orientada a objeto, embora tudo nela seja um. #WIN.

O código acima basicamente lê um txt onde coloquei todas as minhas respostas (linha 4 a 6). No script observe um um binding (usando let) para duas variáveis de nomes norm e press cujos valores são o primeiro e segundo ítem da lista retornada de uma série de aplicação de funções:

  • to-matrix: deve ser intuitivo, estou convertendo meu data-set em uma matriz
  • (partition-all 9) : como optei por colocar todas as respostas juntas (em condições normais e de pressão), apenas organizei os dados por estilo, que corresponde as questões a,b,c e d. Então tenho 9 questões para uma e 9 para outra condição.
  • (map trans): a função anterior particionou minha matrix em 2, uso a função nativa map, para gerar a matriz transposta de cada uma delas.
  • (map #(map sum %)): A função anterior gerou uma transposta para cada matriz, ou seja, 2 matrizes, por isso o map outra vez, mas ao invez de aplica trans eu aplico uma função anônima #(map sum %). Esta função diz: para cada linha da matriz (map) aplique a função de soma (sum). Ah! Cada linha da matriz será passada como primeiro argumento (%) para a função anônima.

Sem atribuições, sem mutações, nada.

Isso é permitido devido à função ->>, que executa  uma espécie de folding das funções listadas, aplicando na próxima função – como último parâmetro – o resultado da execução anterior. A gente já faz muito isso em programação funcional, e chama-se fold (dobrar). Mas, mais frequentimente “dobramos” listas de números, Strings, etc. Por que não dobrar uma sequencia de funções?

Pronto! Agora é só pegar os dados e brincar de gráficos.

Para mostrar os resultados, criei duas funções, a bar e a line (definidas por defn). A função bar recebe a primeira lista de valores (norm) – que corresponde a meu Estilo Motivacional em Situação Normal – e retorna um gráfico em barras:

Naturalmente, a segunda lista de valores de (press), mostra meu Estilo Motivacional em situações de Pressão. Mais uma vez usei bar para gerar o gráfico:

Por fim, e tão sem necessidade quanto calcular e gerar gráficos (a não ser a própria diversão e aprendizado), observei que em situação de pressão meus estilos tendem a se equilibrar. Quanto? Para saber o quão distante estão meus estilos nas duas condições, gerei um terceiro gráfico onde uso Desvio Padrão, a função sd do Incanter.stats. Note que em situação normal, meu estilo Conciliador é mais baixo, o que gera um desvio de aproximadamente 4.5 pontos. Com o equilibrio, passo a ter um desvio de pouco mais de 1.5 pontos. O gráfico a seguir mostra que mudando de condição, há um decrescimento no desvio.

Como foi possível notar, meu Estilo Motivacional predominante é o Manutenção. Isso significa (também) que sou capaz de fazer algo como este post só por diversão e a troco de algumas horas pensando e estudando.

Sugestão para executar o script em sua máquina: Cljr vai ajudar a instalar e rodar tudo redondinho inclusive com o claspath configurado. Lembre de executar um:

> cljr install incanter

É preciso executar o lemo.cljr no mesmo diretório que o lemo.txt. A versão utilizada no post é a {:major 1, :minor 2, :incremental 0, :qualifier “beta1″}.

Espero que tenha sido divertido, você encontra o original dos fontes em um dos meus Gists: Este. E lá você pode ver a evolução da coisa. Comecei brincando de calcular e terminei neste post (que decidi fazer hoje mesmo).

Antes que esqueça, o Incanter se inspirou no R, que é uma linguagem  funcional para construção de computações estatísticas provinda do S. R possui forte semelhança com APL, que tem uma implementação feita pelo próprio criador da, chamada J. Ambas Sensacionais!

Até a próxima e não esqueça de me seguir no twitter: @paulosuzart.

Nota: no código, note que :y-label tem os dois pontos juntos à letra y, o que é não possível com a letra x, por isso ao espaço entre o : e o x. O wordpress resolveu colocar um emoticon ao detectar esta sequencia.

Written by paulosuzart

agosto 19, 2010 at 10:17 pm

Publicado em clojure

Tagged with ,

Python, Java NIO => JTornado

leave a comment »

Desde o últmimo post parei com Scala. 0.o

Devido a um problema com as versões da linguagem (incompatibilidade binária e mudanças na estratégia de Collections para aumentar a compatibilidade com o Java), muito se especulou sobre a estabilidade da linguagem e muitas discussões acirradas (vejam os tweets entre @jboner e @codemonkeyism. Por este motivo tirei férias de Scala e mergulhei profundamente em Python.

Fui surpreendido com uma linguagem extremamente madura, poderosa e completa. Foi tão apaixonante quanto Scala. Como já desejava construir algo no GAE usando python, não perdi tempo e criei o Twittograph (@twittograph), o que deve ser em breve a nova maneira de pedir autógrafos aos seus ídolos.

Então estudei muito (não só Python): Eventlet, Twisted, Tornado, Linux Epoll, Python Select, Python Fabric, fiz Gists, Avro, Boost e Java NIO, clojure. Devo com certeza ter esquecido algo. Não dá pra comentar de cada um destes ou o post ficaria bastante extenso. Fica a dica: Python, Tornado e Clojure. Usem.

Passei a usar o Python Fabric no dia-a-dia, e usei o Tornado para construir o Twittograph. Como vocês podem perceber eu estava navegando pra todos os lados ao mesmo tempo, e as chances de ficar parado eram grandes, até que @abraaoisvi me alertou que eu deveria focar. Foi então que @rafaelfelini – até então recém apaixonado por python – sugeriu “construir” uma versão do Tornado em Java.

Assim nasce o JTornado. Construído em conjunto com o Rafael. Tá, o nome não é lá essa criatividade. Pensamos em Cyclone, Transtornado, Huracan, etc. Bom, deixa JTornado mesmo.

Se você quer praticidade, precisa conhecer o Tornado, feito pelo Facebook (link acima). Mas se você quer esta mesma praticidade em Java e sabe que Java para Web != Servlet. Conheça o JTornado. O JTornado pode ser visto como um framework web com um servidor de alta performance embutido, ou um servidor de alta performance com um framework web embutido. Este é um direcionamento que ainda vamos discutir.

O próprio @felipejcruz, criador do easy_tornado já se mostrou a favor do foco num framework para aplicações assíncronas de rede, que eventualmente oferece um framework web. Vamos ver!

Logo logo devo postar os percalços enfrentados para usar Java NIO e ao mesmo tempo usar low-level concurrency, leia-se threads. Como foi construir um server baseado em processos (Tornado) utilizando a JVM que nos limita neste aspecto. E muito mais. Devo escrever sobre algumas boas práticas – que acreditamos que sejam boas – para o uso de NIO aliado à alta performance com threads.

Veja algumas discussões no Stackoverflow.com durante este tempo:

Como não pode faltar código num post, segue uma micro app usando o JTornado, mas escrita em Clojure:

;Starts an JTornado HTTP Server and a sample RequestHandler.
; Bit verbose due to compilation directives. Recommendation is to generate
; a set of macros to hide this.
(ns org.ctornadoweb
; Compiled and implements a static main method to start the server
  (:import (org.jtornadoweb HttpServer)
           (org.jtornadoweb.Web$Application)
           (org.jtornadoweb.Web$RequestHandler))
  (:gen-class :prefix "server-"))

(gen-class
 :name org.ctornadoweb.MyHandler
 :extends org.jtornadoweb.Web$RequestHandler
 :prefix "do-")

(defn do-get [this]
  "Handles the HTTP GET method"
  (.write "hello clojure"))
(defn do-post [this]
  "Handles the HTTP POST method"
  (.write (.getArgument "name" "default" false)))

(defn server-main []
  "main method"
 (.listen
  (org.jtornadoweb.HttpServer.
   (.add (org.jtornadoweb.Web$Application.) "/" org.ctornadoweb.MyHandler)
     false nil false) 8089))

;use (compile 'org.ctornadoweb)

Basta fazer um curl http://localhost:8089 e tudo funcionará :)

Aguarde o próximopost para informações completas de Java NIO  e JTornado. ;)

Update: Desde que a versão Scala 2.8.0 final foi liberada, retomei os estudos e meu interesse pela linguagem continua. A propósito, o único motivo para o JTornado ser construído em Java é ganhar tempo, pois os colaboradores se sentem mais a vontade com Java. Provavelmente algumas funcionalidades podem ser escritas em Scala ou até mesmo Clojure.

Written by paulosuzart

julho 23, 2010 at 2:51 pm

Publicado em Java, nio, python

Tagged with , ,

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.