Planear dependências de compilação para o seu pipeline

Concluído

Nesta unidade, você aprenderá sobre o código de empacotamento para facilitar o compartilhamento. Você descobrirá por que você deve fazer pacotes, os tipos de pacotes que você pode criar, onde você pode hospedar os pacotes e como você pode acessá-los quando eles são hospedados. Você também aprenderá sobre o controle de versão de pacotes.

As bases de código estão sempre a crescer e a tornar-se mais complexas. É incomum para uma equipe escrever todo o código que seu aplicativo usa. Em vez disso, a equipe inclui código existente escrito por outros desenvolvedores. Pode haver muitos desses pacotes, ou dependências, em um aplicativo. É importante gerenciar ativamente essas dependências para poder mantê-las adequadamente e garantir que elas atendam aos requisitos de segurança.

Vamos verificar e ver como está a equipa. O Guilherme juntou a equipa para falar sobre uma alteração potencial no seu código que poderia ajudar outra equipa.

Reunião de equipa

Andy: Olá a todos. Eu estava conversando com a equipe que está trabalhando no sistema de back-end para o Space Game. Eles poderiam usar os modelos que usamos para o site em um aplicativo de back-end que planejam escrever.

Amita: O que você quer dizer com modelos?

Andy: Como você sabe, o site Space Game é um aplicativo ASP.NET Core. Ele usa o padrão Model-View-Controller—ou MVC—para separar os dados de como esses dados são exibidos na interface do usuário. Eu estava pensando que poderíamos criar um pacote que contém nossas classes de modelo para que qualquer aplicativo possa usá-las.

Amita: Qual é exatamente o objetivo?

Andy: Ambas as nossas equipas partilharão a mesma base de dados. O jogo envia pontuações altas à base de dados; lemos estas pontuações para apresentar nas classificações.

Amita: Isso faz sentido. Como vamos criar este pacote?

Andy: É por isso que eu queria conversar com você. Temos algumas opções, e estou à procura de ideias.

Tim: Eu adoraria ajudar, mas primeiro tenho algumas perguntas. Eu sou novo nisto e quero saber como tudo funciona.

O que é um pacote?

Um pacote contém código reutilizável que outros programadores podem utilizar nos seus próprios projetos, mesmo que não o tenham escrito.

Para idiomas compilados, um pacote normalmente contém o código binário compilado, como arquivos .dll em .NET ou arquivos .class em Java. Para linguagens que são interpretadas em vez de compiladas, tais como JavaScript ou Python, um pacote pode incluir código-fonte.

De qualquer forma, são normalmente compactados pacotes ZIP ou um formato semelhante. Os sistemas de pacotes geralmente definem uma extensão de arquivo exclusiva, como .nupkg ou .jar, para tornar claro o uso do pacote. A compactação pode ajudar a reduzir o tempo de download e também produzir um único arquivo para simplificar o gerenciamento.

Os pacotes também geralmente contêm um ou mais arquivos que fornecem metadados ou informações sobre o pacote. Estes metadados poderão descrever o que faz o pacote, especificar os seus termos de licenciamento, as informações de contacto do autor e a versão do pacote.

Por que motivo devo criar um pacote?

Há vantagens em criar um pacote em vez de duplicar o código.

Uma das razões para criar um pacote em vez de duplicar o código é impedir o desvio. Quando o código é duplicado, cada cópia pode divergir rapidamente para satisfazer os requisitos de um aplicativo específico. Torna-se difícil migrar as alterações de uma cópia para as outras. Por outras palavras, perde a capacidade de melhorar o código de forma a beneficiar todos os utilizadores.

Os pacotes também agrupam funcionalidades relacionadas num componente reutilizável. Dependendo da linguagem de programação, um pacote pode fornecer aos aplicativos acesso a determinados tipos e funções, enquanto restringe o acesso aos detalhes de sua implementação.

Outro motivo para criar um pacote é fornecer uma forma consistente de criar e testar a funcionalidade desse pacote. Quando o código é duplicado, cada aplicativo pode criar e testar esse código de maneiras diferentes. Um conjunto de testes pode incluir verificações das quais outro conjunto poderia beneficiar.

Uma compensação é que você tem outra base de código para testar e manter com um pacote. Você também deve ter cuidado ao adicionar recursos. De um modo geral, um pacote deve conter recursos que beneficiam muitos tipos de aplicativos. Por exemplo, Json.NET é um pacote NuGet popular para .NET que permite trabalhar com arquivos JSON. O Json.NET é open source, por isso a comunidade pode propor melhorias e comunicar problemas.

Quando vários aplicativos podem se beneficiar do mesmo código, as vantagens superam em muito as desvantagens. Tem apenas uma base de código, apenas um conjunto de testes e apenas um processo de compilação para gerir.

Como posso identificar dependências?

Se o objetivo for reorganizar seu código em componentes separados, você precisará identificar as partes do seu aplicativo que podem ser removidas, empacotadas para serem reutilizáveis, armazenadas em um local central e versionadas. Você pode até querer substituir seu próprio código por componentes de terceiros que são de código aberto ou que você licencia.

Há muitas maneiras de identificar as dependências potenciais em sua base de código. Isso inclui a verificação do código em busca de padrões de reutilização e a análise da arquitetura da solução. Aqui estão algumas maneiras de identificar dependências:

  • Código duplicado.

    Se certas partes do código aparecerem em vários lugares, isso é uma boa indicação de que você pode reutilizar o código. Centralize essas partes duplicadas de código e reempacote-as adequadamente.

  • Alta coesão e baixo acoplamento.

    Uma segunda abordagem é procurar elementos de código que tenham uma alta coesão entre si e baixo acoplamento com outras partes do código. Em essência, alta coesão significa manter partes de uma base de código que estão relacionadas entre si em um único lugar. O acoplamento baixo, ao mesmo tempo, consiste em separar partes não relacionadas da base de código, tanto quanto possível.

  • Ciclo de vida individual.

    Procure partes do código que tenham um ciclo de vida semelhante que você possa implantar e liberar individualmente. Se esse código puder ser mantido por uma equipe separada, é uma boa indicação de que você pode empacotá-lo como um componente fora da solução.

  • Peças estáveis.

    Algumas partes da sua base de código podem ser estáveis e mudar com pouca frequência. Verifique seu repositório de código para encontrar código com baixa frequência de alteração.

  • Código e componentes independentes.

    Sempre que o código e os componentes são independentes e não estão relacionados a outras partes do sistema, você pode isolá-los em dependências separadas.

Você pode usar várias ferramentas para ajudá-lo a digitalizar e examinar sua base de código. Eles variam de ferramentas que verificam códigos duplicados e desenham gráficos de dependência de solução a ferramentas que podem calcular métricas para acoplamento e coesão.

Que tipos de pacotes existem?

Cada arquitetura ou linguagem de programação fornece a sua própria forma de criar pacotes. Os sistemas de pacotes populares fornecem documentação sobre como o processo funciona.

Talvez você já esteja familiarizado com esses sistemas de pacotes populares:

  • NuGet: empacota bibliotecas .NET
  • NPM: pacotes de bibliotecas JavaScript
  • Maven: empacota bibliotecas Java
  • Docker: empacota software em unidades isoladas chamadas containers

Onde estão alojados os pacotes?

Você pode hospedar pacotes em sua própria rede, ou você pode usar um serviço de hospedagem. Um serviço de alojamento é normalmente denominado por repositório de pacotes ou registo de pacotes. Muitos desses serviços fornecem hospedagem gratuita para projetos de código aberto.

Aqui estão alguns serviços de hospedagem populares para os tipos de pacotes que acabamos de descrever:

  • Galeria NuGet

    Os pacotes NuGet são usados para artefatos de código .NET. Esses artefatos incluem assemblies .NET e arquivos relacionados, ferramentas e, às vezes, metadados. O NuGet define a forma como os pacotes são criados, armazenados e consumidos. Um pacote NuGet é essencialmente uma estrutura de pastas compactadas com arquivos no formato ZIP e tem a extensão .nupkg .

  • NPM

    Um pacote NPM é usado para JavaScript. Um pacote NPM é um arquivo ou pasta que contém arquivos JavaScript e um arquivo package.json que descreve os metadados do pacote. Para node.js, o pacote geralmente contém um ou mais módulos que podem ser carregados depois que o pacote é consumido.

  • Repositório Central Maven

    O Maven é usado para projetos baseados em Java. Cada pacote tem um arquivo de modelo de objeto de projeto que descreve os metadados do projeto e é a unidade básica para definir um pacote e trabalhar com ele.

  • Hub do Docker

    Os pacotes do Docker são chamados de imagens e contêm implantações completas e independentes. Mais comumente, uma imagem do Docker representa um componente de software que pode ser hospedado e executado por si só, sem dependências de outras imagens. As imagens do Docker são em camadas e podem depender de outras imagens.

