Controle seus projetos legados no TFS

Quem disse que é preciso estar na versão mais nova das linguagens de programação da moda para poder adotar práticas de DevOps e usar uma ferramenta de ALM como o TFS ou o VSTS?

Nesta série de posts, quero mostrar como a manutenção de seus projetos legados pode ser muito mais simples do que você imagina se você se permitir experimentar.

 

Continue lendo “Controle seus projetos legados no TFS”

Use “Unpublish branch” no branch master e sinta seu coração parando por alguns segundos

"Metralhadora na mão de macaco" é uma das melhores analogias de todos os tempos!Recentemente eu descobri – por acaso – um fluxo de trabalho potencialmente perigoso enquanto estava usando usando a ferramenta gráfica de Git do Visual Studio 2013 Team Explorer (conhecida como “Git Tools for Visual Studio” e que vêm nativamente no VS 2013). Dependendo da sua sequência de ações, pode levar à perda de todo o conteúdo de seu repositório Git no TFS!

Continue lendo “Use “Unpublish branch” no branch master e sinta seu coração parando por alguns segundos”

Compartilhando biblioteca entre projetos com o TFS

Na semana passada o amigo Ricardo Dorta me mandou uma pergunta por email que é tão comum que achei que merecia virar um post.

Lembro que quando usava Source Safe (jesus!!!), ele tinha uma opção de link, que fazia com que ao modificar um arquivo em um projeto, o mesmo arquivo em outro projeto também era modificado.

Explicando o contexto, tenho algumas assemblies com classes que serão utilizadas por vários projetos, porém esses projetos tem targets diferentes (Xamarin, Unity, Windows Store, Windows Phone etc…). A solução tosca é criar todos os projetos na mesma pasta compartilhando os arquivos fisicamente. Será que o TFS me da uma solução mais “elegante”?

Em suma: Temos vários projetos de aplicações (por exemplo, uma aplicação Web e outra Windows Phone) em soluções diferentes (pois são sistemas diferentes). Entretanto, esses projetos dependem de bibliotecas comuns, que por sua vez estão em suas próprias soluções. Como lidar com isso?

O problema

Considere a estrutura de projetos abaixo. Repare que temos dois diretórios de bibliotecas (FrameworkLib1, FrameworkLib2) e dois sistemas (PhoneApp, WebApp).

Estrutura original dos projetos
244

Os dois sistemas consomem as duas bibliotecas. Ou seja, é como se a estrutura de projetos fosse, na verdade, assim:

Estrutura com as bibliotecas sob os sistemas
244

Dessa forma, os sistemas poderiam referenciar os projetos das bibliotecas. Não apenas isso, mas seria possível também editar as bibliotecas ao mesmo tempo que damos manutenção nos sistemas.

O jeito obsoleto – Share do SourceSafe

O Visual SourceSafe oferecia um recurso de compartilhamento (Share, ou “link” como meu amigo chamou). Com ele, era possível fazer exatamente o que ele gostaria: “injetar” os projetos das bibliotecas na estrutura dos sistemas.

Compartilhando pastas no SourceSafe
162

Dessa maneira, criava-se uma estrutura como a da figura a seguir. Nela, quaisquer checkins feitos nos diretórios PhoneApp/Src/PhoneApp/Lambda3.FrameworkLib1 (ou FrameworkLib2) seriam refletidos no diretório original Lambda3.FrameworkLib1/Lambda3.FrameworkLib1 (ou FrameworkLib2).

Essa técnica até resolveria o problema do meu amigo – independente de ser a melhor solução ou não – não fosse um pequeno detalhe: o TFS não tem o recurso de Share.

No TFS temos três abordagens possíveis: uma client-side, uma server-side e uma terceira independente do TFS.

Abordagem 1:  Client-side – Mapeamentos de workspace

Um recurso poderoso – e pouco explorado – do TFS é o uso do mapeamento de workspaces para baixar o código-fonte em locais específicos do nosso computador.

