¿Cómo puedo promover el uso del patrón Builder en mi equipo?

22

Nuestra base de código es antigua y los nuevos programadores, como yo, aprenden rápidamente a hacerlo de la misma manera en aras de la uniformidad. Pensando que tenemos que comenzar en alguna parte, me encargué de refactorizar una clase de titular de datos como tal:

  • Se eliminaron los métodos de establecimiento y se hicieron todos los campos final(tomo " finales bueno" axiomáticamente). Los setters se usaron solo en el constructor, como resultado, por lo que esto no tuvo efectos secundarios.
  • Introdujo una clase de constructor

La clase Builder era necesaria porque el constructor (que es lo que provocó la refactorización en primer lugar) abarca aproximadamente 3 líneas de código. Tiene muchos parámetros.

Por suerte, un compañero de equipo mío estaba trabajando en otro módulo y necesitó los setters, porque los valores que requería estaban disponibles en diferentes puntos del flujo. Por lo tanto, el código se veía así:

public void foo(Bar bar){
    //do stuff
    bar.setA(stuff);
    //do more stuff
    bar.setB(moreStuff);
}

Argumenté que debería usar el generador en su lugar, porque deshacerse de los establecedores permite que los campos permanezcan inmutables (ya me han escuchado hablar sobre la inmutabilidad antes), y también porque los constructores permiten que la creación de objetos sea transaccional. Dibujé el siguiente pseudocódigo:

public void foo(Bar bar){
    try{
        bar.setA(a);
        //enter exception-throwing stuff
        bar.setB(b);
    }catch(){}
}

Si se dispara esa excepción, barhabrá datos corruptos, que se habrían evitado con un generador:

public Bar foo(){
        Builder builder=new Builder();
    try{
        builder.setA(a);
        //dangerous stuff;
        builder.setB(b);
        //more dangerous stuff
        builder.setC(c);
        return builder.build();
    }catch(){}
    return null;
}

Mis compañeros de equipo respondieron que la excepción en cuestión nunca se disparará, lo cual es lo suficientemente justo para esa área de código en particular, pero creo que falta el bosque para el árbol.

El compromiso era volver a la solución anterior, es decir, usar un constructor sin parámetros y configurar todo con los establecedores según sea necesario. La razón era que esta solución sigue el principio KISS, que el mío viola.

Soy nuevo en esta empresa (menos de 6 meses) y estoy completamente consciente de que perdí esta. Las preguntas que tengo son:

  • ¿Hay otro argumento para usar Builders en lugar de la "vieja forma"?
  • ¿Vale la pena el cambio que propongo?

pero en serio,

  • ¿Tiene algún consejo para presentar mejor tales argumentos cuando aboga por probar algo nuevo?
rath
fuente
66
El generador necesitará establecer valores de alguna manera. Entonces no resuelve el problema básico.
Amy Blankenship
3
¿Cuál es la razón por la cual las cosas (más / peligrosas / lanzando excepciones) no se pueden mover antes de la llamada setA?
yatima2975
2
¿Solo 3 líneas de parámetros de constructor? Eso no es tan malo.
pjc50
77
En cualquier diseño de software, siempre hay compensaciones entre complejidad y desacoplamiento. Aunque creo que estoy de acuerdo con usted personalmente en que el constructor es una buena solución aquí, su compañero de trabajo tiene razón al dudar por KISS. Mantengo un software que es increíblemente demasiado complicado, y parte de la razón es porque cada nuevo empleado se vuelve pícaro y dice "Esto es estúpido, voy a hacer esto a mi manera", por lo tanto, tenemos 5 marcos para programar Trabajos en segundo plano y 8 métodos para consultar una base de datos. Todo es bueno con moderación y no hay una respuesta correcta clara en casos como este.
Brandon
3
KISS es un concepto difuso, los objetos modificables son fuente de complejidad enormemente subestimados por los desarrolladores, hacen que el manejo de múltiples subprocesos, depuración y excepciones sea mucho más difícil que uno inmutable. O el objeto es válido o se crea una excepción en la construcción (¿qué mejor lugar para atrapar esa excepción?).
Alessandro Teruzzi

