miércoles, 24 de febrero de 2021

Jefe que manda vs. líder que asiste

Para mandar sólo hay que tener una posición de fuerza. Desde una posición de fuerza basta con decir qué se quiere dentro de tu campo de actuación y tus trabajadores lo harán. Desde una posición de fuerza podemos contradecir a nuestros empleados, sin importar que ellos tengan más experiencia o sepan más que nosotros, o que sistemáticamente y a veces de forma inconsciente convirtamos su trabajo en una rutina insoportable. Desde una posición de fuerza, en definitiva, podemos mandar.

Pero esa posición también nos permite "dirigir", que no es exactamente lo mismo. Es cierto que una de las acepciones de "dirigir" es "gobernar", pero ésa es sólo una de entre las diez definiciones que le otorga la Real Academia de la Lengua. Las otras nueve se basan casi todas en un modo de guía o consejo para conseguir un objetivo.

Incluso una posición de fuerza también nos da mejor opción que los demás a ser "líder", a estar atento a los problemas laborales individuales y de equipo con objeto de encaminarlos hacia los resultados de deseados, a motivarlos para que se impliquen en la tarea y acometan nuevos proyectos con empeño. En otras palabras, la función de un líder está relacionada con servir al equipo; esto es, estar para solucionar los problemas de los equipos, no para crearlos. A este respecto y en la medida de lo posible, debe fomentar la felicidad de los trabajadores.

Para los que quieren buscar un beneficio práctico en esta conducta, la felicidad de los trabajadores no hay que perseguirla necesariamente por utopías ni normas morales, sino como contraposición a la infelicidad. Un trabajador infeliz está escasamente motivado. Para un trabajador a disgusto, la empresa representa en exclusiva las horas en las que deja de hacer otras cosas. Este sentimiento es, en el mejor de los casos, neutro, y eventualmente hostil.

¿Merece la pena invertir en la felicidad de los trabajadores? Indudablemente sí. Ya sólo por el hecho de tener el poder de conseguir que las personas que trabajan satisfactoriamente vuelvan más contentos a su casa merece la pena plantearlo. En cuanto a los intereses empresariales, a la larga se pierden más recursos en lograr que los trabajadores desmotivados respondan bien que lo que se invertiría tratando de aportar un ambiente laboral que potencie la felicidad. Entre otros motivos, esto es debido a que las acciones correctivas tomadas para conseguir que quienes no quieren trabajar trabajen suelen derivar en recorte de condiciones tanto para pecadores como para justos. El resultado es que quienes no trabajaban antes siguen sin trabajar y los que trabajaban antes sienten que se les castiga sin motivo. La degradación de la motivación de los trabajadores sigue una progresión geométrica.

En contra de lo que puede parecer, un ambiente feliz no requiere de futbolines o salas de masajes. Tampoco de subidas de sueldo ni de más días de vacaciones. Esos beneficios se aprecian los primeros meses, pero a continuación se convierten en un derecho adquirido: si mi jefe, mi empresa o mi entorno me hacen sentir mal sistemáticamente, me sentiré mal cobre lo que cobre, porque el dinero no puede suplir todo el tiempo una mala emoción; es como mezclar peras con manzanas.

jueves, 18 de febrero de 2021

No confundas al cliente con el usuario

Existen dos diferencias fundamentales entre el cliente y el usuario: la primera, de índole técnica, reside en que el cliente no va a enfrentarse con el sistema una vez implantado (a menos que también sea usuario); la segunda, derivada de la primera, es que mientras que el cliente suele desear que el proyecto sea un éxito, esto no siempre sucede con los usuarios.

¿Por qué? El origen pasa por un problema interno de la empresa, en general de comunicación y motivación. Comunicación porque tal vez no se les explica a los trabajadores el interés de la empresa por cambiar el sistema actual o instalar uno nuevo. Y motivación porque exista un problema de personal previo a la decisión, se excluya al usuario final de la planificación y/o el usuario piense que el cambio no servirá para nada, perjudicará su trabajo diario e incluso pondrá en peligro su estabilidad laboral.

Independientemente de cuáles sean las peculiaridades de la empresa y la actitud inicial de los usuarios, ganárselos es tan importante como conseguir mantener la implicación del cliente. Muchos proyectos finalizados, entregados, probados y perfectamente funcionales ni siquiera han empezado a utilizarse por la negativa de los usuarios y la desidia de la dirección ante esta actitud. La muerte por inanición de los programas es un peligro real, y más habitual de lo que sería deseable.

Así pues, no hay que escatimar recursos para estar cerca de los usuarios, conocer sus problemas con los sistemas actuales y qué esperan de la solución que se está desarrollando. Busca a la persona con más carisma de tu equipo de trabajo y acércalo a quienes en última instancia y en el mejor de los casos tratarán directamente con la aplicación, que les muestre los prototipos tal y como se les envían al cliente, y que comunique y tenga en cuenta cualquier sugerencia que escuchada.

