2008/04/14

INdT no FISL, com competição em Python!

Instituto Nokia de Tecnologia promove desafios em parceria
com Forum Nokia na Arena de Programação do FISL 2008

Vencedores serão premiados com dispositivos Nokia N95 e Nokia N800. Inscrições estão abertas no site do FISL 09

O Instituto Nokia de Tecnologia (INdT) participará, pela primeira vez, do Fórum Internacional Software Livre (fisl), que terá sua nona edição entre 17 e 19 de abril, em Porto Alegre. O instituto, em parceria com o Forum Nokia, comunidade on-line com mais de três milhões de desenvolvedores cadastrados, promoverá desafios na Arena de Programação do evento e premiará os vencedores com aparelhos Nokia N95 e Internet Tablets Nokia N800.
Os desafios consistem em disputas que levam em conta habilidades técnicas de programação e desenvolvimento. As competições, realizadas individualmente e em grupo, serão vinculadas a projetos open source para plataformas móveis.

Serão duas fases: qualifying e insanifying. No qualifying, tarefas mais simples ajudam os times a se familiarizarem com a linguagem Python para o sistema operacional Symbian S60 e com a API (Interface de Programação de Aplicativos) da plataforma. Aqueles com os melhores resultados passam para a etapa seguinte, quando usarão parte do conhecimento adquirido durante o qualifying.

O resultado será uma contribuição para um projeto de software livre com o qual os participantes poderão continuar colaborando mesmo após o FISLl.

2008/02/18

Javascript HP-12C emulator

For those who like the HP-12C calculator, this emulator may be of interest. It has been tested on Firefox 2 and Internet Explorer 7.

I have always liked the HP-12C calculator (in fact I have three of them), and always wanted to write a HP emulator. The current state of Web browsers and Javascript allowed it to be written as a Web application, so (hopefully) everyone can use it, using any client platform.

The emulator aims to be very faithful to the real thing, to the point that even most of the calculator's limitations are reproduced. The programming mode is fully implemented (though it needs to be tested in more depth). Most of the math has been checked against the real calculator, and should give the same results to the 8th or 9th decimal digit.

The main (intentional) differences are: the ON button behavior (which toogles between decimal point and comma) ; and program memory is not shared with number memory, so typing a 99-step program does *not* reduce number memory from 20 to 8 positions -- you can always use all 20 positions in the emulator. (IMHO it would be pedantic and pointless to reproduce that particular "feature" of the real calculator).

It seems not to work in IE6, so patches and suggestions are welcome.

Enjoy!

2008/02/05

Fighting with web frameworks -- wrapup

After several posts about my work with Turbogears (Python framework for Web applications) and Luca (my general ledger application). Each post presents some problems and some alternatives, none is conclusive. It's time to write a conclusion.

The spark of all my posts was my disappointment with some aspects of Luca development, the main one being the difficulty of introducing changes in UI in a productive way. Every controller has three XML templates, one for AJAX version and two for the "lite" version (Javascript-free, for old or incompatible browsers). So, in a sense, Luca has two separate UIs. So I wrote a template generator and wrote the "meta-templates" using Python syntax instead of XML. Now, every change in UI is leveraged (I only need to change the generator, and the templates will be affected at once).

But then I noted that most of the data that I put in the meta-template, already existed in several other places: the controller and the model. So, if e.g. a table gets a new column, I need to change the model, the controller and the meta-template.

Automated testing was another problem: it is easy to test the controllers in Turbogears (Luca has something around 92% test coverage) but it is almost impossible to test the views, I would have to write a HTML interpreter to do that. And, since there are several XML templates per controller, they certainly have bugs.

First I blamed Model-View-Controller pattern for my woes, then Turbogears, then myself. I found another design pattern called "naked objects", kind of an anthitesis to MVC, that seem to solve all my problems.

