Como você aborda conflitos de dependência transitiva que são conhecidos apenas em tempo de execução? [fechadas]


9

Como você normalmente aborda problemas de dependência transitiva que ocorrem em tempo de execução em grandes projetos de software?

Nas últimas três semanas, tenho tentado iniciar um componente de um grande software dentro de outro componente do software, mas ele morre intermitentemente devido a problemas de dependência transitiva que são conhecidos apenas em tempo de execução.

Por problemas de dependência transitiva, quero dizer que certas dependências das dependências de um determinado projeto colidem com outras dependências no tempo de execução, causando instabilidade ou falha instantânea.

Existem centenas e centenas de dependências em uso e há aproximadamente 50 subprojetos associados à ferramenta, que são trabalhados isoladamente por outras equipes, em que todos os módulos possuem dependências profundamente aninhadas entre si. Ninguém sabe para que servem todos os subprojetos, dada a escala e a complexidade do projeto.

Nessa situação, você tentaria gerar uma representação visual do DAG para cada uma das dependências do componente afetado e tentaria determinar onde colisões podem ocorrer no tempo de execução? Não tenho controle sobre como as dependências são gerenciadas em outros subprojetos e não posso alterar nenhum código Java que tenha sido escrito por outros desenvolvedores

As soluções apresentadas apenas funcionam por uma ou duas horas e, em seguida, param de funcionar devido a alterações nos componentes upstream. Um exemplo de um componente upstream é um artefato no qual o projeto em que estou trabalhando depende do qual é construído em um estágio anterior no pipeline de IC.


A pedido de outras pessoas , incluirei informações sobre qual tecnologia está sendo usada, correndo o risco de encerrar a pergunta por fornecer informações demais ou o corpo ficar muito longo:

  • Maven é usado para gerenciamento de dependências; e
  • A mola é usada como um recipiente DI;
  • A maioria dos problemas de dependência envolve sobreposição de contextos de bean como resultado dos contextos de outros módulos serem carregados no tempo de execução
  • O produto funciona corretamente, e existem inúmeros cordões de testes de unidade e testes de integração para evitar a correção funcional do programa

Em geral, estou procurando uma abordagem independente de idioma para identificar maneiras de resolver conflitos de dependência sem enumerar todas as combinações possíveis das dependências de um determinado projeto.

Não consigo re-arquitetar o projeto, adicionar portas de qualidade adicionais, promover mudanças de paradigma na empresa ou alternar idiomas como uma resolução.


Você está falando de algo como o contêiner de DI não está configurado corretamente para saber que, para o IFoo, use o IFooImpl?
Andy

Não, é mais como o pacote (b) no projeto (b) é uma dependência transitiva do pacote (a) no projeto (A), mas (B) é introduzido apenas em tempo de execução. Todo o software funciona a partir do que eu sei, mas só preciso do conjunto apropriado de dependências para permitir que todas as dependências transitivas sejam resolvidas adequadamente. Existem conjuntos de dependências que permitirão que o produto seja iniciado corretamente, mas essas configurações são muito frágeis. Como desenvolvedor júnior. Eu não tenho controle sobre isso.
Tyler

2
Vamos lá, "questão da dependência" é um termo muito genérico, e todo mundo que lê isso provavelmente imagina algo diferente. Para softwares do mundo real, isso depende da tecnologia; portanto, dê um exemplo real de uma tecnologia específica que você tem em mente. Os problemas estão surgindo porque faltam componentes necessários? Ou porque uma versão errada é fornecida? Que tipo de mecanismo de resolução de dependência já existe? Por favor, esclareça.
Doc Brown

11
No mundo .Net, resolvo esse problema apenas instalando os pacotes no meu projeto principal de aplicativo. Embora nenhum código de aplicativo realmente use as bibliotecas de plug-ins diretamente, o compilador .Net garante que a DLL esteja no local certo durante a compilação e, portanto, a implantação.
Andy

2
"Não tenho controle sobre como as dependências são gerenciadas e não posso alterar nenhum código" - o que realmente você pode alterar? Se você não pode mudar nada, a pergunta parece inútil.
Doc Brown

Respostas:


6

Pode ser possível resolver seu problema usando carregadores de classes customizados para dar a cada módulo no aplicativo seu próprio ambiente de execução.

Basicamente, você definiria um ambiente principal que consiste em um pequeno kernel do aplicativo, juntamente com quaisquer dependências que sejam universalmente acordadas e todas as interfaces necessárias para que os módulos se comuniquem. Em seguida, cada módulo que você carrega obtém seu próprio carregador de classes que pode acessar (1) classes do ambiente de tempo de execução, (2) classes do núcleo do aplicativo e (3) classes desse módulo e suas dependências diretas. Toda a comunicação entre módulos passa por interfaces definidas no núcleo, para que nenhum módulo dependa diretamente de outro.

Essa técnica é usada em servidores de aplicativos para permitir que os aplicativos tenham dependências que de outra forma entrariam em conflito, para que você possa ver uma implementação funcional da técnica, por exemplo, no Tomcat (e, se tiver sorte, poderá usar o Tomcat) implementação com poucas alterações).