viernes, 12 de febrero de 2021

Gestión de mensajes

La gestión eficiente de mensajes merece una atención especial en el campo de la construcción de software por dos razones: reutilización y, opcionalmente, internacionalización. La reutilización es común a todas las aplicaciones; resulta tedioso tener que escribir un mensaje de error varias veces a lo largo de un programa. Respecto a la internacionalización, la escritura de dicho texto directamente en el código fuente hace inviable que el sistema pueda traducirse a otros idiomas.

Existen dos formas de optimizar la gestión de mensajes: una, dependiente del entorno de desarrollo, consiste en utilizar archivos de recursos específicos de aquél en los cuales pueden definirse diferentes mensajes en varios idiomas; la otra, independiente, utiliza archivos propios o tablas en la base de datos para la gestión de mensajes. Me centraré en la segunda, al ser más general, teniendo en cuenta que no todos los entornos facilitan el trabajo con archivos de recursos.

La solución es tan sencilla como definir una serie de tablas como las siguientes: 

Tabla

Campo

Tipo

Error

Id

int32

Id_Language

int32

Code

int32

Message

varchar(512)

 

 

 

Tabla

Campo

Tipo

Language

Id

int32

Name

varchar(32)   

donde a continuación se muestran valores de ejemplo:

Id

Id_Language

Code

Message

1

1

1

El valor {0} de la variable/parámetro '{1}' debe estar en el rango {2}.

2

1

2

La variable/parámetro '{0}' no puede ser nulo o vacío.

3

2

2

Variable/parameter '{0}' can't be null or empty.

[...]

[...]

[...]

[...]

Id

Name

1

Spanish

2

English

[...]

[...]

De igual modo, se crea una clase Error con un código similar al propuesto (en este caso, en C#):


public static class Error
{
  // Deben corresponderse a los identificadores equivalentes
  // de la tabla Error

  public enum EError { InvalidRange = 1, EmptyOrNull = 2, […] }
  public enum EErrorType { Error, Fatal }

  public void PrintError(EError eError, params Object[] aoValue) {
    Print(EErrorType.Error, eError, aoValue);
  }

  public void PrintFatal(EError eError, params Object[] aoValue) {
    Print(EErrorType.Fatal, eError, aoValue);
  }

  private void Print(EErrorType eErrorType, EError eError,
    params Object[] aoValue) {
    MessageBox.Show(Messaje(eError, aoValue), ErrorType(eErrorType));
  }

  prívate string ErrorType(EErrorType eErrorType) {
    return eErrorType == EErrorType.Error ? "Error" : "Fatal";
  }

  private string Message(EErrorType eErrorType, EError eError,
    params Object[] aoValue) {
    return String.Format(MesssagePattern(eError), oValue);
  }

   private string MessagePattern(EError eError) {
    return (Database.MessajeError((int)eError,
      (int)Config.CurrentLanguage).ToString();
  }
}

Donde Database y Global son clases estáticas para acceso a información de la base de datos (en este caso, el mensaje del error) y para almacenar la información de configuración de la aplicación, respectivamente.


Con este código y el correspondiente cuidado al cargar la tabla en la base de datos, pueden gestionarse fácilmente los mensajes de error. Asimismo, la modificación del texto de los mensajes de error y la inclusión de nuevos idiomas no necesita la parada del sistema.

martes, 2 de febrero de 2021

Excepciones

 A diferencia de las aserciones referidas en entradas previas, las excepciones sí son esperadas durante la ejecución, si bien son infrecuentes y no se sabe cuándo aparecerán. Otra diferencia con las aserciones es que las excepciones son (o deben ser) disparadas por fuentes externas al programa y no controlables por el programador.

También es frecuente utilizarlo para el control de variables de entrada en métodos públicos y que pueden ser invocados desde la interfaz de usuario:

public void SaveVehicle(string sPlate, string sBrand){

    if (sPlate == null || sPlate == '')
        throw new ArgumentException(Error.Message(
            Error.EError.EmptyValue, "
sPlate"));

    if (sBrand == null ||
sBrand == '')
        throw new ArgumentException(Error.Message(
            Error.EError.EmptyValue, "sBrand"));

    […]
}

Esta solución está supeditada a que el método sea público: si el método es privado, se da por hecho que los valores usados para invocarlo han sido depurados y, por tanto, se utilizarían aserciones.  

Por último, debe recordarse que las excepciones se utilizan para controlar comportamientos no esperados y que rompen el orden de ejecución natural de un proceso. No deben utilizarse para controlar el flujo esperado del programa. Por ejemplo, al encontrar un carácter de fin de archivo esperado no ha de lanzarse una excepción para cerrar el archivo, al ser esto parte natural del proceso; un condicional es más correcto y óptimo.