A extinção do programador sênior

Posted by Humberto on julho 29, 2010

Quando foi a última vez em que você viu um programador sênior? Eu tenho tido sérias dificuldades para encontrar algum. Acho que se estivesse procurando ararinhas azuis teria tido mais sucesso — será que alguma toparia programar? Desconfio que não. Consciente da causa ecológica, ela me diria: cada ararinha programando toma o lugar de um programador sênior, que é de uma espécie muito mais em risco do que eu. E bateria as asas em retirada.

É claro que, ao contrário da pobre arara, o programador sênior ainda existe, e em grandes quantidades. Mas algo deu errado na evolução da sua espécie que, ao invés de melhorar, foi substituída por uma variedade mais fácil de reproduzir, bem adaptada ao cativeiro, de comportamento dócil, capaz de passar anos fazendo a mesma coisa e com duas opções de cor: terno preto ou azul. E que, curiosamente, não consegue programar. Eu já vou batizando essa variedade de programador senhor.

Estou falando por experiência própria. A empresa em que eu trabalho está recrutando um “programador sênior” há alguns meses. Dada a indisponibilidade dos colegas no nosso networking (o que nos pouparia um grande tempo), resolvemos apelar e buscar no mercadão de trabalho (vulgo apinfo, catho, essas coisas). Nós filtramos dezenas de currículos, conduzimos entrevistas, aplicamos testes. Com isso, conseguimos achar diversos programadores senhores mas nenhum propriamente sênior. A maioria tinha 10+ anos de carreira, 30+ anos de idade e -1 noção para bolar respostas satisfatórias para questões como:

  1. Como dois programas podem se comunicar?
  2. O que são threads?
  3. Implemente o fizz buzz na linguagem que preferir.

E assim por diante. Nada muito específico: preferimos encontrar gente que tivesse convivido com certos problemas, independente da tecnologia adotada. Gente demonstrasse senioridade propriamente dita: maturidade, bom senso, raciocínio, segurança. E conhecimento suficiente para não achar que a chave de todos os problemas é uma consulta ao Google (houve quem confessasse isso). Não encontramos essa gente ainda, mas em compensação vimos muitas pessoas bem intencionadas, certamente esforçadas, mas com imensas dificuldades para concatenar opiniões a respeito de conceitos que julgamos básicos e, no nosso negócio, fundamentais.

Sequer exigimos que o candidato conheça tópicos como controle de versão, orientação a objetos, design patterns, agilidade e etcetera, que são sinais mais do que evidentes de maturidade. Já entendemos que tudo isso está além dos limites do habitat do programador senhor. São coisas tão exóticas quanto um programador sênior genuíno, que só deve existir em áreas de proteção ambiental, como este blog.

(Às araras azuis que estiverem interessadas no recrutamento: por ora concluímos o processo, mas não deixem de entrar em contato.)

Active Record em: Como adicionar comportamento as suas associações

Posted by Roger Leite on maio 19, 2010

Qualquer um que comece a desenvolver com Active Record (AR), minha primeira recomendação é, para tudo e leia:  A Guide to Active Record Associations ou O Guia de Associações do Active Record. O guia é bem completo, e descreve muito bem os tipos de associações que estão disponíveis no AR.

Association Proxy, #wtf !

As associações:

  • belongs_to
  • has_one
  • has_many
  • has_and_belongs_to_many

Quando usadas, adicionam alguns métodos (veja Detailed Association Reference). Por exemplo, ao declarar uma associação belongs_to, o model “ganhará” os seguintes métodos:

  • association(force_reload = false)
  • association=(associate)
  • build_association(attributes = {})
  • create_association(attributes = {})

Onde association, será substituído pelo nome da associação. Exemplo retirado do guides:

class Order < ActiveRecord::Base
   belongs_to :customer
end

Cada instância de Order, conterá os métodos:

  • customer
  • customer=
  • build_customer
  • create_customer

O association proxy, é o objeto que faz a ligação do objeto que contém a associação, conhecido como owner, e o objeto associado, conhecido como target.

Legal e daí !?!

Graças ao association proxy, ao declarar uma associação, podemos extendê-la e adicionar comportamentos “customizados”. No guia, é citado como Association Extensions. O código de exemplo abaixo, está no github em random-samples.

Para exemplificar, vamos criar um modulo que adiciona o comportamento de uma galeria a qualquer coleção.

module GalleryColletion
 
  def current=(curr = nil)
    @current, @index = nil
 
    if curr.nil?
      @current = collection.first
      @index = 0
    else
      collection.each_with_index do |item, index|
        if item.id.to_i == curr.to_i
          @current = item
          @index = index
        end
      end
    end
    @current
  end
 
  def current
    @current
  end
 
  def position
    @index + 1
  end
 
  def previous?
    return false if @index.nil?
    !!(@index - 1 >= 0)
  end
  def previous
    collection[@index - 1] if previous?
  end
 
  def next?
    return false if @index.nil?
    !!(@index + 1 < collection.size)
  end
  def next
    collection[@index + 1] if next?
  end
 
  private
 
  def collection
    proxy_owner.send(proxy_reflection.name)
  end
 
end

Gallery Collection

Note que o modulo está na pasta lib, logo, a pasta tem que ser adicionada no path via config/environment.rb.

Para extender a associação, declare:

class Article < ActiveRecord::Base
  has_and_belongs_to_many :images, :extend => GalleryColletion
end

Article model, Image model aqui.

Agora para navegar entre as imagens, você pode usar:

a = Article.first
a.images.current = 1 #1 e o Image.id que deseja selecionar
a.images.current
a.images.position
a.images.next?
a.images.next
a.images.previous?
a.images.previous

