¿Es el algoritmo más importante que el lenguaje de programación?

35

Durante el concurso actual de Google Code Jam (2013) , hubo un problema que llevó a las personas de C ++ y Java a más de 200 líneas de código en comparación con las personas de Python que resolvieron el mismo problema solo con 40 líneas de código.

Python no es directamente comparable con C ++ y Java, pero la diferencia de verbosidad que pensé podría influir en la eficiencia del algoritmo.

¿Qué tan importante es conocer el algoritmo correcto en comparación con la elección del idioma? ¿Podría un programa Python excelentemente implementado implementarse en C ++ o Java de una mejor manera (usando el mismo algoritmo) y esto tiene alguna relación con la verbosidad natural de ciertos lenguajes de programación?

superspacemarines
fuente
16
Se ha dicho (y lo creo) que el lenguaje de programación en el que trabajas influye en la forma en que piensas sobre un problema. Esto implicaría que lenguajes de programación muy diferentes podrían ser adecuados para diferentes clases de problemas.
Joris Timmermans
1
Mucho de esto depende completamente de la escala en la que esté trabajando más allá de LOC. Algunos idiomas simplemente no admiten las necesidades de velocidad o concurrencia. Los algoritmos son importantes, pero a veces si el lenguaje x es y veces más lento que el lenguaje z, simplemente no se puede usar x independientemente de la verbosidad.
Plataforma
Como nota, lo único que he aprendido en la escuela es que todos tienen un error por línea de código que permanece constante independientemente del código utilizado. Por lo tanto, si un lenguaje que le permite hacerlo en menos líneas de código resulta en menos errores, por lo tanto, puede llevarlo al mercado más rápido y menos posibilidades de que aparezca un error cuando un usuario lo esté utilizando. Entonces, en mi opinión, elegiría el mejor idioma para el trabajo que todos los demás en la compañía saben que se requiere para trabajar en ese proyecto.
Travis Pessetto
55
@Travis: "el defecto por tasa de SLOC permanece constante independientemente del idioma", aunque no es cierto. Ver la respuesta de John.
Ben Voigt
¡Ahora me tienes pensando en participar en el próximo concurso usando F # como idioma!
code4life

Respuestas:

73

Obviamente, si considera esta pregunta en el contexto de algo como Google Code Jam, entonces el pensamiento algorítmico es claramente más importante cuando tiene que resolver problemas algorítmicos.

Sin embargo, en la vida cotidiana, también se deben considerar alrededor de un millón de otros factores, lo que hace que la pregunta sea mucho menos negra frente a blanca.

Solo un contraejemplo: si necesita 200 líneas más en Java, pero todos en su empresa conocen Java, esto no es gran cosa. Si pudieras escribirlo en 5 líneas de Python o en cualquier otro idioma, pero serías el único en la compañía en conocer ese idioma, es un gran problema. De hecho, es tan importante que ni siquiera se te permitirá hacerlo y, en cambio, tendrás que escribirlo en Java.

Desde la perspectiva de un artesano, siempre tratamos de acercarnos con la herramienta adecuada para el trabajo, pero la palabra correcta es tan difícil que uno puede equivocarse fácilmente.

Por el contrario, encontré que el pensamiento algorítmico en las empresas estaba casi ausente. Solo unas pocas personas selectas lo poseen, mientras que el Joe promedio a menudo ya tiene problemas para estimar las complejidades de tiempo de ejecución de los bucles, búsquedas, etc.

Sin embargo, en términos de competiciones algorítmicas, mi experiencia personal de competir en ellas durante varios años, me dice claramente que debes apegarte a un idioma. La velocidad es un factor importante y simplemente no puede permitirse perder el tiempo en sus herramientas, cuando debe dedicarlas a resolver los problemas dentro del límite de tiempo. También considere que escribir 200 líneas de código Java sin pensar es aún mucho más rápido que crear a mano 50 líneas de código python complicado que requiere mucho pensamiento, pero ambos resuelven más o menos el mismo problema.

Ah, y finalmente, asegúrese de comprender las principales diferencias entre el código algorítmico de competencia y el código de producción de la compañía. He visto codificadores algorítmicos fantásticos, que escribieron códigos horribles que nunca aceptaría en un producto.

