2008-12-03 22 views
67

Subversion le permite incrustar copias de trabajo de otros repositorios usando externals, lo que permite un control de versión fácil de software de biblioteca de terceros en su proyecto.¿La subversión es externa a un antipatrón?

Si bien estos parecen ideales para la reutilización de las bibliotecas y de control de versiones de vendor software, no están exentos de their critics:

Por favor, no use externas de Subversion (o similares en otras herramientas), que son una antipatrón y, por lo tanto, innecesaria

¿Hay riesgos ocultos en el uso de elementos externos? Por favor explique por qué serían considerados antipatrón.

+0

Ver también esta respuesta: http://stackoverflow.com/a/248367/29152. – DuckMaestro

+0

He visto mejores preguntas que las señaladas por los moderadores como inadecuadas para los foros de desbordamiento de pila debido a la naturaleza subjetiva de las posibles respuestas. Es bastante extraño lo inconsistentes que son los moderadores al marcar preguntas cuando, en algunos casos, las respuestas posteriores no están permitidas. – shawn1874

Respuesta

70

Soy el autor de la cita en la pregunta, que vino de un previous answer.

Jason tiene razón al desconfiar de declaraciones breves como la mía, y pedir una explicación. Por supuesto, si explicara completamente todo en esa respuesta, necesitaría haber escrito un libro.

Mike también tiene razón al señalar que uno de los problemas con una característica de svn:external es que los cambios en la fuente de destino podrían romper su propia fuente, especialmente si esa fuente de destino está en un repositorio que no es de su propiedad.

Al explicar más mi comentario, permítanme decir primero que hay formas "seguras" de utilizar la característica svn:external, al igual que con cualquier otra herramienta o función. Sin embargo, me refiero a él como antipattern porque la característica es mucho más probable que se use incorrectamente. En mi experiencia, siempre se ha usado mal, y es muy poco probable que alguna vez lo use de esa manera segura ni recomiende ese uso. Tenga en cuenta que no me refiero al menosprecio al equipo de Subversion. Me encanta Subversion, aunque tengo la intención de pasar a Bazar.

El principal problema con esta característica es que fomenta y se utiliza normalmente para vincular directamente el origen de una compilación ("proyecto") a la fuente de otra, o para vincular el proyecto a un archivo binario (DLL, JAR , etc.) de lo que depende. Ninguno de estos usos es sabio, y constituyen un antipatrón.

Como dije en mi otra respuesta, creo que un principio esencial para las compilaciones de software es que cada proyecto construye exactamente UN entregas binarias o primarias. Esto se puede considerar una aplicación del principio de separation of concerns al proceso de compilación. Esto es particularmente cierto con respecto a un proyecto que hace referencia directamente a la fuente de otro, que también es una violación del principio de encapsulation. Otra forma de este tipo de infracción es intentar crear una jerarquía de compilación para construir un sistema o subsistema completo mediante la invocación recursiva de subconstrucciones. Maven recomienda encarecidamente/impone este comportamiento, que es una de las muchas razones por las que no lo recomiendo.

Finalmente, considero que hay varias cuestiones prácticas que hacen que esta característica sea indeseable. Por un lado, svn:external tiene algunas características de comportamiento interesantes (pero los detalles se me escapan por el momento). Por otro lado, siempre encuentro que necesito tales dependencias para ser explícitamente visibles para mi proyecto (proceso de compilación), no oculto como algunos metadatos de control de origen.

Entonces, ¿cuál es una manera "segura" de usar esta función? Lo consideraría así cuando lo usa temporalmente una sola persona, como una forma de "configurar" un entorno de trabajo. Pude ver dónde un programador podría crear su propia carpeta en el repositorio (o uno para cada programador) donde configuraría los enlaces svn:external a las otras partes del repositorio en las que están trabajando actualmente. Luego, el pago de esa única carpeta creará una copia de trabajo de todos sus proyectos actuales. Cuando se agrega o finaliza un proyecto, las definiciones svn:external se pueden ajustar y la copia de trabajo se puede actualizar adecuadamente. Sin embargo, prefiero un enfoque que no esté vinculado a un sistema de control de fuente en particular, como hacer esto con un script que invoca los checkouts.

