Problemas com a RVM no Ubuntu 10.10 (e a solução!)

Instalei o Ruby 1.9.2 a partir da RVM no Ubuntu 10.10 e ocorreram uns erros ao instalar a gem do Rails (falta do pacote zlib) e ao executar uma aplicação Rails (falta do pacote openssl).

Parece que no CentOS ocorre esse erro também.

Uma boa explicação sobre os problemas (e a solução) está no link abaixo:
http://www.flaviamissi.com.br/instalando-rvm-ruby-e-rails-no-ubuntu-10-10/

________________

Daniel Lopes escreveu sobre como instalar corretamente o RVM (além do Ruby 1.9.2 e a última versão do Rails):
https://github.com/danielvlopes/ruby-unix/blob/master/pt/ubuntu_10.10.md

Pra mim, faltou executar $rvm notes e instalar o que estava faltando.

Instalando Jetty Plus no Lucid Lynx

Há alguns dias precisei instalar o Jetty com a extensão Jetty-Plus em um Ubuntu 10.04 (Lucid Lynx). Resolvi usar o apt-get. Instalar o Jetty foi muito fácil. Mas na hora de instalar o Jetty-Plus deu um trabalhinho…

Mas por que eu precisei do Jetty-Plus? É que o Jetty-Plus facilitada o acesso a vários recursos do Java, entre eles JNDI.

No pacote do Jetty para o Ubuntu, o Jetty-Plus não é instalado. Pensei que bastasse instalar o pacote recomendado libjetty-extra, mas precisei fazer algumas outras alterações.

A partir da versão 10.10 (Maverick Meerkat), o pacote libjetty-extra já com os jars e as configurações do Jetty-Plus.

Instalando o Jetty com o apt-get

Para instalar o Jetty no Ubuntu (ou Debian) é fácil:

sudo apt-get install jetty

Para executar o Jetty recém instalado com sucesso, é preciso editar o arquivo /etc/default/jetty e modificar a primeira linha para:

NO_START=0 # change to 0 to allow Jetty to start

Então, basta executar:

sudo /etc/init.d/jetty start

Ou mais fácil:

sudo service jetty start

Instalando o Jetty-Plus no Lucid Lynx

Para instalar o Jetty-Plus no Lucid Lynx, precisamos primeiramente instalar o pacote libjetty-extra para que sejam instalados os jars de naming, entre outras coisas. Sem os pacotes de naming, não é possével usar os recursos de JNDI do Jetty-Plus.

apt-get install libjetty-extra

Além disso, é preciso baixar o jar do Jetty-Plus na mão. A versão do Jetty usada pelo Lucid Lynx é a 6.1.22. Depois de feito o download do jetty-plus.jar da versão 6.1.22, é preciso colocá-lo em /usr/share/java, criando um link simbólico para o arquivo em /usr/share/jetty/lib. Dessa maneira, as convenções usadas pelo pacote são seguidas.

sudo ln --symbolic /usr/share/java/jetty-plus.jar /usr/share/jetty/lib

É interessante criar uma pasta webapps-plus em /var/lib/jetty/ para que possamos colocar os WAR’s que utilizam JNDI e os outros recursos do Jetty-Plus. Tambem é bom criar um link simbólico dessa pasta para /usr/share/jetty.

sudo ln --symbolic /var/lib/jetty /usr/share/jetty

Então, é preciso criar um arquivo jetty-plus.xml e colocar as configuracões de JNDI ou EnvEntry. A propriedade webappdir deve apontar para o diretório webapp-plus criado.

Para habilitar a leitura do jetty-plus ao inicar o Jetty, é necessário editar o arquivo /usr/share/jetty/etc/jetty.conf e inserir “jetty-plus.xml” na última linha.

Então, basta iniciar o serviço do Jetty e suas aplicações poderão usar recursos de JNDI.

sudo service jetty start

JUnit 4 e arquivos

Testar código que manipula arquivos com o JUnit em geral é muito chato. Os testes ficam cheios de código que usa a API de io do Java e que deixa de expressar o comportamento do código.

A classe TemporaryFolder do JUnit 4.7 tem uma API para criar arquivos e diretórios dentro de um diretório temporário. Essa classe usa o mecanismo de @Rule do JUnit 4 apagar arquivos depois de cada teste (depois até do @After do teste atual).

public class FileUploaderTest {
	
    @Rule
    public TemporaryFolder folder = new TemporaryFolder();

	private static final String INPUT_FILENAME = "input.ext";
	private static final String OUTPUT_FILENAME = "output.ext";
	
	private FileUploader fileUploader;
	private File inputFile;
	private File outputDir;

	@Before
	public void setUp(){
		outputDir = folder.newFolder("outputDir");
		fileUploader = new FileUploader(outputDir);
		inputFile = new File(INPUT_FILENAME);
	}

	@Test
	public void shouldWriteTheUploadedFile() throws IOException{
		inputFile = folder.newFile(INPUT_FILENAME);

		fileUploader.upload(inputFile, OUTPUT_FILENAME);
		
		File outputFile = new File(outputDir, OUTPUT_FILENAME);
		assertTrue(outputFile.exists());
	}

	@Test(expected=FileUploadException.class)
	public void inputFileShouldNotBeADirectory(){
		inputFile = folder.newFolder(INPUT_FILENAME);
		fileUploader.upload(inputFile, OUTPUT_FILENAME);
	}
}

Cuidado com os Feature Branches locais

Feature Branching is a poor man’s modular architecture, instead of building systems with the ability to easy swap in and out features at runtime/deploytime they couple themselves to the source control providing this mechanism through manual merging. daqui

Feature Branching, ou branching por funcionalidade, é uma técnica muito usada para controle de versão de código em que um branch é criado para cada funcionalidade do sistema. A técnica facilita o controle do que será disponibilizado na versão a ser fechada: é feito o merge para o trunk somente das funcionalidades desejadas.

Martin Fowler explica no artigo Feature Branch porque evitar branches por funcionalidade é uma boa prática para quem faz Integração Contínua. Mesmo com sistemas de controle de versão mais modernos (e distribuídos) como Git, que é ótimo para fazer merges, usar branches por funcionalidade não é uma boa idéia.

No meu projeto atual, resolvemos evitar branches por funcionalidade. No caso de uma funcionalidade ficar pela metade em uma iteração, apenas removíamos os resquícios dela da tela (em geral, tirando do menu). Em alguns casos, foi preciso atrasar ou abortar a iteração, mas apenas em casos muito pontuais (mudanças críticas que afetavam o sistema como um todo).

Apesar da pontualidade desses casos, isso afetou negativamente o comportamento da equipe. Ser responsável por atrasar ou abortar uma iteração era algo muito ruim porque afetava negativamente o andamento do projeto. Por isso, eu e os meus colegas passamos a criar Feature Branches locais: deixámos de comitar o código frequentemente, afim de evitar comitar funcionalidades pela metade, que poderiam atrasar o entregável.

Esses feature branches locais fizeram que não houvesse integração contínua: só no final de cada funcionalidade a equipe comitava o código. Como, em geral, isso acontecia simultaneamente para várias funcionalidade e no final da iteração, isso acabava acarretando em mais atrasos nas entregas.

Logo percebemos isso e nos policiamos para que isso não ocorresse novamente.

Enfim, evite feature branches locais!

______

Outra prática ruim é trabalhar durante muito tempo com os testes no vermelho. Acontece quando você trabalha numa funcionalidade que faz testes em outros pontos do sistema falharem. Aí, você continua trabalhando na sua funcionalidade, ignorando os testes que estão falhando. Nesse caso, estamos dando passos muito longos e sem segurança. É importante seguir a regra de não inserir código de produção com testes falhando.

______

Há algumas equipes que prezam código limpo, mas que dão um tiro no pé:  não comitam o código antes de atingir uma versão “perfeita”. É o over-refactoring.

______

Quem faz deploy contínuo tende a usar feature branches, mas cuidam para que eles existam pelo menor período de tempo possível.