miércoles, mayo 23, 2018

Abstracciones prematuras

Cuando empecé a programar, cuando aprendía un nuevo patrón de diseño no tardaba mucho en encontrar en donde aplicarlo. Mis proyectos rápidamente tenían varias clases que representaban cada abstracción del patrón que quería aplicar. Lo mismo pasaba con arquitecturas y formas de organizar mis proyectos. Hubo un tiempo donde creaba tres capas al iniciar mi proyecto (presentación, reglas de negocio y acceso a datos), hubo otra época en que creaba una capa de servicios al iniciar el proyecto y otra de repositorios; en otro tiempo creaba interfaces para casi todas las clases con la idea de poder cambiar las implementaciones sin afectar el resto del proyecto.

Con el tiempo fui descubriendo que el tener muchas abstracciones tiene un precio. Aunque siempre digo que las clases son gratis y no debes tener miedo de crear una más. No pienso lo mismo cuando se trata de agregar una nueva capa de abstracción. Esas sí me van a costar si me lleno de clases o interfaces que no hacen otra cosa más que abstraer la implementación de algo que puede ser simplemente una clase concreta.

Ahora mi regla es: si solo hay una implementación entonces no se necesita una interfaz. Las implementaciones que solo se usan para los tests no cuentan, me refiero a implementaciones de código real. Si después descubrimos que habrá otra implementación, es entonces cuando se hace un refactoring del código para introducir la interfaz; pero no antes. Debemos resistir la tentación de la capitis y solo agregar abstracciones cuando sea necesario. Si encontramos una abstracción con una sola implementación concreta entonces se trata de una abstracción prematura.



Por ejemplo:

Supongamos que tenemos una lista de clientes y nos piden que la exportemos a un archivo CSV. Es posible que hagamos una clase CustomerExporter con el método Export; de momento con eso es suficiente.

Sabemos que quizás en un futuro nos pidan que también se pueda exportar a otro formato; pero de momento no es parte del alcance del proyecto y quizás nunca sea necesario otro formato. Si introducimos una interfaz ICustomerExporter y la única implementación CustomerCsvExporter tendremos complejidad innecesaria y una abstracción prematura.

Es hasta que tengamos el requerimiento o necesidad de poder exportar clientes en otro formato que debemos realizar el refactoring e introducir la abstracción para las dos o más implementaciones.


viernes, enero 05, 2018

Emprendiendo

En julio 2017 dejé de trabajar desde casa y empecé a ir a mi oficina. Antes de ese mes había estado trabajando desde casa por más de diez años y era algo que me gustaba, hasta presumía el no tener que salir de mi casa todos los días. Tomar la decisión de empezar a ir a una oficina (sin que nadie me lo estuviera pidiendo) no fue tan fácil.

Tenía tiempo que, además de mi trabajo de tiempo completo, tomaba proyectos de desarrollo por mi cuenta, como freelance. Fue en febrero que tuve un "padawan" y entre los dos trabajamos en los proyectos para los que me iban contratando. Cada uno de nosotros, trabajaba desde su casa, usábamos herramientas como  Skype y GoToMeeting para estar en constante comunicación y nos reuníamos cada semana en un café a platicar del estatus de los proyectos. Hacíamos una pequeña retrospectiva de la semana.

Después de meses trabajando así decidí empezar a tomar más proyectos por mi cuenta e iniciar mi propia empresa. Ya no como freelancer sino como una empresa de desarrollo. No íbamos a poder dos personas terminar todos los proyectos, por lo que sería necesario que el equipo creciera. Teníamos en mente a unos muchachos que estaban por egresar de la universidad. Los cuales necesitarían apoyo para iniciar su camino como profesionales. Esta fue una de las razones que nos convencimos de que era necesaria tener nuestra propia oficina.

Para mi, la decisión se miraba venir desde que quise tomar más trabajo por mi cuenta, sabía que eso implicaba salir de mi zona de confort literalmente, tendría que salir de mi casa, donde estaba a gusto todo el día, a tener que salir a trabajar a una oficina todos los días, por más horas de las de un turno.



Han sido meses de mucho aprendizaje. Hemos tenido varios cambios en la empresa: pasé de ser una persona física a ser una persona moral, ahora tenemos una nómina que pagar, empleados que llegan y otros que se van. He aprendido que el negocio del software no es lo mismo que el desarrollo de software y que si quieres vivir programando todo el día entonces no pongas una empresa por tu cuenta. La mayoría del tiempo se va en cosas del negocio y no necesariamente en lo que te gusta hacer, es por eso se necesita tener a un equipo.

