Webcast: Como melhorar a performance do meu site?

April 23rd, 2010

Galera, estou postando aqui um Webcast que gravei para o blog da Locaweb. Trabalho na equipe de desenvolvimento Front-End / UX da Locaweb.

O que você pode fazer hoje para deixar seu site mais rápido?

Um site pode levar por volta de 200ms para gerar o HTML que será recebido pelo browser. Mas o tempo de “montagem” desta página no browser leva diversos segundos, tendo casos extremos com mais de 10 segundos.

Então a mudança que você pode fazer hoje, que vai impactar mais seu usuário ou cliente, é otimizar o tempo de carregamento de seu site no browser. Não é gastar horas e horas otimizando seu código server-side como Ruby on Rails, PHP ou .NET. Mesmo que seu site já tenha milhares de acessos por hora, a primeira coisa a ser feita é otimizar a performance de seu site no browser, e depois partir para a otimização de server-side.

Nesse Webcast falo sobre várias técnicas e dicas para melhorar a performance client-side de seu site:

Enviem dúvidas nos comentários abaixo.

Tag it! Tag suggestions, editor and autocomplete in a jQuery UI plugin

March 24th, 2010

After looking for a jQuery plugin for handling a tag suggestion form field, also with a autocomplete feature – in much the same way ZenDesk.com does – I ended up developing a customization of jQuery UI that does the same interaction.

UPDATE June 19th, 2011: due to other pressing priorities I delegated the development/support of this plugin to Alex Ehlke who is now doing an amazing job keeping this plugin up to date. Links below are now pointing to his repository. Thanks for your amazing help, Alex!

Official page for the project: http://aehlke.github.com/tag-it/

See the screenshot

See the Demo

Fork Tag it! on Github

Download the Tag it! plugin

Cheers! ;)

Gerador de CPF e CNPJ mais rápido no browser

March 23rd, 2010

Na linha de automatizar tudo que faço manualmente, criei um bookmarklet que gera um CPF ou CNPJ diretamente do browser.

Assim você não precisa mais procurar por “gerador de CPF e CNPJ” no Google ;)

Como usar:

- abra esta página e arraste os 2 links para a barra de Bookmarks de seu browser;
- clique em um dos favoritos e pronto, um novo CPF ou CNPJ é gerado sem você precisar sair da página que você estava usando :)

O projetinho está no Github – caso você queira fazer um fork :)

An elegant way to log with a Ruby block

January 2nd, 2010

Imagine you created a generator much like Rails. It creates a series of directories and copy a set of files to a specific location. Some things may fail, and you need a nice way to show what’s going on behind the scenes.

I was browsing some code on GitHub and found an elegant approach to this problem.


