2009-12-01 17 views
11

El nuevo idioma de Google Go intenta facilitar la administración de dependencias por explicitly requiring that all dependencies listed in a module actually be used. El compilador rechazará un módulo que declara una dependencia a un módulo sin usar nada de ese módulo.Pros y contras de Go rechazar dependencias no utilizadas

Es ilegal que un paquete para importar sí mismo o para importar un paquete sin hacer referencia a cualquiera de sus identificadores exportados.

Puedo pensar en algunas ventajas obvias (por ejemplo, módulos más limpios) pero tal vez hay algunas no obvias. La única desventaja que puedo pensar es tener un compilador excesivamente pedante, quejándose demasiado durante la refacturación, pero ¿tal vez hay más?

¿Tiene alguna experiencia con otros idiomas haciendo cumplir esto? ¿Cuáles son los pros y los contras de este enfoque?

Respuesta

5

No solo debe usar explícitamente todas las dependencias, sino que también se deben usar todas las variables. El compilador le dará errores cuando tenga variables no utilizadas.

Son molestos. Pero hará felices a los demás porque obtienen un código limpio.

Estoy pensando que probablemente los diseñadores de Go se propongan Ir a ser un idioma que depende en gran medida del IDE.

+2

+1 para el diseño basado en IDE. Llegué a la misma conclusión, principalmente por el hecho de que solo los archivos objeto tienen algo parecido a un encabezado, y también que Go incluye módulos para analizar Go. –

0

Según lo mencionado por yuku, si tienes un IDE que esté a la par con lo que Netbeans y Eclipse pueden hacer por Java, realmente no tienes que preocuparte por este tipo de cosas.

Haga clic con el botón derecho en la pequeña bombilla en el margen y seleccione "Eliminar todas las dependencias no utilizadas".

Para las variables que no se usan, generalmente tienen un subrayado ondulante, y son bastante fáciles de detectar.

La única diferencia aquí es que a diferencia de otros idiomas, en realidad tiene el compilador quejándose además del IDE pero si usa un IDE de todos modos, esto se convierte en un problema.

En el trabajo, tenemos políticas de codificación que afirman que tenemos que hacer lo mismo (nosotros), entre otras cosas, para otros idiomas, por supuesto. Entonces diría que este tipo de esto realmente tiene aplicaciones reales. Aunque en mi humilde opinión, el compilador debe darle al desarrollador la opción de activar y desactivar este comportamiento. Modo estricto alguien?

+0

+1 para el modo estricto: me gusta la función, pero también creo que es una buena idea poder desactivarla. –

1

Supongo que la mayor motivación para esto, y el mayor resultado, es una mejora en los tiempos de compilación. El video de vista previa de tecnología hizo que su capacidad para compilar grandes cantidades de código en períodos de tiempo cortos fuera importante (su ejemplo fue 200,000 líneas de código en 8 segundos en una MacBook, sin especificaciones de la máquina).

También en el video tecnológico, mencionan específicamente que una de las formas más importantes que lograron fue cambiando la forma en que se compilaron y vincularon los módulos.

Aquí hay un ejemplo de cómo algo que trabajaría en una corriente de C/C++ sistema:

Clase A se define en el archivo de cabecera C_H e implementado en C_CPP. La clase B deriva de C y se implementa en los archivos B_H y B_CPP. La clase A deriva de B y se implementa en los archivos A_H y A_CPP.

Debido a las cadenas de derivación, A_CPP incluye A_H, B_H, y C_H. B_CPP incluye B_H y C_H. C_CPP incluye C_H. Debido a la naturaleza del preprocesador C, que resulta esencialmente una #include en una operación de cortar y pegar, los contenidos de C_H se ejecutan a través del compilador 3 veces y B_H se ejecuta a través de dos veces.

Además, el contenido de A_CPP, B_CPP y C_CPP todos viven en sus propios archivos de objetos. Por lo tanto, cuando el enlazador va a resolver A.o, se ve obligado a cargar y procesar tanto B.o como C.o. Además, cuando resuelve B.o, tiene que procesar C.o nuevamente.

Los encabezados precompilados pueden ayudar bastante con la primera parte de este problema, pero también pueden ser un dolor real de mantener y conozco a muchos desarrolladores que simplemente no los usan por ese motivo. Asimismo, no cambia fundamentalmente el problema - las cabeceras todavía se procesan en varios niveles varias veces, sólo que ahora un binario precompilado se procesa en lugar de la fuente. Se cortan varios pasos, pero no todo el proceso.

