Como programador, me encuentro en el dilema donde quiero hacer que mi programa sea lo más abstracto y general posible.
Hacerlo generalmente me permitiría reutilizar mi código y tener una solución más general para un problema que podría (o no) aparecer nuevamente.
Entonces esta voz en mi cabeza dice, ¡solo resuelve el problema, tonto, así de fácil! ¿Por qué pasar más tiempo del necesario?
De hecho, todos nos hemos enfrentado a esta pregunta en la que Abstracción está en tu hombro derecho y Solve-it-stupid se sienta a la izquierda.
¿Cuál escuchar y con qué frecuencia? ¿Cuál es tu estrategia para esto? ¿Deberías abstraerlo todo?
time-management
problem-solving
abstraction
Bryan Harrington
fuente
fuente
Respuestas:
Nunca haga un resumen hasta que deba hacerlo.
En Java, por ejemplo, debe usar interfaces. Son una abstracción.
En Python no tienes interfaces, tienes Duck Typing y no necesitas altos niveles de abstracción. Entonces simplemente no lo haces.
No resumas hasta que lo hayas escrito tres veces.
Una vez es, bueno, una vez. Solo resuélvelo y sigue adelante.
Dos veces es la indicación de que puede haber un patrón aquí. O tal vez no. Puede ser solo una coincidencia.
Tres veces es el comienzo de un patrón. Ahora trasciende la coincidencia. Ahora puede abstraer con éxito.
No.
De hecho, nunca debes abstraer nada hasta que tengas una prueba absoluta de que estás haciendo el tipo correcto de abstracción. Sin la "Regla de las tres repeticiones", escribirás cosas que son inútilmente abstraídas de una manera inútil.
Esta es una suposición que a menudo es falsa. La abstracción puede no ayudar en absoluto. Se puede hacer mal. Por lo tanto, no lo hagas hasta que debas hacerlo.
fuente
Ah, YAGNI. El concepto de programación más abusado.
Hay una diferencia entre hacer que su código sea genérico y hacer un trabajo extra. ¿Debería dedicar más tiempo a acoplar su código sin apretarlo y adaptarlo fácilmente para hacer otras cosas? Absolutamente. ¿Debería pasar tiempo implementando funcionalidades innecesarias? No. ¿Debería pasar tiempo haciendo que su código funcione con otro código que aún no se ha implementado? No.
Como dice el refrán "Haz lo más simple que pueda funcionar". El caso es que la gente siempre confunde lo simple con lo fácil . La simplicidad requiere trabajo. Pero vale la pena el esfuerzo.
¿Puedes ir por la borda? Por supuesto. Pero mi experiencia es que pocas compañías necesitan más de una actitud de "hazlo ahora" de lo que ya tienen. La mayoría de las empresas necesitan más personas que piensen las cosas con anticipación. De lo contrario, siempre terminan teniendo un problema autosuficiente en el que nadie tiene tiempo para nada, todos siempre tienen prisa y nadie hace nada.
Piénselo de esta manera: es muy probable que su código se vuelva a usar de alguna manera. Pero no vas a predecir correctamente de esa manera. Así que haga su código limpio, abstracto y poco acoplado. Pero no intente hacer que su código funcione con ninguna pieza específica de funcionalidad que aún no exista. Incluso si sabes que existirá en el futuro.
fuente
simple
yeasy
!Un silogismo:
La generalidad es cara.
Estás gastando el dinero de otras personas.
Por lo tanto, el gasto de generalidad debe justificarse ante los interesados.
Pregúntese si realmente está resolviendo el problema más general para ahorrar dinero a las partes interesadas más adelante, o si le parece un desafío intelectual hacer una solución innecesariamente general.
Si se determina que la generalidad es deseable, entonces debe diseñarse y probarse como cualquier otra característica . Si no puede escribir pruebas que demuestren cómo la generalidad que ha implementado resuelve un problema requerido por la especificación, ¡no se moleste en hacerlo! Una característica que no cumple con los criterios de diseño y que no se puede probar es una característica en la que nadie puede confiar.
Y finalmente, no existe tal cosa como "lo más general posible". Supongamos que escribe software en C #, solo por el argumento. ¿Vas a hacer que cada clase implemente una interfaz? ¿Cada clase es una clase base abstracta con cada método un método abstracto? Eso es bastante general, pero no es "tan general como sea posible". Eso solo permite a las personas cambiar la implementación de cualquier método a través de subclases. ¿Qué pasa si quieren cambiar la implementación de un método sin subclasificar? Puede hacer que cada método sea en realidad una propiedad de tipo delegado, con un setter para que las personas puedan cambiar cada método por otro. ¿Pero qué pasa si alguien quiere agregar más métodos? Ahora cada objeto tiene que ser expandible.
En este punto, debe abandonar C # y adoptar JavaScript. Pero aún no has llegado a un lugar lo suficientemente general; ¿Qué pasa si alguien quiere cambiar cómo funciona la búsqueda de miembros para este objeto en particular? Tal vez deberías escribir todo en Python en su lugar.
El aumento de la generalidad a menudo significa abandonar la previsibilidad y aumentar enormemente los costos de prueba para garantizar que la generalidad implementada realmente tenga éxito en satisfacer una necesidad real del usuario . ¿Están esos costos justificados por sus beneficios para las partes interesadas que pagan por ellos? Quizás lo son; eso depende de usted para discutir con las partes interesadas. Mis partes interesadas no están en absoluto dispuestas a que abandone la escritura estática en busca de un nivel de generalidad totalmente innecesario y extremadamente costoso, pero tal vez el suyo sí lo esté.
fuente
Para ser claros, hacer algo generalizado e implementar una abstracción son dos cosas completamente diferentes.
Por ejemplo, considere una función que copia la memoria.
La función es una abstracción que oculta cómo se copian los 4 bytes.
int copy4Bytes (char * pSrc, char * pDest)
Una generalización sería hacer que esta función copie cualquier número de bytes.
int copyBytes (char * pSrc, char * pDest, int numBytesToCopy)
La abstracción se presta para su reutilización, mientras que la generalización solo hace que la abstracción sea útil en más casos.
Más específicamente relacionado con su pregunta, la abstracción no solo es útil desde una perspectiva de reutilización de código. Muchas veces, si se hace correctamente, hará que su código sea más legible y fácil de mantener. Usando el ejemplo anterior, ¿qué es más fácil de leer y entender si está hojeando el código copyBytes () o un bucle for iterando a través de un conjunto de datos en movimiento índice por índice? La abstracción puede proporcionar una especie de auto documentación que, en mi opinión, hace que el código sea más fácil de trabajar.
Como regla general, si puedo encontrar un buen nombre de función que describa exactamente lo que pretendo que haga un fragmento de código, entonces escribo una función para él, independientemente de si creo que lo volveré a usar o no.
fuente
Una buena regla general para este tipo de cosas es Cero, Uno, Infinito. Es decir, si necesita lo que está escribiendo más de una vez, puede asumir que lo necesitará aún más veces y generalizar. Esta regla implica que no te molestes con la abstracción la primera vez que escribes algo.
Otra buena razón para esta regla es que la primera vez que escribe el código, no necesariamente sabrá qué abstraer porque solo tiene un ejemplo. La Ley de Murphy implica que si escribe código abstracto la primera vez, el segundo ejemplo tendrá diferencias que no anticipó.
fuente
Eric Lippert señala tres cosas que creo que se aplican en su artículo a prueba de futuro de un diseño . Creo que si lo sigues estarás en buena forma.
fuente
Depende de por qué está codificando, el propósito de su proyecto. Si el valor de su código es que resuelve un problema concreto, entonces desea hacerlo y pasar al siguiente problema. Si hay cosas rápidas y fáciles que puede hacer para facilitar las cosas para los futuros usuarios del código (incluido usted mismo), entonces, por todos los medios, haga ajustes razonables.
Por otro lado, hay casos en los que el código que está escribiendo tiene un propósito más genérico. Por ejemplo, cuando está escribiendo una biblioteca para otros programadores, que la usarán en una amplia variedad de aplicaciones. Los usuarios potenciales son desconocidos y no puede preguntarles exactamente qué quieren. Pero desea que su biblioteca sea ampliamente útil. En tales casos, pasaría más tiempo tratando de apoyar la solución general.
fuente
Soy un gran admirador del principio KISS.
Me concentro en proporcionar lo que me piden que haga, y no en cuál es la mejor solución. Tuve que abandonar el perfeccionismo (y el TOC), porque me hizo sentir miserable.
fuente
No estoy de acuerdo con "resolverlo estúpido" , creo que puede ser más "resolverlo de manera inteligente" .
¿Qué es más inteligente?
La opción predeterminada debería ser la segunda. A menos que pueda demostrar una necesidad generacional.
La solución generalizada solo debe ser cuando se sabe que es algo que se utilizará en múltiples proyectos / casos diferentes.
Por lo general, encuentro que las soluciones generalizadas se sirven mejor como "Código de biblioteca principal"
fuente