En Nextail durante una epoca me tocó hacer bastantes onboardings de gente para Data Science. Por lo general es gente a la que le falta mucho conocimiento de lo que en nuestro mundillo están consideradas buenas practicas de programación.
Este documento es un documento adaptado del original que usé internamente, que nunca pasó de ser un borrador; y extendido un poco, por ser el contexto ya diferente.
El objetivo es tener una guía para que una persona Junior sepa en que cosas puede mejorar. Que tenga un mapa. Este mapa está basado en mi experiencia y opinión por lo que es totalmente subjetivo
El contenido tiene tres partes:
- 101: los fundamentos que si o si necesias conocer
- 102: cosas adicionales para ser un desarrollador completo
- Extras
Este contenido está enfocado simplemente a capacidades técnicas, que no son las únicas a cubrir…
Y por recalcar que no quede… Esta es una profesión de aprendizaje sin fin.
101
Agile
Parto de la premisa de que se quiera desarrollar Software de una manera ‘agile’. Pero…. ¿Que es agile? Todo empezó en el 2001 con el Agile Manifesto, pero desde entonces ha habido mucha confusión con el concepto. Por ejemplo hacer Scrum no implica hacer Agile como yo y mucha gente entendemos el termino. Puedes tener rituales de Scrum pero no ser nada Agile. De hecho hoy en día podrás escuchar el termino ‘fake agile’.
Para entender como yo entiendo agile, lo mejor es que os redirija a una charla que dió mi amigo Eduardo Ferro (eferro) en Sevilla: Agilidad. Hacia la entrega continua. ¿Qué te lo impide? CAS2017.
La visión de eferro incluye básicamente XP y DevOps.
Recomiendo también un par de libros:
- The clásico sobre XP de Ken Beck: Extreme Programming Explained
- Y uno muy cortito y muy al grano de lo que es agilidad de Ron Jeffries: The Nature of Software Development
Software Design
Object Oriented Programing (OOP)
Yo diría que todo el mundo sabe lo que es la Programación Orientada a Objetos (OOP), pero la realidad es que es dificil crear buenas abstracciones. Aunque llevemos programando muchos años, erramos miserablemente.
OOP no es el único paradigma a usar, pero sin duda es el mas extendido, por lo que a no ser que programes en un paradigma totalmente diferente (como funcional por ejemplo) es algo a tener en tu caja de herramintas.
Como comentaba, este ejercicio de crear este ‘mapa’ vino de trabajar con Data Scientists en entorno de Pandas, y dicho entorno realmente no favorece nada el crear abstracciones adecuadas. Pero se puede. De hecho en Nextail lo hicimos.
Para OOP voy a recomendar sólo un libro, 99 bottles de Sandi Metz.
Cuando lo leí me encantó. Es un libro increible. El código es en Ruby. Si nunca has visto Ruby no te preocupes porque es realmente fácil de seguir.
Recursos relacionados:
Hexagonal Arquitecture
Es una arquitectura que pone el foco en aislar la infraestructura del dominio.
Introduce un par de terminos rarunos (Ports and Adapters) que son Interfaces e Implementaciones de esos Interfaces. Para marear la perdiz, puedes escuchar el concepto de puertos primarios y secundarios. Si quieres para fardar, aprendetelo, pero no tiene mucho valor. Primario es un puerto externo (hacia el usuario) y secundario interno (por ejemplo a la BD). Yo te lo suelto aquí obviamente para fardar.
Con esta arquitectura tendrás el código en tres capas, infraestructura, dominio y aplicación al igual que con una arquitectura de capas, pero la diferencia como ya comentamos es que ni el dominio ni la aplicación dependerán de la infraestructura.
Como ahora mismo no tengo una referencia buena a mano, dejo un enlace a la wikipedia.
SOLID
¿Que es codigo SOLID? En realidad diría casi se ha convertido en un sinónimo de código mantenible. Las letras vienen de una seríe de principios que ayudan a ello, pero puedes perfectamente tener código mantenible sin aplicarlos. Y puedes cumplirlos y que el código sea un estercolero.
Dicho esto el principio de Single Responsibility es tan básico… Y si haces arquitectura hexagonal deberas usar el principio de Dependency Inversion si o si.
Testing
Aparte de ser capaz de diseñar buen software es muy importante tenerlo testeado. Hay diferentes estrategias que puedes aplicar dependiendo de la base de código:
- Testing pyramid
- Testing Diamond
- Reverse testing pyramid
En cada una de esas estrategias se da mas peso a que tests hacer. La más común a escuchar es la de la piramide, donde hay mas tests unitarios, luego van los de integración y luego los end-to-end.
Que es mas conveniente dependerá del contexto. No hay una verdad absoluta.
Si tengo que recomendar algo sobre testing te sugeriría probar a hacer Test Driven Development (TDD).
Tests unitarios y de integración
Hay diferentes maneras de catalogar los tests, pero al final lo mas común es oir los conceptos de tests unitarios y de integración. Y aún asi, no todo el mundo los entiende igual.
Yo cuando hablo sobre ellos me gusta aclarar como yo lo veo: unitario es un test rápido e integración es un test lento. Es decir, si toco infraestructura para mi es un test de integración. Puedes tocar la BD y parecerte rápido… Pero te puedo asegurar que cuando el numero de tests crece no será así. Para mi un test unitario puede involucrar muchas clases.
Si los discriminas, en tu sistema de integración continua lo suyo es que corras primero los unitarios (rápidos).
Otro test que debieras hacer en cuanto puedas es un test end-to-end. Un test que prueba tu sistema en produción. Puede ser simplemente un happy path.
Siempre debieras hacer algún test de integración y luego complementar con tests unitarios. Como ahora mismo no tengo en mi cabeza alguna recomendación, no pongo nada, pero hay mucha literatura sobre testing.
TDD
Sobre TDD hay una charla excepcional: TDD, Where did it All Go Wrong. Sobre libros no puedo hacer ninguna recomendación, porque no he leido ninguno, pero tanto en la charla anterior como otras que he visto recomiendan (de nuevo Ken Beck) Test Driven Development by Example.
Una manera fantástica de hacer TDD es haciendo Software Katas en pareja o en grupo. Esta es una actividad que al menos hace años las comunidades crafters hacían.
Es muy útil que tengas TDD en tu caja de herramientas. No hace falta que te conviertas en un talibán del TDD. No tenes porque usarlo siempre. Yo cuando lo uso, muchas veces no hago un TDD de libro… Muchas veces en lugar de empezar con TDD hago un pequeño diseño, y luego ya salgo al flujo TDD.
Test Doubles
Si deseas ejecutar los tests de manera desacoplada de la infraestructura, necesitas dominar que tipos de objetos te pueden ayudar. Básicamente lo que necesitas es un Test Double, y los tienes de diferentes tipos: Dummy, Fake, Stubs, Spies, and Mocks.
En el enlace anterior tienes una explicación sobre los diferentes tipos.
Fixtures, object mothers and data builders
Veamos que son, desde el mas sencillo al menos.
Es bastante común tener un conjunto de datos para asegurar que el sistema funciona. Es lo que se conocen como fixtures. Tienen dos ventajas:
- Son muy comodas para empezar a hacer tests de integración.
- Es la mejor forma de empezar a añadir tests a un modulo que heredas y que no los tiene.
Tienen la desventaja que son poco flexibles. Si empiezas a tener configuraciones complejas lo mejor es pasarte a las object mothers, que básicamente son:
- Una clase que contiene métodos factoría estáticos que se usan para crear objetos que se usan en los tests
- El nombre de los métodos ayudan a identificar el estereotipo del objeto creado.
- La idea es que los desarrolladores se familiaricen con los objetos creados y los usen en escenarios de testeo.
Pero tambien tienen sus problemas:
- Si tienes muchas variaciones en los tests necesitas muchos metodos factorias por lo que las clases pueden acabar muy hinchadas.
- Si no conoces los datos usados, los tests pueden ser oscuros.
- Variables que afectan a los tests pueden no ser evidentes ya que están ocultas durante la creación.
- Los métodos factoría acaban siendo una fixture compartida.
Para solventar los problemas de las objects mothers tenemos los test data builders. Para cada clase que quieres usar en un test creas un builder que:
- Tiene un attributo para cada parametro de construction.
- Inicializa los atributos con valores por defecto seguros o usados frecuentemente.
- Tiene un método de constructión que crea un objeto usando los atributos.
- Tiene un conjunto de métodos públicos que se pueden encadenar para dar valores a los attributos.
102
Devops
De esto solo doy un vuelo rasante, de cosas que al menos te deben sonar…
12 factor
Parallel changes
Es interesante saber como hacer despliegues seguros en paralelo. Dan muchísima seguridad a la hora de ir evolucionando un legacy.
Continous integration and Continour Delivery
Debieras tener claro la diferencia entre CI y CD. ¡Ojo! que un codigo se haya desplegado no significa que esté disponible para los usuarios.
Observability
Es básico para mantener y evolucionar una aplicación. Como mínimo debieras tener logs. Recomendable tener integrado un sistema de gestión de errores como por ejemplo Rollbar o Sentry.
Si quires saltar al siguiente nivel, y sobre todo si tu sistema es distribuido, mete traces.
Simplemente con logs y trazas, es muy facil empezar a crear métricas.
Como la obserbability no va a ser el core de tu negocio mi recomendación es usar algo como Datadog, si te lo puedes permitir…
Refactoring
No he leido el libro que está considerado la biblia, que es el libro de Martin Fowler.
DDD (Domain Driven Design)
Si tu proyecto es complejo y grande, es una técnica para diseñar software que me parece potentisima para evitar a largo plazo lo que se conoce como BBoM (Big Ball of Mud).
Yo ahora mismo me estoy terminando de leer un libro que me parece exceptional: Learning Domain-Driven Design ) de Vlad Khononov.
Runners y Expectations en testing
Para ejecutar los tests necesitaras lo que es un runner. Normalmente vas a tener varios disponibles, pero normalmente hay uno que es el lider en el lenguaje que uses. Por ejemplo en python el claro lider actual es pytest.
A mi personalmente me gusta mucho el estilo de los tests en formato BDD. Si lo tienes disponible te lo recomiendo. En ruby por ejemplo tienes RSpec.
En el caso de las expectations pasa lo mismo, las hay con un estilo ms BDD frente los clasicos asserts. Como puedes adivinar prefiero las primeras por ser mas expresivas. Además típicamente las librerías te permiten crear tus propios matchers.
Design Patterns
Llamamos Design Patterns, a una serie de patrones recurrentes en el diseño de software que se han identificado y catalogado. Facilitan la comunicación entre desarrolladores, por lo que no esta de mas saber sobre ellos. Ejemplos: Facade, Factory, Singleton, Command.
Hay libros sobre el tema pero creo es mejor que en caso de que te los encuentres acudas a un catalogo. El libro de refactoring de Martin Fowler los usa.
Product
Un tema muy amplio, pero muy interesante y útil saber sobre él en el caso de trabajar en una compañia de producto.
No es algo tan relevante como otras cosillas, pero si hay tiempo y ganas… Hay libros clásicos, pero como no he leido ninguno no recomiendo nada.
En mi caso lo que se producto, viene básicamente de:
- Haber hecho un curso de Product Owning.
- La experiencia de haber trabajado en producto ya por muchos años, por lo que si es tu caso, ya de puro roce irás aprendiendo cosas
- Leer.
- Asistir a conferencias o open spaces. Por ejemplo en la CAS o AOS suele haber cosas de producto.
También tienes eventos y meetups específicos de producto.
Teams and organization
Ahora mismo hay un libro que hay que leer, Team Topologies. Yo no lo he hecho, pero lo tengo pedido…
Extras
Para acabar dejo un par de charlas:
- 7min, 26 secs
- Simplicidad para desarrolladores de Eduardo Ferro.
Un artículo:
- How I learned to love mocks. Explica porque deberías mockear los ‘adapters’ y proporciona muchas referencias para continuar profundizando.
Y el blog de Eduardo Ferro con mucha mierda sobre agile de verdad.