¿Existe una correlación entre la escala del proyecto y la rigurosidad del lenguaje?

72

Al explicar la diferencia entre la rigurosidad de los lenguajes y los paradigmas a un colega mío, terminé afirmando que:

  • Los lenguajes tolerantes, como los lenguajes dinámicos e interpretados, se utilizan mejor para prototipos y proyectos pequeños o aplicaciones web de tamaño mediano. Al elegir lenguajes dinámicos elegantes como Python o JavaScript con Node.js, los beneficios son:

    1. Desarrollo rápido,

    2. Código reducido repetitivo,

    3. Capacidad para atraer a programadores jóvenes y creativos que huyen de "lenguajes corporativos"   como Java.

  • Los idiomas compilados / tipados estáticamente son los mejores para aplicaciones que requieren una mayor rigurosidad, como aplicaciones críticas para el negocio o aplicaciones para aplicaciones de tamaño mediano a grande.

    1. Paradigmas y patrones conocidos desarrollados durante décadas,

    2. Facilidad de comprobación estática,

    3. Capacidad para encontrar muchos desarrolladores profesionales con décadas de experiencia.

  • Lenguajes estrictos como Haskell, Ada o técnicas como los contratos de Código en C # son mejores para los sistemas que favorecen la seguridad sobre la flexibilidad (incluso si Haskell puede ser extremadamente flexible), como los sistemas críticos y los sistemas que se espera que sean extremadamente estables. Los beneficios son:

    1. Capacidad para atrapar tantos errores como sea posible en tiempo de compilación,

    2. Facilidad de comprobación estática,

    3. Facilidad de pruebas formales.

Sin embargo, al observar los lenguajes y tecnologías utilizados para proyectos a gran escala por grandes corporaciones, parece que mi afirmación es incorrecta . Por ejemplo, Python se utiliza con éxito para sistemas grandes como YouTube u otras aplicaciones de Google que requieren una cantidad importante de rigor.

¿Existe todavía una correlación entre la escala del proyecto y la rigurosidad del lenguaje / paradigma que debe usarse?

¿Hay un tercer factor que he olvidado tener en cuenta?

Donde me equivoco

Arseni Mourzenko
fuente
12
La verificación estricta de tipos y la verificación estática de tipos no son lo mismo. Python se tipea dinámicamente, pero es más estricto que C. La ventaja de la verificación de tipos estáticos no es la rigidez per se sino que los tipos se verifican en el momento de la compilación, no en el tiempo de ejecución. He tratado con muchos problemas de C / C ++ en mi carrera debido al casting implícito.
Gort the Robot
55
Probablemente hay algo que decir sobre el ciclo de vida: el software que comienza en su primera categoría puede evolucionar hacia los demás, "arrastrando" el lenguaje con él.
Mat
11
Lo único elegante de javascript es que se ejecuta en la mayoría de los navegadores.
JeffO
1
@StevenBurnap: No podría estar más de acuerdo con respecto a la diferencia entre estático y estricto. Java es otro punto en el espectro, siendo estático y demasiado estricto. Los desarrolladores a menudo reprenden la escritura estática utilizando Java como ejemplo, pero gran parte de esa crítica debería dirigirse al compilador demasiado estricto de Java , no a la escritura estática en general. Simplemente mire Scala en la misma JVM, que está estáticamente escrita, pero tiene un código mucho menos detallado debido a las fantásticas capacidades de inferencia de tipos del compilador.
Cornel Masson
2
"Python se usa con éxito para sistemas grandes": ¿cuál es la definición de "éxito" aquí? ¿Que se ejecuta principalmente y produce algún resultado? ¿Se incluye la cantidad de pruebas y mano de obra requerida? ¿Qué pasa con la mantenibilidad?
Den

Respuestas:

39

Un estudio de caso interesante sobre los asuntos de proyectos de escala que usan lenguaje dinámico e interpretado se puede encontrar en Beginning Scala por David Pollak.

Comencé a buscar una forma de expresar el código en mi cerebro de una manera más simple y directa. Encontré a Ruby y Rails. Me sentí liberado. Ruby me permitió expresar conceptos en muchas menos líneas de código. Rails era mucho más fácil de usar que Spring MVC, Hibernate y los otros frameworks web Java "simplificados". Con Ruby and Rails, pude expresar mucho más de lo que estaba en mi cabeza en un período de tiempo más corto. Fue similar a la liberación que sentí cuando me mudé de C ++ a Java ...

