Computing">
[Go to site: main page, start]

100% encontró este documento útil (2 votos)
475 vistas51 páginas

Prácticas de Código Limpio en Español

Este documento presenta varios principios para escribir código limpio. Brevemente describe la Ley del Boy Scout, que implica mejorar el código existente cada vez que se trabaja en él, y la Teoría de las ventanas rotas, que sugiere que es mejor arreglar problemas de código pequeños cuando surgen para evitar que empeoren. También menciona que el código debe ser fácil de entender y modificar, tener una única responsabilidad y ser lo más simple posible.

Cargado por

m0rta
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
100% encontró este documento útil (2 votos)
475 vistas51 páginas

Prácticas de Código Limpio en Español

Este documento presenta varios principios para escribir código limpio. Brevemente describe la Ley del Boy Scout, que implica mejorar el código existente cada vez que se trabaja en él, y la Teoría de las ventanas rotas, que sugiere que es mejor arreglar problemas de código pequeños cuando surgen para evitar que empeoren. También menciona que el código debe ser fácil de entender y modificar, tener una única responsabilidad y ser lo más simple posible.

Cargado por

m0rta
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

1ª edición

Clean Code.
Las mejores prácticas para un
código limpio.
Clean Code.

1
Atribución 4.0 Internacional

Usted es libre para:

Compartir, copiar y redistribuir el material en cualquier medio o formato.

Adaptar, remezclar, transformar y crear a partir del material para cualquier

propósito, incluso comercialmente.

El licenciante no puede revocar estas libertades en tanto usted siga los

términos de la licencia.

Bajo los siguientes términos:

Atribución Paradigma Digital. Usted debe darle crédito a esta obra de

manera adecuada, proporcionando un enlace a la licencia, e indicando si se

han realizado cambios. Puede hacerlo en cualquier forma razonable, pero no

de forma tal que sugiera que usted o su uso tienen el apoyo del licenciante.

No hay restricciones adicionales: Usted no puede aplicar términos legales ni

medidas tecnológicas que restrinjan legalmente a otros hacer cualquier uso

permitido por la licencia.

V.1.0 - Septiembre de 2022

[Link]
Autor: Antonio José García.

Ilustraciones: Marta Ruiz.

Maquetación: David Mota.


Contenido:
— Introducción. 06

— 01. ¿Qué es código limpio? 08

— 02. Principios del clean code. 12

— 03. Code style. 14

— 04. Nomenclatura. 16

— 05. Comentarios. 22

— 06. Funciones. 26

— 07. DRY (Don’t repeat yourself). 34

— 08. Tratamientos de errores. 36


Clean Code.

4
— 09. Clases y objetos. 38

09.01 STUPID Antipattern. 41

09.02 SOLID pattern. 42

— 10. Introducción al testing 44

— Autores. 48
Clean Code.

5
Introducción:
Introducción.

Como desarrolladores/as, nos hemos encontrado en muchas ocasiones


frente a un código que nos cuesta entender, mantener, que genera
errores, fricciones en los equipos… ¿Cómo podemos asegurarnos de
no llegar a este punto? Existe una serie de recomendaciones y técnicas
que permiten tener un código limpio, pero llegar a esta maestría exige
dos cosas: conocimiento y trabajo.

Tenemos que aplicar una buena teoría a nuestro trabajo diario para
tener un código limpio. Durante este proceso cometeremos errores,
aprenderemos de ellos e iremos siendo mejores artesanos de código.
A lo largo de este ebook vamos a ver diversas definiciones y técnicas
de clean code que están muy relacionadas entre sí. Pero primero
empecemos por definir qué es código limpio.
Clean Code.

7
— 01

¿Qué es
código
limpio?
01 — ¿Que´es código limpio?

No existe una definición exacta de código limpio, pero vamos a ver una
serie de definiciones que nos van a ayudar a entender el concepto:

Cualquier idiota puede hacer código que compila, pero solo un


buen programador puede hacer código que otros entiendan.

Martin Fowler.

El código es para seres humanos, no para máquinas, por lo que debe ser
entendible. Es tan importante que sea legible como ejecutable.

Me gusta que mi código sea elegante y eficiente. La lógica debe


ser directa para evitar errores ocultos, las dependencias deben
ser mínimas para facilitar el mantenimiento, el tratamiento
de errores completo y sujeto a una estrategia articulada y el
rendimiento debe ser óptimo para que no se tienda a estropear el
código con optimizaciones sin sentido.

El código limpio hace bien una cosa.

Bjarne Stroustup, inventor de C++.


Clean Code.

Aquí se abordan varios temas: evitar acoplamientos y responsabilidad única


(patrón SOLID). Nuestro código debe hacer una cosa y hacerla bien.

9
01 — ¿Que´es código limpio?

El código limpio es simple y directo. Se lee como un texto bien


escrito. No oculta la intención del diseñador sino que muestra
nítidas abstracciones y líneas directas de control.

Grady Booch, autor de Object Oriented Analysis and Design


