Cuando desarrollo software, a menudo tengo una biblioteca 'central' centralizada que contiene código útil que puede ser compartido y referenciado por diferentes proyectos.
Ejemplos:
- un conjunto de funciones para manipular cadenas
- expresiones regulares de uso común
- código de implementación común
Sin embargo, algunos de mis colegas parecen estar alejándose de este enfoque. Tienen inquietudes como la sobrecarga de mantenimiento del código de reevaluación utilizado por muchos proyectos una vez que se soluciona un error. Ahora estoy reconsiderando cuándo debería estar haciendo esto.
¿Cuáles son los problemas que hacen que usar una biblioteca 'núcleo' sea una mala idea?
code-reuse
libraries
Alex Angas
fuente
fuente
Respuestas:
Las bibliotecas principales son malas cuando comienzan a sufrir un deslizamiento de características y muy malas cuando no están bien mantenidas.
Puede encontrar este artículo interesante para un punto de vista extendido (con el que estoy totalmente de acuerdo):
http://www.yosefk.com/blog/redundancy-vs-dependencies-which-is-worse.html
Don Knuth: "Para mí, el 'código reeditable' es mucho, mucho mejor que una caja negra o un juego de herramientas intocables ... nunca me convencerás de que el código reutilizable no es principalmente una amenaza".
fuente
Usar la idea de que una biblioteca central es mala cuando varios proyectos dependen de ella, es como decir que no debes usar jQuery para la web, libxml en tus aplicaciones * nix, o cualquier otro marco o biblioteca. Mire todo el ecosistema del desarrollo moderno (DRY, OOP, etc.) y cada aplicación está construida a partir de un conjunto de bibliotecas y marcos.
Lo que puede ser malo es si no tiene ningún tipo de pruebas unitarias, no realiza una prueba de regresión y no utiliza ningún tipo de API / ABI con su biblioteca. Si todas sus aplicaciones tienen pruebas adecuadas, su biblioteca tiene pruebas adecuadas, y se asegura de que si interrumpe las llamadas de función, actualice el número de versión de la API adecuadamente.
Para una cobertura completa, lo que probablemente uno desearía es cuando se realicen cambios en la Biblioteca, puede ejecutar un conjunto de pruebas que verifiquen que la API no se haya roto y que la ejecución de todo el código esté libre de errores. Luego puede incorporar la última actualización de la biblioteca a su aplicación y ejecutar el mismo conjunto de pruebas. Si actualiza la API, debe documentarse para que sepa qué debe hacer en su aplicación para actualizarla. De cualquier manera, cuando ejecuta las pruebas para su aplicación, puede estar tan seguro como en sus pruebas de que nada se ha roto.
Al usar jquery, mootools, cualquier biblioteca o framework javascript, no puede usar ciegamente la nueva versión, lamentablemente no puede incluso con una versión menor de 1.6.z a veces.
fuente
Si tiene un conjunto completo de pruebas unitarias para la biblioteca principal; Eso no es un problema. No se registrará ningún código a menos que se pasen todas las pruebas. Si introduce un defecto, escribe una prueba fallida para reproducir el defecto y corregirlo; entonces siempre estarás probando ese error también. Siempre.
Además, la funcionalidad que describe es muy fácil de escribir para pruebas unitarias.
Como un problema secundario, es posible que desee tener más de una biblioteca principal para no tener que incluir el código RegEx a menos que lo desee.
fuente
Ofreceré una versión ligeramente diferente de esto. ¡Una biblioteca central, en muchos casos, es una excelente idea!
Si tiene dos proyectos separados, deben estar en dos depósitos de código separados. Ahora dependen de una funcionalidad común. Consideremos, por ejemplo, las aplicaciones de procesamiento de paquetes. La funcionalidad común puede incluir:
Ahora, diferentes aplicaciones de procesamiento de paquetes pueden necesitar un subconjunto diferente de estos. ¿Debería implementar una biblioteca central con un repositorio de código fuente, o debería tener 18 repositorios diferentes para cada uno de estos módulos? Recuerde que estos módulos pueden tener interdependencias, por lo que la mayoría de estos módulos pueden depender, por ejemplo, del módulo misceláneo.
Afirmaré que tener una biblioteca central es el mejor enfoque. Reduce la sobrecarga de muchos repositorios de código fuente. Reduce el infierno de dependencias: una versión particular de los asignadores de memoria puede necesitar una versión particular de un módulo misceláneo. ¿Y si desea que la versión 1.7 del asignador de memoria dependa de varios 2.5 y la versión 1.2 del árbol AVL según varios 2.6? Es posible que no pueda vincular varios 2.5 y 2.6 varios al mismo tiempo a su programa.
Entonces, adelante e implemente la siguiente estructura:
He visto que cambiar a este tipo de estructura desde la estructura:
Ha llevado a un mantenimiento reducido y a un mayor intercambio de código a través de mecanismos sin copia.
También he visto proyectos que utilizan la siguiente estructura:
... y el infierno de dependencia y la proliferación de números de repositorio han sido problemas genuinos.
Ahora, ¿debería usar una biblioteca de código abierto existente en lugar de escribir la suya propia? Necesitas considerar:
Usualmente uso la regla de que todo lo que esté por debajo de 1000 líneas de código que no requiera algo más allá de la experiencia del programador debe implementarse por su cuenta. Nota: las 1000 líneas incluyen pruebas unitarias. Por lo tanto, no recomendaré escribir 1000 líneas de código por su cuenta si requiere 10 000 líneas adicionales para las pruebas unitarias. Para mis programas de procesamiento de paquetes, esto significa que los únicos componentes externos que he usado son:
Algunas cosas que he implementado por mi cuenta porque son simples incluyen incluso cosas como:
... porque las implementaciones personalizadas de estos pueden permitir una gran alineación, lo que lleva a un rendimiento mejorado.
No hago criptografía; si lo hiciera, agregaría algún tipo de biblioteca criptográfica en la lista, ya que escribir algoritmos criptográficos por su cuenta puede ser susceptible a ataques de temporización de caché, incluso si puede con pruebas exhaustivas de la unidad, demuestre que son compatibles con los algoritmos oficiales.
fuente
Una biblioteca central puede ser mala cuando varios proyectos dependen de ella, no solo tiene que probar los cambios en su núcleo, sino que también tiene que hacer una prueba de regresión en cada proyecto dependiente. En segundo lugar, sus API principales nunca pueden cambiar porque tendrá que refactorizar cada proyecto dependiente. Cuantos más proyectos utilicen su biblioteca, más profunda será la trampa.
Otro problema es la tendencia a comenzar a arrojar todo lo "común" en su biblioteca central, hincharlo y hacer que sea más difícil sacar piezas pequeñas. Solo diré que una vez escuché de un lugar que temía tocar cualquiera de sus numerosas bibliotecas principales, la sobrecarga de las pruebas de regresión de control de calidad fue tan grande.
En cambio, ¿tal vez pueda crear un recurso de fragmento de código para permitir que los equipos de proyecto busquen y obtengan el código que necesitan y se separen de cualquier problema de mantenimiento o regresión? Eso es lo que hago en casa, de todos modos.
fuente
Un punto aún no mencionado es que cualquier código tendrá dependencias de algo , incluso si es literalmente lo único que se ejecuta en la ROM de un microcontrolador incorporado; Si el fabricante del controlador cambia algún comportamiento en el que se basa el código, el código tendrá que modificarse para que funcione en los chips fabricados después del cambio, o de lo contrario los fabricantes del dispositivo que usa el código tendrán que adquirir de alguna manera los chips que sí lo hacen. no incorpore el cambio, posiblemente pagando una prima de precio por ellos.
El uso de una biblioteca para realizar varias funciones de hardware puede significar que el código ahora depende de una biblioteca, mientras que no lo había sido anteriormente, pero también puede eliminar las dependencias entre el código y el hardware. Por ejemplo, un fabricante de chips podría prometer suministrar una biblioteca para todos los chips presentes y futuros que siempre realizarán ciertas funciones de E / S de cierta manera. El código que usa esa biblioteca para realizar esas funciones de E / S dependería del fabricante para proporcionar versiones apropiadas de esa biblioteca, pero ya no dependería del fabricante para usar la misma implementación de hardware de esas funciones.
Desafortunadamente, a menudo es difícil saber cuál es el enfoque correcto para el código a prueba de futuro. He visto casos en los que un proveedor de chips cambió la forma en que funcionaba una biblioteca (para acomodar nuevos chips), incluso cuando se usaba para acceder a un chip que había cambiado. También he visto casos en los que un fabricante de chips cambió la forma en que funcionaba su hardware, pero las bibliotecas suministradas se ajustaron adecuadamente, por lo que el código que usaba rutinas de biblioteca continuaría funcionando sin cambios, mientras que el código que accedía al hardware directamente tenía que ajustarse.
Situaciones similares existen con las aplicaciones de Windows. A veces, a Microsoft le encanta cambiar la forma en que las aplicaciones deben hacer las cosas; el código que usa ciertas bibliotecas para tales cosas puede actualizarse simplemente actualizando la biblioteca, mientras que el código que no usa bibliotecas que se actualizan para ellas debe actualizarse manualmente.
fuente
Quería contribuir con una versión ligeramente diferente de esto, aunque me encanta la
Denis de Bernardy
respuesta y el artículo vinculado sobre minimizar las dependencias frente a minimizar las redundancias (reflejan altamente mis propios pensamientos sobre este tema en el que creo que la reutilización del código es un acto de equilibrio).El mayor problema que tengo con una
core
biblioteca es este:Y creo que es muy probable que la respuesta sea " nunca ". Es posible que la gente siempre tenga la tentación de agregarlo, ya que modela una idea tan nebulosa, especialmente si esta biblioteca está evolucionando durante el desarrollo del software en lugar de tener objetivos anticipados por adelantado. Y tal vez agregar a la biblioteca no sea lo peor del mundo, ya que no romperá las dependencias existentes de la biblioteca, pero con objetivos tan nebulosos, la biblioteca podría volverse cada vez más ecléctica y fea, proporcionando una funcionalidad dispareja en la que alguien interesado en el uso de la biblioteca solo puede encontrar una pequeña porción de ella aplicable a sus necesidades.
Las dependencias en su base de código idealmente deberían fluir hacia paquetes muy estables. Un
core
paquete podría encontrarse fácilmente muy inestable, mientras que grandes porciones de su base de código tienen dependencias que fluyen hacia él.Así que creo que vale la pena dividir la biblioteca en bibliotecas más uniformes dedicadas a hacer algo más específico que simplemente, "biblioteca central de cualquier cosa que la gente pueda necesitar con frecuencia" para que pueda crecer en una dirección más uniforme con una mejor coordinación entre sus compañeros de equipo sobre exactamente lo que debería y, lo que es más importante, no debería hacer, y potencialmente alcanzar un punto de estabilidad en el que esté bien probado y no sientas que hay que agregarle nada más para que sea relativamente " completo "y estable (como en, inmutable).
fuente
Escribir bibliotecas para cosas básicas como cadenas y listas vinculadas es bastante tonto en este milenio. Use un lenguaje de programación incluido con baterías que ya tenga la funcionalidad principal.
Si le gusta escribir bibliotecas centrales de soporte en tiempo de ejecución solo por diversión, diseñe un nuevo lenguaje de programación. Si haces eso en una aplicación, esencialmente estás desarrollando un lenguaje fuera de su lado.
Además, ¿alguien no ha escrito N bibliotecas principales diferentes en el idioma que está utilizando? Investigar los marcos existentes y elegir el más adecuado puede ser un mejor uso del tiempo que hacerlo desde cero.
fuente