Git es un sistema control de versiones distribuido, y el más usado del mundo, a continuación veremos como instalar Git en MacOS, linux y windows. Es muy importante tener instalado este programa para ser más productivo a la hora de escribir código de programación y trabajar en equipo.
¿Qué es un sistema de control de versiones?
Si te lo preguntas, básicamente un sistema de control de versiones te permite guardar los cambios que aplicas a un conjunto de archivos, estos cambios se guardan en una especie de historial, con el cual puedes regresar en el tiempo a cualquier punto registrado en ese historial. Es decir, te da la habilidad de mantener las versiones de tu software por si quieres usar una versión anterior especifica, o necesitas utilizar un cambio en el código que se realizó anteriormente.
Conozco dos formas de instalar Git en MacOS. Una es con un instalador de paquetes binarios y la otra a través de un administrador de paquetes muy bueno, aunque no oficial de macOS, llamado Homebrew. Para las instalaciones en Linux y Windows, la cosa es mucho más sencilla.
Instalar Git en MacOS desde un paquete binario
Primero te vas a este enlace, en la sección de Binary Installer, seleccionas la última versión indicada, en este ejemplo es la 2.31.0
Dependiendo del tipo de procesador de tu computadora, te dará la opción de descargar si es Intel u otro tipo de procesador.
Una vez descargado en tu computadora, solo le das doble clic al archivo git-2.31.0-intel-universal-mavericks.dmg mostrado en la imagen de abajo, en mi caso mi procesador es intel. Se abrirá una carpeta con un archivo del mismo nombre, pero con extensión pkg, y lo abrimos.
Si te sale el siguiente mensaje es porque la fuente de este paquete no está registrada como una fuente de confianza. Esto es una configuración predeterminada de macOS.
Para brincarnos fácilmente esta configuración porque git realmente si es de confianza, basta con presionar Ctrl + Clic y seleccionamos abrir.
Ahora simplemente le decimos que efectivamente si lo queremos ejecutar presionando este otro botón abrir.
Ya dentro del instalador solo le decimos que continué hasta que termine la instalación.
Ahora verificamos en la terminal que Git está instalado, usando el comando git --version.
Instalar Git en MacOS con Homebrew
Antes debemos instalar el administrador de paquetes Homebrew con el siguiente comando:
Si te pide permisos de superusuario, solo ingresa tu contraseña:
Después te avisará de algunos cambios de acceso, permisos de carpetas y archivos necesarios para que homebrew funcione. Además, si no tienes las herramientas de línea de comandos de Xcode, también te las instalará. Para todo esto te pedirá una confirmación, dependiendo de tu conexión y configuración puede tardar varios minutos.
Si te pide de nuevo autorización para eliminar los archivos temporales que ocupó para la instalación de las herramientas de xcode, solo ingresa de nuevo tu contraseña.
Ahora si debe proceder a la instalación de homebrew, cuando termine, la terminal debe imprimir algo como la imagen de abajo, también en la imagen se ve como puedes verificar la instalación ejecutando el comando brew help.
Finalmente podemos instalar Git, ejecutando el siguiente comando:
brew install git
Cuando se instale correctamente te debe imprimir en la terminal algo parecido a la siguiente imagen:
Si quieres verificar la versión de la instalación, puedes ejecutar el comando git --version
Instalar git en Linux, distribuciones basadas en debian
La instalación de git en linux es más sencilla con los administradores de paquetes de tu distribución de Linux.
Primero necesitamos actualizar la lista de paquetes disponibles.
$ sudo apt update
Ahora si actualizamos git con la última versión disponible en los repositorios de paquetes.
$ sudo apt install git
Para comprobar que git se instaló correctamente.
$ git --version
El comando te debe imprimir la versión actualizada, algo como lo de abajo.
git version 2.31.0
Instalar git en Windows
Para instalar git en windows, es aún más sencillo que en macOS y Linux. Solo tienes que entrar el sitio oficial de git y dar clic sobre el botón de descarga.
Ejecutar el archivo ejecutable descargado y simplemente seguir las instrucciones de instalación, con las opciones de configuración seleccionadas por defecto. En cada pantalla, ya saben , “siguente”, “siguiente”, y “siguiente”.
Y ya solo espera a que termine la instalación
Por último lanza el git bash y ejecuta el comando git --version
Configuración inicial de Git recomendada
Es recomendado configurar git para empezar a trabajar con él, esto te ayuda a registrar tus cambios y versiones con tu información personal.
Para establecer la configuración con tu nombre y correo electrónico vamos a usar el comando git config.
Los tipos de datos en Javascript son un poco diferentes en comparación con otros lenguajes de programación como C o JAVA.
JavaScript es un lenguaje débilmente tipeado, esto quiere decir que no es necesario definir el tipo de dato. Pero tampoco es que no tenga tipos, pues el tipo de dato es definido en tiempo de ejecución por Javascript.
Este comportamiento y especificación de los tipos de datos aplica para cualquier lugar donde se ejecute javascript, ya sea en el navegador, en node.js, mongodb, o cualquier herramienta que use Javascript.
Ahora si analizamos un poco el concepto de tipos, cuando realizas una suma entre números en el mundo real no te importa que tipo es, solo te importa que se puedan sumar, sin importar si es un entero, o decimal. Estos subtipos de números siguen siendo parte del conjunto de números reales, y son utilizados en la vida real.
Javascript nos permite aplicar este pensamiento y con eso nos ahorramos muchas comparaciones de tipos. Habrá ocasiones en que no quede de otra que convertirlos o compararlos, pero entre menos lo hagamos, más sencillo será nuestro código, y por consiguiente más fácil de entender y más rápido de ejecutar.
Se dice que Javascript tienen un sistema de tipos de datos dinámico, esto es porque las variables que se crean pueden recibir cualquier otro tipo de dato en cualquier momento, e ir cambiando de tipo según el valor que guarden. Lo que realmente nos interesa es el valor y que podemos hacer con ese valor, no tanto el tipo.
Más adelante veremos algunas conversiones y comparaciones que pueden confundir y complicar el código, la recomendación es disminuir su uso en la medida de lo posible. Aunque no veremos muy a detalle cada tipo, sí que veremos cosas más importantes, necesarias para usar los tipos de datos en Javascript.
Es útil que se sepa definir variables y constantes, si no sabes como crear una variable o una constante, puedes revisar esta información antes de continuar.
Tipos de datos primitivos
Es aquel que no es un objeto
No tiene métodos.
Son inmutables
Tenemos siete tiposdatos primitivos en Javascript.
Number, números como; 1, 0, 18500, 89.95124
BigInt, agregado en el 2020, para representar números enteros muy, pero muy grandes, 99999999999999n
String, cadena de caracteres como 'Hola' y "Buenas noches".
Boolean, solo acepta true o false, es decir, si o no.
null, sirve para indicar que algo es nada, su único valor es null.
undefined, sirva para indicar que algo aún no está definido.
Symbol, agregado en el 2015, con EcmaScript 6
Tipos de datos Objetos
Todo lo demás tipos de datos en Javascript son objetos. En la sección Objetos está la explicación.
Number
Si hubiera escrito esto antes del 2020, te diría que solo hay un tipo de dato numérico, lamentablemente (con algunas excepciones) se agregó un nuevo valor numérico llamado BigInt. En esta sección fingiremos que no existe.
Number es un valor flotante de 64 bits, es decir, es un número double en otros lenguajes de programación, básicamente este es el único tipo de dato numérico en javascript, no existen enteros (a excepción de BigInt), decimales, flotantes o doubles. Su especificación está proporcionada por IEEE-754.
La forma de definirlos y usarlos es muy sencilla, simplemente escribes el número, no importa si es entero o decimal, punto flotante o double, como mencionamos antes, todos estos serán de tipo double para javascript. Esta es la forma recomendada de definirlos.
const edad =33;const PI =3.1416;const descuento =0.30;const pesoEnDolares =0.05;// que tristeza xD!!edad + descuento;// 33.30, no nos interesa el tipo, solo la suma
Como vemos en la última línea, podemos sumar enteros y decimales sin ningún problema, no nos interesa el tipo, nos interesa la habilidad de sumarlos.
Se sabe que los valores flotantes tienen cierto error de precisión al realizar operaciones aritméticas, la operación más obvia es la división.
0.2+0.1;// es igual a 0.30000000000000004
Como vemos no nos da un valor exacto de 0.3, para mitigar esto puedes multiplicar los valores por 100 y luego dividir el resultado entre 100.
(0.2*100+0.1*100)/100;// es igual a 0.3
NaN
Existe un número especial llamado NaN. Este valor es el error de una operación con números.
25*undefined;// es igual a NaN25*{};// es igual a NaN
Todo operación que tenga NaN como uno de sus operandos, dará como resultado NaN.
25*NaN;// es igua a NaN25+NaN;// es igual a NaN
NaN ni siquiera es igual a NaN
NaN===NaN;// es igual a falseNaN==NaN;// es igual a false
Para mitigar este extraño comportamiento, se recomienda usar el método Number.isNaN(), también existe una función global llamada isNaN(), pero debido a la funcionalidad implícita de Javascript en querer convertir entre tipos automáticamente, nos puede dar resultados muy extraños. Así que como recomendación siempre usa Number.isNaN(). Esta última función revisa si el tipo es Number e igual a NaN, cualquier otro valor nos regresara false.
// Usando funcion globalisNaN('jaime');// true --> Esto esta mal, deberia seguir regresando false// lo que realmente hace es una conversion automaticaconst result =Number('jaime');// NaNisNaN(result);// trueNumber.isNaN('343434');// falseNumber.isNaN('jaime');//falseNumber.isNaN(1+undefined);// true
Podemos ver en el primer ejemplo que la función global regresa true cuando debería ser false, esto es por la conversión automática de tipos que hace javascript.
Función Number(valor)
Puedes convertir un valor a número usando la función Number(valor), solo ten cuidado porque esta función puede regresar 0 para muchos valores, así como también NaN.
Por último tenemos las funciones Number.parseInt(valor) y Number.parseFloat(valor), si el valor no es un string, entonces lo convierten a string utilizando el método .toString() antes de convertirlo a Number.
Este tipo de valor es nuevo, agregado al lenguaje en el 2020, se utiliza para representar valores enteros muy grandes, especialmente para cálculos matemáticos con cantidades muy largas.
Para usar este tipo de dato al número se le agrega la letra n al final. Esta es la forma recomendada.
const enteroMuyGrante =999999999999999999999999999999999999999999999999999n;const otroEnteroMuyGrande =55555555555555555555555555555555555555555555555n;const result = enteroMuyGrande * otroEnteroMuyGrande;//
Se pueden realizar operaciones entre el tipo Number y el BigInt, pero debido a que la conversión entre tipos puede provocar perdida de precisión, se recomienda solo usar valores BigInt cuando se estén ocupando valores mayores a 253 y solo realizar operaciones con valores del mismo tipo BigInt.
Otra mala noticia sobre BigInt es que no puedes utilizar sobre un valor BigInt los métodos del objeto Math, por ejemplo no puedes utilizat Math.sqrt().
Math.sqrt(99);// 9.9498743710662Math.sqrt(99999999999999999n);// Uncaught TypeError: Cannot convert a BigInt value to a number
Como recomendación final, no te compliques la vida, no uses BigInt a menos que el problema que quieras solucionar necesite forzosamente números enteros muy grandes.
Función BigInt(valor)
Puedes convertir y crear un BigInt con la función BigInt(valor)
BigInt('9999999999');// 9999999999n
Boolean
Boolean es un tipo de dato lógico, el cual es representado únicamente por dos valores true y false. Muy útil para tomar decisiones en nuestros programas. Nombrado así por el matemático George Boole.
Se pueden definir valores tipo Booleanos de la siguiente manera. Esta es la forma recomendada
const tieneHijos =true;const esEstudiante =false;
Se usan mucho en operaciones lógicas, por ejemplo:
if (tieneHijos) {// Si "si" tiene hijos, preguntar cuantos hijos tiene}else{// si "no"}if (esEstudiante) {// Si "si" es estuduante, aplicar descuento}else{// si "no"}
Función Boolean(valor)
Los Booleanos también tiene una función Boolean(valor), es adecuado para crear booleanos y convertir explicitamente un valor a Booleano. Más detalles abajo en la sección Valores que pueden generar Booleanos.
null
Este tipo de dato en Javascript es muy fácil, es un dato que significa que no es nada en comparación con los demás tipos de datos. En otros lenguajes null hace referencia a un apuntador o una referencia de memoria que está vacía, pero en javascript es diferente, simplemente es un valor que significa “nada”.
const nada =null;
undefined
Este tipo de dato representa algo que aún no está definido. Es el valor automático de las variables, parámetros y propiedades de objetos que no se les ha definido un valor.
let nombre;// undefinedlet edad;// undefinednombre ===undefined;// trueedad ===undefined;// true
Symbol
Este tipo de dato se utiliza principalmente para garantizar que su valor sea único e inmutable. Se puede usar como propiedades de objetos para reducir accesos a esas propiedades y con eso evitar modificaciones indeseadas. Cuando veamos más a detalle a los objetos veremos en la práctica su uso.
Para crear este tipo de dato primitivo se usa la función Symbol(). Es la única forma de crear un symbol y es la recomendada.
const nombre =Symbol('Jaime');const nombreIgual =Symbol('Jaime');nombre === nombreIgual;// false
String o cadena de caracteres
Los string nos permiten guardar información en forma de texto. Son una secuencia de uno o más caracteres de 16 bits, UTF-16. No existe el tipo `char` como en otros lenguajes, si deseas un carácter, pues simplemente creas un string con un solo carácter. ¿Sencillo no?
Tenemos tres formas para crear un string.
En realidad se puede también crear strings con la función String(valor) o en forma de constructor new String(valor), pero no nos compliquemos la existencia y ocupes solo las tres de abajo por simplicidad:
Con comillas simples, ''. Recomendada si no necesitas evaluar expresiones dentro.
Comillas dobles, ""
backticks, `` . Recomendada si necesitas evaluar expresiones dentro.
const nombre ='Jaime';const apellidoPaterno ="Cervantes";const apellidoMaterno =`Velasco`;
La tercera forma de definir Strings, nos permite usar expresiones dentro de la cadena de caracteres, por lo que es muy útil. Por ejemplo:
La propiedad length de un string se usa para saber la longitud de una cadena de caracteres, verás con el tiempo que esto es útil cuando trabajas con cadenas de caracteres.
const nombre ='Jaime Cervantes Velasco';nombre.length // 23
Objetos
Todo lo demás tipos de datos son objetos, una función es un objeto. Un objeto es una colección de pares nombre: valor, parecido a los “arrays asociativos” de PHP. Estos pares de nombre/valor se les llama propiedades, una propiedad es como una variable y puede contener cualquier tipo de valor.
Algunos objetos en Javascript:
Object
Function
Array
Date
RegExp
Error
Objetos envolventes de primitivos
Incluso los tipos de datos primitivos String, Boolean, Number, BigInt y Symbol tiene su correspondiente representación en Objeto, llamados objetos envolventes. De hecho Javascript implícitamente convierte estos datos primitivos a objetos para poder ocupar métodos y propiedades útiles. Por ejemplo la propiedad length de una cadena de caracteres.
¿Cómo pensabas obtener la longitud de una cadena de caracteres? Entendiendo que una cadena de caracteres es un dato primitivo y no tiene métodos
'Jaime Cervantes Velasco'.length;// 23, el pri// A groso modo, lo que sucede implictamente al querer obtener lenght:const nuevoString =newString('Jaime Cervantes Velasco');nuevoString.length;// 23(5).toFixed(2);// 5.00// Igual a groso modo pasa algo asi:const numero =newNumber(5);numero.toFixed(2);// 5.00false.toString();// 'false'// Igual a groso modo pasa algo asi:const booleano =newBoolean(false);numero.toString(2);// false// Estos dos tipos de datos primitivos no permiten el uso de new(9n).toLocaleString();// '9'Symbol('Hi').toString();// 'Symbol(Hi)'
Aunque los tipos de datos BigInt y Symbol no permiten el uso de new no quiere decir que por detrás no se creen objetos, está claro que javascript los envuelve en un objeto porque nos permite utilizar los métodos del ejemplo, toLocaleString y toString.
¿Cómo crear un objeto?
Para crear un objeto no necesitas crear una clase, tú simplemente creas el objeto y lo empiezas a utilizar. La forma más fácil de crear un objeto es usando la definición que llaman objeto literal, donde simplemente abres y cierras llaves {}. Esta es la forma recomendada.
En el ejemplo tenemos un objeto persona, tiene varias propiedades de diferentes tipos, su nombre es un String, su edad es un Number, getNombre y hablar son de tipo Function, las funciones que son miembros de un objeto se les llama métodos.
Más abajo hay ejemplos de objetos.
Accediendo a propiedades con corchetes, ['key']
En el ejemplo anterior vimos como acceder al método hablar(), este método sigue siendo una propiedad y es de tipo function. Pero existe otra notación para acceder a las propiedades, usando corchetes. Muy parecido a como se acceden a los elementos de un array.
persona.edad;// regresa 33persona['edad'];// regresa 33// obtenemos la funciónn con corcheteds y la invocamos con parentesisconst frase = persona['hablar']();console.log(frase);// 'Hola soy Jaime Cervantes Velasco, tengo 29 años.'
Como un array es un objeto, igual que una función, también le puedes agregar propiedades.
const numeros = [1,2,3,4,5,6];numeros.miPropiedad ='Mi propiedad de un arreglo';console.log(numeros.miPropiedad);// 'Mi propiedad de un arreglo
¿Cómo crear un objeto Date?
const fecha =newDate();console.log(fecha);// Fri May 28 2021 10:46:27 GMT-0500 (hora de verano central)
Como te podrás imaginar, al objeto date también le podemos agregar propiedades porque es un objeto
De momento espero que esto te dé una idea de la importancia de los objetos en Javascript y por eso se merece una explicación más extensa en una futura publicación.
Valores que pueden generar un boleano false
Existen valores verdaderos y valores falsos, que aplicados en una condición se comportan como Booleanos. Esto es debido a que Javascript hace una conversión de tipos implícita, que nos puede sorprender si no tenemos cuidado, por eso aquí te dejo la lista de valores que pueden regresar un Boleano false.
false
null
undefined
0
0n
NaN
”, “”, “ (cadena de caracteres vacía)
Todos los demás valores, incluyendo los objetos, en una condición o pasados a la función Boolean(valor) regresan el Boleano true. Un string con un espacio " ", regresa true, y un string con valor "false" también regresa true.
Función Boolean(valor)
Existe una función global para crear valores Booleanos, Boolean(valor). Donde si valor es uno verdadero, regresa true, de lo contrario, regresa false.
Boolean(false);// falseBoolean(null);// falseBoolean(undefined);// falseBoolean(0);// falseBoolean(0n);// falseBoolean(NaN);// falseBoolean('');// false// Todos los demas valores van a regresar trueBoolean('');// trueBoolean('false');// trueBoolean('jaime cervantes');// trueBoolean({});// trueBoolean([]);// true;
En condiciones lógicas
Las condiciones lógicas en javascript verifican sin una expresión regresa true o false, ejecutan un conversión implicita.
Este operador nos permite identificar el tipo de dato con el que estamos trabajando, útil en caso de que no sepamos de donde viene la información, o queremos tratar los datos con base en su tipo. El operador regresa el nombre en minúsculas del tipo de dato.
typeof5;// 'numbertypeofNaN;// 'number'typeof99999999999999999999999999999999999999999999999n;// 'bigint'typeoftrue;// 'boolean'typeofnull;// 'object', esto es un error que existe desde la primera versión de JStypeofundefined;// 'undefined'typeofSymbol('simbolo');// 'symbol'typeof'cadena de caracteres';// 'string'typeof{};// 'object'typeof [];// 'objecttypeofnewDate();// 'object'typeofnewString('Jaime');// Objecttypeoffunction(){}// 'function'typeofclassA{}// 'function'
Existe un error conocido en javascript, cuando se ejecuta el operador typeof sobre null, este regresa ‘object'. Este error existe desde la primera versión de Javascript, cosas malas pasan cuando escribes código a las carreras.
Si todos los demás valores que no son primitivos son objetos, cuando usamos el operador typeof sobre ellos, ¿Qué tipo de datos nos indicara que son?, exacto, 'object'. Tal como en el ejemplo de arriba cuando pasamos un objeto literal, un array vacío, un objeto tipo fecha y cuando ocupamos los objetos envolventes de primitivos como new String('Jaime').
Existe una excepción en typeof, cuando el valor es una función o una clase, regresara function. Recuerda, una función en javascript, también es un objeto.
Verificar tipos con el método Object.prototype.toString
Como vimos, es algo confuso utilizar el operador typeof, yo prefiero utilizar un método más seguro, es algo raro, pero como todo en Javascript es un objeto y el objeto base del cual parten todos los tipos de datos en javascript es Object, con excepción de los datos primitivos ( Aunque estos a su vez tienen su versión objeto), entonces podemos hacer algo como lo siguiente.
La propiedad especial prototype es muy importante en Javascript, si has leído más de una de mis publicaciones, te habrás percatado que he mencionado que Javascript es un lenguaje de programación multiparadigma y orientado a objetos basado en prototipos, en otra publicación explicaremos a detalle la funcionalidad de prototipos en Javascript.
Conclusión
Todo en Javascript es un objeto, con la excepción de los tipos primitivos, pero como ya vimos, al querer usarlos como objetos invocando algún método, es ahí donde javascript los envuelve (en la practica todo es un objeto).
Cualquier lenguaje de programación tiene buenas cosas que podemos aprovechar, pero también puede tener cosas extrañas y confusas (comparando con la mayoria de los lenguajes de programación modernos), como el operador typeof y el método Object.prototype.toString, el valor NaN, los valores que pueden generar un boleano false, y muchas otras cosas que no vimos por razones de simplicidad. Queda del lado del programador tomar las mejores partes y eliminar o mitigar las que no nos ayudan a comunicarnos mejor con nuestro equipo de trabajo, siempre con un enfoque a simplificar las cosas.
En el caso de la creación de algún tipo de dato en Javascript, la manera más simple y fácil de usar, es simplemente creando los valores que vamos a utilizar. Tal como se recomendó en secciones anteriores, a esta forma de crearlos se les llama literales.
const numero =9999.54;const enteroGrande =99999999999999n;const boleano =true;const nulo =null;let noDefinido;const simbolo =Symbol('identificador');const cadenaDeCaracteres ='Jaime Cervantes Velasco';const cadenaDeCaractresConExpresion =`El numero ${numero} es "Number"`;const objeto ={};const arreglo = [];
Existen aún más detalles que cubrir sobre los tipos de datos en javascript, pero sobre la marcha iremos viendo más temas necesarios, de momento me parece que esta información es suficiente.
En realidad TDD significa Desarrollo guiado por pruebas, del inglés Test Driven Development. Lamentablemente es un nombre que no le hace justicia, lo que realmente guía al desarrollo siguiendo esta práctica, son las especificaciones o comportamientos.
Ya sé, ya sé, para la gente que sabe que es BDD seguro se pregunta, ¿Guiado por comportamiento?, ¿Eso no es BDD?, pero el contenido de esta publicación clarificará la estrecha relación entre TDD y BDD. Mostraremos una perspectiva en la que en esencia, son lo mismo.
Origen de TDD en la vida
Una de las características principales y de hecho el primer paso cuando se aplica desarrollo guiado por pruebas es el entender bien el problema a resolver. Es por eso que se escriben las pruebas primero, esta idea ha existido desde que el ser humano hace cualquier tipo de trabajo, ejemplo:
Un cazador enseña a su hijo como cazar una cebra y le indica que el mejor lugar para clavarla es justo debajo de la oreja, donde puede atravesar su cráneo, pero ese es un tiro muy difícil. Le dice que el tiro más facil es “Apuntar a las rayas que la cebra tiene en el pecho”. Mientras el padre dibuja las rayas en el tronco de un árbol (simplicidad).
– Sigue practicando el tiro a una distancia de 20 pasos hasta que claves la lanza correctamente”, luego -“No espera, sostén la lanza así”, más tarde – “Si, así está mejor, continua así” … – “Ahora, pídele a tu tío que te enseñe cómo hacer que la cebra se acerque a una distancia de 10 pasos” (iterativo e incremental, lotes pequeños, ciclo de retroalimentacion)
El objetivo del padre y del hijo es que este último pueda cazar una cebra (enfoque).
Lo ideal es clavar la cebra justo debajo de su oreja. Esto es una tarea difícil para el hijo, entonces utilizando un proceso iterativo e incremental, se empieza con el paso más fácil hasta ahora conocido. El paso es apuntar al pecho de la cebra a una distancia de 20 pasos (simplicidad).
Después surge otro inconveniente, sostener la lanza correctamente, por eso se trabaja en ello. Posteriormente surge otra cosa, hacer que la cebra se acerque hasta 10 pasos de distancia (lotes pequeños, iteraciones y vamos incrementando hasta la meta). Aunque no se menciona la razón, podemos suponer que, el padre se quiere asegurar que el hijo pueda clavar la cebra en el primer tiro
Ahora bien, de momento se cumple el objetivo (enfoque), cazar a una cebra, por lo que el padre y el hijo pueden detenerse ahí. Conforme se empieza a trabajar en la solución, muchas veces esta es mucho más simple de lo que se pensaba en el inicio.
El punto es que este proceso iterativo e incremental permite ahorrarnos tiempo, dinero y esfuerzo implementando una solución mucho más simple. Y si te preguntas cuál es la solución complicada, esa es la de “clavarla justo debajo de la oreja”.
TDD está basado en principios ágiles y el manifiesto
Todo este proceso natural e inconsciente sobre como clavar a una cebra, descrito en la sección anterior, gira alrededor de principios ágiles. Y estos principios a su vez se relacionan fuertemente con el manifiesto ágil.
Simplicidad, el arte de maximizar el trabajo no realizado, es esencial.
Algunos conocerán los principios KISS y YAGNI en programación.
Así también algunos habrán escuchado NO DESPERDICIAR de Lean manufacturing
LOTES PEQUEÑOS en cada iteración, de Lean Manufacturing
Ciclo de retroalimentación
Proceso iterativo e incremental
Estos son los más importantes desde mi punto de vista y tal vez los que más podemos notar en el día a día.
Origen de TDD en programación
Para darte una idea del origen real de TDD, voy a citar varias fuentes.
No teníamos manuales para ENIAC. Aprendimos a programar estudiando los diagramas de bloques lógicos. Que bendición. Desde el principio supe cómo funcionaban las computadoras. Nos ganamos el respeto de los ingenieros desde el principio porque realmente sabíamos lo que estábamos haciendo y pudimos depurar mejor que ellos porque teníamos nuestros programas de prueba y nuestro conocimiento de la computadora.
Betty Jean Jennings Bartik, ENIAC programmer 1946
El primer ataque al problema puede realizarse antes de comenzar la codificación. Para determinar completamente la precisión de las respuestas, es necesario tener un caso de verificación calculado a mano con el cual comparar las respuestas que luego serán calculadas por la máquina.
Esto significa que las máquinas de programas almacenados realmente nunca se utilizan para un problema de una sola vez. Siempre debe haber un elemento de iteración para que valga la pena. Los cálculos manuales se pueden realizar en cualquier momento durante la programación. Sin embargo, con frecuencia las computadoras son operadas por expertos en computación para preparar los problemas como un servicio para ingenieros o científicos.
En estos casos, es muy deseable que el “cliente” prepare el caso de verificación, en gran parte porque tal procedimiento puede señalar errores lógicos y malentendidos entre el programador y el cliente. Si el cliente va a preparar la solución de prueba, lo mejor para él es comenzar mucho antes del problema real, ya que para cualquier problema importante se necesitarán varios días o semanas para calcular la prueba
Digital Computer Programming, D.D. McCracken, 1957
Otro dato, de la época de John Von Neumann, en una entrevista realizada a Gerald. M. Weingberg por Michael Bolton
Jerry: No llamábamos a esas cosas por esos nombres en ese entonces, pero si miras mi primer libro (Computer Programming Fundamentals, Leeds & Weinberg, first edition 1961 —MB) y muchos otros desde entonces, verás que siempre fue así como pensabamos que era la única forma lógica de hacer las cosas. Lo aprendí de Bernie Dimsdale, quien lo aprendió de von Neumann.
… luego me encontré con Bernie (en 1957), quien me mostró cómo la gente verdaderamente inteligente hacía las cosas. Mi ego estaba un poco en shock al principio, pero luego me di cuenta de que si von Neumann hacía las cosas de esta manera, yo debería hacerlo.
John von Neumann fue mucho más inteligente de lo que yo seré jamás, o de lo que la mayoría de la gente será, esto significa es que debemos aprender de él …
Geral M. Weinberg
La descripción original de TDD estaba en un libro antiguo sobre programación. El libro decía, tome la cinta de entrada, escriba manualmente lo que espera en la cinta de salida, luego programe hasta que la cinta de salida real coincida con la salida esperada.
Después de escribir el primer marco xUnit en Smalltalk, recordé haber leído esto y lo probé. Ese fue el origen de TDD para mí. Al describir TDD a programadores mayores, a menudo escucho: “Por supuesto. ¿De qué otra manera podrías programar? ” Por lo tanto, me refiero a mi papel como “redescubrir” TDD.
Kent Beck
Si analizamos un poco estos últimos datos, en esa época se necesitaban ejecutar pruebas y resolver el problema en papel antes de correr el programa en la computadora porque era muy tardado volver a ejecutar el programa después de una falla ya sea por el tiempo de “ejecución” o porque las máquinas de esa época simplemente no eran tan sofisticadas como las de hoy en día.
Todo esto nos indica la importancia de las pruebas y así no retrasar el tiempo necesario para que la solución funcione correctamente y con menos esfuerzo, en la actualidad no ha cambiado mucho, eso sí, tenemos otros problemas, además el software que se desarrolla hoy en día tiene mayor escala y las funcionalidades son más sofisticadas.
Otro punto que nos enseñan estos datos, es que la comunicación entre los involucrados desde un principio es importante para evitar errores lógicos y malentendidos entre el cliente y el programador. Aquí los clientes también pueden ser usuarios, personas de UX y product owners.
Lo descrito por Kent Beck es muy interesante, programadores más viejos están de acuerdo en que no existe una mejor manera de programar que la de escribir las pruebas primero.
En conclusión, estos datos nos abre los ojos a que las pruebas siempre han sido parte del proceso de diseño y codificación. Y que se hacen lo más antes posible (test-first programming)
OK, ¿Qué es TDD?
Es una disciplina que te permite eliminar el miedo a modificar el código de un software, lo que resulta en la limpieza constante del código, por lo que se asegura que el software escale de manera fluida, sin retrasos y dolores de cabeza. Permitiendo tener un software lo suficientemente flexible para poder adaptarse a cualquier cambio.
TDD es una práctica ágil, por consiguiente basada en principios ágiles que nos permite tener una guía en el desarrollo de software para nunca perder el enfoque.
TDD se basa en la mentalidad de prevenir defectos en lugar de resolverlos después, es obvio que no se puede prevenir todos los casos, pero si un gran número con un conjunto de pruebas bien hechas.
Históricamente hablando, ha probado ser en la gran mayoría de los casos, la mejor manera de crear productos de calidad. Significa Desarrollo guiado por pruebas (Test Driven Development), pero como mencionamos antes, la palabra especificación, la describe mejor, algo así como SDD, Specification Driven Development.
Red-Green-Refactor
En la práctica, consiste en tres pasos segun Kent Beck:
RED. Escribe una pequeña prueba que no funcione, tal vez ni siquiera compile al principio
GREEN. Haz que la prueba funcione rápidamente, cometiendo los pecados necesarios en el proceso.
REFACTOR. Elimina todo el código duplicado creado
Ahora bien, cuáles son los beneficios principales:
Ciclo de retroalimentación y comunicación
Crear calidad, no medirla
Herramienta de diseño
Elimina el miedo a cambiar o mejorar el código
Documentación precisa
TDD como ciclo de retroalimentación y comunicación
Las organizaciones que diseñan sistemas (en el sentido amplio) están limitadas a producir diseños que son copias de las estructuras de comunicación de dichas organizaciones.
Melvin E. Conway, 1968
Individuos e interacciones sobre procesos y herramientas
Manifiesto ágil
Un ciclo de retroalimentación es muy importante para todo lo que hacemos, entre más pronto tengamos retroalimentación, más pronto podemos reaccionar y corregir nuestras acciones.
Cualquier metodología, framework o proceso ágil tiene como uno de sus elementos principales uno o varios ciclos de retroalimentación. Por ejemplo, en scrum, cada iteración llamada sprint es un ciclo de retroalimentación, las retroespectivas es claramente otro. Todos los días el daily es un ciclo retroalimentación. Cada release es un ciclo retroalimentación.
Estos ciclos de retroalimentación nos permiten tener una excelente comunicación y de forma constante.
TDD es lo mismo que BDD
Pero hablando en conjunto, desde el punto de vista técnico y de negocio, trasladado al código, el cual es el que nos permite cumplir con el comportamiento deseado de una determinada aplicación, ¿Existe algún ciclo de retroalimentación? ¿Qué nos permita corregir errores lo más pronto posible?
Respuesta ante el cambio sobre seguir un plan
Manifiesto ágil
Claro que sí, existen dos prácticas muy útiles para esto, una se llama BDD y la otra TDD, estas prácticas responden dos preguntas muy importantes:
¿Estamos construyendo el software correcto?, ¿El que el usuario final necesita?
¿Estamos construyendo correctamente el software, ¿Con la suficiente flexibilidad que permita adaptarse a las nuevas necesidades de los usuarios?
Aunque BDD y TDD parecen que son dos cosas diferentes, en realidad son lo mismo, TDD se empezó a utilizar primero, de hecho se creaban pruebas de aceptación, de integración y unitarios usando TDD. Luego, apareció ATDD y BDD (con ayuda de DDD) como extensiones de TDD.
En realidad BDD aporta a TDD:
La mejora en la retroalimentación y comunicación entre todo el equipo, programadores y no programadores
Comportamientos documentados con mayor claridad y precisión
Lo que escribimos en código de prueba son el reflejo de las especificaciones, el objetivo primordial de las pruebas no es verificar exactamente que una clase o método se ejecute correctamente, sino cómo se comporta según el deseo implícito de los usuarios finales, y este deseo implícito se plasma explícitamente en las especificaciones creadas antes de empezar escribir código de programación.
Lo anterior es muy importante porque nos da el objetivo y el foco correcto a nuestro desarrollo. Esta idea la podemos decir de las siguientes formas, desarrollo guiado por:
Especificación.
El dominio
Comportamiento
Pruebas, la definición más conocida y que lamentablemente genera más confusión.
TDD para crear calidad, no para medirla
La palabra Testing (Prueba) en el mundo de QA (Quality assurance), quiere decir probar después de que el software está desarrollado, probar y probar hasta comprobar que el software no tiene defectos. Debido a esto, las pruebas de QA sonuna forma de medir la calidad de un producto, pero no es una forma de construir un producto con calidad.
El ciclo de retroalimentación que nos da el escribir y terminar una funcionalidad y luego probar es ineficiente porque la retroalimentación se obtiene muy tarde. Es posible trabajar en algo equivocado por minutos, horas y hasta días, a veces ese trabajo tiene que ser desechado o mínimo con muchos cambios.
Cuando la retroalimentación se retrasa mucho tiempo, por ejemplo, después de un ciclo de pruebas por parte de QA, el desarrollador encargado no tiene el contexto o no lo recuerda bien. Y esto genera más gastos, porque una vez reportado por QA se debe de encontrar la fuente del defecto y replicarlo, luego entender el problema, entender el código relacionado y además el tiempo que se tome corregirlo. Y otra vez QA prueba y reporta si el bug ha sido arreglado o no.
De nuevo el principio de Lean manufacturing sobre trabajar sobre cosas simples y pequeñas, no esperar a encontrar errores o mitigarlos hasta el final de la cadena de producción, sino en cada pequeña etapa del proceso tener uno o más ciclos completos de retroalimentación.
Ayuda a devops
Esto último va de la mano con la integración continua y despliegue continuo, si las pruebas fallan, no se puede establecer una integración y mucho menos un despliegue a producción.
Dado que un ciclo de retroalimentación temprana sucede en varios niveles del software, las incidencias aparecen antes de una integración y también mucho antes de un despliegue.
Claro que nunca se podrá mitigar todas los bugs o incidencias, pero por supuesto que se puede disminuir en una gran proporción, esto de igual manera resulta en reducción de costos, tiempo y esfuerzo.
El ambiente en los equipos se vuelve productivo, mejora la comunicación y seguridad en que de verdad se está entregando un producto de calidad, esto produce estimaciones más precisas, seguras, y honestas.
TDD como herramienta de diseño
Colaboración con el cliente sobre negociación contractual
Manifiesto ágil
Al escribir las pruebas primero (test-first programming) nos enfocamos en que el código de producción sea accesible desde el código de pruebas y sea fácil de probar. Esto quiere decir que desde un inicio nos preocupamos por el diseño y la arquitectura de nuestro código de producción, porque para que nuestro código de producción sea accesible y fácil de probar debe estar desacoplado.
Al escribir las pruebas, nuestra perspectiva de programador cambia, ahora pensamos en como otros programadores van a usar la API de nuestra funcionalidad antes de crearla, también desde la perspectiva de negocio porque cuando escribimos nuestras pruebas, a menudo nuevas dudas surgen que debemos indagar con personas que no son necesariamente programadores (muchas veces con cliente y usuarios).
Cada una de nuestras pruebas deben ejecutarse independientemente de las otras, en nuestro esfuerzo de hacer que las pruebas se ejecuten independientemente, mejoramos el diseño del software, por ejemplo, una prueba unitaria corre dentro de un ambiente que no es real, se ejecuta sobre lo que llamamos test fixtures y sus dependencias (muchas de las cuales serán código de producción) deben ser lo bastante flexibles de tal manera que permitan ser sustituidas, invocadas y verificadas fácilmente. Esto permite crear un software con alta cohesión y bajo acoplamiento, es decir, con un buen diseño y una buena arquitectura.
Nuestros diseños deben consistir en muchos componentes altamente cohesivos y débilmente acoplados, solo para facilitar las pruebas.
Kent Beck
El código de pruebas debe desarrollarse con la más alta calidad posible, deben ser fácil de entender y fácil de ejecutar de manera independiente, y al enfocarnos en este aspecto, el código de producción creado también resulta de la más alta calidad posible. Sin perder de vista que esto sucede paso a pasito, en un proceso enfocado a la simplicidad, iterativo e incremental.
El resultado de un buen diseño, también resulta en que las modificaciones de código se hacen mucho más rápido, y esto quiere decir que no necesitas quedarte horas extras programando, tendrás más tiempo personal, que puedes compartir con tu familia, hijos, con tu pareja (o amante), etcétera.
TDD elimina el miedo a modificar el código
¿Por qué la mayoría de los programadores tienen miedo de hacer cambios a su código? ¡Tienen miedo de romper el código! ¿Por qué tienen miedo de romper el código? Porque no tienen pruebas.
Las pruebas son más importantes que el código de producción porque permiten que el sistema se vuelva flexible, de otra manera el miedo a la modificación del código crece, porque se teme romper la funcionalidad, y entonces el software ya no es adaptable, poco a poco, entre más evoluciona, menos flexible se vuelve por miedo a realizar modificaciones que rompan el producto.
¿No te ha pasado en algún proyecto, donde necesitas hacer unas modificaciones al código, y existen partes que mejor ni las tocas por miedo de romper alguna funcionalidad?, porque realmente no estás seguro de lo que esa parte del código hace y no tienes un conjunto de pruebas que respalde tus cambios.
¿Qué es código legacy?
Codigo que los programadores tienen miedo cambiar
Eli Lopia CEO de typemock
Código sin pruebas
Michael C. Feather
TDD permite mitigar el miedo de modificar tu código o el de otra persona. ¿Cómo puedes tener seguridad de que las funcionalidades que desarrollas tienen la calidad suficiente para decir que está terminado? Sin un conjunto de pruebas no tienes esa seguridad, y como ya hemos comentado antes, esperar retroalimentación hasta el ciclo de pruebas de un equipo de QA, es demasiado tarde.
Cuando se tiene un buen conjunto de pruebas, no tienes miedo de hacer los cambios necesarios, porque si rompes algo, las pruebas te lo advierten casi en tiempo real mientras estás realizando las modificaciones.
Individuos e interacciones sobre procesos y herramientas
Manifiesto ágil
Segun Ken Beck el miedo tiene los siguientes efectos, te hace:
Inseguro sobre el código que escribes
Querer comunicar menos
Tímido a la retroalimentación
Gruñón
Ningún efecto de arriba es de ayuda a la hora de programar y menos cuando nos enfrentamos a un problema complicado. Así que Kent Beck recomienda los siguientes puntos usando TDD:
En lugar de dudar de tu código, empieza a aprender cosas concretas lo más rápido posible. Paso a pasito, lotes pequeños y de manera iterativa e incremental con el ciclo red-green-refactor.
En lugar de quedarte callado, comunícate más claramente. Al usar TDD aumentas la calidad y por consiguiente estás dispuesto a comunicar dudas o problemas que enfrentas a la ahora de programar
En lugar de evitar retroalimentación, busca ayuda, y retroalimentación concreta.
(Sobre lo gruñón, estas por tu cuenta). Pero con más seguridad en tu código, menos problemas y más tiempo personal, seguro que tu nivel de gruñón bajará.
TDD como documentación precisa
Software funcionando sobre documentación extensiva
Manifiesto ágil
Para tener una documentación detallada es necesario mucho tiempo y esfuerzo porque la documentación siempre cambia conforme se le agregan nuevas funcionalidades o se modifican las ya existentes. Entonces ese tiempo y esfuerzo mejor se invierte en obtener software funcionando que puede ser presentado al cliente y obtener retroalimentación. Es muy difícil mantener sincronizada la documentación con el verdadero funcionamiento (con el código), con el tiempo la documentación miente sobre la funcionalidad, la única fuente de verdad es el código, el código no miente.
La mejor documentación e instrucciones de como funciona una pieza del sistema se encuentran en las personas y el código que ellas crean. Es de valor inigualable poner énfasis en la excelencia técnica y al buen diseño para mejorar la agilidad, es decir, código limpio, bien diseñado y utilizando TDD y BDD. De esta forma no necesitas llegar al detalle de alguna pieza del sistema, simplemente la usas con seguridad del resultado debido al buen diseño y a la calidad de la misma, lo que por supuesto te ahorra muchísimo tiempo. Claro que esto no se puede lograr sin las personas, sin su disciplina y auto organización.
Para ponerlo más claro, cuando tienes la disciplina de hacer TDD, cada una de las pruebas que creas, describe perfectamente como cada función o método, clase y/o componente se utiliza, de una manera tan precisa que si algo va mal cuando se está modificando, al menos una de las pruebas fallara casi al instante.
Cuando realizas pruebas de métodos y funciones, tienes que describir que parámetros reciben y que resultados regresan ¿Qué más documentación necesitas? Tampoco digo que nunca se haga documentación, claro que si, pero es una inversión de tiempo, dinero y esfuerzo, que puedes disminuir considerablemente y que puedes posponer hasta las etapas más estables del producto, cuando se sabe que su funcionalidad cambiará poco o en intervalos más largos de tiempo.
Al final, como programadores, siempre nos aseguramos o solo confiamos al 100% sobre como funciona cualquier API de software hasta que le echamos un ojo al código y lo probamos. Y sería estupendo que la funcionalidad del código esté descrita detalladamente a través de un conjunto de pruebas.
El modelo o mapa de como vemos el mundo real, eso es un paradigma, es una manera de ver y hacer las cosas. Siguiendo esta lógica, un paradigma de programación no es más que una forma de ver y crear código de programación.
Los paradigmas son poderosos porque crean los cristales o las lentes a través de los cuales vemos el mundo.
Existe tres principales paradigmas de programación utilizados en la actualidad y que en JavaScript siempre han existido desde su primera versión.
Paradigma de programación Estructurada
Orientada a objetos
Funcional
Ahora bien, si nos apegamos a la frase de Stephen R. Covey, sobre que los paradigmas crean las lentes a través de los cuales vemos el mundo. Imaginemos que los tres paradigmas anteriores, cada uno, son un par de lentes que nos ponemos a la hora de programar y que podemos cambiar esos lentes según nuestras necesidades visuales (de programación o solución de problemas).
Paradigma de programación estructurada
Origen
En el año 1954 apareció el lenguaje de programación FORTRAN, luego en 1958 ALGOL y en 1959 COBOL. Tiempo después Edsger Wybe Dijkstra en 1968 descubre el paradigma de programación estructurada, decimos que “descubre” porque en realidad no lo inventaron. Aunque este paradigma de programación se formalizó tiempo después de la aparición de estos lenguajes de programación, era posible hacer programación estructurada en ellos.
Dijkstra reconoció que la programación era difícil, y los programadores no lo hacemos muy bien, de lo cual estoy totalmente de acuerdo. Un programa de cualquier complejidad tiene muchos detalles para el cerebro humano. De hecho la neurociencia nos indica que la mente enfocada solo puede trabajar con cuatro datos a la vez, cuanto mucho. Por esta razón, si se descuida un pequeño detalle creamos programas que parecen funcionar bien, pero que fallan en formas que uno nunca se imagina.
Pruebas
La solución de Dijkstra fue utilizar pruebas, solo que estas pruebas usaban mucho las matemáticas, lo cual era bastante difícil de implementar. Durante su investigación encontró que ciertos usos de GOTO hacían difícil descomponer un programa grande en piezas más pequeñas, no se podía aplicar “divide y vencerás”, necesario para crear pruebas razonables.
Secuencia, selección e iteración
Böhm y Jacopini probaron dos años antes que todos los programas pueden ser construidos por solo tres estructuras: secuencia, selección e iteración. Dijkstra ya conocía estas tres estructuras y descubrió que estas mismas son las necesarias para hacer que cualquier parte del programa sea probado. Es aquí donde se formaliza el paradigma de programación estructurada.
Edsger nos indica que es una mala práctica usar GOTO y sugiere usar mejor las siguientes estructuras de control:
If, then, else (selección)
do, while, until (iteración o repetición)
Descomposición de pequeñas unidades fáciles de probar
Hoy en día la mayoría de los lenguajes de programación utilizan la programación estructurada, JavaScript utiliza este tipo de programación. El ejemplo más sencillo son las condiciones if.
const EDAD_MINIMA =18;if (edad >= EDAD_MINIMA) {// hacer algo porque es mayor que 18}else{// Hacer otra cosa en caso contraio}
Y si lo aislamos en una función, tenemos una descomposición de funcionalidades o unidades que pueden ser probadas con mayor facilidad. En la siguiente sección veremos la importancia de tener una unidad completamente probable
Con esta condición tenemos un control directo de lo que puede suceder si la edad es mayor o igual a 18, y también en el caso de que la edad sea menor.
Tampoco seamos tan estrictos, seguro que la sentencia GOTO tiene sus méritos y tal vez era muy eficiente en algunos casos, pero pienso que para evitar malos usos que probablemente causaban desastres, Dijkstra recomendó dejar de usar GOTO.
Pruebas, divide y vencerás
La programación estructurada nos permite aplicar la filosofía de “divide y vencerás”, porque nos permite crear pruebas de pequeñas unidades, hasta tener todo el programa cubierto. La solución matemática de Wybe Dijkstra nunca se construyo, precisamente por su dificulta de implementación. Y lamentablemente en nuestros días aún existen programadores que no creen que las pruebas formales sirven para crear software de alta calidad.
Y digo crear, porque verificar el correcto funcionamiento después de crear, no es más que una simple medición y se pierde la oportunidad de reducir tiempo y dinero.
Método científico, experimentos e impirismo
La buena noticia es que el método matemático no es la única forma de verificar nuestro código, también tenemos el método científico. El cual no puede probar que las cosas sean absolutamente correctas desde el punto de vista matemático. Lo que si se puede hacer es crear experimentos y obtener resultados suficientes para verificar que nuestras teorías funcionan. Dado que nuestras teorías funcionan sobre estos experimentos, entonces concluimos que son lo suficientemente “correctas” para nuestros propósitos de validación.
Si la teoría es fácilmente validada como falsa, entonces es momento de modificarla o cambiarla. Así es el método científico y así es como actualmente se hacen las pruebas:
Primero establecemos nuestra teoría (escribimos la prueba), después construimos los experimentos (escribimos código de producción) y finalmente verificamos (corremos la prueba) y repetimos este ciclo hasta tener evidencia suficiente.
Las pruebas muestran la presencia, no la ausencia, de defectos
Edsger Wybe Dijkstra dijo “Las pruebas muestran la presencia, no la ausencia, de defectos”. Ósea, un programa puede ser probado incorrecto mediante pruebas, pero no puede ser probado correcto. Todo lo que podemos hacer con nuestras pruebas es validar que nuestro programa funciona lo suficiente bien para nuestros objetivos. Pero nunca podemos estar cien por ciento seguros de la ausencia de defectos.
Si nunca podemos estar cien por ciento seguros que nuestro código es correcto, aun con sus pruebas, ¿Qué nos hace pensar que sin pruebas entregamos un programa con la suficiente validez para afirmar que no se comete conscientemente alguna negligencia?
El control directo
La programación estructurada nos enseña sobre el control directo, es decir, controlar el flujo secuencial de las operaciones a través de las estructuras de control, sin descuidar la recomendación de Wybe Dijkstra sobre GOTO. Esta recomendación también es aplicable a sentencias que cambian drásticamente el flujo normal de las operaciones, por ejemplo un breakdentro de un ciclo for anidado, ese breakrompe el control directo porque complica abruptamente el entendimiento del algoritmo. Tampoco seamos puristas, seguro habrá casos que necesites de estas sentencias, pero de primera instancia, trata de evitarlas.
En conclusión, el paradigma de programación estructurada nos enseña:
El control directo, claro y explicito de lo que hace un pedazo de código
Paradigma de programación orientada a objetos
¿Surgido de funciones?
El paradigma de programación orientada a objetos se descubrió en 1966 por Ole Johan Dahl y Kristen Nygaard cuando desarrollaban simula 67. Dos años antes de la programación estructurada y su adopción por la comunidad de programadores fue tiempo después. En 1967 se lanzó Simula 67, Simula fue el primer lenguaje de programación orientado a objetos, básicamente le agregó clases y objetos a ALGOL, inicialmente Simula iba a ser una especie de extensión de ALGOL.
Durante el desarrollo de Simula, se observó que la ejecución de una función de ALGOL necesita de ciertos datos, los cuales se podían mover a una estructura de árbol. Esta estructura de árbol es un Heap.
La función padre se convierte en un constructor, las variables locales se convierten en las propiedades y las funciones hijas (anidadas) en sus métodos. De hecho este patrón es aún muy utilizado por Javacript para crear módulos y usar herencia funcional. También esto describe como funcionan las clases en Javascript, por detrás son funciones.
Esparcimiento del polimorfismo
Todo esto ayudó mucho a que se implementará el polimorfismo en los lenguajes de programación orientados a objetos. Ole Johan Dahl y Kristen Nygaard inventaron la notación:
objeto.funcion(parametro)
La ejecución de funcion que pertenece a objeto, pero más importante, le pasamos un mensaje a través de parámetros desde la primera parte del código a la segunda parte localizada en un objeto diferente.
La biología molecular y el paso de mensajes
Tiempo después se creó Smalltalk, un lenguaje de programación orientado a objetos mucho más sofisticado y moderno, a cargo de este proyecto estaba Alan Kay. A esta persona se le atribuye la definición formal de la programación orientada a objetos.
La principal influencia en la programación orientada objetos de Alan Kay fue la biología, él es licenciado en biología. Aunque es obvio que fue influenciado por Simula, la influencia de LISP (lenguaje de programación funcional) no es tan obvia.
Desde un inicio él pensaba en los objetos como células interconectadas en una red, de la cual se podrían comunicar mediante mensajes.
Alan Kay comentó lo siguiente:
Lamento que hace tiempo haya acuñado el término Objetos para la programación porque hizo que las personas se enfocaran en la parte menos importante. La gran idea es “Envío de mensajes“.
Alan Kay
Mi Ingles es malo así que pueden revisar el texto original aquí.
Mejor composición de objetos sobre herencia de clases
Smalltalk permitió también la creación de Self, creado en Xerox Parc y luego migrado a Sun Microsystems Labs. Se dice que Self es una evolución de smalltalk.
En este lenguaje de programación se introdujo la idea de prototipos, eliminando la utilización de clases para crear objetos, este lenguaje utiliza los objetos mismos para permitir que un objeto reutilice las funcionalidades de otro.
Self es un lenguaje rápido y en general se le conoce por su gran rendimiento, self hizo un buen trabajo en sistemas de recolección de basura y también utilizaba una maquina virtual para administrar su ejecución y memoria.
La máquina virtual Java HotSpot se pudo crear gracias a Self. Lars Bak uno de los últimos contribuidores de Self, se encargó de la creación del motor de Javascript V8. Debido a la influencia de Self tenemos hoy en día el motor de JavaScriptV8, el cual lo utiliza node.js, mongoDB yGoogle Chrome internamente.
Self seguía una de las recomendaciones del libro Design Patterns: Elements of Reusable Object-Oriented Software, mucho antes de que saliera publica esta recomendación:
Mejor composición de objetos a herencia de clases.
Design Patterns: Elements of Reusable Object-Oriented Software
Ejemplo
Actualmente Javascript utiliza prototipos para la reutilización de código, se podría decir que usa composición, en lugar de herencia. Veamos un ejemplo:
const persona ={saludar(){return'Hola'}};// se crea un programador con el prototipo igual al objeto personaconst programador = Object.create(persona);programador.programar=()=>'if true';const saludo = programador.saludar();const codigo = programador.programar();console.log(saludo);// 'Hola'console.log(codigo);// 'if true'
El objeto programador se basa en el prototipo de `persona`. No hereda, solo reutiliza directamente la funcionalidad de `persona`.
JavaScript surge poquito después de JAVA, en el mismo año. JavaScript tomo influencias de Self, y a su vez Self fue influido por smalltalk.
La sintaxis de clases actuales en Javascript no es más que una fachada, bueno un poco más exacto son una evolución de las funciones constructoras, pero internamente, su base, son las funciones y los prototipos.
La comunicación con el paso de mensajes
Como ya vimos, el origen de la programación orientada objetos tiene su origen en las funciones, y la idea principal siempre ha sido la comunicación entre objetos a través del paso de mensajes. Podemos decir que La programación orientada a objetos nos habla del paso de mensajes como pieza clave para la comunicación de objetos, por ejemplo, cuando un método de un objeto invoca el método de otro.
objeto.funcion(parametro);
En conclusión, el paradigma de programación orientado a objetos, nos enseña:
El paso de mensajes para la comunicación entre objetos
Paradigma de programación funcional
Cálculo lambda
La programación funcional es el paradigma de programación más viejo, de hecho su descubrimiento fue mucho antes de la programación para computadoras, fue descubierto en 1936 por Alonzo Church, cuando invento el cálculo lambda, base del mismo problema a resolver de su alumno Alan Turing.
Como dato curioso el símbolo del cálculo lambda es:
λ
El primer lenguaje basado en programación funcional fue LISP, creado por John McCarthy. Como vimos anteriormente, Alan Kay también tomo influencias de LISP para crear Smalltalk, con esto podemos comprobar que los paradigmas de programación pueden estar unidos y su relación entre ellos surge de la idea de como resolver problemas de manera más eficiente, no están peleados, ni separados, buscan el mismo objetivo y de alguna manera evolucionan en conjunto.
La base del cálculo lambda es la inmutabilidad,más adelante revisaremos este concepto.
Similitudes con los paradigmas OO y estructurada
Como vimos en el paradigma de programación estructurada, podemos descomponer nuestros programas en unidades más pequeñas llamadas procedimientos o funciones. Dado que la programación funcional es el paradigma más viejo, podemos decir que el paradigma de programación estructurada también se apoya en la programación funcional.
Ahora bien, si analizamos un poco la notación objeto.funcion(x) que vimos en la sección del paradigma de programación orientada a objetos, no es muy diferente de funcion(objeto, parametros), estas dos lineas de abajo son iguales, la idea fundamental es el paso de mensajes, como nos indica Alan Kay.
Smalltalk usa el “El Modelo Actor”, el cual dice que los actores se comunican entre ellos a través de mensajes.
Por otro lado tenemos a LISP, el cual tiene un “Modelo despachador de funciones” que actualmente le llamamos lenguaje funcional, estos modelos son idénticos, porque las funciones y métodos lo que hacen es enviar mensajes entre actores.
Un ejemplo de esto es cuando una función llama a otra función o cuando se invoca el método de un objeto, lo que sucede es que existen actores y se comunican entre ellos a través de mensajes.
De nuevo el paso de mensajes
Entonces podemos recalcar que la idea principal de la POO es el envío de mensajes y que no es muy diferente de la programación funcional, de hecho según lo que ya establecimos en las secciones anteriores, POO nació de una base funcional. Y aquí es importante remarcar lo que dijo Alan Kay Co-creador de SmallTalk:
Lamento que hace tiempo haya acuñado el término Objetos para la programación porque hizo que las personas se enfocaran en la parte menos importante. La gran idea es “Envío de mensajes“.
Alan Kay
A partir de los modelos de comunicación entre mensajes de Smalltalk y LISP, se creó Scheme.
Scheme tiene la bondad de usar Tail recursion y closure para obtener un lenguaje funcional, closure permite tener acceso a las variables de una función externa aun cuando esta ya haya regresado algún valor. Esto es el mismo principio que origino a la programación orientada a objetos a cargo de Ole Johan Dahl y Kristen Nygaard. ¿Recuerdan la pregunta de closure en Javascript?
Javascript usa mucho closure en su paradigma de programación funcional. JavaScript tomó influencias de Scheme, a su vez Scheme fue influido por LISP.
Sin efectos colaterales
La base del cálculo lambda es la inmutabilidad, por consiguiente, la inmutabilidad también es la base del paradigma de programación funcional.
Nosotros como programadores funcionales debemos seguir este principio y limitar las mutaciones de objetos lo más que se pueda para evitar efectos colaterales.
Repito, la idea principal de la programación funcional es la inmutabilidad, la cual te permite crear tus programas con menos errores al no producir efectos colaterales difíciles de controlar.
Como ejemplo, supongamos que tenemos un objeto persona y queremos “cambiar” el nombre, lo más obvio seria modificar la propiedad nombre directamente, pero que pasa si ese objeto es utilizado en otra parte y se espera que nombre sea “Jaime”, es por eso que en lugar de cambiar la propiedad nombre, solo creamos un nuevo objeto persona con diferente nombre, sin modificar el original.
Por último, el paradigma de programación funcional nos enseña:
Sin efectos colaterales, para una expresión clara y menos propensa a errores
Conclusión
Es importante destacar que si los tres paradigmas de programación fueron implementados entre los años 1958 con LISP (programación funcional) y Simula (programación Orientado a objetos) en 1966, y el descubrimiento del paradigma de programación estructurado en 1968, en solo un lapso de 10 años existió la innovación de los paradigmas de programación, y realmente nuevos paradigmas no han surgido, al menos que no sean basados en estos tres principales.
Ahora mismo ya han pasado más de 60 años, lo que nos dice de la importancia y la firmeza que tienen a pesar del tiempo transcurrido.
Paradigma de programación funcional (1958, ya implementado en un lenguaje de programación para computadoras, recordemos que fue descubierto en 1936)
Orientado objetos (1966)
Estructurada (1968)
La implementación de estos tres paradigmas desde el inicio en el interior de JavaScript han hecho que este lenguaje de programación tenga el éxito global de hoy en día. Y nos comprueba lo valioso de combinar los paradigmas al escribir nuestros programas.
JavaScript es en lenguaje de programación multiparadigma, por lo que se puede combinar los paradigmas para crear un código mucha más eficiente y expresivo usando:
El control directo, claro y explicito de lo que hace un pedazo de código
El paso de mensajes para la comunicación entre objetos
Sin efectos colaterales, para una expresión clara y menos propensa a errores
La programación en parejas es una práctica ágil donde dos personas trabajan en una sola computadora para resolver un problema. La programación en pareja abre un canal de comunicación y retroalimentación inmediata entre dos personas, para analizar, diseñar, probar y crear una solución utilizando código de programación.
¿Cuántas veces no hemos necesitado ayuda para resolver un problema?
¿Para lavar los trastes? – Oye, dejaste jabón en esa parte, – El plato tiene una manchita ahí.
También cuando manejamos un automóvil, nuestro copiloto nos dice:
Dobla a la derecha, este camino es más corto.
¡Aguas de este lado viene carro! ¡Ahí hay un bache!
Aquí es donde otra persona y dos ojos más entran en acción.
Desde un inicio, desde que existe la interacción social, siempre se busca simplificar las tareas y hacerlas con la mejor calidad posible. Como vemos en la sección anterior, el trabajo en pareja siempre ha existido y da muy buenos resultados.
Un cazador enseña a su hijo como cazar una cebra y le indica que el mejor lugar para clavarla es justo debajo de la oreja, donde puede atravesar su cráneo, pero ese es un tiro muy difícil. El tiro más fácil es – “Apuntar a las rayas que la cebra tiene en el pecho” (mientras dibuja las rayas en el tronco de un árbol).
– “Sigue practicando el tiro a una distancia de 20 pasos hasta que claves la lanza correctamente”, luego -“No espera, sostén la lanza así”, más tarde – “Si, así está mejor, continua así” … – “Ahora, pídele a tu tío que te enseñe cómo hacer que la cebra se acerque a una distancia de 10 pasos”
Betty Snyder y yo, desde el principio, éramos una pareja. Y creo que el mejor diseño y todas esas cosas son hechas en pareja porque mutuamente se puede criticar, identificar errores y usar las mejores ideas de ambos.
Betty Jean Jennings Bartik, ENIAC programmer 1946
Jean Bartik formó parte de las ahora justamente reconocidas primeras programadoras de ENIAC, donde según fuentes también practicaban “Test First development”.
Frederick Phillips Brook, 1953
Fred Brook, autor del libro The Mythical Man-Month: Essays on Software Engineering del año 1975, un libro sobre ingeniería de software y administración de proyectos. También conocido por la ley de Brook, la cual empezó a definirla cuando trabajaba para IBM en el desarrollo del sistema operativo OS/360. En este libro él menciona lo siguiente:
Agregar mano de obra a un proyecto de software retrasado, lo retrasa aún más.
Frederick Phillips Brook
Brook le escribió a Laurie Williams:
Compañero de posgrado Bill Wright y yo probamos por primera vez la programación en parejas cuando era un estudiante graduado (1953 -1956). Produjimos 1.500 líneas de código libre de defectos; se ejecutó correctamente en el primer intento.
Frederick Phillips Brook
Richard P. Gabriel en 1972
1972-1973, Dick Gabriel hace programación en pareja con Jonl White, usando Lisp como lenguaje de programación. Después como encargado del desarrollo de Common Lisp, programación en parejas fue una de las prácticas principales.
Dynamic Duos, 1978-1988
Larry Constantine, pionero en la ingeniera de software, con más de 200 publicaciones y 22 libros. Reporto en su visita a Whitesmiths Inc. que en cada terminal había dos programadores trabajando. Le llamó “Dynamic Duo”, Whitesmiths creó el primer compilador comercial del lenguaje de programación C.
“Las personas a veces sienten que pueden resolver un problema solo si tienen ayuda. Algunos problemas son más grandes que los de cualquier individuo”. La solución propuesta del patrón organizacional es “emparejar diseñadores compatibles para trabajar juntos; …
James Coplien
El proyecto Pasteur extrajo muestras empíricas de 50 organizaciones de desarrollo de software altamente efectivas, usando técnicas de análisis y recopilación de datos similares a las usadas por sociólogos y antropólogos.
Finalmente Kent Beck, unos de los firmantes del manifiesto ágil, creador de programación extrema y de sus propias palabras, el “redescubridor de TDD” en 1998 agregó “pair programming” como una de las prácticas de Extreme Programming.
Beneficios de programación en parejas
Todos los beneficios de más abajo se resumen en los tres principales aquí listados, que desde el punto de vista de negocio, son el objetivo de implementar cualquier práctica ágil.
Disminuir los tiempos
Reducir el Estrés
Aumentar el Dinero o las ganancias
Además estos beneficios son el resultado de aplicar los siguientes principios ágiles:
Individuos e interacciones sobre procesos y herramientas.
Respuesta ante el cambio sobre seguir un plan.
Software funcionando sobre documentación extensiva.
Canal de comunicación y colaboración
Se abren muchos canales de comunicación (más si se rotan las parejas) que estimulan la colaboración. Si combinamos diferentes perspectivas, ideas, conocimiento técnico y conocimiento del negocio, entonces el resultado es una solución superior, una solución más simple y más sólida. Sin mencionar que el tiempo en llegar a una solución se reduce considerablemente.
Muchísimas veces ni siquiera tenemos que esperar a que nuestra prueba falle o esperar a debuguear para notar un error, nuestro compañero con su lindo cerebro y sus dos ojos nos lo puede indicar de inmediato.
Incluso ni siquiera tenemos que recordar la especificación del problema a resolver (por eso de la pérdida de enfoque), porque tenemos otra mente que nos lo recuerda.
Code Review Continuo
Cuando se está programando en pares se obtiene retroalimentación inmediata de nuestro compañero, vamos a llamarle “code review instantáneo”. Así que actuamos ante ese cambio de idea, perspectiva, mejora, error cometido, cualquier cosa que nos ayude a resolver el problema o mejorar la solución.
Te falta un punto y coma.
¿No te falto definir la variable que contiene los datos de tu parámetro?
Ahí debe ser un string no la referencia al método
Son frases que he escuchado mucho antes de ejecutar la verificación de la prueba, el feedback o review lo obtengo aún mucho más rápido que la prueba automatizada. Esto en realidad es un ciclo de retroalimentación más eficiente.
Esparcir el conocimiento técnico y de negocio
Transferencia de conocimiento, siempre existe algo que aprender del compañero, tanto del entendimiento del problema y el negocio, como técnicamente.
Esparcimiento y homologación del estándar y estilo de programación definido por el proyecto.
Si un integrante del equipo se va, no importa, todos los demás tienen contexto y el conocimiento adecuado.
Mucho menos tiempo descubriendo lo que hizo el excompañero
Los nuevos integrantes del equipo obtienen el conocimiento y el contexto rápidamente de los compañeros con más tiempo en el proyecto, preguntando y haciendo programación en parejas.
Aumento en la calidad del producto
Si solo armas lo primero que piensas, nunca tendrás tiempo para pensar en una segunda cosa mejor.
Kent Beck
Diferentes perspectivas que ayudan a encontrar una solución mucho más simple. Esto significa menos tiempo desarrollando, las soluciones simples son mucho más sustentables, es más fácil comprenderlas, implementarlas en otros lugares/casos, modificarlas y mejorarlas. Siguiendo el principio ágil de “Simplicidad, el arte de maximizar el trabajo no realizado”.
Combinación de ideas y creatividad para mejorar la solución. Casi siempre el desarrollo de cualquier cosa que usa dos mentes, resulta en un diseño superior. Y este punto se relaciona mucho con el siguiente principio ágil. “La excelencia técnica y el buen diseño, mejoran la agilidad”.
Utilizar cada pieza del sistema como una verdadera caja negra, debido a un diseño superior creado por dos mentes, porque es simple y de mayor calidad, nos ahorra tiempo revisando los cables detrás de una funcionalidad. Nos permite enfocarnos en el problema y no como funcionan las piezas necesarias.
Disminuye la necesidad de documentación en etapas tempranas de desarrollo. Por que el conocimiento se esparce, la documentación pierde sentido en etapas tempranas, una documentación solo funciona cuando se tiene una versión muy estable de una pieza de software, no queremos perder el tiempo en modificar la documentación cada vez que cambiamos algo en el código.
Lo recomendado es invertir ese tiempo en tener un conjunto de pruebas automatizadas y claramente diseñadas, enfocándose en transmitir de manera transparente los requerimientos, que sean fácilmente entendidos en la primera lectura. No necesitamos documentación que nos dé una especificación desactualizada o errónea. Al hacer pruebas y mejor aún, “test-first developement” en pareja, aumenta considerablemente la calidad.
Ahorra tiempo, mayor velocidad
En lugar de pasar una hora atorado haciendo una tarea individual, en pareja muchas veces lo resuelven en cinco minutos. ¿Nunca te ha pasado que estás atorado durante dos horas, luego te vas a dar una vuelta, regresas y en menos de cinco minutos encuentras la solución? Pues en pareja no necesitas esperar esas dos hora e irte a dar una vuelta, tu compañero podría tener la solución o conversándolo con él en conjunto cristalizan una aún mejor.
El tiempo que te sobra lo ocupas para todavía hacer más.
Debido al beneficio de esparcir el conocimiento, aceleramos el nivel técnico y de negocio de los nuevos integrantes.
Por el aumento de calidad ya explicada, las integraciones son más rápidas, se resuelven, es más rápido modificar funcionalidades e implementar nuevas por la simplicidad de las mismas.
Reduce el Estrés
Entre menos tiempo pases trabajando tendrás menos estrés y una mente fresca y creativa (comprobado científicamente). Por lo cual tus tareas las resolverás más rápido, con ganas y con orgullo. Tendrás más tiempo después de tus horas de trabajo para estar con la familia, con la novia o esposa, o simplemente hacer tus cosas personales
Ahorra dinero
Es bueno para el negocio, entregas más rápidas, iteraciones con mayor alcance y por supuesto mejor retorno de inversión por la calidad del software y la flexibilidad de adaptarse a las nuevas necesidades del usuario final (por el diseño superior creado en pareja).
¿Como hacer programación en parejas?
Existen varias formas de usar la programación en parejas, los más usados y simples son:
Driver y navigator
Ping Pong
Driver y navigator
Se tiene dos perspectivas en cuanto al código.
El driver es la persona que controla la computadora y escribe el código, el navigator sentado a su lado observa el proceso desde otra perspectiva, revisando cada línea de código mientras el driver escribe, al mismo tiempo que apoya al driver dándole dirección y desbloqueándolo.
Una persona se encarga de la táctica (driver) y la otra de la estrategia (navigator).
Es importante cambiar los roles continuamente, así mitigamos el aburrimiento y cambiamos de perspectiva para tener ideas frescas.
El navigator puede anotar sus ideas para no cortarle la inspiración al driver, estas ideas se pueden mencionar cuando el driver termine de escribir el código que tenía en su mente.
Según la neurociencia, la programación en parejas une dos tipos de pensamientos. El driver trabaja en un modo de pensamiento enfocado, mientras que el navigator trabaja con un modo de pensamiento difuso.
Porque ahora tenemos dos mentes, podemos separar estas dos perspectivas y utilizarlas al mismo tiempo.
Ejemplo de esto es lo que ya comentamos, cuando estás atorado con un problema por dos horas, te vas a dar una vuelta, tomar café o algo y regresas, te sientas enfrente de tu computadora y en cinco minutos lo resuelves.
Ping pong
El primer developer escribe la próxima prueba
El segundo developer hace pasar la prueba y escribe la próxima prueba
El primer developer hace pasar la prueba
Después de que alguno de los programadores hace pasar la prueba, ambos hacen el refactor utilizando driver y navigator.
Esta es una técnica bastante sencilla y útil para cambiar frecuentemente entre driver y navigator, así ambos programadores practican ambos modos de pensamiento. Fomenta la creatividad y el uso de prácticas ágiles como TDD y BDD.
¿Cuánto cuesta hacer programación en parejas?
Uno puede pensar que el costo de hacer programación en parejas es el doble debido a que dos personas trabajan para completar una sola tarea, pero no es así, según estudios realizados por Laurie Williams en el año 1999 en la universidad de Utah, haciendo programación en parejas solo aumentó un 15% de tiempo para completar la tarea.
Ese 15% de tiempo gastado fue recuperado en un código con 15% menos defectos.
Según este estudio el código generado individualmente es 15 veces más costoso debido al mayor esfuerzo de arreglar los defectos. Luego si ese defecto se filtra a producción, entonces el costo es 60 veces más.
¿Por qué es más costoso el desarrollo con programadores individuales? Porque el diseño individual es inferior a un diseño creado por dos personas. Dos cabezas son mejor que una.
Este resultado se alinea con la filosofía de prevención de incidencias y que entre más tiempo pasa en encontrar el defecto, es más costoso porque primero se tiene que volver a replicar, entender el problema, entender el código relacionado y además el tiempo gastado en la solución. ¿Qué pasa si es un defecto que se detecta después de un año? ¿Qué pasa si la persona con más conocimiento del contexto ya no está en el proyecto o no está disponible?
¿Y si tenemos un equipo distribuido? ¿Cómo hacemos programación en pareja?
En la actualidad existen muchas aplicaciones de videollamadas para compartir pantallas, IDEs con extensiones o plugins y hasta aplicaciones para compartir el control de tú maquina que te permiten tener una colaboración en tiempo real sobre el código en cuestión.
Jeff Dean y Sanjay Ghemawat. Super reconocidos en google porque salvaron a la empresa de morir, arreglaron el enorme crawler de google que había parado de funcionar en el año 2000. Han creado juntos en google a mapReduce, BigTable y Spanner. Y muchas cosas más fuera de google.
Kent Beck (Co-creador principal de extreme programming) y Erich Gamma (co-autor del libro Design Patterns: Elements of Reusable Object-OrientedSoftware). Juntos crearon JUNIT el principal framework de automatización de pruebas para Java y también para Kotlin.
Alistair Cuckborn. Creador de la familia de métodos Crystal clear y Heart of agile
Ron Jeffries. Firmante del manifiesto ágil y co-creador de extreme programming
Ward Cunningham. Firmante del manifiesto ágil y co-creador de extreme programming
Martin Fowler. Firmante del manifiesto ágil y autor del libro Refactoring: Improving the Design of Existing Code
Robert C. Martin. Firmante del manifiesto ágil y conocido por acuñar los principios de diseño SOLID
Michael Feathers. Autor del libro Working Effectively with Legacy Code
No todo es color de rosa en la práctica
¿Cuándo no hacer programación en parejas?
Si la tarea es demasiada sencilla o algo repetitivo.
Cuando ninguno tiene mucho conocimiento del problema y/o código a modificar.
Mejor ambos se asignan tareas de investigación para retroalimentarse después y compartir ese nuevo conocimiento.
Cuando uno de los pares ya pasó mucho tiempo haciendo programación en parejas. Continuar haciéndolo por mucho tiempo es demasiado desgaste mental.
¿Cuánto tiempo hacer programación en parejas?
Definitivamente no 8 horas al día, mucho tiempo haciendo programación en parejas es muy cansado, según fuentes lo recomendado es de 1.5 a 4 horas diarias.
¿Qué tan a menudo cambiar de pareja?
Cada vez que se sienta la necesidad según el problema a resolver. Se recomienda cambiar de pareja diariamente para esparcir el conocimiento técnico y de negocio, pero si alguien aún no entiende un concepto con su pareja actual, entonces no debería cambiar de pareja hasta que tenga sólido ese concepto.
Recomendaciones de interacción social
Super importante tener como base siempre estos tres principios humanos latentes en cada momento para las interacciones sociales.
Respeto, de hecho un valor de scrum y extreme programming.
Honestidad, alineado con la transparencia del empirismo de scrum y el coraje en extreme programming.
Justicia, es justo pensar en el bienestar de todas las personas involucradas. Da el coraje (otro valor de scrum y XP) de hacer programación en pareja y buscar acuerdos mutuos. Al mismo tiempo te hace pensar en lo más justos para ambos, como pareja.
Las personas importan
Piensa en tu compañero, lo más importante son las personas, actua de la forma mas justa posible para entablar comunicacion y acuerdos.
También ponte en los zapatos de los usuarios finales, ¿Querrías tener problemas si fueras tú el que usa la aplicación? Esto ayuda a tener una mente positiva y darnos el coraje de hacer pair programming por el bien de todos. Genera Compromiso y justicia hacia los involucrados.
Tres hábitos para la comunicación y no estancarse.
Piensa en ganar/ganar. A veces puede haber conflictos de ideas, piense en lo más importante, las personas, todos pueden salir ganando, en lugar de perder mucho tiempo debatiendo ¿Por qué no prueban ambas ideas? Paso a paso se darán cuenta de lo mejor para el problema o muchas veces son una combinación de las dos posturas.
Procura primero comprender y después ser comprendido.
Cuando se debaten ideas debemos entender profundamente la otra idea, escuchar con la verdadera intención de comprender. Un buen doctor primero hace un diagnóstico antes de dar una receta.
Ahora tu turno de exponer tu idea.
Sinergizar. Encontrar la solución juntos, tu idea en combinación con la mía genera una mejor, 1 + 1 = 3, 4 o 5, de esas dos ideas sale una tercera, una superior.
Reitero, si el debate sobre las ideas se está alargando, es mejor elegir un término medio y empezar a tirar código, conforme avancen verán por cuál idea se inclinan más.
Planifica
Tengan un horario de sesiones, con el objetivo de no solaparse con reuniones importantes. Con tu familia establece acuerdos y horarios para que tampoco te interrumpan a menos que de verdad sea algo importante.
Por ejemplo, si tu hijo quiere que juegues con él en el momento de la sesión de pair programming, aunque de verdad yo creo que jugar con tu hijo es más importante que trabajar, también podrías establecer con tu hijo los horarios de juego para que no se solapen con los horarios de trabajo.
Sin distracciones
Sin distracciones mientras se hace pair programming, respeta el tiempo de tu compañero y mantente enfocado en lo que están haciendo juntos, no leas emails, no veas mensajes de WhatsApp o de Facebook, trata de no hacer llamadas. Así eres justo con el tiempo de la otra persona.
Pomodoro
Es bueno tomar breaks cada veinticinco minutos o más dependiendo como se sientan y utilizar de cinco a diez minutos como recompensa para ahora si hacer lo que quieran, como revisar Facebook o el WhatsApp. Esto disminuye la fatiga y mantiene las ideas frescas porque constantemente te recompensas y le dices a tu cerebro que los próximos veinticinco minutos valen la pena.
Apertura
Mucho, mucho respeto a las ideas de tu compañero, no importa si tienes más experiencia o menos, recuerda que diferentes ideas y perspectivas nos llevan a mejores soluciones. El genio John Von Neumman pedía constantemente a sus compañeros que revisaran su trabajo.
Piensa en la crítica como algo que te ayude a mejorar.
Elimina el condicionamiento social
Normalmente se tiene la idea de que equivocarse es malo, de que no saber es herejía, al contrario, ser vulnerable en estos aspectos ayuda mucho a mejorar como individuo, como equipo y a mejorar el producto. Y todo el mundo debe estar consciente de esto, a no juzgar y abrazar las diferencias, las cuales son muy importantes a la hora de innovar porque diferentes perspectivas siempre nos permite construir una mejor forma de ver las cosas, lo que lleva a generar mejoras ideas y aumentar la creatividad.
La importancia de Celebrar
Celebren juntos después de terminar con una tarea, vayan a tomar un café, coman algo, jueguen un videojuego, que sé yo, el chiste que celebren. Esto promueve un mini team building y entrenan a su cerebro para no cansarse y tener pensamientos positivos para continuar. Ayuda al estrés.
De programación en parejas a Mob programming
Es una práctica ágil moderna que extiende la idea de pair programming a todo el equipo, donde se puede incluir todo tipo de involucrado en el producto. Desde programadores, administradores de base de datos, gente de diseño y experiencia de usuario, product owners, project managers, hasta clientes y usuarios.
Toda la gente brillante trabajando en lo mismo, al mismo tiempo, en el mismo espacio, en la misma computadora
Woody Zuill
Mob Programming es integración continua para ideas.