with Applications.

Volvemos a reincidir en hacer solo una cosa y que no haya comportamientos


ocultos. El código no es una película de suspense, debe ser claro y directo.

El código limpio siempre parece que ha sido escrito por alguien a


quien le importa. No hay nada evidente que hacer para mejorarlo.
El autor pensó en todos los aspectos posibles y, si intentamos
imaginar alguna mejora, volvemos al punto de partida y solo
nos queda disfrutar del código que alguien a quien le importa
realmente nos ha proporcionado.

Michael Feathers, autor de Working Effectively


with Legacy Code.

Como buenos artesanos de código, debemos comprometernos con nuestro


desarrollo y hacerlo lo mejor que podamos. Es muy importante la ACTITUD, y
debemos mejorar la forma en la que nos desarrollamos e ir mejorando poco a
Clean Code.

poco.

10
01 — ¿Que´es código limpio?

El código limpio se puede leer y mejorar por parte de un


programador que no sea su autor original. Tiene pruebas unitarias
y de aceptación, nombres con sentido. Ofrece una y no varias
formas de hacer algo. Sus dependencias son mínimas y ofrece
un API claro. El código debe ser culto en función del lenguaje, ya
que no toda la información necesaria se puede expresar de forma
clara en el código.

Dave Thomas, fundador de Eclipse.

Aquí se incide sobre el buen mantenimiento del código, el nombrado correcto


(que veremos más adelante), bajo nivel de acoplamiento (al tener pocas
dependencias) y una legibilidad clara del código.

Trabajando es la forma en que obtendremos la madurez en el desarrollo.


Como buenos artesanos de software, debemos preocuparnos de hacer
código de la mejor manera que seamos capaces: de forma elegante,
sencilla, óptima y bonita, teniendo siempre en cuenta el sentido común.

Entonces... ¿Qué es código limpio?


Como ya hemos comentado, debemos ser artesanos de software:
involucrarnos en nuestro código y aplicar el sentido común. Tiene
que ser sencillo, fácil de entender, de mantener, hacer una única cosa
Clean Code.

y óptimo.

11
— 02

Principios del
clean code.
02 — Principios del clean code.

Ley del Boy Scout.


Se resume en dejar el campamento más limpio que cómo lo hemos
encontrado. De esta forma, cada vez que tengamos que hacer un nuevo
desarrollo, intentaremos mejorar el código existente. Así, en cada
iteración, el código va quedando mejor.

Teoría de las ventanas rotas.


Si en un edificio existe una ventana rota, lo más probable es que
los vándalos vayan rompiendo más y más. Ocurre lo mismo con la
basura en la calle: si no se va recogiendo, lo más seguro es que vaya
apareciendo más. Si lo llevamos a nuestro mundo, nos encontramos
clases, módulos mal diseñados y difíciles de mantener que sabemos
que existen y debemos eliminarlos lo antes posible. Quizás en el
momento actual no podamos acometer la tarea, pero añadamos la
tarea al backlog y acometámosla lo antes posible.
Clean Code.

13
— 03

Code style.
03 — Code Style.

El 80% de las modificaciones se realizan durante el mantenimiento


y por personas que no desarrollaron esa pieza, por lo que cobra
gran importancia la mantenibilidad. Un lenguaje bien estructurado,
indentado y con coherencia nos ayuda a entenderlo más rápido, ser
más ágiles y eficientes en el desarrollo.

Es cierto que hay lenguajes como Python que precisan que la


indentación sea correcta, pero para el resto de lenguajes existen
formateadores y plantillas que nos ayudan con esta tarea,
independientemente del IDE de desarrollo que estemos usando.
Además, si como equipo utilizamos la misma plantilla, los cambios al
hacer un pull request son menores.
Clean Code.

15
— 04

Nomenclatura.
04 — Nomenclatura.

Al final, nosotros somos humanos y el código binario lo entienden las


máquinas. Merece la pena dedicar tiempo a pensar el orden de nuestro
código, y no empezar a desarrollar pensando solo en que funcione.
Si llevamos a cabo esta tarea mejoraremos en claridad, generalidad,
mantenibilidad y en facilitar su comprensión.

El idioma en el que desarrollamos el código y los comentarios


que le añadimos debe ser un acuerdo del equipo. Es cierto que si
desarrollamos en inglés, las palabras son más cortas y encajan mejor
con los frameworks que utilizamos. Lo mismo nos ocurre con los
comentarios. Pero apliquemos el sentido común y, si hay algo que
es difícil de expresar, podemos usar el idioma en el que quede mejor
reflejado. Dicho esto, intentemos evitar desarrollos con mezcla de
idiomas en el código, ya que conseguiremos que el conjunto sea más
complejo de entender.

Nombrado con coherencia.

El nombrado es de vital importancia y debe ser representativo. Da igual


que sea una clase, un método, un argumento… Tenemos que ponerle
un nombre coherente que evite las pistas falsas sobre qué es, para qué
sirve o cómo se usa. Debe ser un nombrado representativo y distintivo.