module Glue
  module Generator
    extend self
    extend Glue::Helper

    def generate!(options={})
      templates = File.expand_path(File.dirname(__FILE__) + "/../../templates")
      output = File.expand_path(options[:path])

      # create root directory
      run "creating #{Colorize.yellow(output, :style => :underscore)} directory" do
        FileUtils.mkdir_p(output)
      end

      # create javascripts directory
      run %(creating #{Colorize.yellow("public/javascripts")} directory) do
        FileUtils.mkdir_p File.join(output, "public/javascripts")
      end

      # create images directory
      run %(creating #{Colorize.yellow("public/images")} directory) do
        FileUtils.mkdir_p File.join(output, "public/images")
      end

      # create views directory
      run %(creating #{Colorize.yellow("views/layouts")} directory) do
        FileUtils.mkdir_p File.join(output, "views/layouts")
      end
    end
  end
end

module Glue
  module Helper
    def run(message, &block)
      $stdout << "\n#{message}... "

      begin
        yield
        $stdout << Colorize.green("done!")
      rescue Exception => e
        $stdout << Colorize.red("error ~ #{e.message}")
      end
    end
  end
end

This code does a few interesting things:

  • the “run” method is defined inside a helper module. It begins by receiving a message (what are you doing right now?) and a block. It starts by giving control to the caller with a yield (now the execution inside the “run” method is halted). So the block passed to the run method is now executed. This block is actually the lines you see above between “run … / end”;
  • So in this block you can “do your thing”. For example, create a directory, request some info from a remote API, or whatever;
  • When the block is finished running, the lines after yield (in the “run” method) are executed. If no exception is raised a Ok message is printed, otherwise we’ll see what went wrong with the specific exception message.

This is very cool. You can now execute failure-prone tasks in a very elegant way, and with a really nice syntax :)

This code was created by Nando Vieira in an interesting project called Glue, which is a simple static site generator for Ruby that uses Haml, Sass and Textile/Markdown. The documentation is here.

You can see the code samples above, here and here.

Reasons to use a no-sql database like mongoDB

December 26th, 2009

In this article I’ll talk about reasons to use mongoDB and other no-sql databases.

Relational databases are often used in many web apps. But usually when the time comes to scale the app to a few millions users, you have to make choices on your architecture.

For instance, a common practice to handle high load is to put one or more of the most used tables in separate servers. In order to use this technique, a developer will have to resolve the issue of join queries. How do you query tables that aren’t in the same location and yet have high performance?

One solution is to denormalize data, thus duplicating content in all tables that may have a query that needs to know about it. Think of 2 tables: contacts and users. The tables are separated into 2 different servers. And you have a feature in your app, in which you show all contacts from a specific user. You need a join query, but you can’t use it. So you duplicate some of the fields from the contacts table, right inside your users table. For instance, you create a field called contact_names, in which you put only the names, of all contacts from that user, separated by commas. It’s a easy way to solve the problem, but it comes with a cost. You have to worry about syncing the contacts in all tables that know something about contacts.

Bottom line? You started developing your app with join queries, but at some point you had to give up on it.

So, if using a traditional database forces you to stop using some of its features somewhere down the road, why not start with a kind of database that avoids the things that are not scalable and sustainable in the long run?

In mongoDB a solution for this problem would be creating a document Contacts, and embed it inside the document Users. So, each user will have its contacts right there, inside each one of the User records. No need to use join queries.

However, there are times when you need to have a model that is connected to several others.

For example, let’s say you need to relate Contacts to several models such as Clients, Suppliers and Employees. So you create 4 collections: Clients, Suppliers, Employees and Contacts. You connect them all together via a db reference. This acts like a foreign key. But, this is not the mongoDB way to do things. Performance will penalized.

So the general question should always be “Why can’t I embed this document?“. Or even better: “Does this object merit its own collection, or rather should it embed in objects in other collections?“.

There are some general rules on when to embed, and when to reference (grabbed from mongodb website):

  • “First class” objects, that are at top level, typically have their own collection;
  • Line item detail objects typically are embedded;
  • Objects which follow an object modelling “contains” relationship should generally be embedded;
  • Many to many relationships are generally by reference;
  • Collections with only a few objects may safely exist as separate collections, as the whole collection is quickly cached in application server memory;
  • Embedded objects are harder to reference than “top level” objects in collections, as you cannot have a DBRef to an embedded object (at least not yet);
  • It is more difficult to get a system-level view for embedded objects. For example, it would be easier to query the top 100 scores across all students if Scores were not embedded;
  • If the amount of data to embed is huge (many megabytes), you may reach the limit on size of a single object;
  • If performance is an issue, embed;

The way I see it, you can still have more or less the best of both worlds: the flexibility of documents and the performance of embedded documents. And you still have a way to emulate foreign keys, like a relational database – but not without a penalty on performance. I don’t know how mongoDB and MySQL compare to each other in the long run, for the usual web app. It’d be cool if someone did some benchmarks on this subject.

Read more about mongoDB database schema design.

Playing with mongoDB

December 25th, 2009

It’s been a long time I hear about mongoDB and its awesomeness, so now’s the time to play with it! :)

In this article I’ll try to summarize what’s mongoDB, why it’s so cool, and how to start playing with it.

What is mongoDB?

mongoDB is one of the new NO-SQL databases. It means it’s not record-oriented like relational databases. Instead, it’s schema-free and collection oriented. And also, it’s a document database.

So what’s a document? It’s the first unit of data in a mongoDB. A document is simply an array of key-value pairs like this:


{
     name: "John Doe",
     age: 40
}

Note: we call this notation BSON, which stands for “Binary Serialized dOcument Notation”.

Back to the document. This “document” is similar to a record in a usual relational database. You can use Strings, Integers and many other data types, including arrays and other Documents. You have the ability to nest Documents, like, Person -> Children -> Toys.

So what’s a table then? Collections act more or like tables. A collection holds one or more documents.

And ultimately a database is a group of collections. Each collection has a unique name inside a database.

With the document stuff out of the way, let’s see why this database seems to cool.

Why is mongoDB so cool?

Working with a no-SQL database means you have several advantages over a traditional database. Here are some of them:

  • there is no schema. You don’t have to use Rails migrations for creating tables and columns. You simply start using them, and the database creates them on the fly. When using the gem mongomapper, for example, you simply declare the keys inside your model, and that’s it. Simple like that;
  • the data is formatted using a JSON-like format, giving greater flexibility and at the same time simplicity. New data types can be added, depending on how your format your Document before saving it into the database;
  • storage of binary files such as videos and photos on the database is possible and more important, efficient;

Basically, mongoDB bridges the gap between key-value stores (which are highly scalable) and traditional RDBMS (which provide structured schemas and powerful queries).

Other than these things, mongoDB also supports some types of database replication. It also offers auto-sharding, a feature that allows one to build a large horizontally scalable database cluster that can incorporate additional machines dinamically. It also supports map-reduce.

Installing mongoDB

Simply download the binaries. Unpack the tar.gz to /usr/local/bin/mongo and add ‘/usr/local/bin/mongo/bin’ to your PATH. Create the directory to which the database files will be saved to:

mkdir -p /data/db

Start the server with:

mongod

It listens for connections on port 27017 by default. Open another shell and start the mongo shell with:

mongo

Interesting enough, the mongo shell uses Javascript as its language :)