A medida que mis proyectos de Ruby and Rails crecieron más allá de unos pocos miles de líneas de código y agregué miembros del equipo a mis proyectos, los desafíos de los lenguajes dinámicos se hicieron evidentes.

Estábamos gastando más de la mitad de nuestro tiempo de codificación escribiendo pruebas, y gran parte de las ganancias de productividad que vimos se perdieron en la escritura de pruebas . La mayoría de las pruebas habrían sido innecesarias en Java porque la mayoría de ellas estaban orientadas a garantizar que habíamos actualizado las llamadas cuando refactorizamos el código cambiando los nombres de los métodos o los recuentos de parámetros. Además, descubrí que al trabajar en equipos donde había fusiones mentales entre dos y cuatro miembros del equipo, las cosas salieron bien en Ruby, pero a medida que intentamos atraer nuevos miembros al equipo, las conexiones mentales eran difíciles de transmitir a los nuevos miembros del equipo .

Fui a buscar un nuevo entorno de lenguaje y desarrollo. Estaba buscando un lenguaje que fuera tan expresivo como Ruby pero tan seguro y de alto rendimiento como Java ...

Como puede ver, los principales desafíos en el escalado de proyectos para el autor resultaron en el desarrollo de pruebas y la transferencia de conocimiento.

En particular, el autor entra en más detalles al explicar las diferencias en la escritura de pruebas entre los idiomas escritos dinámicamente y estáticamente en el Capítulo 7. En la sección "Conejos conmovedores conmovedores: escaleras de Dwemthy", el autor analiza el puerto de Scala de un ejemplo particular de Ruby:

Por qué Lucky Stiff ... introduce algunos de los conceptos de metaprogramación de Ruby en Dwemthy's Array en los que un conejo lucha contra una serie de criaturas. N8han14 actualizó el ejemplo para trabajar en Scala ...

En comparación con el código Ruby, las partes de la biblioteca del código Scala eran más complejas. Tuvimos que hacer mucho trabajo para asegurarnos de que nuestros tipos fueran correctos. Tuvimos que reescribir manualmente las propiedades de Creature en las clases DupMonster y CreatureCons. Esto es más trabajo que method_missing. También tuvimos que hacer una buena cantidad de trabajo para apoyar la inmutabilidad en nuestras Criaturas y Armas.

Por otro lado, el resultado fue mucho más poderoso que la versión Ruby. Si tuviéramos que escribir pruebas para nuestro código Ruby para probar lo que nos asegura el compilador Scala, necesitaríamos muchas más líneas de código. Por ejemplo, podemos estar seguros de que nuestro Conejo no podría empuñar un Hacha. Para obtener esta garantía en Ruby, tendríamos que escribir una prueba que asegure que la invocación |^de un conejo falla. Nuestra versión Scala garantiza que solo las Armas definidas para una Criatura dada puedan ser utilizadas por esa Criatura, algo que requeriría mucha reflexión en tiempo de ejecución en Ruby ...


Leer más arriba puede hacernos pensar que a medida que los proyectos crecen aún más, la redacción de pruebas puede volverse prohibitivamente engorrosa. Este razonamiento sería incorrecto, como lo demuestran los ejemplos de proyectos muy grandes exitosos mencionados en esta misma pregunta ("Python se usa con éxito para ... YouTube").

La cuestión es que la ampliación de los proyectos no es realmente sencilla. Los proyectos muy grandes y de larga duración pueden "permitirse" diferentes procesos de desarrollo de pruebas, con conjuntos de pruebas de calidad de producción, equipos de desarrollo de pruebas profesionales y otras cosas pesadas.

Las suites de prueba de Youtube o el Kit de compatibilidad de Java seguramente viven una vida diferente a las pruebas en un pequeño proyecto tutorial como Dwemthy's Array .

mosquito
fuente
24

Tu afirmación no está mal. Solo necesitas cavar un poco más profundo.

