Programar no es desarrollar

Me encanta programar. Probablemente sea la parte de mi trabajo que más disfruto. Y creo que soy capaz de valorar la importancia de programar bien y el impacto que ello tiene en el buen desarrollo de un proyecto de software.

Recuerdo cuando, hace unos 20 años, estaba empezando la carrera de Ingeniería Informática y pensaba que programar era algo sin importancia. Algo de lo que podían ocuparse «esos de FP», porque nosotros, los auténticos ingenieros, nos encargaríamos de la parte de análisis, diseño, gestión de proyecto y demás cosas importantes. Total, rellenar los huecos de nuestros fantásticos diseños no era muy distinto de niños coloreando sus cuadernos de dibujo, y para eso no hacía falta gente con nuestras enormes capacidades. Huelga decir que, además de ser un planteamiento arrogante que sóla la juventud y la necedad pueden sostener, estaba completamente equivocado.

Por suerte los tiempos han cambiado (al menos en parte), y ese enfoque en el que los programadores son los últimos monos, ya no está tan en boga. Es verdad que sigue habiendo reductos en los cuales la jerarquía basada en jefes de proyectos, analistas funcionales, analistas programadores, programadores, etc., se mantiene, pero me atrevería a decir que es una visión que está en declive y se está dejando de ver la programación como una tarea mecánica destinada a la gente con menos experiencia para empezar a valorarla más.

Claro que, como siempre que cambian las tornas, corremos el riesgo de irnos al otro extremo. Al de entender la programación como la parte fundamental del desarrollo de software. Y me temo que tampoco es así. Hace tiempo que dejé de creer en la separación rígida entre roles en el mundo del desarrollo de software, pero pese a ello, y sin pretender en ningún momento sonar arrogante, considero importante distinguir entre programar y desarrollar software. Entre programadores y desarrolladores de software.

Pero, ¿qué se supone que debe hacer un programador? Como mínimo, ser capaz de escribir la secuencia de pasos para resolver un problema en un lenguaje que sea capaz de interpretar una máquina. Hay gente muy buena en eso. Humanos con los que puedes hablar en lenguaje natural y se encargan de convertirlo a C, Python, o el lenguaje de turno. Y no sólo eso. Lo hacen con un código elegante, eficiente, fácil de mantener, acorde a las buenas prácticas de turno y que cumple todas las expectativas de los crafters más exigentes.

Vamos a ver un ejemplo.

Programando Bien™

Supongamos que tenemos que añadir una pequeña funcionalidad a un producto que ya existe: editar un tweet. Como somos afortunados, resulta que Twitter está desarrollado siguiendo todas las buenas prácticas de turno y su código es fácil de modificar.

OJO: esta simplificación es mentira y no tiene sentido para la escala de Twitter, pero es sólo un ejemplo.

Por supuesto, estamos usando DDD y arquitecturas poligonales con cebolla, así que nuestro código empieza por un servicio de aplicación/caso de uso tal que así:

public class TweetEditor {
  // Inyectados por constructor
  private readonly IUnitOfWork uow;
  private readonly ITweetRepository repository;

  public void EditTweet(Guid tweetId, string newContent) {
    using (var tx = uow.Start()) {
      var tweet = repository.GetById(tweetId);
      tweet.UpdateContent(newContent);
      tx.CommitChanges();
    }
  }
}

Vamos bien. Tenemos un servicio que recibe sus dependencias por constructor, utiliza una entidad de dominio, Tweet, un repositorio, y el patrón UnitOfWork. Todo muy de libro. En nuestra entidad implementamos la (simple) lógica de negocio:

public class Tweet {

  // ... todo lo que existiera antes en la entidad Tweet

  public void UpdateContent(string newContent) {
    Check.Require(!string.IsNullOrWhiteSpace(newContent));

    this.content = newContent;
  }
}

Perfecto. Lógica encapsulada en la entidad y garantizando que se mantienen los invariantes adecuados.

Desde un punto de vista de programación esta implementación es estupenda (asumiendo siempre que lo de las arquitecturas poligonales y el diseño OO sea lo tuyo). Tenemos código claro, con nombres bien escogidos, responsabilidades aisladas, estamos escribiendo código idiomático al lenguaje y arquitectura elegidos, aplicamos patrones de diseño ampliamente conocidos y contrastados…