No need to create a database

One important note. You never have to create a database or collection.

The moment you try to access a database or collection, the underlying database and/or collection is created automatically.

Let’s add some data

In your mongo shell, type the following:


> a = { brand: "Toyota", model: "Corolla" };
> b = { name: "John", age: 40 }
> db.things.save(a);
> db.things.save(b);

Now to query all saved documents inside the collection things, run:

> db.things.find();
{ "_id" : ObjectId("4b33dee3844fab562308bb5f"), "brand" : "Toyota", "model" : "Corolla" }
{ "_id" : ObjectId("4b33dee5844fab562308bb60"), "name" : "John", "age" : 40 }

Important things to note:

  • the collection things is created automatically;
  • the documents inside a collection may have different scructures, as you can see these 2 documents have different fields;
  • upon being inserted into the database, objects are assigned an object ID in the field _id;
  • when you run these commands above, the object IDs will be different.

Adding more data

You noticed by now we are using Javascript inside the mongo client/shell. This means you can use something you already know to interact with mongoDB.


> for( var i = 1; i < 10; i++ ) db.things.save( { x:4, j:i } );
> db.things.find();
{ "_id" : ObjectId("4b33dee3844fab562308bb5f"), "brand" : "Toyota", "model" : "Corolla" }
{ "_id" : ObjectId("4b33dee5844fab562308bb60"), "name" : "John", "age" : 40 }
{ "_id" : ObjectId("4b33df5b844fab562308bb61"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4b33df5b844fab562308bb62"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4b33df5b844fab562308bb63"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4b33df5b844fab562308bb64"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4b33df5b844fab562308bb65"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4b33df5b844fab562308bb66"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4b33df5b844fab562308bb67"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4b33df5b844fab562308bb68"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4b33df5b844fab562308bb69"), "x" : 4, "j" : 9 }

Iterating the data using the cursor

When we ran db.things.find(); in the last example, the shell automatically showed all data from the collection. But if we assign a variable to the find() method, we can iterate the data it as we wish:


var cursor = db.things.find();
> cursor.next()
{
        "_id" : ObjectId("4b33dee3844fab562308bb5f"),
        "brand" : "Toyota",
        "model" : "Corolla"
}
> cursor.next()
{
        "_id" : ObjectId("4b33dee5844fab562308bb60"),
        "name" : "John",
        "age" : 40
}
> cursor.next()
{ "_id" : ObjectId("4b33df5b844fab562308bb61"), "x" : 4, "j" : 1 }
> cursor.next()
{ "_id" : ObjectId("4b33df5b844fab562308bb62"), "x" : 4, "j" : 2 }