En pocas palabras, los grandes sistemas usan múltiples idiomas, no solo un idioma. Puede haber partes que se crean con lenguajes "estrictos", y puede haber partes que se crean con lenguajes dinámicos.

En cuanto a su ejemplo de Google y YouTube, escuché que usan Python principalmente como "pegamento" entre varios sistemas. Solo Google sabe con qué están construidos esos sistemas, pero apuesto a que muchos de los sistemas críticos de Google están construidos usando lenguajes estrictos y "corporativos" como C ++ o Java, o tal vez algo que ellos mismos crearon como Go.

No es que no pueda usar lenguajes tolerantes para sistemas a gran escala. Muchas personas dicen que Facebook usa PHP, pero se olvidan de mencionar que Facebook tuvo que crear pautas de programación extremadamente estrictas para usarlo eficientemente a esta escala.

Entonces sí, se requiere cierto nivel de rigor para proyectos a gran escala. Esto puede provenir de la rigurosidad del lenguaje o el marco, o de pautas de programación y convenciones de código. No puede simplemente tomar algunos graduados universitarios, darles Python / Ruby / JavaScript y esperar que escriban software que se adapte a millones de usuarios.

Eufórico
fuente
"No puedes simplemente tomar unos pocos graduados universitarios" ... "y esperar que escriban software que se adapte a millones de usuarios". probablemente hubiera sido suficiente.
dyesdyes
Vale la pena señalar aquí que, al igual que con Google y Python, el uso de PHP en Facebook es en gran medida como pegamento ... Entiendo que para la mayoría de las funciones, PHP se usa principalmente como un cliente relativamente simple en un sistema de servidor más complejo que generalmente se implementa en un lenguaje "pesado" más tradicional, como Java, C ++, Haskell, OCaML, etc.
Julio
"Solo Google sabe con qué están construidos esos sistemas". Incluso tengo algunas dudas al respecto :) En mi experiencia, ninguna entidad individual (persona o no) puede enumerar todas las partes de un sistema muy grande. En muchos casos, enterrado en los cuencos de algún servidor hay una pieza olvidada del guión de Perl, Fortran o KSH que realiza 'Magia'.
mattnz
3

Hay dos tipos de errores para verificar: errores de tipo (concatenar un entero + lista de flotantes) y errores de lógica de negocios (transferir dinero a una cuenta bancaria, verificar si la cuenta de origen tiene dinero).

La parte "dinámica" de un lenguaje de programación dinámico es el lugar donde tiene lugar la verificación de tipo. En un lenguaje de programación "tipado dinámicamente", la verificación de tipo se realiza mientras se ejecuta cada instrucción, mientras que en un lenguaje de "lenguaje tipado estáticamente" se realiza en el momento de la compilación. Y puede escribir un intérprete para un lenguaje de programación estático (como lo hace emscriptem ), y también puede escribir un compilador estático para un lenguaje de programación dinámico (como lo hace gcc-python o shed-skin ).

En un lenguaje de programación dinámico como Python y Javascript, debe escribir pruebas unitarias no solo para la lógica empresarial del programa, sino también para verificar si su programa no tiene errores de tipo o sintaxis. Por ejemplo, si agrega "+" un número entero a una lista de flotantes (que no tiene sentido y emitirá un error), en un lenguaje dinámico, el error se generará en tiempo de ejecución al intentar ejecutar la instrucción. En un lenguaje de programación estático como C ++, Haskell y Java, el compilador detectará este tipo de error de tipo.

Una base de código pequeña en un lenguaje de programación verificado dinámicamente es más fácil de buscar errores de tipo porque es más fácil tener una cobertura del 100% del código fuente. Eso es todo, ejecutas el código a mano varias veces con diferentes valores y listo. Tener una cobertura del 100% del código fuente le da una pista clara de que su programa puede no tener errores de tipo .

Con una gran base de código en un lenguaje de programación comprobado dinámicamente, es más difícil probar cada declaración con cada combinación de tipos posible, especialmente si es descuidado y escribe una función que puede devolver una cadena, una lista o un objeto personalizado dependiendo de sus argumentos.

En un lenguaje de programación comprobado estáticamente, el compilador detectará la mayoría de los errores de tipo en tiempo de compilación. Lo digo más porque un error de división por cero, o un error de matriz fuera de límites también son errores de tipo.

