El arte de escribir código como un pianista | Equipo de tecnología de JD Cloud

Prefacio

¿Cómo evaluar la calidad de un sistema? ¿Qué tipo de sistema o software se puede llamar de alta calidad? Se puede ver desde tres perspectivas: la primera es el diseño arquitectónico, como la selección de tecnología, las consideraciones de coherencia de datos en sistemas distribuidos, etc., la segunda es la gestión de proyectos: ya sea desarrollo ágil o desarrollo en cascada, la deuda técnica debe limpiarse. , refactorizar el código, etc., lo último es inseparable de la calidad del código, la calidad del código afecta directamente la mantenibilidad y escalabilidad del sistema. Es como un automóvil: tiene un interior de alta gama y una apariencia hermosa, pero su chasis es pobre y su potencia es débil. Difícilmente se lo puede llamar un buen automóvil. Este artículo discutirá con usted cómo escribir código limpio y de alta calidad como programador desde una perspectiva subjetiva y objetiva.

perspectiva subjetiva

Espíritu de ingeniero

Haga clic en el avatar de JingME para ver que nuestro título interno es "Ingeniero de desarrollo xx", no "Escritor de códigos xx". Esta división puede entenderse como la división de maestro (maestro). Los programadores maestros consideran el sistema como una historia, en lugar de escribir . como un programa . Como desarrollador, debes ser responsable del código que escribes. Cuando nombras una clase como @author, debes tener una sensación de logro. Un día en el futuro, tal vez un año, dos años o incluso cinco años después, otros Los colegas lo harán Después de leer este código, suspirarás sinceramente "genial" en lugar de quejarte de "¿qué diablos escribiste?" El paquete de concurrencia escrito por Doug Lea sigue siendo famoso después de muchos años.

Mejorar la legibilidad del código

Lo primero que se debe lograr es que el código esté escrito para que la gente lo lea . Es sólo básico para que las máquinas lo ejecuten. Un código excelente no necesita demasiados comentarios. El código en sí es un comentario . La legibilidad se refiere a la capacidad de otros desarrolladores para comprender rápidamente la intención y la función del código. El código conciso es más fácil de entender, probar y mantener. En segundo lugar, evite la duplicación, la duplicación de código es la raíz de todos los males en el software ; se crearon muchos principios y patrones de diseño para eliminar la duplicación.

perspectiva objetiva

A continuación, desde una perspectiva objetiva, daremos ejemplos de problemas comunes en las revisiones diarias de código para darle alguna referencia.

probar/captar usar

1. El bloque try/catch debe ser lo más pequeño posible y solo try/catch para situaciones impredecibles. Las excepciones previsibles deben verificarse antes de intentar.

Circunstancias imprevistas: llamadas remotas, lectura y escritura de IO, API de terceros, etc. Situaciones predecibles: un parámetro está vacío, una lista no tiene elementos, etc.



¿Cuáles son los beneficios de los pequeños bloques try/catch?

  • El código está ordenado y puede reducir la sangría de otros códigos.
  • Exquisito control de excepciones, que puede proporcionar indicaciones específicas, alarmas UMP, resultados de registros o devoluciones de códigos de error para excepciones específicas.

2. Si realmente necesita intentar capturar todo el método, es mejor escribir un nuevo método para separar el procesamiento de lógica de negocios y el manejo de excepciones.

Por ejemplo:



Hay mucho contenido en el bloque de código try/catch, lo que indica que la capacidad de control del código no es lo suficientemente buena . Si hay un intento, intente asegurarse de que el intento esté en la primera línea y no debe haber otro contenido. después de atrapar/finalmente.

longitud del método

Las líneas de método deben ser lo más cortas posible; cuanto más cortas, mejor. Permite a los lectores comprender qué hace este método tan pronto como hacen clic. Por ejemplo:



Este es un método para consultar precios. La captura de pantalla de este método es demasiado larga para caber en una página. Si desea descubrir qué hace este método, no puede resolverlo fácilmente con los comentarios en el cuerpo del método.