Caso esteja com coragem, baixe o projeto e veja rodando.

Dúvidas, sugestões, algum “case” de sucesso, comente!

Teste sua aplicação de Linha de Comando com Cucumber! 1

Posted by Roger Leite on maio 14, 2010

É engraçado como tudo é questão de treino e disciplina. Levei um tempo para me acostumar com TDD, Vim e não poderia ser diferente com testes funcionais, sendo mais especifico, Cucumber.

Até o momento, só tinha usado cucumber em projetos web. E quando voltei a desenvolver o rubygems_snapshot, senti falta de algo para testar funcionalmente. Baseado no pik, montei um esquema simples para validar qualquer aplicação de linha de comando.

Como instalar

Basicamente, será necessário (fontes via gist):

  • rake para executar o cucumber
  • env_terminal.rb
  • terminal_steps.rb

Dado que você tem cucumber instalado, com o esquema da pasta “features”.

  • Copie o cucumber.rake para a raiz.
  • Copie o env_terminal.rb para a pasta features.
  • Copie o terminal_steps.rb para a pasta features/step_definitions/terminal_steps.rb.
  • Edite o  env.rb incluindo (pode ser no começo):
require "env_terminal"
  • Dentro do Rakefile, pode ser no final mesmo, adicione:
load "cucumber.rake"

Como usar

Todas features:

rake cucumber

Features com a tag @wip, também conhecida como Work in Progress.

rake cucumber:wip

Informações Extras

Caso precise de mais informações, você tem a opção de ver a saída dos comandos, executando a rake assim:

rake cucumber show_output=true

ou

rake cucumber:wip show_output=true

No caso do snapshot, tive a necessidade de “modificar” o comando gem toda vez que era executado, ou melhor, passar um parâmetro para controlar o ambiente. Dentro do env_terminal.rb, existe o método gsub_command, nele você pode “redefinir” comandos, caso necessite.

Gostei, quero mais!

A solução acima, é bem “caseira”. Para projetos simples com funcionalidades simples, funciona bem.

Caso queira algo mais robusto, você tem a opção da gem Aruba.

Tem este post como introdução:

Aruba – Cucumber Goodness for the Command-Line

Agile Enterprise Edition 3

Posted by Rodrigo Panachi on dezembro 21, 2009

Para começar o post, segue esta história sobre gerenciamento que vi no blog do Gustavo Ribeiro:

Todos os dias, uma formiga chegava cedinho ao escritório e pegava duro no trabalho. A formiga era produtiva e feliz. O gerente marimbondo estranhou a formiga trabalhar sem supervisão. Se ela era produtiva sem supervisão, seria ainda mais se fosse supervisionada.

E colocou uma barata, que preparava belíssimos relatórios e tinha muita experiência, como supervisora. A primeira preocupação da barata foi a de padronizar o horário de entrada e saída da formiga.

Logo, a barata precisou de uma secretária para ajudar a preparar os relatórios e contratou também uma aranha para organizar os arquivos e controlar as ligações telefônicas.

O marimbondo ficou encantado com os relatórios da barata e pediu também gráficos com indicadores e análise das tendências que eram mostradas em reuniões.

A barata, então, contratou uma mosca, e comprou um computador com impressora colorida. Logo, a formiga produtiva e feliz, começou a se lamentar de toda aquela movimentação de papéis e reuniões!
O marimbondo concluiu que era o momento de criar a função de gestor para a área onde a formiga produtiva e feliz, trabalhava. O cargo foi dado a uma cigarra, que mandou colocar carpete no seu escritório e comprar uma cadeira especial.

A nova gestora cigarra logo precisou de um computador e de uma assistente (sua assistente na empresa anterior) para ajudá-la a preparar um plano estratégico de melhorias e um controle do orçamento para a área onde trabalhava a formiga, que já não cantarolava mais e cada dia se tornava mais chateada.

A cigarra, então, convenceu o gerente marimbondo, que era preciso fazer um estudo de clima. Mas, o marimbondo, ao rever as cifras, se deu conta de que a unidade na qual a formiga trabalhava já não rendia como antes e contratou a coruja, uma prestigiada consultora, muito famosa, para que fizesse um diagnóstico da situação. A coruja permaneceu três meses nos escritórios e emitiu um volumoso relatório, com vários volumes que concluía: “Há muita gente nesta empresa!”

Então o marimbondo mandou demitir a formiga porque ela andava muito desmotivada e aborrecida.

Então lembrei de uma imagem que ilustra perfeitamente esta fábula e retrata fielmente a “organização” de alguma empresas:

Dividir para conquistar: você está fazendo isso errado!

Quando uma startup passa a vender mais e ter uma procura maior por seus produtos/serviços (o que é bom), uma reação comum da “cúpula” é aumentar o quadro de funcionários visando atender a demanda. Logo surgem os problemas com a organização do pessoal e/ou fluxo de trabalho. A solução mais simplista (e óbvia) é a especialização: fulano faz isso, ciclano faz aquilo, e beltrano gerencia. Logo controles são criados, fluxos validados, centros de custo, documentos, reuniões, atas, comitês, gestão de pessoas e relacionamento, terceirização, cargos, departamentos… e nasce o monstro da burocracia, aka “enterprise”.

Com essa especialização, cada “módulo” (também conhecido como departamento) começa a perder o foco no GRANDE objetivo da empresa e passa a defender apenas seus interesses – a famosa MISSÃO da empresa passa a ser coadjuvante. O resultado? A empresa dobra ou triplica seu quadro de funcionários e na maioria dos casos, seu lucro bruto. Porém agora tem mais despesas com pessoal e gastos extras para manter esse novo modelo “enterprise”. Trocando em miúdos, continua na mesma!

