¿Debería la solución ser lo más genérica posible o tan específica como sea posible?

124

Digamos que tengo una entidad que tiene el atributo "type". Podría haber más de 20 tipos posibles.

Ahora me piden que implemente algo que permita cambiar el tipo de A-> B, que es el único caso de uso.

Entonces, ¿debo implementar algo que permita cambios de tipo arbitrarios siempre que sean tipos válidos? ¿O SOLO debería permitir que cambie de A-> B según el requisito y rechazar cualquier otro tipo de cambio como B-> A o A-> C?

Puedo ver los pros y los contras de ambos lados, donde una solución genérica significaría menos trabajo en caso de que surja un requisito similar en el futuro, pero también significaría más posibilidades de equivocarse (aunque controlamos al 100% a la persona que llama en este momento). punto).
Una solución específica es menos propensa a errores, pero requiere más trabajo en el futuro si surge un requisito similar.

Sigo escuchando que un buen desarrollador debe tratar de anticipar el cambio y diseñar el sistema para que sea fácil de extender en el futuro, ¿qué parece una solución genérica?

Editar:

Agregar más detalles a mi ejemplo no tan específico: la solución "genérica" ​​en este caso requiere menos trabajo que la solución "específica", ya que la solución específica requiere validación tanto en el tipo antiguo como en el nuevo, mientras que la solución genérica solo necesita validar el nuevo tipo.

Programación de amor
fuente
97
Esa es una pregunta interesante. He tenido una discusión sobre algo así con mis abuelos (un programador de temporizadores muy, muy antiguo) y su respuesta fue algo en la línea de "lo más genérico que resuelve su problema específico", que se reduce a una fantasía " Depende". Las declaraciones generales en el desarrollo de software rara vez funcionan: las cosas deben tomarse siempre caso por caso.
T. Sar
2
@ T.Sar agregue esto como respuesta y votaré :-)
Christophe el
44
¿Qué es una "solución genérica" ​​en su opinión? Además, aclare lo que quiere decir con “solo caso de uso”. ¿Quiere decir que solo se permite una transición de A-> B o que solo se especifica esa transición, y que no sería una condición de error pasar de cualquier otro estado a otro estado? Como desarrollador, debe pedirle al autor del caso de uso que lo aclare. Si no se permite ninguna otra transición y su código lo permite independientemente de quién controla a la persona que llama, su código no cumplió con los requisitos.
RibaldEddie
55
El principio de que si X es una buena idea, entonces solo X debe ser óptimo todo el tiempo, parece tener un atractivo particular para los desarrolladores (o al menos un grupo vocal entre ellos), pero considere esto: las reglas generales de programación son como proverbios, en el sentido de que a menudo puedes encontrar un par con implicaciones opuestas. Esta es una señal de que debe usar su juicio (como lo recomiendan las respuestas aquí) y tener cuidado con el dogma.
sdenham
2
La generalización prematura puede causar tanta acidez estomacal como la optimización prematura: terminas escribiendo una gran cantidad de código que quizás nunca se use. Primero se resuelve el problema específico, luego se generaliza a medida que surge la necesidad.
John Bode

Respuestas:

296

Mi regla de oro:

  1. la primera vez que encuentre el problema, solo resuelva el problema específico (este es el principio de YAGNI )
  2. la segunda vez que se encuentre con el mismo problema, considere generalizar el primer caso, si no es mucho trabajo
  3. una vez que tenga tres casos específicos en los que pueda usar la versión generalizada, entonces debería comenzar a planificar realmente la versión generalizada; por ahora, debe comprender el problema lo suficientemente bien como para poder generalizarlo.

Por supuesto, esta es una guía y no una regla estricta: la respuesta real es utilizar su mejor criterio, caso por caso.