During Luca development, a "pattern" emerged in the controllers: the "data transmission line". Different levels of the controller deal with a different data representation, and data goes through a "transformer" when crossing from/to another level. Luca controllers have three explicit data presentations: Web (that go to the XML templates or are coming from the forms), Intermediate (manipulated by all non-trivial validation and business rules), and SQL (ready to be fed into SQLObject). In truth we have two more data representations, that fortunately we don't have to deal with: SQLObject (that translates to/from SQL) and pure HTML/form (that is translated by XML templates and by CherryPy respectively).

The 3 explicit data transformers are inside the controllers, but now I feel that intermediate-SQL transformer belongs to the Model, and the Web-intermediate transformer should belong to View. The controllers are swollen, and yet there is redundant information in model, view and controller.

All cards in the table, my conclusions are:

* Turbogears, as well as all other web frameworks that I have seen, mislead (and sometimes even forces) the developer into using MVC the wrong way.

* They establish that one SQL table == one Model class, making the Model a kind of passive element in their MVC interpretation. Models should be much more intelligent than a simple object-relational mapper. Just because the ORM frees the developer from writing SQL (which I don't perceive as so advantageous), it does not mean that a ORM-mapped table is a full-fledged Model.

The developer can easily avoid this problem by developing more intelligent Model classes that in turn manipulate the ORM classes, and setting up a controller that just forwards the requests to the model.

* Most frameworks establish that a XML template system is the "View", when the View should be a normal and almighty Python class. Since XML is obviously not a programming language, every XML template has a (bad) way to allow Python code into the XML. The result is an underpowered, ugly templating language which makes PHP look pretty in comparison.

This one is more difficult to solve, though most frameworks allow the developer to write their own view class. Turbogears specifies the View as a controller method decorator, so it clearly thinks that View is just a "data transformer", and not an intelligent class that can take intelligent decisions.

Turbogears tries to give more power to the XML templates by "widgets" -- Python classes that can generate XML snippets. Being Python classes, they can be much more intelligent than a XML template. It is a good initial idea, but widgets have some problems: they are INCREDIBLY difficult to understand, and they are sent to the page via the controller, so it is another source of contamination of View businesses into the Controller.

The real solution is to have Views as full-powered Python classes, which *in turn* can use some kind of XML templating system.

* As a result of previous items, the Controller ends up swollen with code. But unfortunately the centralization of activities in Controller does not exempt the developer of writing redundant code in Views and Models.

* Most frameworks map Web pages and Web requests into controllers' methods. This is nice except that Controller must mimic the Web site structure. And site structure should be exclusive business of View. If a different UI must be supported (i.e. a new View must be written), the controller will not be adequate.

It already happened in Luca, just because I support AJAX and non-AJAX pages. The AJAX pages call JSON controller methods, and non-AJAX pages call other methods. It is necessary since data from form submits are different than data sent directly via JSON. (The JSON methods are "more pure" since they are not contaminated by the form -- View -- details, so they can also be called by the mobile client that runs in cell phone).

* The antithesis of MVC -- naked objects -- solves most of the abovementioned problems by compulsory automatic generation of UI code. It is an utopia; it would never suffice everybody's needs, but it is worthwile to purse that utopia, up to a certain extent.

It translates to: we should write Views that derive their behaviour from Model introspection as much as possible. It ensures that all function points will look the same, and more important, an improvement or bugfix in View will yield profits to every function point.

The risk is, of course, going too far and giving our application that boring appearance of the 1980's when database-tied 4th generation languages ruled the world.

But if we go too far, it is easy to fall back and add customizations to selected Views. It is way easier to commit the opposite mistake: NOT to pursue any kind of automatic UI generation, and discover that you cannot fix the mistake anymore because you have hundreds of incompatible Views.


In short, Web frameworks should:

1) review their interpretation of MVC;

2) promote the development of much more powerful Model objects, instead of simple ORM classes;

3) make Views as real objects instead of simple "filters", which in turn can use XML templates;

4) Encourage and supply good tools for at least some degree of automatic UI generation.

2008/02/01

Naked objects

