Design, OOP, Ruby

Eigenclasses for lunch – The Ruby Object Model

So if you’re a Ruby programmer you probably know that everything in Ruby is an object. Ok, good. But another thing that’s worth noting is Ruby objects hierarchy. Since Ruby 1.9, its hierarchy is like this:

Ruby Basic Model

*’C’ means Class and ‘S’ means Superclass.

You can open your irb console and see it for yourself by typing:


class Person
 end

Person.class
 #=> Class
 Person.class.superclass
 #=> Module
 Person.class.superclass.superclass
 #=> Object
 Person.class.superclass.superclass.superclass
 #=> BasicObject
 Person.class.superclass.superclass.superclass.superclass
 #=> nil (there is nothing above BasicObject)

Differently from languages like Java and C# for example, you can change a Ruby Class on-the-fly. You can pretty much do:


class Fixnum
  def even?
    self%2 == 0
  end
end

1.even?
 #=> false
2.even?
 #=> true

Because classes are open in Ruby, you’re allowed to modify them during the execution of your program. This is a very very powerful feature and opens an ocean of possibilities. But wait! There is more! It’s even possible to modify an instance on-the-fly too!


french = Person.new
def french.hello
  'Bonjour'
end

french.hello
 #=> Bonjour
 person = Person.new
 person.hello
 # => undefined method 'hello'

We just created a method exclusively for the object and not for every instance of the Person class. But once again, everything in Ruby is an object, therefore, belong to a class. So here’s the 64k dollars question: when we add a method to an instance of Person, which class are we modifying? It can’t be Person, otherwise it would alter all the instances of Person. And we know it didn’t! Neither can it be in the object: we know objects don’t hold methods, but data. So…

Where the heck is the hello method?



The term “eigenclass” has been used in the ruby community to denote a class of a specific object. Some people like to call it “singleton classes” instead. One way or another, the concept remains. And what really happens when you modify an instance’s method is that Ruby creates an anonymous class to hold the object’s singleton methods. Then this anonymous class assumes the role of the object’s class. And finally, the original (and former) object’s class becomes the superclass of the anonymous class. Complicated eh? No really, it is. But hey, classes are open, what did you expect?

And just to confirm that the eigenclass holds the objects modified methods, try this in your irb console:


#reopens the Object class and create a method that returns the eigenclass
class Object
  def eigenclass
    class << self; self; end   
  end 
end 
french.eigenclass.instance_methods.include? :hello 
#=> true
person.eigenclass.instance_methods.include? :hello
#=> false

So there you go. The notation “class << self” is like saying “open the class of self for me and do:”. Since eigenclass() is an instance method, self inside it refers to the object calling the method. Once inside the self’s class, we can just return self, which will refer to the current class, which is the eigenclass.

The (complete) Ruby Object Model



So what happens when I create an eigenclass of a class? Let’s say that Person now inherits from the Animal class, that has the following method definition:


def Animal.lives?
  true
end

Well, in that moment, an eigenclass is created to store the class method “lives?”. So now we have Animal and its eigenclass. When we call a class method in the Animal object itself, Ruby is going to look for it (1) in the Animal class and (2) in Animal’s eigenclass. This is called “The method lookup chain”.

But what happens when we call ‘Person.lives?’ ? It works! But how is it possible to inherit the superclass’s class methods? The thing is, when a class method is created inside Person’s superclass, Ruby not only generates Animal’s eigenclass, but also Person’s. And yet it makes Animal’s eigenclass become the superclass of Person’s eigenclass! I know, I know. Unbelievably complicated. You need to see the diagram to grasp the idea of it:

The Ruby Object Model

* ‘C’ means class and ‘S’ means superclass.

Remember, that’s the Ruby object method lookup path. This is how Ruby finds your methods. It is a really complicated subject, especially if you’re just starting to get acquainted with the Ruby language. But once you get it, you just don’t forget it. Just go ahead and play with these concepts. You’ll get the grasp before you know it…

Padrão
Design, Lógica

Tail-recursive algorithms

What is a tail recursive algorithm?

 

  If you’re a programmer for some time now, you probably know what a recursive function/method is. I mean, if you don’t, you probably shouldn’t be here in the first
place. This is NOT the place to be learning this kind of stuff… Just kidding. I shouldn’t be explaining this here but I will anyway. Firstly because I am one of those good guys, you know? Also because my mom taught me to be kind to people. But mainly because it’s straightforward: A recursive function is one that calls itself. Pretty much like a dog trying to bite his own tail. An algorithm to implement the Fibonacci sequence could be made recursive, for instance this one in Scala (and I’m gonna use this language in this post as I’m getting familiar with the language):


def fibonacci(x: Int): Int =
 if(x == 0 || x == 1) 1
 else fibonacci(x-1) + fibonacci(x-2)

  Alright! It’s a piece of cake in theory really. In practice? Well, not exactly. It can be very very frustrating, especially if you have a bigger function and you need