Franco
fuente
1
+ 1 para "millones de otros factores a considerar"
ozz
1
Agregaré a esto que si se trata de un problema funcional que está tratando de resolver, ¡por el amor de Dios, use un lenguaje funcional! Por lo tanto, argumentaría que realmente debería pegar un lenguaje por paradigma de programación principal.
Martijn Verburg el
66
+1 para la última oración.
Shivan Dragon
44
+1 Líneas de código es una métrica terrible en sí misma. Necesitamos medir la capacidad de mantenimiento , no las líneas de código. 200 líneas de código de tipo seguro pueden ser mucho más fáciles de mantener que 50 líneas de Python.
Phil
2
@ Phil: Y 200 líneas de Python pueden ser mucho más fáciles de mantener que 50 líneas de código de tipo seguro. Nunca he visto tanta ventaja de claridad en lenguajes de tipo seguro, suponiendo un código bien escrito.
David Thornley
17

Yo diría que, incluso fuera de las competiciones, el pensamiento algorítmico es más importante que conocer cada truco para un lenguaje específico.

Por supuesto, desea conocer el idioma con el que trabaja lo mejor posible, pero los idiomas van y vienen, mientras que la capacidad de pensar de manera abstracta en términos de algoritmos es una habilidad altamente transferible.

Caso en cuestión: si recuerdo bien, hubo una publicación aquí en Programmers hace un tiempo en la que alguien se quejó de haber fallado a FizzBuzz en una entrevista y culpó a su falta de conocimiento sobre el operador de módulo de Java. Esta conclusión es errónea: la falta de conocimiento sobre cómo funciona el módulo lo hizo incapaz de pensar algorítmicamente sobre el problema y resolverlo, incluso en ausencia de un operador de módulo dedicado. Yendo más allá: Java tiene una clase Tree: ¿qué pasa si, en el futuro, tiene que trabajar con un lenguaje que no implemente esta clase? Nuevamente, la capacidad de pensar sobre el problema triunfa sobre los detalles específicos del idioma.

Admito que los ejemplos son simplistas, pero ayudan a transmitir el punto.

ACEG
fuente
14

El lenguaje importa.

DARPA y la Marina de los EE. UU. Realizaron un experimento de tiroteo hace casi 20 años. El ganador del fugitivo caballo oscuro fue Haskell. Ada y C ++ estuvieron ambos representados; Java no lo era.

Casi al mismo tiempo, Pratt & Whitney realizó un estudio de minería de datos sobre proyectos de controladores de motores a reacción, observando datos de tarjetas de tiempo y rastreadores de errores. Descubrieron que Ada daba el doble de productividad al programador y 1/4 de la densidad de defectos de cualquier otro lenguaje que estaban usando.

Atari solía usar FORTH para desarrollar videojuegos, y el hecho de que usaran FORTH se consideraba extremadamente patentado.

Los comentarios de Paul Graham sobre el uso de LISP son bien conocidos. Los comentarios de Erann Gat sobre LISP en JPL son igualmente convincentes, aunque no tan conocidos.

El software de aviónica Boeing 777 es prácticamente todo Ada. Su experiencia fue muy buena, a pesar de que un subcontratista importante tuvo que comenzar de nuevo a mitad de camino.

El lenguaje importa.

John R. Strohm
fuente
Obviamente, Java se lanzó después de ese experimento al que te estás vinculando.
toasted_flakes
el artículo fue lanzado en 1994. El primer lanzamiento público de Java fue 1995.
Alessandro Teruzzi
El punto no es que su idioma favorito particular haya sido o no representado en un experimento en particular. El punto es que el lenguaje IMPORTA. Ha habido MUCHOS estudios anecdóticos que lo demuestran de manera bastante concluyente. También vale la pena señalar que, a pesar de ser rechazado principalmente por los programadores estadounidenses, Ada todavía se usa mucho en Europa, especialmente para sistemas de alta confiabilidad, y todavía se usa en ciertos sistemas de campo en los EE. UU.
John R. Strohm
7

