Código legado. O Horror!!

Cthulhu

Cthulhu

Existem, na comunidade, várias definições para o que seria código legado: todo código que você escreveu é legado; o código que outra pessoa escreveu é legado; o código ruim, de difícil manutenção é legado. Não importando a definição, podemos identificar uma característica primordial, o código legado é aquele difícil de mudar. E isso, geralmente é um terror para os desenvolvedores.

Quem escreveu o código, não necessariamente é um desenvolvedor ruim. Precisamos entender o contexto. Mas gosto da idéia de que a qualidade do código é um espelho do local onde ele foi desenvolvido. Se o código é ruim, a empresa pode apresentar sintomas graves de uma péssima gestão, principalmente em se tratando de comunicação inter-departamentos, já que normalmente as demandas não vem de TI. Nesse cenário, será bem difícil trabalhar em melhorias do código legado, enquanto não houver melhorias nos processos internos da empresa e um alinhamento de negócios com TI. Mas, ainda assim, agente tenta.

Já tive a oportunidade de trabalhar em muitos projetos legados. Sei que você também tem muita história pra contar a respeito de suas aventuras nas matas densas do legado. Você irá achar que, a partir daqui, eu estarei exagerando e querendo causar polêmica, mas não, o que vou contar é a mais pura verdade. Já trabalhei com código que dava vontade de vomitar só de olhar pra ele. hahaha. Não é pra tanto, mas já chegou perto disso.

Trabalhei em projetos legados bem complexos e com uma base de código bem ‘doente’, normalmente monstros monolíticos. Mas apesar disso, os softwares eram, e são até hoje, bastante elogiados. Assim como para seres humanos o que importa é o caráter e não a aparência, para software o que importa é o valor que ele entrega ao cliente. Mas isso é só um lado da moeda. Aqueles sistemas tão elogiados de que falei faziam bem o seu trabalho, mas apresentavam uma base de código extremamente difícil de gerenciar, o que dificultava a criação de novas funcionalidades e melhorias.

Outro fator que considero importante em um cenário como esse é a satisfação com o seu trabalho. É bem ruim ter que trabalhar todo dia fazendo remendos em uma estrutura ‘capenga’. É desmotivante, é cansativo e isso pode aumentar a rotatividade em sua empresa. E a alta rotatividade de desenvolvedores é um fator que contribui a gerar mais código ruim. É extremamente frustrante quando, devido a algum fator, ou vários fatores, não é possível melhorar a base de código.

Você pode achar que isso tudo é muito mimimi. Mas que fique claro que o maior prejudicado nessa história é a empresa que mantém o código. Se não for possível fazer melhorias, a empresa terá que conviver com os custos de se manter um legado ruim. A escolha é sua, ficar no mimimi ou partir pro ataque.

Enfrentando o monstro

Uma outra definição para sistemas legados, e essa foi a que mais gostei, nos diz que sistema legado é todo sistema que não está coberto por uma suíte de testes, ou seja, você estará construindo código legado toda vez que você escreve código sem testes. Interessante. Então fica a dica: sempre que for refatorar, escreva um teste, se bem que refatorar sem testar não faz sentido. Mas quando se tem uma base de código muito grande e complexa, isso não é tão fácil. Além disso, você irá encontrar no legado muitos recursos que nem são utilizados. Puro lixo.

O código legado tem a característica de ser bastante acoplado. Então uma forma de começar a refatoração é isolando as dependências e trabalhar em cima delas. Inicialmente pode ser inviável criar testes de unidade, mas é possível criar testes de aceitação e isso pode ser um bom começo.

Outra forma seria o que Martin Fowler chama de estrangular a aplicação. Você vai criando um novo sistema nas bordas do antigo, muitas vezes de forma transparente ao usuário. Não é uma tarefa tão simples, principalmente se precisar rever a modelagem do banco de dados. É um processo bastante demorado e pode durar anos, mas é eficaz. É importante estar alinhado com a gerência e que ela saiba o que você está fazendo, mas algumas vezes é mais fácil pedir perdão do que permissão, essa é a verdade.