Or we can use iterate programmatically:


> var cursor = db.things.find();
> while (cursor.hasNext()) {print (tojson(cursor.next())); }
{
	"_id" : ObjectId("4b33dee3844fab562308bb5f"),
	"brand" : "Toyota",
	"model" : "Corolla"
}
{
	"_id" : ObjectId("4b33dee5844fab562308bb60"),
	"name" : "John",
	"age" : 40
}
{ "_id" : ObjectId("4b33df5b844fab562308bb61"), "x" : 4, "j" : 1 }
{ "_id" : ObjectId("4b33df5b844fab562308bb62"), "x" : 4, "j" : 2 }
{ "_id" : ObjectId("4b33df5b844fab562308bb63"), "x" : 4, "j" : 3 }
{ "_id" : ObjectId("4b33df5b844fab562308bb64"), "x" : 4, "j" : 4 }
{ "_id" : ObjectId("4b33df5b844fab562308bb65"), "x" : 4, "j" : 5 }
{ "_id" : ObjectId("4b33df5b844fab562308bb66"), "x" : 4, "j" : 6 }
{ "_id" : ObjectId("4b33df5b844fab562308bb67"), "x" : 4, "j" : 7 }
{ "_id" : ObjectId("4b33df5b844fab562308bb68"), "x" : 4, "j" : 8 }
{ "_id" : ObjectId("4b33df5b844fab562308bb69"), "x" : 4, "j" : 9 }

Or use it like an array:


> var cursor = db.things.find();
> cursor[5]
{ "_id" : ObjectId("4b33df5b844fab562308bb64"), "x" : 4, "j" : 4 }

Important note: mongoDB cursors are not snapshots. For instance, if your cursor has 10 documents, and another user removes one of them from the collection, your cursor will return only 9 documents. You have to use explicit locking to prevent this.

How to query data

Let's see how to query the database for specific things we need to find.

The important thing to know is that queries, in a mongoDB database, are documents themselves. Let's have a look:

SELECT * FROM things WHERE model='Corolla';

will be:


> db.things.find(
     {model:'Corolla'}).forEach(
     function(x) { print (tojson(x));});
{
        "_id" : ObjectId("4b33dee3844fab562308bb5f"),
        "brand" : "Toyota",
        "model" : "Corolla"
}

Now, if we want to specify what fields we need, instead of running a "SELECT *" query, mongoDB lets you return "partial documents". To do this, you supply a second argument to the find() method, specifying what elements you need it to return:

SELECT brand FROM things WHERE model='Corolla';


> db.things.find(
     {model:'Corolla'}, {brand:true}).forEach(
     function(x) { print (tojson(x));});
{ "_id" : ObjectId("4b33dee3844fab562308bb5f"), "brand" : "Toyota" }

As you see, the query only returned the field 'brand' along with the object ID.

So, how to limit how many documents the database will return? Use the limit() method:

SELECT j FROM things WHERE x=4 LIMIT 2;


> db.things.find({x:4}, {j:true}).limit(2).forEach(
     function(x) { print (tojson(x));});
{ "_id" : ObjectId("4b33df5b844fab562308bb61"), "j" : 1 }
{ "_id" : ObjectId("4b33df5b844fab562308bb62"), "j" : 2 }

Or you can use the helper method findOne, if you want to return only 1 document:


> db.things.findOne({x:4})

{ "_id" : ObjectId("4b33de25ba7e40276b83ad53"), "x" : 4, "j" : 1 }

Note that in this case, all fields will be returned.

Conclusion

mongoDB is easy to learn. Its features are useful for web apps, specially having the need to build something scalable right from the beginning. Being a document database, it provides greater flexibility never before offered by traditional databases. mongoDB and its friends like CouchDB are definitely worth a look.

In the next article we'll see how to start playing with mongoDB in Rails. Stay tuned! :)

Portraits and Photography

September 27th, 2009

Clique aqui para a versão em Português.

My latest passion has been portraiture and photography in general._dsc0600-flickr

From an old hobby, the interest only grew even more after I discovered the Strobist website. David Hobby teaches everything about lighting your little flash unit, and the secret is: use it off your camera.

