Por una razón que es en gran medida irrelevante, instalé Delphi 7 una vez más en mucho tiempo. Tengo que decir que me quedé completamente impresionado, de una manera que no he estado en bastante tiempo. No es así como recuerdo las cosas. La instalación tomó alrededor de 30 segundos. El lanzamiento tardó 2 segundos, y fue inmediatamente utilizable. Puedo presionar "Ejecutar" el segundo después de que comenzó, y menos de un segundo después el programa en blanco ya está visible y ejecutándose. ¡Hurra por que las computadoras sean mucho más rápidas!
Pero la razón por la que me ha impresionado es porque usualmente uso Visual Studio 2010, eso no se siente tan ágil en absoluto. Por supuesto, Delphi 7 es un sistema mucho más pequeño que Visual Studio 2010, pero tiene la apariencia de tener todas las cosas realmente necesarias allí: una paleta de control, un diseñador de formularios, un editor de código con la finalización de código. Me doy cuenta de que el lenguaje puede ser más simple, y la finalización del código puede ser mucho menos potente, y el IDE puede no ser tan extensible y rico en funciones, pero aún así: no entiendo cómo (es decir, a través de qué mecanismo) tiene muchas características adicionales (que quizás aún no haya activado) hacen que un sistema como Visual Studio siempre se sienta lento en comparación.
Me gustaría preguntar a las personas con experiencia en el trabajo con sistemas la escala de Visual Studio: ¿qué es lo que los hace lentos? ¿Son las capas sobre capas de abstracciones necesarias para mantener la base de código dentro de las capacidades de comprensión humana? ¿Es la gran cantidad de código que debe ejecutarse? ¿Es la tendencia moderna hacia enfoques de ahorro de tiempo del programador a un costo (alucinantemente enorme) en el departamento de ciclos de reloj / uso de memoria?
fuente
Respuestas:
Astronáutica Arquitectónica
Visual Studio 2010 se basa en Windows Presentation Foundation. Eche un vistazo a la clase Button para WPF. Es el noveno hijo de una clase base. Tiene alrededor de 5 páginas de propiedades, métodos y eventos. Detrás de escena tiene otras cinco páginas de definiciones de estilo que describen sus esquinas bellamente redondeadas y las sutiles transiciones de animación cuando un cursor del mouse se mueve sobre él. Esto es todo por algo que fundamentalmente muestra texto o una imagen y produce un evento de clic cuando detecta que se está presionando un botón del mouse.
Detenga un programa como Visual Studio en cualquier punto aleatorio. Mira el rastro de la pila. Es muy probable que tenga 20 niveles de profundidad en la pila de llamadas y que se hayan cargado cinco DLL para llegar allí.
Ahora, compara estas dos cosas con Delphi. Apuesto a que encuentra que un botón de Delphi tiene solo 20 propiedades, métodos y eventos. Apuesto a que el IDE de Delphi solo tiene un seguimiento de pila de 5-7 niveles de profundidad. Porque cuando las computadoras eran más lentas, simplemente no podía tomar la sobrecarga de Visual Studio 2010 sin que el IDE tomara 40 minutos para comenzar :-)
¿Es uno mejor que el otro? Bueno, generalmente puedo decirle a un programa Delphi cuando se carga porque se ve plano, los colores están silenciados (¿8 bits quizás?), Y no hay sombras o animaciones sutiles. Me siento "barato" en estos días. Barato, pero rápido.
¿Estamos mejor? Esa es una pregunta para los filósofos, no para los codificadores.
fuente
Creo que adivinó varios de ellos, pero me gustaría ofrecer lo que considero el factor más importante, después de haber trabajado en una base de código razonablemente grande (no estoy seguro de si es tan grande como Visual Studio), estaba en los millones de líneas de código categoría y alrededor de mil complementos) durante aproximadamente 10 años y se producen fenómenos de observación.
También es un poco menos controvertido ya que no entra en las API o las características del lenguaje ni nada de eso. Esos se relacionan con "costos" que pueden generar un debate en lugar de "gastos", y quiero centrarme en "gastos".
Coordinación suelta y legado
Lo que observé es que la falta de coordinación y un largo legado tienden a generar una gran cantidad de desechos acumulados.
Por ejemplo, encontré alrededor de cien estructuras de aceleración en esta base de código, muchas de ellas redundantes.
Tendríamos un árbol KD para acelerar un motor de física, otro para un nuevo motor de física que a menudo se ejecutaba en paralelo con el anterior, tendríamos docenas de implementaciones de octrees para varios algoritmos de malla, otro árbol KD para renderizar , selección, etc., etc., etc. Estas son estructuras de árbol grandes y voluminosas que se utilizan para acelerar las búsquedas. Cada individuo puede llevar cientos de megabytes a gigabytes de memoria para una entrada de tamaño muy promedio. No siempre se crearon instancias y se usaron todo el tiempo, pero en un momento dado, 4 o 5 de ellos podrían estar en la memoria simultáneamente.
Ahora todos estos almacenaban exactamente los mismos datos para acelerar la búsqueda de ellos. Puede imaginarlo como la antigua base de datos analógica que almacena todos sus campos en 20 mapas / diccionarios / árboles B + redundantes diferentes a la vez, organizados de forma idéntica por las mismas teclas, y los busca todo el tiempo. Ahora estamos tomando 20 veces la memoria y el procesamiento.
Además, debido a la redundancia, hay poco tiempo para optimizar cualquiera de ellos con el precio de mantenimiento que viene con eso, e incluso si lo hiciéramos, solo tendría el 5% del efecto que idealmente tendría.
¿Qué causa este fenómeno? La falta de coordinación fue la causa número uno que vi. Muchos miembros del equipo a menudo trabajan en sus ecosistemas aislados, desarrollando o utilizando estructuras de datos de terceros, pero no utilizan las mismas estructuras que otros miembros del equipo estaban utilizando, incluso si eran directamente duplicados evidentes de las mismas preocupaciones.
¿Qué hace que este fenómeno persista? El legado y la compatibilidad fue la causa número uno que vi. Como ya pagamos el costo de implementar estas estructuras de datos y grandes cantidades de código dependían de estas soluciones, a menudo era demasiado arriesgado intentar consolidarlas en menos estructuras de datos. A pesar de que muchas de estas estructuras de datos eran altamente redundantes conceptualmente, no siempre estaban cerca de ser idénticas en sus diseños de interfaz. Por lo tanto, reemplazarlos habría sido un cambio grande y arriesgado en lugar de simplemente dejarles consumir memoria y tiempo de procesamiento.
Eficiencia de memoria
Por lo general, el uso de la memoria y la velocidad tienden a estar relacionados al nivel masivo al menos. A menudo puede detectar software lento por cómo está acumulando memoria. No siempre es cierto que más memoria conduzca a una desaceleración, ya que lo que importa es la memoria "activa" (a qué memoria se accede todo el tiempo, si un programa usa una gran cantidad de memoria pero solo se usa 1 megabyte de todo el tiempo). tiempo, entonces no es un gran problema en cuanto a velocidad).
Por lo tanto, puede detectar los potenciales cerdos en función del uso de memoria la mayor parte del tiempo. Si una aplicación requiere decenas a cientos de megabytes de memoria en el inicio, probablemente no será muy eficiente. Decenas de megabytes pueden parecer pequeños cuando tenemos gigabytes de DRAM en estos días, pero los cachés de CPU más grandes y lentos todavía están en el rango de megabytes miserables, y los más rápidos todavía están en el rango de kilobytes. Como resultado, un programa que usa 20 megabytes solo para iniciarse y no hacer nada en realidad todavía está usando bastante "mucha" memoria desde el punto de vista de la caché de la CPU del hardware, especialmente si se accede a los 20 megabytes de esa memoria repetidamente y con frecuencia a medida que se ejecuta el programa.
Solución
Para mí, la solución es buscar equipos más pequeños y coordinados para crear productos, que puedan hacer un seguimiento de sus "gastos" y evitar "comprar" los mismos artículos una y otra vez.
Costo
Me sumergiré en el lado del "costo" más controvertido solo un poco con un fenómeno de "gasto" que he observado. Si un lenguaje termina con un precio inevitable para un objeto (como uno que proporciona reflexión en tiempo de ejecución y no puede forzar la asignación contigua para una serie de objetos), ese precio solo es costoso en el contexto de un elemento muy granular, como un soltero
Pixel
oBoolean
.Sin embargo, veo un montón de código fuente para los programas que hacen manejar una carga pesada (por ejemplo: se trata de cientos de miles a millones de
Pixel
oBoolean
casos) pagar ese costo a un nivel tan granular.La programación orientada a objetos puede exacerbar eso. Sin embargo, no es el costo de los "objetos" per se o incluso la OOP la culpa, es simplemente que dichos costos se pagan a un nivel tan granular de un elemento pequeño que se creará por millones.
Así que ese es el otro fenómeno de "costo" y "gasto" que estoy observando. El costo es de centavos, pero los centavos se suman si estamos comprando un millón de latas de refresco individualmente en lugar de negociar con un fabricante para una compra a granel.
La solución aquí para mí es la compra "a granel". Los objetos están perfectamente bien incluso en idiomas que tienen un precio de centavos para cada uno, siempre que este costo no se pague individualmente un millón de veces por el equivalente analógico de una lata de refresco.
Optimización prematura
Nunca me gustó la redacción que Knuth usó aquí, porque la "optimización prematura" rara vez hace que los programas de producción del mundo real sean más rápidos. Algunos interpretan eso como "optimizar temprano" cuando Knuth se refería más a "optimizar sin el conocimiento / experiencia adecuada para conocer su verdadero impacto en el software". En todo caso, el efecto práctico de la verdadera optimización prematura a menudo hará que el software sea más lento , ya que la degradación en la capacidad de mantenimiento significa que hay poco tiempo para optimizar las rutas críticas que realmente importan .
Este es el fenómeno final que observé, donde los desarrolladores que intentaban ahorrar centavos en la compra de una sola lata de refresco, nunca más para comprar, o peor aún, una casa, perdían todo su tiempo pellizcando centavos (o peor, centavos imaginarios de no entender su compilador o la arquitectura del hardware) cuando se gastaron miles de millones de dólares en otros lugares.
El tiempo es muy limitado, por lo que tratar de optimizar los absolutos sin tener la información contextual adecuada a menudo nos priva de la oportunidad de optimizar los lugares que realmente importan y, por lo tanto, en términos de efecto práctico, diría que "la optimización prematura hace que el software sea mucho más lento". "
El problema es que hay tipos de desarrolladores que tomarán lo que escribí anteriormente sobre los objetos y tratarán de establecer un estándar de codificación que prohíba la programación orientada a objetos o algo así de loco. La optimización efectiva es una priorización efectiva, y no tiene ningún valor si nos estamos ahogando en un mar de problemas de mantenimiento.
fuente
--force
por parte de los gerentes gritando "serás despedido si no implementas esto para mañana" que destruirá años de buenas prácticas de ingeniería de software, TDD, pruebas unitarias y cualquier principio de programación humano y sensato. , además de otras dos veces que estabas cansado ... ese tipo que dejó enojado a la compañía porque lo despidieron sin razón y estropeó la base de código ... esas bibliotecas descontinuadas que nunca actualizaste ... y aquí lo tienes: deliciosa base de código de espagueti y software hinchado. Buen