Archive for marzo 2011
Motivación o imposición

Los tiempos que corren son tremendamente competitivos, donde los márgenes son ajustados, los plazos cortos y la exigencia de calidad y funcionalidad es muy alta. Es por ello que a todo responsable de equipos o proyectos le exigen más eficiencia y por lo tanto un aumento de la productividad.
Pero mi pregunta es... ¿cómo?
Por otro lado tenemos, de forma general, gente menos motivada, faltos de ilusión y como consecuencia, faltos de compromiso. Personalmente percibo en mis compañeros de trabajo (algunos ya son ex compañeros) que este año pasado, no han recibido el reconocimiento que esperaban... ¿tenemos falsas expectativas?, ¿nos valoran de manera objetiva y justa?, es evidente que la situación económica de las empresas, condiciona las valoraciones y las mejoras retributivas al personal...entonces...¿es realmente justo? ¿Es justo que se estanquen o deceleren las carreras profesionales por causas ajenas a tu actividad laboral?, no obstante creo que es algo que debemos intentar comprender y saber razonar.
¿Mejorar la productividad? Ummm, no dejo de darlo vueltas... pero la pregunta sigue siendo: ¿cómo? ... seguro que tiene que haber alguna fórmula...
El caso es que mi jefe me dijo hace unos días: "Este año tenemos que mejorar la productividad de los equipos un 10%" y el eco resuena en mi cabeza "diezporciento, zporciento, ciento, ento, ento..."
Eso se traduce en que cada miembro de cada equipo tiene que ser más productivo en su especialidad (el programador, el analista, el tester, el diseñador...), es decir que tienen que hacer el mismo trabajo pero un 10% más rápido, por lo tanto tenemos que terminar la ejecución de las tareas cuando estas lleguen al 90% de la estimación.

foreach persona in equipos.personas
{
persona.productividad += 10%;
}
Ojala tratar con personas fuese tan fácil como tratar con máquinas...
Para construir software tenemos: Personas, Herramientas y Procesos.
Y el objetivo es hacer software en plazo, funcionalidad y con un coste de un 10% menos.
(Cómo veis he colocado a los individuos y su interacción por encima de los procesos y herramientas)... Es que desde hace algún tiempo hago unos estiramientos todas las mañanas y me estoy volviendo muy ágil.
Las herramientas son las que nos proporciona el mercado, unas mejoras, otras peores, más productivas, menos... son las que son y están las que están, y ¡creedme! No se ha incrementado tanto la productividad como aseguraban las campañas de marketing con cada versión de Visual Studio.
Los procesos los define tu metodología de desarrollo y están muy depuradas y optimizadas, solo tenemos que seleccionar una e incorporar esos procesos.
Yo creo que la clave está en las personas... Hace tiempo leí que para ser ágil había que serlo con las personas adecuadas http://www.elraul.com/?p=812 ¡Y estoy de acuerdo!
Pero es evidente que el Racing de Santander no puede prescindir de todos sus jugadores y contratar a los Ronaldinhos de turno. ¡Hay que mejorar la productividad de la gente que tienes! (salvo excepciones)
Pero mi pregunta es... ¿cómo? ¿Motivación o imposición?
Yo tengo muy clara esta disyuntiva, creo que la motivación es el mejor remedio para aumentar la productividad. Mi opinión es que de la imposición obtienes beneficios instantáneos, pero la productividad desciende de manera exponencial en el tiempo. Esta conclusión es a la que llego, haciendo memoria y examen de conciencia, al experimentar estas dos técnicas sobre mi propio trabajo. Mi experiencia profesional ha sido mas enriquecedora, creativa y productiva cuando mas motivado me he encontrado, cuando he percibido un alto nivel de confianza y la presión ha sido la justa y necesaria. Por otro lado, cuando he recibido imposición, he intuido desconfianza y eso ha implicado desmotivación. Entiendo que no todas las personas somos iguales, ni reaccionamos de la misma forma a los agentes externos, pero sí creo que para profesiones que requieren un alto grado de pericia, creatividad y concentración es muy necesario sentirse motivado.
¿Todavía sigues leyendo? ... ¡qué bien! Porque hasta ahora no he dicho nada interesante, pero ahora viene mi propuesta para combatir la baja productividad.
¿Qué factores mejoran la motivación?

En realidad no he conseguido realizar una ordenación que me satisfaga, así que lo dejaré así tal y como se ve en la pirámide y espero que me hagas un comentario con el orden que estimes e incluyas alguno que falte, ya que esto es algo muy personal.