to debug it (Debug Hell). Cool. No, wait! But what about this tail-recursive thing? In traditional recursion, you perform your recursive calls first and only then you
use the returned values to calculate the result. For example, take the traditional implementation of the factorial function.


def fat(x: Int): Int =
  if(x <= 1) 1
  else x*fat(x-1)

It would be calculated like this:


fat(4) =
 4*(fat(3)) =
 4*(3*fat(2)) =
 4*(3*(2*fat(1))) =
 4*3*2*1 = 24

In tail-recursive style though, you perform the calculations first and then the recursive call is executed, passing the current result to the next recursive step.
Still using the factorial:


def loop(y: Int, x: Int):Int =
 {
    if(x <= 1) y;
    else {
      val sum: Int = y*x;
      loop(sum, x-1);
    }

}

def fat(n: Int) = loop(1,n)

In this case, we have an accumulator that already has the partial result and only passes it to the next recursion, if there is one:


fat(4) =
 loop(1,4) =
 loop(4,3) =
 loop(12,2) =
 loop(24, 1) =
 24



“Tail-recursive or not tail-recursive: that is the question!”


  Notice in this last example there is no calculation after the recursion. The recursive call is the last action in the function. Nothing else. That pretty much differentiates a tail-recursion algorithm. In a general way, if the last action of a function is to call a function (itself or another one), only one stack frame would be necessary for both. This type of call is known as a “tail call”. But what is a stack frame after all? And what difference does it make to reuse a stack frame?



“A Stack frame, a Stack frame. My kingdom for a Stack frame!”


To run your code, the Virtual Machine uses a special architecture to manage all the variables and methods in memory. For example, in the JVM memory is divided in 4 types: Heap (where instance variables, references and objects go), Stack(containing methods and the order of calls), code (contains the bytecode) and static (keeps static data and methods).

So stacks. Imagine a big stack in memory to keep the calls to your methods. Say you have a method prepare() that calls doSomething() and this last one calls doSomethingElse(). In the stack, they would be in that same order bottom-up (see picture 1). Of course, these methods have data like local variables and stuff, so where do they keep this data? On the method’s frame. The elements in the stack are called “frames”. These frames are simply blocks in memory that stores a method call and its data just like explained before.

Picture 1

Picture 1: In the picture you see the stack executing a method call. Notice that every new call is put on top of the last one, i.e the lower one is the first in Stack (top).



Back on the tail-recursive algorithms. Think about it: if one can reuse the stack frame for different calls, the execution uses constant stack space, which means the function is executed as a simple loop. Yes, there is an equivalence between a tail-recursive function and a loop. Which means you can convert a while loop, for example, into a tail-recursive function and vice-versa! It can be a big deal for the VM executing your code to reuse the current stack frame time and time again especially in deep recursions. You avoid the trap of falling into a stackoverflow error, which is basically a stack running out of stack frames. And clearly this allows for some optimization. However, if you find yourself in a situation where you have a clean non tail-recursive function (like fibonacci or factorial above) but there’s no risk to get a StackOverflow error because you’re not running deep recursion chains, so don’t lose your sleep on it. Clarity and good design are often more important aspects of an application than computational efficiency. Though, learning this feature of functional programming can help you if you need a different recursive strategy. Who knows?

Padrão
Experiências

Posts em inglês em 3…2…

Desde o começo desse blog pensei se não deveria escrever posts em inglês. Naquela época a resposta foi NÃO. Era realmente um experimento pequeno (ainda é, mas era menor ainda) , que era direcionado aos meus colegas de trabalho e depois foi ampliado aos desenvolvedores brasileiros iniciantes. A ideia era atingir um público alvo menor. Bom, a minha ideia de direção mudou. Os posts estão ficando mais avançados e gostaria de ampliar esse público alvo agora. Por isso, decidi que escrever em inglês é uma boa para ampliar meus horizontes. Alguns amigos já haviam me sugerido fazer essa transição, mas como estava sem blogar por um tempão mesmo, decidi deixar isso no prego.  Obviamente, grande parte dos desenvolvedores nacionalmente e internacionalmente conhecidos blogam em inglês pelo mesmo motivo. Enfim, motivos para fazer isso não faltavam. Me faltava para tanto.

Além disso, vou tentar escrever posts menores, mais concisos e em linguagens diferentes do Java, tipo Ruby, Scala, Lua e Javascript. Agradeço aos leitores que se tornaram surpreendentemente mais do que eu esperava! =D.

Padrão
Lógica

Brincando com números primos

“Escolha um número primo maior que 3. Eleve-o ao quadrado e subtraia 1 dele. O resultado é divisível por 24! Mas, por que?”

