código limpio
El arte de hacer software.
@adesis
http://goo.gl/pnIUJ
artesanos del software
Porque hacer software es un arte,
Nuestra "User STORY'
Como un artesano del software
Quiero escribir mejor código
Para que mis colegas desarrolladores
entiendan lo que hace
entiendan lo que hace
Y disfrutemos leyéndolo
Porque somos artesanos
Manifesto for Software Craftsmanship.
Como aspirantes a Artesanos del Software estamos mejorando el nivel del desarrollo profesional del software mediante la práctica y la ayuda a otros para aprender este arte. A través de este trabajo valoramos:
-
No sólo software que funciona,
si no también software bien hecho.
- No sólo que responda a cambios,
si no también que añada valor de forma continuada. - No sólo individuos e interacciones,
si no también una comunidad de profesionales. - No sólo colaboración con el cliente,
si no también una asociación productiva.
Esto es, en la búsqueda del primer elemento de cada frase, hemos encontrado que el segundo es indispensables.
Estamos aquí poR el código
ESCRIBIR Código:
LA ÚNICA PARTE DEL PROCESO
DE DESARROLLO de software
QUE NO TE PUEDES SALTAR
El código:
se escribe una vez
se modifica 10 veces
se lee 100 veces
¿QUÉ Implica el
código MALO?
Puede llevar a la ruina
A UNA COMPAñÍA
Coste de los bugs
¿QUé entendemos
por código Limpio?
ALGUNAS DEFINICIONES:
Bjarne STROUSTRUP
(Inventor de C++)
Elegante y eficiente.
Lógica directa, mínimas dependencias y fácil de mantener.
GRADY BOOCH
(Desarrolló UML)
-
El código limpio se lee como prosa bien escrita
"BIG" dave thomas
(Padrino de Eclipse)
- El código limpio puede ser leído y mejorado
por un desarrollador distinto de su autor original.
- Tiene tests unitarios y de aceptación.
- Tiene nombres con significado.
- Proporciona una forma de hacer las cosas en lugar
de muchas alternativas.
Michael Feathers
(Autor de "Working Effectively with Legacy Code")
- El código limpio parece estar hecho
por alguien a quien le importa.
Ron Jeffries
(Extreme Programming Adventures in C#)
- Pasa todos los tests
- No tiene duplicidades
- Expresa las ideas de diseño del sistema
- Minimiza el número de entidades
como clases, métodos y similares
Ward cunningham
(Inventor de la Wiki y mucho más)
- Sabes que estás trabajando con código limpio
cuando cada rutina que lees resulta ser como lo
que esperabas encontrarte. - Cuando parece que el lenguaje fue hecho para
el problema que resuelve el código.
la regla del boy scout
Porque no es suficiente escribir buen código.
El código se tiene que mantener sin pudrirse
ni degradarse.
El código se tiene que mantener sin pudrirse
ni degradarse.
"Deja el lugar donde acampaste un poco
más limpio que como lo encontraste."
más limpio que como lo encontraste."
Nombres SIGNIFICATIVOS
Significativo: que da a entender
o conocer con precisión.
o conocer con precisión.
Nombres que revelen intención
El nombre de una variable, función,
parámetro o clase debería aclarar:
parámetro o clase debería aclarar:
- ¿por qué existe?
- ¿qué hace?
- ¿cómo se usa?
Dedica el tiempo necesario a escoger el nombre.
int d; //dias transcurridos
//VS int diasTranscurridos; int diasDesdeCreacion; int diasDesdeModificacion;
Evita desinformación
Se debe prevenir el uso de
nomenclatura que introduzca confusión.
nomenclatura que introduzca confusión.
cuentasList; //Si no es de tipo List....
XYZControllerConManejoEficienteDeStrings;
XYZControllerConAlmacenamientoEficienteDeStrings;
haz distinciones que aporten valor
public void copiarObjeto(Clase1 o1, Clase1, o2);
//vs
public void copiarObjeto(Clase1 origen, Clase1 destino);
pronunciable
Si no lo puedes pronunciar,
no puedes debatir sobre el
sin quedar como un idiota.
no puedes debatir sobre el
sin quedar como un idiota.
- Por favor, revisa que el servicio PHCTB2
informa correctamente el IUCC en el OGEST.
informa correctamente el IUCC en el OGEST.
- ¿El servicio PHCPB2?....
nombres buscables
De lo más usado:
Ctrl+F: buscar en fichero
Ctrl+Shift+F: buscar en ficheros
(o el acceso rápido que tenga tu IDE)
Aumenta tu productividad con buenos nombres
evita encodings
¿No tenemos lenguajes con tipado estático?
- iContador
- arrNums
- bOcupado
(Y para tipado dinámico, apoyate en TDD)
evita mapas mentales
Los lectores no tienen que tener que traducir
tus nombres a otros que entiendan.
tus nombres a otros que entiendan.
La claridad es fundamental.
nombres de clases
- Deberían ser nombres y no verbos
- Evitar palabras ambiguas como "Manager",
"Gestor", "Procesador", "Controller", "Data",
"Info"
nombres de métodos
- Deben ser un verbo
- Y en castellano además es bueno
que sea imperativo - En el caso de constructores, mejor
que sobrecargar es usar métodos estáticos
de factoría.
Contexto
aporta contexto si es necesario
pero
evitar contexto gratuito
Evita cosas como:
- Reusar el nombre de una clase dentro
de una propiedad: Contacto.ContactoNombre
- Prefijar las clases con el nombre de una aplicación,
para eso están los namespaces/packages.
una palabra por concepto
- Consistencia en toda la aplicación.
- Evita que una palabra tenga varios significados.
- Evita usar varias palabras para lo mismo.
palabras del ámbito de negocio
- Utiliza la semántica del ámbito de negocio
de la aplicación: ¿que palabras usa tu cliente? - Las términos usados deben coincidir
con la forma en que los usuarios verbalizan
los problemas.
Funciones
Cada vez más importantes: FP
(Functional programming o programación funcional)
(Functional programming o programación funcional)
pequeñas
Primera regla: Tienen que ser muy pequeñas.
Segunda regla: Deben ser aún más pequeñas.
Tercera regla: Todavía es muy grande.
hacen una cosa
Una función:
hace solo UNA cosa,
y la hace BIEN
y no hace nada más.
un nivel de abstracción
Una función no debe mezclar
niveles de abstracción.
niveles de abstracción.
Por ejemplo, no debe hacer invocaciones
a funciones de alto nivel y cosas técnicas
a la vez.
a funciones de alto nivel y cosas técnicas
a la vez.
String documento = generaDocumento();
documento.append("Generado automaticamente por el sistema.")
SWITCH
Suficiente entidad para ser la única
responsabilidad de una función.
responsabilidad de una función.
public Importe calculaPaga(Empleado e) throws TipoEmpleadoInvalidoException {
switch(e.type) {
case COMISIONISTA:
return calculaComisiones(e);
case ASALARIADO:
return calculaSalario(e);
case FREELANCE:
return calculaPagoPorHoras(e);
default:
throw new TipoEmpleadoInvalidoException(e);
}
}
Muchas alternativas
var calculadoras = {}; calculadoras.COMISIONISTA = calculaComisiones(); calculadoras.ASALARIADO = calculaSalario(); calculadoras.FREELANCE = calculaPagoPorHoras(); function calculaPaga(empleado) { return calculadoras[empleado.type](empleado); }
nombres descriptivos
- Sin miedo a los nombres largos.
- Mejor un nombre largo y claro
que corto y enigmático. - Mejor un nombre largo y claro
que un comentario. - Utiliza un estilo que facilite la lectura.
- Sin pasarse:
ARGUMENTOS
Número de parámetros:
- Ninguno: bueno..
- Uno (función monádica): BIEN, fácil de concatenar.
- Dos (función diádica): humm... ok
- Tres (función triádica): hummmmmm..... ¿estas seguo?
- Más de tres: Refactoriza
Flags:
- ¿Se entienden?
.render(true)
vs
.renderSuite()
.renderSingleTest()
SIN EFECTOS SECUNDARIOS
- Mejor programación funcional.
- Los efectos secundarios
generan acoplamientos. - Si no queda más remedio, que quede
explicitado:
.compruebaClaveEIniciaSesion()
CONSULTA U ORDEN
Las funciones deberían:
- hacer algo
- consultar algo
- pero no ambas cosas
(aunque a veces se resuelve bien, jQuery)
/*Comentarios*/
¿Buenos o malos?
Los comentarios no son la
solución a un mal código.
solución a un mal código.
BUENOS COMENTARIOS
- Comentarios legales
- Comentarios informativos (por ejemplo,
referenciando documentos normativos
sobre el cálculo de el DC de un CCC) - Explicando intenciones
- Comentando APIs públicas
MALOS COMENTARIOS
- Mascullando
- Redundantes: RUIDOOOO
- Que conducen a engaño
(TooMuchCopyPasteException) - Comentando código complicado:
reescribe el código!!! - Código comentado: ¿no tienes control de versiones?
- Diario: ¿no tienes control de versiones????
- Marcas personalizadas: porque el cierre
del bucle está muy lejos?? refactoriza! - Documentación de métodos privados???
Formateo
- Cualquiera puede escribir código que entienda
un ordenador - Los buenos programadores escriben código
que otras personas pueden entender
FORMATEO: Hablamos de comunicación
FORMATEO VERTICAL
- Separación de bloques
- Bloques compactos
Distancia entre elementos:
- Acerca conceptos relacionados
- Una función que invoque a otra: acércalas
- El llamador por encima del llamado (excepción:
JavaScript que pasa JSLint) - Variables declaradas cerca de donde se usan
- Variables de instancia al principio de la clase
Formateo horizontal
- Líneas cortas
- Una acción por línea
- Indentación, informa de jerarquía
FORMATEO
Lo más importante:
el equipo manda
objetos y estructuras de datos
Hay un motivo para la existencia de variables privadas:
no queremos que nadie dependan de ellas.
¿Por qué añadir getters y setters a todas ellas?
abstracciones correctas
Hablemos de un punto:
public class Punto {
public double x;
public double y;
}
public interface Punto {
public double getX();
public double getY();
public setCartesianas(double x, double y);
public double getR();
public double getTheta();
public setPolares(double r, double theta);
}
estructuras u objetos
- En lenguaje procedimental es más fácil
añadir funcionalidad sin afectar a las
estructuras. En OO, es fácil añadir nuevas
clases sin cambiar las funciones.
- En lenguaje procedimental es difícil añadir
estructuras, pues afecta a todas las funciones.
En OO, es más difícil añadir funciones porque
todas las clases se ven afectadas.
Ley de demeter
Un objeto no debe conocer nada
acerca de las interioridades de los objetos
que maneja.
acerca de las interioridades de los objetos
que maneja.
Queremos evitar los accidentes de trenes:
ctx.getSession(true).getStorage().get("dato").value
DTO
Data Transfer Object
gestión de errores
¿Códigos de error devueltos
por una función? No, por favor.
por una función? No, por favor.
Programación síncrona: excepciones.
Programación asíncrona: objetos de error.
- Patrón de continuación: primer argumento
- Promesas o FRP: función controladora de error
Excepciones ¿chequeadas o no?
Unchecked salvo que sea
imprescindible lo contrario.
imprescindible lo contrario.
definición y CONTEXTO
Las excepciones tienen que definirse
en función de las necesidades de los usuarios.
en función de las necesidades de los usuarios.
Tienen que proporcionar el contexto suficiente
para entender su generación.
para entender su generación.
NULL
No devuelvas null
(En algunos lenguajes te puedes proteger de
NullPointerExceptions: scala, coffescript,...)
NullPointerExceptions: scala, coffescript,...)
NO PASES NULLs
(En Java, intenta poner todo con final y te ahorrarás muchos NullPointerException)
tests unitarios
Los tres pasos:
- Escribe código de producción sólo cuando
tengas un test unitario que lo pruebe que falle. - Escribe el código de prueba mínimo y necesario
que haga que el código de producción falle. - Solo escribe el código de producción imprescindible
para que el test pase.
SOBRE LOS TESTS
- Limpio
- Un concepto por test
- Una afirmación por test
-
Tres pasos para un test:
- Prepara el escenario
- Ejecuta el código
- Comprueba el resultado
TEST FIRST
F: FAST.
Rápidos.
I: INDEPENDENT.
Independientes entre si.
R: REPEATABLE
Repetibles independientemente del entorno.
S: SELF VALIDATING
Si o No. Pasa o no pasa. Resultado claro.
T:TIMELY
Escritos secuencialmente, justo antes
de necesitarse.
de necesitarse.
clases
Las clases deben ser pequeñas.
Tener una única responsabilidad.
Cohesión entre sus métodos y propiedades.
emergencia
Todas las reglas descritas anteriormente
conducen a un diseño emergente.
Es la consecuencia de seguir los siguientes
pasos (ordenados por importancia):
conducen a un diseño emergente.
Es la consecuencia de seguir los siguientes
pasos (ordenados por importancia):
- Ejecutar todos los tests
- Que no haya duplicidades
- Expresar la intención mediante el código
- Minimizar el número de clases y métodos
Para recordar
¡ACRÓNIMOS y frasecitas!
(En inglés...)
SRP
Single Responsibility Principle
Todo objeto tiene una única responsabilidad
completamente encapsulada
completamente encapsulada
KISS
Keep it simple, stupid!
Keep it simple and stupid.
Keep it short and simple.
Keep it simple and straightforward.
Vamos, simplicidad.
YAGNI
You ain't gonna need it.
Cuidado con los "por si acaso".
Implementa la funcionalidad cuando
la necesites.
Implementa la funcionalidad cuando
la necesites.
DRY and DIE
Don't repeat yourself.
Duplication is evil.
Toda pieza de conocimiento debe
tener una representación única,
inequívoca y autoritaria.
tener una representación única,
inequívoca y autoritaria.
ley de demeter
No hables con extraños.
POLS
Principle of Least Suprise.
Las cosas deberían comportarse
como se espera que se comporten.
como se espera que se comporten.
Principio de hollywood
No nos llames, ya te llamamos nosotros.
POGE
Principle of Good Enough
Favorece diseños sencillos y rápidos (pero
potencialmente extensibles) sobre diseños elaborados.
potencialmente extensibles) sobre diseños elaborados.
Implementa lo que necesites,
no lo que creas que vas a necesitar.
no lo que creas que vas a necesitar.
Ley de Brook
Nueve mujeres no hacen un bebé en un mes.
¡gracias!
¿dudas?
REFERENCIAS
- Clean Code: A Handbook of Agile Software Craftmanship (Robert C. Martin)
- Refactoring: Improving the Design of Existing Code (Martin Fowler)
- Extreme Programming Adventures in C# (Ron Jeffries)
- Seven Languages in Seven Weeks (Bruce A. Tate)
- 97 things every programmer should know (Muchos autores)
codigo limpio
By Gonzalo Ruiz de Villa
codigo limpio
- 45,172