Clean Code & SOLID Flashcards

1
Q

¿Cuáles son los objetivos principales del diseño de código?

A
  • Mantenibilidad,
  • simplicidad,
  • claridad,
  • flexibilidad y
  • legibilidad.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Nombres: ¿Cómo tienen que ser?

A

Significativos y pronunciables

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

¿Qué deben revelar los nombres?

A

La intención

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

¿Por qué se deben evitar valores fijos en el código?

A

Los valores fijos no son buscables, es preferible usar constantes con nombres claros.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

¿Qué principio sigue el enfoque de usar polimorfismo en lugar de banderas (flags)?

A

Principio de responsabilidad única, ya que separa las condiciones en funciones específicas en lugar de manejar múltiples casos en una sola función.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

¿Qué significa el principio DRY?

A

“Don’t Repeat Yourself”, es decir, evitar la duplicación de código.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

¿Qué dice la “Regla del Boy Scout” en el desarrollo de software?

A

Deja el código en mejor estado del que lo encontraste, siempre mejorando aunque sea un poco.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

¿Qué significa el “Principio de la menor sorpresa”?

A

El código debe comportarse de manera que sea intuitivo y no sorprenda a quienes lo leen o lo mantienen.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

¿Qué tipo de comentarios son buenos?

A

Comentarios legales, informativos, que expliquen la intención o clarifiquen el código, advertencias de consecuencias, y comentarios TODO.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

¿Qué significa el acrónimo F.I.R.S.T. en pruebas unitarias?

A

Fast, Independent, Repeatable, Self-Validating, Timely.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

¿Qué principios se deben seguir al escribir casos de prueba?

A

Prueba una sola cosa por caso de prueba, usa un único método de assert, y utiliza nombres descriptivos.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q
A
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

¿Cuál es el principio de “Single Responsibility”?

A

Una función o clase debe tener una única responsabilidad o propósito.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

¿Cuál es el beneficio principal del “Single Responsibility Principle”?

A

Facilita el mantenimiento y reduce el acoplamiento al tener clases enfocadas en un solo propósito.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

¿En qué consiste el “Open/Closed Principle” (OCP)?

A

Las clases deben estar abiertas para extensión, pero cerradas para modificación.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

¿Cómo se puede cumplir con el “Open/Closed Principle”?

A

Mediante el uso de abstracciones, como interfaces o clases base, que permiten extender el comportamiento sin modificar el código existente.

17
Q

¿En qué consiste el “Liskov Substitution Principle” (LSP)?

A

Los objetos de una subclase deben poder reemplazar a los de su clase base sin alterar el correcto funcionamiento del programa.

18
Q

¿Qué problemas se pueden evitar aplicando el “Liskov Substitution Principle”?

A

Evita violaciones en el comportamiento esperado del programa cuando se utilizan subclases, asegurando la compatibilidad.

19
Q

¿En qué consiste el “Interface Segregation Principle” (ISP)?

A

Los clientes no deberían estar forzados a depender de interfaces que no utilizan. Es preferible tener interfaces específicas y pequeñas.

20
Q

¿Cómo ayuda el “Interface Segregation Principle” en el diseño de software?

A

Minimiza el acoplamiento al permitir que las clases dependan solo de los métodos que realmente necesitan, evitando la implementación de métodos innecesarios.

21
Q

¿En qué consiste el “Dependency Inversion Principle” (DIP)?

A

Los módulos de alto nivel no deben depender de los de bajo nivel. Ambos deben depender de abstracciones (interfaces o clases abstractas), y las abstracciones no deben depender de detalles.

22
Q

¿Qué principio se aplica?
Antes:

public class Reporte {
    public String generarReporte() {
        // Generar contenido del reporte
        return "Contenido del reporte";
    }

    public void imprimirReporte() {
        // Imprimir el reporte en consola
        System.out.println(generarReporte());
    }
}

Despues:

// Clase responsable solo de generar el contenido del reporte
public class Reporte {
    public String generarReporte() {
        return "Contenido del reporte";
    }
}

// Clase responsable solo de imprimir el reporte
public class ImpresoraReporte {
    public void imprimir(String contenidoReporte) {
        System.out.println(contenidoReporte);
    }
}
A

Single Responsability Principle

23
Q

¿Qué principio se aplica?
Antes:

public class CalculadoraDeArea {

    public double calcularArea(Object forma) {
        if (forma instanceof Circulo) {
            Circulo circulo = (Circulo) forma;
            return Math.PI * circulo.radio * circulo.radio;
        } else if (forma instanceof Rectangulo) {
            Rectangulo rectangulo = (Rectangulo) forma;
            return rectangulo.ancho * rectangulo.alto;
        }
        return 0;
    }
}

class Circulo {
    public double radio;
}

class Rectangulo {
    public double ancho;
    public double alto;
}

Despues:

// Interfaz que define un contrato para las formas
public interface Forma {
    double calcularArea();
}

// Implementación de un Círculo que calcula su propia área
public class Circulo implements Forma {
    public double radio;