Respuestas:

46

Pensando que tenemos que comenzar en alguna parte, me encargué de refactorizar una clase de titular de datos

Aquí es donde salió mal: realizó un cambio arquitectónico importante en la base de código de modo que se volvió muy diferente de lo que se esperaba. Sorprendiste a tus colegas. La sorpresa solo es buena si se trata de una fiesta, el principio de menos sorpresa es dorado (incluso si se trata de fiestas, ¡entonces sabría usar calzoncillos limpios!)

Ahora, si pensabas que este cambio valía la pena, habría sido mucho mejor esbozar el pseudocódigo que muestra el cambio y presentarlo a tus colegas (o al menos a quien tenga el rol más cercano al arquitecto) y ver qué pensaban antes de hacer algo. Tal como está, te volviste pícaro, pensaste que toda la base de código era tuya para jugar como creías conveniente. ¡Un jugador del equipo, no un jugador de equipo!

Puede que sea un poco duro contigo, pero he estado en el lugar opuesto: mira un código y piensa "¡¿WTF sucedió aquí ?!", solo para encontrar que el chico nuevo (casi siempre es el chico nuevo) decidió cambiar un montón de cosas basadas en lo que él piensa que debería ser la "forma correcta". Tornillos con el historial de SCM también, que es otro problema importante.

gbjbaanb
fuente
77
"La sorpresa solo es buena si se trata de una fiesta", ¡ eso no es verdad para todos! Dejaría de hablar con cualquier llamado amigo que me arrojó una sorpresa nada , especialmente un partido . Con la gente . Ugh
Darkhogg
3
Entonces, si cada patrón de refactorización y diseño, o cada decisión como "¿Utilizo el acceso y el mutador aquí o el patrón del constructor?" tiene que ser aprobado por un equipo, ¿cómo se sentirán los desarrolladores facultados para hacer lo correcto? ¿Cómo va a hacer cambios con visión de futuro si todo debe ser diseñado por un comité? He estado en el lugar del OP antes, donde estoy atrapado teniendo que mantener un código sin sentido (como el nuevo) que todos los demás tenían miedo de cambiar porque es consistente . La consistencia es buena y todo, pero no a expensas de la mejora.
Brandon el
11
@ Brandon no, pero todo cambio de gran alcance que los afecte debería hacerlo. Si tiene que corregir un error, es solo otro bit de código, no es gran cosa. Si toma una decisión que afecta a todos los demás, es al menos cortés decirles lo que está haciendo. Puede obtener el acuerdo del equipo para cambiar su código sin sentido, y luego sus cambios se convierten en la nueva consistencia. Solo tienes que hablar con tus colegas. No hay nada malo en decir "voy a cambiar el patrón de acceso horrible que todos odiamos" y escuchar a sus colegas responder con "sí, ya es hora de que alguien se
ocupe de
13
@Brandon hay un dicho: "El camino al infierno está pavimentado con buenas intenciones". La consistencia no solo es buena , ¡es necesaria ! Imagine tratar de administrar un equipo de desarrolladores que administran colectivamente 20 aplicaciones, cada una de las cuales está escrita en un estilo y / o arquitectura diferente porque las preferencias, la tecnología actual, las tendencias, etc., dictaminaron lo que era mejor en ese momento. Lograr que el equipo esté de acuerdo en que algo debería cambiar puede ser la diferencia entre que el nuevo tipo sea aceptado porque resolvieron un problema de larga data y que lo despidan por ser arrogante con lo que creías que era mejor.
DrewJordan
3
@Brandon: si vas a volverse pícaro y arreglar algo "que todos están de acuerdo en que está mal", entonces probablemente tendrías más éxito eligiendo algo que "todos están de acuerdo en que está mal" en lugar de elegir algo que, en el mejor de los casos, tiene diferentes campamentos en el tema; como la inmutabilidad. Un buen diseño / arquitectura hace que la inmutabilidad sea de alto costo prácticamente sin recompensa. Entonces, a menos que su equipo haya tenido problemas porque están usando setters, entonces no estaba solucionando ningún problema. OTOH, si esto ha sido una fuente de errores frecuentes, entonces parece que las ramificaciones justifican una decisión del equipo.
Dunk
21