Um outro cenário é reescrever tudo. Isso pode ser possível, mas tem que ser analisado com cautela. Dependendo do contexto pode ser a melhor solução, ou pode ser catastrófico. Tive a experiência de trabalhar num sistema legado que estava até bem escrito. O problema é que ele havia sido desenvolvido com um framework caseiro que possuia geradores de código e o dono não estava mais na empresa. Não havia muito o que fazer. Resolvemos reescrever tudo com um novo framework que estávamos testando na época (um framework bastante conhecido e usado pela comunidade). Um fator que ajudou bastante é que a modelagem de dados do sistema legado estava impecável, então reaproveitamos o banco.

Uma dica final é sempre seguir padrões. Estar atento ao que a comunidade recomenda e participar de eventos é importante. Você pode estar sendo o vilão escrevendo o legado de amanhã. Poupe sua mãe de xingamentos. Lembre-se que o código não é seu, mesmo que você o tenha escrito.

referências:

Michael Feathers, Working Effectively with Legacy Code, Prentice Hall, 2005.

Martin Fowler, “StranglerApplication”, http://www.martinfowler.com/bliki/StranglerApplication.html.

Mary e Tom Poppendieck, Implementando o Desenvolvimento Lean de Software

Criando abstrações com repositórios

Ainda hoje vejo muita gente utilizando o padrão DAO em novos projetos, mesmo usando novas tecnologias de persistência como Hibernate e JPA. Não vou entrar em discussões sobre o padrão DAO estar morto ou não. O fato é que em projetos legados, principalmente os que usam JDBC, o DAO está bem vivo. Mas e em projetos que usam ORM? É necessário usar DAOs e os famosos DAOs Genéricos?

Usar DAOs, hoje, pode ser algo extremamente redundante. Pois as ferramentas de ORM já implementam o padrão DAO. Por que você implementaria novamente? Mas, claro, mesmo em projetos novos, pode ser que apareça o cenário para se utilizar o DAO. É uma decisão de design que não deve se basear em senso comum. Projetar software não é uma tarefa trivial, porém, muitos ainda se baseiam em receitas de bolo e não param para trabalhar no design da aplicação. Mas nós aprendemos a criar DAOs na camada de persistência. Como fazer de outra maneira?

Lembre-se que o DAO existe para abstrair a camada de persistência e criar uma interface para o acesso aos dados. Hoje isso já está pronto e quem o faz é a ferramenta de ORM. Em determinados cenários não vejo problema em injetar o EntityManager do JPA direto no Controller. Algumas vezes não existe motivo para se criar uma camada desnecessária. No entanto, é mais usual que tenhamos que fazer consultas usando HQL ou JPA QL, ou que seja necessário o controle manual de  transações. Esse tipo de coisa jamais deve ficar na camada de aplicação. Existe uma forma mais elegante de abstrair a camada de persistência. Criando repositórios.

Repository é um conceito do Domain Drive Design. A camada de domínio de uma aplicação é onde se encontram as regras de negócio, logo, o que ocorre nessa camada está na ‘boca do povo’, ou seja, está nos brainstorms, reuniões de levantamento de requisitos, e nas conversas entre desenvolvedores e pessoal de negócios. A camada de domínio precisa ser escrita no que chamamos de linguagem ubíquoa, a linguagem comum entre devs e negócios.

O que normalmente encontramos dentro de controllers é algo assim:


BookDao dao = new BookDAO();
Book book = dao.findById(id);

Primeiro, se estivermos usando ORM, o DAO é desnecessário. Segundo, é feio de ler. Não tem nada a ver com uma liguagem de domínio. É muito comum as pessoas somente trocarem o nome DAO por Repository e modificar a interface método.

/**

*/
public class BookRepository {

  public final EntityManager entityManager;

  public BookRepository(EntityManager entityManager){
    this.entityManager = entityManager;
  }

  public void add(Book book){
    this.entityManager.merge(book);
  }

  public Book findBook(String id){
    return this.entityManager.find(Book.class, id);
  }

}

A chamada fica assim:

  BookRepository bookRepository = new BookRepository();
  Book book = bookRepository.findBook(id);

Bem melhor, mas ainda temos alguns problemas. Muitos desenvolvedores costumam usar o termo repository no nome das classes, assim como fazem com o dao. Devemos usar nomes significativos para nossas classes, métodos e variáveis, principalmente em se tratando de classes de domínio. Que tal se mudarmos o nome da nossa classe para Library?

  Library library = new Library();
  Book book = library.findBook(id);

