Principios de refactorización "Refactorización para mejorar el diseño del código 1 existente"

Prefacio

Refactorizando el diseño del código existente, un libro sagrado clásico, comencé hace dos años, leí hace medio año, y se siente regular, a partir de hoy, léelo de nuevo, ¡espero que haya una cosecha diferente!

/**
* @startTime 2020-12-16 23:22
* @endTime 2020-12-16 23:59
* @startPage 1 
* @endPage 55
* @efficiency 56/1 = 56页/天
* @needDays 412/56 = 7天
* @overDay 2020-12-16 + 7天 = 2020-12-22 
*/

Capítulo 1. Refactorización, el primer caso

La llamada refactorización consiste en modificar el código sin cambiar el comportamiento externo del código para mejorar la estructura interna del programa. La refactorización es un método de acabado de programa ordenado formado a través del trabajo duro, que puede minimizar la posibilidad de introducir errores en el proceso de acabado. Básicamente, la refactorización consiste en mejorar el diseño del código después de escribirlo.

Cualquier tonto puede escribir código que una computadora pueda entender, y solo un código que los humanos puedan entender es un excelente programador.

Capítulo 2 Principios de refactorización

1. Qué es la refactorización

Un ajuste a la estructura interna del software, el propósito es mejorar la comprensibilidad y reducir el costo de modificación sin cambiar el comportamiento observable del software.

El propósito de la refactorización es hacer que el software sea más fácil de entender y modificar.

Cuanto más difícil es ver la intención del diseño del código, más difícil es proteger el diseño. La refactorización frecuente puede ayudar al código a mantener su forma correcta. Para lograr lo mismo, los programas mal diseñados a menudo requieren más código, debido a que el código usa exactamente las mismas declaraciones en diferentes lugares para hacer lo mismo. Por lo tanto, una dirección importante para mejorar el diseño es eliminar el código duplicado. La importancia de esta acción es facilitar modificaciones futuras. Reducir la cantidad de código no hace que el sistema se ejecute más rápido, porque casi no tiene un impacto obvio en la pista en ejecución del programa. Sin embargo, la reducción de la cantidad de código facilitará las modificaciones futuras del programa.

/**
* @startTime 2020-12-17 22:00
* @endTime 2020-12-17 22:50
* @startPage 56 
* @endPage 64
* @efficiency 64/2 = 32页/天
* @needDays 412/32 = 13天
* @overDay 2020-12-16 + 13天 = 2020-12-29 
*/

2. La refactorización facilita la comprensión del software

Facilite la comprensión de los revisores y facilite que la siguiente persona se haga cargo de su código. Quizás la próxima persona que se haga cargo de su código sea usted mismo. A veces, puedes tomar un fragmento de código y escribirlo tú mismo. No puedes estar seguro, ¿verdad?

  • Beneficios de la refactorización
  • Refactorización para ayudar a encontrar errores
  • Refactorización para mejorar la velocidad de programación

3. Momento de la reconstrucción

  • Tres cosas, tres reconstrucciones
  • Refactorizar al agregar características
  • Refactorizar al corregir errores
  • Refactorizar al revisar el código

4. Por qué es útil la refactorización

  1. Programas que son difíciles de leer y difíciles de modificar;
  2. Procedimientos lógicamente repetidos, difíciles de modificar;
  3. Al agregar un nuevo comportamiento, es necesario modificar el programa del código existente, que es difícil de modificar;
  4. Los programas con lógica condicional compleja son difíciles de modificar;

Por tanto, esperamos que el programa:

  1. Fácil de leer
  2. Toda la lógica solo se especifica en una ubicación única;
  3. Los nuevos cambios no pondrán en peligro el comportamiento existente;
  4. Exprese la lógica condicional lo más simple posible;

Capa indirecta y refactorización

El valor de la capa indirecta:

  1. Permitir el intercambio de lógica;
  2. Explicación separada de intención y realización;
  3. Aislar cambios;
  4. Encapsular la lógica condicional;

5. El problema de la reconstrucción

(1) Base de datos

migración de datos

(2) Modificar la interfaz

No publique la interfaz demasiado pronto, modifique la política de propiedad del código para que la refactorización sea más sencilla.

(3) Cambios de diseño que son difíciles de completar mediante refactorización

(4) Cuándo no se debe refactorizar 

/**
* @startTime 2020-12-20 11:50
* @endTime 2020-12-20 15:30
* @startPage 65 
* @endPage 102
* @efficiency 102/5 = 20.4页/天
* @needDays 412/20.4 = 20天
* @overDay 2020-12-16 + 20天 =  2020-01-04
*/