Por suerte, un compañero de equipo mío estaba trabajando en otro módulo y necesitó los setters, porque los valores que requería estaban disponibles en diferentes puntos del flujo.

Como se describe, no veo qué hace que el código requiera establecedores . Probablemente no sé lo suficiente sobre el caso de uso, pero ¿por qué no esperar hasta que se conozcan todos los parámetros antes de crear una instancia del objeto?

Como alternativa, si la situación requiere establecedores: ofrezca una forma de congelar su código para que los colocadores arrojen un error de aserción (también conocido como error del programador) si intenta modificar los campos después de que el objeto esté listo.

Creo que eliminar los setters y usar final es la forma "adecuada" de hacerlo, así como forzar la inmutabilidad, pero ¿es realmente con lo que deberías pasar tu tiempo?

Consejos generales

Viejo = malo, nuevo = bueno, a mi manera, a tu manera ... este tipo de discusión no es constructiva.

Actualmente, la forma en que se usa su objeto sigue una regla implícita. Esto es parte de la especificación no escrita de su código y su equipo podría pensar que no hay mucho riesgo para otras partes del código de usarlo incorrectamente. Lo que quiere hacer aquí es hacer que la regla sea más explícita con un generador y comprobaciones en tiempo de compilación.

De alguna manera, la refactorización del código está vinculada a la teoría de la Ventana Rota : le parece correcto solucionar cualquier problema tal como lo ve (o tomar nota para alguna reunión posterior de "mejora de la calidad") para que el código siempre parezca agradable de trabajar, Es seguro y limpio. Sin embargo, usted y su equipo no tienen la misma idea sobre lo que es "suficientemente bueno". Lo que ve como una oportunidad para contribuir y mejorar el código, de buena fe, probablemente se ve de manera diferente al equipo existente.

Por cierto, no debe suponerse que su equipo sufre necesariamente de inercia, malos hábitos, falta de educación, ... lo peor que puede hacer es proyectar una imagen de un sabelotodo que esté allí para mostrarles Cómo codificar. Por ejemplo, la inmutabilidad no es algo nuevo , sus pares probablemente lo hayan leído, pero el hecho de que este tema se esté volviendo popular en los blogs no es suficiente para convencerlos de que dediquen tiempo a cambiar su código.

Después de todo, hay infinitas formas de mejorar una base de código existente, pero cuesta tiempo y dinero. Podría mirar tu código, llamarlo "viejo" y encontrar cosas sobre las que jugar. Por ejemplo: sin especificación formal, no hay suficientes afirmaciones, tal vez no hay suficientes comentarios o pruebas, no hay suficiente cobertura de código, algoritmo no óptimo, demasiado uso de memoria, no usa el "mejor" patrón de diseño posible en cada caso, etc. ad nauseam . Pero para la mayoría de los puntos que plantearía, pensarías: está bien, mi código funciona, no hay necesidad de pasar más tiempo en él.

Tal vez su equipo piense que lo que sugiere es más allá del punto de rendimientos decrecientes. Incluso si hubiera encontrado una instancia real de un error debido al tipo de ejemplo que muestra (con la excepción), probablemente solo lo arreglarían una vez y no querrían refactorizar el código.

Entonces, la pregunta es sobre cómo gastar su tiempo y energía, dado que son limitados . Se realizan cambios continuos en el software, pero generalmente su idea comienza con un puntaje negativo hasta que pueda proporcionar buenos argumentos. Incluso si tiene razón sobre el beneficio, no es un argumento suficiente en sí mismo, porque terminará en la canasta "Es bueno tener, un día ... ".

Cuando presenta sus argumentos, debe hacer algunos controles de "cordura": ¿está tratando de vender la idea o usted mismo? ¿Qué pasa si alguien más le presentó esto al equipo? ¿Encontraría algunos defectos en su razonamiento? ¿Está tratando de aplicar alguna práctica recomendada general o tuvo en cuenta los detalles de su código?