Ir enfoca las cosas de manera diferente. En las palabras que parecen sacadas de la PDF from their tech talk:

"El compilador Ir tira transitiva información de tipo dependencia del fichero objeto - pero sólo lo que necesita Si A.go depende de B.go depende C. .go: - compilar C.go, B.go, luego A.go. - para compilar A.go, el compilador lee Bo no Co A escala, esto puede ser una gran aceleración de ".

OK, la tangente se hace ligera. ¿Por qué es eso relevante? La respuesta también está en el PDF de Go Tech Talk:

"Modelo de paquete: dependencias explícitas para permitir compilaciones más rápidas."

supongo que los desarrolladores Go tomaron la postura de que cuando los tiempos de compilación se miden en segundos, incluso en caso de grandes proyectos, que es más productivo para los desarrolladores para mantener tiempos de compilación que se corta. Digamos que me lleva 8 segundos recopilar 200,000 líneas de código y descubrir que tengo una importación de paquete extraño, 5-10 segundos (con un IDE bueno o una buena familiaridad con su entorno de desarrollo) para encontrarlo y solucionarlo, y otros 8 segundos para recompilar. Llámalo 30 segundos en total, y ahora todas mis compilaciones futuras permanecen en el rango de 10 segundos. O podemos dejar que nuestro módulo crezca al incluir dependencias innecesarias, y observar que el tiempo de compilación aumenta de 8 a 10, 12 o 15 segundos. No parece mucho porque todos estamos acostumbrados a compilar tiempos del orden de minutos, pero cuando comienzas a darte cuenta de que eso es una degradación del rendimiento del 25%, te paras a pensarlo un minuto.

Ir tiempos de compilación son ya la velocidad del rayo. Tenga en cuenta también que las velocidades del procesador siguen aumentando (si no tanto como en el pasado) y que el número de núcleos disponibles también está aumentando (y la compilación de grandes cantidades de código es muy adecuada para multihebras). Hoy, 200,000 líneas de código en 8 segundos significa que no es irracional imaginar 200,000 líneas de código compiladas de forma esencialmente instantánea en 10 años. Creo que el equipo de Go ha tomado una decisión consciente aquí para hacer que los tiempos de compilación sean cosa del pasado, y aunque el problema que usted menciona es solo una pequeña parte de eso, es y aún forma parte de eso.

En otra nota completamente, el equipo de Go también parece haber desarrollado una filosofía de diseño del lenguaje que obliga a algunas buenas prácticas de programación.Para su crédito, se han esforzado por lograrlo sin penalizaciones graves de rendimiento, y han tenido éxito en gran medida. [Aparte: las dos únicas cosas que puedo pensar de forma directa que impactan en el rendimiento son la recolección de basura y las variables inicializadas a la fuerza - y esto último es bastante trivial en este día y edad.] Esto va a irritar a algunos programadores, mientras hace felices a otros . Es un viejo y viejo argumento en el mundo de la programación, y está bastante claro en qué lado se ha basado Go, le guste o no.

Creo que las dos fuerzas juntas influyeron en su decisión, y creo que al final del día es un buen camino a seguir, aunque apoyo a otros comentaristas que sugirieron permitir una bandera "--strict" o alguna para hacer que este comportamiento particular sea opcional, particularmente durante las primeras etapas del ciclo de vida de un proyecto. Me pude ver fácilmente definiendo variables o incluyendo paquetes cuando empiezo a escribir código que sé que necesitaré más tarde, aunque todavía no he escrito el código que los necesita.

+0

"Si el módulo A requiere el módulo B que requiere el módulo C, la mayoría compilaría C, compilaría B y C (nuevamente) y luego compilaría A, B (nuevamente) y C (nuevamente) y luego resolvería los problemas de vinculación" - no, no lo harían. Compilan cada archivo fuente una vez y luego los vinculan entre sí. –

+0

Nick, me equivoqué un poco, y actualizaré mi respuesta momentáneamente con la corrección. Sin embargo, si usa archivos de encabezado en C/C++, termina con ** grandes ** porciones de código que se compilan más de una vez. –

+0

Sí, los encabezados se incluyen más de una vez, ya que son procesados ​​por el preprocesador. Si tiene 'grandes' bits del código en sus archivos de encabezado, UR DOIN IT WRONG. –