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.
Data types in Javascript are a little different compared to other programming languages like C or JAVA.
JavaScript is a weakly typed language, this means that it is not necessary to define the data type. But it is not that it does not have types, since the data type is defined at run time by Javascript.
This behavior and specification of data types applies to any place where javascript is executed, whether in the browser, in node.js, mongodb, or any tool that uses Javascript.
Now if we analyze the concept of types a little, when you make a sum between numbers in the real world you don't care what type it is, you only care that they can be added, regardless of whether it is an integer or decimal. These subtypes of numbers are still part of the set of real numbers, and are used in real life.
Javascript allows us to apply this thinking and with that we save many type comparisons. There will be times when we have no choice but to convert or compare them, but the less we do it, the simpler our code will be, and therefore easier to understand and faster to execute.
It is said that Javascript has a dynamic data type system, this is because the variables that are created can receive any other type of data at any time, and change type depending on the value they store. What we are really interested in is the value and what we can do with that value, not so much the type.
Later we will see some conversions and comparisons that can confuse and complicate the code, the recommendation is to reduce their use as much as possible. Although we will not see each type in great detail, we will see more important things necessary to use data types in Javascript.
It is useful to know how to define variables and constants, if you do not know how to create a variable or a constant, you can review this information before continuing.
Primitive data types
It is one that is not an object
It has no methods.
They are immutable
We have seven guysprimitive data in Javascript.
number, numbers like; 1, 0, 18500, 89.95124
BigInt, added in 2020, to represent very, very large integers, 99999999999999n
String, character string like 'Hello' and "Good night".
Boolean, only accept true either false, that is, yes or no.
null, serves to indicate that something is nothing, its only value is null.
undefined, serves to indicate that something is not yet defined.
symbol, added in 2015, with EcmaScript 6
Data Types Objects
All other data types in Javascript are objects. In the section Objects there is the explanation.
number
If I had written this before 2020, I would tell you that there is only one numeric data type, unfortunately (with some exceptions) a new numeric value called BigInt. In this section we will pretend that it does not exist.
number is a value 64 bit float, that is, it is a number double In other programming languages, this is basically the only numeric data type in JavaScript, there are no integers (except for BigInt), decimals, floats or doubles. Its specification is provided by IEEE-754.
The way to define and use them is very simple, you simply write the number, it does not matter if it is integer or decimal, floating point or double, as we mentioned before, all of these will be of type double for javascript. This is the recommended way to define them.
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
As we see in the last line, we can add integers and decimals without any problem, we are not interested in the type, we are interested in the ability to add them.
Float values are known to have a certain precision error when performing arithmetic operations, the most obvious operation being division.
0.2+0.1;// es igual a 0.30000000000000004
As we see, it does not give us an exact value of 0.3, to mitigate this you can multiply the values by 100 and then divide the result by 100.
(0.2*100+0.1*100)/100;// es igual a 0.3
NaN
There is a special number called NaN. This value is the error of an operation with numbers.
25*undefined;// es igual a NaN25*{};// es igual a NaN
Any operation you have NaN as one of its operands, will result in NaN.
25*NaN;// es igua a NaN25+NaN;// es igual a NaN
NaN it is not even equal to NaN
NaN===NaN;// es igual a falseNaN==NaN;// es igual a false
To mitigate this strange behavior, it is recommended to use the method Number.isNaN(), there is also a global function called isNaN(), but due to the implicit functionality of Javascript in wanting to convert between types automatically, it can give us very strange results. So as a recommendation always use Number.isNaN(). This last function checks if the type is number and equal to NaN, any other value will return false.
// Usando funcion globalisNaN('James');// true --> Esto esta mal, deberia seguir regresando false// lo que realmente hace es una conversion automaticaconst result =number('James');// NaNisNaN(result);// truenumber.isNaN('343434');// falsenumber.isNaN('James');//falsenumber.isNaN(1+undefined);// true
We can see in the first example that the global function returns true when it should be false, this is due to the automatic type conversion that javascript does.
Function Number(value)
You can convert a value to a number using the function Number(value), just be careful because this function can return 0 for many values, as well as NaN.
Finally we have the functions Number.parseInt(value) and Number.parseFloat(value), if the value is not a string, then convert it to string using the method .toString() before converting to number.
This type of value is new, added to the language in 2020, it is used to represent very large integer values, especially for mathematical calculations with very large quantities.
To use this type of data, the letter is added to the number n in the end. This is the recommended way.
const enteroMuyGrante =999999999999999999999999999999999999999999999999999n;const otroEnteroMuyGrande =55555555555555555555555555555555555555555555555n;const result = enteroMuyGrande * otroEnteroMuyGrande;//
Operations can be performed between the Number type and the BigInt, but because conversion between types can cause loss of precision, it is recommended to only use values BigInt when values greater than 2 are being used53 and only perform operations with values of the same type BigInt.
Another bad news about BigInt is that you cannot use the object's methods on a BigInt value. MathematicsFor example, you cannot use Math.sqrt().
Mathematics.sqrt(99);// 9.9498743710662Mathematics.sqrt(99999999999999999n);// Uncaught TypeError: Cannot convert a BigInt value to a number
As a final recommendation, do not complicate your life, do not use BigInt unless the problem you want to solve necessarily requires very large integers.
BigInt(value) function
You can convert and create a BigInt with the function BigInt(value)
BigInt('9999999999');// 9999999999n
Boolean
Boolean is a logical data type, which is represented by only two values. true and false. Very useful for making decisions in our programs. Named after the mathematician George Boole.
Boolean type values can be defined as follows. This is the recommended way
const tieneHijos =true;const esEstudiante =false;
They are widely used in logical operations, for example:
if (tieneHijos) {// Si "si" tiene hijos, preguntar cuantos hijos tiene}else{// si "no"}if (esEstudiante) {// Si "si" es estuduante, aplicar descuento}else{// si "no"}
Boolean function(value)
Booleans also have a function Boolean(value), is suitable for creating booleans and explicitly converting a value to Boolean. More details below in the section Values that can generate Booleans.
null
This data type in Javascript is very easy, it is a data that means it is nothing compared to the other data types. In other languages null It refers to a pointer or a memory reference that is empty, but in javascript it is different, it is simply a value that means “nothing".
const nada =null;
undefined
This data type represents something that is not yet defined. It is the automatic value of variables, parameters and properties of objects that have not had a value defined.
let name;// undefinedlet edad;// undefinedname ===undefined;// trueedad ===undefined;// true
symbol
This type of data is primarily used to ensure that its value is unique and immutable. It can be used as object properties to reduce access to those properties and thus avoid unwanted modifications. When we look at the objects in more detail we will see their use in practice.
To create this type of primitive data the function is used Symbol(). It is the only way to create a symbols and it is the recommended one.
const name =symbol('Jaime');const nombreIgual =symbol('Jaime');name === nombreIgual;// false
String or string of characters
Strings allow us to save information in text form. They are a sequence of one or more 16-bit, UTF-16 characters. There is no `char` type like in other languages, if you want a character, you simply create a string with a single character. Simple right?
We have three ways to create a string.
Actually you can also create strings with the function String(value) or in constructor form new String(value), but let's not complicate our existence and only use the three below for simplicity:
With single quotes, ''. Recommended if you do not need to evaluate expressions inside.
Double quotation marks, ""
backticks, `` . Recommended if you need to evaluate expressions within.
const name ='Jaime';const last name ="Cervantes";const mother's last name =`Velasco`;
The third way to define Strings, allows us to use expressions within the character string, so it is very useful. For example:
const name ='Jaime';const last name ="Cervantes";const mother's last name =`Velasco`;const nombreCompleto =`${name}${last name}${mother's last name}`;// Jaime Cervantes Velasco
Strings are immutable, when you modify or extend a string a new one is actually generated.
Two character strings can be the same
You can check that two character strings are the same with ===.
The property length of a string is used to know the length of a string of characters, you will see over time that this is useful when working with strings of characters.
const name ='Jaime Cervantes Velasco';name.length // 23
Objects
All other data types are objects, a function is an object. A object is a collection of pairs name: value, similar to PHP's “associative arrays”. These pairs of name/value They are called properties, a property is like a variable and can contain any type of value.
Some objects in Javascript:
object
function
array
date
RegExp
Mistake
Primitive Wrapping Objects
Even primitive data types String, Boolean, Number, BigInt and Symbol has its corresponding representation in Object, called enveloping objects. In fact, Javascript implicitly converts this primitive data to objects in order to occupy useful methods and properties. For example the property length of a string of characters.
How were you planning to get the length of a character string? Understanding that a character string is primitive data and has no methods
'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)'
Although the BigInt and Symbol data types do not allow the use of new It does not mean that objects are not created behind, it is clear that javascript wraps them in an object because it allows us to use the methods of the example, toLocaleString and toString.
How to create an object?
To create an object you don't need to create a class, you simply create the object and start using it. The easiest way to create an object is to use the definition called literal object, where you simply open and close keys {}. This is the recommended way.
In the example we have an object person, has several properties of different types, its name is a String, his age is a number, getName and talk are of type function, functions that are members of an object are called methods.
Below are examples of objects.
Accessing properties with square brackets, ['key']
In the previous example we saw how to access the method talk(), this method is still a property and is of type functions. But there is another notation to access properties, using square brackets. Very similar to how the elements of an array are accessed.
person.edad;// regresa 33persona['edad'];// regresa 33// obtenemos la funciónn con corcheteds y la invocamos con parentesisconst frase = persona['talk']();console.log(frase);// 'Hola soy Jaime Cervantes Velasco, tengo 29 años.'
Since an array is an object, just like a function, you can also add properties to it.
const numeros = [1,2,3,4,5,6];numeros.miPropiedad ='Mi propiedad de un arreglo';console.log(numeros.miPropiedad);// 'Mi propiedad de un arreglo
How to create an object date?
const fecha =newdate();console.log(fecha);// Fri May 28 2021 10:46:27 GMT-0500 (hora de verano central)
As you can imagine, we can also add properties to the date object because it is an object
For now, I hope this gives you an idea of the importance of objects in Javascript and why it deserves a more extensive explanation in a future publication.
Values that can generate a boolean false
There are true values and false values, which when applied to a condition behave like Booleans. This is because Javascript does an implicit type conversion, which can surprise us if we are not careful, so here I leave you the list of values that can return a Boolean false.
false
null
undefined
0
0n
NaN
"", "", " (empty character string)
All other values, including objects, in a condition or passed to the function Boolean(value) the Boolean returns true. A string with a space " ", came back true, and a string with value "false" also returns true.
Boolean function(value)
There is a global function to create Boolean values, Boolean(value). Where yes worth It's a real one, come back true, otherwise it returns 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;
Under logical conditions
Logical conditions in javascript check without a return expression true either false, they execute an implicit conversion.
This operator allows us to identify the type of data we are working with, useful in case we do not know where the information comes from, or we want to process the data based on its type. The operator returns the lowercase name of the data type.
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');// Objecttypeoffunctions(){}// 'function'typeofclassA{}// 'function'
There is a known bug in javascript, when the typeof operator is executed on null, this one comes back'object'. This bug has existed since the first version of Javascript, Bad things happen when you write code on the run.
If all other non-primitive values are objects, when we use the operator typeof about them, what type of data will you tell us what they are? Exactly, 'object'. Just like in the example above when we pass an object literal, an empty array, a date type object and when we use the surrounding objects of primitives like new String('Jaime').
Existe una excepción en typeof, cuando el valor es una función o una clase, regresara functions. Recuerda, una función en javascript, también es un objeto.
Check types with the method Object.prototype.toString
As we saw, it is somewhat confusing to use the operator typeof, I prefer to use a safer method, it is somewhat strange, but since everything in Javascript is an object and the base object from which all data types in javascript start is object, with the exception of the primitive data (although these in turn have their object version), then we can do something like the following.
The special property prototype is very important in Javascript, if you have read more than one of my publications, you will have noticed that I have mentioned that Javascript is a multiparadigm and object-oriented programming language based on prototypes, in another publication we will explain in detail the functionality of prototypes in Javascript .
Conclusion
Everything in Javascript is an object, with the exception of primitive types, but as we already saw, when wanting to use them as objects by invoking some method, that is where javascript wraps them (in practice everything is an object).
Any programming language has good things that we can take advantage of, but it can also have strange and confusing things (compared to most modern programming languages), such as the operator typeof and the method Object.prototype.toString, the value NaN, the values that can generate a boolean false, and many other things we didn't see for simplicity's sake. It is up to the programmer to take the best parts and eliminate or mitigate those that do not help us communicate better with our work team, always with a focus on simplifying things.
In the case of creating some type of data in Javascript, the simplest and easiest way to use is simply creating the values that we are going to use. As recommended in previous sections, this way of creating them is called literal.
const numero =9999.54;const enteroGrande =99999999999999n;const boleano =true;const nulo =null;let noDefinido;const simbolo =symbol('identifier');const cadenaDeCaracteres ='Jaime Cervantes Velasco';const cadenaDeCaractresConExpresion =`El numero ${numero} es "Number"`;const object ={};const arreglo = [];
There are even more details to cover about data types in javascript, but as we go we will see more necessary topics, for now it seems to me that this information is enough.
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.
The model or map of how we see the real world, that is a paradigm, it is a way of seeing and doing things. Following this logic, a programming paradigm is nothing more than a way of viewing and creating programming code.
Paradigms are powerful because they create the glasses or lenses through which we see the world.
There are three main programming paradigms used today and in JavaScript they have always existed since its first version.
Structured programming paradigm
Object-oriented
Functional
Now, if we stick to the phrase of Stephen R. Covey, that paradigms create the lenses through which we see the world. Let's imagine that the three previous paradigms, each, are a pair of glasses that we put on when programming and that we can change those glasses according to our visual needs (for programming or problem solving).
Structured programming paradigm
Origin
In 1954 the FORTRAN programming language appeared, then in 1958 ALGOL and in 1959 COBOL. Time after Edsger Wybe Dijkstra in 1968 discover the structured programming paradigm, we say “discover” because they didn't actually invent it. Although this programming paradigm was formalized some time after the appearance of these programming languages, it was possible to do structured programming in them.
Dijkstra He recognized that programming was difficult, and programmers don't do it very well, which I totally agree with. A program of any complexity has many details for the human brain. In fact, the Neuroscience tells us that the focused mind It can only work with four pieces of data at a time, at most. For this reason, if one small detail is neglected, we create programs that seem to work well, but fail in ways you never imagine.
Evidence
Dijkstra's solution was to use tests, only these tests used a lot of mathematics, which was quite difficult to implement. During his research he found that certain uses of GOTO made it difficult to decompose a large program into smaller pieces, it could not be applied “divide and conquer”, necessary to create reasonable evidence.
Sequence, selection and iteration
Böhm and Jacopini They proved two years earlier that all programs can be built by just three structures: sequence, selection and iteration. Dijkstra already knew these three structures and discovered that these are the ones necessary to make any part of the program tested. This is where the structured programming paradigm is formalized.
Edsger tells us that it is bad practice to use GOTO and suggests better using the following control structures:
If, then, else (selection)
do, while, until (iteration or repetition)
Decomposition of small units easy to test
Nowadays most programming languages use structured programming, JavaScript uses this type of programming. The simplest example is if conditions.
const EDAD_MINIMA =18;if (edad >= EDAD_MINIMA) {// hacer algo porque es mayor que 18}else{// Hacer otra cosa en caso contraio}
And if we isolate it in a function, we have a decomposition of functionalities or units that can be tested more easily. In the next section we will see the importance of having a completely probable unit
With this condition we have direct control of what can happen if the age is greater than or equal to 18, and also in the event that the age is younger.
Let's not be so strict either, surely the GOTO ruling has its merits and perhaps it was very efficient in some cases, but I think that to avoid misuses that probably caused disasters, Dijkstra recommended to stop using GOTO.
Test, divide and conquer
Structured programming allows us to apply the “divide and conquer” philosophy, because we allows you to create small unit tests, until the entire program is covered. The mathematical solution of Wybe Dijkstra It was never built, precisely because of its difficulty in implementation. And unfortunately today there are still programmers who do not believe that formal tests are useful for create high quality software.
And I say create, because verify correct operation after create, is nothing more than a simple measurement and the opportunity to reduce time and money is lost.
Scientific method, experiments and impiricism
The good news is that the mathematical method is not the only way to verify our code, we also have the scientific method. Which cannot prove that things are absolutely correct from a mathematical point of view. What we can do is create experiments and obtain enough results to verify that our theories work. Since our theories work on these experiments, then we conclude that they are “correct” enough for our validation purposes.
If the theory is easily validated as false, then it is time to modify or change it. This is the scientific method and this is how tests are currently done:
First we establish our theory (write the test), then we build the experiments (write production code) and finally we verify (run the test) and repeat this cycle until we have enough evidence.
Tests show the presence, not the absence, of defects
Edsger Wybe Dijkstra said “Testing shows the presence, not the absence, of defects.” That is, a program can be proven wrong by testing, but it cannot be proven correct. All we can do with our tests is validate that our program works well enough for our goals. But we can never be one hundred percent sure of the absence of defects.
If we can never be one hundred percent sure that our code is correct, even with its tests, what makes us think that without tests we deliver a program with sufficient validity to affirm that no negligence is consciously committed?
direct control
lto structured programming teaches us about direct control, that is, controlling the sequential flow of operations through the control structures, without neglecting the recommendation of Wybe Dijkstra about GOTO. This recommendation also applies to statements that drastically change the normal flow of operations, for example a breakwithin a cycle for nested, that breakIt breaks direct control because it abruptly complicates the understanding of the algorithm. Let's not be purists either, there will surely be cases where you need these sentences, but in the first instance, try to avoid them.
In conclusion, the structured programming paradigm teaches us:
The direct, clear and explicit control of what a piece of code does
Object-oriented programming paradigm
Arised from functions?
The object-oriented programming paradigm was discovered in 1966 by Ole Johan Dahl and Kristen Nygaard when they were developing simula 67. Two years before structured programming and its adoption by the programming community was some time later. In 1967 it was launched Simulates 67, Simulates It was the first object-oriented programming language, it basically added classes and objects to ALGOL, initially Simula was going to be a kind of extension of ALGOL.
During the development of Simula, it was observed that the execution of an ALGOL function requires certain data, which could be moved to a tree structure. This tree structure is a Heap.
The parent function becomes a constructor, the local variables become the properties, and the child (nested) functions become its methods. In fact, this pattern is still widely used by Javascript to create modules and use functional inheritance. This also describes how classes work in Javascript, behind are functions.
Spread of polymorphism
All this helped a lot to implement polymorphism in object-oriented programming languages. Ole Johan Dahl and Kristen Nygaard invented the notation:
object.function(parametro)
The execution of function that belongs to object, but more importantly, we pass a message through parameters from the first part of the code to the second part located in a different object.
Molecular biology and message passing
Some time later it was created Smalltalk, a much more sophisticated and modern object-oriented programming language, in charge of this project was Alan Kay. This person is credited with the formal definition of object-oriented programming.
The main influence on Alan Kay's object-oriented programming was biology, he has a degree in biology. Although it is obvious that it was influenced by Simula, the influence of LISP (functional programming language) is not so obvious.
From the beginning he thought of objects as interconnected cells in a network, from which they could communicate through messages.
Alan Kay commented:
I'm sorry I coined the term a long time ago. Objects for programming because it made people focus on the least important part. The big idea is “Sending messages“.
Alan Kay
My English is bad so you can check the original text here.
Better object composition over class inheritance
Smalltalk It also allowed the creation of Self, created at Xerox Parc and later migrated to Sun Microsystems Labs. It is said that Self It is an evolution of smalltalk.
In this programming language the idea of prototypes, eliminating the use of classes to create objects, this language uses the objects themselves to allow one object to reuse the functionalities of another.
Self It is a fast language and is generally known for its great performance, self It did a good job on garbage collection systems and also used a virtual machine to manage its execution and memory.
The virtual machine Java HotSpot It could be created thanks to Self. Lars Bak one of Self's latest contributors, he was in charge of creating the V8 Javascript engine. Due to the influence of Self we have today the engine of JavaScriptV8, which uses it node.js, mongoDB andGoogle Chrome internally.
Self followed one of the book's recommendations Design Patterns: Elements of Reusable Object-Oriented Software, long before it came out, published this recommendation:
Better composition of objects to class inheritance.
Design Patterns: Elements of Reusable Object-Oriented Software
Example
Currently Javascript uses prototypes for code reuse, you could say that it uses composition, instead of inheritance. Let's look at an example:
const person ={greet(){return'Hola'}};// se crea un programador con el prototipo igual al objeto personaconst programmer = object.create(persona);programmer.programar=()=>'if true';const saludo = programmer.greet();const codigo = programmer.programar();console.log(saludo);// 'Hola'console.log(codigo);// 'if true'
The object programmer It is based on the prototype of `person`. It doesn't inherit, it just directly reuses the functionality of `person`.
JavaScript emerged shortly after JAVA, in the same year. JavaScript took influences from Self, and in turn Self was influenced by smalltalk.
The syntax of current classes in Javascript is nothing more than a facade, well a little more accurately they are an evolution of the constructor functions, but internally, their basis are functions and prototypes.
Communication with message passing
As we already saw, the origin of object-oriented programming has its origins in functions, and the main idea has always been communication between objects through message passing. We can say that Object-oriented programming tells us of message passing as a key piece for the communication of objects, for example, when a method of one object invokes the method of another.
object.function(parametro);
In conclusion, the object-oriented programming paradigm teaches us:
Message passing for communication between objects
Functional programming paradigm
lambda calculation
Functional programming is the oldest programming paradigm, in fact its discovery was long before computer programming, it was discovered in 1936 by Alonzo Church, when I invented the lambda calculus, based on the same problem to be solved by your student Alan Turing.
As a curious fact, the symbol of the lambda calculus is:
λ
The first language based on functional programming was LISP, created by John McCarthy. As we saw previously, Alan Kay also took influence from LISP to create Smalltalk, with this we can see that the programming paradigms can be united and their relationship between them arises from the idea of how to solve problems more efficiently, they are not fighting, nor Separated, they seek the same goal and somehow evolve together.
The basis of the lambda calculus is immutability,We will review this concept later.
Similarities with OO and structured paradigms
As we saw in the structured programming paradigm, we can decompose our programs into smaller units called procedures or functions. Since functional programming is the oldest paradigm, we can say that the structured programming paradigm also relies on functional programming.
Now, if we analyze the notation a little object.function(x) that we saw in the object-oriented programming paradigm section, is not very different from function(object, parameters), these two lines below are the same, the fundamental idea is the passing of messages, as Alan Kay tells us.
Smalltalk uses the “The Actor Model”, which says that actors communicate with each other through messages.
On the other hand we have LISP, which has a “Function dispatcher model” What we currently call functional language, these models are identical, because what functions and methods do is send messages between actors.
An example of this is when a function calls another function or when an object's method is invoked, what happens is that actors exist and they communicate with each other through messages.
Message passing again
So we can emphasize that the main idea of OOP is the sending of messages and that it is not very different from functional programming, in fact according to what we already established in the previous sections, OOP was born from a functional base. And here it is important to highlight what he said Alan Kay Co-creator of SmallTalk:
I'm sorry I coined the term a long time ago. Objects for programming because it made people focus on the least important part. The big idea is “Sending messages“.
Alan Kay
From the communication models between Smalltalk and LISP messages, it was created scheme.
scheme has the goodness to use tail recursion and closure to obtain a functional language, closure allows access to the variables of an external function even when it has already returned a value. This is the same principle that gave rise to object-oriented programming by Ole Johan Dahl and Kristen Nygaard. Do you remember the closure question in Javascript?
Javascript uses closure a lot in its functional programming paradigm. JavaScript took influences from scheme, at the same time scheme was influenced by LISP.
No side effects
The basis of the lambda calculus is immutability, therefore, lImmutability is also the basis of the functional programming paradigm.
We as functional programmers must follow this principle and limit object mutations as much as possible to avoid side effects.
I repeat, the main idea of functional programming is immutability, which allows you to create your programs with fewer errors by not producing side effects that are difficult to control.
As an example, suppose we have an object person and we want to “change” the name, the most obvious thing would be to modify the name property directly, but what happens if that object is used elsewhere and the name is expected to be “Jaime”, that is why instead of changing the name property , we only create a new person object with a different name, without modifying the original.
functionscambiarNombre(name,person){return{ name:name, edad:person.edad}}const James ={name:'Jaime',edad:30};const juan =cambiarNombre('Juan', jaime);console.log(jaime);// { nombre: 'Jaime', edad: 30 }console.log(juan);// { nombre: 'Juan', edad: 30 }
Here you will find more details about the fundamental principles of functional programming:
Finally, the functional programming paradigm teaches us:
No side effects, for clear expression and less prone to errors
Conclusion
It is important to note that if the three programming paradigms were implemented between 1958 with LISP (functional programming) and Simula (object-oriented programming) in 1966, and the discovery of the structured programming paradigm in 1968, in only a period of 10 For years there has been innovation in programming paradigms, and new paradigms have not really emerged, unless they are based on these three main ones.
Right now more than 60 years have passed, which tells us the importance and firmness they have despite the time that has passed.
Functional programming paradigm (1958, already implemented in a programming language for computers, remember that it was discovered in 1936)
Object Oriented (1966)
Structured (1968)
The implementation of these three paradigms from the beginning within JavaScript has made this programming language the global success it is today. And it proves to us the value of combining paradigms when writing our programs.
JavaScript is a multi-paradigm programming language, so you can combine the paradigms to create much more efficient and expressive code using:
The direct, clear and explicit control of what a piece of code does
Message passing for communication between objects
No side effects, for clear expression and less prone to errors
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.
He 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.
He 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 by 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 and 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.