Luego, debe asegurarse de no aparecer como si está tratando de corregir los "errores" pasados ​​de su equipo. Ayuda a demostrar que no es su idea, pero puede recibir comentarios razonablemente. Cuanto más lo haga, más oportunidades tendrá de seguir sus sugerencias.

volcado de memoria
fuente
Tienes toda la razón. Una pequeña objeción: no es la "forma antigua" frente a "mi nueva forma nueva y súper increíble". Soy plenamente consciente de que podría estar hablando sin sentido. Mi problema es que si continúo usando prácticas de software que todos en la compañía encuentran horrible, podría estancarme como desarrollador. Por lo tanto, trato de introducir algún cambio, incluso si estoy equivocado. (La tarea se activó por una solicitud para refactorizar una clase relacionada)
rath
@rath ¿No se están desarrollando nuevas bases de código?
biziclop
@biziclop Hay nuevos módulos que se están conectando a la antigua base de código. Trabajé en uno recientemente. Días felices.
rath
55
@rath ¿Quizás necesita un proyecto personal en el que pueda trabajar en su propio tiempo en el que pueda avanzar en su propio desarrollo? Tampoco me convence su argumento de patrón "Constructor"; los captadores / establecedores parecen ser una solución perfectamente correcta basada en la información que ha proporcionado. Recuerde que usted es responsable ante su empleador y su equipo; su prioridad es asegurarse de que cualquier trabajo que realice sea beneficioso para aquellos a quienes debe rendir cuentas.
Ben Cottrell
@rath Bueno, incluso si no está en un código "antiguo / nuevo", lo que importa es cómo lo percibe el receptor, especialmente si tienen más poder de decisión que usted. Parece que quiere introducir cambios por su propio interés y no por el producto que desarrolla. Si todos en la empresa encuentran horrible la práctica, eventualmente cambiará, pero esto no parece ser una prioridad.
coredump
17

¿Cómo puedo promover el uso del patrón Builder en mi equipo?

Usted no

Si su constructor tiene 3 líneas de parámetros, es demasiado grande y complejo. Ningún patrón de diseño lo arreglará.

Si tiene una clase cuyos datos están disponibles en diferentes momentos, deben ser dos objetos diferentes, o su consumidor debe agregar los componentes y luego construir el objeto. No necesitan un constructor para hacer eso.

Telastyn
fuente
Es un gran titular de datos de Stringsy otras primitivas. No hay lógica en ningún lado, ni siquiera verifica si hay nulls, etc. Por lo tanto, es solo tamaño, no complejidad en sí misma. Pensé que hacer algo así builder.addA(a).addB(b); /*...*/ return builder.addC(c).build();sería mucho más fácil a la vista.
rath
8
@rath: es un gran poseedor de datos de cadenas y otras primitivas. => entonces tienes otros problemas, espero que a nadie le importe si el campo de correo electrónico accidental se asigna con la dirección de correo del chico ...
Matthieu M.
@MatthieuM. Un problema a la vez, supongo :)
rath
@rath: seguro que parece que incorporar un buen esquema de verificación de validación hubiera sido mucho más útil y más fácil de recibir que tratar de descubrir cómo descifrar el patrón del generador en el código ya existente. En otro lugar dijiste que querías superarte. Aprender a obtener la ganancia máxima con el menor esfuerzo y consecuencias es definitivamente un atributo que debe desarrollarse.
Dunk
1
Tengo muchísimos constructores con muchos más parámetros que eso. Necesario en los patrones de IoC. Mala generalización en esta respuesta.
djechlin
16

Pareces más concentrado en tener razón que en trabajar bien con los demás. Peor aún, reconoce que lo que está haciendo es una lucha por el poder y, sin embargo, no puede pensar cómo es probable que las personas sientan las cosas cuya experiencia y autoridad desafía.

Invierta eso.

