¿Cuál es el mejor enfoque para codificar en un entorno de compilación lenta?

15

Solía ​​codificar en C # en un estilo TDD: escribir / o cambiar un pequeño fragmento de código, volver a compilar en 10 segundos la solución completa, volver a ejecutar las pruebas y nuevamente. Fácil...

Esa metodología de desarrollo funcionó muy bien para mí durante algunos años, hasta el año pasado cuando tuve que volver a la codificación C ++ y realmente siento que mi productividad ha disminuido drásticamente desde entonces. El C ++ como lenguaje no es un problema: tenía mucha experiencia en desarrollo de C ++ ... pero en el pasado.

Mi productividad todavía está bien para proyectos pequeños, pero empeora cuando con el aumento del tamaño del proyecto y una vez que el tiempo de compilación llega a más de 10 minutos, se vuelve realmente malo. Y si encuentro el error, tengo que comenzar la compilación nuevamente, etc. Eso es simplemente frustrante.

Por lo tanto, llegué a la conclusión de que en pequeños fragmentos (como antes) no es aceptable: cualquier recomendación, ¿cómo puedo acostumbrarme al viejo hábito de codificar durante una hora más o menos, al revisar el código manualmente (sin depender de un compilador rápido de C #)? , y solo recompilando / volviendo a ejecutar pruebas unitarias una vez cada dos horas.

Con un C # y TDD fue muy fácil escribir un código de forma evolutiva: después de una docena de iteraciones, cualquier basura con la que comencé terminaba en un buen código, pero ya no funciona para mí (en una compilación lenta ambiente).

mosquito
fuente
stackoverflow.com/questions/5078409/… Probablemente deberían fusionarse / en un solo lugar.
Ben L
Vea laso stackoverflow.com/questions/373142/… para acelerar los tiempos de compilación de C ++.
Eclipse
2
Comienza una pelea de espadas . ; p
Steven Jeuris
La última vez que usé C ++ en serio, el uso de encabezados precompilados redujo el tiempo de compilación en un factor cuatro.
gnasher729

Respuestas:

16

Varias cosas me vienen a la mente:

  1. Hacer uso de compilación distribuida . Puede hacer esto con GCC ("distCC"?) O VC ( Xoreax 'IncrediBuild no es exactamente barato, pero vale cada centavo gastado en él).

  2. Divida su proyecto en bibliotecas cargadas dinámicamente e intente minimizar las dependencias con cuidado. Los ejecutables más pequeños se vinculan mucho más rápido.

  3. Programa contra pequeños proyectos de prueba en lugar de toda la gran aplicación.

  4. Emplee la programación meta plantilla para realizar algoritmos en tiempo de compilación . Sí, esto realmente aumentará los tiempos de compilación, pero también disminuirá los tiempos de respuesta necesarios para las pruebas: si se compila bien, está listo.

  5. Invierta en hardware . Más núcleos de CPU (en su máquina o en otros) harán maravillas con la compilación distribuida, y mucha memoria más un disco rápido (SSD en lugar de HDD) ayudará mucho. Si tiene un sistema de 64 bits y cantidades obscenas de RAM, la compilación en un disco RAM puede proporcionar un aumento de velocidad increíble.

sbi
fuente
1
los cachés de compilación son en realidad una mejor idea que la compilación distribuida en mi experiencia.
pqnet
Hablando de disco RAM frente a SSD, me sorprendió bastante que no aumentara tanto la velocidad de compilación. Mi proyecto actual (Java en Android) se compila desde el estado limpio en ~ 45 segundos desde SSD y en ~ 40 segundos desde el disco RAM (y toda la cadena de herramientas está en el disco RAM, no solo las fuentes). No es un aumento dramático, diría.
Haspemulator
10

Otra solución técnica aún no mencionada por otros es cambiar a unidades de estado sólido en lugar de discos duros normales. En un proyecto anterior en el que trabajé, los SSD redujeron los tiempos de construcción del rango de 30 minutos a 3.

Por supuesto, son costosos. Para su jefe, calcule el precio del tiempo perdido del desarrollador contra el precio de la inversión única. La inversión probablemente se amortice en unos pocos meses.

Péter Török
fuente
66
Eso es interesante. Eso dice que el 90% del tiempo de compilación es la latencia de disco de E / S.
Mike Dunlavey
No he visto una disminución del 90%, pero sí sustancial. No parece acelerar la compilación, pero definitivamente acelera el enlace. Si realiza pequeños cambios en un proyecto grande (por lo que no hay mucha compilación en un cambio), y vuelve a vincular, bien podría obtener esto. (Esto es Visual Studio 2008, usando C ++.)
David Thornley
1
Esta es una buena idea. Además, montar una parte de RAM en su sistema de archivos funcionaría rápido y es barato.
Goran Jovic
2
Ramdisk es aún más rápido (y más barato).
SK-logic
1
@ John: Sí, un compilador bien escrito debería (en mi humilde opinión) estar vinculado a E / S.
Mike Dunlavey
3

Más planificación, codifique en fragmentos más grandes, escriba pruebas de integración en lugar de pruebas unitarias y ejecute el conjunto de pruebas build + durante la noche.

Nemanja Trifunovic
fuente
3

Los largos tiempos de compilación son un problema a veces, pero la modularización ya mencionada puede ayudar a superar eso (principalmente).

Mucho más grave es estar atascado en un entorno donde no se puede compilar en absoluto, donde cada cambio de código debe enviarse a otro departamento en otro continente para su aplicación al entorno de prueba / desarrollo, un proceso que puede llevar días completar.

Ahora estoy trabajando en un entorno así, y este sistema ya me ha costado más de una semana (y el proyecto solo tiene un presupuesto para 4 semanas en total antes de que se agote el dinero) solo para instalar la versión inicial de nuestros cambios (y luego cometieron errores que hacen que parte del servidor no sea recogido por el servidor de aplicaciones, por lo que estamos viendo varios días más de demoras). Cada cambio menor ahora (digamos que encontramos algo en las pruebas que necesita reparación, como una condición de error omitido) puede causar un retraso de otro día o más.

En tales condiciones, intenta asegurarse de que no haya errores antes de intentar compilar su código. Se siente casi como si volviera a la programación de mainframe, donde teníamos 5 minutos de tiempo de CPU por mes disponibles para todo el trabajo de compilación y prueba.

jwenting
fuente
1
Chico, esa es una situación del infierno. Sí recuerdo los días del mainframe. Hicimos muchas "comprobaciones de escritorio" del código. Es sorprendente cuánto se hizo de esa manera, como simulaciones interminables de vuelos a la luna.
Mike Dunlavey
3

Puedo recordar fácilmente cuando las compilaciones tomaron mucho tiempo. Algunos enfoques atenuantes:

  • Construya el sistema combinando bibliotecas o dlls. De esa manera, cuando modifica algún código, la única parte que necesita ser recompilada es su parte.
  • La cantidad de puntos en el código que necesita editar para implementar una función no solo afecta la cantidad de edición que tiene que hacer, sino también la frecuencia con la que coloca errores, amplificando el bucle compilar-depurar-editar-compilar. Cualquier cosa que reduzca la redundancia del código, como DRY, ayuda.
  • Si está en el depurador y puede editar, volver a compilar y continuar sin salir del depurador, eso es realmente útil.
Mike Dunlavey
fuente
2

¿Más de 10 minutos para una compilación? ¿Seriamente?

¿Está utilizando un IDE que hace construcción incremental (por ejemplo, Eclipse)? Si no, probablemente debería hacerlo, hará la compilación básica en segundos en lugar de minutos.

¿O estás hablando de cosas de integración, donde necesitas construir la aplicación completa para probar tu cambio? Si es así, mire las pruebas más pequeñas para asegurarse de que los errores principales estén fuera de su código antes de tener que hacer la compilación completa.

TrueDub
fuente
55
10 minutos es pequeño. He trabajado para un proyecto que tardó una hora en compilar y vincular desde cero en una máquina de un solo núcleo, PCH y todo. Por supuesto, a excepción de las versiones de lanzamiento automático, nadie lo construiría en un solo núcleo de procesador, pero aún así ... Si tuviera que cambiar algo en un encabezado que se incluye en casi todas partes (manipulación de cadenas, manejo de errores), podría volverse loco.
sbi
2
Solía ​​funcionar (hace años) en un sistema que tardó 48 horas en compilarse. Por supuesto, una construcción completa solo se inició el viernes por la noche, con suerte que se realizará cuando volvamos a la oficina el lunes. En su lugar, creamos módulos pequeños según sea necesario (por ejemplo, una sola DLL).
Jwent
2
-1 a todos los comentarios anteriores si pudiera hacer +1 en TrueDub. Sí, si está volviendo a compilar todo, puede llevar mucho tiempo. Sin embargo, si se piensa en la gestión de dependencias, los proyectos de recompilación completos de 10 horas pueden tener recompilaciones incrementales en menos de un minuto. Todos deberían avergonzarse de perder el tiempo de sus empleadores esperando sus recompilaciones cuando aplicar un poco de inteligencia les ahorrará grandes cantidades de tiempo.
Dunk
2
Y si trabaja en una tienda pequeña que se encuentra en un proyecto de varios MLoC, eso significa que una parte considerable del código es antigua, comenzó hace una década como múltiples proyectos pequeños, donde la velocidad de compilación nunca fue un problema, y la gestión de dependencias es abominablemente mala. Entonces, ¿vas a decirle a esa compañía que deseche todo esto y pase otra década reescribiéndolo?
sbi
2
@Dunk: Era una empresa pequeña, con menos de una docena de desarrolladores trabajando en un proyecto multi-MLoC. Eso es muy diferente de los cientos de desarrolladores que lo hacen: no puedes volver a escribir nada desde cero, porque necesitarías años para hacerlo. Por mucho que odiara la idea, invertir en compilación distribuida era económicamente factible, reescribir no lo era. Ah, y heredé esas interfaces. :-xNo estuve allí hace una década, cuando fueron pensados. (He cambiado un montón de código que emplear TMP, para encontrar más errores en la compilación, y menos en el campo.)
SBI
2

Primero, ¿por qué toma tanto tiempo compilar en primer lugar?

  • ¿Su entorno (IDE, make, lo que sea) admite construcciones incrementales? Asegúrese de que solo está volviendo a compilar los cambios, en lugar de todo.
  • Si tiene una máquina multinúcleo, su IDE puede admitir compilación paralela. Sé a ciencia cierta que Visual Studio hace eso. Aparentemente también lo hace gcc. Así que obtenga una mejor máquina y habilite la compilación paralela.
  • Considere usar encabezados precompilados.
  • Si intenta todo eso y la compilación sigue siendo lenta, revise su código. Busque dependencias innecesarias. ¿Incluye un encabezado donde una declaración de reenvío sería suficiente? Considere usar el lenguaje PIMPL para reducir la dependencia de los encabezados.

Si después de todo esto su tiempo de compilación sigue siendo lento, rompa el problema: cree muchos proyectos de prueba pequeños y trabaje en cada uno individualmente. Asegúrese de tener un sistema de compilación nocturno automatizado que realice un nuevo pago, construya todo y ejecute todas las pruebas unitarias automáticamente.

Finalmente, si aún le toma mucho tiempo probar sus cambios, piense más en ellos. Asegúrese de hacer una diferencia en su sistema de control de versiones y revise cuidadosamente todos los cambios antes de realizar la prueba. En resumen, esto es muy parecido al desarrollo de sistemas integrados, donde el tiempo de respuesta para una prueba es largo y su capacidad para examinar el estado del sistema es limitada.

Esto me lleva a otra idea: instrumente su código para usar el registro. De esta manera, puede ver cuál es el problema sin reconstruir y volver a ejecutar una docena de veces.

Dima
fuente
2
No estoy seguro de si GCC admite compilaciones paralelas tanto como el hecho de que make o herramientas similares comenzarán varias copias de GCC si usted también lo dice.
Zachary K
1
+1 para PIMPL. Trabajé en un proyecto donde los tiempos de construcción se salieron de control. En ese proyecto, no me importé cuántos encabezados se incluían en cada encabezado. En mi próximo proyecto, me propuse minimizar esto haciendo un uso extensivo de PIMPL. Los tiempos de construcción continúan siendo excelentes, aunque el segundo proyecto es probablemente el doble del tamaño del primero.
Jason B
1

Probablemente necesite un enfoque de múltiples puntas:

1) Sistemas de construcción más rápidos. Tantos núcleos / ram / disco rápido como pueda pagar. Para proyectos C ++ más grandes, encontrará que el disco es a menudo un limitador, así que asegúrese de tener uno rápido.

2) Más modularización del proyecto. Divida las cosas para que los cambios no puedan causar fácilmente una compilación completa de todo. Francamente, inserte tantas cosas básicas como sea posible en archivos dll / so separados para que parte del proyecto pueda separarse por completo del resto.

