¿Cómo puedo evitar sentir siempre que si reconstruyo completamente mi programa desde cero lo haría mucho mejor? [cerrado]

91

He aprendido una cantidad significativa de codificación, sin embargo, siempre ha sido en un entorno científico (no informático), completamente autodidacta sin que nadie me guíe en la dirección correcta. Por lo tanto, mi viaje de codificación ha sido ... desordenado. Ahora me doy cuenta de que cada vez que construyo algún tipo de programa, al final, me doy cuenta de cómo podría haberlo hecho de manera mucho más elegante, mucho más eficiente y de una manera que es mucho más flexible y fácil de administrar en el futuro. En algunas circunstancias, he regresado y reconstruido cosas desde cero, pero por lo general esto no es prácticamente factible. Si bien la mayoría de mis programas hasta ahora han sido relativamente pequeños, parece bastante difícil reescribir completamente programas grandes cada vez que creas algo.

Me pregunto, ¿es esta una experiencia normal? Si no, ¿cómo evita que esto suceda? He intentado planificar las cosas por adelantado, pero parece que no puedo prever todo realmente hasta que empiezo a elaborar un código.

Ashish
fuente
87
es normal, programa más
Ewan
77
Relevante .
Neil
43
Bienvenido a la programación. Si no mira el código antiguo y piensa "urgh", entonces debería comenzar a preocuparse, ya que significa que ha dejado de aprender.
Caltor
99
Honestamente, cuando vi esta pregunta, me reí, porque literalmente todos los programadores que he hablado también, incluido yo mismo, tienen este sentimiento, constantemente, en todo momento. Si quería entrar en un campo en el que sentía que el producto final que fabricaba no tenía fallas, la programación era el campo equivocado para elegir.
Zibbobz

Respuestas:

4

Este sentimiento es completamente normal y esperado. Significa que estás aprendiendo. Casi cada vez que comienzo un nuevo proyecto, comienzo en una dirección y al final lo diseño de manera diferente.

Es una práctica común desarrollar primero un prototipo antes de comenzar con lo real. También es común volver a visitar el código antiguo y refactorizarlo . Esto es más fácil si su diseño es modular : puede rediseñar fácilmente partes y piezas a la vez sin tener que destruir totalmente su diseño anterior.

Para algunas personas, ayuda escribir pseudocódigo primero. A otros les resulta útil comenzar escribiendo comentarios que describan lo que hará el código, y luego escribir el código una vez que la estructura general esté allí. Estas dos cosas lo ayudarán a planificar mejor su diseño y podrían evitar la necesidad de una reescritura.

Si forma parte de un equipo, tener un proceso de revisión es crucial para el proceso de diseño. Pídale a alguien que revise su código para que pueda aprender cómo mejorar su diseño.

asrjarratt
fuente
100

Esta es una experiencia muy común.

La mayoría de las personas con las que interactúo, y yo también, me siento así. Por lo que puedo decir, una razón para esto es que aprende más sobre el dominio y las herramientas que usa al escribir su código, lo que lo lleva a reconocer muchas oportunidades de mejora después de que ya haya escrito su programa.

La otra razón es que puede tener una idea en mente sobre la solución de código limpio ideal y luego el mundo real y sus limitaciones desordenadas se interponen en su camino, lo que le obliga a escribir soluciones y hacks imperfectos que pueden dejarlo insatisfecho.

"Todos tienen un plan hasta que los golpeen en la cara".

Qué hacer al respecto

Hasta cierto punto, tendrá que aprender a aceptar que su código nunca será perfecto. Una cosa que me ayudó con eso es la mentalidad de "Si odio el código que escribí hace un mes, significa que he aprendido y me convierto en un mejor programador".

Una forma de aliviar el problema es estar constantemente atento a posibles mejoras a medida que trabaja y refactorizar continuamente. Asegúrate de lograr un buen equilibrio entre refactorizar y agregar nuevas características / corregir errores. Esto no ayudará con grandes problemas de diseño, pero generalmente lo dejará con una base de código más pulida de la que puede estar orgulloso.