Um feed do pacote refere-se ao seu servidor de repositório de pacotes. Este servidor pode estar na Internet ou atrás do seu firewall na sua rede. Por exemplo, você pode hospedar seus próprios feeds NuGet usando produtos de hospedagem como Azure Artifacts e MyGet. Também pode alojar pacotes numa partilha de ficheiros.

Ao alojar pacotes atrás da firewall, pode incluir feeds para os seus próprios pacotes. Também pode armazenar em cache pacotes em que confia na sua rede quando os seus sistemas não conseguem ligar-se à Internet.

Que elementos compõem uma boa estratégia de gestão da dependência?

Uma boa estratégia de gestão da dependência depende destes três elementos:

  • Padronização.

    Padronizar como você declara e resolve dependências ajudará seu processo de liberação automatizado a permanecer repetível e previsível.

  • Formatos e fontes de embalagem.

    Cada dependência deve ser empacotada usando o formato aplicável e armazenada em um local central.

  • Controlo de versões.

    Você precisa acompanhar as alterações que ocorrem ao longo do tempo nas dependências, assim como faz com seu próprio código. Isso significa que as dependências devem ser versionadas.

Quem pode aceder aos pacotes?

Muitos feeds de pacotes fornecem acesso sem restrições a pacotes. Por exemplo, você pode baixar Json.NET do nuget.org, sem a necessidade de entrar ou autenticar.

Outros feeds de pacotes exigem a autenticação. Pode autenticar o acesso aos feeds de várias formas. Por exemplo, alguns tipos de feeds necessitam de um nome de utilizador e palavra-passe. Outros feeds exigem um token de acesso, que normalmente é uma longa série de caracteres que identifica quem você é e a quais recursos você tem acesso. Você pode definir tokens de acesso para expirar após um determinado período de tempo.

Como se processa o controlo de versões dos pacotes?

O esquema de versões depende do sistema de empacotamento que utilizar.

Por exemplo, os pacotes NuGet utilizam o Semantic Versioning (Controlo de Versões Semântico).

O Semantic Versioning (Controlo de Versões Semântico) é um esquema de versões popular. Este é o formato:

Major.Minor.Patch[-Suffix] (Principal.Menor.Patch[-Sufixo])

Aqui está o que cada um desses parâmetros significa:

  • Uma nova versão Principal introduz alterações significativas. Normalmente, os aplicativos precisam atualizar como usam o pacote para trabalhar com uma nova versão principal.
  • Uma nova versão secundária introduz novos recursos, mas é compatível com versões anteriores.
  • Um novo patch introduz correções de bugs compatíveis com versões anteriores, mas não novos recursos.
  • A parte -Sufixo é opcional e identifica o pacote como uma versão de pré-lançamento. Por exemplo, 1.0.0-beta1 pode identificar o pacote como a primeira compilação de pré-lançamento beta para a versão 1.0.0.

Quando referencia um pacote, fá-lo através do número da versão.

Veja um exemplo de instalação de um pacote usando o PowerShell e um número de versão específico:

Install-Package Newtonsoft.Json -Version 13.0.1

O que acontece quando o pacote é alterado?

Quando você faz referência a um pacote do seu aplicativo, normalmente fixa — ou especifica — a versão desse pacote que deseja usar.

Muitas estruturas permitem especificar intervalos permitidos de versões de pacotes a serem instaladas. Alguns também permitem que você especifique curingas, que chamamos de versão flutuante.

Por exemplo, no NuGet, versão "1.0" significa que a primeira versão é igual ou maior do que 1.0. "[1.0]" especifica apenas a versão de instalação 1.0 e não uma versão mais recente.

Aqui estão alguns outros exemplos:

Esta notação: Seleciona:
(1.0,) A primeira versão que for superior a 1
[1.0,2.0] A primeira versão que é maior ou igual a 1.0 e menor ou igual a 2.0
(1.0,2.0) A primeira versão que for superior a 1.0 e inferior a 2.0
[1.0,2.0) A primeira versão maior ou igual a 1.0 e menor que 2.0

À medida que cada mantenedor lança uma nova versão do pacote, você pode avaliar o que mudou e testar seu aplicativo em relação a ele. Quando estiver pronto, pode atualizar o número da versão do pacote na sua configuração e submeter a alteração para o seu pipeline de compilação.

Aqui está um exemplo de como você pode incluir o pacote Newtonsoft.Json no arquivo de projeto do aplicativo C# (.csproj). Este exemplo especifica a versão 13.0.1 desse pacote:

<ItemGroup>
  <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

Verifique o seu conhecimento

1.

O que é um pacote?

2.

Digamos que criou um pacote que pretende partilhar publicamente. Qual é a maneira mais fácil de fazer isso?