Concéntrese en trabajar con otros. Enmarca tus pensamientos como sugerencias e ideas. Haga que ELLOS hablen de SUS ideas antes de hacer preguntas para que piensen en las suyas. Evite las confrontaciones directas y esté dispuesto a aceptar que continuar haciendo las cosas a la manera del grupo (por ahora) es más productivo que pelear una batalla cuesta arriba para cambiar el grupo. (Aunque traiga las cosas de vuelta.) Haga que trabajar con usted sea una alegría.

Haga esto de manera consistente y debería crear menos conflictos, y ver que otras ideas sean adoptadas por otros. Todos sufrimos la ilusión de que el argumento lógico perfecto sorprenderá a otros y ganará el día. Y si no funciona de esa manera, creemos que debería .

Pero eso está en conflicto directo con la realidad. La mayoría de los argumentos se pierden antes de que se haga el primer punto lógico. Incluso entre personas supuestamente lógicas, la psicología triunfa sobre la razón. Convencer a la gente se trata de superar las barreras psicológicas para ser escuchado adecuadamente, y no de tener una lógica perfecta.

btilly
fuente
2
Frame your thoughts as suggestions and ideas. Get THEM to talk through THEIR ideas before asking questions to make them think about yours+1 para eso, sin embargo
rath
2
@rath Tenga en cuenta que otras personas podrían no estar leyendo su libro. Es posible que la persona que está teniendo la discusión lo considere como una confrontación, lo que podría ser contraproducente para sus objetivos.
Iker
2
@rath: No hay bien o mal. Solo compensaciones. Y la mayoría de las veces, las compensaciones implican más que solo código.
Marjan Venema
1
@Dunk Todo lo que existe son compensaciones. Los llamamos correctos o incorrectos cuando las compensaciones son claras y obviamente de un lado. Sin embargo, reconocer cuándo eso se vuelve ambiguo es más fácil si nos enfocamos en que sean compensaciones desde el principio.
btilly
2
No hay una sola "mejor práctica" de programación que yo sepa que no tenga excepciones donde no sea la mejor. A veces es difícil encontrar esas excepciones, pero siempre existen.
btilly
11

¿Hay otro argumento para usar Builders en lugar de la "vieja forma"?

"Cuando tienes un nuevo martillo, todo se verá como un clavo". - Esto es lo que pensé cuando leí tu pregunta.

Si yo fuera su colega, le preguntaría "¿por qué no inicializar todo el objeto en el constructor?" Eso es lo que es su funcionalidad después de todo. ¿Por qué usar el patrón de construcción (o cualquier otro diseño)?

¿Vale la pena el cambio que propongo?

Es difícil saber de ese pequeño fragmento de código. Tal vez lo sea: usted y sus colegas deben evaluarlo.

¿Tiene algún consejo para presentar mejor tales argumentos cuando aboga por probar algo nuevo?

Sí, aprenda más sobre el tema antes de discutirlo. Ármate con buenos argumentos y razones antes de entrar en la discusión.

BЈовић
fuente
7

He estado en la situación en la que fui reclutado por mis habilidades. Cuando pude ver el código, bueno ... fue más que horrible. Cuando intentas limpiarlo, alguien que ha estado allí por más tiempo siempre suprime los cambios, porque no ven los beneficios. Suena como algo que estás describiendo. Terminó con mi renuncia a ese puesto y ahora puedo evolucionar mucho mejor en una empresa que tiene una mejor práctica.

No creo que debas actuar junto con los demás en el equipo porque han estado allí más tiempo. Si ve que los miembros de su equipo usan malas prácticas en los proyectos en los que trabaja, es una responsabilidad que tenga que señalarlo, como lo ha hecho. Si no, entonces no eres un recurso muy valioso. Si señala las cosas una y otra vez, pero nadie está escuchando, solicite a la gerencia un reemplazo o cambie de trabajo. Es muy importante que no te permitas adaptarte a las malas prácticas.

A la pregunta real

¿Por qué usar objetos inmutables? Porque sabes con lo que estás lidiando.

Supongamos que tiene una conexión de base de datos que se pasa que le permite cambiar el host a través de un configurador, entonces no sabe qué conexión es. Siendo inmutable, entonces lo sabes.