Simplemente realice un empaquetado de procesamiento simple, este método puede volverse fácil de entender y no es necesario escribir una línea de comentarios.

Después de una simple refactorización:







A juzgar por el código anterior, el primer párrafo divide el código de consulta de precios en dos partes: primero, analiza el estado de aprobación de la consulta y luego consulta los precios por separado según el estado de aprobación. El segundo párrafo divide la consulta de precio en dos partes: una es consultar el precio bajo aprobación, la otra es consultar el precio después de la aprobación y, finalmente, las dos se combinan y se devuelven. El tercer párrafo es el código para consultar el precio durante la aprobación. Obviamente, hay dos modos para consultar el precio durante la aprobación, modo de porcentaje y modo de precio mínimo. Después de consultar los resultados, se devuelve la combinación para obtener el precio de canal del producto. .

En comparación, no es difícil ver que el bloque de código original es demasiado largo y está profundamente anidado (un bucle for anida if y luego anida if), lo que resulta en una legibilidad reducida. Si quiero cambiar un determinado fragmento de código, debo pensarlo detenidamente. Pero después de la división, puede localizar rápidamente el bloque de código de destino sin preocuparse por el impacto en otros métodos. Además, las pruebas unitarias facilitarán la escritura de casos de prueba.

Está prohibido modificar los datos de los parámetros de entrada dentro del método.

Desde la perspectiva de los conceptos de sistema, los sistemas generalmente se pueden dividir en dos categorías. A un tipo se le da una entrada y obtiene una salida. Este tipo se llama responsivo; al otro tipo se le da una entrada pero no tiene salida. Este tipo se considera imperativo. De manera similar, para los métodos, los métodos reactivos reciben un parámetro de entrada y obtienen un parámetro de salida. Los más comunes incluyen conversión de modelos, consulta de datos, etc., mientras que los métodos imperativos incluyen enviar mensajes y ejecutar un hilo.

Pero no importa cómo cambien, estos tienen una cosa en común: no modificarán los datos de entrada .

1. Provocar efectos secundarios inesperados: si un método modifica los parámetros pasados ​​y la persona que llama confía en el valor del parámetro original, la persona que llama puede verse afectada sin saberlo. Esto puede hacer que el comportamiento del programa se vuelva impredecible, aumentando la complejidad del código y la probabilidad de errores.
2. Destruir la coherencia de los datos: si varios métodos comparten el mismo objeto como parámetro y todos estos métodos pueden modificar el objeto, estos métodos pueden interferir entre sí, lo que hace que el estado de los datos se vuelva caótico e impredecible.
3. Puede aumentar la dificultad del mantenimiento del código: cuando un método modifica los parámetros pasados, es posible que el código que llama al método deba depender de este comportamiento de modificación. Esto aumenta el acoplamiento del código, haciéndolo más difícil de entender, mantener y reutilizar. Cuando es necesario modificar un método, es posible que sea necesario modificar todos los lugares donde se llama al método al mismo tiempo, lo que aumenta el costo de mantenimiento del código.

Por ejemplo:



Aquí se llaman tres métodos establecidos, pero ¿quién puede saber de un vistazo a qué objeto establece el valor? Tienes que hacer clic uno por uno para ver la implementación específica y saber dónde asignar valores.

Si realmente necesita modificar el valor de un parámetro, puede crear un nuevo objeto para almacenar el resultado modificado y devolvérselo a la persona que llama. Esto mantiene su código claro, mantenible y comprobable, y reduce los efectos secundarios no deseados y los problemas de coherencia de los datos.

parámetros del método

Cuantos menos parámetros tenga un método, mejor. El parámetro ideal es ningún parámetro, seguido de un único parámetro. Se deben evitar en la medida de lo posible tres o más parámetros.

Continuando con el código anterior, la última línea es "Establecer tipo de canal". Hay dos parámetros de entrada en el método establecido. Puede extraer su objeto de asignación y reducir un parámetro de entrada, de la siguiente manera:



Si la lógica de procesamiento de un método solo se basa en los datos de un determinado objeto variable local, entonces este método se puede colocar dentro del objeto para reducir aún más los parámetros del método y mejorar la reutilización del código, por ejemplo:



Desde este punto de vista, los dos métodos de entrada de parámetros se han reducido con éxito a un método sin parámetros.En comparación con el código original, el alcance del método del código original se limita al interior de la clase, y el parámetro final- El método gratuito solo necesita obtener el objetivo. Las instancias de objetos se pueden llamar en cualquier lugar, lo que reduce la necesidad de escribir código duplicado.

reducir la sangría

Una gran cantidad de sangría en el código obviamente afecta la lectura. Siempre que sea posible, debemos reducir la sangría y el nivel en el código tanto como sea posible. Un buen código debe leerse como un periódico, con un diseño limpio y elegante, en lugar de subir escaleras.

Echemos un vistazo al siguiente código:



Hay dos niveles de anidamiento if en el código. Primero, podemos simplificar el primer nivel de anidamiento if y simplemente revertir la condición de juicio de if para obtener el siguiente código:



Esto reduce un nivel de sangría y luego realiza algunos ajustes de variables y parámetros:



De esta forma, en comparación con el código anterior, ¿se mejora la legibilidad?

responsabilidad única

En la programación orientada a objetos, el "Principio de responsabilidad única" (SRP) significa que una clase o módulo debe tener solo una razón para su cambio, es decir, una clase o módulo debe tener solo una responsabilidad u objetivo principal. Al perfeccionar funciones y responsabilidades, se puede mejorar la mantenibilidad, reutilización y escalabilidad del código.

Mira el código a continuación:



Desde el punto de vista de la declaración, este método se utiliza para guardar datos de la tarea, pero de hecho, si algunos datos en los parámetros de entrada no están vacíos (en realidad, es difícil ver los datos específicos de un vistazo cuando se observa la implementación de este método), realizará la operación de actualización. Esta forma de escribir no sólo confunde a los lectores, sino que también reduce la escalabilidad del código.

P: ¿El método compareAndSet de AtomicInteger viola la responsabilidad única? R: No viola el principio de responsabilidad única. El método compareAndSet es una operación atómica proporcionada por la clase AtomicInteger. Se utiliza para comparar si el valor actual es igual a un valor esperado dado. Si es igual, el valor actual se establece en un nuevo valor. La responsabilidad de este método es implementar una comparación atómica y establecer operaciones para garantizar la seguridad de los subprocesos en un entorno de subprocesos múltiples. El método compareAndSet, como una de las operaciones, está diseñado para satisfacer necesidades específicas y no viola el principio de responsabilidad única. El principio de responsabilidad única requiere que una clase o módulo tenga solo una responsabilidad principal, y la responsabilidad principal de la clase AtomicInteger es proporcionar operaciones de enteros atómicos. El método compareAndSet es parte de ella y es parte de la responsabilidad principal de la clase. Por lo tanto, el método compareAndSet no viola el principio de responsabilidad única.     

Utilice nombres significativos

En el siguiente código, el valor de retorno de checkParam es un valor booleano, pero como lector, no sé si debería devolver True si la verificación pasa o si la verificación falla.



En términos generales, la verificación se utiliza como nombre del método al principio y no tiene valor de retorno. Si la verificación falla, se generará una excepción. Los métodos que devuelven valores booleanos suelen empezar con is, veamos si sería más fácil de leer si lo escribiéramos de otra forma.



Utilice nombres significativos

Lo que es típico aquí es el nodo de juicio condicional en el archivo de disposición de flujo, que utiliza números sin sentido como 0 y 1. Es difícil ver lo que se dice de un vistazo, debe hacer clic en él uno por uno para ver el Lógica para ordenarlo y cambiarlo a algo significativo. Nómbrelo para facilitar su comprensión.