Daniel Pryden
fuente
1
¿Puedes explicar qué es YAGNI?
Bernhard
77
@ Bernard No lo vas a necesitar . Un principio de diseño de software muy útil.
Angew
44
"En thing1, thing2, piense en usar una matriz. En thing1, thing2, thing3, casi con toda seguridad use thing[]matriz en su lugar". es una regla general similar para decidir entre múltiples variables o una sola matriz.
Joker_vD
15
Otra forma de establecer la regla # 1: "No se puede generalizar una cosa".
Wayne Conrad
2
@SantiBailors: Como dice Doc Brown en su respuesta, a menudo sobreestimamos enormemente la cantidad de esfuerzo desperdiciado que podríamos gastar al construir el primero en tirar. En The Mythical Man-Month , Fred Brooks dice: "Planea tirar uno, de todos modos lo harás". Dicho esto: si inmediatamente encuentra más de un uso para algo, por ejemplo, al recibir un conjunto de requisitos donde claramente necesitará resolver el mismo problema más de una vez, entonces ya tiene más de un caso para generalizar de, y eso está totalmente bien y no está en conflicto con mi respuesta.
Daniel Pryden
95

Una solución específica [...] requiere más trabajo en el futuro si se necesita un requisito similar

He escuchado este argumento varias docenas de veces y, según mi experiencia, regularmente resulta ser una falacia. Si generaliza ahora o más tarde, cuando surja el segundo requisito similar, el trabajo será casi el mismo en total. Por lo tanto, no tiene sentido invertir un esfuerzo adicional en generalizar, cuando no sabe que este esfuerzo alguna vez dará sus frutos.

(Obviamente, esto no se aplica cuando una solución más general es menos complicada y requiere menos esfuerzo que una específica, pero según mi experiencia, estos son casos raros. Este tipo de escenario se editó luego en la pregunta, y no es uno mi respuesta es sobre).

Cuando aparece el "segundo caso similar", es hora de comenzar a pensar en generalizar. Será mucho más fácil generalizar correctamente entonces, porque este segundo requisito le brinda un escenario en el que puede validar si hizo las cosas genéricas correctas. Cuando intentas generalizar solo para un caso, estás disparando en la oscuridad. Hay muchas posibilidades de que generalice en exceso ciertas cosas que no necesitan ser generalizadas, y omita otras partes que deberían. Y cuando surge un segundo caso y te das cuenta de que generalizaste las cosas equivocadas, entonces tienes mucho más trabajo por hacer para solucionarlo.

Así que recomiendo retrasar cualquier tentación de hacer las cosas "por si acaso". Este enfoque solo conducirá a más esfuerzos de trabajo y mantenimiento cuando se perdió la ocasión de generalizar tres, cuatro o más veces y luego tener una pila de código de aspecto similar (tan duplicado) para mantener.

Doc Brown
fuente
2
Para mí, esta respuesta no tiene sentido en el contexto de OP. Está diciendo que pasará menos tiempo generalizando ahora y menos tiempo en el futuro, a menos que en el futuro sea necesario que la implementación sea específica. Está argumentando en contra de "invertir un esfuerzo adicional en generalizar", mientras que OP invertirá un esfuerzo adicional solo si no se generaliza. (pensar) .... raro: $
msb
2
@msb: ese contexto se agregó después de que escribí mi respuesta y va en contra de lo que el OP decía antes, especialmente en la parte que cité. Mira mi edición.
Doc Brown
2
Además, la solución generalizada será más complicada, por lo que cuando tenga que adaptarla para el segundo caso, le llevará mucho más tiempo volver a comprenderla.
AndreKR
44
Doc, aparte, pero nunca habría imaginado que eras un hablante no nativo. Sus respuestas siempre están bien escritas y bien argumentadas.
user949300
2
Me imagino tu acento cuando leo tus futuras respuestas. :-)
user949300
64

TL; DR: depende de lo que intentes resolver.

Tuve una conversación similar con mis abuelos sobre esto, mientras estábamos hablando de cómo Func y Action en C # son increíbles. My Gramps es un programador de temporizador muy antiguo, que ha estado relacionado con los códigos fuente desde que el software se ejecutó en computadoras que ocuparon toda una habitación.

