JulioContreras2023
    • 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
    # ++**Proyecto Malla de juegos**++ **++Nombre:++** el n-migos: **++Integrantes:++** Sebastian Aillapan Orlando Caullan Nicolas Toledo John Fernandez Julio Contreras # Índice 1. Taller 1 - Inicio del proyecto 1.1 Descripción del Proyecto 1.2 Tecnologías 1.3 Priorización de Funcionalidades 1.4 Imagenes de Diagramas 2. Taller 2 - Calidad e inspección de codigo 1. Sección Grupal 1.1 Complejidad Ciclomática total 1.2 Complejidad Ciclomática por clase 1.3 Complejidad Ciclomática por método 1.4 Anáñisis de Acoplamiento con CBO 2. Sección Individual 2.1 Sebastian Aillapan - Análisis de Cohesión y Propuesta de Mejora 2.2 Orlando Caullan - Análisis de Cohesión y Propuesta de Mejora 2.3 Nicolas Toledo - Análisis de Cohesión y Propuesta de Mejora 2.4 John Fernandez - Análisis de Cohesión y Propuesta de Mejora 2.5 Julio Contreras - Análisis de Cohesión y Propuesta de Mejora 3. Tabla de evaluación 3. Taller 3 - Refactoring 1. Clase Catalogo (Code Smell: "Large Class") 1.1 Analisis 1.2 Pruebas Unitarias 1.3 Refactoring 2. Clase Perfil (Code Smell: "Speculative Generality") 2.1 Analisis 2.2 Pruebas Unitarias 2.3 Refactoring 3. Clase UsuarioNoRegistrado(Code Smell: "Lazy Class") 3.1 Analisis 3.2 Pruebas Unitarias 3.3 Refactoring 4. Link video 5. Link GitHub 6. Rubrica de Evaluación # Taller 1 - Inicio del proyecto ## **++1.1 Descripción del Proyecto:++** La Biblioteca o Malla de Juegos es una aplicación web que permite a los usuarios explorar y gestionar una colección de juegos clasificados por género y otros atributos. Los usuarios pueden buscar juegos, ver detalles, y gestionar sus propias preferencias, incluyendo la puntuación y las reseñas. **++Idea inicial:++** Aplicacion/web, Biblioteca de juegos organizados por genero y otro tipo de atributos ## **++1.2 Tecnologias:++** -SpringBoot -Front ## **++1.3 Priorizacion de funcionalidades:++** ++**Obligatorias:**++ 1. Dentro del sistema se mostrara un catalogo de juegos por el cual el usuario podra: -navegar por las secciones de juegos -seleccionar un juego 2. El sistema tendra un apartado de busqueda de juegos la cual sera una barra visible desde la landing page que tendra opciones como: -Busqueda por nombre -Filtros predeterminados (categoria, año, etc)//por definir 3. El sistema permitira mostrar una ventana con descripcion de un juego con informacion como: -Resumen del juego (titulo, genero, desarrollador, etc) -Imagen -Reseñas -Calificacion 4. Los usuarios registrados podran obtener un juego desde su ventana de descripcion con la siguiente funcion: -Añadir a biblioteca 5. El sistema tendra un registro de usuarios, este pedira datos como: -Nombre (obligatorio) -Contraseña (obligatorio) -Generos de juego favorito (opcional) 6. Los usuarios (registrados) podran acceder a sus cuentas a travez de un login el cual les pedira: -Nombre (obligatorio) -contraseña (obligatorio) 7. Los usuarios (registrados) podran acceder a su perfil el cual mostrara los siguiente: **informacion:** -Nombre de usuario -Generos favoritos de juego **Opciones:** -Ingresar a biblioteca personal -Editar perfil 8. Cada usuario (registrado) tendra una biblioteca personal (a la que podran acceder desde perfil) en la cual puede gestionar juegos (contenidos en su biblioteca) con las siguientes funcionalidades: -Puntuar un juego -Dejar una reseña textual sobre un juego -Eliminar una reseña textual hecha -Agregar juegos a su biblioteca -Agregar juegos a sus favoritos (ideal) -Eliminar juegos de sus favoritos (ideal) 9. Los usuarios (registrados) podran editar su perfil desde una ventana especial con los siguientes campos: -modificar nombre -Agregar generos favoritos de juego -Quitar generos favoritos de juego ++**Ideales:**++ 1. El usuario tendra un apartado de juegos deseados el cual se puede modificar desde el perfil con las siguientes opciones: -Agregar juegos a sus deseados -Quitar juegos de sus deseados 2. El usuario puede proporcionar un correo electronico el cual sirve para: -Recuperacion de contraseña -Mensajes de ultimas novedades (spam) 3. El usuario (registrado) podra hacer un ranking top personal de sus juegos favoritos en el cual podra: -agregar juegos de su biblioteca a al ranking (con un maximo de 10 juegos) -seleccionar juegos para eliminarlos de el ranking -subir de puesto un juego en el ranking -bajar de puesto un juego en el ranking 4. El sistema debera poder recomendar un juego segun las preferencias del usuario (registrados) esto siempre y cuando este halla dejado puntuaciones y preferencias. ++**Fuera de alcance:**++ 1. Abran usuarios con el rol de administrador que tendran permisos especiales de la pagina 2. Al ingresar al sistema se podra interactuar con un mini reproductor de musica 3. El sistema tendra una funcionalidad de compra y venta de juegos para usuarios logeados con las siguientes funcionalidades: -Comprar un juego -Vender un juego -Intercambiar juegos con otro usuario ## ++**1.4 Imagenes de Diagramas**++ **Diagrama de Flujo** ![imagen](https://hackmd.io/_uploads/rJlBhLP1Jg.png) **Diagrama de Casos de Uso** ![HyTxANKnA](https://hackmd.io/_uploads/BJlYhLwkyl.jpg) # Taller 2-Calidad e Inspección de Código ## 2. Sección Grupal ### ++2.1 Complejidad Ciclomática Total++ ![ComplejidadCiclomatica](https://hackmd.io/_uploads/rkOLWWvyJg.png) ""Resultado del análisis de la complejidad ciclomática total del proyecto."" - La complejidad ciclomática del proyecto completo es de 69. ""Análisis del riesgo asociado"" Una complejidad ciclomática de 69 representa un riesgo considerable para el proyecto, afectando la mantenibilidad, la facilidad de prueba y la capacidad de evolución del software. ### ++2.2 Complejidad Ciclomática por Clase++ ![ComplejidadClases](https://hackmd.io/_uploads/Hkajz-D1yl.png) "" Resultado de la complejidad ciclomática por cada clase."" - Para calcular la complejidad ciclomática por clase tenemos que dividir la complejidad ciclomática total por el numero de clases. Al hacer este calculo obtenemos que la complejidad por clase es de **7,6**. "" Análisis del riesgo asociado para cada clase."" - La clase con la deuda tecnica mas alta es la de catalogo con una deuda tecnica de una hora 50 minutos, la clase con el riesgo mas alto es la de usuarioRegistrado con un puntaje de c. ### ++2.3 Complejidad Ciclomática por Método++ ![ComplejidadFunciones](https://hackmd.io/_uploads/rJ0NzWD11g.png) "" Detalle de la complejidad ciclomática por método."" - En este caso dividiremos la complejidad ciclomática total en la cantidad de metodos. La complejidad sería de **1,5** por método. "" Riesgos asociados por métodos."" - Con una complejidad ciclomática de 1,5 por metodo, los riesgos asociados a los metodos no son elevedados.Aun así pueden existir riesgos ocultos en los metodos mas extensos que se camuflan dentro de esta estadistica. ### ++2.4 Análisis de Acoplamiento con CBO++ "" Diagrama de clases y explicación del CBO de cada clase."" - **Usuario:** La clase Usuario tiene una relación con la clase UsuarioNoRegistrado, ya que la flecha indica una relación de herencia CBO:1 - **UsuarioNoRegistrado:** Hereda de Usuario, por lo que está acoplada a esta clase. Aparte de esta relación, no tiene interacciones con otras clases en el diagrama CBO: 1 - **UsuarioRegistrado:** Está relacionada con la clase Usuario (herencia). Interactúa directamente con la clase Juego a través de métodos como agregarJuegoBiblioteca(), eliminarJuegoBiblioteca() y puntuarydejarReseña(). También interactúa con Perfil (crea y edita). Además, está relacionada con Biblioteca por medio de la gestión de juegos dentro de esta. CBO: 4 - **Perfil:** UsuarioRegistrado (posee una referencia a un usuario registrado). Biblioteca (posee una referencia a la biblioteca del usuario). CBO: 2 - **Reseña:** UsuarioRegistrado, ya que cada reseña está vinculada a un usuario que la escribe. Juego, dado que una reseña siempre pertenece a un juego específico. CBO: 2 - **Biblioteca:** UsuarioRegistrado (en el contexto de gestionar los juegos que tiene un usuario en su biblioteca). Juego (puesto que administra una colección de juegos). CBO: 2 - **Catalogo:** Catalogo tiene una relación directa con Juego, ya que su propósito es almacenar una lista de juegos y permitir que estos se gestionen y se muestren. CBO: 1 - **Juego:** Biblioteca (porque los juegos se guardan y eliminan de la biblioteca). Catalogo (porque el catálogo muestra y gestiona los juegos). Reseña (porque los juegos contienen reseñas). UsuarioRegistrado (porque los usuarios registrados pueden puntuar o dejar reseñas en los juegos). CBO: 4 ![imagen](https://hackmd.io/_uploads/rJlBhLP1Jg.png) "" Tipos de acoplamiento detectados: acoplamiento de datos, control, global, etc."" - 1.Acoplamiento de datos: UsuarioRegistrado tiene métodos que interactúan con la clase Juego para agregar o eliminar juegos de la biblioteca (agregarJuegoBiblioteca(), eliminarJuegoBiblioteca()), lo que implica que se pasan instancias de Juego como parámetros. También sucede con Perfil, que almacena un UsuarioRegistrado y una Biblioteca - 2.Acoplamiento de control: La clase UsuarioRegistrado utiliza métodos de Reseña como dejarReseña(), lo que sugiere que está dirigiendo el flujo de control hacia Reseña. Esto indica una dependencia en la secuencia de llamadas entre métodos. ## ++3. Sección Individual++ ### 3.1 Sebastian Aillapan - Análisis de Cohesión y Propuesta de Mejora #### 3.1.1 Análisis de Cohesión (LCOM4) *Clase analizada: `Juego.java` Resultado del análisis de cohesión (LCOM4): Métodos de la clase Juego: **getTitulo():** Accede a titulo. **setCalificacion():** Accede a calificacion. **agregarResena():** Accede a resenas. **eliminarResena():** Accede a resenas. **mostrarDetalles():** Accede a titulo, genero, desarrollador, calificacion, y imagen. Grupo 1: Métodos que acceden a titulo: **getTitulo()** y **mostrarDetalles()**. Grupo 2: Métodos que acceden a calificacion: **setCalificacion()** y **mostrarDetalles()**. Grupo 3: Métodos que acceden a resenas: **agregarResena()** y **eliminarResena()**. Grupo 4: El método **mostrarDetalles()** interactúa con varios atributos, pero no todos. El valor de LCOM4 en este caso sería mayor que 1 debido a que tenemos varios subconjuntos de métodos que no interactúan entre sí, lo que indica que la cohesión de la clase es baja. ##### Tipos de cohesión detectados: **Cohesión funcional:** Está presente en métodos como agregarResena() y eliminarResena(), que cumplen una tarea específica relacionada con la gestión de reseñas. **Cohesión de control:** En los métodos que gestionan las reseñas, hay cierta dependencia del estado de la lista resenas. **Cohesión lógica:** En métodos como mostrarDetalles(), donde se accede a múltiples atributos para mostrar la información del juego, se observa cierta cohesión lógica, pero podría mejorarse si este método gestionara más atributos. ### 3.1.2 Propuesta de Mejora de Acoplamiento Clase analizada: `Juego.java` #### Propuesta detallada de mejora para reducir el acoplamiento: los puntos principales de acoplamiento son: 1.- Dependencia directa de la clase Reseña: La clase Juego tiene una lista de reseñas que están directamente acopladas a la clase Reseña. 2.- Dependencia directa de tipos específicos (como String, ArrayList): Aunque no es tan problemático como la dependencia de otras clases, aún puede mejorarse la flexibilidad del código. **Propuesta:** 1) Reducir el acoplamiento con Reseña: Utilizando una interfaz como Resenable, logramos que Juego no dependa directamente de la implementación específica de Reseña. Esto permitirá que en el futuro se puedan utilizar otros tipos de reseñas sin modificar la clase Juego. 2) Mejorar la flexibilidad de las colecciones: Al usar la interfaz List en lugar de ArrayList, se reduce el acoplamiento con una implementación específica de la colección. 3) Opcional: Desacoplar la gestión de imágenes: Al usar una interfaz para gestionar cómo se obtienen las imágenes, se reduce el acoplamiento entre la clase Juego y cómo se maneja el almacenamiento de las imágenes. #### 3.1.3 Propuesta de Mejora de Cohesión Propuesta para mejorar la cohesión de la clase analizada (ClaseX.java). ### 3.2 Orlando Caullan - Análisis de Cohesión y Propuesta de Mejora #### 3.2.1 Análisis de Cohesión (LCOM4) **Clase analizada**: `Perfil.java` #### Resultado del análisis de cohesión (LCOM4) La métrica **LCOM4** indica que la clase `Perfil` tiene **alta cohesión**, ya que sus métodos interactúan con los mismos atributos (`usuario` y `biblioteca`). Esto sugiere que los métodos están bien relacionados con los datos de la clase. Tipos de cohesión detectados: - **Cohesión funcional**: Los métodos `mostrarInformacion()` y `editarInformacion()` están relacionados con los atributos `usuario` y `biblioteca`, mostrando un comportamiento cohesionado. #### 3.2.2 Propuesta de Mejora de Acoplamiento (CBO) **Clase analizada**: `Perfil.java` Análisis del acoplamiento La clase `Perfil` tiene un acoplamiento alto con las clases: - `UsuarioRegistrado` - `Biblioteca` Problema detectado: - La clase depende directamente de los detalles de implementación de `UsuarioRegistrado` y `Biblioteca`, lo que aumenta su acoplamiento y puede generar problemas de mantenimiento si estas clases cambian en el futuro. Propuesta detallada de mejora para reducir el acoplamiento: - Utilizar **Inyección de Dependencias** para evitar que `Perfil` dependa directamente de `UsuarioRegistrado` y `Biblioteca`. - Implementar **abstracciones** para reducir la dependencia de clases concretas, favoreciendo el uso de interfaces u otras soluciones que desacoplen las dependencias. #### 3.2.3 Propuesta de Mejora de Cohesión (LCOM4) **Clase analizada**: `Perfil.java` Análisis de la cohesión actual: La clase `Perfil` tiene buena cohesión actualmente, ya que sus métodos (`mostrarInformacion()` y `editarInformacion()`) acceden a los mismos atributos (`usuario` y `biblioteca`). Propuesta para mejorar la cohesión: - En el caso de que se añadan más métodos que operen exclusivamente sobre uno de los atributos (`usuario` o `biblioteca`), se recomienda dividir la clase en dos clases más especializadas. Esto garantizaría que cada clase mantenga una cohesión alta al interactuar con un conjunto común de atributos. ### 3.3 Nicolas Toledo - Análisis de Cohesión y Propuesta de Mejora #### 3.3.1 Análisis de Cohesión (LCOM4) Clase analizada: UsuarioRegistrado.java Resultado del análisis de cohesión (LCOM4): - La clase UsuarioRegistrado tiene una cohesión de 3 lo que indica que esta clase esta haciendo demasiadas cosas distintas. Metodos de que interactuan con biblioteca ![image](https://hackmd.io/_uploads/BkOHwLvJke.png) Metodos que interactuan con Juego ![image](https://hackmd.io/_uploads/ByR_uLPkJe.png) Tipos de cohesión detectados: - 1. Grupo Manejo de la sesión: **Metodos:** iniciarSesion() **Atributos:** nombre, contraseña **Desc:** Este grupo tiene cohesión funcional porque está enfocado en una sola funcionalidad. - 2. Grupo Gestión de la biblioteca: **Metodos:** getBiblioteca(), agregarJuegoBiblioteca(), eliminarJuegoBiblioteca(), buscarJuegoPorNombre(), filtrarJuegos(). **Atributos:** biblioteca **Desc:** Este grupo presenta una cohesión de comunicación, ya que los metodos no dependen entre si pero trabajan con los mismos datos. - 3. Grupo Gestión de reseñas y puntuaciones: **Metodos:** puntuarJuego(), dejarResena(), eliminarResena(). **Atributos:** Ningún atributo propio de la clase, interactuan con un objeto Juego y reseña. **Desc:** Este grupo tiene cohesión funcional porque todos los métodos están relacionados con la funcionalidad de gestión de reseñas y puntuación de los juegos. #### 3.3.2 Propuesta de Mejora de Acoplamiento (CBO) Clase analizada: UsuarioRegistrado.java - Al reubicar los metodos de biblioteca y reseña que no corresponden a esta clase disminuira el acoplamiento de esta clase. #### 3.3.3 Propuesta de Mejora de Cohesión (LCOM4) - Se propone separar las responsabilidades que tiene la clase de usuarioRegistrado.Los metodos que interactuan con la clase biblioteca pasaran a estar dentro de biblioteca, lo mismo con los metodos de reseña que pasar a estar en la clase reseña, al dividir estos metodos las tres clases que quedaran tendran un LCOM4 de 1 y una cohesión funcional. ### 3.4 John Fernandez - Análisis de Cohesión y Propuesta de Mejora #### 3.4.1 Análisis de Cohesión (LCOM4) **Clase analizada:** `Resena.java` ![imagen](https://hackmd.io/_uploads/rJvRjBwyyg.png) ![imagen](https://hackmd.io/_uploads/S1fW3rw1Jl.png) #### Resultado del análisis de cohesión (LCOM4): en la clase existen 3 componentes distintos: 1) incluye solo el método **getUsuario()**. 2) incluye los métodos que acceden a eliminada(**getTexto(),editarTexto(),eliminar(), esEliminada()**). 3) incluye solo el método **getFechaCreacion()** en resumen el LCOM4 de la clase Resena es 3, lo que significa que la cohesión de la clase es moderada a baja,lo que indica que hay espacio para mejorar la organización interna de la clase, haciendo que los métodos trabajen más en cojunto o asignando responsabilidades a otras clases. #### Tipos de cohesión detectados: **1.- Cohesión Funcional:** los métodos **eliminar()** y **esEliminada()** trabajan en conjunto para manejar el estado de la reseña eliminada. Esto sugiere que estan cohesionados funcionalmente, ya que su propósito es gestionar el mismo aspecto de la clase. **2.- Cohesión Temporal:** aparece en el constructor de la clase, ya inicializa los atributos **usuario**,**texto**,**fechaCreacion**, y **eliminada** al mismo tiempo cuando se crea una nueva instancia de la clase. **3.- Cohesión Lógica:** **getUsuario** y **getTexto()** no comparten atributos, pero estan cohesionados lógicamente porque ambos son aspectos importantes de una reseña. #### 3.4.2 Propuesta de Mejora de Acoplamiento (CBO) Clase analizada: `Resena.java` Propuesta detallada de mejora para reducir el acoplamiento: 1) Se podria desacoplar **Resena** de **UsuarioRegistrado** y utilizar una interfaz Usuario par aque la Resena no dependa directamente de UsuarioRegistrado. Ejemplo: ![imagen](https://hackmd.io/_uploads/HkdjANvJJe.png) 2) También podríamos desacoplar **Resena** de **Juego** y usar una interfaz Contenido Reseñable para que Resena pueda aceptar Cualquier contenido de Juego u otras clases que puedan ser necesarias a futuro. Ejemplo: ![imagen](https://hackmd.io/_uploads/ryMjyHwJJg.png) Estas mejoras harán que el codigo sea más flexible, modular y menos propenso a errores si alguna de las clases cambien en el futuro, cumpliendo con el objetivo de reducir los riesgos y el acoplamiento. #### 3.4.3 Propuesta de Mejora de Cohesión (LCOM4) Las propuestas de mejora para la cohesión de la clase Reseña incluyen: la edición del texto y la fecha de edición en un método más completo (actualizarResena()). Añadir un método para restaurar reseñas eliminadas, permitiendo una gestión más completa del estado de eliminación. Agregar un método mostrarDetalles() para devolver todos los detalles relevantes de la reseña en un solo lugar. Centralizar la validación del texto en un método privado, mejorando la cohesión lógica. Estas mejoras harán que la clase Reseña sea más cohesiva y organizada, ya que los métodos estarán más relacionados entre sí y con los atributos que gestionan. ### 3.5 Julio Contreras - Análisis de Cohesión y Propuesta de Mejora #### 3.5.1 Análisis de Cohesión (LCOM4) Clase analizada: [Catalogo].java ![image](https://hackmd.io/_uploads/ByEGcUv1kl.png) ##### Resultado del análisis de cohesión (LCOM4): El análisis de cohesión en la clase Catalogo muestra que los métodos dentro de la clase tienen responsabilidades diversas en concreto hay dos tipos de componentes: 1.- Métodos que manejan la lista de juegos (ingresarJuego, mostrarCatalogo). 2.- Metodos que se encargan de la interacción con la API (conseguirIDs, conseguirJuegos). En resumen el LCOM4 de la clase es de 2 y sus funciones son manejar tanto la lógica de administración de juegos como la comunicación con la API. ##### Tipos de cohesión detectados: **1.- Cohesión Funcional:** Algunos métodos como ingresarJuego() y mostrarCatalogo() están cohesionados, ya que todos trabajan directamente con la lista de juegos. **2.-Cohesión lógica:** Los métodos que interactúan con la API (conseguirIDs() y conseguirJuegos()) dependen de parámetros como las URLs y las respuestas HTTP, pero no están directamente relacionados con la administración interna de los juegos. #### 3.5.2 Propuesta de Mejora de Acoplamiento (CBO): Clase analizada: [Catalogo].java **1.- Separación de responsabilidades:** Se propone dividir la responsabilidad de la clase en dos partes: una para manejar el catálogo de juegos y otra para la comunicación con la API. De esta manera, se reduce el acoplamiento directo de la clase Catalogo con elementos externos como HttpURLConnection y JSONObject, delegando la comunicación con la API a una clase externa que se encargue de estos detalles. **2.- Inyección de dependencias:** Introducir una instancia externa para el servicio API mediante inyección de dependencias. Esto permite desacoplar la clase Catalogo de los detalles de implementación de la API. #### 3.5.3 Propuesta de Mejora de Cohesión (LCOM4) **Propuesta:** Dividir la clase Catalogo en dos clases con responsabilidades claras: una clase encargada de gestionar el catálogo de juegos (administración, visualización) y otra clase que maneje la comunicación con la API externa. Esto aumenta la cohesión funcional de cada clase, ya que cada una tendrá una responsabilidad única y bien definida. Al separar las funcionalidades relacionadas con la API, se logra que la clase Catalogo solo maneje la lógica de los juegos, lo que incrementa la cohesión y facilita el mantenimiento y la extensibilidad del código. ## Tabla de evaluación ![image](https://hackmd.io/_uploads/rksCS6Lyyx.png) # Taller 3 - Refactoring ## 1. Clase Catalogo (Code Smell: "Large Class") ### 1.1 Analisis **Code Smell detectados:** Long Method y Large Class **Técnica de Refactoring:** Extract Class **++Contexto++** La clase "Catalogo" es muy larga, tiene 2 métodos (con más de 30 líneas cada 1) que se pueden dividir en métodos más pequeños, sin embargo el code smell “long method”, puede resolverse de paso al aplicar “Extract Class” y crear una clase la cual gestione de mejor manera estos 2 métodos (y de paso aplicar “extract method”) los cuales cumplen dos funciones a la vez. **++Clase Catalogo pre-Refactoring:++** ![image](https://hackmd.io/_uploads/SylBHGa-kl.png) **Solucion Propuesta:** La clase se va a separar en 3, una para crear y gestionar catálogo, otra para las funcionalidades que recopilan información de la api y la ultima que creara los juegos del catálogo a partir de los datos recopilados de la clase anterior. --- ### 1.2 Pruebas Unitarias Las pruebas unitarias hechas para "Catalogo" fueron generadas con ia tomando en cuenta que esta clase se va a refactorizar más adelante y las pruebas se tienen que mantener para las funcionalidades de catalogo, los métodos a testear y los cuales después del refactoring deberían de funcionar como antes son los siguientes: ![image](https://hackmd.io/_uploads/BJetvMTZkl.png) **++Consideraciones dentro de las PU:++** 1. Debido a la separación de clases, las pruebas unitarias irreparablemente tendrán que cambiar su sintaxis, sin embargo se van a testear las mismas 4 funcionalidades principales intentado cambiar solo las instancias a la clase "Catalogo" por la clase necesaria. 2. El método mostrarCatalogo no modifica ni devuelve nada dentro del código por lo que en este caso se omitió dentro de las pruebas para poder mostrar su funcionamiento por consola en el video. **++Peticion de pruebas unitarias a IA++** Después de definir los métodos importantes que mantienen la integridad de las funcionalidades de catálogo se le pidió el siguiente prompt a Chat Gpt: *“Quiero que me ayudes a hacer pruebas unitarias para una clase hecha en Java, siguiendo la rúbrica que te proporcione, a la clase en cuestión se le aplicará un refactoring ya que esta presenta el code smell "large class", esto porque la clase llamada catálogo maneja 3 tareas las cuales pueden dividirse en más clases, lo que se hará será lo siguiente: La clase se va a separar en 3, una para crear y gestionar catálogo, otras para las funcionalidades que recopilan información de la api y las que crean los juegos del catálogo. Ten en cuenta que las pruebas unitarias deben de estar diseñadas para que funciones antes y después del refactoring, aunque sea prácticamente imposible mantener las pruebas 100% estáticas después del cambio que resulta separar una clase, quiero que crees las pruebas unitarias para que se parezcan lo más posible a su versión pre-refactoring.”* Al entregarle la rúbrica de evaluación y la clase a refactorizar las pruebas generadas fueron las siguientes: class CatalogoTest { private Catalogo catalogo; @BeforeEach void setUp() { catalogo = new Catalogo(); } @Test void testIngresarJuego() { Juego juego = new Juego("Titulo1", "2022", "Accion", "Desarrollador1", "url_imagen", "Descripción breve"); catalogo.ingresarJuego(juego); assertEquals(1, catalogo.getListaJuegos().size()); assertEquals("Titulo1", catalogo.getListaJuegos().get(0).getTitulo()); } @Test void testIngresarID() { catalogo.ingresarID(123); catalogo.ingresarID(123); // Intentamos agregar la misma ID otra vez assertEquals(1, catalogo.gameIDs.size()); // La ID no debe duplicarse } @Test void testConseguirIDs() { // Simulamos la obtención de IDs de la API catalogo.conseguirIDs(); assertFalse(catalogo.gameIDs.isEmpty()); // Verificamos que la lista de IDs no esté vacía después de la llamada } @Test void testConseguirJuegos() { // Primero agregamos algunas IDs catalogo.ingresarID(1); catalogo.ingresarID(2); // Ejecutamos el método para conseguir los juegos catalogo.conseguirJuegos(); // Verificamos que los juegos fueron añadidos assertFalse(catalogo.getListaJuegos().isEmpty()); } } **++Conclusion de la PU:++** Las pruebas obtenidas de la ia resultaron ser adecuadas a nuestro criterio para asegurar que el proceso de refactoring sea bien implementado y que no cambie el funcionamiento del catalogo, despues del refactoring lo unico que se cambio en las pruebas fue una instancia adicional de "CreadorJuegos" que contiene los metodos "ingresarID" y "getGameIDs", El uso de la ia fue beneficioso pero no crucial pues desde un principio ya se definio los puntos a testear y mantener en el funcionamiento de catalogo. --- ### 1.3 refactoring **++Resumen:++** Se aplico la tecnica de refactoring **"Extract Class"**, separando la clase catalogo en 3: 1. Catalogo: Clase encargada de gestionar el catalogo de juegos 2. CreadorJuegos: Clase encargada de crear instancias de juego 3. Clase encargada de extraer datos sobre juegos desde una api **++Resultados++** El funcionamiento del catalogo siguio tal cual antes y despues del refactoring con la excepcion del metodo ++"conseguirIDs"++ que paso de estar en "Catalogo" a "CreadorJuegos", necesitando una llamada de atributo mas: Catalogo.conseguirIDs(); ---> catalogo.getCreadorJuegos().conseguirIDs(); Despues de aplicar **"Extract Class** este es el resultado": --- **++Catalogo:++** ![image](https://hackmd.io/_uploads/Hkzs9Xa-Je.png) --- **++CreadorJuegos:++** ![image](https://hackmd.io/_uploads/HJRpqXTWkx.png) --- **++ConsultorApi:++** ![image](https://hackmd.io/_uploads/S1i1jX6Zkx.png) --- **++Conclusion del refactoring:++** Ahora la clase Catalogo cumple unicamente su funcion dejando las otras funcionalidades a otras clases, mejorando la cohesion de esta. durante el proceso pre y post refactoring la salida no cambio: ++uso del catalogo++ //pruebas catalogo post-refactoring Catalogo catalogo = new Catalogo(); catalogo.mostrarCatalogo(); catalogo.conseguirJuegos(); catalogo.getCreadorJuegos().conseguirIDs(); catalogo.conseguirJuegos(); catalogo.mostrarCatalogo(); //pruebas catalogo pre-refactoring CatalogoPreR preCatalogo = new CatalogoPreR(); preCatalogo.mostrarCatalogo(); preCatalogo.conseguirJuegos(); preCatalogo.conseguirIDs(); preCatalogo.conseguirJuegos(); preCatalogo.mostrarCatalogo(); ++salida (ambos casos):++ El catálogo está vacío de momento Primero se tienen que ingresar las ID al catálogo IDs conseguidas Se añadió el juego 'Grand Theft Auto V' al catálogo Se añadió el juego 'The Witcher 3: Wild Hunt' al catálogo Se añadió el juego 'Portal 2' al catálogo Se añadió el juego 'Counter-Strike: Global Offensive' al catálogo Se añadió el juego 'Tomb Raider (2013)' al catálogo Se añadió el juego 'Portal' al catálogo Se añadió el juego 'Left 4 Dead 2' al catálogo Se añadió el juego 'The Elder Scrolls V: Skyrim' al catálogo Se añadió el juego 'Red Dead Redemption 2' al catálogo Se añadió el juego 'BioShock Infinite' al catálogo ----------------------------------------------------------------------------------------- Título: Grand Theft Auto V Género: Action Desarrollador: Rockstar North, Rockstar Games Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/20a/20aa03a10cda45239fe22d035c0ebe64.jpg ----------------------------------------------------------------------------------------- Título: The Witcher 3: Wild Hunt Género: Action, RPG Desarrollador: CD PROJEKT RED Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/618/618c2031a07bbff6b4f611f10b6bcdbc.jpg ----------------------------------------------------------------------------------------- Título: Portal 2 Género: Shooter, Puzzle Desarrollador: Valve Software Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/2ba/2bac0e87cf45e5b508f227d281c9252a.jpg ----------------------------------------------------------------------------------------- Título: Counter-Strike: Global Offensive Género: Shooter Desarrollador: Valve Software, Hidden Path Entertainment Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/736/73619bd336c894d6941d926bfd563946.jpg ----------------------------------------------------------------------------------------- Título: Tomb Raider (2013) Género: Action, Fighting Desarrollador: Crystal Dynamics Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/021/021c4e21a1824d2526f925eff6324653.jpg ----------------------------------------------------------------------------------------- Título: Portal Género: Action, Puzzle Desarrollador: Valve Software, NVIDIA Lightspeed Studios Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/7fa/7fa0b586293c5861ee32490e953a4996.jpg ----------------------------------------------------------------------------------------- Título: Left 4 Dead 2 Género: Action, Shooter Desarrollador: Valve Software, Turtle Rock Studios Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/d58/d588947d4286e7b5e0e12e1bea7d9844.jpg ----------------------------------------------------------------------------------------- Título: The Elder Scrolls V: Skyrim Género: Action, RPG Desarrollador: Bethesda Game Studios Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/7cf/7cfc9220b401b7a300e409e539c9afd5.jpg ----------------------------------------------------------------------------------------- Título: Red Dead Redemption 2 Género: Action Desarrollador: Rockstar Games Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/511/5118aff5091cb3efec399c808f8c598f.jpg ----------------------------------------------------------------------------------------- Título: BioShock Infinite Género: Action, Shooter Desarrollador: Aspyr Media, 2K Australia, Irrational Games Calificación: 0.0 Url de Imagen: https://media.rawg.io/media/games/fc1/fc1307a2774506b5bd65d7e8424664a7.jpg --- ## 2. Clase Perfil (Code Smell: "Speculative Generality") ### 2.1 Analisis **Code Smell detectados:** Speculative Generality **Técnica de Refactoring:** Inline Class, Remove Parameter ++Contexto++ La clase ++"Perfil"++ en su primera version contenia un atributo de biblioteca que no se usaba en el codigo actual, lo cual indica que tiene un "Speculative Generality" esto suele ocurrir cuando un atributo o clase anticipa una necesidad que no existe. Para resolver estos problemas, se aplicaron las siguientes técnicas de refactorización: ++**Inline Class:**++ Esta tecnica se utilizo para simplificar la clase, eliminando la referencia innecesaria a ++"Biblioteca"++ ya que no se requeria para la funcion actual de ++"Perfil"++. Al quitarla, la clase se centro en su proposito principal, que es representar la informacion de++"UsuarioRegistrado"++, reduciendo asi el acoplamiento y mejorando la cohesion. ++**Remove Parameter:**++ Tambien aplicamos Remove Parameter. Esta simplificacion elimino metodo adicional, haciendo que la clase fuera más directa y ligera, sin metodos necesario que no aportaban valor a su funcionalidad. ++**Clase Perfil pre-Refactoring:**++ ![imagen_2024-11-09_152139223](https://hackmd.io/_uploads/SyhEu7Tb1l.png) **Solucion Propuesta:** La solucion es eliminar la clase biblioteca que se genera dentro de perfil ya que esta como una clase innecesaria y eliminar el metodo de editarInformacion(). ### 2.2 Pruebas Unitarias Las pruebas unitarias fueron creadas por nuestra cuenta en la cual un test consiste en la creacion de la clase perfil y otro test para ver el metodo mostrar informacion con un assert si coicide que el usuario que se le entrego. ``` package org.example; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import java.io.ByteArrayOutputStream; import java.io.PrintStream; public class PerfilTest { private Perfil perfil; private UsuarioRegistrado usuario; private final ByteArrayOutputStream ContenidoSystem = new ByteArrayOutputStream(); @BeforeEach void setUP(){ usuario = new UsuarioRegistrado(1,"juanito", "22123"); System.setOut(new PrintStream(ContenidoSystem)); } @Test void CrearPerfil() { Perfil perfil = new Perfil(usuario); assertNotNull(perfil, "La clase perfil no fue creada correctamente"); } @Test void MostrarInformacion(){ Perfil perfil = new Perfil(usuario); perfil.mostrarInformacion(); String MostratUsuario = "Mostrando información del perfil del usuario: " + usuario.toString() + System.lineSeparator(); assertEquals(MostratUsuario, ContenidoSystem.toString()); } } ``` ++**Comprobacion de funcionamiento:**++ ![image](https://hackmd.io/_uploads/SyQAY4TWJx.png) ### 2.3 Refactoring ++**Resumen:**++ Se aplicaron las tecnicas de refactoring **"Inline Class"** a la clase biblioteca y **"Remove Parameter"** al metodo de editarInformacion(). **++Resultados++** Después de aplicar los cambios la clase quedo de esta manera: ![image](https://hackmd.io/_uploads/HknEsI6Wyx.png) Para comprobar que sigue funcionando tenemos los resultado de las pruebas unitarias: ![image](https://hackmd.io/_uploads/HysS3LT-Je.png) **++Conclusion del refactoring:++** Después de refactorizar la clase perfil se logro una clase más limpia sin metodos adicionales que molestara la clase cumpliendo unicamente su funcion. ## 3. Clase UsuarioNoRegistrado(Code Smell: "Lazy Class") ### 3.1 Análisis **Code Smell detectado:** Lazy Class **Técnica de Refactoring:** Inline Class **++Contexto++** La clase UsuarioNoRegistrado no cumple ninguna función en especifico, sus métodos son solo prints de mensajes y además esta clase no era usada nunca en la aplicación. **++Clase UsuarioNoRegistrado pre-Refactoring:++** ![Captura de pantalla 2024-11-09 141040](https://hackmd.io/_uploads/ByGCwmpbyg.png) **++Clase UsuarioRegistrado pre-Refactoring:++** ![image](https://hackmd.io/_uploads/BJzDYXaZJl.png) ![image](https://hackmd.io/_uploads/HyfFKX6-ke.png) ![image](https://hackmd.io/_uploads/Sy13Yma-1e.png) ![image](https://hackmd.io/_uploads/SydCFQa-ke.png) **Solucion propuesta:** Al aplicar la técnica de refactoring inline class, UsuarioNoRegistrado puede quedar como un parámetro booleano en usuarioRegistrado donde el parametro es true si el usuario esta registrado y false si el usuario no esta registrado. ### 3.2 Pruebas Unitarias Las pruebas se generaron para la clase usuarioRegistrado para chequar que al agregar el parámetro que remplaza a la clase UsuarioNoRegistrado este no afecte el funcionamiento de la clase. ``` package org.example; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import static org.junit.jupiter.api.Assertions.*; class UsuarioRegistradoTest { static UsuarioRegistrado usuarioRegistrado; static Juego juegoTest; @BeforeAll static void setUpBeforeClass(){ usuarioRegistrado = new UsuarioRegistrado(1,"Test","123"); juegoTest = new Juego("Titulo1", "2022", "Accion", "Desarrollador1", "url_imagen", "Descripción breve"); } @Test void testIniciarSesion() { ByteArrayOutputStream outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); usuarioRegistrado.iniciarSesion("123"); assertEquals("Iniciando sesión para el usuario: Test\r\n",outContent.toString()); System.setOut(System.out); } @Test void testIniciarSesionClaveIncorrecta() { ByteArrayOutputStream outContent = new ByteArrayOutputStream(); System.setOut(new PrintStream(outContent)); usuarioRegistrado.iniciarSesion("1234"); assertEquals("contrasena no valida",outContent.toString()); System.setOut(System.out); } @Test void testAgregarJuegoBiblioteca() { usuarioRegistrado.agregarJuegoBiblioteca(juegoTest); assertFalse(usuarioRegistrado.getBiblioteca().getJuegos().isEmpty()); } @Test void testEliminarJuegoBiblioteca() { usuarioRegistrado.eliminarJuegoBiblioteca(juegoTest); assertTrue(usuarioRegistrado.getBiblioteca().getJuegos().isEmpty()); } @Test void testDejarResena(){ usuarioRegistrado.dejarResena(juegoTest,"Resena Test"); assertFalse(juegoTest.getResenas().isEmpty()); } @Test void testDejarResenaVacia(){ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> usuarioRegistrado.dejarResena(juegoTest, "") ); assertEquals("El texto de la reseña no puede estar vacío.", exception.getMessage()); } @Test void testEliminarResena(){ usuarioRegistrado.eliminarResena(juegoTest,juegoTest.getResenas().get(0)); assertTrue(juegoTest.getResenas().isEmpty()); } @Test void testPuntuarJuego(){ usuarioRegistrado.puntuarJuego(juegoTest,1); assertEquals(1,juegoTest.getCalificacion()); } } ``` ### 3.3 Refactoring #### Pre-Refactoring: La clase UsuarioNoRegistrado extiende de Usuario para representar a usuarios que aún no se han registrado. Esta clase incluye métodos específicos como registrar() e iniciarComoInvitado(), pero su funcionalidad se limita a operaciones muy básicas que no aprovechan realmente el beneficio de una jerarquía de clases. Esto incrementa la complejidad del código, pues se deben gestionar dos tipos de usuarios, UsuarioRegistrado y UsuarioNoRegistrado, aunque el comportamiento es en gran medida similar. #### Refactorig: Para simplificar y refactorizar nuestra clase UsuarioNoRegistrado, es conveniente eliminarla y trasladar su funcionalidad a la clase UsuarioRegistrado usando un atributo booleano, por ejemplo, estaRegistrado. Esto eliminará la necesidad de una jerarquía separada para los usuarios no registrados y reducirá el código duplicado. ##### 1.- Identificamos en qué clases o métodos se utiliza UsuarioNoRegistrado: En nuestro caso ninguna clase está ocupando ni referenciando a la clase UsuarioNoRegistrado solo a usuarioRegistrado. ##### 2.- Evaluar el Propósito del código dentro de UsuarioNoRegistrado: luego de la inspección de código cruzada que podríamos integrar directamente en otra clase o manejarse con una clase Usuario genérica. pero como existe la clase UsuarioRegistrado es mejor integrar a esta clase los métodos o funciones pensadas en UsuarioNoRegistrado. Y mover cualquier validación específica o lógica de UsuarioNoRegistrado si es necesario. #### Cambios principales: ##### 1.- Clase UsuarioRegistrado: • Agregamos el constructor y el metodo estaRegistrado, el cual usamos para condicionar el acceso a métodos. • Cada método restringido verifica estaRegistrado y responde si el usuario no tiene permisos. ##### 2.- Clase UsuarioNoRegistrado: • Clase completa eliminada #### Post-Refactoring: Se elimina la clase UsuarioNoRegistrado y se integra su funcionalidad directamente en la clase UsuarioRegistrado mediante un atributo booleano (esRegistrado). Con este enfoque, un usuario puede estar registrado o no dependiendo del valor de este atributo, y todos los métodos están en una sola clase, simplificando la jerarquía y reduciendo el código repetitivo. Este refactoring mejora la legibilidad y facilita el mantenimiento, ya que ahora se gestiona solo una clase. Se elimina la clase UsuarioNoRegistrado y se integra su funcionalidad directamente en la clase UsuarioRegistrado mediante un atributo booleano (esRegistrado). Con este enfoque, un usuario puede estar registrado o no dependiendo del valor de este atributo, y todos los métodos están en una sola clase, simplificando la jerarquía y reduciendo el código repetitivo. Este refactor mejora la legibilidad y facilita el mantenimiento, ya que ahora se gestiona solo una clase. #### Pruebas Unitarias: Las pruebas unitarias siguen funcionando sin problemas: ![image](https://hackmd.io/_uploads/r1eVDHTbkg.png) --- ## Link del video: https://drive.google.com/drive/folders/1eZGSWbrvRxL-hWZQwbZ65e68zgmy2l1X?usp=sharing --- ## Link del GitHub: https://github.com/ElCuervas/n-migos.java --- ## Rubrica de evaluacion: ![image](https://hackmd.io/_uploads/rkY0C86bJx.png)

    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