udemy solid software single responsibility principios patrones mega ejemplos ejemplo diseño c# design-patterns solid-principles

c# - software - solid php



Cómo implementar los principios de SOLID en un proyecto existente (4)

Hay un libro clásico de Martin Fowler - Refactorización: Mejorando el diseño de código existente.

Allí proporciona un conjunto de técnicas de diseño y ejemplos de decisiones para hacer que su base de código existente sea más manejable y mantenible (y de eso se trata todo sobre los directores de SOLID). Aunque hay algunas rutinas estándar en la refactorización, es un proceso muy personalizado y no se pudo aplicar una solución a todos los proyectos.

La prueba de unidad es uno de los pilares de la esquina para que este proceso tenga éxito. Es necesario que cubra su base de código existente con suficiente cobertura de código para que esté seguro de no romper cosas al cambiarlo. En realidad, el uso de un moderno marco de pruebas de unidad con soporte de burla lo animará a diseñar mejor.

Hay herramientas como ReSharper (mi favorito) y CodeRush para ayudar con los tediosos cambios de código. Pero esos son generalmente cosas mecánicas triviales, tomar decisiones de diseño es un proceso mucho más complejo y no hay tanto soporte de herramientas. Usando diagramas de clase y UML ayuda. De eso sería de lo que yo partiría. Trate de darle sentido a lo que ya está allí y dale algo de estructura. Luego, desde allí puede tomar decisiones sobre la descomposición y las relaciones entre diferentes componentes y cambiar su código en consecuencia.

Espero que esto ayude y feliz refactorización!

Pido disculpas por la subjetividad de esta pregunta, pero estoy un poco atascado y agradecería alguna orientación y consejo de cualquiera que haya tenido que lidiar con este problema antes:

Tengo (en lo que se ha convertido) un gran proyecto de API REST escrito en C # 2.0 y algunas de mis clases se han vuelto monstruosas. Mi clase principal de API es un ejemplo de esto: con varias docenas de miembros y métodos (probablemente se aproximan a cientos). Como puede imaginar, se está convirtiendo en una pequeña pesadilla, no solo para mantener este código, sino que simplemente navegar por el código se ha convertido en una tarea rutinaria.

Soy razonablemente nuevo en los principios SOLID y soy un fanático de los patrones de diseño (pero todavía estoy en esa etapa en la que puedo implementarlos , pero no lo suficiente como para saber cuándo usarlos , en situaciones en las que no es tan obvio) .

Necesito dividir mis clases en tamaño, pero no sé cuál es la mejor manera de hacerlo. ¿Pueden mis colegas de StackOverflow sugerir formas en que hayan tomado los monolitos de códigos existentes y los hayan reducido a tamaño?


Lo que hice cuando se me presentó este tipo de cosas (y admitiré fácilmente que no he usado los principios de SOLID antes, pero por lo poco que sé de ellos, suenan bien) es mirar el código base existente de Un punto de vista de conectividad. Esencialmente, al observar el sistema, debería poder encontrar algún subconjunto de funcionalidades que estén altamente acopladas internamente (muchas interacciones frecuentes) pero acopladas externamente de manera flexible (pocas interacciones poco frecuentes). Por lo general, hay algunas de estas piezas en cualquier base de código grande; Son candidatos a la escisión. Esencialmente, una vez que haya identificado a sus candidatos, tiene que enumerar los puntos en los que están acoplados externamente al sistema en su conjunto. Esto debería darle una buena idea del nivel de interdependencia involucrado. Generalmente hay un poco de interdependencia involucrada. Evaluar los subconjuntos y sus puntos de conexión para refactorización; Con frecuencia (pero no siempre) termina siendo un par de refactorizaciones estructurales claras que pueden aumentar el desacoplamiento. Con un ojo en esas refactorizaciones, use los acoplamientos existentes para definir la interfaz mínima requerida para permitir que el subsistema funcione con el resto del sistema. Busque puntos en común en esas interfaces (con frecuencia, encontrará más de lo que usted esperaría). Y por último, implementa estos cambios que has identificado.

El proceso suena terrible, pero en la práctica, en realidad es bastante sencillo. Tenga en cuenta que esta no es una hoja de ruta para llegar a un sistema completamente diseñado (para eso, debe comenzar desde cero), pero sin duda disminuirá la complejidad del sistema en su conjunto y aumentará la comprensibilidad del código.


Será un proceso lento. Debe leer el código e identificar las partes que no cumplen con los principios de SOLID y refactorizar en nuevas clases. El uso de un complemento de VS como Resharper ( http://www.jetbrains.com ) ayudará con el proceso de refactorización.

Idealmente, tendrá una buena cobertura de pruebas unitarias automatizadas para que pueda asegurarse de que sus cambios no presenten problemas con el código.

Más información

En la clase de API principal, debe identificar los métodos que se relacionan entre sí y crear una clase que represente más específicamente qué acciones realiza el método.

p.ej

Digamos que tuve una clase de dirección con variables separadas que contienen el número de la calle, el nombre, etc. Esta clase es responsable de insertar, actualizar, eliminar, etc. Si también tuviera que formatear una dirección de una manera específica para una dirección postal, podría haber un método llamado GetFormattedPostalAddress () que devolvió la dirección formateada.

Alternativamente, podría refactorizar este método en una clase llamada AddressFormatter que toma una dirección en su constructor y tiene una propiedad Get llamada PostalAddress que devuelve la dirección formateada.

La idea es separar diferentes responsabilidades en clases separadas.


Principio de responsabilidad única : una clase debe tener solo una razón para cambiar. Si tienes una clase monolítica, entonces probablemente tenga más de una razón para cambiar. Simplemente defina su única razón para cambiar y sea tan granular como sea razonable . Sugeriría comenzar "grande". Refactoriza un tercio del código en otra clase. Una vez que tengas eso, entonces vuelve a comenzar con tu nueva clase. Ir directamente de una clase a 20 es demasiado desalentador.

Principio abierto / cerrado : una clase debe estar abierta para la extensión, pero cerrada para el cambio. Cuando sea razonable, marque sus miembros y métodos como virtuales o abstractos. Cada elemento debe ser de naturaleza relativamente pequeña y ofrecerle alguna funcionalidad básica o definición de comportamiento. Sin embargo, si necesita cambiar la funcionalidad más adelante, podrá agregar código, en lugar de cambiarlo para introducir una funcionalidad nueva / diferente.

Principio de sustitución de Liskov : una clase debe ser sustituible por su clase base. La clave aquí, en mi opinión, es hacer correctamente la herencia. Si tiene una declaración de caso enorme, o dos páginas de declaraciones if que verifican el tipo derivado del objeto, entonces está violando este principio y necesita repensar su enfoque.

Principio de segregación de la interfaz : en mi opinión, este principio se parece mucho al principio de responsabilidad única. Solo se aplica específicamente a una clase / interfaz de alto nivel (o madura). Una forma de usar este principio en una clase grande es hacer que su clase implemente una interfaz vacía . A continuación, cambie todos los tipos que usan su clase para que sean el tipo de la interfaz. Esto romperá su código. Sin embargo, señalará exactamente cómo está consumiendo su clase. Si tiene tres instancias en las que cada una utiliza su propio subconjunto de métodos y propiedades, ahora sabe que necesita tres interfaces diferentes. Cada interfaz representa un conjunto colectivo de funcionalidades y una razón para cambiar.

Principio de inversión de dependencia : la alegoría padre / hijo me hizo entender esto. Piensa en una clase de padres. Define el comportamiento, pero no se preocupa por los detalles sucios. Es confiable. Una clase infantil, sin embargo, tiene que ver con los detalles, y no se puede depender porque cambia con frecuencia. Siempre desea depender de los padres, las clases responsables y nunca al revés. Si tiene una clase para padres que depende de una clase para niños, obtendrá un comportamiento inesperado cuando cambie algo. En mi opinión, esta es la misma mentalidad de SOA. Un contrato de servicio define entradas, salidas y comportamiento, sin detalles.

Por supuesto, mis opiniones y entendimientos pueden ser incompletos o incorrectos. Sugeriría aprender de personas que hayan dominado estos principios, como el tío Bob. Un buen punto de partida para mí fue su libro, Principios, patrones y prácticas ágiles en C # . Otro buen recurso fue el tío Bob en Hanselminutes .

Por supuesto, como Joel y Jeff señalaron , estos son principios, no reglas. Deben ser herramientas para ayudarlo a guiarlo, no la ley de la tierra.

EDITAR:

Acabo de encontrar estos screencast SOLID que parecen realmente interesantes. Cada uno es de aproximadamente 10-15 minutos de duración.