Aprendiendo Python

Los programadores somos personas obsesionadas con el aprendizaje y yo no me libro. He estado varias semanas reflexionando sobre como podía avanzar profesionalmente y finalmente he llegado a la conclusión de que necesito tapar algunos agujeros en mi curriculum. Para que eso no fuese muy aburrido he elegido hacerlo con un lenguaje nuevo para mi: Python 3.6

Es decir que voy a reforzar mi puesto de Full stack developer en dos aspectos principalmente:

  • En back-end con python
  • En front-end con react

Por el camino tengo que reconstruir mi portfolio personal y poner en valor correctamente toda la experiencia ganada en la etapa junior. Una vez todo puesto en orden…

Cuando esta primera etapa termine, hay varios caminos que se presentan y que me motivan:

  • Data analysis / Machine learning
  • VR / AR
  • Mas front-end y aplicaciones moviles (PWA, react native)

Pero eso llegara mas tarde y aun lo veo borroso. Solo se puede hacer una cosa a la vez, asi que hoy he comenzado a ver algunos básicos de Python que me ayudan a arrancar haciendo algunos scripts:

1. Abre una url en el navegador cada dos segundos

import webbrowser
import time


print("This program started on "+time.ctime())
breaks = 3

while breaks > 0:
    time.sleep(2)
    webbrowser.open("https://www.youtube.com/watch?v=IkOLYvOvH2w")
    breaks = breaks - 1

2. Cambia el nombre a una lista de ficheros

import os


def rename_files():
    photos_path = "/home/defnx/PycharmProjects/learn/photos"
    os.chdir(photos_path)
    file_list = os.listdir(photos_path)
    table = str.maketrans(dict.fromkeys("0123456789"))

    for file_name in file_list:
        os.rename(file_name, file_name.translate(table))


rename_files()

3. Dibuja en una ventana

import turtle


def main():
    window = turtle.Screen()
    window.bgcolor("black")
    drawer = turtle.Turtle()
    drawer.color("red")
    drawer.speed(20)
    drawer.shape("turtle")

    for i in range(1, 37):
        draw_square(drawer)
        drawer.right(10)

    window.exitonclick()


def draw_square(drawer):
    for i in range(1, 5):
        drawer.forward(200)
        drawer.right(90)


main()

4. Envía sms usando twilio

from twilio.rest import Client

account_sid = "XXXXXXXXXXXXXXXXXXXXXXXXXXX"
auth_token  = "XXXXXXXXXXXXXXXXXXXXXXXXXXX"
client = Client(account_sid, auth_token)

message = client.messages.create(
    to="+34456789123",
    from_="+34456789123",
    body="Hello from Python!")

print(message.sid)

5. Verifica si en un texto hay tacos

import urllib.request
import urllib.parse


def read_text():
    quotes = open("/home/defnx/PycharmProjects/learn/text")
    contents_of_file = quotes.read()
    quotes.close()
    check_profanity(contents_of_file)


def check_profanity(text_to_check):
    query = urllib.parse.urlencode({'q': text_to_check})
    url = "http://www.wdylike.appspot.com/?"+query
    connection = urllib.request.urlopen(url)
    output = connection.read()
    connection.close()

    if b"true" in output:
        print("Profanity Alert!!")
    elif b"false" in output:
        print("This document has no curse words!")
    else:
        print("Could not scan the document properly.")


read_text()

 

 

 

 

Apis que no odiaré

No puedo negar que estoy un poco cansado de oír a las vedettes de la programación. Ultimamente tiendo a conceder mas crédito a blogeros, amigos, comentaristas de reddit y en general programadores anónimos que realizan cada día su trabajo en un entorno real.

Porque seamos serios, para estos tíos solo hay una forma correcta de hacer las cosas: hacerlas bien. Y no es lo que encuentro cada día en el mundo real (odio hablar así pero…).

Mi entorno es la trinchera ya sabes.

 

Dicho esto, valoro mucho a estos personajes, es solo que muchas veces su discurso perfecto emitido desde la torre de marfil no casa bien en un mundo real de deadlines y balances empresariales. Voy a tomar algunas notas rápidas sobre lo que me encuentre en este libro. No pretendo ser pedagógico, mas bien quiero tener algunas notas que me puedan ayudar cuando construya la próxima api.

Lo primero que necesitas para hacer apis que no odies es un programa que genere datos de prueba. Un seeder que llene tu base de datos de bullshit para hacer tests. En el libro recomienda Faker. Lo probaré.

Después hay que planear y crear las URL (endpoints). Para ello vamos a crear una lista de nombres, y para cada nombre, una lista de acciones que contendrán las 4 tipicas de cualquier CRUD mas cualquier otra que necesitemos, incluyendo posibles filtros para los datos (parámetros). Por ejemplo:

Lugares:

  • Create
  • Read
  • Update
  • Delete
  • List (lat, lon)
  • Images

En este caso necesitamos una lista de lugares, que opcionalmente se pueda filtrar por latitud y longitud. también podemos subir imágenes. Si nuestra api solo permite subir una imagen, que sustituye a la anterior, el recurso sera /image.


Básicos de Restful

  • GET /resources
  • GET /resources/x
  • GET /resources/x,y,z
  • GET /users/x/places/y (embebbed data)

Recordar que x, y o z aquí es mejor que sean UUID y no un simple autoincrement. Los autoincrement ofrecen una información a los usuarios de la api que normalmente preferimos ocultar.

  • DELETE /places/x
  • DELETE /places/x,y,z
  • DELETE /places
  • DELETE /places/x/image
  • DELETE /places/x/images

PUT / POST

Usamos PUT cuando conocemos la url completa de antemano y no importa cuantas veces se ejecute, el resultado sera el mismo. En los otros casos, usa POST. Por ejemplo, si quiere subir la imagen de un usuario:

PUT /users/x/image

Conozco la url completa y aunque use el endpoint diez veces el resultado sera siempre el mismo, sustituir la imagen existente.

POST /computers/x/settings

Aqui puedo subir a cada vez una setting diferente, así que el resultado no es necesariamente el mismo.

Algún consejo mas

  • Usa siempre plural en los recursos, es mas consistente.
  • No pongas verbos en la url, solo nombres (recursos)
  • Cada recurso / nombre tiene su controlador. El resto de normas tiene cierta flexibilidad, por ejemplo si un recurso solo atañe a users, tal vez podamos tratarlo en el UsersController.

Input & Output

O lo que es lo mismo, como organizar y estructurar las requests y las responses de nuestra api:

Requests:

POST /authors/4/book HTTP/1.1
Host: api.cool-authors.com
Authorization : Bearer cn389ncoiwuencr
Content-Type: application/json
{"user_id" : 2 }

Responses:

HTTP/1.1 200 OK
Server: nginx
Content-Type: application/json
...
{
    "id":"44556",
    "book": {
        "id":"4562"
    }
}

Como Content-Type usaremos siempre application/json que es mucho mas claro y legible y da lugar a menos errores y mas precisión en el tipado que por ejemplo application/x-www-form-urlencoded, muy usado en PHP. Hay muy pocos casos en los que xml sea necesario. Personalmente me parece odioso XML y SOAP y solo trabajo en ello como mercenario o obligado por circunstancias particulares que espero se repitan lo menos posible en el futuro.

KISS

Sobre la estructura del contenido no hay consenso.

  • JSON api (uno o varios resources, no hay diferencia, devuelve un array de objetos)
  • Twitter (si hay varios recursos devuelve un array, si no devuelve el objeto)
  • Facebook (como twitter pero incluye los recursos dentro de un namespace, lo que facilita añadir metadata potencialmente)

Se recomienda incluir siempre un namespace que agrupe el recurso único o la colección:

{
  "data": {
    "id": "503294",
    "name": "defnx"
  }
}

{
  "data": [
    {
      "id": "503294",
      "name": "defnx"
    },
    {
      "id": "503296",
      "name": "yuale"
    }
  ]
}

Mi experiencia personal me hace preferir devolver siempre una colección, aunque puedo ver ventajas en ambos estilos. Tal vez solo sea una cuestión de gustos personales donde finalemente se impondrá la visión del manager (generalmente arbitraria).


Códigos de estado HTTP, errores y mensajes

Incluso cuando algo va mal preparando la respuesta, devolvemos datos. La información sobre como ha ido en el servidor llega al cliente gracias a los codigos HTTP y los mensajes de error. Algunos códigos HTTP típicos son:

  • 200 – Todo ha ido bien
  • 201 – Algo se ha creado bien
  • 202 – Request aceptada, se procesa asíncronamente
  • 400 – Error en la estructura de la request
  • 401 – No autorizado (no hay usuario)
  • 403 – El usuario no puede acceder esos datos
  • 404 – La ruta no es valida o el recurso no existe
  • 405 – El método no esta permitido
  • 410 – Los datos han sido borrados, desactivados…
  • 500 – Un error inesperado en el servidor
  • 503 – Servicio no disponible en este momento

