You are here: Blogsphere Popular
Keep up to date with your favourite Rails bloggers in context.
We recently got some really high praise from a client:
Thank you for everything you have done so far. Our reception has been very strong from our customer base and we seem to be off to a great start. […] We have a pretty good idea that our next feature will be around X. Right now, I need to know how much money this feature may cost in order to get a better idea of time frames and what we need to do with respect to current customer load and additional funding. […] The original estimate of N hours was almost spot on, and so was most everything else, so an estimate/guesstimate is fine. I’m sure this will generate more questions.
(Emphasis mine)
While the kudos are awesome, what really stuck out to me was the client’s perception that our estimate was spot on. I totally understand that perception: from a happy client’s perspective, a good estimate is in the result, not the process. But if an outside observer were to judge our estimation process for the project by conventional standards, they’d probably conclude that the estimate we put together was pathetic. “What?” you say? Let me explain…
First of all, estimate quality typically has a high correlation to the granularity of the tasks being estimated. The more a feature is decomposed, the more probability the estimates generated for the sub-pieces will be accurate. But on the push for this client’s initial Minimum Viable Product (MVP) we didn’t do any granular estimation – the N hours estimated were based on looking at their MVP as a whole.
It gets even more pathetic, though: you see, one important way to make sure you give good estimates is to closely track the actual time spent vs. the estimate on each task, and then to adjust your upcoming estimates as you figure out the variance between those two. Yet on this project, we didn’t even have individual, per-task estimates, and we didn’t track actual time on a per-task basis. So there was no midstream adjustment to the estimates at all – the original estimate was N hours, and that’s what we hit within 10%.
Now there is one indicator of a good estimate that we did have, and that is prior experience with the problem space. We’ve built a lot of web applications over the past four years, and we also had some pre-existing domain knowledge around the problem the client was solving with the initial MVP. But this just takes the estimate from really pathetic back to a plain old pathetic: there has to be (and is) a very powerful offset to the apparent problems with this estimate that made it work where it shouldn’t have.
Here it is:
Our estimate was spot on because the client was engaged, focused on a truly minimum viable product, and trusted us. In a nutshell, the estimate was awesome because the client was awesome.
We do our best work in a time box: give us an hourly budget, and we’ll have a constant conversation with you as we develop, constantly tweaking, simplifying, removing and even adding things to make sure the desired outcome is achieved when we hit the end of the runway. The reason it works is that in a startup, the desired outcome is not software to spec. The desired outcome is an MVP that you can take to market and get concrete feedback on.
As a matter of fact, in a startup environment the “keys to effective estimation” are all liabilities. Breaking features down to a granular level is time consuming and half the time you’re decomposing features that don’t make it into the final product. Tracking estimates vs. actuals is useless when the strategy and approach to each task change multiple times between estimation and realization. And while domain knowledge is awesome, startups are often solving a unique problem, making domain knowledge hard to come by.
Good estimates happen to savvy founders, since they set a reasonable time box and then actively engage with the team building the product to simplify and fit the result into the estimate. If that sounds like you, we need to talk!
CouchDB para Brasileiros
Hoje o Lucas Renan entrou em contato comigo para tirar uma dvida sobre o funcionamento do Couchrest e acabei tomando conhecimento de um trabalho que ele vem fazendo e que muito til para a comunidade Brasileira. O Lucas est traduzindo a documentao do CouchDB.

Voc pode conferir essa traduo em: http://www.p3m.com.br/blog/category/couchdb
Criando um Chat com Reactor e WebSockets
Obs: Este artigo tem a ver com a prova-de-conceito Cramp Chat Demo disponível no Github.
Existe um caso de uso de aplicações web que é o envio frequente de conteúdo adicional. Por exemplo uma conversa de chat, ou um livestream de feeds, ou até mesmo APIs públicas muito acessadas. O padrão de solução costuma ser um javascript que, em intervalos regulares, faz requisições Ajax a um servidor que retorna o conteúdo adicional a ser acrescentado na página. Isso é um polling.
Outro padrão é manter uma conexão HTTP aberta, recebendo conteúdo continuamente num stream. Para isso temos termos/técnicas guarda-chuva como Comet, Ajax Push, Reverse Ajax, HTTP server push, etc.

