Aunque puedo codificar, todavía no tengo experiencia trabajando en proyectos grandes. Lo que hice hasta ahora fue codificar pequeños programas que se compilan en cuestión de segundos (varios ejercicios c / c ++ como algoritmos, principios de programación, ideas, paradigmas, o simplemente probar api ...) o trabajar en algunos proyectos más pequeños que fueron hecho en un lenguaje de scripting (python, php, js) donde no se necesita compilación.
La cuestión es que, cuando codifico en un lenguaje de script, cada vez que quiero probar si algo funciona, simplemente ejecuto el script y veo qué sucede. Si las cosas no funcionan, simplemente puedo cambiar el código e intentarlo nuevamente ejecutando el script nuevamente y seguir haciéndolo hasta que obtenga el resultado que quería. Mi punto es que no tiene que esperar cualquier cosa para compilar y por eso es bastante fácil tomar una gran base de código, modificarla, agregarle algo o simplemente jugar con ella: puede ver los cambios al instante.
Como ejemplo tomaré Wordpress. Es bastante fácil intentar descubrir cómo crear un complemento para él. Primero comienza creando un complemento simple "Hello World", luego crea una interfaz simple para que el panel de administración se familiarice con la API, luego la construye y hace algo más complejo, mientras tanto cambia la apariencia de un par de veces .. La idea de tener que volver a compilar algo tan grande como WP una y otra vez, después de cada cambio menor para intentar "si funciona" y "cómo funciona / siente" simplemente parece ineficiente, lento e incorrecto.
Ahora, ¿cómo podría hacer eso con un proyecto que está escrito en un lenguaje compilado? Me gustaría contribuir a algunos proyectos de código abierto y esta pregunta me sigue molestando. La situación probablemente difiere de un proyecto a otro, donde algunos de ellos que se pensaron sabiamente serán "modulares" de alguna manera, mientras que otros serán solo una gran gota que necesita ser recompilada una y otra vez.
Me gustaría saber más sobre cómo se hace esto correctamente. ¿Cuáles son algunas prácticas comunes, enfoques y diseños de proyectos (patrones) para hacer frente a esto? ¿Cómo se llama esta "modularidad" en el mundo de los programadores y qué debo buscar en Google para obtener más información al respecto? ¿Es frecuente que los proyectos crezcan a partir de sus proporciones de primer pensamiento que se vuelven problemáticas después de un tiempo? ¿Hay alguna manera de evitar la compilación prolongada de proyectos no tan bien diseñados? ¿Una forma de modularizarlos de alguna manera (quizás excluyendo partes no vitales del programa durante el desarrollo (¿alguna otra idea?))?
Gracias.
fuente
Respuestas:
Tal como se ha dicho, nunca recompila todo el proyecto cada vez que realiza un pequeño cambio. En cambio, solo recompila la parte del código que ha cambiado, así como todo el código que depende de él.
En C / C ++, la compilación es bastante sencilla. Usted Compilar traducir cada archivo fuente en código máquina (los llamamos objeto archivos * .o) y luego se enlazan todos sus archivos de objetos en una gran ejecutable.
Al igual que MainMa mencionó, algunas bibliotecas están integradas en archivos separados, que se vincularán dinámicamente en tiempo de ejecución con el ejecutable. Estas bibliotecas se denominan Objetos compartidos (* .so) en Unix y Bibliotecas vinculadas dinámicamente (DLL) en Windows. Las bibliotecas dinámicas tienen muchas ventajas, una de las cuales es que no necesita compilarlas / vincularlas, a menos que su código fuente cambie efectivamente.
Existen herramientas de automatización de compilación que lo ayudan a:
Los más famosos (make, ant, maven, ...) pueden detectar automáticamente qué partes del código han cambiado desde la última compilación, y exactamente qué objeto / binario necesita actualizarse.
Sin embargo, esto conlleva el costo (relativamente pequeño) de tener que escribir un "script de compilación". Es un archivo que contiene toda la información sobre su compilación, como definir los objetivos y sus dependencias, definir qué compilador desea y qué opciones usar, definir su entorno de compilación, las rutas de su biblioteca, ... Quizás haya escuchado sobre Makefiles (muy común en el mundo Unix), o build.xml (muy popular en el mundo Java). Esto es lo que ellos hacen.
fuente
build.xml
archivoNo recompilas todo el proyecto cada vez. Por ejemplo, si se trata de una aplicación C / C ++, hay posibilidades de que se separe en bibliotecas (DLL en Windows), cada biblioteca se compila por separado.
El proyecto en sí generalmente se compila diariamente en un servidor dedicado: son compilaciones nocturnas. Este proceso puede llevar una gran cantidad de tiempo, ya que incluía no solo el tiempo de compilación, sino también el tiempo dedicado a ejecutar pruebas unitarias, otras pruebas y otros procesos.
fuente
Creo que todas las respuestas hasta ahora se han aludido también, es que los grandes proyectos de software casi siempre se dividen en partes mucho más pequeñas. Cada pieza se almacena normalmente en su propio archivo.
Estas piezas se compilan individualmente para crear objetos. Los objetos son entonces ligados juntos para formar el producto final. [En cierto modo, es como construir cosas con Legos. No intentas moldear la pieza final de una gran pieza de plástico, sino que combinas un montón de piezas más pequeñas para hacerlo.]
Romper el proyecto en piezas que se compilan individualmente permite que sucedan algunas cosas interesantes.
Edificio incremental
En primer lugar, cuando cambia una pieza, generalmente no tiene que volver a compilar todas las piezas. En términos generales, siempre que no cambie la forma en que otras piezas interactúan con su pieza, las otras no necesitan ser recompiladas.
Esto da lugar a la idea de construcción incremental . Cuando se realiza una compilación incremental, solo se recompilan las piezas afectadas por el cambio. Esto acelera enormemente el tiempo de desarrollo. Es cierto que es posible que aún tenga que esperar a que todo se vuelva a vincular, pero que sigue siendo un ahorro por tener que volver a compilar y volver a vincular todo. (Por cierto: algunos sistemas / idiomas admiten enlaces incrementales para que solo las cosas que cambiaron tengan que volver a vincularse. El costo de esto generalmente está en un rendimiento y tamaño de código deficientes).
Examen de la unidad
La segunda cosa que le permite hacer piezas pequeñas es observar individualmente las piezas antes de combinarlas. Esto se conoce como pruebas unitarias . En la Prueba de unidad, cada unidad se prueba individualmente antes de integrarse (combinarse) con el resto del sistema. Las pruebas unitarias se escriben normalmente para que puedan ejecutarse rápidamente sin involucrar al resto del sistema.
El caso limitante de aplicar pruebas se ve en Test Driven Development (TDD). En este modelo de desarrollo, no se escribe / modifica ningún código a menos que sea para corregir una prueba fallida.
Haciéndolo más fácil
Por lo tanto, desglosar las cosas parece bueno, pero también parece que se necesita mucho trabajo para construir el proyecto: debe calcular qué piezas cambiaron y qué depende de esas piezas, compilar cada pieza y luego vincular todo.
Afortunadamente, los programadores son flojos *, por lo que inventan muchas herramientas para facilitar su trabajo. Con ese fin, se han escrito muchas herramientas para automatizar la tarea anterior. Los más famosos de estos ya se han mencionado (make, ant, maven). Estas herramientas le permiten definir qué piezas se deben unir para hacer su proyecto final y cómo las piezas dependen unas de otras (es decir, si cambia esto, es necesario volver a compilarlo). El resultado es que al emitir un solo comando se da cuenta de lo que se necesita volver a compilar, lo compila y se vuelve a vincular todo.
Pero eso todavía deja descubrir cómo se relacionan las cosas entre sí. Eso es mucho trabajo y, como dije antes, los programadores son flojos. Así que se les ocurrió otra clase de herramientas. ¡Estas herramientas se han escrito para determinar las dependencias para usted! A menudo, las herramientas son parte de Entornos de Desarrollo Integrado (IDE) como Eclipse y Visual Studio, pero también hay algunas independientes que se utilizan para aplicaciones genéricas y específicas (makedep, QMake para programas Qt).
* En realidad, los programadores no son realmente vagos, solo les gusta pasar su tiempo trabajando en problemas, no haciendo tareas repetitivas que un programa pueda automatizar.
fuente
Aquí está mi lista de cosas que puede intentar para acelerar las compilaciones de C / C ++:
fuente
Ejecutar algo interpretado también es muy ineficiente y lento, y (posiblemente) incorrecto. Te estás quejando de los requisitos de tiempo en la PC del desarrollador, pero no compilar causa requisitos de tiempo en la PC del usuario , lo que podría decirse que es mucho peor.
Más importante aún, los sistemas modernos pueden hacer reconstrucciones incrementales bastante avanzadas y no es común recompilar todo para cambios menores: los sistemas compilados pueden incluir componentes de script, especialmente comunes para cosas como la interfaz de usuario.
fuente
Si el proyecto implementa el DAG de dependencia de compilación adecuado, puede salirse con la recompilación de los archivos de objeto que afecta su cambio.
Suponiendo también un DAG de dependencia de compilación adecuado, puede compilar utilizando múltiples procesos. Un trabajo por núcleo / CPU es la norma.
Puede crear múltiples ejecutables para pruebas que solo vinculen archivos de objetos particulares.
fuente
Además de la respuesta de MainMa, también hemos actualizado las máquinas en las que trabajamos. Una de las mejores compras que hemos realizado fue un SSD para cuando no puedes evitar recompilar todo el proyecto.
Otra sugerencia sería probar un compilador diferente. En el pasado, cambiamos del compilador de Java a Jikes y ahora pasamos a usar el compilador incluido con Eclipse (no sé si tiene un nombre) que aprovecha mejor los procesadores multinúcleo.
Nuestro proyecto de 37,000 archivos tardó alrededor de 15 minutos en compilarse desde cero antes de realizar estos cambios. Después de los cambios, se redujo a 2-3 minutos.
Por supuesto, vale la pena mencionar el punto de MainMa nuevamente. No vuelva a compilar todo el proyecto cada vez que quiera ver un cambio.
fuente