Por que desenvolver bibliotecas internas para aplicativos internos?


10

Estou tendo dificuldades para entender por que você deve desenvolver bibliotecas internas para serem usadas exclusivamente no desenvolvimento de aplicativos internos. Aprecio que, se eu quiser usar o software que alguém de fora da organização escreveu, eles poderão me enviar seus arquivos de cabeçalho e arquivos .a ou .so e eu posso apenas vinculá-lo ao meu projeto (supondo que eles sejam compilados no mesmo ambiente) .

Mas por que uma biblioteca interna deve ser desenvolvida apenas para ser vinculada a um aplicativo interno quando eu tenho acesso aos arquivos de cabeçalho e implementação e posso apenas incluí-los na minha árvore de origem e compilá-los todos juntos?

Em outras palavras: se algum código fonte é escrito, como você decide se ele deve ser compilado em uma biblioteca binária e vinculado ao seu aplicativo ou apenas incluído nos arquivos de origem do projeto e compilado regularmente?

Quando digo 'incluir' arquivos em cada projeto, não pretendo copiar e colar cada arquivo na árvore de origem do projeto atualmente sendo desenvolvido. Refiro-me ao desenvolvimento de um diretório / biblioteca (separado para qualquer projeto) contendo código-fonte comum que pode ser incluído nos arquivos de um projeto da maneira usual, como #include.

ps Estou falando de desenvolvimento c / c ++ aqui para vários aplicativos de desktop.


Respostas:


25

Existem inúmeras razões para criar bibliotecas e bibliotecas compartilhadas (em arquivos .dll ou .so), mesmo para uso interno:

  1. A reutilização entre projetos é muito mais limpa
  2. Separação de responsabilidades - parte do seu código pode ser mais adequada para diferentes desenvolvedores ou equipes
  3. Você pode se beneficiar de melhorias nas bibliotecas que outras equipes fazem sem precisar localizar o código específico
  4. Tempos de construção mais rápidos, se a biblioteca é estável, ela não precisa ser reconstruída.
  5. Espaço em disco - você pode ter apenas a biblioteca e os cabeçalhos no projeto
  6. Se você usar bibliotecas compartilhadas, poderá economizar economia de memória com apenas uma cópia carregada na RAM, mesmo que vários programas a estejam usando.
  7. Você geralmente acaba com uma melhor documentação e teste das bibliotecas
  8. Design e código mais limpos - pensar em estruturar as coisas em bibliotecas deve resultar em grupos de funcionalidades relacionados em cada biblioteca e você tende a separar o código genérico, nas bibliotecas , das especificações do aplicativo, no aplicativo .
  9. Se você possui algoritmos proprietários em bibliotecas, pode restringir o acesso à fonte, por exemplo, não permitindo que contratados ou equipes terceirizadas cheguem à fonte.
  10. O código da biblioteca pode ser colocado sob uma licença diferente do Aplicativo em que foi originalmente escrito, algumas empresas são conhecidas pelas bibliotecas de Código Aberto das quais se orgulham - obtendo muitos elogios na comunidade de Código Aberto e, em algum momento, aprimoramentos importantes contribuídos de volta.

Algumas empresas ainda têm uma prática contábil em que os projetos que criam bibliotecas recebem algum reembolso por cada reutilização.


1
Ou em uma variação do ponto 9, você pode liberar a biblioteca com uma licença diferente do código principal do aplicativo.
Michael Borgwardt

@MichaelBorgwardt - Bom ponto para o ponto 10 acima.
26617 Steve Barnes

Além disso, ter algum código como uma biblioteca separada ajuda a evitar atalhos durante a programação, como "Vou adicionar este parâmetro extra aqui .." e ajuda a encontrar melhores maneiras de implementar os recursos necessários.
Valdas

11

