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

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

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

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

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

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

“Check in”, “Check-in” ou “Checkin”?

Exemplo de uso da expressão Check InNão sei vocês, mas eu sempre fiquei na dúvida quando tinha que escrever um post ou artigo sobre controle de versão:

Afinal, qual o jeito certo de escrever – “Check in”, “Check-in” ou “Checkin”?

Hoje, numa thread na lista de discussão que nós MVPs usamos para falar com o time de produto de ALM (Visual Studio e TFS), finalmente aprendi o jeito “certo” – bom, pelo menos um jeito consistente de escrever…  Smile

Chris Clements, Documentation Manager da Microsoft, explicou qual o padrão usado internamente para as documentações do produto:

Utilização Forma Correta Exemplo
Verbo Check in
(separado, sem hífen)
Check In Pending Changes
Adjetivo Check-in
(com hífen)
Check-in Operation;
Gated Check-in Build
Substantivo Check-in
(com hífen)
At the time of your next check-in

Agora pelo menos já dá para ter algum padrão para seguir sempre que precisarmos escrever sobre operações de check-in (com hífen! Smile), certo?

Um abraço,
Igor

Check-in simultâneo em múltiplos team projects afeta políticas de check-in

Acabei de descobrir por acaso – através de uma pergunta do meu amigo MVP Daniel Oliveira – que o TFS pode apresentar um comportamento inesperado e deixar de executar algumas políticas sob certas circunstâncias.

Se você:

  • Usar a janela Pending Changes para fazer check-in de vários arquivos ao mesmo;
  • Selecionar arquivos pertencentes a diferentes team projects;
  • E tentar fazer o check-in de todos ao mesmo tempo;

Então somente serão executadas as políticas comuns a todos os projetos.

Em outras palavras: Dados os team projects ProjectA e ProjectB, configurados como a seguir;

  • ProjectA: Política de check-in Work Itemsativada;
  • ProjectB: Políticas de check-in Work Items e Code Analysis ativadas.

Ao efetuar o check-in dos arquivos $\ProjectA\foo.cs e $\ProjectB\Bar.cs (um de cada team project), apenas a política de Work Items (comum aos dois projetos) será executada. A política de Code Analysis será ignorada!

Quais as alternativas?

  1. Configurar todos os team projects para seguirem as mesmas políticas (nem sempre é viável);
  2. Fazer check-ins de apenas um team project por vez. Para evitar que o desenvolvedor se confunda e faça check-in de mais de um team project ao mesmo tempo, foi criado um add-in que alerta o desenvolvedor e impede o check-in “promíscuo”. Saiba mais em: http://social.msdn.microsoft.com/Forums/en/tfsversioncontrol/thread/a71ac2f0-dc9c-4c03-a6a3-ab59877c55d8

Um abraço,
Igor

Como desfazer check-outs de outros usuários

Quantas vezes já passamos (ou vimos alguém passar) por isso?

“Um funcionário saiu da empresa e largou um monte de arquivos em check-out. Ninguém sabe a senha dele. Mas nem ia adiantar, a máquina já foi formatada mesmo…”

 

 

 

 

 

E agora, como cancelar os check-outs feitos por outro usuário? O segredo está na (relativamente pouco conhecida) ferramenta de linha de comando do Team Explorer, tf.exe. Abra o prompt de comando do Visual Studio 2008 e execute:

tf workspaces /owner:<nome_do_usuário> /server:<nome_do_servidor>

image

Com isso você consegue listar os workspaces do usuário em questão. Você vai precisar dessa informação para a próxima etapa:

tf undo /workspace:<nome_do_workspace>;<nome_do_usuario> /recursive /server:<nome_do_servidor> $/*.*

 image

Para cada workspace listado na etapa anterior, execute o comando acima.

Technorati Tags: ,,

Por que as políticas de check-in não são obrigatórias?

Mais uma da série “dúvidas comuns que respondemos infinitas vezes”: Por que as políticas de check-in não são obrigatórias?

O recurso de check-in policy (política de check-in) é percebido pelos usuários do TFS como uma grande vantagem. Com ele, é possivel definir algumas premissas para a aceitação do código-fonte:

  • Você testou seu código antes de fazer check-in?
  • Você analisou o seu código para garantir que ele atende aos padrões da empresa?
  • Você lembrou de associar suas alterações no código à atividade/demanda que originou essas alterações?

image

As políticas de check-in são definidas em nível de projeto (Team Project) e se aplicam a todos os desenvolvedores que atuam no tal projeto. Toda vez que eles tentam efetuar um check-in, as políticas são validadas e o usuário é alertado caso elas não sejam atendidas.

O ponto mais polêmico em relação às políticas de check-in é que elas podem ser ignoradas pelo usuário!

image

Por quê isso? Já ouvi pessoas falando que a Microsoft fez o serviço “pela metade”, deixando de fora a possibilidade de barrar o check-in. Bom, temos algumas explicações para isso. A primeira delas vem de um blog de FAQ do Team System:

Can we disable the “Override CheckIn Policy Failure” checkbox? Can that be customized based on User Login, Policy Type or File type?

No. We get a lot of requests for this but our contention is that the person defining the policy can’t envision the situations that will arise where policy will need to be overridden. Thus, we designed it to be fully auditable by including policy compliance data in the changeset details and in the checkin mail that is delivered, but left it up to the developer to determine whether they have a good reason for overriding.

A razão é simples: se o desenvolvedor optou por ignorar a política de check-in, ele deve ter um bom motivo. Trabalho em equipe presume confiança entre seus membros, logo não faz sentido partir da premissa que todos são imaturos e irresponsáveis. Entretanto, como auditoria é fundamental em qualquer projeto (mesmo nos “ágeis”), o TFS registra no evento de check-in sempre que alguém optou por desconsiderar políticas de check-in que não estavam sendo atendidas.

Dica:  Na edição de Julho/2008 do Team Foundation Server Power Tools há uma nova ferramenta, o Alert Editor, que simplifica bastante o processo de auditoria das políticas de check-in. Adicione um alerta para ser notificado sempre que alguém optar por ignorar uma política definida num team project:

image

Entendendo políticas de check-in – com sorte, de uma vez por todas :-)

Há uma triste verdade a respeito das políticas de check-in, uma ainda pior que o fato de podermos usar o famigerado “override”: políticas de check-in não são universais. Ou seja, elas não são executadas e garantidas pelo servidor. Cada aplicativo-cliente é responsável por executar as políticas de check-in que lhe convierem.

Do ponto de vista técnico, check-in policies nada mais são que assemblies .NET instalados em cada computador onde serão executados. Esses assemblies contêm algumas classes que implementam interfaces específicas definidas no SDK do Visual Studio. Quando instalamos o Team Explorer (cliente do TFS), recebemos “de brinde” as quatro políticas de check-in originais.

No ato do check-in, o programa que o desenvolvedor estiver usando (por exemplo, o Visual Studio 2008) contata o servidor e obtém uma lista com os nomes das políticas de check-in que deveriam ser executadas, junto com suas respectivas configurações (que também foram definidas no servidor). Em seguida, verifica se essas políticas estão disponíveis no computador local e procede à sua execução. Com isso, podemos entender a afirmação de que “cada aplicativo-cliente é responsável por executar as políticas de check-in que lhe convierem”.

O Visual Studio (2005/2008) é o cliente “premium” para o TFS. Como tal, é o único que garante executar todas as políticas de check-in que estiverem devidamente registradas no servidor e instaladas no computador do desenvolvedor. Isso traz uma variável adicional ao já conturbado universo das check-in policies. Ainda que possamos criar nossas próprias políticas de check-in (acrescentando novas opções às quatro originais), não há nada que garanta que elas serão executadas. Isso me faz lembrar de um velho problema que aflite desenvolvedores Web há muito tempo: Validação no Cliente vs. Validação no Servidor.

Validação no Cliente vs. Validação no Servidor

No universo da Web, aplicativos feitos em qualquer tecnologia (ASP.NET, PHP, Ruby, Java etc…) certamente se vêem às voltas com a necessidade de solicitar dados ao usuário. Formulários são usados para as mais diferentes entradas de dados. Porém, o HTML não é exatamente a melhor tecnologia para a criação de formulários de dados. Ele não tem praticamente nenhum recurso padrão de validação de conteúdo que os browsers possam usar para conferir o que o usuário nos levou. Isso geralmente leva a duas opções:

Prós Contras
Validação no Cliente Rápido. Feedback instantâneo ao usuário. Dados incorretos podem ser facilmente corrigidos, sem a necessidade de uma “viagem de ida e volta” dos dados ao servidor para a validação Inseguro. Como depende de Javascript, pode não ser executado (ex.: o usuário desativou a execução de scripts em seu browser). Além disso, o usuário poderia, maliciosamente ou não, subverter o script, fazendo-o aceitar dados inválidos.
Validação no Servidor Seguro. O código rodando dentro do servidor está fora do alcance de usuários maliciosos, que não poderão alterar as regras de validação. Não há como forçar a entrada de dados inválidos. Lento. Os dados precisam ser enviados ao servidor para que possam ser validados. Se forem encontrados erros nas informações prestadas pelo usuário, é necessário enviar uma notificação ao browser para que seja feita a correção – depois da qual o processo recomeça.

As boas práticas do desenvolvimento para a Web nos dizem que devemos, sempre que possível, oferecer as duas opções ao mesmo tempo. A conveniência da validação no cliente aliada à segurança da validação no servidor. Repare que a validação no cliente tem apenas o papel da conveniência, nunca podendo substituir a validação no servidor. Se tiver que optar por apenas uma delas, não há dúvidas: fique com o servidor.

Bom, você deve estar se perguntando, mas o que isso tem a ver com o assunto em pauta? Tudo! Encare as políticas de check-in do TFS como client-side validation: rápidas, porém inseguras. Se eu realmente quiser garantir que o check-in é seguro e atende às definições do meu processo de desenvolvimento, preciso ter o equivalente TFS da server-side validation. As alternativas são:

  • Team Build + Integração Continua (CI, Continuous Integration): Com o TFS 2008 é possível disparar o processo de build automatizado do Team Build simplesmente fazendo um check-in. Com isso, podemos verificar se as alterações que acabaram de ser produzidas se integram adequadamente ao restante do código já existente no repositório. Efetuar o build a cada check-in visa a validar continuamente a integração entre os diversos trechos de código produzidos todo o tempo pela equipe de desenvolvimento. Daí vem o termo integração contínua. Como o processo de build é disparado automaticamente pelo ato de check-in, e como ele ocorre no agente de build (e não na máquina do desenvolvedor), ele acaba sendo o equivalente da validação de servidor das aplicações Web. Podemos rodar a análise estática de código, podemos rodar testes unitários, podemos auditar o código. Se houver algum problema, o build é marcado como falho (“quebrado”). O changeset (as alterações feitas pelo desenvolvedor) que deu origem ao build pode, então, ser desfeito (usando, por exemplo, o comando tfpt rollback).
  • Gated check-in: O problema da solução apresentada acima, 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. O TFS “Rosario” terá suporte nativo a gated check-in. Por enquanto, você pode usar o OpenGauntlet para ter esse recurso à disposição no TFS 2008.

Resumo da ópera

Politícas de check-in são um recurso bastante poderoso e conveniente. Devido ao fato de poderem ser facilmente burlados, devem ser usados apenas como lembrete para os desenvolvedores. Dessa forma, eles serão lembrados de testar seu código, associar work items etc. Para garantir que o código produzido por sua equipe atenda aos critérios definidos em sua empresa, utilize alguma técnica de gated check-in.