¿Cómo maneja un salto de complejidad?

13

Parece una experiencia infrecuente pero común que a veces trabajas en un proyecto y, de repente, algo aparece inesperadamente, arroja una enorme llave en las obras y aumenta la complejidad un montón.

Por ejemplo, estaba trabajando en una aplicación que hablaba con los servicios SOAP en otras máquinas. Saqué un prototipo que funcionaba bien, luego desarrollé un extremo frontal regular y, en general, puse todo en marcha de manera agradable, bastante simple y fácil de seguir. Funcionó muy bien hasta que comenzamos a realizar pruebas en una red más amplia y, de repente, las páginas empezaron a agotarse, ya que la latencia de las conexiones y el tiempo requerido para realizar cálculos en máquinas remotas dieron como resultado solicitudes de tiempo de espera para los servicios de soap. Resultó que necesitábamos cambiar la arquitectura para hacer girar las solicitudes en sus propios subprocesos y almacenar en caché los datos devueltos para que pudieran actualizarse progresivamente en segundo plano en lugar de realizar cálculos en base a solicitud por solicitud.

Los detalles de ese escenario no son demasiado importantes, de hecho no es un gran ejemplo, ya que era bastante previsible y las personas que han escrito muchas aplicaciones de este tipo para este tipo de entorno podrían haberlo anticipado, excepto que ilustra una forma en que uno puede comenzar con una premisa y un modelo simples y de repente tener una escalada de complejidad en el desarrollo del proyecto.

¿Qué estrategias tiene para lidiar con estos tipos de cambios funcionales cuya necesidad surge, a menudo como resultado de factores ambientales en lugar de cambios en las especificaciones, más adelante en el proceso de desarrollo o como resultado de las pruebas? ¿Cómo se equilibra entre evitar los riesgos de optimización prematura / YAGNI / ingeniería excesiva de diseñar una solución que mitigue los problemas posibles pero no necesariamente probables en lugar de desarrollar una solución más simple y fácil que sea tan efectiva? ¿Pero no incorpora la preparación para cada eventualidad posible?

Edit: la respuesta de Crazy Eddie incluye "lo absorbes y encuentras la forma menos costosa de implementar la nueva complejidad". Eso me hizo pensar en algo que estaba implícito en la pregunta, pero no lo mencioné específicamente.

Una vez que golpeas ese golpe, incorporas los cambios necesarios. ¿Hace lo que mantendrá el proyecto lo más cercano posible al cronograma posible pero puede afectar la capacidad de mantenimiento o regresa a su arquitectura y lo vuelve a trabajar a un nivel más detallado que puede ser más fácil de mantener pero hará retroceder todo durante el desarrollo?

    
pregunta glenatron 10.02.2011 - 15:51

8 respuestas

8

Lo que me viene a la mente al leer este es el ágil adagio: aborde primero las tareas más riesgosas y / o menos entendidas dentro del ciclo de vida del proyecto . Es decir. trate de armar un esqueleto de trabajo del proyecto lo antes posible, para demostrar que el concepto funciona. Esto, a su vez, también permite ejecutar cualquier tipo de pruebas crueles para detectar si la arquitectura cumple realmente su promesa en circunstancias de la vida real. Además, si hay alguna tecnología / plataforma / herramienta nueva y desconocida incluida en la solución, llévela temprano también.

Si la arquitectura central es correcta, las funcionalidades individuales se pueden agregar y probar de forma incremental, y se pueden volver a diseñar cuando sea necesario, con un costo relativamente menor. La necesidad de cambiar la arquitectura es el gran riesgo, con el que uno debe lidiar por adelantado. Esto da una respuesta rápida: en el peor de los casos, si todo el concepto se desmorona, lo sabemos temprano y podemos abortar el proyecto con una pérdida mínima.

    
respondido por el Péter Török 10.02.2011 - 16:09
6

Su ejemplo tocó algunos de los aspectos más desafiantes de la programación, a saber, computación distribuida y programación concurrente , que se utilizan cada vez más y hacen que los programadores trabajen cada vez más.

Incluso la programación "normal" (un solo hilo en una máquina) es tan compleja para cualquier programa no trivial, que requiere una gran habilidad y años de experiencia para ser bueno en eso, pero aún lejos de " resuelto ". Incluso en este nivel, las complejidades, en su mayoría debidas a explosión combinatoria , superan ampliamente la capacidad del cerebro humano para agarrar y entender Pensar lo contrario es una tontería.

