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:
Existem inúmeras razões para criar bibliotecas e bibliotecas compartilhadas (em arquivos .dll ou .so), mesmo para uso interno:
Algumas empresas ainda têm uma prática contábil em que os projetos que criam bibliotecas recebem algum reembolso por cada reutilização.
fonte
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 .
fonte
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).
fonte
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:
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.
fonte
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?
fonte
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"
A
usada por um aplicativo e um testador de unidade. Sempre que você adiciona um cpp aA
, é 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 seB
mudar para usar outra biblioteca? Você precisará excluir os cpps doA
em todos os projetos, dependendo apenas deB
.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.
fonte
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).
fonte