Veo con optimismo el siguiente año de Evolución Apps.

martes, diciembre 26, 2017

Esa es una buena pregunta...

"Esa es una buena pregunta...". Esa frase la he escuchado varias veces, sobre todo en presentaciones cuando alguien de los asistentes pegunta y el presentador no sabe la respuesta. ¿Es eso lo que la hace una buena pregunta, que el presentador no conozca la respuesta? No creo, quizás si fuera importante la pregunta entonces la persona que presenta ya conociera la respuesta.

Las buenas preguntas nos ayudan a comprender
El desconocer la respuesta no hace, necesariamente, a una pregunta buena. Para mi una buena pregunta es la que ayuda a entender o explicar mejor algún tema. Si la pregunta no aporta información relevante al tema entonces no es buena, independientemente de que se conozca su respuesta.

A veces no tenemos respuesta para las buenas preguntas y nos hacen darnos cuenta de lo que no sabemos del tema. Saber lo que no sabemos es importante y por eso muchas de las preguntas para las que no tenemos una respuesta son buenas; pero no son buenas porque no tengamos la respuesta. Sino porque nos hace conocer más del tema, que hay otras cosas por descubrir.

Dejemos de usar la frase: "Esa es una buena pregunta..." si es solo porque no conocemos la respuesta porque eso promueve preguntas para escenarios muy específicos que no aportan mucho al tema en general. Puede haber una pregunta donde la respuesta parece obvia y aclara algo que quizás puede ser ambiguo, esa puede ser una buena pregunta; pero si andamos buscando preguntas que nadie sabría la respuesta, solo porque esas son las "buenas" podemos perdernos de comprender mejor el tema.

Las buenas preguntas son las que nos ayudan a comprender.

martes, diciembre 19, 2017

Actitud en Proyectos Legacy

Los proyectos legacy... esos proyectos que por lo general fueron iniciados por alguien más. Aunque a veces fueron iniciados por nosotros mismos. Por lo general son viejos y ya no programamos así o en ese lenguaje. Alguien tiene que darles mantenimiento, corregirlos...

Cuando nos toca empezar a trabajar en un proyecto de esos a veces puede ser frustrante el tratar de moverle, agregarle funcionalidad usando herramientas "anticuadas" o usando convenciones de nombrado diferentes a lo que quisiéramos. Siempre está ese pensamiento, indecisión de: "Y si lo reescribimos"  o "seguiremos usando lo mismo". Es pesado trabajar en proyectos así, sobre todo si fue hecho de una manera poco organizada o si cuenta con mucha deuda técnica. Es fácil caer en quejas y empezar a verlo todo mal.

La experiencia de haber visto otros proyectos similares, de conocer diferentes arquitecturas, haber leído artículos sobre cosas que la gente intenta te ayuda a darte una idea de que estaban pensando los programadores anteriores y conocer por qué agregaron esa interfaz que a lo mejor no tiene sentido si solo tiene una implementación. La experiencia también puede hacernos arrogantes y ver con mayor desprecio ese proyecto que usa otras practicas a las que recomendarías o ya usamos y aprendimos que no son lo mejor para ese tipo de proyecto.

Si no tienes experiencias puede ser también frustrante porque no es algo que tú conoces y por lo tanto no es algo que recomendarías. A veces cuando uno empieza quiere usar lo que conoce, la tecnología con la que jugó en proyectos de prueba, que generalmente es algo nuevo. El querer usar lo último y que nos toque trabajar en un proyecto con tecnología vieja puede frustrarnos y sentir que estamos estancados. Sin aprender cosas que nos van a ayudar en el futuro.



Cuando tienes que trabajar en proyectos legacy que inició alguien más, la buena actitud con la que revisas el problema es parte de las habilidades necesarias para mejorarlo. Debemos pensar que el equipo anterior tomó decisiones con la mejor intención, con la información que tenían en ese momento.

Es fácil juzgar una vez que ves que el resultado no fue el esperado y tienes que corregirlo. Pero entrar al problema con quejas en lugar de entender el porqué de la situación, es más desgastante y puede ser más costoso porque puede haber cosas rescatables en el proyecto que no veras, además corres el riesgo de cometer los mismos errores por no entenderlos. 

Evita esa frustración, piensa que se hizo lo que se creyó mejor y éntrale al proyecto con una buena actitud, buscando dar soluciones en lugar de quejas. El primer paso es darte cuenta que está en ti cambiar las cosas.

