Introducción a Redux con React

El propósito de este artículo es explicar cómo estructurar una aplicación básica de React en conjunto con Redux, explicando también algunos conceptos teóricos elementales.

Cabe destacar que este artículo no incorpora la herramienta Redux Toolkit. Esto será explicado en un artículo siguiente pero vamos a adelantar que Readux Toolkit representa una forma mejorada y simplificada de trabajar. De cualquier modo, creemos importante conocer primero cómo es la forma clásica.

Para facilitar la comprensión, este artículo utiliza nombres en español en variables e identificadores en general creados por nosotros. Hace un tiempo encontré que esta diferenciación ayuda bastante a comprender y separar lo que es parte del lenguaje o framework de algo que estamos creando como desarrolladores.

Principios de Redux

Empezaremos mencionando que Redux es una librería independiente de React. Se puede utilizar en forma totalmente separada. En este caso vamos a ver la forma de utilizarla en una aplicación React.

Redux es un framework de JavaScript cuya función es permitir compartir variables de estado de una forma global a nuestra aplicación.

Por el contrario, con React se mantienen estados independientes en cada componente y, si es necesario pasar información de estado de un componente a otro, tenemos que duplicarla.

La forma de funcionar de Redux está basada en tres elementos básicos: actions, stores y reducers. Voy a explicar brevemente cada uno a continuación:

Estado inicial

Antes que nada, nuestra aplicación debe definir su estado inicial. Supongamos que nuestra aplicación representa a una manzana. El estado inicial podría ser algo así:

const manzanaInicial = {
  color: 'roja',
  sucia: true,
  bocadosRestantes: 5
};

Actions

Las acciones son la forma que tiene nuestra aplicación de comunicarse con Redux. Básicamente, las acciones son objetos con una propiedad type requerida, la cual indica el nombre de la acción a realizar.

Si se requieren enviar datos adicionales, normalmente se envían en un objeto payload, aunque puede tener cualquier nombre o bien, se pueden enviar como propiedades adicionales del objeto action.

El envío de las acciones a los reducers se realiza mediante la función dispatch del store. El dispatch recibe un único argumente, que es la action. En función del type de la acción, el reducer realizará los cambios al estado que sean necesarios.

Más adelante veremos también el concepto de “action creators”. Estos no son otra cosa que “wrappers” para las llamadas al dispatch cuando se necesitan realizar operaciones un poco más complejas en las que interviene otro elemento llamado middleware.

De esta forma, en lugar de hacer un dispatch({ type: “cargarDatos”}) tal vez estemos llamando a una función cargarDatos() que dentro tendrá una llamada a una función asincrónica y luego llamará al dispatch con los datos obtenidos: dispatch({ type: “cargarDatos”, payload: datos}).

Siguiendo con nuestro ejemplo de la manzana, las posibles acciones que podríamos realizar sobre ella podrían ser:

const LAVAR = { type: 'LAVAR' };
const COMER = { type: 'COMER', bocados: 2 };
const PODRIR = { type: 'PODRIR' };

Reducers

Son funciones que realizan cambios en el estado de acuerdo a la acción recibida. Por consiguiente, son funciones que reciben un estado inicial y un objeto action. El objeto action tiene siempre una propiedad type y luego puede contener datos adicionales. El reducer es el único que puede cambiar el estado, ya que no se puede acceder al store de otra forma.

Un ejemplo de función reducer para nuestra manzana podría ser el siguiente:

function manzanaReducer(state = manzanaInicial, action) {
  switch(action.type) {
    case 'LAVAR':
      // mantiene todos los estados y cambia el campo sucia a falso
      return { ...state, sucia: false };

    case 'COMER':
      // decrementa el número de bocados
      return {
        ...state,
        bocadosRestantes: Math.max(0, state.bocadosRestantes - action.bocados)
      };

    case 'PODRIR':
      // cambia el color a marrón
      return { ...state, color: 'marrón' };

    // no sabemos cómo tratar otras acciones así que solo devolvemos el estado actual
    default:
      return state;
  }
}

En el argumento del switch también podríamos utilizar simplemente action y utilizar las constantes que definimos en lugar de los strings. De esta forma evitaríamos errores al tipear mal los strings.

Store

El store es el lugar donde nuestra aplicación guardará el estado. Lo más recomendable es tener un único store por aplicación. La creación se realiza mediante la función createStore la cual recibe como primer argumento los reducers que vamos a utilizar y como segundo argumento, el estado inicial. Opcionalmente se puede definir un middleware y enviarlo como tercer argumento (luego explicaremos la función del middleware).

