¿Cómo supero la parálisis mediante análisis al codificar?

37

Cuando comienzo un nuevo proyecto, muchas veces inmediatamente empiezo a pensar en los detalles de la implementación. "¿Dónde voy a poner el DataBaseHandler? ¿Cómo debería usarlo? ¿Deberían las clases que quieran usarlo extenderse de alguna superclase abstracta? ¿Debería usar una interfaz? ¿Qué nivel de abstracción voy a usar en mi clase que contiene métodos para enviar solicitudes y analizar datos? "

Termino estancado durante mucho tiempo porque quiero codificar la extensibilidad y la reutilización. Pero siento que es casi imposible dejar de pensar en cómo implementarlo perfectamente.

Y luego, si trato de decir "¡atorníllelo, hágalo!", Golpeo una pared de ladrillos muy rápido porque mi código no está organizado, mezclo niveles de abstracciones, etc.

¿Cuáles son algunas técnicas / métodos que tiene para iniciar un nuevo proyecto y al mismo tiempo configurar una estructura lógica / modular que se adapte bien?

- - EDITAR - -

Bueno, este es el tipo de pregunta a la que es difícil aceptar una respuesta, pero quería obtener más comentarios, ver si hay algún consenso. TDD suena realmente genial y, francamente, he tenido la intención de ponerme al día con el uso de JUnit, etc. Al mismo tiempo, ¿qué piensan los fanáticos de TDD sobre el hecho de que un punto legítimo en relación con TDD para resolver mi problemas particulares, es que TDD realmente no parece abordar la cuestión del diseño. Claro, estoy de acuerdo en que TDD me ayudará a definir lo que quiero hacer y luego gradualmente puedo trabajar sobre cómo, pero hay muchos patrones / estructuras de diseño generales diferentes que podrían pasar por las pruebas unitarias. Eso es todo: prueba UNIDADES individuales. Supongo que estoy un poco confundido ... No sé. Talvez yo'

¡Gracias!

LuxuryMode
fuente
2
Dé un paso atrás, tome un bolígrafo y papel, dibuje la imagen más grande. esto le ayudará a continuación, el diseño de la puesta en práctica de una manera más estructurada en lugar de perder su auto en los detalles ...
Darknight
Esta es una gran pregunta. Esta es una trampa en la que también he sido culpable.
Corv1nus
1
Posible duplicado de ¿Cómo trato la parálisis de análisis?
mosquito

Respuestas:

16

Recomiendo usar Test-Driven-Development , lleva un tiempo acostumbrarse especialmente cuando se trabaja con un buen IDE como eclipse, pero las ventajas son excelentes.

Básicamente, lo que debe hacer es escribir las pruebas en su código antes de escribir el código en sí. Por lo tanto, se ve obligado a mirar su código desde el punto de vista de cómo se usará, lo que significa que sus interfaces evolucionan a medida que se implementan más escenarios.

Otra característica es que se implementa en trozos muy pequeños (se hacen más grandes cuanto más experiencia tenga en la técnica y en la programación), por lo que le obliga a centrarse en un problema muy pequeño y bien definido cada vez.

Y también desde que primero escribe una prueba y solo luego la implementa, tiene una prueba fallida frente a usted. Entonces, si usted es como la mayoría de los programadores, no se dejará llevar por un análisis loco porque pensará: "Necesito que esta prueba funcione".

Un breve ejemplo de Java:
Digamos que quiero desarrollar un programa que lea y escriba un mensaje desde un DB.

Así que empiezo con la primera acción bien definida, necesito un DB:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
}

ok, entonces veo que necesito implementar la clase DbConnector.getDB para que devuelva la base de datos, hasta que esta prueba falle. Voy y hago eso ...

No agrego lo siguiente que quiero hacer, cargar el mensaje desde la base de datos:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
  String message = db.fetchMessage(key);
  assertEquals("hello world", message);
}

Ahora he agregado otra pequeña característica a la base de datos que es buscar un mensaje, voy e implemento eso, una vez terminado, continúo con una función a la vez hasta llegar a algo como esto:

@Test
public void testDB() {
  DB db = DbConnector.getDB(address);
  assertNotNull(db);
  String message = db.fetchMessage(key);
  assertEquals("hello world", message);
  message = "foo bar";
  db.storeMessage(message);
  message = db.fetchMessage();
  assertEquals("foo bar", message);
}