Andreas Kammerloher
fuente
18
Lo único que agregaría a esta respuesta es, aprender y seguir los principios de TDD al escribir código. Esas pruebas proporcionan un entorno seguro para refactorizar y reescribir a medida que continúa mejorando como desarrollador y desea realizar cambios en el código existente.
David Arno
10
@DavidArno, ¿cuál es el punto de refactorizar con las pruebas presentes? Es como actualizar un sistema y hacer una copia de seguridad antes ... 0 diversión.
Džuris
3
@ Džuris, :) Es cierto, si te gustan los desafíos, no escribas exámenes
David Arno
66
@ Džuris ¡Es como saltar de un avión usando un paracaídas!
JollyJoker
3
@jamesqf: esa es una caracterización errónea de lo que hacen TDD y las pruebas unitarias, por ejemplo, pueden decirle que su modelo o algoritmo está implementado correctamente y que no ha roto nada cuando refactoriza. No pueden decirle que su modelo es realmente útil. Eso es tan cierto en un entorno científico como lo es en cualquier otro.
Ant P
46

Aprenda la refactorización: el arte de mejorar gradualmente el código. Todos aprendemos todo el tiempo, por lo que es muy común darse cuenta de que el código que ha escrito usted mismo podría escribirse de una mejor manera.

Pero debería poder transformar el código existente para aplicar estas mejoras sin tener que comenzar desde cero.

JacquesB
fuente
44
Esta práctica también lo ayudará a aprender a escribir código que sea modular y que se pueda refactorizar más fácilmente. Todas las conferencias en el mundo no me enseñaron este hábito tanto como tener que dividir las grandes funciones antiguas en trozos manejables para que no tuviera que reescribir desde cero. Cada nuevo proyecto, lo hago mejor.
JKreft
El mejor punto de partida en mi opinión para aprender sobre la refactorización es: La refactorización se trata de nuevas características
Wildcard
9

Si tiene excelentes requisitos estáticos y los comprende bien y tiene tiempo para un análisis detallado, tiene la posibilidad de encontrar un buen diseño con el que todavía estará satisfecho cuando haya terminado.

Incluso en ese maravilloso caso, es posible que aprenda nuevas características del lenguaje que habrían ayudado a hacer un mejor diseño.

Sin embargo, por lo general, no será tan afortunado: los requisitos serán menos que estelares e incompletos y, aunque pensó que los entendía, resulta que hay áreas sobre las que hizo suposiciones inválidas.

Luego, los requisitos cambiarán a medida que los usuarios echen un vistazo a sus entregas iniciales. Entonces, algo que los usuarios no controlan cambiará, por ejemplo, la legislación fiscal.

Todo lo que puedes hacer es diseñar, asumiendo que las cosas cambiarán. Refactorice cuando pueda, pero tenga en cuenta que el tiempo y el presupuesto a menudo significarán que su entrega final no es tan elegante como lo hubiera sido si supiera al principio lo que sabe ahora.

Con el tiempo, mejorará al profundizar en los requisitos que recibe y conocerá qué partes de su diseño probablemente necesitarán flexibilidad para absorber el cambio.

Al final, sin embargo, acepte que el cambio es constante e ignore la punzada que dice "Podría haberlo hecho mejor". Siéntete orgulloso y feliz de haber brindado una solución.

Pico salvaje
fuente
O, en otras palabras: aprenda a diseñar para obtener flexibilidad desde el principio, sin introducir gastos innecesarios. Idealmente, la flexibilidad deriva de la simplicidad. Entonces su diseño tiene la oportunidad de pasar la prueba de los requisitos cambiantes.
cmaster
3

¿Cómo puedo evitar sentir siempre que si reconstruyo completamente mi programa desde cero lo haría mucho mejor?

Lo que podría hacer es crear un prototipo desechable, antes de comenzar a hacer el proyecto "real". Rápido y sucio. Luego, cuando obtienes un prototipo para probar un concepto, conoces el sistema y cómo hacer las cosas correctamente.

