código limpio

El arte de hacer software.


@gruizdevilla

@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


 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#)

  1. Pasa todos los tests
  2. No tiene duplicidades
  3. Expresa las ideas de diseño del sistema
  4. 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.

"Deja el lugar donde acampaste un poco
más limpio que como lo encontraste."

Nombres SIGNIFICATIVOS


Significativo: que da a entender
o conocer con precisión.

Nombres que revelen intención


El nombre de una variable, función,
 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.

   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.

- Por favor, revisa que el servicio PHCTB2
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
u32Identificador

(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.


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)

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.

Por ejemplo, no debe hacer invocaciones
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.


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:

miObj.elMetodoConNombreTanLargoQueAlFinalNoTeAcuerdasDelPrincipio()

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.

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.

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.


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.

definición y CONTEXTO


Las excepciones tienen que definirse
en función de las necesidades de los usuarios.

Tienen que proporcionar el contexto suficiente
para entender su generación.


NULL



No devuelvas null

(En algunos lenguajes te puedes proteger de 
NullPointerExceptions: scala, coffescript,...)

NO PASES NULLs

(En Java, intenta poner todo con final y te ahorrarás muchos NullPointerException)

tests unitarios


Los tres pasos:

  1. Escribe código de producción sólo cuando
    tengas un test unitario que lo pruebe que falle.
  2. Escribe el código de prueba mínimo y necesario
    que haga que el código de producción falle.
  3. 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:


  1. Prepara el escenario
  2. Ejecuta el código
  3. 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.



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):

  1. Ejecutar todos los tests
  2. Que no haya duplicidades
  3. Expresar la intención mediante el código
  4. 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


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.

DRY and DIE


Don't repeat yourself.
Duplication is evil.

Toda pieza de conocimiento debe
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.

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.

Implementa lo que necesites,
no lo que creas que vas a necesitar.

Ley de Brook




Nueve mujeres no hacen un bebé en un mes.



¡gracias!



¿dudas?

REFERENCIAS


codigo limpio

By Gonzalo Ruiz de Villa