Há alguns dias atrás, o Joshua Bloch, programador proeminente e mais conhecido pelo seu belo livro Effective Java, propôs esse problema de aritmética no twitter. Pelo visto, o Joshua Bloch gosta bastante de desafios matemáticos. Na verdade, todo bom programador que eu conheço ou mesmo apenas ouvi falar, tem uma quedinha pela ciência exata. Mas veja bem, isso não significa que para ser bom programador TEM que ser bom em matemática. Isso é apenas uma correlação, não implica causalidade.

Mas, vamos ao que interessa. Por que sempre que eu escolher um primo maior que 3, elevá-lo ao quadrado e subtrair por 1, o resultado sempre será divisível por 24? É bem simples entender porque, mas preste atenção.
Vamos por partes. Escolha um primo (digamos p) maior que 3. Logo temos p > 3.
Elevando ao quadrado e subtraindo 1, temos p²-1, certo?
O que exatamente é p² – 1? Nada mais que o produto de (p + 1) x (p – 1).
A partir daí é “sacada”. Vamos juntar os fatos:

1 – Você sabe que, qualquer que seja o número escolhido, ele faz parte da sequência: p – 1, p, p + 1. Você sabe também que a cada 3 números inteiros em sequência, um tem que ser divisível por 3. Como esse não é p (por definição), será ou p+1 ou p – 1.

2 – Também sabe que acima de 2, todos os primos são ímpares. Logo p + 1 e p – 1 são pares.

3 – Se p – 1 e p + 1 são pares, ao menos um deles tem de ser divisível por 4. Enquanto o outro será divisível por 2 (e não divisível por 4) e 3.

4 – Para um número ser divisível por 8, ele precisa ser divisível por 2 e 4. E para ser divisível por 24, tem de ser divisível por 3 e 8. Logo, temos que (p – 1)(p + 1) cumpre essa premissa perfeitamente. Daí, (p + 1) (p – 1) sempre será divisível por 24.

É uma prova simples e sem muita formalidade. Porém, elegante o bastante para ser apreciada por aqueles que curtem uma aritmética básica. Espero que tenham gostado!

Padrão
Desenvolvimento Web, Design

Exceções: “checked ou unchecked – Eis a questão!”

Você é designado para procurar um bug num sistema super importante onde você trabalha. Ao ler o código, você percebe um trecho assim:


try {
    controladorUsuario.salvar(diretor);
 }
 catch(Exception e) {}

E agora? Largo tudo, ligo pra minha mãe dizendo que a amo e me jogo da varanda? Calma, ainda não. Você, como bom programador deve consertar o código primeiro. Pensando em como as exceções são tratadas de forma desordenada nos sistemas legados que eu já trabalhei/já fiz, resolvi pesquisar mais sobre a forma correta de se tratar erros/exceções nos nossos  sistema. Há tempos já vinha pensando sobre o assunto e resolvi escrever no blog agora, como uma forma de difundir essas técnicas. Neste post, eu dou algumas dicas e conceitos sobre exceções que pude coletar em alguns livros de peso na área de desenvolvimento de Software. Aí vão elas:

Checked ou unchecked?

Primeiramente, vamos aprender/rever o conceito de exceções checked (checadas) e unchecked (não checadas) que servirão de base para alguns argumentos mais a frente neste post.

Checked:  São exceções que obrigatoriamente devem ser tratadas de alguma forma. Ou seja, o programador é obrigado a fazer algo com ela – tratar com um bloco try-catch (e suas combinações) ou relançar com throws na assinatura do método. Note que esse tipo de exceção não existe na maioria das linguagens. Por exemplo, Ruby e C# não possuem o conceito de checked exceptions.

Unchecked: São exceções que o programador não é obrigado a tratar.  Elas podem ser tratadas, mas o ponto é que isto não é obrigatório! Caso não sejam tratadas,  são automaticamente relançadas para a camada acima até achar alguém em alguma camada que a trate – em última instância, o erro é lançado na tela ou pior, estoura silenciosamente e pára. Em Java, essas exceções são subclasses de RuntimeException (exceções de tempo de execução).