lunes, octubre 23, 2017

Limite de edad al buscar programador(a)

He notado que varias ofertas de empleo para programadores tienen un limite de edad, dicen algo como: "se solicita programador (o programadora) de 20 a 34 años" como si después de cierta edad se nos empezara a olvidar como programar. Por lo que he visto, entre más mayor sea el programador más experiencia de vida tiene y hay que explicarle menos el porqué de las cosas. Programar no es una actividad física que requiera de juventud.

La edad no define las ganas de trabajar. He conocido tanto a personas que siempre quieren echarle ganas al trabajo, como personas que siempre tienen flojera y nomas quieren estar jugando, de todas las edades. Si esto es cierto entonces ¿Por qué habrá esta restricción de edad en las ofertas de empleo?


He pensando que lo hacen para pagar menos, entre mayor es la persona generalmente tiene más compromisos y por lo tanto más gastos. Necesita más dinero y tiempo para sus compromisos fuera del trabajo. Un joven quizás no necesite tanto dinero y pueda quedarse hasta tarde porque le gusta lo que hace.

Hace tiempo en un episodio del dev3cast, Gabriel me preguntó que si yo contrataría a alguien mayor. Me tomó de sorpresa la pregunta y titubeé  al contestar. Me sentí mal por eso; pero así de pronto pensé que prefería contratar a alguien más joven que yo. La razón por la que no pensaba en contratar a alguien mayor es porque en ese tiempo hablamos de contratarlo no como empleado de la empresa donde trabajo, sino como ayudante para proyectos que hago por mi cuenta. Esos proyectos generalmente los hacia para clientes que me conocen y les "gusta" la forma en que trabajo. Pensaba que con un joven sería más fácil que hiciera las cosas a mi modo, sin tener que darle explicaciones del porqué.

Ahora que he iniciado una empresa de desarrollo de software por mi cuenta, me doy cuenta que esto no es necesariamente buena idea... porque aunque mis clientes lleguen a mí debido a que me conocen como  programador y piense (yo) que quieren el código como si fuera hecho por mi mismo (en realidad no, lo que quieren es una solución, el código no importa), el trabajo lo puede hacer cualquier persona sin importar la edad que tenga. Incluso, ahora que he tratado con varios jóvenes, el tener cierta edad puede ser una ventaja que no tienen los jóvenes, por la simple experiencia que te da la vida. Explicar los requerimientos y entender las prioridades para una persona mayor puede ser más fácil.

Al final lo importante es la actitud y la responsabilidad de cada persona, como empresa buscamos gente que saque el trabajo sin excusas, sin tener miedo a aprender, la edad no importa.

miércoles, junio 28, 2017

La tentación de la capitis

Cada que inicio un nuevo proyecto lo veo como una oportunidad para organizar diferente la estructura, la arquitectura, a fin de mejorar la forma en que se desarrolla el proyecto.

En esta etapa es fácil caer en la tentación de crear varias capas (capitis), con esto me refiero a la intención de separar toda la lógica o "responsabilidades" en proyectos separados. Intentar que el modelo del dominio del problema quede "puro", es decir, limpio de dependencias externas. Sin "manchas" con detalles de frameworks. Que alguien al abrir el proyecto vea nombres de carpetas que tengan que ver con el negocio, y no con detalles "sucios" como controllers, views, etc.

Es divertido definir la capa de negocio (o dominio) y estar programando abstracción, tras abstracción. Para después crear proyectos de implementaciones concretas usando cierta tecnología, librería o framework. Como no queremos tener implementaciones concretas, entonces definimos interfaces. Las cuales serán consumidas por la capa de presentación, claro que sin conocer las implementaciones concretas. Así será "fácil" cambiar (pensamos) de  implementación sin afectar la aplicación en un futuro.

Por poner un ejemplo (cuando se trabaja con .NET) se puede llegar a tener un proyecto "Negocio" que solo tiene clases que contienen el "core" del problema e interfaces para todo lo demás que necesita contener dependencias de terceros. Después se agrega un proyecto para cada tecnología que necesitas para realmente hacer las cosas, como "Negocio.EntityFramework" que es una implementación de nuestro proyecto usando EntityFramework para guardar los datos. Y nos sentimos bien porque en un futuro "podríamos" tener un proyecto "Negocio.FileSystem" que guarda los datos en disco directamente o una implementación que los guarde en MongoDB "Negocio.MongoDb". Esto por poner ejemplos. También podemos abstraer el Web como una presentación más y llegar a tener más interfaces e implementaciones concretas que podemos cambiar. Hay veces que se agrega una capa de "servicios" que lo único que haces es llamar a la capa de acceso a datos, incluso a veces es peor y llama a una capa de repositorios que entonces esa sí llama a la base da datos.

