Soy un estudiante de secundaria que trabaja en un proyecto de C # con un amigo mío con aproximadamente el mismo nivel de habilidad que yo. Hasta ahora, hemos escrito aproximadamente 3,000 líneas de código y 250 líneas de código de prueba en un lapso de 100 confirmaciones. Debido a la escuela, pospuse el proyecto durante unos meses y recientemente pude retomarlo nuevamente.
Cuando lo recuperé, comprendí que el código que había escrito estaba mal diseñado, como la inclusión de subprocesos excesivos en el procesador, la prevención deficiente de las condiciones de carrera en la interacción entre la CPU, la GPU y el cartucho de juego emulados. , así como el código que es simplemente redundante y confuso.
El problema es que ni siquiera he terminado la funcionalidad principal de mi programa, por lo que no puedo refactorizar realmente, y me siento desanimado de seguir siendo perfectamente consciente de que el diseño de mi código es defectuoso. Al mismo tiempo, no quiero abandonar el proyecto; Se ha hecho un progreso sustancial y el trabajo no debe desperdiciarse.
Siento que tengo un par de opciones: simplemente terminar la funcionalidad trabajando alrededor del diseño deficiente y luego refactorizar una vez que todo está funcionando, detener todo y trabajar para desenredar todo antes de que el resto de la funcionalidad pueda terminar, comenzar el proyecto todo para que esté fresco en mi mente nuevamente, o abandone el proyecto debido a su tamaño excesivo (esencialmente "de vuelta al tablero de dibujo").
Basado en la experiencia de otros en tales proyectos, ¿cuál es el recurso para volver a estar en el camino correcto? De las respuestas en este sitio, el consenso general es que la reescritura generalmente es innecesaria, pero es una opción disponible si el código no puede mantenerse sin un costo excesivo. Realmente me gustaría continuar con este proyecto, pero tal como está, mi código no está diseñado lo suficientemente bien como para que pueda continuar, y una sensación de desánimo me impide continuar.
Respuestas:
Si estuviera en tu lugar, probablemente lo intentaría de esta manera:
Primero, termine el proyecto actual, al menos parcialmente, lo antes posible, pero en un estado de trabajo . Probablemente necesite reducir sus objetivos originales, piense en la funcionalidad mínima que realmente necesita ver en la "versión 1.0".
entonces, y solo entonces piense en una reescritura desde cero (llamemos a esto "versión 2.0"). Tal vez pueda reutilizar parte del código de V1.0. Tal vez, después de volver a dormir sobre la situación, tome la decisión de refactorizar la V1.0 y guardar la mayor parte. Pero no tome esta decisión antes de no tener una "prueba de concepto V1.0" a la mano.
Un programa de trabajo "1.0" es algo que puede mostrar a otros, incluso cuando el código es malo (que nadie más se molestará, excepto usted mismo). Si en medio de la creación de V2.0 se da cuenta de que se está quedando sin tiempo, todavía tiene V1.0 como un éxito parcial, lo que será mucho mejor para su moral. Sin embargo, si no termina la V1.0 primero, existe una gran posibilidad de que nunca complete la V2.0 porque cuando esté a la mitad, habrá un punto en el que no estará satisfecho con el diseño nuevamente, ¿y luego? ¿Abandonarás V2.0 nuevamente y trabajarás en V3.0? Existe un alto riesgo de toparse con este círculo interminable, nunca llegar a su fin.
Mejor aproveche esto como una oportunidad para aprender cómo lograr objetivos intermedios, en lugar de una oportunidad para aprender cómo dejar atrás proyectos en un estado inacabado.
fuente
Better take this as an opportunity to learn how to achieve intermediate goals, instead of an opportunity to learn how to leave projects in an unfinished state behind.
Los proyectos de TI terminados, incluso los defectuosos, son mucho mejores que los que no están terminados.
Los inconclusos también pueden enseñarle mucho, pero no tanto como los terminados.
Es posible que no lo vea ahora, pero obtiene una enorme cantidad de valor trabajando incluso con código defectuoso.
Mi voto es para terminar y luego, tal vez, refactorizar, si es necesario. Cuando comience a trabajar con más proyectos, verá que sorprendentemente a menudo la parte que "estaba destinada a ser refactorizada" permanece intacta durante años, mientras que otras piezas se extienden.
Desde el punto de vista del empleo, en la mayoría de los casos, obtendrá más felicitaciones por un proyecto terminado.
fuente
Felizmente comenzaría el proyecto nuevamente.
Eres un estudiante y todavía estás aprendiendo. Esto lo coloca en una posición muy diferente a la pregunta a la que se vinculó.
No tiene responsabilidad profesional por su código; Si eliminara todo el proyecto en este momento y se fuera, no sufriría ninguna repercusión. Esta es una gran ventaja para un desarrollador. En la pregunta que vinculó, esos desarrolladores están tratando de mantener un software por el que las personas pagan dinero, e incluso pequeños errores pueden causar grandes problemas con los clientes, lo que hace que sea peligroso escribir desde cero. No tienes ese problema.
Como proyecto personal, esta es la oportunidad perfecta para probar cosas nuevas y aprender de sus errores. Es genial que reconozca que su antiguo código tiene problemas, porque eso significa que ha aprendido cómo hacerlo mejor. La experiencia a través de prueba y error puede ser invaluable para los programadores principiantes.
Su proyecto es relativamente pequeño, y básicamente no tiene pruebas. Podría ser tan corto algunas noches escribir 3000 líneas desde cero, especialmente porque ya tiene ideas sobre qué hacer mejor la próxima vez.
Trabajar en una base de código rota será una pérdida de moral mucho mayor de lo que lo haría una reescritura.
Además, esta puede ser una gran oportunidad para intentar escribir un programa más modular con pruebas unitarias. Hacerlo hace que sea mucho más fácil entender el código si vuelve a él después de un largo descanso, y ayuda a evitar errores que podría introducir accidentalmente debido al olvido.
Finalmente, aquí hay una opinión sobre la sabiduría de a veces dar pasos hacia atrás para dar pasos más grandes hacia adelante.
fuente
Probablemente todavía estés en la parte de "desarrollo rápido" de tu desarrollo. Hay una buena posibilidad de que dentro de unos meses descubras que tu nuevo e impresionante diseño está horriblemente roto de formas que ni siquiera sabías cuando comenzaste.
Haga las cosas : esta es la cosa más importante que necesita aprender. Créame, conozco a muchas personas (no solo programadores) que están atrapados en el ciclo "seguir comenzando desde cero desde que aprendí mucho antes de comenzar este proyecto". El problema es que nunca termina , hasta que dejas de aprender cosas nuevas, lo cual no es un buen lugar para estar :)
También es importante para poder terminar realmente cualquier cosa. Comenzar de nuevo es emocionante, genial, divertido ... pero si solo aprendes eso, nunca podrás terminar nada. Nuevamente, esa no es una habilidad muy útil, y en realidad no se siente tan bien como hacer algo útil (o divertido). La vida es corta, el tiempo es limitado y no puedes seguir practicando sin resultados tangibles: te volverás loco de eso. Si no puede comenzar a trabajar porque simplemente no puede decidir qué enfoque tomar, ya está en la zona de peligro.
Siempre habrá impulsos para comenzar de nuevo. Incluso en un entorno de aprendizaje, es muy probable que sea una mala idea. Eso no significa que necesite llevar cada prototipo a una aplicación lista para producción, ni mucho menos. Pero necesita al menos llegar a una fase de prototipo funcional: lo más probable es que ayude a su moral, y es un rasgo muy útil para un desarrollador de cualquier tipo. Haz las cosas . Y la parte divertida es que rápidamente verás que hay un millón de cosas más divertidas o útiles que puedes hacer con tu prototipo en lugar de "reescribirlo desde cero", y en muchos casos, incluso refactorizarlo. Todo lo que haces tiene un costo: al menos, podrías haber estado haciendo otra cosa mientras tanto.
fuente
Sigo la ideología "Haz que funcione, hazlo bien, hazlo rápido" en el desarrollo de software.
En este momento, no ha terminado el paso 1. Haga que funcione primero, y luego puede preocuparse por lo feo que es su código. En realidad, crear un producto que funcione es una de las cosas más difíciles para los nuevos desarrolladores, ya que se ven envueltos en tratar de perfeccionar su código la primera vez, por lo que se quedan atrapados en Optimization Hell y nunca llegan a terminar. implementando todas las características. Tienes que aprender a dejar de lado todas esas preocupaciones sobre la refactorización y la optimización para que puedas concentrarte en hacer que el software funcione. Una vez que obtenga más experiencia, naturalmente hará más cosas bien la primera vez, por lo que se necesita menos refactorización.
Tenga en cuenta: la optimización prematura es la raíz de todo mal (vea esta excelente pregunta de Programmers.SE para una buena discusión). Si pasa demasiado tiempo pensando en cómo mejorar su código, se atasca en la parálisis del análisis . Esto mata el proyecto. Es mejor terminar el proyecto antes de comenzar a intentar optimizarlo.
Para citar a un gran orador motivador: solo hazlo .
Como siempre, hay un xkcd relevante:
fuente
Reescribirlo. El código que no funciona tiene poco valor, y tres mil líneas no es mucho código. No tomará casi tanto tiempo como para escribir el código que tiene actualmente, y será mucho mejor. A menudo he tirado quinientas o mil líneas de código pobre, y a menudo la reescritura es un quinto de largo.
La mayoría de las nociones en torno a "no reescribir" se refieren a sistemas grandes que hacen cosas importantes y experimentan cambios constantes para cumplir con los requisitos cambiantes. Las reescrituras de sistemas complejos en uso rara vez tienen éxito.
Tu situación es todo lo contrario. Tiene una pequeña aplicación sin usuarios y los únicos requisitos son los que elige implementar. Así que adelante y reescríbalo.
fuente
Reiniciar desde cero suele ser un mal movimiento en proyectos de la vida real, principalmente porque los proyectos de la vida real acumulan correcciones de errores de los que un nuevo desarrollador no está al tanto (por ejemplo, vea Cosas que nunca debe hacer , de Joel en el blog de Software ).
Sin embargo, los proyectos escolares no heredan esa historia y generalmente comienzan codificando y diseñando al mismo tiempo con un conocimiento parcial de la informática y la falta de experiencia. Consideraría su primera versión como un prototipo, utilizado como una prueba de concepto que ha fallado, y felizmente lo tiraría a la basura (vea ¿Cuáles son las diferencias entre los prototipos desechables y los evolutivos? Para una discusión sobre los prototipos desechables versus los evolutivos).
El diseño correcto ha madurado en su cabeza y no debería tomar mucho tiempo para escribirlo en el código.
fuente
Respetuosamente estoy en desacuerdo con las sugerencias de que reescribir es una mala idea.
En el ámbito del ciclo de vida del software, generalmente se acepta que el tiempo y el esfuerzo necesarios para corregir un error aumenta en un orden de magnitud cada capa en el ciclo de vida. Es decir, si lleva 1 hora corregir un error en el nivel de requisitos, llevará 10 horas en diseño, 100 horas en pruebas de codificación y 1000 horas como corrección de errores. Esos números pueden sonar escandalosos, pero la industria los acepta como aproximadamente correctos. Obviamente, menos en un proyecto más pequeño, pero la idea general sigue siendo. Si su proyecto tiene un defecto de diseño básico, entonces es más apropiado llamar a eso una experiencia de aprendizaje y regresar, revisar sus requisitos iniciales y rediseñar.
También recomendaría considerar un modelo de Desarrollo Dirigido por Prueba usando pruebas unitarias estructuradas. Son un dolor y al principio parecen una pérdida de tiempo, pero su capacidad para descubrir errores, especialmente cuando se integra con el código de otra persona, no puede exagerarse.
fuente
Me perdiste en esta oración:
Creo en el principio (establecido en Systemantics ) que
Entonces, escribir un sistema complejo incluye
... es decir, los siguientes pasos:
Tenga en cuenta que el paso 3 podría involucrar:
Además, el Paso 2 "Pruébelo para asegurarse de que funciona" podría implicar una reescritura si no es así.
Si estuviera construyendo sobre una base de código podrida, no me gustaría agregar más funcionalidades. Por lo tanto, me inclinaría a programar algo como "simplificar la implementación de subprocesos existente" como el próximo trabajo a implementar. Suponiendo que ha estado probando a medida que avanza, debería poder tratar esto como un ejercicio de refactorización. Los criterios de éxito / salida para esta fase de trabajo serían:
Por cierto, "probarlo para asegurarse de que funciona" no necesariamente significa "pruebas unitarias": cuando la estructura del equipo es simple, puede probar un sistema (simple) usando pruebas de sistema (simples) (en lugar de pruebas unitarias) .
fuente
Uno de los problemas que enfrenta cuando se encuentra con un problema como este es que está emocionalmente apegado al código que ha escrito hasta ahora de una forma u otra.
Un colega me dijo que estaba escribiendo un programa mientras estaba en la universidad mientras recibía lecciones de un famoso profesor (creo que era Dijkstra). Le pidió al profesor que mirara el código en el que había estado trabajando durante más de un mes. El profesor le preguntó si había hecho una copia de seguridad, él respondió que no. Luego, el profesor eliminó todo su código y le dijo que lo volviera a escribir.
Estaba enojado, pero 3 días después terminó el programa, con un código más limpio y menos errores y menos líneas de código.
Trate de hacer una estimación honesta sobre qué opción es mejor en el tiempo disponible para el proyecto.
Las 3 opciones son
He sido programador profesional durante más de 10 años, y en mi línea de trabajo he llegado a la conclusión de que la última opción es la mayoría de las veces la elegida, pero no siempre es la mejor opción.
fuente
Parece que tus habilidades han crecido sustancialmente en ese período de tiempo. Quizás trabajar en ese proyecto contribuyó a ello. Diseñarlo nuevamente como una experiencia de aprendizaje intencional sería fructífero.
Recuerde, esto no es algo que deba entregar como un programa de trabajo para un cliente. Fue escrito específicamente para la práctica. Por lo tanto, a menos que desee practicar problemas de envío y una entrega defectuosa, creo que actualmente se encuentra en una fase de desarrollo en la que trabajar sus "músculos de diseño" sería fructífero.
Al hacerlo, concéntrese en el proceso de diseño y la planificación, y reflexione sobre sus cosas existentes y reflexione sobre lo que está entendiendo mejor.
fuente
Refactorizador Refactorizador Refactor! REFACTOR !!!!
Honestamente, no importa cuán experimentado sea, este es un problema común. Escribiste código, aprendiste algo y quieres usar el nuevo conocimiento en el código anterior. Desea medir el código antiguo con el nuevo conocimiento.
Eso simplemente no funcionará. Si haces eso, tu aplicación / juego nunca se completará. En su lugar, trate de asignar su tiempo en el proyecto para que algunas de sus "tareas" sean refactorizar el código incorrecto. Digamos, por ejemplo, que tuviste un método horrible para salvar el juego. Sigue trabajando en el juego en sí, pero encuentra algo de tiempo para refactorizar (reemplazar) ese horrible método. Intente mantener los refactores pequeños, y no debería ser un problema.
Cuando llegas a una parte importante de la aplicación que necesita un refactor, lo estás haciendo mal, en serio. Rompe esa refactorización en partes más pequeñas. Intenta pasar siete horas escribiendo código y una hora refactorizando.
Cuando haya terminado con el proyecto y presione la función de congelación, puede pasar un tiempo masivo refactorizando. Por ahora, termina el juego, pero aún intenta refactorizar algunos. Eso es lo mejor que puedes hacer.
Siempre habrá algo para refactorizar.
fuente
Yo diría que depende un poco de qué tipo de código tiene ahora y dónde se encuentran exactamente los problemas. Es decir, si sus fundamentos son buenos (diseño de clase adecuado en la mayoría de las partes, buen desacoplamiento / cohesión, etc., solo algunas malas elecciones como los hilos que mencionó), entonces, por supuesto, obtenga un 1.0 básico y luego refactorice como No hay mañana.
Por otro lado, si en realidad es solo un montón de archivos de texto feos y abrumados que de alguna manera pasan el compilador, sin estructura perceptible, etc. (en otras palabras, un prototipo de prueba de concepto de aprendizaje en el trabajo), entonces prefiero eliminarlo y comenzar de nuevo.
En su próxima versión, realice un enfoque ágil: establezca una línea de tiempo repetitiva fija, como 2 semanas o lo que se ajuste a su horario. Al comienzo de cada fragmento (llamémoslo un sprint), establezca metas que se puedan lograr en las 2 semanas. Anímate y hazlos, haz todo lo posible para que funcione. Establezca sus objetivos para que después de cada 2 semanas tenga algo que se pueda mostrar a un amigo, no solo un trabajo interno abstracto. Google "scrum" y "objetivo inteligente". Todo esto es muy fácil de hacer, si estás solo, solo un trozo de papel con algunos puntos de viñeta rápidamente anotados.
Si puedes hacer eso, entonces comenzar de nuevo es bueno. Si sabes en el fondo que después de comenzar de nuevo, es probable que termines donde estás ahora, de todos modos, entonces sigue con tu código y haz que funcione.
fuente
Tienes que ponerte en el lugar del empleador.
Para la mayoría de los reclutadores, sería lo más valioso si sigue este camino: - Termine con el 100% de las pruebas en el nuevo código que escriba. - Agregue pruebas para el código antiguo (mal diseñado). - Refactorízalo para lograr lo que querías como diseño.
Haga todo eso con un buen proceso de versiones, ramas y etiquetas.
Reescribir es a menudo una idea sexy, pero a menudo es una idea que tienen los recién llegados, lo cual es un poco peligroso en la vida real. Demostrar que estás más dispuesto a mejorar la calidad del trabajo que ya hiciste en lugar de comenzar desde cero es una buena señal de que eres una persona seria.
Sin embargo, obviamente puedes reescribirlo, pero conviértelo en otro proyecto.
fuente
Solo para agregar algo de mi experiencia pasada a la mezcla. Llevo más de un año trabajando en un proyecto paralelo, siempre que tengo unos minutos libres. Este proyecto pasó de un simple banco de pruebas a una clase estática a un diseño de línea delgada orientado a objetos que es ahora.
A lo largo de todos estos cambios, he mantenido la misma funcionalidad del código, excluyendo las correcciones de errores y los beneficios de rendimiento (debe ser lo más rápido posible). La misma base de código aunque refactorizada se ha mantenido igual y, como tal, la he mejorado enormemente sin tener que volver a escribir el código desde cero y perder el tiempo.
Esto ha significado que he podido mejorar el código a un ritmo más rápido que antes. También significaba que, a medida que avanzaba, era más fácil saber qué era necesario eliminar, es decir, clases innecesarias, y qué podría ser más fácil que reescribir con la vieja idea aún en mi mente.
Por lo tanto, mi consejo sería refactorizar su código y continuar a partir de ahí haciendo mejoras según sea necesario. Aunque recuerde que si decide reescribir desde cero, debe tomar las buenas ideas del antiguo proyecto y mirarlas detenidamente para ver dónde están defectuosas. Es decir, no solo copie el código antiguo al nuevo proyecto.
fuente
La respuesta depende de algo que me gusta llamar el "techo de complejidad". A medida que agrega más y más a una base de código, hay una tendencia a que se vuelva más y más compleja y cada vez menos organizada. En algún momento, alcanzará un "límite de complejidad", en cuyo punto el progreso será muy difícil. En lugar de tratar de seguir moviéndose por la fuerza bruta, es mejor retroceder, reorganizar / reescribir y luego seguir avanzando.
Entonces, ¿tu código base es tan malo que te estás acercando a un límite de complejidad? Si siente que es así, tómese un tiempo para limpiar y simplificar antes de continuar. Si la forma más fácil de limpiar es reescribir algunas partes, está bien.
fuente
¿Ninguno? ¿Ambos?
Continúe en adelante, dedique algún tiempo a revisar el diseño existente y a agregar nueva funcionalidad.
Si tiene interacciones rápidas, ese podría ser un buen lugar para comenzar ("hilos excesivos en el procesador" suena como una ineficiencia, en lugar de algo que podría causar problemas de corrección). Vea si puede encontrar una forma general de escapar de las razas (y posiblemente puntos muertos), o al menos múltiples formas específicas de hacerlo.
No sé en qué medida hay disponibles detectores de punto muerto y carrera para C #, pero si existen, pueden ser útiles para identificar qué problemas hay y verificar que sus soluciones funcionan.
Creo que, en general, estoy más motivado para solucionar problemas con el código que hace algo útil, en lugar de tirarlo a la basura y comenzar, de nuevo, desde cero. Hay casos en los que el desarrollo de campo quemado (en analogía a greenfield y brownfield ...) es más satisfactorio, pero eso es generalmente para cosas en las que el enfoque existente está tan alejado de donde debería estar que ya ni siquiera está mal.
fuente
Si su código es modular, entonces debería poder terminar el resto del código alrededor de los componentes mal escritos y luego volver a escribir los componentes mal escritos sin afectar el resto del código.
En ese caso, depende de usted cuando reescribe los componentes mal escritos. Si los componentes mal escritos están tan mal escritos que el código terminado no funcionará con ellos tal como están, entonces deberá volver a escribirlos antes de poder terminar el resto del código.
fuente
La primera pregunta que debe hacerse es "¿qué tan grave es la falla?"
¿Qué hiciste exactamente mal?
Si algo es tan malo que desperdiciará toneladas de horas tratando de trabajar con el problema, expone datos confidenciales (contraseñas / tarjetas de crédito) o causa una mala vulnerabilidad, entonces tal vez debería editarlo, pero la mayor parte del tiempo puede toma lo que tienes, termínalo y soluciona el problema más tarde.
Los programadores adoran mejorar sus aplicaciones, queriendo que sean "lo mejor posible", pero ese no es el enfoque correcto.
SI libera su aplicación lo antes posible, incluso si no es 100%, errores y todo, entonces recibe retroalimentación de otros, mientras tiene tiempo para corregir los errores y otras cosas para la versión 1.1. Otras personas podrán ayudarlo a mejorar la aplicación, y es posible que haya perdido el tiempo haciendo algo que a la gente no le haya gustado.
Entonces, en su caso, publíquelo, obtenga algunos comentarios, y luego puede estructurar la versión 2.0 con todos los cambios y corregir la falla que tiene.
Otra cosa para recordar es que estamos mejorando constantemente. Hay un dicho que dice que si puede ver su código de hace un año y ver que es malo, eso significa que aún está mejorando, y eso es una gran cosa.
fuente
Depende de cuán desordenado esté tu código.
Si cometió errores reales de n00b que hacen que su código sea demasiado complejo o detallado, entonces recomendaría reescribir esas partes.
Si cree que tiene errores serios que tendrá que corregir de todos modos, escriba algunas pruebas unitarias que puedan verificar si ha solucionado el error (... ya que aún no puede iniciar el programa). Es mejor corregir los errores temprano, y definitivamente es mejor corregir los errores mientras aún recuerdas lo que hace el código.
Si no le gusta cómo se llaman los métodos, o a qué clase pertenecen, o pequeñas cosas como esa, simplemente use el IDE. (Recuerde, esto es C #, no algunos javascript, python, perl, php, etc.) Cuando está trabajando en un código que usa el componente afectado, y tiene una idea clara de lo que debería estar haciendo ese componente, luego refactorícelo si su IDE lo hace indoloro.
De lo contrario, haz que funcione y perfecciona tus habilidades en el próximo proyecto.
fuente
Como otros han sugerido, como este es un proyecto personal, no (todavía) un proyecto profesional, consideraría seriamente una reescritura.
Sin embargo, puede aprovechar el método científico aquí, realizando un experimento. Primero, concebir una hipótesis. El mío sería, "probablemente sea hora de una reescritura". Para ahorrar tiempo, reducir el costo de la falla y limitar un poco el sesgo a priori, antes de continuar con la programación, decida un período de tiempo ("cuadro de tiempo"). Sugeriría quizás 4 horas de reloj de pared. También decida una metodología para evaluar la hipótesis. Como las apuestas son bajas, sugeriría como metodología, simplemente pregúntese: "¿Me alegro de haber hecho esto?" Ahora comienza el experimento. Después de su período de tiempo elegido, ¿cuál es la evaluación de la hipótesis? Por ejemplo, desde mi ejemplo, ¿está contento de haber comenzado a reescribir ahora que ha pasado 4 horas haciéndolo? Entonces es probablemente la elección correcta.
Puedes pedir todos los consejos del mundo, pero no hay nada como probar una hipótesis empíricamente.
Algunas razones para considerar seleccionar una reescritura como su experimento:
Terminar algo es una buena idea, pero no en el vacío. Si comienza una reescritura, puede optar por terminar algo terminando un submódulo en particular. Puede establecer eso como primer objetivo, después del experimento anterior. Terminar no tiene que significar terminar su proyecto principal inicial todavía. Después de terminar un módulo, termine otro, etc., hasta que termine de reescribir todo el alcance de su proyecto original, si lo desea.
fuente