Algumas outras razões possíveis que podem ser aplicadas a projetos maiores e não triviais:

  • Tempos de compilação: enormes projetos monolíticos de C ++ com milhares de arquivos, milhares de classes, funções etc. podem levar muito tempo para serem compilados (o que prejudica a produtividade se você desejar recompilar toda vez que alterar algumas linhas de código). Bibliotecas vinculadas estaticamente e dinamicamente são compiladas de forma independente e não precisam ser recompiladas se sua fonte não tiver sido alterada.

  • Separação lógica de módulos ou subsistemas distintos : sistemas grandes geralmente são mais fáceis de gerenciar se áreas distintas de funcionalidade são colocadas em módulos separados, e os desenvolvedores não são confrontados com a pesquisa em enormes pastas / projetos contendo milhares de arquivos / classes.

  • Limites entre desenvolvedores / equipes : os desenvolvedores que criam novas funcionalidades separadas ao mesmo tempo podem reduzir o potencial de conflitos de mesclagem, se for possível que cada desenvolvedor trabalhe em módulos diferentes.

  • Código que não deve ser liberado em um ambiente ativo : Por exemplo, bibliotecas de teste de unidade ou bibliotecas 'simuladas' usadas para teste do desenvolvedor para substituir um componente do sistema ativo (hardware, APIs, sistemas remotos, bancos de dados etc.)

  • Sinalizadores de compilador : se você se encontra na posição muito infeliz de se integrar com a API de algum terceiro que espera um sinalizador de compilador estranho, a biblioteca pode ser uma "camada de descontaminação" entre a API de terceiros e o restante do aplicativo.

  • Recursos opcionais / otimização : em sistemas grandes, um aplicativo pode esperar antes de carregar certos módulos vinculados dinamicamente na memória em tempo de execução, se eles não forem críticos para a funcionalidade básica do aplicativo.


Em geral, muitos projetos internos geralmente são pequenos aplicativos que não se beneficiam de serem divididos em bibliotecas separadas. Se você estiver trabalhando em um projeto minúsculo como desenvolvedor solitário, talvez não precise se preocupar em dividir seu código em bibliotecas (ainda ...). Não esqueça o princípio YAGNI .


3
@ downvoter - você poderia explicar o motivo do voto negativo? O feedback das respostas é útil para melhorar a qualidade deste site para todos.
precisa

4

Sua pergunta original pode ter causado um mal-entendido aqui para a maioria dessas outras respostas. Como você pretende não copiar o código existente nos projetos, mas incluir os mesmos arquivos de origem de projetos diferentes como referências , qualquer argumento de "código duplicado" se torna inútil, assim como muitos outros argumentos apresentados.

Observe que às vezes (- nem sempre -) é uma técnica sensata . De fato, quando você coloca todos os arquivos de origem que deseja reutilizar nos projetos em uma pasta de inclusão separada, você também criou uma biblioteca - uma biblioteca de códigos-fonte, não uma biblioteca binária. Especialmente em C ++, ao criar bibliotecas genéricas com modelos, não é incomum ter bibliotecas somente de cabeçalho, que precisam apenas de uma inclusão simples e sem preparativos de vinculação separados.

Então, acho que sua verdadeira pergunta é - quando criar bibliotecas de código-fonte ou quando preferir bibliotecas binárias pré-compiladas? Nesta resposta mais antiga deste site , discuti alguns prós e contras de bibliotecas somente de cabeçalho, talvez isso ajude você. A principal vantagem das bibliotecas de código-fonte é que elas não precisam ser compiladas com o mesmo tempo de execução e / ou sinalizadores de compilador / vinculador compatíveis que o aplicativo que as utiliza. As desvantagens são os tempos de compilação adicionais e o requisito de fornecer acesso ao código fonte (o que obviamente não é um problema para o tipo de projetos "internos" que você tem em mente).


É verdade que eu quis dizer uma biblioteca de código-fonte comum a vários projetos em que você apenas faz referência aos arquivos necessários através da diretiva típica #include - eu não conhecia o termo até que você o disse e editarei o pergunta agora. Sua resposta vinculada também é muito útil.
Andrew Murtagh

@ AndrewMurtagh: o fato de você estar aceitando tão rapidamente a resposta de MichaelBorgwardt me surpreendeu, porque o que ele escreveu parece ser um mal-entendido dele ou meu.
Doc Brown

bem, ele esclareceu a confusão inicial que eu tinha sobre quando agrupar código que seria comum a vários projetos em um único pacote (seja nas bibliotecas binárias ou nas bibliotecas de código-fonte), mas, de fato, eu estava falando em ter um único diretório de origem código que poderia ser compartilhado entre projetos e não copiar e colar cada arquivo em cada projeto, conforme eu precise deles.
Andrew Murtagh

2

Concordo com outros comentaristas quando escrevem que você não deve duplicar o código. No seu caso, no entanto, parece que você (ou pessoas com quem trabalha) está criando bibliotecas para código que não é duplicado em nenhum outro lugar.

Nesse caso, aviso contra generalização prematura . Muitas vezes, há a sensação de que um pedaço de código será reutilizável. No entanto, sem conhecer os detalhes íntimos de como o segundo caso de uso usará esse código, é muito fácil dedicar mais tempo aos recursos de "reutilização" que não serão realmente úteis nos casos adicionais ou para fazer suposições que se provem erradas. o segundo caso.

Escrever uma "biblioteca" para um caso de uso pode se transformar em um exercício muito caro, sem recompensa - já fui mordido por isso várias vezes.

Custos de exemplo:

  1. Tempo / energia gasto na consideração de casos de uso "gerais"
  2. Tempo gasto tornando a "biblioteca" distribuível para o seu "cliente" (seu próprio código)
  3. Pressão futura para usar a "biblioteca", mesmo que não corresponda totalmente ao próximo caso de uso

Minha regra geral é: não crie código em uma biblioteca, a menos que eu tenha pelo menos 2 locais separados onde o código é necessário.


2
Eu vi quase exatamente os mesmos motivos usados ​​por alguns desenvolvedores, porque os códigos deles estão todos em um único arquivo de origem> 20k. Quando combinado com nomes peculiares e comentários ruins, você logo terá um código que é mais rápido reescrever do que manter.
26617 Steve Barnes #

Ponto importante: certamente não estou argumentando contra a criação de códigos legíveis e de manutenção. Arquivos separados, métodos / classes bem nomeados e estrutura do pacote são componentes importantes da manutenção. O que quero dizer é que os custos de escrever + distribuir uma biblioteca são muito altos quando existe apenas um único caso de uso para a "biblioteca".
Sam

1
Por outro lado, não estou argumentando que você necessariamente precise empacotar e distribuir uma biblioteca em todos os casos, apenas que escrever e estruturar como se seu código pudesse um dia se tornar uma biblioteca geralmente vale um pouco de esforço e muitas vezes paga dividendos, mesmo que o código nunca se torne distribuído como uma biblioteca.
9788 Steve Barnes

1

por que uma biblioteca interna deve ser desenvolvida apenas para ser vinculada a um aplicativo interno quando eu tenho acesso aos arquivos de cabeçalho e implementação e posso apenas incluí-los na minha árvore de origem e compilá-los todos juntos?

Porque se você "apenas incluí-los na minha árvore de origem", está duplicando o código .

O problema é que você não se beneficiará de nenhuma melhoria (incluindo correções críticas) feitas pelo projeto em que você copiou o código, nem se beneficiará de nenhuma melhoria que você fizer.

Você pode pensar que pode resolver esse problema simplesmente copiando regularmente a versão mais recente do código em sua árvore de origem, talvez até automatizada usando um submódulo no git ou algo semelhante. Mas você terá constantemente sua quebra de compilação devido a alterações incompatíveis da API. Uma biblioteca, por outro lado, possui uma API pública "oficial" que seus desenvolvedores sabem que não pode ser alterada sem coordenar com os clientes.

Finalmente, pode haver razões técnicas - poderia ser necessário manter parte do código como uma biblioteca para que ele possa ser carregado opcionalmente ou mesmo carregado e descarregado sob demanda e, assim, reduzir o uso de memória quando a funcionalidade não é necessária?


1
Pelo que entendi, o principal motivo para transformar um pedaço de código em uma biblioteca é quando ele será usado em diferentes projetos (mesmo que todos sejam desenvolvidos internamente) para que esse código não seja duplicado, atualizado e mantido separadamente? E se você estiver desenvolvendo apenas um único projeto, não será necessário criar algo em uma biblioteca (a menos que você pretenda usá-lo em outros projetos posteriormente).
Andrew Murtagh