Ok então. Mas, qual das duas usar? “Se a maioria das linguagens não tem exceções checadas, é porque não são realmente muito importantes” você talvez pense.  Esse é um assunto que dá muito pano pra manga e vários escritores técnicos bem reconhecidos já opinaram sobre isso. Alguns contra, outros a favor. Mas, gosto de ver pelo seguinte ponto de vista: Isso depende muito do que você quer. Pense por um momento no conceito de capturar exceções. É uma chance que o programador tem de se recuperar de uma falha na execução do programa. Quando você lança uma exceção checada, você está na verdade deixando bem explícito pra quem for cliente do seu código que ele tem sim uma chance de se recuperar da falha que ocorreu.  Por exemplo, ao tentar sacar R$50,00 numa conta com R$10,00 de saldo, você deve lançar algo do tipo SaldoInsuficienteException – checada. Dessa forma, não tem perigo de o programador deixar essa falha vazar para a camada acima e você o dá a chance de redirecionar o usuário para uma página de erro mais amigável. Agora, caso haja um incêndio no prédio onde o seu banco de dados está e nessa mesma hora o usuário tentou persistir um novo saldo, o que fazer? Bom, não tem como se recuperar, tem? Normalmente não.  Você não quer obrigar o programador a tratar um erro que não tem mais o que fazer, quer? Então lance uma exceção unchecked. São justamente essas 2 perguntas que você deve se fazer. “Existe uma chance de se recuperar da falha? ” e/ou “Quero dar uma chance de se recuperar dessa falha?”. É por isso que exceções como a famosa NullPointerException são não-checadas. Mesmo que você trate dentro do bloco catch para que o procedimento seja repetido ou algo assim, não vai mudar o fato que você está tentando acessar uma referência nula. Simplesmente ocorreu um erro de programação.

Cada um no seu quadrado

É importante respeitar o nível de abstração dos seus componentes. Tipo,  você já deve ter visto algo como (assuma que essa essa exceção é checked):


class TelaSalvarConta {

...

    try {

        conta.salvar();

   }