11
Não tenho permissão para reprojetar o projeto para resolver o problema de dependência. Mudar para uma arquitetura semelhante ao microkernel seria bem legal, no entanto.
Tyler

2
@ Tyler: no entanto, acho que essa é uma resposta boa e genérica para a parte genérica da pergunta.
Doc Brown

11
Isso soa um pouco como osgi.
SpaceTrucker 26/08/15

4

Nunca trabalhei com Maven ou Spring, mas para fornecer uma resposta genérica a uma pergunta genérica: quando se trata de problemas de dependência, seu sistema deve ser projetado para detectá-los o mais cedo possível e quando esses problemas são detectados , eles devem ser sinalizados imediatamente, incluindo sua possível causa.

Idealmente, esse momento não está no "tempo de execução da produção". O melhor momento é o "tempo de construção", mas isso parece impossível no seu caso. Portanto, a segunda melhor opção são os testes de tempo de execução. Você nos disse que existem "testes de integração", mas como eles não detectam os problemas de dependência, eles parecem estar incompletos ou não testam colisões de dependência em geral. É aí que você deve começar a tentar resolver o problema.

Além disso, para tornar os testes mais eficazes, seus componentes precisam "falhar rapidamente" quando surge um problema de dependência. Isso significa que, assim que uma dependência é resolvida e um componente é carregado, possíveis colisões de dependência devem ser verificadas e sinalizadas imediatamente. Se o sistema funcionar pela primeira vez por uma hora antes que uma colisão seja detectada, fica muito difícil identificar a causa do problema. Não sei se o Maven / Spring já fornece uma estratégia interna de "falha rápida", mas se esse não for o caso, tente pensar nessa direção.

Para mitigar problemas na produção, seu sistema deve ser projetado para não morrer completamente quando ocorrer uma colisão de dependência com um subcomponente menos importante envolvido. A falha não deve ser mascarada, é claro, mas o sistema deve idealmente rejeitar o carregamento desse componente, registrar e / ou sinalizar o problema e permanecer em um estado estável. Quando o componente é carregado primeiro, o sistema fica instável e você detecta o problema somente depois; provavelmente, você terá que desligar e reiniciar o sistema completamente, o que eu acho que é algo que você deseja evitar.

Por exemplo, se o seu sistema for uma loja virtual e o sub-módulo para "assinatura de boletim informativo" não puder ser carregado por algumas horas, isso pode ser mais facilmente tolerado como se a loja inteira não funcionasse mais.

Finalmente, isso pode não ser uma opção no seu caso, mas se os componentes puderem ser executados com melhor isolamento uns dos outros, e se isso puder evitar colisões de dependência, essa pode ser uma abordagem que vale a pena pensar.


2

Considere isso comigo pensando em voz alta aqui. Dependendo dos requisitos / restrições de tempo, posso considerar isso:

1) crie uma lista de interfaces e suas implementações (usando reflexão, se disponível)

2) crie uma espécie de wrapper em torno do seu DI. Quando um DI é solicitado a fornecer uma implementação concreta, verifique se já existe uma regra de DI; se a regra existe - basta retornar o que seu DI fornece; caso contrário, se houver uma única implementação de uma interface e você puder criar uma instância - log e retornar uma instância; caso contrário, faça logon e falhe.

Depende de como você deseja se envolver, eu acho, mas eventualmente você só quer ter uma lista completa do que requer o que - essa solução acabará gerando essa lista.

No entanto, sem dúvida isso é muito trabalhoso e não é confiável - e se você tiver uma condição estranha que exija certa dependência uma vez na lua azul?

O que você quer dizer quando diz "alterações nos componentes upstream"?


Desculpe, eu não queria fornecer muitas informações básicas - quando descrevo o ambiente operacional, as perguntas são geralmente negadas e queimadas até a morte. Vou atualizar a pergunta original com uma seção de definições.
Tyler

2

Se eu o seguir corretamente, o problema é que o código que você precisa usar depende do tempo de execução dos módulos expressos no Spring XML, mas o maven não é informado sobre eles. Portanto, quando você os usa, as coisas que eles precisam (as dependências transitivas) não estão no seu caminho de classe e não fazem o que deveriam.

Eu acho que quando você pergunta aos seus colegas 'como faço para que isso funcione?', Eles dizem 'obviamente você precisa desta lista de 35 módulos e versões , como você pode não saber disso?'

Presumivelmente, quando o teste de integração é concluído, os módulos necessários são declarados como dependências de teste. Portanto, a solução sistemática é configurar inspeções dos pom's de teste de integração para garantir que eles tenham apenas ferramentas de teste de terceiros declaradas como dependências de teste. Isso pode até ser automatizado pelo plugin maven enforcer .

Aparentemente, você não pode fazer isso, então sua melhor opção provavelmente é encontrada aqui .


É exatamente o que está acontecendo, pelo que posso dizer. Até agora, estou manipulando 30 dependências e ajustando os escopos para eliminar colisões, mas a revisão por pares é o que é necessário aqui.
Tyler
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.