Para el registro, mi exposición más reciente a este problema ocurrió durante el verano de 2008 en un cliente de consultoría que usaba svn:external en una escala masiva: TODO fue reticulado para producir una única copia maestra de trabajo. Sus Ant & guiones de compilación basados ​​en Jython (para WebLogic) se construyeron sobre esta copia maestra de trabajo. El resultado neto: NADA podría construirse de forma independiente, había literalmente docenas de subproyectos, pero ninguno era seguro para pagar/trabajar por sí mismo. Por lo tanto, cualquier trabajo en este sistema primero requirió una verificación/actualización de más de 2 GB de archivos (también colocaron binarios en el repositorio). Hacer cualquier cosa fue un ejercicio inútil, y me fui después de intentar durante tres meses (también había muchos otros antipatritos presentes).

EDIT: exponer sobre recursiva construye -

lo largo de los años (sobre todo la última década), he construido sistemas masivos de las compañías Fortune 500 y grandes agencias gubernamentales que implican muchas docenas de sub-proyectos organizados en jerarquías de directorios que son muchos niveles profundos. He utilizado proyectos/soluciones de Microsoft Visual Studio para organizar sistemas basados ​​en .NET, Ant o Maven 2 para sistemas basados ​​en Java, y he comenzado a usar distutils y setuptools (easyinstall) para sistemas basados ​​en Python. Estos sistemas también han incluido enormes bases de datos típicamente en Oracle o Microsoft SQL Server.

He tenido un gran éxito diseñando estas construcciones masivas para facilitar el uso y la repetibilidad.Mi estándar de diseño es que un nuevo desarrollador puede aparecer en su primer día, recibir una nueva estación de trabajo (tal vez directamente de Dell con solo una instalación típica de sistema operativo), recibir un documento de configuración simple (generalmente solo una página de instrucciones de instalación). y poder configurar completamente la estación de trabajo y construir el sistema completo desde la fuente, sin supervisión, sin asistencia, y en medio día o menos. Invocar la compilación en sí implica abrir un shell de comando, cambiar al directorio raíz del árbol de origen y emitir un comando de una línea para compilar TODO.

A pesar de ese éxito, la construcción de un sistema de construcción tan masivo requiere gran cuidado y una adhesión estricta a principios sólidos de diseño, al igual que con la construcción de una aplicación/sistema masivo y crítico para el negocio. He descubierto que una parte crucial es que cada proyecto (que produce un artefacto/entregable único) debe tener un solo script de compilación, que debe tener una interfaz bien definida (comandos para invocar porciones del proceso de compilación), y debe mantenerse. solo de todos los otros (sub) proyectos. Históricamente, es fácil construir todo el sistema, pero es difícil/imposible construir solo una pieza. Recientemente, he aprendido a asegurarme cuidadosamente de que cada proyecto realmente se desarrolle solo.

En la práctica, esto significa que debe haber al menos dos capas de scripts de compilación. La capa más baja son los scripts de compilación del proyecto que producen cada producto/artefacto. Cada script reside en el directorio raíz de su árbol fuente del proyecto (de hecho, este script define su árbol fuente del proyecto), estos scripts no saben nada sobre el control fuente, esperan ejecutarse desde la línea de comando, hacen referencia a todo en el proyecto relativo al script de compilación, y hacen referencia a sus dependencias externas (herramientas o artefactos binarios, no a otros proyectos fuente) en función de algunas configuraciones configurables (variables de entorno, archivos de configuración, etc.).

La segunda capa de scripts de compilación también se debe invocar desde la línea de comandos, pero estos saben sobre el control de origen. De hecho, esta segunda capa es a menudo un único script que se invoca con un nombre de proyecto y una versión, luego verifica el origen del proyecto nombrado en un nuevo directorio temporal (tal vez especificado en la línea de comando) e invoca su script de compilación.

Puede ser necesario que haya más variaciones para acomodar servidores de integración continua, plataformas múltiples y varios escenarios de lanzamiento.

