3.4.03. Clean code - diezMalena/api_FCTFiller GitHub Wiki

Justificación y objetivos

FCTFiller es un proyecto colaborativo en el que participamos seis desarrolladores junior, desarrollando funcionalidades de forma coordinada pero independiente, en una metodología ágil como lo es Scrum. En este contexto, por mucho que se pongan unas bases de trabajo comunes, es fácil que haya que limpiar el código de cuando en cuando.

Los objetivos que se buscan con esto son dos:

  1. Limpiar el código que se ha hecho hasta la fecha.
  2. Establecer unas bases para desarrollar el código de forma más organizada y limpia.

¿A qué nos referimos con limpiar el código? Podemos dividirlo en varias tareas:

Eliminar código sobrante

Código relacionado con la depuración de errores

Durante el desarrollo, utilizamos funciones nativas de los lenguajes y los framework que nos ayudan a saber qué está haciendo nuestro código cuando nos falla algo o, simplemente, queremos probarlo. Son los error_log(), dd() o print_r() de Laravel; y los console.log() en Angular. Las llamadas a estas funciones suelen quedarse en el código, aunque sea comentado, tras terminar el desarrollo de una funcionalidad. En ese momento, rara vez tienen utilidad (y, si la tienen, se pueden recuperar fácilmente).

Se deben eliminar todas las del código más o menos estable.

Comentarios innecesarios

Es común que comentemos y descomentemos trozos de código cuando desarrollamos, por miedo a perder trabajo o ideas que nos podrían ser útiles. También es común que nos olvidemos de eliminar el código comentado que ya no nos sirve, así como las ideas que hemos anotado y que ya no aplican al desarrollo.

Se deben eliminar todas las llamadas a métodos y los fragmentos de código comentados, así como las ideas comentadas, que no aporten nada al desarrollo futuro.

Se deben conservar los comentarios que sirvan como guía para entender el código o que contengan ideas para el desarrollo futuro.

Documentación de métodos

En un proyecto colaborativo como éste, todos necesitaremos usar métodos que han desarrollado otros compañeros. Al mismo tiempo, desarrollaremos métodos que otros compañeros necesitarán. Para que sepamos usarlos correctamente y depurar nuestro código en caso de que algo falle, es importante que documentemos los métodos, incluyendo, en el siguiente orden:

  1. Explicación de la funcionalidad del método.
  2. Parámetros (@param): tipo y significado.
  3. Valor devuelto (@return): tipo, significado y posibles valores
  4. Autor o autores (@author): Nombre <email>

Además, es conveniente que añadamos comentarios explicando partes del código que creamos que pueden ser vitales o difíciles de entender.

Formato general común

Gran parte de los estándares de formato se pueden alcanzar usando el formateador automático del editor de código que usamos (Visual Studio Code). Se debe pasar el formateador automático en todos los archivos antes de hacer commit.

Sería conveniente picar código teniendo en cuenta unos mínimos:

  • Declarar las variables en camel case, comenzando en minúscula (variableDeEjemplo).
  • Declarar las clases y modelos en camel case, comenzando en mayúscula (ModeloDeEjemplo).
  • Declarar los atributos de las tablas de la base de datos en snake case (atributo_ejemplo). Por coherencia y comodidad, los atributos de los modelos y clases tendrán el mismo formato.
  • No dejar más de dos líneas vacías consecutivas.
  • Dejar un espacio entre la declaración de una función y la llave, o un salto de línea.
  • Dejar un espacio antes y después de expresiones de asignación de variables (=) y operaciones booleanas (===, >, &&...).
  • Dejar una línea vacía entre agrupaciones de código o bloques diferenciados.
  • Si se declaran varias variables al inicio de una función o estructura, ponerlas al principio y separarlas del resto del código con un salto de línea.

Agrupación de métodos (y código) por funcionalidad: #region y #endregion

En cualquier proyecto mínimamente extenso, es importante agrupar los métodos según la funcionalidad a la que están asociados, de forma que se mantenga cierto orden y el código sea más fácil de explorar. La estructura #region ... #endregion está presente en muchos lenguajes de programación y de marcas actuales, y nos permite agrupar código bajo un título para contraerlo o visualizarlo a conveniencia en los editores de código.

Se debe agrupar el código, usando #region ... #endregion, en los tres lenguajes en los que está escrito el proyecto: php, js y html

PHP - Laravel