Pero no se sorprenda, si después de N años vuelve a este código y piensa "qué desastre".

BЈовић
fuente
3
O, si le muestras el prototipo a tu jefe, él dice 'Brillante, eso servirá'. te mueve a otro proyecto y tu prototipo se convierte en producción.
Ryanfae Escocia
2
Este consejo es tan común que hay un dicho al respecto. "Construye uno para tirar". Y ese consejo es tan mal utilizado que hay un dicho al respecto: "Si construyes uno para tirar, probablemente tirarás dos".
Eric Lippert
2
@EricLippert Mi experiencia ha sido terrible en la dirección opuesta: si creamos uno para tirar, inevitablemente se lo enviamos al cliente.
Jon
2
@ Jon: Sí, eso puede suceder, particularmente cuando la administración comete errores "parece que la interfaz de usuario funciona" y en realidad hay algún código allí. Dicho esto, mi experiencia siempre ha sido, ya que uno de mis compañeros de trabajo solía decir "tenemos suficiente tiempo para construirlo mal dos veces, pero no suficiente para hacerlo bien una vez". :-)
Eric Lippert
@EricLippert Esa es exactamente la razón para construir la GUI al final, y NO construir la GUI para un prototipo;)
B 29овић
3

Recuerda este mantra:

Lo perfecto es enemigo de lo bueno .

La solución perfecta no siempre es la solución ideal . La solución ideal es la que logra el estado "suficientemente bueno" con la menor cantidad de trabajo.

  • ¿Cumple con todos los requisitos de funcionalidad y rendimiento?
  • ¿Está libre de errores críticos que no puede solucionar en la arquitectura actual?
  • Calcule cuánto trabajo invertirá para mantener esta aplicación en el futuro. ¿El esfuerzo de reescritura sería más que el esfuerzo a largo plazo que ahorraría?
  • ¿Existe la posibilidad de que su nuevo diseño realmente empeore las cosas?

Si responde afirmativamente a todas estas preguntas, entonces su software es "suficientemente bueno" y no hay una buena razón para reescribirlo desde cero. Aplica las lecciones de diseño que has aprendido a tu próximo proyecto.

Es perfectamente normal que cada programador tenga un par de programas desordenados en el pasado. Sucedió varias veces durante mi carrera como desarrollador de software que miré un código, me pregunté "¿Qué idiota escribió este desastre?", Verifiqué el historial de versiones y me di cuenta de que era yo de hace varios años.

Philipp
fuente
3

He intentado planificar las cosas por adelantado, pero parece que no puedo prever todo realmente hasta que empiezo a elaborar un código.

Es tentador pensar que una planificación perfecta le dará un diseño / arquitectura de software perfecto, sin embargo, resulta que es categóricamente falso. Hay dos grandes problemas con esto. En primer lugar, "en papel" y "el código" rara vez coinciden, y la razón es porque es fácil decir cómo se debe hacer en lugar de hacerlo realmente . En segundo lugar, los cambios imprevistos en los requisitos se vuelven aparentes tarde en el proceso de desarrollo que no pudieron haber sido razonados desde el principio.

¿Has oído hablar del movimiento ágil? Es una forma de pensar donde valoramos "reaccionar al cambio" en lugar de "seguir un plan" (entre otras cosas). Aquí está el manifiesto (es una lectura rápida). También puede leer sobre Big Design Up Front (BDUF) y cuáles son las dificultades.

Desafortunadamente, la versión corporativa de "Agile" es un montón de falsos (maestros de scrum certificados, procesos pesados ​​en nombre de "Agile", forzar scrum, forzar una cobertura de código del 100%, etc.), y generalmente resulta en cambios de proceso estúpidos porque los gerentes Creo que Agile es un proceso y una bala de plata (de los cuales no lo es). Lea el manifiesto ágil, escuche a las personas que comenzaron este movimiento como el tío Bob y Martin Fowler, y no se deje engañar por la versión sin sentido de "ágil corporativo".