Onde está o erro? Mais uma vez o FOCO está na solução ao invés de PROBLEMA. Se você ler meus posts anteriores vai ver que este é um tema recorrente. Então por que as empresas continuam fazendo as coisas erradas e cometendo os mesmos erros?

Idéias criativas surgem das pessoas diretamente relacionadas com os problemas e não de diretores, contadores, gestores, etc. Esse modelo “enterprise” é um overhead organizacional que só gera ruído e desperdício!

A solução é adotar agile!

SOLUÇÃO!? Mas qual era o PROBLEMA mesmo!? Sim, mais uma vez o foco é a solução ao invés do problema.

Como eu disse nos posts anteriores, acreditar que uma mudança drástica do processo pode mudar a cultura da empresa e pincipalmente as pessoas é o maior erro na adoção de metodologias ágeis. Mudam o processo mas não mudam as pessoas.

De uma forma simples e direta, agile resume-se a quatro valores:

Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan

Ou seja, pessoas, software, colaboração e feedback. Simples assim!

O manifesto ágil não cita nada sobre “enterprise”, sobre a implementação. Este é o grande desafio em sua adoção. Como seguir estes valores sem burocratizar e engessar o processo? Como criar uma relação de colaboração com os clientes? Como responder rapidamente a mudanças? Como eliminar o esforço que não agrega valor ao produto e/ou empresa? Como evitar politicagem?

Mantenha-se pequeno!

Otimize! Busque soluções para os problemas que impedem de produzir mais e com mais qualidade. Faça MAIS com MENOS. Foque no O QUE ao invés do COMO. Escale as pessoas verticalmente!

Inove! Não espere conseguir resultados diferentes fazendo sempre a mesma coisa. Busque novidades, opniões, experiências. Ouça seus funcionários, seus clientes. Estude, pesquise, arrisque, erre, acerte… continuamente.

Mantenha o foco! Tenha um GRANDE e único objetivo e certifique-se que todos acreditem nesta filosofia. É importante que todos comprem a idéia e o modus operandis.

Finalizando, este é apenas meu ponto de vista, baseado na minha experiência em diversas empresas grandes e pequenas, vivenciando problemas, errando muito e principalmente aprendendo com os erros dos outros. Agilidade pode funcionar bem em grandes corporações, desde que haja foco e que todos comprem a idéia. Você pode concordar ou não.

Ruby: quando a linguagem de programação faz diferença! 3

Posted by Rodrigo Panachi on agosto 18, 2009

Pretendo neste post falar um pouco da minha evolução na programação e como Ruby e Rails agregaram mais conhecimento e me tornaram um melhor desenvolvedor.

A gente se forma na faculdade e de repente estamos trabalhando como programador em alguma empresa de software. A primeira coisa que você vai concluir é que nada a maioria das coisas que foram ensinadas na faculdade não se aplicam na vida real. Triste realidade…

Mas como um bom programador (que você é) logo começará a se questionar e se interessar por novos assuntos, aprender novos conceitos e técnicas de programação, pois você não se sentirá confortável fazendo as mesmas tarefas repetitivas ou que não sejam otimizadas.

Orientação a objetos

Nada de cachorrinhos ou pessoas com ações como andar, comer, etc. No mundo real, seus problemas são faturas, notas fiscais, relatórios, importadores de arquivos, planilhas… e por aí vai. Seu primeiro desafio será de entender a orientação a objetos de verdade. Mas não se preocupe se isto demorar um pouco pois logo a “lâmpada” acenderá e tudo ficará claro como o dia.

Linguagem e frameworks

Agora você consegue modelar os objetos da sua aplicação mas se depara com assuntos técnicos que podem ser solucionados prontamente utilizando-se frameworks e alguns recursos avançados da linguagem em questão. Logo você estará visitando os sites da documentação do Struts, do Hibernate, do Ant… e descobrirá que o nome Apache, além de tribo indígena, é muito mais do que um servidor Web. Após muitas provas de conceito e algumas noites sem dormir, você será um programador muito produtivo e confiante.

Análise e documentação

Parabéns! Aqui você já pode ser considerado um desenvolvedor. Logo seu destaque na equipe será recompensado com mais trabalho de corno desafiador. Nesta fase sua empresa se parece com uma padaria: “Me vê meio quilo do relatório X”, “Faz dois webservices pra viagem!”, “Aí, saindo uma fornada de casos de uso…”, etc. Logo alguém tem a brilhante idéia de “documentar” tudo desde uma simples alteração no CSS do sistema até complexos e numerosos diagramas e notações daquele novo sistema para integração. No começo a novidade até parece ser uma boa idéia, mas logo você vai descobrir que o que realmente importa é ouvir os problemas dos clientes.

Testes

Se você não teve a sorte de ser orientado desde o começo da sua carreira sobre desenvolvimento guiado por testes, você aprende a importância de testes da melhor maneira possível: tomando na cabeça! Os problemas começam a ficar mais claros. Você fica mais focado na tarefa que está desempenhando e felizmente também cresce profissionalmente com este aprendizado. Você se pergunta como conseguia desenvolver sem testes e por que a linguagem que você utiliza não tem um suporte mais “nativo” a testes.

Metodologia

No decorrer da sua experiência você tentará desempenhar suas atividades de várias maneiras. Quando você faz de tudo um pouco acha que o melhor seria fazer apenas uma tarefa específica mas depois descobre que estava enganado. Neste ponto você provavelmente já experimentou pelo menos duas metodologias de desenvolvimento e saberá identificar as vantagens e desvantagens em cada uma.

Agilidade