Reglas de nomenclatura de clases y métodos.

Los nombres de clases usan sustantivos o frases nominales, los nombres usan verbos o estructuras de gerundio.

Esto es más fácil de entender, así que no daré ejemplos por ahora.

No dejes contenido irrelevante

Antes de iniciar MR, verifique si hay "código comentado" y TODO en el código.

Para el código comentado, si otros desarrolladores intervienen más tarde, estarán muy confundidos: ¿por qué deberían comentarse estas dos líneas de código? ¿Son importantes? ¿Están ahí porque algún día serán necesarios? ¿O simplemente se te olvidó borrarlo en ese momento? ¿O es para que sirva de recordatorio para futuras modificaciones? Estas preocupaciones pueden impedir que otros desarrolladores limpien el código comentado, lo que hace que el código se conserve permanentemente y forme un "código fantasma".

Para TODO, se recomienda que al escribir todo, haga un seguimiento de su ERP, quién lo resolverá, cómo resolverlo y cuándo es la fecha límite. Porque en la mayoría de los casos, Más tarde es igual a nunca . Con el tiempo, incluso yo me olvidé de esta tarea, de por qué la escribí en ese momento y de cómo abordarla, lo que genera peligros ocultos para el sistema.



Como se mencionó anteriormente, el colega que escribió este TODO renunció y ahora solo Dios sabe qué es el TODO.

enumerar

Desarrolle un buen hábito: cuando utilice variables definidas por enumeraciones, extraiga una referencia a la enumeración para facilitar la lectura de otros desarrolladores.

Por ejemplo:



Esta es una variable agotable (porque los estados son limitados), pero el lector no conoce los estados específicos. En realidad, hay una enumeración asociada a él.



Para facilitar la lectura, puede utilizar el método @see/@link de javaDoc donde se define la variable para indicar el rango de enumeración de esta variable.



prueba de unidad

La importancia de una sola prueba es evidente: primero cavemos un hoyo aquí y luego escribamos un artículo separado.

Conclusión

Al final de escribir, me gustaría recomendar a todos un libro clásico "Code Cleanliness". De hecho, el libro se publicó antes y parte del conocimiento del libro puede estar un poco desactualizado, pero los primeros capítulos Todavía vale la pena leerlos. El código limpio requiere los esfuerzos conjuntos del equipo. Los miembros del equipo deben seguir estilos y estándares de codificación consistentes, realizar revisiones de código e intercambio de conocimientos, y mantener y mejorar conjuntamente la calidad del código. No es sólo un estilo de codificación, sino una forma de pensar y de valores . El código elegante es como una obra de arte y, como dice el título, debe escribirse como un pianista.

Autor: JD Retail Tan Lei

Fuente: Comunidad de desarrolladores de JD Cloud Indique la fuente al reimprimir

Lei Jun: La versión oficial del nuevo sistema operativo de Xiaomi, ThePaper OS, ha sido empaquetada. La ventana emergente en la página de lotería de la aplicación Gome insulta a su fundador. Ubuntu 23.10 se lanza oficialmente. ¡También podrías aprovechar el viernes para actualizar! Episodio de lanzamiento de Ubuntu 23.10: La imagen ISO fue "retirada" urgentemente debido a que contenía discurso de odio. Un estudiante de doctorado de 23 años solucionó el "error fantasma" de 22 años en Firefox. Se lanzó el escritorio remoto RustDesk 1.2.3. Wayland mejorado para soportar TiDB 7.4 Lanzamiento: Oficial Compatible con MySQL 8.0. Después de desconectar el receptor USB Logitech, el kernel de Linux falló. El maestro usó Scratch para frotar el simulador RISC-V y ejecutó con éxito el kernel de Linux. JetBrains lanzó Writerside, una herramienta para la creación de documentos técnicos.
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4090830/blog/10120040
Recomendado
Clasificación