En particular, generalmente puede salirse con la suya haciendo TDD (Test Driven Development) en código científico , y hay una buena probabilidad de que su proyecto de software resulte bastante bueno. Esto se debe a que el código científico exitoso en su mayoría tiene interfaces ultra utilizables, con el rendimiento como una preocupación secundaria (y a veces competitiva), y por lo que puede salirse con la suya con un diseño más "codicioso". El tipo de TDD obliga a su software a ser ultra-utilizable , porque usted escribe cómo quiere que se llamen las cosas (idealmente) antes de implementarlas. También fuerza pequeñas funciones con pequeñas interfaces que pueden llamarse rápidamente de manera simple, "entrada" / "salida", y lo coloca en una buena posición para refactorizar en caso de que los requisitos cambien.

Creo que todos podemos estar de acuerdo en que numpyes un software informático científico exitoso. Sus interfaces son pequeñas, súper utilizables y todo funciona muy bien juntos. Tenga en cuenta que numpyla guía de referencia recomienda explícitamente TDD: https://docs.scipy.org/doc/numpy-1.15.1/reference/testing.html . He usado TDD en el pasado para el software de imágenes SAR (Synthetic Aperature Radar): y también puedo afirmar que funciona extremadamente bien para ese dominio en particular.

Advertencia: La parte de diseño de TDD funciona menos bien en sistemas donde una refactorización fundamental (como decidir que necesita que su software sea altamente concurrente) sería difícil, como en un sistema distribuido. Por ejemplo, si tuviera que diseñar algo como Facebook donde tiene millones de usuarios simultáneos, sería un error hacer TDD (para impulsar su diseño) (todavía está bien usarlo después de tener un diseño preliminar y simplemente hacer "probar primero el desarrollo "). Es importante pensar en los recursos y la estructura de su aplicación antes de saltar al código. TDD nunca lo llevará a un sistema distribuido de alta disponibilidad.

¿Cómo puedo evitar sentir siempre que si reconstruyo completamente mi programa desde cero lo haría mucho mejor?

Teniendo en cuenta lo anterior, debería ser algo evidente que un diseño perfecto es realmente imposible de lograr, por lo que perseguir un diseño perfecto es un juego tonto. Realmente solo puedes acercarte. Incluso si crees que puedes rediseñar desde cero, probablemente todavía hay requisitos ocultos que no se han mostrado. Además, las reescrituras tardan al menos el tiempo necesario para desarrollar el código original. Es casi seguro que no será más corto, ya que es probable que el nuevo diseño tenga sus propios problemas imprevistos, además de que tiene que volver a implementar todas las características del sistema anterior.

Otra cosa a tener en cuenta es que su diseño solo importa cuando cambian los requisitos .No importa cuán malo sea el diseño si nada cambia (suponiendo que sea completamente funcional para los casos de uso actuales). Trabajé en una línea de base que tenía una declaración de cambio de línea de 22,000 (la función era aún más larga). ¿Fue un diseño terrible? Diablos, sí, fue horrible. ¿Lo arreglamos? No. Funcionó tan bien como estaba, y esa parte del sistema nunca causó fallas o errores. Solo se tocó una vez en los dos años que estuve en el proyecto, y alguien, lo adivinaste, insertó otro caso en el interruptor. Pero no vale la pena tomarse el tiempo para arreglar algo que se toca con poca frecuencia, simplemente no lo es. Deje que el diseño imperfecto sea como es, y si no se rompe (o se rompe constantemente), no lo arregle. Entonces quizás podrías hacerlo mejor ... pero valdría la pena volver a escribir? ¿Qué ganarás?

HTH.

Matt Messersmith
fuente
2

Estoy totalmente de acuerdo con la respuesta proporcionada por Andreas Kammerloher, pero me sorprende que nadie haya sugerido aprender y aplicar algunas de las mejores prácticas de codificación. Por supuesto, esto no es una bala de plata, pero usar un enfoque abierto, patrones de diseño, comprender cuándo huele su código, etc., lo convertirá en un mejor programador. Investigue cuál es el mejor uso de bibliotecas, marcos, etc. Hay mucho más seguro, solo estoy rascando la superficie.