Los códigos http deben usarse como categorías generales de errores, pero probablemente vamos a necesitar mas granularidad en la respuesta, creando nuestros propios tipos de errores y mensajes explicativos.

{
  "error": {
    "type": "OAuthException",
    "code": "err-1234",
    "message": "sorry bro",
    "href": "http://api.example.com/docs/errors/#err-1234"
  }
}

Si hay varios, se pueden agrupar en un array “errors”. La estructura de un objeto error puede contener algunos elementos que especifica la json-api, como id, href, status, code, title, detail, links o path.


Testing

Como los unit tests en una api con muchos endpoints muchas veces se convierten en una pesadilla, en el libro se propone usar Behat en un entorno de desarrollo PHP. Se trata de una herramienta BDD (Behaviour Driven Development) que viene a ser lo mismo que Cucumber.

Feature: Users

Scenario: Finding a specific user
    When I request "GET /users/1"
    Then I get a "200" response
    Then I scope into de "data" property
        And the properties exist:
            """
            id
            name
           """
        And the "id" property is an integer

Con una herramienta de este tipo debemos definir “Features” que corresponden a nuestros recursos (los nombres). A continuación definimos “Scenarios” que corresponden de alguna forma a los métodos _test de nuestro set de unit tests. Y para cada escenario definimos “Steps” que pueden recordar los asserts de nuestros unit tests. Todo ello expresado casi en lenguaje natural.

Ahora que no hay nada de código escrito, es el mejor momento para escribir todos los tests de esta forma. Así continua la reflexión sobre la api antes de ponerse a escribir líneas.

Para poder ejecutar estos tests, hay que darle a la librería algunos detalles como el host de nuestra api. Mas sobre como usar behat aquí.


Outputting data

En un capitulo anterior el autor recomienda usar un namespace para agrupar los resultados, el usa “data”.

También devuelve un array de objetos si hay varios recursos en la respuesta:

{
  "data": [
    {
      "id": 5,
      "name": "defn.es"
    },
    {
      "id": 6,
      "name": "abrahammesa.com"
    }
  ]
}

O el objeto mismo directamente si solo hay un recurso:

{
  "data": {
    "id": 5,
    "name": "defn.es"
  }
}

Respecto al controlador, no debería hacer uso de un ORM u otro mecanismo de recuperación de datos de la base directamente para devolver los datos. Es decir que entre la recuperación de datos y el return debe haber una selección de los elementos concretos que deseamos devolver y castings adecuados a los tipos de datos que esperamos. Aqui algunas razones:

  • Rendimiento
  • Casting en string de las extensions PHP (boolean se convierte en “1” o “0”)
  • Seguridad (clientes de la api que potencialmente ven datos comprometedores)
  • Estabilidad

Para hacer ese tipo de transformaciones podemos usar la librería Fractal.

Si nuestro modelo de datos cambia debemos ser cuidadosos para dejar esos cambios dentro del scope de nuestra aplicación y que no salgan al exterior si no es indispensable.

Los errores tendrán  cada tipo que usemos su método correspondiente, y tendremos la posibilidad de definir errores customizados si es necesario en un método genérico que responde con un error. Tiendo a pensar que los códigos de error HTTP ya gestionan muchos casos, pero que es posible que en efecto necesitemos mas granularidad.


Relación entre los datos

Nuestro modelo de base de datos no tiene porque ser fiel a la estructura de nuestra api, aunque en la mayoría de los casos se parecerán mucho. Cuando nuestro recurso tiene datos asociados tenemos que encontrar el equilibrio entre enviar todos los datos relacionados, o enviar urls para que sea el cliente quien recupere los datos. Es decir, entre enviar muchos Kb y tener menos trafico http, o enviar pocos Kb y tener mas requests http.

Otras soluciones:

Enviar los identificadores de los objetos relacionados y hacer una segunda requests con todos ellos.

{
  "data": {
    "id": 5,
    "name": "defn.es",
    "_links": {
      "domains": ["3", "4"]
    }
  }
}

Sideloading: Evita la duplicación de datos embebidos.

{
  "data": [
    {
      "id": 5,
      "name": "defn.es",
      "_links": {
        "domains": ["3", "4"]
      }
    },
    {
      "id": 6,
      "name": "defn.com",
      "_links": {
        "domains": ["3", "4"]
      }
    }
  ],
  "_linked": {
    "domains": [
      {
        "id": "3",
        "name": "www.defn.com"
      },
      {
        "id": "4",
        "name": "api.defn.com"
      }
    ]  
  }
}

Embedded Documents (Nesting)

Para mi es la mejor de las que expone el libro, porque el cliente obtiene exactamente lo que necesita y se reduce el numero de requests, optimizando la descarga de datos. Se trata de que nuestra api de lo que se le pide.

/posts?include=comments,author.image

Debugging

Postman! El libro no habla de ello, pero me encanta. Junto con un browser claro.


Authentication

Autenticarse en una api sirve para hacer un seguimiento de los usuarios, dar contexto a los usuarios, dar o quitar acceso a ciertos recursos, activar o desactivar cuentas, etc.

A veces nuestra api no necesita esta funcionalidad, porque sus recursos son públicos y son de lectura únicamente o tal vez se encuentra en una red privada, protegida de otras formas. Para el resto de casos seguramente convenga implementar un login.

Basic

Se trata de enviar un nombre y una contraseña. Es fácil de implementar pero no es segura, especialmente en http. En cada request el nombre y la contraseña son enviados en el header, lo cual es potencialmente un riesgo.

Digest

Mejora la seguridad con respecto a Basic. En lugar de enviar la contraseña envía el hash MD5 calculado de ella. El problema es que sigue siendo una forma no muy segura de logarse en la que hay que enviar en cada request la contraseña. Sobre SSL es bastante seguro.

OAuth 1.0a

Es muy segura y no envía la contraseña constantemente en el header. Pero es difícil trabajar con ello. El token nunca cambia así que la seguridad se compromete si se usa mucho tiempo. Se trata de una tecnología en desuso.

OAuth 2.0

Requiere SSL. El usuario recibe un token de acceso que puede usar en cada request. Estos tokens caducan al cabo de un tiempo determinado. Para controlar ese tiempo, puedes recoger una exception “Not Authorized”, y pedir otro token en ese wrapper. Implementarlo a mano es muy difícil, así que mejor usar alguna librería. El libro recomienda dos (en el caso de PHP):


Pagination

De lo que hablamos aquí es de dividir el resultado potencial de una sola request imaginaria, en varias requests. Esto nos ayuda a presentar los datos de forma mas amable para el cliente así como mejorar la performance de la llamada (http y database).

Para conseguirlo vamos a enviar un parámetro mas en nuestra query string:

/domains?number=10

La response incluiría información sobre la pagination así como la url que debemos llamar para obtener la siguiente pagina:

{
  "data": [
    
  ],
  "pagination": {
    "total": 100,
    "count": 10,
    "per_page": 10,
    "current_page": 1,
    "total_pages": 10,
    "next_url": "/domains?page=2&number=10"
  }
}

Sin duda contar los totales puede ser pesado en grandes bases de datos. En muchos casos hay que cachear el resultado, precalcularlo o filtrarlo a través de otros atributos:

/domains?iso=es&page=2&number=120

Otra forma de obtener una pagination es gracias a los cursores, una respuesta podría quedar así:

{
  "data": [

  ],
  "pagination": {
    "cursors": {
      "after": 10,
      "next_url": "/domains?cursor=10&number=10"
    }
  }
}

Es una forma eficiente de tratar con muchos datos sin contarlos, el problema es que siempre habrá una ultima request que no retornara nada.


Content negotiation

Envía el tipo de documento que deseas en el Accept Header y tratalo en la API recuperando el MimeType. Si el tipo no existe, devuelve un error 415.

GET /domains HTTP/1.1
Host: api.test.loc
Accept: application/json

HATEOAS

Una api no puede ser considerada restfull si no incluye hiperlinks en sus respuestas. Gracias a ellos podemos explorar el resto de la api y trabajar con los recursos cómodamente.

{
  "data": [
      ...
  ],
  "link": [
    {
      "rel": "self",
      "uri": "/domains/1"
    },
    {
      "rel": "domain.subdomains",
      "uri": "/domains/1/subdomains"
    }
  ]
}

Versioning

Por ultimo en este largo post, solo comentar que respecto al versionado (algo a lo que se vera obligada nuestra api de una forma u otra) parece que no hay una solución ideal, ya que todas rompen de una forma u otra RestFull.

A mi la aproximación que mas me gusta (Sturgeon approved) es la que usa el header para indicar la versión que se usa, a través del atributo “Content”, de la manera en que se hace en la api de Github:

Accept: application/vnd.github.v3+json

De esta forma las URL de nuestros recursos serán siempre iguales, respeta las ideas de HATEOAS, es simple de usar y no hay problemas con el cache.