    @Override
    public double calcularArea() {
        return Math.PI * radio * radio;
    }
}

// Implementación de un Rectángulo que calcula su propia área
public class Rectangulo implements Forma {
    public double ancho;
    public double alto;

    @Override
    public double calcularArea() {
        return ancho * alto;
    }
}

// Calculadora de área que no necesita ser modificada
public class CalculadoraDeArea {
    public double calcularArea(Forma forma) {
        return forma.calcularArea();
    }
}
A

Open/Closed principle.

Podemos usar polimorfismo. Creamos una interfaz para las formas geométricas y cada nueva forma implementa su propio método para calcular el área. De esta forma, podemos añadir nuevas formas sin modificar la clase CalculadoraDeArea.

24
Q

¿Qué principio se aplica?
Antes:

class Rectangulo {
    protected int ancho;
    protected int alto;

    public void setAncho(int ancho) { this.ancho = ancho; }
    public void setAlto(int alto) { this.alto = alto; }

    public int getArea() { return ancho * alto; }
}

class Cuadrado extends Rectangulo {
    @Override
    public void setAncho(int ancho) {
        this.ancho = ancho;
        this.alto = ancho;  // Fuerza a que alto sea igual a ancho
    }

    @Override
    public void setAlto(int alto) {
        this.ancho = alto;
        this.alto = alto;  // Fuerza a que ancho sea igual a alto
    }
}

Despues:

class Rectangulo {
    protected int ancho;
    protected int alto;

    public void setAncho(int ancho) { this.ancho = ancho; }
    public void setAlto(int alto) { this.alto = alto; }

    public int getArea() { return ancho * alto; }
}

class Cuadrado {
    private int lado;

    public void setLado(int lado) { this.lado = lado; }

    public int getArea() { return lado * lado; }
}
A

Principio de Sustitución de Liskov. Si se sustituyera un Rectangulo por un Cuadrado, el comportamiento sería inesperado. El comportamiento del Cuadrado rompe las expectativas de la clase base Rectangulo porque cambia las reglas del rectángulo (ancho ≠ alto).

Luego del cambio, Cuadrado y Rectangulo tienen comportamientos coherentes sin romper el principio de sustitución. Se puede tratar a cada clase de acuerdo a su naturaleza sin sorpresas inesperadas.

25
Q

¿Qué principio se aplica?

// Clase de bajo nivel que envía correos electrónicos
public class NotificadorEmail {
    public void enviarCorreo(String mensaje) {
        // Lógica para enviar un correo electrónico
        System.out.println("Enviando correo: " + mensaje);
    }
}

// Clase de alto nivel que utiliza NotificadorEmail para enviar notificaciones
public class UsuarioServicio {
    private NotificadorEmail notificadorEmail;

    public UsuarioServicio() {
        this.notificadorEmail = new NotificadorEmail();
    }

    public void notificarUsuario(String mensaje) {
        notificadorEmail.enviarCorreo(mensaje);
    }
}

Aplicado:

// Interfaz que define el contrato para la notificación
public interface Notificador {
    void notificar(String mensaje);
}

// Clase de bajo nivel que implementa la interfaz para enviar correos electrónicos
public class NotificadorEmail implements Notificador {
    @Override
    public void notificar(String mensaje) {
        System.out.println("Enviando correo: " + mensaje);
    }
}

// Nueva clase de bajo nivel que implementa la interfaz para enviar SMS
public class NotificadorSMS implements Notificador {
    @Override
    public void notificar(String mensaje) {
        System.out.println("Enviando SMS: " + mensaje);
    }
}

// Clase de alto nivel que depende de la abstracción (Notificador) y no de la implementación concreta
public class UsuarioServicio {
    private Notificador notificador;

    public UsuarioServicio(Notificador notificador) {
        this.notificador = notificador;
    }

    public void notificarUsuario(String mensaje) {
        notificador.notificar(mensaje);
    }
}
A

Principio de Inversión de Dependencias (DIP) o Dependency Inversion Principle.

26
Q

¿Qué principio se aplica?
Antes:

class Servicio {
    public void ejecutar() {
        // Lógica de servicio
    }
}

class Controlador {
    private Servicio servicio = new Servicio();

    public void hacerAlgo() {
        servicio.ejecutar();
    }
}

Despues:

interface IServicio {
    void ejecutar();
}

class Servicio implements IServicio {
    public void ejecutar() {
        // Lógica de servicio
    }
}

class Controlador {
    private IServicio servicio;

    public Controlador(IServicio servicio) {
        this.servicio = servicio;
    }

    public void hacerAlgo() {
        servicio.ejecutar();
    }
}
A

Principio de Inversión de Dependencias. Antes, Controlador está acoplado directamente a Servicio, dificultando pruebas y la posibilidad de cambiar la implementación de Servicio.
Ahora, Controlador depende de la interfaz IServicio, lo que permite inyectar diferentes implementaciones de Servicio y facilita las pruebas. Esto reduce el acoplamiento y mejora la flexibilidad.