Cambió de técnico varias veces en su vida. Escribió código en C, COBOL, Pascal, BASIC, Fortran, Smalltalk, Java y finalmente comenzó C # como un hobby. Aprendí a programar con él, sentándome en su regazo mientras no era más que un devling, quitando mis primeras líneas de código en el editor azul de SideKick de IBM. Cuando tenía 20 años, ya había pasado más tiempo codificando que jugando afuera.

Esos son algunos de mis recuerdos, así que discúlpeme si no soy exactamente práctico mientras los vuelvo a contar. Soy un poco aficionado a esos momentos.

Eso es lo que me dijo:


"¿Deberíamos buscar la generalización de un problema o resolverlo en el ámbito específico, pregunta? Bueno, esa es una ... pregunta".

Gramps hizo una pausa para pensarlo por un breve momento, mientras fijaba la posición de sus lentes en su rostro. Estaba jugando un juego de combinar 3 en su computadora, mientras escuchaba un LP de Deep Purple en su antiguo sistema de sonido.

"Bueno, eso dependería de qué problema estés tratando de resolver", me dijo. "Es tentador creer que existe una única solución sagrada para todas las opciones de diseño, pero no hay una. La arquitectura de software es como el queso".

"... Queso, abuelo?"

"No importa lo que pienses sobre tu favorito, siempre habrá alguien que piense que es maloliente".

Parpadeé confundido por un momento, pero antes de que pudiera decir algo, Gramps continuó.

"Cuando estás construyendo un auto, ¿cómo eliges el material para una parte?"

"Yo ... supongo que depende de los costos involucrados y de lo que debe hacer la parte, supongo".

"Depende del problema que la parte esté tratando de resolver. No harás una llanta de acero o un parabrisas de cuero. Escoges el material que mejor resuelva el problema que tienes a mano. Ahora, ¿qué es un ¿Solución genérica? ¿O específica? ¿Para qué problema, para qué caso de uso? ¿Debería adoptar un enfoque funcional completo para dar la máxima flexibilidad a un código que se utilizará solo una vez? ¿Debería escribir un código muy especializado y frágil para una parte de su sistema que verá muchos usos y posiblemente muchos cambios? Las opciones de diseño como esas son los materiales que elige para una parte de un automóvil o la forma del ladrillo de Lego que elige para construir una pequeña casa ¿Qué ladrillo de Lego es el mejor?

El programador anciano buscó un pequeño modelo de tren de Lego que tiene sobre su mesa antes de continuar.

"Solo puedes responder eso si sabes para qué necesitas ese ladrillo. Cómo demonios sabrás si la solución específica es mejor que la genérica, o viceversa, si ni siquiera sabes qué problema tienes tratando de resolver? No puedes ver más allá de una elección que no entiendes ".

"... ¿Acabas de citar The Matrix? "

"¿Qué?"

"Nada, continúa".

"Bueno, supongamos que estás tratando de construir algo para el Sistema Nacional de Facturas. Sabes cómo se vería esa API infernal y su archivo XML de treinta mil líneas desde adentro. ¿Cómo se vería una solución 'genérica' para crear ese archivo? el archivo está lleno de parámetros opcionales, lleno de casos que solo las ramas de negocios específicas deberían usar. En la mayoría de los casos, puede ignorarlos de manera segura. No es necesario crear un sistema de factura genérico si lo único que usted necesita es " alguna vez venderé zapatos. Simplemente cree un sistema para vender zapatos y conviértalo en el mejor sistema de facturación de ventas de zapatos. Ahora, si tuviera que crear un sistema de facturación para cualquier tipo de cliente, en una aplicación más amplia: para ser revendido como un sistema de ventas independiente y genérico,por ejemplo, ahora es interesante implementar esas opciones que solo se usan para gas, alimentos o alcohol.Ahora esos son posibles casos de uso. Antes eran solo algunos casos hipotéticos de No usar , y no desea implementar No usar casos. No usar es el hermano pequeño de No necesito ".