Uma coleção de livros, geralmente é uma biblioteca, não é verdade? Mas ainda há um problema. O alto acoplamento com a implementação do repositório. Em se tratando de uma classe de repositório, ela poderá ser usada em vários locais, tanto em controllers, quanto em classes de serviços e até mesmo por classes de modelo. Mesmo usando injeção de dependência, ainda ficamos acoplados com a camada de persistência. Então podemos criar uma interface.


public interface Library{

  void add(Book book);

  List<Book> allBooks();

  Book findBook(String id);

}

E fazemos com que a classe repository implemente a interface Library.


public class BookRepository implements Library {

  public final EntityManager entityManager;

  public BookRepository(EntityManager entityManager){
    this.entityManager = entityManager;
  }

  public void add(Book book){
    this.entityManager.merge(book);
  }

  public List<Book> allBooks(){
    return this.entityManager.createQuery("select b from Book b", Book.class).getResultList();
  }

  public Book findBook(String id){
    return this.entityManager.find(Book.class, id);
  }

}

Agora através de injeção de dependência, as classes podem receber a interface Library como dependência, e não mais depender de sua implementação. Podemos criar uma camada de persistência e inserir as classes *Repository nela enquanto que as interfaces ficam na camada de domínio. Em Domain Drive Design, as classes que implementam a persistência localizam-se na camada de infraestrutura enquanto que as interfaces dos repositórios podem ficar no mesmo pacote dos modelos, na camada de domínio.

Baixe aqui, um exemplo de aplicação modelada com DDD.

#mobileEmAcao 2014

ArteSafo2

O Mobile em Ação é um evento que foi criado com intuito de reunir pessoas interessadas em desenvolvimento para plataformas móveis, focando em utilizar a tecnologia para um bem social.

No primeiro dia, terão apresentações introdutórias sobre cada plataforma e a dinâmica do evento. Traga seu notebook, pois ensinaremos como configurar cada ambiente. Já no segundo dia, serão formados times para resolverem desafios ligados ao tema: “Problemas Sociais”. Durante isso, haverão coaches disponíveis para ajudarem na ideia e na tecnologia escolhida.

Ao término, cada time apresentará o que foi desenvolvido ao longo do evento. Logo em seguida, haverá uma retrospectiva sobre o evento e happy hour para comemorar!

São apenas 20 vagas!

Investimento: R$ 20,00

Garanta já a sua participação clicando no link para inscrição.

7 anos de Tá Safo

A comunidade Tá Safo vem demonstrando, através de ações, que em qualquer tipo de empreendimento, o fator decisivo são as pessoas. 7 anos se passaram desde o primeiro encontro da comunidade e nesse percurso fizemos muitos amigos por todo o Brasil, participando de eventos, compartilhando idéias fomentando a cultura de colaboração que é o carro chefe desse momento em que vivemos no Brasil e no mundo. O momento de transformar ideias em ações concretas de forma colaborativa.

Mesmo depois de 7 anos, ainda nos perguntam: como participar do Tá Safo? E a resposta pode parecer simples, mas, realmente, não é. Pois para participar do Tá Safo, é preciso quebrar regras, quebrar paradigmas, sair da zona de conforto. É preciso se expor, não ter medo de parecer bobo. Não ter medo de errar e saber que a falha é medida primária de progresso. É preciso saber disseminar informação, compartilhar conhecimento. É preciso conhecer pessoas. Entender que tecnologia é um meio e não um fim. Saber compreender as diferenças. É preciso querer mudar o mundo.

Por isso, talvez não seja fácil participar do Tá Safo. Mas queremos muito que você participe dessa jornada conosco. “Porque aqueles que são loucos o suficiente para achar que podem mudar o mundo, são as que de fato, mudam.

The crazy ones. Citação do famoso comercial da Apple  de 1997.

“Isto é para os loucos. Os desajustados. Os rebeldes. Os criadores de caso. Os que são peças redondas nos buracos quadrados. Os que vêem as coisas de forma diferente. Eles não gostam de regras. E eles não têm nenhum respeito pelo status quo. Você pode citá-los, discordá-los, glorificá-los ou difamá-los. A única coisa que você não pode fazer é ignorá-los. Porque eles mudam as coisas. Eles inventam. Eles imaginam. Eles curam. Eles exploram. Eles criam. Eles inspiram. Eles empurram a raça humana para frente. Talvez eles tenham que ser loucos. Como você pode olhar para uma tela em branco e ver uma obra de arte? Ou sentar em silêncio e ouvir uma música jamais composta? Ou olhar para um planeta vermelho e ver um laboratório sobre rodas?

