que - ¿Cómo puedo usar Python para el desarrollo a gran escala?
python español (8)
Me interesaría aprender sobre el desarrollo a gran escala en Python y especialmente sobre cómo mantener una gran base de código.
Cuando realiza cambios de incompatibilidad en la firma de un método, ¿cómo encuentra todos los lugares donde se llama ese método? En C ++ / Java el compilador lo encontrará para usted, ¿cómo lo hace en Python?
Cuando realiza cambios en el interior del código, ¿cómo averigua qué operaciones proporciona una instancia, ya que no tiene un tipo estático para buscar?
¿Cómo se manejan / evitan los errores de tipeo (errores tipográficos)?
¿UnitTest se usa como sustituto de la comprobación de tipo estática?
Como puedes imaginar, casi solo trabajé con lenguajes tipados estáticamente (C ++ / Java), pero me gustaría poner mis manos en Python para programas más grandes. Pero tuve una experiencia muy mala, hace mucho tiempo, con el lenguaje clipper (dBase), que también se tipeó dinámicamente.
La respuesta habitual a eso es probar las pruebas de prueba. Se supone que tienes un extenso conjunto de pruebas unitarias y lo ejecutas a menudo, especialmente antes de que una nueva versión se conecte.
Los defensores de los lenguajes de tipado dinámico argumentan que debe probar de todos modos, ya que incluso en un lenguaje tipado estático, el cumplimiento de las reglas crudas del sistema tipo cubre solo una pequeña parte de lo que potencialmente puede salir mal.
Tuve cierta experiencia con la modificación de "Frets On Fire", un clon de código abierto de python "Guitar Hero".
como yo lo veo, Python no es realmente adecuado para un proyecto de gran escala.
Me encontré gastando una gran parte de los problemas de depuración del tiempo de desarrollo relacionados con la asignación de tipos incompatibles, cosas que los lenguajes de tipo estático revelarán sin esfuerzo en tiempo de compilación. Además, dado que los tipos se determinan en tiempo de ejecución, tratar de comprender el código existente se vuelve más difícil, porque no tiene idea de cuál es el tipo de parámetro que está mirando actualmente.
Además de eso, llamar funciones usando su cadena de nombre con la __getattr__
integrada __getattr__
es generalmente más común en Python que en otros lenguajes de programación, lo que hace que el gráfico de llamadas a una función determinada sea algo difícil (aunque puede llamar funciones con su nombre en algunos lenguajes tipados estáticos también).
Creo que Python realmente brilla en software de pequeña escala, desarrollo rápido de prototipos y pegado de programas existentes, pero no lo usaría para proyectos de software a gran escala, ya que en esos tipos de programas la mantenibilidad se convierte en el verdadero problema, y en mi opinión, python es relativamente débil allí.
mi 0.10 EUR:
Tengo varias aplicaciones de Python en ''producción''-estado. nuestra compañía usa java, c ++ y python. desarrollamos con el eclipse ide (pydev para python)
los tests de unidad son la solución clave para el problema. (también para c ++ y java)
el mundo menos seguro de "tipado dinámico" le hará menos descuidado sobre la calidad de su código
POR EL CAMINO :
el desarrollo a gran escala no significa que uses un solo idioma.
El desarrollo a gran escala a menudo usa un puñado de idiomas específicos para el problema .
así que estoy de acuerdo con el problema del martillo :-)
No use un destornillador como martillo
Python no es un lenguaje estático, por lo que no intente usarlo de esa manera.
Cuando usa una herramienta específica, la usa para lo que se ha construido. Para Python, significa:
Duck typing : sin verificación de tipo. Solo el comportamiento importa. Por lo tanto, su código debe estar diseñado para usar esta característica. Un buen diseño significa firmas genéricas, sin dependencias entre componentes, altos niveles de abstracción ... Por lo tanto, si cambia algo, no tendrá que cambiar el resto del código. Python tampoco se quejará, para lo que fue construido. Los tipos no son un problema.
Enorme biblioteca estándar . No necesita cambiar todas sus llamadas en el programa si usa funciones estándar que no ha codificado usted mismo. Y Python viene con baterías incluidas. Los sigo descubriendo todos los días. No tenía idea de la cantidad de módulos que podía usar cuando comencé e intenté reescribir material existente como todos. Está bien, no puedes arreglarlo todo desde el principio.
No escribes Java, C ++, Python, PHP, Erlang, lo que sea, de la misma manera. Son buenas razones por las que hay espacio para cada uno de tantos idiomas diferentes, no hacen las mismas cosas.
Las pruebas unitarias no son un sustituto
Las pruebas unitarias deben realizarse con cualquier idioma. ¡La biblioteca de pruebas unitarias más famosa ( JUnit ) es del mundo de Java!
Esto no tiene nada que ver con los tipos. Verifica los comportamientos, de nuevo. Evitas problemas con la regresión. Usted asegura que su cliente está en las pistas.
Python para proyectos a gran escala
Los idiomas, las bibliotecas y los marcos no se escalan. Las arquitecturas lo hacen.
Si diseñas una arquitectura sólida, si puedes hacer que evolucione rápidamente, entonces se escalará. Pruebas unitarias de ayuda, verificación de código automático también. Pero solo son redes de seguridad. Y pequeños.
Python es especialmente adecuado para grandes proyectos porque impone algunas buenas prácticas y tiene muchos patrones de diseño habituales incorporados. Pero, de nuevo, no lo use para lo que no está diseñado. Por ejemplo: Python no es una tecnología para tareas intensivas de CPU.
En un gran proyecto, lo más probable es que uses varias tecnologías diferentes de todos modos. Como SGBD y un lenguaje de plantillas, o de lo contrario. Python no es una excepción.
Probablemente quiera usar C / C ++ para la parte de su código que necesita para ser rápido. O Java para caber en un entorno Tomcat . No lo sé, no me importa. Python puede jugar bien con estos.
Como conclusión
Mi respuesta puede parecer un poco grosera, pero no me malinterpreten: esta es una muy buena pregunta.
Mucha gente viene a Python con viejos hábitos. Me jodí tratando de codificar Java como Python. Puedes, pero nunca obtendrás lo mejor de ello.
Si jugaste / quieres jugar con Python, ¡es genial! Es una herramienta maravillosa. Pero solo una herramienta, realmente.
Cambios incompatibles en la firma de un método. Esto no ocurre tanto en Python como en Java y C ++.
Python tiene argumentos opcionales, valores predeterminados y mucha más flexibilidad para definir firmas de métodos. Además, la tipificación de pato significa, por ejemplo, que no es necesario cambiar de una clase a una interfaz como parte de un cambio significativo de software. Las cosas simplemente no son tan complejas.
¿Cómo encuentras todos los lugares donde se llama ese método? grep funciona para lenguajes dinámicos. Si necesita conocer cada lugar en el que se utiliza un método, grep (o búsqueda equivalente soportada por IDE) funciona muy bien.
¿Cómo averigua qué operaciones proporciona una instancia, ya que no tiene un tipo estático para buscar?
a. Mira la fuente. No tiene que lidiar con el problema de Java / C ++ de las bibliotecas de objetos y los archivos jar. No necesita todas las ayudas y herramientas elaboradas que esos idiomas requieren.
segundo. Un IDE puede proporcionar información de firma bajo muchas circunstancias comunes. Puedes, fácilmente, vencer los poderes de razonamiento de tu IDE. Cuando eso suceda, probablemente debas revisar lo que estás haciendo para asegurarte de que tenga sentido. Si su IDE no puede razonar su tipo de información, quizás sea demasiado dinámica.
do. En Python, a menudo trabajas a través del intérprete interactivo. A diferencia de Java y C ++, puede explorar sus instancias de forma directa e interactiva. No necesita un IDE sofisticado.
Ejemplo:
>>> x= SomeClass()
>>> dir(x)
¿Cómo manejar / prevenir errores de tipeo? Igual que los lenguajes estáticos: no los previene. Usted los encuentra y corrige. Java solo puede encontrar una cierta clase de errores tipográficos. Si tiene dos nombres similares de clase o variable, puede terminar en un problema profundo, incluso con la comprobación de tipo estático.
Ejemplo:
class MyClass { }
class MyClassx extends MyClass { }
Un error tipográfico con estos dos nombres de clase puede causar estragos. ["Pero no me pondría en esa posición con Java", dicen los amigos. Convenido. Tampoco me pondría en esa posición con Python; haces clases que son profundamente diferentes, y fallarán temprano si se usan mal.]
¿UnitTest se usa como sustituto de la comprobación de tipo estática? Aquí está el otro punto de vista: la comprobación estática del tipo es un sustituto del diseño claro y simple.
He trabajado con programadores que no estaban seguros de por qué funcionaba una aplicación. No podían entender por qué las cosas no compilaban; el no sabía la diferencia entre la superclase abstracta y la interfaz, y no pudo entender por qué un cambio en el lugar hace que muchos otros módulos se cuelguen en un archivo JAR por separado. La comprobación de tipo estática les dio una confianza falsa en un diseño defectuoso.
Los lenguajes dinámicos permiten que los programas sean simples. La simplicidad es un sustituto de la comprobación de tipos estáticos. Clarity es un sustituto de la comprobación de tipo estática.
Aquí hay algunos elementos que me han ayudado a mantener un sistema bastante grande en Python.
Estructura tu código en capas. es decir, lógica de biz separada, lógica de presentación y sus capas de persistencia. Invierta un poco de tiempo en la definición de estas capas y asegúrese de que todos en el proyecto estén comprados. Para sistemas grandes, crear un marco que lo obligue a un cierto modo de desarrollo también puede ser clave.
Las pruebas son clave, sin pruebas unitarias es probable que termine con una base de código no administrable varias veces más rápido que con otros idiomas. Tenga en cuenta que las pruebas unitarias a menudo no son suficientes, asegúrese de tener varias pruebas de integración / aceptación que puede ejecutar rápidamente después de cualquier cambio importante.
Utilice el principio Fail Fast . Agregue afirmaciones para casos en los que sienta que su código puede ser vulnerable.
Tener un registro estándar / manejo de errores que lo ayudará a navegar rápidamente hacia el problema
Use un IDE (PyDev funciona para mí) que proporciona la integración de tipo adelanto, pyLint / Checker que lo ayuda a detectar errores tipográficos comunes de inmediato y promover algunos estándares de codificación
Tenga cuidado con sus importaciones, nunca lo haga a partir de x import * o haga importaciones relativas sin el uso de.
Refactor, una herramienta de búsqueda / reemplazo con expresiones regulares a menudo es todo lo que necesita para mover los métodos / refactorización del tipo de clase.
Como nadie señaló pychecker, pylint y herramientas similares, voy a hacer lo siguiente: pychecker y pylint son herramientas que pueden ayudarlo a encontrar suposiciones incorrectas (sobre las firmas de funciones, los atributos de los objetos, etc.). No encontrarán todo lo que un compilador pueda encontrar en un lenguaje tipado estáticamente, pero pueden encontrar problemas que dichos compiladores de dichos idiomas tampoco pueden encontrar.
Python (y cualquier lenguaje de tipado dinámico) es fundamentalmente diferente en términos de los errores que es probable que cause y cómo los detectaría y corregiría. Tiene desventajas definidas y ventajas, pero muchos (incluyéndome a mí) argumentarían que en el caso de Python, la facilidad de escribir código (y la facilidad de hacerlo estructuralmente sólido) y de modificar el código sin romper la compatibilidad API (agregando nuevos argumentos opcionales , proporcionando diferentes objetos que tienen el mismo conjunto de métodos y atributos) lo hacen adecuado para grandes bases de código.
Mi regla general es usar lenguajes dinámicos para proyectos pequeños que no son de misión crítica y lenguajes de tipo estático para grandes proyectos. Me parece que el código escrito en un lenguaje dinámico como Python se "enreda" más rápidamente. En parte es porque es mucho más rápido escribir código en un lenguaje dinámico y eso lleva a atajos y un diseño peor, al menos en mi caso. En parte es porque tengo IntelliJ para una refactorización rápida y fácil cuando uso Java, que no tengo para Python.