Gramps volvió a colocar el tren de lego en su lugar y volvió a su juego de combinar 3.

"Por lo tanto, para poder elegir una solución genérica o específica para un problema dado, primero debes comprender cuál es ese problema. De lo contrario, solo estás adivinando, y adivinar es el trabajo de los gerentes, no de los programadores. Como casi todo en TI, depende ".


Entonces, ahí lo tienes. "Depende". Esa es probablemente la expresión de dos palabras más poderosa cuando se piensa en el diseño de software.

T. Sar
fuente
14
Estoy seguro de que hay algo útil en esa historia, pero fue demasiado doloroso de leer, lo siento
GoatInTheMachine
28
Su primera publicación fue una anécdota breve y divertida, y por supuesto es una cuestión de opinión, pero a menos que realmente me guste el estilo de escritura de alguien, encuentro historias largas como esta realmente indulgentes y un poco inapropiadas fuera de un blog personal
GoatInTheMachine
16
@ T.Sar no escucha a los que odian, tu publicación es una joya de consejos útiles de un gurú. +1
LLlAMnYP
77
La parte de "arquitectura de software es como el queso" fue simplemente increíble. De hecho, esta respuesta es una joya!
Mathieu Guindon
3
¿Quizás esta respuesta también es como el queso? ;) Pero por favor, "SmallTalk" debería ser "Smalltalk", y sí, estoy siendo ese tipo, lo siento.
fede s.
14

Principalmente, debe tratar de anticipar si es probable que ocurra tal cambio, no solo una posibilidad remota en algún momento.

Si no, generalmente es mejor optar por la solución simple ahora y extenderla más tarde. Es muy posible que tenga una imagen mucho más clara de lo que se necesita entonces.

te doblo
fuente
13

Si está trabajando en un dominio que es nuevo para usted, entonces la Regla de tres que Daniel Pryden mencionó definitivamente debería aplicarse. Después de todo, ¿cómo se supone que construirás abstracciones útiles si eres un novato en esa área? Las personas a menudo están seguras de sí mismas en su capacidad de atrapar abstracciones, aunque rara vez es el caso. Según mi experiencia, la abstracción prematura no es menos malvada que la duplicación de código. Las abstracciones incorrectas son realmente dolorosas de comprender. A veces aún más doloroso refactorizar.

Hay un libro que aborda mi punto acerca de un área desconocida en la que el desarrollador está trabajando. Consiste en dominios específicos con extracciones útiles extraídas.

Zapadlo
fuente
La pregunta es clara sobre un problema concreto.
RibaldEddie
44
La respuesta es lo suficientemente genérica como para abordar este problema concreto. Y la pregunta no es lo suficientemente específica como para recibir un recibo concreto: como puede ver, no se mencionan detalles de dominio en una pregunta. Incluso los nombres de clase no están especificados (A y B no cuentan).
Zapadlo
77
"¿Debería una respuesta de stackoverflow ser lo más genérica posible o tan específica como sea posible?"
Lyndon White
@LyndonWhite ¿una pregunta de stackoverflow debe ser lo más genérica posible (¡demasiado amplia!) O tan específica como sea posible (¡como se llame esa falla!)? Decir ah.
4

Dada la naturaleza del cuerpo de su pregunta, suponiendo que la haya entendido correctamente, en realidad veo esto como una pregunta de diseño de las características del sistema central más que una pregunta sobre soluciones genéricas frente a soluciones específicas.

