Trabaje desde afuera hacia adentro. Necesita un programa que muestre una ventana con tres cuadros de texto y un botón, y cuando ingresa texto en los tres y hace clic en el botón, hace algo interesante con el texto para producir un resultado que se muestra en una ventana emergente diálogo. Todo eso es muy desalentador cuando nos fijamos en el trabajo a realizar en su conjunto.
Pero, ¿cómo te comes un elefante? Un bocado a la vez. En primer lugar, necesitas un programa. Por lo tanto, escriba el código básico requerido para un programa válido que se inicia y se detiene sin hacer nada. Ahora, el código debe mostrar una ventana. Por lo tanto, cree una ventana básica, sin nada, y escriba el código para mostrar esa ventana al usuario. Ahora, cuando ejecuta el código, obtiene una ventana en blanco; oye, estás en camino, el programa está haciendo algo. Ahora, agregue tres cuadros de texto y un botón. Ahora el formulario se ve como algo, y puede ingresar texto. Por último, escriba el código que hace las cosas interesantes al texto en los cuadros de texto. Finalmente, escriba el código que muestra una ventana emergente al usuario con los resultados de este interesante cálculo.
Haz un poco de trabajo de diseño por adelantado. Si bien el desarrollo de afuera hacia adentro es una buena mentalidad para tener en todo momento, a veces es necesario tener un mapa más definido de cómo proceder. Esto puede ser para que no te codifiques en una esquina, o para que puedas dividir el trabajo entre múltiples desarrolladores mientras aseguras que lo que las otras personas están codificando funcionará con tu código. Entonces, haga el mismo proceso de afuera hacia adentro, excepto que en lugar de hacer el trabajo, describa el trabajo, comenzando desde el resumen “necesitamos un programa” hasta el “QuickSort esta lista por una expresión particular” (o incluso más específico) dependiendo de tu idioma y de lo que estés haciendo).
Considere la “narrativa del caso de uso”. Mire el programa desde la perspectiva de la persona que lo usará. ¿Qué esperan que tengan que hacer y qué esperarían como resultado cuando lo hicieran? Codifique el programa para cumplir con esas expectativas, y nada más. Luego, considere otra narrativa de un caso de uso superpuesto. Agregue más código para cumplir con esas nuevas expectativas. Continúe agregando código para cumplir con cada nueva narrativa de casos de uso, hasta que el código haga todo lo que el usuario necesita que haga.
- ¿Cómo puedo realmente aprender de lo que leo?
- ¿Los estudiantes de IIT madras necesitan un 85% de asistencia? Si no, ¿cómo podemos llegar al 75%?
- ¿Cuáles son algunas cosas que debo considerar al elegir un programa de diseño?
- ¿Los zoológicos siguen siendo relevantes para las sociedades de educación y entretenimiento?
- ¿Qué explica el estado relativamente bajo del trabajo social como profesión?
No te atasques en detalles. Puede perderse fácilmente en los bits y bytes de un sub-algoritmo particular de su programa. Debes ser lo suficientemente inteligente como para darte cuenta de cuándo sucede esto, dar un paso atrás y mirar la imagen más grande. ¿El código que está escribiendo hace su trabajo correctamente y tan rápido como tiene que hacerlo? Entonces sigue adelante . Deja de preocuparte por cómo se ve o cómo está diseñado; Lo más probable es que nunca lo vuelvas a ver.
Haz que funcione, hazlo limpio, hazlo SÓLIDO. Esta es mi regla de “tres golpes” para trabajar con una línea o bloque de código. Cuando se escribe una línea de código por primera vez, no obtiene puntos de estilo para sumar 2 y 2. Haga lo que tiene que hacer y asuma, como en el punto anterior, nunca volverá a ver esa línea de código. Sin embargo, la próxima vez que coloque el cursor en esa línea de código, acaba de refutar esa suposición original. Regresará para corregir o extender el código para que haga lo que hace mejor o haga más. Mientras lo hace, busque formas de “limpiar” el código, refactorizando las declaraciones repetidas en bucles, bloques repetidos en métodos, nombrando variables de forma más intuitiva (pero concisa), etc. Ahora el código debe ser correcto y fácil de entender.
La próxima vez que regrese a este código, probablemente sea un gran problema; o se le pide que haga aún más, o necesita hacerlo en más lugares. Ahora, debe comenzar a prestar atención a los principios de diseño orientado a objetos y las mejores prácticas, como SOLID o GRASP. Prefiero SOLID ya que sus reglas son un poco más definidas; GRASP es un poco más intuitivo y subjetivo, y aunque muy poco es absoluto en el diseño del programa, es mejor IMO definir el ideal y trabajar para lograrlo, en lugar de definir cómo mejorarlo sin definir cuándo ha terminado.
Las reglas SÓLIDAS son:
SRP – Principio de responsabilidad única: un objeto de código (método, clase, interfaz) idealmente debe tener exactamente una razón para cambiar. Este es el ideal del principio general de diseño de “alta cohesión”; todo el código dentro de un objeto debe estar relacionado con un propósito de alcance limitado. Es la base de un buen diseño orientado a objetos, la creación de “código de raviolis”; fragmentos de código del tamaño de un bocado que se pueden examinar individualmente o en combinación con otros.
OCP: principio abierto / cerrado: idealmente, un objeto debe estar abierto a cualquier extensión, pero cerrado a cualquier cambio. Al agregar código para admitir algún comportamiento nuevo, idealmente no debería existir un código correcto existente. Esto se debe a que cualquier código que cambie tiene el potencial de error y, por lo tanto, debe volver a probar todos los casos de uso originales del código modificado. Además, al agregar este nuevo código al código existente, le da al código dos razones para cambiar; un cambio en el comportamiento existente o nuevo En cambio, es mejor “extender” el código original, ya sea derivando una nueva clase de la existente para implementar un nuevo comportamiento, o dando a la clase existente una referencia al nuevo código que puede usar en cierto modo ya está familiarizado (como una nueva devolución de llamada o un controlador de eventos).
Este es un poco falso porque un programa nunca puede cerrarse a todo tipo de cambio. En cambio, el objetivo es identificar cómo es probable que tenga que cambiar un fragmento de código y diseñarlo para que el cambio identificado pueda ocurrir mediante la extensión del objeto en lugar de agregar más código dentro de él.
LSP – Principio de sustitución de Liskhov: Un objeto A, que depende de un objeto B, debe poder usar cualquier C que se derive de B sin saber la diferencia. Esto básicamente significa que el uso de cualquier objeto que exponga una “interfaz” particular a sus consumidores debe ser idéntico a cualquier otro objeto que exponga la misma interfaz; no se necesita conocimiento especializado del objeto exacto que se utiliza. Esto se relaciona con el OCP y SRP; un nuevo objeto que viola el LSP, por ejemplo, al requerir que se llame a un método nuevo para inicializarlo, requiere que cada uso de la interfaz cambie para incorporar el cambio en el uso, y también requiere que cada clase existente en la familia cambie para exponer el nuevo método incluso si no lo necesitan.
ISP – Principio de segregación de interfaz: muchas interfaces con pocos métodos son mejores que pocas interfaces con muchos métodos. Este es básicamente el SRP para interfaces. Si tiene una interfaz con tres métodos, y agrega un parámetro a uno de ellos, cada implementación de la interfaz debe cambiar para acomodar el nuevo parámetro, cada uso del método debe cambiar para pasarlo, y cada uso de la interfaz misma al menos debe volver a compilarse, incluso si no utiliza ese método en absoluto . Por lo tanto, evitar esta situación es una ventaja definitiva; Si el uso de una interfaz no utiliza un método particular, tal vez ese método no pertenezca a esa interfaz específica.
Todavía se debe tener cuidado para adherirse al SRP. El código con un solo propósito, la mayoría de las veces, implementa una única interfaz que le permite cumplir el propósito.
DIP – Principio de inversión de dependencia: los objetos de código nunca deberían depender de objetos concretos, sino de abstracciones. Un objeto A que tiene que saber sobre B tendrá que cambiar si alguna vez desea utilizar C en su lugar. Por el contrario, si A dependiera de una interfaz I, que tanto B como C implementaron, A no tendría que cambiar cuando cambiara B por C. Esta es la esencia del “acoplamiento flojo”, y va junto con el LSP y el OCP ; poder intercambiar una dependencia por otra sin ningún cambio en el uso significa varias cosas que son buenas para el codificador. Es más fácil reorganizar los objetos para hacer algo diferente sin necesidad de volver a codificar las piezas. Es más fácil probar cada objeto de código de forma aislada conectando dependencias “ficticias” como simulacros y trozos. Es más fácil entender el propósito básico de un objeto de código (y, por lo tanto, su “razón para cambiar”).