En la parte del servidor, pondremos énfasis agrupando el código de dos tipos de archivos: el archivo de rutas (api.php) y los Controladores.

  • Empezando por api.php:

    • Se agruparán las rutas por perfil (o funcionalidad, si no se asocian a ningún perfil), utilizando la función Route::group(...) de Laravel.
    • Si es necesario, se aplicará un prefijo.
    • Se deberán aplicar los middleware correspondientes a cada grupo (Cors invariablemente)
    • Sobre la agrupación, deberá ponerse un decorador que detalle de qué perfil son las rutas que se están agrupando.
    • Dentro de la agrupación, se colocará un decorador que delimite un subgrupo de rutas por funcionalidad.
    • Ejemplo:
    /*
    |--------------------------------------------------------------------------
    | Rutas para los perfiles de jefatura
    |--------------------------------------------------------------------------
    */
    Route::group(['prefix' => 'jefatura', 'middleware' => ['Cors', 'auth:api']], function () {
        /*******************************SUBIDA CSV*******************************/
        Route::post('recibirCSV', [ControladorJefatura::class, 'recibirCSV']);
        /************************************************************************/
        
        /******************************CRUD ALUMNOS******************************/
        Route::get('/listarAlumnos/{dni_logueado}', [ControladorJefatura::class, 'listarAlumnos']);
        Route::get('/verAlumno/{dni_alumno}', [ControladorJefatura::class, 'verAlumno']);
        Route::post('/addAlumno', [ControladorJefatura::class, 'addAlumno']);
        Route::put('/modificarAlumno', [ControladorJefatura::class, 'modificarAlumno']);
        Route::delete('/eliminarAlumno/{dni_alumno}', [ControladorJefatura::class, 'eliminarAlumno']);
        Route::get('/listarGrupos', [ControladorJefatura::class, 'listarGrupos']);
        /************************************************************************/
    });
  • En cuanto a los métodos de los Controladores:

    • Se agruparán por funcionalidad usando la estructura #region ... #endregion.
    • Si dicha funcionalidad tiene métodos similares (por ejemplo, un CRUD que tenga varios métodos para obtener registros o una funcionalidad que tenga métodos principales y métodos auxiliares), se subdividirá usando la misma estructura.
    • En nuestro caso, además de esta estructura, deberemos colocar un decorador antes y otro después de la región.
    /***********************************************************************/
    #region Nombre de la agrupación
    public function hacerAlgo() { ... }
    
    public function hacerOtraCosa() { ... }
    #endregion
    /***********************************************************************/

JavaScript - Angular

En JavaScript, para establecer una región, se deben poner dos barras (un comentario, //) antes de declarar y finalizar la región:

/***********************************************************************/
//#region Funcionalidad 1
hacerAlgo() { ... }

hacerOtraCosa() { ... }
//#endregion
/***********************************************************************/

La agrupación de bloques de código similares en Angular afecta a dos tipos de ficheros: los archivos de servicios (.service.ts) y los TypeScript de los componentes (.component.ts).

  • Archivos de servicios: el código se agrupa por funcionalidades de la misma forma que en el código de la API. Si el código es escaso, no es necesario agruparlo por regiones.
  • TypeScript de los componentes: también agrupamos el código por funcionalidades y subfuncionalidades. Se pueden añadir las regiones y subregiones necesarias para agrupar el código, aunque contamos con algunas regiones típicas:
    • Inicialización de variables (y formulario): contiene la declaración de variables, el constructor y el ngOnInit(). Esta región está presente en todos los archivos de componente. Si el componente tiene formulario, su inicialización se engloba dentro.
    • Gestión del formulario: contiene los métodos que gestionan el formulario (get(), onSubmit()...).
    • Gestión de datatables: contiene los métodos relacionados con las datatables.
    • Servicios - Peticiones al servidor: contiene los métodos que hacen peticiones a la API mediante llamadas a los archivos de servicios.
    • Invocación de modales: contiene los métodos que invocan modales y cuadros de diálogo.
    • Funciones auxiliares: contiene funciones auxiliares.

HTML5

En el caso de los archivos de la vista de cada componente (.component.html), la agurpación varía ligeramente.

  • Los bloques de código diferenciadas se comentarán haciendo uso de los comentarios típicos de HTML.
  • Cuando el bloque esté englobado dentro de una sola etiqueta, se colocará el comentario sobre él:
    <!-- Títulos de las secciones -->
    <div class="row">
        <div class="page-header d-flex justify-content-between pb-3">
            <h1 class="h2">Seguimiento de prácticas</h1>
            <button type="button" class="btn btn-outline-default mr-2" placement="left"
            ngbTooltip="Haga clic para acceder a la ayuda de esta sección" (click)="abrirAyuda()">?</button>
        </div>
    </div>
  • Cuando el bloque esté englobado en dos o más etiquetas hermanas, se hará una región:
    <!-- #region Títulos de las secciones -->
    <div class="row">
        ...
    </div>
    <div class="row">
        ...
    </div>
    <!-- #endregion -->

Parametrización

Las variables que tomen un valor constante para toda la aplicación deberán parametrizarse en el archivo correspondiente al framework. De esta forma, se reducirán los errores al teclear o copiar y pegar código.

En el caso de Laravel, se almacenarán en la clase auxiliar Parametros como variables públicas constantes:

//----Roles de empresa
public const REPRESENTANTE_LEGAL = 1;
public const RESPONSABLE_CENTRO = 2;
public const TUTOR_EMPRESA = 3;

//----Roles de docente
public const DIRECTOR = 1;
public const JEFE_ESTUDIOS = 2;
public const TUTOR = 3;
public const PROFESOR = 4;

En el caso de Angular, se almacenarán en los archivos environment (environment.ts y envinronment.prod.ts):

export const environment = {
    production: false, //true si es environment.prod.ts
    apiUrl: "http://localhost:8000/api/",
    alumnos: "alumnos",
    materias: "materias",
    matriculas: "matriculas",
    notas: "notas",
    unidades: "unidades",
    profesores: "profesores",
    apiUrlFirma: "http://localhost:8000/api/"
};
⚠️ **GitHub.com Fallback** ⚠️