Pila fifo de objetivos para 2017

Creo que el final del año es el peor momento para crear nuevos objetivos. En general cualquier estado de euforia, de exaltación, de irrealidad incluso diría como la navidad, no es el mejor momento para crear nuevos objetivos.

Yo antes también lo hacía así, y todo quedaba por lo general en papel mojado. Ahora busco otras épocas más tranquilas, más conscientes, para pensar en los retos que están por venir a corto plazo. Además me parece artificial escoger el año como periodo. Sin duda habrá retos que requieran poco tiempo y otros que requieran más. Habrá retos que cumplamos y otros que no. Por que un año? Solo es una representación arbitraria (como casi todo al principio) respecto a una estrella llamada Sol en una minúscula galaxia en mitad de un espacio infinito.

Para mi un objetivo o un reto es un contrato, así que me cuido mucho de que pongo en esa lista. Y desde luego no es algo que haga con unas cuantas copas de champagne en el cuerpo el día 31.Hoy es 1 de enero y no he añadido nada a mi lista. Mi 1 de enero de 2017 lo he pasado con mi familia, también he salido en bici por Lyon, donde vivo desde finales del 2012.

21 Km, Lyon, 3°C, media de 16 km/h
21 Km, Lyon, 3°C, media de 16 km/h

Al salir he pensado que debía parecer una de esas personas que el día anterior se dijo: En 2017 haré más deporte!

Cuando todo el mundo esta nervioso y dejándose llevar, mas estricto intento ser con mis ideas.

 

Otro estilo de objetivos que nunca me han funcionado. Quiero decir que hay que ser concreto. Que significa hacer más deporte? Ir al gimnasio? Salir a correr? Salir en bici? Cuántos días lo harás por semana, cuántas horas, qué necesitas? Hay que concretar. Cuanto más detallado, más fuerte es el contrato, y para mi, más difícil de romper.

Romper un contrato generalmente significa ser capaz de encontrar las excusas necesarias para no cumplirlo.

 

Tengo objetivos aun en mi lista, porque añadir algo nuevo ahora? para sentirme mejor? A veces decirse que uno va a hacer algo es un poco como empezar a hacerlo. Nada más lejos, pero nos hace sentir bien por un instante, es adictivo pero uno se mira y sigue ahí, en el sofá sin hacer nada. Hace un año o dos añadí a mi lista : No ser vago. Me ha ayudado mucho a trabajar por el resto.

Yo soy programador y en mi lista solo hay dos proyectos relativos a la programación, dos aplicaciones que quiero crear y que me ayudaran en mi día a día. Los objetivos están bien, una persona debe tener rumbo, aunque no sea fijo, pero debe dirigirse hacia algún punto. Yo no soportaría vivir sin uno. Pero cuidado, porque puede que uno se pase los días mirando a ese horizonte sin hacer nada para conseguirlo. Hay que vivir el día, lo que hagas hoy te puede ayudar a conseguir esos objetivos.

No lo hago cada día, pero a veces por la mañana me siento tranquilamente y leo la lista y me pregunto qué puedo hacer hoy para avanzar en este o en tal objetivo. Así que mi reto se divide en micro retos que tienen validez hoy. Un reto no sale de la lista hasta que ha sido conseguido, y no entran nuevos retos hasta que la lista no se hace más pequeña. Pero la lista no cambia cada año, sino que está siempre ahí, siempre está viva y nunca se renueva, solo entran y salen lineas, contratos, retos. Pero no dejo de vivir el día a día, parando los pies al bullshit de fin de año (lo mismo ocurre al final del verano).

Si no has encontrado las razones correctas que te motiven a hacer algo, es decir, si en realidad no quieres hacer algo, por que añadirlo a una lista ? Por que contarlo a alguien ? Yo guardo mis objetivos en privado, no soy muy 2.0, no uso las redes sociales, llámame bicho raro, todo lo que tengo es este blog y una cuenta de twitter en la que no escribo o escribo y borro periódicamente. Por qué ponerse en evidencia ? Yo no escribiría mas de 5 o 6 cosas en esa lista, cosas que realmente estoy dispuesto a hacer. Cosas que me hagan avanzar, en lugar de retos que solo sirven a crear una imagen y auto-convencerse de cosas erróneas. No quiero que las mismas frustraciones se repitan al final de cada ciclo.

Objetivos que podrían estar activos hoy:

  • Menos programación pero mas práctica, quiero aprender las bases y quiero darme lo que me falta para ser un full-stack web developer.
  • Disfrutar mas de todo lo que había antes de la programación: literatura, cine y deporte.
  • Llevar a cabo los proyectos personales de programación.
  • Dedicar menos atención al ruido de Internet: Aporta o aparta (de mi camino)
  • Quiero hacerme algunos tattoos nuevos!
  • Recuperar cierto orden y calma tras unos meses tumultuosos, suena abstracto pero se puede concretar.

Seguro que podría añadir mas cosas, pero que sentido tiene? Lo importante es lo que haces no lo que piensas o dices. Probad a medir a las personas por lo que hacen, no por lo que parecen. La lista de objetivos debería ser una pila FIFO.

ES6

He estado leyendo sobre las novedades de ES6 y aquí va un pequeño recopilatorio de algunas de ellas.

Classes

Para comenzar aquello de lo que tanto se hablaba cuando salió. Lo primero que hay que decir es que es solo maquillaje para hacer la vida mas fácil en algunos aspectos y escribir menos. Aunque parezca una clase, se seguirá comportando como una simple función.

Como ventaja, al utilizar la sintaxis de clase, puede que sea mas simple tratar con la herencia de prototipos de Javascript.

class Car {
  constructor(brand, model, year) {
    this.brand = brand;
    this.model = model;
    this.year = year;
  }

  printOut() {
    console.log(`${this.brand} ${this.model} - ${this.year}`);
  }
}

let myCar = new Car('Daewoo', 'Kalos', 2005);
console.log(myCar.printOut()); //Daewoo Kalos - 2005
typeof myCar; //object
typeof Car; //function

Las clases pueden ser anónimas, asignando su definición a una variable, después usaremos esta variable para crear una nueva instancia de la clase.

var Car = class {
  constructor(brand, model, year) {
    this.brand = brand;
    this.model = model;
    this.year = year;
  }

  printOut() {
    console.log(`${this.brand} ${this.model} - ${this.year}`);
  }
};

var myCar = new Car();

En ES6 hay herencia, y puede ser útil para acceder al prototipo cómodamente.

class Amphibious {
  constructor(type = 'river') {
    this.type = type;
  }

  crossRiver() {
    console.log('I am swimming');
  }
}

class Car extends Amphibious {
  constructor(type, brand, model, year) {
    super(type);
    this.brand = brand;
    this.model = model;
    this.year = year;
  }

  printOut() {
    console.log(`${this.brand} ${this.model} - ${this.year}`);
  }
}

var car = new Car('Alfa Romeo', 'Giulia', 1998);
console.log(car.printOut());
console.log(car.crossRiver());

const

Como su nombre sugiere, se trata de una constante, es decir, un valor que no puede cambiar a lo largo de la ejecución de nuestro programa una vez que ha sido definido, al contrario que ocurre con las variables.

A día de hoy esto es así al menos en Chrome y Firefox, sin embargo Safari las trata como simples variables. Son por lo tanto útiles como en cualquier lenguaje, para albergar valores inmutables.

const MAX_CHILD_AGE = 18;
//Si intento redefinirla, obtendré un error
const MAX_CHILD_AGE = 16;
//Uncaught TypeError: Identifier 'MAX_CHILD_AGE' has already been declared(…)

let

Esta novedad me gusta mucho, porque permite controlar el scope de nuestras variables de una forma precisa. Al declarar una variable con let lo que ocurre es que esa variable solo sera modificable o accesible en el scope en el que ha sido definida: bloque, declaración o expresión donde se usa.

Sin embargo con var se puede acceder a la variable en el scope exterior a donde la estemos usando. Con un ejemplo siempre es mas claro.

var color = "red";
console.log(color);
if (true) {
  var color = "blue";
  console.log(color);
}
console.log(color);
let shape = "square";
console.log(shape);
if (true) {
  let shape = "circle";
  console.log(shape);
}
console.log(shape);

Generators

Me parecen bastante divertidos. Son unas funciones especiales, que nos permiten ejecutarlas por partes y parar o hacer continuar la ejecución. Las reconoceremos porque tiene un asterisco junto a la palabra function y contienen el termino yield.

De alguna forma se trata de una factoría de iteradores cuyo estado es controlado por una función. Por lo tanto nos puede ayudar a crear funciones asíncronas.

Un objeto es un iterador cuando sabe como acceder a los elementos de una colección, mientras mantiene un registro de su posición actual dentro de esa secuencia. En JavaScript un iterador es un objeto que proporciona un método next() que devuelve el siguiente elemento en la secuencia. Este método devuelve un objeto con dos propiedades: done y value. Ver mas sobre ello en MDN.

 