A photographer named Jeremy Cowart created a movement called Help Portrait, check the video here and the Help Portrait website. On December 12th photographers from around the world will go out in the streets and reach people in need, and simply take their photographs. This is to help people that would never been able to pay for a photograph. The idea is: shoot and deliver the prints later. Just that. Connections will be made and you’ll learn a lot about people.

Inspired by a post on Zack Arias blog, I started to take some portraits right away. This is in preparation for the Help Portrait official day. So I went ahead and asked if a local retirement home would open their doors so I could photograph (for free) all of their 60 residents, elderly ladies and men. They were very happy to get this offer and yesterday I could do the photo session.

I’m really happy with the results. Many of the ladies and men were very happy about the photos. Some were not excited about having a photo taken, so for these I’d just showed some of the previous photos and let them decide. After this, some got excited and let me take their photos. Soon I’ll be able to see their joy when I deliver them the prints.

I started to process some of the images, and the best ones I posted on Flickr. I’ll be printing all photos and giving to them.

I learned that from very small things we can make people in need a little more happier. I saw a phrase written on their car that read “Love never gets old”.

Check some of the elderly portraits I shot on the retirement home.


Minha recente paixão tem sido retratos e fotografia em geral.

A partir de um hobby antigo, o interesse cresceu ainda mais depois que descobri o site Strobist. David Hobby ensina tudo sobre como iluminação com flashs portáteis, e no final das contas o segredo é: use ele fora de sua câmera.

Um fotógrafo chamado Jeremy Cowart criou um movimento, o Help Portrait. Confira o vídeo aqui e o site do Help Portrait. Em 12 de dezembro fotógrafos do mundo inteiro vão sair nas ruas, encontrar pessoas com algum tipo de necessidade (seja pessoas sem-teto, crianças órfãs, ou qualquer tipo de necessidade), e simplesmente vão dar um presente: tirar uma fotografia delas e depois levar a foto impressa. Isto será feito para ajudar aqueles que talvez nunca poderiam pagar por uma fotografia. Conexões serão feitas e você vai aprender bastante coisas sobre pessoas.

Inspirado por um post no blog de Zack Arias, comecei a tirar alguns retratos imediatamente. Esta é uma preparação para o dia oficial do Help Portrait. Fui em frente e perguntei em uma casa de repouso da cidade, se eu poderia visitá-los e tirar fotos (gratuitas) de todos seus 60 residentes. Eles ficaram muito felizes com a oferta e ontem eu pude fazer a sessão de fotos.

Estou muito feliz com os resultados. Muitos das senhoras e senhores ficaram felizes com a idéia de tirar fotos. Alguns não ficaram muito animados com a idéia, mas nestes casos eu mostrava as fotos de outras senhoras e alguns se animavam depois disso. Em breve vou poder ver a alegria deles ao receberem as fotos em mãos.

Comecei a processar algumas das imagens, e postei algumas das melhores no Flickr. Vou imprimir todas as fotos e dar de presente para eles.

Aprendi que com pequenas coisas você pode fazer pessoas em necessidades um pouco mais felizes. Vi uma frase escrita em um carro deles escrita assim “O amor nunca envelhece”.

Confira alguns dos retratos das senhoras da casa de repouso.

Palestra: Web Performance Client Side

September 14th, 2009

215987893_f665d2fa1dHá algumas semanas tive a oportunidade de palestrar internamente em dois eventos aqui na Locaweb:

  • Locaweb Tech Day: um evento de dia inteiro que ocorre a cada 2 meses, onde cada pessoa pode palestrar sobre um assunto de interesse;
  • Palestras Técnicas: ocorre às quintas-feiras, durando 1 hora. Uma pessoa por semana palestra sobre um assunto técnico.

Nas duas oportunidades palestrei sobre como fazer um site ficar mais rápido, e abrir num “estalo”. O título das palestras foi: Web Performance Client Side.

