Prohibir llamadas a funciones / clases arbitrarias en código externo

12

He experimentado casos en los que sería valioso restringir el acceso a la API de bibliotecas y marcos externos para evitar consecuencias negativas en el sistema.

Por ejemplo, en una aplicación de SharePoint puede parecer natural llamar spList.Items.GetItemByIdpara obtener un elemento de la lista, incluso tal vez en un bucle, sin darse cuenta de que esto puede conducir a grandes problemas de rendimiento.

También podría ser que debamos prohibir el uso de SmtpClient para obligar a todos a usar nuestra propia clase para enviar correos electrónicos, para asegurarnos de que podamos usar proxy y burlarnos de todos los correos electrónicos en el entorno de prueba.

¿Hay alguna forma confiable y razonablemente directa de lograr estas restricciones en el código externo, excepto desde ciertos lugares específicos en nuestro propio código? No es necesario, bajo ninguna circunstancia, impedir el acceso a estos métodos / clases, por ejemplo, por reflexión o simplemente por algún tipo de deshabilitación, más bien debería ser una advertencia estricta de que no deberían usarse. Preferiblemente, forzar al programador a tomar medidas activas para anular estas restricciones si es posible / necesario.

Alex
fuente
11
Esto suena como la imposición de una forma extrema de estilo de codificación (Prohibido usar una llamada de biblioteca particular). Entonces, para mí, surge la pregunta de requisito previo: ¿hace revisiones de código o verificaciones de estilo en primer lugar?
Peter M
3
¿Espera atrapar y bloquear estas llamadas en tiempo de ejecución o tiempo de compilación ?
MetaFight el
1
Como estás usando C #, ¿alguna vez has oído hablar de StyleCop ? Sabes que puedes crear reglas personalizadas a tu gusto, ¿verdad?
Machado
10
" ¿Hay alguna forma confiable y razonablemente sencilla de lograr estas restricciones en el código externo, excepto desde ciertos lugares específicos en nuestro propio código? ". Sí: escriba su propio Roslyn Analyzer para informar que el acceso a ciertas API es un error de compilación.
David Arno
3
@Machado, StyleCop es efectivamente un producto muerto. Se está reemplazando con StyleCopAnalyzers, que está construido sobre Roslyn. Definitivamente no sería una buena idea invertir tiempo en escribir reglas personalizadas de StyleCop en estos días.
David Arno

Respuestas:

8

¿Hay alguna forma confiable y razonablemente directa de lograr estas restricciones en el código externo, excepto desde ciertos lugares específicos en nuestro propio código?

Como la pregunta es específicamente sobre C #, hay una solución basada en compilador que se puede usar aquí para hacer cumplir tales reglas: Roslyn Analyzers . Podría escribir su propio analizador que informa que accede a ciertas API como un error de compilación o advertencia.

Un conjunto de ejemplos de analizadores, que proporcionan muchos códigos de ejemplo al escribir el suyo, son los analizadores StyleCop , que son un reemplazo de la antigua función StyleCop para C #.

Dicho esto, tales controles automáticos siempre pueden ser solucionados por personas decididas a "romper las reglas". Por lo tanto, este enfoque no es un sustituto de las revisiones de código como se discutió en la respuesta de Karl Bielefeldt. Puede ayudar con tales revisiones, pero no debe reemplazarlas.

David Arno
fuente
Nunca fue la intención reemplazar nada más, solo estaba buscando una herramienta especializada para mi caja de herramientas.
Alex
25

Puede hacer cosas que requieren mucho tiempo, como escribir un contenedor alrededor de la API externa que omita sus operaciones no deseadas, pero nada supera la capacitación y las revisiones de código, porque cualquiera que sea el estándar o las medidas técnicas que implemente, las personas encontrarán formas creativas de sortearlas. .

Por ejemplo, tenemos varios servicios escritos en Scala, y una de las cosas que pedimos en el momento de la revisión del código es la inmutabilidad, pero a menudo lo comunicamos como deshacerse de él vars. Alguien el otro día usó un val x: ListBuffer [Boolean] para mantener una sola variable mutable como el único elemento en la lista. No puede asignar otro ListBuffera x, pero puede reemplazar los elementos de la lista en su lugar tanto como desee. Tan malo como usar un var, pero más astuto.

En otras palabras, debe verificar si las personas están analizando sus soluciones técnicas. Si esas soluciones técnicas son costosas y agregan complejidad, también puede verificar que lo estén codificando correctamente.

Karl Bielefeldt
fuente
¡Maldita sea eso es astuto!
cuando el
@snb Es equivalente a lo que Java hace como un truco para moverse solo para poder devolver un objeto / valor y no tener argumentos de referencia adecuados; pasando una matriz en su lugar que tendrá sus contenidos actualizados. (Algunos ejemplos: AtomicMarkableReference.gety AtomicStampedReference.get).
JAB
Gracias por su respuesta, pero definitivamente no estoy interesado en hacer cosas complejas que consumen mucho tiempo, como escribir envoltorios alrededor del código externo. Eso probablemente ni siquiera ayudaría, ya que solo pueden ir a la fuente. Esta respuesta parece suponer que una solución será costosa y agregará complejidad. ¿Qué pasa con una solución pura y simple?
Alex
1
@Alex, la solución más simple está ahí: "nada supera la capacitación y las revisiones de código".
Mr.Mindor
2
"No hay nada mejor que hacerlo manualmente" es correcto hasta que alguien lo automatice.
Ewan
0