En nuestro ejemplo, podemos crear el store de la siguiente forma:

const miStore = Redux.createStore(manzanaReducer, manzanaInicial);

Una vez que tenemos esta configuración básica, podemos hacer el dispatch de acciones e ir cambiando por los diferentes estados.

Supongamos que lavamos la manzana. Esto equivale a hacer:

miStore.dispatch(LAVAR);

Si hacemos un console.log(store.getState()) antes y después del dispatch obtendremos lo siguiente:

{ color: 'roja', sucia: true, bocadosRestantes: 5 } // antes
{ color: 'roja', sucia: false, bocadosRestantes: 5 } // después

El ejemplo completo

Para probar el ejemplo completo que planteamos aquí, pueden crear un nuevo archivo llamado index.js (o cualquier nombre) en Visual Studio Code y copiar el código completo a continuación:

index.js

const Redux = require('redux'); // Aquí utilizamos require porque no estamos trabajando con un módulo

// DEFINIMOS NUESTRA MANZANA INICIAL (ESTADO INICIAL):
const manzanaInicial = {
    color: 'roja',
    sucia: true,
    bocadosRestantes: 5
  };

// DEFINIMOS NUESTRAS POSIBLES ACCIONES:
const LAVAR = { type: 'LAVAR' };
const COMER = { type: 'COMER', bocados: 2 };
const PODRIR = { type: 'PODRIR' };

// CREAMOS LA FUNCIÓN QUE UTILIZAREMOS COMO REDUCER
function manzanaReducer(state = manzanaInicial, action) {
    switch(action) {
      case LAVAR:
        // mantiene todos los estados y cambia el campo sucia a falso
        return { ...state, sucia: false };
  
      case COMER:
        // decrementa el número de bocados
        return {
          ...state,
          bocadosRestantes: Math.max(0, state.bocadosRestantes - action.bocados)
        };
  
      case PODRIR:
        // cambia el color a marrón
        return { ...state, color: 'marrón', bocadosRestantes: 0 };
  
      // no sabemos cómo tratar otras acciones así que solo devolvemos el estado actual
      default:
        return state;
    }
}

// CREAMOS NUESTRO STORE
// Le indicamos qué reducer (o reducers) debe utilizar y cuál es el 
// estado inicial de nuestra aplicación
const miStore = Redux.createStore(manzanaReducer, manzanaInicial);

// Mostramos el estado inicial antes de enviar algún dispatch
console.log(miStore.getState());

miStore.dispatch(LAVAR);
console.log(miStore.getState());

miStore.dispatch(COMER);
console.log(miStore.getState());

miStore.dispatch(PODRIR);
console.log(miStore.getState());

Luego, abrimos una terminal dentro del mismo Visual Studio Code yendo a Terminal/New Terminal.

En la terminal ejecutamos nuestro script con node de la siguiente forma:

node index.js

El resultado será el siguiente:

{ color: 'roja', sucia: true, bocadosRestantes: 5 }
{ color: 'roja', sucia: false, bocadosRestantes: 5 }
{ color: 'roja', sucia: false, bocadosRestantes: 3 }
{ color: 'marrón', sucia: false, bocadosRestantes: 0 }

Hasta aquí hemos visto solamente los conceptos básicos de Redux sin siquiera haber utilizado nada de React. A continuación vamos a ver cómo utilizarlo ya integrado en una React App.

Ejemplo inspirado en: https://dev.to/hemanth/explain-redux-like-im-five.

Agregando Redux a React

El objetivo de este artículo es explicar cómo incorporar Redux a una aplicación React de una forma más o menos básica y reutilizable.

Como vimos antes, podemos tener una aplicación totalmente funcional que usa Redux en un solo archivo. Del mismo modo también podríamos incorporar componentes de React varios en el mismo archivo.

Sin embargo, queremos presentar una forma de trabajar más organizada para que nuestras aplicaciones sean más fáciles de mantener.

Vamos a considerar el desarrollo de una app muy simple que mostrará una lista de usuarios, los cuales los vamos a obtener de https://jsonplaceholder.typicode.com/users.

Empecemos con la instalación de los paquetes redux y react-redux con npm:

npm install redux react-redux

Crearemos una aplicación simple en React:

npx create-react-app redux-blog

Por el momento vamos a crear un componente muy básico de React que listará los usuarios de la forma clásica y luego lo modificaremos.

Creemos entonces una carpeta components. Movamos el archivo App.js dentro de esta carpeta para mantener todos los componentes organizados ahí dentro. Si estamos trabajando con Visual Studio Code, nos preguntará si queremos actualizar los imports automáticamente. Si no, deberemos corregir el import a App en el archivo src/index.js.