Enquanto alguns os vêem como loucos, nós vemos gênios. Porque aqueles que são loucos o suficiente para achar que podem mudar o mundo, são os que de fato, mudam.”

Parabéns a Comunidade Tá Safo!

Rails para desenvolvimento de produtos

Não é novidade que RubyOnRails, hoje conhecido somente como Rails, tomou de assalto o mundo do desenvolvimento web. Sendo uma verdadeiro canivete suíço para o desenvolvedor full stack, Rails, aliado a simplicidade da linguagem Ruby, tornou-se referência para desenvolvimento de apps de maneira rápida e com qualidade. Não é a toa que o Rails é tão utilizado em startups. Neste post, vamos entender o porquê.

Ferramentas de linha de comando

Infelizmente, ainda temos pessoas com a mentalidade de que a linha de comando é algo ultrapassado, quando, na verdade, esta mentalidade é que é ultrapassada. A tela preta, ou branca se você usa mac :p, é uma ferramenta que pode nos proporcionar uma grande produtividade.

Como disse acima, o rails é um canivete suíço. Dentro dele, podemos encontrar algumas ferramentas que serão importantes durante o ciclo de desenvolvimento. O Rake é um software de gerenciamento de tarefas similar ao Make do Unix. Ele irá nos auxiliar na automatização de tarefas. Aquelas tarefas chatas, como executar migrações de banco agora poderão ser executadas de maneira mais ágil. Ele já vem com algumas tasks pré-definidas, mas também é possível criar as próprias tasks. Pra quem usa banco de dados relacional, é uma mão na roda. O rake foi criado pelo saudoso Jim Weirich, falecido recentemente.

tarefas pré-definidas

tarefas pré-definidas do rake

O Bundler é outra ferramenta de linha de comando que vem com o rails. Sua função é gerenciar as dependências do projeto. Não gosto de fazer essa comparação, mas pra quem vem do java, seria similar ao Maven. Sim, o rails possui dependências. Bibliotecas, que no universo ruby são conhecidas como gems. O Bundler gerencia essas gems que ficam definidas em um arquivo na raiz do projeto chamado Gemfile. Através dele, podemos ter controle sobre versões, instalação e atualizações das gems, organizando-as de acordo com o environment,  promovendo um ambiente mais consistente.

 

Gemfile

Gemfile

Com o comando rails server ou simplesmente rails s, o rails executa seu servidor embutido WEBrick. Uma maneira simples de rodar a aplicação em ambiente de desenvolvimento.

rails server

rails server

Assets Pipeline

Esta é uma das ferramentas mais poderosas para a produtividade  do desenvolvedor web, existente na atualidade. Ela, na verdade, é um conjunto de bibliotecas voltadas para resolver a questão dos assets nos projetos rails. Com a necessidade de se criar apps que proporcionam a melhor experiência possível ao usuário, não é novidade que abusamos de arquivos css, imagens e plugins do jquery. Logo é uma boa prática, minificar esses arquivos, para melhorar o carregamento das páginas e evitar requests desnecessárias ao servidor. Mesmo hoje em dia, ainda encontramos sites e web  apps que carregam tudo sem mificar. Esse é justamente o problema que o assets pipeline veio resolver com o comando: bundle exec rake assets:precompile.

Após a execução, o rails calcula o digest MDi do arquivo e adiciona ao nome do arquivo ficando assim application-e049a640704156e412f6ee79daabc7f6.css. Esse nome depende do conteúdo do arquivo, logo quando uma nova versão do asset for gerada, o nome irá mudar fazendo com que o cache do navegador não seja acionado, resolvendo o famigerado problema de o usuário ter de limpar o cache cada vez que tiver uma atualização nos arquivos estáticos.

Além de minificar, o assets pipeline compacta os arquivos no formato gzip, o que significa um arquivo com tamanho em bytes muito menor, se o servidor web aceitar o formato, claro. Hoje já existem ferramentas ótimas que auxiliam o desenvolvedor front-end como o Yeoman, mas em se tratando de rails, o assets pipeline ainda é uma excelente opção.