Felizmente sua experiência o guia para um caminho mais ágil. Após aprender e aplicar os mandamentos do manifesto ágil e aprimorar seus conceitos e habilidades técnicas, desenvolver aplicações torna-se uma tarefa “natural” que você desempenha com fluência independente da linguagem ou tecnologia utilizada. Suas maiores conquistas se resumem em conseguir contornar um problema tecnológico ou limitação da linguagem, negociar o escopo do projeto com o cliente, implementar a maior cobertura de testes possíveis, automatizar processos durante o desenvolvimento, etc.

Neste ponto você começa a se questionar: o que devo fazer agora para evoluir profissionalmente?

Ruby!

Eis que você conhece Ruby e Rails. A linguagem parece estranha a primeira vista mas após algum tempo dedicado e muito estudo você descobre que é uma ferramenta muito poderosa e produtiva, onde você pode “fluir” com seu desenvolvimento. Você pensa no que quer fazer e faz! Escreve sua “feature”, implementa e roda! Simples e divertido!

Ruby e Rails vieram suprir uma necessidade e/ou carência dos desenvolvedores por simplicidade. Até seu surgimento, desenvolver aplicações nas linguagens populares do mercado era uma tarefa complicada e trabalhosa. Ruby é uma linguagem poderosa. Rails é simples e muito produtivo. Combinação perfeita!

O que você tá esperando? Comece agora mesmo a estudar Ruby e Rails e seja feliz!

UPDATE: para não causar confusão, alterei o título. Lembre-se: Ruby é linguagem e Rails é framework!

Cuidado com Casos de Uso 2

Posted by Roger Leite on julho 21, 2009

Na Engenharia de Software, um caso de uso (ou use case) é um tipo de classificador representando uma unidade funcional coerente provida pelo sistema, subsistema, ou classe manifestada por seqüências de mensagens intercambiáveis entre os sistemas e um ou mais atores. Pode ser representado por uma elipse contendo, internamente, o nome do caso de uso. (fonte: Wikipédia)

A própria explicação do Caso de Uso demonstra o que costumam ser na prática, ou seja, um monte de buzzwords para enganar o usuário e levar a sua assinatura. Este por sinal, só é citado no segundo parágrafo…

É uma cilada Bino!!!

Caso de Uso!?! Pode ser uma cilada Bino!

Pontos negativos que podem tornar numa cilada:

  • Não tem público definido. Casos de Uso são feitos para os analistas, desenvolvedores, testadores e as vezes para o usuário.
  • Casos de Uso não compilam. O usuário quer um sistema e não papéis para assinar.
  • Não traz o famoso ROI, traduzindo, retorno de investimento. Já vi muitos projetos de “anos em análise”, e no final, tinham uma bíblia inútil junto com um grande rombo nas contas.
  • Difícil de manter atualizado. É natural que as coisas mudem, e a cada mudança ter que atualizar quilos de documentos, não é prático e muito caro.
  • Pelo fato de terem um público abrangente, é consumido muito tempo com detalhes inúteis, como diagramas de “tudo”, que não ajudam em nada no desenvolvimento. Mais um item que consome tempo, recurso e muito dinheiro.

A lista pode continuar fácil, mas devemos ir para a parte que interessa:

Como corresponder a expectativa do usuário?

Vou colocar o que está dando certo para mim. Caso encontrem alguma semelhança com o capítulo 7 do Pragmatic Programmer, não estranhem, foi de lá mesmo que eu me “inspirei”.

Nada melhor do que a dica 51 (uma boa idéia!) para começar:

Don’t gather requirements — Dig for them

Numa tradução livre e tosca, colocaria assim:

Não reuna requisitos, cave-os!

  • Este negócio de “cavar”, é algo como: descobrir por que o usuário faz, e não somente como. Descobrindo o por que, você consegue sugerir maneiras diferentes de como fazer. Isso nos leva a próxima dica.
  • Lembre-se que, requisitos não são arquitetura, nem design, muito menos interface do usuário. Requisitos são necessidades!
  • Não seja escravo de nenhuma anotação. Use o melhor método que se comunica com o seu público. No meu caso, papel e caneta, com rascunhos da futura tela, já está funcionando e bem.
  • Não ter medo de sugerir novas idéias. Acredito que se dependesse da maioria dos usuários, todos os sistemas teriam cara de Excel! :D Com o porque em mente, fica mais fácil sugerir funcionalidades como filtros, layout etc.
  • Some things are better done, than described. -> Algumas coisas são melhores feitas do que descritas. Pra mim, esta dica tem funcionado com reformulação de telas, algum “filtro maluco” etc.

Sei que este post é muito “abstrato”, rápido e sem referência nenhuma, mas a idéia em si é causar uma reflexão em ti, sobre o modo que tu trabalha. Hoje, ele é prático? o cliente está satisfeito com resultado? o cliente está satisfeito com a velocidade, desde a análise a concepção? está havendo desperdício de verba?

Estas perguntas são interessantes, e sempre devem ser feitas. Por mais que o software seja problemático, se conseguirmos corresponder a expectativa do usuário, teremos mais um cliente satisfeito na carteira.

O tema Caso de Uso, é polêmico, e não quero causar flame. Pra cada ambiente, equipe, produto/projeto existe uma maneira diferente de trabalhar. O que espero evitar, são aqueles papéis inúteis, com: “se a ação teve sucesso, deve mostrar ok” … bah!

Por sinal, um dos cinco grandes erros não técnicos, cometidos por programadores (original aqui) é: Esquecer do usuário. Lembre disto! ;)

Agilidade é a buzzword do momento 3

Posted by Rodrigo Panachi on abril 22, 2009

