Posts tagged "the plataforma way"

2009 se foi. Foram 10 meses muito agitados para nós. Aprendizado intenso, momentos de cansaço físico, desafios constantes e dúvidas sobre o futuro são fatores que estão presentes no nosso dia-a-dia.

Antes de iniciar as operações da Plataforma Tecnologia (fev/09), nos questionávamos duas perguntas que davam frio na barriga:

Como fazer uma empresa de serviços dar certo?!
Como sair da inércia e conquistar os primeiros clientes?!

Não sabíamos as respostas. Mas estávamos lá.
Cada um com suas habilidades e todos com um sentimento que se equilibrava entre arrogância e inocência. Sem motivos muito claros, nós simplesmente acreditávamos que poderia dar certo.  Então, por que não tentar?

Aqui estamos: tentando.

É difícil dizer se a Plataforma Tecnologia será bem sucedida ou não. Só o futuro dirá.

O que podemos dizer é que avançamos muito mais do que imaginávamos e acreditamos estar na direção certa.  Sabemos onde queremos chegar, mas há inúmeros caminhos para escolher. Uns melhores, outros piores.

Fato é que durante 2009 descobrimos algumas coisas que consideramos valiosas e queremos compartilhar nossa opinião.  Seguem abaixo.

  • Contrate pessoas cujo trabalho você confia (e vice-versa): se você precisa micro-gerenciar sua equipe, então algo está errado. Micro-gerenciar times de desenvolvimento de software é uma tentativa (ruim) de assegurar a qualidade durante o processo produtivo. É preciso entender que o processo em si não é tão importante. O importante é o resultado final. Dê autonomia a sua equipe. Parta do pressuposto que sua equipe é capaz de atingir os objetivos até que seja provado o contrário (e se o “contrário” ocorrer, há diversas ações que podem ser tomadas, mas isso rende assunto para um outro post inteiro).
  • A maioria dos clientes descrevem soluções ao invés de descrever as reais necessidades: é natural que isso ocorra. E ao invés de culpá-los por não saberem descrever corretamente as necessidades, ajude-os a esclarecer qual o problema a ser resolvido. Em seguida, construa com ele uma solução (software).
    Não se esqueça que é o seu cliente que tem o conhecimento sobre o segmento/negócio e uma boa solução será resultado de um trabalho conjunto. Se um cliente não se dispuser a trabalhar em conjunto para desenhar uma solução, então caia fora. Este projeto terá grandes chances de ter problemas.
  • 6 meses é muito tempo para empresas recém-nascidas e pequenas: É importante saber onde se quer chegar, mas nesta fase da empresa, não faz muito sentido realizar planejamentos com horizontes longos. Muita coisa muda e muito rápido.
    Descobrimos que vale a pena fazer planejamentos com maior freqüência e com horizontes mais curtos. É como se a cada 6 meses a empresa estivesse realizando um “release”. Faça “retrospectivas”, “release plannings”, “sprint plannings” relativos à empresa e priorize a execução do que trará mais valor durante os próximos 6 meses. A grande vantagem de uma empresa de pequeno porte é sua capacidade de responder à mudanças (agilidade). Aproveite-a!
  • Nunca haverá momento ideal para implementar algo: já nos pegamos dizendo “assim que der uma sossegada, a gente começa a re-estruturar bla-bla-bla”. A verdade é que este momento de sossego dificilmente chegará, ainda mais se a empresa estiver em crescimento. Se há necessidade em implementar ou mudar algo na empresa, faça-o o quanto antes (ou de acordo com a prioridade). Esperar só vai piorar os sintomas que este problema estiver causando. Quanto mais você esperar, pior será.
  • Saiba claramente qual o seu DNA: isso pode soar um pouco filosófico, e de fato é. Mas é algo que se mostrou muito importante para nós. Todo o time deve saber e compartilhar dos valores que moldam as decisões de negócio e refletem na maneira de operar o dia-a-dia da empresa. Pode ocorrer momentos em que fechar um novo contrato significará deixar o DNA de lado e isso será um pouco doloroso.
    Mas da nossa experiência, posso afirmar que valeu a pena não se desviar do DNA. Quando olhamos para trás, fica muito claro que tomamos boas decisões. Warren Buffet já dizia… “In the business world, the rear view mirror is always clearer than the windshield“.
    É a mais pura verdade!

Espero que estes tópicos possam ajudar startups e outras empresas iniciantes.

Gostaria de pedir que ajudem a enriquecer o post e comentem. Compartilhem suas experiências!

Well, we are in business for almost one year and we are happy to say that quite a lot of applications were already delivered. In each one of them, we were definitely learning and moving toward the Plataforma way of doing things.

So I want to talk the way we treat Rails controllers at Plataforma. With love, of course, but we are going to go deeper than that, specifically in three steps:

1) Using InheritedResources to dry up controllers
2) Splitting your controllers by scope with nested controllers
3) Creating acts_as_* and filters to contain common logic and configuration among controllers

Step 1: Using InheritedResources to dry up controllers

InheritedResources is a tool that allows drying up your controllers, by removing the common logic and taking care of stuff like relationships.

