Ao desenvolver software, geralmente tenho uma biblioteca 'central' centralizada contendo código útil que pode ser compartilhado e referenciado por diferentes projetos.
Exemplos:
- um conjunto de funções para manipular strings
- expressões regulares comumente usadas
- código de implantação comum
No entanto, alguns dos meus colegas parecem estar se afastando dessa abordagem. Eles têm preocupações como a sobrecarga de manutenção do código de reteste usado por muitos projetos depois que um bug é corrigido. Agora estou reconsiderando quando deveria estar fazendo isso.
Quais são os problemas que tornam uma má ideia usar uma biblioteca 'principal'?
code-reuse
libraries
Alex Angas
fonte
fonte
Respostas:
As bibliotecas principais são ruins quando começam a sofrer com o surgimento de recursos e muito ruins quando não são bem mantidas.
Você pode achar este artigo interessante para um ponto de vista estendido (com o qual concordo plenamente):
http://www.yosefk.com/blog/redundancy-vs-dependencies-which-is-worse.html
Don Knuth: "Para mim, 'código reeditável' é muito, muito melhor do que uma caixa preta ou um kit de ferramentas intocável ... você nunca vai me convencer de que o código reutilizável não é principalmente uma ameaça".
fonte
Usar a idéia de que uma biblioteca principal é ruim quando vários projetos dependem dela é como dizer que você não deve usar o jQuery para a Web, libxml nos aplicativos * * nix ou qualquer outra estrutura ou biblioteca. Observe todo o ecossistema do desenvolvimento moderno (DRY, OOP, etc) e cada aplicativo é criado a partir de um conjunto de bibliotecas e estruturas.
O que pode ser ruim é se você não possui nenhum tipo de teste de unidade, não faz teste de regressão e não usa nenhum tipo de API / ABI com sua biblioteca. Se todos os seus aplicativos tiverem testes adequados, sua biblioteca terá testes adequados e, se você interromper as chamadas de função, atualize o número da versão da API adequadamente.
Para uma cobertura completa, o que você provavelmente desejaria é quando forem feitas alterações na Biblioteca, você pode executar um conjunto de testes que verificarão se a API não foi quebrada e se a execução de todo o código está livre de erros. Em seguida, você pode inserir a atualização mais recente da biblioteca em seu aplicativo e executar o mesmo conjunto de testes. Se você atualizar a API, ela deverá ser documentada para que você saiba o que precisa fazer no seu aplicativo para atualizá-lo. De qualquer forma, quando você executa os testes para o seu aplicativo, pode estar tão confiante quanto nos testes que nada quebrou.
Ao usar jquery, mootools, qualquer biblioteca ou estrutura javascript, você não pode usar cegamente a nova versão; infelizmente, nem mesmo com um lançamento menor do 1.6.z às vezes.
fonte
Se você possui um conjunto abrangente de testes de unidade para a biblioteca principal; isso não é um problema. Nenhum código será verificado a menos que todos os testes passem. Se você apresentar um defeito, escreva um teste com falha para reproduzir e corrigir o defeito; então você sempre testará esse erro também. Para sempre.
Além disso, a funcionalidade que você descreve é muito fácil de criar testes de unidade.
Como um problema secundário, convém ter mais de uma biblioteca principal para não precisar incluir o código RegEx, a menos que queira.
fonte
Vou oferecer uma visão ligeiramente diferente sobre isso. Uma biblioteca principal, em muitos casos, é uma excelente ideia!
Se você tiver dois projetos separados, eles deverão estar em dois repositórios de código separados. Agora eles dependem da funcionalidade comum. Vamos considerar, por exemplo, aplicativos de processamento de pacotes. A funcionalidade comum pode incluir:
Agora, aplicativos de processamento de pacotes diferentes podem precisar de um subconjunto diferente deles. Você deve implementar uma biblioteca principal com um repositório de código-fonte ou deve ter 18 repositórios diferentes para cada um desses módulos? Lembre-se de que esses módulos podem ter interdependências; portanto, a maioria desses módulos pode depender, por exemplo, do módulo diverso.
Afirmo que ter uma biblioteca principal é a melhor abordagem. Reduz a sobrecarga de muitos repositórios de código-fonte. Isso reduz o inferno das dependências: uma versão específica dos alocadores de memória pode precisar de uma versão específica do módulo diverso. E se você quiser a versão 1.7 do alocador de memória, dependendo da versão 2.5 e da árvore 1.2 do AVL, dependendo da versão 2.6? Talvez você não consiga vincular diversos 2.5 e 2.6 ao mesmo tempo ao seu programa.
Então, vá em frente e implemente a seguinte estrutura:
Eu vi que mudar para esse tipo de estrutura a partir da estrutura:
Levou à redução da manutenção e ao aumento do compartilhamento de código por meio de mecanismos que não sejam de copipaste.
Também vi projetos usando a seguinte estrutura:
... e a dependência do inferno e a proliferação de números de repositórios têm sido problemas genuínos.
Agora, você deve usar uma biblioteca de código aberto existente em vez de escrever sua própria? Você precisa considerar:
Eu costumo usar a regra de que tudo abaixo de 1000 linhas de código que não exija algo além do conhecimento do programador deve ser implementado por conta própria. Nota: as 1000 linhas incluem testes de unidade. Portanto, certamente não defenderei a criação de 1000 linhas de código por conta própria, se exigir 10.000 linhas adicionais para testes de unidade. Para meus programas de processamento de pacotes, isso significa que os únicos componentes externos que usei são:
Algumas coisas que eu implementei por conta própria porque são simples incluem até coisas como:
... porque implementações personalizadas deles podem permitir inlining pesado, levando a um desempenho aprimorado.
Eu não faço criptografia; se o fizesse, adicionaria algum tipo de biblioteca de criptografia na lista, pois a escrita de algoritmos de criptografia por conta própria pode ser suscetível a ataques de tempo de cache, mesmo que você possa, com um teste de unidade completo, mostrar que são compatíveis com os algoritmos oficiais.
fonte
Uma biblioteca principal pode ser ruim quando vários projetos dependem dela, não apenas é necessário testar quaisquer alterações em seu núcleo, mas também é necessário testar a regressão para cada projeto dependente. Em segundo lugar, suas principais APIs nunca podem ser alteradas porque você precisará refatorar todos os projetos dependentes. Quanto mais projetos usarem sua biblioteca, mais profunda será a armadilha.
Outro problema é a tendência de começar a jogar tudo "comum" em sua biblioteca principal, inchando e dificultando a inserção de pequenos pedaços. Vou apenas dizer que uma vez ouvi falar de um lugar que ficou com medo de tocar em qualquer uma das suas numerosas bibliotecas principais, a sobrecarga dos testes de regressão ao controle de qualidade foi tão grande.
Em vez disso, talvez você possa criar um recurso de trecho de código para permitir que as equipes de projeto pesquisem e obtenham o código necessário e se afastem de quaisquer problemas de manutenção ou regressão? De qualquer maneira, é o que eu faço em casa.
fonte
Um ponto ainda não mencionado é que qualquer código terá dependências de algo , mesmo que seja literalmente a única coisa executando na ROM de um microcontrolador incorporado; se o fabricante do controlador alterar algum comportamento em que o código se baseia, o código precisará ser modificado para funcionar com chips fabricados após a alteração, ou os fabricantes do dispositivo que usa o código precisarão, de alguma forma, adquirir chips que não incorporar a alteração - possivelmente pagando um prêmio por eles.
O uso de uma biblioteca para executar várias funções de hardware pode significar que o código agora depende de uma biblioteca, embora não tivesse sido anteriormente, mas também pode eliminar as dependências entre o código e o hardware. Por exemplo, um fabricante de chips pode prometer fornecer uma biblioteca para todos os chips presentes e futuros que sempre executam determinadas funções de E / S de uma certa maneira. O código que usa essa biblioteca para executar essas funções de E / S se tornaria dependente do fabricante para fornecer versões apropriadas dessa biblioteca, mas não seria mais dependente do fabricante para usar a mesma implementação de hardware dessas funções.
Infelizmente, muitas vezes é difícil saber qual é a abordagem correta para o código à prova de futuro. Vi casos em que um fornecedor de chips mudou a maneira como uma biblioteca funcionava (para acomodar novos chips), mesmo quando estava sendo usado para acessar um chip que havia mudado. Também vi casos em que um fabricante de chips alterava a maneira como seu hardware funcionava, mas as bibliotecas fornecidas eram ajustadas adequadamente, de modo que o código que usava as rotinas de uma biblioteca continuava funcionando sem alterações, enquanto o código que acessava o hardware diretamente precisava ser ajustado.
Situações semelhantes existem com aplicativos do Windows. Às vezes, a Microsoft gosta de mudar a maneira como os aplicativos são obrigados a fazer as coisas; o código que usa determinadas bibliotecas para tais coisas pode ser atualizado simplesmente atualizando a biblioteca, enquanto o código que não usa bibliotecas que são atualizadas para elas deve ser atualizado manualmente.
fonte
Eu queria abordar isso com uma abordagem um pouco diferente, apesar de adorar
Denis de Bernardy
responder e vincular artigos sobre minimizar dependências e minimizar redundâncias (eles refletem muito meus próprios pensamentos sobre esse assunto, onde acredito que a reutilização de código é um ato de equilíbrio).O maior problema que tenho com uma
core
biblioteca é este:E acho que é muito provável que a resposta possa ser " nunca ". As pessoas sempre podem ser tentadas a adicionar a ela, uma vez que modela uma idéia tão nebulosa, especialmente se essa biblioteca está apenas evoluindo durante o desenvolvimento do software, em vez de ter objetivos antecipados. E talvez adicionar à biblioteca não seja a pior coisa do mundo, pois não quebrará as dependências existentes da biblioteca, mas, dados objetivos tão nebulosos, a biblioteca pode se tornar cada vez mais eclética e feia, fornecendo funcionalidades díspares das quais alguém está interessado o uso da biblioteca pode encontrar apenas uma pequena parte aplicável às suas necessidades.
As dependências na sua base de código devem idealmente fluir para pacotes muito estáveis. Um
core
pacote pode facilmente se tornar muito instável, enquanto grandes partes da sua base de código têm dependências fluindo em direção a ele.Então, acho que vale a pena dividir a biblioteca em bibliotecas mais uniformes, dedicadas a fazer algo mais específico do que apenas "biblioteca principal de tudo o que as pessoas possam precisar com frequência", para que ela cresça em uma direção mais uniforme e com melhor coordenação entre os colegas de equipe. sobre exatamente o que deveria e, o que é mais importante, não deveria fazer, e potencialmente alcançar um ponto de estabilidade onde é bem testado e você não sente que há mais alguma coisa que precisa ser adicionada a ele para que seja relativamente " completo "e estável (como inalterável).
fonte
Escrever bibliotecas para coisas básicas como strings e listas vinculadas é bastante tolo neste milênio. Use uma linguagem de programação incluída nas baterias que possua as principais funcionalidades.
Se você gosta de escrever as principais bibliotecas de suporte em tempo de execução apenas por diversão, crie uma nova linguagem de programação. Se você faz isso em um aplicativo, basicamente está desenvolvendo um idioma para o lado.
Além disso, alguém já não escreveu N bibliotecas principais diferentes no idioma que você está usando? Pesquisando estruturas existentes e escolhendo a mais adequada pode ser um uso melhor do tempo do que fazê-lo do zero.
fonte