Puede parecer un ejemplo muy simple, pero esto también funciona para tareas más complejas. Sé que al principio lleva mucho tiempo, pero a medida que te acostumbras, ves que, de hecho, es mucho más eficiente. Para uno, evita la parálisis por análisis y para otro, obtiene un código mucho más robusto que generalmente tiene menos errores y pasa por menos iteraciones.

Asaf
fuente
44
Y TDD lo obliga a refactorizar mucho, por lo que está entrando en un modo de trabajo de refactorización continua que ayudará a romper el muro de ladrillos de código desordenado, como mencionó programmers.stackexchange.com/questions/86364/… .
encogerse
De hecho, encuentro que el primer aspecto de prueba de TDD es un obstáculo en este tipo de circunstancias. Si tengo suficientes problemas para diseñar la interfaz en sí, ¿cómo va a ser más fácil o más obvio diseñar las pruebas? Eso y la carga del refactor en el comienzo de intentar diseñar algo es demasiado alta. Me pregunto cómo otros lidian con eso.
Steven Evers
1
@SnOrfus, cierto. TDD funciona bien cuando tienes tus módulos y quieres concentrarte en qué versus cómo. Pero esos módulos pueden organizarse de muchas maneras. Cómo se agrupan, qué tipo de estructura usará realmente no se aclara a través de TDD.
LuxuryMode
55
Hmmmm esto suena como un fanático de TDD ..... ¿Qué pasó con el uso de lápiz y papel para dibujar una arquitectura? o estoy chapado a la antigua y no lo suficiente "a la moda" ....
Darknight
1
La pluma y el papel (o pizarra) son buenos. Dibuje el plan general, el panorama general. Si no cabe en una hoja de papel, es demasiado complicado. Una vez que tenga el plan general, puede ocuparse con BDD, burlarse, etc.
Donal Fellows
10

Esto me sucede a mí, así que me he acostumbrado a aceptar (y adoptar) una mentalidad de refactorización continua. Hago lo más simple que podría funcionar, luego lo limpio, lo organizo, lo desacopla, lo pruebo y sigo adelante.

Eso no quiere decir que no haya mucha planificación, pero sucede muy rápido y con mayor frecuencia como garabatos en la chatarra o en mi cabeza. En general, a veces llamo a este pequeño proceso micro iteraciones porque tardan de 5 a 20 minutos cada una y, por experiencia, se necesitan 2-3 para terminar lo que estoy trabajando (dependiendo de lo que estoy haciendo, obviamente).

Como nota al margen: he enseñado a varias personas en diferentes formas de escritura (informes, ensayos y redacción técnica en general) y esta es la misma forma en que hago que escriban cosas para superar el bloqueo del escritor. "Solo deja salir cualquier cosa sobre tu tema que se te ocurra en la página. Luego tendremos sentido y lo separaremos en párrafos y verificaremos el flujo. Si es necesario, incluso lo reescribiremos".

Steven Evers
fuente
1
+1 por mencionar la escritura. Recientemente adopté el enfoque de refactorización frecuente de la codificación y lo apliqué a la escritura; funciona muy bien para mi
Zsolt Török
2

