janeiro 27th, 2009 §
Minha opinião: não.
Um projeto não anda mais rápido com menos qualidade ou mais lento com mais qualidade. Os profissionais que defendem a tese de que qualidade interfere no prazo do projeto, costumam se alienar nos Gantt Charts. Pois, quando ocorre uma redução na qualidade, os gráficos apresentam “progressos” que inexistem, porque não é progresso de fato, é apenas um trabalho que será adiado mais pra frente, sempre antes do prazo de entrega. Queda de qualidade apenas cria mais impedimentos para a conclusão do software, não encurta o seu tempo.
Na maioria das vezes, os profissionais não sabem definir, em seu prójeto de software, o que é qualidade. Não raro, pra algumas pessoas, a qualidade é definida como a produção de um diagrama extenso no Rose, a definição detalhada de padrões, as checagens intermitentes que garanta que nada saiu do lugar, o padronização de codificação… Desculpe, mas nada disso tem a ver com qualidade.
Permita-me explicar: na verdade, uma das coisas que determina a existência de projetos atrasados é a desconfiança. Sim, é um fator humano, não técnico. A desconfiança faz com que aquilo que, em condições normais, seria ridículo, se torne perfeitamente plausível num ambiente hostil.
Exemplos em desenvolvimento de software: o programador que (re)escreve toda a conversa por e-mail (pois há a desconfiança de que o outro lado mude de idéia); o manda-chuva que escreve uma aplicação “amarrada” (pois não há garantia de que os programadores juniores escrevam corretamente); o arquiteto que escreve toneladas de documentação (numa eventual cobrança dos superiores, ele pode comprovar que fez o trabalho corretamente); o especialista que encontra um nicho de trabalho numa equipe e não faz outra coisa (garante que ele não será cobrado por problemas no profuto final); o gerente que põe um prazo apertado (para garantir que não haverá “corpo-mole”).
Ou seja, todos desconfiam de que seus pares possam um dia puxar o teu tapete, de que seus subordinados mintam e não entreguem o esperado, de que seus superiores não te dê suporte e não torele as mínimas faltas, de que os clientes tentem enrolar e te trapacear… A solução adotada por muitos são os infindáveis documentos que devem ser assinados com sangue por ambas as partes, as verificações e reverificações de procedimentos, a mentira, a cortina de fumaça, as desculpas de que “isso é assim mesmo”… Todo esse trabalho só existe por causa da desconfiança, trabalho esse que consome tempo que consome dinheiro que não servirá pra nada no produto a ser entregue (como se diz por aí: não “agrega valor”).
A solução é simples, a princípio. Se existe desconfiança, crie um ambiente de confiança. Dããã! Fazer isso não é tão simples, e depende de tolerância, respeito mútuo, valorização de um time ao invés de um indivíduo. Cuidar da confiança é bem melhor do que as firulas que servem apenas para remediar situações específicas que não atacam o mal pela raiz. Parece até que as pessoas procuram buscam curar o câncer receitando analgésicos!
janeiro 21st, 2009 §
Isso mesmo! Não vá hastear a bandeira vermelha lutando pela condição injusta que os programadores são tratados. Para o mercado de trabalho, você é um produto que possui valor. Também não fique triste, você não tem que se conformar, você pode ficar por cima. Vou te dar alguns exemplos:
1.
Você é um agricultor, e a produção na roça é seu único meio de sustento. Como sua produção é revertida em dinheiro, você está mais interessado em cultivar aquilo que te oferece o maior retorno. Mas o problema é: o que cultivar? Imagine que num determinado ano a batata está com preços lá nas alturas. Com isso, você passará o ano cultivando batatas. No ano seguinte, você vende o seu produto para receber a grana alta que estava tanto sonhando… porém o valor recebido está bem abaixo do esperado.
Por que isso? O que aconteceu? Simples, você não foi o único que olhou o preço alto das batatas. Todos olharam! E o que essa multidão fez? Plantaram batatas! E com tantas batatas disponíveis no mercado, o preço individual caiu. Simples regra econômica. Os poucos que se deram bem, foram aqueles que não cultivaram batatas, mas algodão, cuja produção diminuiu de um ano pra outro.
Agora mude as palavras, ao invés de agricultor, leia programador. Ao invés de batata, leia qualquer tecnologia ou buzzword da moda, como SOA ou Cloud Computing. Perceba que no momento em que você ouvir uma expressão da moda, levará um ano (tá, mais ou menos) para você ficar muito bom. Até lá, aquilo que você estudou não será uma área tão bombada, e seu salário permanecerá igual ao que era antes. Ruim, não?
Por que você resolveu aprender aquele conteúdo na primeira vez que o viu? Necessidade de se adequar ao mercado? Minha opinião, você não pode ser tudo aquilo que a sopa de letrinhas das ofertas de emprego lhe pedem, esqueça! Quando se pede muita coisa, fica-se a sensação de que a consultoria está buscando um Chuck Norris, um herói que faça o impossível possível. Tenha como guia aquilo que você faz e gosta. Exemplo: surgiu a API do Android, uma biblioteca que permite construir aplicativos para o sistema operacional dos futuros celulares. Deveria eu aprender essa API? Talvez até faça sucesso, mas o que eu faço (e gosto) é programar aplicativos que rodam em servidores, nunca me interessei por aplicações móveis. Então, colocarei esse framework como baixa prioridade na lista das coisas que gostaria de aprender. Porém, existem programadores que já conhecem Java ME ou que sonham em trabalhar com celulares, que talvez encontrem uma motivação maior do que eu encontraria para aprender o Android.
E se o framework fizer sucesso? Vou deixar perder essa oportunidade? Sim, pois não conheço dispositivos móveis, e não é a área que eu gosto mais.
2.
Qual a diferença entre Bohemia e Itaipava? Não sou conhecedor tanto assim do universo etílico, mas posso afirmar uma coisa: a primeira é mais cara que a segunda. Por que? Bohemia é supostamente de qualidade superior em relação às outras cervejas. Não só isso, essa qualidade é perceptível aos consumidores da bebida, fazendo com que estes paguem mais caro sem reclamar. De fato, para a AmBev, não custa muito mais produzir Bohemia do que produzir Antarctica. Muito provavelmente, a companhia mantém uma margem de lucro baixa para as cervejas mais populares, compensando a perda com as cervejas mais elaboradas. É fato que, para os poucos que não se importam em pagar mais caro e que apreciam uma boa bebida, o preço pago a mais não é uma ofensa, mas ao contrário, chega a ser considerado justo e até credita-se a ter um melhor custo-benefício. Bohemia é o que se pode chamar de produto premium, que não é limitado às cervejas, existindo em vários segmentos de mercado onde o produto final não é uma commodity.
Agora, se você é um produto, por que não ser então um produto premium? Ser premium significa simplesmente que você oferece mais valor ao seu empregador, e portanto recebe mais por isso; mas não porque você resolveu dar uma de machão e ficou trabalhando 14 horas por dia, mas porque você é diferenciado. Tá, eu sei, a maioria das empresas não dão a mínima, tomam mesmo é Kaiser. Mas e se existir 1% onde o ambiente onde não é assim? Não vale a pena ser diferenciado?
Mas como ser diferenciado? Duas dicas (que não são as únicas):
- leia um livro de computação por ano: sério, a absoluta maioria dos programadores não fazem isso, um livro por ano é garantia certa de estar bastante acima dos outros. Se precisa te indicação, reduzo a dois livros: The Pragmatic Programmer, e Patterns of Enterprise Application Architecture.
- aprenda inglês: leva tempo, uns cinco anos ou mais (e não há cursinhos que focam “na conversação” que vai reduzir esse tempo), mas não é algo que vai se perder no tempo e ficar ultrapassado.
3.
Carro: existe o ano do modelo. Roupas: existe a estação. Computadores: existe incremento de mais e mais velocidade e capacidade.
A indústria, a partir do século XX aprendeu a incrementar seus produtos de tempos em tempos. Alguns podem pensar que isso é esperteza dos empresários para fazerem os consumidores comprarem mais. Mas, se pensarmos bem, quando o consumidor possui um produto que estragou ou quebrou, e quer comprar um novo, ele não tem o desejo de comprar a mesma coisa, prefere comprar algo melhor do que ele tinha. Então, é do interesse de tanto dos empresários quanto dos consumidores que os produtos ofertados mudem com o tempo.
Nossa área também vive essa constante de mudanças. O tempo passa e novas bibliotecas, novos frameworks, novas linguagens surgem e, embalados por “vendors” ou por evangelistas, eles são ofertados ao mercado. Não raro, os programadores ficam numa batalha contrária, reclamando do excesso de frameworks, da modinha de linguagens, do fluxo incessante de alterações… Melhor seria se essa multiplicação de novas coisas terminassem, não é mesmo?
Discordo! Seu problema é não entender princípios e padrões existentes em cada tecnologia. Por exemplo, vários frameworks seguem o mesmo padrão MVC, várias linguagens seguem o paradigma de orientação a objetos, outras linguagens seguem o paradigma funcional, mecanismos de persistência costumam apresentar os atributos “sujos” e o cache de requisições numa mesma transação. Aprender aquilo que está por trás de tecnologia é a melhor maneira de, quando algo novo e melhor surgir, você não fique perdido. Há um “problema”: abstrair conceitos de ferramentas só é possível quando você se defronta com mais de um tipo de linguagem ou framework. Infelizmente, a maioria apenas conhece uma linguagem (Java), apenas um banco (Oracle), apenas um mecanismo de persistência (Hibernate) e apenas um framework (Struts). Se é esse seu caso, corra atrás de aprender uma segunda opção. E se conseguir abstrair, as terceiras e quartas opções serão bastante fáceis.
janeiro 14th, 2009 §
Esse post é uma continuação da série Closure, que também já falou de C++.
Java tem closure? Como assim? Bom, a linguagem tem mais alguns truques que dá pra se aproximar melhor de closure do que C++, mas ainda é bem distante de linguagens onde closures é uma coisa natural (tanto é que os javeiros mal usam essa sintaxe). Enfim, e ainda por cima, precisarei utilizar a principal muleta das linguagens chinfrins: design patterns.
» Read the rest of this entry «
janeiro 12th, 2009 §
Meu, hoje, 12/01, quase tive um ataque cardíaco (não, não tive não, é brincadeira). Duas coisas que eu vi, uma na Mundo Java, outra no GUJ, me deixaram com raiva.
Vamos à Mundo Java primeiro que, como sempre, está excelente. Hoje vi só a matéria sobre EJB e Spring (muito boa), porém houve um pequeno trecho que me deixou de estômago embrulhado (ênfases são minhas):
Anti-pattern em injeção de dependência
Com a facilidade e praticidade do EJB 3.0, alguns desenvolvedores acabam deixando de lado a preocupação com a escalabilidade e gerenciamento de recursos do container, anotando toda e qualquer classe do sistema para se beneficiar da injeção de dependência. Isso não é uma boa prática porque cada objeto anotado com @Stateless existirá um novo recurso para ser gerenciado pelo servidor de aplicações.
Um exemplo prático dessá má utilização de injeção de dependências no ambiente EJB é a implementação do design pattern Data Access Object (DAO) como um EJB. Dependendo do design do software, cada funcionalidade do sistema irá conter um DAO e essa funcionalidade será um Session Bean para se beneficiar do recurso de injeção de dependência do servidor de aplicações. Para evitar esse problema, uma solução seria injetar o EntityManager diretamente nos session beans, por meio da anotação @PersistenceContext, ou utilizar o design pattern Abstract Factory.
Primeiro, vamos à bronca: você não está programando em C, nem precisa ouvir os malucos que programam nessa linguagem. Fim da bronca.
Segundo, existe dois problema na definição de um Stateless Session Bean (SLSB): um que a anotação não é sobre o objeto (isso ainda não existe na linguagem), mas na classe; e dois que, quando você cria um SLSB, não há a criação de um recurso, mas de váááários recursos em pool. Se você olhar na configuração do Glassfish, verá que por default é possível ter até 1024 instâncias de SLSB no pool.
Terceiro, sabe qual a justificativa para isso ser um anti-pattern? Escalabilidade, só isso! Não é problema de code smell, de código que gera resultados imprevisíveis, de problemas de manutenção…, nem nada! Simplesmente ES-CA-LA-BI-LI-DA-DE! Agora, o pool de instâncias de SLSB não existe para se ganhar escalabilidade? Se tiver problemas com isso, vai nas configurações de seu servidor e mude os parâmetros do container EJB! Outra solução é comprar mais memória ou, se for mais sério, fazer load balance de mais de um servidor.
Pior ainda, a alternativa ao “anti-pattern” é “injetar o EntityManager diretamente nos session beans”, o que fatalmente acarretaria códigos macarrônicos com métodos gigantescos e difíceis de ler. Ou então, “[utilize] o design pattern Abstract Factory” que, pelo que já vi usado no contexto do EJB, é POG!; pois é usado um único EJB para o Factory, que devolveria os DAOs necessários, que por sua vez, tem código muito mais idiota para se pegar o EntityManager do que se fosse feito por SLSB!
Gente, use SLSB para DAO também! Que mal há nisso? Escalabilidade não é! Acho que no fundo, as pessoas sentem saudades do tempo em que cada camada tinha seu framework, tipo: era Struts para a apresentação, EJB para a camada de negócio, Hibernate para a persistância… Hoje estamos se aproximando da era onde os SLSB podem ser usados até na camada de apresentação (Seam / Web Beans)! E ninguém passou a escrever código horrível por causa disso! Por que raios ainda ficar nesse pensamento?
Vamos ao tópico do GUJ, maldito! (Não você que é maldito! O tópico!) (link) O cara parecia que quer defender com unhas e dentes que usar static é melhor que criar instâncias, polimorfismo…, enfim, essa coisa linda que é o OO.
Bom, o que sei é que usar static a torto e a direito no Java EE dá merda, pois é um static por class loader, e os servidores de aplicações possuem vários class loaders, cada um com potencialidade de carregar a classe e ter seu próprio static. Segundo, que com métodos static não dá pra fazer muita coisa que o Java EE oferece (EJB, por exemplo). Terceiro, que é idiota mesmo, coisa de gente que não sabe OO.
Agora, sabe a justificativa para usar static? O cara acredita que é mais rápido, simplesmente isso! Quer dizer, dava muito bem pra gerar um código bom, usando OO, e comprar uma máquina de configuração muito boa. Muito melhor do que se matar em otimizações minúsculas de veracidade duvidosa.
Aliás, vou dar um guideline para se fazer otimizações:
1. Pergunte ao cliente se está achando o sistema lento. Se a resposta for não, fim do guideline.
2. A compra de mais memória, mais disco ou mais blade custa menos que o pagamento de uma equipe de desenvolvedores? Se sim, vá na Santa Efigênia e fim de guideline.
3. Meça a duração usando vários casos possíveis.
4. Faça a alteração e meça de novo.
5. Se a nova medida não for muito menor que a medida antiga, jogue suas alterações no lixo e volte ao passo 4.
6. Caso contrário, comite a alteração e dê por encerrado (por enquanto).
Os dois casos me deixam perplexos: é como se para se justificar alguma coisa que não sabe bem o porquê, ao invés de ir mais a fundo e pesquisar, diz-se apenas que a altenativa “ruim” tem problemas de desempenho ou escalabilidade! Simples assim! E esquece que esses dois tipos de problemas está mais relacionado à arquitetura, à característica do sistema, ao “conjunto da obra” e muito pouco sobre a tecnologia ou o paradigma em si. Por muito escarcéu, muita gente escolhe o Barrabás.
Agora, por que as pessoas usam o argumento do desempenho / escalabilidade? Tenho duas teorias:
1. Alguns programadores aprenderam apenas uma determinada tecnologia em sua carreira. Quando esta tecnologia começa a sumir, eles passam a ter um certo desdém pelo novo, classificando pelos mais variados adjetivos. Alguns deles simplesmente não colam. Porém, o que, às vezes, fica marcado, é dizer que tal coisa não tem desempenho ou não tem escalabilidade, e por uma única razão: é difícil provar a menos que se meça com os próprios olhos. E como muita gente não faz isso, fica-se no benefício da dúvida.
2. Alguns programadores trabalham em ambientes péssimos de trabalho, a principal é a ausência de decisão e autonomia. Normalmente, as decisões são concentradas em pouquíssimas pessoas, e que nem sempre são as mais qualificadas. Os “artefatos” que saem das mãos dessas pessoas são os famosos diagramas de UML, bastando o programador codificar. (O mais imbecil nisso é que os “eleitos” escrevem diagramas tão detalhados que poderiam ter feito o negócio direto em código, e que haveria a mesma abstração. Mas não fazem código porque delegar essa atividade pra alguém é a melhor maneira de camuflar seus próprios erros.) E como o programador não tem a liberdade necessária para fazer seu trabalho, só lhe resta uma coisa intelectual para fazer: otimizar. Pena que será imperceptível para os olhos dos outros. Pena que o próximo a dar manutenção será ele mesmo.
janeiro 10th, 2009 §
Já viu aquelas discussões no Reddit ou GUJ sobre usar ou não exceções checadas? Sempre tem uns proponentes e oponentes defendendo um jeito ou de outro. Invariavelmente, a discussão não dá em nada. Primeiro porque não é uma questão de escolher um jeito e usá-lo por todo o sistema. Segundo porque, já que isso existe, a menos que você queira mudar pra C#, você é obrigado a conviver.
Se eu tivesse a oportunidade, do tipo, sei lá: viesse um cara, chamado James e me dissesse:
Leo, seguinte, eu tô a fim de fazer uma nova linguagem aí e, sei lá, achei interessante forçar o tratamento de exceções pra que ninguém esquecesse de tratá-lo, tipo uma exceção checada. O que você acha?
Minha resposta:
Horrível!
Sim, existe um limite prático pra tipagens verificadas por compilador, o aumento da complexidade. Isso certamente acaba complicando mais pra quem começa na linguagem. Mas enfim, já que não me consultaram…. o melhor é usá-las, e usá-las com sabedoria.
Mas Leo, como seria?
Boa pergunta. Uma definição legal é do livro Effective Java, que diz, na página 244:
… use checked exceptions for conditions from which the caller can reasonably be expected to recover… use runtime exceptions to indicate programming errors…
Lendo essas duas definições, pode parecer confuso, veja o que alguém poderia pensar: “Exceção checada só ocorre quando há erros de programação. Nunca cometo erros, logo sempre usarei exceções checadas!”
Não, não e NÃO!!!
Pra entender o que é um erro de programa, você deveria entender que os métodos de seus objetos só podem ser executados se determinadas pré-condições sejam satisfeitas. O problema é que miuta gente também nunca ouviu falar em pré e pós-condições. E dos que ouviram, aplicam de um jeito errado. Meu, vou contar uma história: uma vez eu estava vendo um “documento” de “caso de uso” e lá tinha a seção “pós-condições”. Em todas as vezes, juro, em TODAS as vezes, estava escrito: “Pós-condição: caso de uso executado com sucesso.”. O que?! Significa que é uma condição sine qua non de que NUNCA vai dar falha?
Vamo lá: pré-condição e pós-condição refere-se ao mundo externo do método (ou do fluxo ou do processo, depende do seu ponto de vista). Pré é como o estado do “mundo” deve estar antes da execução. Pós é como o “mundo” irá ficar.
Exemplo: um método de inserção. A pré-condição é de que o objeto exista e que seja de um tipo específico. A pós-condição é que no banco existirá um registro a mais, ou ficará como antes (em caso de erro).
E se eu chamar o método e a pré-condição não estiver sido respeitada? Erro! O método nem é chamado. E se a pós-condição não for respeitada? Erro também! O sistema, pelo menos, deve voltar ao estado anterior da execução.
Claro que isso não é implementado nativamente nas linguagens mais populares, nem nas mais-ou-menos populares. Em Java, por causa disso, você trata as pré-condições usando exceções. (As pós poderiam ser a captura de exceções de outros métodos que o método chama.) E como violação de pré-condição é um erro, você usa exceção não-checada, pois esta deve ser usada em caso de erros de programa.
Quer ver um exemplo de onde se usa exceção não-checada como violação de pré-condição? HttpServletResponse! Existe uma condição que é o seguinte: uma vez aberto um OutputStream ou um Writer, não se pode abrir um outro stream, nem executar um forward. O que acontece quando alguém, “sem querer”, comete essa cagada esse erro?
É lançada uma exceção não-checada, a IllegalStateException.
Como guia: use exceções não-checadas quando o chamador tem meios de checar se os parâmetros ou o estado do objeto estão corretos antes da execução do método (claro, não é uma ciência exata, podem haver, err…, exceções). No caso acima, a pessoa poderia muito bem verificar se, no Response, é possível criar um novo fluxo chamando o método isCommitted().
E quando usar exceções checadas? Existem casos em que o método não tem qualquer meio de verificar determinada pré-condição, ou tem mas o meio de verificar é praticamente a própria execução do método. O chamador então deve se arriscar chamando o método, e este deve dizer depois se deu certo ou não, lançando exceção, checada!
Exemplo: método parse() de DateFormat, que vai pegar uma String, e devolver a representação dela como um Date. Repare que é lançando exceção checada ParseException caso a String não seja uma data. Por que exceção checada? Porque verificar se uma String é realmente uma data não é tarefa trivial, não dando pra contar com uma verificação prévia antes da execução do método. Por outro lado, parseInt() da classe Integer não lança exceção checada, pois é possível facilmente verificar se uma String contém somente números.
Outro exemplo são os métodos write() de BufferedWriter ou prepareStatement() de Connection que lançam exceções checadas por uma razão simples: nem o chamador nem o método tem a mínima noção se o sistema de arquivos ou o banco de dados está em condições de realizar a ação desejada (e verificar isso pode resultar em outra exceção!).
Como guia: use exceções checadas quando o chamador precisa tomar uma “rota alternativa” após o método ser chamado, pois não dá pra evitar o pior antes.
Uma outra coisa, nem sempre dá pra saber a priori se determinada exceção deveria ser checada ou não. Se você criou uma exceção checada, mas seus chamadores não fazem outra coisa a não ser relançar a exceção ou fazer o log dele, é porque você tem que converter a exceção checada em exceção não checada! Exceções checadas é para quando o chamador precisa tomar uma atitude a respeito. Se nenhum chamador precisou fazer isso, é porque, muito provavelmente, a exceção nunca precisaria ser tratada e o lançamento dela significa simplemente um erro de programa.
Outra coisa, exceções precisam ter nomes significativos. Evite as famosas “exceções arquiteturais” ou “exceções de camadas”, que você identifica por DaoException, BusinessException, ApplicationException ou NomeDaEmpresaException. Todas elas não dão significado ao erro que ocorreu e o programador certamente não irá tratá-las adequadamente, pois não tem a mínima idéia do que fazer, dada a ausência de informações contidas nessa exceção.
E evite criar novas exceções quando existem algumas delas já prontas pra você, como é o caso de NullPointerException (sim, se você receber um parâmetro nulo, não há problema nenhum em você lançar essa exceção, colocando uma mensagem talvez), IllegalArgumentException ou IllegalStateException. Elas não são exclusivas das bibliotecas Java, nem são exceções reservadas. Use-as quando for o caso.
janeiro 7th, 2009 §
Esse post é uma continuação da série Closure.
C++ tem closure? Como assim? Viajou, né? Bom, vou tentar fazer algo, só não sei se vai dar certo. A minha idéia é fazer uma classe Observer onde é possível registrar uma closure. Quando for chamado a função notify() do objeto dessa classe, a closure será chamada e esta terá inclusive referencia de um contexto que não existe pro objeto Observer. » Read the rest of this entry «
janeiro 4th, 2009 §
Existem três propostas de closures em Java, BGGA, CICE/ARM e FCM. A primera proposta é a mais forte mas também a mais criticada, e, ao que parece, não haverá espaço para closures no Java 7. Mas o que é closure? » Read the rest of this entry «
janeiro 3rd, 2009 §
Sim, esse é o último post, mas não significa que não vou escrever mais. Apenas que os próximos posts serão os penúltimos, antepenúltimos, ante-antepenúltimos… É tudo de trás pra frente, os últimos serão sempre os primeiros. Logo, por ser a primeira vez que escrevo aqui, este será o último, simples assim.
Veja bem, não dá pra chamá-lo de “primeiro”, pois afinal, quem irá lê-lo? Mesmo que esse blog tenha mais adeptos no futuro, os novos leitores nunca se darão ao trabalho de ir nos arquivos mais antigos pra ver esse post aqui. Ou seja, este post é de poucos leitores, daqueles que pessoalmente convidei à leitura e daqueles maníacos que, sem nada pra fazer, lerão os posts de trás pra frente até chegar a esse.
Esse post está sendo publicado num período estranho, estamos no primeiro mês de um ano que é o último da década. E que nome tem essa década? Anos zero? Anos dois mil? Ou mais formalmente: primeira década do século vinte e um? Estaremos próximos do fim dela e nem nos preocupamos com um nome! Normal, foi uma década (seja qual for o nome) agitada. » Read the rest of this entry «