RubyGems

A comunidade ruby é extremamente ativa e moldada pela filosofia open source. A infinidade de gems existentes é um absurdo. Essas bibliotecas se tornaram grandes aliadas na produtividade do desenvolvedor. Para todo problema que você pensar, é possível que alguém já tenha criado uma gem. Existem algumas que considero tops e merecem uma atenção extra.

O Devise é uma biblioteca que resolve o problema da autenticação no rails. Autenticação é algo que, quase sempre, é uma implementação repetitiva, ou seja, para todo app que você fizer, a implementação será a mesma. O que considero até uma tarefa meio chata e que não tem valor agregado. O Devise nos proporciona implementar uma autenticação robusta de forma fácil e rápida. Ele possui encripitação por Bcrypt, suporte a Omniauth, confirmação por email, recuperar senha, track através de contador, timestamp e ip, suporte a internacionalização, entre outras coisas. Ele gera automaticamente as views com os formulários, nos poupando de uma tarefa meio ‘sacal’, com pouquíssimas etapas de configuração.

O Simple Form é uma ferramenta que nos fornece helpers com componentes para a criação de formulários de forma simples e rápida. O rails já vem, por default, com helpers de formulário. Eles nos auxiliam a criar formulários com código ruby, sem os div hell, tornando o código mais legível. O Simple Form nos proporciona uma DSL mais elegante, e componentes mais semânticos. Ele possui integração com o Twitter bootstrap e com o Foundation, nos possibilita criar formulários estilizados sem tocar em nenhum css.

Abaixo um exemplo de formulário html puro utilizando twitter bootstrap:


<form accept-charset="UTF-8" action="/articles/6" class="simple_form form-horizontal" id="edit_article_6" method="post" novalidate="novalidate">

  <legend>Article</legend>
  <div class="control-group string required article_name">
  	<label class="string required control-label" for="article_name">
  		<abbr title="required">*</abbr> Name
  	</label>
  	<div class="controls">
  		<input class="string required span6" id="article_name" name="article[name]" type="text" value="SimpleForm 2.0" />
  		<p class="help-block">add your article title here</p>
  	</div>
  </div>

  <div class="control-group string required article_name">
  	<div class="controls">
  		<div class="input-prepend">
    		<span class="add-on">Name</span>
    		<input class="string required" id="article_name" maxlength="255" name="article[name]" size="255" type="text" value="SimpleForm 2.0" />
			</div>
		</div>
	</div>

  <div class="control-group boolean optional article_published">
  	<label class="boolean optional control-label" for="article_published">
  		Published
  	</label>
  	<div class="controls">
  		<input name="article[published]" type="hidden" value="0" />
  		<label class="checkbox">
  			<input class="boolean optional" id="article_published" name="article[published]" type="checkbox" value="1" />
  		</label>
  	</div>
  </div>

  <div class="control-group check_boxes optional article_content_type">
  	<label class="check_boxes optional control-label">
  		Stacked checkboxes
  	</label>
  	<div class="controls">
  		<label class="checkbox">
  			<input class="check_boxes optional" id="article_content_type_blog" name="article[content_type][]" type="checkbox" value="Blog" />
  			Blog
  		</label>
  		<label class="checkbox">
  			<input class="check_boxes optional" id="article_content_type_editorial" name="article[content_type][]" type="checkbox" value="Editorial" />
  			Editorial
  		</label>
  		<label class="checkbox">
  			<input class="check_boxes optional" id="article_content_type_announce" name="article[content_type][]" type="checkbox" value="Announce" />
  			Announce
  		</label>
  		<label class="checkbox">
  			<input class="check_boxes optional" id="article_content_type_advertisement" name="article[content_type][]" type="checkbox" value="Advertisement" />
  			Advertisement
  		</label>
  		<input name="article[content_type][]" type="hidden" value="" />
  	</div>
  </div>

  <div class="control-group check_boxes optional article_content_type">
  	<label class="check_boxes optional control-label">
  		Inline checkboxes
  	</label>
  	<div class="controls">
  		<label class="checkbox inline">
  			<input class="check_boxes optional" id="article_content_type_blog" name="article[content_type][]" type="checkbox" value="Blog" />
  			Blog
  		</label>
  		<label class="checkbox inline">
  			<input class="check_boxes optional" id="article_content_type_editorial" name="article[content_type][]" type="checkbox" value="Editorial" />
  			Editorial
  		</label>
  		<label class="checkbox inline">
  			<input class="check_boxes optional" id="article_content_type_announce" name="article[content_type][]" type="checkbox" value="Announce" />
  			Announce
  		</label>
  		<label class="checkbox inline">
  			<input class="check_boxes optional" id="article_content_type_advertisement" name="article[content_type][]" type="checkbox" value="Advertisement" />
  			Advertisement
  		</label>
  		<input name="article[content_type][]" type="hidden" value="" />
  	</div>
  </div>

  <div class="control-group radio_buttons optional article_content_type">
  	<label class="radio_buttons optional control-label">
  		Stacked radios
  	</label>
  	<div class="controls">
  		<label class="radio">
  			<input class="radio_buttons optional" id="article_content_type_blog" name="article[content_type]" type="radio" value="Blog" />
  			Blog
  		</label>
  		<label class="radio">
  			<input class="radio_buttons optional" id="article_content_type_editorial" name="article[content_type]" type="radio" value="Editorial" />
  			Editorial
  		</label>
  		<label class="radio">
  			<input class="radio_buttons optional" id="article_content_type_announce" name="article[content_type]" type="radio" value="Announce" />
  			Announce
  		</label>
  		<label class="radio">
  			<input class="radio_buttons optional" id="article_content_type_advertisement" name="article[content_type]" type="radio" value="Advertisement" />
  			Advertisement
  		</label>
  	</div>
  </div>

  <div class="control-group radio_buttons optional article_content_type">
  	<label class="radio_buttons optional control-label">
  		Inline radios
  	</label>
  	<div class="controls">
  		<label class="radio inline">
  			<input class="radio_buttons optional" id="article_content_type_blog" name="article[content_type]" type="radio" value="Blog" />
  			Blog
  		</label>
  		<label class="radio inline">
  			<input class="radio_buttons optional" id="article_content_type_editorial" name="article[content_type]" type="radio" value="Editorial" />
  			Editorial
  		</label>
  		<label class="radio inline">
  			<input class="radio_buttons optional" id="article_content_type_announce" name="article[content_type]" type="radio" value="Announce" />
  			Announce
  		</label>
  		<label class="radio inline">
  			<input class="radio_buttons optional" id="article_content_type_advertisement" name="article[content_type]" type="radio" value="Advertisement" />
  			Advertisement
  		</label>
  	</div>
  </div>

  <div class="control-group select optional article_content_type">
  	<label class="select optional control-label" for="article_content_type">
  		Content type
  	</label>
  	<div class="controls">
  		<input name="article[content_type][]" type="hidden" value="" />
  		<select class="select optional" id="article_content_type" multiple="multiple" name="article[content_type][]">
  			<option value="Blog">Blog</option>
				<option value="Editorial">Editorial</option>
				<option value="Announce">Announce</option>
				<option value="Advertisement">Advertisement</option>
			</select>
			<p class="help-block">multiple select</p>
		</div>
	</div>

  <div class="control-group select optional article_category">
  	<label class="select optional control-label" for="article_category">
  		Category
  	</label>
  	<div class="controls">
  		<select class="select optional" id="article_category" name="article[category]">
  			<option value=""></option>
				<option value="Blog">Blog</option>
				<option value="Editorial">Editorial</option>
				<option value="Announce">Announce</option>
				<option value="Advertisement">Advertisement</option>
			</select>
			<p class="help-block">simple select box</p>
		</div>
	</div>

  <div class="control-group text optional article_content">
  	<label class="text optional control-label" for="article_content">
  		Content
  	</label>
  	<div class="controls">
  		<textarea class="text optional span6" id="article_content" name="article[content]">
			</textarea>
		</div>
	</div>

  <div class="control-group string optional disabled article_disabled_text">
  	<label class="string optional control-label" for="article_disabled_text">
  		Disabled text
  	</label>
  	<div class="controls">
  		<input class="string optional disabled" disabled="disabled" id="article_disabled_text" name="article[disabled_text]" type="text" />
  		<p class="help-block">an example of disabled input</p>
  	</div>
	</div>

  <div class="control-group string optional article_disabled_text">
  	<label class="string optional control-label" for="article_disabled_text">Disabled text</label>
  	<div class="controls">
	  	<div class="input-prepend">
		    <span class="add-on">
		      <input id="remove" name="remove" type="checkbox" value="true" />
				</span>
				<input class="string optional disabled" disabled="disabled" id="article_disabled_text" maxlength="255" name="article[disabled_text]" size="255" type="text" />
			</div>
			<span class="help-block">This is the hint text</span>
		</div>
	</div>

  <div class="control-group string optional article_disabled_text">
  	<label class="string optional control-label" for="article_disabled_text">
  		Disabled text
  	</label>
  	<div class="controls">
	  	<div class="input-append">
		    <input class="string optional disabled mini" disabled="disabled" id="article_disabled_text" maxlength="255" name="article[disabled_text]" size="255" type="text" />
		    <span class="add-on active">
		      <input id="remove" name="remove" type="checkbox" value="true" />
				</span>
			</div>
			<span class="help-block">This is the hint text</span>
		</div>
	</div>

  <div class="form-actions">
    <input class="btn btn-primary" name="commit" type="submit" value="Update Article" />
    <input class="btn btn-danger" name="commit" type="reset" value="Cancel" />
  </div>