Nos últimos anos o mercado de TI cresceu exponencialmente. Surgiram desde pequenas empresas especializadas em construir websites até monstruosas fábricas de software com seus contratos milionários. Algumas com orçamento limitado outras com dinheiro jorrando pelos canos. Umas com problemas por falta de organização outras com problemas burocráticos. Bons profissionais vs. equipes de sobrinhos, habilidade técnica contra enxurradas de documentos… muito fracasso, pouco sucesso.

A meta é coletar as moedas até conseguirmos uma estrela

Surgiram muitas empresas especializadas em desenvolver software ou que têm um software como produto principal. Normalmente, essas empresas se preocupam apenas em satisfazer os investidores e se esquecem dos clientes. Focam em vender e deixam a qualidade de lado. Prezam pela imagem e ignoram os problemas.

É uma triste realidade que essas empresas tenham mais executivos do que programadores. Como diz o Luli Radfahrer, executivos são aqueles seres que se vestem com um pensamento fracassado, usam uma linguagem própria sendo uma mistura de termos que só eles entendem e 20% de palavras em inglês… não vivem os problemas reais da empresa. É como se estivessem em outro mundo: Mario World!

O mundo dos executivos: nuvens sorrindo

A maioria das empresas que têm problemas com desenvolvimento de software ainda estão vivendo na década de 90. Internet ainda é uma palavra assustadora. Programador é apenas um funcionário que sabe o que significam siglas de informática e sabem mexer no computador. Mudança ainda é encarada como algo arriscado, que deve ser planejado, estudado e aprovado pelo presidente, diretoria e gestores. A palavra da vez é processo e seu fiel companheiro é prazo. A burocracia é uma amiga que garante que as coisas não fujam de controle. Nesse cenário não há como fugir do waterfall.

O maior problema do waterfall são os papéis: cada um com sua “especialidade”. Alguém determina que um infeliz funcionário vai ser responsável por “levantar requisitos”. Faz um cursinho de UML e começa a escrever uma quantidade sem fim de Casos de Uso sem ter noção alguma do que seu trabalho afeta no processo. Então a “equipe” começa a ter muito “retrabalho”, uma vez que os clientes não estão satisfeitos com o que está sendo entregue. Logo percebem que devem fazer o “levantamento” mais detalhado e passam a engessar ainda mais o processo com reuniões, assinaturas, etc. Conclusão: tempo e dinheiro desperdiçados e nenhum resultado satisfatório.

Seu trabalho é digitar xxx a cada 108 segundos

Meu trabalho é digitar 4 8 15 16 23 42 a cada 108 segundos

Falta de foco? Profissionais não qualificados? Processo falho? Não apenas isso: não há comunicação, não há troca de experiências. O waterfall favorece o aparecimento da síndrome do funcionário público: “eu sou gerente: eu córdeno, não preciso saber programar”. As decisões geralmente são tomadas por uma única pessoa. Os projetos seguem o modelo de construção civil. Os profissionais se acomodam pois não veem perspectiva, não conhecem o processo completo, não são ouvidos e por isso não são valorizados.

O foco destas empresas está longe de ser tecnologia. Se concentram em suas buzzwords, processos e reuniões e se esquecem do produto, ou seja, o software. Focam mais na solução do que no problema. Fazendo uma analogia, essas empresas são como um barco furado, onde está entrando água mas há pessoas com baldes para retirá-la e mantê-lo flutuando. Se a agua subir muito, contratam mais pessoas para operar os baldes. Enquanto isso, os executivos ficam acenando como se nada tivesse acontecendo. Quando perguntam se há algum problema, nenhum fdp infeliz tem coragem para falar que o problema é o furo no barco!

As empresas que focam em tecnologia e nos profissionais, tipo o Google ou a 37signals, estão se dando bem e mostrando que agilidade não é apenas mais um processo… é algo real e que funciona!

Agilidade é sair fazendo as coisas de qualquer jeito

Diante do cenário caótico das empresas, um grupo de profissionais organizou um movimento a fim de unificar as práticas bem sucedidas e tornar o processo de desenvolvimento mais produtivo e pragmático: o manifesto ágil. Quem freqüenta esse blog sabe que nós somos fãs e seguidores das práticas ágeis, não porque somos fanáticos e acreditamos somente em uma verdade absoluta, mas por que já sofremos muito com projetos e empresas fracassadas, vivenciamos os problemas que compartilhamos neste blog, passamos noites em claro corrigindo código escrito por maus profissionais, acumulamos horas em reuniões suficiente para tirarmos brevê, tivemos que negociar com cliente, com o chefe, fazer entrevista, contratar, gerenciar, analisar, programar, testar… nós sofremos os problemas do waterfall na pele!

O termo agilidade é bem popular atualmente: “precisamos agilizar nosso processo de desenvolvimento”. Como divulgação do manifesto ágil é algo muito positivo, pois mais pessoas podem conhecer e utilizar as práticas ágeis. Mas, como toda fama tem seu lado negativo, não seria diferente neste caso. Muitos profissionais “gafanhoto” estão utilizando esse termo como alavancagem profissional. Já tem gerente falando que RUP é ágil, arquiteto defensor de modelagem UML ágil, diagrama ER ágil, modelo de dados ágil, caso de uso ágil, cronograma ágil, etc. Ou seja, estão distorcendo totalmente o propósito e a filosofia da agilidade.

Como disse o Chapiewski, os programadores estão querendo ir direto para a sobremesa e esquecendo de comer seus vegetais. Agile é muito mais do que desenvolver iterativamente, fazer stand-up meetings e planejamentos ágeis. Não dá para ignorar todas as práticas de engenharia de software que realmente fazem com que a produção e mudanças em softwares sejam ágeis, sem contar todos os princípios e práticas que fazem uma diferença enorme.