Normalmente, as “boas práticas” recomendam que mapeemos apenas o diretório-raiz do servidor do TFS a um diretório local em nosso computador; dessa forma, garantimos a consistência da estrutura de diretórios. Mas para resolver este caso específico, iremos contra essa boa prática. Veja o que eu fiz:

  1. Na janela Source Control Explorer, selecionei a opção Workspaces:
    Opção "Workspaces" da janela Source Control Explorer
  2. Depois, cliquei em Add para adicionar um novo workspace:
    Criando um novo workspace na caixa de diálogo Manage Workspaces
  3. Finalmente, configurei meus mapeamentos. Repare que peguei os diretórios dos projetos das minhas bibliotecas e “injetei-os” sob o diretório da minha aplicação. O resultado final é exatamente o mesmo que teríamos com o Share do SourceSafe. Qualquer alteração que eu faça nesses diretórios mapeados refletirá nos originais.
    Mapeando as bibliotecas para dentro do diretório do projeto

Prós e contras

  • Prós
    • Fácil de configurar – similar ao comando Share do SourceSafe;
    • Não requer nenhuma alteração no servidor. A configuração é feita apenas no workspace;
    • Alterações feitas nos projetos das bibliotecas são refletidas imediatamente no diretório original.
  • Contras
    • Por ser uma solução client-side, precisa ser repetida no computador de todos os desenvolvedores;
    • Como não podemos criar mais de um mapeamento por diretório, não dá para configurar PhoneApp e WebApp (nossos exemplos) ao mesmo tempo. Precisaríamos ter um workspace para cada aplicação;
    • Times não podem escolher quando recebem as alterações feitas por outros times, já que estão todos apontando para o mesmo diretório compartilhado;
    • Mapeamento deve ser replicado manualmente nas definições de build automatizado, senão não compila.

Abordagem 2: Server-sideBranches

O uso de workspaces pode ser bem simples, mas não dá para garantir que todos os desenvolvedores estarão com seus workspaces devidamente configurados. Se alguém estiver fora do padrão, estará feita a “caquinha”! Smile

Assim, uma alternativa mais “segura” seria definir os compartilhamentos do lado do servidor e não do lado do cliente. Dessa forma evitaríamos a necessidade de configurar o que quer que fosse nas máquinas dos desenvolvedores.

E como fazer isso do lado do servidor? Ora, é simples: com branches!

  1. Crie uma branch para cada biblioteca:
    image
  2. Aponte para dentro do diretório da solução dos aplicativos que irão consumir as bibliotecas:
    image
  3. Repita o processo para cada biblioteca. O resultado final será algo assim:
    image

Prós e contras

  • Prós
    • Solução server-side – não depende de configuração na máquina dos desenvolvedores;
    • Mais fácil de garantir que todos estão seguindo a mesma estrutura definida no servidor;
    • Permite o isolamento de alterações – ou seja, um time consegue decidir quando recebe as alterações feitas por outro time;
    • Transparente para a automação de build – nenhuma configuração adicional necessária.
  • Contras
    • Alterações não são propagadas imediatamente. Requer Merge para transferir alterações feitas nas cópias dos aplicativos para o diretório original das bibliotecas (e vice-versa);
    • Sujeito a perda de sincronia e excesso de conflitos se o time não se lembrar de fazer merges com frequência;
    • Mais branches para serem gerenciados – todo branch deve ser gerenciado!

Abordagem 3: Independente – Nuget

As duas soluções anteriores, apesar de funcionarem, têm suas limitações. O que mais me incomoda nelas é o processo para a sincronização das alterações feitas nas cópias das bibliotecas (injetadas dentro das solutions das aplicações) e seus diretórios originais. Na primeira solução, baseada em workspaces, não temos controle nenhum. Já na segunda, temos algum controle (pois podemos decidir o momento do merge) mas ainda assim não é um processo 100% seguro.

Por conta disso, prefiro uma solução baseada em Nuget:

  1. As bibliotecas (FrameworkLib1, FrameworkLib2) são empacotadas como pacotes Nuget (sugiro o uso do TFS Nugetter);
  2. Criamos um Feed Nuget local para hospedar os pacotes (com o Nuget Server);
  3. Os projetos deixam de referenciar diretamente os projetos das bibliotecas e passam a referenciar os pacotes Nuget.

Conclusão

Mas afinal de contas, qual é a melhor solução? Claro que isso depende muito do cenário de cada time, mas no geral eu tendo a recomendar a seguinte ordem de preferência:

image
111

A solução baseada em Nuget, apesar de ter o custo inicial mais alto (pois depende de montagem de infraestrutura) acaba sendo, ao longo do tempo, a mais robusta. Mas, como dizem os americanos, YMMV. Smile

Um abraço,
Igor

Private Builds e Gated Check-ins

Caixa de diálog de Gated Check-inSe você leu meu último post sobre Private Builds, deve ter notado uma semelhança com a funcionalidade de Gated Check-in.

Para aqueles que não sabem o que é um Gated Check-in, vai aí um resumo de um post que fiz sobre o assunto:

O problema da solução apresentada acima [NA: Uso de Integração Contínua], baseada apenas no servidor de build, é que o check-in precisa ser feito antes de ser validado. Ou seja, em caso de problemas eu necessariamente terei que desfazer manualmente as alterações que quebraram o build. O ideal seria que eu pudesse disparar o buid antes do check-in, só efetivando a alteração no controle de versão se tudo corresse bem. É justamente disso que trata o conceito de gated check-in: As operações de check-in são interceptadas (geralmente usando shelvesets) e redirecionadas para um servidor de build especial. Esse servidor combina o código-fonte que já existe no TFS com as alterações que acabaram de vir do desenvolvedor. Se tudo correr bem, só então é que o check-in será consumado.

Reparou na parte que diz que o TFS “combina o código-fonte que já existe no TFS com as alterações que acabaram de vir do desenvolvedor”? É exatamente isso que faz o Private Build, certo?

Logo, podemos dizer que Private Build e Gated Check-in são a mesma coisa? Bem, quase. Smile

Private Build e Gated Check-in são baseados na mesma infraestrutura que permite a execução de builds baseados em shelvesets. A diferença é o gatilho: enquanto o Private Build é opcional e disparado sob demanda pelo desenvolvedor, o Gated Check-in é obrigatório e disparado no check-in.

Qual é o melhor? Private Build ou Gated Check-in?

Não sei se dá para ser tão simplista assim. Neste caso não há melhor ou pior.

Temos clientes que preferem a segurança do Gated Check-in. Ele reduz drasticamente o risco de quebras no build. Entretanto, ele torna o processo de check-in mais burocrático e lento. Times mais maduros acabam sendo “atrapalhados” pelo Gated Check-in.

Minha opinião pessoal? Use Gated Check-in na branch de desenvolvimento APENAS SE O TIME AINDA NÃO FOR MADURO. Em todos os outros casos, confie no bom-senso do time. Eles usarão o Private Build sempre que necessário.

 

Um abraço,
  Igor

SVNBridge: Integre seu TFS 2010 com clientes Subversion

image
80

Um dos grandes desafios de muitas empresas que pretendem migrar do Subversion para o TFS é: como integrar meu time – e suas ferramentas – ao novo servidor?

Se você usa ferramentas que oferecem suporte nativo ao TFS – como o Visual Studio, o Eclipse (com o Team Explorer Everywhere) ou até mesmo o IntelliJ IDEA – fica mais fácil. O problema é quando o time está usando ferramentas que só sabem falar com o Subversion, tal como o Adobe Dreamweaver ou o Apple Xcode.

Para esses casos, uma alternativa pode ser o SVNBridge – um tradutor de protocolos (ou “bridge”) que emula o protocolo do Subversion, “enganando” os clientes como o Dreamweaver ou o Xcode e fazendo-os acreditar que estão conectados a um repositório Subversion, quando na verdade estão falando com o TFS.

O SVNBridge foi criado pelo time do CodePlex para que clientes SVN (em especial o TortoiseSVN) pudessem ser usados para conexão com os TFS oferecidos pelo serviço CodePlex. O time percebeu que muitas empresas poderiam se beneficiar disso e portanto decidiram compartilhar o código.

Se você já usa (ou pretende usar) o TFS e tem pessoas no seu time que dependem de ferramentas que não “falam” TFS mas “falam” Subversion, experimente o SVNBrigde!

Um abraço,
    Igor