Y cuando se trata de las características y capacidades del sistema central, las más confiables son las que no están allí. Vale la pena errar por el lado del minimalismo, especialmente teniendo en cuenta que, en general, es más fácil agregar funcionalidades centralizadas, deseadas desde hace mucho tiempo, que eliminar funciones problemáticas, indeseadas durante mucho tiempo, con numerosas dependencias porque ha hecho que trabajar con el sistema sea mucho más difícil de lo que debe ser al tiempo que plantea interminables preguntas de diseño con cada nueva característica.

De hecho, a falta de una fuerte anticipación de si esto será necesario con frecuencia en el futuro, trataría de evitar ver esto como un reemplazo de tipo de A a B si es posible, y en su lugar solo buscarlo como una forma de transformar el estado de A. Por ejemplo, configure algunos campos en A para que se transforme y parezca B para el usuario sin cambiar realmente a un 'tipo' de cosas diferente: podría hacer que A almacene B de forma privada utilizando la composición y las funciones de llamada en B cuando el estado de A está configurado para indicar que debe imitar B para simplificar la implementación si es posible. Esa debería ser una solución muy simple y mínimamente invasiva.

De todos modos, haciendo eco de muchos otros, sugeriría errar por el lado de evitar soluciones genéricas en este caso, pero más aún porque supongo que esto es en consideración de agregar una capacidad muy audaz al sistema central, y allí me gustaría sugiera errar al lado de dejarlo afuera, especialmente por ahora.


fuente
"Echas de menos todos los errores que no codificas". (a partir del cartel de baloncesto: se olvida de todas las vacunas que no toma)
3

Es difícil dar una respuesta genérica a este problema específico ;-)

Cuanto más genérico sea, más tiempo ganará para futuros cambios. Por ejemplo, por esta razón, muchos programas de juegos usan el patrón de componente de entidad en lugar de construir un sistema de tipo muy elaborado pero rígido de los personajes y objetos en el juego.

Por otro lado, hacer algo genérico requiere una inversión inicial de tiempo y esfuerzo en diseño que es mucho mayor que para algo muy específico. Esto conlleva el riesgo de una ingeniería excesiva e incluso de perderse en posibles requisitos futuros.

Siempre vale la pena ver si hay una generalización natural que lo lleve a un gran avance. Sin embargo, al final, es una cuestión de equilibrio, entre el esfuerzo que puede gastar ahora y el esfuerzo que pueda necesitar en el futuro.

Christophe
fuente
3
  1. Híbrido. Esto no tiene por qué ser una o una pregunta. Puede diseñar la API para conversiones de tipo general mientras implementa solo la conversión específica que necesita en este momento. (Solo asegúrese de que si alguien llama a su API general con una conversión no admitida, falla con un estado de error "no compatible").

  2. Pruebas. Para la conversión A-> B, voy a tener que escribir una (o una pequeña cantidad) de pruebas. Para una conversión genérica x-> y, podría tener que escribir una matriz completa de pruebas. Eso es mucho más trabajo, incluso si todas las conversiones comparten una única implementación genérica.

    Si, por otro lado, resulta que hay una forma genérica de probar todas las conversiones posibles, entonces no hay mucho más trabajo y podría inclinarme por una solución genérica antes.

  3. Acoplamiento. Un convertidor de A a B necesariamente necesita conocer los detalles de implementación sobre A y B (acoplamiento estrecho). Si A y B todavía están evolucionando, esto significa que podría tener que seguir revisando el convertidor (y sus pruebas), lo que apesta, pero al menos está limitado a A y B.

    Si hubiera optado por una solución genérica que necesita acceso a los detalles de todos los tipos, incluso a medida que evolucionan las C y las D, es posible que deba seguir ajustando el convertidor genérico (y un montón de pruebas), lo que puede retrasarme incluso aunque nadie todavía tiene que convertir en una C o una D .

    Si tanto las conversiones genéricas como las específicas se pueden implementar de una manera que solo esté unida a los detalles de los tipos, entonces no me preocuparía por esto. Si una de ellas se puede hacer de una manera flojamente acoplada pero la otra requiere un acoplamiento estrecho, entonces ese es un fuerte argumento para el enfoque flojo de la puerta.