Algunas cosas que podrían funcionar:

  • Identifique el problema central que está tratando de resolver: ¿cuál es el corazón de lo que quiere hacer? Implemente solo eso y el mínimo código de soporte necesario para que se ejecute. Una vez que funcione a su satisfacción, desarrolle iterativamente, refactorizando sin piedad en cada paso.
  • Vea si otros paradigmas de programación funcionan para usted. A pesar de todos sus méritos, la programación orientada a objetos no es la respuesta a todos los problemas, y no todos los cerebros de los programadores funcionan de esa manera. Elija un lenguaje funcional (puro); escribe un código de procedimiento; sumergirse al nivel de hardware y hacer algo de C o quizás incluso ensamblador; etc. Algunos idiomas que pueden sacudir su mente (suponiendo que actualmente esté usando algo como C ++ / Java / C # / VB / ...): Haskell, ML, Lisp (varios dialectos para elegir), Erlang, Prolog, Smalltalk, Javascript (si deja de intentar que se comporte como Java y adopte su naturaleza de cierre), C, Pascal, awk y probablemente una docena más. La característica clave es que deben ser muy diferentes de lo que usa ahora. Esto no es algo que quieras hacer en un gran proyecto con mucho en juego,
  • Use un método de diseño radicalmente diferente. Vea si puede elegir el diseño desde un ángulo diferente. Supongo que generalmente comienzas a diseñar diseñando tus clases; ¿Qué tal si comienzas con estructuras de datos para un cambio? ¿O qué tal si primero diseñas la interfaz de usuario, literalmente dibujando formularios de entrada antes de diseñar cualquier funcionalidad?
tdammers
fuente
1

Para muchas decisiones de diseño, puede ayudar hacer un "pico", que es un esfuerzo de investigación corto y de tiempo limitado en el que puede explorar algunas opciones de arquitectura u diseño codificando un prototipo desechable. Por ejemplo, podría explorar el uso de alguna biblioteca de código abierto o cómo organizará sus clases e interfaces. La clave es mantenerlo breve para que pueda probar otro enfoque si el primero no es satisfactorio y, con suerte, obtendrá el conocimiento suficiente en el ejercicio para tomar mejor las decisiones arquitectónicas o probar el concepto. El ejercicio en sí implica una codificación inmediata que ayuda a salir del "bloque de escritores" sin comprometerse necesariamente con el "git 'er done" demasiado pronto.

Después de eso, es beneficioso utilizar el enfoque TDD o BDD que Asaf mencionó para seguir adelante con la implementación del proyecto.

Llavero
fuente
+1 estoy de acuerdo. Planee tirar el primer intento. Trátelo como una experiencia de aprendizaje. He tirado hasta seis, antes de pensar que quiero seguir con el séptimo.
Mike Dunlavey
1

No lo necesitarás , así que no pienses demasiado al principio.

Invierta más tiempo para definir, comprender el objetivo y el problema.

La "extensibilidad y reutilización" es el resultado natural del ciclo de vida de los programas de software bien escritos.

9dan
fuente
0

Asumiré que estamos viendo un proyecto de tamaño mediano.
Empezaría yendo a la mesa de dibujo. Debe tener sus requisitos funcionales y no funcionales listos antes de hacer esto. Primero se te ocurrirá la arquitectura del software, es decir, mirar cualquier patrón arquitectónico que se adapte a tus requisitos
Una vez que decidas cómo se ve tu arquitectura, deberías pasar al diseño de bajo nivel, e mirar todas las entidades, clases y funcionalidades. . Aquí, nuevamente intentará e identificará los patrones de diseño que encajan. En el proceso, sabrá cuáles son sus clases base y las interfaces que necesitaría
. Luego puede construir el marco y ejecutar algunas pruebas rápidas para ver si esto satisface todos sus requisitos no funcionales
Luego iría con Test Driven Development como ha sugerido @Asaf.

Recuerde, a pesar de pasar un buen tiempo en diseño y arquitectura, siempre esté dispuesto a volver a visitar la arquitectura si surge la necesidad.

hangar18
fuente
0

Creo que esta es una gran pregunta, y nada funcionará para todos. Creo que esa parálisis es un subproducto natural de ser cada vez más competente en su campo. Dicho esto, aquí hay algunas cosas que hago que ayudan, pero no resuelven el problema:

  • Ponga a un lado su proyecto original y trabaje en la versión fugia. Esta es la versión donde te dices a ti mismo: a. Se supone que el código no es bonito. De hecho, dite a ti mismo, no se permiten refactorizaciones y reformateos importantes. Deje que esté absolutamente desorganizado y libérese de los lazos de una buena codificación. si. Solo tiene que funcionar. do. Siempre me sorprende lo que aprendo sobre el espacio del problema cuando descarto todas las demás preocupaciones. También termino con pequeñas cositas que a menudo me ayudan a llegar al diseño correcto de una manera más ilustrada.

  • Reserve un período de tiempo decente en el que esté en el proyecto, simplemente sin una computadora. Intenta conceptualizar lo que realmente estás tratando de lograr y busca ese zen mágico que trascienda la locura de OO / Patrón de diseño.

Kevin Hsu
fuente
0

Da una expresión concreta a tus pensamientos: escríbelos / escríbelos, dibuja o lo que sea. Esto lo ayudará a revisar sus pensamientos cuando sea necesario; te impedirá ir en círculos; te ayuda a pensar más claramente.

Cada vez que me veo yendo a ninguna parte y a todas partes pensando en algo, las escribo y me ayuda a pensar con claridad.

Srisa
fuente
0

Por lo general, empiezo desde cero, creo el prototipo más simple posible y hago que algo funcione. Use el prototipo para realizar ingeniería inversa en los casos de prueba de ruta feliz, los casos de prueba para manejar las interfaces y luego piense en los contratos previos / posteriores para ayudar a construir la cobertura de prueba.

No se preocupe por la abstracción, la optimización o la verificación hasta que se comprenda completamente el problema.

Sbrenton
fuente