...
Debemos revisar si se requiere documentar todo el código para documentación, en caso de que no se requiera debemos evitar cualquier comentario.
Declaraciones
Imports. Cuando declaramos imports debemos de evitar usar el comodín o wildcard para evitar cargar dependencias que no se usan.
...
En cualquier de estos tipos de variables, no debemos declarar más de una variable por línea. Así también, siempre debemos inicializar las variables de instancia y de clase evitando que las variables no primitivas tengan un valor null.
Al tener la versión de java 17 es importante considerar la inferencia de tipos usando var en las variables locales (incluyendo ciclos y lambdas) así como si se asigna valor una sola vez, declararla final.
Sentencias
Debemos recordar que es importante que solo se tenga una sentencia por línea de código. En las sentencias como if o for es importante colocar las llaves del bloque de código que le corresponde aunque solo tenga una línea de código en el bloque.
...
Debemos usar constantes en lugar de tener cadenas de texto o números por todas partes, si esos textos o números se pueden representar en un conjunto que compartan un contexto se puede crear una enumeración.
Encapsulación
Todos Todas nuestras variables de instancia de un Bean debería ser encapsulas para evitar el acceso directo a sus valores, dado esto se deben crear sus métodos getter y setter. De ser posible todos nuestros beans deberían ser no mutables quitando los métodos setter. En este ultimo caso se recomienda usas el tipo record.
Duplicidad de código
Uno de los problemas más frecuentes identificados al realizar un code review es el código repetido duplicado y aunque es difícil de eliminarlo cuando ya se ha concluido, es importante no crearlo. Para esto nos podemos apoyar en patrones de diseño o en los principios solid para evitarlo. ¡No copiemos código! O si lo hacemos asegurémonos que es imposible implementar una solución alterna.
...
Si bien es cierto que la herencia es unos de los elementos más importantes de la programación orientada a objetos al reutilizar los atributos y métodos comunes, también puede tener sus problemas si la profundidad de herencia es muy grande. Ya que cada subclase hereda los atributos y métodos del padre haciendo difícil la lectura del código y su mantenimiento, así también el diseño se vuelve más complejo. Por lo que es recomendable una herencia con una profundidad no mayor a 3 o 4.
Principios SOLID
Acrónimo propuesto por Robert Martin:
Single Responsibility Principle
Open-Close Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
Estos principios nos ayudan a crear software escalable, código fácil de leer y entender, tener alta cohesión y un bajo acoplamiento, y con esto el mantenimiento es más sencillo.
SRP
Al abstraer un objeto que tenga su funcionalidad bien definida logramos incrementar la cohesión y disminuir el acoplamiento. Esto se logra al delegar por herencia ciertas responsabilidades, esto es que una clase no debe contener atributos o métodos que no le correspondan.
...
OCP
Todo el software es propenso a crecimiento en funcionalidad pero, al realizarse no debería de modificar la funcionalidad existente y ya probada. Este principio indica justo eso: abierto para la extensión pero cerrado para la modificación. Es complicado realizar esto sin un buen análisis y un conocimiento adecuado del proyecto para prever futuros cambios, pero es deseable que siempre consideremos una extensión futura.
Conseguimos esto con componentes con alta cohesión (SRP) y con una buena dirección de las dependencias (DIP).
...
LSP
El principio de sustitución de Liskov nos dice: un subtipo S de T puede ser asignado a T sin alterar el comportamiento esperado. Esto puede verse como herencia y polimorfismo, pero va más allá y eso se ve en el "sin alterar el comportamiento esperado". Lo que se debe considerar es que al usar el polimorfismo, una clase no debe contener atributos/métodos que no le correspondan. Para lograr esto debemos crear clases que implementen esa funcionalidad y que hereden de la clase padre de donde se quitaron los atributos/métodos.
...
ISP
El principio de segregación de interfaces nos dice que una cliente no puede depender de métodos que no use, en caso de que pase debemos crear una o más interfaces y repartir los métodos evitando que algún cliente que usaba la interface quede con un método que no use como dependencia, al realizar esto podemos tener que un cliente use métodos de diferentes interfaces lo que sería correcto.
...
DIP
El principio de inversión de dependencias nos dice que el objeto contenido en otro no debe depender del principal y viceversa. Esto es que cuando modelamos una solución debemos abstraer el objeto de más bajo nivel con su funcionalidad básica y por medio de una interface definir la funcionalidad genérica del objeto de bajo nivel que será implementado por el de alto nivel. Con esto logramos que ninguno de los objetos dependa uno del otro y la dependencia entre ambos esta dado por una interface.
...
Usar este principio de forma correcta nos permite tener código desacoplado, código reutilizable y escalable.
Nomenclatura para el nombrado de los servicios
El estándar de nombramiento de microservicios es el siguiente:
<canal>-<tipo>-<dominio o funcionalidad>-service
Canal. únicamente se usa si el servicio estará en la capa OSL (canal), de ser el caso, se debe usar el nombre del canal como prefijo, por ejemplo, un servicio que será consumido por el app Spin estará en la capa de canal mobile y su nombre deberá comenzar con “mobile”. Si es un servicio de capa DSL core, no debe llevar ningún valor en este campo.
Ejemplos de canales y servicios:
...
Canal
...
Ejemplos
...
mobile
...
mobile-transaction-service, mobile-profile-service
...
fraud-support
...
fraud-support-service
...
customer-support
...
customer-support-service
Dominio o funcionalidad. únicamente se usa si el servicio es de capa DSL, el valor será el dominio o funcionalidad que abstraiga el servicio. Por ejemplo: account-service, user-service, transaction-inquiry-service, pricing-service.
...
Consideraciones para el desarrollo de Token Digital
Anotaciones de lombok
Todos los beans deben tener la anotación de lombok:
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@ToString
Archivos YML o properties
Se deben crear archivos de tipo yml o properties en caso de que se deba parametrizar alguna propiedad que pueda cambiar con el tiempo. De preferencia solo agregar parámetros de una lectura.
Logs
Se debe usar la anotación:
@slf4j
para los logs. Los scopes usados serán:
error. Para los logs de las excepciones
debug. Para imprimir datos que ayuden a resolver issues
info. Para dar información adicional
· Se deben crear los logs necesarios en cada clase.
· Es obligatorio crear un log en cada excepción.
Se agregará el siguiente formato para la escritura de los logs:
:: clase :: metodo >> mensage
Validaciones
Con librerías. Usar librerías ya existentes de spring, hibernate, etc.
Con anotaciones. Se deben crear anotaciones para validaciones no existentes en las librerías, que deberían de ser todas las correspondientes al negocio.
Principios SOLID
Acrónimo propuesto por Robert Martin:
Single Responsibility Principle
Open-Close Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle
Estos principios nos ayudan a crear software escalable, código fácil de leer y entender, tener alta cohesión y un bajo acoplamiento, y con esto el mantenimiento es más sencillo.
SRP
Al abstraer un objeto que tenga su funcionalidad bien definida logramos incrementar la cohesión y disminuir el acoplamiento. Esto se logra al delegar por herencia ciertas responsabilidades, esto es que una clase no debe contener atributos o métodos que no le correspondan.
...
OCP
Todo el software es propenso a crecimiento en funcionalidad pero, al realizarse no debería de modificar la funcionalidad existente y ya probada. Este principio indica justo eso: abierto para la extensión pero cerrado para la modificación. Es complicado realizar esto sin un buen análisis y un conocimiento adecuado del proyecto para prever futuros cambios, pero es deseable que siempre consideremos una extensión futura.
Conseguimos esto con componentes con alta cohesión (SRP) y con una buena dirección de las dependencias (DIP).
...
LSP
El principio de sustitución de Liskov nos dice: un subtipo S de T puede ser asignado a T sin alterar el comportamiento esperado. Esto puede verse como herencia y polimorfismo, pero va más allá y eso se ve en el "sin alterar el comportamiento esperado". Lo que se debe considerar es que al usar el polimorfismo, una clase no debe contener atributos/métodos que no le correspondan. Para lograr esto debemos crear clases que implementen esa funcionalidad y que hereden de la clase padre de donde se quitaron los atributos/métodos.
...
ISP
El principio de segregación de interfaces nos dice que una cliente no puede depender de métodos que no use, en caso de que pase debemos crear una o más interfaces y repartir los métodos evitando que algún cliente que usaba la interface quede con un método que no use como dependencia, al realizar esto podemos tener que un cliente use métodos de diferentes interfaces lo que sería correcto.
...
DIP
El principio de inversión de dependencias nos dice que el objeto contenido en otro no debe depender del principal y viceversa. Esto es que cuando modelamos una solución debemos abstraer el objeto de más bajo nivel con su funcionalidad básica y por medio de una interface definir la funcionalidad genérica del objeto de bajo nivel que será implementado por el de alto nivel. Con esto logramos que ninguno de los objetos dependa uno del otro y la dependencia entre ambos esta dado por una interface.
...
Usar este principio de forma correcta nos permite tener código desacoplado, código reutilizable y escalable.
Nomenclatura para el nombrado de los servicios
El estándar de nombramiento de microservicios es el siguiente:
<canal>-<tipo>-<dominio o funcionalidad>-service
Canal. únicamente se usa si el servicio estará en la capa OSL (canal), de ser el caso, se debe usar el nombre del canal como prefijo, por ejemplo, un servicio que será consumido por el app Spin estará en la capa de canal mobile y su nombre deberá comenzar con “mobile”. Si es un servicio de capa DSL core, no debe llevar ningún valor en este campo.
Ejemplos de canales y servicios:
Canal | Ejemplos |
mobile | mobile-transaction-service, mobile-profile-service |
fraud-support | fraud-support-service |
customer-support | customer-support-service |
Dominio o funcionalidad. únicamente se usa si el servicio es de capa DSL, el valor será el dominio o funcionalidad que abstraiga el servicio. Por ejemplo: account-service, user-service, transaction-inquiry-service, pricing-service.
Otra consideración para el nombrado de servicios es el agrupado en capas en donde tenemos las siguientes:
...
Data Layer. En esta capa se concentran las bases de datos.
...
Contrato para servicios REST
...
Lo ideal es usar las tecnologías más usadas ya que estas han sido probadas y validadas por muchísimos otros proyectos. Por lo que de esto y de acuerdo a lo que usan en Spin, las tecnologías que usaremos serán:
Framework: Spring con Spring Boot 2 y Spring Cloud
Servidore de aplicaciones: Se usaran Saas en la nube usando AWS (S3, Cognito, EC2, CloudWatch, RDS, Lamdas, SQS) y Google Cloud
Kinesis
Base de datos: MongoDB, Redis 3
Spring Cloud
gRPC
REST
MongoDB
Kubernetes
Docker
Dynatrace
React Native
Configcat
Repositorio: Bitbucket usando git
Versión de Java: 8
Otros: OTP, retrofit
Spock Testing Framework
Dynatrace
Java 17
AWS
Adicional a esto se usara como IDE IntelliJ Community al tener una de las comunidades más activas y contar con plugins fáciles de instalar y usar.
...
Integración continua. Para esto podemos usar herramientas de control de versiones como SVN o GIT. En nuestro caso usaremos git, con github y bitbucket. La forma como iremos integrando nuestros cambios será la siguiente:
...
Distribución continua. Nos ayuda a realizar una liberación de forma constante y sencilla en uno o más ambientes, una de las herramientas más usadas es Jenkins con la ayuda de pipelines. Adicional a esto nos ayuda Docker y Kubernetes para poder gestionar instancias de forma dinámica de acuerdo a la demanda de los servicios quitándole un trabajo que antes era muy complejo a DevOps.En nuestro caso DevOps se encargara de esta actividad. es Jenkins con la ayuda de pipelines. Adicional a esto nos ayuda Docker y Kubernetes para poder gestionar instancias de forma dinámica de acuerdo a la demanda de los servicios quitándole un trabajo que antes era muy complejo a DevOps.
En nuestro caso DevOps se encargara de esta actividad.
Asignación de nombres de branches
Considerar la HU de Jira para nombrar los branches en los que se subirá el código del sprint, por ejemplo:
feature/PALO-231
Jira Legacy | ||||||
---|---|---|---|---|---|---|
|
Fecha | Autor | Descripción del cambio |
---|---|---|
| Se agrega la sección de: Consideraciones para el desarrollo de Token Digital | |