Adrian McCarthy
fuente
2
La prueba es un buen punto. Es una gran ventaja si diseña las soluciones genéricas basadas en conceptos de la teoría de categorías , porque a menudo obtiene teoremas gratuitos que prueban que la única implementación posible para una firma (que acepta el verificador de tipo del compilador) es la correcta , o al menos que si el algoritmo funciona para cualquier tipo en particular, también debe funcionar para todos los demás tipos.
Leftaroundabout
Supongo que hay una razón específica de dominio por la que solo se solicitó una conversión de tipo, lo que significa que la mayoría de las conversiones de tipo serían acciones no válidas en el dominio del problema y, por esa razón, la aplicación no debería admitirla hasta que están oficialmente permitidos. Esta respuesta se acerca más a esa argumentación.
Ralf Kleberhoff
3

¿Debería la solución ser lo más genérica posible o tan específica como sea posible?

Esa no es una pregunta que responda.

Lo mejor que puede obtener razonablemente es algunas heurísticas para decidir qué tan general o específico es hacer una solución dada. Trabajando en algo como el proceso a continuación, generalmente la aproximación de primer orden es correcta (o lo suficientemente buena). Cuando no lo es, es probable que el motivo sea demasiado específico del dominio para ser cubierto de manera útil en detalle aquí.

  1. Aproximación de primer orden: la regla habitual de tres de YAGNI según lo descrito por Daniel Pryden, Doc Brown, et al .

    Esta es una heurística generalmente útil porque es probablemente lo mejor que puede hacer sin depender del dominio y otras variables.

    Entonces, la presunción inicial es: hacemos lo más específico.

  2. Aproximación de segundo orden: según su conocimiento experto del dominio de la solución , usted dice

    La solución "genérica" ​​en este caso requiere menos trabajo que la solución "específica"

    entonces podríamos reinterpretar YAGNI como una recomendación de evitar el trabajo innecesario , en lugar de evitar generalidades innecesarias. Entonces, podríamos modificar nuestra presunción inicial y, en cambio, hacer lo más fácil .

    Sin embargo, si su conocimiento del dominio de la solución indica que la solución más fácil puede abrir muchos errores, o ser difícil de probar adecuadamente, o causar cualquier otro problema, entonces ser más fácil de codificar no es necesariamente una razón suficiente para cambiar nuestro Elección original.

  3. Aproximación de tercer orden: ¿su conocimiento del dominio del problema sugiere que la solución más fácil es realmente correcta, o está permitiendo que muchas transiciones que usted sabe no tengan sentido o estén mal?

    Si la solución fácil pero genérica parece problemática, o no está seguro de su capacidad para juzgar estos riesgos, probablemente sea mejor hacer el trabajo extra y mantenerse con su suposición inicial.

  4. Aproximación de cuarto orden: ¿su conocimiento del comportamiento del cliente, o cómo esta característica se relaciona con los demás, o las prioridades de gestión del proyecto, o ... alguna otra consideración no estrictamente técnica modifica su decisión de trabajo actual?

Inútil
fuente
2

Esta no es una pregunta fácil de responder con una respuesta simple. Muchas respuestas han dado heurística construida alrededor de una regla de 3, o algo similar. Ir más allá de esas reglas generales es difícil.

Para responder realmente a su pregunta, debe tener en cuenta que es probable que su trabajo no implemente algo que cambie A-> B. Si usted es un contratista, tal vez ese sea el requisito, pero si es un empleado, lo contrataron para realizar muchas tareas más pequeñas para la empresa. Cambiar A-> B es solo una de esas tareas. A su empresa también le importará qué tan bien se pueden hacer los cambios futuros, incluso si eso no se indica en la solicitud. Para encontrar "TheBestImplementation (tm)", debe mirar la imagen más grande de lo que realmente se le pide que haga, y luego usar eso para interpretar la pequeña solicitud que se le ha dado para cambiar A-> B.