Algunos puntos:

  • Las primeras posiciones tienden a ser C ++ / C / Java, independientemente de cuántas líneas de código exista la diferencia entre ese y algún otro lenguaje. Esto puede ser más sobre que los codificadores principales tienden a elegir estos idiomas sobre otros, probablemente debido a su velocidad bruta.
    Desafortunadamente, no puede ver fácilmente el lenguaje de programación en Google Code Jam, pero descargué algunos de los principales y, por lo que recuerdo, estos son principalmente C / C ++. TopCoder (un popular sitio de alojamiento de concursos de programación en línea) en su mayoría tiene resultados similares.

  • Debido a que son bastante bajo nivel, estoy bastante seguro de que no va a batir fácilmente C / C ++ en términos de tiempo de ejecución cruda (y Java no arrastrarse demasiado lejos). Según mi experiencia, los idiomas escritos dinámicamente tienden a ser significativamente más lentos que los idiomas escritos estáticamente. Es posible que la solución óptima ni siquiera sea lo suficientemente rápida en algunos idiomas, pero esto no debería ser una regla general.

  • El algoritmo correcto es vital. Si supiste cómo resolver todos los problemas (en gran detalle) desde el principio, y eres un codificador bueno y rápido, lo más probable es que ganes, independientemente del idioma en el que codifiques (asumiendo la solución óptima en ese idioma) es lo suficientemente rápido)

  • El número directo de líneas no es tan importante. Una vez que obtenga suficiente experiencia en programación, sabrá que puede pasar 10 minutos programando 10 líneas o 200 líneas, todo depende de cuán complejas sean las líneas. Además, si ha codificado un código similar cientos de veces, podrá hacerlo con bastante rapidez. Sin mencionar también todas las macros que los principales codificadores de C / C ++ suelen utilizar para optimizar su tiempo de codificación.

  • Frank hace un buen punto: (fuera de las competencias de programación) no se puede codificar en Python para su empresa si toda su base de código está en C o lo que sea, debe ajustarse a su lenguaje.

  • Es razonablemente fácil cambiar de idioma, no es fácil construir años de conocimiento de pensamiento algorítmico. Estoy dispuesto a apostar que casi cualquier programador excelente puede cambiar a otro lenguaje (vagamente similar) en, digamos, una semana. Tal vez él / ella no sea lo suficientemente bueno como para ganar competencias de programación en ese idioma (déle otras 2 semanas), pero tendrá lo básico.

Dukeling
fuente
Falsedad: la descarga de varias soluciones de algunos sitios de concurso de códigos es un estudio científico definitivo suficiente para concluir que definitivamente se sabe con certeza cómo se ven las primeras posiciones.
Lie Ryan
@LieRyan Es cierto, pero participar en algunas docenas de competencias de programación (como lo he hecho) en (posiblemente) el sitio más popular (TopCoder) y siempre ver la mayoría de las primeras posiciones como C / C ++ / Java es bastante significativo. Además, dije "tienden a" no "son siempre".
Dukeling
no está de acuerdo con que "el número directo de líneas no es tan importante". el código es el enemigo
jk.
66
@jk. ¿Debería haber resaltado "tal"? Importa, pero no es el alfa y el omega. ¿Prefieres unas pocas líneas menos que la legibilidad? Claro que no. Tomaré unas simples declaraciones if a una expresión multi-condicional muy confusa, ilegible, con desplazamiento de bits, multiplicando, dividiendo, sumando, restando, XORing, ANDing, cualquier día. Posiblemente no sea de lo que estaba hablando, pero a eso se reduce a veces la reducción del recuento de líneas. Y estaba hablando más de implementar algo complejo en pocas líneas, o algo simple en muchas líneas; este último a menudo lleva menos tiempo.
Dukeling el
5

¿Se puede implementar mejor la misma lógica en C ++? Por supuesto que puede, si por mejor quiere decir más rápido y más eficiente en memoria. El problema es que la cantidad de esfuerzo requerida para hacerlo es significativamente mayor. Además, en teoría, aún podría ir a un nivel inferior e implementarlo en C puro o incluso ASM, lo que tomaría aún más tiempo, pero podría tener un código aún más optimizado.

