Principio de responsabilidad única - Una clase solo debe tener un motivo para cambiar. Si tienes una clase monolítica, probablemente tenga más de un motivo para cambiar. Simplemente defina su único motivo para cambiar, y sea tan granular como razonable. Sugeriría comenzar "grande". Refactorizar un tercio del código en otra clase. Una vez que tenga eso, vuelva a comenzar con su nueva clase. Pasar directamente de una clase a 20 es demasiado desalentador.
Principio abierto/cerrado - Una clase debe estar abierta para extensión, pero cerrada para cambios. Donde sea razonable, marque sus miembros y métodos como virtuales o abstractos. Cada ítem debe ser relativamente pequeño por naturaleza y darle una funcionalidad básica o una definición de comportamiento. Sin embargo, si necesita cambiar la funcionalidad más tarde, podrá agregar el código, en lugar de cambiar el código para introducir funcionalidades nuevas/diferentes.
Liskov Substitution Principio - Una clase debe ser sustituible por su clase base. La clave aquí, en mi opinión, es hacer la herencia correctamente. Si tiene una gran declaración de caso, o dos páginas de declaraciones if que verifican el tipo derivado del objeto, entonces está violando este principio y necesita replantearse su enfoque.
Interface Segregation Principle - 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 utilizar este principio en una clase grande es hacer que su clase implemente una interfaz vacía. Luego, cambie todos los tipos que usan su clase para que sean del tipo de la interfaz. Esto romperá tu código. Sin embargo, señalará exactamente cómo está consumiendo su clase. Si tiene tres instancias en las que cada una usa su propio subconjunto de métodos y propiedades, entonces ahora sabe que necesita tres interfaces diferentes. Cada interfaz representa un conjunto colectivo de funcionalidades y una razón para cambiar.
Dependency Inversion Principio - La alegoría de padres/hijos me hizo entender esto. Piensa en una clase para padres. Define el comportamiento, pero no se preocupa por los detalles sucios. Es confiable. Sin embargo, una clase para niños tiene que ver con los detalles y no se puede depender de ella porque cambia con frecuencia. Siempre quiere depender de los padres, las clases responsables y nunca a la inversa. Si tienes una clase para padres dependiendo de una clase para niños, obtendrás un comportamiento inesperado cuando cambies 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 dominan estos principios, como el tío Bob. Un buen punto de partida para mí fue su libro, Agile Principles, Patterns, and Practices in C#.Otro buen recurso fue Uncle Bob on Hanselminutes. Por ejemplo, como Joel and Jeff pointed out, estos son principios, no reglas. Deben ser herramientas para guiarte, no la ley de la tierra.
EDIT:
Acabo de encontrar estas SOLID screencasts la que se ven realmente interesante. Cada uno tiene aproximadamente 10-15 minutos de duración.
Soy un gran admirador de Resharper, y lo he usado durante mucho tiempo, y tengo cierta cobertura de prueba de unidad, pero no lo suficiente. ¿Hay algo más específico para pensar al hacer el refactor? – Ash