Desenvolvimento Web, Web development

Programming inception (or understanding Node.js event loop)

    One of the main problems today in web development is the cost of I/O. I mean, everybody is talking about it. Every web app nowadays, even the smallest ones like blogs or personal pages follow the internet trend of being interconnected. So they always present a link to connect to Facebook, Twitter, LinkedIn and whatnot. Also many of them connects to Databases and clouds. Either way, they use a lot of I/O. And that’s where lies the problem.

But I don’t want to play with my threads anymore ma!

    Imagine a web app that receives millions of requests per minute and communicates with databases (wait for queries and updates) and other services around the web. Now take a look at this table to see why I/O is such a big problem for current programming technologies:

io-cost

    Notice that most Databases nowadays writes on disk, which means it’s slow. When the application needs to communicate with another service through network the waste is even bigger.
How to deal with many requests at a time? Well, today there are some fundamental ways to deal with concurrency in web servers, namely thread-per-request and process-per-request (using Unix’s fork() ).

Thread-per-request: Each request makes the server start a new thread to deal with it. Threads may not consume memory like processes, of course. But, needless to say it eats a lot of memory from the machine anyway. Take a look at this graph to see the difference between a server that uses this model (Apache with mpm_event) against one that uses a single-thread approach (Nginx):

nginx-apache-memory

Ooh! And don’t forget that when working with threads, things can get “real messy real quickly”.

Process-per-request: Each request starts a new process in the server. A process is heavier on the machine than a thread: it consumes even more memory and the overhead to start a process is higher. But some servers found a workaround: Unix forking. With forking we can create a new copy of the main process and instead of allocating a whole new memory for the child process, we can “share” the same memory of the main parent process. Servers like Passenger and Unicorn use this feature. Still, with hundreds, even thousands of connections, fork will be called until we have thousands of processes, which is not the way to go.

Enter Node.js

    The powerful concept behind Node is its single-threaded event-loop that leverages asynchronous calls for doing many things, even (take a guess) I/O! For instance in Java, while executing some code, if you send a query to the database, the code will have to wait for the database to complete it. No, not Node.js. It will execute the lines of code after the database command and then go back to it when the result is ready. It’s really only one thread running, which means if you put a “sleep” in your code, it will block the server for the amount of time stipulated on the sleep function. The idea is pretty cool, but let’s see some example of it. Imagine you have an array of objects you need to save on database and afterwards calculate some stats about these saved records:

//P.S: Really tried to display this code as a snippet.
//It just was not WordPress' day =/

// Loop through some items
items.forEach(function(item){
//Now write each of this items to the disk (I/O here)
item.saveAsync();
});
// This function is meant to be called once all the async
// calls above are done, but we don't know if/when they are,
// and therein lies the problem with this approach
calculateStatsAfterSaving();

It’s not about Node.js, it’s about the Reactor Pattern

    To better understand how the Reactor pattern works, let me help you with an analogy. Imagine you have a coffee shop in one of the most crowded corners in NYC. People are ordering all the time and you serve the tables yourself. Sometimes the order is something previously prepared like a milk or a water. But once in a while some smarty pants will order a spaghetti. If you stop to make the spaghetti, people will be waiting a while since you are the only who serves the tables. But you’re awesome and decides to delegate the task of preparing meals to your butlers: Jeeves and Alfred. You tell them: “Jeeves, you make the pasta and Alfred makes the sauce. When you guys finish, put it on the counter and notify me.” This way it becomes pretty simple for you to handle more orders quickly. If more complicated orders like this shows up, well, just imagine Jeeves and Alfred are so competent that they can receive concurrent requests, no problem. That’s the idea behind the Reactor pattern.
     The single-thread keeps receiving requests all the time and responding, but it cannot block to do more “complex” ones, like blocking I/O (database queries, connect to Facebook, write to a file and so on) otherwise all the other requests will have to wait to be served. Internally, this single-thread delegates the work to fibers, which can run in parallel and avoid blocking the thread by doing I/O. Think of these fibers as threads. Except they’re light-weight and decide when they will pause or resume, not the kernel. See the picture to understand better.

node_loop

    Another detail important to mention is that Node.js expects to return quickly to the client. So if a callback function works with a very long computation, the single-thread will be busy with it, which can stop the event-loop completely. The advantage comes when you have a lot of blocking I/O. Disaster comes when you have CPU-intensive work.

Is Node.js really “the king’s new clothes” ?

    Callbacks can be hard to understand. For all of us used to program in a synchronous way, async can get real messy. Starting with the code. Imagine that: for every function, pass another function with the commands to execute when the first function is finished. What if the callback has a callback itself ? See the point? Node.js is generally not easy to understand, like, say, Ruby or Java. The strategy changes. The way of thinking changes. It can be a lot of different things at once. But no worries: there are solutions. Just to mention some of them, node-async and node-Fibers try to solve the problem with many nested callbacks and exception handling. Going back to the problem some lines above, node-async has some functions that help us to write more readable code:

//P.S: Really tried to display this code as a snippet.
//It just was not WordPress' day =/
async = require("async");
// 1st is the array of items
async.each(items,
// 2nd the function that each item is passed into
function(item, callback){
// Call an asynchronous function
item.saveAsync (function (){
// When done, alert via callback
callback();
});
},
// 3rd parameter is the function call when everything is done
function(err){
// All done
calculateStatsAfterSaving();
}
);

    Yeah, yeah, I agree with you that either way synchronous code beats asynchronous code. So remember that before choosing Node.js for your next project. Although, threads are a pain to work with. You need to be aware of what classes/libraries are thread-safe, be careful to avoid deadlocks and memory leaks, not to mention the whole parafernalia of options to use: mutexes, threads, semaphores, locks, synchronized blocks etc. On the other hand, the Node.js concurrency model is very easy to learn! Although its code will not always present an elegant approach. So either way there will be trouble. The thing is: concurrency is not a simple problem. Therefore solving this complex issue can get messy, one way or another.

Padrão
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