A veces existe la necesidad de una tercera capa de scripts que invoca la segunda capa de scripts (que invoca la primera capa) con el fin de crear subconjuntos específicos del conjunto de proyectos general. Por ejemplo, cada desarrollador puede tener su propia secuencia de comandos que crea los proyectos en los que están trabajando hoy. Puede haber un script para compilar todo con el fin de generar la documentación maestra o calcular métricas.

Independientemente, he encontrado que intentar tratar el sistema como una jerarquía de proyectos es contraproducente. Vincula los proyectos entre sí para que no se puedan compilar libremente solos o en ubicaciones arbitrarias (directorio temporal en el servidor de integración continua) o en un orden arbitrario (suponiendo que se satisfacen las dependencias). A menudo, intentar forzar una jerarquía rompe cualquier integración IDE que se pueda intentar.

Finalmente, construir una jerarquía masiva de proyectos puede ser simplemente demasiado intensivo en el rendimiento. Por ejemplo, durante la primavera de 2007, intenté una jerarquía de fuentes modesta (Java más Oracle) que construí utilizando Ant, que finalmente falló porque la compilación siempre abortaba con una excepción OutOfMemoryException de Java. Esto fue en una estación de trabajo RAM de 2 GB con un espacio de intercambio de 3,5 GB para el cual había sintonizado la JVM para poder usar toda la memoria disponible. La aplicación/sistema era relativamente trivial en términos de cantidad de código, pero las invocaciones de compilación recursivas eventualmente agotaron la memoria, sin importar la cantidad de memoria que le di. Por supuesto, también llevó una eternidad ejecutar también (30-60 minutos era común, antes de abortar). Sé cómo sintonizar MUY bien, pero al final simplemente estaba excediendo los límites de las herramientas (Java/Ant en este caso).

Así que hágase un favor, construya su compilación como proyectos independientes, luego compórtelos en un sistema completo. Mantenlo ligero y flexible. Disfrutar.

EDITAR: Más sobre antipatrones

en sentido estricto, un anti patrón es una solución común que parece que se soluciona el problema, pero no lo hace, ya sea porque deja lagunas importantes o porque introduce problemas adicionales (a menudo peores que el problema original). Una solución implica necesariamente una o más herramientas más la técnica para aplicarlas al problema en cuestión. Por lo tanto, es difícil referirse a una herramienta o una característica específica de una herramienta como un antipatrón, y parece que las personas están detectando y reaccionando a ese estiramiento, es suficiente.

Por otro lado, dado que parece ser una práctica común en nuestra industria centrarse en las herramientas en lugar de la técnica, es la herramienta/función la que llama la atención (una encuesta informal de preguntas aquí en StackOverflow parece ilustrar fácilmente) Mis comentarios y esta pregunta en sí reflejan esa práctica.

Sin embargo, a veces parece especialmente justificado realizar ese estiramiento, como en este caso. Algunas herramientas parecen "guiar" al usuario a técnicas particulares para aplicarlas, hasta el punto en que algunos argumentan que tools shape thought (ligeramente reformulada). Es sobre todo en ese espíritu que sugiero que svn:external es un antipatrón.

Para establecer el problema de manera más estricta, el antipatrón es diseñar una solución de compilación que incluya vincular proyectos en el nivel de origen o versiones implícitamente las dependencias entre proyectos o permitir que esas dependencias cambien implícitamente, porque cada uno esto invoca consecuencias muy negativas. La naturaleza de la característica similar a svn:external hace que evitar esas consecuencias negativas sea muy difícil.

El manejo adecuado de las dependencias entre proyectos implica abordar esas dinámicas junto con el problema de base, y las herramientas y técnicas conducen por un camino diferente. Un ejemplo que debe considerarse es Ivy, que ayuda de manera similar a Maven, pero sin las muchas desventajas. Estoy investigando a Ivy, junto con Ant, como mi solución a corto plazo para el problema de compilación de Java. A largo plazo, estoy buscando incorporar los conceptos centrales y las características en una herramienta de código abierto que facilita una solución multiplataforma.

+4