Si usted es un programador de nivel bajo recién salido de la universidad, a menudo es aconsejable hacer exactamente lo que le dijeron que hiciera. Si fue contratado como arquitecto de software con 15 años de experiencia, generalmente es aconsejable pensar en cosas importantes. Cada trabajo real va a caer en algún lugar entre "hacer exactamente lo que es la tarea estrecha" y "pensar en el panorama general". Sentirás dónde encaja tu trabajo en ese espectro si hablas con la gente lo suficiente y haces suficiente trabajo para ellos.

Puedo dar algunos ejemplos concretos donde su pregunta tiene una respuesta definitiva basada en el contexto. Considere el caso en el que está escribiendo software crítico para la seguridad. Esto significa que tiene un equipo de prueba de pie para garantizar que el producto funcione según lo prometido. Se requiere que algunos de estos equipos de prueba prueben cada ruta posible a través del código. Si habla con ellos, puede descubrir que si generaliza el comportamiento, agregará $ 30,000 a sus costos de prueba porque tendrán que probar todas esas rutas adicionales. En ese caso, no agregue funcionalidad generalizada, incluso si tiene que duplicar el trabajo 7 u 8 veces debido a ello. Ahorre dinero a la empresa y haga exactamente lo que se indica en la solicitud.

Por otro lado, considere que está haciendo una API para permitir a los clientes acceder a los datos en un programa de base de datos que hace su empresa. Un cliente solicita permitir cambios A-> B. Las API generalmente tienen un aspecto de esposas doradas: una vez que agrega funcionalidad a una API, normalmente no se supone que elimine esa funcionalidad (hasta el próximo número de versión principal). Es posible que muchos de sus clientes no estén dispuestos a pagar el costo de actualizar al siguiente número de versión principal, por lo que puede quedarse atrapado con la solución que elija durante mucho tiempo. En este caso, yo altamente recomiendo crear la solución genérica desde el principio. Realmente no desea desarrollar una API incorrecta llena de comportamientos únicos.

Cort Ammon
fuente
1

Hmm ... no hay mucho contexto para obtener una respuesta ... haciéndose eco de las respuestas anteriores, "depende".

En cierto sentido, tienes que recurrir a tu experiencia. Si no es tuyo, entonces alguien más mayor en el dominio. Podrías objetar lo que dicen los criterios de aceptación. Si se trata de algo así como "el usuario debería poder cambiar el tipo de" A "a" B "'versus' el usuario debería poder cambiar el tipo de su valor actual a cualquier valor alternativo permitido '.

Con frecuencia, los criterios de aceptación están sujetos a interpretación, pero un buen personal de control de calidad puede escribir criterios apropiados para la tarea en cuestión, minimizando la interpretación necesaria.

¿Existen restricciones de dominio que no permiten cambiar de "A" a "C" o cualquier otra opción, sino solo "A" a "B"? ¿O es solo un requisito estrictamente especificado que no es "pensar hacia adelante"?

Si el caso general fuera más difícil, iría a preguntar antes de comenzar el trabajo, pero en su caso si pudiera 'predecir' que vendrían otras solicitudes de cambio de 'tipo' en el futuro, estaría tentado a: a) escriba algo reutilizable para el caso general, y b) envuélvalo en un condicional que solo permita A -> B por ahora.

Suficientemente fácil de verificar para el caso actual en pruebas automatizadas, y lo suficientemente fácil de abrirse a otras opciones más adelante si / cuando surgen diferentes casos de uso.

railsdog
fuente
1

Para mí, una directriz que establecí hace un tiempo es: "Para requisitos hipotéticos solo escriba código hipotético". Es decir, si anticipa requisitos adicionales, debe pensar un poco sobre cómo implementarlos y estructurar su código actual para que no se bloquee de esa manera.