O mercado que não é bobo já percebeu esse movimento migratório e lançou seus cursos de “Gerenciamento de projetos ágeis com MSProject”, “Desenvolvendo aplicações web com agilidade”, “Aprenda a programar com JUnit e TDD”. Não demorou muito para que uma massa de desenvolvedores colocasse o termo ágil em seus currículos. Pretensiosos demais em achar que um cursinho qualquer pode ensinar todo conceito e técnicas ágeis catalogadas por profissionais com décadas de experiência em desenvolvimento de software.

“Estou aprendendo Ruby on Rails por que o mercado está pagando bem“. do dia para a noite surgiram milhares de especialistas ágeis. O cara que programava em .NET ou Java no modelo tradicional (digitador de código), faz um cursinho rápido e de repente começa a desenvolver aplicações numa tecnologia que exige uma enorme bagagem conceitual. Faz tudo errado, pois não sabe realmente o que está fazendo, o projeto fracassa e ainda deixa a tecnologia com má fama. Isso aconteceu com PHP, ASP e está acontecendo com Rails.

Programar é difícil, não é um trabalho para qualquer aventureiro. É preciso estudar muito, se dedicar e principalmente, gostar! Não basta apenas estudar para conseguir uma certificação pois não garante nada. Deve-se viver a programação, participar de fóruns, contribuir com projetos open-source, discutir idéias, ser auto-crítico, ler muito, praticar, apreciar as boas práticas e abolir o que não presta…

Agilidade é propor soluções simples para os problemas

Agilidade é propor soluções simples para os problemas

Agilidade não é anarquia, não significa “sair fazendo as coisas de qualquer jeito”, dizer “não” para documentação, etc. É uma mudança de atitude, uma nova maneira de enfrentar os problemas e propor soluções simples e práticas, é ter foco, é saber fazer mais com menos, é automatizar tarefas, é estar comprometido… agilidade é atitude.

Contratamos uma consultoria para implantar Scrum

Scrum é a metodologia da moda. Assim que começou a se popularizar entre a comunidade de desenvolvedores, não demorou muito para o que vários sites e blogs se dedicassem exclusivamente na sua divulgação, apresentando benefícios, artigos, guias, exemplos, certificados para imprimir e pendurar em uma moldura na parede, etc. Logo surgiram as consultorias especializadas em adestramento treinamento e implantação de Scrum nas empresas. Um pouco de política aqui e influência ali até que a INFO Magazine publicasse uma matéria dizendo sua empresa deveria usar Scrum como solução para todos os problemas.

Mais uma vez, a falta de foco e maturidade das empresas distorcem tudo. Muitas empresas “compraram” o Scrum como a solução pronta. Bastar treinar os funcionários, comprar blocos de post-it e tudo passa a funcionar bem e gerar lucro. Pagam um curso de “gerenciamento de projetos com Scrum” para os gerentes. Depois apostam todos as fichas em um projeto “piloto”. Fazem tudo que manda o manual: reuniões diárias, planing-pocker, quadro com post-its, etc. E o projeto… fracassa!

Queimando dinheiro

Queimando dinheiro

Então quer dizer que Scrum não funciona? Foi dinheiro desperdiçado? Tanto esforço para nada? Neste caso, devo dizer que sim! Se esqueceram do processo anterior falho, funcionários pouco qualificados e dos líderes sem foco. Escolheram aqueles funcionários mais “experientes” para serem o Scrum Master. Sim, aqueles mesmos que só sabiam escrever casos de uso e diagramas UML. Se esqueceram dos valores, dos princípios, da atitude, do relacionamento com o cliente. O pensamento não mudou, o foco ainda era no processo. Depois de tanto esforço, só deram outro nome o waterfall. Não demorou muito e surgiram os papéis, artefatos, documentos… ou seja, a empresa continua cometendo os mesmos erros!

Não importa a tecnologia ou processo se não souber usá-lo corretamente! E definitivamente Scrum não pode ser encarado como mais um processo bonitinho, com seus papéis, artefatos, bla bla bla. Um processo de software que funciona é aquele onde a equipe está realmente comprometida e tem experiência acumulada para enfrentar e resolver problemas ao longo do desenvolvimento da aplicação. O processo, ou metodologia, será meramente um nome para as práticas que a equipe conhece e utiliza naturalmente.

Resumo

Não há ferramenta, metodologia ou processo que substitua a atitude e experiência de um verdadeiro desenvolvedor ágil. Estude, pratique, esteja comprometido, estude denovo, questione-se, estude novamente. Revise seu código, estude mais um pouco, e principalmente, tenha atitude! Agilidade não é metodologia, é atitude!

Remarkable, jqGrid no Rails, Heroku e Github issues

Posted by Equipe 1up4dev on abril 20, 2009

Este é o primeiro post que publicaremos semanalmente reunindo novidades sobre desenvolvimento, artigos, notícias e temas variados sobre Rails.

Remarkable 3.0

Foi lançada a nova versão do Remarkable, um framework para testes com RSpec. Dentre as novidades, estão:

  • I18n, possibilitando gerar o output das specs no seu idioma favorito fluente
  • Pending Macros, facilitando o agrupamento das specs pendentes
  • Macro stubs e mais opções de Matchers, simplificando testes com mocks

Para instalar basta um sudo gem install remarkable_rails

Saiba mais no site do Carlos Brando, lendo a documentação ou espiando o código no Github.

jqGrid no Rails