+1; Respuesta fantásticamente escrita con algunas ideas muy convincentes. En particular, me gusta mucho la aplicación de los principios de diseño SOLID/OOP para el proceso de construcción. –

+0

+1. Uso svn: externals para apuntar a las versiones troncales de las bibliotecas comunes que he escrito. Pero soy una persona que trabaja para una pequeña empresa. Me facilita la corrección de errores y me aseguro de que salgan la próxima vez que actualice una aplicación. Pero también me he quemado. Todas las cosas con moderación. –

+2

> subconstrucciones de invocación recursiva ¿Puede dar más detalles? He leído "Recursive Make Considered Harmful", pero sigo sin ver el problema, o qué debería hacerse exactamente para evitarlo. – KeyserSoze

19

El principal riesgo al usar svn: externals es que el repositorio al que se hace referencia se cambiará de una manera que rompe el código o introduce una vulnerabilidad de seguridad. Si el repositorio externo también está bajo su control, entonces esto puede ser aceptable.

Personalmente, solo uso svn: externals para apuntar a las ramas "estables" de un repositorio que tengo.

+16

Por eso es (o debería ser) una práctica común apuntar enlaces svn: externos en lanzamientos etiquetados, incluso en lo que concierne a revisiones específicas en lugar de solo/trunk @ HEAD, que es un problema. –

+1

Buen punto, Quick Joe. Creo que lo adoptaré como mi nueva política. – Mike

+2

No soy un tipo de persona de documentación formal, pero para cosas complejas e importantes como el control de fuentes, tiendo a leer la documentación de las funciones que planeo usar antes de usarlas. La documentación de subversión sugiere "Debes considerar seriamente utilizar números de revisión explícitos en todas tus definiciones externas". Junto con la explicación, también explican por qué. – jpierson

65

No creo que esto sea un antipatrón en absoluto. Hice algunas búsquedas rápidas en Google y básicamente no obtuve nada ... nadie se queja de que usar svn: externals sea malo o dañino. Por supuesto, hay algunas advertencias que debes tener en cuenta ... y no es algo que debas espolvorear en todos tus repositorios ... pero en cuanto a la cita original, esa es solo su opinión personal (y subjetiva) . Él nunca discutió realmente sobre svn: externals, excepto para condenarlos como un antipatrón. Tales afirmaciones radicales sin ningún tipo de apoyo o al menos con un razonamiento sobre cómo la persona llegó a hacer la declaración siempre son sospechosas.

Dicho esto, existen algunos problemas con el uso de elementos externos. Al igual que Mike respondió, pueden ser muy útiles para señalar las ramas estables del software lanzado ... especialmente el software que ya controlas. Los usamos internamente en una serie de proyectos para bibliotecas de servicios públicos y demás. Tenemos un pequeño grupo que mejora y trabaja en la base de bibliotecas de servicios públicos, pero ese código base se comparte en una serie de proyectos. No queremos que varios equipos solo verifiquen el código del proyecto de utilidad y no queremos tratar con un millón de sucursales, por lo que para nosotros svn: external funciona muy bien. Para algunas personas, pueden no ser la respuesta. Sin embargo, estoy totalmente en desacuerdo con la afirmación "Por favor no use ..." y que estas herramientas representan un antipatrón.

+11

Respuesta mucho mejor que la aceptada. –

+20

Acepto, la respuesta aceptada es basura. Lo leí por completo y no vi una razón concreta para apoyar sus afirmaciones. "Por un lado, svn: external tiene algunas características de comportamiento interesantes (pero los detalles se me escapan por el momento)" estaba tan cerca como llegó. –

9

Si simple externo es un antipatrón porque puede romper su repositorio, entonces uno con revisión explícita no debería.

Extracto de svn book:

Una definición externa es una asignación de un directorio local a la URL ** - y, posiblemente, una revisión en particular - ** de un recurso versionado.

Creo que todo depende de su propósito de usar la función, no es un antipatrón por sí mismo.

+2

Aquí, aquí! No puedo creer todas las quejas sobre lo externo sin ejemplos reales y sanos. –

8