//GENERATORS
var numberGenerator = function* numberGenerator() {
  var number = 0;
  yield number++;
  yield number++;
  yield number++;
  yield number++;
  yield number++;
  return;
}();
console.log(numberGenerator.next());
console.log(numberGenerator.next());
console.log(numberGenerator.next());
console.log(numberGenerator.next());
console.log(numberGenerator.next());
console.log(numberGenerator.next());
//{ value: 0, done: false }
//{ value: 1, done: false }
//{ value: 2, done: false }
//{ value: 3, done: false }
//{ value: 4, done: false }
//{ value: undefined, done: true }

next() puede recibir un parámetro, que sera considerado en la función como el resultado del ultimo yield.

Default function parameters

Puede parecer increíble, pero aun no existían. Estamos acostumbrados a verlos en otros lenguajes como PHP. Tan simple como:

function takeCare(takeIt = 'easy') {
  console.log(takeIt);
};
takeCare(); //easy

Template literals

Parece ser que tenemos una forma de decir adiós al infierno de las dobles comillas y las concatenaciones con el símbolo +.

En general, incluir información compleja es mas sencillo. Veamos algunos ejemplos.

//Concatenar con variables
var animal = 'cats';
var sentenceES5 = 'She said ' + animal + ' are independent';
var sentenceES6 = `She said ${animal} are independent`;
console.log(sentenceES5);
console.log(sentenceES6);

//Saltos de linea
var sentenceES5 = 'She said ' + animal + '\nbreak the line';
var sentenceES6 = `She said ${animal}
break the line`;
console.log(sentenceES5);
console.log(sentenceES6);

//Concatenar con operaciones
var sentenceES5 = 'She said ' + animal + ' break the line ' + (1 + 1) + ' times';
var sentenceES6 = `She said ${animal} break the line ${1 + 1} times`;
console.log(sentenceES5);
console.log(sentenceES6);

//Llamar a funciones
var sentenceES5 = animal.toUpperCase() + ' are evil';
var sentenceES6 = `${animal.toUpperCase()} are evil`;
console.log(sentenceES5);
console.log(sentenceES6);

Arrow functions

Lo primero que hay que decir es que las arrow functions vienen a resolver un problema de diseño de javascript: la palabra this en una función sin scope, se refiere al objeto window. Es decir que las arrow functions vinculan contextualmente this a la función, lo que es de esperar o lo que lógicamente un programador podría esperar, como ocurre por ejemplo en un objeto:

var car = {
  color: "red",
  wheels: ['RF', 'LF', 'RR', 'LR'],
  printWheels: function () {
    this.wheels.forEach(function (wheel) {
      console.log(wheel + ' in a ' + this.color + ' car');
    });
  },
};
car.printWheels();
//this.color es undefined. Si anadimos:
this.color = "blue"
car.printWheels()
//RF in a blue car
//LF in a blue car
//RR in a blue car
//LR in a blue car

Si, es una de esas extravagancias de javascript, como tantas otras, que los programadores han resulto de forma imaginativa en versiones anteriores, por ejemplo creando una variable self a la que se asigna this. De forma que el scope en el momento de definir el objeto esté disponible al ejecutarlo.

Veamos ahora como this se refiere al contexto en el que se encuentra, usando arrow functions.

var car = {
  color: "red",
  wheels: ['RF', 'LF', 'RR', 'LR'],
  printWheels() {
    this.wheels.forEach((wheel) => {
      console.log(wheel + ' in a ' + this.color + ' car');
    });
  }
};
car.printWheels();
//RF in a red car
//LF in a red car
//RR in a red car
//LR in a red car

Spread Operator

Este operador, usado antes de un array, sirve para extenderlo, por ejemplo para incluir los elementos de un array dentro de otro sin aumentar las dimensiones, o para usar los elementos de un array como argumentos de una función. Siempre es mejor ver el código:

//crea un array unidimensional
var animals = ['owl', 'camel', 'pinguin', 'otter', 'beaver', 'ox'];
var flowers = ['Water lily', 'Hibiscus', 'Bird of paradise'];
var things = ['car', ...animals, ...flowers, 'computer'];
console.log(things);
//pasar argumentos de funciones
var numbers = [2, 6, 9, 10];
console.log(Math.min(...numbers));
//otro ejemplo
var sumArgs = (a, b, c) => {
  return a + b + c
};
console.log(sumArgs(...numbers));

Destructuring assignment

Nos ayuda a asignar los elementos de un array a variables rápidamente.

//ES5
var myArray = ['pear','apple','strawberry'];
console.log(myArray[0]);

//usando asignación por destructuring:
var [pera, manzana, fresa] = myArray;
console.log(pera);
console.log(manzana);
console.log(fresa);

//otros ejemplos
var[primero, ...elResto] = myArray;
var[primero,,tercero] = myArray;

//Con objetos también funciona:
var post = {
  author : 'Pepe',
  title : 'Ecmascript 6'
};
var {author, title} = post;
console.log(author);
console.log(title);