No significa que no verá su antiguo código como una basura total (en realidad verá los programas más antiguos incluso más basura que sin este conocimiento) pero con cada nuevo software que escriba verá tu mejoras Tenga en cuenta también que la cantidad de mejores prácticas de codificación aumenta con el tiempo, algunas simplemente cambian para que nunca llegue a la perfección. Acepta esto o todo el camino.

Otra cosa buena es tener una revisión de código. Cuando trabajas solo es fácil cortar esquinas. Si tiene una segunda persona revisando su código, podrá indicarle dónde no sigue esas mejores prácticas. De esta manera, producirá un mejor código y aprenderá algo.

Ister
fuente
1

Para agregar a las otras excelentes respuestas aquí, una cosa que encuentro útil es saber a dónde quieres llegar .

Es raro que se le dé el visto bueno para una gran refactorización por sí solo. Pero a menudo puede hacer pequeños refactorizaciones a medida que avanza, 'bajo el radar', mientras trabaja en cada área de la base de código. Y si tiene una meta en mente, puede aprovechar estas oportunidades para moverse, paso a paso, en la dirección correcta.

Puede llevar mucho tiempo, pero la mayoría de los pasos mejorarán el código, y el resultado final valdrá la pena.

Además, ¡sentir que podrías hacerlo mejor es una buena señal ! Demuestra que te importa la calidad de tu trabajo y que lo estás evaluando críticamente; entonces probablemente estés aprendiendo y mejorando. No dejes que estas cosas te preocupen, ¡pero no dejes de hacerlas!

gidds
fuente
1

Inadvertidamente te has topado con uno de los mayores desafíos (aventuras) de la humanidad, el puente entre el hombre y la máquina. El puente entre el hombre y la estructura física, la Ingeniería Civil, por ejemplo, ha estado en progreso durante unos 200 años o más.

Dado que el desarrollo de software realmente solo se convirtió en la corriente principal en los años 90, tiene aproximadamente 30 años. Hemos aprendido que no se trata tanto de una disciplina de ingeniería como de una ciencia social, y recién hemos comenzado.

Sí, probará TDD, Refactorización, Programación funcional, Patrón de repositorio, Abastecimiento de eventos, MV algo, Java Script (<- Haga esto, es una locura), Enlace de modelo, Sin SQL, Contenedores, Ágil, SQL (<- haga esto es poderoso)

No hay una solución. Incluso los expertos todavía están agarrando pajitas.

Bienvenido, y ten cuidado, es un lugar solitario; pero absolutamente fascinante

Mario
fuente
1

Voy a ir un poco contra la corriente. Esto es increíblemente común , pero no es aceptable . Lo que esto indica es que no estás reconociendo buenas formas de organizar tu código mientras lo escribes. La sensación proviene de que su código no es sencillo .

Su experiencia también fue mía durante mucho tiempo, pero recientemente (en los últimos dos años), he estado produciendo más código que no me hace sentir que necesito tirar todo. Esto es más o menos lo que hice:

  1. Sea claro sobre las suposiciones que está haciendo un bloque de código en particular. Lanzar errores si no se cumplen. Piense en esto de forma aislada , sin depender de los detalles sobre lo que está haciendo el resto del software. (Lo que está haciendo el resto del software influye en las suposiciones que aplica y en los casos de uso que admite, pero no influye si arroja un error cuando se viola una suposición).
  2. Deja de creer que seguir las reglas, patrones y prácticas producirá un buen código. Deseche las mentalidades y prácticas que no son obvias y directas. Este fue enorme. OO y TDD generalmente se enseñan de una manera que no se basa en consideraciones prácticas, como un conjunto de principios abstractos que debe seguir al escribir código. Pero esto es completamente inútil para desarrollar realmente un buen código. Si usa OO o TDD, debe usarse como solución a los problemas que entiende que tiene . En otras palabras, solo deben usarse cuando se observa un problema y se piensa: "Bien, esto tiene mucho sentido y es extremadamente obvio como una buena solución". No antes.
  3. Cuando estoy escribiendo código, concéntrate en dos preguntas:
    • ¿Estoy usando funciones y bibliotecas en la forma en que fueron diseñadas para ser utilizadas ? Esto incluye usarlo para los tipos de problemas que estaba destinado a resolver, o al menos muy similares.
    • Es simple ? ¿Mis compañeros de trabajo y yo podremos seguir la lógica fácilmente más adelante? ¿Hay cosas que no son inmediatamente obvias por el código?

