miércoles, 29 de julio de 2009

¿Cómo medir el rendimiento de tus métodos?

Un tema muy importante es el rendimiento de nuestro código, ¿Cuánto tarda en ejecutarse?, ¿Podría hacerlo más rápido aún? éstas preguntas tenemos que tenerlas en cuenta siempre a la hora de programar, por lo que ahora veremos como medirlo mediante un pequeño ejemplo en donde veremos la diferencia entre concatenar con el "+" y hacerlo con una clase del Framework llamada StringBuilder.


  

using System;

using System.Collections.Generic;

using System.Windows.Forms;

using System.Threading;

using System.Text;

 

namespace DemoXml

{

    static class Program

    {

        ///

        /// The main entry point for the application.

        ///

        [STAThread]

        static void Main()

        {

            Test();

        }

 

        //número de vueltas

        static int avgLoops = 10;

 

        //número de concatenaciones

        static int testAppends = 10000;

 

        public static void Test()

        {

            //tres timespan para tener el valor en segundoss

            TimeSpan concatTotal = new TimeSpan();

            TimeSpan concatMaloTotal = new TimeSpan();

            TimeSpan builderTotal = new TimeSpan();

 

            //pintamos un encabezado

            Console.WriteLine("***********************************************************");

            Console.WriteLine("Vuelta | Con mala praxis |     Normal     |  StringBuilder ");

            Console.WriteLine("***********************************************************");

 

            for (int i = 1; i <= avgLoops; i++)

            {

                //en los tres casos sacamos el tiempo actual

                //lo almacenamos en una variable,

                //inmediatamente se ejecuta el método

                //luego se toma el segundo valor de tiempo

                //y por último se restan.

 

                DateTime timeStart1 = DateTime.Now;

                AppendMethod();

                DateTime timeEnd1 = DateTime.Now;

                concatTotal += timeEnd1 - timeStart1;

 

                DateTime timeStart3 = DateTime.Now;

                AppendMethod_Bad();

                DateTime timeEnd3 = DateTime.Now;

                concatMaloTotal += timeEnd3 - timeStart3;

 

                DateTime timeStart2 = DateTime.Now;

                MethodStringBuilder();

                DateTime timeEnd2 = DateTime.Now;

                builderTotal += timeEnd2 - timeStart2;

 

 

                //los escribimos en la consola

                Console.WriteLine("# {0}   |      {1}      |      {2}     |      {3}      ",

                    i.ToString().PadLeft(2, ' '),

                    (timeEnd3 - timeStart3).TotalSeconds.ToString().PadRight(5, '0'),

                    (timeEnd1 - timeStart1).TotalSeconds.ToString().PadRight(5, '0'),

                    (timeEnd2 - timeStart2).TotalSeconds.ToString().PadRight(5, '0'));

 

 

            }

 

            //por ultimo imprimimos los promedios

            Console.WriteLine("***********************************************************");

            Console.WriteLine("Promedios");

 

            Console.WriteLine("Tiempo concatenando (Con mala praxis): {0} segundos.",

                Math.Round(concatMaloTotal.TotalSeconds / avgLoops, 3).ToString().PadRight(5, '0'));

 

            Console.WriteLine("Tiempo concatenando (Normal):          {0} segundos.",

                Math.Round(concatTotal.TotalSeconds / avgLoops, 3).ToString().PadRight(5, '0'));

 

            Console.WriteLine("Tiempo con StringBuilder:              {0} segundos.",

                Math.Round(builderTotal.TotalSeconds / avgLoops, 3).ToString().PadRight(5, '0'));

 

            Console.WriteLine("***********************************************************");

 

            Console.Read();

        }

 

        //metodos originales sin código de pruebas

        private static string AppendMethod_Bad()

        {

            //este metodo concatena valores aleatorios

            //el problema de éste es que la clase Random

            //la instanciamos en cada vuelta, por lo

            //que se produce una perdida de rendimiento

            string result = "";

            for (int i = 0; i <>

            {

                Random rand = new Random(DateTime.Now.Millisecond);

                result += (byte)rand.Next(65, 91);

            }

            return result;

        }

 

        private static string AppendMethod()

        {

            //de mejor forma instanciamos Random

            //antes del ciclo y ejecutamos el Next

            //tantas veces como necesitemos

            string result = "";

            Random rand = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i <>

            {

                result += (byte)rand.Next(65, 91);

            }

            return result;

        }

 

        private static string MethodStringBuilder()

        {

            //Acá podemos ver que el uso del StringBuilder

            //es muy sencillo.

            StringBuilder builder = new StringBuilder();

            Random rand = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i <>

            {

                builder.Append(rand.Next(65, 91));

            }

            return builder.ToString();

        }

    }

}




Vemos que la diferencia es grande utilizando StringBuilder, por lo que es recomendado utilizarlo en dos casos: cuando no sepas la cantidad de vueltas que da el bucle o cuando la el número de vueltas sea significativo.

Gracias por leer

miércoles, 22 de julio de 2009

Navegadores, ¿Cómo escojer uno?