Pero no escriba código real para estos ahora, solo piense un poco en lo que haría. De lo contrario, generalmente hará las cosas innecesariamente complejas y probablemente se molestará más tarde cuando surjan requisitos reales que difieran de lo que esperaba.

Cuatro su ejemplo: si tiene todos los usos del método de conversión bajo su control, puede llamarlo convertAToB por ahora y planear usar una refactorización de "método de cambio de nombre" en el IDE para cambiarle el nombre si necesita una funcionalidad más general más adelante. Sin embargo, si el método de conversión es parte de una API pública, esto podría ser bastante diferente: ser específico bloquearía la generalización más adelante, ya que es difícil cambiar el nombre de las cosas en ese caso.

Hans-Peter Störr
fuente
0

Sigo escuchando que un buen desarrollador debe tratar de anticipar el cambio y diseñar el sistema para que sea fácil de ampliar en el futuro,

En principio sí. Pero esto no necesariamente conduce a soluciones genéricas.

En lo que a mí respecta, existen dos tipos de temas en el desarrollo de software, en los que debe anticipar cambios futuros:

  • Bibliotecas destinadas a ser utilizadas por terceros, y
  • Arquitectura general del software.

El primer caso se resuelve observando su cohesión / acoplamiento, inyección de dependencia o lo que sea. El segundo caso está en un nivel más abstracto, por ejemplo, elegir una arquitectura orientada a servicios en lugar de una gran cantidad de código monolótico para una aplicación grande.

En su caso, está solicitando una solución específica para un problema específico, que no tenga ningún impacto previsible en el futuro. En este caso, YAGNI y DRY son buenos lemas para disparar:

  • YAGNI (no lo va a necesitar) le dice que implemente las cosas básicas y mínimas que necesita y usa en este momento . Significa implementar el mínimo que hace que su conjunto de pruebas actual cambie de rojo a verde, si usa el desarrollo de estilo TDD / BDD / FDD. Ni una sola línea más.
  • DRY (no repita usted mismo) significa que si usted viene sobre un problema similar de nuevo, a continuación, se toma una buena mirada a si necesita una solución genérica.

En combinación con otras prácticas modernas (como una buena cobertura de prueba para poder refactorizar de manera segura), esto significa que terminará con un código medio rápido, simple y escrito que crece según sea necesario.

¿Cuál suena como una solución genérica es el camino a seguir?

No, parece que debería tener entornos de programación, lenguajes y herramientas que faciliten y refactoricen cuando lo necesiten. Las soluciones genéricas no proporcionan eso; desacoplan la aplicación del dominio real.

Eche un vistazo a los marcos ORM o MVC modernos, por ejemplo, Ruby on Rails; a nivel de aplicación, todo se centra en hacer un trabajo no genérico. Obviamente, las bibliotecas de rails son casi 100% genéricas, pero el código de dominio (del que trata su pregunta) debería estar haciendo travesuras mínimas en ese aspecto.

AnoE
fuente
0

Una forma diferente de pensar sobre el problema es considerar lo que tiene sentido.

Por ejemplo, había una aplicación que estaba desarrollando que tenía secciones que hacían casi lo mismo pero tenían reglas de permiso inconsistentes. Como no había razón para mantenerlos diferentes, cuando reescribí esa sección, hice que todos hicieran los permisos de la misma manera. Esto hizo que el código general fuera más pequeño, más simple y la interfaz era más consistente.

Cuando la gerencia decidió permitir el acceso de otras personas a una función, pudimos hacerlo simplemente cambiando una bandera.

Obviamente tiene sentido hacer la conversión de tipo específico. ¿También tiene sentido hacer conversiones de tipo adicionales?

Tenga en cuenta que si la solución general es más rápida de implementar, entonces el caso específico también es fácil, solo verifique que sea la única conversión de tipo que está permitiendo.

Si la aplicación se encuentra en un área altamente regulada (una aplicación médica o financiera) intente involucrar a más personas en su diseño.

Robert Baron
fuente