En este caso hay que tener en cuenta que en lugar de “[” hemos usado “{“.

Ademas como nombre de las variables no podemos poner cualquier cosa, sino el nombre de la propiedad que queremos recuperar, a no ser que lo especifiquemos :

var {author: customName, title} = post;

Aquí, customName es el nombre que queremos darle, y author es el nombre de la propiedad del objeto post que queremos recuperar.

Y hasta aquí he llegado en este post, por supuesto hay muchísimo mas, espero tratar otros asuntos de ES6 en próximamente.

La S de SOLID

Para poder decir que uno escribe código limpio tiene que comprender y saber aplicar lo que esconde el acrónimo S.O.L.I.D. El programador Robert C. Martin lo acuñó con el objeto de recordar estas cinco normas que todo clean coder debe divulgar y utilizar.

Estos principios se aplican a programación orientada a objetos. El objetivo principal es que nuestros programas sean mas fácilmente mantenibles y comprensibles así como permitir que crezcan y evolucionen de forma limpia e inteligente.

Los cinco principios son :

  1. Single responsibility
  2. Open-closed
  3. Liskov substitution
  4. Interface segregation
  5. Dependency inversion

Si queréis escribir buen código, aplicar estos principios. ¿Perdéis la calma luchando contra vuestro código? ¿Vuestros programas están llenos de wtf’s? ¿Vuestro código es hostil? Tal vez necesitáis S.O.L.I.D inyectado en vena.

En este post escribo sobre el primer principio.

Robert C. Martin definió SRP inspirándose en el concepto de cohesión explicado por Tom DeMarco. Cuando he leído sobre SRP la parte mas difícil de comprender ha sido precisamente “responsabilidad”.

¿Qué es una responsabilidad?

Una razón para cambiar

 

¿Y qué es una razón para cambiar?: Una de las explicaciones que mas me gusta es la que atiende al sujeto de esa responsabilidad, es decir: ¿a quien responde esa responsabilidad?

Una clase solo debería responder a una necesidad

 

Si una clase posee varias responsabilidades, estará también articulando varias relaciones de responsabilidad con varios actores.

No podemos entender responsabilidad como algo concreto a nivel técnico, ni asimilarlo al trabajo de una función o de toda una clase. La responsabilidad es algo mas amplio, es una explicación semántica sobre lo que hace la clase, no una definición de las tareas que ejecuta.

Es un error pensar que este principio acarrea clases de una sola función. Una sola responsabilidad puede ser definida por diversas funciones, o por una sola, seria estúpido establecer un numero. Aquí de lo que se trata es de que nuestra clase responda a una sola exigencia, a una solo necesidad. Si mi clase solo responde a una necesidad, entonces solo hay un motivo por que el que pueda ser modificada: el cambio de la necesidad misma.

Imaginemos un programa que necesita utilizar la API de un servicio web. Podemos pensar en construir una clase que realice una llamada al servicio, trate la respuesta y actualice una base de datos con las informaciones recibidas.

class WebServiceConnector
{
    public function makeCall()
    {
    }

    public function parseResponse()
    {
    }

    public function connectDatabase()
    {
    }

    public function updateInfo()
    {
    }
}

Analizando ligeramente esta clase, vemos que en efecto hay muchas razones para cambiar, es decir, que es muy probable que tengamos que modificar esta clase por diferentes motivos.

Imaginemos que usamos una base de datos mysql pero que cuando nuestro sistema crece hasta los trescientos millones de registros, decidimos usar una base de datos hypertable. Deberemos realizar cambios relativos a bases de datos en una clase en la que por ejemplo, encontramos llamadas a servicios web: dos responsabilidades que definitivamente no tienen nada en común.

Si el servicio web que utilizamos cambia su interfaz, haremos cambios en la función que realiza las llamadas, mientras que nuestra base de datos, nuestro parseo de datos y nuestra modificación en base de datos, no necesitan ser modificados.

Esta clase responde a la necesidad de comunicarse con un servicio web, de analizar los documentos XML recibidos, de gestionar la comunicación con la base de datos y también de actualizar informaciones en una base de datos. Es una clase Frankenstein que pretende contentar a muchos actores: documentos XML, servicios web soap o bases de datos mysql.

Todas estas responsabilidades, agrupadas en una sola clase están acopladas. Es decir, tienen un nivel de acoplamiento máximo cuando en realidad son objetivamente distintas.

Es necesario separarlas:

class SoapClient
{

}

class Parser
{

}

class DatabaseDriver
{

}

class ApiConnector
{

}

Aquí no pretendo ser exhaustivo, solo reflejar la necesidad de SRP conceptual o filosóficamente. Por supuesto, nos debemos preguntar si estas clases que hemos creado tras una primera reflexión, tienen una sola responsabilidad, es decir, si tienen un solo motivo para cambiar, y si no, analizarlas y modificarlas convenientemente.

Este principio es la base de todo lo demás. Si el programador no pone empeño y horas en realizar un buen diseño, separando las responsabilidades y evitando el acoplamiento, muchas otras buenas practicas y principios se verán muy comprometidos.

Dependency Injection

“As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.”

 

A: ¿Detrás de cuantas cosas de programación esta Fowler? y en general los que hicieron el Agile Manifesto?

D: No sé, pero es el padre de muchas cosas.

A: Menuda cabeza (por fin estoy leyendo su articulo), pero habla de tres tipos de DI, dos usan librerías externas así que no le veo mucho interés. A ver la tercera.

D: Yo quiero hacer algo parecido a DI. Tener algo que instancie al comienzo de la ejecución, y decirle get(NombreDeLaInterface::class) y que me la dé. De esa manera no meto todas esas instanciaciones en 1000 sitios. Al fin y al cabo es como tener un factory que me dé las dependencias. No será una librería de inyección de dependencias, pero así tengo todo ese tipo de instanciaciones en un solo sitio. Y como configuré los environments en CI (production, development y testing), pues que dependiendo del environment que se esté ejecutando, poder cambiar.

A: Parece lo que Fowler llama Injector . Define una interfaz para el.

D: Me ayudó mucho a entenderlo usando la librería que se usa en Android para ello “Dagger”, vas creando “Componentes”, que tienen métodos con la anotación @Provides y lo que retorne, luego en tiempo de compilación se resuelven todas las dependencias. En las clases de cliente, añades un @Inject Repository userRepository y ya el inyector hace su trabajo. Si he notado que al principio con pocas cositas, es fácil de llevar, pero cuando se hace mas grande, ya tienes que ir dividiendo esos componentes, para quizás encapsular los conceptos del dominio. UserComponent, ProductComponent etc…

A: me recuerda a ng2 eso que dices, diría que es la misma filosofía.

D: Dagger 1, fue desarrollado por Sqare, y Dagger2 le hizo fork Google, quizás hayan usado un poco esa filosofía en los laboratorios oscuros de google…

A: pues para no variar no entiendo el ejemplo de Fowler…

D: jajaja

A: supongo que es Java verbosity… “Then, as usual, I need some configuration code to wire up the implementations. For simplicity’s sake I’ll do it in code.” No se lo que es el container.

D: mas abajo lo usa en registerComponents() pero es eso, un contenedor. Parece que internamente, en el container registra un nombre y una clase.

A: si, pero no me dice nada eso. Es decir, que lo veo mágico, no se como funciona ni veo el ejemplo.

D: bueno imagino que ahí está esa magia. Es un simple ejemplo.

A: pues no me vale ! xD

D: Si se pone a sacar el container, saldría una librería ahí xD “Martindency Fowler Injection”

A: luego hay gente para la que DI es simplemente pasar en el constructor las dependencias

D: yo diferenciaría entre DI (Dependency Inversion) y DI (Dependency Injection) donde Dependency Inversion es el patrón, y Dependency Injection la herramienta para llevar a cabo las inyecciones.

A: si, pero debe haber confusión entre la gente, porque veo por ejemplo un articulo aquí donde se dice que que dependency injection es pasar por parámetro… asi que no se, un lio.

D: al menos yo personalmente intento separar ambos. Creo que es igual que MVC, para algunos es una arquitectura para todo y para otros es solo una arquitectura de la capa de presentación. Creo que el software es un cúmulo de ideas con doble sentido.

A: veo que en general la gente usa el termino “dependency injection” refiriéndose a “constructor injection” o “setter injection” cosa que no tiene nada de especial. Yo cuando pienso en dependency injection pienso en “interface injection”, cosa que no entiendo.

D: yo el setter injection no lo he usado nunca

UserRepository repo = new SQLUserRepository();
repo.setMapper(new UserMapper());

vs

UserRepository repo = new SQLUserRepository(new UserMapper));

se consigue lo mismo, pero y con interface ? a que te refieres con interfaces? uhum al InterfaceInjection como explica el?

A: si

A: osea lo que hace es crear una interfaz que define por ejemplo un Finder, luego las implementaciones concretas, ok pero porque la clase que usa la implementacion debe implementar tb la interfaz ? no se, ya te digo que no lo entiendo. He encontrado esto: What is dependency injection? a ver si me ayuda.

D: creo que es un ejemplo de como hacer un inyector mas bien no?, al que tu le pasas un algo que necesita inyección (que implemente el InjectFinder)

A: “Dependency Injection is where components are given their dependencies through their constructors, methods, or directly into fields.”
vale, entonces es solo eso…

D: el Interface Injection que expone creo que es solo una forma de hacerlo

A: vale. No se, pensaba que era algo mas sofisticado, yo hago DI desde el principio! antes de saber como se llamaba.

D: seguramente el container, le pides una clase, que en el ejemplo que pone es MovieLister que tiene para inyectar un MovieFinder y un FinderFileName. El container imagino que instancia el MovieLister, y le hará el “injectFinder(loquesea) y injectFileName(loquesea) de manera que para cuando tu tienes el movielister, ya tiene todo inyectado

A: lo que pasa es lo que te decía, que Fowler siempre complica un poco todo mas de lo que es…. es su forma de pensar, es un tío complejo. Lo que no veo ahora es la ventaja de hacer eso frente a usar el constructor o el setter o directamente la propiedad. (Tener mas de una implementacion ?)

D: Ahí ya supongo que es cuestión de necesidad.

A: Injection Container parece que es eso, un contenedor que inyecta las dependencias allí donde se necesite no?

D: le veo la lógica en el caso de que quieras obtener un MovieLister:

public void testIface() {
    configureContainer();
    MovieLister lister =     
       (MovieLister)container.lookup("MovieLister");
    Movie[] movies = lister.moviesDirectedBy("Sergio Leone");
    assertEquals(
       "Once Upon a Time in the West", 
       movies[0].getTitle()
    );
}

Imagina que hace:

MovieLister lister = (MovieLister)  
container.lookup("IMDBMovieLister");

ese container puede usar la misma instancia del movieLister que tenías, pero le inyecta el MovieFinder de IMDB de modo que ahora el movieLister ha cambiado dependencias, sin tener que crear otra instancia, con inyección por constructor, esto no hubieras podido hacerlo es el caso de uso que se me ha ocurrido para este tipo.

A: es decir la ventaja aquí es usar una misma instancia de movieLister. Inyectando diferentes “finders” en una clase aparte llamada “container” . Con constructor no funciona, pero yo puedo hacer un setter cada vez del finder, sin cambiar tampoco la instancia de MovieLister.

D: no sé si en realidad Fowler lo ha hecho por esto, pero podría resolver este caso de uso.

A: la única utilidad que le veo es en aplicaciones enormes donde merezca la pena tener el container.

D: date cuenta, que cuando usas la herramienta como Dependency Injection, vas a depender de un “Container” siempre. Porque te quitas un boilerplate en código cliente y porque es bastante cómodo, y esto no afectaría a tu core si no lo haces “intrusivo”

A: entonces lo que aplica internamente el container es dependency injection de forma automatizada digamos, es un patrón de diseño ? o es un framework ?

D: ahí está la diferencia que te dije antes. El Container es la herramienta, y la inversión de dependencia, el caso de uso, el patrón.

A: el patrón es ultra simple, el framework no.

D: tu puedes desatornillar un tornillo con un destornillador, o con una taladradora a la que le has puesto el cabezal para desatornillar. Ahora bien, desatornillar el tornillo de la tapa del ordenador, no es lo mismo que desatornillar el tornillo de un camión, pero en general, es Desatornillar, sabes que para un lado aprietas y para otro aflojas.

A: Interesante metáfora. El ejemplo de container que pone aquí me queda mas claro. Es simplemente una clase que asocia una instancia a sus dependencias y la entrega al cliente.

D: crees que debería hacerme poeta? siempre suspendía Lengua Castellana y Literatura, y ahora encuentro pequeños resquicios en mis metáforas. xDDD

A: jajaja pues oye, es un campo a explorar, igual encuentras placer en ello.

D: pero lo que decías, es que en general es eso. Algo a lo que le dices “Dame esto”, y te lo dá. No es muy diferente a un Factory como ves.

A: “Last, but not the least, each time I want to get a mailer, I don’t need a new instance of it. So, the container can be changed to always return the same object:” si te fijas, también habla de eso, es también otra de las cosas que controla el container? Puedes evitar “singletons” que tiran de comprobar si existe una instancia con la variable static. Solo necesitarías (en un ejemplo básico) un singleton, el simple Container. A cambio de depender del container.. cosa que tampoco mola no ? pero supongo que no se puede tener todo.

D: Bueno, supongo que depende del lenguaje y la aplicación

A: Como siempre es un compromiso.

D: el container es eso, si le pides algo y no lo tiene, lo crea, por lo que el impacto de construirlo (si no es complejo o no necesita nada externo), es diminuto

A: bueno esta bien, los posts y esta conversación me han aclarado el tema, menos mal que te tengo aquí.

D: a mi me ha enseñado el inyector de android tras pegarme muchos golpes contra la pared. Tiene unas anotaciones, que se llaman @singleton pero en realidad hace que las dependencias no sean singleton, sino que solo habrá 1 en el graph de objetos. Sin embargo, si no lo tiene, te va a dar siempre una nueva pero esto, ya es algo que la herramienta te ofrece. El container, como te lo montes, da igual, el te va a dar las cosas, a tu código cliente le da igual, como se instancien!

A: respecto a los tests…. si haces tdd, nunca tendrás el container en los tests no ? a no ser que lo estés creando… digo que por ejemplo el test instanciara el mailer y el transport y quiza otro test probara el container.

D: pues a mi parecer ya depende si es un end to end, si vas a hacer uso del container pero en test unitarios, a no ser que sean tests del Container, no lo necesitarías

A: si, eso pienso yo tb

D: es decir, yo el container no lo veo en el core o domain

A: es una utilidad no ? como lo situarías ? capa de infraestructura ?

D: Pues no sabría donde situarlo porque lo veo mas externo a la aplicación en sí.

A: entonces, desde el punto de vista de hexagonal seria capa de infraestructura yo creo… metiendo ddd no se donde se quedaría, me anoto la duda.

D: basándome en el rosco de Clean Architecture, quizás lo pondría en la verde. Y no estaría seguro, es algo que te resuelve las dependencias.

A: es como una metaclase que organiza otras clases.

A: como adaptador ?

D: una librería que instancia cosas xD

A: pero si lo pones en la capa exterior, tu core depende de algo externo (prohibido). Tendrás que aplicar DI al container.

D: estaría fuera del application, basándome en el dibujito

A: vale, yo a eso lo llamo infraestructura. El pb es resolver la dependencia del core sobre una clase externa.

D: a que te refieres?, algún ejemplo?

A: tu core depende del container para obtener las clases que sea con sus “injecciones” y eso no es posible. Como dice U Bob, los módulos solo pueden depender sobre módulos mas internos, no al contrario.

D: yo en mis apps con Clean (que no brillan, las cosas como son), no he necesitado usar el framework en el core nunca. Desde el punto de vista de clean architecture, iría en aquello que invoca los use cases.

A: sea… por ejemplo… en un controlador web

D: tu cuando obtienes el “Interactor” del CA (Clean Architecture), ya tiene sus dependencias resueltas. No deberías usar el inyector mas. Otra cosa es cuando se plantea el problema de tener que elegir entre diferentes implementaciones en runtime.

A: en ese caso pensaba antes, al hacerte la pregunta.

D: es algo que inevitablemente no he logrado averiguar, pero me ha pasado. Pero sabes que pienso?, que si por ejemplo guardar algo en un sitio u otro, es una regla de negocio, eso lo convierte en un caso de uso, no sé si me explico.

A: si, que si encuentras ese problema, tal vez tienes un code smell, un problema de diseño. Y debes sacar esa decisión.

D: si los usuarios con nombre Pepe van a guardarse en un sitio, y los que se llaman Paco en otro, esto es una regla de negocio y vas a tener que tener algún tipo de orquestador que decida donde van las cosas. Lo cual puede ser un caso de uso por ejemplo. Suena feo, porque es como si tu lógica de negocio tuviera que saber sobre la infraestructura

A: si, obligas al core a preocuparse por un detalle, cosa que no es factible, pero si tu core usa un container, entonces no hay ese problema no ? Pero el container debería formar parte del core, o bien invertir la dependencia para que el core no dependa en una capa de la cebolla superior, es decir el core solo se preocupa de llamar un método guardaX() y nada sabe de la implementacion, lo cual esta bien. El container facilita eso. Yo creo que desde el punto de vista de hexagonal tendrías un puerto de salida con su adaptador… puede que el adaptador se ocupara de recuperar la implementacion por ejemplo. Tu core solo dice guarda lo que sea! y va al output port con un objeto command. Y el adaptador puede por ejemplo examinar ese objeto command y obtener la implementacion que lo guarda.

D: hombre, tu adapter, puede tener algún mecanismo de decisión. Puedes tener un OrquestorUserRepository que implementa la interface de UserRepository el cual para crearse necesita un UserRepositoryFactory y en el save(user);

if (user.name === "Paco"){
    userRepositoryFactory->getSQLRepository()->save(user))
} else if (user.name === "Manolo") {
    userRepositoryFactory->getCloudRepository()->save(user));
}