 Existen muchos navegadores gratuitos hoy en día, tantos hay que los usuarios ni saben las diferencias entre uno y otro. Entonces en este post los compararemos brevemente para que tengamos una idea de cual usar, o usar varios.

Vamos a ver cuales son los Navegadores más utilizados, según Wikipedia:



Internet Explorer (65.50%)
Mozilla Firefox (22.51%)
Safari (8.43%)
Google Chrome (1.80%)
Opera (0.72%)
Other (1.04%)


Vamos ahora a discutir cada navegador:

Internet Explorer: es el más utilizado pero no necesariamente el mejor, esto pasa porque viene preinstalado en Windows . En la Unión Europea Windows 7 va a venir sin IE debido a leyes antimonopolio, personalmente me parece lo más tonto que le hayan pedido a Microsoft, de hecho la versión se va a llamar Windows 7 EU si no me equivoco.

IE siempre va a ser nuestro aliado a la hora de que tengamos que descargar nuestro navegador favorito o cuando, por ejemplo, por X razón nuestro navegador falla. Por eso es bueno tener un segundo navegador instalado y qué mejor que IE que viene Preinstalado :).

El único fallo que tiene es que cada pestaña tarda demasiado en abrir. Pero de resto funciona y es bastante estable. Otro problemita es que no siguen los estándares web, lo que produce que muchas paginas se vean mal en otros navegadores.


Mozilla Firefox: fue mi navegador por defecto por muchos años, desde la versión 1 hasta la 2. FF es full personalizable, tiene skins, extensiones, además de ser Open Source. El navegador como tal es full bueno, tiene muchisimas opciones y considerablemente estable. 

Hablando del porcentaje de uso, el número que tiene se debe a varias razones:  la primera es que tiene un buen marketing. La segunda es que es el navegador por defecto de las distribuciones de Linux, por lo que, al igual que Microsoft es adóptado simplemente porque viene instalado (Aunque normalmente vienen otros aparte como Konqueror). Y por último el tema Open Souce, es decir, de entre los navegadores libres FF, sin duda alguna, es el mejor, por lo que es adoptado por muchos seguidores de dicho movimiento.

FF tiene bastantes formas de personalizarse, pero esa es su debilidad, cada vez que lo instalas tienes que encontrar entre cientos de extensiones UNA que funcione y que siempre tienes que poner cada vez que instalar FF en un equipo nuevo.

Con respecto a los estándares, FF los sigue casi al 100%. Si no me equivoco la versión 3.5 sacó 100/100 en la prueba acid 3.


Safari: el navegador de Apple, muy bueno, estable y con buen look (Obviamente Apple jeje). De  Safari no hay mucho de decir, ni tampoco que desear, cumple bastante bien con su objetivo,es rápido y bueno. El problema está en su simplicidad, es un navegador y punto. 


Google Chrome: el nuevo navegador de Google, lo utilizo como mi segundo navegador por que es sencillo y rápido, Tiene una tajada del mercado de navegadores bastante grande y en crecimiento constante. Claro! esto es gracias a la super campaña de Google de colocar un enlace en su portal de búsqueda (Adivinen cuál es el buscador más utilizado).

Además cumple bien con los estándares web (100/100 en acid 3). Y el javascript se ejecuta muy muy rápido.


Opera: Mi navegador preferido. Este navegador tiene un detalle en particular: la innovación. Opera fue el primer navegador en utilizar pestañas (tabs) en vez de abrir varias instancias. Además de un sin fin de opciones y cosas personalizables 100%.

Siempre es el primero en pasar las pruebas de Acid, incluso, el primero que paso Acid 3, aunque google diga que Chrome lo hizo primero, ya que Opera lanzó Presto (el renderizador) en diciembre de 2008 y Chrome 2 pasó la pruba meses después.