@AndrewMurtagh: Sim, é exatamente assim que eu diria. Embora possa haver razões técnicas também; Não estou familiarizado com o desenvolvimento de C / C ++ - talvez seja necessário manter parte do código como uma biblioteca para que ele possa ser carregado opcionalmente ou mesmo carregado e descarregado sob demanda e, assim, reduz o uso de memória quando a funcionalidade não é necessária?
Michael Borgwardt

Acredito que isso seja possível através de bibliotecas compartilhadas. Obrigado por esclarecer, marcarei sua resposta como aceita.
Andrew Murtagh

Quase todos os VCS da década passada suportam referências ou submódulos externos. Isso removeu o código duplicado e o problema da correção de bug. Pode incluir mais informações sobre por que essas soluções não são viáveis ​​se você ainda acredita que são problemas válidos.
Sirisian

Pense também em manutenção. 1) A lib pode ser mantida independentemente e em paralelo. 2) O código é fácil de substituir. 3) Base de código pequena é mais fácil de gerenciar para equipes pequenas e mais fácil de entender para todos. 4) se o tempo de colocação no mercado for crítico, você prefere ter versões mais rápidas. Código nas bibliotecas é o código que você não compila repetidamente no pipeline (IMO). 5) É código reutilizável confiável ... você fez isso ;-)
LAIV

1

Gostaria de detalhar os custos que sua solução tem a longo prazo.

Claramente, adicionar uma biblioteca a um projeto tem alguma sobrecarga, tudo acima se for o primeiro: os fluxos de trabalho devem ser alterados, às vezes até a infraestrutura e alguns membros da equipe podem não gostar (no início). Portanto, as vantagens da sua solução são óbvias, pois impõem menos custos agora .

No entanto, à medida que o seu projeto cresce, também aumentam os custos da "pseudo-biblioteca". Suponha que você tenha uma "pseudo-biblioteca" Ausada por um aplicativo e um testador de unidade. Sempre que você adiciona um cpp a A, é necessário adicioná-lo aos dois projetos, caso contrário eles não serão vinculados.

E se a sua "pseudo-biblioteca" for usada por outra "pseudo-biblioteca" B? Você precisa adicionar seu novo cpp em vários outros projetos. E se Bmudar para usar outra biblioteca? Você precisará excluir os cpps do Aem todos os projetos, dependendo apenas de B.

Tudo isso seria de graça se uma biblioteca real fosse usada. Portanto, a questão é: quantos cpps são necessários para justificar a mudança para uma biblioteca real?

Mas espere, há ainda mais garantias: um desenvolvedor não gosta desse trabalho estúpido de procurar todos os projetos que precisam do novo cpp e adicionará seu código / classes em algum lugar nos arquivos já existentes, o que não é uma coisa boa em a longo prazo.

Portanto, o uso da "pseudo-biblioteca" pode ser o primeiro passo para interromper um projeto monolítico, mas você não deve esperar muito para torná-lo uma biblioteca real para poder usar suas vantagens.


0

Mas por que uma biblioteca interna deve ser desenvolvida apenas para ser vinculada a um aplicativo interno quando eu tenho acesso aos arquivos de cabeçalho e implementação e posso apenas incluí-los na minha árvore de origem e compilá-los todos juntos?

Se a biblioteca for usada apenas por um aplicativo, provavelmente você não precisará dela como uma biblioteca separada.

Se a biblioteca é utilizada por 3.500 aplicativos, então você absolutamente fazer precisar dele como uma biblioteca separada.

E se houver um erro na biblioteca e você precisar corrigi-lo? Ou alguma mudança estatutária ou regulamentar ocorre, o que significa que você precisa alterar a maneira como a biblioteca funciona?

Se estiver em uma biblioteca separada, você poderá (potencialmente) consertar a biblioteca, testá-la novamente e reimplantá-la, e todos os aplicativos se beneficiarão da correção.

Se estiver apenas no código-fonte "local" para cada aplicativo, você precisará alterar, recriar, testar e reimplementar todos os aplicativos individualmente . Esse é um exercício muito maior (ou seja, mais caro).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.