La respuesta de Karl es 100% correcta. No hay forma de garantizar la conformidad. Sin embargo, además de la capacitación y las revisiones de código, considere el uso de herramientas de análisis estático para garantizar el cumplimiento. (Nota: dije "además de", ya que también se pueden omitir exactamente de la misma manera que Karl declaró).

La ventaja de usar herramientas de análisis estático es la de eliminar el tedioso análisis de código humano en busca de casos de "uso múltiple de IEnumerable" o cualquier problema de rendimiento de la semana que esté viendo (o, al menos, siempre siento que estoy mirando a). Esto permitirá que las revisiones y la capacitación del código se centren en temas más "interesantes".

Para C #, específicamente, he incluido algunas sugerencias a continuación. Conéctelos a su entorno de compilación y listo. Pero, en general, no importa qué idioma esté usando, hay una herramienta de análisis estático en alguna parte.

Copie / pegue directamente desde la página de Wikipedia, use la página wiki para obtener la información y los enlaces más recientes: https://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis#.NET

  • .NET Compiler Platform (Codename Roslyn): marco de compilación de código abierto para C # y Visual Basic .NET desarrollado por Microsoft .NET. Proporciona una API para analizar y manipular la sintaxis.
  • CodeIt.Right: combina el análisis de código estático y la refactorización automática a las mejores prácticas que permiten la corrección automática de errores e infracciones de código; admite C # y VB.NET.
  • CodeRush: un complemento para Visual Studio que alerta a los usuarios sobre violaciones de las mejores prácticas.
  • FxCop: análisis estático gratuito para programas de Microsoft .NET que compila a CIL. Independiente e integrado en algunas ediciones de Microsoft Visual Studio; por Microsoft.
  • NDepend: simplifica la administración de una base de código .NET compleja mediante el análisis y la visualización de dependencias de código, al definir reglas de diseño, al hacer un análisis de impacto y al comparar diferentes versiones del código. Se integra en Visual Studio.
  • Parasoft dotTEST: un complemento de análisis estático, pruebas unitarias y revisión de código para Visual Studio; funciona con lenguajes para Microsoft .NET Framework y .NET Compact Framework, incluidos C #, VB.NET, ASP.NET y Managed C ++.
  • Sonargraph: admite C #, Java y C / C ++ con un enfoque en análisis de dependencia, verificación de arquitectura automatizada, métricas y la capacidad de agregar métricas personalizadas y verificadores de código.
  • StyleCop: analiza el código fuente de C # para aplicar un conjunto de reglas de estilo y coherencia. Puede ejecutarse desde el interior de Microsoft Visual Studio o integrarse en un proyecto de MSBuild.
Azul Reginald
fuente
-1

Para ampliar la sugerencia de "capacitación y revisión de código" planteada en otra respuesta: dado que el código que desea prohibir es el código legal, no puede contar con que el compilador lo impida, y tendrá que confiar en un proceso posterior, La revisión.

Esto puede (y debe) incluir pasos de revisión manual y automática:

  • Prepare una lista de verificación de problemas conocidos y revísela en sus revisiones de código manuales, una por una. Tenga una reunión periódica para revisar y actualizar la lista de verificación. Siempre que se detecte y analice un error desagradable, agréguelo a la lista de verificación.

  • Agregue reglas de verificación para buscar patrones conocidos. Esto puede ser complicado de escribir, pero para un proyecto grande, con el tiempo, puede ser útil. TFS le permite escribir reglas en C #, y otros sistemas de compilación tienen sus propios ganchos. Considere usar compilaciones cerradas para rechazar registros que coincidan con el patrón. Sí, ralentiza el desarrollo, pero después de un cierto tamaño y complejidad del proyecto, reducir la velocidad de los desarrolladores puede ser algo bueno.

Avner Shahar-Kashtan
fuente
-1

Quizás el compilador pueda ayudarlo a capturar llamadas no deseadas.

Cambie el nombre de las clases / métodos de código en su propia biblioteca que no deberían ser utilizados por clientes externos de la biblioteca. Alternativamente, haga que las clases / métodos sean internos y agregue elementos internos visibles para aquellas clases que pueden usarlos.

Los usuarios externos de lib obtendrán un método / clase de error de compilación no encontrado.

Clases / métodos prohibidos de las bibliotecas públicas: cree el mismo espacio de nombres / clase / método en su biblioteca

Los usuarios de lib externos obtendrán un error de compilación debido a la clase duplicada encontrada

[actualizar]

No es necesario, bajo ninguna circunstancia, impedir el acceso a estos métodos / clases, por ejemplo, por reflexión o simplemente algún tipo de desactivación ...

obligando al programador (... cliente de la lib ...) a tomar medidas activas para anular estas restricciones si es posible / necesario.

k3b
fuente
Votar a favor de esto, no solo porque es un truco desagradable, sino que se soluciona fácilmente con C # (con el cual el OP ha etiquetado la pregunta) usando alias externos .
David Arno