En opera no hace falta descargar extensiones ni addins (aunque se puede instalar aparte muchas otras cosas, además de poder hacer widgets) , ya que viene lleno de características que lo hacen ser la mejor suite de Internet (A mi parecer). Entre las cosas que trae podemos nombrar: Cliente Correo, Gestor de Descargas, Cliente Bit-Torrent, Cliente IRC, Lector RSS y Corrector Ortográfico.

Además de eso puedes crear tu propia versión para distribuirla o tu mismo tener una personalizada para que cada vez que tengas que instalarla no tengas que configurar nada composer.opera.com .

Opera con su poco porcentaje de usuarios se ha mantenido en aproximadamente el mismo número y creciendo poco a poco, con muy pocas variaciones, lo que indica que los usuarios se sienten bastante bien con él.


Conclusión:

Ya describimos por encima todos los navegadores, y expuse mi punto de vista sobre cada uno. Yo personalmente utilizo Opera 10 beta para uso diario y Chrome para labores puntuales o dias que simplemente no quiera tocar la sesión de Opera. 

Ahora ¿Cuál deberías usar? depende de tus necesidades, mi recomendación es: no usar uno por usarlo, sino que descargues todos los que puedas, ver sus diferencias , post y contras. Y si quieres comenta tus experiencias.

Además les pregunto a los que ya están decididos por uno ¿Qué navegadores utilizas y Por qué?, o si tienes alguna duda pregunta en los comentarios, que entre todos te ayudaremos a resolverlo!


Como siempre, gracias por leer!

Dónde utilizar manejo de excepciones (Try-Catch-Finaly)

El try-catch no puede ser utilizado para todas las validaciones que tengamos en la aplicación, tampoco podemos meterla dentro de un gran try porque es más difícil seguir el control del error. Además de que perdemos un poco de performance ahí. 

Entonces dentro las buenas prácticas para utilizar tenemos:

  1. Para validar valores nulos o rango de valores NO usar try-catch, mejor usar condiciones.
  2. Cuando usas Streams de cualquier tipo (Memory, File, Network, etc) y cuando abres conexiones (Tcp, Udp, Serial, etc) SIEMPRE usar try-catch-finaly. Y en el finaly cerrar la conexión o el stream, así nos aseguramos de que siempre quede cerrado.
  3. Intentar siempre no atajar las excepciones declarando Exception en el catch, sino por la excepción que lance el método, es decir, si vas a ejecutar un método que abre un archivo y ese archivo no existe, lo más seguro es que lance un FileNotFoundException, entonces se hace un catch por ese y por cada uno de las posibles excepciones del método. Así tenemos más control sobre el error.
  4. Las transacciones también deben de escribirse dentro de un bloque try-catch, y en el catch llamar al rollback, ya que si ocurre un error se cancela todo el proceso y mantenemos la integridad de la data.


Un pequeño ejemplo de lo mencionado anteriormente:


public void OpenDocument(string filepath)

{

    //Declaramos el stream y el reader afuera del try

    //para que puedan ser accesados en el finaly

    FileStream fileStream = null;

    StreamReader reader = null;

 

    try

    {

        //abrimos el archivo

        fileStream = new FileStream(filepath, FileMode.Open);

        //creamos el reader

        reader = new StreamReader(fileStream);

        //leemos el archivo

        string filecontent = reader.ReadToEnd();

    }

    catch (FileNotFoundException fileEx)

    {

        //se captura la excepción si no existe el archivo

        //que viene como parámetro del método open y se

        //muestra el error.

        MessageBox.Show("No se pudo encontrar el archivo", "Error");

    }

    finally

    {

        //El bloque finaly SIEMPRE se ejecuta, no importa

        //lo que pase, por eso cerramos el stream aquí, sea que

        //hayamos leido correctamente el archivo o que se

        //produsca una excepción, SIEMPRE se ejecuta el finaly.

        reader.Close();

    }

}

La próxima entrada será de Streaming, así que no se la pierdan!


finaly

{

       Gracias por leer!

sábado, 18 de julio de 2009

Cómo formatear código en tu web

Hoy estaba buscando una manera más fácil de colocar formato al código que coloco en los post, por lo que comencé a buscar en google a ver si alguien tenía alguna herramienta o algo parecido, pero solamente encontré unas páginas que pintan las palabras clave como public, void, class, return, pero no las clases ni los strings, en eso recuerdo una vez copié código desde Visual Studio hasta Word y el formato se mantuvo. Inmediatamente se me ocurre pegarlo de Visual Studio hacia el editor de post para crear una entrada, pero el formato no funciona.

Algo decepcionado y pensando de nuevo en el trabajo que lleva coloear y formatear el código a mano, se me pasa por la cabeza copiarlo primero a Word y luego a blogger!! y Funcionó perfecto!! :) 

Ahora conocen el truco, echan el código en Visual Studio, lo pegan en Word, lo copian de nuevo, y lo pegan finalmente en el editor de entradas. 

Un código demo:

[DllImport("User32", EntryPoint = "GetWindowPlacement")]

private static extern bool GetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);


Espero les sea de gran ayuda, por lo menos para mi si =)


Como siempre gracias por leer!


viernes, 17 de julio de 2009

Generics en .Net

Muchos han escuchado el termino de clase genérica o un tipo genérico, y esto es lo que vamos a definir en esta entrada. 

¿Qué es algo genérico en la vida cotidiana?, puede ser un producto que no tenga una marca como tal, pero igual funciona. En programación podemos utilizar el mismo concepto pero para nuestro código, en donde el tipo se especifica en tiempo de ejecución. Éste tipo de técnicas nos van a permitir reducir la duplicación de código y también el uso de interfaces o clases base en momentos que no son necesarios.

Esto quiere decir que con Generics podemos reducir significativamente la cantidad de código en operaciones que sean repetitivas a lo largo de la aplicación, pero que se efectúen con varios tipos que no tienen nada que ver unos con otros.

Para los programadores de C++ es un concepto parecido a los templates.

Existen varios lenguajes que soportan Generics, entre los cuales están: Java, Eiffel, C++(templates), Ada, Haskell,C#,VB.Net, entre otros.

Ahora vamos a poner en practica los conceptos para poder entenderlo un poco mejor:

public class Program

{

     public static void Main(string[] args)

     {

          int resultInt = GetFibonacci<int>(30);

          long resultLong = GetFibonacci<int>(45000);

     }

     public static T GetFibonacci<int>(T number)
     {
          if (x <= 1)

               return 1;

          return GetFibonacci<T>(x-1) + GetFibonacci<T>(x-2);    

      } 

}

Como podemos observar creamos un método en donde el tipo del parámetro y el retorno es del mismo tipo que se le asigna en el momento de llamarlo colocando el tipo entre los simbolos < y >.

Ahora que pasa si en T colocamos Person o algo parecido, vamos a tener un problema, y la única forma de resolverlo es utilizando condiciones en la asignación del tipo. Es decir, podemos restringir el uso haciendo que T implemente alguna Interfaz o Herede de alguna clase, esto se hace mediante la palabra reservada where.

Ahora necesitamos un método que obtenga el valor menor de un arreglo:

public static T GetMinimun<T>(IList list) where T : IComparable<T>

{

     T result = list[0];

     for(int i =0; i < list.Count ; i++)

     {

          if(list[i] < result)

               result = list[i];

     }

     return result;

}

Podemos ver que utilizamos "where" para restringir el paso de cualquier tipo y solamente permitir a aquellos que implementen IComparable. Aunque funciona perfectamente el ejemplo sin el where, puede darse el caso de que se utilice con algún tipo que no tenga implementada la interfaz por lo que nos daría un error al intentar comparar con otro objeto del arreglo.


Como punto final veremos el uso de delegados genéricos para así completar el post de Delegados.

Existe la posiblidad de crear clases genericas y métodos genéricos, pero también podemos definir delegados genéricos, los cuales nos van a ayudar a reutilizarlos y solamente intercambiar la clase de los argumentos, ejem:

public delegate void MyDelegate<T>(object sender, T e);

Esto nos permite poder crear eventos sin estar codificando y codificando un delegado para cada uno. Ejmplo de uso:

public class TestClass

{

      public event MyDelegate<MouseEventArgs>(object sender, MouseEventArgs e);

      public event MyDelegate<MyOwnEventArgs>(object sender, MyOwnEventArgs e);

}

De esta forma nos ahorramos bastantes líneas de código, disminuyendo el tiempo de desarrollo de la aplicación.


Gracias por leer!

jueves, 16 de julio de 2009

Vulnerabilidad de tipo Zero-day en Firefox 3.5