    catch(ConcurrentSerializationException exc) {...}

Aqui temos uma classe de alto nível manipulando um objeto de domínio e lançando uma exceção de baixíssimo nível. Isso é uma exposição indevida de seus objetos e significa que você quebrou o encapsulamento violentamente. Essa exceção deve ter vindo de há muito tempo sendo relançada pela própria API  até chegar a camada mais alta do sistema. Isso significa que a assinatura do método salvar() da classe Conta tem uma exceção (throws) com esse mesmo nome: ConcurrentSerializationException. Absurdo, não? Isso jamais devia ter acontecido. Em algum ponto, algum programador da API deveria ter feito:


catch(ConcurrentSerializationException exc) {

    throw new ObjectAlreadyInTransactionException(exc);

}

Sendo ObjectAlreadyInTransactionException uma exceção não-checada, não seria necessário o programador declarar uma exceção na assinatura do método, além disso, se ele desejar tratar essa exceção mesmo sem ser obrigado a isso, ele tem uma exceção mais próxima da camada de negócios.

Em resumo, trate cada exceção de acordo com a camada do sistema a qual ela pertence.

Evite sujeiras

E por sujeira eu quero dizer exceções checadas. Por exemplo, você gosta da forma como a API IO de Java trata as exceções? Todas elas são checadas! Muitas vezes eu quero fazer algum teste bem bobo no qual eu preciso ler um arquivo ou um properties e adivinha… sim, preciso de um try-catch pra um erro que não há recuperação.  Lembre-se que o tratamento de exceções por meio de try-catch impossibilita melhoria de performance no seu código pela JVM. Isso é muito importante. Sem contar que deixa seu código sujo e “fedido”. Ou então você precisa de mais uma exceção declarada na assinatura do método, o que quebra o encapsulamento (dando dicas pra o cliente do código o que aquele método faz) e dificulta a flexibilidade da API impondo regras a quem quiser herdar aquele método.  Faça o máximo para sempre lançar exceções não checadas, exceto (como já falado) se existir uma forma de se recuperar do erro e você quiser realmente obrigar o cliente a fazer isso. Um aspecto em que você sai ganhando é que em exceções não checadas você pode simplesmente deixar que elas cheguem a parte mais “alta” da aplicação e tratá-las de forma centralizada. Por exemplo, num ambiente web com filtros.  Senão utilizando algum framework de AOP.

Os erros são amigos

É de partir o coração ver algumas pessoas fazerem o seguinte ao tratar erros:


catch(Exception e) {}

ou


catch(Exception e) {

throw new Exception("Erro!");

}

Esses dois exemplos mostram código terrível e jamais devem ser usados. No primeiro o programador simplesmente ignora o erro e este se perde no limbo. Se você for forçado a tratar o erro no seu código, você deve tentar ao menos logar a exceção. Jamais ignore-a completamente como no primeiro caso.  Uma boa abordagem é tentar relançar a exceção em forma de RuntimeException, dando um throw new RuntimeException(e) – ou qualquer outra exceção do tipo RuntimeException que se adeque semanticamente ao erro. Dessa forma, você pára de impor que as camadas acima tenham de tratar ou declarar a exceção. Repito, jamais ignore exceções no catch.

O segundo exemplo é melhor que o primeiro mas ainda assim não é o ideal. Se um outro desenvolvedor está testando sua aplicação e se depara com uma mensagem de exceção dessa? Tipo… o que aconteceu que deu erro? Pois é, você pode ser mais específico e criar uma exceção mais específica para o erro, assim também como uma mensagem mais explicativa. Lembre sempre disso: “Programe sempre como se o cara que fosse  manter seu código fosse um psicopata violento que sabe onde você mora”.

Conclusão

Mostrei aqui algumas dicas de boas práticas sobre como lidar com exceções. Não é nada muito difícil, realmente. Apenas exige esforço constante do desenvolvedor para que o código seja facilmente compreendido. Pense sempre se deve realmente usar uma exceção checada. Na maioria dos casos uma exceção não checada dá conta do recado de forma mais sucinta. Não misture as abstrações das exceções. Exceções de baixo nível em baixo nível, as de alto nível em alto nível. E sempre que for tratar uma exceção, verifique se está tratando no nível correto de abstração. Se estiver, utilize mensagens explicativas sobre o erro ocorrido. E caso encontre aberrações (como a mencionada no começo do post), não se jogue da varanda. Respire fundo e comece a aplicar o que aprendeu.

Padrão
Desenvolvimento Web, Design, Design Patterns, Experiências

MVC não é sobre camadas!

- Como você separa as camadas do seu sistema?

- Ah… Sistema Web eu uso MVC mesmo.

Apesar de pouco tempo de carreira, já ouvi respostas como essas de tuia. Desenvolvedores graduados, mestrados, doutorados, verdadeiros alquimistas (note o tom irônico) argumentando que MVC é um padrão arquitetural onde você divide seu sistema em camadas, sendo elas: Model, View e Controller.  E, logo, se você utiliza MVC não há espaço para as camadas mais tradicionais: Apresentação, Negócios e Persistência. A verdade é que esse argumento é tão infundado quanto errôneo.  Apesar de achar essa confusão um tanto quanto natural (afinal eu já fiz essa confusão também), entendo porque ela existe. A sigla MVC tem sido “passada” para os aprendizes de desenvolvimento de software como… justamente, um sigla. Não é explicada a origem do padrão, nem a definição formal do que é, nem tampouco onde ela deve ser aplicada.  Enfim, não vou nem me delongar muito sobre o porquê da confusão, mas antes, pretendo esclarecê-la. Primeiro, vamos ver um pouco sobre a origem do MVC e sua definição.

O que danado é MVC ?


MVC é um padrão arquitetural originalmente criado em Smalltalk no fim da década de 70 que teve por objetivo inicial trazer simplicidade ao manipular interfaces  gráficas.  O que simbolizam essas letras?

M: Model. É o modelo de negócio da sua aplicação. Suas classes básicas, seus Services, o que quer que você utilize e seja particular do seu domínio. Seria o core da sua aplicação. Classes como Conta, Banco, classes de repositórios (não confundir com DAOs), classes de serviço, as exceções específicas do seu domínio e  classes utilitárias do domínio se encaixam no ‘M’ de Model, ou modelo.

V: View. É a parte responsável por mostrar visual para o usuário. O objetivo da View é mostrar o estado atual do seu modelo. É papel da View saber quando o modelo foi mudado (o modelo também pode notificar a view da mudança, apesar de eu não gostar desta versão), de forma que ela possa refletir isso de forma plena. Todos os componentes gráficos estão incluídos nessa categoria. E por componente eu não quero dizer classe, por exemplo, JSPs são views. Também arquivos html, javascript, swf, além de classes que tratam de interfaces gráficas – Actions da vida em ambiente web e TelaCadastro ou TelaLogin em ambientes Desktop etc.

C: Controller. É a parte mais inteligente desse padrão. É responsável por tomar a decisão “para quem devo direcionar, dado que o usuário propagou esse estímulo”. Por exemplo, uma classe ‘Controller’  recebe uma requisição do usuário e, baseada nessa requisição, decide qual view será mostrada para o usuário. Em ambientes Web essa classe faz o papel de “Front Controller”, que já é outro padrão arquitetural.

Já vi muito, mas muito mesmo, ocorrer a confusão entre Controllers e Controladores. Controller é completamente diferente de Controladores de objetos de domínio. Controladores são parte do domínio: realizam serviços utilizando classes básicas e suas dependências.  São Model. Controllers não devem fazer parte do seu domínio. Alguns colocam como View e em alguns casos utilizam como parte da camada de aplicação. Certa vez,  decidimos não utilizar esse nome confuso, mas o sufixo “Service” para nomear as classes que realizavam operações nas classes básicas. Mais tarde, um dos líderes técnicos disse que tinha uma observação a fazer. Ele incentivou a equipe a prezar por código de qualidade, porque no nosso sistema estávamos manipulando objetos de negócio diretamente na “Camada de View” sem passar pela “Camada do Controlador”. Um verdadeiro estupro. Claro que não o critiquei publicamente e não expus o comentário cheio de infelicidades, mas me limitei a esclarecer que os controladores estavam sim ali, apenas com sufixos diferentes. Também expliquei a diferença entre Controller e Controladores, e que aquilo estava causando confusão, de forma que todos ficaram satisfeitos.

MVC são apenas alguns patterns!

MVC na verdade tem por objetivo definir interações entre componentes do sistema e não agrupar componentes da aplicação, como muitos o entendem. Para entender isso, note que  MVC realmente é sobre design patterns (padrões de projeto). Mais especificamente – Strategy e Observer. Mais especificamente são 2 interações entre componentes:

1 – Quando o Model (Observable) muda seu estado, a View (um Observer) é notificada.

2 – Quando a View propaga alguma ação, como o Controller é o Strategy da View, a View delega ao Controller a decisão de “para que parte do Model notificar a mudança”. Esse Controller, por ser um Strategy, pode ser modificado em tempo de execução.

 

Interações são descritas por meio de Patterns.

Head First Design Patterns (Freeman & Freeman)

Estes são os 2 princípios fortes por trás do MVC. Alguns ainda dizem que existe um Composite limitado ao Model, mas isso é se prender demais a versão original do padrão feita em SmallTalk. Enfim, note que estas interações não dizem NADA a respeito de camadas. São interações ora essa! Ou seja, não é necessário você ter um componente View pra estar utilizando MVC, apesar de eu nunca ter visto isso acontecer na prática. Mas sim, você pode utilizar esse mesmo modelo de interações entre componentes de inúmeras formas diferentes, usando View ou não.  Também não é necessário estar usando Web pra utilizar MVC. De fato, originalmente MVC surgiu pra aplicações Desktop… Enfim, você pode sim utilizar o padrão MVC num sistema Desktop tipo um Swing do Java ou na sua aplicação Android ou Flash! Lembre-se, MVC é sobre interações entre componentes! Repita pra você mesmo: MVC não é sobre camadas! É sobre interações!


Tá, mas e a divisão por camadas que a minha avó me ensinou?


Camadas são utilizadas nas aplicações modernas para separar responsabilidades do sistema. Componentes com responsabilidades iguais ou similares ficam na mesma camada. Como já dito, numa aplicação Enterprise clássica por exemplo, temos Apresentação (componentes de interface gráfica), Negócios (classes básicas, services, helpers etc.) e Persistência. Imagine que essas camadas são empilhadas de forma que as que lidam com infra-estrutura estão na parte de baixo da pilha e as que lidam com interação com usuário estão mais acima. Nesse caso, teríamos de cima pra baixo: Apresentação -> Negócio -> Persistência. O ideal é que as camadas se comuniquem sempre com as abaixo e jamais com as acima delas:

Camadas separando responsabilidades

Camadas separando responsabilidades

Repare bem que agora estou falando de separar responsabilidades. MVC me provê 2 interações chave,  e eu as aplico onde quiser. Já separação por camadas me provê onde colocar os componentes, e eu faço interações como quiser. Inclusive posso utilizar… MVC! Não, esses 2 padrões não são auto-excludentes! Posso sim usar ambos na minha aplicação. E muitas fazem isso.

Uma vez definidas as camadas (sendo da forma tradicional ou não), eu posso agora olhar para as classes que interagem entre si, aplicar os patterns mencionados e estarei usando MVC. Utilizando os 2 padrões, normalmente a camada de apresentação fica com todos os elementos da View, e a camada de Negócios fica com o Model. O Controller não é tão simples porque é uma classe bem inteligente e exige bastante controle. Se sua aplicação for Web você “ganha ele de graça” com o framework que estiver usando ou com Servlets. Caso precise implementar, acho preferível colocar na camada de apresentação para não gerar dependências desnecessárias.

Conclusão

Jamais confunda esses dois padrões. MVC diz respeito a interações entre componentes, não quer dizer que a aplicação tem que ser web nem mesmo que precise ter uma View. Camadas separam componentes da aplicação de acordo com responsabilidades. Ambos os padrões são muito úteis como ferramenta para qualquer desenvolvedor, mas é necessário ter perspicácia para ver as coisas além do óbvio, além do que é passado por aí. Não force o uso destes padrões (nem de algum outro). Mas use-os com moderação, onde os benefícios deles fiquem bem claros para você e para o seu cliente. Eu gosto muito deste post do Phillip Calçado sobre MVC e da explicação deste livro.  Qualquer dúvida, postem comentários. Ah! E usem filtro solar! =]