Parece que encontrei o pattern que eu estava procurando nos posts anteriores:
Naked Objects, considerado a antítese do Model-View-Controller. A idéia é implementar todas as regras de negócio num único objeto, o "objeto de domínio", que faz as vezes de Model mais Controller. A partir dele, todas as interfaces de usuário são geradas de forma automática.

A grande vantagem do Naked Objects é a centralização de informações. Alterar um ponto de função implica em mexer apenas num arquivo de código-fonte, ao invés de vários, e todas as interfaces refletem automaticamente a mudança. A desvantagem é obviamente a rigidez das interfaces geradas.

Na minha visão, o Naked Objects não é o "contrário" do MVC, é simplesmente um caminho diferente de chegar no mesmo lugar. Ao invés de desenvolver três classes (Model, View e Controller), desenvolve-se apenas uma (um Controller que açambarca ou pelo menos esconde o Model), e o View é gerado de forma automática.

Na verdade, pode ser preciso desenvolver também o gerador de Views, que vai ser apenas um por tipo de interface (Web, texto, GUI etc.). Na verdade é bom que o desenvolvedor tenha como modificar esse gerador, pois mitiga a desvantagem da rigidez.

2008/01/29

Mais lamúrias sobre frameworks Web

Continuando a fuçar "onde foi que eu errei" a respeito do Luca e dos frameworks para Web, cheguei a algumas conclusões parciais.

Primeiro, durante o desenvolvimento do Luca apareceu um pattern interessante: a "representação de dados" em formatos diversos, e a conversão de uma representação para outra por meio de filtros. O Luca lida com dados em 3 formatos distintos:

Representação SQL (RS): É a que pode ser oferecida diretamente ao Model, no caso o SQLObject. Por conseqüência, é praticamente pareada com a estrutura da tabela SQL. Também é o formato obtido quando se puxa dados via SQLObject.

Representação intermediária (RI): O controlador só manipula e valida dados nesse formato, portanto pode ser considerado o "principal". As demais representações só existem para satisfazer outros componentes.

Representação Web (RW): Formato que visa satisfazer ao template XML. Também é o formato que é obtido quando o usuário submete dados via formulário Web.

O controlador deve implementar os filtros de conversão entre RS, RI e RW,, mas ele herda filtros default suficientemente poderosos para as conversões triviais, de strings e inteiros, que são a maioria. Apenas os dados "excepcionais", cuja representação no SQL não tenha nada a ver com o apresentado na página HTML, precisam ser convertidos pelo controlador.

Com isso eu tentei isolar as "regras de negócio" do controlador ao máximo, tornando-as independentes tanto dos detalhes desagradáveis do SQLObject quanto dos dados vindos diretamente da Web (que podem estar sujos ou num formato não ideal). Também tentei economizar código, de modo que especificando as colunas numa única tabela molda todo o comportamento do controlador, evitando ter de repetir as mesmas variáveis um monte de vezes.

Infelizmente, as colunas ainda precisam ser especificadas novamente nos templates XML e nos validadores Turbogears (que no Luca são utilizados para apenas converter tipos, não para a validação completa). Este fato é uma das minhas principais broncas.

Então, pensando em termos de processamento de dados, tudo que é mostrado na Web vem de um banco de dados. De forma simétrica, tudo que o usuário faz no sistema tem como único objetivo final gravar dados no banco. Entra porco, sai lingüiça. O fluxo de dados de SQL para HTML é:

SQL -> Model -> RS -> Filtro SI -> RI -> Filtro IW -> RW -> XML -> HTML

O fluxo de dados do formulário até o SQL é um pouco diferente, na ponta Web:

Form -> Validador TG -> RW -> Filtro IW -> RI -> Filtro SI -> RS -> Model -> SQL

O problema da promiscuidade entre Model, View e Controller é que quase todos os blocos acima estão contidos no Controller: RS, Filtro SI, Ri, Filtro IW, RW e validador TG. O Controller está trabalhando demais.

O Model deveria, além de esconder o banco de dados SQL, também implementar a representação intermediária (RI). Ou seja, ele deveria fornecer e aceitar dados no formato predileto do Controller, inclusive fazendo a validação. O Model ideal é muito mais que um simples mapeamento SQL-objeto. Isso encurta o fluxo para:

Model -> RI -> Filtro IW -> RW -> XML -> HTML

O próximo problema é a representação Web. Como os templates XML são linguagens canhestras, o Controller tem de trabalhar mais, oferecendo dados "pré-mastigados" ao template. Daí a necessidade do filtro IW.

A rigor esse filtro deveria estar numa classe View separada do Controller; o que não é possível no Turbogears porque o View é apenas o mecanismo de template XML, e escrever um View "completo" exige código de verdade. Nesse cenário ideal, o fluxo fica

Model -> RI -> View{Filtro IW, RW, XML, HTML}

Até aqui, "consertar" o Luca demandaria as seguintes providências:

* Escrever Models melhores, que isolem completamente o SQLObject do resto da aplicação e interfaceiem dados no formato predileto dos Controllers -- o RI.

* Escrever decorators View mais poderosos, que aceitem diretamente dados RI e virem-se para transformar dados "puros" numa página Web.

Mas a contaminação dos Controllers não se resume ao fluxo de dados -- ela também ocorre nas chamadas a métodos. Por que?

Porque é justamente esta a idéia do CherryPy, componente do Turbogears: se você invoca uma página bla.com.br/bla/ble, isso provoca a chamada a um método "ble" do objeto Controller "bla". Sem dúvida é uma coisa boa, mas talvez o objeto "bla" não devesse ser um Controller no sentido MVC do termo...

Se os métodos do Controller são moldados de acordo com as páginas Web, é óbvio que o controlador vai ficar viciado com o jeito Web de ser. Se for necessária qualquer outra interface que não Web, já vai ficar complicado ou impossível usá-lo para atender outros tipos de cliente, como texto, GUI... ou mesmo AJAX.

O cliente AJAX é um caso interessante porque do ponto de vista do controlador ele não é Web, pois o cliente AJAX troca dados puros com o controlador (codificados em JSON), e não páginas ou formulários. Um controlador "viciado" para Web não servirá nem para AJAX. Será preciso criar novos métodos.

É exatamente o que acontece no Luca: há métodos JSON para as páginas AJAX, e há métodos de páginas Web para as páginas sem AJAX (utilizáveis em navegadores antigos ou incompatíveis). Funciona, mas duplica algum código e mistura conceitos.

O ideal seria haver um pré-controlador para Web, intimamente ligado ao View, que atendesse as páginas Web normais, e este por sua vez refurmulasse a requisição controlador "puro", agnóstico ao View, e implementa apenas as regras de negócio. Já as requisições JSON poderiam ir direto ao controlador "puro", pois trafegam dados puros (e podem servir a clientes GUI).

No Luca, há apenas um controlador "puro", que é responsável por comunicar-se com o celular (assim eu posso registrar minhas despesas no celular e fazer upload via Bluetooth). Por sua vez, este controlador invoca métodos de outros, pois diversas transações diferentes são levadas a cabo a cada sincronização celular-servidor. (Foi fácil chamar métodos de outros controladores pois todos já tinham suporte a AJAX).

Em resumo:

* No Turbogears e aparentemente nos demais frameworks, induz-se poluição dos Controllers devido à anemia dos Models e dos Views;

* Os Models "sugeridos" pelos frameworks são fracos pois são apenas uma casca fina sobre SQL, embora seja fácil implementar e usar Models mais adequados.

* Os Views dos frameworks são fracos pois restringem-se a encoders, como os templates XML, quando deveriam ser classes Python normais (e estas sim, por sua vez, poderiam usar algum mecanismo de template XML).

* Talvez eu esteja exigindo do Turbogears que sejam servidores de aplicação, não simples um framework Web que é afinal a sua proposta. (Mas, na minha opinião, um sistema AJAX tem características não-Web.)

* Minhas queixas contra o MVC estavam erradas, o problema dos frameworks poderia ser a má interpretação do pattern MVC.