Lo que termina pasando, la mayoría de las veces que he visto esa arquitectura, es que solo se tiene una implementación para cada Interfaz. Es decir tantas abstracciones para nada. Solo es más código para ocultar la implementación concreta, al final esa abstracción contendrá fugas para así poder acceder a la funcionalidad que tiene la implementación concreta. A veces se usa el pretexto de que las pruebas serán más fáciles; pero la verdad es que en muchos de esos proyectos ni si quiera hay pruebas unitarias.

Darle mantenimiento a un proyecto así es más complejo de lo necesario, por varias razones:
  1. Es más difícil encontrar la implementación concreta de un método porque la mayoría del código tiene llamadas a interfaces, debes buscar en otro proyecto la implementación.
  2. La configuración necesaria es mayor, se necesita configurar todos los tipos en un contenedor de dependencias o usar el patrón de service locator (que tiene sus propias desventajas) para instanciar las clases concretas que implementan las interfaces del core.
  3. La cantidad de código escrito es mayor (sin ningún beneficio, si solo tienes una implementación), por lo tanto entenderlo es más complicado.
  4. Como la cantidad de código es mayor, hay mayor posibilidad de bugs. 
  5. Un cambio trivial puede significar realizar cambios a todas las capas, debido a las abstracciones con fugas.
Aún conociendo esas desventajas y haber tenido que mantener proyectos de este tipo, donde incluso he visto que se agregaran abstracciones para obtener la fecha y hora del sistema. Aun así cuándo estoy por iniciar un proyecto nuevo, tengo esa sensación de dejar "puro" el dominio y las implementaciones concretas declararlas en otro proyecto. Aún sabiendo que no vale la pena, como que se antoja dejarme llevar en ese viaje creando abstracción sobre abstracción.

A veces siento que he logrado separarlo en capas, con moderación, limitando mis abstracciones. Es decir sin llegar al extremo de tener puras interfaces en el dominio. Pero casi siempre tengo que recordar que "No voy a necesitar otra implementación", pensar en YAGNI y el principio KISS. Recordar que siempre puedo refactorizar si se llega a ocupar. el refactoring es fácil porque el código es poco.  

Siempre es más fácil agregar una capa después, que darte cuenta que no la ocupabas y tratar de quitarla. Limitemos nuestras abstracciones.

viernes, junio 02, 2017

QA no debe encontrar errores.


En equipos de desarrollo, además de las personas que programan, también hay personas que realizan las pruebas a los releases o entregas que realizan los programadores. Es el equipo de QA. Este equipo (como su nombre lo dice "Quality Assurance") se asegura de que el producto entregado por el equipo de desarrollo esté libre de errores o bugs.

Un "malentendido" que a veces veo en algunos equipos es: que creemos que las personas de QA están para probar nuestro código por nosotros. Que están ahí para revisar si el cambio que hicimos, lo hicimos bien. A veces nos da flojera y sentimos que no ocupamos correr el programa y revisar si lo que hicimos está bien. Solo cambiamos el código y lo enviamos a QA para que lo prueben ellos.

Es un "malentendido" porque QA no está para eso, QA no está para que nosotros los programadores hagamos cosas bien. Eso lo tenemos que hacer habiendo equipo de QA o no. Es responsabilidad de cada persona revisar que el trabajo que hizo se haya hecho bien, de manera profesional. Sin embargo, me ha tocado ver que llegan a ser ridículos algunos de los bugs que encuentra el equipo de QA. Cosas que si nosotros como programadores le hubiera dado una revisada lo hubiéramos visto. Nos debería de dar vergüenza que QA encuentre errores, no debería ser común. Evitemos esa actitud de que no nos importa cuantos bugs se encuentren.

Como programadores, debemos tener claro que la responsabilidad de que nuestro trabajo esté bien hecho no es responsabilidad del equipo de QA, es nuestra. El equipo de QA está ahí solo como una Safety-Net, una red de protección por si acaso fallamos, no es para que seamos flojos y entreguemos trabajo mediocre.

Robert C. Martin (aka Uncle Bob) habla un poco de eso en su presentación sobre profesionalismo. Les recomiendo que (si no la han visto) la miren.