De arriba hacia abajo es una excelente manera de describir cosas que sabes o de reconstruir cosas que ya has construido.
El mayor problema de arriba hacia abajo es que, con frecuencia, simplemente no hay "arriba". Cambiará de opinión sobre lo que debe hacer el sistema al desarrollarlo y al explorar el dominio. ¿Cómo puede ser su punto de partida algo que no sabe (es decir, qué quiere que haga el sistema)?
Un "local" de arriba hacia abajo es algo bueno ... pensar un poco antes de la codificación es claramente bueno. Pero pensar y planificar demasiado no lo es, porque lo que está imaginando no es el escenario real (a menos que ya haya estado allí antes, es decir, si no está construyendo, sino reconstruyendo). De arriba hacia abajo global cuando se construyen cosas nuevas no tiene sentido.
El enfoque de abajo hacia arriba debe ser (globalmente) a menos que conozca el 100% del problema, solo necesita codificar la solución conocida y no le importa buscar posibles soluciones alternativas.
El enfoque de Lisp es el destilado ascendente. No solo construye de abajo hacia arriba, sino que también puede dar forma a los ladrillos de la forma en que los necesita. Nada está arreglado, la libertad es total. Por supuesto, la libertad asume la responsabilidad y puedes hacer cosas horribles haciendo un mal uso de este poder.
Pero un código horrible se puede escribir en cualquier idioma. Incluso en idiomas que tienen forma de jaulas para la mente, diseñados con la esperanza de que con esos idiomas incluso los monos puedan poner en marcha buenos programas (una idea tan errónea en tantos niveles que duele incluso con solo pensarlo).
Su ejemplo es sobre un servidor web. Ahora, en 2012, este es un problema bien definido, tiene especificaciones a seguir. Un servidor web es solo un problema de implementación. Especialmente si su objetivo es escribir un servidor web sustancialmente idéntico a los otros miles de servidores web que existen, entonces nada está realmente claro, excepto algunas minucias. Incluso su comentario sobre RSA sigue hablando de un problema claramente definido, con especificaciones formales.
Con un problema bien definido, con especificaciones formales y soluciones ya conocidas, la codificación solo se conecta en los puntos. De arriba hacia abajo está bien para eso. Este es el cielo del gerente de proyecto.
Sin embargo, en muchos casos no existe un enfoque conocido y probado que se utilice para conectar los puntos. En realidad, muy a menudo es difícil decir incluso cuáles son los puntos.
Supongamos, por ejemplo, que se le pide que instruya a una máquina de corte automática para alinear las piezas que se cortarán con un material impreso que no se ajuste perfectamente al logotipo repetitivo teórico. Se le entregan las partes e imágenes del material tomadas por la máquina.
¿Qué es una regla de alineación? Tú decides. ¿Qué es un patrón, cómo representarlo? Tú decides. ¿Cómo alinear las partes? Tú decides. ¿Se pueden "doblar" las piezas? Depende, algunos no y otros sí, pero, por supuesto, no demasiado. ¿Qué hacer si el material está demasiado deformado para que una parte lo corte aceptablemente? Tú decides. ¿Todos los rollos de material son idénticos? Por supuesto que no, pero no puede molestar al usuario para adaptar las reglas de alineación para cada rollo ... eso sería poco práctico. ¿Qué fotos están viendo las cámaras? El material, lo que sea que eso signifique ... puede ser color, puede ser negro sobre negro donde solo el reflejo de luz hace evidente el patrón. ¿Qué significa reconocer un patrón? Tú decides.
Ahora intente diseñar la estructura general de una solución para este problema y haga una cotización, en dinero y tiempo. Mi apuesta es que incluso la arquitectura de su sistema ... (sí, la arquitectura) estará equivocada. La estimación del costo y el tiempo serán números aleatorios.
Lo implementamos y ahora es un sistema que funciona, pero cambiamos de opinión sobre la forma misma del sistema muchas veces. Agregamos subsistemas completos que ahora ni siquiera se puede acceder desde los menús. Cambiamos los roles maestro / esclavo en los protocolos más de una vez. Probablemente ahora tengamos suficiente conocimiento para intentar reconstruirlo mejor.
Otras compañías, por supuesto, resolvieron el mismo problema ... pero a menos que esté en una de estas compañías, probablemente su proyecto detallado de arriba hacia abajo será una broma. Podemos diseñarlo de arriba hacia abajo. No puedes porque nunca lo hiciste antes.
Probablemente también puedas resolver el mismo problema. Trabajando de abajo hacia arriba sin embargo. Comenzando con lo que sabes, aprendiendo lo que no sabes y sumando.
Se desarrollan nuevos sistemas de software complejos, no diseñados. De vez en cuando, alguien comienza a diseñar un nuevo y complejo sistema de software mal especificado desde cero (tenga en cuenta que con un gran proyecto de software complejo solo hay tres posibilidades: a] la especificación es difusa, b] la especificación es incorrecta y contradictoria o c] ambos ... y más a menudo [c] es el caso).
Estos son los proyectos típicos de grandes empresas con miles y miles de horas arrojados solo a diapositivas de PowerPoint y diagramas UML. Invariablemente fallan por completo después de quemar cantidades embarazosas de recursos ... o, en un caso muy excepcional, finalmente entregan una pieza de software demasiado cara que implementa solo una pequeña parte de las especificaciones iniciales. Y ese software invariablemente es profundamente odiado por los usuarios ... no el tipo de software que compraría, sino el tipo de software que usa porque se ve obligado a hacerlo.
¿Significa esto que creo que deberías pensar solo en el código? Por supuesto no. Pero en mi opinión, la construcción debería comenzar desde abajo (ladrillos, código de concreto) y debería subir ... y su enfoque y atención al detalle deberían, en cierto sentido, "desvanecerse" a medida que se aleja de lo que tiene. A menudo, se presenta de arriba hacia abajo como si tuviera que poner el mismo nivel de detalle en todo el sistema a la vez: solo manténgalo dividiendo cada nodo hasta que todo sea obvio ... en los módulos de realidad, el subsistema "crece" a partir de subrutinas. Si no tiene experiencia previa en el problema específico, su diseño descendente de un subsistema, módulo o biblioteca será horrible. Puede diseñar una buena biblioteca una vez que sepa qué funciones poner, no al revés.
Muchas de las ideas de Lisp se están volviendo más populares (funciones de primera clase, cierres, tipeo dinámico por defecto, recolección de basura, metaprogramación, desarrollo interactivo), pero Lisp sigue siendo hoy (entre los lenguajes que conozco) bastante único en lo fácil que es dar forma al código por lo que necesitas
Los parámetros de palabras clave, por ejemplo, ya están presentes, pero si no estuvieran presentes, podrían agregarse. Lo hice (incluida la verificación de palabras clave en tiempo de compilación) para un compilador de Lisp de juguete con el que estoy experimentando y no requiere mucho código.
En cambio, con C ++, lo máximo que puede obtener es un grupo de expertos en C ++ que le dicen que los parámetros de palabras clave no son tan útiles, o una implementación de plantilla increíblemente compleja, rota y con respaldo medio que de hecho no es tan útil. ¿Son las clases C ++ objetos de primera clase? No, y no hay nada que puedas hacer al respecto. ¿Puedes tener introspección en tiempo de ejecución o en tiempo de compilación? No, y no hay nada que puedas hacer al respecto.
Esta flexibilidad de lenguaje de Lisp es lo que lo hace ideal para la construcción de abajo hacia arriba. Puede construir no solo subrutinas, sino también la sintaxis y la semántica del lenguaje. Y en cierto sentido, Lisp es de abajo hacia arriba.