es una forma de hacerlo. Es como cuando tienes que obtener de un repo y cachear, está claro que eso es algo que se puede controlar en esa capa.

A: en clean code, el libro, Uncle Bob dice lo mismo sobre DI…. y habla de containers muy someramente (cita spring para java) y como toooodo el mundo, hace link del articulo de Fowler. Fowler is God.

D: Fowler tio, fowler. Joder es que ese tío es un crack en serio. Creo que es uno de los grandes de la historia del IT.

A: sin duda. Le he dado otra vuelta a su articulo y lo veo mas claro.

Value Objects

En DDD (domain driven design) los value objects son objetos simples que cuantifican, miden o describen algo que pertenece a nuestro dominio. Representan un valor y es su valor lo que importa y lo que los diferencia de otros value objects.

Hay dos aspectos a tener en cuenta para entenderlo mejor:

  1. Como dice Ward Cunningham, es una medida o una descripción de algo.
  2. Su identidad se define a través de su estado y no usando un campo identificador único. Así que, como dice Martin Fowler, dos value objects son iguales si sus atributos contienen los mismos valores. Deben ser inmutables.

Algunos ejemplos de value objects pueden ser:

  • Una fecha
  • Dinero
  • Un nombre
  • Una dirección
  • Una cantidad

Un ejemplo concreto

Por ejemplo, en una receta de cocina, podríamos tener un value object que representara la cantidad “250 gramos”. En realidad esa instancia concreta de la cantidad “250 gramos” no importa demasiado en si misma, si no es a través de su valor. En tanto que objeto inmutable, sea esta u otra instancia, lo importante es el valor que tiene. Será igual a otra con el valor “250 gramos”.

Si necesitáramos representar el valor “1 kilogramo”, aunque también se trata de una cantidad, en lugar de modificar la instancia previa, crearemos una nueva.

Una ventaja obvia de conceptualizar estas descripciones bajo la forma de value objects, es que todo el comportamiento relativo a ellos puede ser implementado dentro de esas clases, por ejemplo una validación. De esta forma tenemos otra ventaja: luchamos contra el anti-pattern de los modelos de dominio anémicos.

Show me the code

Me gustaría traducir en código el ejemplo de la cantidad para los ingredientes de una receta. Por ejemplo “250 gramos” podría ser resuelto con una clase que guarde el tipo de medida (gramos, kilos, mililitros…) y otra que une este concepto a una cantidad (1, 250, 3.5).

Ambas son value objects, en este caso miden la cantidad necesaria de un ingrediente en una receta.

class Measure
{

    private $name;

    public function __construct($name)
    {
        $this->setName($name);
    }

    private function setName($name)
    {
        //implements some validation
        $this->name = $name;
    }

    public function name()
    {
        return $this->name;
    }
}
 

class Quantity
{

    private $amount;
    private $measure;

    public function __construct($amount, Measure $measure)
    {
        $this->setAmount($amount);
        $this->setMeasure($measure);
    }

    private function setAmount($amount)
    {
        $this->amount = floatval($amount);
    }

    private function setMeasure(Measure $measure)
    {
        $this->measure = $measure;
    }

    public function amount()
    {
        return $this->amount;
    }

    public function Measure()
    {
        return $this->measure;
    }
}

Arquitectura hexagonal

 Una de las razones por las que una arquitectura de software es necesaria es que los frameworks en los que habitualmente trabajamos como laravel o symfony promueven un estilo de código que no satisface las necesidades de las grandes aplicaciones.