La computación distribuida y la programación concurrente agregan dos dimensiones más al tamaño del espacio de "complejidad", que crece al menos en forma cúbica (sp?) (n ^ 3) en comparación con la programación "normal". Solo por ejemplo, piense en algunos nuevos conjuntos de problemas y falacias que tenemos que enfrentar. Incluso para jugar con una idea, se puede decir que es posible ridiculizar las interconexiones y los efectos secundarios a esta escala.

Claramente no tengo ninguna bala de plata, pero estoy bastante seguro de que el error más grande que se puede cometer es pensar que lo comprendes todo & resuelto.

Algunas ideas sobre cómo hacer frente a todo esto, además de lo que otras respuestas ya han cubierto:

  • Gran humildad
  • Acepte que su sistema / programa es imperfecto, impermanente e incompleto .
  • Prepárese para errores
  • Abrazar el cambio
  • Plan de redundancia
  • Piense en pruebas futuras
  • Mire (o estudie) biología o sociología cómo se comportan los sistemas complejos
  • Haga todo lo posible para evitar un estado mutable. Opte por protocolos sin estado (como REST y HTTP).
  • La programación funcional podría aliviar algo del dolor

Supongo que podría seguir y seguir. Tema muy interesante :)

    
respondido por el Maglob 10.02.2011 - 21:05
2

No estoy de acuerdo con el espíritu de la respuesta de @Péter Török porque asume que un equipo (o un individuo) necesariamente puede prever los elementos más riesgosos al principio del ciclo de vida del proyecto. Por ejemplo, en el caso del OP, el equipo no pudo prever la complejidad creciente asociada a la solución de múltiples subprocesos hasta que sus espaldas estuvieran contra la pared.

La pregunta del OP es buena y responde a un problema que tienen muchas tiendas de desarrollo de software.

Aquí es cómo me ocuparía del problema:

  1. Sigue los consejos de Fred Brooks y organiza a tus desarrolladores como un equipo de cirugía .
  2. Elija un cirujano maestro sabio y "benevolente" que pueda: A) Conseguir la confianza y el respeto de sus compañeros; y B) Tomar decisiones difíciles de manera oportuna.
  3. Espere que el cirujano principal reduzca la complejidad en la parte delantera y en la parte posterior del proceso de desarrollo.

Más sobre el punto # 3:

  1. El cirujano principal debe hacer un esfuerzo consciente para proponer la solución más sencilla que funcione. Años de experiencia significativa deberían poner al cirujano principal en condiciones de hacerlo.
  2. La organización más amplia, es decir, los superiores del cirujano maestro, debe dar al equipo el tiempo y los recursos suficientes para reducir la complejidad después de la fecha de envío. Esto permitirá que el equipo de desarrollo envíe el código de manera oportuna y realice kaizen para reducir la complejidad de forma continua.
respondido por el Jim G. 10.02.2011 - 17:04
1

Código a las interfaces

Al escribir una nueva funcionalidad que interactúe con otra funcionalidad, haga un límite en forma de una interfaz (la clase de Java) a través de la cual todos pasan. Esta voluntad

  1. asegúrese de tener control total sobre las funcionalidades que se utilizan
  2. le permite tener múltiples implementaciones de la misma funcionalidad.
  3. mantenga la complejidad general hacia abajo porque los módulos solo están ligeramente conectados en lugar de estar completamente entrelazados.
respondido por el user1249 10.02.2011 - 20:54
0
  

uno puede comenzar con una premisa y un modelo simples y, de repente, tiene una escalada de complejidad en el desarrollo del proyecto

No es sorprendente.

Esto es desarrollo de software. Si no está inventando algo nuevo, está descargando una solución probada y existente.

Hay poco terreno intermedio.

Si estás inventando algo nuevo, entonces debe haber al menos una característica que no entiendas completamente. (Para entenderlo completamente , tendría que tener una implementación que funcione, que solo usaría).

¿Cómo manejar esto?

  1. Ten expectativas realistas. Estás inventando algo nuevo. Debe haber partes que no entiendas.

  2. Ten expectativas realistas. Si parece funcionar correctamente la primera vez, has pasado por alto algo.

  3. Ten expectativas realistas. Si fuera simple, alguien más lo habría hecho primero, y simplemente podría descargar esa solución.

  4. Ten expectativas realistas. No se puede predecir el futuro muy bien.