3) Compilaciones incrementales / compilaciones distribuidas / almacenamiento en caché según corresponda a su entorno. En algunos sistemas, distcc (construcción distribuida) y ccache (almacenamiento en caché de material parcialmente construido) pueden ahorrar mucho tiempo de compilación.

4) Asegúrese de que su compilación pueda estar bien paralela. Especialmente en un entorno de archivos MAKE, no es difícil entrar en una situación en la que accidentalmente ha configurado los archivos MAKE de manera tal que no puede hacer una construcción paralela.

Michael Kohne
fuente
0

El registro extenso y la validación interna han sido útiles durante largos tiempos de respuesta. Una vez que haya terminado su compilación, una sola ejecución puede revelar un gran conjunto de posibles problemas a la vez.

Cuando se trata de algoritmos o contabilidad bastante complejos, puede ser útil incluir una versión altamente simplificada en paralelo con la 'real'. En cualquier ejecución, tiene datos de referencia útiles incluidos.

Joris Geer
fuente
0

Lo que dijeron @sbi y @Michael Kohne.

Pase tiempo y energía en el proceso de construcción en sí. Érase una vez un producto majestuoso y maduro que tardó más de una hora en desarrollarse por completo. Se dedicó mucho tiempo y energía a arreglar lo que las dependencias de construcción afirmaban ser, y luego, a arreglar / reducir lo que realmente eran. El tiempo de construcción se redujo a ~ 30 minutos.

El cambio de herramientas de compilación lo dejó caer más. Para un proyecto de varias partes, 'scons' puede hacer todas las compilaciones antes de hacer cualquier enlace. 'make' usando múltiples makefiles hace compilaciones de un solo proyecto antes de los enlaces de ese proyecto, luego continúa.

Eso nos llevó al punto de que todos los comandos de compilación individuales se podían hacer masivamente paralelos. 'distcc' en máquinas lentas, make / scons -j8 en máquinas multinúcleo. Eso llevó las construcciones completas a unos pocos minutos.

En una luz diferente, cree un proceso de construcción nocturno automatizado. De esa manera, si algo problemático se compromete con su repositorio de origen, la primera persona en llegar al trabajo, ver y solucionar el problema, puede evitar que varias personas (re) realicen múltiples compilaciones fallidas.

Rick Berge
fuente