Por supuesto, en el caso de competiciones como Code Jam o TopCoder, no es un problema, ya que son solo 40 líneas frente a 200 líneas. Por otro lado, en este tipo de competencia, lo que más importa es la complejidad de tiempo / espacio del algoritmo. Mientras que en la aplicación de la vida real, YMMV, en este tipo de competencias, el algoritmo O (n) escrito en los idiomas más lentos siempre vencerá a O (n²) escrito en los idiomas más rápidos. Especialmente que habrá pruebas múltiples que son el peor de los casos.

Pero aparte de las competiciones, si estamos hablando de grandes proyectos de la vida real, entonces ya no son 40 líneas frente a 200 líneas. En grandes proyectos, la enorme base de código comienza a ser un problema. En ese momento llegas a:

C ++ vs Python?

ingrese la descripción de la imagen aquí

Python puro es lento. Es por eso que el intérprete estándar de Python (CPython) está escrito en C. Prácticamente todo con funciones integradas escritas como C. altamente optimizado. Python también se puede usar fácilmente junto con las bibliotecas C (a través de ctypes o como módulos nativos de cpython ) y con las bibliotecas C ++ a través de Boost :: Python . De esta manera, puede escribir su lógica de alto nivel en Python, un lenguaje que es flexible, permite la creación rápida de prototipos y la adaptación (lo que significa que puede pasar más tiempo ajustando y mejorando su algoritmo). OTOH, puede escribir sus funciones de biblioteca de nivel inferior en el módulo C o C ++. Un gran ejemplo de este enfoque es SciPy, que es la biblioteca Python, pero bajo el capó utiliza bibliotecas numéricas altamente optimizadas como ATLAS, LAPACK, Intels MKL o ACML de AMD.

vartec
fuente
Lo que estás escribiendo solo raspa la superficie. Está asumiendo una noción de "mejor" que no todos comparten. La calidad siempre es una cuestión de adecuación a los objetivos de uno. La programación en C ++ no siempre es una buena opción para cada objetivo.
reinierpost
1
@reinierpost: por eso escribí sobre un esfuerzo significativamente mayor. En los casos que mencionas, C ++ no se ajusta bien, pero no porque no se pueda hacer. No encaja bien, porque requerirá demasiados recursos de desarrollador.
vartec
Lo que es más, simplemente no es mejor en ese caso.
reinierpost
2
y, de hecho, esto es lo que sucede en muchas industrias, los juegos, por ejemplo, tienen mucho código Lua que pega el código C ++ para el rendimiento y la productividad.
gbjbaanb
4

En mi opinión, lo que las personas consideran coloquialmente un "lenguaje de programación" son en realidad tres cosas diferentes:

  1. Tipo de lenguaje y sintaxis
  2. IDE de idioma
  3. Bibliotecas disponibles para un idioma

Por ejemplo, cuando alguien menciona C # en una discusión, puede pensar que está hablando de la sintaxis del lenguaje (1), pero es 95% seguro de que la discusión involucrará .Net framework (3). Si no está diseñando un nuevo lenguaje, es difícil y generalmente inútil aislar (1) e ignorar (2) y (3). Esto se debe a que IDE y la biblioteca estándar son "factores de comodidad", cosas que afectan directamente la experiencia de usar una herramienta determinada.

Los últimos años también participé en Google Code Jam. La primera vez opté por C ++ porque tiene un buen soporte para leer la entrada. Por ejemplo, leer tres enteros de una entrada estándar en C ++ se ve así:

int n, h, w;
cin >> n >> h >> w;

Mientras que en C # el mismo se vería así:

int n, h, w;
string[] tokens = Console.ReadLine().Split(' ');
n = int.Parse(tokens[0]);
h = int.Parse(tokens[1]);
w = int.Parse(tokens[2]);

Eso es mucho más sobrecarga mental para una funcionalidad simple. Las cosas se vuelven aún más complicadas en C # con entrada multilínea. Tal vez simplemente no he descubierto una mejor manera en ese entonces. De todos modos, no pude pasar la primera ronda porque tenía un error que no podía corregir antes del final de la ronda. Irónicamente, el método de lectura de entrada ofuscó el error. El problema era simple, la entrada contenía un número que era demasiado grande para un entero de 32 bits. En C # int.Parse(string)arrojaría una excepción, pero en C ++ la secuencia de entrada del archivo establecería un cierto indicador de error y fallaría silenciosamente, haciendo que el desarrollador desprevenido desconozca un problema.

Ambos ejemplos demuestran cómo se usó la biblioteca en lugar de la sintaxis del lenguaje. El primero demuestra la verbosidad y el otro demuestra la fiabilidad. Muchas bibliotecas se portan a varios idiomas y algunos idiomas pueden usar bibliotecas que no están específicamente diseñadas para ellos (consulte la respuesta de @ vartec sobre Python con bibliotecas C).

Para concluir, conocer el algoritmo correcto ayuda. En las competencias de codificación es crucial, especialmente cuando los recursos, como el tiempo de ejecución y la memoria, están limitados a propósito. En el desarrollo de aplicaciones es bienvenido pero generalmente no es crucial. La mantenibilidad es más importante allí. Se puede lograr mediante la aplicación de patrones de diseño correctos, con una buena arquitectura, código legible y documentación relevante y todos esos métodos dependen en gran medida de las bibliotecas internas y de terceros. Por lo tanto, me parece más importante saber qué tipo de ruedas ya se han inventado y cómo se ajustan y cómo hacer las mías.

Emperador Orionii
fuente
1
La preparación es importante cuando sea posible. Con Google Code Jam tengo una pequeña biblioteca que lee la entrada y muestra la salida como lo desean, e incluyo ese código en mi envío.
Mark Hurd
La segunda vez hice algo similar pero como plantilla de proyecto. Crea un archivo fuente con una clase de entrada a continuación Mainy algunas cosas dentro del Mainmétodo (instancia de mi clase de entrada y la secuencia de salida y el bucle de mayúsculas y minúsculas).
Emperador Orionii
No recuerdo la última vez que leí de stdin. Dame un archivo que pueda pegar en un analizador JSON.
gnasher729
2

Si desea competir en competencias de programación cronometrada, debe aprender el lenguaje más expresivo permitido en la competencia. Perl probablemente sería el mejor, seguido de Ruby o Python. Aún necesitará una buena instalación con algoritmos, pero al menos no se atascará escribiendo algo como

Integer prev = b.get(k)
if (prev == null) prev = 0
Integer v = a.get(k);
if (v == null) v = 0;
b.put(prev + v);

en lugar de

b[k] += a[k]

No te preocupes por aprender varias bibliotecas. Todos son muy similares y la documentación está en línea. Ser fluido en lenguajes más expresivos te hará un mejor programador (pero posiblemente frustrado) en lenguajes menos expresivos. Lo contrario no es verdad.

nótese bien

La diferencia entre 200 líneas de código y 40 líneas de código es enorme, y es aún mayor cuando es la diferencia entre un programa de 200,000 líneas y un programa de 40,000 líneas. Entonces es la diferencia entre un equipo de cinco más un gerente y un equipo de uno o dos.

