Proibir chamadas para funções / classes arbitrárias em código externo

12

Eu experimentei casos em que seria valioso restringir o acesso à API de bibliotecas e estruturas externas para evitar consequências negativas no sistema.

Por exemplo, em um aplicativo do SharePoint, pode parecer natural chamar spList.Items.GetItemByIdpara obter um item da lista, mesmo que seja em um loop, sem perceber que isso pode levar a enormes problemas de desempenho.

Também é possível que precisamos proibir o uso do SmtpClient para forçar todos a usar nossa própria classe para enviar email, para garantir que possamos proxy e zombar adequadamente de todos os emails no ambiente de teste.

Existem maneiras confiáveis ​​e razoavelmente diretas de obter essas restrições no código externo, exceto em determinados locais específicos do nosso próprio código? Não é necessário absolutamente sob todas as circunstâncias impedir o acesso a esses métodos / classes, por exemplo, por reflexão ou apenas algum tipo de desativação, deve ser um aviso estrito de que eles não devem ser usados. De preferência, forçando o programador a tomar ativamente medidas para substituir essas restrições, se possível / necessário.

Alex - Pare SE
fonte
11
Isso soa como uma imposição de uma forma extrema de estilo de codificação (proibido usar uma chamada de biblioteca específica). Então, para mim, isso levanta a questão de pré-requisito: você faz alguma revisão de código ou verificação de estilo em primeiro lugar?
Peter M
3
Você espera capturar e bloquear essas chamadas em tempo de execução ou tempo de compilação ?
MetaFight
1
Desde que você está usando C #, você já ouviu falar sobre o StyleCop ? Você sabe que pode criar regras personalizadas como quiser, certo?
Machado
10
" Existem formas confiáveis ​​e razoavelmente diretas de obter essas restrições no código externo, exceto em determinados locais específicos do nosso próprio código? ". Sim: escreva seu próprio Roslyn Analyzer para relatar o acesso a determinadas APIs como um erro de compilação.
22817 David Arno
3
@ Machado, StyleCop é efetivamente um produto morto. Ele está sendo substituído pelo StyleCopAnalyzers, construído sobre Roslyn. Definitivamente, não seria uma boa ideia investir tempo escrevendo regras personalizadas do StyleCop atualmente.
David Arno

Respostas:

8

Existem maneiras confiáveis ​​e razoavelmente diretas de obter essas restrições no código externo, exceto em determinados locais específicos do nosso próprio código?

Como a pergunta é especificamente sobre C #, existe uma solução baseada em compilador que pode ser usada aqui para impor essas regras: Roslyn Analyzers . Você pode escrever seu próprio analisador que relata o acesso a determinadas APIs como um erro ou aviso de compilação.

Um exemplo de conjunto de analisadores, que fornecem muitos códigos de exemplo ao escrever seus próprios, são os analisadores StyleCop , que substituem o antigo recurso StyleCop do C #.

Dito isto, essas verificações automatizadas sempre podem ser contornadas por pessoas determinadas a "violar as regras". Portanto, essa abordagem não substitui as revisões de código, conforme discutido na resposta de Karl Bielefeldt. Pode ajudar com essas revisões, mas não deve substituí-las.

David Arno
fonte
Nunca foi a intenção de substituir mais nada, estava apenas procurando uma ferramenta especializada para minha caixa de ferramentas.
Alex - Pare SE
25

Você pode fazer coisas demoradas, como escrever um invólucro em torno da API externa que exclui suas operações indesejadas, mas nada supera as análises de treinamento e de código, porque, independentemente dos padrões ou medidas técnicas que você colocar em prática, as pessoas encontrarão maneiras criativas de contorná-las .

Por exemplo, temos vários serviços escritos em Scala, e uma das coisas que pedimos no momento da revisão de código é a imutabilidade, mas geralmente o comunicamos como se livrar do vars. Alguém no outro dia usou um val x: ListBuffer [Boolean] para armazenar uma única variável mutável como o único item da lista. Você não pode atribuir outro ListBufferpara x, mas pode substituir os itens da lista no local o quanto quiser. Tão ruim quanto usar um var, mas mais furtivo.

Em outras palavras, você deve verificar se as pessoas estão contornando suas soluções técnicas. Se essas soluções técnicas são caras e aumentam a complexidade, você também pode apenas verificar se elas estão codificando corretamente.

Karl Bielefeldt
fonte
caramba, isso é sorrateiro!
whn
@snb É equivalente ao que o Java faz como um hack para contornar apenas poder retornar um objeto / valor e não ter argumentos de referência adequados; passando uma matriz que terá seu conteúdo atualizado. (Alguns exemplos: AtomicMarkableReference.gete AtomicStampedReference.get).
JAB
Obrigado pela sua resposta, mas definitivamente não estou interessado em fazer coisas complexas e demoradas, como escrever wrappers em torno do código externo. Isso provavelmente nem ajudaria, pois eles podem simplesmente ir à fonte. Essa resposta parece assumir que uma solução será cara e aumentará a complexidade. Que tal uma solução pura e simples?
Alex - Pare SE
1
@ Alex, a solução mais simples está aí: "nada supera o treinamento e as revisões de código".
Mr.Mindor
2
"nada supera fazê-lo manualmente" está certo até que alguém o automatize.
Ewan
0

