jueves, 14 de noviembre de 2013

Capítulo 1 de libro examen para certificación 70-536 en español

El Examen 70-536 de nombre TS: Microsoft .NET Framework - Application Development Foundation de Microsoft, liberado el 21 de Marzo del 2008, y que actualmente no está vigente, pero sin embargo, es uno de los mejores libros (a mi gusto) donde están los fundamentos de la programación en .Net, específicamente del Framework 2.0 y por ende una sólida base para los que trabajamos con las siguientes versiones del Framework como la versión 4.0 o 4.5.

Cuando estudié para esta certificación que finalmente no di (de flojo), lo hice con el libro oficial MCTS Self-Paced Training Kit (Exam 70-536): Microsoft® .NET Framework Application Development Foundation, Second edition que en Amazon está en 43,54 dolares unos 21 mil, más el envío a Chile dan un costo total aproximado calculo de unos 28 mil, pero que pillas en Google fácilmente con la palabra clave "70-536 pdf", bueno cuando estudié, realizaba la traducción/transcripción del libro ya que para mí me salía más fácil entender. Este es el primer capítulo, lecciones 1, 2, 3 y 4 traducido al español y que quiero compartir con ustedes ya que lo tenía botado en mi viejo baúl en dropbox:

Leyenda
F: Framework

CAPÍTULO 1 : Fundamentos del Framework

Lección 1: Tipos por Valor

  • String no es por Valor, sino por Referencia.
  • Al usarse una variable por valor en un procedimiento, se hace una copia de esta, por lo que si se hacen cambios adentro, no se ve afectado la variable al salir
  • Son valores chicos, usan 16 bytes o menos cada uno. Son altamente performantes
  • Tipos de datos numéricos y bool son tipos por valor
  • Son datos datos que están directos en memoria, en una zona llamada "Pila"
  • Hay 3 tipos:

1. Build-in: los da el Framework
A. Numéricos: optimizado para Int32, UInt32 y Double
    System.Sbyte -128 a 127
    System.Byte 0 a 255
    System.Int32 / Int C#, Integer en VB –2147483648 a 2147483647   -> Int32 es una estructura y no una clase (ya que esta ultima es un tipo de dato por referencia)
    System.UInt32 0 a 4294967295
    Int64 –9223372036854775808 a 9223372036854775807
    Single –3.402823E+38 a 3.402823E+38
    Double –1.79769313486232E+308 a 1.79769313486232E+308   (más preciso)
    Decimal: –79228162514264337593543950335 a 79228162514264337593543950335   (cientifico/estadistico)
            IntCtr permite que el largo lo defina el SO por ej. Windows 32 o 64 bits, puede ser mas largo o mas corto que el numero que que lo del int
      B. Otros
      System.Char letras unicode
      System.Boolean true/false
      System.IntPr         puntero a memoria
      System.DateTime      momentos en el tiempo

      - Se autodeclaran, tienen implícito un constructor, no requieren new. El constructor le asigna un nulo o 0, pero siempre se debe inicializar. Ejemplo: Bool test = false;
      - C# es case-sensitive, Visual Basic no.
      - Declarar un objeto nulo cuando no se quiere inicializar, se puede usar la sentencia Nullable:
         Nullable b = null;   
         //en C# permite igual   
         bool? b = null;   
         //o también
         int? i = null;
      
      - Para ver si un objeto nullable tiene valor, usar HasValue:
         if (b.HasValue)
      

      2. User-defined
      - Son Estructuras o structs, contienen otros tipos de datos, por ej:
         System.Drawing.Point p = new System.Drawing.Point(20, 30);   // Point es Value Type
      
      - Se pueden crear con la palabra "struct", estas SOLO tienen tipos por VALOR
          struct Cycle
          { 
           int _val, _min, _max;
       
           public Cycle(int min, int max)
           {
           _val = min;
           _min = min;
           _max = max;
           }
      
      - Se puede convertir a tipo por Referencia cambiando Struct por Class, se puede tener 2 variables apuntando a la misma dirección de memoria, quedando en una zona llamada HEAP de la memoria.
      - Al hacer esto se almacena fuera de los 12 bytes de la pila.
      - Usualmente las estructuras son mas eficientes que las clases. Deberías definir estructuras si el tipo anda mejor como tipo por valor que por referencia.
      - Se debe escoger una estructura SOLO si: Lógicamente es como tener un simple valor, tiene un tamaño menor a 16 bytes, no cambiara luego de su creación, no usa tipos por referencia SOLO por Valor.

      3. Enumeraciones
         public enum Genders : int { Male, Female };
         public Genders gender;
      

      Lección 2: Tipos por Referencia

      -La mayoría de los tipos del F son por referencia.
      -Se guarda la dirección de los datos en memoria, no los datos en si, un "puntero" en la pila, en una zona llamada HEAP.
      -El F maneja lo que esta en el HEAP con el Garbaje collector o GC, este escanea la memoria en busca de valores no referenciados.
      -El GC se gatilla cuando el F lo necesita o cuando se ejecuta GC.Collect.
      -Al tener una variable por referencia, si tengo otra que le asigno el valor, en verdad es la copia de la dirección no del valor. Ejemplo:
        struct Numbers
        {
         public int val;
         public Numbers(int _val)
         { val = _val; }
         public override string ToString()
         { return val.ToString(); }
        }  
        Numbers n1 = new Numbers(0);   // -> Numerse es una variable por referencia
        Numbers n2 = n1;
        n1.val += 1;
        n2.val += 2;
        Console.WriteLine("n1 = {0}, n2 = {1}", n1, n2);  // -> N1: 1  N2: 2
        
        Si lo cambiamos a Clase: 
        
        // C#
        Class Numbers
        {
        ... 
      
      La salida es ----> N3: 3 N2: 3 ya que ambos apuntan a la misma dirección no al valor en si. La modificar la referencia, se modifican todas las copias de la referencia.
      Weak refference: es una referencia débil o que puede ser eliminada por el Garbaje Collector a pesar de usar usada y no asignada a null que es cuando el garbaje collector debería eliminarla.
      - Hay 2500 tipo por referencia build-in en el F. No todos derivan del System.ValueType.
      - Tipos por referencia mas comunes: System.Object, System.String, Systen.Text.TextBuilder, System.Array, System.IO.Stream, System.Exception.
      - No todos los tipo de objetos que derivan de System.Object son tipo de objetos por referencia. Puede derivar objeto de tipo por Valor.
      - Strings y String Builders: proveen manipulación de datos.
      - Es mejor usar StringBuilder en vez de String cuando se quiere armar un gran string con pedazos de string mas chicos. No así cuando se quiere buscar o reemplazar.
      -String soporta 32,767 bytes.
         string s = "this is some text to search";  
         s = s.Replace("search", "replace");
      
      -Los string son inmutables en .Net, es decir, cualquier cambio en ellos genera un nuevo string y el viejo pasa a ser marcado como listo para eliminar por el GC. Ejemplo:
         // C#
         string s;
         s = "wombat"; // "wombat"
         s += " kangaroo"; // "wombat kangaroo"
         s += " wallaby"; // "wombat kangaroo wallaby"
         s += " koala"; // "wombat kangaroo wallaby koala" 
      - Solo el último vale y tiene una referencia, los otros se eliminaran por el GC.
      - No tener esos string intermedios ayuda al performance ya que evita que el GC trabaje.
      - Para evitar string intermedios, se puede usar:
      - Métodos Concat, Join o Format de la clase String.
      - Usar clase StringBuilder para trabajar con varios "mutables" strings.
         System.Text.StringBuilder sb = new System.Text.StringBuilder(30);
         sb.Append("wombat"); // Build string.
         sb.Append(" koala");
         string s = sb.ToString(); // Copy result to string.
      
      -La clase String permite sobreescribir operadores de System.Object:
         suma vb + o &  C# +
         igualdad vb =  C# ==
         no igualdad vb <>  c# !=
         asignación vb y c# =
      
      - Como crear y ordenar Arreglos:
         int[] ar = { 3, 1, 2 };   
         Array.Sort(ar);   
         //mostramos los resultados:  
         Console.WriteLine("{0}, {1}, {2}", ar[0], ar[1], ar[2]);
      

      Como crear y usar Streams
      - Los streams se usan para escribir datos en el disco o enviar paquetes por red.
      - El tipo base es System.IO.Stream de otros tipos.
      - Tipos stream para red se ubican en System.Network.Sockets
      - Stream encriptados estan en System.Security.Cryptography namespace.
      - Tipos stream comunes: FileStream, MemoryStream, StreamReader, StreamWriter.
      - StreamReader y StreamWriter te permite escribir y leer archivos del disco.
         use namespace System.IO
         // Escribe en un txt
         StreamWriter sw = new StreamWriter("text.txt");
         sw.WriteLine("Hello, World!");
         sw.Close();   
         // Lee un archivo y muestra
         StreamReader sr = new StreamReader("text.txt");
         Console.WriteLine(sr.ReadToEnd());
         sr.Close();
      

      Como lanzar y capturar Excepciones
      - Las excepciones son "eventos" inesperados que interrumpen la normal ejecución de un assembly.
      - Las excepciones no evitan que un software se caiga sino que sirve para uno se adelante y las capture y maneje
      - Ejemplo:
         use namespace System.IO
         try
         {
          StreamReader sr = new StreamReader(@"C:\boot.ini");
          Console.WriteLine(sr.ReadToEnd());
         }
         catch (Exception ex)
         {
          // If there are any problems reading the file, display an error message
          Console.WriteLine("Error reading file: " + ex.Message);
      
          //Este caso puede arrojar error: file not found error, insufficient privileges error
          //o un error al leer el archivo. Y la ejecucion "salta" al Catch.
         }
      
      - La clase base Exception es muy útil ya que contiene el mensaje de error y mas datos de la aplicación.
      - Uno puede hacer Excepciones propias derivando de System.ApplicationException.
      - Se pueden tener múltiples clases Exceptions para responder diferente a algún tipo de error, el F ejecutara el primer bloque Catch que coincida con el tipo de Exception definido.
      - Se deben ordenar las excepciones desde las mas especificas a la mas global, generalmente Exception.
         Try
          Dim sr As StreamReader = New StreamReader("text.txt")
          Console.WriteLine(sr.ReadToEnd)
          Catch ex As System.IO.FileNotFoundException
           Console.WriteLine("The file could not be found.")
          Catch ex As System.UnauthorizedAccessException
           Console.WriteLine("You do not have sufficient permissions.")
          Catch ex As Exception
           Console.WriteLine("Error reading file: " + ex.Message)
         End Try
      

      -El bloque try/catch soporta un bloque Finally que se ejecuta bien caiga o no en algún Catch. Se usa para cerrar Streams, o limpiar algún objeto.
         StreamReader sr = new StreamReader("text.txt");
         try
         {
          Console.WriteLine(sr.ReadToEnd());
         }
         catch (Exception ex)
         {
          // If there are any problems reading the file, display an error message
          Console.WriteLine("Error reading file: " + ex.Message);
         }
         finally
         {
          // Close the StreamReader, whether or not an exception occurred
          sr.Close();
         }
      

      - Fijarse que el primer bloque StreamReader sr ... se movió afuera del bloque try esto porque el bloque Finally NO pueda acceder a variables declaradas dentro del bloque Try.
      - En general se declaran la variables afuera del bloque try y en el bloque try se programa todo el codigo.
      - Usar un bloque try/catch tiene una baja penalidad en performance pero la tiene.
      - Ejemplo obtener tipo con IF (Object.GetType().IsValueType)
         SByte a = 0;
         Byte b = 0;
         Int16 c = 0;
         Int32 d = 0;
         Int64 e = 0;
         string s = "";
         Exception ex = new Exception();
         object[] types = { a, b, c, d, e, s, ex };
         foreach ( object o in types )
         {
          string type;
          if (o.GetType().IsValueType)
           type = "Value type";
          else
           type = "Reference Type";
          Console.WriteLine("{0}: {1}", o.GetType(), type );
         }
      

      - Unir elementos de un arreglo de string con espacio:
         string s = "Microsoft .NET Framework 2.0 Application Development Foundation";
         string[] sa = s.Split(' ');
         x = string.Join(" ", sa); -> vuelve a estar como antes.
      

      Lección 3: Construyendo clases

      ¿Qué es un Herencia?

      - La consistencia de clases se hace gracias a la herencia e interfaces.
      - La herencia sirve para crear clases a partir de otras o crear nuevos tipos a partir de otros.
      - Por ejemplo la clase Bitmap herada Image pero la extiende, por lo que tiene mas funcionalidades.
      - Puedes crear tu propia Excepcion heredando de System.ApplicationException.
      - Ejemplo obtener tipo con IF (Object.GetType().IsValueType)
         class DerivedException : System.ApplicationException
         {
           public override string Message
           {
             get { return "An error occurred in the application."; }
           }
         }
      
         //Puedes lanzar la exepcion con throw new 
         // C#
         try
         {
            throw new DerivedException();
         }
         catch (DerivedException ex)
         {
            Console.WriteLine("Source: {0}, Error: {1}", ex.Source, ex.Message);
         }
      
      - La nueva excepción tiene .Source por ejemplo ya que aunque no este implementado, al heredar de System.ApplicationException la tiene.
      - La herencia permite el intercambio de clases, por ejemplo si tenemos 5 clases que heredan de System.Drawing.Brush, si el método Graphics.DrawRectangle requiere un objeto System.Drawing.Brush, se le debe pasar alguno de los que heredan y no el padre.

      ¿Que es una interface?

      - Interfaces o "contrato" definen un conjunto común de miembros que todas las clases que la implementan deben proveer.
      - Por ejemplo la interfaz IComparable define el método CompareTo el cual permite comparar 2 clases. Entones todas las clases que implementen la interface IComparable, ya sean clases propias del F o clases tuyas, pueden ser comparadas por la igualdad.
      - La interfaz "IDisposable" es una interface que solo provee un método Dispose.
      - Permite que otros assemblys creen una instancia de tu clase y puedan liberar cualquier recurso que la instancia haya consumido.
      - Usa interface para definir un conjunto de miembros que DEBEN ser implementados por tipos asociados.
      - Permite a uno escribir código para liberar manualmente los recursos.
      - Ejemplo:
         class BigClass : IDisposable
         {
         }
      
      - Luego con Visual Studio, coloca el boton derecho en IDisposable -> Implement Interface -> Implement Interface y Visual Studio automáticamente coloca el código:
         public void Dispose()
         {
            throw new NotImplementedException();
         }
      
      - Otras interfaces muy usadas IComparable, IDisposable, IConvertible, ICloneable, IEquatable, IFormattable.
      - puedes crear tus propias interfaces por si quieres crear múltiples clases que tengan un comportamiento similar.
      - Ejemplo interfaz con 3 miembros:
         // C#
         interface IMessage
         {
         // Send the message. Returns True is success, False otherwise.
         bool Send();
         // The message to send.
         string Message { get; set; }
         // The Address to send to.
         string Address { get; set; }
         }
      
      - Si quieres implementar esa interfaz en tu clase, Visual Studio genera el siguiente template:
         class EmailMessage : IMessage 
         {
          public bool Send()
          {
          throw new Exception("The method or operation is not implemented.");
          }
          public string Message
          {
          get
          {
          throw new Exception("The method or operation is not implemented.");
          }
          set
          {
          throw new Exception("The method or operation is not implemented.");
          }
          }
          public string Address
          {
          get
          {
          throw new Exception("The method or operation is not implemented.");
          }
          set
          {
          throw new Exception("The method or operation is not implemented.");
          }
          }
         }
      
      - Visual Studio permite extraer o armar una Interfaz a partir de los métodos de una clase, con el 2do. botón sobre la clase dada (que puede o no heredar de una interfaz) -> Refactor -> Extract Interface -> seleccionas que miembro quieres extraer, ok
      - Las clases pueden implementar diferentes interfaces a la vez por ejemplo las interfases IComparable, IDisposable:
         class EmailMessage : IMessage, IComparable, IDisposable

      Clases Parciales
      - Son nuevas en .Net 2.0.
      - Permiten dividir una clase en múltiples archivos, con el beneficio de esconder detalles y enfocarse en los aspectos claves.
      - Un Windows form tiene una clase parcial ya que tiene el código generado por el diseñador en la clase media oculta form.Designer.cs. En Visual Basic hay que escoger View All files, en C# esta enable por defecto.
      - Las Clases parciales no son parte del examen.

      ¿Qué es Generics?

      - Son tipos partes del F, permite definir un tipo dejando detalles sin especificar.
      - En vez de especificar los tipos de parámetros o tipos de miembros en clases, puedes dejar que el código lo haga. Esto permite al consumidor de código especificar el tipo que el requiera.
      - Es nuevo en .Net 2.0 y hay muchas preguntas de estas en el examen.
      - Hay clases genéricas por defecto en el namespace de System.Collections.Generic. Incluyendo: Dictionary, Queue, SortedDictionary, y SortedList.
      - Hay tipos genéricos: Nullable y EventHandler (Boolean y Point no lo son).
      - Estas clases funcionan similar a aquellas no genéricas de System.Collections, pero tiene mejoras en performance y son de tipo seguro (safe type), esto quiere decir que no tiene que ver con seguridad, sino que siempre se accede a los objetos asignados de forma compatible.

      ¿Por qué usar Generic?
      - F 1.0 y 1.1 no soportan generic, en vez de eso se usan clases Object para parámetros y miembros que debías castear a otra Clase.
      - Tiene 2 ventajas:
        A. Reduce errores de runtime: el compilador no puede detectar errores si se usa la clase object, por ejemplo si se castea un string a Object y luego de ese Object a int, el compilador no hara catch del error, sino que el runtime lanzará una excepción. Al usar Generic, el compilador detecta el error antes de iniciarse. Adicionalmente puede escribir constraint para limitar el número de clases que usan generic.
        B. Mejora de Performance: Usar Casting requiere lo que se llama "Boxing" o "Unboxing" lo que hace trabajar al procesador y baja el performance, al usar Generic no se usa casting.
      NOTA del autor del libro: En la vida real, en pruebas hechas no hay mejoras sustanciales en performance, bajo 100.000 iteraciones. y son de pocos segundos, por lo que se recomienda usar generic no tanto por performance, pero si por ser "safe type".
      - Ejemplo de clase que usa Object y otra que usa Genérica.
         // C#
         class Obj
         {
          public Object t;
          public Object u;
          public Obj(Object _t, Object _u)  // -> tiene 2 tipos Object
          {
           t = _t;
           u = _u;
          }
         }
         class Gen     // -> tiene los tipos T y U
         {
          public T t;
          public U u;
          public Gen(T _t, U _u)
          {
           t = _t;
           u = _u;
          }
         }
      
      - El código que consume determina si es T y U es Entero o String.
      - Hay una limitante: el código solo funciona si el desarrollo esta hecho para cada instancia de Generic, int o string ya que estamos limitados a la clase Object, igualmente se puede llamar a ToString() o GetHashCode métodos dentro de la clase pero no + o >.
      - Consumir un tipo Generico: aqui se debe especificar el tipo:
         // Add two strings using the Obj class
         Obj oa = new Obj("Hello, ", "World!");
         Console.WriteLine((string)oa.t + (string)oa.u);
         // Add two strings using the Gen class
         Gen ga = new Gen("Hello, ", "World!");
         Console.WriteLine(ga.t + ga.u);
         
         // Add a double and an int using the Obj class
         Obj ob = new Obj(10.125, 2005);
         Console.WriteLine((double)ob.t + (int)ob.u);
         // Add a double and an int using the Gen class
         Gen gb = new Gen(10.125, 2005);
         Console.WriteLine(gb.t + gb.u);
      
      
      Si lo ejecutas la clase con Gen es un poco mas rapido ya que no requiere Box/Unbox de la clase Object.
      - Los errores surgen en compilación y no en run-time. Es mas fácil determinar errores de compilación que errores de ejecución:
         // C#
         // Add a double and an int using the Gen class
         Gen gc = new Gen(10.125, 2005);
         Console.WriteLine(gc.t + gc.u);
         // Add a double and an int using the Obj class
         Obj oc = new Obj(10.125, 2005);
         Console.WriteLine((int)oc.t + (int)oc.u);   // aqui hay error en (int)oc.t ya que es double, al compilar no se da cuenta
      

      Como usar constraint en Generic
      -Interface: permite solo tipos que implementen interfaces especificas para usar en tu generic.
      -Class: permite solo tipos que implementen clases especificas para usar en tu generic.
      -Constructor: permite decir que requiere tipos que usen genéricos para implementar un constructor con parámetros.
      -Tipo por valor o referencia: Requiere que los tipos que usan tu generic sean de tipo valor o referencia.
      - Se puede usar la clausula where para aplicar la constraint. Por ejemplo la constraint para X interfaz:
         // C#
         class CompGen
         where T : IComparable
         {
          public T t1;
          public T t2;
          public CompGen(T _t1, T _t2)
          {
           t1 = _t1;
           t2 = _t2;
          }
          public T Max()
          {
           if (t2.CompareTo(t1) < 0)
            return t1;
           else
            return t2;
          } 
         }
      
      - Si estas creando un clase genérica y necesitas hacer dispose de los objetos genéricos: Usar una Constraint que requiera un tipo Genérico que implemente la interfaz IDisposable. Y no implementar la interfaz IDisposable directamente.

      Eventos
      - La mayoría de las aplicaciones no son lineales, tienen eventos.
      - Un evento es un mensaje que envía un objeto en señal de una acción, que puede ser un clic del mouse, o gatillado por algún otro programa.
      - El objeto que gatilla el evento se llama event sender y el que captura el evento event receiver y lo maneja (lo que se conoce como handle).
      - El objeto que envía no sabe que objeto recibe (handle) el evento por lo que el F provee un guía o puntero entre quien envía y quien recibe, se llama Delegado.
      - Un Delegado es una clase que tiene el control de la referencia. A diferencia de otras clases, una clase delegado tiene una firma o "signature" y esta puede referenciar solo a métodos que coinciden con dicha firma.
      - Una firma o signature en C# es el nombre del método + el tipo del método + Valor/Referencia/Resultado de Parámetros. Ejemplo:
         interface ITest
         {
            void F();                     // F()
            void F(int x);                // F(int)
            void F(ref int x);            // F(ref int)
            void F(int x, int y);         // F(int, int)
            int F(string s);              // F(string)
         }
      
      - Un delegado es el equivalente a una función type-safe o a un callback.
      - Una declaración del delegado es suficiente para definir un clase delegada, esta declaración reemplaza la firma del delegado y el Common Language Runtime provee la implementación.
      - Ejemplo de una declaración de delegado:
         // C#
         public delegate void AlarmEventHandler(object sender, EventArgs e);
      
      - La firma estándar de un delegado que manejada eventos es definir un método que no retorne valor dado, entonces se usa "void" y donde el primer parámetro es la instancia que gatilla el evento, como no sabemos es tipo "Object", y el segundo es de tipo "EventArgs" que mantiene los datos del evento. Si el evento gatillado no tiene datos de evento, el segundo parámetro solo seria una instancia de EventArgs.
      - El delegado EventHandler es predifinido para los casos que se quiere un manejador de eventos que no genera datos de evento.
      - Para asociar al evento con el método que gatillo el evento, agrega una instancia del delegado en el evento. El event handler sera llamado si el evento ocurre a menos que remuevas el delegado.
      - Como responder a un evento: Se debe hacer 2 cosas: A. Crear un método que responda al evento. Este método debe coincidir con al firma del Delegado. Típicamente retorna un "void" y acepta 2 parámetros un "Objeto" y un "EventAgrs" o (clase derivada)
         // C#
         private void button1_Click(object sender, EventArgs e)
         {
           // Method code
         }
      
      B. Agregar el manejador de eventos (en este caso usamos button1_Click) que indica que método debería recibir el evento (apunta al método anteriormente creado):
         // C#
         this.button1.Click += new System.EventHandler(this.button1_Click);
      
      - NOTA: el .NET Framework 2.0 incluye una nueva version generica del tipo "EventHandler".
      - Cuando el evento ocurre, el método especificado se ejecutara.

      Como lanzar un evento
      - Crear un delegado:
         public delegate void MyEventHandler(object sender, EventArgs e);
      - Crear un miembro de un Evento de tipo que coincida con el Delegado creado:
         public event MyEventHandler MyEvent;
      - Invocar el delegado dentro del método cuando lanzas el evento, con VB es muy simple, C# no tanto:
         'VB
          Dim e As EventArgs = New EventArgs
          RaiseEvent MyEvent(Me, e)
          // C#
          MyEventHandler handler = MyEvent;
          EventArgs e = new EventArgs();
          if (handler != null)
          {
           // Invokes the delegates.
           handler(this, e);
          }
          // Note that C# checks to determine whether handler is null.
          // This is not necessary in Visual Basic
      

      Atributos
      - describen un tipo, método, propiedad/miembro con la idea de programar la técnica de Reflection.
      - algunos usos comunes de los atributos son:
      A. especificar privilegios de seguridad que requiere una clase
      B. especificar privilegios para reducir los riesgos de seguridad
      C. declarar capacidades, como soportar serialización -> transformar una clase a ciertos bytes con un formato determinado, por ejemplo transformar a XML. Solo se serializa métodos puplicos.
      D. describe un assembly dándole un titulo, descripción y copyright.
      - Los atributos derivan de Systenm.Attribute.
      - Los atributos se especifican <> en VB o con [] con C#.
      Ejemplo:
         // C# - AssemblyInfo.cs
         [assembly: AssemblyTitle("ch01cs")]
         [assembly: AssemblyDescription("Chapter 1 Samples")]
         [assembly: AssemblyConfiguration("")]
      
      - Visual Studio automáticamente genera atributos como el titulo, descripción, compañía y versión. Deberías editar esos valores en los proyectos que generes.
      - Otro atributo es definir si la clase es serializable, con el atributo Serializable:
         ' VB
          Class ShoppingCartItem
         End Class
         // C#
         [Serializable]
         class ShoppingCartItem
         {
         }
      
      - Sin el atributo Serializable, la clase no se puede serializar.
      - El siguiente código indica que la clase requiere leer el archivo C:\boot.ini, ya con esto, si hay un error (de privilegio u otro), el runtime puede lanzar una excepción ANTES de ejecutar el bloque de código.
      - Ejemplo:
         // C#
         using System;
         using System.Security.Permissions;
         [assembly:FileIOPermissionAttribute(SecurityAction.RequestMinimum, Read=@"C:\boot.ini")]
         namespace DeclarativeExample
         {
          class Class1
          {
           [STAThread]
           static void Main(string[] args)
           {
            Console.WriteLine("Hello, World!");
           }
          }
         }
      

      ¿Qué es el Type Forwarding (Tipo forwardng)?
      - Es nuevo de F 2.0.
      - Es un atributo (implementado en TypeForwardedTo) que te permite mover el tipo de un assembly (Assembly A) a otro (Assembly B), sin necesidad de recompilar los clientes que consumen el assembly A.
      - Luego que un componente (assembly) viaja y es usado por una aplicación, puedes usar Type Forwarding para mover un tipo de una componente a otro assembly y enviar la componente actualizada y las clientes no necesitan ser recompiladas.
      - Type Forwarding: Es utilizado para cuando por ejemplo, tienes una clase en una dll, pero con el paso del tiempo re estructuras tu aplicación y resulta que esa clase ya no queda en esa dll sino en otra. ¿entonces tienes que ir en cada uno de tus clientes a reinstalar la aplicación? No, entonces puedes utilizar TypeForwarding para indicarle al CLR que busque esa clase en otra dll diferente de la dll original.
      - Para mover el tipo de una class library a otro:
      A. Agrega el atributo TypeForwardedTo a la clase de origen.
      B. Corta de la definición del tipo de la source class library.
      C. Pega la definición del tipo en class library destino.
      D. Recompila ambas librerías.
      - Ejemplo: El siguiente código muestra el atributo que es usado para mover TypeA de la class library a un DestLib:
         // C#
         using System.Runtime.CompilerServices;
         [assembly:TypeForwardedTo(typeof(DestLib.TypeA))]
      

      Lección 4: Conversion entre tipos

      Conversiones en VB y C#

      - Por defecto, VB permite conversión implícita, C# no ya que pierde precisión.
      - Para desactivar la conversión implícita en VB agrega "Option Strict On" en casa archivo o en las propiedades del proyecto en VS.
      - Tanto VB y C# permiten conversión implícita si el tipo destino coincide o se acomoda con el tipo de origen. A esto se le conoce como "widening conversion", ej:
         // C#
         int i = 1;
         double d = 1.0001;
         d = i; // Conversion allowed.
      
      - Si el rango del origen excede en precision al tipo destino, esta operación es llamada "narrowing conversion", requiere una conversión explicita.
      - Métodos de conversiones Explicitas:
         
         Tipo System          VB        C#         Convert
         System.Convert                            entre tipos que implmenten IConvertible
                              Ctype    (type)cast 
         type.ToString()
         type.Parse 
         type.TryParse,                            -> nuevo en F 2.0
         type.TryparseExact                        -> nuevo en F 2.0
                             CBool, Cint, CStr, etc  
                             DirectCast
                             TryCast               -> nuevo en F 2.0
      
      - Las conversiones narrowing fallan si el rango del tipo de origen excede el rango del tipo de destino, por lo que se recomienda usar bloques try, o usar TryParse/TryCast para validar la salida.

      Boxing y UnBoxing
      - Hay que tratar de evitarlos si tiene un código que se repite mucho y usas Boxing/UnBoxing.
      Boxing: Convertir un tipo por valor a uno por referencia.
      - Se debe evitar para no tener overhead o "costo de tiempo extra".
      - Boxing se gatilla igualmente mucho llamas métodos virtuales cuya estructura herede de "System.Object", como "ToString".
         // C#
         int i = 123;
         object o = (object) i;
      
      UnBoxing: Convertir un tipo por referencia a uno por valor.
         // C#
         object o = 123;
         int i = (int) o;
      
      - Para evitar este uso:
        -implementar versiones especificas de procedimientos que acepten ese especifico tipo de dato. La mejor opción es crear métodos sobrecargados que uno que acepte el parámetro OBJECT.
        -usar generics en lo posible en vez de usar parámetros Objects.
        -sobreescribe los miembros virtuales "ToString", Equals y GetHash cuando se definan las estructuras.

      Como implementar la Conversión en Tipos Custom.
      A. Definir operadores de conversión para simplificar las conversiones narrowing y widering.
        - Te permite asignar directamente asignar desde un tipo por valor a tu tipo custom.
        - Usa la clausula Widening/implicit úsala para conversiones que no pierdan precisión.
        - Usa la clausula Narrowing/explicit úsala para conversiones que pueden perder precisión.
      B. Sobreescribir ToString() para proveer conversiones PARA string y sobreecribe Parse para proveer conversión DESDE string.
      C. Implementar System.IConvertible para permitir la conversión a través de System.Convert. Usa esta técnica para permitir conversiones de la cultura.
      D. Implementa una clase TypeConverter para permitir una conversión en tiempo de diseño para ser utilizada en la ventana de Propiedades de VS. Conversiones en tiempo de diseño esta fuera del examen.
      Operadores de Conversión
      - Es nuevo en F 2.0.
      - Por ejemplo asignacion DESDE Enteros y HASTA Enteros usando implicit/explicit, sobreescribiendo ToString y evitando hacer boxing:
       // C#
       struct TypeA
       {
        public int Value;
        // Allows implicit conversion from an integer.
        public static implicit operator TypeA(int arg)
        {
         TypeA res = new TypeA();
         res.Value = arg;
         return res;
        }
        // Allows explicit conversion to an integer
        public static explicit operator int(TypeA arg)
        {
         return arg.Value;
        }
        // Provides string conversion (sin boxing).
        public override string ToString()   // -> To sobreescribimos String, evitamos Boxing
        {
         return this.Value.ToString();   // retornamos algo diferente al nombre del tipo (type name).
        }
       }
       //Ahora podemos asignar Enteros directamente:
       // C#
       TypeA a; int i;
       // Widening conversion is OK implicit.
       a = 42; // Rather than a.Value = 42
       // Narrowing conversion must be explicit.
       i = (int)a; // Rather than i = a.Value
       Console.WriteLine("a = {0}, i = {0}", a.ToString(), i.ToString());
      
      - Para implementar la interface "System.IConvertible":
      - Agrega la interfaz "IConvertible" a la definicion del tipo.
      - Con VS hazlo automáticamente y VS insertara 17 declaraciones de miembros, incluyendo "GetTypeCode", "ChangeType" y "ToType" para cada tipo base.
      - No es necesario implementar todos los métodos como "ToDateTime".
      - Para métodos inválidos solo lanza una excepcion "InvalidCastException"
      - Luego de implementar la Interfaz "IConvertible", el tipo custom puede ser convertido usando el estandar "System.Convert":
         // C#
         TypeA a; bool b;
         a = 42;
         // Convert using ToBoolean.
         b = Convert.ToBoolean(a);
         Console.WriteLine("a = {0}, b = {1}", a.ToString(), b.ToString());
      

      Términos importantes del capítulo


      - boxing: Convertir un tipo por valor a uno por referencia. "overhead" o "costo de tiempo extra".
      cast
      constraint
      contract
      exception
      filtering exceptions
      garbage collection
      generic type
      heap
      interface
      narrowing: Conversión con perdida de precisión. Por ejemplo de Int32 a Int16.
      nullable type
      signature: Es una "firma" que consiste en nombre del método + el tipo del método + Valor/Referencia/Resultado de Parámetros. Ejemplo void F(int x); int X(ref int z)
      stack
      structure
      unboxing: Convertir un tipo por referencia a uno por valor.
      widening: Conversión sin perdida de precisión. Por ej de Int16 a Int32.

      Fin Traducción capítulo 1 del libro MCTS Self-Paced Training Kit (Exam 70-536): Microsoft® .NET Framework Application Development Foundation, Second edition

      jueves, 3 de octubre de 2013

      Resumen Capítulo 1 Manual de la Historia de Chile - F. Frías, para Chilean People

      Hola gente! Ahora les va el resumen del Capítulo 1 del libro Manual de la Historia de Chile de Francisco F. Frías.

      Fundación del Imperio Español


      - Nace el Renacimiento: Movimiento artístico y cultural. El humanismo nace con la consigna de que el hombre es el centro de todo y no tanto los dioses o la teología. Nace el hombre renacentista donde busca poder, riqueza, sabiduría, un clásico ejemplo es Da Vinci.
      - Sucede la reforma o crisis de la Iglesia  fue debido al nacionalismo y racionalismo de las personas sumado a la corrupción de los cabecillas de la Iglesia.
      - Los efectos que tuvo esto fue que estos conflictos pasaron a América. Crece rivalidad política-religiosa entre España e Inglaterra.
      - Enrique el Navegante de Portugal crea la primera escuela naval. Conquista tierras africanas.
      - Hay rivalidad entre los reyes de Castilla y Portugal.
      - Cristóbal Colón (nació en la República de Génova) quiso ir a las Indias por el Occidente ya que el creía que la tierra era redonda. Le pidió auspicio al Rey Juan II de Portugal, pero este dijo que no ya que en Portugal tenía excelentes navegantes y que no requería servicios de terceros y Colón además exigía recompensas.
      - Luego Colón fue a España a tratar con los Reyes Católicos, durante 7 años de trámites. (Eso si que era burocracia papá).
      - Capitulaciones de Santa Fe (1942): Contrato entre Colón y los Reyes Católicos. El documento dice que Colón sería Virrey y Gobernador de las tierras que encontrara y le pasarían 3 naves: La Santa María, la Pinta y la Niña. Un total de 120 hombres. Martín Alonso sería su socio.
      - El destino del primer viaje de Colón: Islas Canarias.
      - El 12 de Octubre de 1942 llegó a El Salvador (Las Bahamas), luego descubre la isla de Cuba y La Española. Luego volvió a España. Tanto él como en España creyeron que era Asia.
      - Juan II cuando supo dijo que esas tierras descubiertas eran de Portugal por el tratado de 1480. Por su parte los Reyes Católicos apelaron al pontífice romano Alejandro VI con lo que este creo la Bula Intercaetera (1493) que era una línea que iba a los 100 leguas al oeste de las Islas de Cabo Verde. A Juan II no le gustó y negociaron, formándose el Tratado de Tordesillas (1494) que es un nueva línea a 370 leguas (1 legua = 5 Kms) al oeste de las Islas de Cabo Verde. Lo que quedara al oeste de la línea sería de Portugal y al este de España.
      - El 2do. viaje de Colón fue hacia Puerto Rico y Jamaica, colonizándola en 1943.
      - Los ingleses siguieron los pasos de Colón y Juan Cabotto descubrió "Nueva Escocia" en Canadá.
      - Los Portugueses con Vasco da Gama en 1498 descubren las verdaderas indias rodeando el Cabo de Buena Esperanza y llegando al África. Luego de apoderarían de las Indias vedando a los árabes.
      - Colón viaja por 3ra. vez y descubre Venezuela.
      - Los portugueses descubren Brasil en 1500. Y se adueñan definitivamente de las Indias.
      - Colón hace su 4to. viaje a América Central y se devuelve. Luego muere sólo en Valladolid en 1506.
      - Américo Vespucio dice que las tierras de Colón son un Nuevo Mundo, entonces se le llamó injustamente a estas tierras "América".
      - Américo Vespucio estuvo a las órdenes de España y Portugal, descubrió el Golfo de México.
      - El cartógrafo Martín Valdseemuller empezó a llamar América el Nuevo Mundo en los mapas en 1507.
      - España con Américo V. querían ir a las Indias pasando por América y aprovechar de descubrir algo más.
      - Una vez muerto Vespucio en 1512 le siguió el navegante español Juan Días de Solís que descubre el Río de la Plata en 1516. Los indios lo mataron en la actual Uruguay.
      - Hernando de Magallanes (también conocido como Fernando de Magallanes) era portugués nacionalizado español. Quería ir a las Indias por el Nuevo Mundo y así reclamar algo de especies que según él le pertenecía al rey de España por el Tratado de Tordesillas.
      - La expedición de Magallanes zarpó de España en 1519, descubre el Estrecho de Magallanes en 1520. Muere en las islas de Filipinas ya de vuelta a España.
      - Toma el mando Sebastian Elcano quien pasa por el Cabo de Buena Esperanza y llega a España en 1522.
      - Francia con Verrazzano descubre las tierras que son la actual Canadá en 1524.
      - España y Portugal se disputan las Islas Molucas que tienen especies. España vende las islas a Portugal por cierta suma de dinero y oro con lo que se firma el Tratado de Zaragoza en 1529.
      - Sin esas islas, los Españoles quedan cortos de oro, y es ahí donde miran hacia el Nuevo Mundo como una esperanza de riqueza en oro, plata y metales preciosos.
      - Francia envía a Canadá a Cartier en 1534 y es conocido como descubridor de Canadá oficialmente.
      - Por las rivalidades, los franceses, ingleses y holandeses no reconocen que las tierras descubiertas hasta ahora son de España y por ejemplo, los holandeses tratará de colonizar Brasil y el sur de Chile. 

      miércoles, 11 de septiembre de 2013

      Resumen Introducción a Manual de la Historia de Chile - F. Frías, para Chilean People

      Hola a todos! Uno de mis hobbies ocultos es la Historia de Chile, otro es hacer resúmenes, así que se me ocurrió juntarlos y nació este post. Personalmente se muy poco de nuestra historia, así que puse las pilits leyendo en mi tiempo libre.
      Bueno, en esta entrada les traigo un capítulo piloto, es la Introducción, al estilo chilensis claro, del libro Manual de la Historia de Chile: Desde la Prehistoria hasta el 2000, la idea es poner lo justo y necesario, sin parafernalia, ya que todos sabemos que somos pajeros para leer en Chile ¿onofre?, y de pasada ayudar con mi grano de arroz en la educación de mi querido país.

      Ojo: esto no fue un tema copy-paste como las tareas de los pendex! Lo lei y redacté tratando de explicar con mis pocas palabras. Al que le sirva, bien, al que no, que vaya a llorar a la FIFA.

      Si la cosa prende, uyuiii!, ahí si que podemos seguir capítulo a capítulo avanzando y todos aprendemos. ¡Comenten cabros, pero por favor no sean tontos graves!

      NOTA: Todos los créditos para el gurú Francisco Frías Valenzuela autor del libro.

      Introducción - Europa en el siglo XV

      -Como antecedente se tiene que el Descubrimiento y Conquista de América fue a fines del siglo V, no terminaba aun la Edad Media.

      Factor 1: Se crean grandes estados nacionales


      -Se estaba acabando el sistema Feudal y se reemplaza por el sistema de Reinados, con un Rey con poder absoluto y dinastías con hijos (Ej, los Tudor Inglaterra). Se unifican los países en una ley común y lengua común.
      -Primer país en unificarse fue Francia, luego Inglaterra, luego España. España estaba divido en reinos para luchar contra Musulmanes, los reinos de Castilla y Aragon se unificaron y quedaron a cargo de los llamados Reyes Católicos Isabel y Fernando V, ellos inician la "expansión" marítima de Castilla con el primer Viaje de Cristóbal Colón.
      -Portugal estaba en muy buenas condiciones para expansión marítima.
      -Todos creían que la cristiandad debía estar unido a la Iglesia y al imperio Germánico, sucesor del Imperio Romano, pero ambos lucharon por tener el dominio total, esto llevo a la quiebra de la unidad cristiana y al dominio del emperador o Papa. El occidente dominaba.
      -Alemania e Italia logran unificarse en 1870.

      Factor 2: Cambio a régimen Capitalista


      - Antes la moda era la "economía señorial" y la "economía urbana".
      - Ahora había un "Capitalismo comercial" forma primitiva del nuevo sistema económico, se comercializaba mercadería.
      - Luego nace el "Capitalismo financiero", se comercializaba dinero. Nacen los bancos y banqueros, letras de cambio, crédito y cambio de monedas. "Préstamo e interés" es condenado como usura, se practica a escondidas o de deja en manos de los judíos. Aparece el "cambio internacional" donde se cambian monedas según el valor que representan.
      - Este factor esta ligado al anterior, ya que los estados naciones miden su poder en riquezas y deben tener dinero para mantener ejércitos, pagar servicios y la burocracia que era mucha.
      - La necesidad de dinero, llevará a los reinos a luchar por el oro y expandirse buscando nuevas tierras.
      - Colón de pensamiento "moderno" ya buscaba el camino mas corto de España a las islas ricas en especias, por lo que se dice que el descubrimiento de Colon fue una "hazaña del Capitalismo".

      Factor 3: progresos de la geografía y técnica naval


      - En la Edad Media se hicieron progresos que sin ellos no se hubiese podido avanzar luego, como la esfericidad de la tierra, conocimiento de países del oriente y otros.
      - Los árabes de la Edad Media viajaban a la India o China, con el tiempo de adueñaron de la ruta marítima y por el Mediterráneo llevaban lo que traían de Oriente.
      - Francia envió al veneciano Marco Polo a investigar a la india y este volvió contando puras maravillas.
      - Las técnicas navales nuevas fueron: la brújula, antes se navegaba bordeando las costas, y viendo las estrellas. Fue creado por los chinos.
      - El timón reemplazó a los remos.
      - Las Cartas de navegación, eran los mapas y tenían dibujos de monstruos marinos.
      - Latitud y Longitud: los árabes usaban el astrolabio. La longitud no sabían mucho como calcularla.
      - Carabelas: eran livianas no mas de 80 toneladas, de 3 mástiles, echa para que todo viento le ayude, puede navegar en sentido contrario rápidamente. La Santa Maria de Colon media 22 mts. de largo, fue reconstruida en 1892.
      - El mediterráneo era disputado por griegos vs fenicios, romanos vs cartagineses, árabes vs bizantinos. Los italianos luego los monopolizaron.
      - Los productos que se comercializaban eran: diamantes, marfil, tapices, laca, porcelana, sedas, ámbar, nuez moscada, vainilla, opio, jengibre. Esto eran el lujos de los reyes. El trueque que exigían los indios a cambio era oro, plata, mercurio, escarlata, tejidos.
      - Existían 3 rutas comerciale
      s en el mediterráneo: mar rojo, golfo pérsico o vía terrestre.
      - El mediterráneo estaba peligrando por: la expansión turca (otomanos) ya que conquistaron el imperio Bizantino y con ellos Constantinopla, cerrando el mediterráneo o cobrando tributos muy caros. Todos estaban urgidos: Francia, Italia, Países Bajos.
      - Se empieza a sentir una escasez de metales preciosos en Europa ya que las minas de Sajonia, Bohemia o Tirol se agotan. Esto hace que se requieran mas metales preciosos. Justo es cuando todos quieren mas lujo y derroche. Se hace necesario encontrar una ruta marítima hacia las Indias que no interviniera con el Mediterráneo, aunque se tuviera que recurrir a las armas.

      lunes, 12 de agosto de 2013

      El Mítico Hombre-Mes (The Mythical Man-Month) capítulo 3 en español

      Hola a todos!
      He terminado la traducción del Capítulo 3 del libro The Mythical Man-Month: Essays on Software Engineering.
      En este capítulo Brooks explica un estilo de organizar un equipo de desarrollo de software en base un equipo quirúrgico (cuya idea inicial fue de Harlan Mills), donde todos tienen roles bien diferenciados.

      ¿Será aplicable en la actualidad este modelo? Yo creo que sí, adaptado ciertos roles gracias a las nuevas tecnologías existentes hoy.

      Como dice Luigi del videojuego, "Here we go!":

      The Mythical Man-Month : Essays on Software Engineering.
      Capítulo 3: El equipo de cirugía

      Figura 3.1.
      Estudios revelan grandes diferencias individuales de desempeño, a menudo relacionado por el grado de importancia de lo que se realiza.
      SACKMAN, ERIKSON Y GRANT

      En los debates o foros de computación se ve muchas veces a jóvenes jefes o líderes de proyectos que dicen estar a favor de un equipo fuerte y reducido, pero de un nivel de primera clase, en vez de tener un equipo con cientos de desarrolladores pero de un nivel medio-bajo. Así lo creen muchos. 

      Pero esta ingenua afirmación no resuelve la difícil pregunta: ¿cómo construir grandes sistemas informáticos que tienen una planificación muy larga? Echemos un vistazo más detallado de este problema.

      El problema


      Los gerentes informáticos o los Jefes de Proyecto (JP) desde hace tiempo han reconocido la diferencia de productividad entre los buenos y malos desarrolladores. Pero si se llega a medir dicha diferencia, el resultado nos sorprendería a todos. En uno de estos estudios, los autores Sackman, Erikson y Grant midieron el desempeño de un grupo de desarrolladores experimentados. En tan sólo este grupo, la relación entre los mejores y peores desempeños fue de 10:1 en una medición de la productividad, ¡y de un increíble 05:01 en velocidad de programación! En resumen los 20,000 dólares / año de un programador experimentado (Nota del traductor: en la época sería algo como 1.2 millones en pesos chilenos mensuales) puede ser hasta 10 veces más productivo que un programador de 10,000 dólares al año. Además, los datos no mostraron correlación alguna entre la experiencia y el rendimiento (dudo que eso es una verdad universal).

      He sostenido anteriormente que la coordinación de un gran número de mentes tiene un gran costo en esfuerzo y una parte importante de ese costo es la comunicación, esto a la vez tiene un costo en la corrección de los efectos nocivos por la falta de comunicación (y hay que modificar o depurar algo). Esto también nos lleva a pensar que el sistema debería ser construido por el menor número de mentes posible. Por ejemplo, se tiene la experiencia del desarrollo de algunos grandes sistemas donde se usa una gran fuerza bruta, por lo tanto, son lentos de construir, ineficientes y con subsistemas que no están integrados conceptualmente. Por ejemplo tenemos el OS/360, Exec 8, Alcance 6600, Multics, TSS, SAGE, etc, y la lista sigue y sigue.

      Entonces uno podría lanzar ideas: si un proyecto es de 200 hombres y de ellos hay 25 líderes o jefes de proyectos que son los analistas desarrolladores más competentes y experimentados, lo mejor sería despedir al resto, los 175 desarrolladores, y poner sólo a los jefes y líderes desarrollar. Otra idea sería tomando en cuenta lo se dijo al inicio, es decir, de tener sólo un equipo pequeño pero fuerte, que por consenso no excede las 10 personas. 

      Si tomamos la idea de tener 200 personas, es tanta gente que tendrá que ser necesario tener dos niveles de administración, y cerca de cinco directores o jefes. Además se necesita el apoyo en finanzas, personal administrativo, espacio, secretarias y operadores. Por otro lado, este equipo de 200 hombres en verdad no es lo suficientemente grande para construir un sistema "muy grande" por el método de fuerza bruta. Considere por ejemplo la posibilidad del desarrollo de un OS/360 (Nota del traductor: Sistema Operativo de IBM hecho entre 1962 y 1972) que en su mejor momento trabajaban más de 1000 personas, entre ellos desarrolladores, escritores, operadores, oficinistas, secretarias, ejecutivos, soporte, etc. De 1963 a 1966 probablemente trabajaron en esta empresa 5000 años/hombre en etapas de diseño, construcción y documentación. ¡Si los hombres y meses fueran uniformes, nuestro equipo de 200 hombres habría tardado 25 años y no 10 en llevar el producto a su presente estado! 

      En conclusión, este es el problema con un equipo pequeño pero fuerte: es demasiado lento para desarrollar sistemas grandes. Consideremos de nuevo el caso de OS/360, y veamos la opción de abordarlo con un equipo más pequeño pero muy agudo técnicamente. Para esto consideremos lo que dijimos antes, de dejar como consenso que un equipo pequeño es de 10 hombres. Según las estadísticas, a lo más estos serán 7 veces más productivos que un equipo de desarrolladores de nivel medio-bajo tanto en codificación como en documentación. Supongamos además, que el OS/360 se construye sólo por desarrolladores de nivel promedio (cosa que está "lejos" de ser verdad). Como dato aparte, hay una mejora de la productividad al menos en 7 veces debido a la baja comunicación que se requiere por parte de este equipo reducido.
      Ahora supongamos que el mismo único equipo está trabajando todo el tiempo del proyecto, esto sería: 5000 / (10x7x7) = 10 años aproximadamente, entonces el trabajo 5000 años/hombres se hará en 10 años.

      La consulta que se genera ahora es: ¿el producto será interesante 10 años después de su diseño inicial? ¿O ha quedado obsoleto debido al rápido desarrollo de nuevas tecnologías de software?

      El dilema es algo cruel. Para sistemas medianos o chicos, uno debería preferir pocas pero buenas mentes para obtener una eficiencia y una integridad conceptual. Sin embargo, en sistemas grandes uno requiere saber manejar una considerable mano de obra, para que el producto de software tenga una fecha de finalización acorde. ¿Cómo se pueden conciliar estas dos necesidades?

      Propuesta de Mills


      Una propuesta de Harlan Mills ofrece una solución fresca y creativa. Mills propone que cada segmento de un gran trabajo debe ser abordado por un equipo, pero que el equipo se organizará como un equipo quirúrgico en lugar de un equipo estilo "matanza de cerdo". Es decir, en lugar de que cada miembro haga cortes sobre el problema, uno sólo hace el corte y los demás le dan todo el soporte posible, lo que mejorará la eficiencia y productividad de toda la actividad.

      Este mismo concepto se puede encontrar en el poema Desiderata si lo aplicáramos en el trabajo. Pocas mentes están involucrados en el diseño y la construcción, sin embargo, muchos "meten mano", ¿funcionará? ¿Quiénes son los anestesiólogos y enfermeros en un equipo de desarrollo y cómo se divide el trabajo? Permítanme libremente mezclar metáforas para sugerir cómo un equipo puede funcionar de esta forma aplicando un sistema de soporte o colaboraciones.

      El cirujano. Mills le llama programador jefe. Él (el Cirujano), personalmente define las especificaciones funcionales y de desempeño, los diseños del programa, códigos, tests y escribe la documentación. Programa en un lenguaje de programación estructurado como PL/I (Nota del traductor: parecido a Pascal, no quedaba de otra, en la epoca no habían lenguajes como C# o Java que son orientados a objetos), y accede a algún sistema de computación donde ejecuta sus pruebas, pero también almacena las diferentes versiones de sus programas, actualiza sus archivos y documenta. Debe tener un gran talento, de unos diez años de experiencia desarrollando sistemas importantes y con muchos conocimientos de aplicaciones, matemáticas, negocios, etc.

      El asistente o copiloto. Él es el alter ego del cirujano, capaz de hacer cualquier parte del trabajo, pero tiene menos experiencia. Su principal función es participar en el diseño con puntos de vista críticos y visión de evaluador. El cirujano discute las ideas con él, pero no está obligado a aceptar sus consejo a ojos cerrados. El asistente a menudo representa a su equipo en los debates sobre la función y la conexión con otros equipos. Lo sabe todo acerco del código. Investiga el diseño de estrategias alternativas. Obviamente, él sirve también como una especie de seguro contra desastres para el cirujano. Incluso puede escribir código, pero la responsabilidad final de las líneas escritas no recae en él.

      El administrador. El cirujano es el jefe pero también debe ver todo lo referente al personal, aumentos, manejo de espacio, etc., por lo que no le alcanza el tiempo para estos en estos asuntos. Así que necesita un administrador profesional que maneje el dinero, la gente, el espacio, y las máquinas, pero a la vez, que interactúe con toda el resto de la organización. F. Terry Baker, sugiere que el administrador debe tener un trabajo a tiempo completo solamente si el proyecto es de importancia legal, contractual, de informes o requerimientos financieros debido a una relación productor-comprador. Por otra parte, un administrador puede apoyar a un máximo de dos equipos.

      El editor. El cirujano es responsable de generar la documentación para obtener la máxima claridad en el diseño y desarrollo. Este es tanto para los casos de descripciones externas como internas. El editor, sin embargo, toma la documentación generada por el cirujano, la critica, la hace un reworks (retrabajo), le proporciona referencias y bibliografía en la medida de los posible, la agranda por medio de versiones y supervisa la mecánica de la documentación.

      Dos secretarios. El administrador y el editor tendrán cada uno, un secretario, estos se encargarán de la correspondencia del proyecto y archivos que no sean el producto mismo. (Nota del traductor: hay que ponerse en contexto de que en el año 1972 cuando se estableció este sistema de manejo de equipos no se usaban los correos electrónicos como hoy en día).

      Un recepcionista. Él es responsable de mantener todos la registros técnicos que genere el equipo, en un archivo tipo librería de software. El recepcionista se entrenó como secretario y tiene por lo tanto archivos legibles tanto por un computador como por humanos. Todo lo que sea una entrada al sistema pasa por el recepcionista, quien deja registro de los puntos claves si son necesarios. Los aspectos de salida pasan igual por él para ser archivados y ordenados. En la actualidad, esta información de las ejecuciones y estados se mantienen en un notebook, antes se guardaban en un archivos físicos.

      Es absolutamente vital para el concepto de Mills lo que él llama la transformación de la programación de un arte privado a una práctica pública haciendo que el equipo funcione visiblemente para todos los miembros del equipo y la identificación de todos programas y datos sean propiedad de todo el equipo, no una propiedad privada.

      La función especial del recepcionista es liberar a los programadores de las tareas administrativas, sistematizar y asegurar un rendimiento adecuado de esas tareas a menudo olvidadas y aumentar el activo más valioso: el producto que se genera. Es evidente que estas tareas se deben realizar de manera secuencial. Cuando se utilizan elementos de interacción, especialmente aquellos que requieren una copia impresa, las funciones del recepcionista no disminuyen, sino que cambian. Él registra todas las copias privadas de cada actualización que tenga algún miembro del equipo y utiliza su propia herramienta para el control de la integridad y la disponibilidad del producto.

      El toolsmith (Nota del traductor: es como un experto en herramientas de apoyo). Para que funcione este modelo, debe existir un conjunto de servicios de edición de archivos, textos y de depuración, por lo que un equipo rara vez tendrá que usar su propia máquina para esto. Sin embargo, estos servicios deben estar disponibles con una alta capacidad de respuesta y fiabilidad, y el cirujano debe ser el único que puede de adecuar estos servicios a su disposición. Por lo tanto aquí nace la figura de un toolsmith que trabaja para el cirujano. Este personaje que es responsable de garantizar la idoneidad de estos servicios básicos y que a la vez debe construir, mantener y actualizar sus propias herramientas - sobretodo servicios informáticos interactivos - que necesitará el equipo. Cada equipo tendrá su propio toolsmith, independientemente si hay un servicio común central, su trabajo es tener disponibles las herramientas necesarias o buscadas por su cirujano, por sobre lo que se solicite desde algún otro equipo. Este especialista a menudo debe construir servicios especializados, procedimientos catalogados o macros.

      El tester. El cirujano necesita un banco de casos de prueba adecuados para probar tonta piezas particulares que desarrolle como para una prueba completa del sistema o módulo. Por lo tanto, el tester es al mismo tiempo un adversario que elabora los casos de prueba para especificaciones funcionales como también pruebas que sirven para depurar la aplicación en el día a día. También planea secuencias de prueba y establece el andamiaje necesario para pruebas de componentes.

      Experto en el lenguaje. En el momento que llegó el lenguaje de programación Algol, la gente comenzó a reconocer que existían ciertas personas que se deleitaban en el dominio de la complejidad de un lenguaje de programación, y estos expertos resultaban ser muy útiles y ampliamente consultados. El talento aquí es bastante diferente al de un cirujano, que es principalmente un diseñador del sistema y que piensa en aspectos funcionales. El experto en el lenguaje conoce varias de manejar el lenguaje de forma ordenada y eficiente para sacar adelante cosas difíciles, oscuras o realizar ciertos trucos. A menudo tendrá que hacer breves investigaciones de buenas prácticas (de dos o tres días). Un experto en lenguaje puede ayudar a un máximo de dos o tres cirujanos. 

      Entonces esto responde a la pregunta de cómo las 10 personas podrían contribuir en un sistema de roles bien diferenciado, donde el equipo de programación esté basado en el modelo quirúrgico.

      ¿Cómo funciona?


      El equipo que se acaba de definir coincide con el poema Desiderata en varios puntos. Diez personas, siete de los cuales son profesionales, están trabajando en el problema, pero el sistema es el producto de una mente o dos como mucho pero que actúan como uno animo. (Nota del traductor: no encontré el significado, pero debe ser algo como una "una unidad").
      Tenga en cuenta, en particular, las diferencias entre un equipo típico de dos programadores y un equipo del tipo cirujano-copiloto. En primer tipo, en el equipo convencional, los programadores dividen el trabajo y cada uno es responsable del diseño y ejecución de su parte del trabajo. En el equipo quirúrgico, el cirujano y el copiloto son cada uno consciente de todo el diseño y de todo el código. Esto evita problemas tanto logísticos como la asignación de espacios, accesos al disco, etc., como también asegura la integridad conceptual de la obra.

      En segundo lugar, en el equipo convencional los programadores son iguales y las inevitables diferencias de juicio deben ser habladas o se verán comprometidas.
      Dado que el trabajo y los recursos se dividen, las diferencias en el juicio se limitan a la estrategia global y la interconexión, pero agravadas por las diferencias de intereses, por ejemplo, cuanto buffer se usará en una variable. (Nota del traductor: actualmente sería análogo a definir el largo de una variable en un mapeo de Hibernate o un SP de SQL).
      En el equipo quirúrgico, no hay diferencias de intereses, ya que estas diferencias de criterio se resuelven por el cirujano de forma unilateral. Estas dos diferencias: la falta de división del problema y la relación superior-subordinado, hacen que sea posible que el equipo quirúrgico actúe como uno animo.
      Sin embargo, la especialización de la función del resto del equipo es la clave de su eficacia, ya que permite un patrón de comunicación radicalmente más simple entre los miembros, que se ve en la figura 3.1.

      Fin del capítulo 3.

      Bueno, esta fue la traducción, aparte encontré estos interesantes enlaces que apoyan la lectura:


      lunes, 24 de junio de 2013

      ¿Me han hackeado mi página hecha en Joomla?

      Intro

      El otro día viendo una página que administro que usa Joomla, me encontré con esto en la página inicial o home:


      Y me fui de ass, como se dice en nuestro muy buen vocabulario, ¿qué diablos?

      Bueno, buscando y metiendo mano logré resolverlo. 

      Esta guia es para quienes, así como yo les han hackeado su web hecha en Joomla, no son expertos en seguridad, y quieren volver todo a la normalidad. Ahora si, DEPENDE de que tan bolsa les hayan hecho el sitio. 
      Esta entrada les puede ayudar con algunos truquillos simples que aprendí con la lección, sobretodo útiles si usan Joomla, y para nada pretende ser la "gran guia anti hackers para bobos con claves pencas" ni algo parecido.

      Buscando

      Lo primero que encontré, fue que la clave administrador del panel de Administración estaba cambiada:
      Entonces me acordé del CPanel, pude entrar por suerte (gracias sr. hacker) y ahí uno va a Php My Admin

      Adentro fue a la base de datos de Joomla, en mi caso X_joomla y luego a la tabla de usuarios, en mi caso s70n8_users. Aquí encontré algo raro ya que solo existía un súper usuario y una cuenta nueva que no era la mia, sino del tal hacker, hasta con su correo...lo otro raro, es que ambas cuentas, la de admin y la del hacker, tenían la misma clave.

      Tomé la clave, la copie, y pegué en http://www.md5decrypter.com/ y tuve la suerte (por 2da vez) que me entregó resultado. Esa clave la use en el Administrador y entró.

      Adentro lo primero fue ir a Site -> My Profile y cambié la clave por una muy segura con letras + puntos + números + símbolos raros. Luego vi esa clave en la base de datos y la anote en el block de notas.

      Ya con el control de Administrador de Joomla, me puse a ver qué componente pudo haber cambiado el hombre para cambiar el home del sitio, y encontré luego buscar un rato que lo que cambió no fue la página sino el Template. Como no he cambiado el template de Joomla desde que lo instalé, el template por defecto usado es gk_music_free - Default así que fue a ver los archivos y estos sólo eran CSS, no creo que cambió esos archivos. 
      Abajo estaban los Templates Master lo más seguro que cambió algo por ahí pero me dio lata entrar uno a uno. Lo dejé para una futura revisión si no encontraba nada en mi siguiente búsqueda.

      Mejor volví al administrador y fui al Administrador de Archivos del servidor y ahí vi un archivo index.php interesante dentro del template gk_music_free

      Lo abrí y cha-chan, ¡adentro estaba el código HTML con el mismo mensaje del hacker!

      Solución

      Ahora que estaba claro el problema, donde fue el hack exacto que realizó nuestro amigo, el resto era sencillo, fui a bajar la última versión del template GK Music Free: http://www.newone.org/gk-music-free-responsive-template-j25, abrí los archivos, y reemplacé el index.php del template que baje por el del servidor y listo. Esto lo hize por FTP, me salió más cómodo.

      Resumen


      • La clave está en tener una password suficientemente segura en el panel Administrador del Joomla, en el CPanel y en la Base de Datos, esto quizá no les evite el problema, pero al menos le hará un poco más costoso que los hackeen.
      • NO usen Joomla si quieren un sitio seguro, así de simple. De hecho ahora mismo estoy migrando el sitio a uno hecho “a mano” sin Joomla.

      martes, 9 de abril de 2013

      El Mítico Hombre-Mes (The Mythical Man-Month) capítulo 2 en español

      Hola a todos!
      He terminado la traducción del Capítulo 2 del libro The Mythical Man-Month: Essays on Software Engineering.
      En este capítulo entrega ciertas fórmulas muy valiosas que todo líder de proyecto o JP debería tener. También se nota que el libro al ser de 1995, explica en base a metodologías de la época como RUP, por lo que los amantes de las nuevas metodologías ágiles deberán asociarla.

      Vamos directo al hueso:

      The Mythical Man-Month : Essays on Software Engineering.
      Capítulo 2 : The Mythical Man-Month

      Traducción terminada el 09 de Abril del 2013, por Ing. Hernaldo González Candia (hernaldog@gmail.com)
      Todos los créditos son para el autor del libro Frederick Phillips Brooks.


      La buena cocina toma su tiempo. Si se demora es para darle un mejor servicio y complacerlo mejor.
      MENU DEL RESTAURANT ANTOINE EN NEW ORLEANS

      Más proyectos de software han fracasado por falta de tiempo que por cualquier otra causa combinada. ¿Por qué es tan común esta causa?

      En primer lugar, nuestras técnicas de estimación están poco desarrolladas. Ya que reflejan una suposición sin voz, totalmente falsa, asumiendo que todo va a salir bien.

      En segundo lugar, nuestras técnicas de estimación confunden esfuerzo con progreso, ocultando el supuesto de que los hombres y los meses son intercambiables.

      En tercer lugar, porque no estamos seguros de nuestras propias estimaciones, esto sumado a que los líderes del proyecto en general no son "cortésmente tercos" como lo es el chef Antoine.

      En cuarto lugar, no se controla bien el progreso de lo planificado. Hay técnicas probadas en otras disciplinas de ingeniería que serían grandes innovaciones en la Ingeniería de Software.

      En quinto lugar, cuando se reconoce el atraso, la natural (y tradicional) respuesta es agregar más mano de obra. Esto es lo mismo sofocar un incendio con gasolina, las cosas empeorarán más y quedarán peores. Más fuego requiere más gasolina y así comienza un ciclo que siempre termina en un desastre.

      El monitoreo del plan es un tema que da para un ensayo aparte.

      Vamos a considerar otros aspectos del problema con más detalle.


      Optimismo


      Todos los programadores son optimistas
      . Tal vez este tipo de brujería moderna atrae especialmente a los que creen en los finales felices y las madrinas de las hadas. Tal vez esas cientos de frustraciones desaparecen de la mente de aquellos que sólo se centran en el objetivo final. Tal vez sea simplemente que los computadores son cada vez más nuevos y rápidos, los programadores son cada vez más jóvenes y los jóvenes son siempre optimistas. Pero sin embargo, el proceso siempre funciona igual y el resultado es el mismo: "esta vez es seguro que correr", o "acabo de encontrar el último bug".

      Así que la primera suposición falsa que subyace a toda programación o planificación de sistemas que todo va a ir bien, es decir, que cada tarea sólo va a demorar lo que "debería" demorar y no más.

      La omnipresencia del optimismo entre los programadores merece más que un análisis a la rápida. Dorothy Sayers, en su excelente libro Mind of the Maker (La Mente del Creador), divide la actividad creativa en tres etapas: la idea, la implementación y la interacción. Un libro, un computador, o un programa llega a existir por primera vez como un ideal a construir, y se construye fuera del tiempo y del espacio, pero está completa en la mente del autor. Luego se realiza dentro del tiempo y el espacio, ya sea por una pluma, tinta y papel, con un hilo, silicio o hierro. La creación sólo se completa cuando alguien lee el libro, utiliza el computador o corre el programa, así interactúan con la mente del creador.

      Esta descripción, que la señorita Sayers utiliza en su libro para iluminar no sólo la actividad creativa humana, sino también aspectos cristianos, nos ayudará en nuestra presente tarea. Para los creadores humanos de las cosas, la no completud e inconsistencia de nuestras ideas se ponen en manifiesto sólo durante la implementación. Por esto es que la escritura, la experimentación, la "elaboración" son disciplinas esenciales para aquel que es teórico.

      En muchas actividades creativas el medio de ejecución es intratable. Cortar madera, pintar un frontis o terminar un circuito eléctrico. Estas limitaciones físicas del medio pueden restringir las ideas en que estas pueden ser expresadas y que crean dificultades inesperadas en la implementación.

      La implementación entonces, toma tiempo y sudor, tanto por los medios físicos como por las insuficiencias de las ideas subyacentes. Tenemos la tendencia a culpar a los medios físicos por la mayor parte de nuestras dificultades de implementación; porque los medios no son "nuestros" en el forma en que lo son las ideas y los colores del orgullo de nuestro juicio.

      La programación, sin embargo, se crea con un medio sumamente tratable. El programador construye a partir de puro pensamiento: conceptos y representaciones muy flexibles de los mismos. Debido a que el medio es tratable, se esperan pocas dificultades en la implementación, de ahí nuestro optimismo generalizado. Debido a que nuestras ideas son defectuosas, tenemos errores, por lo que el optimismo está injustificado.

      En una simple tarea, la suposición de que todo va a ir bien tiene un efecto probabilístico en la planificación del proyecto. De hecho, podría avanzarse como se está planeado ya que siempre hay atrasos considerados en el plan y que están repartidos o distribuidos dada cierta probabilidad. No es así con los "no atrasos" que tienen una probabilidad finita. Una gran tarea de programación, sin embargo, consiste en muchas sub-tareas algunas asociadas de punta a punta, y en donde la probabilidad de que cada una vaya a ir bien es extremadamente pequeña.


       El Hombre-Mes


      El segundo modo de pensamiento falso se expresa en una unidad de esfuerzo empleado bastante en la estimación y programación del plan: el hombre-mes. En efecto, el costo varía según el número de hombres y el número de meses que se tengan. El progreso en cambio, no siempre variará. Por lo tanto el hombre-mes, como unidad para medir el tamaño de un trabajo, es un mito peligroso y engañoso. Esto implica que los hombres y los meses sólo se pueden intercambiar sólo bajo ciertas condiciones.

      Fig. 2.1 Tiempo versus el número de trabajadores, esto en una tarea perfectamente particionable.

      Los hombres y los meses son productos intercambiables sólo cuando una tarea se puede dividir entre muchos trabajadores sin comunicación entre ellos (Fig. 2.1). Este es el caso, por ejemplo, de cosechar trigo o recoger algodón, pero nunca en la programación de sistemas.

      Cuando una tarea no puede ser dividida debido a las limitaciones secuenciales, si se aplica un mayor esfuerzo, no tendrá ningún efecto sobre la programación (Fig. 2.2). El crecimiento de un niño tarda nueve meses, no importa cuántas matronas le asistan. Muchas de las tareas de software tienen esta característica debido a que hay etapas del desarrollo que son secuenciales.
      Fig. 2.2 Tiempo versus número de trabajadores, esto en una tarea que no es particionable.

      Si las tareas pueden dividirse, requerirán comunicación entre las sub-tareas,  por lo tanto, se debe añadir al trabajo mismo, el esfuerzo de la comunicación. Entonces, lo mejor que podemos alcanzar es algo un poco menos eficiente que el modelo de intercambio de los hombres con los meses (Fig. 2.3).
      Fig. 2.3 Tiempo versus número de trabajadores, esto en una tarea particionable pero que requiere comunicación.

      Adicionalmente, la comunicación se compone de dos partes, la capacitación (training) y la intercomunicación. Cada trabajador debe recibir capacitación en la tecnología, las metas, la estrategia global y el plan de trabajo. Esta formación no puede ser dividida, por lo que esta parte del esfuerzo que se añadió varía linealmente en relación al número de trabajadores.

      La intercomunicación es peor. Si cada parte de la tarea debe ser separadamente coordinada con cada una de las otras partes, el esfuerzo aumenta en la medida de:
      N * (N -1) / 2 
      Tres trabajadores requieren tres veces más intercomunicación que dos, cuatro requieren seis veces más que dos.
      Si por otra parte, es necesario que existan reuniones entre tres, cuatro o más trabajadores para resolver algún problema en conjunto, las cosas empeoran más aún. El esfuerzo agregado de comunicarse plenamente puede contrarrestar la división de la tarea original y nos lleve a la situación de la Figura 2.4.
      Fig. 2.4 Tiempo versus número de trabajadores, esto en una tarea que requiere complejas interrelaciones.

      Ya que la construcción de software es básicamente un sistema de esfuerzo - lo que incluye un ejercicio de complejas interrelaciones - y que conlleva un gran esfuerzo de comunicación que rápidamente lleva a que se disminuya el tiempo de trabajo individual provocada por la partición de las tareas. Entonces la adición de más hombres hace que se alargue la programación del plan estimado y no se acorte.


      Sistemas de Test


      No hay partes en el plan programado que se vea tan fuertemente afectado por las restricciones secuenciales como son las faces de depuración y prueba. Además, el tiempo requerido depende del número y la sutileza de los errores encontrados. Teóricamente, este número debería ser cero. A causa del optimismo, por lo general esperan que el número de errores sea menor del que en verdad resulta ser. Por lo tanto, la etapa de testing es la más reprogramada o replanificada de todo el plan.


      Desde hace algunos años he estado utilizando con buena tasa de éxito la siguiente regla de oro para la estimación de una tarea de software:
      • 1 / 3 planificación
      • 1 / 6 codificación
      • 1 / 4 testeo o depuración de las componentes y una prueba básica del sistema
      • 1 / 4 prueba del sistema y de todos los componentes involucrados

      Esto difiere de una estimación convencional en varios aspectos importantes:
      1. La fracción dedicada a la planificación es más grande de lo normal. Aun así, es apenas suficiente para producir una especificación detallada y sólida, y no lo suficiente para incluir la investigación o la exploración de nuevas técnicas.
      2. Casi la mitad de la estimación está dedicada a la depuración de código lo que es mucho más grande que lo tradicional.
      3. La parte fácil de estimar es la codificación, que es la sexta parte de la estimación.
      Si examinamos como funciona en general la estimación en proyectos que no son de software, encontramos que son pocos los que estiman la mitad del tiempo para los test. Y que si en efecto, se usaba dicho tiempo para ese propósito, muchos de esos proyectos terminaron en fecha (no atrasados). Esto no sucede en los tests de sistemas de software.

      En general no se deja tiempo suficiente para los test de sistemas, y en particular en software esto causa un gran desastre. Dado que el retraso se produce al final de la programación, no se es consciente de los problemas de fechas o estimaciones hasta cuando se acerca la fecha de entrega. Dar esas malas noticias, tarde y sin advertencias previas, es inquietante tanto para los clientes como para los gerentes a cargo.

      Por otra parte, un retraso en esta fase tiene inusuales repercusiones financieras y psicológicas. El proyecto está con su capacidad completa de personal y el costo del día a día es alto. Si estamos ante algo más serio, como la construcción de algún software que da soporte a otro negocio (transporte de equipos, habilitación de nuevos módulos, etc.) hace que los costos secundarios producto del atraso sean muy altos. Esto se da casi siempre en software asociado al transporte o envío de productos. De hecho, estos costos secundarios pueden ser muy superiores a todos los demás. Por eso es muy importante que en el plan de estimación original se estime considerando un tiempo suficiente para las pruebas del sistema.


      Estimación cobarde


      Obsérvese que tanto para el programador como para el jefe de proyecto o líder a cargo, el uso de un patrón pueden determinar una fecha estimada de  finalización en el plan, pero no la fecha real de entrega. Una tortilla puede prometerse servirse en dos minutos cuando se sabe que en ese tiempo hay una baja probabilidad de que no esté lista. Ahora, cuando no está lista en esos dos minutos, el cliente tiene dos opciones: esperar o comérsela cruda. Los clientes de Software tienen las mismas opciones.
      El cocinero en cambio tiene otra opción, subir la temperatura. El resultado suele ser una tortilla que está quemada por una parte y cruda en otra.

      No creo que los jefes de proyecto o líderes tengan menos coraje y firmeza que  los cocineros, ni que otros administradores de otras área de la ingeniería. Pero desarrollar falsamente para que el término de la programación coincida con la fecha deseada es mucho más común en nuestra disciplina que en otras áreas de la ingeniería. Es muy difícil hacer una defensa vigorosa, plausible o involucrando todos los riesgos que se visualizan, de una estimación que se obtuvo bajo un método no cuantitativo, con pocos datos de apoyo y aprobada principalmente por los presentimientos de los gerentes.

      Es evidente que se necesitan soluciones. Tenemos que desarrollar y dar a conocer las cifras de productividad, las cifras de incidencias que se dan, las reglas de estimación, etc. El conjunto sólo se puede beneficiar si se comparten esos datos.
      Hasta que la estimación no se vea sólida, los jefes o líderes tendrán que endurecer su columna vertebral y defender sus estimaciones con la seguridad de que sus "corazonadas" determinen una buena estimación.


      El desastre de una planificación regenerativa


      ¿Qué hace uno cuando se ve que un proyecto de software se va a atrasar? Añadir mano de obra naturalmente. Como sugieren las Fig. 2.1 a la 2.4, esto puede o no puede ayudar.

      Consideremos un ejemplo. Supongamos que una tarea se estima en 12 meses-hombre y asignados a tres hombres para cuatro meses. Les pondremos a cada bloque, que representa cada uno, un mes, los códigos A, B, C, D y obtenemos una medición (Fig. 2.5). Supongamos ahora que el primer bloque no se logra hasta transcurrido dos meses (Fig. 2.6). ¿Cuáles son las alternativas que se enfrentaría quien está encargado del plan?
      Figura 2.5


      Figura 2.6


      Figura 2.7

      1. Asumir que la tarea debe hacerse a tiempo. Supongamos que sólo ese primer bloque fue estimado con optimimismo, tal como se ve en Fig. 2.6. Entonces quedan 9 meses-hombre de esfuerzo restantes, y como hay un bloque de atraso que son 3 meses, será necesario 4 hombres para cubrir ese bloque. Agregamos 2 hombres a los 3 asignados para 2 bloques.

      2. Asumir que la tarea debe hacerse a tiempo. Supongamos que la estimación total fue uniformemente baja, tal como muestra la Figura 2.7. El esfuerzo gastado son 3 meses, quedan 9, pero como se asume que es una estimación uniformemente optimista, este sube a 18 meses-hombre, es decir, cada bloque restante de 6 y no 3 meses. Esto hace que se requieran 9 hombres en total, 6 hombres en vez de 3 asignados.

      3. Reprogramar. Quiero tomar el consejo dado por P. Fagg, un ingeniero de hardware con experiencia, "no tomar los pedazos". Es decir, que en la nueva estimación haya tiempo suficiente para que el trabajo puede ser realizado cuidadosamente y completamente con tal que de no volver hacer una reprogramación.

      4. Acortar la tarea. Esto tiende a suceder de todos modos en la práctica una vez que el equipo observa que los tiempos se están agotando. Cuando los costos secundarios del atraso son muy altos, esta es la única acción factible. La única alternativa del Jefe de Proyecto o Gerente es acortar la tarea formalmente y con cuidado, para volver a estimar dicha parte ya que sino, verá como la tarea se acorta en silencio por el equipo debido a un diseño incompleto y a las pruebas inconclusas.


      En los dos primeros casos, insistiendo en que la tarea no debe ser alterada en cuatro meses, es desastroso. Considere los efectos regenerativos, por ejemplo, para la primera variante (Fig. 2.8). Los dos nuevos hombres, aunque sean competentes y se hayan reclutado rápidamente, requerirán entrenamiento en la tarea por alguno de los hombres experimentados. Si esto toma un mes, los tres hombres-meses ya no podrán trabajar sobre la estimación original. Además, la tarea, originalmente particionada en tres bloques, debe ser reparticionada ahora en cinco partes, así que el poco trabajo que se avanzó se perderá y las pruebas del sistema deberán extenderse.


      Figura 2.8

      Así, al final del tercer mes, faltan más de 7 hombre-mes, y se tiene 5 personas capacitadas y sólo un mes disponible. Como la Fig. 2,8 indica, el producto está tan atrasado como si no se hubiese añadido nada (Fig. 2.6).

      Para poder realizarla en cuatro meses, teniendo en cuenta sólo el tiempo de entrenamiento pero dejando afuera tiempos de reparticionamiento y las pruebas del sistema, sería necesario agregar 4 hombres y no 2, al final del segundo mes. Para cubrir efectos del reparticionamiento y las pruebas del sistema habría que agregar aún más hombres. Ahora, sin embargo, se tiene un equipo de 7 hombres y no de 3, por lo que aspectos como la organización del equipo y la división de tareas ahora son de un grado y tipo diferente.

      Hay que tener en cuenta que para el final del tercer mes las cosas se ven muy negras. El hito del 1ro. de Marzo no se ha alcanzado a pesar de todo el esfuerzo en gestión. Es muy fuerte la tentación de repetir el ciclo, agregando aún mas mano de obra, lo que sería una locura.

      Lo anterior supone que sólo el primer hito fue desestimado. Si el 1 de Marzo se hace una reestimación de que toda la planificación bajo un punto de vista que toda la planificación anterior fue optimista, como muestra la Figura. 2.7, se requiere añadir sólo 6 hombres más a la tarea original. Los cálculos acerca del tiempo de entrenamiento, reparticionamiento y pruebas del sistema, se dejan como ejercicio al lector. Sin lugar a dudas, el desastre regenerativo da por resultado un producto más pobre, atrasado y reprogramado con respecto al plan original de tres hombres.

      Si lo simplificamos de forma escandalosa, planteamos la Ley de Brooks:

      Agregar más mano de obra a un proyecto de software que está atrasado, lo atrasa más.

      Esta es entonces la desmitificación del hombre-mes. El número de meses de un proyecto depende de sus limitaciones secuenciales. El máximo número de hombres que se pueden agregar al proyecto depende del número de sub-tareas independientes. A partir de estas dos factores se puede derivar una planificación utilizando menos hombres y más meses. (El único riesgo sería la obsolescencia del producto.) No se puede, sin embargo, hacer un plan con más hombres y menos meses. Hay que recordar que más proyectos de software han fracasado por quedar cortos de tiempo que por cualquier otra causa combinada.