int d;

¿Para qué se usa? ¿Qué hace? No nos aporta ninguna pista.

int numberOfDaysElapsed

Sé su propósito y el valor que va a guardar.


Clean Code.

17
04 — Nomenclatura.

No usar nombres con variaciones mínimas.

public List<Account> getPublicAccount

public List<Account> getPublicAccounts

Aquí realmente estoy forzado a ver la implementación para entender


qué está ocurriendo. Estos dos nombres me generan desinformación:
¿Qué diferencia hay entre las dos funciones?

Por el contrario si tenemos:

public List<Account>

getPublicAccountsForActiveUsersInThisBank

public List<Account>

getPublicAccountsForInactiveUsersInThisBank

Lo anterior también aplica a los argumentos en las funciones.

public void copyChars(Char a, Char a1);

¿Cuál es el origen y cuál el destino? En este caso de nomenclatura,

estoy obligado a ver la implementación.

public void copyChars(Char source, Char destination);

Ya no es necesario que vaya a ver el código de la función, con

esta nomenclatura queda claro.

Merece la pena dedicar tiempo a pensar el


Clean Code.

orden de nuestro código.


18
04 — Nomenclatura.

Usemos nombres que podamos pronunciar y no caigamos en nombres


divertidos o frikis.

Si no es posible pronunciarlo, va a ser más difícil poder explicar o


inferir su propósito. Lo mismo ocurre si usamos algún nombre divertido
que en ese momento parecía adecuado. La persona que venga detrás
seguramente no piense como la persona que lo creó, y no le estamos
haciendo ningún favor a la hora de entender el código.

private String cMarcaAc, dDescMod, desEmpre;

Tenemos que investigar cada una, ya que con esta nomenclatura no

entendemos qué es o a qué se refiere.

private String activeBrandName, moduleDescription,

companyName

Nombres distintivos.
Clean Code.

19
04 — Nomenclatura.

Tipo y nombres coherentes.

La idea es no generar pistas falsas.

private String accountList;

¿Plural y es sólo un string?¿Almacena una o varias account

concatenadas? Tengo que investigar cómo se asigna el valor y su uso.

private String account;

Singular, almacena una sola cuenta.

private List<String> accountList;

Es una lista de cuentas y es coherente con el nombre.

Prefijos y sufijos que no aportan nada.

Product = ProductInfo = ProductData (es lo mismo)

En este ejemplo nos estamos refiriendo a “Product”, y los sufijos no

aportan nada salvo desorientación.

Otro ejemplo de prefijos que no aportan nada es añadir el tipo a la


variable (notación húngara) a su nombre. Esto nos obligaría, además,
a cambiar la variable si cambiamos de tipo. Existen lenguajes
fuertemente tipados donde esta técnica tiene todavía menos sentido.

private int Icount; boolean bIsActive;

Es cierto que existen casos donde un prefijo nos aporta el contexto de


la variable con la que estamos trabajando. Si estamos trabajando con
el atributo status de la clase Product en otra parte, productStatus nos
Clean Code.

ayuda a identificar claramente a qué estamos haciendo referencia.

20
04 — Nomenclatura.

Si todas nuestras clases tienen el mismo prefijo, realmente ese prefijo


no aporta nada y nos dificulta la búsqueda de clases. Un ejemplo claro
es cuando prefijamos todas las clases con el nombre de una empresa;
quizás esas clases puedan ser extraídas a una librería.

Ocurre lo mismo si prefijamos las interfaces con una I. No está


aportando nada y estamos perdiendo abstracción. Pero por el
contrario, si a una implementación le añadimos Impl al final de la clase
(CacheServiceImpl, CacheServiceRedisImpl), indicamos claramente su
propósito.

De la misma forma, añadir el sufijo cuando trabajamos con patrones


nos aporta semántica.

ProductFactory, AccountFacade, CustomerPublisher

Como regla general, sería recomendable no usar en clases:

• Solo un verbo (Manager, Procesor, Get…) que no nos identifica


claramente su propósito.

• Ni palabras generalistas como Data, Info, General…

Pero sí nombres o frases como ProductorParser, CustomerValidator…

Los métodos hacen acciones, por lo que deben llevar un verbo como
parte de su nombre y también indicar sobre qué actúa.
Clean Code.

getAccount(), generateProduct(…), setName(…)

21
— 05

Comentarios.
05 — Comentarios.

Los comentarios deben aportar el conocimiento necesario donde no


hemos podido expresarnos con el código.

A su vez, un comentario implica una responsabilidad de mantenimiento


según se vaya actualizando esa pieza de código y nunca, nunca, nunca,
debe servir para comentar código. El código comentado nos genera
dudas y, para esa función, tenemos los repositorios de código.

En qué casos nuestros comentarios no tienen sentido:

• Comentarios con cambios por fecha. Para eso tenemos los