La mayoría de las veces, la verdadera discusión no se trata de lenguajes de programación sino de las personas que usan esos lenguajes. Y esto es cierto porque, por ejemplo, el lenguaje ensamblador es tan poderoso como cualquier otro lenguaje de programación, sin embargo, estamos escribiendo código en JavaScript. ¿Por qué? Porque somos humanos. Primero, todos cometemos errores y es más fácil y menos propenso a usar una herramienta dedicada especializada para una tarea específica. En segundo lugar, hay una restricción de recursos. Nuestro tiempo es limitado, y escribir páginas web en el ensamblaje llevaría años terminar.

vz0
fuente
3

Mi experiencia con los sistemas grandes es que se mantienen o caen no por elección de idioma, sino por cuestiones de diseño / arquitectura o cobertura de prueba . Prefiero tener un talentoso equipo de Python en mi gran proyecto empresarial, que uno mediocre de Java.

Habiendo dicho eso, cualquier lenguaje que le permita escribir significativamente menos código , debe valer la pena mirarlo (por ejemplo, Python vs Java). Quizás el futuro esté en lenguajes inteligentes, de tipo estático, con inferencia de tipos avanzada (por ejemplo, en el molde Scala). ¿O híbrido, como C # está intentando con su dynamiccalificador ...?

Y no olvidemos el "otro" beneficio de tipeo estático: completar el código IDE / intellisense correctamente, que en mi opinión es una característica esencial, no agradable de tener.

Cornel Masson
fuente
1
"code-complete / intellisense": la refactorización automática también es bastante importante.
Den
@Den Absolutamente. ¿Podría ser que los lenguajes dinámicos lo ayuden a escribir versiones iniciales muy rápidamente (más fácil, menos código para escribir), pero se atasquen más tarde, ya que cada vez es más difícil evaluar el impacto del cambio o refactorizar (sin herramientas de refactorización automatizadas)?
Cornel Masson
0

Otra consideración es quién detrás de escribir aplicaciones a gran escala. He trabajado en muchos lugares que desean usar Ruby o Python en algunos proyectos grandes de estilo empresarial, pero son constantemente "derribados" por los gerentes de TI y los equipos de seguridad corporativa precisamente por la naturaleza de código abierto de los proyectos.

Me han dicho: "No podemos usar Ruby on Rails porque es de código abierto y alguien podría poner piratas informáticos que roban información crítica o protegida". Lo siento, pero una vez que alguien tiene esa mentalidad de código abierto == mal, es casi imposible cambiarlo. Esa línea de pensamiento es una enfermedad corporativa.

C # y Java son de confianza idiomas con confianza plataformas. Ruby y Python no son lenguajes confiables.

Jarrett Meyer
fuente
2
No estoy de acuerdo con la última línea. Java se encuentra en uno de sus puntos de confianza más bajos. C # es considerado con cautela por toda la comunidad de código abierto. Ruby es visto como sólido pero lento (a pesar de que ya no lo es) y Python es el hijo del glamour del caballo de trabajo de confianza de industrias completas (¿aprendizaje de máquinas y ciencia de datos, alguien?).
CodeBeard
1
Los lenguajes dinámicos son malos para la seguridad, pero el "código abierto" no es una buena razón. Quizás querían decir "es fácil influir en una parte del código desde una parte completamente diferente del código". Ver programmers.stackexchange.com/questions/206558/…
Eufórico el
1
Tenga en cuenta que, de hecho, la "fuente abierta" es uno de los aspectos de elección de un idioma. Esa es, por ejemplo, una de las tres razones dadas por Jeff Atwood para explicar por qué Discourse usa Ruby.
Arseni Mourzenko
C # es completamente de código abierto ahora, sin embargo, todavía está curada, planificada y desarrollada por desarrolladores profesionales, lo cual es bueno, supongo. Esperemos que el tipo de "Python 3 vs 2" no suceda aquí.
Den
Los programadores introducen los errores y los agujeros de seguridad y no los idiomas, y para el registro, he contribuido con una serie de soluciones de seguridad para proyectos de código abierto. ¿Cuántos proyectos cerrados he ayudado? ¡cero!
Reactgular