Después de leer this very informative (albeit somewhat argumentative) question Me gustaría conocer su experiencia en la programación de grandes proyectos con Python. ¿Las cosas se vuelven inmanejables a medida que el proyecto se hace más grande? Esta preocupación es una cosa que me mantiene apegado a Java. Por lo tanto, estaría particularmente interesado en comparaciones informadas de mantenimiento y extensibilidad de Java y Python para proyectos de gran tamaño.¿Cómo afecta la capacidad de tipeo estático de Python la capacidad de mantenimiento y la extensibilidad en proyectos más grandes?
Respuesta
Trabajo en un producto comercial a gran escala hecho en Python. Doy una estimación muy aproximada de 5000 archivos x 500 líneas cada uno. Eso es alrededor de 2.5 millones de líneas de Python. Tenga en cuenta que la complejidad de este proyecto probablemente sea equivalente a 10 mil + líneas de código en otros idiomas. No he tenido noticias de un solo ingeniero/arquitectura/gerente que se queje de que el código de Python no se pueda mantener. Por lo que he visto en nuestro rastreador de errores, no veo ningún problema sistémico que pueda evitarse mediante la comprobación de tipos estáticos. De hecho, hay muy pocos errores en el uso incorrecto del tipo de objeto.
Creo que este es un muy buen tema académico para estudiar empíricamente por qué el lenguaje basado en clases estáticas no parece ser tan crítico como uno podría pensar.
Y sobre la extensibilidad. Acabamos de agregar una base de datos 2 en la parte superior de la base de datos 1 en nuestro producto, ambas no SQL. No hay problemas relacionados con la verificación de tipos. En primer lugar, hemos diseñado una API lo suficientemente flexible como para anticipar diferentes implementaciones subyacentes. Creo que el lenguaje dinámico es más una ayuda que un obstáculo en este sentido. Cuando pasamos a las pruebas y la frase de corrección de errores, estábamos trabajando en el tipo de errores que las personas que trabajan en cualquier idioma deberían enfrentar. Por ejemplo, problemas de uso de memoria, problemas de coherencia y de integridad referencial, problemas de manejo de errores. No veo que la comprobación del tipo estático tenga mucha ayuda en ninguno de estos desafíos. Por otro lado, nos hemos beneficiado enormemente del lenguaje dinámico al poder inyectar código en pleno vuelo o después de parches simples. Y podemos probar nuestra hipótesis y demostrar nuestras soluciones rápidamente.
Es seguro decir que la mayoría de nuestros más de 100 ingenieros son felices y productivos usando Python. Probablemente sea impensable para nosotros construir el mismo producto usando un lenguaje estático en la misma cantidad de tiempo con la misma calidad.
¡Guau! Lo siento, no puedo dejar de comentar sobre esto. Es bueno saber ... –
¿Cuáles son las herramientas que utiliza? Integración continua ? ¿Cuál es su estrategia para probar? ¿Diría que los ingenieros son todos desarrolladores maduros de Python? – Rytek
Según mi experiencia, los idiomas tipificados de forma estática pueden ser difíciles de mantener. Por ejemplo, digamos que tiene una función de utilidad que acepta una clase personalizada como parámetro. Si en el camino adoptas una nueva convención de nombres, el nombre de esta clase tendrá que cambiar, y luego todas tus funciones de utilidad deberán cambiar también. En un lenguaje como Python, no importa, siempre que la clase implemente los mismos métodos.
Personalmente, desprecio un idioma que se interpone en mi camino. La velocidad de expresar tus ideas es valiosa, y esta es la ventaja que Python tiene sobre Java.
Estoy trabajando en _la peor base de código Java alguna vez creada en la historia del tipo de hombre en este momento. Está plagado de estados globales innecesarios, declaraciones de no hacer nada (incluso no hacer instancias de clases anónimas), cargadores de clases personalizados innecesarios, basura en el sistema de archivos con basura al azar, condiciones de carrera, quién sabe qué más, sin embargo, es relativamente fácil trabajar con ... ¿Por qué? porque es un lenguaje simple, aunque Python también lo es ... Todo el propósito del tipado estático es hacer que todo ** esté estático **; es decir: ** fácil de analizar **. –
Su ejemplo de convención de nomenclatura no tiene ningún sentido: 1. Tanto en Python como en Java, _nunca_ le pasa el nombre de una clase a una función a menos que esté buscando problemas o tenga un caso de uso muy específico. 2. Contrariamente al código de Java sin reflejos, el código de Python _no se puede reconstruir de manera determinista para usar nombres de métodos nuevos debido a la escritura dinámica. 3. El código Pythonic sigue las convenciones de nomenclatura PEP8, la mayoría de Java sigue theConventionLikeThis, ¿por qué alguna vez usarías tu propia convención cuando ya tienes que mezclar bibliotecas de facto que usan todas las convenciones de facto? –
Además, es posible que desee probar Haskell antes de decir que la tipificación estática "se interpone en su camino" ... Tal vez su impresión proviene de la forma tonta (aunque simple y sólida) en que Java lo implementó. –
He utilizado Python para muchos proyectos, desde unos pocos cientos de líneas hasta varios miles de líneas. La escritura dinámica ahorra mucho tiempo y hace que los conceptos OO como el polimorfismo sean mucho más fáciles de usar. El sistema de tipos no hace que los proyectos no se puedan mantener. Si tiene problemas para imaginar eso, intente escribir algunas cosas en Python y vea cómo funcionan.
El problema en discusión no es escribir un nuevo programa * ex nihilo * - que, sí, es mucho más fácil en un lenguaje de tipado dinámico como Python; el problema es la capacidad de mantenimiento y, en particular, la manera en que elude el código de otra persona. Debido a que las firmas de método de un lenguaje de tipado dinámico no llevan inherentemente ningún tipo de información, se pierde un mecanismo de auto-documentación incorporado. –
@outisnihil Mi punto no era solo que escribir código nuevo en Python era fácil, sino que, en mi experiencia, el código de Python es bastante fácil de mantener. Supongo que no lo dije explícitamente, pero no todos los proyectos para los que he usado Python han sido solo. Esto es más un testimonio que una respuesta profunda, pero pensé que podría agregar valor a la conversación. – nmichaels
Para mí, al menos, Python hace que sea más fácil comprender el algoritmo dentro de cada método, pero (al igual que todos los lenguajes de tipado dinámico) comprender cómo usar los métodos existentes un poco más (sin documentación). –
Una gran base de código en python sin buena cobertura de prueba podría ser un problema. Pero eso es solo una parte de la imagen. Se trata de personas y enfoques adecuados para hacer el trabajo.
Sin
- control de código fuente
- de seguimiento de fallos
- Unidad de Pruebas de
- equipo comprometido
que puede fallar con cualquier tipo de lenguaje.
Mi experiencia ha sido que una base de código Python es menos tolerante con los nuevos desarrolladores a quienes se les ha encomendado la tarea de mantener el código después de que los desarrolladores originales ya hayan cambiado de sitio. La base de código particular que encontré no tenía ninguna prueba unitaria, lo que significaba que todos los errores solo se detectaban en las pruebas de integración o (como ocurría con demasiada frecuencia) en el campo. Los lenguajes de tipo estático pueden detectar algunos de los errores más estúpidos que puede cometer, pero ciertamente no es una solución mágica. –
Los idiomas con tics estáticos le dan una firma de método más detallada. Si está tratando con una base de código que está mal documentada y no muy auto-documentada, puede ser de gran ayuda. Desafortunadamente, los buenos lenguajes de tipo dinámico (estoy pensando en Python aquí) hacen que el prototipado sea demasiado fácil: puedes poner en marcha un programa y estar muy cerca de completarse tan rápido que nombrar y documentar correctamente te parezca una tarea insuperable. Los desarrolladores deben aprender la importancia de * elegir buenos nombres * antes de que el tipado estático pierda gran parte de su ventaja en el mantenimiento. –
Recuerdo los días anteriores y posteriores a la innovación de IntelliJ IDEA. Hay grandes diferencias. Antes, la tipificación estática era solo para compilación, el desarrollo básicamente trata el código fuente como archivos de texto. Después, el código fuente es información estructurada, muchas tareas de desarrollo son más fáciles, gracias al tipado estático.
Sin embargo, no es como si los viejos tiempos fueran un infierno. Lo tomamos como está, hacemos lo que sea necesario, usamos las herramientas disponibles hasta la fecha, construimos el sistema, la satisfacción. No hubo demasiados recuerdos infelices. Eso es probablemente lo que los programadores de tipeo dinámico sienten ahora. No está tan mal.
Por supuesto, nunca volveré a los viejos tiempos. Si tengo prohibido usar un IDE así, supongo que tendremos que programarnos todos juntos.
Según mi experiencia, la capacidad de mantenimiento depende del bajo acoplamiento, la buena documentación, el buen proceso de desarrollo y las excelentes pruebas. La tipificación estática tiene muy poco que ver con esto.
Los errores que Java detectará en tiempo de compilación son solo un pequeño subconjunto de los errores que pueden ocurrir. También son casi siempre los más triviales para detectar mediante pruebas; ¡no hay forma de que pierdas la posibilidad de invocar un método en un objeto de la clase incorrecta si pruebas que tu código produce la respuesta correcta! En ese sentido, podría argumentar que Python en realidad es mejor para garantizar la calidad; por forzando a a probar al menos un poco para asegurarse de que su código está libre de errores tipográficos simples, se asegura de que en realidad haga pruebe al menos un poco.
De hecho, Java ni siquiera es un muy buen ejemplo de un lenguaje con fuertes controles estáticos para detectar muchos errores. Intente programar en Haskell o Mercury para ver a qué me refiero, o mejor aún, intente programar en Scala e interactuar con bibliotecas de Java; la diferencia en la cantidad de "corrección" que el compilador puede garantizarle es sorprendente cuando compara el código idiomático normal de Scala usando bibliotecas Scala con el código que tiene que tratar con las bibliotecas Java (de hecho lo he hecho, dado que programo un poco en Scala en Android).
Su capacidad de escribir buen código mantenible en grandes código bases trabajados por muchos desarrolladores durante largos períodos de tiempo, a pesar de las deficiencias de detección de error estático de Java en comparación con lenguajes como Scala, depende de exactamente las mismas técnicas Python los programadores suelen hacer lo mismo en sus grandes bases de código, a pesar de las deficiencias de la detección de errores estáticos de Python en comparación con Java.
Trate de rastrear la fuente de un objeto aparentemente mal formado en un marco grande, de tipo dinámico con muchos IoC u otros patrones de diseño donde el objeto no se puede rastrear directamente en la pila.
Ahora intente hacer esto en un lenguaje estático.
A menos que el tipo de objeto esté documentado cerca del sitio de uso (por ejemplo, a través de anotaciones tipo, la biblioteca de tipo seguro de Python) o en algún lugar de la pila, deducir de dónde vino puede ser virtualmente imposible. Hablo por experiencia, después de haber intentado depurar partes del framework BuildBot. Implicó una inmensa cantidad de búsqueda de texto en bruto a través del marco, incluso utilizando IDEs sofisticados como PyDev, Komodo y Wingware.
No dudo que sea posible imponer algunas restricciones de tipo a los lenguajes dinámicos, pero la falta de estandarización en esto parece ser un impedimento para cualquiera que intente depurar parte de un marco existente grande.
- 1. Mantenimiento de recursos (resx) en grandes proyectos
- 2. ¿Cómo cambia la capacidad de StringBuilder?
- 3. Prioridades de codificación: rendimiento, capacidad de mantenimiento, reutilización?
- 4. Capacidad de PHP para manejar la recursión
- 5. La expresión idiomática y la capacidad de prueba
- 6. Delphi: Capacidad de mantenimiento virtual vs virtual Resumen
- 7. reducir la capacidad de un vector stl
- 8. Diseño de la capacidad de prueba en C++
- 9. ¿Tiene la JVM la capacidad de detectar oportunidades de paralelización?
- 10. ¿Cómo obtener la capacidad de ArrayList en Java?
- 11. Cómo deshabilitar la capacidad de seleccionar en un DataGridView?
- 12. ¿Cuál es la importancia de establecer la capacidad de `IList`?
- 13. Capacidad de ArrayList
- 14. Capacidad predeterminada de StringBuilder
- 15. ¿Tiene node.js la capacidad de leer desde la URL?
- 16. eliminar la capacidad para cerrar la barra de tareas
- 17. Declaración de la capacidad de una lista en Java
- 18. Capacidad máxima de almacenamiento de la base de datos SQLite
- 19. capacidad StringBuilder()
- 20. ¿std :: vector.pop_back() cambia la capacidad del vector?
- 21. Cómo liberar la capacidad no utilizada de una cadena
- 22. ¿Cómo establecer la capacidad CAP_SYS_NICE para un usuario de Linux?
- 23. Capacidad de uint64_t?
- 24. Sugerencias para agregar capacidad de complemento?
- 25. Capacidad de respuesta de CLLocationManager
- 26. Medición de la capacidad de prueba del código de C#
- 27. Planificación de la capacidad del tamaño de caché
- 28. ¿Existe un límite en cuanto a la capacidad de JSON?
- 29. son HashMaps con capacidad predefinida más rápido
- 30. ¿Aumenta la capacidad de memoria del emulador de Android?
Este es el tipo de pregunta que siempre me confunde. ¿Cómo puede el sistema de tipeo afectar la mantenibilidad? Hay dos posibilidades: o puede confiar en las personas que se registran en su base de origen o no puede. En el primer caso, no tiene ningún problema, independientemente del idioma, el sistema, los marcos, etc. que esté utilizando. Si no puede confiar en ellos, no hay esperanza para usted, independientemente del idioma, sistema, marcos, etc. que esté utilizando. Ciertamente no veo cuán pequeño puede ser un pedazo del pastel como el sistema de tipeo puede hacer una diferencia en cuanto a la mantenibilidad general de un proyecto. –
Parece un buen candidato para CW. – nmichaels
@Nathon y aaa - CWed es – JnBrymn