Todo lo que nos falta

Si la programación que hemos realizado en el ejemplo anterior es tan buena (o al menos no es horrible), ¿podemos estar tranquilos? La verdad es que no. Puede que el código cumpla todo eso que hemos mencionado antes, pero la implementación que hemos hecho de la funcionalidad presenta un montón de problemas que no están relacionados, al menos directamente, con el código que hemos escrito.

Pensemos un poco en lo que implica poder editar el contenido de un tweet.

¿Qué va a ocurrir con las respuestas a ese tweet? Es decir, ¿qué ocurre si escribo un tweet diciendo «El Real Madrid es el mejor», alguien me contesta, «Qué razón tienes», y luego lo edito y pongo «El Real Madrid es el peor». ¿Se deben mantener las respuestas? ¿Se debe notificar a quien ha respondido para que pueda editar su respuesta? ¿Hace falta que los usuarios puedan saber si un tweet se editó y en qué momento?

Algo similar ocurre con los retweets. ¿Al cambiar el contenido del tweet se deshacen los retweets anteriores? ¿Se notifica a los usuarios para que elijan qué hacer con su retweet? ¿Y con los tweets que citan al original? Con los likes pasa algo parecido. Y con los momentos que enlazan al tweet.

Además, twitter es una aplicación distribuida con clientes parcialmente conectados. ¿En las aplicaciones móviles vamos a actualizar los tweets que están en el timeline para que vean el nuevo contenido? ¿Los dejamos desactualizados a menos que refresquen? Y eso en los clientes oficiales, ¿que hacemos con los demás clientes? ¿Exponemos un nuevo API para que puedan detectar los cambios?

Claro que también tenemos que pensar en los usuarios. ¿Van a entender la funcionalidad? ¿De qué manera se la vamos a exponer? ¿La vamos a desplegar a todos a la vez? ¿Probamos primero con algún grupo de usuarios? Y ya que hablamos de desplegar, ¿cómo haremos el paso a producción? ¿Hace falta modificar los datos existentes, por ejemplo para añadir una fecha de actualización? Si es así, ¿qué reglas vamos a seguir para actualizarlos?

Y todavía no hemos dicho nada de pruebas, porque ahora que hemos empezado a ver todas las implicaciones que tiene esto de editar un tweet, habrá que preparar una buena batería de pruebas (idealmente automatizada, pero al menos manual) para comprobar que todos estos casos que estamos encontrando funcionan como deben.

Cuando empezamos a analizar el problema nos damos cuenta de que el código que hemos escrito antes, por muy bonito, sólido y limpio que sea, no vale de mucho.

Desarrollar software

Creo que con este ejemplo podemos empezar a intuir a qué me refiero con que programar no es desarrollar.

En cuanto saltamos del divertido mundo de las katas y los puzzles al Mundo Real™, la parte de programación «pura» empieza a perder peso. Programar es una parte necesaria para desarrollar software, pero no es suficiente y tampoco es la más importante.

Seamos realistas, en las aplicaciones de línea de negocio que desarrollamos la mayoría de nosotros, gran parte de las funcionalidades no son nada complicadas de implementar y se basan en guardar algo en una base de datos, pintarlo en la pantalla adecuada, y hacer un par de cálculos por el camino.

Lo complicado suele venir de cómo interactúan esas funcionalidades con todas las demás que ya existen en el sistema, con cómo vamos a cambiar la forma de trabajar de los usuarios actuales, con cómo vamos a adaptar los datos ya existentes para que sean compatibles con las nuevas funcionalidades o de qué forma podrá venderse la funcionalidad de forma atractiva y eficiente.

En definitiva, la parte complicada es pensar, analizar y diseñar la solución desde el punto de vista de procesos y operativa, no de código.

Visto así, resulta tentador volver a pensar en jerarquías rígidas en las que unos señores muy listos hacen la labor de análisis funcional, transmiten ese análisis a arquitectos y diseñadores, los cuales pasan unos diagramas UML a programadores y listo. A pintar y colorear. Sin embargo no creo que eso funcione realmente.

Es cierto que es imposible que alguien sea bueno en todo, por lo que pretender que una persona sea a la vez experto en negocio, en experiencia de usuario, en usabilidad, en bases de datos, en despliegues en la nube y en otras mil cosas no tiene sentido. Pero hay alternativas.