Mi código ahora es más "procesal", con lo que quiero decir que está organizado por las acciones que toma en lugar de las estructuras de datos que usa. Utilizo objetos en lenguajes donde las funciones independientes no se pueden reemplazar sobre la marcha (C # y Java no pueden reemplazar las funciones sobre la marcha, Python sí). Tengo una tendencia a crear más funciones de utilidad ahora, que simplemente eliminan algunas molestas repeticiones para poder leer la lógica de mi código. (Por ejemplo, cuando necesitaba procesar todas las combinaciones de elementos en una lista, empujé el índice a un método de extensión que devuelveTuples para que la función original no esté abarrotada con esos detalles de implementación.) Ahora paso muchas cosas más como parámetros a funciones, en lugar de hacer que una función llegue a algún otro objeto para buscarla. (La persona que llama lo busca o lo crea en su lugar y lo pasa). Ahora dejo más comentarios que explican cosas que no son obvias solo al mirar el código , lo que facilita el seguimiento de la lógica de un método. Solo escribo pruebas en casos limitados en los que me preocupa la lógica de algo que acabo de hacer, y evito usar simulacros. (Hago más pruebas de entrada / salida en piezas lógicas aisladas). El resultado es un código que no es perfecto , pero que en realidad parece estar bien., incluso 2 o 3 años después. Es un código que responde bastante bien al cambio; Se pueden agregar, eliminar o cambiar cosas menores sin que todo el sistema se desmorone.

Hasta cierto punto, usted tiene que pasar por un periodo en el que las cosas son un desastre para que tenga un poco de experiencia para ir fuera de. Pero si las cosas todavía están tan desordenadas que quieres tirarlo todo y comenzar de nuevo, algo está mal; no estas aprendiendo

jpmc26
fuente
0

Al recordar que su tiempo es limitado. Y tu tiempo futuro también es limitado. Ya sea para el trabajo o la escuela o proyectos personales, cuando se trata de código de trabajo , debe preguntarse "¿reescribir este es el mejor uso de mi tiempo limitado y valioso?". O tal vez, "¿es este el uso más responsable de mi tiempo limitado"?

A veces la respuesta será inequívocamente . Usualmente no. A veces estará cerca y tendrás que usar tu discreción. A veces es un buen uso de tu tiempo simplemente por las cosas que aprenderás al hacerlo.

Tengo muchos proyectos, tanto laborales como personales, que se beneficiarían de un puerto / reescritura. También tengo otras cosas que hacer.

Jared Smith
fuente
0

Es una parte completamente normal del aprendizaje. Te das cuenta de los errores a medida que avanzas.

Así es como se mejora y no es algo que deba evitar.

mathreadler
fuente
0

Puede darse la experiencia de saber que el impulso seductor de reescribir generalmente no es productivo. Encuentre algún proyecto de código abierto antiguo, velludo e poco elegante de complejidad moderada. Intenta reescribirlo desde cero y mira cómo te va.

  • ¿Su diseño desde cero terminó tan elegante como esperaba?
  • ¿Es su solución realmente al mismo problema exacto? ¿Qué características omitiste? ¿Qué casos límite te perdiste?
  • ¿Qué lecciones duramente ganadas en el proyecto original borraste en la búsqueda de la elegancia?
  • Después de agregar esas piezas faltantes a su diseño, ¿está tan limpio como lo estaba sin ellas?

Eventualmente, su instinto cambiará de pensar "podría reescribir este sistema mucho mejor" a pensar "la crudeza de este sistema puede ser indicativo de cierta complejidad que no es evidente de inmediato".

Maxpm
fuente