Según fuentes ha sido encontrado un bug en el reciente Firefox 3.5, de tipo Zero-day, esto significa que es una vulnerabilidad que nadie conoce o también que no hay forma de solucionarlo, ni fix, ni  un parche.

La empresa de seguridad informática Secunia fué la que advirtió del fallo, el cual permite a un atacante remoto ejecutar codigo arbitrario en el equipo donde se ejecuta Firefox.

"La vulnerabilidad es causada debido a un error cuando se procesa codigo Javascript",según la empresa.

Aún no se ha pronunciado Mozilla para ofrecer una solución, pero estos días va a salir la versión 3.5.1 que va a tratar con éste y otros problemas. Por lo que les recomiendo descargar Opera a los usuarios de Firefox mientras se soluciona todo ésto. Pueden hacerlo en el panel derecho del blog.


Gracias por leer!

Resultados de la encuesta:


Primer lugar: C# 10 votos

Segundo lugar: C++ 2 votos

Tercer lugar: empatados Java, VB.net y Php




Nota: Estos resultados solo muestran la tendencia del uso del lenguaje de los lectores del blog.

Delegados en C#

Un delegado es un tipo que especifica un método a llamar, y opcionalmente una referencia a otro delegado. Normalmente se utilizan, aparte de otras cosas, para implementar callbacks y eventos. Entonces, en pocas palabras para los programadores de C++, podemos decir que un delegado es un puntero a un método.

 

Además, los delegados en .net permiten la ejecución asíncrona del método apuntado (Ver),  y también nos permiten obtener un arreglo de los delegados que está apuntando en cadena.

 

¿Cómo declaro un delegado?

 

Supongamos que tenemos el siguiente método:

 

public int Sum(int a, int b)

{

     return a + b;

}

 

Entonces para crear un delegado tenemos que respetar tu firma y su tipo de retorno, quedaría así:

 

public delegate int SumDelegate(int a, int b);

 

Es practicamente un método pero sin cuerpo y con la palabra DELEGATE antes del tipo de retorno. Veamos un ejemplo de uso:

 

public void main(string[] args)

{

     // instanciamos y apuntamos al método Sum.

     SumDelegate sd = new SumDelegate(Sum); 

     //llamamos al delegado y como éste está apuntando

      //a Sum, lo ejectuta y retorna el resultado.

     int result = sd(2,3); // result es igual a 5

}

 

Ahora veamos un uso importante de los delegados:

Los eventos

Un evento es una acción que se inicia fuera de contexto, es manejado en uno más  métodos del programa. Por ejemplo un evento iniciado por el usuario sería el Mouse Click, pero también hay eventos que son iniciados por otros objetos por ejemplo: Application.ThreadException para manejar las excepciones de la aplicación.

Algo que hay que tener en cuenta es que un evento es un delegado que nada más puede invocarse desde el contexto en donde se declaró. Esto quiere decir que una clase que tenga un evento, éste solamente puede llamarse desde dentro de la clase y no fuera de ésta.

Otra punto importante es que el delegado que usemos para definir el evento puede ser cualquiera, tanto uno que venga en el framework como otro nuestro.

Ejemplo:

//esta es la clase donde está el evento

public class Person

{

     //Definimos el evento usando el Delegado EventHandler

     //EventHandler es un delegado bastante usado para eventos que

     //no necesiten pasar datos hacia los parámetros del método suscrito

     public event EventHandler NameChanged;

     public string m_name;

     public string Name

     {

          get { return m_name; }

          set

          {

                //Si el nombre cambia:

                if(value != name)

               {               

                   m_name = value;

                   //Si no hay suscripciones a NameChanged éste queda null

                   //entonces si no es null podemos invocarlo.

                   if(NameChanged != null)

                       NameChanged(this, EventArgs.Empty);

                 }

           }

     }

}

 

//esta es la clase donde está suscrito el evento

public class TestClass

{

     public void Test()

     {

          Person p = new Person();

          p. Name =”Pepe”;   // no se ejecuta el evento

          p.NameChanged += new EventHandler(Person_NameChanged);

          p.Name = “Juan”; // ya estamos suscritos y se ejecuta el NameChanged

      }

      prívate void Person_NameChanged(object sender, EventArgs e)

      {

          //Aki hacemos algo cuando cambie el nombre de person.

      }

}

Siempre hay que mantener el uso del sender y el argumento.  En caso de que se quiera pasar data, simplemente en vez de colocar EventArgs, se coloca una clase que herede de ésta y se le ponen las propiedades necesarias.