Siempre se pueden construir equipos en los que quienes dominan estas áreas colaboren estrechamente para el desarrollo de cada funcionalidad, pero incluso si no existe esa disponibilidad de expertos, lo que sí esperaría de un desarrollador de software es que sea consciente de que es necesario preocuparse por esas cosas. Las hará mejor o peor, podrá necesitar más o menos ayuda externa para las áreas en las que más pueda cojear, pero al menos lo intentará.

En mi caso, trabajo en un equipo pequeño. Eso hace que a la hora de buscar compañeros le demos mucha importancia a esa capacidad de resolver problemas y tener una visión más amplia que escribir un código bonito. Sencillamente porque no nos podemos permitir tener una separación de roles en las que alguien analiza un problema, se lo pasa a otra persona para que diseñe el UX, y luego dan unas pantallas a un programador para que las implemente. Por supuesto le damos mucha importancia a la calidad del código, pero si no va acompañada de una preocupación por todo lo demás, no nos sirve de nada.

Por suerte, al igual que la mayoría del código que escribimos no tiene gran complejidad, muchas veces todas estas cosas que rodean al código tampoco son tan sumamente complejas vistas por separado como para necesitar grandísimos expertos en la materia. A lo mejor como desarrollador no eres experto, por ejemplo, en el negocio para el que estás desarrollando, o no tienes grandes dotes para el diseño de interacción, pero con que hagas pequeños avances en estas áreas, con que te preocupes un poco, el resultado mejorará enormemente.

Igual que ser capaz de escribir no te hace escritor, ser capaz de programar no te hace desarrollador. Hay mucho más que eso.

5 comentarios en “Programar no es desarrollar

  1. Has escrito el post que muchas veces he querido escribir y nunca he sabido. Sólo espero que quienes lo lean puedan entender (sin haberlo vivido antes) su profundo significado.

  2. Rafael Cano dijo:

    Jeje, a lo que llamas desarrollar es lo que yo llamo, toca pensar.

    Un saludo.

  3. La palabra es diseñar, no desarrollar. Y el diseñador es precisamente la persona encargada de ver todas las implicaciones e interacciones del sistema y orientarlas hacia el objetivo de la aplicación.

    En mi caso concreto, el campo del videojuego, el diseñador de juegos es el encargado de crear un diseño que tenga en cuenta todos los aspectos del juego. Y ciertamente, no tiene por qué ser programador (aunque es muy útil serlo) porque su rol está orientado a la experiencia del usuario y no al comportamiento interno de la aplicación.

    Concretamente el ejemplo que pones sobre editar tweets es un claro ejemplo de diseño de aplicación. No necesitas ser programador para entender que si alguien edita su tweet lo que han dicho los demás puede no tener sentido. Tienes que ser una persona que entienda lo que desean los usuarios incluso más allá de lo que los usuarios puedan creer que desean.

  4. Muy relacionado con esto viene el tema de «¿qué es un buen programador?», la famosas 10x de productividad.

    Creo que la afirmación tendría que ser «un buen desarrollador puede ser 10 veces (o lo que sea) más productivo que uno mediocre». Realmente con una visión más global, más allá del código, una persona puede hacer realmente la diferencia.

  5. Iván Gabriel Sosa dijo:

    «La parte complicada (y sumamente interesante agregaría) es pensar, analizar y diseñar la solución desde el punto de vista de procesos y operativa.»
    Arriba leí un comentario que la palabra es diseñar, nosotros lo llamamos analizar. Sin un buen análisis no hay software robusto, que contemple todos los casos, sea lo que se necesita y resuelva el problema. Siempre manteniendo la máxima sencillez y claridad en los procesos y sus iteraciones.
    Por mi parte, soy Analista Programador, y cuando surge un nuevo requerimiento o sistema, el análisis es lo primero en nuestro equipo. Hay que tomarse el tiempo para hacerlo, aunque dure varias semanas o uno/dos meses.
    Generalmente no lo hago solo, sino con el equipo: otro analista, el programador, el implementador. Se ven muchas cosas que uno solo no siempre ve, por más experiencia que tenga.
    He visto sistema e implementaciones fallar de forma terrible por no contar con un buen análisis.
    Saludos y muy buena publicación.

Comentarios cerrados.