Sin embargo, supongamos que tiene una estructura de datos que puede recuperarse de la persistencia y luego volver a persistir con datos nuevos, entonces tiene sentido que esta estructura no sea inmutable. Es la misma entidad, pero los valores pueden cambiar. En su lugar, utilice objetos de valor inmutable como argumentos.

Sin embargo, en lo que está centrando la pregunta es en un patrón de generador para deshacerse de las dependencias en el constructor. Digo un gran NO gordo a esto. La instancia es obviamente demasiado compleja ya. ¡No intentes ocultarlo, arréglalo!

Tl; dr

Eliminar los setters puede ser correcto, dependiendo de la clase. El patrón de construcción no está resolviendo el problema, solo lo está ocultando. (La suciedad debajo de la alfombra todavía existe incluso si no puedes verla)

superhéroe
fuente
No conozco los detalles de tu situación, pero si entraste y trataste de cambiar todo sin primero ganar la confianza de las personas con tus habilidades o no tomarte el tiempo para aprender "por qué" hacen las cosas como lo hacen, entonces te trataron exactamente como lo tratarían en casi cualquier empresa, incluso en las realmente buenas. En realidad, especialmente en los realmente buenos. Una vez que las personas tienen confianza en las habilidades de alguien, entonces es simplemente una cuestión convincente para sus sugerencias. Si no puede hacer un caso convincente, entonces hay una buena posibilidad de que su sugerencia no sea tan buena.
Dunk
1
No sé qué responder a sus suposiciones @Dunk No estaba tratando de cambiar todo, intenté limpiarlo. Y no fueron las personas las que sabían lo que estaban haciendo, orgullosamente crearon clases y funciones donde cientos de líneas de código, con idk cuántos estados, globales, etc., el nivel estaba más cerca de un jardín de niños más pequeño. Así que mantengo mi declaración. Nunca retrocedas cuando notes que estás en una posición en la que tendrás que adoptar malas prácticas para encajar.
superhéroe
@Dunk Intentar cambiar la forma en que las personas codifican como miembro del equipo no es lo que hago. Pero les digo desde el principio; "No trabajaré en este proyecto sin reescribirlo por completo" , si el código es una basura. Si eso no es apropiado, bueno ... entonces es mutuo. No se trata solo de una comodidad, se trata del hecho de que necesito ser responsable de lo que produzco. No puedo hacer eso si el código circundante en el proyecto es un completo desastre.
superhéroe
No tiene que trabajar "para siempre" con código que sea basura o seguir malas prácticas simplemente porque así es como se está haciendo. Sin embargo, si desea tener éxito en cambiar las cosas, es mejor que pruebe su credibilidad primero como mínimo. Casi todos los desarrolladores piensan que el código que heredan es basura. Si cada compañía acordó con el nuevo tipo cada vez sin siquiera saber su verdadero nivel de habilidad, entonces la basura se convertirá en un tugurio. Además, debe tomarse el tiempo para comprender por qué las cosas se hacen como están. A veces, la forma "incorrecta" es la forma "correcta" para una situación específica.
Dunk
@Dunk Veo que tienes una opinión diferente que yo en este asunto. El tuyo parece ser más popular, si lees las otras respuestas. No estoy de acuerdo, por qué escribí esta respuesta en oposición. Lo que has dicho no ha cambiado de opinión.
superhéroe
2

Si bien todas las demás respuestas son muy útiles (más útiles que las mías), existe una propiedad de los constructores que aún no ha mencionado: al convertir la creación de un objeto en un proceso, puede imponer restricciones lógicas complejas.

Puede ordenar, por ejemplo, que ciertos campos se establezcan juntos o en un orden específico. Incluso puede devolver una implementación diferente del objeto de destino dependiendo de esas decisiones.

// business objects

interface CharRange {
   public char getCharacter();
   public int getFrom();
   public int getTo();
}

class MultiCharRange implements CharRange {
   final char ch;
   final int from;
   final int to;

   public char getCharacter() { return ch; }
   public int getFrom() { return from; }
   public int getTo() { return to; }
}

class SingleCharRange implements CharRange {
   final char ch;
   final int position;