repositorios de código, changelog, Jira...
• Metadatos: autores, fecha…
• Justificaciones de decisiones.
• Explicación demasiado profunda.
• Comentarios obsoletos. O lo actualizamos o tenemos que
eliminarlo.
• Código comentado. Tenemos que eliminarlo porque nos genera
más desinformación.
• Código redundante, como podría ser el getter o el setter de un
campo.
• Menciones a otros usuarios que quizás no formen parte ya del
equipo de desarrollo.
• Usar comentarios para separar bloques o señalar llaves de apertura
o cierre.

Los comentarios deben aportar el


conocimiento necesario donde no hemos
Clean Code.

podido expresarnos con el código.

23
05 — Comentarios.

Los comentarios son notas técnicas y de diseño que merece la pena


leer, y se deben mantener en el futuro.

Deben tener un lenguaje claro y una ortografía correcta. El desarrollo


es una actividad social y todo lo que podamos ayudar y guiar será de
gran utilidad. Debemos tener cuidado con pensar que nuestro código
es autocomentado y expresar con palabras donde nuestro código no
puede llegar.
Clean Code.

24
05 — Comentarios.

Un ejemplo de un buen comentario.

/**
* Servicio principal desde el cual se orquestn tres llamadas a
* los subsistemas de obtención de información extendida de cada
* uno de los productos resultantes de la consulta inicial a la
* base de datos
*
* <pre>
* Las tres llamadas son:
* - Obtencion de precios
* - Obtención de la taxonomía del producto
* - Obtencion de manuales de usuario
*
* </pre>
*
* @param ProductSearchParameterIDTO
* @return ProductFlowODTO
*/