6. Refactorización y diseño

Muchas personas consideran el diseño como una parte clave del desarrollo de software y consideran la programación como un trabajo mecánico de bajo nivel. Piensan que el diseño es como dibujar dibujos de ingeniería y la codificación es como una construcción.

Incluso si comprende completamente el sistema, mida su rendimiento en lugar de adivinar. Las conjeturas te harán aprender algo, pero lo más probable es que te equivoques.

7. Refactorización y ejecución

Primero escriba el software ajustable, luego ajústelo para obtener suficiente velocidad.

Tres formas de escribir software rápido:

(1) Método de presupuesto de tiempo

Normalmente se utiliza en sistemas en tiempo real con requisitos de rendimiento extremadamente altos.

Al descomponer el diseño, es necesario hacer un presupuesto y asignar ciertos recursos de antemano a cada componente, incluido el tiempo y la trayectoria de ejecución. Cada componente no debe exceder su propio presupuesto, incluso si tiene un mecanismo para programar y aprovisionar tiempo entre componentes.

Este método concede gran importancia al rendimiento y es necesario para sistemas como los reguladores de frecuencia cardíaca, porque los datos tardíos en dichos sistemas son incorrectos. Pero para algunos sistemas de gestión, esta búsqueda de rendimiento es demasiado.

(2) Método de atención continua

Este método requiere que cualquier programador intente garantizar el alto rendimiento del sistema al hacer algo en cualquier momento.

Este método parece muy común y se siente muy atractivo, pero generalmente no ayuda mucho.

(3) Etapa de optimización del rendimiento

Al escribir un programa, no es necesario prestar demasiada atención al rendimiento. Una vez desarrollado el código, habrá una etapa de optimización del rendimiento. Una vez que se ingresa a esta etapa, el rendimiento del programa se ajusta de acuerdo con un programa específico.

En la etapa de optimización del rendimiento, primero debe usar una herramienta de medición para monitorear el funcionamiento del programa, deje que le diga en qué parte del programa se consume mucho tiempo y espacio. De esta forma, se puede encontrar un pequeño fragmento de código donde se encuentra el punto de acceso de rendimiento. Luego, debe concentrarse en estos códigos calientes y usar los métodos de optimización en el método de atención continua para optimizarlos. Cada paso debe compilarse, probarse y medirse nuevamente.

8. ¿Dónde está el origen de la reconstrucción?

Capítulo 3 Mal olor a código

1. Código duplicado

Cuando dos funciones de la misma clase contienen la misma expresión, es necesario extraer el código repetido y luego dejar que ambas ubicaciones llamen al fragmento de código extraído.

2. Función demasiado larga

Todos los beneficios aportados por la capa indirecta, la capacidad de explicación, la capacidad de compartir y la capacidad de elección.

Las funciones deben descomponerse de manera más agresiva. Siempre que sentimos que necesitamos comentarios para explicar algo, escribimos las cosas que deben explicarse en una función independiente y la nombramos según su propósito (en lugar de implementación). Incluso podemos comparar una Agrupe incluso una línea de código para hacer esto. Incluso si la acción de llamada de función reemplazada es más larga que la función en sí, siempre que el nombre de la función pueda explicar su propósito, no debemos dudar en hacerlo. La clave no es la longitud de la función, sino la distancia semántica entre el "qué" y el "cómo" de la función.

(1) Función de refinamiento

(2) Reemplazar variables temporales con consultas

(3) Introduzca el objeto de parámetro o mantenga el objeto intacto

(4) Reemplazar funciones con objetos de función

Coloque esta función especial en un objeto separado, de modo que la variable local se convierta en un campo en el objeto y luego pueda descomponer esta función grande en múltiples funciones pequeñas en el mismo objeto.

Este libro continúa enfatizando la belleza de las funciones pequeñas.

(5) Las expresiones condicionales y los bucles a menudo también son señales refinadas.

Expresión condicional de descomposición;

Destile el bucle y su código en una función independiente.

3. Categoría de gran tamaño

Si desea hacer demasiadas cosas con una sola clase, aparecerán demasiadas variables de instancia en ella. Una vez que esto suceda, seguirá un código repetido.

Se pueden extraer varias variables juntas en una nueva clase utilizando la clase refinada.

4. Columna de parámetros demasiado larga

5. Cambios divergentes

6. Modificación de tiro

Si encuentra un cierto cambio y tiene que hacer pequeños cambios en muchas clases diferentes, puede destilar el código que ha cambiado en una nueva clase.

7. Parcela adjunta

