Como mejorar el tiempo de compilación en C++

 Mejorar el tiempo de compilación es la base para poder mejorar la calidad de todo nuestro código. En muchas ocasiones, la velocidad de compilación no recibe la atención que se merece dado que o bien se buscan soluciones "hardware" como mejores servidores de compilación o compilación distribuida o bien se acepta que a medida que el proyecto crece el tiempo de compilación también debe crecer, incluso cuando este incremento es desorbitado. 

El gran problema es que un proyecto con un tiempo de compilación excesivo es desmoralizante para el programador, afecta claramente a la calidad y velocidad de implementación de código e impide realizar técnicas de programación como TDD o refactor continuo. Tener un proyecto con un tiempo de compilación excesivo hace que tendamos a ser conservadores con el número de cambios y a reducir las pruebas, es decir, reduce drásticamente nuestra capacidad para mejorar la calidad de nuestro código.

Por si fuera poco, tambien reduce nuestra flexibilidad para adaptarnos a nuestros clientes. Imaginas ir a casa del cliente, hacer los cambios que el pida y tener que esperar 4 horas a que se compile el proyecto? Imaginas hacer un spike para hacer una demo sencilla y tener que esperar 1 hora?. Un tiempo excesivo de compilación nos resta agilidad y reduce la versatilidad de nuestro producto.

Ahora bien, como podemos mejorar nuestro tiempo de compilación en C++? Básicamente solo hay una manera, reduciendo el número de includes que el compilador tenga que procesar. Sencillo de decir, pero difícil de plasmar en el código, no? Por suerte, hay un conjunto de pasos que si los sigues te permitirán disminuir drásticamente el tiempo de compilación:


1. Los includes han de ir en el .cpp, no en el .h 

El motivo de esto es bastante sencillo. Muchas veces hay la tendencia inconsciente que como los .cpp de una clase hacen el include del .h correspondiente , no necesitamos poner includes en el .cpp y con que todo vaya en el .h ya tenemos suficiente. CRASO ERROR. Los .h incluyen otros .h, cuando un proyecto crece en tamaño el número de .h implícitos crece exponencialmente. Dado que es extremadamente raro que alguien haga un include de un .cpp, podemos asumir que todo include que podamos mover directamente del .h al .cpp es un include que solo se hará una vez en toda la compilación.


2. Se han de usar las predefiniciones en los .h

Una vez ya hemos movido los includes obvios a los .cpp, ahora tendremos que mover aquellos que no son tan sencillos de ver. Generalmente, cuando hacemos un include en un .h lo hacemos básicamente para poder tener las definiciones de las clases y tipos usados en las interficies de entrada/salida de nuestro .h. Dado que no necesitamos saber lo que hay dentro de las clases, sino poderle explicar al compilador que va a recibir o devolver una cierta clase o enum, podemos predefinir la clase y pasar el include al .cpp ( dado que en el .cpp si que usaremos la clase y necesitaremos tenerla incluida). 

Los enums nos obligaran a hacer include si o si. El truco es convertir los enums a enum class permitiéndonos esto hacer la predeclaración del enum como si fuera una clase. Puede implicar hacer un poco de refactor en el código, pero vale la pena.

Usando las predefiniciones de clases, gran parte de los includes ya se habrán movido a los .cpp y se habrá reducido en gran cantidad el volumen de includes del arbol de compilación.


3. Se han de eliminar todos los includes redundantes.

Uno de los grandes problemas de los includes es que una vez se han puesto da pereza miedo quitarlos. Los includes se van acumulando incluso cuando ya no son necesarios y en muchas ocasiones hacemos includes de .h que incluyen todo un grupo de funcionalidades extensas por que nos da bastante pereza buscar exactamente cual sería el .h que deberíamos incluir porque "total, así ya funciona". Deberemos solventar esto, revisando uno a uno todos los includes, tirando de lógica , intuición o inspiración divina.  

Un segundo punto a revisar es la necesidad de ciertos includes debido al árbol de includes que tengamos. Es decir, no necesitamos incluir un fichero que ya teníamos incluido de forma implícita en otro include. 

A veces, la mejor forma de mejorar estos puntos es comentar el include que creemos que no es necesario y compilar. Si se queja la compilación es que seguramente era necesario, sino se queja la compilación casi seguro que puedes eliminarlo. Es un proceso manual y lento pero que da sus frutos a largo plazo. Cada include que quitamos es un pequeño paso que hacemos para reducir el tiempo de compilación.


4. Se ha de refactorizar la estructura de includes.

Una vez ya hemos reducido "mecánicamente" el número de includes ahora toca una pensar un poco. Realmente es necesario hacer un include de un .h con 1000 funciones para usar solamente 1? Sería posible mover esa función a otro fichero? Realmente haría falta usar esa función? Hay otra manera de hacerlo? ...

Este punto no es fácil de implementar pero si tu objetivo es mejorar la calidad de código de tu proyecto es claramente una de las más importantes. Poner en duda todo, refactorizar y buscar maneras mejores y más organizadas de implementar el código es el camino para que nuestro código pueda seguir mejorando de una forma sostenible.


VALE, BIEN, PERO TRABAJO CON UN PROYECTO VIEJO Y GRANDE, QUE HAGO?

Exactamente lo mismo que acabo de explicar. Si tienes experiencia trabajando en proyectos grandes sabes que el problema de la compilación puede ser muy serio, y la solución parece imposible debido al volumen de ficheros. Bien, paciencia, tranquilidad y perseverancia, no te puedo decir mucho más, pero los únicos pasos que puedes dar son los que he explicado. La ventaja con los proyectos grandes es que aunque dé MUCHO miedo empezar a tocar includes , si eres mínimamente hábil escogiendo por donde empezar, los resultados se pueden ver en muy poco tiempo. Recuerda la ley de Pareto, con el 20% del esfuerzo obtendrás el 80% de los beneficios, es decir, con pocos includes que toques verás como el tiempo de compilación empieza a reducirse de forma drástica. 

Con constancia y paciencia conseguirás reducir los tiempos de compilación a unos niveles aceptables en muy poco tiempo.

No dudes en hacerme llegar tus preguntas sobre el tema

Nos vemos



No hay comentarios:

Publicar un comentario