@Override
public ProductDocumentRSRDTO
searchProduct(ProductSearchParameterIDTO
productSearchParameterIDTO) {
Clean Code.

25
— 06

Funciones.
06 — Funciones.

Hace muchos años, las funciones eran subrutinas compuestas por


miles de líneas. Después, vinieron los lenguajes que limitaban el tamaño
a unas cuantas líneas. Pero, ¿cómo deberían ser nuestras funciones?

Deberían ser concretas, claras y con una única responsabilidad (esto


conectaría con los principios SOLID). Además, al ser concreta, su
tamaño es pequeño y esto nos favorece a la hora de poder testear
nuestro código. Cuanto más pequeña es la función, normalmente es
más fácil de entender y no oculta ningún efecto secundario.

El lenguaje y cómo están escritas cobra mucha importancia. Si el


nombre que elegimos describe su propósito, no será necesario entrar
en un principio a su implementación. Además, estamos acostumbrados
a leer de izquierda a derecha y en párrafos. Una buena indentación
y separar cambios u operaciones en párrafos es de gran ayuda. Las
llaves, estructuras de código, agrupar algunas operaciones… nos
pueden ayudar a ello.

Una función debe ser concreta, clara y con


una única responsabilidad.
Clean Code.

27
06 — Funciones.

A continuación podemos ver una función bien escrita que se puede


entender de un simple vistazo:

public ProductDocumentRSRDTO
searchProduct(ProductSearchParameterIDTO
productSearchParameterIDTO) {

/*Transformamos a UniqueSearchParameterIDTO*/
UniqueSearchParameterIDTO uniqueSearchParameterIDTO = this.
productServiceTransformer
.toUniqueSearchParameterIDTO(ProductSearchParameterIDTO);

/*Buscamos las referencias por cada producto*/


ProductFlowODTO productFlowODTO =
[Link]
.findReferencesInUniqueSearch(uniqueSearchParameterIDTO);

/*Si tenemos referencias vamos a completar la documentación*/


if ([Link]() != null) {
productFlowODTO = completeDocumentation(productFlowODTO);
}

ProductDocumentRSRDTO productDocumentRSRDTO = this.


productServiceTransformer
.toProductDocumentRSRDTO([Link]());

return productDocumentRSRDTO;

Cuando estemos codificando y tengamos un switch (de hecho Python


no tiene), se nos debería encender una alarma y revisar qué estamos
haciendo, porque en muchos casos esa función hace más de una cosa
y estamos violando el principio de responsabilidad única.
Clean Code.

28
06 — Funciones.

Un mal ejemplo (se están haciendo muchas cosas en la misma función):

switch (value) {
case 1: return sendEmail();
case 2: return calculatePercentage();
case 3: return callToCics();

Normalmente, la solución es hacer una factoría abstracta que haga


visible el comportamiento, pero no hay una regla escrita, depende del
caso. La solución es favorecida mediante el uso del polimorfismo.

Sobre el número de argumentos, la regla sería que cuantos menos,


mejor (que nos favorece a testearlas con mayor facilidad).

• Lo ideal sería tener funciones monádicas (consultas y


transformaciones sobre un objeto).
• Diádicas, no son el mal pero a veces son necesarias (como en
las que tenemos un expected, actual). Aunque si podemos
transformarlas en monádicas, mucho mejor.
• Evitemos en lo posible funciones triádicas.
• A partir de aquí (poliádicas) la recomendación sería encapsularlas
en un objeto. Aquí ocurren varios factores: no nos acordamos
de los argumentos y su orden, si fuera necesario otro argumento
impactaría más en el código y es más fácil de utilizar y probar.

Los nombres de los argumentos deben ser identificativos.

Una función bien escrita se puede entender


Clean Code.

de un simple vistazo.

29
06 — Funciones.

Si tenemos un argumento que es un booleano, puede ser indicativo que


nuestra función hace más de una cosa. Porque dependiendo del valor
del booleano hace una u otra cosa.

public committeeODTO saveCommittee(CommitteeIDTO committeeIDTO,


Boolean isUnique);

Las funciones que no se utilizan (muertas) deben ser eliminadas, al


igual que todo el código que se encuentre comentado, porque para eso
tenemos los repositorios de código.

Dentro del código hay que minimizar el acoplamiento (lo que sabe una
clase de otra). Para ello existe la ley de Demeter, que básicamente la
podríamos resumir en que una clase habla con sus amigos y no con
desconocidos:

• Accede a tus atributos (simples o compuestos).


• Accede a tus propiedades.
• Accede a los atributos de las funciones.

De esta forma minimizamos los cambios en caso de un cambio de


una estructura. Pensemos qué ocurre si cambiamos los atributos de
la función doSomething en el código de la izquierda, fuertemente
acoplado respecto con el de la derecha. Además es probable que si
no somos conscientes, el código de la izquierda estará repartido por
muchas clases en vez de manejar la clase Z.

X xVariable = getX();
Y yVariable = xVariable getY();
getX().getY().getZ().doSomething();
Z zVariable = yVariable getZ();
Clean Code.

[Link]();
[Link] = url;

30
06 — Funciones.

Si poseemos un objeto que contiene otros objetos, no deberíamos


expandir el acceso a ellos en profundidad desde la raíz sino desde el
propio atributo (acceso a los inmediatos).

Otra recomendación es minimizar los condicionales. Si tenemos más


de dos condicionales, deberíamos extraer en un método y refactorizar.
El código de debajo es más entendible.

if ([Link](SUMMER_START) || [Link](SUMMER_END)) {

charge = quantity * winterRate + winterServiceCharge;

} else {

charge = quantity * summerRate;

if (notSummer(date)) {

charge = winterCharge(quantity);

} else {

charge = summerCharge(quantity);
}

Debemos evitar los efectos secundarios que se producen:

• Cuando una función altera variables locales o de clase.


• Cuando se crean dependencias con respecto al orden de ejecución
Clean Code.

de los métodos.

31
06 — Funciones.

Además, cuando esto ocurre es porque la función hace más de una


cosa. Es importante el orden en el que se ejecuta y tener errores donde
no corresponde.

¿Por qué se inicializa la base de datos en una función que hace login?

Boolean login(String user, String password) {


if (validLogin(user, password)){
initDatabase();
return true;
}
return false;
}
Clean Code.

32
06 — Funciones.

¿Cómo debería ser el proceso de creación de una función? Aquí


dejamos unas recomendaciones.

• Estructuremos bien nuestras ideas y lo que queremos hacer.


• Generemos un borrador de cómo lo vamos hacer.
• Iteremos nuestro borrador hasta que estemos seguros que es la
mejor solución.

Dicho esto, a la hora de codificar intentemos:

• Hacer funciones claras y pequeñas.


• Pensar una buena nomenclatura y buscar una buena organización.
• Eliminar duplicidad, abstraer, generalizar y usar todas las buenas
prácticas que conozcamos.
• Repetir todo lo anterior e intentar mejorarnos como
desarrolladores/as.
Clean Code.

33
— 07

DRY
(Don’t repeat
yourself).
07 — DRY (Don’t repeat yourself).

Simplemente se trataría de no repetir código. Cuando tengamos la


sensación de estar haciendo lo mismo, merece la pena pararse y mirar
si podemos hacer una librería, una funcionalidad genérica o cualquier
técnica con la podamos reutilizar el código.

Debemos estar comprometidos con el desarrollo y refactorizar cuando


sea necesario, buscando una mayor mantenibilidad y claridad. Si no,
estamos generando una ventana rota y habrá que hacer un doble
esfuerzo en el futuro para mantener ese código.
Clean Code.

35
— 08

Tratamientos
de errores.
08 — Tratamientos de errores.

En primer lugar, es mejor devolver excepciones que códigos que luego


sean capturados y tratados por un handler. Con excepciones queda
más claro y más mantenible, y si trabajamos con aspectos (AOP) la
excepción se podría tratar fácilmente.

No devolvamos null y fallemos lo antes posible justo donde ha ocurrido


el error. Al final, delegamos ese tratamiento del null en otra parte que
no es responsable.

Es importante no ocultar los errores, registrar en los logs y fallar lo


antes posible para poder ver qué está ocurriendo y dónde con mayor
exactitud.

No devuelvas null y falla lo antes posible, no


ocultes los errores, busca por qué ha fallado y
añade pistas que faciliten el trabajo.

Contextualicemos los errores y añadamos pistas que nos faciliten


nuestro trabajo, ver por qué ha fallado, incluso datos para poder
reproducirlo.

Por último y para evitar acoplamientos, cuando consumimos un API


o librería de terceros no deberíamos propagar sus excepciones y
encapsularlas en excepciones propias. De esta forma, nuestro código
está más preparado para futuros cambios.
Clean Code.

37
— 09

Clases y
objetos.
09 — Clases y objetos.

Dependiendo del lenguaje, existe un code style con un orden de


declaración de los elementos que conforman una clase. Por ejemplo,
en Java suele ser: atributos estáticos, métodos estáticos, atributos
públicos, atributos privados, constructores, métodos públicos,
métodos privados...

Como regla general, debemos pensar que nuestras clases deben


tener un tamaño reducido. Así podemos asegurarnos de que tiene
una única responsabilidad y no es una clase todopoderosa (God
Object Antipattern), que significa que conoce más de lo debe (de su
responsabilidad).

Hay dos conceptos claves: el acoplamiento y la cohesión.

Acoplamiento :

Es el grado en el cual una clase sabe acerca de otras clases. Un


acoplamiento fuerte significa que las clases están muy relacionadas
y que necesitan saber mucho unas de las otras, lo que provoca que
los cambios se propaguen por todo el sistema. Posiblemente sea más
difícil de mantener y de entender.

Para ello, debemos fomentar el bajo acoplamiento que nos permite:


entender una clase sin leer otras, cambiar una clase sin afectar a otras y
mejorar la mantenibilidad del código.
Clean Code.

39
09 — Clases y objetos.

Cohesión :

Es el grado de cómo una clase está diseñada para interactuar consigo


misma. Es individual por cada clase, y nos ayuda a ver si tiene un
propósito bien enfocado.

Debemos tender a minimizar el acoplamiento y aumentar la cohesión.

Normalmente trabajamos con aplicaciones que tienen N capas o


módulos independientes. Para conseguir un desacoplamiento alto
existen DTO (Data transfer Object), que son clases de intercambio entre
capas. Son objetos simples que no tienen lógica.

Existen librerías que nos ayudan a mantener la claridad de nuestros


objetos y liberarnos de ese código que forma parte de nuestra clase
pero aporta poco (getters, setters, toString, constructores...). El uso de
Lombok o el uso de Java Records (JDK >= 14) nos puede ayudar para ese
propósito.

Además, para transformaciones de objetos tenemos la librería de


Mapstruct, que nos facilita mucho el trabajo (compatible con Lombok).

Nuestras clases deben tener un tamaño


reducido. Así podemos asegurarnos de que
tienen una única responsabilidad.
Clean Code.

40
—09.01
09 — Clases y objetos.

STUPID Antipattern.
Cuando no cumplimos estas recomendaciones, podemos estar
cayendo en el antipatrón STUPID. Es importante reinventarse cada día y
mejorar como desarrollador/a para no caer en estas malas prácticas, a
veces sin ser conscientes. STUPID son las siglas de:

• Singleton: Debemos evitarlos por varias razones: son difíciles de


testear, guardan un estado global de la aplicación, son difíciles de
mantener, ocultan dependencias y suelen estar muy acoplados.
• Tight coupling: Esto ocurre cuando muchas clases conocen mucho
sobre otras clases que no deberían conocer. Al final, un cambio en
una clase impacta en muchas otras, empeorando la mantenibilidad
y disminuyendo la capacidad de reutilizar. Un acoplamiento ligero
es necesario, ya que tenemos interfaces de integración entre
diferentes módulos.
• Untestability: Si nuestro código es difícil de testear seguramente
esté fuertemente acoplado, o algo hemos hecho mal.
• Premature optimization: Sería refactorizar algo que realmente no
es necesario y que nos puede llevar a situaciones más complejas.
Por eso, siempre debe priorizarse el sentido común.
• Indescriptive naming: El código es para humanos, no usemos
abreviaturas ni nombres impronunciables. Busquemos una buena
nomenclatura ya sea para clases, funciones, paquetes...
• Duplication: Este punto ya lo vimos en el apartado de DRY.
Escribamos nuestro código una vez y reutilicémoslo.
Clean Code.

41
—09.02
09 — Clases y objetos.

SOLID pattern.
Para luchar contra STUPID tenemos el patrón SOLID, que es una
colección de principios de diseño de buen código recogidos por Rober
C. Martin. Si cumplimos el patrón, el código será legible, reutilizable y
mantenible. Estos principios son:

• Single Responsibility Principle

• Open/Closed Principle

• Liskov Substitution Principle

• Interface Segregation Principle

• Dependency Inversion Principle

Single Responsability: Una clase debe tener una única responsabilidad


y una razón para cambiar. Si se asume más de una responsabilidad, el
código quedará acoplado y será más sensible al cambio. Evitemos las
clases todopoderosas (god classes) y dividamos las responsabilidad
(divide y vencerás).

Open/Closed: El resumen es que una clase debe estar abierta


para extender (heredar), pero cerrada (se puede reutilizar) para
modificaciones.
Los componentes de nivel superior (ancestros) están protegidos de
cambios de los de nivel inferior (descendientes). La funcionalidad se
ordena de manera jerárquica.
Clean Code.

Como regla general, todos los atributos de una clase serán privados y
tendremos los getters y setters que tengan sentido.

42
09 — Clases y objetos.

Liskov Substitution: Los objetos de un programa deberían ser


reemplazables por instancias de sus subtipos sin alterar el correcto
funcionamiento del programa. Cada clase que hereda de otra puede
usarse como su padre sin necesidad de conocer las diferencias entre
ellas.

Interface Segregation: Muchas interfaces de cliente específicas


son mejores que una interfaz de propósito general. Es decir, cuando
desarrollamos y queremos implementar algo específico no debemos
estar obligados a implementar más métodos de los que realmente
necesitamos. Imaginemos una navaja suiza: es mejor hacer una cosa
bien, que tener que hacer muchas si solo quiero cortar.

Dependency Inversion: Se basa sobre todo en dos puntos:


• Las abstracciones no deben depender de las implementaciones
(deberíamos poder cambiar de implementación y nuestro código
seguiría funcionando).
• Las implementaciones dependen de las abstracciones.
No añadamos clases concretas al contrato de la interfaz y usemos
interfaces en nuestras clases. Lo que buscamos es reducir el
acoplamiento y aumentar la reutilización.
Clean Code.

43
— 10

Introducción al
testing.
10 — Introducción al testing.

Test de UI:

• Se ejecutan sobre la capa de UI.


• Son lentas de ejecutar.
• Son difíciles de ejecutar en un entorno local.
• Son de alto nivel y suelen requerir licencias.

Test de Servicio:

• Se ejecutan sobre la capa de API.


• Son end to end, obviando la capa de UI.
• Son pruebas de alto nivel funcional.
• Si detectamos un error, seguramente nos falten test unitarios.

Test Unitarios:

• Se ejecutan sobre partes concretas del código.


• Son muy rápidas de ejecutar.
• Garantizan que los errores no se van a reproducir.
Clean Code.

45
10 — Introducción al testing.

Test Unitarios:

Nuestros test deben cumplir las siguientes características.

• Fast: Cuanto más rápidos sean, más veces los ejecutaremos.


• Isolated: El orden de ejecución no importa porque son test
aislados.
• Repeteable: Somos capaces de repetirlos y siempre obtienen el
mismo resultado.
• Self-validating: Son autovalidados, no requieren de ninguna acción
manual para validarlos y el resultado es un booleano.
• Timely: El test debe ser diseñado antes del código que queremos
probar. Esto está en conexión directa con el desarrollo guiado por
los test (TDD), que tendría que ser la forma en la que deberíamos
desarrollar por todos los beneficios que nos aporta.
Clean Code.

46

Clean code always looks like
it was written by someone
who cares.

Robert C. Martin, Clean Code: A Handbook of


Clean Code.

Agile Software Craftsmanship.


47
Clean Code.

Autor:
48
Antonio
José García.
Estrategia.

Soy un apasionado de las últimas tecnologías,


siempre con ganas de aprender y mejorar. Me
encanta cualquier deporte y soy socio del Real
Madrid. También me gusta la cerveza, el cine y los
videojuegos.
Clean Code.

49
Think Big.

V.1.0 - Septiembre de 2022

info@[Link]

Common questions

Con tecnología de IA

Una nomenclatura consistente en el código es esencial, ya que ayuda a todos los miembros del equipo a entender inmediatamente qué hace cada parte del software, mejorando la comunicación y colaboración. Nombres claros y representativos evitan confusiones y reducen la necesidad de comentarios explicativos, mientras que la incoherencia puede llevar a errores de interpretación y dificultades para compartir y revisar el código eficazmente . Además, una nomenclatura clara y estándar simplifica la integración del trabajo de diferentes partes del equipo, lo que es crucial en un entorno de desarrollo colaborativo .

Limitar las dependencias es crucial en el desarrollo de software para facilitar el mantenimiento y comprensión del código. Un bajo nivel de acoplamiento implica que cada clase o módulo del software conoce y depende de otras lo mínimo necesario, permitiendo modificar una parte del sistema sin afectar considerablemente a las demás . Esto reduce la propagación de errores y hace el sistema más flexible y sostenible .

El antipatrón STUPID es perjudicial para la mantenibilidad del código porque introduce varios problemas. Las clases muy acopladas (Tight Coupling) dificultan los cambios, ya que un cambio en una afecta a muchas otras. La mala nomenclatura (Indescriptive Naming) complica la comprensión del código. La optimización prematura (Premature Optimization) puede llevar a complejidades innecesarias. La falta de testabilidad (Untestability) significa que los errores son difíciles de detectar y solucionar, y la duplicación de código (Duplication) incrementa el esfuerzo de mantenerlo . Estos factores minan la calidad del software, haciéndolo difícil de entender, mantener, y extender .

La estética en el código limpio implica mantener una estructura legible y mínimamente compleja, favoreciendo una eficiencia clara y un entendimiento rápido del código por parte de cualquier desarrollador. Esto no solo mejora la legibilidad, haciéndolo parecer un texto bien escrito , sino que evita optimizaciones prematuras que podrían comprometer la simplicidad . Un código atractivo estéticamente tiende a ser sinónimo de código eficaz y cuidadosamente considerado, lo que disminuye los errores y facilita la mantenibilidad .

En el código limpio, los comentarios deben aportar información que no puede expresarse claramente a través del código mismo. Son útiles para aclarar la intención detrás de bloques complejos o decisiones de diseño. Los errores comunes incluyen utilizar comentarios para código comentado, justificar decisiones obsoletas, o agregar metadatos personales (autores, fechas) cuando ya existen herramientas para ese seguimiento . Los comentarios obsoletos o que repiten obviedades solo generan confusión o sobrecarga innecesaria .

Los principios SOLID son un conjunto de reglas de diseño que, cuando se aplican, promueven la creación de software que es fácil de mantener y ampliar. Incluyen el Principio de Responsabilidad Única, el Principio de Abierto/Cerrado, el Principio de Sustitución de Liskov, el Principio de Segregación de Interfaces y el Principio de Inversión de Dependencias. Estos principios ayudan a reducir el acoplamiento, mejorar la cohesión y crear sistemas flexibles, facilitando el cambio y aumentando la reutilización .

La cohesión se refiere a qué tan bien los elementos de una clase trabajan juntos para cumplir un propósito único y específico. Una alta cohesión asegura que una clase tenga un enfoque claro y bien definido, lo que facilita su mantenimiento y comprensión. Esto también conduce a un diseño más modular y flexible, donde cada clase realiza una tarea específica y su interacción con otras clases es bien definida .

La Ley del Boy Scout, aplicada a la codificación, implica dejar el 'campamento' (código) más limpio de lo que lo encontramos, es decir, mejorar constantemente el código existente. Cada vez que se trabaja con código, se debe hacer un esfuerzo por refactorizar y mejorar su calidad. Esto previene la acumulación de 'deuda técnica' y mejora la mantenibilidad a largo plazo del software . Es esencial porque, al igual que ocurre con basura o ventanas rotas, la falta de mantenimiento puede llevar a un deterioro más rápido y costoso de corregir .

El principio de Responsabilidad Única establece que una clase debe tener una única razón para cambiar, lo que significa que debe encargarse de una responsabilidad concreta. Esto previene la creación de clases "todopoderosas" que manejan múltiples responsabilidades, las cuales son difíciles de mantener y acoplar, ya que cualquier cambio puede tener efectos no deseados . Al dividir las responsabilidades en clases más pequeñas y específicas, se mejora la mantenibilidad, ya que los cambios en una funcionalidad específica solo afectan a una parte del código .

Las pruebas unitarias y de servicio son esenciales para asegurar la calidad continua de un proyecto de software a medida que evoluciona. Las pruebas unitarias son rápidas y se ejecutan en partes específicas del código, garantizando que los componentes individuales funcionen correctamente y evitando la propagación de errores . Las pruebas de servicio validan el comportamiento correcto de las APIs y son esenciales para comprobar el funcionamiento del sistema de extremo a extremo, descubriendo errores integrales que puedan requerir revisiones mayores del código . En conjunto, permiten que los desarrolladores realicen cambios con confianza, sabiendo que cualquier problema se detectará y resolverá rápidamente antes de implementarlo en producción.

1
Clean Code.
Clean Code.
Las mejores prácticas para un 
código limpio.
1ª edición
Atribución 4.0 Internacional  
Usted es libre para:
Compartir, copiar y redistribuir el material en cualquier medio o formato
Autor: Antonio José García.
Ilustraciones: Marta Ruiz.
Maquetación: David Mota.
4
Clean Code.
— Introducción.	
06
— 01. ¿Qué es código limpio?	
08
— 02. Principios del clean code.	
12
— 03. Code style.	
14
5
Clean Code.
— 09. Clases y objetos.	
38	
	
09.01 STUPID Antipattern.	
41
	
09.02 SOLID pattern.	
42
— 10. Introducción al t
Introducción:
7
Clean Code.
Introducción.
Como desarrolladores/as, nos hemos encontrado en muchas ocasiones 
frente a un código que nos cue
01
—
¿Qué es 
código 
limpio?
9
Clean Code.
No existe una definición exacta de código limpio, pero vamos a ver una 
serie de definiciones que nos van a ayu
10
Clean Code.
Como buenos artesanos de código, debemos comprometernos con nuestro 
desarrollo y hacerlo lo mejor que podamos

También podría gustarte