A resposta de Karl está 100% correta. Não há como garantir a conformidade. No entanto, além das revisões de treinamento e código, considere o uso de ferramentas de análise estática para garantir a conformidade. (Nota: eu disse "além de", pois é possível contorná-las exatamente da mesma maneira que Karl afirmou).

A vantagem de usar ferramentas de análise estática é remover a tediosa análise de código humano, procurando instâncias de "uso múltiplo de IEnumerable" ou qualquer problema de desempenho da semana em que você está olhando (ou, pelo menos, que eu sempre sinto que estou olhando para). Isso permitirá que as revisões e o treinamento do código se concentrem em questões mais "interessantes".

Para C #, especificamente, incluí algumas sugestões abaixo. Conecte-os ao seu ambiente de construção e pronto. Mas, geralmente, não importa qual idioma você esteja usando, há uma ferramenta de análise estática disponível em algum lugar.

Copie / cole diretamente da página da Wikipedia, use a página da wiki para obter as informações e links mais recentes: https://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis#.NET

  • Plataforma do compilador .NET (Codename Roslyn) - estrutura de compilador de código-fonte aberto para C # e Visual Basic .NET, desenvolvida pela Microsoft .NET. Fornece uma API para analisar e manipular sintaxe.
  • CodeIt.Right - combina análise de código estático e refatoração automática às melhores práticas, o que permite a correção automática de erros e violações de código; suporta C # e VB.NET.
  • CodeRush - Um plug-in para o Visual Studio que alerta os usuários sobre violações das práticas recomendadas.
  • FxCop - Análise estática gratuita para programas Microsoft .NET que compila com o CIL. Autônomo e integrado em algumas edições do Microsoft Visual Studio; pela Microsoft.
  • NDepend - simplifica o gerenciamento de uma base de código .NET complexa, analisando e visualizando dependências de código, definindo regras de design, fazendo análises de impacto e comparando diferentes versões do código. Integra-se ao Visual Studio.
  • Parasoft dotTEST - Um plug-in de análise estática, teste de unidade e revisão de código para o Visual Studio; trabalha com linguagens para Microsoft .NET Framework e .NET Compact Framework, incluindo C #, VB.NET, ASP.NET e C ++ gerenciado.
  • Sonargraph - Suporta C #, Java e C / C ++, com foco em análise de dependência, verificação automatizada de arquitetura, métricas e a capacidade de adicionar métricas personalizadas e verificadores de código.
  • StyleCop - Analisa o código fonte do C # para impor um conjunto de regras de estilo e consistência. Pode ser executado de dentro do Microsoft Visual Studio ou integrado a um projeto MSBuild.
Reginald Blue
fonte
-1

Para elaborar a sugestão "treinamento e revisão de código" apresentada em outra resposta: como o código que você deseja proibir é o código legal, você não pode contar com o compilador que o impede e precisará confiar em um processo posterior, A revisão.

Isso pode (e deve) incluir etapas de revisão manual e automática:

  • Prepare uma lista de verificação de problemas conhecidos e repasse-os em suas revisões de código manuais, uma por uma. Tenha uma reunião recorrente para revisar e atualizar a lista de verificação. Sempre que um bug desagradável for detectado e analisado, adicione-o à lista de verificação.

  • Adicione regras de check-in para procurar padrões conhecidos. Isso pode ser complicado de escrever, mas para um projeto grande, com o tempo, pode ser útil. O TFS permite escrever regras em C #, e outros sistemas de construção têm seus próprios ganchos. Considere usar construções fechadas para rejeitar check-ins que correspondem ao padrão. Sim, atrasa o desenvolvimento, mas após um certo tamanho e complexidade do projeto, desacelerar os desenvolvedores pode ser uma coisa boa.

Avner Shahar-Kashtan
fonte
-1

Talvez o compilador possa ajudá-lo a capturar chamadas indesejadas.

Renomeie as classes / métodos de código em sua própria lib que não devem ser usados ​​por clientes externos da lib. Alternativamente, torne as classes / métodos internos e adicione internos visíveis para as classes que têm permissão para usá-los.

Usuários de bibliotecas externas obterão um método / classe de erro de compilação não encontrado.

Classes / métodos proibidos de bibliotecas públicas: crie o mesmo espaço para nome / classe / método em sua biblioteca

Usuários de bibliotecas externas receberão um erro de compilação devido à classe duplicada encontrada

[atualizar]

Não é necessário absolutamente em todas as circunstâncias impedir o acesso a esses métodos / classes, por exemplo, por reflexão ou apenas algum tipo de desativação, ....

forçando o programador (... cliente da lib ...) a tomar ativamente medidas para substituir essas restrições, se possível / necessário.

k3b
fonte
Voto negativo, não apenas porque é um hack desagradável, mas é facilmente contornado com C # (com o qual o OP marcou a pergunta) usando aliases externos .
David Arno