</form>

E agora, o mesmo formulário com código ruby com Simple Form:


<% simple_form_for(@article, :html => { :class => 'form-horizontal' }) do |f| %>

<%= f.input :name, :input_html => { :class => "span6" }, :hint => "add your article title here" %>

<%= f.input :name, :wrapper => :prepend, :label => false do %>
    <%= content_tag :span, "Name", :class => "add-on" %>
    <%= f.input_field :name %>
<% end %>

<%= f.input :published, :as => :boolean %>

<%= f.input :content_type, :collection => content_type_options, :as => :check_boxes, :label => 'Stacked checkboxes' %>

<%= f.input :content_type, :collection => content_type_options, :as => :check_boxes, :item_wrapper_class => 'inline', :label => 'Inline checkboxes' %>

<%= f.input :content_type, :collection => content_type_options, :as => :radio_buttons, :label => 'Stacked radios' %>

<%= f.input :content_type, :collection => content_type_options, :as => :radio_buttons, :item_wrapper_class => 'inline', :label => 'Inline radios' %>

<%= f.input :content_type, :collection => content_type_options,
              :hint => "multiple select", :input_html => { :multiple => true } %>

<%= f.input :category, :collection => content_type_options,
              :hint => "simple select box" %>

<%= f.input :content, :input_html => { :class => "span6" } %>

<%= f.input :disabled_text, :disabled => true,
              :hint => "an example of disabled input" %>

<%= f.input :disabled_text, :wrapper => :prepend, :hint => 'This is the hint text' do %>
	<%= content_tag :span, :class => "add-on" do %>
	  <%= check_box_tag :remove, 'true' %>
	<% end %>
	<%= f.input_field :disabled_text, :disabled => true %>
<% end %>   

<div class="form-actions">
	<%= f.button :submit, :class => 'btn-primary' %>
	<%= submit_tag 'Cancel', :type => :reset, :class => "btn btn-danger" %>
</div>                                       

Existem outras gems muito utilizadas: paperclip, uma solução simples para upload de arquivos; resque para se criar background jobs; omniauth, autenticador multi-provider; Rspec, suite de testes automatizados; Capybara ajuda a criar testes automatizados que rodam no navegador e muitas outras. O próprio rails é uma gem.

RestFul

Dependendo do cenário, quando no início do projeto vem a dúvida de fazer ou não mobile first. Hoje, a web mobile ainda possui certas limitações, como performance, usabilidade e acesso a dispositivos do smartphone. Nesse caso, normalmente opta-se por apps nativos. No entanto, mesmo apps nativos se comunicam com recursos externos. Se não houver necessidade de um módulo web, o rails talvez não seja a melhor solução. Um cenário mais conhecido é apps web tendo necessidade de uma versão mobile.

É considerado uma boa prática expor uma interface restful que poderá ser acessada por um eventual aplicativo mobile ou desktop. Criar rotas restful no rails é muito simples. Basta utilizar o método resources no arquivo config/routes.rb.

 