Padrão
Design, Design Patterns

Sua API fala? – Interfaces fluentes

Pra começo de conversa eu chego e digo logo que não gosto da forma como Java trata datas e calendários. Há alguns anos atrás eu lia alguns programadores ‘rock-stars’ dizerem que era uma API mal feita e tudo mais. Mas eu não entendia o porquê. Bom, há algum tempo eu tenho entendido a razão disso. Tirando o fato da classe Date e da classe Calendar serem mutáveis (inclusive essa questão já é clichê, falo disso em outro post – prometo), as operações não são nada elegantes. Trabalhosas, verbosas, exigem um monte de classes pra formatar tipo DateFormat, NumberFormat (no caso de números), apresenta problemas de performance em certos casos, difícil de estender e etc.  Todo mundo que já trabalhou um pouco com Java sabe como essa API funciona. Talvez não tenha noção do como ela é chata de trabalhar, mas sabe como funciona. Veja isso por exemplo:


//Isso tudo é pra setar uma data (12 de fevereiro de 1987)

 Calendar calendar = Calendar.getInstance();
 calendar.setTimeZone(TimeZone.getTimeZone("Universal");
 calendar.set(Calendar.DATE, 12);
 calendar.set(Calendar.MONTH, 2 - 1);
 calendar.set(Calendar.YEAR, 1987);
 Date feb12_1987 = calendar.getTime();

Um monte de linha de código pouquíssimo expressivas. Mais feio que parto de ouriço. E olhe que essa data não está sendo formatada. Se alguém quiser escrever isso no cabeçalho duma página, por exemplo? Mais trabalho ainda pra formatar em String e… haja paciência. Não estou querendo dizer que você jamais deva usar a API Dates e Calendars na vida. Mas, veja como essa API soa melhor:


//Setando a mesma data (12 de fevereiro de 1987) usando Joda-Time API

DateTime feb12_1987 = new DateTime().withDayOfMonth(12).withMonthOfYear(2).withYear(1987);

Então? Bem melhor, não? Não mudei o objeto em questão (cada método chamado retorna um novo objeto DateTime modificado), não usei variáveis static, não precisei criar um calendário pra fazer operações no meu tipo principal (no caso data) e o melhor de tudo: tudo em uma linha e facílimo de ler. Muito elegante. Esse é um belo exemplo onde a API Joda-Time usa method chaining, que é a técnica de encadear os métodos chamando-os em seguida, mas, vai além, faz o serviço de forma fluente! Repare como essa chamada parece mesmo uma frase: “nova data com dia do mês:12, com mês do ano:2 e com ano 1987.”  Alguém pode dizer que isto é, na verdade, o padrão Builder. Bom, também. Mas não apenas. Builder se preocupa apenas em construir objetos, não com legibilidade e fluência. Builder por padrão é usado com métodos set() e isso por si só já tira a fluência da chamada. Ah sim, além disso podemos fazer qualquer operação no objeto com interfaces fluentes (formatar saída, fazer conversões etc.), enquanto com Builder a idéia é apenas construir o objeto. Enfim, a API do Joda fornece uma porção de interfaces fluentes que me deixam feliz e satisfeito =D . Mas, o que exatamente é a tal da interface fluente?

Interface fluente é um estilo de escrever código no qual a função ou as funções que você deseja desempenhar são feitas de uma maneira bem mais simples do que a maneira usual e simplesmente “fluem”. “Interfaces” no sentido mais amplo da palavra , ou seja, os métodos expostos de uma dada classe. E não necessariamente interfaces Java.  Também podem ser chamadas de Interfaces Humanas, visto que o código cliente é que vai ser muito mais fácil e legível de escrever e compreender. Já pra quem escreve a API é mais difícil. Sim, mais difícil porque exige muito mais tempo pensando (às vezes muito tempo mesmo) em como prover um sistema de encadeamento de métodos que qualquer pessoa possa usar facilmente, com uma nomenclatura super clara que realmente indique qual o passo a seguir e ainda com todos os atributos de qualidade que uma boa API deve ter – alta coesão e baixo acoplamento.  Nem adianta eu ficar tentando explicar com conceitos esse estilo de API. Um exemplo vale mais do que mil palavras. E com certeza você vai entender melhor o que são de fato com exemplos. Suponha uma classe Money que representa uma quantia de dinheiro em qualquer moeda. Eu quero dar suporte aos clientes dessa interface para fazer soma de valores, subtrações de valores, conversão de moedas (tanto em símbolo que representa a moeda como em taxa de conversão) e formatação pra String. Então criei uma classe Money (me apeguei mais a fluência dela e deixei algumas potenciais falhas , por exemplo  tratamento de erros e outros, não reparem):

 


public class Money {

  public static final String REAIS = "R$";

  public static final String USDOLLARS = "U$";

  public static final String EUROS = "€";

  public static final String COMMA = ",";

  public static final String POINT = ".";

  private double value;

  private boolean usingComma;

  private static NumberFormat formatter;

  static {

    formatter = NumberFormat.getNumberInstance();

    formatter.setMinimumFractionDigits(2);

  }

  //Valor padrão

  private String currency = USDOLLARS;

  private Money(double value) {

    this.value = value;

    this.usingComma = false;

  }

  public static Money get(double value) {

    return new Money(value);

  }

  public static Money get(String value)  {

    double numValue = Double.parseDouble(value);

    return new Money(numValue);

  }

  public double value() {

    return this.value;

  }

  public long inCents() {

    return (long)this.value*100;

  }

  public String asString() {

    String formattedValue = formatValue();

    return formattedValue;

  }

  public Money in(String currentCurrency) {

    this.currency = currentCurrency;

    return this;

  }

  public Money usingComma() {

    this.usingComma = true;

    return this;

  }

  public Money convertTo(String currency) {

    this.value *= MoneyConversion.calculate(this.currency, currency);

    this.currency = currency;

    return this;

  }

  public Money plus(double amount) {

    this.value += amount;

    return this;

  }

  public Money minus(double amount) {

    this.value -= amount;

    return this;

  }

  private String formatValue() {

    String formattedValue = this.currency + formatter.format(this.value);

    if(this.usingComma) {

      if(formattedValue.contains(POINT)) {

        formattedValue = formattedValue.replace(POINT, COMMA);

      }

    }

    else {

      if(formattedValue.contains(COMMA)) {

        formattedValue = formattedValue.replace(COMMA, POINT);

      }

  }

  return formattedValue;

}

public static void main(String[] args) {

    String result1 = Money.get(10).in(REAIS).convertTo(USDOLLARS).usingComma().asString();

    System.out.println(result1);

    long result2 = Money.get(1).plus(15).plus(60).minus(50.5).inCents();

    System.out.println(result2 + " cents");

    String result3 = Money.get(0).plus(100).in(EUROS).asString();

    System.out.println(result3);

  }

}

 

“Ah!” – alguém pode dizer – “mas não era melhor fazer métodos do tipo…  new Money(10).convertFromReaisToDollarsUsingCommaAndFormatAsString ?” Veja bem, nesse caso o método viola o Princípio da Responsabilidade Única fazendo 3 coisas. Além disso, eu continuo a ter uma grande quantidade de métodos como seria no caso sem interface fluente. Imagina só fazer um método para cada combinação diferente de operações! Flexibilidade zero.

É meio estranho o fato de você retornar o próprio objeto num método modificador. Mas lembre-se que esse é um padrão de escrita diferente. Diferente de  JavaBeans, onde o objeto teria apenas seus atributos e cada um com seu get e set correspondente. Para obtermos a fluência precisamos invocar os métodos desejados sempre retornando algo que possa ser usado na próxima invocação. No caso, eu escolhi por retornar novas instâncias de Money(de forma que eles são imutáveis) exceto quando o cliente desejar pegar o resultado final das operações, quando o retorno é uma String com o valor formatado (asString()) ou a quantidade de centavos (caso queira formatar da sua própria forma). Mas como eu disse, Money é uma classe boba no sentido dos pequenos detalhes. A ênfase está nos nomes e eu não me canso de estressar esse ponto: Pare bastante pra pensar nos nomes dos métodos da sua interface fluente! Sem dúvida é bem mais trabalhoso fazer algo assim com qualidade, mas os resultados são fascinantes. Ah sim! Note que algumas linguagens tornam essa tarefa mais fácil, por exemplo Ruby e Python, tão falados hoje em dia. Em Java e C# já não é tão fácil ou os resultados não são ótimos. C++ e  C são verbosas demais, cheias de lixo sintático e tal. No mais, linguagens dinâmicas (também por serem ricas em syntax sugar) são mais produtivas pra isso também.

Mas cuidado! Não saia por aí fazendo interfaces fluentes em todo código que pegar. É uma técnica que deve ser usada com moderação e razoabilidade. Uma classe com 2 métodos e sem nenhuma chance de crescer não tem motivo de ser fluente – já é simples por natureza. Se não houver um bom range de combinações possíveis de operações também não compensa – muito trabalho pra projetar algo que não vai ser usado. E cuidado pra não ficar com mania de fluência e querer aplicar princípios de fluent interfaces em classes normais, fazendo sets retornar objetos e tal. Isso é uma violação do princípio CommandQuerySeparation. Simplesmente não funciona, ok?

Note que TDD (Test-Driven Development) cai como uma luva se você está querendo implementar Fluent Interfaces.  Tipo, primeiro você escreve a forma que o cliente deve chamar as operações (seu código não vai compilar) e depois escreva apenas código necessário para fazer seu teste compilar.  Depois refatore sua implementação para fazer o teste passar. Existe uma pá de bons artigos sobre interfaces fluentes. Eu gosto desse e desse principalmente que é baseado no post clássico do Martin Fowler. Outros exemplos de APIs Java escritas neste estilo e amplamente difundidas são JMock (para testes) e Criteria do Hibernate. Enfim, a idéia motivadora por trás disso tudo é sempre a mesma – programe não apenas para a máquina entender, mas [principalmente] para as pessoas entenderem.

Padrão