Existen defectos definitivos en las versiones externas de subversión, pero parece que las utilizamos de manera razonablemente satisfactoria para incluir bibliotecas (tanto propias como de proveedores) de las que depende el proyecto actual. Entonces no los veo como un "antipatrón". Los puntos de uso más importantes para mí son:

  • Señalan una revisión o etiqueta específica (nunca el encabezado) del otro proyecto.
  • Se insertan en el proyecto actual lejos de su propio código fuente, etc. (por ejemplo, en un subdirectorio llamado "archivos de soporte").
  • Se refieren únicamente a los otros archivos de "interfaz" de proyectos (por ejemplo, carpeta de inclusión) y bibliotecas binarias (es decir, no obtenemos la fuente completa del otro proyecto).

Yo también estaría interesado en cualquier riesgo importante de esta disposición, y mejores enfoques.

2

Decir que A es B no tiene un un b a menos que se diga qué esto es así.

La falla principal que veo con las referencias externas en subversión es que no se garantiza que el repositorio esté presente cuando actualiza su copia de trabajo.

Subversion referencias externas se pueden utilizar, y se abusa, y la característica en sí no es más que eso, una característica . No se puede decir que sea un patrón, ni un antipatón .

He leído la respuesta de la persona que cita, y debo decir que no estoy de acuerdo. Si su proyecto requiere archivos de la versión XYZ de un repositorio, una referencia de subversión externa puede proporcionarle fácilmente eso.

Sí, puede usarlo incorrectamente al no especificar específicamente qué versión de esa referencia necesita. ¿Eso te dará problemas? ¡Probable!

¿Es un antipatrón? Bueno, eso depende. Si sigues el enlace proporcionado por el autor del texto que citas, es decir. here, luego no. Que algo puede ser usado para proporcionar una mala solución no hace todo el método de hacerlo antipattern. Si esa fuera la regla, entonces diría que los lenguajes de programación en general son antipatrones, porque en todos los lenguajes de programación usted puede hacer malas soluciones.

+2

Un antipatrón es una solución que crea más problemas, a menudo más problemas de los que resuelve. Usar algo así como la función svn: external para dependencias es solo un caso. Intentaré ilustrar pronto. –

+4

@RobWilliams - Me gustaría ver tu ilustración de svn: externos representados como un patrón de anit. Además, me gustaría ver su solución para incorporar datos compartidos en un sistema controlado por versiones sin introducir duplicación. –

18

Un hilo viejo, pero quiero abordar la preocupación de que un cambio externo podría romper su código. Como se señaló anteriormente, esto se debe a un uso incorrecto de la propiedad externa. Las referencias externas deberían, en casi todas las instancias, apuntar a un número de revisión específico en el URI del repositorio externo. Esto asegura que el externo nunca cambiará a menos que lo cambie para apuntar a un número de revisión diferente.

Para algunas de nuestras bibliotecas internas, que usamos como elementos externos en nuestros proyectos de usuario final, he encontrado que es útil crear una etiqueta de la biblioteca en la versión Major.Minor, donde aplicamos ningún cambio de rotura. Con un esquema de control de versiones de cuatro puntos (Major.Minor.BugFix.Build), permitimos que la etiqueta se mantenga actualizada con los cambios de BugFix.Build (una vez más, no se aplican cambios de interrupción). Esto nos permite usar una referencia externa a la etiqueta sin un número de revisión. En el caso de cambios importantes o de otro tipo, se crea una nueva etiqueta.

Las externas en sí no son malas, pero eso no impide que las personas creen malas implementaciones de ellas. No se necesita mucha investigación, solo un poco de lectura a través de algunos documentos, para aprender cómo usarlos de manera segura y efectiva.

+0

nunca es demasiado tarde para aclarar las cosas. :-) Gran respuesta. –

+1

"Las referencias externas deben, en casi todos los casos, señalar un número de revisión específico en el URI del repositorio externo" - y obtendrá otro lado oscuro - perfectamente válido y pasar todas las pruebas su código (para elementos externos obsoletos) se rompe, cuando Descubrirá commits en la parte superior del enlace a su código, en el caso de que ocurra en la fecha límite en su mayoría –

Cuestiones relacionadas