Cuando trabajamos en un proyecto desde el inicio tenemos todo el control. Según avanza el proyecto se generan un montón de reglas no escritas que aplicamos habitualmente. El problema es que cuando la aplicación crece y tal vez nuevos programadores llegan o los que había se marchan, todas esas reglas no serán necesariamente aplicadas. El código será cada vez más un problema.

Se necesitan por lo tanto principios de organización. El más conocido es MVC.

Los gurús del software nos están siempre diciendo lo que está bien y lo que está mal. Finalmente solo tú como programador sabes lo que conviene a tu aplicación según tus medios y el contexto en general en el que te mueves. Cualquier decisión sobre arquitectura y prácticas de desarrollo en general debe ser tomada, bajo mi punto de vista, siempre tomando en cuenta tu contexto. Por ejemplo no tendrá mucho sentido aplicar DDD si nuestra aplicación es un CRUD con 4 controladores. Aunque por supuesto siempre podrás hacerlo, aunque solo sea por diversión.

MVC no es suficiente

Hay polémica sobre si MVC es arquitectura o no. Desde mi punto de vista no lo es. Lo veo como una guía de diseño como lo puede ser DDD, aunque mucho más simple y no apta para resolver problemas complejos. Por supuesto su aplicación genera una topología que produce modelos, vistas y controladores. En el fondo la discusión sobre si es arquitectura o es un principio de diseño es bastante estéril y no tiene importancia. Es habitual que los programadores nos pongamos muy pesados con los detalles sin importancia. El problema principal que yo veo es que la M de MVC tiene normalmente demasiado trabajo, y es responsable de demasiadas cosas. A menudo algunas de sus responsabilidades se trasladan al controlador creando poco a poco clases demasiado grandes y con demasiadas responsabilidades, lo que lleva al título del siguiente punto:

Difícil hacer tests

MVC viene de los frameworks. Y mucho software está íntimamente ligado al framework en el que fue creado. Este podría ser un proceso de trabajo habitual:

  • Elegir un framework
  • Elegir una librería de persistencia
  • Elegir una librería frontend
  • Instalar el skeleton de la aplicación
  • Borrar el código de demo
  • Auto-generar las entidades
  • Auto-generar los controladores CRUD

Aunque todo esto es muy importante, no es el núcleo de nuestro software. Todas estas decisiones, tomadas a priori, harán más lento y complicado hacer tests ya que estaremos obligados a instanciar todos esos elementos para poder probar una clase. Qué duda cabe que si no vas a hacer tests esto no representará un problema.

En mi experiencia personal estoy en un momento en el que tras rechazar los frameworks, quiero volver a experimentar con ellos, ya que tienen indudables ventajas, por ejemplo llevar a cabo miles de tareas tediosas que no queremos programar por nosotros mismos. Eso está bien, pero es necesario saber establecer los límites de nuestra aplicación y dejar claro su alcance y donde termina el framework.

Los frameworks encapsulan muchos detalles para nosotros, como transformar una request en un tipo de dato como XML o JSON. También la comunicación con la base de datos o el uso del protocolo HTTP. Sin embargo hay que encontrar la forma de trabajar limpiamente con ellos.

Abstracción

Un aspecto muy importante del desarrollo de aplicaciones limpias es la abstracción. Otro problema de los frameworks es que no son capaces de generar abstracción por nosotros. Por ejemplo para hacer una consulta y extraer unos datos a través de la capa de persistencia, el framework nos propondrá elementos muy concretos relativos a bases de datos relacionales, métodos como buildQuery o where ademas de ver los nombres de campos y tablas de bases de datos en el código. No es nada abstracto, son más bien implementaciones muy concretas.

Código acoplado

Otro problema con los frameworks es que tu código está muy acoplado con el llamado delivery mechanism. Me cuesta traducir esa expresión al castellano, tal vez “mecanismo de entrega”. En los frameworks veremos que habitualmente ese mecanismo de entrega es de un solo tipo: La web. Normalmente el controlador expresará lenguaje relacionado con la web y la base de datos. ¿Pero qué ocurre si queremos ejecutar código desde una línea de comandos? Será imposible. El código está muy ligado a un controlador web.

Revelar intenciones

Otro problema es que el código MVC normalmente no muestra la intención del código. En inglés habréis oído hablar de “reveals intentions. Leyéndolo no sabemos de qué trata, qué hace, cuál es la necesidad o su significado. Si observas su árbol de directorios, solo ves carpetas como models, views, controllers que en efecto no revelan nada sobre el comportamiento de la aplicación.

Todo esto puede estar muy bien cuando haces un desarrollo de app muy rápido. El código que obtienes usando la documentación de un framework normalmente es útil para hacer CRUDs.

¿Como arreglar esto?

Arquitectura hexagonal

A menudo instalamos el framework y sentimos que nuestra aplicación ya está funcionando. Creo que en realidad aun no tienes nada aparte de un montón de código que no tiene nada que ver con tu dominio.

Tenemos que saber diferenciar entre lo que constituye nuestra aplicación y todo lo demás. A nuestra aplicación nos referimos con el nombre core:

El core es lo que permite solucionar los problemas concretos a los usuarios de nuestra aplicación en un dominio concreto. También forma parte del core las formas de interacción con el mismo, definidas en los casos de uso.

 

A todo lo demás nos referimos con el nombre detalles (de la aplicación). Es aconsejable que nuestra aplicación no sepa nada del exterior y que sea únicamente a través de interfaces bien definidas donde se produce la comunicación. Es decir que nuestro software es permeable solo en la medida que queremos. En contraste con una aplicación MVC común incrustada en un framework, que está completamente infestada por los detalles de implementación de la infraestructura.

Llamamos infraestructura a todo aquello que es exterior al core. Estos son algunos ejemplos:

  • Comunicar con la web
  • Comunicar con la línea de comandos
  • Relación con el sistema de archivos
  • Comunicación con la base de datos
  • Envío de emails

Un diseño demasiado pobre y compacto arruinará la capacidad de mantener, probar y hacer evolucionar correctamente los sistemas complejos. Para aliviar eso tenemos arquitecturas de capas que permiten separar el código, así como establecer reglas para comunicarse entre ellas, establecer los límites o boundaries en inglés, además de ayudar a colocar nuestro código donde corresponda en lugar de depender de esas “reglas no escritas”.

Hablando de sistemas de capas, Uncle Bob dice algo muy importante que debe destacarse (traslado la idea, no traduzco su frase):

Las dependencias sólo pueden ser de fuera hacia adentro, es decir, un modulo solo puede depender de algo que está en una capa inferior y nunca al contrario. Por lo tanto nuestro core nunca debe saber nada de las capas exteriores.

 

Ports

Para cruzar los límites enviamos mensajes en nuestro código. Estos mensajes pueden ser funciones y argumentos. Los límites de la aplicación están en los inputs ports. Un mensaje viene del exterior y si quieres que tu app se comunique con el exterior hay que establecer un input port que lo permita. Quiero experimentar con esta idea y escribir un post mas adelante sobre lo que puede ser un port usando un framework web.

Adapters

Por ejemplo el caso típico en la web sería un puerto que utiliza el protocolo de comunicación HTTP. Siempre que hay un puerto, hay algún tipo de traducción o transformación que es realizada por un adapter, de tal manera que una web request pueda ser procesada. Un adapter sería por lo tanto un grupo de clases que pueden transformar una petición externa, por ejemplo en la web, en algo que pueda ser tratado por la capa de dominio.

“Ports and adapters” es un alias para arquitectura hexagonal.

 

Los puertos permiten que exista la comunicación y los adapters traducen los mensajes del exterior para que puedan ser tratados en el interior. Por ejemplo una request web será convertida en un objeto command. Este objeto revela sus intenciones gracias a su nombre y ya no tiene nada que ver con el mecanismo de entrega (la web), es por lo tanto self-contained y pierde toda relación con el mundo exterior. Este objeto command es únicamente un mensaje y no realiza ninguna acción. A continuación un handler aceptará el command y hará lo necesario para que la acción se lleve a cabo.

Si la acción implica una persistencia, se usará de la misma forma un puerto de persistencia que puede actuar sobre cualquier tipo destino, por ejemplo una base de datos. La particularidad aquí es la siguiente:

Normalmente en un diseño clásico nuestro dominio (core) tendrá una clase que depende de un repositorio situado en la capa de infraestructura. Por ejemplo:

  • Core
  • usersRepository (Class)
  • Infrastructure
  • queryBuilder
  • entityManager

El usersRepository depende del queryBuilder y del entityManager. Como hemos visto anteriormente nuestro core no puede depender de clases situadas fuera del dominio (en capas externas). Para solucionar este dilema tenemos que usar inversión de dependencias:

  • Core
  • usersRepository (Interface) Nuestro dominio define la interfaz, esta no sabe nada de los detalles de implementación de la persistencia.
  • Application layer
  • usersRepositoryHandler
  • Infrastructure
  • usersRepository (Implementa la interfaz)
  • Podemos añadir cualquier implementación que respete la interfaz para conectar con otro tipo de persistencias.

En nuestro dominio definiremos una interfaz de repositorio en la capa de aplicación y tendremos un handler que usará el repositorio, dependerá de la interfaz, no de la implementación concreta. En la capa de infraestructura tendremos un repositorio que implementa la interfaz para crear un tipo de persistencia concreta.

¿Para qué sirve todo esto?

Separation of concerns. Tendremos varias capas en las que repartir nuestro código:

  • Core
  • Domain layer
  • Application layer
  • Infrastructure

Estamos seguros de poner nuestro código en la capa correcta. Es un principio de organización que ayuda en aplicaciones de cierta complejidad.

Tenemos casos de usos con comandos y handlers que realizan la acción que nuestra aplicación debe llevar a cabo. Esto aísla nuestro core del exterior.

La arquitectura hexagonal soporta muy bien diversos métodos de diseño como BDD, DDD, TDD o CQRS. También podría aplicarse en microservices, obteniendo muchos pequeños hexágonos.

Esto permite escribir tu aplicación como si el mundo exterior no existiera, y a continuación conectarla creando ports y adapters. Esto es muy interesante para hacer tests.

Conclusión

Creo firmemente en las ventajas de posponer siempre que sea posible todas las decisiones relativas a la capa de infraestructura, partiendo de la necesidad de crear un dominio sólido y testeable, estableciendo los puertos y los adaptadores que mas tarde nos permitirán conectar nuestra aplicación al mundo exterior.

Al principio podremos mockear esos boundaries y trabajar cómodamente por ejemplo usando TDD.

Por supuesto, el 90% de este post son ideas traducidas y adaptadas por mi durante el estudio y presentadas aquí para quien pueda sacar provecho de ello. No me doy ningún crédito por ello.

Arquitectura hexagonal es un concepto desarrollado por Alistair Cockburn. Como no, hace falta leer y releer los consejos de Robert C. Martin (Uncle Bob) para entender este ecosistema y en general las buenas practicas de programación orientada a objetos.

Domain Driven Design

Domain Driven Design book by Eric Evans

 

No sabia que cuando en la oficina he dicho “Al final de lo que se trata es de que el cliente sea feliz y de que nosotros los programadores también lo seamos” lo que estoy haciendo es promover Domain Driven Design.

Microservices, Self contained systems, Domain driven design y otros en el fondo lo que pretenden es que todos los actores de un dominio particular extremen su rendimiento y felicidad. La empresa que necesita una solución de software de calidad obtendrá un beneficio a medio plazo. Los programadores diseñarán paso a paso una aplicación en la que pueden confiar y los managers dejarán de arrancarse el pelo.

Divide y vencerás

Cuando observo un poco mas de cerca estas metodologías tengo la impresión de que todas se parecen demasiado, aun con sus grandes diferencias. Es como si todas ellas emanaran de la misma fuente: La necesidad de separar las responsabilidades a todos los niveles.

El principio SR (Single responsability) impregna todo buen comienzo en los cuentos de software. Al dedicar tiempo a definir:

  • el modelo de tu dominio
  • los objetos que lo habitan
  • sus necesidades
  • los datos que circulan y su forma de transmitirse y relacionarse
  • los servicios y la infraestructura que existe en el mundo representado e inmaterial del software

lo que haces es una vez más dividir.

Cuando la aplicaciones comenzaron a crecer exponencialmente y los pioneros de la profesión notaban que perdían el control y se les ponían de corbata, se hicieron necesarias normas que ayudaran a organizar sistemas complejos.

Hablemos

Al parecer había un abismo entre los equipos que desarrollaban el software y aquellos que llevan a cabo la “principal” actividad empresarial. Vamos, lo que todo el mundo identificaría como la fuente de beneficios. ¿Y el software entonces, qué es?. Lo que promueve el DDD en los equipos de trabajo es llegar a desarrollar un idioma conjunto, usado tanto por los expertos de dominio como por los desarrolladores. Esto quiere decir muchas cosas, por ejemplo tu variable $hash2 que solo tu sabes lo que es se convertirá en $bookings. Como ves la variable $bookings es significativa tanto para los expertos de dominio, como para los desarrolladores de software. Para conseguir eso muchas horas de común conversación habrán tenido lugar en la sala de reuniones. Cuando todo el mundo comparte los mismos conceptos, la misma semántica de dominio: hemos alcanzado el nirvana del DDD y nuestro software debe reflejarlo.

De qué trata

De modelar tu software siguiendo una hermenéutica de dominio. Lo cual quiere decir que una vez conocemos el mundo que debe representar nuestro software, resolverlo usando DDD, nos provee un marco en el que trabajar con garantías de que ese mundo no se convertirá en algo incomprensible, monolítico e imposible de verificar: Spaguetti code.

Crear sistemas complejos basados en software de alta calidad. DDD no es arquitectura. Descubrir poco a poco el dominio, interactuar con los expertos, generar poco a poco el Ubiquitous language común a todos, es aportar valor y conocimiento al negocio.

Show me the money!

 

Colofón

Como introducción de un novato en DDD, no deberías fiarte en absoluto de lo que digo sino leer el famoso libro de Eric Evans. Los sistemas complejos necesitan formas de construirse, de organizarse e integrarse, así como filosofías de trabajo y formas de entender la profesión. Veo un poco de todo eso en el DDD.

DDD provee un análisis sintáctico para la arquitectura de software.

 

Desde un punto de vista más técnico, para aplicar DDD a tu aplicación, además de mejorar la comunicación con el cliente y ser experto del dominio, hay que saber utilizar Domain Services, Value Objects, Modules, Aggregates, Entities, Domain Events, Factories o Repositories.

Por qué escribir un blog

A: […] Estaba mirando él email de devexperto, es verdad que en fin, si uno no se expone tampoco pasa nada, depende de lo que uno busque o necesite, para mi no va unido a esta profesión. Yo a lo máximo que podría llegar es a tener un blog y no se, tal vez dar una charla ? Por qué no.

D: Si, yo por ejemplo a mas no aspiro pero me parece curiosa esta frase “Si a día de hoy eres feliz en la situación en la que te encuentras, tu trabajo te gusta, te encaja en tu estilo de vida, y no te aporta ninguna gratificación compartir conocimiento, me parece perfectamente válido no hacer nada.” A lo de ser feliz en el día de hoy, con el trabajo que hago, con mi estilo de vida, desde luego no me pasa. Ni estoy feliz con lo que hago últimamente, ni estoy feliz con la situación. Ni estoy feliz con mi estilo de vida. Y sin embargo si me aporta gratificación aportar algo (aunque haga mas de 1 año que no lo hago).

Quizás, el aportar eso, mediante el blog o github, pueda aportarme esa gratificación que el trabajo no me da, aunque mi meta no sea dar charlas ni nada, pero no sé, quizás el aportar esas ideas, cosas, curiosidades a otros, para retornar a la comunidad todo lo que aprendo de ella, me haga ser un pelín mas feliz, o al menos sentirme cómodo en la comunidad.

 

A: Eso es cierto, aportar cosas satisface. Y es un esfuerzo positivo digamos, a la vez q aprendes tu, lo compartes. Pero no se, el enfoque de devexperto lo veo guay para los programadores, por que tenemos las herramientas, pero vamos, que también a veces se pone demasiado en la programación… Igual solo somos currelas y punto no se. Un soldador no se plantea nada de esto. Tengo la impresión de que en nuestra profesión siempre hay algo más, el extra que cambia todo.

D: Si, te refieres a… no sé, dar ese algo mas de sí no?

A: Si, a que por ejemplo, se presupone la pasión.

Para mucha gente programar es como ir a alicatar, un trabajo y nada mas.

 

D: Si pero ahí está el tema, creo que no estás en ese trabajo adecuado. Claramente, el trabaja en Plex, remoto, para el su vida así es feliz.

A: El esta en la Meca, en las antípodas de mi trabajo.

D: Para ti, que te obligan a escribir mierda, y no te dejan pensar ni opinar sobre lo que ves, pues es normal que no estés en el mismo pensamiento.

A: Así es, estamos enjaulados en sistemas viejos de trabajar, estos tíos son afortunados.

Tenemos en nuestras manos el poder de cambiar si queremos.

 

D: Y bueno, quizás ellos están ahí por eso. Porque han dado ese poquito mas. Quizás cuando quitemos el polvo a los blogs, y empecemos a darles cera, pues quizás no nos lleve a mejor. Pero quizás si nos haga pensar “Bueno, el trabajo ha sido una mierda, pero con el nuevo post he ayudado a 20 tíos”

A: Si, o con el pet project, o con los repositorios…. yo este fin de semana he leído código ng2 de tíos que no saben que me están ayudando, esta guay.