Ejml:

public class NameChangedEventArgs : EventArgs

{

       private string m_newName;

       public string NewName

       {

               get { return m_newName; }

       }

}


Ahora quedan dos formas de utilizarlo, la primera es crear nuestro delegado y la segunda es utilizar al EventHandler genérico el cual vamos a hablarles en otra ocasión. Entonces vamos a definir nuestro delegado:

public delegate void NameChangedEventHandler(object sender, NameChangedEventArgs e);

El uso es idéntico al ejemplo anterior pero cambiamos EventHandler por NameChangedEventHandler.


Gracias por leer!

martes, 14 de julio de 2009

Tres Code Snippets para EventArgs (C#)

Hoy les paso un archivo .Zip con tres Code Snippets en C# para crear clases de EventArgs. Los archivos tienen que copiarlos dentro de la carpeta :

Mis Documentos\Visual Studio [versión]\Code Snippets\Visual C#\My Code Snippets\ 


Si por alguna razón no funciona, copienlos en la carpeta de Snippets de Visual Studio:

C:\Program Files\Microsoft Visual Studio [versión]\VC#\Snippets\1033\Visual C#


Si el enlace se rompe o deja de funcionar por favor notificarme por los comentarios para subir uno nuevo:

Descargar

Gracias por leer!!

lunes, 13 de julio de 2009

¿Software Libre o Software Propietario?

Mucha gente se siente atraída hacia el movimiento de Software Libre, ya sea porque le gusta colaborar o porque entienden que el código es más seguro, mientras otros se inclinan hacia el software propietario, licencias y demás. Aquí cada quién tiene sus gustos, pero tampoco hay que dejarse llevar por el fanatismo.

Siempre hablan de las ventajas de cada uno, ahora vamos a ver las desventajas de ambos:

Software Libre

Aunque puedes conseguir ayuda online en un foro o página web, siempre puedes encontrarte con algún problema muy difícil de resolver, por lo que vas a tener que acudir a un consultor el cual te va poner unos precios exorbitantes. Además de eso si alguna aplicación falla de repente NADIE te va a dar soporte, solamente ayuda de un buen samaritano en un foro.

Otro problema es que de cada aplicación hay mil versiones, es decir, a alguien le gusta X programa, lo cambia a su antojo y le pone otro nombre, y así sucesivamente hasta crear 100 aplicaciones que hacen lo mismo. Esto termina en que los esfuerzos de éstos programadores se dividan en varios proyectos y obviamente pierden la fuerza que deberían tener. Un ejemplo son las Distros de Linux, o Compiz y Beryl (que se fusionaron de nuevo :S), Firefox (sí, firefox), clientes de mensajería, de correo electrónico, reproductores de música/video, en fin una infinidad.


Software Propietario

Cuando encuentran un fallo la actualización se tarda considerablemente más en salir y aunque se tarde, hay empresas que incluso te dan parches temporales. Además hay quienes alegan que el software no-libre puede tener instrucciones que espíen a tu pc, y bueno puede que lo tengan,pero puede que no, aunque a mi personalmente me parece un poco paranoico.


Licencias

Ahora con el tema del licenciamiento han habido y habrán muchas discusiones, pero yo soy de los que están de acuerdo con las licencias, ya que como programador se el trabajo que lleva hacer un software que, además, trae beneficios para la empresa que lo adquiere. Un ejemplo que me dijo un amigo:

Imagínate que vas a la carnicería a comprar algo de carne molida para una pasta, y le dices al carnicero: Me da medio kilo por favor. Y cuando te dice son tantos bolívares tu le respondes que no tienes que pagarlo porque como haces software libre,la carne también debe ser libre y todo libre, es decir,el esfuerzo no se paga, sino que uno trabaja para los demás. Tu programas gratis y el carnicero te da carne molida gratis.

Yo lo veo como una utopía, pero como toda utopía es imposible de lograr. Así que, qué mejor forma de pagar por algo?. Vender tu trabajo! Tus conocimientos aplicados a un área. Y no es que esté 100% de parte del Software propietario pero mi trabajo vale, tu trabajo vale.

Bueno los dejo con esa reflección.

Nota para los de Software Libre: yo fuí beta tester de Firefox y otros programas open source como Blender por muchos años y me gusta serlo, pero no tiene que ver con mi punto de vista sobre los negocios.

Como siempre, gracias por leer!