Se você já parou pra pensar em otimização de um website, vai perceber que o lado server side (sua aplicação Rails, PHP, etc) conta na velocidade de carregamento, mas na prática representa muito pouco. Isto acontece porque uma requisição é processada pelo servidor em 200 milisegundos, digamos, enquanto o mesmo site pode levar 10 segundos para carregar no browser. Então qualquer otimização que ocorra em server-side só vai afetar a quantidade de pessoas que podem acessar seu site ao mesmo tempo. Não afeta a velocidade individual que cada pessoa vai ter ao navegar nas páginas de seu site.

E para melhorar a velocidade client-side, a que realmente importa na maioria das vezes, existem várias técnicas inteligentes e interessantes. Na apresentação que coloquei no SlideShare, você pode pegar um apanhado com as últimas técnicas para desenvolvimento web com vistas à performance no browser.

Existe muita coisa mesmo na apresentação, e é imperdível pra quem trabalha com Desenvolvimento Web.

Veja a apresentação sobre Web Performance Client Side no SlideShare. Ou baixe o PDF, mas para isso você precisa ter conta no SlideShare.

Quick and dirty way to find broken links on your website

July 23rd, 2009

These days I had to find if there was any broken link (error 404) in a group of sites.

I found this to be very useful:

wget –recursive –spider http://levycarneiro.com

This command will download everything from the URL, and generate a report like this:

Found 13 broken links.

http://levycarneiro.com/levy@levycarneiro.com referred by:

http://levycarneiro.com/

http://levycarneiro.com/images/posts/Multiple_models_one_form_NewProject.jpg referred by:

http://levycarneiro.com/category/ruby-on-rails/

http://levycarneiro.com/tag/twitter/levy@levycarneiro.com referred by:

http://levycarneiro.com/tag/twitter/

http://levycarneiro.com/tag/rails/levy@levycarneiro.com referred by:

http://levycarneiro.com/tag/rails/

http://levycarneiro.com/tag/portfolio/levy@levycarneiro.com referred by:

http://levycarneiro.com/tag/portfolio/

http://levycarneiro.com/2009/04/transito-nao-an-experiment-with-twitter-traffic-jams-and-ruby-on-rails/levy@levycarneiro.com referred by:

http://levycarneiro.com/2009/04/transito-nao-an-experiment-with-twitter-traffic-jams-and-ruby-on-rails/

http://levycarneiro.com/tag/traffic/levy@levycarneiro.com referred by:

http://levycarneiro.com/tag/traffic/

http://levycarneiro.com/tag/projects/levy@levycarneiro.com referred by:

http://levycarneiro.com/tag/projects/

http://levycarneiro.com/category/projects/levy@levycarneiro.com referred by:

http://levycarneiro.com/category/projects/

http://levycarneiro.com/tag/ruby/levy@levycarneiro.com referred by:

http://levycarneiro.com/tag/ruby/

http://levycarneiro.com/category/ruby-on-rails/levy@levycarneiro.com referred by:

http://levycarneiro.com/category/ruby-on-rails/

http://levycarneiro.com/category/twitter/levy@levycarneiro.com referred by:

http://levycarneiro.com/category/twitter/

http://levycarneiro.com/tag/ruby-on-rails/levy@levycarneiro.com referred by:

http://levycarneiro.com/tag/ruby-on-rails/

I’ve got some work to do then :)

Google Chrome prefetches DNS for speed up browser performance

June 29th, 2009
Google Chrome

Google Chrome

Browser performance problems? Simple tricks to the rescue:

“To speed up browsing, Google Chrome resolves domain names before the user navigates, typically while the user is viewing a web page. This is done using your computer’s normal DNS resolution mechanism; no connection to Google is used. As a result, user navigation time in Google Chrome when first visiting a domain is on average about 250ms faster than traditional browsing, and the occasional but painful 1-second-plus delays are almost never experienced.”

And how it works:

DNS prefetching just resolves domain names before a user tries to navigate, so that there will be no effective user delay due to DNS resolution. The most obvious example where prefetching can help is when a user is looking at a page with many links to various unexplored domains, such as a search results page. Google Chrome automatically scans the content of each rendered page looking for links, extracting the domain name from each link, and resolving each domain to an IP address. All this work is done in parallel with the user’s reading of the page, hardly using any CPU power. When a user clicks on any of these pre-resolved names to visit a new domain, they will save an average of over 250ms in their navigation.”

Check the full article.

Very clever and efficient.