Kevin Cline
fuente
3
(a) Sé con certeza que C / C ++ / Java tienden a ser las primeras posiciones en las competencias de programación. (b) C / C ++ es considerado como el "lenguaje más poderoso" por muchos (definitivamente por encima de Perl / Ruby / Python). (c) Debido a la sobrecarga del operador, el código C ++ puede verse casi idéntico a su segundo ejemplo. (d) Una verificación tan extensa (en Java, ¿verdad?) solo se requiere si: (1) No tiene idea de lo que está haciendo. (2) La naturaleza de los datos es tal que se requiere (no sucede en las competencias de codificación). (3) Está escribiendo un código para que lo usen otras personas (no aplicable).
Dukeling
1
@Dukeling: Según este estudio ( page.mi.fu-berlin.de/prechelt/Biblio/jccpprtTR.pdf ), los lenguajes de script permiten un desarrollo más rápido y un código fuente más pequeño. Según otro estudio ( flownet.com/gat/papers/lisp-java.pdf ), Lisp ofrece aún más productividad que los lenguajes de secuencias de comandos. Según el segundo estudio citado anteriormente, el código Lisp resulta ser casi tan rápido como el código C ++, mientras que lleva menos tiempo escribirlo.
Giorgio
"entre un programa de 200,000 líneas y un programa de 40,000 líneas": Creo que hay que distinguir. Las diferencias debidas a la verbosidad del lenguaje de programación (sintaxis) no agregan complejidad al código y, por lo tanto, pueden tener poco impacto en el esfuerzo de mantenimiento requerido. Por otro lado, puede tener un recuento de líneas diferente debido a las diferentes características del idioma. Por ejemplo, en Python no tiene que administrar la memoria, mientras que en C debe implementar toda su administración de memoria usted mismo. Entonces, estoy de acuerdo con usted en que en el código C tiene más funcionalidad y definitivamente necesita un tiempo de mantenimiento adicional.
Giorgio el
@Giorgio No estoy discutiendo sobre el tiempo de desarrollo o el tamaño del código fuente, simplemente lo que realmente sucede en las competencias de programación, basado en una experiencia significativa.
Dukeling el
1
Estaba citando dos artículos científicos (que vale la pena echarle un vistazo a la OMI), no estaba hablando de lo que piensan las personas en las páginas web. El hecho de que una opinión esté muy extendida no implica automáticamente que sea válida. :-) Al menos, uno tiene que verificarlo de alguna manera rigurosa.
Giorgio el
2

Cualquier algoritmo puede implementarse en cualquier lenguaje de programación. Después de todo, no es la sintaxis lo que importa. Pero usar un lenguaje de alto nivel como Python tiene sus propias ventajas. Menos trabajo y menos cantidad de codificación. Entonces, para implementar un algoritmo en Python, necesitará menos líneas de las que se requieren en un lenguaje de bajo nivel como C.

Python tiene la mayoría de las estructuras de datos integradas en su biblioteca. Pero en C, debemos comenzar desde cero y usar una estructura para construirlo todo. Ciertamente, existen diferencias entre el lenguaje de alto nivel y el de bajo nivel, pero el lenguaje no debería impedir que implemente ningún algoritmo.

Robin Thomas
fuente
2

Si bien extrapolar el ejemplo "40 LoC vs 200 LoC", diciendo "bueno, solo una quinta parte de la LoC total es obviamente más rápida de escribir, por lo que debe ser mejor" puede parecer tentador, realmente creo que hay poca verdad que encontrar allí.

La optimización para la menor cantidad de LoC casi nunca es una buena idea en mi opinión. Sí, cada LoC escrito es un potencial para errores, y nunca tiene que depurar lo que nunca escribió etcetc. El punto es, optimizar la legibilidad y el desacoplamiento. No importa si resuelve un problema utilizando una expresión regular grande de 20 líneas, en lugar de escribir un módulo de 1k LoC. La expresión regular será una pared opaca, extremadamente propensa a los insectos, difícil de entender, una pesadilla para alterar sin cambiar su comportamiento de manera no detectable, etc.

Deshacerse de repeticiones y verbosidad que no agregan ningún valor está muy bien, pero por otro lado, usar algo como Java o C #, tener conocimiento sobre patrones de diseño y herramientas como resharper le permiten TANTA flexibilidad en la refactorización del código , limpiarlo con el tiempo, descomponer cosas, etc., eso sería MUCHO más difícil si lo hubiera escrito como un script de Python o una aplicación de rubí mucho más pequeños.

Una comparación muy reveladora: Prefiero tener 100k LoC de código C # desacoplado cubierto por pruebas, lleno de cosas "excesivas" como patrones de estrategia, fábricas, etc., en lugar de una aplicación python de 20k que simplemente "hace las cosas". 5 veces más código o no, la arquitectura gana todos los días.

Estoy totalmente de acuerdo en que algunos tipos de trabajo son más fáciles y más convenientes en algunos idiomas, pero creo más en la elección de su idioma en función de las herramientas que necesita y cuáles son los requisitos (y podrían ser en el futuro cercano).

sara
fuente