Todos estos factores hay que cruzarlos con el índice de motividad (lo acabo de buscar en google y no sale nada así que me apropio el término y el copyright ;)), que no es más que la capacidad y facilidad que tiene una persona para ser motivada, generalmente ausente en personas negativas. Además los seres humanos seguimos un axioma que define nuestro comportamiento y es que se basa en estados de ánimo, es por ello que este factor también influye de forma considerable.
- Interés en el proyecto: Tenemos que intentar conseguir proyectos interesantes y asignarlos a las personas menos motivadas y con un índice de motividad alto. Es necesario que lo vean como una oportunidad para expresar su capacidad. Por supuesto esto varía dependiendo de los intereses de cada uno, por eso es importante conocer a las personas, averiguar sus intereses y tener comunicación continua.
- Formación y conocimiento recibido: Es muy importante que la gente se forme en cursos o de compañeros de más nivel y aprenda nuevas tecnologías y técnicas de desarrollo. Creo que este aspecto nos diferencia de otras profesiones, la necesidad imperiosa del reciclaje tecnológico.
- Ambiente de trabajo: Para mejorar el ambiente de trabajo es necesario transmitir cercanía, cordialidad y compañerismo, no excederse en la presión, promover la justicia entre compañeros y evitar las rivalidades y enfrentamientos. En definitiva tratar de crear un grupo de compañeros que tengan un objetivo común y velen por su cumplimiento de una forma agradable.
- Salario percibido: Esto es lo más complicado pero creo que dentro de nuestras posibilidades tenemos que intentar ser justos y evidenciar y notificar las injusticias en este aspecto.
- Responsabilidad y confianza: Dar responsabilidad a alguien denota confianza y por lo tanto es una compensación y una expresión de un trabajo previo bien hecho.
- Horario flexible: La diferencia entre un trabajo manufacturero y uno artístico, como es la construcción de software, reside en el número de decisiones que se toman por unidad de tiempo, y para tomar esas decisiones de la manera más eficiente debemos tener un estado mental de alta concentración, es por ello que aunque sí es bueno que tengamos un horario marco de trabajo, no debamos ceñirnos a él, al son de una bocina.
- Evolución profesional: Es importante generar perspectivas de crecimiento profesional en las personas, mantener un cierto grado de ilusión, por una progresión, que, aunque no sea inmediata es algo que se valora a la hora de elegir un empleo y creo que también influye en la motivación, al menos a mi me influye. También es importante para tu propio crecimiento, que el equipo crezca contigo.
En resumen, ¡motivación! ¡motivación! y ¡motivación! es la mejor gasolina para mover el motor de la creatividad y productividad.
Me satisface enormemente que hayas llegado al final de la lectura... ahora me gustaría saber tu opinión.
¿estás de acuerdo con este planteamiento?
WHERE IN con LINQ
//Si usamos Linq2SQL usar
NorthwindDataContext nc = new NorthwindDataContext();
NorthwindEntities ne = new NorthwindEntities();
var suppliers = from s in ne.Suppliers
where (s.CompanyName.StartsWith("E"))
select s.SupplierID;
int[] supplierIDs = suppliers.ToArray();
var products = from p in ne.Products
where (supplierIDs.Contains((int)p.SupplierID))
select p;
XNA Pong game
Muy simple y solo como ejemplo de la primera aplicación que hice.
Crear el proyecto
Crear los sprites con los que se jugara, muy simples ya que solo están como ejemplo:
Crear la clase que manejara a los jugadores: Paddle
- /// <summary>
- /// Creata una paleta
- /// </summary>
- class Paddle
- {
- /// <summary>
- /// Variable con la posicion
- /// </summary>
- public Point pos;
- /// <summary>
- /// Velocidad de la paleta
- /// </summary>
- public int speed;
- /// <summary>
- /// Constructor
- /// </summary>
- /// <param name="x"></param>
- /// <param name="y"></param>
- public Paddle(int x, int y)
- {
- /// La paleta inicia en la posicion que se le pase al constructor
- pos = new Point(x, y);
- /// Velocidad por defecto
- speed = 3;
- }
- }
Crear la clase que maneja el objeto : Ball
- /// <summary>
- /// Creaa un objeto con la pelota
- /// </summary>
- class Ball
- {
- /// <summary>
- /// Posicion de la pelota
- /// </summary>
- public Point pos;
- /// <summary>
- /// Velocidad horizontal y vertical
- /// </summary>
- public int h_speed, v_speed;
- /// <summary>
- /// Constructor
- /// </summary>
- /// <param name="x"></param>
- /// <param name="y"></param>
- public Ball(int x, int y)
- {
- /// La posicion inicial de la pelota se le pasa al constructor
- pos = new Point(x, y);
- /// La velocidad inicial y la direccion es randomica
- Random rand = new Random();
- h_speed = rand.Next(3, 7);
- if (rand.Next(0, 2) == 0) h_speed *= -1;
- rand = new Random();
- v_speed = rand.Next(3, 7);
- if (rand.Next(0, 2) == 0) v_speed *= -1;
- }
- }
En la clase Game1.cs, crear variables que contengan a los “jugadores” y la pelota, además una variable que maneje generación de valores randomicos y una con el estado del teclado.
- GraphicsDeviceManager graphics;
- SpriteBatch spriteBatch;
- Texture2D t_paddle1, t_paddle2, t_ball;
- Paddle paddle1;
- Paddle paddle2;
- Ball ball;
- Random rand = new Random();
- KeyboardState currentState;
Crear un método que inicializa las posiciones de los Sprites en el juego, se llama ResetGame, e incluimos una llamada desde el constructor:
- /// <summary>
- /// Allows the game to perform any initialization it needs to before starting to run.
- /// This is where it can query for any required services and load any non-graphic
- /// related content. Calling base.Initialize will enumerate through any components
- /// and initialize them as well.
- /// </summary>
- protected override void Initialize()
- {
- // TODO: Add your initialization logic
- base.Initialize();
- ResetGame();
- }
- /// <summary>
- /// Inicializa los valores del juego
- /// </summary>
- void ResetGame()
- {
- paddle1 = new Paddle(10, 200);
- paddle2 = new Paddle(770, 200);
- ball = new Ball(385, 285);
- }
En el método LoadContent, que se ha generado automáticamente agregamos la carga de nuestros Sprites:
- /// <summary>
- /// LoadContent will be called once per game and is the place to load
- /// all of your content.
- /// </summary>
- protected override void LoadContent()
- {
- // Create a new SpriteBatch, which can be used to draw textures.
- spriteBatch = new SpriteBatch(GraphicsDevice);
- // TODO: use this.Content to load your game content here
- t_paddle1 = Content.Load<Texture2D>("paddle");
- t_paddle2 = Content.Load<Texture2D>("paddle");
- t_ball = Content.Load<Texture2D>("ball");
- }
En el método Draw, agregamos:
- /// <summary>
- /// This is called when the game should draw itself.
- /// </summary>
- /// <param name="gameTime">Provides a snapshot of timing values.</param>
- protected override void Draw(GameTime gameTime)
- {
- GraphicsDevice.Clear(Color.CornflowerBlue);
- // TODO: Add your drawing code here
- spriteBatch.Begin();
- spriteBatch.Draw(t_paddle1, new Rectangle(paddle1.pos.X, paddle1.pos.Y, t_paddle1.Width, t_paddle1.Height), Color.CornflowerBlue);
- spriteBatch.Draw(t_paddle2, new Rectangle(paddle2.pos.X, paddle2.pos.Y, t_paddle2.Width, t_paddle2.Height), Color.CornflowerBlue);
- spriteBatch.Draw(t_ball, new Rectangle(ball.pos.X, ball.pos.Y, t_ball.Width, t_ball.Height), Color.CornflowerBlue);
- spriteBatch.End();
- base.Draw(gameTime);
- }
Si se compila y ejecuta en este momento, tenemos el siguiente resultado:
Movimientos Humano y Computadora, Detección de colisiones
Dado que se jugara HumanoVsComputadora, lo primero que se hace es capturar la entrada de teclado y actualizar el movimiento de la paleta del Humano, además validamos que no salgamos de los límites de la ventana, esto lo hacemos desde un nuevo método, UpdatePaddles:
- void UpdatePaddles()
- {
- /// Capturamos las pulsaciones del teclado
- currentState = Keyboard.GetState();
- Keys[] currentKeys = currentState.GetPressedKeys();
- /// Solo hacer caso de las teclas que requerimos
- foreach (Keys key in currentKeys)
- {
- if (key == Keys.Up)
- paddle1.pos.Y -= paddle1.speed;
- if (key == Keys.Down)
- paddle1.pos.Y += paddle1.speed;
- if (key == Keys.Escape)
- this.Exit();
- }
- /// Varificar que no salimos de la ventana
- if (paddle1.pos.Y <= 10) paddle1.pos.Y = 10;
- if (paddle2.pos.Y <= 10) paddle2.pos.Y = 10;
- if (paddle1.pos.Y + t_paddle1.Height >= Window.ClientBounds.Height - 10)
- paddle1.pos.Y = Window.ClientBounds.Height - t_paddle1.Height - 10;
- if (paddle2.pos.Y + t_paddle2.Height >= Window.ClientBounds.Height - 10)
- paddle2.pos.Y = Window.ClientBounds.Height - t_paddle2.Height - 10;
- }
La “inteligencia” de la computadora, se reduce a que su paleta sigue la posición Vertical de la pelota, por lo que el anterior método quedaría así:
- void UpdatePaddles()
- {
- /// Capturamos las pulsaciones del teclado
- currentState = Keyboard.GetState();
- Keys[] currentKeys = currentState.GetPressedKeys();
- /// Solo hacer caso de las teclas que requerimos
- foreach (Keys key in currentKeys)
- {
- if (key == Keys.Up)
- paddle1.pos.Y -= paddle1.speed;
- if (key == Keys.Down)
- paddle1.pos.Y += paddle1.speed;
- if (key == Keys.Escape)
- this.Exit();
- }
- /// La paleta de la computadora solo sigue a la pelota
- paddle2.speed = ball.h_speed;
- if (paddle2.pos.Y + (t_paddle2.Height / 2) > ball.pos.Y)
- paddle2.pos.Y -= paddle2.speed;
- else if (paddle2.pos.Y + (t_paddle2.Height / 2) < ball.pos.Y)
- paddle2.pos.Y += paddle2.speed;
- /// Varificar que no salimos de la ventana
- if (paddle1.pos.Y <= 10) paddle1.pos.Y = 10;
- if (paddle2.pos.Y <= 10) paddle2.pos.Y = 10;
- if (paddle1.pos.Y + t_paddle1.Height >= Window.ClientBounds.Height - 10)
- paddle1.pos.Y = Window.ClientBounds.Height - t_paddle1.Height - 10;
- if (paddle2.pos.Y + t_paddle2.Height >= Window.ClientBounds.Height - 10)
- paddle2.pos.Y = Window.ClientBounds.Height - t_paddle2.Height - 10;
- }
Ahora se requiere mover la pelota, se lo hace desde un nuevo método UpdateBall:
- void UpdateBall()
- {
- /// Actualiza la posicion de la pelota
- ball.pos.X += ball.h_speed;
- ball.pos.Y += ball.v_speed;
- /// Verificar limites
- /// Inferior
- if (ball.pos.Y > (Window.ClientBounds.Height - 10 - t_ball.Height))
- ball.v_speed *= -1;
- /// Superior
- if (ball.pos.Y < 10)
- ball.v_speed *= -1;
- }
Finalmente implementamos un “detector de colisiones”, que simplemente compara las posiciones de los Sprites de la pantalla, y según eso calcula la nueva dirección de la pelota, velocidad después de “golpearla” y si una de las paletas no ha alcanzado a golpear la bola, en cuyo caso el juego comienza de nuevo, llamando al método ResetGame:
- void CheckCollisions()
- {
- /// Verificar si la pelota esta yendo a la izquierda
- if (ball.h_speed < 0)
- {
- /// Verifica si la pelota a rebasado la paleta
- if (ball.pos.X < paddle1.pos.X + 20)
- {
- /// Si la pelota no fue golpeada, fin del juego
- if ((ball.pos.Y + t_ball.Height < paddle1.pos.Y) || (ball.pos.Y > paddle1.pos.Y + t_paddle1.Height))
- {
- ResetGame();
- }
- else
- {
- /// Se golpea la pelota, se cambia su direccion
- /// y se le da una velocidad inicial randomica, entre 3 y 7
- if (ball.h_speed < 0)
- ball.h_speed = rand.Next(3, 7);
- else ball.h_speed = rand.Next(-6, -2);
- if (ball.v_speed < 0)
- ball.v_speed = rand.Next(3, 7);
- else ball.v_speed = rand.Next(-6, -2);
- }
- }
- }
- else
- {
- /// Verifica si la pelota a rebasado la paleta
- if (ball.pos.X + t_ball.Width > paddle2.pos.X)
- {
- /// Si la pelota no fue golpeada, fin del juego
- if ((ball.pos.Y + t_ball.Height < paddle2.pos.Y) || (ball.pos.Y > paddle2.pos.Y + t_paddle2.Height))
- {
- ResetGame();
- }
- else
- {
- /// Se golpea la pelota, se cambia su direccion
- /// y se le da una velocidad inicial randomica, entre 3 y 7
- if (ball.h_speed < 0)
- ball.h_speed = rand.Next(3, 7);
- else ball.h_speed = rand.Next(-6, -2);
- if (ball.v_speed < 0)
- ball.v_speed = rand.Next(3, 7);
- else ball.v_speed = rand.Next(-6, -2);
- }
- }
- }
- }
Implementamos la lógica de actualización del juego, desde le método Update:
- /// <summary>
- /// Allows the game to run logic such as updating the world,
- /// checking for collisions, gathering input, and playing audio.
- /// </summary>
- /// <param name="gameTime">Provides a snapshot of timing values.</param>
- protected override void Update(GameTime gameTime)
- {
- // Allows the game to exit
- if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
- this.Exit();
- // TODO: Add your update logic here
- UpdatePaddles();
- UpdateBall();
- CheckCollisions();
- base.Update(gameTime);
- }
F5 y a jugar!
Los fuentes, aquí:
Importar archivos de texto con LINQ
Zanahorias, 5,0 .50Naranjas, 6, 1.25Manzanas, 7, 2.50
1: public static IEnumerable<string> ReadLinesFromFile(string filename)2: {3: using (StreamReader reader = new StreamReader(filename))4: {5: while (true)6: {7: string s = reader.ReadLine();8: if (s == null)9: break;10: yield return s;11: }12: }13: }
1: var products = from line in ReadLinesFromFile(@"c:\import.txt")2: let item = line.Split(’,’)3: select new4: {5: Producto = item[0],6: Cantidad = Convert.ToInt32(item[1]),7: Precio = Convert.ToDecimal(item[2]),8: Total = Convert.ToInt32(item[1]) * Convert.ToDecimal(item[2])9: };
Y finalmente pasamos el resultado a un DataGrid:
1: GridView1.DataSource = products;2: GridView1.DataBind();
Hola mundo con Smart Client Software Factory
- Crear un nuevo proyecto de aplicación de Smart Client
- En Visual Studio 2010, seleccione Nuevo en el menú Archivo y, a continuación, haga clic en Project.
- En el cuadro de diálogo New Project Smart Client Development.
- Seleccione la aplicación Smart Client (C #) Visual Studio template.
- En el cuadro Nombre, escriba HelloWorldApplication, a continuación, haga clic en Aceptar.
- En el asistente, acepte la configuración predeterminada, seleccione Show documentation after recipe completes y a continuación, haga clic en Finish.
- Crear un módulo de Hello World
- En el Explorador de soluciones, haga clic en la solución, seleccione Smart Client Software Factory, a continuación, haga clic en Add Business Module (C#).
- En el cuadro de diálogo Agregar nuevo proyecto, HelloWorldModule en el cuadro Nombre.
Haga clic en Aceptar. - En el asistente, acepte la configuración predeterminada, seleccione Show documentation after recipe completes y a continuación, haga clic en Finish.
- Añadir la vista
- En el Explorador de soluciones, haga clic en HelloWorldModule, seleccione Smart Client Software Factory, a continuación, haga clic en Add View (with presenter).
- En el cuadro de diálogo Add View (with presenter), escriba HelloWorldView en el cuadro Ver, seleccione Show documentation after recipe completes y a continuación, haga clic en Finish.
- En el Explorador de soluciones, haga doble clic en el archivo HelloWorldView.cs para poder ver el Diseñador. Arrastre un cuadro de texto en la vista, y escribir Hola Mundo.
- Configurar HelloWorldView para mostrar la vista en el Shell
- En el Explorador de soluciones, abrir ModuleController.cs en el proyecto HelloWorldModule.
- Agregue el siguiente código .
- using HelloWorldApplication.Infrastructure.Interface.Constants;
- En el método AddViews agregue el siguiente código.
- HelloWorldView hwview = ShowViewInWorkspace< HelloWorldView >(WorkspaceNames.RightWorkspace);
- F5 compilar y ejecutar...