Javier Nieto
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # Informe de Análisis del Código Fuente y Métricas Asociadas # Índice 1. [Introducción](#1-introducción) 2. [Captura de Pantalla del Panel de Control de SonarQube](#2-captura-de-pantalla-del-panel-de-control-de-sonarqube) - 2.1 [Descripción de Métricas](#21-descripción-de-métricas) 3. [Descripción y Análisis de Errores Potenciales](#3-descripción-y-análisis-de-errores-potenciales) - 3.1 [Bugs en el Backend](#31-bugs-en-el-backend) - 3.1.1 [Bug en ClinicOwnerService.java](#311-bug-en-clinicownerservicejava) - 3.1.2 [Bug en ClinicService.java](#312-bug-en-clinicservicejava) - 3.1.3 [Bug en HotelRoomService.java](#313-bug-en-hotelroomservicejava) - 3.1.4 [Nuevo Bug en BookingService.java](#314-nuevo-bug-en-bookingservicejava) - 3.1.5 [Nuevo Bug en AdoptionRequestRestController.java](#315-nuevo-bug-en-adoptionrequestrestcontrollerjava) - 3.2 [Bugs en el Frontend](#32-bugs-en-el-frontend) 4. [Análisis de "Code Smells"](#4-análisis-de-code-smells) - 4.1 [Análisis del backend de Adoptions](#41-análisis-del-backend-de-adoptions) - 4.1.1 [Code Smell: Declare this local variable with "var" instead.](#411-code-smell-declare-this-local-variable-with-var-instead) - 4.1.2 [Code Smell: Remove this unnecessary cast to "List".](#412-code-smell-remove-this-unnecessary-cast-to-list) - 4.1.3 [Code Smell: Rename this local variable to match the regular expression '[a-z][a-zA-Z0-9]*$'.](#413-code-smell-rename-this-local-variable-to-match-the-regular-expression-az-azaz0-9) - 4.2 [Análisis del frontend de Adoptions](#42-análisis-del-frontend-de-adoptions) - 4.2.1. [Code Smell: 'const' is already declared in the upper scope.](#421-code-smell-const-is-already-declared-in-the-upper-scope) - 4.2.2. [Code Smell: 'module' import is duplicated.](#422-code-smell-module-import-is-duplicated) - 4.2.3. [Code Smell: Remove this useless assignment to variable "variable".](#423-code-smell-remove-this-useless-assignment-to-variable-variable) - 4.2.4. [Code Smell: Remove the declaration of the unused 'variable' variable](#424-code-smell-remove-the-declaration-of-the-unused-variable-variable) - 4.2.5. [Code Smell: Update this function so that its implementation is not identical to the one on line 'line number'.](#425-code-smell-update-this-function-so-that-its-implementation-is-not-identical-to-the-one-on-line-line-number) - 4.3 [Análisis del backend de HotelRooms](#43-análisis-del-backend-de-hotelrooms) - 4.3.1 [Code Smell: Rename this package name to match the regular expression '[a-z_]+(\.[a-z_][a-z0-9_]*)*$'.](#431-code-smell-rename-this-package-name-to-match-the-regular-expression-az-a-z-a-z0-9) - 4.3.2 [Code Smell: Declare this local variable with "var" instead.](#432-code-smell-declare-this-local-variable-with-var-instead) - 4.4 [Análisis del frontend de HotelRooms](#44-análisis-del-frontend-de-hotelrooms) - 4.4.1. [Code Smell: Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed](#441-code-smell-refactor-this-function-to-reduce-its-cognitive-complexity-from-19-to-the-15-allowed) - 4.4.2. [Code Smell: Remove this useless assignment to variable "petsOwned"](#442-code-smell-remove-this-useless-assignment-to-variable-"petsOwned") - 4.4.3. [Code Smell: 'pet' is already declared in the upper scope](#443-code-smell-'pet'-is-already-declared-in-the-upper-scope) - 4.4.4. [Code Smell: 'clinic' is already declared in the upper scope](#444-code-smell-'clinic'-is-already-declared-in-the-upper-scope) - 4.4.5. [Refactor this code to not use nested template literals](#445-refactor-this-code-to-not-use-nested-template-literals) - 4.4.6. ['react-router-dom' import is duplicated](#446-'react-router-dom'-import-is-duplicated) - 4.4.7. [Remove this useless assignment to variable "setHotelRooms"](#447-remove-this-useless-assignment-to-variable-"setHotelRooms") - 4.4.8. [Remove this useless assignment to variable "setAlerts"](#448-remove-this-useless-assignment-to-variable-"setAlerts") - 4.5 [Análisis del backend de Booking](#45-análisis-del-backend-de-booking) - 4.5.1 [Code Smell: Remove usage of generic wildcard type](#451-code-smell-remove-usage-of-generic-wildcard-type) - 4.5.2 [Code Smell: Call "Optional#isPresent()" before accessing the value](#452-code-cmell-call-"Optional#isPresent()"-before-accessing-the-value) - 4.6 [Análisis del frontend de Booking](#46-análisis-del-frontend-de-booking) - 4.6.1. [Code Smell: Refactor this function to reduce its Cognitive Complexity from 46 to the 15 allowed](#461-code-smell-refactor-this-function-to-reduce-its-cognitive-complexity-from-46-to-the-15-allowed) - 4.6.2. [Code Smell: Remove this useless assignment to variable "variable"](#462-code-smell-remove-this-useless-assignment-to-variable-"variable") - 4.6.3. [Code Smell: 'const' is already declared in the upper scope](#463-code-smell-'const'-is-already-declared-in-the-upper-scope) - 4.6.4. [Refactor this code to not use nested template literals](#464-refactor-this-code-to-not-use-nested-template-literals) - 4.6.5. ['react-router-dom' import is duplicated](#446-'react-router-dom'-import-is-duplicated) - 4.6.6. [Remove this unused import of 'useFetchState'](#466-remove-this-unused-import-of-'useFetchState') - 4.7 [Análisis de los tests del servicio de Booking](#46-análisis-de-los-tests-de-servicio-de-Booking) - 4.7.1. [Remove this 'public' modifier](#471-'remove-this-public-modifier) - 4.7.2. [Complete the assertion](#472-complete-the-assertion) 5. [Conclusiones](#5-conclusiones) 7. [Referencias](#6-referencias) ## 1. Introducción En este informe, se presenta un análisis detallado del código fuente de nuestro proyecto utilizando la herramienta SonarQube. Se analizan las métricas del código, los posibles errores (bugs) encontrados y los diferentes tipos de "code smells". Este análisis se basa en las versiones generadas en S1 y S2, analizando el código en la rama principal para los commits correspondientes. ## 2. Captura de Pantalla del Panel de Control de SonarQube ### 2.1 Dashboard del backend ![Captura de Pantalla del Panel de Control del backend](https://cdn.discordapp.com/attachments/1219593343382589500/1223611026704961576/image.png?ex=661a7b92&is=66080692&hm=a933d41847d4277c1cd4a42aec9fcf76f21d85919d5d6f44f6d8003f3e867443&) ![Captura del LOC](https://cdn.discordapp.com/attachments/1219593343382589500/1223618920074838107/image.png?ex=661a82ec&is=66080dec&hm=ccb653fc59efbf9b78b413578aa48abe4cfb7000006e03d97f73e71f7eda2af3&) ### 2.2 Dashboard del frontend ![Captura de Pantalla del Panel de Control del frontend](https://cdn.discordapp.com/attachments/1219593343382589500/1225045586441539594/image.png?ex=661fb39c&is=660d3e9c&hm=d020bdff986b3527200d6cf97be2afb177fcca5c99f01ac45207347a2d18f30d&) ![Captura del LOC](https://cdn.discordapp.com/attachments/1219593343382589500/1225045989547839609/image.png?ex=661fb3fc&is=660d3efc&hm=8524a07bd600a11c63d60cb6121f5d4b0ee05fc5537f693800b8634f09d6891b&) ### 2.3 Descripción de Métricas A continuación, analizaremos los distintos tipos de métricas proporcionadas por las 2 captura de pantalla mostradas anteriormente, describiendo en qué consisten dichas métricas y sus valores correspondientes arrojado por el análisis realizado por SonarQube. Nuestro proyecto ha pasado todas las condiciones. También es necesario mencionar que las métricas 2,3,4 y 5 son subtipos pertenecientes a un tipo de métrica mayor denominada Issues, pero las hemos desglosado de esta manera para que su posterior desarrollo sea más claro. - **Métrica 1:** Lines of code (S). Número de líneas físicas en nuestro proyecto que presentan al menos un carácter y que no son un espacio en blanco, una tabulación o un comentario. En nuestro caso, en el backend tenemos 4800 líneas de código que cumplen estas condiciones, de las cuales 4500 corresponden al lenguaje de programación Java y 285 a XML. Respecto al frontend, tenemos unas 12000 líneas de código, de las cuales 11000 son del lenguaje javascript, y apenas 1000 líneas pertenecen a CSS. - **Métrica 2:** Vulnerabilities (A). Problemas descubiertos que afectan a la seguridad de la aplicación y que deben solucionarse de inmediato. En nuestro proyecto no encontramos ningun tipo de vulnerabilidad que comprometa la seguridad de nuestro proyecto en ninguno de los sentidos, ni en el backend ni en el frontend, de ahí que en las capturas anteriores se muestren con un 0. - **Métrica 3:** Bugs (C). En pocas palabras, son errores encontrados en el código de nuestro proyecto. Más concretamente, encontramos 5 bugs, además de otros 4 en el frontend, todos estos con un nivel de severidad "Major". Estos 5 son el mismo tipo de bug, solo que se encuentran en distintas clases de nuestro proyecto: - Call "Optional#isPresent()" before accessing the value. Presente en AdoptionRequestRestController (método createAdoptionRequest), BookingService (método update), ClinicService (método update), ClinicOwnerService (método findByUserId) y HotelRoomService (método update). Los bugs del frontend se encuentran divididos en distintas clases del proyecto, y son: - Remove this conditional structure or edit its code blocks so that they're not all the same (src/auth/register/index.js). - Unexpected missing generic font family (src/global.css). - Unexpected duplicate "position" (src/static/css/owner/consultations.css). - Unexpected duplicate "height" (src/static/css/owner/editPet.css). - **Métrica 4:** Security Hotspots (E). Fragmento de código sensible a la seguridad, pero es posible que la seguridad general de la aplicación no se vea afectada. En nuestro proyecto encontramos solo 1 en el backend: - Categoría: Insecure Configuration (Priority: Low). Presente en la clase DevelopersController. Respecto al frontend, nuestro proyecto presenta solo otro security hotspots: - Categoría: Weak Cryptography (Priority: Medium) Presente en la clase src/owner/visits/visitEdit/index.js - **Métrica 5:** Code Smells (A). Código que dificulta el mantenimiento (huele mal). En nuestro backend encontramos 228 code smells, con un nivel de mantenibilidad "A". Estos 228 code smells se pueden agrupar por tipos en función de su severidad: - Blocker: 1 code smell. - Critical: 3 code smells. - Major: 29 code smells. - Minor: 40 code smells. - Info: 155 code smells. En nuestro frontend encontramos 174 code smells, también con un nivel de mantenibilidad "A". Estos son: - Blocker: 0 code smell. - Critical: 33 code smells. - Major: 106 code smells. - Minor: 35 code smells. - Info: 0 code smells. - **Métrica 6:** Coverage. Indica gráficamente cuántas líneas del código están cubiertas por pruebas unitarias. En nuestro caso hemos realizado un total de 249 pruebas unitarias en el backend, pero el resultado arrojado por SonarQube es desconcertante ya que nos indica que tenemos una cobertura del 0.0%. No entendemos el motivo por el qué ocurre esto ya que con el numero de pruebas unitarias realizadas deberíamos alcanzar un nivel de cobertura mucho mayor. También es necesario mencionar que los test de owner service, porporcionados por el propio código base del proyecto, presentan un error de inicialización con lo que no podemos pasar esa parte de las pruebas. Respecto al frontend no se han realizado pruebas unitarias de ningún tipo por lo que la cobertura es del 0.0% - **Métrica 7:** Duplicated code. Porcentaje de código dulicado en nuestro proyecto. En nuestro proyecto tenemos un 0.0% de duplicaciones en 4800 líneas de código, y 0 bloques de código duplicados.Esta ausencia de duplicaciones no solo contribuye a la claridad y mantenibilidad del código, sino que también indica una sólida práctica de desarrollo que minimiza la redundancia y maximiza la reutilización de código. Sin embargo, en el frontend tenemos un 15.3% de código duplicado y 57 bloques duplicados, unos números notablemente mayores que en nuestro backend y que nos enfocaremos en mejorar en el siguiente Sprint - **Métrica 8:** Cyclomatic Complexity. Se trata de contar el número de sentencias condicionales ‘if’, ‘for’, ‘while’, y otros, en un método. Cada vez que el flujo de control del código de un método se bifurca, el contador ciclomático se incrementa en uno. Cada método tiene un valor mínimo de uno por defecto, excepto para los métodos ‘get’ y ‘set’ en cuyo caso no se tienen en cuenta para la complejidad. Así, se puede obtener una medida cuantitativa de la dificultad de crear pruebas automáticas del código y también es una medición orientativa de la fiabilidad del mismo. Los niveles de complejidad funcionan de la siguiente manera: - 1 a 10: Sin riesgo - 11 a 20: Riesgo Moderado - 21 a 50: Riesgo Alto - Mayor que 50: Es necesario/imprescindible refactorizar. En ninguna clase de nuestro proyecto, ya sea del backend o del frontend, superamos el nivel 50 de complejidad ciclomática, por lo que no sería imprescindible refactorizar. - **Métrica 9:** Cognitive Complexity. La complejidad cognitva es una medida de la complejidad similar a la complejidad ciclomática, pero teniendo en cuenta algunos detalles sobre la cognición humana. Nuestro proyecto tampoco presenta un nivel de complejidad cognitiva alto ni en el backend ni en el frontend. - **Métrica 10:** Debt (A). Es el esfuerzo futuro que se debe realizar para arreglar defectos, vulnerabilidades y problemas de mantenimiento que en su momento se introdujeron en los sistemas por alguna urgencia, plazo de entrega ajustado o falta de conocimiento. Cuanto más tiempo se deja pasar desde que se introducen los problemas hasta que se aborda su resolución, mayor será el esfuerzo necesario para arreglarlos. En el caso de nuestro backend, tardaríamos un total de 6h24min en resolver la deuda técnica acarreada en el Sprint pasado y en este. Por otro lado, respecto al frontend, tardaríamos un total de 3 dias y 4 horas en resolver la deuda técnica acarreada, un tiempo significativamente mayor si lo comparamos con el backend. # 3. Descripción y Análisis de Errores Potenciales En esta sección no nos vamos a centrar únicamente en los bugs incluidos durante el desarrollo de los sprints 1 y 2, sino que también nos centraremos en aquellos bugs que ya se encontrasen en el sistema, ya que consideramos que lo óptimo es identificar todos los bugs posibles del sistema, para evitar que este llegue a dar algún fallo y sea lo más eficiente posible. ## 3.1. Bugs en el Backend ### 3.1.1. Bug en ClinicOwnerService.java En la clase ClinicOwnerService, específicamente en el método findById(int clinicOwnerId), se ha detectado un bug relacionado con el acceso a un valor opcional sin verificar su presencia. El método en cuestión es el siguiente: ```java @Transactional(readOnly = true) public ClinicOwner findById(int clinicOwnerId) throws DataAccessException { --> return clinicOwnerRepository.findById(clinicOwnerId).get(); } ``` ### Origen del Bug: Este bug se originó en la creación de la aplicación, ya que la llamada Optional#get() se realiza sin verificar si el valor está presente previamente. Esto puede conducir a una excepción NoSuchElementException si el valor no está presente en el Optional. ### Consecuencias: La aplicación puede fallar inesperadamente si el Optional devuelto por findById no contiene un valor. ### Solución: La solución para este bug implica agregar una verificación para asegurarse de que el valor esté presente antes de intentar acceder a él. Esto se puede lograr mediante el uso del método Optional#isPresent(). Solo después de verificar que el valor está presente, se debe llamar a Optional#get(). Aquí está la solución aplicada al método findById: ```java @Transactional(readOnly = true) public ClinicOwner findById(int clinicOwnerId) throws DataAccessException { Optional<ClinicOwner> clinicOwnerOptional = clinicOwnerRepository.findById(clinicOwnerId); if (clinicOwnerOptional.isPresent()) { return clinicOwnerOptional.get(); } else { throw new NoSuchElementException("ClinicOwner with ID " + clinicOwnerId + " not found"); } } ``` ## 3.1.2 Bug en ClinicService.java En la clase ClinicService, específicamente en el método update(Clinic clinic, int clinicId), se ha detectado un bug similar al anterior. El método en cuestión es el siguiente: ```java @Transactional public Clinic update(Clinic clinic, int clinicId) throws DataAccessException { // BUG: Esta línea puede producir un "NoSuchElementException" --> Clinic clinicToUpdate = clinicRepository.findById(clinicId).get(); if (clinic.getClinicOwner() != null){ BeanUtils.copyProperties(clinic, clinicToUpdate, "id", "owners"); } else { BeanUtils.copyProperties(clinic, clinicToUpdate, "id", "clinicOwner", "owners"); } return save(clinicToUpdate); } ``` ### Origen del Bug: Este bug también se originó en la creación de la aplicación y está relacionado con el acceso a un valor opcional sin verificar su presencia. ### Consecuencias: Al igual que en el caso anterior, el acceso directo a Optional#get() puede provocar una excepción NoSuchElementException si el valor no está presente en el Optional. ### Solución: Para corregir este bug, es necesario modificar el método update en la clase ClinicService. En lugar de acceder directamente al valor opcional mediante Optional#get(), debemos primero verificar si el valor está presente utilizando el método Optional#isPresent(). Si el valor está presente, lo obtenemos utilizando Optional#get() y luego procedemos con la actualización del objeto Clinic. Si el valor no está presente, lanzamos una excepción NoSuchElementException indicando que la clínica con el ID proporcionado no se encontró. Aquí está la solución aplicada al método update: ```java @Transactional public Clinic update(Clinic clinic, int clinicId) throws DataAccessException { Optional<Clinic> clinicOptional = clinicRepository.findById(clinicId); if (clinicOptional.isPresent()) { Clinic clinicToUpdate = clinicOptional.get(); if (clinic.getClinicOwner() != null){ BeanUtils.copyProperties(clinic, clinicToUpdate, "id", "owners"); } else { BeanUtils.copyProperties(clinic, clinicToUpdate, "id", "clinicOwner", "owners"); } return save(clinicToUpdate); } else { throw new NoSuchElementException("Clinic with ID " + clinicId + " not found"); } } ``` ## 3.1.3 Bug en HotelRoomService.java En la clase HotelRoomService, se ha detectado otro bug similar. El método afectado es update(HotelRoom hotelRoom, int hotelRoomId), que tiene la siguiente estructura: ```java @Transactional public HotelRoom update(HotelRoom hotelRoom, int hotelRoomId) throws DataAccessException { // BUG: Esta línea puede producir un "NoSuchElementException" --> HotelRoom hotelRoomToUpdate = hotelRoomRepository.findById(hotelRoomId).get(); if (hotelRoom.getClinicOwner() != null){ BeanUtils.copyProperties(hotelRoom, hotelRoomToUpdate, "id", "owners"); } else { BeanUtils.copyProperties(hotelRoom, hotelRoomToUpdate, "id", "clinicOwner", "owners"); } return save(hotelRoomToUpdate); } ``` ### Origen del Bug: Este bug fue introducido recientemente por un miembro del equipo en la release 1.0.0, durante el sprint 1 y también está relacionado con el acceso a un valor opcional sin verificar su presencia. ### Consecuencias: Al igual que en los casos anteriores, el acceso directo a Optional#get() sin verificar si el valor está presente puede provocar una excepción NoSuchElementException. ### Solución: Se debe agregar una verificación previa para asegurarse de que el valor esté presente antes de llamar a get() en el Optional. ```java @Transactional public HotelRoom update(HotelRoom hotelRoom, int hotelRoomId) throws DataAccessException { Optional<HotelRoom> optionalHotelRoom = hotelRoomRepository.findById(hotelRoomId); if (optionalHotelRoom.isPresent()) { // Verificar si el valor está presente HotelRoom hotelRoomToUpdate = optionalHotelRoom.get(); if (hotelRoom.getClinicOwner() != null){ BeanUtils.copyProperties(hotelRoom, hotelRoomToUpdate, "id", "owners"); } else { BeanUtils.copyProperties(hotelRoom, hotelRoomToUpdate, "id", "clinicOwner", "owners"); } return save(hotelRoomToUpdate); } else { throw new NoSuchElementException("HotelRoom with id " + hotelRoomId + " not found"); } } ``` ## 3.1.4. Nuevo Bug en BookingService.java En la clase BookingService, específicamente en el método update(Booking booking, int bookingId), se ha detectado un nuevo bug introducido en la última release 2.0.0. ```java @Transactional public Booking update(Booking booking, int bookingId) throws DataAccessException { // BUG: Esta línea puede producir un "NoSuchElementException" --> Booking bookingToUpdate = bookingRepository.findById(bookingId).get(); if (booking.getOwner() != null){ BeanUtils.copyProperties(booking, bookingToUpdate, "id", "owners"); }else{ BeanUtils.copyProperties(bookingToUpdate, bookingToUpdate, "id", "clinicOwner", "owners"); } return save(bookingToUpdate); } ``` ### Origen del Bug: Este bug se originó recientemente en la última release 2.0.0, durante el segundo sprint de la aplicación. La llamada Optional#get() se realiza sin verificar si el valor está presente previamente. ### Consecuencias: Este bug puede causar una excepción NoSuchElementException si el valor no está presente en el Optional, lo que podría llevar a un comportamiento inesperado de la aplicación. ### Solución: Antes de llamar a get() en el Optional, se debe verificar si el valor está presente utilizando el método Optional#isPresent(). Esto garantiza que no se produzcan excepciones al intentar acceder al valor. ```java @Transactional public Booking update(Booking booking, int bookingId) throws DataAccessException { Optional<Booking> bookingOptional = bookingRepository.findById(bookingId); if (bookingOptional.isPresent()) { Booking bookingToUpdate = bookingOptional.get(); if (booking.getOwner() != null){ BeanUtils.copyProperties(booking, bookingToUpdate, "id", "owners"); } else { BeanUtils.copyProperties(bookingToUpdate, bookingToUpdate, "id", "clinicOwner", "owners"); } return save(bookingToUpdate); } else { throw new NoSuchElementException("Booking with ID " + bookingId + " not found"); } } ``` ## 3.1.5. Nuevo Bug en AdoptionRequestRestController.java En la clase AdoptionRequestRestController, específicamente en el método createAdoptionRequest(AdoptionRequestDTO adoptionRequestDTO), se ha detectado otro nuevo bug en la última release 2.0.0. ```java @ResponseStatus(HttpStatus.CREATED) public ResponseEntity<AdoptionRequest> createAdoptionRequest(@RequestBody @Valid AdoptionRequestDTO adoptionRequestDTO) { Pet pet = petService.findPetById(adoptionRequestDTO.getPetId()); // BUG: Esta línea puede producir un "NoSuchElementException" --> Owner owner = ownerService.optFindOwnerByUser(userService.findCurrentUser().getId()).get(); // Verificar si el solicitante es el propietario legítimo de la mascota if (!adoptionRequestService.isOwnerOfPet(pet, owner)) { return new ResponseEntity<>(HttpStatus.UNAUTHORIZED); // Devolver un estado de no autorizado si el solicitante no es el propietario legítimo } // Verificar si ya existe una solicitud activa para la mascota if (adoptionRequestService.existsActiveAdoptionRequestForPet(pet)) { return new ResponseEntity<>(HttpStatus.CONFLICT); // Devolver un estado de conflicto si ya hay una solicitud activa } // Guardar la solicitud de adopción si todas las verificaciones pasan return new ResponseEntity<>(adoptionRequestService.createAdoptionRequest(owner, pet, adoptionRequestDTO), HttpStatus.CREATED); } ``` ### Origen del Bug: Este bug también se introdujo en la última release 2.0.0 de la aplicación(Sptint 2). Al igual que en el caso anterior, la llamada Optional#get() se realiza sin verificar si el valor está presente previamente. ### Consecuencias: El acceso directo a Optional#get() sin verificar si el valor está presente puede provocar una excepción NoSuchElementException, lo que puede causar un mal funcionamiento de la aplicación. ### Solución: Se debe agregar una verificación previa para asegurarse de que el valor esté presente antes de llamar a get() en el Optional, como se recomendó para el bug anterior. ```java @ResponseStatus(HttpStatus.CREATED) public ResponseEntity<AdoptionRequest> createAdoptionRequest(@RequestBody @Valid AdoptionRequestDTO adoptionRequestDTO) { Pet pet = petService.findPetById(adoptionRequestDTO.getPetId()); Optional<Owner> optionalOwner = ownerService.optFindOwnerByUser(userService.findCurrentUser().getId()); if (optionalOwner.isPresent()) { // Verificar si el valor está presente //Resto del código } else { throw new NoSuchElementException("Owner not found for current user"); } } ``` ## 3.2. Bugs en el Frontend ### 3.2.1. Bug en auth/register/index.js En la clase auth/register/index.js específicamente en la función handleSubmit, se ha detectado un bug en las líneas 83-87. ```javascript useEffect(() => { if (type === "Owner" || type === "Vet") { if (registerFormOwnerInputs[5].values.length === 1){ fetch("/api/v1/clinics") .then(function (response) { if (response.status === 200) { return response.json(); } else { return response.json(); } ``` ### Origen del Bug: Este bug se originó en la creación de la aplicación, en este caso vemos como los bloques lógicos están duplicados. ### Consecuencias: Como consecuencia de este bug,a pesar de que no genera un error en el proyecto, va a causar que no va a importar si la condición se cumple o no, pudiendo generar fallos que todavia no hallamos experimentado. ### Solución: La solución más sencilla en este caso sería modificar el código dentro de cada bloque para dejarlos diferentes, quedando el código de esta forma: ```javascript useEffect(() => { if (type === "Owner" || type === "Vet") { if (registerFormOwnerInputs[5].values.length === 1){ fetch("/api/v1/clinics") .then(function (response) { if (response.status === 200) { return response.json(); } else { throw new Error("Failed to fetch clinics"); } ``` ### 3.2.2. Bug en css/owner/consultations.css En la clase src/static/css/owner/consultations.css, en concreto, en la línea 95 del fichero (línea 10 a continuación), se ha detectado un bug introducido en la release 1.0.0. ```css= .checkbox-wrapper-10 .tgl + .tgl-btn:after, checkbox-wrapper-10 .tgl-flip + .tgl-btn:before { display: inline-block; transition: all 0.4s ease; width: 100%; text-align: center; ->position: absolute; line-height: 2em; font-weight: bold; color: #fff; ->position: absolute; top: 0; left: 0; -webkit-backface-visibility: hidden; backface-visibility: hidden; border-radius: 4px; } ``` ### Origen del Bug: Este bug se originó recientemente en la primera release de la aplicación. En este caso, observamos que la propiedad "position" se encuentra duplicada. ### Consecuencias: Como consecuencia de este bug, no genera un error en el proyecto, no obstante, se relaciona con un problema de legibilidad y redundancia en el código. La repetición de las propiedades de estilos en un mismo bloque puede dificultar la comprensión del código a la hora de su posterior análisis. ### Solución: La solución más sencilla en este caso sería eliminar la duplicación que encontramos, quedando el código de esta forma: ```css= .checkbox-wrapper-10 .tgl + .tgl-btn:after, checkbox-wrapper-10 .tgl-flip + .tgl-btn:before { display: inline-block; transition: all 0.4s ease; width: 100%; text-align: center; position: absolute; line-height: 2em; font-weight: bold; color: #fff; top: 0; left: 0; -webkit-backface-visibility: hidden; backface-visibility: hidden; border-radius: 4px; } ``` ### 3.2.3. Bug en src/static/css/owner/editPet.css En la clase src/static/css/owner/editPet.css, en concreto, en la línea 13 del fichero, se ha detectado un bug de duplicación de uno de los parámetros introducido en la release 1.0.0. ```css= .edit-pet-form-container{ max-width: 600px; ->height: 800px; width: 90%; ->height: 90%; margin-top: 10%; } ``` ### Origen del Bug: Este bug se originó recientemente en la primera release de la aplicación. En este caso, observamos que la propiedad "height" se encuentra duplicada. ### Consecuencias: Como consecuencia de este bug, no genera un error en el proyecto, no obstante, se relaciona con un problema de legibilidad y redundancia en el código. La repetición de las propiedades de estilos en un mismo bloque puede dificultar la comprensión del código a la hora de su posterior análisis. ### Solución: La solución más sencilla en este caso sería eliminar la duplicación que encontramos, quedando el código de esta forma: ```css= .edit-pet-form-container{ max-width: 600px; height: 300px; width: 90%; margin-top: 10%; } ``` ### 3.2.4. Bug en src/global.css En la clase src/global.css, en concreto, en la línea 16 del fichero, se ha detectado un bug del tipo 'Unexpected missing generic font family' ```css= font-family: 'american-typewriter'; ``` ### Origen del Bug: Este bug indica un problema con la configuración de fuentes debido a una referencia incorrecta de la misma. ### Consecuencias: Como consecuencia de este bug, si la fuente especificada no se carga correctamente y no se proporciona una fuente genérica de respaldo, la apariencia de la aplicación puede ser inconsistente y poco profesional. Esto puede dar la impresión de que la aplicación no está bien diseñada o cuidada. ### Solución: Para solucionar este error, hay que asegurarse de que todas las reglas de fuente tengan al menos una fuente genérica especificada como respaldo. Al proporcionar una fuente genérica de respaldo, se asegura de que el texto en la aplicación web aún sea legible incluso si la fuente específica no está disponible en el dispositivo del usuario. Por ejemplo: ```css= font-family: 'american-typewriter', 'sans-serif'; ``` # 4. Análisis de "Code Smells" Para esta sección, hemos decidido repartirnos el código producido durante los sprints 1 y 2, de tal manera que cada miembro del equipo se ha encargado de analizar exahusivamente los malos olores de su parte, y plantear ciertas soluciones. ## 4.1. Análisis del backend de Adoptions ### 4.1.1. Code Smell: Declare this local variable with "var" instead. - **Descripción:** Este "code smell" se refiere a la declaración de variables locales utilizando el tipo concreto en lugar de la palabra clave "var". - **Causas del code smell:** - No se está siguiendo la convención de usar "var" para declarar variables locales en el código base. - Ejemplo: En la clase AdoptionRequestRestController.java, las líneas 80 y 81: ```java Pet pet = petService.findPetById(adoptionRequestDTO.getPetId()); Owner owner = ownerService.optFindOwnerByUser(userService.findCurrentUser().getId()).get(); ``` - **Gravedad del code smell:** Info - Aunque no afecta directamente a la funcionalidad, puede dificultar la legibilidad del código y violar las convenciones de codificación. - **Solución:** - Reemplazar las declaraciones de variables con el tipo concreto por la palabra clave "var" donde sea apropiado y mejore la legibilidad del código. - Ejemplo de solución: ```java var pet = petService.findPetById(adoptionRequestDTO.getPetId()); var owner = ownerService.optFindOwnerByUser(userService.findCurrentUser().getId()).get(); ``` ### 4.1.2. Code Smell: Remove this unnecessary cast to "List". - **Descripción:** Este "code smell" indica que se está realizando un casting innecesario a un tipo "List". - **Causas del code smell:** - Se está realizando un casting a un tipo "List" cuando no es necesario, ya que los métodos del repositorio ya devuelven un tipo "List". - Ejemplo: En la clase AdoptionRequestService.java, en los métodos "findAllByStatus" y "findAllByOwnerAndStatus": ```java @Transactional(readOnly = true) public List<AdoptionRequest> findAllByStatus(AdoptionStatus adoptionStatus) throws DataAccessException { return (List<AdoptionRequest>) adoptionRequestRepository.findAllByStatus(adoptionStatus); } @Transactional(readOnly = true) public List<AdoptionRequest> findAllByOwnerAndStatus(Owner owner, AdoptionStatus adoptionStatus) throws DataAccessException { return (List<AdoptionRequest>) adoptionRequestRepository.findAllByOwnerAndStatus(owner, adoptionStatus); } ``` - **Gravedad del code smell:** Minor - Aunque no es crítico, puede indicar una práctica de codificación no óptima y conducir a un código redundante. - **Solución:** - Eliminar el casting innecesario y utilizar directamente el tipo devuelto por los métodos del repositorio. - Ejemplo de solución: ```java @Transactional(readOnly = true) public List<AdoptionRequest> findAllByStatus(AdoptionStatus adoptionStatus) throws DataAccessException { return adoptionRequestRepository.findAllByStatus(adoptionStatus); } @Transactional(readOnly = true) public List<AdoptionRequest> findAllByOwnerAndStatus(Owner owner, AdoptionStatus adoptionStatus) throws DataAccessException { return adoptionRequestRepository.findAllByOwnerAndStatus(owner, adoptionStatus); } ``` ### 4.1.3. Code Smell: Rename this local variable to match the regular expression '[a-z][a-zA-Z0-9]*$'. - **Descripción:** Este "code smell" indica que el nombre de una variable local no sigue la convención de nombres establecida. - **Causas del code smell:** - La variable "AdoptionRequestId" no sigue la convención de nombres establecida en el código base. - Ejemplo: En la clase AdoptionRequestRepository.java, en el método "findById": ```java Optional<AdoptionRequest> findById(Integer AdoptionRequestId); ``` - **Gravedad del code smell:** Minor - Aunque no afecta directamente a la funcionalidad, es importante seguir las convenciones de nomenclatura para mantener la consistencia en el código. - **Solución:** - Cambiar el nombre de la variable para que cumpla con la convención de nomenclatura establecida, por ejemplo, "adoptionRequestId". - Ejemplo de solución: ```java Optional<AdoptionRequest> findById(Integer adoptionRequestId); ``` ## 4.2. Análisis del frontend de Adoptions ### 4.2.1. Code Smell: 'const' is already declared in the upper scope. - **Descripción:** Este "code smell" indica que la constante ya está declarado en el ámbito superior. - **Causas del code smell:** - La causa principal de este code smell es la redefinición de una variable en un ámbito donde ya existe una variable con el mismo nombre en un ámbito superior. - Ejemplo: En la clase adoptionApplication/index.js: ```java const errorMessage = await response.text(); ``` - **Gravedad del code smell:** Major - Aunque no afecta directamente a la funcionalidad, es importante tener en cuenta la reutilización de variables. - **Solución:** - Reutilizar la variable superior en caso de que se trate de la misma o renombrarla de una forma diferente. - Ejemplo de solución: ```java const messageError = await response.text(); ``` ### 4.2.2. Code Smell: 'module' import is duplicated. - **Descripción:** Este "code smell" indica que se ha importado el mismo módulo más de una vez. - **Causas del code smell:** - La causa principal de este code smell es la importación duplicada del módulo - Ejemplo: En la clase adoption/index.js: ```java import React from 'react'; import '../App.css'; import tokenService from "../services/token.service"; import { useState, useEffect} from "react"; ``` - **Gravedad del code smell:** Minor - Aunque no afecta directamente a la funcionalidad, es importante mantener el código limpio de importaciones duplicadas - **Solución:** - Incluir todo lo necesario en la misma importación del módulo a utilizar. - Ejemplo de solución: ```java import '../App.css'; import tokenService from "../services/token.service"; import { useState, useEffect, React} from "react"; ``` ### 4.2.3. Code Smell: Remove this useless assignment to variable "variable" - **Descripción:** Este "code smell" indica que hay que eliminar esta asignación inútil a la variable. - **Causas del code smell:** - La causa principal de este code smell el hecho de haberse de haber olvidado eliminar dichas asignaciones que han sido utilizadas en otras versiones del código. - Ejemplo: En la clase adoption/index.js, la variable message: ```java const [message, setMessage] = useState(null); ``` - **Gravedad del code smell:** Major - Aunque no afecta directamente a la funcionalidad, es importante mantener el código limpio de asignaciones inútiles. - **Solución:** - Utilizar dicha asignación o eliminarla. - Ejemplo de solución: ```java const [setMessage] = useState(null); ``` ### 4.2.4. Code Smell: Remove the declaration of the unused 'variable' variable. - **Descripción:** Este "code smell" indica que hay que eliminar la declaración de la variable que no ha sido usada. - **Causas del code smell:** - La causa principal de este code smell el hecho de haberse de haber olvidado eliminar dichas declaraciones que han sido utilizadas en otras versiones del código. - Ejemplo: En la clase adoption/index.js, la variable visible: ```java const [visible, setVisible] = useState(false); ``` - **Gravedad del code smell:** Minor - Aunque no afecta directamente a la funcionalidad, es importante mantener el código limpio de declaraciones de variables que no han sido usadas. - **Solución:** - Utilizar dicha declaración o eliminarla. - Ejemplo de solución: ```java const [setVisible] = useState(false); ``` ### 4.2.5. Code Smell: Update this function so that its implementation is not identical to the one on line 'line number'. - **Descripción:** Este "code smell" indica es necesario actualizar esta función para que su implementación no sea idéntica a la de la línea indicada. - **Causas del code smell:** - Durante una refactorización previa del código, se pudo haber extraído una función duplicada pero se olvidó reemplazar una de las instancias por la nueva función refactorizada. - Ejemplo: En la clase myAdoptionApplications/index.js, la función error: ```java .catch(error => { console.error('Error:', error); setMessage('Failed to fetch adoption applications'); setVisible(true); }); ``` - **Gravedad del code smell:** Major - Aunque no afecta directamente a la funcionalidad, puede afectar negativamente la calidad general del código y la eficiencia del desarrollo. Es importante abordar este tipo de code smells para mejorar la calidad y mantenibilidad del código a largo plazo. - **Solución:** - Refactorizar el código para eliminar la duplicación y promover la reutilización de código. Extraer la lógica común a una función separada, creando una nueva función que contenga la lógica común. Puedes llamar a esta nueva función desde ambas ubicaciones en el código en lugar de duplicar la lógica. - Ejemplo de solución: - Con esta refactorización, tenemos una función handleError que se encarga de manejar el error y establecer el mensaje. Podemos llamar a esta función en lugar de duplicar la lógica en varios lugares, lo que mejora la legibilidad, el mantenimiento y la reutilización del código. ```java .catch(handleError); function handleError(error) { console.error('Error:', error); setMessage('Failed to fetch adoption applications'); setVisible(true); } ``` ## 4.3. Análisis del backend de HotelRooms ### 4.3.1. Code Smell: Rename this package name to match the regular expression '[a-z_]+(\.[a-z_][a-z0-9_]*)*$'. - **Descripción:** Este "code smell" indica que el nombre de un paquete no sigue la convención de nombres establecida. - **Causas del code smell:** - El paquete "hotelRoom" no sigue la convencion de nombres establecida en el código base - Ejemplo: En la clase HotelRoom.java, el paquete "hotelRoom": ```java package org.springframework.samples.petclinic.hotelRoom; ``` - **Gravedad del code smell:** Minor - Aunque no afecta directamente a la funcionalidad, es importante seguir las convenciones de nomenclatura para mantener la consistencia en el código. - **Solución:** - Cambiar el nombre del paquete para que cumpla con la convención de nomenclatura establecida, por ejemplo, "hotelroom". - Ejemplo de solución: ```java package org.springframework.samples.petclinic.hotelroom; ``` ### 4.3.2. Rename this field to match the regular expression '[a-z][a-zA-Z0-9]*$' - **Descripción:** Este "code smell" indica que el nombre de un campo no sigue la convención de nombres establecida. - **Causas del code smell:** - No se está siguendo la convencion de nombres de los campos establecida en el código base - Ejemplo: En la clase HotelRoom.java, el campo "associated_clinic" y el campo "size_of_room": ```java @ManyToOne @JoinColumn(name = "associated_clinic", referencedColumnName = "id") private Clinic associated_clinic; @Column(name = "size_of_room") @NotNull @Min(0) @Max(30) private Integer size_of_room; ``` - **Solución:** - Cambiar el nombre del campo para que cumpla con la convención de nomenclatura establecida, por ejemplo, "associatedClinic" o "sizeOfRoom". - Ejemplo de solución: ```java @ManyToOne @JoinColumn(name = "associatedClinic", referencedColumnName = "id") private Clinic associatedClinic; @Column(name = "sizeOfRoom") @NotNull @Min(0) @Max(30) private Integer sizeOfRoom; ``` ### 4.3.3. Code Smell: Declare this local variable with "var" instead. - **Descripción:** Este "code smell" se refiere a la declaración de variables locales utilizando el tipo concreto en lugar de la palabra clave "var". - **Causas del code smell:** - No se está siguiendo la convención de usar "var" para declarar variables locales en el código base. - Ejemplo 1: En la clase HotelRoomRestController.java, las líneas 49, 71 y 74: ```java User user = userService.findCurrentUser(); HotelRoom newHotelRoom = new HotelRoom(); ClinicOwner owner = clinicOwnerService.findByUserId(userService.findCurrentUser().getId()); ``` - Ejemplo 2: En la clase HotelRoomService.java, la línea 65: ```java HotelRoom hotelRoomToUpdate = hotelRoomRepository.findById(hotelRoomId).get(); ``` - **Gravedad del code smell:** Info - Aunque no afecta directamente a la funcionalidad, puede dificultar la legibilidad del código y violar las convenciones de codificación. - **Solución:** - Reemplazar las declaraciones de variables con el tipo concreto por la palabra clave "var" donde sea apropiado y mejore la legibilidad del código. - Ejemplo de solución: ```java var user = userService.findCurrentUser(); var newHotelRoom = new HotelRoom(); var owner = clinicOwnerService.findByUserId(userService.findCurrentUser().getId()); var hotelRoomToUpdate = hotelRoomRepository.findById(hotelRoomId).get(); ``` ## 4.4. Análisis del frontend de HotelRooms ### 4.4.1. Code Smell: Refactor this function to reduce its Cognitive Complexity from 19 to the 15 allowed. - **Descripción:** Este "code smell" indica que la complejidad cognitiva puede reducirse del nivel 19 hasta el nivel 15. - **Causas del code smell:** - La función "EditHotelRoom" tiene una complejidad cognitiva demasiado alta y es necesario refactorizarla - Ejemplo: En la clase index.java de hotelRoomEdit: ```java export default function EditHotelRoom() ``` - **Gravedad del code smell:** Critical - Afecta directamente a la funcionalidad y es necesaria una refactorización inmediata del código presente en esta función. - **Solución:** - Modificar la función donde nos indica sonarqube para reducir su complejidad cognitiva al nivel mínimo posible detectado por este. ### 4.4.2. Code Smell: Remove this useless assignment to variable "petsOwned" - **Descripción:** Este "code smell" nos indica que podemos eliminar sin problema la variable "petsOwned" de la función "EditHotelRoom". Es similar al code smell "Remove the declaration of the unused 'petsOwned' variable" pero con una gravedad mayor - **Causas del code smell:** - Se declara "petsOwned" como un useState([]) pero nunca es utilizada - Ejemplo: En la clase index.java de hotelRoomEdit: ```java const [petsOwned, setPetsOwned] = useState([]); ``` - **Gravedad del code smell:** Major - Es necesario eliminar esta declaración ya que no es utlizada en ningún momento en esta clase. - **Solución:** - Modificar la declaración de esta variable. - Ejemplo de solución: ```java const [setPetsOwned] = useState([]); ``` ### 4.4.3. Code Smell: 'pet' is already declared in the upper scope. - **Descripción:** Este "code smell" nos indica que la variable "pet" ha sido declarada con anterioridad en una instacia mayo del codigo - **Causas del code smell:** - Se declara la varibale "pet" dentro de un bucle if cuando ha sido declarada con anterioridad en una instancia mayor - Ejemplo 1: En la clase index.java de hotelRoomEdit: ```java if (name === "allowedPetType") { const pet = pets.find((pet) => pet.id === Number(value)); ``` - Ejemplo 2: En la clase index.java de hotelRoomEdit: ```java const petOptions = petTypes.map((petTypeName) => { // Encuentra la primera mascota con el nombre del tipo const pet = pets.find((pet) => pet.type.name === petTypeName); ``` - **Gravedad del code smell:** Major - Es necesario modificarlo ya que puede afectar en gran medida a la mantenibilidad de nuestro código e introducir nuevos bugs. - **Solución:** - Modificar el bucle o la declaración de dicha variable sin afectar al funcionamiento interno del código. ### 4.4.4. Code Smell: 'clinic' is already declared in the upper scope. - **Descripción:** Este "code smell" nos indica que la variable "clinic" ha sido declarada con anterioridad en una instacia mayo del codigo - **Causas del code smell:** - Se declara la varibale "clinic" dentro de un bucle if cuando ha sido declarada con anterioridad en una instancia mayor - Ejemplo: En la clase index.java de hotelRoomEdit: ```java } else if (name === "associated_clinic") { const clinic = clinics.find((clinic) => clinic.id === Number(value)); ``` - **Gravedad del code smell:** Major - Es necesario modificarlo ya que puede afectar en gran medida a la mantenibilidad de nuestro código e introducir nuevos bugs. - **Solución:** - Modificar el bucle o la declaración de dicha variable sin afectar al funcionamiento interno del código. ### 4.4.5. Refactor this code to not use nested template literals. - **Descripción:** Este "code smell" nos indica que debemos refactorizar una parte del codigo para no generar plantillas anidadas - **Causas del code smell:** - Se establece una plantilla anidada - Ejemplo: En la clase index.java de hotelRoomEdit: ```java function handleSubmit(event) { event.preventDefault(); fetch(`/api/v1/HotelRooms${hotelRoom.id ? `/${hotelRoom.id}` : ""}`, ``` - **Gravedad del code smell:** Major - Es necesario modificarlo ya que podemos perder mantenibilidad a largo plazo en nuestro código. - **Solución:** - Modificar esta plantilla anidada de forma que quede como un estado separado. - Ejemplo de solución: ```java event.preventDefault(); let id = hotelRoom.id ? `/${hotelRoom.id : ""; let message = `/api/v1/HotelRooms${id}`; ``` ### 4.4.6. 'react-router-dom' import is duplicated. - **Descripción:** Este "code smell" nos indica que una importación de 'react-router-dom' esta separada y podría hacerse junta. - **Causas del code smell:** - Una importación de 'react-router-dom' se realiza en dos pasos en lugar de en uno. - Ejemplo: En la clase index.java de hotelRoomList: ```java import { useState } from "react"; import { Link } from "react-router-dom"; import { Button, ButtonGroup, Table } from "reactstrap"; import tokenService from "../../services/token.service"; import useFetchState from "../../util/useFetchState"; import getErrorModal from "../../util/getErrorModal"; import "../../static/css/admin/adminPage.css"; import { useNavigate } from "react-router-dom"; ``` - **Gravedad del code smell:** Minor - No es de gran importancia ya que no afecta al codigo de manera directa. - **Solución:** - Declarar la importación de otra manera. - Ejemplo de solución: ```java import { Link, useNavigate } from "react-router-dom"; ``` ### 4.4.7. Remove this useless assignment to variable "setHotelRooms". - **Descripción:** Este "code smell" nos indica que podemos eliminar sin problema la variable "setHotelRooms" de la función "HotelRoomsList". Es similar al code smell "Remove the declaration of the unused 'setHotelRooms' variable" pero con una gravedad mayor. - **Causas del code smell:** - Se declara "setHotelRooms" como un useFetchState([]) pero nunca es utilizada - Ejemplo: En la clase index.java de hotelRoomList: ```java const [hotelRooms, setHotelRooms] = useFetchState( [], `/api/v1/HotelRooms?userId=${user.id}`, jwt, setMessage, setVisible ); ``` - **Gravedad del code smell:** Major - Es necesario eliminar esta declaración ya que no es utlizada en ningún momento en esta clase. - **Solución:** - Modificar la declaración de esta variable de otra manera. - Ejemplo de solución: ```java const [hotelRooms] = useFetchState( [], `/api/v1/HotelRooms?userId=${user.id}`, jwt, setMessage, setVisible ); ``` ### 4.4.8. Remove this useless assignment to variable "setAlerts". - **Descripción:** Este "code smell" nos indica que podemos eliminar sin problema la variable "setAlerts" de la función "HotelRoomsList". Es similar al code smell "Remove the declaration of the unused 'setAlerts' variable" pero con una gravedad mayor. - **Causas del code smell:** - Se declara "setAlerts" como un useState([]) pero nunca es utilizada - Ejemplo: En la clase index.java de hotelRoomList: ```java const [alerts, setAlerts] = useState([]); ``` - **Gravedad del code smell:** Major - Es necesario eliminar esta declaración ya que no es utlizada en ningún momento en esta clase. - **Solución:** - Modificar la declaración de esta variable de otra forma. - Ejemplo de solución: ```java const [alerts] = useState([]); ``` ## 4.5. Análisis del backend de Booking ### 4.5.1 Code Smell: Remove usage of generic wildcard type. - **Descripción:** Este "code smell" indica que debemos eliminar el comodín para tipos genéricos. - **Causas del code smell:** - Se está declarando que un método no devuelva un tipo específico. - Ejemplo: - En la clase BookingController.java, en el método "createBooking", el tipo de objeto que devuelve es ResponseEntity<?> - En la clase BookingController.java, en el método "updateBooking", el tipo de objeto que devuelve es ResponseEntity<?> ```java! public ResponseEntity<?> createBooking(@RequestBody @Valid Booking booking) ``` ```java! public ResponseEntity<?> updateBooking(@PathVariable("bookingId") Integer bookingId, @RequestBody @Valid Booking booking) ``` - **Gravedad del code smell:** Major - Aunque no afecta directamente a la funcionalidad, puede generar problemas en la API a la hora de crear objetos que luego no se procesen de forma adecuada. - **Solución:** - Cambiar el tipo de objeto que devuelve el método para así mantener una legibilidad y funcionamiento correcto. - Ejemplo de solución para ambos métodos: ```java! public ResponseEntity<Booking> createBooking(@RequestBody @Valid Booking booking) ``` ```java! public ResponseEntity<Booking> updateBooking(@PathVariable("bookingId") Integer bookingId, @RequestBody @Valid Booking booking) ``` ### 4.5.2 Code Smell: Call "Optional#isPresent()" before accessing the value. - **Descripción:** Este "code smell" nos indica que debemos hacer una llamada al método "isPresent()" para un objeto de tipo Optional antes de obtener el respectivo valor de éste. - **Causas del code smell:** - Se intenta obtener una propiedad de un objeto Optional. - Ejemplo: - En la clase BookingService.java, en el método "update", se realiza esta operación a un objeto ```java! public Booking update(Booking booking, int bookingId) throws DataAccessException { Booking bookingToUpdate = bookingRepository.findById(bookingId).get(); ``` - **Gravedad del code smell:** Major - No se comprueba un objeto con el que posteriormente se va trabajar, lo que puede provocar errores en próximas líneas, por no realizar la comprobación con el método "isPresent()". - **Solución:** - Agregar el método "isPresent()" para poder comprobar de forma correcta. - Ejemplo de solución: ```java! public Booking update(Booking booking, int bookingId) throws DataAccessException { Optional<Booking> optionalBooking = bookingRepository.findById(bookingId); if(optionalBooking.isPresent()){ Booking bookingToUpdate = optionalBooking.get(); } ``` ## 4.6. Análisis del frontend de Booking ### 4.6.1. Code Smell: Refactor this function to reduce its Cognitive Complexity from 46 to the 15 allowed. - **Descripción:** Este "code smell" indica que la complejidad cognitiva puede reducirse del nivel 46 hasta el nivel 15. - **Causas del code smell:** - La función "BookingForm" tiene una complejidad cognitiva demasiado alta y es necesario refactorizarla - Ejemplo: En la clase index.java de hotelRoomEdit: ```java export default function BookingForm() ``` - **Gravedad del code smell:** Critical - Afecta directamente a la funcionalidad y es necesaria una refactorización inmediata del código presente en esta función. - **Solución:** - Modificar la función donde nos indica sonarqube para reducir su complejidad cognitiva al nivel mínimo posible detectado por este. ### 4.6.2. Code Smell: Remove this useless assignment to variable "variable" - **Descripción:** Este "code smell" nos indica que debemos eliminar las variables setSelectedPet y clinic de la función "BookingForm". Es similar al code smell "Remove the declaration of the unused 'variable' variable" pero con una gravedad mayor - **Causas del code smell:** - Se declara "petsOwned" como un useState([]) pero nunca es utilizada - Ejemplo: En la clase bookingForm.js, las variables 'setSelectedPet' y 'clinic': ```java const [selectedPet, setSelectedPet] = useState(null); const [clinic, setClinic] = useState(null); ``` - **Gravedad del code smell:** Major - Aunque no afecta directamente a la funcionalidad, es importante mantener el código limpio de asignaciones inútiles. - **Solución:** - Utilizar dicha asignación o eliminarla. - Ejemplo de solución: ```java const [selectedPet] = useState(null); const [setClinic] = useState(null); ``` ### 4.6.3. Code Smell: 'const' is already declared in the upper scope. - **Descripción:** Este "code smell" indica que la constante ya está declarado en el ámbito superior. - **Causas del code smell:** - La causa principal de este code smell es la redefinición de una variable en un ámbito donde ya existe una variable con el mismo nombre en un ámbito superior. - Ejemplo: En la clase bookingForm.js: ```java const selectedPet = petsOwned.find((pet) => pet.id === Number(value)); ``` - **Gravedad del code smell:** Major - Aunque no afecta directamente a la funcionalidad, es importante tener en cuenta la reutilización de variables. - **Solución:** - Para resolver este problema, se recomienda reutilizar la variable definida en el ámbito superior en lugar de declarar una nueva constante con el mismo nombre. - Ejemplo de solución: ```java let selectedPet = petsOwned.find((pet) => pet.id === Number(value)); ``` ### 4.6.4. Refactor this code to not use nested template literals. - **Descripción:** Este "code smell" nos indica que debemos refactorizar una parte del codigo para no generar plantillas anidadas - **Causas del code smell:** - Se establece una plantilla anidada - Ejemplo: En la clase bookingForm.js de booking: ```java function handleSubmit(event) { event.preventDefault(); fetch(`/api/v1/Bookings${booking.id ? `/${booking.id}` : ""}`, ``` - **Gravedad del code smell:** Major - Es necesario modificarlo ya que podemos perder mantenibilidad a largo plazo en nuestro código. - **Solución:** - Modificar esta plantilla anidada de forma que quede como un estado separado. ```java event.preventDefault(); let id = booking.id ? `/${booking.id : ""; let message = `/api/v1/Bookings${id}`; fetch(message), ``` ### 4.6.5. 'react-router-dom' import is duplicated. - **Descripción:** Este "code smell" nos indica que una importación de 'react-router-dom' esta separada y podría hacerse junta. - **Causas del code smell:** - Una importación de 'react-router-dom' se realiza en dos pasos en lugar de en uno. - Ejemplo: En la clase index.js de booking: ```java import { useState, useEffect } from "react"; import { Link } from "react-router-dom"; import { Button, ButtonGroup, Table } from "reactstrap"; import tokenService from "../../services/token.service"; import useFetchState from "../../util/useFetchState"; import getErrorModal from "../../util/getErrorModal"; import "../../static/css/admin/adminPage.css"; import { useNavigate } from "react-router-dom"; import "../../static/css/table/tableHeader.css"; ``` - **Gravedad del code smell:** Minor - No es de gran importancia ya que no afecta al codigo de manera directa. - **Solución:** - Declarar la importación de otra manera. - Ejemplo de solución: ```java import { Link, useNavigate } from "react-router-dom"; ``` ### 4.6.6. Remove this unused import of 'useFetchState' - **Descripción:** Este "code smell" nos indica que podemos eliminar la importación de useFetchState ya que no es utilizada. - **Causas del code smell:** - Una importación de 'useFetchState' que no es utilizada - Ejemplo: En la clase index.js de booking: ```java import useFetchState from "../../util/useFetchState"; ``` - **Gravedad del code smell:** Minor - No es de gran importancia ya que no afecta al codigo de manera directa. - **Solución:** - Eliminar dicha importación ## 4.7. Análisis de los tests del servicio de Booking ### 4.7.1. Remove this 'public' modifier. - **Descripción:** Este "code smell" nos indica que podemos eliminar el modificador "public" a la clase. - **Causas del code smell:** - Estamos usando JUnit5, el cual es más tolerante en cuanto a las visibilidades de las clases de testing que ofrecía JUnit4, que exigía que todo fuera público. - Fragmento del código en cuestión: ```java public class BookingServiceTests { ``` - **Gravedad del code smell:** Minor - No es de gran importancia ya que no afecta al codigo de manera directa. - **Solución:** - Eliminar dicho modificador - Ejemplo de solución: ```java class BookingServiceTests { ``` ### 4.7.2. Complete the assertion. - **Descripción:** Este "code smell" nos indica que debemos completar la aserción, ya que está incompleta - **Causas del code smell:** - Aunque la aserción esté escrita, en algunos marcos de pruebas puede procesarse como incompleta - Fragmento del código en cuestión: ```java @Test void shouldFindBookingsByUserId(){ Collection<Booking> bookings = this.bookingService.findBookingsByUserId(1); assertThat(bookings.size()>0); } ``` - **Gravedad del code smell:** Major - Es importante corregir esto ya que las pruebas son vitales para el futuro desarrollo del proyecto. - **Solución:** - Cambiar dicha aserción para que sea completa - Ejemplo de solución: ```java @Test void shouldFindBookingsByUserId(){ Collection<Booking> bookings = this.bookingService.findBookingsByUserId(2); assertNotNull(bookings); } ``` # 5. Conclusiones En base a los resultados del análisis realizado con SonarQube, se pueden extraer las siguientes conclusiones: ## 5.1 Conclusiones sobre las métricas del código. En base al análisis de las métricas proporcionadas por SonarQube en nuestro proyecto, se pueden extraer varias conclusiones importantes. En primer lugar, el proyecto ha superado satisfactoriamente todas las condiciones establecidas, lo que indica un nivel aceptable de calidad en el desarrollo tanto del backend como del frontend. No se han identificado vulnerabilidades significativas que comprometan la seguridad de la aplicación, lo cual es un aspecto muy positivo. Sin embargo, se han detectado varios bugs tanto en el backend como en el frontend, todos ellos clasificados con una severidad "Major". Esto muestra la necesidad de prestar una atención adicional a la calidad del código y a las pruebas realizadas, especialmente para evitar posibles problemas en el futuro. La ausencia de duplicaciones en el código del backend es una señal positiva, ya que contribuye a la claridad y mantenibilidad del mismo. Sin embargo, en el frontend se identificó un porcentaje de código duplicado más elevado, lo que sugiere oportunidades de mejora en la estructura y organización del código. En cuanto a la complejidad del código, tanto la complejidad ciclomática como la cognitiva se encuentran dentro de rangos aceptables en todas las clases tanto del backend como del frontend, lo que indica un nivel razonable de comprensión y mantenibilidad del código. Por último, se estimó el esfuerzo necesario para abordar la deuda técnica acumulada en el proyecto, siendo significativamente mayor en el frontend que en el backend. Esto subraya la importancia de priorizar la resolución de los problemas identificados en el frontend para garantizar la estabilidad y mantenibilidad a largo plazo del proyecto. ## 5.2 Conclusiones sobre los errores potenciales encontrados. Al analizar los bugs detectados en nuestro proyecto, hemos adquirido una un mayor conocimiento sobre la importancia de la gestión rigurosa del código y la coherencia en el desarrollo de software. En el backend, nos dimos cuenta de la necesidad de validar la presencia de valores opcionales antes de intentar acceder a ellos. Los errores encontrados en ClinicOwnerService, ClinicService y HotelRoomService subrayan la importancia de este principio fundamental para evitar excepciones NoSuchElement y garantizar la integridad de nuestro sistema. En el frontend, debemos de mantener la consistencia y la simplicidad en el código. La duplicación de propiedades de estilo y la falta de uniformidad pueden comprometer la mantenibilidad y la comprensión del código, lo que dificulta la resolución de problemas y las futuras actualizaciones. Además, la gestión de fuentes en global.css nos ha enseñado la importancia de asegurar la disponibilidad de fuentes genéricas como respaldo, garantizando una apariencia coherente y profesional en diferentes dispositivos y entornos de usuario, fortaleciendo la identidad visual de nuestra aplicación. El abordaje de estos bugs no solo implica correcciones inmediatas, sino que también nos brinda valiosas lecciones que informarán y mejorarán nuestras prácticas de desarrollo en el futuro, asegurando la calidad y estabilidad de nuestro proyecto a largo plazo. ## 5.3 Conclusiones sobre los "code smells" identificados. Respasando los "code smells" detectados por SonarQube, podemos sacar ciertas conclusiones: ### 5.3.1 "Code smells" de backend Respecto a los "code smells" de backend, encontramos repetidos 2: - **Forma errónea de declaración variables locales:** No afecta a la funcionalidad - **Rename this local variable to match the regular expression:** No afecta a la funcionalidad De forma singular, encontramos 2: - **Casting innecesario:** Genera código redundante - **Comodín a tipos genéricos:** Posibilidad de procesamiento erróneo de datos De forma general, estos "malos olores" no tienen un impacto directo en la funcionalidad implementada. No obstante, a la larga, puede afectar para el mantenimiento del código, ya que puede dificultar la legibilidad del código, violando las convenciones de codificación. Además, si no resolvemos estos "code smells", en un futuro, si se decide ampliar o editar alguna funcionalidad, puede que no obtengamos el funcionamiento deseado, ya sea, por ejemplo, con el casting innecesario, o devolviendo un comodín para tipos genéricos. ### 5.3.2 "Code smells" de frontend Respecto a los "code smells" de frontend, encontramos repetidos algunos, como: - **Const already declared in the upper score:** No afecta a la funcionalidad - **Module import is duplicated:** No afecta a la funcionalidad - **Remove this useless assignment to variable "variable":** No afecta a la funcionalidad - **Refactor this code to not use nested template literals:** Se puede perder mantenibilidad a largo plazo en el código - **Refactor this function to reduce its cognitive complexity:** Afecta de forma directa a la funcionalidad De forma singular, encontramos 3: - **Remove this unused import of 'useFetchState':** No afecta a la funcionalidad - **Remove the declaration of the unused 'variable' variable:** No afecta a la funcionalidad - **Update this function so that its implementation is not identical to the one on line 'line number':** No afecta a la funcionalidad Vemos que la mayoría de "malos olores" detectados por SonarQube no afectan directamente a las funcionalidades implementadas. No obstante, a la larga, puede afectar para el mantenimiento del código, ya que puede dificultar la legibilidad y mantenimiento del código. Además, si no resolvemos estos "code smells", en un futuro, si se decide ampliar o editar alguna funcionalidad, puede que sea más complejo debido a un posible aumento de la deuda técnica, por ejemplo. ## 5.4 Recomendaciones para mejorar la calidad del código y abordar las áreas problemáticas. Para mejorar la calidad del código y abordar las áreas problemáticas identificadas en nuestro proyecto, hemos llegado a la conclusión de aplicar la siguientes políticas: - Implementar una validación rigurosa de los valores opcionales para evitar excepciones y garantizar la integridad del sistema. - Realizar una revisión de los estilos de codificación y estructura del código en el frontend para eliminar duplicaciones y mejorar la coherencia. - Establecer una estrategia para la gestión coherente de fuentes y estilos, asegurando la disponibilidad de fuentes genéricas como respaldo. - Adoptar prácticas ágiles de desarrollo, como la revisión continua del código y la realización de pruebas exhaustivas, para identificar y corregir problemas de manera proactiva. Pensamos que estas recomendaciones ayudarán a optimizar la calidad y la estabilidad del código, asegurando el éxito a largo plazo de nuestro proyecto. ## 6. Actividad extra: Implementación y análisis adicional En esta sección, se detalla la implementación y el análisis adicional llevado a cabo como parte de una actividad extra dentro del proyecto. Con el objetivo de mejorar la calidad del código y prevenir posibles problemas futuros, se asignaron tareas específicas a tres miembros del equipo: Nuno Jose, Javier García y Javier Nieto. Cada uno de ellos se encargó de abordar una parte de los bugs identificados en el sistema, mientras que también se dedicaron a eliminar los code smells dentro de su área de responsabilidad. Estos cambios se realizaron en la rama `hotfix/2.0.1` del repositorio del proyecto y posteriormente se fusionaron con las ramas `main` y `develop`. Este enfoque de trabajo colaborativo y la implementación oportuna de mejoras son fundamentales para mantener la estabilidad, confiabilidad y mantenibilidad del código a lo largo del tiempo. A continuación, se presentan los detalles de las acciones realizadas y su impacto en la calidad del software. ### 6.1 Actividad extra - Javier Nieto En esta actividad extra, me he encargado de solucionar 3 de los 5 bugs del backend y de corregir los code smells identificados en la sección 4.1 del informe. - 3.1.1. Bug en ClinicOwnerService.java El problema consistía en que la llamada `Optional#get()` se realizaba sin verificar si el valor estaba presente previamente, lo que podía conducir a una excepción `NoSuchElementException`. He solucionado este bug verificando si el valor está presente antes de llamar a `Optional#get()`. Si el valor no está presente, se lanza una excepción `NoSuchElementException`. - 3.1.2. Bug en ClinicService.java Similar al caso anterior, la llamada `Optional#get()` se realizaba sin verificar la presencia del valor, lo que podría resultar en una excepción `NoSuchElementException`. Para resolverlo, he añadido la verificación de la presencia del valor antes de llamar a `Optional#get()`. - 3.1.5. Nuevo Bug en AdoptionRequestRestController.java Este bug también estaba relacionado con la llamada `Optional#get()` sin verificar la presencia del valor. He corregido este problema incluyendo la verificación de la presencia del valor antes de llamar a `Optional#get()`. Es crucial abordar estos bugs ya que su resolución: - Previene excepciones NoSuchElementException, mejorando así la estabilidad del sistema. - Aumenta la robustez del código al manejar adecuadamente los casos donde el valor puede no estar presente. - Mejora la estabilidad, confiabilidad y mantenibilidad del código, lo que facilita su comprensión y modificación en el futuro. En cuanto a los code smells identificados en la sección 4.1 del informe: - **4.1.1. Code Smell: Declare this local variable with "var" instead** He modificado la declaración de la variable utilizando la palabra clave `var` en lugar de especificar explícitamente el tipo de la variable. - **4.1.2. Code Smell: Remove this unnecessary cast to "List"** He eliminado el casting innecesario a `List` ya que no era necesario y mejoraba la legibilidad del código. - **4.1.3. Code Smell: Rename this local variable to match the regular expression '[a-z][a-zA-Z0-9]*$'** He cambiado el nombre de la variable para que coincida con la expresión regular proporcionada, lo que mejora la consistencia y la legibilidad del código. Estos cambios no afectan directamente a la funcionalidad del sistema, pero mejoran la calidad del código y facilitan su mantenibilidad y legibilidad. ### 6.2 Actividad extra - Nuno José del Pino Escalante En esta actividad extra, me he encargado de solucionar los bugs del frontend y de corregir los code smells identificados en la sección 4.3 y 4.4 del informe. - 3.2.1. Bug en auth/register/index.js El promblema consiste en que en el bloque if de las lineas 83-87 no estaba bien implementado, ya que no impoortaba el resultado del if. He solucionado el bug cambiando la clausula else para que devuelva un mensaje de error correcto - 3.2.2. Bug en css/owner/consultations.css El bug generaba un problema de legibilidad, debido a que la porpiedad position se encontraba duplicada. Así que para solucionarlo he borrado una de las dos duplicaciones. - 3.2.3. Bug en src/static/css/owner/editPet.css Este error tambien trata sobre una duplicación, pero en este caso sería del parámetro height, así que se ha solucionado quitando la duplicación. - 3.2.4. Bug en src/global.css Se detectó un bug del tipo 'Unexpected missing generic font family. Para solucionarlo hemos asegurado de que todas las reglas de al menos una fuente genérica especificada como respaldo. Es crucial abordar estos bugs ya que su resolución: - Previene errores no deseados, mejorando así la estabilidad del sistema. - Mejora la estabilidad, confiabilidad y mantenibilidad del código, lo que facilita su comprensión y modificación en el futuro. En cuanto a los code smells identificados en la sección 4.3 y 4.4 del informe: - **4.3.1. Code Smell: Rename this package name to match the regular expression '[a-z_]+(.[a-z_][a-z0-9_])$'** He modificado el nombre del paquete para que cumpla con las convenciones. - **4.3.2. Rename this field to match the regular expression '[a-z][a-zA-Z0-9]*$'** Se han cambiado los nombres de los campos para que cumplan con las convenciones - **4.3.3. Code Smell: Declare this local variable with "var" instead.** He modificado la declaración de la variable utilizando la palabra clave `var` en lugar de especificar explícitamente el tipo de la variable. - **4.4.3. Code Smell: 'pet' is already declared in the upper scope.** Se ha cambiado la segunda declaración y se ha puesto let en vez de const para que esta en vez de ser declarada nuevamente, meta los valores en la variable previamente declarada. - **4.4.4. Code Smell: 'clinic' is already declared in the upper scope.** Se ha cambiado la segunda declaración y se ha puesto let en vez de const para que esta en vez de ser declarada nuevamente, meta los valores en la variable previamente declarada. - **4.4.5. Refactor this code to not use nested template literals.** He refactorizado el código de manera que no se generen plantillas anidadas. - **4.4.6. 'react-router-dom' import is duplicated.** Se ha corregido la duplicación del import. - **4.4.7. Remove this useless assignment to variable "setHotelRooms".** He eliminado la asignación de 'setHotelRooms' ya que no era usada. - **4.4.8. Remove this useless assignment to variable "setAlerts".** He eliminado la asignación de 'setAlerts' ya que no era usada. Estos cambios no afectan directamente a la funcionalidad del sistema, pero mejoran la calidad del código y facilitan su mantenibilidad y legibilidad #### Análisis en sonar Analizando Sonar, se puede ver que al eliminarse los bugs, la fiabilidad del backend ha pasado de C a A. Esta mejora en la fiabilidad es un indicador importante de la calidad y estabilidad del sistema. Al solucionar los bugs identificados por SonarQube, se han eliminado posibles puntos de falla y se ha aumentado la confiabilidad del sistema en general. Esto significa que el código ahora es menos propenso a errores y fallos inesperados, lo que resulta en una mejor experiencia para los usuarios finales y una mayor confianza en la aplicación. Además, al corregir los code smells identificados en el código, se ha mejorado significativamente la mantenibilidad del sistema. Los code smells son señales de posibles problemas en el diseño o estructura del código que pueden dificultar su comprensión y mantenimiento a largo plazo. Al eliminar estos code smells, se ha mejorado la legibilidad, claridad y coherencia del código, lo que facilita su mantenimiento y evolución futura. Los desarrolladores podrán trabajar de manera más eficiente y efectiva en el código, lo que reduce el tiempo y los recursos necesarios para realizar cambios y mejoras en el sistema. Además, la corrección de los code smells también ha contribuido a reducir la deuda técnica del proyecto. La deuda técnica se refiere a la cantidad de trabajo adicional necesario para abordar los problemas identificados en el código. Al eliminar los code smells, se ha reducido la cantidad de trabajo futuro necesario para mantener y mejorar el sistema. Esto significa que el proyecto está en una posición más sólida y saludable, con menos compromisos técnicos y un código más limpio y mantenible. En resumen, al eliminar los bugs y corregir los code smells identificados en el código, se ha mejorado la fiabilidad, mantenibilidad y calidad general del sistema. Esto proporciona una base sólida para futuros desarrollos y garantiza una mejor experiencia para los usuarios finales. ## 7. Referencias - Este informe con todo el seguimiento en Hackmd: https://hackmd.io/@BZjkAsVaRBSUX2KZbyMjEg/SyVAxlSyR/edit ---

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully