Pensamiento orientado a objetos vs pensamiento por procedimientos

Todavía recuerdo la primera vez que entré en contacto con los conceptos de la programación orientada a objetos. Yo estaba navegando en msdn library (vs6) en una sección denominada libros y tropiezo con un libro llamado «Visual basic 6 business objects». Había sólo unos capítulos incluidos pero los encontré increíbles. Habia aprendido y llevaba escribiendo aplicaciones vb6 por un tiempo para entonces pero encontré el vocabulario extraño: «Objeto de negocio», «Encapsulamiento», «Polimorfismo» y así sucesivamente. Inmediatamente me enganchó. Entre más aprendía, más quería empezar a codificar en este modo nuevo y maravilloso. Pero cuando tuve que escribir el código, me pareció tan difícil empezar! La cosa es que la programación orientada a objetos requiere una nueva mentalidad y este cambio toma tiempo.

El problema

Creo que el problema surge porque casi cada desarrollador es expuesto primeramente a la programación por procedimientos y generalmente tarda mucho tiempo para ser expuesto a la programación orientada a objetos. También la enseñanza de la programación orientada a objetos es a menudo muy pobre. Estos 2 hechos combinados con un montón de tutoriales por ahí para aprender lenguajes orientados a objetos que no consisten mas que en ejercicios de programación por procedimientos impone el estilo por procedimientos mas firmemente en la mente de los programadores.

Así que ¿como se ve el código por procedimientos? Hay tantas maneras y formas que en lugar de un ejemplo compartiré algunos indicadores.

  1. Los objetos contienen o sólo datos o sólo métodos
  2. Los objetos muestran datos con el único propósito de ser utilizado por otra parte
  3. Casi la totalidad de la lógica esta en métodos estáticos

De pensamiento por procedimientos a orientado a objetos

Así, la programación por procedimientos se trata de los procedimientos y los datos que pasas a ellos. Empiezas a pensar cuáles son las variables, cómo se representan (estructuras de datos) y qué hacer con ellas mientras que un estilo objeto orientado a objetos te hace pensar en quién hace qué (responsabilidades) y quien trabaja con quien con el fin de completar una tarea (colaboración). El cómo (implementación) es relegado a una etapa posterior. En lugar de pensar sobre los datos y procedimientos, ahora tienes objetos que empaquetan datos y procedimientos para hacer las cosas.

Ahora viene la parte difícil, la mayoría de las veces debes exponer sólo los métodos, no datos (propiedades). Si estás familiarizado con un lenguaje orientado a objetos (como java o  C#) intenta escribir un programa sin el uso de propiedades. No expongas datos solo para que alguien mas los utilice. Pide ayuda no datos (encapsulamiento). Esto llevará naturalmente a objetos que tienen datos y los métodos para manipular esos datos. Esto es bueno. Así que en lugar de escribir mailer.send(mail) ahora vas a escribir mail.sendThrough(mailer). Y mailer puede tener algo que parece mailer.send(recipient,sender,subject,body). Este sutil cambio tiene un gran impacto en el código. Pruebalo y deja de escribir pascal en Java 😉

TDD: El contexto es el rey

¿Así que quieres empezar a hacer TDD eh? has leído todos los blogs sobre el tema, visto todos los videos en la web y ahora estás listo para comenzar. Abres tu editor de código de elección y comienzas un nuevo proyecto y un nuevo proyecto de prueba. Y te quedas mirando. Sabes lo que tienes que hacer: escribir una prueba, hacerla fracasar, escribir el código más simple para hacerla pasar, refactorizar el código para que se vea bien. Y volvemos a empezar. El punto es, que realmente no sabes qué probar. O cómo saber qué probar. ¿Todos hemos estado ahi con la cara en blanco y un solo pensamiento: por dónde empiezo?

El principal problema es la falta de experiencia. Realmente no puedo pensar en otra cosa. Supongo que no es un problema cuando se está haciendo TDD con alguien que ya tiene experiencia en esto, pero si este no es tu caso no te preocupes, sólo tienes que hacer una cosa: empezar.

Supongo que es diferente para todos pero quiero compartir algunas de mis propias prácticas personales sobre este asunto. Espero que esto te ayuda a empezar.

  1. Definir las acciones del sistema.
  2. Definir los objetos de negocio en base a cada caso de uso.
  3. Escribir la primera prueba para un objeto de negocio.
  4. Crear interfaces para cualquier dependencia no definida todavía.

Definir las acciones del sistema

Uno de los errores más comunes que he visto son la falta de alcance y contexto. Sé lo que voy a decir suena tonto pero realmente, realmente, necesitas sentarte a averiguar lo que el sistema va a hacer antes de escribir algo de código. He visto tantas personas fracasando en esto!! Mi técnica favorita para esto es usar diagramas de casos de uso UML. Para empezar realmente no me enfoco demasiado en los detalles, solo quiero tener una idea general del alcance del sistema y los usuarios involucrados. Un diagrama de casos de uso permite ver cómo los actores van a interactuar con el sistema y las acciones específicas que un rol/personaje puede hacer con él. Cuando se trabaja en un entorno ágil he encontrado que éstos casos de uso corresponden muy bien con historias de usuario e incluso con epics si utilizas scrum. Recuerda que esta es una vista de alto nivel del sistema. No te enredes demasiado con los detalles. Aún mejor, no pienses en los detalles para nada. Todavía no.

Definir los objetos de negocio en a por base del caso de uso

Una vez que has definido los casos de usos para el sistema, selecciona uno. Ahora puedes entrar en los detalles (mas o menos). Aquí yo suelo utilizar un diagrama de interacción UML para definir la forma en que los objetos cooperarán para lograr los objetivos del caso de uso. Resiste la tentación de comenzar a dibujar los detalles de implementación: ahora lo único que te importa son las cosas que solicitas hacer al objeto y lo que esperas recibir de él. En otras palabras las entradas y salidas de lo objetos. Recuerda que estamos hablando de objetos de negocio, a menos que es necesaria para el flujo principal, no pongas ningún objeto relacionado con la infraestructura, es decir objetos que encapsulan llamadas a base de datos, servicios web y otras cosas que no tienen lógica del negocio y que solo están destinados a ser utilizados por otros objetos.

Escribir la primera prueba para un objeto de negocio

Al fin podemos codificar! Primero seleccione el caso de uso en el que deseas enfocarte. Ya? Ahora crea un archivo para contener las pruebas relacionadas con uno de los objetos de negocios. He adoptado algunas practicas del movimiento BDD y generalmente agrego la palabra «specs» (de specifications) al nombre del archivo. Así que vamos a decir que tengo un objeto de negocio llamado Cuenta, el archivo de prueba sería nombrado CuentaSpecs. Y digamos que este objeto particular tiene un método llamado Retirar, entonces quizás crearia algunas pruebas llamadas DebeRestarLosFondosAlRetirar, DebeFallarElRetiroSiNoTieneFondosSuficientes y así sucesivamente. Nota que en todas mis pruebas comencé con la palabra «debería». Es otra practica adoptada de BDD. Me gusta porque es más fácil expresar cual es el comportamiento esperado. Al final hay que recordar que no estas escribiendo pruebas, estas diseñando código. Por lo menos la implementacion de los métodos en los objetos. Por cierto, no te preocupes si decides hacer las cosas de una manera diferente al diagrama de interacción, esto es parte del show también y sucede muy a menudo que una buena idea resulta para ser demasiado compleja en el momento de codificarla. No tengas miedo a probar varios enfoques.

Crear interfaces para cualquier dependencia no definida todavía

Si al mismo tiempo de codificar descubres una dependencia a un objeto aún no creado, define una interfaz. No te quiebres la cabeza tratando de crear un objeto para proporcionar el servicio que necesitas, esto probablemente sea implementado por otro objeto mas adelante. Ademas de que esta fuera del alcance de la prueba. Así que define la interfaz con los métodos que necesitas y usala. No te sientes mal si tienes interfaces con solo 1 o 2 métodos, está bien. También es un efecto secundario a TDD y uno bueno:) (busca en google el principio de segregación de interfaz). De todos modos ahora necesitas un objeto que implemente la interfaz para usarlo en tu prueba. Puedes escribir uno. O mejor aun puedes usar mocks. Te recomiendo irte por esta ultima opción. No deberías perder tiempo escribiendo objetos que están fuera del alcance de lo que estas probando. Realmente no agrega valor. Busca en la red alguno de los muchos frameworks de mocking disponibles para la plataforma que estas usando. Experimenta hasta que encuentres uno con el que te sientas cómodo.

Algunas últimas palabras (y advertencias)

El propósito de todo lo que he cubierto aquí es para ayudarte a empezar. Conforme vayas obteniendo experiencias puedes omitir algunos de los pasos descritos aquí. Tal vez empieces a crear pruebas que representan el caso de uso conjunto en lugar de utilizar un diagrama de secuencia (yo lo he hecho). Pero si estas iniciando, te recomiendo seguir el procedimiento que he descrito arriba. Esto te dará algo de valor para empezar practicar TDD: contexto. ¿Qué probar? ¿qué no probar? ¿dónde empezar? que todo depende del contexto. Una vez establecido, las respuestas a estas preguntas fluirán naturalmente. El resto del procedimiento ya lo aprendiste de los libros, podcasts y post como éste: verde, rojo, refactorizar. También tengo una advertencia: no trates de escribir todas las pruebas desde el principio. No pienses en repasar todos casos de uso tratando de identificar cada prueba de antemano. Esta es una mala idea. La razón es simple: están diseñando código no escribiendo pruebas. Las pruebas son sólo una herramienta de diseño, como pluma y papel. Y al diseñar el código, hay varias decisiones que se tienen que hacer cuando algo inesperado surge en el código. También algunas pruebas darán lugar a la creación de otras.

Así que ahí lo tienen. Como siempre los comentarios son bienvenidos. Si tienes algún tip, sugerencia o una alternativa, me encantaría leerlo!

Hackeando un sistema de seguridad intercom para abrir la puerta con un teléfono

Cómo comenzó…

La oficina que actualmente trabajo en el se encuentra en un edificio que tiene un sistema de interfon. Cuando cualquiera de nosotros quiere entrar, basta con pulsar un botón y esperar que alguien responda y presione un botón en el auricular para abrir la puerta.

El problema se presenta cuando no hay nadie dentro (o esta en el baño).

Así surgió la idea de crear un servicio para abrir la puerta con el teléfono. ¿Cómo lo hacemos?

El algoritmo es algo como esto:
1) averiguar cómo funciona el botón de auricular
2) crear un circuito para hackear la señal del auricular
3) Codificar un servicio para activar el circuito
4) Hacer una aplicación de teléfono para comunicarse con el servicio

Así que vamos!

Descubra cómo funciona el auricular

Afortunadamente, en el trabajo contamos con gente muy hábil. Así que le pedí uno de ellos, Javier, echarle un vistazo al aparato. Resulta que la puerta funciona con un dispositivo magnético. El botón interrumpe el poder que mantiene el imán energizado. Lo hace tocando 2 pequeñas placas. No podía ser más sencillo.

Crear un circuito para hackear la señal

Usando un protoboard, Javier monto un circuito que consistió en circuit1un relé y un arduino (junto con un ethernet shield). La idea era conectar algunos cables en las placas, y usar el relé para cerrar el circuito. Para activar el relé, tendríamos que enviar que una instrucción al Arduino que estaria conectado al módem. Así que todo lo que tenemos que hacer es conectarnos a la red inalámbrica y enviar un comando a la dirección de ip de Arduino.

Codificar un servicio para activar el circuito

Ya que no tengo ninguna experiencia significativa codificando en un Arduino (aunque había codificado algo para un microcontrolador rabbit antes) me base en uno de los demos para un servidor web. Después de algunos ajustes y pruebas, termine con algo como:

#include <SPI.h>
#include <Ethernet.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0x60, 0xA5, 0xEA, 0x0E, 0x07, 0x10
};
IPAddress ip(200, 200, 200, 200);

EthernetServer server(80);

void setup() {

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  pinMode(7,OUTPUT);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}


void loop() {
 
 // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    
// an http request ends with a blank line
    boolean currentLineIsBlank = true;
    String currentLine = "";
    String command = "";
    
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        currentLine = currentLine + c;
        
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        
        if (c == '\n' && currentLineIsBlank && command == "some command") {

          digitalWrite(7, HIGH);  
          delay(1000);              
          digitalWrite(7, LOW);    
          //delay(1000);  
          
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");            
          client.println(command);
          client.println("</html>");
          command = "";
          break;
        }
        
        // you're starting a new line 
        if (c == '\n') {                                 
          currentLineIsBlank = true;
          Serial.println("current line = " + currentLine);
          currentLine = "";
        } 
       // you've gotten a character on the current line 
       else if (c != '\r') {                          
          currentLineIsBlank = false;
        } 

       //get the command
       else if (c == '\r' and currentLine.startsWith("GET")){ 
          int start = currentLine.indexOf('/')+1;
          int endAt = currentLine.indexOf(' ',start);
          command = currentLine.substring(start, endAt);         
        }
      }
    }

    // give the web browser time to receive the data
    delay(1);

    // close the connection:
    client.stop();
    Serial.println("client disconnected");
    Ethernet.maintain();
  }
}

La idea era proporcionar una API web que respondiera la petición a una URL concreta. A continuación extraemos la última parte de la url solicitada y utilizamos esto como comando para activar el relé y por lo tanto, abrir la puerta. Cualquier persona con la dirección ip y la URL correcta puede activar el relé, siempre y cuando sea la misma subred que el Arduino.

Código de una aplicación de teléfono para comunicarse con el servicio

Por lo tanto, Josue (otro compañero de trabajo) sugirió que puesto que había creado la web también podría crear una aplicación de teléfono para consumirla. Ya que la mayoría de las personas de la oficina tienen un teléfono android, pensé que sería una buena oportunidad para probar la plataforma. Tengo cero conocimiento del modelo de programación Android, asi que Josue sugirió que le echara un vistazo a Xamarin. Resulta ser bastante sencilla. Todavía tengo que aprender más de la plataforma…

Aquí está el código:

[Activity(Label = "Jarvis", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        private string url = "http://200.200.200.200/";

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            Button button = FindViewById<Button>(Resource.Id.MyButton);
            TextView text = FindViewById<TextView>(Resource.Id.textView1);
            
            button.Click += async(sender,e) =>
            {
                try
                {
                    await send(jarvisCommands.openDoor);
                    text.Text += "Get in! \n\r";
                }
                catch (Exception ex)
                {
                    text.Text += ex.Message + "\n\r" + Resources.GetString(Resource.String.Error) + "\n\r";
                }

            };
        }

        private async Task send(jarvisCommands command)
        {
                HttpWebRequest request = (HttpWebRequest) HttpWebRequest.Create(new Uri(url + command.ToString()));
                request.ContentType = "application/text";
                request.Method = "GET";
                await request.GetResponseAsync();
         
        }

        enum jarvisCommands { openDoor}

Cosas aprendidas:
1) la necesidad es la madre de la inventiva
2) puedes crear cosas interesantes cuando estás rodeado de gente interesante
3) si sabes Java, C++, C# o cualquier otro idioma entre llaves, ya eres capaz de escribir algo para el Arduino
4) conceptualmente el codigo en la plataforma Android es sólo una implementación de un bus de mensajes

Creo que esto es todo. Hasta el próximo post! (Voy a escribir a menudo, en serio)

Matriz de arquitectura de aplicaciones

La matriz de arquitectura de aplicaciones es una herramienta que se me ocurrió para explicar a un amigo la relación entre los patrones de diseño, las tecnologías y la arquitectura de un proyecto en el que participe por un breve tiempo. Permite a cualquier desarrollador que tenga cierta experiencia, obtener una idea general de la manera en la que esta estructurada una aplicación.Esto resulta especialmente útil en una época en que los sistemas distribuidos son cada vez mas la regla que la excepción y donde el soporte para múltiples plataformas es un requisito en mas y mas proyectos.

Consiste en 3 columnas, Capa, Tecnología y Patrones de diseño.

Supongamos por ejemplo que estamos participando en un proyecto que sigue la metodología DDD (Domain Driven Design). Nuestra matriz probablemente se vería algo como:

CAPA TECNOLOGÍA PATRONES
Presentación ASP.Net MVC MVC
Aplicación ASP.Net Web API Application Services
Dominio Portable Class Library Aggregate, Entity, Value Object, Repository, Domain Services
Infraestructura WCF, MS SQL 2008, Entity Framework

o quitando la capa de aplicación:

CAPA TECNOLOGÍA PATRONES
Presentación ASP.Net MVC MVC
Dominio Portable Class Library Aggregate, Entity, Value Object, Repository, Domain Services
Infraestructura WCF, MS SQL 2008, Entity Framework

Y allí lo tienen. Fácil ¿no? Solo me resta aclarar que la columna Capa, se refiere a la separación lógica (layer en ingles) y no física (tier en ingles) de una aplicación. Esto quiere decir que todas las capas bien podrían estar en una aplicación winforms.

Tarea: Crea una matriz para algún proyecto en el que hayas trabajado recientemente.

¿Creen que me falto algún aspecto significativo de la arquitectura de una aplicación? ¿Como usarías esta matriz? ¿Que cambios le harías?

Evolucodigo

En el inicio…

Tenía como 14 años cuando empecé a programar. Empece con archivos .bat en ms dos. Mas adelante mi padre me consiguió una copia de visual studio 6 y un amigo me presto un libro para aprender a programar en visual basic 6. Estaba emocionado. Era otro mundo. Pase las vacaciones ese verano en frente de una computadora y me encantó. Y ya entrados en materia descubri access y aprendí un poco de sql. Mas adelante aprendí foxpro 2.6  y como ya tenia una copia de visual foxpro 6, empecé a programar en vfp6 también.

Primer encuentro

Solia leer mucho en ese tiempo. Hasta la fecha. Un día encontré un articulo en MSDN llamado algo asi como vb6 business objects. Cuando empecé a leerlo aparecieron muchas dudas en mi mente: ‘objetos’? ‘Herencia’? ‘Eventos’ me sonaba familiar, pero que rayos era  ‘polimorfismo’? .
Afortunadamente, Rockford Lhotka (el autor) había agregado una introducción a la programacion orientada a objetos. Eso fue suficiente para entender cual era el próximo paso.

La búsqueda

Des afortunadamente no había mucha información sobre el tema en aquel entonces (o al menos yo no tenía acceso a ella), así que solo me quedaba entrar en la universidad para aprender mas. Pero no fue así. Si me hablaron de encapsulamiento, herencia, polimorfismo y todo el mumbo jumbo de términos. Pero nunca aprendí a pensar de una manera orientada a objetos. Sin embargo, la escuela tenía una conexión a Internet decente y así me dí a la tarea de buscar todo lo que pudiera acerca del tema. Me encontré con uml y me pareció interesante…
Y también xml, html (¿que pasa con tanto ML?).
Aun cuando tome un curso en c++ (que era mas como c) y java (del tipo forms over data) todavía me sentía mas cómodo en vb6. Incluso trate de practicar programación orientada a objetos en vb6 pero la falta de soporte para la herencia me dificulto hacer casi cualquier ejercicio encontrado en la red.

Un rayo de esperanza

Alrededor del séptimo semestre tuve la oportunidad de entrar a trabajar en una pequeña empresa de desarrollo de software. Estaba tan emocionado! Al fin! Un lugar para aprender todo lo que había buscado todo este tiempo!  Y si que aprendí! C#, sql server y el .net framework. Y también tenía la oportunidad de trabajar en proyectos reales. Pero aun sentía que me faltaba algo. Me tomo un par de años darme cuenta: estaba programando foxpro en el .net framework. Aun seguía pensando orientado a funciones. Aun cuando estaba usando objetos, no eran mas que contenedores de datos que pasábamos de una función a otra. Así que traté de ver las cosas de otra perspectiva. Esta vez realmente trate de producir código orientado a objetos. Investigue y trate de practicar TDD, DDD, BDD (ahora la moda es DD?) Y poco a poco empecé a lograrlo. Empece a hacer la transición hacia una mentalidad orientada a objetos. Todavía me falta mucho pero sigo avanzando.

Todo está en la mente

Ya que he trabajado en diferentes lugares, desde empresas de desarrollo hasta empresas transnacionales, me he encontrado con todo tipo de código. Así me di cuenta que hay un montón de gente que está en la misma situación que yo hace un par de años. Tienen herramientas mas novedosas pero siguen haciendo lo mismo. Desde entonces me he preguntado como ayudar a estos programadores a iniciar la transición hacia un tren de pensamiento mas orientado a objetos. Este blog es un intento. Y no soy el único. Hay un mundo de información: libros, artículos, cursos, que compartiré aquí. Son cosas que me han funcionado y espero que a ti también. Así que no te vayas, la diversión está por comenzar 😉