   public char getCharacter() { return ch; }
   public int getFrom() { return position; }
   public int getTo() { return position; }
}

// builders

class Builder1 {
   public Builder2 character(char ch) {
      return new Builder2(ch);
   }
}

class Builder2 {
   final char ch;
   int from;
   int to;

   public Builder2 range(int from, int to) {
      if (from > to) throw new IllegalArgumentException("from > to");
      this.from = from;
      this.to = to;
      return this;
   }

   public Builder2 zeroStartRange(int to) {
      this.from = 0;
      this.to = to;
      return this;
   }

   public CharRange build() {
      if (from == to)
         return new SingleCharRange(ch,from);
      else 
         return new MultiCharRange(ch,from,to);
   }
}

Este es un ejemplo indirecto que no tiene mucho sentido, pero demuestra las tres propiedades: el personaje siempre se establece primero, los límites de rango siempre se establecen y validan juntos, y usted elige su implementación en el momento de la construcción.

Es fácil ver cómo esto puede conducir a un código de usuario más legible y confiable, pero como también puede ver, hay un inconveniente: un montón de código de constructor (e incluso omití los constructores para acortar los fragmentos). Entonces intenta calcular la compensación haciendo preguntas como:

  • ¿Solo instanciamos el objeto de uno o dos lugares? ¿Es probable que esto cambie?
  • ¿Quizás deberíamos imponer estas restricciones refactorizando el objeto original en una composición de objetos más pequeños?
  • ¿Terminaríamos pasando el constructor de un método a otro?
  • ¿Podríamos usar un método de fábrica estático en su lugar?
  • ¿Es esto parte de una API externa, que debe ser tan infalible y hábil como sea posible?
  • Aproximadamente, ¿cuántos de nuestros retrasos actuales de errores podrían haberse evitado si tuviéramos constructores?
  • ¿Cuánta escritura de documentación adicional ahorraríamos?

Sus colegas simplemente decidieron que la compensación no sería beneficiosa. Debes discutir las razones de manera abierta y honesta, preferiblemente sin recurrir a principios abstractos, sino concentrándote en las implicaciones prácticas de esta solución o aquella.

biziclop
fuente
1
Al convertir la creación de un objeto en un proceso, puede imponer restricciones lógicas complejas. BAM Y todo lo que esto implica sobre la complejidad cuando se organiza en pasos más pequeños, discretos y simples .
radarbob
2

Parece que esta clase es en realidad más de una clase, juntas en la misma definición de archivo / clase. Si es un DTO, entonces debería ser posible instanciarlo de una vez y que sea inmutable. Si no utiliza todos sus campos / propiedades en ninguna transacción, es casi seguro que está rompiendo el principio de Responsabilidad Única. Podría ser que dividirlo en clases DTO más pequeñas, más coherentes e inmutables podría ayudar. Considere leer Clean Code si aún no lo ha hecho para poder articular mejor los problemas y los beneficios de hacer un cambio.

No creo que pueda diseñar código a este nivel por comité, a menos que esté literalmente programando en la mafia (no parece que esté en ese tipo de equipo), así que creo que está bien hacer un cambio basado en su mejor juicio, y luego tómalo en la barbilla si resulta que lo juzgaste mal.

Sin embargo, siempre que pueda articular los posibles problemas con el código tal como está, aún puede debatir que se requiere una solución , incluso si la suya no es la aceptada. Las personas son libres de ofrecer alternativas.

" Las opiniones fuertes, las opiniones débiles " es un buen principio: sigue adelante con confianza en función de lo que sabe, pero si encuentra alguna información nueva que lo contrarreste, sea modesto, renuncie y entre en una discusión sobre cuál debería ser la solución correcta ser. La única respuesta incorrecta es dejar que empeore.

Neil Barnwell
fuente
Definitivamente no es un diseño del comité, que es parte de la razón por la cual el código apesta tanto. Demasiado de algo bueno, supongo. Que es un DTO pero no voy a romper en pedazos; Si el código base es malo, la base de datos es mucho, mucho peor. +1 (principalmente) para el último párrafo.
rath