El interés de la función en una determinada clase es mucho mayor que el interés en la clase en la que se encuentra. En este momento, es necesario transferir la posición de la función.

8. Grupo de lodo de datos

Un método de buen juicio es: al eliminar uno de los muchos datos, ¿los demás datos pierden su significado? Si ya no tienen sentido, esta es una señal clara y debe generar un nuevo objeto.

Reducir el número de campos y parámetros puede, por supuesto, eliminar algunos malos olores, pero lo que es más importante: una vez que tenga un objeto nuevo, tendrá la oportunidad de hacer que el programa emita una fragancia. Una vez que tenga el nuevo objeto, puede comenzar a buscar gráficos de adjuntos, que pueden ayudarlo a señalar los diversos comportamientos del programa que se pueden mover a la nueva categoría. No lleva mucho tiempo, todas las clases aprovecharán al máximo su valor en su pequeña sociedad.

9. Tipos básicos de paranoia

Los principiantes en la tecnología de objetos generalmente no están dispuestos a usar objetos pequeños en tareas pequeñas, como cadenas especiales como dinero, números de teléfono y códigos postales que combinan valores numéricos y monedas. Parece simple. En este caso, puede usar objetos para reemplazar valores de datos. Reemplace el valor de datos que existía originalmente solo con el objeto, para salir de la cueva tradicional y entrar en el mundo de los objetos calientes.

10. Switch horror apareció

Una de las características más obvias de los programas orientados a objetos es que utilizan menos sentencias de cambio.

En esencia, el problema con las declaraciones de cambio es la repetición. A menudo encontrará la misma declaración de cambio dispersa en diferentes ubicaciones. Si desea agregarle una nueva cláusula de caso, debe buscar todas las instrucciones de cambio y modificarlas. El polimorfismo en la orientación a objetos puede aportar soluciones elegantes.

11. Sistema de herencia paralelo

Si encuentra que una clase agrega una subclase, también debe agregar una subclase a otra clase. Si descubre que el prefijo del nombre de clase de un sistema de herencia es exactamente el mismo que el prefijo del nombre de otro sistema de herencia, huele este mal olor.

La estrategia general para eliminar esta duplicación es permitir que una instancia de un sistema de herencia haga referencia a una instancia de otro sistema de herencia. Si realiza esfuerzos constantes para utilizar el método de transferencia y el campo de transferencia, puede ocultar el sistema de herencia del lado de referencia invisible.

12. Redundancia

Colapsar el sistema de herencia;

Inline la clase;

13. Habla sobre el futuro

14. Campos temporales confusos

15. Cadena de mensajes acoplada de varios grados

16. El intermediario

17. Relación ambigua

18, similar a la misma clase

19 Biblioteca de clases imperfectas

La introducción de funciones adicionales, es decir, la encapsulación de parámetros complejos;

Introduzca la extensión local, es decir, herede la biblioteca de clases y agregue los métodos que necesite;

20, clase de datos ingenuos

21. Regalo rechazado

Reemplazar herencia con delegación.

22, demasiados comentarios

Cuando ves un montón de comentarios, a menudo es porque tu código es malo y necesitas usar comentarios para explicarlo. Demasiados comentarios indican que debería refactorizar el código.

Cuando sienta la necesidad de escribir comentarios, intente refactorizar primero e intente que todos los comentarios sean redundantes.

Capítulo 4 Creación de un sistema de prueba

1. El valor del código de autocomprobación

De hecho, el momento más útil para escribir código de prueba es antes de programar. Cuando necesite agregar funciones, escriba primero el código de prueba correspondiente.

Escribir código de prueba en realidad es preguntarse qué debe hacer para agregar esta función. Escribir código de prueba también le permite concentrarse en la interfaz en lugar de en la implementación.

2. Marco de prueba JUnit

3. Agregue más pruebas

  • Es mejor escribir una prueba imperfecta y ejecutarla, en lugar de esperar una prueba perfecta;
  • Considere las condiciones de contorno que pueden salir mal y concentre la potencia de fuego de prueba allí;
  • Cuando se crea que algo va mal, no olvide comprobar si se lanza la excepción esperada;
  • No escriba pruebas solo porque las pruebas no pueden detectar todos los errores, porque las pruebas pueden detectar la mayoría de los errores;

 

Publicación anterior: [Redacción de código de alta calidad: 151 sugerencias para mejorar los programas Java]

Artículo siguiente: Conocimiento profundo de la máquina virtual Java

Supongo que te gusta

Origin blog.csdn.net/guorui_java/article/details/111305499
Recomendado
Clasificación