jQuery é um dos frameworks Javascript mais populares do mercado. O que esse cara fez foi juntar o jqGrid, que é um plugin muito bom para trabalhar com grids, num plugin para Rails, facilitando sua utilização.

Veja aqui um guia de utilização do plugin, a aplicação de exemplo ou confira o código no Github.

Heroku

Apesar da simplicidade do Business Bingo Generator, houve muitas “manhas” aprendidas no seu desenvolvimento. O Heroku foi uma delas, onde pudemos publicar rapidamente a aplicação. Se você quer hospedar um projeto simples feito em Rails, nós o recomendamos. O seu uso é muito simples e a incrível idéia de usar o git como interface para deploy é realmente sensacional. Basta instalar o client do Heroku, dar um “git push” e pronto: a aplicação está no ar!

Github Issue Tracker

Nova funcionalidade no GitHub para facilitar nossas vidas, permitindo informar os “bugs” nos projetos. No link acima, contém o vídeo “Introduction to GitHub Issues” para mais detalhes.

Caso já use um Issue Tracker para o seu projeto no github, você pode desabilitá-lo na seção do Features na aba Admin.

TPW – Testando sistemas legados: manipulando dependências 3

Posted by Rodrigo Panachi on fevereiro 19, 2009

Pela definição de Michael Feather, código legado é código sem testes! Não importa se o código foi escrito semana passada ou alguns anos atrás. Qualquer manutenção será de difícil entendimento por outra pessoa e não haverá garantias de seu funcionamento. Uma vez que não há “controle”, é mais difícil rastrear as alterações; pior do que uma nova funcionalidade que não funciona, é uma funcionalidade antiga que começa a falhar. Este é um risco que um desenvolvedor não pode correr!

Não altere código legado até que seja possível testá-lo

Um dos problemas mais comuns em sistemas legados é a interdependência de classes, ou seja, o alto acoplamento, que sempre está ligado com a baixa coesão. Se estes termos são difíceis de entender, pense em acoplamento como sendo o grau com que as classes referenciam umas as outras e coesão o quanto uma classe está focada em realizar suas responsabilidades.

Para que seja possível testar o comportamento de uma classe “acoplada”, o comportamento de suas dependências precisa ser simulado. Isto normalmente é feito através de objetos falsos, ou mocks, que são injetados na instância da classe em questão. Este padrão é conhecido como Inversão de Controle e Injeção de dependência, onde o controle sobre as dependências da classe são delegados à outro objeto, ou normalmente um container de objetos, responsável por injetar as dependências nas instâncias das classes. Simples, não?! Mas isso será detalhado em outro post…

Voltando para os testes, no post anterior começamos a organizar o projeto automatizando o build e centralizando a execução dos testes para evitar que fiquem “soltos” pelo código. Agora vamos nos concentrar em escrever os casos de teste, refatorando o necessário para lidar com as dependências das classes.

Partindo da premissa que o projeto não possuí nenhum framework de inversão de controle, utilizaremos um certo “padrão” que permite manipular as dependências de uma classe por meio de herança, sem alterar seu comportamento original. A idéia é resolver as dependências da classe através de getters protegidos, que podem ser sobrescritos em uma classe filha no momento do teste. Isso permite que, na classe estendida, o método sobrescrito retorne um objeto mock, por exemplo, com o comportamento esperado para o teste.

Vamos tomar como exemplo, uma classe simples com algumas dependências e responsável por encapsular algumas regras de negócio referentes à Estoque.

public class EstoqueLogic {
    public boolean verificaDisponibilidade(Produto produto, Integer quantidade) {
        EstoqueDAO dao = new EstoqueDAO();
        Estoque estoque = dao.localizaProduto(produto.getCodigo());
        return estoque.getQuantidade() >= quantidade;
    }
}

Da forma como esta classe foi escrita, é impossível testar a regra de disponibilidade independentemente, pois depende do objeto EstoqueDAO para localizar as informações necessárias para o método. Mas com um pequeno refactoring, a responsabilidade de resolver a dependência EstoqueDAO passa a ser responsabilidade da própria classe Estoque:

public class EstoqueLogic {
    public boolean verificaDisponibilidade(Produto produto, Integer quantidade) {
        EstoqueDAO dao = getEstoqueDAO();
        Estoque estoque = dao.localizaProduto(produto.getCodigo());
        return estoque.getQuantidade() >= quantidade;
    }
    protected EstoqueDAO getEstoqueDAO() {
        return new EstoqueDAO();
    }
}

Desta forma, é possível “injetar” um objeto que simule a dependência do EstoqueDAO estendendo a classe e sobrescrevendo o método getEstoqueDAO() para retornar a instância desejada. O teste ficaria mais ou menos assim:

public class EstoqueLogicTest {

    public void testVerificandoDisponibilidadeDeUmProduto() {

        //Criando o objeto EstoqueDAO mock, simulando o comportamento desejado
        final EstoqueDAO estoqueDAOMock = new EstoqueDAO() {
            @Override
            public Estoque localizaProduto(String codigo) {
                Produto produto = new Produto();
                produto.setCodigo(codigo);
                Estoque estoque = new Estoque();
                estoque.setProduto(produto);
                estoque.setQuantidade(5);
                return estoque;
            }
        };

        //Sobrescrevendo o método getEstoqueDAO para retornar o Mock
        EstoqueLogic logic = new EstoqueLogic() {
            @Override
            protected EstoqueDAO getEstoqueDAO() {
                return estoqueDAOMock;
            }
        };

        //Definindo o teste e executando
        Produto produto = new Produto();
        produto.setCodigo("123456");        

        boolean estaDisponivel = logic.verificaDisponibilidade(produto, 10);
        assertTrue(estaDisponivel);

        boolean naoEstaDisponivel = logic.verificaDisponibilidade(produto, 2);
        assertTrue(naoEstaDisponivel);
    }
}