routes.rb

routes.rb

Com o comando rake routes é possível visualizar as rotas criadas:

rake routes

rake routes

Exemplo de controller restful:


class ProductsController < ApplicationController
  before_action :set_product, only: [:show, :edit, :update, :destroy]

  # GET /products
  # GET /products.json
  def index
    @products = Product.all
  end

  # GET /products/1
  # GET /products/1.json
  def show
  end

  # GET /products/new
  def new
    @product = Product.new
  end

  # GET /products/1/edit
  def edit
  end

  # POST /products
  # POST /products.json
  def create
    @product = Product.new(product_params)

    respond_to do |format|
      if @product.save
        format.html { redirect_to @product, notice: 'Product was successfully created.' }
        format.json { render :show, status: :created, location: @product }
      else
        format.html { render :new }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /products/1
  # PATCH/PUT /products/1.json
  def update
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to @product, notice: 'Product was successfully updated.' }
        format.json { render :show, status: :ok, location: @product }
      else
        format.html { render :edit }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  # DELETE /products/1.json
  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to products_url }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def product_params
      params.require(:product).permit(:name, :price, :category)
    end
end

Controllers restful também são muito úteis quando usamos algum framework javascript para single-page applications como AngularJs ou Backbone.js.

Testes automatizados

No vocabulário de startups existe um termo conhecido como “pivotar” que nada mais é quando o empreendedor decide mudar o plano de negócios depois de ter testado uma estratégia e não ter obtido os resultados esperados. E em se tratando de produtos web, muitas vezes há a necessidade de realizar mudanças no modelo de domínio da aplicação. Agora, imagine não possuir testes automatizados em um cenário como este. Seria catastrófico.

A comunidade ruby, é muito exigente nesse aspecto. É preciso ter cobertura de testes. Tanto que o rails vem com uma suite de testes embutida, o minitest. Apesar disso, muitos desenvolvedores preferem adotar uma suite de testes externa e mais robusta, o Rspec. A api do Rspec nos fornece uma DSL simples e elegante para BDD (Behaviour-Driven Development). Logo, além de uma cobertura de testes, ele nos fornece uma documentação da nossa aplicação sempre atualizada.

Abaixo, um exemplo de teste de model com rspec:


require "spec_helper"

describe User do
  it "orders by last name" do
    lindeman = User.create!(first_name: "Andy", last_name: "Lindeman")
    chelimsky = User.create!(first_name: "David", last_name: "Chelimsky")

    expect(User.ordered_by_last_name).to eq([chelimsky, lindeman])
  end
end

A linha 8 é a assertiva. Repare como é fácil entender o código.

Conclusão

Essa foi uma abordagem bem superficial. É claro que o rails possui muito mais recursos. Sem dúvida é uma excelente ferramenta que ajuda a resolver problemas de maneira prática e elegante, possui uma comunidade muito ativa, com excelentes profissionais que prezam pela qualidade e boas práticas.

referências:

http://guides.rubyonrails.org/

http://www.akitaonrails.com/2012/07/01/asset-pipeline-para-iniciantes

 

Tá safo! no Startup Weekend Belém

topo_site_swbelem1-1024x327Olá, moçada! Para quem ainda não está sabendo, no mês de Abril acontecerá a 1ª edição de Belém de um evento conhecido mundialmente, o Startup Weekend. Nós do Tá safo! estamos apoiando o evento e agora podemos publicar uma excelente notícia. Além de estarem vindo pessoas de renome no cenário empreendedor nacional, teremos pessoas da comunidade:

tasafoA novidade é que convidamos um pessoal irado, e que admiramos tanto, do #horaextra que finalmente conhecerão a galera e os sabores de Belém do Pará :)

horaextraA cereja do bolo fica por conta de uma das pessoas mais fantásticas com quem já trabalhei. A Verena Petitinga é Product Manager da aceleradora 21212, ela ajuda você a destampar sua mente e desenvolver produtos de altíssima qualidade.

21212Pessoal, é só uma mostra do que tem por vir. Espero que vocês fiquem motivados a participar do evento que será uma experiência bem intensa e produtiva. Veja a programação e grade completa no site do evento. E o último recado é que as inscrições estão bombando, não perca tempo e faça logo a sua clicando aqui!

Nos vemos por lá! Tá safo?