Si ya habíamos ejecutado npm run build deberemos reiniciarlo luego de este cambio.

Creación del componente Usuarios

Seguidamente creamos la carpeta usuarios dentro de components y dentro, el archivo index.js que contendrá nuestro componente.

Para la llamada “clásica”, necesitaremos instalar axios. Esta es una herramienta que nos servirá para realizar llamadas a web apis:

npm install axios

Nuestro componente “clásico” quedaría así:

Archivo src/components/usuarios/index.js

import React, {Component} from 'react';
import axios from 'axios';

class Usuarios extends Component {

    state = { usuarios: [] };

	async componentDidMount() {
		const respuesta = await axios.get('https://jsonplaceholder.typicode.com/users');
        this.setState({usuarios: respuesta.data});
	}

	render() {
		return (
			<ul>
				{this.state.usuarios.map((usuario) => (
                    <li>{usuario.name} ({usuario.email})</li>
                ))}
			</ul>
		);
	}
};

export default Usuarios;

Con esto ya deberíamos poder visualizar la lista de usuarios y sus emails en el navegador:

Imagen mostrando el listado de usuarios obtenidos de la url json placeholder, funcionando en el navegador, con url localhost:3000.

Esta sería una aplicación React extremadamente sencilla. El único estado que tiene esta aplicación es el array de usuarios obtenidos. Tampoco es una aplicación que justifique el uso de Redux, pero lo vamos a aplicar para aprenderlo.

Action Creators

En primer lugar crearemos una carpeta src/actions. En esta carpeta crearemos los archivos de acuerdo a funcionalidades similares. Por ejemplo, AuthenticationActions.js, contendría signInAction() o logoutAction. Un archivo BlogActions.js contendría acciones tales como getBlogPostActionI(), deleteComment() o updateBlogPostAction().

Archivo src/actions/usuariosActions.js

import axios from 'axios';

export const traerTodos = () => async (dispatch) => {
  const respuesta = await axios.get('https://jsonplaceholder.typicode.com/users');
  dispatch({
    type: 'traer_usuarios',
    payload: respuesta.data
  })
};

En este ejemplo estamos definiendo la acción traerTodos. Al igual que todas las acciones, esta es una función que devuelve otra función. En este caso, la función devuelta por traerTodos está marcada como asincrónica (async) porque dentro tenemos una llamada a otra función asincrónica (indicada con await), axios.get().

Es importante destacar que podemos utilizar traerTodos como una acción porque vamos a utilizar el middleware Redux Thunk. De lo contrario, las acciones deberían ser objetos planos como lo es el argumento del dispatch.

Una vez que tenemos el resultado del axios.get() en la constante respuesta, llamamos al dispatch y le enviamos el tipo de acción a llamar (traer_usuarios) y el payload, que es respuesta.data.

Hay que tener en cuenta que, según la teoría de Redux, la acción propiamente dicha es lo que estamos enviando como argumento del dispatch. Con esta función traer_todos que creamos estamos “wrappeando” la llamada al dispatch para agregar algo de funcionalidad adicional.

Reducers

Crearemos una carpeta src/reducers y dentro, nuestro primer reducer:

Archivo: src/reducers/usuariosReducer.js:

const INITIAL_STATE = {
	usuarios: [] // el estado inicial es un array vacío llamado usuarios
};

export default function UsuariosReducer(state = INITIAL_STATE, action){
	switch (action.type) {
		case 'traer_usuarios':
			return { ...state, usuarios: action.payload };

		default: return state;
	};
};

Como nuestra aplicación puede contener varios reducers, vamos a crear un “índice” y a combinarlos a todos en una única variable.

En la misma carpeta crearemos un archivo index.js. Este archivo nos servirá para la combinación que mencionamos. Para poder hacer esto primero tenemos que importar la función combineReducers.

Archivo: src/reducers/index.js

import { combineReducers } from 'redux';
import usuariosReducer from './usuariosReducer';

export default combineReducers({
	usuariosReducer
});

En este caso estamos utilizando un único reducer llamado usuariosReducer.

Configuración del Store

Ahora que ya tenemos nuestros reducers, podemos crear nuestro Store en nuestro src/index.js de la siguiente manera:

import misReducers from './reducers';

const store = createStore(
	misReducers, // Reducers
	{}, // Estado inicial
);

Aquí estamos importando el módulo que definimos en reducers/index.js (from ‘./reducers’) y, como es un export de tipo default podemos darle el nombre que queremos. En este caso lo llamamos misReducers.

Seguidamente, creamos nuestro único store al que llamaremos miStore. Para ello hacemos uso de la función createStore que recibe los reducers que utilizaremos y el estado inicial (algunos desarrolladores prefieren utilizar el createStore en el index.js dentro de una carpeta src/store).

Otro cambio que nos falta es el agregado del Provider para indicarle a nuestro App cuál será el store que utilizará nuestra aplicación. Así es como nos queda todo el index.js:

Archivo src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';

import { createStore } from 'redux';
import { Provider } from 'react-redux';

import misReducers from './reducers';

const miStore = createStore(
	misReducers, // Reducers
	{}, // Estado inicial
);

ReactDOM.render(
	<Provider store={ miStore }>
	  <App />
	</Provider>,
	document.getElementById('root')
);

Uso de Middleware

Un middleware, como Redux Thunk, nos permite interceptar un dispatch de Redux para devolver una función en lugar de un objeto action plano, que sería lo esperable. Esto es especialmente útil en el caso de llamadas asincrónicas. El middleware retrasa entonces el dispatch de la acción hasta que se completa una línea de código asincrónica. Más info: https://platzi.com/blog/como-funciona-redux-thunk/

Para comenzar, hay que realizar la instalación con:

npm install redux-thunk

En src/index.js falta añadir el middleware que nos permitirá realizar las llamadas async. Para esto hay que comenzar por importar reduxThunk desde ‘redux-thunk‘ y la función applyMiddleware de ‘redux‘:

import reduxThunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';

Vamos a aplicar el reduxThunk como middleware. Esto lo debemos especificar en la función createStore. Con estos cambios, nuestro index quedaría así:

Archivo src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import misReducers from './reducers';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import reduxThunk from 'redux-thunk';


const miStore = createStore(
  misReducers,
  {},
  applyMiddleware(reduxThunk)
);