O método getEstoqueDAO() da classe EstoqueLogic foi sobrescrito para retornar o objeto estoqueDAOMock com as informações necessárias para o teste, ou seja, o comportamento das dependências foi simulado, possibilitando que o teste ficasse concentrado apenas da classe Estoque.

Elimine as dependências e teste onde os bugs estão!

Este padrão fornece apenas uma maneira de lidar com as dependências das classes para escrever testes. A dica aqui é manter o foco: defina apenas testes para as funcionalidades que estiver alterando e que exercitem pontos críticos e/ou regras de negócio. Então, refatore apenas as classes necessárias para simular e validar o fluxo destes testes, nem que seja apenas seus “contratos“. Não há necessidade de escrever testes muito granulares nem alterar todas as classes de um sistema legado.

No caso de classes com muitas dependências, o melhor é refatorá-la, separar as responsabilidades e testá-las individualmente. Para classes com dependências de Utils e/ou muitas chamadas à métodos estáticos, uma estratégia parecida pode ser utilizada. Mas estes são assuntos para os próximos posts. Acompanhem!

TPW – Testando sistemas legados: automatizando o build 2

Posted by Rodrigo Panachi on fevereiro 11, 2009

Imagine o cenário: você caiu de para-quedas naquele projeto que todo mundo na empresa fez gambiarra deu manutenção e agora precisa implementar uma nova funcionalidade. Mesmo que tenha alguma documentação, vai ser inútil neste caso. Então você começa a vasculhar o código e encontra dezenas de classes com nomes parecidos, vários arquivos XML’s dos inúmeros frameworks utilizados anteriormente, TO’s, VO’s, Actions, Utils… ou seja, um lugar cheio de janelas quebradas.

O mais fácil neste caso seria fazer seu trabalho, quebrando mais algumas janelas caso necessário, e cair fora o quanto antes. Mas você, desenvolvedor ágil, sabe que além de ser falta de profissionalismo, você corre o risco de cair novamente no mesmo projeto. Então aproveite a oportunidade para fazer uma pequena faxina e preparar o projeto para escrever os testes das novas funcionalidades que irá desenvolver, garantido assim a qualidade, pelo menos, do seu trabalho.

Durante minha carreira fui obrigado tive a oportunidade de dar manutenção em diversos projetos “frankenstein” de onde adquiri certa experiência para poder “organizar a casa” e trabalhar decentemente no código. É claro que não estou falando em escrever testes para o projeto inteiro, mas pelo menos garantir a qualidade do código que desenvolvi ou irei desenvolver.

Há um certo padrão que todo software de qualidade deve seguir. Além dos padrões e boas práticas como organização do código em pacotes vs. responsabilidade, uma coisa essencial para o projeto é sua construção, ou seja, a forma que o software é “entregue”. Acredito que este seja o primeiro passo para começar a organizar a bagunça de um projeto.

A construção do projeto deve ser automática e desempenhada por uma ferramenta de build como o Ant ou Maven, com tarefas (tasks) e objetivos bem definidos. Normalmente, um build do projeto deve:

  1. Preparar o código e dependências
  2. Compilar os arquivos fontes
  3. Executar os testes
  4. Empacotar a distribuição

No exemplo abaixo usarei o Ant, que é a ferramenta de build (para Java) mais popular do mercado e muito simples de utilizar. O importante neste processo é ser pragmático: não perca o foco! Você poderia (e futuramente deveria) utilizar o Maven, mas adequá-lo a um sistema legado não é tão simples quanto parece.

Tendo os objetivos do build definidos, basta escrever o script do Ant. Isso deve ser feito no arquivo build.xml, no root do projeto. As tarefas são definidas pelas tags <target> e podem ser dependentes para garantir a sequencia de execução. Em cada target são definidas as ações executadas, como rodar o compilador (javac), copiar um arquivo, rodar os testes, etc. Uma vez que as tarefas estão configuradas, basta executar o build pelo próprio IDE ou linha de comando.

<project name="frank" default="package">
    <path id="classpath">
        <pathelement location="build/bin"/>
        <fileset dir="src">
            <include name="*.java"/>
        </fileset>
        <fileset dir="lib">
            <include name="*.jar"/>
        </fileset>
    </path>
    <target name="clean">
         <delete dir="build"/>
          <mkdir dir="build"/>
    </target>
    <target name="compile" depends="clean">
        <javac srcdir="src" destdir="build">
            <classpath refid="classpath"/>
        </javac>
    </target>
    <target name="test" depends="compile">
        <junit>
            <classpath refid="classpath"/>
            <batchtest>
                <fileset dir="build" includes="*Test"/>
            </batchtest>
        </junit>
    </target>
    <target name="package" depends="compile, test">
        <war destfile="frank.war" webxml="web/WEB-INF/web.xml">
        <classes dir="build"/>
    </target>
</project>

Neste script estão definidas as tarefas necessárias para executar um build, conforme citei anteriormente. Por enquanto isto será o mínimo necessário para dar suporte as próximas etapas da sua missão. Mesmo que o projeto já tenha um build em Ant aproveite para revisá-lo. Tarefas bem simples e bem definidas são mais fáceis de entender e manter.

Com o build implementado, você não terá mais que se preocupar com o empacotamento do projeto. Agora comece a direcionar seus esforços para escrever os testes. Deixe que o Ant se encarregará de executá-los para você.

No próximo post vou apresentar alguns padrões e práticas de refactoring utilizados para possibilitar escrever testes que dependem de classes legadas do projeto.