respondido por el S.Lott 10.02.2011 - 16:44
0

Diseñar y codificar con la obsolescencia en mente. Supongamos que lo que usted codifique hoy deberá ser eliminado y reemplazado mañana.

    
respondido por el Ian 10.02.2011 - 17:34
0

El entorno debe ser parte de la especificación. Por lo tanto, un cambio en el entorno ES un cambio en la especificación. Si, por otro lado, basaste tu prototipo y diseño en un entorno diferente al que estaba en la especificación, cometiste un error estúpido. De cualquier manera, lo absorbes y encuentras la forma menos costosa de implementar la nueva complejidad.

    
respondido por el Crazy Eddie 10.02.2011 - 19:47
0

Como con la mayoría de los problemas de programación, depende , en mi opinión. Este problema es tan intrínseco al trabajo creativo, que no debes olvidar que van a ocurrir fallas, y eso es O.K. . La programación es un problema complejo, y por lo general no conoce la solución correcta hasta que ya lo haya resuelto.

Sin embargo, hay una gran cantidad de factores locales y específicos que pueden entrar en juego aquí, como:

  • Los objetivos de este sistema. ¿Es algo excepcional? ¿Tiene la intención de mantener este sistema funcionando a medio o largo plazo?

Para las cosas a corto plazo, puede que no valga la pena pensar en ello más que suficiente para ponerlo en funcionamiento. La refactorización es costosa y es algo que no crea un valor final inmediato para su usuario. Sin embargo , no hay ningún caso en el que pueda pensar que no sea el software descartable absoluto, donde es tan corto plazo que no vale la pena mejorar su diseño. Es mucho más importante poder entender lo que hiciste y solucionarlo rápidamente, que terminar ahora mismo. Si es para el largo plazo, es muy probable que rinda frutos eventualmente (y posiblemente mucho más pronto de lo que piensan todos los involucrados), o lo inverso (no hacerlo causará dolor muy pronto en lugar de "cuando tengamos que solucionarlo"). Casi me siento tentado a decir "siempre tómate el tiempo para hacerlo mejor", pero hay algunos casos en los que eso no es posible.

  • Los objetivos del equipo. ¿Es más bien un "hazlo ahora, cueste lo que cueste", o el tipo de cosa "hagámoslo bien"?

Esto debería influir enormemente en sus decisiones. Su equipo apoyará esta decisión, ya sea brindándole recursos para rediseñar, o exigirá la solución rápida que se realizará ahora. En mi opinión, si descubres que el equipo te está empujando en la dirección equivocada constantemente, es una gran señal de alerta. He visto que este tipo de cosas terminan en un escenario en el que se está produciendo una constante extinción de incendios, donde nunca hay tiempo para rediseñar porque siempre estás solucionando los problemas que crea el diseño incorrecto. Sin embargo, también puede haber un término medio: "duct-tape" ahora, arregle lo antes posible (pero en realidad, hágalo).

  • Su comprensión del problema. ¿Por qué no funcionó la solución anterior?

Realmente importante. Piense en cuál es el error o problema y por qué está sucediendo. Este tipo de situación es una gran oportunidad para encontrar suposiciones, restricciones e interacciones defectuosas (o faltantes). En general, siempre favorece entender mejor tu problema en lugar de resolver el problema actual. Esta es probablemente tu mayor defensa contra YAGNI / sobreingeniería. Si entiendes tu problema lo suficientemente bien, entonces lo resolverás él y no otros problemas.

Finalmente, intenta construir las cosas de la manera correcta . No estoy hablando de los errores y problemas que enfrenta cuando entiende más sobre el problema o su error humano inherente. No quiero decir "no cometas errores y hazlo perfecto la primera vez", eso es imposible. Quiero decir, trate de administrar bien la complejidad en su trabajo diario, arregle ventanas rotas, sea lo más simple posible, mejore su código y su pensamiento todo el tiempo. De esa manera, cuando (no si) cambia los golpes en su puerta, puede darle la bienvenida con los brazos abiertos en lugar de una escopeta.

    
respondido por el Juan Carlos Coto 06.03.2015 - 23:14

Lea otras preguntas en las etiquetas