As técnicas no cliente variam bastante. Mas os backends não variam muito. Por exemplo, uma aplicação Rails é limitada ao número de conexões simultâneas (ativas exatamente ao mesmo tempo) pelo número de processos carregados. Se tivermos 10 processos Rails de pé, só podemos ter 10 conexões simultâneas. Essa característica é mais importante se o tempo de resposta por conexão for muito alto (e é por isso que sempre falamos em fazer o mínimo possível numa requisição e deferir processamentos mais pesados para tarefas em background, usando tecnologias simples como Delayed Job, Resque, ou se a coisa for mais complexa, servidores de fila e mensagens como RabbitMQ).
Se possível, alguns trechos da aplicação que são carregados o tempo todo, por exemplo, por causa do efeito de polling de clientes fazendo requisições muito frequentes, é importante que seja possível maximizar o uso de um processo diminuindo o tempo de resposta. Para isso existem soluções como Rails Metal, Sinatra ou algo ainda mais leve usando Rack puro. A aplicação Campfire da 37signals, por exemplo, tinha um componente feito em C++ que depois foi migrado para outro que eles escreveram em Erlang, para possibilitar alta concorrência junto com alta performance.
O problema a que nos referimos é o que, há 10 anos, chamamos de Problema C10K ou, literalmente, como suportar 10 mil conexões simultâneas ou mais? Assim como Rails, PHP, ASP, Perl tem o mesmo problema: cada conexão é um processo. Começa a ficar bastante difícil administrar uma quantidade tão massiva de processos abertos simultaneamente.
Alguns podem imaginar que o problema é a simples falta de multi-thread nativo (Ruby, Python, tem green-threads, ou lightweight threads). Portanto servidores Java (Tomcat, JBoss, Glassfish) ou .NET (Application Pool de IIS) seriam melhores. De fato, são melhores, mas não são “a” solução para o problema C10K.
O real problema é I/O bloqueante. Independente se é um processo ou um thread, se ele precisar gravar um arquivo, fazer uma query num banco de dados, esse processo precisa esperar o processamento de I/O terminar para prosseguir. Isso “pendura” esse processo ou thread, desde o cliente até a base de dados, por exemplo. A única diferença é que um servidor multi-thread vai aguentar mais tempo, mas o problema é o mesmo.
Portanto, uma solução é unir o modelo multi-processo/multi-thread com I/O assíncrono ou não-bloqueante, mais do que isso, mudar o paradigma procedural por um que é baseado em eventos. Existe um pattern para isso, chamado Reactor.
O mundo Java começou isso antes, com a implementação de NIO a partir do JDK 1.4.2. Sobre ela surgiram servidores de aplicação/frameworks como Grizzly, Apache Mina ou JBoss Netty. No mundo Python existe o framework Twisted e, felizmente para nós rubistas, temos o EventMachine.
Esse tipo de tecnologia, aliado a coisas como o driver assíncrono MySQLPlus para MySQL, permite uma quantidade absurda de conexões simultâneas não-bloqueantes por processo Ruby. Um processo de EventMachine poderia lidar com milhares ao mesmo tempo.
Daí vem o novo framework web Cramp, desenvolvido pelo Pratik Naik, do Rails Core Team, como um mini-framework de aplicações web assíncronas. Minha prova de conceito é justamente um chat – que demandaria muitas conexões simultâneas – e poderia facilmente ser transformado em livestream (que não deixa de ser um chat read-only, a grosso modo).
Eu implementei duas versões: a primeira é o jeito clássico onde o browser faz conexões Ajax em um intervalo regular. Aliado ao Cramp/EventMachine isso já ajuda porque ele suportaria várias conexões simultâneas.
Mas a segunda versão é mais interessante, porque usa uma tecnologia que está disponível no HTML 5, chamado WebSocket. Assim como o XmlHttpRequest, será um componente acessível por Javascript disponível em todo browser que implementar HTML 5. Já existe no Google Chrome 4.x, no Safari/WebKit e no Firefox 3.7.
Com o WebSocket é possível abrir uma conexão HTTP, mantê-la aberta, “escutar” seu stream por novas mensagens e reagir a elas via javascript e inclusive enviar novos dados (como uma nova mensagem), tudo na mesma conexão, sem precisar passar pelo peso da rotina de abrir conexão, enviar/receber dados, fechar conexão e repetir daqui a alguns segundos. Ou seja, a vantagem é diminuir a quantidade enorme de conexões batendo no servidor para uma ordem de grandeza menos.
Obviamente vai demorar um bom tempo para aparecer no IE, mas não temam, existe uma alternativa muito interessante chamada Web-Socket.js e que eu implemento no meu demo. Ela simula a mesma API do WebSocket padrão (e no Chrome ela nem se ativa), mas usa um pequeno Flash como ponte para criar a conexão HTTP permanente, com os mesmos eventos.
A imagem que você vê acima é justamente de Firefox 3.5, Safari 4 e Chrome 4 conversando simultaneamente com 3 conexões permanentes ao servidor baseado em Cramp. O WebSocket tem um handshake próprio para iniciar uma conversa, que precisa ser implementado do lado do servidor, depois disso é HTTP normal. No meu caso, eu trafego dados em formato JSON.
Como era uma prova de conceito, eu armazeno as mensagens num banco de dados MySQL, mas possivelmente eu teria implementado uma fila de mensagens usando um RabbitMQ ou coisa parecida. Outra coisa, obviamente ele não tem diversas funcionalidades básicas como controle de sessões e outras perfumarias.
Somando as tecnologias de WebSocket, servidor web baseado em Reactor, drivers de banco assíncronos e I/O assíncrono em geral, estamos caminhando para um paradigma levemente diferente do atual para escrever aplicações Web de alta demanda. Vale a pena entender essas tecnologias, especialmente para os casos que citei no começo: chat, livestream, apis e tudo mais que demanda alto nível de concorrência.
A prova de conceito do chat está disponível no Github e imagino que o README que deixei seja suficiente para vocês conseguirem duplicar o mesmo ambiente para rodar a aplicação. E, como sempre, pull requests são bem vindos :-)
Tirando uma screenshot do GDM
Para tirar uma screenshot da sua tela de login no Ubuntu, faa o seguinte. Primeiro instale o xnest, se j no estiver instalado:
sudo apt-get install xnest
Depois execute o seguinte comando, que vai mostrar a tela de login dentro de uma janela, que pode ser capturada atravs da tecla Print Screen:
gdmflexiserver --xnest
coterie: A small group of p...
Resentment is like drinking...
“ Resentment is like drinking poison and waiting for the other person to die. ”
Carrie Fisher
Episode 196: Nested Model Form Part 1
ActiveModel: Make Any Ruby Object Feel Like ActiveRecord
[Off-Topic] Quem é o Burro?
Lendo o livro Systems Thinking esbarrei numa história interessante que deu origem ao meu tweet de ontem:
Information < Knowledge < Understanding
Or
What? < How? < Why?
A história é a seguinte: Havia um projeto de controle de natalidade da Fundação Ford na Índia. Eles estavam frustrados tentando ensinar planejamento familiar e controle de natalidade, sem resultados.
“Indianos são irracionais.”
É o que eles achavam pois:
“Eles sabem que o inimigo número um é a população, e aqui estamos nós ensinando sobre controle, dando os contraceptivos e até mesmo um radio como recompensa. Mas veja o que acontece. Eles voltam pra casa, ligam o rádio, e com música fazem um novo bebê.”
Algum tempo depois saiu The New York Times sobre uma mulher brasileira que havia dado a luz ao seu 42o. filho! E eles pensaram “Se isso não é ser irracional, então eu não sei o que é ser irracional.”
Mas pensando bem: “Se uma mulher pode ter 42 filhos, então porque os indianos, na média, tem apenas 4.6? Isso significa que eles sabem como praticar controle, mas não estão dispostos a fazê-lo. Talvez estejamos tentando resolver o problema errado.”
Depois eles descobriram que na época não havia seguro social, não havia aposentadoria, e nenhum benefício de desemprego. Portanto, 3 filhos homens, por padrão, era considerado o sistema de aposentadoria. A primeira prioridade de cada casal era preparar sua aposentadoria.
Estatisticamente, para ter 3 filhos requer uma média de 4.6 filhos. Sem surpresa, aqueles que tinham atingido 3 filhos pararam de fazer mais. Agora, quem é o irracional? O casal indiano que ganhou um rádio de graça ou o cara da fundação Ford que achou que poderia fazer o casal desistir de suas aposentadorias por um mero radinho?
Quando se fala em “problema de natalidade”, temos a informação, ou o que: casais com 4.6 crianças em média aumentam demais a população geral. Também temos o conhecimento, ou o como: programas de controle de natalidade, contraceptivos, palestras, etc. Mas o ponto crucial muitas vezes é a falta de entendimento, do porque. Sem o entendimento, vamos continuar aplicando receitas de bolo que simplesmente não funcionam. Entendendo o porque, conseguimos derivar soluções muito mais efetivas.
Lembram de todo papo de procura por solução raíz, ou os cinco porques, são todas maneiras de tentar eliminar a real causa e não os sintomas.
Introducing Cramp
Cramp is the latest entry on the ruby web frameworks list. However, unlike all the others, Cramp is an asynchronous framework, always running inside EventMachine reactor loop. Cramp isn’t a good fit for most of the web applications out there. However, Cramp is good at holding and working with a large number of open connections. Hence it’ll work great for things like comet, long polling, streaming API or even when your application needs to handle thousands of concurrent connections.
This article assumes that you’re aware with the evented programming model. If you are not, things below this point might not make much of a sense. If you’re interested in learning, you could start by reading about EventMachine and Twisted.
As Cramp requires 3.0-pre versions of ActiveSupport and ActiveModel, you’ll have to install them first. This step will be irrelevant after Rails 3 gets released. But for now, the following should install them both :
gem install activemodel --pre
And then,
gem install cramp
That’ll install Cramp gem along with all the needed dependencies. Please note that Cramp depends on ActiveSupport 3.0-pre gem, which isn’t backwards compatible and this may affect any other gems requiring ActiveSupport without specifying the version number.
Cramp comes with two layers : Controller & Model.
Cramp::Controller is an asynchronous controller layer, that tries being rack compliant as much as possible. Currently, you must use thin in order to run it, as it’s one of the very few webservers capable of running an async rack app – happy to accept patches if someone can get this running on Rainbows!
Here’s the “hello world” of Cramp::Controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
require 'rubygems' require 'cramp/controller' class WelcomeAction < Cramp::Controller::Action on_start :send_hello_world def send_hello_world render "Hello World" finish end end Rack::Handler::Thin.run WelcomeAction, :Port => 3000 |
Now run it directly :
ruby welcome_action.rb
Here WelcomeAction is the rack endpoint, which you can use with config.ru or what have you.
Now let’s dig dipper to understand the code snippet above.
When serving a request, a Cramp::Controller::Action object goes through the following four stages :
To hook into each of these states, Cramp::Controller::Action provides the following callbacks/methods :
before_start callback provides hook into the initialization stage. Each before_start callback accepts a block and must call yield ( or block.call – whichever is appropriate ) or halt. Here’s what a typical usage looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
before_start :verify_id, :find_user def verify_id if params[:id] !~ /\A\d+\z/ halt 500, {'Content-Type' => 'text/plain'}, "Invalid ID" else yield end end def find_user User.where(User[:id].eq(params[:id])).first do |user| if @user = user yield else halt 404, {}, "User not found" end end end |
As you can see above, halt takes status, headers and body as parameters and sends them to the client. It would also halt the callback chain and the request itself. Please note that on_finish callbacks will not get run when you halt. Calling yield will continue the filter chain or enter the next stage if no filters are left to run.
After the before_start stage, Cramp::Controller::Action enters the next stage of Response Initialization. It’ll call the method respond_with, which must return an array of [status, headers]. If this method is not defined, [200, {‘Content-Type’ => ‘text/html’}] status and headers will be used by default.
Here’s an example of using respond_with to send custom status and headers :
1 2 3 4 |
def respond_with content_type = params[:format] == 'xml' ? 'application/xml' : 'application/json' [200, {'Content-Type' => content_type}] end |
A deferrable body is also sent out along with these headers.
After all the verifications and sending out headers, the real work starts. on_start callbacks provide multiple entry points into the Starting stage. These callbacks can send any body to the client using render() method or finish the request by invoking finish(). Note that the render() method can be called any number of times.
Here’s a full example imitating running two long running sql queries from on_start callbacks:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
require 'rubygems' require 'cramp/controller' require 'cramp/model' Cramp::Model.init(:username => 'root', :database => 'arel_development') class SleepingAction < Cramp::Controller::Action on_start :start_sleeping def start_sleeping Cramp::Model.select 'select sleep(1)', method(:on_first_sleep) end def on_first_sleep render "First Sleep Complete...\n" render "Going to sleep one more time now..\n" Cramp::Model.select 'select sleep(1)', method(:on_second_sleep) end def on_second_sleep render "Second Sleep Complete. Time to finish!\n" finish end end Rack::Handler::Thin.run SleepingAction, :Port => 3000 |
Now if you hit this using curl:
[lifo@null ~]$ curl http://0.0.0.0:3000/
First Sleep Complete...
Going to sleep one more time now..
Second Sleep Complete. Time to finish!
[lifo@null ~]$
on_finish provides hook into the last stage : Finishing. These callbacks are run when you call finish() from an on_start callback or when the client closes the connection. These callbacks are the perfect place for any cleaning up activities.
Here’s an example of a Cramp::Controller::Action using periodical timer and an on_finish callback.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
require 'rubygems' require 'cramp/controller' require 'cramp/model' class PollUserAction < Cramp::Controller::Action on_start :start_polling on_finish :stop_polling def start_polling # Call find_user every 10 seconds @timer = EventMachine::PeriodicTimer.new(2) { find_user } end def find_user User.first {|u| render "#{u.inspect}\n" } end def stop_polling puts "Cancelling the timer.." @timer.cancel end end Rack::Handler::Thin.run PollUserAction, :Port => 3000 |
In the case above, if you don’t call @timer.cancel, it’ll keep running even after the client closes the connection. The following section will cover the helper method provided by Cramp::Controller for the above pattern called periodic_timer.
The on_finish callback example above has a very common pattern : Starting periodic timers using on_start and cleaning them up using on_finish. Cramp::Controller provides a better alternative : periodic_timer
Using periodic_timer to rewrite the example above :
1 2 3 4 5 6 7 |
class PollUserAction < Cramp::Controller::Action periodic_timer :poll_user, :every => 2 def poll_user User.first {|u| render "#{u.inspect}\n" } end end |
And then Cramp::Controller will take care of starting and stopping EventMachine::PeriodicTimer from the appropriate stages.
You can use more than one periodic timers as well :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class PollUserAction < Cramp::Controller::Action periodic_timer :poll_user, :every => 2 periodic_timer :check_limit_exceed, :every => 10 def poll_user .. end def check_limit_exceed finish if request_limit_exceeded end end |
In the example above, check_limit_exceed() calls finish() if the request limit is exceeded, which in turn will terminate the connection and stop all the timers too.
If you’re using Cramp for streaming or long polling, you’d want to make sure the client doesn’t close the connection prematurely. Cramp::Controller has a handy helper method to make sure that doesn’t happen – keep_connection_alive
keep_connection_alive sends the client an empty string (” “) every 15 seconds by default.
1 2 3 4 |
class PollUserAction < Cramp::Controller::Action periodic_timer :poll_user, :every => 2 keep_connection_alive end |
Or you can change the period by supplying :every option :
1 2 3 4 |
class PollUserAction < Cramp::Controller::Action periodic_timer :poll_user, :every => 2 keep_connection_alive, :every => 30 end |
Cramp::Controller is capable of using a Rack middlewares for routing request and populating params. Here’s an example of a Cramp::Controller using Usher for routing :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
require 'rubygems' require 'cramp/controller' class HomeController < Cramp::Controller::Action on_start :send_hello_world def send_hello_world render "Hello World with #{params[:id]}" finish end end routes = Usher::Interface.for(:rack) do add('/:id').to(HomeController) end Rack::Handler::Thin.run routes, :Port => 3000 |
Cramp::Controller::Action implements the params method like:
1 2 3 |
def params @params ||= @env['usher.params'] end |
If you’re using another rack based router like rack-mount, you might want to override that with the appropriate definition.
As Cramp::Controller tries being a Rack based framework, you should be able to use Rails middlewares for cookies and sessions stores.
Cramp::Controller does not have any built in mechanism for rendering files. However, using something like tilt should be very straight forward.
Cramp::Controller comes with a few helper methods to write integration tests for the application. However, that’s not within the scope of this article. You should have a read through http://github.com/lifo/cramp/tree/master/test/controller to know more.
I haven’t really benchmarked Hello World for Cramp::Controller. However it should be very fast. I was able to have a single Cramp::Controller instance stream to 2000+ concurrent connections just fine. And this is where Cramp::Controller really shines, and not some silly Hello World masturbations.
Also, note that OS X isn’t the best environment for testing concurrent connections, you should be using Linux with a tuned Kernel for this. Check this article for details on tuning the Kernel.
Even though Cramp::Controller tries being as much Rack compliant as possible, it’s not a 100% Rack compliant framework. Rack specs are designed primarily for synchronous frameworks. As Cramp::Controller uses deferrable body, any middlewares operating on the response body will not work without modifications.
Cramp::Model is an asynchronous ORM ( only MySQL supported at the moment ) built on top of ARel and ActiveModel. It’s currently in a very primitive state and provides the following features :
Here’s what a Cramp model looks like :
1 2 3 4 5 6 7 8 9 10 11 |
require 'rubygems' require 'cramp/model' Cramp::Model.init(:username => 'root', :database => 'cramp_development') class User < Cramp::Model::Base attribute :id, :type => Integer, :primary_key => true attribute :name validates_presence_of :name end |
You are required to declare all the columns you wish to use as Attributes. If type is not supplied, String type is assumed.
Currently Cramp::Model provides the following finder method :
It also provides the following methods for specifying options on the find :
The above methods are delegated to Arel and can be chained. As Cramp::Model is an asynchronous ORM, you must supply a callback method for processing the result records. You could do that by calling all, first or each at the end of the chain and supply the callback as a block or a method.
Here are some example usages :
1 2 3 4 5 6 7 8 9 10 11 |
EM.run do User.select(:id, :name).limit(10).offset(20).first {|u| .. } User.where(User[:name].eq('Lush')).limit(2).all {|users| ... } User.each {|user| .. } def lush_users_found(users) ... end User.where(User[:name].eq('Lush'), User[:id].gt(5)).all method(:lush_users_found) end |
For the basic CRUD operations, Cramp::Model provides methods similar to Model#save, which accepts an optional callback. If a callback is provided, it’ll be called after the completion with a Status object, containing metadata about the success or failure of the save operation. Status object has just two methods defined on it : record & success?.
Here’s how you would typically want to save a record to the database :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
EM.run do def user_saved(status) if status.success? ... else user = status.record puts "Oops. Found errors : #{status.record.errors.inspect}" end end user = User.new user.save method(:user_saved) end |
Cramp is hosted on Github http://github.com/lifo/cramp. Please do fork and use the issues if you encounter a bug or need any kind of help.
Web development’s next decade
Entendendo os métodos load e require por dentro
Jason Fried of 37Signals at LessConf 2009
Off-Topic: Literatura para Gerentes Ágeis
Atualização: 06/01: O objetivo do artigo quando comecei a escrevê-lo foi ser realmente assertivo. Ainda me frustra o fato de pesquisar material atual, blogs, artigos, e nenhum assunto relacionado a Agilidade ir mais a fundo nos princípios. Além disso estou um pouco ansioso com minha própria pesquisa, que sempre ainda parece que faltam pedaços e como não há quase ninguém com quem conversar a respeito, fico mais frustrado ainda. Por isso logo no começo do artigo eu já estava de paciência curta e comecei a abusar da primeira e da terceira pessoa, praticamente num diálogo 1 a 1. Como isso não ajuda o objetivo central do artigo, resolvi limar as partes mais agressivas. Vamos ver se agora ficou mais “digerível” :-)
Ano passado compilei uma lista de livros que eu li na minha busca pela essência do verdadeiro gerenciamento. A diferença é que em vez de passar pelos mais triviais como Peter Druker, eu fui atrás dos princípios da Agilidade.
Existem algumas categorias de gerentes: os que são “ágeis” – no sentido mais amplo da palavra – e os “tradicionais”. O segundo grupo – que tem tendências a não querer mudar nem aprender nada – é triste, ponto final. O primeiro está no caminho certo, mas ainda falta muito. As discussões que eu vejo hoje nas comunidades ágeis, infelizmente, também ainda caem na inércia do “bom senso”, do “senso comum” e acabam sendo superficiais.
Um gerente ágil deveria querer se dedicar muito mais. O próprio Scrum é um exemplo disso. Como eu disse no meu artigo Você não entende nada de Scrum : o Jeff Sutherland e Ken Schwaber realmente pesquisaram há muito tempo os assuntos pertinentes e dão as dicas, embora poucos sigam.
Se você quer realmente entender Scrum, esta literatura pode ajudar muito. Para começar, tem os Scrum Papers, que dão a introdução.
Se fez isso então já esbarrou em termos como “Emergência”, “Beira do Caos”, “Sistemas Complexos Adaptativos”, “Auto-Organização”. E se passou por esses termos e ficou por isso mesmo, pense mais uma vez: qual a vantagem de ler sem entender?
Eu também ainda não sei tudo, mas estou inteiramente dedicado a entender isso direito. Sem entender os princípios, só resta “seguir uma receita” e isso é muito pouco. Quem procura por regras ou receitas está tentando retirar a própria responsabilidade, pois se o método, o procedimento, o processo “falhar” ou não der resultados, você sempre pode cair nas desculpas “mas eu segui o método à risca, a culpa não é minha”. E isso foge completamente ao ponto; que resultado você está procurando: seguir regras ou atingir resultados?
Digo isso com “agressividade” mas certa relutância porque eu mesmo já pensei dessa forma. Enfim, depois de passar um tempo lendo mais artigos acadêmicos, neste momento estou lendo estes livros:
Mais do que isso? Por experiência, toda vez que alguém me fala palavras como “caos”, “equilíbrio” percebo que elas estão baseadas na definição casual e não técnica delas. Primeiro, muitos acham que “caos” é simplesmente bagunça, ao totalmente indesejado. Pior ainda: acreditam que o “segredo” está em atingir equilíbrio e ficar nele, confundem a meta como sendo buscar equilíbrio. Não é bem isso.
Segundo a introdução do livro Surfing the Edge of Chaos, veja:
Equilíbrio é o precursor da morte. Quando um sistema vivo está em um estado de equilíbrio, ele é menos responsivo a mudanças acontecendo ao seu redor. Isso o coloca em risco máximo. Quando encarado por ameaças, ou quando é motivado por uma oportunidade, coisas vivas se movem em direção à Beira do Caos. Essa condição evoca altos níveis de mutação e experimentação, e soluções frescas e novas são mais comuns de serem encontradas.
Quando esta excitação se inicia, os componentes de sistemas vivos auto-organizam e novas formas e repertórios emergem do distúrbio.
Sistemas vivos não podem ser dirigidos sobre um caminho linear. Consequências não planejadas são inevitáveis. O desafio é criar distúrbio de uma maneira que faz se aproximar do resultado desejado.
Esta, é uma definição tanto da evolução biológica de seres vivos, mas, se você já leu pelo menos o básico de Scrum e Agile, também é uma forma de descrever o processo Ágil. Releia os Princípios do Manifesto Ágil e vai encontrar textos similares.
Quanto a Sistemas Complexos Adaptativos:
Um sistema complexo adaptativo é formalmente definido como um sistema de agentes independentes que podem agir em paralelo, desenvolvem “modelos” sobre como as coisas funcionam em seus ambientes e, mais importante, refinam esses modelos através de aprendizado e adaptação. O sistema imunológico humano é um sistema complexo adaptativo. Assim também é uma floresta tropical, uma colônia de formigas e um business.
Existe vasta literatura. Procure na Amazon por termos como “Complexity”, “Edge of Chaos”, “Systems Thinking” e verá que faz décadas que pesquisadores das mais diferentes áreas e indústrias vem refinando esse corpo de conhecimento. Técnicas como o Toyota Production System/Lean, Six Sigma, Scrum, Theory of Constraints e outros são todos derivados dessa escola de pensamento.
Da minha lista anterior, reforço a necessidade de leituras como:
Mais preocupantes: técnicas como Lean, TOC, Six Sigma e derivados como técnicas de Kanban, todas são termos que muitos usam de forma errada hoje em dia. Elas foram todas criadas e refinadas em Engenharia de Produção. Estamos sempre falando em “linha de produção”, “manufatura” de bens de consumo materiais, coisas “físicas”. Agora, em Agile, estamos falando de “Software”, algo abstrato e sem paralelo no mundo físico, portanto, sem nenhuma das mesmas referências.
É impossível migrar ipsis literis quaisquer das técnicas de Engenharia de Produção. Não funciona de forma tão simples assim. Um Sprint de Scrum é uma adaptação consciente do Sutherland e Schwaber, sabendo dessa limitação e tentando uma aproximação no mundo abstrato. Mas isso não é óbvio e nem trivial de entender, eu mesmo ainda não entendi completamente e acredito que a maioria das pessoas do mundo ágil não parou para estudar essa diferença.
Muito cuidado: o assunto “Gerenciamento” é muito mais do que mera “experiência” ou “bom senso”. Assim como um bom programador deveria ler muito e pesquisar muito para melhorar sua técnica, assim também deve um gerente. E aqui estou dizendo isso para mim mesmo.
Shorty Awards: Honoring The Best People and Organizations on Twitter
Amazon Kindle 2
The Maximal Usage Doctrine for Open Source
lilt: A characteristic risi...
I’m not a fatalist, b...
“ I’m not a fatalist, but even if I were, what could I do about it? ”
Emo Phillips
FOWA Miami 2010
I have attended FOWA for the past 2 years and can’t say enough good things about it. One of the major highlights for me was meeting and chatting with people like Gary Vaynerchuk, Kevin Rose, Jason Fried, and Kathy Sierra.
This years line up is incredible as well. Here are just a few: Alex Payne, Fred Wilson, Gary Vaynerchuk, John Resig, Molly Holzschlag, Steve Huffman and Tara Hunt. If there is one Tech conference you should not miss, FOWA Miami 2010 is it.
Checkout some of the photos I snapped at the event last year.
Space is limited and you definitely don’t want to miss this conference. Also this is your chance to come out and enjoy sunny Miami Beach.
Haml versus ERB
Hoje lendo a lista rails-br me deparei com uma colocao sobre Haml ser mais lento que HTML(entendi que a pessoa queria dizer ERB) e isso me fez relembrar que no incio do Be on the net eu e o Vincius fizemos alguns benchmarks comparando ERB e Haml.
Na poca nossos benchmarks indicaram que o Haml era mais rpido que o ERB. Cabe destacar que a nossa escolha NO FOI por causa de performance, j que lembro bem que migramos primeiro e fizemos os testes depois. Motivado pela mensagem na lista resolvi refazer os benchmarks e mostrar os nmeros.
Eu estava certo que o Haml se sairia melhor que o ERB mas em 5 minutos eu fiz um cdigo para comparar os dois e descobri que o ERB se sai bem melhor.
Estava tentando me lembrar como foi feito o nosso primeiro benchmark mas no tenho a menor idia. No sei se fizemos algo errado ou se os valores eram diferentes naquela poca.
Fiquei intrigado se com cdigos mais complexos essa performance poderia ser diferente e se isso justificaria o resultado do nosso primeiro benchmark. Resolvi fazer uns testes no Be on the net e o resultado novamente foi mais favorvel ao ERB.
Por se tratar de um produto comercial eu no poderia mostrar os cdigos que eu utilizei. Ento resolvi escrever uns exemplos mais complexos mas desisti aps fazer algumas pesquisas no google e ver que outras pessoas j fizeram o mesmo teste e todos obtiveram resultados semelhantes.
Sugiro dar uma olhada nesses dois posts e ler os comentrios: http://nex-3.com/posts/81-more-haml-benchmark-issues e http://nex-3.com/posts/87-haml-benchmark-numbers-for-2-2
O ERB mais rpido porm esse tipo de concluso bastante perigosa e no devemos olhar apenas esses nmeros para decidir sobre usar ou no o Haml. Dificilmente o gargalo da sua aplicao ser apenas esse render e provavelmente voc poder resolver todos os seus problemas de performance sem a necessidade de pensar nesses nmeros. Se voc est tendo problemas com a performance da sua aplicao sugiro que assista a srie Scaling Rails.
Se hoje eu tivesse que iniciar um projeto novo no pensaria duas vezes e usaria o Haml. Basicamente o Haml menos verboso, sua sintaxe bem amigvel e ainda nos protege de cometer pequenos erros no HTML.
Book Review: “Refactoring in Ruby”
Fixes para Ruby 1.9, Rails 2.3.x e Unicode
Ainda existem alguns problemas entre o Rails 2.3, o Ruby 1.9 e seu suporte a UTF-8 e a forma como ambos o ERB (Embedded Ruby, a engine padrão para templates que usamos no ActionView) e o adapter de MySQL tratam encoding.
Notei isso quando testei meu próprio blog rodando sobre Ruby 1.9 e ele dá o seguinte erro quando tento carregar a aplicação em algum navegador:
1 |
incompatible character encodings: UTF-8 and ASCII-8BIT |
O erro aponta justamente para uma linha onde eu puxo dados de um activerecord. Há duas chances para isso: ou o ERB está tratando o encoding errado ou o ActiveRecord está recebendo o dado com encoding errado. No meu caso acho que é o segundo caso.
Esses erros estão sendo tratados em tickets no Lighthouse como o #2188 Encoding error in Ruby1.9 for templates e o #2476 ASCII-8BIT encoding of query results in rails 2.3.2 and ruby 1.9.1. Existem alguns hacks para ambos os casos. No meu fork do blog Enki eu acabei de subir isso. Mas se quiser corrigir na sua aplicação, faça assim:
Crie um arquivo como “config/initializers/fix_params.rb” com o conteúdo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
module ActionController class Request private # Convert nested Hashs to HashWithIndifferentAccess and replace # file upload hashs with UploadedFile objects def normalize_parameters(value) case value when Hash if value.has_key?(:tempfile) upload = value[:tempfile] upload.extend(UploadedFile) upload.original_path = value[:filename] upload.content_type = value[:type] upload else h = {} value.each { |k, v| h[k] = normalize_parameters(v) } h.with_indifferent_access end when Array value.map { |e| normalize_parameters(e) } else value.force_encoding('utf-8') if '1.9'.respond_to?(:force_encoding) value end end end end |
Em seguida, crie um “config/initializers/fix_renderable.rb” com:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
module ActionView module Renderable #:nodoc: private def compile!(render_symbol, local_assigns) locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join source = <<-end_src def #{render_symbol}(local_assigns) old_output_buffer = output_buffer;#{locals_code};#{compiled_source} ensure self.output_buffer = old_output_buffer end end_src # workaround source.force_encoding('utf-8') if '1.9'.respond_to?(:force_encoding) begin ActionView::Base::CompiledTemplates.module_eval(source, filename, 0) rescue Errno::ENOENT => e raise e # Missing template file, re-raise for Base to rescue rescue Exception => e # errors from template code if logger = defined?(ActionController) && Base.logger logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}" logger.debug "Function body: #{source}" logger.debug "Backtrace: #{e.backtrace.join("\n")}" end raise ActionView::TemplateError.new(self, {}, e) end end end end |
Finalmente, crie um “config/initializers/fix_mysql_utf8.rb” com:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
require 'mysql' class Mysql::Result def encode(value, encoding = "utf-8") String === value ? value.force_encoding(encoding) : value end def each_utf8(&block) each_orig do |row| yield row.map {|col| encode(col) } end end alias each_orig each alias each each_utf8 def each_hash_utf8(&block) each_hash_orig do |row| row.each {|k, v| row[k] = encode(v) } yield(row) end end alias each_hash_orig each_hash alias each_hash each_hash_utf8 end |
Para garantir, leia meu artigo recente sobre Convertendo meu Banco de Latin1 para UTF-8, garanta que no seu “config/database.yml” há a configuração:
1 |
encoding: utf8 |
O último fix é especificamente para MySQL, procure no Lighthouse sobre fixes para outros adapters. Espera-se que isso seja ajustado até o lançamento do Rails 3 ou pelo menos até a próxima release de manutenção do Rails 2.3 com ajustes nos demais adapters. O assunto ainda está em discussão.
Mantendo seu desktop GNOME sem problemas
Esses dias tive alguns problemas customizando um netbook para um cliente, utilizando GNU/Linux Ubuntu rodando o GNOME. O que aconteceu foi que depois de remover ou adicionar alguns pacotes, volta e meia ou os cones, o painel do GNOME e as decoraes das janelas sumiam (s vezes tudo junto!), sabe-se l a razo. Tentei vrias coisas como apagar os diretrios ~/.gconfd, ~/.gnome2, ~/.gnome2_private, sair da sesso, reiniciar (eu hein, esse negcio est comeando a parecer Windows ...), inserir o nautilus, o gnome-panel para iniciarem no .profile, testei incontveis solues na web e nada.
Depois de quebrar muito a cuca, consegui estabilizar inserindo configuraes obrigatrias para a sesso do GNOME. Abri um terminal e executei o seguinte comando:
sudo gconftool-2 --direct \ --config-source xml:readwrite:/etc/gconf/gconf.xml.mandatory \ -t list --list-type string \ -s /desktop/gnome/session/required_components_list [filemanager,panel,windowmanager]
Isso fez com que esses componentes fossem iniciados no tapa quando a sesso comea e at agora est funcionando bem, problema resolvido. O que no me conformo no saber direito a causa deles sumirem. s vezes me bate uma saudade da crueza do Slackware ...
Episode 195: My Favorite Web Apps in 2009
Lidando com Centenas de Projetos no Github
Se você está há algum tempo acompanhando projetos no Github, as chances são que você tem alguns projetos pessoais e algumas centenas de projetos em observação (quando você clica no botão “watch”) na página de cada projeto no Github. Eu, por exemplo, tenho quase 400 projetos em observação. Claro, muitos deles eu nem mexo. Para variar, todos os projetos estão literalmente jogados num único diretório de projetos. Literalmente, uma bagunça. Hora de arrumar minha casa.
Eu resolvi que terei um diretório para meus projetos pessoais ou forks, ou seja, projetos onde eu tenho acesso de push e outro diretório para projetos que eu apenas observo, ou seja, onde eu não posso fazer push. Portanto terei os diretórios “public” e “watched”.
Além disso, quero que nos projetos onde eu tenha acesso de push, o branch ‘origin’ aponte para meu fork, e o repositório original seja adicionado como ‘remote’ com um nome arbitrário mas padronizado – no meu caso, “forked_from”. Fazendo isso, fica simples fazer um script que navegue em todos os projetos e faça fetch dos repositórios originais.
Mas, com centenas de projetos, obviamente eu não quero entrar no site, copiar a URL e fazer ‘git clone’ um a um. Felizmente o Github tem diversas APIs para brincarmos. Sugiro que leiam a documentação aqui. Mais do que isso, até existem projetos de wrappers, como o Octopi mas, no meu caso, não vou usar esse wrapper. Mas algumas APIs ainda estão em falta, por exemplo, é possível puxar uma lista dos seus projetos, saber quais são fork mas ele não trás qual é o repositório original. Para puxar essa informação, usei o bom e velho Mechanize e usei o Selector Gadget para conseguir o selector CSS correto para puxar o nome do repositório original.
Coloquei meu script completo no Gist e você pode baixá-lo assim:
1 2 |
curl http://gist.github.com/268118.txt > ~/bin/github_repos.rb chmod +x ~/bin/github_repos.rb |
Claro, em vez de /usr/local/bin, coloque em algum outro diretório local que esteja no seu path, como ~/bin. Feito isso, manualmente crie um diretório onde você queira colocar seus projetos, por exemplo:
1 2 3 4 |
mkdir -p ~/Documents/Projects/Github/public mkdir -p ~/Documents/Projects/Github/watched cd ~/Documents/Projects/Github github_repos.rb clone |
O importante é criar os diretórios “public” e “watched”. O resto do processo vai demorar bastante tempo porque ele fará um ‘git clone’ de cada projeto. Pode ir tomar um café. Depois que terminar, você pode executar o seguinte comando de tempos em tempos:
1 2 |
cd ~/Documents/Projects/Github github_repos.rb pull |
Isso atualizará todos os seus repositórios. Nos repositórios que você apenas observa, basta um simples ‘git pull’, mas nos que você fez fork, é necessário atualizar os ‘remotes’. Esse script deve fazer o truque.
Como podem ver é um script bastante ‘hackish’, literalmente feito para coçar uma coceira. Se alguém tiver sugestões, por favor não deixe de comentar. Existem dezenas de maneiras de organizar seus projetos, esta é apenas uma e que pode me servir melhor, compartilhe sua idéia.
Tell us what you think of the new BlogSphere feature. We are continually looking to improve and update the
functionality based on your feedback.

Find your next Ruby on Rails project or job.
Exclusive content,
regularly updated - onsite and tele-working positions listed.
An expert in ruby on rails, passionate by code
-
D.L, France