ReactDOM.render(
  <Provider store={miStore}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Conexión a un componente

Para poder conectar nuestro componente con el reducer necesitamos importar la función connect de React-Redux:

import { connect } from 'react-redux';

También tendremos que importar las actions (las crearemos a continuación):

import * as usuariosActions from '../../actions/usuariosActions';

Ya que tengo esto ya puedo conectar mi componente. Al final de nuestro componente primero debemos definir la función mapStateToProps, la cual recibirá como parámetro todos los reducers y puedo devolver los reducers que necesito utilizar.

Una vez que tenemos esta función definida, se le pasa como primer parámetro a la función connect y, como segundo parámetro, todos los actions

const mapStateToProps = (misReducers) => {
  return misReducers.usuariosReducer;
};

export default connect(mapStateToProps, usuariosActions) (Usuarios);

Finalmente, nuestro componente ya podría llamar a la acción traerTodos en el componentDidMount. A continuación, el componente completo:

Archivo src/components/usuarios/index.js

import React, {Component} from 'react';
import { connect } from 'react-redux';
import * as usuariosActions from '../../actions/usuariosActions';

class Usuarios extends Component {

	async componentDidMount() {
		this.props.traerTodos();
	}

	render() {
        console.log(this.props);
		return (
			<ul>
				{this.props.usuarios.map((usuario) => (
                    <li>{usuario.name} ({usuario.email})</li>
                ))}
			</ul>
		);
	}
};

const mapStateToProps = (reducersRecibidos) => {
	return reducersRecibidos.usuariosReducer;
};

export default connect(mapStateToProps, usuariosActions)(Usuarios);

Si observan, acá hemos modificado el método componentDidMount. Ya no necesitamos hacer la petición aquí por medio de axios. Esto lo hacemos ahora llamando a la acción traerTodos().

Otras cosas que hemos modificado:

  • Quitamos el import axios.
  • Eliminamos la inicialización del state.
  • Ya no trabajamos más con la variable this.state.usuarios sino con this.props.usuarios, que nos la proporciona Redux.

Con estos cambios hemos logrado la configuración y el funcionamiento básico de nuestra aplicación con React y Redux.

Por supuesto que hay muchos pasos más y muchas formas diferentes de realizar esta misma acción, pero esto es tan solo el principio.

Resumen

Vamos a repasar brevemente lo que hicimos:

  1. Creamos la app de React con npx create-react-app {nombre-app}
  2. Creamos nuestras acciones en la carpeta src/actions.
  3. Creamos nuestros reducers en la carpeta src/reducers y los combinamos en el index.js.
  4. Creamos el Store en nuestro archivo src/index.js.
  5. En el mismo archivo configuramos el <Provider> y le asignamos el store a utilizar.
  6. En el mismo archivo configuramos el middleware, Redux Thunk.
  7. Por último, conectamos nuestro componente Usuarios, en components/usuarios/index.js con el reducer que queríamos usar.

Código fuente completo: https://github.com/changomarcelo/redux-blog

How to run a SQL Server script from the command line

To run the script file

  1. Open a command prompt window.
  2. In the Command Prompt window, type: sqlcmd -S myServer\instanceName -i C:\myScript.sql
  3. Press ENTER.

To save this output to a text file

  1. Open a command prompt window.
  2. In the Command Prompt window, type: sqlcmd -S myServer\instanceName -i C:\myScript.sql -o C:\EmpAdds.txt
  3. Press ENTER.

No output is returned in the Command Prompt window. Instead, the output is sent to the EmpAdds.txt file. You can verify this output by opening the EmpAdds.txt file.

How to download SQL Server Express, the easy way

For some not easy to understand reason, Microsoft has made downloading SQL Server Express very difficult. According to this blog post, you have to go through 12 steps to download SQL Server Express 2014.

Luckily, Scott Hanselman has put togetter a page where you will find all the direct links you’ve always wanted. So here you have the SQL Server Express download page, just 1 click away!

http://downloadsqlserverexpress.com

The 5 Types of Prospects

1. The Most Aware: Your prospect knows your product, and only needs to know “the deal.”

2. Product-Aware: Your prospect knows what you sell, but isn’t sure it’s right for him.

3. Solution-Aware: Your prospect knows the result he wants, but not that your product provides it.

4. Problem-Aware: Your prospect senses he has a problem, but doesn’t know there’s a solution.

5. Completely Unaware: No knowledge of anything except, perhaps, his own identity or opinion.

Cómo determinar la paridad de claves para encriptación con DES

Un tema que resulta confuso es determinar si una clave DES es odd parity o even parity. El algoritmo DES generalmente se utiliza con claves odd parity ya que son más seguras. Un criptograma creado con una clave even parity es más fácil de desencriptar.

Primero, para que nos pongamos de acuerdo, traduzcamos:

  • Even: par
  • Odd: impar (odd también significa extraño o raro, en inglés).

La condición para que una clave sea odd, es que cada uno de sus bytes sea odd. Si esta condición no se cumple, entonces es even.

  • Si todos los bytes son odd, la clave es odd y es aceptada.
  • Si al menos un byte es even, la clave es even y es rechazada. Algunos sistemas pueden hacer un ajuste para convertirla en odd.

Luego, la condición de odd o even de un byte se determina así:

  • Si el número de “1” en su representación binaria es impar, entonces el byte es odd.
  • Si el número de “1” en su representación binaria es par, entonces el byte es even.

Finalmente, el algoritmo para ajustar una clave even a odd debería ser byte a byte: Si un byte es even, se convierte ese byte a odd. Así para cada uno de los 8 bytes (para una clave single length). La forma en que se debería hacer este ajuste es el siguiente:

  • Si el número de “1” desde el bit 1 al 7 es impar (odd), se setea el bit 8 en “0”. Con esto se obtiene una cantidad impar de “1” en todo el byte, dejandolo odd.
  • Si el número de “1” desde el bit 1 al 7 es par (even), se setea el bit 8 en “1”. Con esto se obtiene una cantidad impar de “1” en todo el byte, dejandolo odd.

En todos los casos, se entiende que el bit 1 es el de la izquierda y el 8 el de la derecha.

Uso de Branches y Tags con SVN

El uso de branches y tags en SVN nos permite una mejor organización del trabajo en equipo. Si bien no muchos usuarios de SVN utilizan esta funcionalidad su uso trae varias ventajas.

Branches

Los branches se utilizan cuando se desea crear una rama independiente de desarrollo para trabajar en alguna funcionalidad nueva de un proyecto que todavía no se quiere incorporar a la línea principal. De esta forma, se crea una copia del proyecto en una carpeta /branches y el programador encargado de esta nueva característica cambiará (switch, según la terminología de SVN) su working copy a este nuevo branch y trabajará sobre este.

Cuando este programador realice operaciones de commit las realizará sobre su branch, sin afectar el desarrollo principal. Cuando esté listo para integrar sus cambios a la línea de trabajo principal, realizará una operación de merge.

Tags

El uso de tags se da cuando queremos “marcar” una determinada revisión por alguna razón en especial. Por ejemplo, podemos querer marcarla porque se trata de un release entregado al cliente. En este caso, como en el anterior, se crea una copia de la revisión deseada del repositorio en la carpeta tags. Técnicamente la creación de un branch y un tag es idéntica, ya que se realizan con el comando svn copy. La diferencia radica en la forma en que se les da su uso; en los branches está permitido realizar commits y en los tags no. Esta “prohibición” sobre la realización de commits o no es virtual, ya que no existe impedimento técnico sino que son los programadores los que lo deben tener en cuenta.

Creación y uso de branches y tags

El comando para la creación, tanto de branches como tags, es svn copy:

$ svn copy http://svn.example.com/proyecto/trunk \            http://svn.example.com/proyecto/branches/soporte-IPv6 \       -m "Branch para agregar soporte para IP v6" 

Si trabajamos con Tortoise SVN es aún más fácil, ya que tenemos un comando Branch/tag. Con Tortoise SVN tan solo tenemos que hacer clic derecho sobre nuestra working copy y elegir el comando Branch/tag. Tortoise reconocerá la URL de origen en el repositorio y nos pedirá la URL de destino, donde queremos hacer la copia.

En la ventana para crear un nuevo branch o tag, también tenemos un checkbox que podemos marcar para automáticamente hacer el switch al branch o al tag recientemente creado. De no hacerlo, podremos realizar el switch en cualquier otro momento con el comando homónimo.

Finalmente, para reintegrar un branch a la línea de desarrollo principal, recurrimos al comando Merge.

Estructura de directorios recomendada

La estructura de directorios recomendada por SVN, para la raíz de nuestros repositorios es de tres carpetas:

  • /trunk: este directorio aloja la línea de desarrollo principal.
  • /tags: en esta carpeta guardamos los tags que vayamos creando, por ejemplo /trunk/release-1.2/.
  • /branches: en esta carpeta guardamos los branches que creemos.

Es una buena práctica seguir esta estructura, aunque aún no hayamos decidido trabajar con branches y tags ya que de decidirlo más adelante será más complicado cambiarlo.

Residuos: ¿Cómo lo hacen en otros países?

Voy a inaugurar una serie de posts donde publicaré sobre cómo han resuelto en otros países problemas cotidianos que sería bueno imitar.

En el caso de la basura he visto diferentes métodos. En México DF, por ejemplo, he visto que el camión de la basura pasa tal como aquí pero con la diferencia de que un señor va tocando una campanita con la mano. Entonces, cuando escuchas la campana tenés que salir de tu casa para sacar la basura y tirarla al camión directamente. El mismo método lo he visto en Lima, Perún. El resultado es interesante ya que la gente no deja la bolsita de basura en la vereda, a cualquier hora, costumbre que solo la he visto en Argentina.

En el caso EE.UU. está bastante mejor pensado. Y es bastante sorprendente que en uno de los paises que mayor basura genera el servicio de recolección es muy eficiente y se ven las calles mucho más limpias que aquí.

Encontré, para ejemplificar, el caso de la ciudad de Allen, Texas, donde estuve de viaje por trabajo varias veces (http://www.cityofallen.org/DocumentCenter/View/143). En dicha ciudad el servicio de recolección de la basura es prestado por la municipalidad, como en casi todos lados. Cada vecino recibe de la municipalidad, en caracter de préstamo, dos tachos de basura grandes, con rueditas (estimo que habrá un caso especial para edificios grandes y oficinas). Uno de los tachos es para basura y el otro para reciclables. Los tachos deben ser sacados a la vereda en el día y horario designado. Si lo sacás en otro horario, te multan, ya que el tacho lleva tu dirección.

Lo que es increíble es que en uno de los paises que más residuos genera es que la recolección de basura común es una vez por semana. La recolección de reciclables, por otra parte, es cada dos semanas.

En el caso de los residuos voluminosos, me he cansado de ver aquí, en Buenos Aires, cómo la gente saca colchones viejos, sillones, cocinas, lavarropas y los tira felizmente a la calle como si se tratara de un basural. En EE.UU. corresponde una buena multa para los infelices que hagan eso. Los residuos voluminosos como esos deben retirarse solamente por pedido y se recolectan solamente una vez al mes.

En otras ciudades de EE.UU., por ejemplo San Francisco, agregan un tacho más de basura para materia orgánica la cual se utiliza para generar fertilizantes.

Sin dudas, son cosas de las que podemos aprender.

Argentina economics for software services buyers

Yesterday, I received an email from an old client, who has hired full time engineers in Argentina, asking me about the economic situation of software outsourcing companies after the new government regulations. He was referring to the new argentinean government regulation for foreign money exchange. So, I gave him some background information.

Why so much USD in Argentina?

Argentineans, for years, were used to save in foreign currency, specially in US dollars, as a way to protect themselves from inflation and economic crisis. US dollars are also used by the Argentinean Central Bankto maintain and somehow control the value of our currency, the Peso. Argentina is the second country in the world after Rusia, with more US dollars outside USA. Another strange thing that happens here is that all real estate operations are made in USD. That doesn’t happen, for example, in our neighbor Brazil, where their currency, the Real is used exclusively for everything, and I think that is what we should do.

The recent economic crisis in Europe is making european companies here to transfer US dollars to Europe, to help their central branches. I’m not sure why, that is apparently not a good thing. Some private savers are also changing more pesos to USD because they fear of the European crisis.

All these scenarios made the government create a new regulation in which they demand that, whoever wants to change Pesos into USD, to prove how they obtain their money.

The issue is that a good part of the pesos which were changed into USD were not legally justified from people or companies who did not pay their taxes. So now, if they don’t have a legal way to demonstrate how they obtained the pesos, they are not allowed to buy USD.

For outsourcing companies doing their things within the law, this is not a problem. I can receive payments from foreign companies as usual and I could buy USD if I wanted.

What changes

As I said before, for companies doing things within the law, that is, paying their taxes, nothing changes. An argentinean company or individual has NO reason to demand more money from you because of this new regulation. Our costs did not go up because of this in any way.

The usual flow is that the outsourcing company emits a valid invoice (valid for the argentinean law) , client transfer the funds, usually via international bank transfer (SWIFT code), and the money is cleared in the company’s account, always in Pesos, which is our national currency.

If, for any reason, the company needs to buy foreign currency, they can do it without any problem, because they report their sales to the Tax Agency monthly.

It is true that providers using services like Xoom or Western Union received their payments in USD before the new regulations and no justification for the origin of the funds were asked for them. The difference now is that, if they want to continue receiving their funds in USD, they will have to prove the origin of the funds; if not, they will pay them in Pesos, at the official exchange rate.

The trick here was that those providers were declaring that the funds received were “familiar help”. That was definitely outside the law.

How to tell if you are hiring within the law

Now, if you are a foreign company hiring argentinean services you may be asking if you are hiring providers within the law.

If you are not hiring registered providers, that means you are paying less than the market value or that your providers are making more because they are not paying their taxes.

Even though you don’t need an invoice, it is your moral obligation to request one.

An argentinean invoice has some elements that will help you determine if it is legal or not.

CUIT

This is the tax identification number. It is a 11 digits number, usually represented as ##-########-#.

If the invoice of your provider does not include this number, you are not receiving a legal invoice and you are probably helping to tax evasion.

With this number, you can find out if you are hiring a provider who is registered in the tax agency. You could go to AFIP, click the Constancia de Inscripción link, and make a query using the CUIT (no dashes).

You could get two result types:

  1. If it says “Régimen Simplificado para Pequeños Contribuyentes” means he is registered in the simplified program for small taxpayers (commonly referred to as “Monotributo”), which is OK. But you should also check the category, which is a capital letter.

    In this page, you can see how much is the tax for each category (values expressed in Pesos). The first column shows you the category letter. The second, the top anual income for each category and the last two columns shows you the total tax they have to pay for services and goods respectively.

  2. If it doesn’t say “Régimen Simplificado para Pequeños Contribuyentes”, your provider is in the “General” program, which is more suitable for companies with an anual income of 46,000 USD or more. This program has more controls from the tax agency and taxpayers are forced to report monthly sales and spendings. They usually pay more in taxes (aprox. 30%), but they can deduct spendings.

Invoice letter

If the services provided are used outside Argentina, your provider should give you an E type invoice wether he is in the Monotributo program or not.

The difference between C and E invoices in Monotributo, for services, is formal. It doesn’t mean they pay different taxes with one invoice type or the other. So some providers could also give you a C type invoice but that should not be a problem.

You should not receive an A nor B invoice, unless you buy directly IN Argentina, because that means that you would be paying the sales tax (21%) and, as a foreign company, you should not pay it.

Transfer method

If you send the funds through international bank transfer, it is very likely that your providers will have to present the invoice that justifies those funds to the bank, to get the money cleared into their bank account.

If you are paying your programmers through services like Western Union or Xoom.com, and you are not asking your providers a valid invoice, you should know that these services do not demand to present an invoice to release the funds, so it is an easy method to skip paying taxes.

Argentinean inflation

Argentina, like many other countries in Latin America is experiencing a continuous growth since 2003. The collateral effect is inflation. That means that, each year, we need more Pesos to live.

Anual inflation in 2010, according to government is approximately 11%. But, to private consultants it is 25%. The trick is that not all the consultants reveal their measure methodology but government does. And government inflation is more country broad while private consultants focus more on big cities. An average between both values is acceptable.

If your provider express the prices in USD, he can make some difference with the exchange rate variation, but it is not enough to cover from inflation. For example, in the last year, USD went up 10%, wich is not enough to cover the average inflation.

In 2011 we might not experience as much of inflation as last year or, at least, not more. But beginning 2012, we will experience a higher cost in services like electricity, gas and water, specially in Buenos Aires and surroundings.

The case of my old customer

My opinion is that his providers were lying and trying to deceive him. They told him that they had to register as exporters and to pay more taxes. They pretended a raise of 30%, which is crazy in any industry.

The fact is that software providers do not need to register as exporters (that is for goods that go through customs), and they don’t have to pay more taxes than what they should be already paying from the beginning.

Probably, these providers realized that they won’t be able to be paid in US dollars anymore, because they are not producing invoices for their work or they are not properly registered and paying their taxes.

Why they would need US dollars? As I said at the beginning, argentineans are used to save in this currency, to protect from inflation or to buy a property. But it is also true that they can exchange the US dollars for the Pesos they need for living at a higher exchange rate than the official in the black market for, easily 15% or 20% more.

Use Cases vs. User Stories

No me parece que haya mucha diferencia entre una metodología dirigida por casos de uso (Use cases) o por historias de usuario (User Stories).

Por lo general, los casos de uso proveen una descripción más detallada “paso a paso” de las acciones que realiza un usuario del sistema para cumplir con su objetivo. Además, los casos de uso contemplan las extensiones, es decir, las diferentes variantes que pueden darse en el camino para alcanzar el objetivo como errores o algún desperfecto en algún sistema dependiente.

Pero es importante entender que no es necesario definir los casos de uso por completo al inicio del proyecto. Estos deben ser primero identificados, declarados y luego definirlos a medida que se avanza en las iteraciones del proyecto. En muchos proyectos me han pedido definir todos los casos de uso por anticipado y esta es una tarea realmente sin sentido.

Otro punto sobre el que se discute mucho es si los casos de uso deberían o no contener información sobre la interfaz de usuario. Mi opinión es que depende de dónde provengan. Si los casos de uso los escribe un analista en base a la información que obtiene del cliente, probablemente no sea necesario definir elementos de la UI. En cambio, en equipos de trabajo más chicos puede darse que la misma persona que define los casos de uso vaya a ser quien luego haga el trabajo de diseño o implementación. En este caso, definir aspectos de la UI puede ser una buena forma de ahorrarse trabajo.

Por último, y siguiendo todavía con los casos de uso, no siempre es necesario utilizar la famosa plantilla de Cockburn para definirlos. En ocasiones basta con una simple descripción, a menos que se requiera una funcionalidad muy específica.

Por el lado de las User Stories, una de sus principales ventajas es que las metodologías ágiles parten de que estas son escritas por el cliente. Para el cliente resulta mucho más natural escribir User Stories que casos de uso, aunque tan solo sean los títulos.

Si bien creo que la información que brindan las User Stories al desarrollador es similar a la que brinda un diagrama de casos de uso, no podemos pedirle al cliente que haga un diagrama. Las User Stories, por definición, se crean utilizando un lenguaje hablado natural, y ahí radica su ventaja que es la facilidad para su concepción.

Error Saving changes is not permitted en SQL Server

En el día de hoy me encontré por primera vez con algo totalmente nuevo para mí. Resulta que el Management Studio para SQL Server 2008 modificó la forma en que se guardan los cambios en la vista diseño de una tabla.

En algunos casos, Management Studio elimina totalmente una tabla y la vuelve a recrear, por ejemplo, cuando tiene que crear una columna en una ubicación específica. Esto es así desde versiones anteriores, pero aparentemente en esta versión 2008 decidieron ponerle una opción que impide esto, mostrando el siguiente mensaje:

Saving changes is not permitted. The changes you have made require the following tables to be dropped and re-created. You have either made changes to a table that can’t be re-created or enabled the option Prevent saving changes that require the table to be re-created.

La solución es muy simple y solo consiste en dirigirse a[Tools/Options/Designers] y desmarcar el checkbox [Prevent saving changes that require table re-creation].