For instance, imagine that you have an Article model which belongs to user. If you want to show all the articles for an specific user, your routes definition and controller are just the following:

# config/routes.rb
map.resources :users do |u|
  u.resources :articles
end
 
# app/controllers/articles_controller.rb
class ArticlesController < InheritedResources::Base
  belongs_to :users
end

It supports nested and/or polymorphic relationships, I18n and other stuff like named scopes.

Almost all of our controllers inherit from InheritedResources::Base and the first step is as simple as that.

Step 2: Splitting your controllers by scope with nested controllers

Sometime ago, Matt Jankowski from Thoughtbot wrote an excellent blog post on how they deal with scoped controllers, like in the scenario above where we want to show all the articles which belongs to an specific user.

Matt tell us that instead of having an ArticlesController, we should have a Users::ArticlesController, so ArticlesController is available if you want to show all the articles in the application.

Since we read this post, we started to use this setup on our applications as well. However, InheritedResources does not play nice with it by default and let’s check why. Our ArticlesController should be renamed to Users::ArticlesController and be rewritten as:

class Users::ArticlesController < InheritedResources::Base
  belongs_to :users
end

The problem is, according to the namespace Users, InheritedResources appends to all named routes the prefix “users”. But since Articles belongs to :user, it also appends “user”. So the resource_url method will actually call “users_user_article_url”, which is not defined. The fix is simple:

class Users::ArticlesController < InheritedResources::Base
  defaults :route_prefix => nil
  belongs_to :users
end

Matt’s post contains a lot of tips about using nested controllers and it’s a must-read.

Step 3: Creating acts_as_* and filters to contain common logic and configuration among controllers

As your application grow, you will start to notice that your controllers will have a lot of configuration values and methods for specific scopes. Let’s consider that in our application an user can only see his articles and we are going to retrieve the user from session. So instead of having a route “/users/:user_id/articles/:id” like above, we should just have “/articles/:id” and our controller will be similar to:

class Users::ArticlesController < InheritedResources::Base
  before_filter :find_user_from_session
  layout "users"
  defaults :route_prefix => nil
 
  protected
 
  # Get the articles scoped to the current user
  def begin_of_association_chain
    @current_user
  end
 
  # Simple method to retrieve an user from session
  def find_user_from_session
    @current_user ||= User.find(session[:user_id])
  end
end

With time, we will notice that several controllers use this same pattern, and we need to refactor it. Our first thought would be move part of the logic to ApplicationController, but our ApplicationController will only grow and grow as you add roles (like Admin) to your application.

A better approach would be to move this specific logic to a controller named Users::ApplicationController inside “app/controllers/users/application_controller.rb”:

class Users::ApplicationController < ApplicationController
  before_filter :find_user_from_session
  layout "users"
 
  protected
 
  def begin_of_association_chain
    @current_user
  end
 
  def find_user_from_session
    @current_user ||= User.find(session[:user_id])
  end
end

Now we can inherit from it and get InheritedResources methods by calling inherit_resources in our controller:

class Users::ArticlesController < Users::ApplicationController
  inherit_resources # the same as inheriting from InheritedResources::Base
  defaults :route_prefix => nil
end

But we are not very happy with this pattern, because we still need to call defaults and set some configuration values (which can be quite a few depending on your application).

What we do instead is create some macros inside a module called Filters. So we create a file at “app/controllers/users/filters.rb” with the following:

module Users::Filters
  def acts_as_user(options={})
    before_filter :find_user_from_session
    layout "users"
    defaults options.reverse_merge(:route_prefix => nil)
    include ControllerMethods
  end
 
  module ControllerMethods
    protected
 
    def begin_of_association_chain
      @current_user
    end
 
    def find_user_from_session
      @current_user ||= User.find(session[:user_id])
    end
  end
end

And extend this module in our ApplicationController:

class ApplicationController < ActionController::Base
  extend Users::Filters
end

And we can use it simply as:

class Users::ArticlesController < InheritedResources::Base
  acts_as_user
end

The main advantage here is that we have more control of our controller configuration through a single interface. If we need to configure a singleton controller or ensure that most controllers have pagination, we can simply do:

module Users::Filters
  def acts_as_user(options={})
    before_filter :find_user_from_session
    layout "users"
    has_scope :paginate, :only => :index unless options.delete(:paginate) == false
    defaults options.reverse_merge(:route_prefix => nil)
    include ControllerMethods
  end

And invoke it as:

acts_as_user :paginate => false
acts_as_user :singleton => true
acts_as_user :paginate => false, :singleton => true

Wrapping up

As you add more roles to your application, you create more filter. Remember that the important here is to keep your code DRY and is NOT reduce the lines of code. So just place inside those acts_as_* helpers configuration which is common to almost all (if not all) controllers. There is some convention over configuration here, so be sure that the whole team working in the project agrees with them as well. In other words: use it with caution, because we certainly do.

This pattern holds almost all controllers in the last applications we built and we are quite happy with it. Be sure to grab our blog feed (see our sidebar), because we will continue writing about the Plataforma way in next posts!