El título de este artículo sólo lo entenderán los Boomers y los Milenials como yo. Mazinger Z eran unos dibujos animados japoneses sobre un niño y un súper robot acojonante que luchaba con otros robots acojonantes u otros bichejos. Tampoco lo recuerdo mucho.
El tema del que vamos a hablar no son los dibujos, no os preocupéis, pero el nombre me venía perfecto para lo que quería explicar.
El caso es que SAP es una herramienta estándar, de caja, instalar, configurar y listo. Esa es su ventaja competitiva, y eso es por lo que los clientes pagan las licencias tan baratas que cobra SAP. Eso es lo que le ha traído aquí a estar donde está, y lo que ha hecho que sus competidores vayan saliendo con sus soluciones «Out of the box» al igual que SAP (Salesforce, Oracle, Microsoft, etc).
Out of the box
Pero en ocasiones, como los niños o los gatos.
A ciertos clientes y consultores lo que les gusta es jugar con la caja y no con el contenido.
Entienden que lo divertido es lo que ponga en la caja del software pero los procesos estándar, aplicaciones, integraciones no se adecúan a ellos.
Es aquí donde nace SAP Mazinger Z, poco a poco empresas, consultores y desarrolladores van construyendo una especie de sistema paralelo al sistema estándar.
Ampliaciones en SAP
Pero ¿por qué he traído el nombre de Mazinger Z? Porque en SAP, las ampliaciones de cliente se realizan, normalmente, con el prefijo Z. Hay locos que usan ‘Y’, pero esa gente quiere ver el mundo arder.
Yo entrando en un proyecto donde las ampliaciones comienzan por Y
Y claro, ceñirse al estándar es, en ocasiones, más difícil que hacerte un Mazinger Z monstruoso.
El primer nivel que debe controlar esto es el propio cliente, que es el dueño del negocio y es el que compra el producto (SAP) y debe ser consecuente con esa decisión.
Nadie compra un Ferrari para llevar una caravana
El segundo nivel es la consultoría. Como consultores tenemos la obligación de conocer la herramienta y saber adaptar el negocio del cliente manteniendo, en la medida de lo posible, el estándar. Ofrecerle al cliente las mejores prácticas tecnológicas de un software usado por miles de empresas. En definitiva, ser un buen consultor.
Y es que, en ocasiones, los sistemas se modifican tanto o se crean tantos procesos no estándar y tan complejos (y mal codificados/documentados) que el cliente y la consultora se hace presa del desarrollo realizado. En ocasiones me he encontrado con semidioses intocables, creadores del averno codificado, que están ahí porque son los padres de la fiera y los únicos que saben domarla. Se han convertido en los dueños del Mazinger Z.
Upgrades y actualizaciones estándar
Porque claro, cuando se compra una herramienta como SAP se paga una licencia anual que, entre otras cosas, te asegura el soporte y mantenimiento de la herramienta estándar, corrigiendo errores vía Support Packages o Notas. Además puedes querer o necesitar un upgrade a una nueva versión superior.
Cada vez que SAP lanza una actualización, los desarrollos Z pueden generar incompatibilidades que requieren tiempo y recursos adicionales para ser resueltos, afectando la agilidad del negocio.
Futuro y tendencia
Con el avance de las plataformas Low-code y No-code, el futuro del desarrollo en sistemas ERP podría orientarse hacia configuraciones cada vez más sofisticadas sin necesidad de recurrir a desarrollos complejos, facilitando el mantenimiento y las actualizaciones. Ejemplos de esto en SAP seria, SAP Build, SAP Build Code, Github Copilot, Microsoft Power Platform, etc.
El desarrollo dentro de suites como SAP es, sin duda, necesario, pero, como consultores, tenemos que conocer la herramienta y sus posibilidades, saber si de una manera u otra los requerimientos del negocio pueden ser satisfechos configurando la herramienta y, finalmente, si es necesario un desarrollo, acotar bien el alcance del mismo.
En un mundo donde la tecnología evoluciona rápidamente, saber cuándo y cómo construir tu propio ‘Mazinger Z’ dentro de SAP puede ser la diferencia entre un sistema que empodera a tu negocio y uno que lo atrapa en su propia complejidad.
Llevo desde los 18 años programando, y empecé por curiosidad y en casa. Es algo que se me da bien, me gusta y me genera satisfacción «crear» algo donde no lo había. Mi perfil profesional actual es bastante amplio, pero nunca quiero dejar ese aspecto de mi día día. Es algo que me llena, que me alegra…. hasta que veo algunas masacres de código que hay por el mundo, que me entran ganas de matar.
if dino_aux2-tipo = ‘velociraptor’ and dino_aux2-enfadado = ‘true’ or dino_tocho = ‘suelto’. Write:/ ‘Me voy’. endif. Viendo tu código te tenían que haber despedido hace tiempo, pero no habría película
Hoy voy a hablar de la calidad del código, no solo en su efectividad, también en su eficiencia, su facilidad de lectura y mantenimiento. A muchos les parecerá una tontería, algo sin importancia, pero un buen código simplifica mucho el mantenimiento, la reutilización, la lectura y documentación.
CleanABAP
Existe un proyecto en GitHub llamado Clean ABAP donde la comunidad de desarrolladores ABAP han sacado una guía de estilo de desarrollo ABAP con las mejores prácticas. Además está en varios idiomas, incluido el Español lo puedes ver aquí.
Y claro, yo iba a escribir mi libro de buenas prácticas desde mi punto de vista. Cosa que he hecho en algún proyecto al ver los desastres que la gente generaba en el sistema. Pero, al ver que ya había un consenso entre desarrolladores ABAP, y que no estaba solo en esto, pues mejor. Lo que voy a hacer es extraer de la guía de estilo CleanABAP aquellas recomendaciones que vea más necesarias. En la guía de estilo (lectura recomendadísima), se dividen las recomendaciones por áreas, vamos a respetarlas por si quieres ir a ver la fuente.
NOTA: Si estás viendo esto desde un móvil o tablet mejor en horizontal, las líneas de código se te van a cortar y hay cosas que no entenderás. No obstante, es preferible que lo leas desde el PC.
Formato
Optimiza para lectura, no para escritura
Siempre escribe pensando en la legibilidad del código, no en lo rápido que puedas escribirlo.
Bueno, yo con esta ya si que me corto las venas. Es un &#+%€ botón, pulsar un botón y te hace gran parte del trabajo.
Usa el Pretty Printer.
Usa el Pretty Printer
En serio. Usa el Pretty Printer.
Usa la configuración de Pretty Printer de tu equipo
Enlazado con lo anterior, tampoco estamos hablando de ingeniería. Es configurar tu Pretty Printer para que actúe de la forma que se consensue en tu equipo de trabajo. Yo, personalmente me gusta así:
Y esto es por lo siguiente:
Sangrar: Obvio, que el texto tenga sus correspondientes sangrías que te indiquen el nivel en el que estás es fundamental.
Conversión mayúsc./minúsc.: A mi me parece muy interesante que las palabras clave sean mayúsculas para ver claramente la acción que se está realizando e identificar las sentencias ABAP de variables, parámetros y literales.
" Ejemplo sin palabras clave mayúsculas select partner into lv_partner from but000 where bu_group = lv_clientes and xdele = abap_false and type = 1.
" Ejemplo con palabras clave mayúsculas SELECT partner INTO lv_partner FROM but000 WHERE bu_group = lv_clientes AND xdele = abap_false AND type = 1.
Por favor, usa el Pretty Printer.
No más de una sentencia por línea de código
Cada línea de código debe contener solo una sentencia, evitando mezclar varias operaciones en una sola línea.
Para mi esto es especial para los IFs con múltiples condiciones. Todo de seguido no se ve claramente.
" Ejemplo Incorrecto IF lv_total > 100 And lv_is_customer = 'X' AND lv_country = 'ES'. lv_discount = lv_total * 0.1. ELSE. lv_discount = 0. ENDIF.
" Ejemplo Correcto IF lv_total > 100 AND lv_is_customer = 'X' AND lv_country = 'ES'. lv_discount = lv_total * 0.1. ELSE. lv_discount = 0. ENDIF.
Aquí la posición de los AND y OR ya es manía personal, hay quien los pone al principio, a mi me gusta ponerlo al final y alinear las variables, los operadores y los AND/OR.
Mantén una longitud de línea razonable
Si la línea de código es demasiado larga, divídela en varias líneas para que sea más fácil de leer y seguir.
" Ejemplo Incorrecto SELECT carrid connid fldate FROM sflight INTO TABLE lt_sflight WHERE carrid = 'LH' AND connid = '0400' AND fldate = '20231010'.
" Ejemplo Correcto SELECT carrid connid fldate INTO TABLE lt_sflight FROM sflight WHERE carrid = 'LH' AND connid = '0400' AND fldate = '20231010'.
Vamos, no hay color. Mi manía personal es ponerlo en ese orden (SELECT, INTO, FROM, WHERE), y alineando desde el INTO. Además con las sentencias ABAP alineadas el código tiene más aire y se lee mejor. Se identifica claramente qué se selecciona, a donde se guarda, de qué tablas y con qué condiciones.
Usa una línea en blanco para separar cosas, pero no más
Utiliza una línea en blanco para separar lógicamente secciones del código, como declaraciones de variables y bloques de código, pero evita poner líneas en blanco innecesarias.
Los bloques de sentencias han de estar separados para su entendimiento. Todo junto no se lee bien.
" Ejemplo Incorrecto DATA: ls_order TYPE zorder, lv_total TYPE p DECIMALS 2, lv_discount TYPE p DECIMALS 2. ls_order-order_id = 'ORD001'. ls_order-customer_id = 'CUST001'. ls_order-status = 'OPEN'. lv_total = 500. lv_discount = lv_total * 0.1. ls_order-total_amount = lv_total. ls_order-discount_amount = lv_discount. INSERT zorder FROM ls_order.
" Ejemplo Correcto DATA: ls_order TYPE zorder, lv_total TYPE p DECIMALS 2, lv_discount TYPE p DECIMALS 2.
Alinea asignaciones al mismo objeto, pero no a objetos diferentes
Cuando asignas valores a varios atributos de un mismo objeto, puedes alinearlos para mejorar la legibilidad, pero evita alinear asignaciones entre diferentes objetos.
" Cómo lo hago yo lo_instance->set_data( EXPORTING iv_name = lv_name iv_age = lv_age iv_address = lv_address iv_order_id = lv_order_id ).
Fíjate en el alineamiento de los =, hace que sepas claramente identificar parámetros de variables. Esto también lo suelo hacer los IFs con los comparadores, pero eso ya es manía personal.
" Ejemplo Incorrecto IF lv_status EQ 'A' AND lv_subtype NE 'X' AND lv_amount GT 100. lv_result = 'Valid'. ELSE. lv_result = 'Invalid'. ENDIF.
" Cómo lo hago yo IF lv_status EQ 'A' AND lv_subtype NE 'X' AND lv_amount GT 100. lv_result = 'Valid'. ELSE. lv_result = 'Invalid'. ENDIF.
Nomenclatura
Usa nombres descriptivos
Los nombres de variables, clases y métodos deben ser lo suficientemente claros para que cualquier desarrollador entienda su propósito sin necesidad de contexto adicional. Por ejemplo
" Declaraciones no descriptivas DATA: lv_amt TYPE i, lt_cust TYPE TABLE OF but000, lt_items_aux TYPE TABLE OF crmd_orderadm_i.
" Declaraciones con nombres descriptivos DATA: lv_total_amount TYPE i, lt_customers TYPE TABLE OF but000, lt_items_completed TYPE TABLE OF items.
No cuesta nada y se lee todo mejor, eso sí, se consecuente con usar cada uno para lo que es, no vayas a meter en lt_items_completed cualquier tipo de posiciones de pedido porque te venga bien.
Usa sustantivos para las clases y verbos para los métodos
Las Clases deberían representar conceptos o entidades y, por lo tanto, se nombran como sustantivos.
" Ejemplos order_calculator order_utils
Los Métodos representan acciones o comportamientos, por lo que deben nombrarse con verbos.
Para mejorar la legibilidad en ABAP, se prefiere el uso de snake_case en lugar de camelCase o PascalCase en variables y métodos. El uso de snake_case es una convención ampliamente utilizada en el código ABAP debido a su compatibilidad con otras herramientas del ecosistema SAP y porque ayuda a mejorar la claridad del código, haciéndolo más legible y fácil de seguir para los desarrolladores.
" Ejemplos Incorrectos DATA: TotalAmountDue type p decimals 2. DATA: itemstoadd type table of items.
" Ejemplos Correctos DATA: lv_total_amount_due TYPE p DECIMALS 2, lt_items_to_add TYPE TABLE OF items.
Constantes
Usa constantes en lugar de números mágicos
Evita usar números sin contexto directamente en el código. En su lugar, define constantes para mejorar la legibilidad.
" Ejemplo Incorrecto IF lv_value > 42.
" Ejemplo Correcto IF lv_value > gc_max_allowed.
Sabemos que el 42 es «El sentido de la vida, el universo y todo lo demás» pero a lo mejor en tu proceso no es el sentido de ese número. Usa constantes, puedes declararlas en un INCLUDE TOP o bien en una clase estática que aglutine varias constantes.
Prefiere clases de enumeración a interfaces de constantes
Esto lo he añadido por el punto anterior. Lo que yo suelo hacer es crear una serie de clases UTIL con métodos estáticos, con un sentido funcional cada una, y sus constantes correspondientes. Voy a poner un ejemplo:
CLASS zcl_crm_ofertas_util DEFINITION. PUBLIC SECTION.
" Constantes para los estados de la oferta CONSTANTS: c_estado_abierto TYPE char10 VALUE 'E0001', c_estado_cerrado TYPE char10 VALUE 'E0002'.
" Métodos estáticos CLASS-METHODS: get_datos_oferta IMPORTING iv_oferta_id TYPE char10 RETURNING VALUE(rt_oferta_datos) TYPE TABLE OF zcrm_oferta.
CLASS-METHODS: get_interlocutores IMPORTING iv_oferta_id TYPE char10 RETURNING VALUE(rt_interlocutores) TYPE ztt_interlocutores. ENDCLASS.
Y las constantes c_estado_abierto y c_estado_cerrado podemos usarlo en cualquier código para comprobar si un pedido tiene ese estado.
IF lv_estado_pedido EQ zcl_order_util=>c_estado_abierto. " Hacer cosas ENDIF.
Variables
Prefiere declaraciones in-line que al inicio
Este apartado no estoy al 100% de acuerdo, porque soy de vieja escuela, antes de que las declaraciones In-line estuviesen disponibles y suelo hacer bastantes declaraciones al inicio. No obstante, creo que tiene bastante razón.
" Ejemplo Incorrecto METHOD calculate_discount. DATA: lv_discount TYPE p DECIMALS 2, lv_total_amount TYPE p DECIMALS 2, lt_clientes TYPE TABLE OF but000.
SELECT * INTO TABLE @DATA(lt_clientes) FROM but000 WHERE bu_group EQ zcl_bp_util=>c_agrupación_cliente. ENDMETHOD.
Lo importante es conocer las declaraciones In-line que son muy útiles y aportan claridad y limpieza al código.
No encadenes declaraciones
Cada declaración debe ocupar una línea por sí misma. Esto facilita el seguimiento de las variables.
" Ejemplo Incorrecto DATA: lv_value TYPE i, lv_discount TYPE p, lv_total TYPE p.
" Ejemplo Correcto DATA: lv_value TYPE i, lv_discount TYPE p, lv_total TYPE p.
A lo que yo añado lo siguiente
Usa «DATA:» y evita usar múltiples DATA
Entras en un código y te encuentras con esto
DATA lv_es_cliente TYPE bu_partner. DATA lt_pedidos_abiertos TYPE TABLE OF zpedidos. DATA ls_pedidos_abiertos TYPE zpedidos. DATA lv_fecha_creacion TYPE datum. DATA lv_sociedad TYPE werks. DATA lt_pedidos_cerrados TYPE zpedidos.
Pero ¿Para qué ponemos tantos DATA. Si ponemos solo un DATA: el Pretty Printer se va a encargar de darle mucho aire y alinear los TYPE.
DATA: lv_es_cliente TYPE bu_partner. lt_pedidos_abiertos TYPE TABLE OF zpedidos. ls_pedidos_abiertos TYPE zpedidos. lv_fecha_creacion TYPE datum. lv_sociedad TYPE werks. lt_pedidos_cerrados TYPE zpedidos.
Vamos. no hay color, y eso que he puesto un ejemplo con seis líneas, he llegado a ver decenas de DATA juntos. Ya sabes, usa el Pretty Printer.
Tablas
Prefiere INSERT INTO TABLE a APPEND TO
Usar INSERT INTO TABLE es más versátil y claro para la inserción de datos en tablas internas. Además el uso del APPEND da errores en las tablas de tipo SORTED y en INSERT INTO TABLE lo gestiona bien.
" Ejemplo Incorrecto APPEND ls_cliente TO lt_clientes.
" Ejemplo Correcto INSERT ls_cliente INTO TABLE lt_clientes.
Ocupa lo mismo y no da problemas.
Prefiere LINE_EXISTS a READ TABLE o LOOP AT
En lugar de leer tablas para verificar si una línea existe, usa la función LINE_EXISTS, que es más clara y eficiente. Esto no lo suelo usar mucho, porque soy vieja escuela, pero me parece muy interesante.
" Ejemplo Incorrecto READ TABLE lt_table WITH KEY id = lv_id TRANSPORTING NO FIELDS. IF sy-subrc = 0. WRITE: 'La línea existe'. ELSE. WRITE: 'La línea no existe'. ENDIF.
" Ejemplo Correcto IF line_exists( lt_table[ id = lv_id ] ). WRITE: 'La línea existe'. ELSE. WRITE: 'La línea no existe'. ENDIF.
Strings
Usa | para construir textos
En ABAP, puedes usar | para concatenar y construir cadenas de forma más limpia que con las antiguas funciones CONCATENATE.
" Ejemplo menos eficiente CONCATENATE lv_name lv_surname INTO lv_fullname.
Este es uno de los principios básicos de CleanABAP. Es mejor hacer un método que haga una cosa cada vez para que el código se pueda leer de forma sencilla y coherente. Para que el método haga una cosa nos tenemos que asegurar que:
Tiene pocos parámetros: Un método que hace una sola cosa debería tener pocos parámetros de entrada. Tener muchos parámetros indica que el método podría estar haciendo más de una tarea
No tiene parámetros booleanos de entrada: Los parámetros booleanos en un método pueden ser una señal de que el método realiza dos cosas: una cuando el valor es verdadero y otra cuando es falso.
Tiene exactamente un parámetro de salida: Un método que hace una sola cosa debería tener solo un resultado. Si devuelve más de un valor, probablemente esté realizando múltiples tareas
Es corto: Un método debe ser corto y directo. Si un método es demasiado largo, es una señal de que está realizando múltiples tareas.
Desciende un nivel de abstracción: Un buen método debe enfocarse en un solo nivel de abstracción. No debe mezclar operaciones de bajo nivel (como acceso a base de datos) con operaciones de alto nivel (como lógica de negocio)
Lanza un solo tipo de excepción: Si un método lanza múltiples tipos de excepciones, es probable que esté haciendo más de una cosa
No puedes extraer más métodos de él con un significado claro: Si no puedes dividir un método en varios métodos más pequeños que tengan un propósito claro y diferenciado, entonces probablemente el método está bien estructurado.
No puedes agrupar sus sentencias en secciones lógicas: Si las sentencias de un método se pueden agrupar en diferentes secciones, es probable que el método esté realizando múltiples tareas.
Mensajes
Haz que los mensajes sean fáciles de encontrar
Para hacer los mensajes fáciles de encontrar en una búsqueda desde la transacción SE91. Realmente yo usaba la sentencia incorrecta, pero la recomendación es no usar eso.
" Ejemplo Incorrecto IF 1 = 2. MESSAGE e001(ad). ENDIF.
" Ejemplo Correcto MESSAGE e001(ad) INTO DATA(message).
Comentarios
Exprésate en código, no en comentarios
El código bien escrito debe ser lo suficientemente claro para no requerir comentarios excesivos.
" Ejemplo Incorrecto " Calcula el total con el descuento lv_total = lv_total - lv_discount.
Usa nombres descriptivos en lugar de comentarios, ya que esto hace el código más autoexplicativo.
Los comentarios no son excusa para nombrar mal objetos
Los nombres de variables y objetos deben ser claros y descriptivos por sí mismos, sin depender de comentarios para su explicación.
" Ejemplo Incorrecto " Cantidad Total DATA: lv_tot_amnt TYPE i.
" Ejemplo Correcto DATA: lv_total_amount TYPE i.
El nombre de la variable debe ser suficientemente descriptivo para evitar depender de comentarios innecesarios.
Usa métodos en lugar de comentarios para segmentar tu código
Es más eficiente y claro usar métodos con nombres descriptivos para organizar las diferentes tareas dentro del código. Esto mejora la legibilidad y el mantenimiento del código, además de seguir el principio de hacer una sola cosa en cada método.
Los comentarios pueden volverse obsoletos o estar mal escritos, lo que puede generar confusión. Sin embargo, los métodos con nombres claros y bien definidos hacen que el propósito de cada sección sea evidente, eliminando la necesidad de comentarios explicativos.
" Ejemplo Incorrecto METHOD process_order. " Validación del cliente IF lv_customer_id IS INITIAL. RETURN. ENDIF.
" Calcular el total lv_total = calculate_total( lt_items ).
" Aplicar el descuento IF lv_discount > 0. lv_total = lv_total - lv_discount. ENDIF.
" Guardar el pedido en la base de datos save_order( lv_order_id ). ENDMETHOD.
METHOD save_order. INSERT INTO zorders VALUES iv_order_id. ENDMETHOD.
El diseño va en los documentos de diseño, no en el código
Evita incluir detalles de diseño en el código, ya que esto pertenece a la documentación externa. El diseño debe documentarse fuera del código para evitar que el código se vuelva innecesariamente complicado de leer.
" Ejemplo Incorrecto " Este método sirve para crear pedidos de venta con los datos de " entrada de cliente, datos organizativos, productos y precios. " Los tipos de posición se calcularán en base al tipo de cliente y el " tipo de pedido que se quiere crear. " Para eso se llamará a la tabla ZTB_TIPO_POS y se recuperarán los " tipos de posición. " El estado del pedido será siempre "Abierto" METHOD crear_pedido_ventas.
Nadie se lee esto, además puede quedar fácilmente obsoleto al cambiar el contenido del método. Si el código se entiende, no hace falta hacer explicaciones de más.
Usa » para comentar, no *
Es preferible usar » para líneas de comentario porque se identan automáticamente al nivel donde aplican al usar Pretty Printer.
" Ejemplo Incorrecto CASE lv_estado. WHEN c_abierto. * Comentario en abierto
WHEN c_en_proceso. * Comentario en proceso
WHEN c_cerrado. * Comentario en cerrado
ENDCASE.
" Ejemplo Correcto CASE lv_estado. WHEN c_abierto. " Comentario en abierto
WHEN c_en_proceso. " Comentario en proceso
WHEN c_cerrado. " Comentario en cerrado
ENDCASE.
Borra el código en lugar de comentarlo
El código obsoleto debe ser eliminado en lugar de ser comentado para evitar confusión. Para algo está la gestión de versiones, el código que pasa por muchas manos y correcciones se vuelve imposible de leer.
No agregues prototipos ni comentarios de fin de métodos (INTERESANTE)
Los comentarios estándar de la firma de métodos o performs no aportan valor y generan ruido en el código. Estos comentarios pueden haber tenido sentido décadas atrás, cuando los entornos de desarrollo eran limitados, pero en los entornos modernos de ABAP (SE24, SE80, ABAP Development Tools en Eclipse), ya no son necesarios, porque la firma del método está fácilmente accesible con herramientas integradas.
" Ejemplo Incorrecto *&---------------------------------------------------------------------* *& Form CHECK_ORDER *&---------------------------------------------------------------------* * text *----------------------------------------------------------------------* * -->P_LV_ABAP_BOOL text * -->P_LV_COUNTRY text * -->P_LV_CUSTOMER_ACTIVE text * -->P_LV_HAS_DISCOUNT text * <--P_LV_TOTAL text * <--P_LV_SPECIAL_CUSTOMER text *---------------------------------------------------------------------- FORM check_order USING p_lv_abap_bool p_lv_country p_lv_customer_active p_lv_has_discount CHANGING p_lv_total p_lv_special_customer.
" Ejemplo Correcto FORM check_order USING p_lv_abap_bool p_lv_country p_lv_customer_active p_lv_has_discount CHANGING p_lv_total p_lv_special_customer.
En Conclusión
Me ha quedado algo largo, y eso que he hecho una selección de las recomendaciones que me parecen más interesantes. A pesar de eso, además yo tengo alguna manía más que realizo en mi día a día (no voy a añadir más leña). En entradas posteriores seguiremos hablando de esto pero desde un punto de vista de comprobar la calidad del código existente.
Por último, si solo me tuviese que quedar un un básico, diría: