oop - segregation - solid principles examples
Usando el Principio de Responsabilidad Individual en el "mundo real" (9)
Básicamente quiero tener una idea del porcentaje de personas que piensan que es razonable usar el Principio de Responsabilidad Individual en el código del mundo real y cuántos realmente lo hacen. En Podcast # 38, Joel habla de cuán inútil es este principio de OOP en el mundo real; y además, esto demuestra que personas como Tío Bob probablemente no hayan escrito sistemas no triviales.
Personalmente, escribí o jugué un papel importante en algunos proyectos de software, pero ahora solo conozco este patrón en mi joven carrera. Me encanta el sonido de este principio y realmente me gustaría comenzar a usarlo. Encontré el argumento de Joel en el podcast bastante débil (como hicieron otros si continúas leyendo los comentarios del blog aquí ). Pero, ¿hay algo de verdad en eso?
¿Qué piensa la comunidad?
Creo que debería ser posible escribir una responsabilidad principal simple de una sola línea para todas las clases. La palabra "y" en este delineador no suele ser una buena señal. La responsabilidad individual a menudo se reduce a seleccionar la abstracción adecuada.
Las GUI cercanas a las clases tienden a reflejar GUI y tienen la responsabilidad única de "ser gui para XXXX". La solución de Coward ...
Creo que los mayores beneficios de ser un desarrollador disciplinado de OO y adherirme al SRP siempre que sea posible son fáciles de probar y mantener, por lo que diría que SRP es un buen objetivo para cualquier sistema que vaya a ser probado / mantenido (básicamente, cualquier cosa menos una sistema desechable).
El mayor problema con algunas de las muchas teorías de programación que existen es que se centran en sugerir que los buenos atributos en el código son, de hecho, buenos atributos para el código. Tienen razón porque son intrínsecamente correctos, y por lo tanto no son particularmente útiles.
Sí, el código debe estar bien escrito, y sí, las cosas no deben repetirse horriblemente, y sí, los cambios no deberían causar extraños descansos en lugares inesperados. Pero, al final del día, un código realmente simple y consistente que expresa la solución de una manera simple y fácilmente comprensible vale mucho más que un gran sistema complejo que cumple con algunos principios rigurosos. Como industria, tendemos a llevar las buenas ideas demasiado lejos, creando masas de complejidad innecesaria en la búsqueda de la solución "correcta", no la mejor.
Pablo.
En general, estoy de acuerdo con los principios SÓLIDOS, pero también debe tenerlos en contexto. Si está escribiendo una Prueba de concepto, entonces los principios SÓLIDOS son menos aplicables.
Por otro lado, si está desarrollando un producto con una vida que abarcará años, entonces es mejor que mire cuidadosamente los principios SÓLIDOS y los aplique. De lo contrario, va a costarle a la empresa toneladas de dinero en productividad.
En lo que respecta a Joel y sus comentarios, tiene un punto válido. A veces, el producto debe enviarse o la empresa falla. Esa es la forma como es.
Como desarrollador, es su responsabilidad enviar el producto, pero el hecho de que el plazo sea ajustado no significa que tenga una arquitectura deficiente. Opciones como usar datasets o entidades comerciales es una decisión simple y ambas tienen esfuerzos de implementación similares, pero a largo plazo el desarrollo y mantenimiento de nuevas características entre los dos es drástico.
En la práctica, es muy difícil obtener un verdadero SRP en situaciones de OO. Considere una clase que existe en un sistema complicado. Probablemente solo tenga una responsabilidad orientada a los negocios (como imprimir un informe), pero tendrá muchas otras responsabilidades internas que violan ideales puros de SRP, como el registro y el manejo de excepciones. Si cambia significativamente su mecanismo de registro, probablemente necesite cambiar las llamadas que realiza su clase de impresión.
Es por eso que AOP fue concebido. Utilizándolo no tiene que cambiar nada más que las clases de registro para cambiar el registro.
Es bueno esforzarse por un SRP orientado a los negocios por razones obvias, pero para sistemas lo suficientemente complicados nunca obtendrás un verdadero SRP en OOP. AOP, claro, pero no OOP.
No tengo idea si ese es el razonamiento de Joel, pero así es como abordaría la idea.
Estoy trabajando en un proyecto que hace muchas cosas diferentes, horriblemente complejas, en un marco que se supone que es fácilmente extensible por otros.
Al principio, las clases eran grandes e hicieron muchas cosas. Para cambiar esos comportamientos, tenías que extender esas clases. Los métodos eran todos virtuales y no cambiaban el estado del objeto, por lo que era bastante fácil hacer esto.
Pero a medida que el sistema creció, se hizo más claro que el marco iba a terminar con una serie de objetos monolíticos, cada uno con muchísimas cadenas de herencia. Esto también dio lugar a dependencias inesperadas: un método abstracto que tomaba una colección de la clase X para producir el objeto Y definido en una clase base dictaba que TODOS tenían que hacerlo de esta manera, incluso cuando no tenía sentido para la mitad del árbol de herencia. Esto también dio lugar a clases masivas que requirieron decenas de pruebas unitarias para obtener una cobertura del código superior al 80%, y la complejidad era tal que no estaba seguro de haber cubierto todo correctamente. Era obvio que este diseño haría que el marco fuera muy rígido e inflexible.
Así que rediseñamos todo a lo largo de las líneas SRP. Tendría su interfaz, una clase base y, posiblemente, una o más clases de implementación. Cada uno estaba compuesto por diferentes objetos que realizaban funciones clave del proceso general. Si quería cambiar una parte, no anulaba un método, producía otro objeto que ampliaba la clase de interfaz / base necesaria y realizaba su trabajo de manera diferente. SRP incluso se tomó en los argumentos y los valores de retorno de los métodos de clase. Para aquellas partes del sistema que necesitaban ser flexibles, en lugar de pasar colecciones de clase X que se utilizan para producir objetos Y, se creó una clase para encapsular el proceso de producción de objetos Y. Los componentes en el sistema pasarían a estos productores, los combinarían con otros (la responsabilidad de los productores) y eventualmente los usarían para producir Y. Esto permitió la creación de diferentes tipos de productores, todos los cuales podrían tratarse exactamente lo mismo, a pesar de que hicieron cosas muy diferentes. El movimiento también redujo drásticamente la base de códigos de cada clase y los hizo MUCHO más fáciles de probar.
Diría que, como nuevo desarrollador, es MUY DIFÍCIL dividir todo en este nivel. Casi tiene que escribir una gran bola de barro, entender cómo funciona y luego rediseñarla como varios componentes diferentes, cada uno de los cuales asume la responsabilidad de una parte del todo.
He tenido cierta experiencia aplicando principios SÓLIDOS y mi experiencia ha sido principalmente buena. También escuché el podcast y parece que ni Jeff ni Joel han intentado alguna de las cosas de las que están hablando el tiempo suficiente para realmente evaluar los beneficios. El principal argumento en contra es que usualmente "escribes más código". Si miro lo que hago, escribo 10 quizás un 20% más de código (generalmente definiciones de interfaz), pero como todo está muy desacoplado, es mucho más fácil de mantener. Casi nunca tengo situaciones donde los cambios en una parte de mi aplicación rompen otras partes. Entonces el 20% de código adicional que tengo que mantener se paga solo.
Jeff también perdió el punto sobre la calidad del código. Él no ve la calidad del código como un gran beneficio para el cliente. Y tiene razón, al cliente no le importa. Al cliente le importa tener nuevas características implementadas rápidamente y ahí es donde entra la calidad del código. He descubierto que la inversión de mantener la calidad del código lo más alto posible siempre se ha amortizado en unos pocos meses. Alta calidad = bajo mantenimiento.
Estoy de acuerdo con ellos en que, como todo lo demás, debes ser pragmático en estas cosas. Si necesita entregar algo, adelante, hágalo rápido y sucio. Pero limpia después.
No he leído ni he escuchado los comentarios de Joel, así que no puedo comentar sobre ellos específicamente.
Creo que hay que mirar el principio de responsabilidad única en términos de un objetivo, en lugar de un requisito estricto. Como ocurre con muchas cosas en el desarrollo de software, hay ideales por los que se debe luchar pero, a menos que su código no tenga un beneficio o costo monetario, debe ser pragmático al atender las necesidades de sus clientes.
Creo que los principios SÓLIDOS a veces no cumplen con la lógica natural / comercial que generalmente se aplica al diseñar clases. Robert C. Martin sacó un ejemplo de las clases Rectange y Square (Square no debería ser un descendiente de Rectangle).
http://www.hanselminutes.com/default.aspx?showID=163
No estoy seguro de que se tratara de SRP, pero la idea es la misma. Los principios SÓLIDOS pueden conducir a decisiones contra intuitivas y es difícil superar esta barrera.
Para mí, ''pautas'' es un nombre más apropiado que ''principios''.