Backbone.js & Knockout

He tenido mucho trabajo y cosas que hacer, que no he podido escribir.

El año pasado mi jefe me pidió que viera las diversas librerías existentes estilo Backbone.js y Knockout. La idea era ver todas las opciones y tomar la más conveniente.

Para ello me puse a leer y buscar bastante información. Además, aproveche de probar cada una y ver como me sentía.  Para ello primero cree una aplicación en Backbone.js y luego observé que tal sería usar Knockout.

El resultado se los comento acá con el código. Así aprenden un poco y elijen el que más les guste.

Backbone.js

Es muy poderoso y usado por muchas personas, pero tiene una curva de aprendizaje un poco fuerte. Se tiene un modelo, con un montón de cosas que hay que definir. Luego, si se siguen las convenciones, al ser modificado, cambia de una vez las vistas. Acá pueden ver mucho mejor todos los detalles.

Lo ideal para trabajar con  él, es tener servicios web de tipo REST.

Crear la aplicación me quitó una tarde y parte de la mañana.

El html:

<div>
    <fieldset>
        <legend>Person List - Using Backbone</legend>
        <div id="person-container">
            <input type="button" value= "Create New" class="Add" id="btn-create-new-person" />
            <table id="person-list">
                <tr>
                    <th>
                        Name
                    </th>
                    <th>
                        Description
                    </th>
                    <th>
                    </th>
                </tr>
            </table>
        </div>
        <script id='person-template' type='text/template'>
            <td><%=ID%></td> <td><%=FirstName%></td> <td><%=LastName%></td> <td><%=Age%></td>
            <td><input type="button" value="Edit" class="person-edit" /> | <input type="button" value="Details" class="person-detail" /> | <input type="button" value="Delete" class="person-delete" /></td>
       </script>
    </fieldset>
</div>

Javascript:

$(function () {

    // Person Model
    var Person = Backbone.Model.extend({
        urlRoot: '/Person/List/',
        initialize: function () {
            console.log('Person initialize');
        },
        defaults: {
            ID: 0,
            FirstName: 'Unknown',
            LastName: 'Unknown',
            Age : 0
        }
    });

    // Person Collection
    var PersonCollection = Backbone.Collection.extend({
        model: Person,
        url: '/Person/List/'
     });

     // Person View - el returns the template enclosed within a tr
     var PersonView = Backbone.View.extend({
         template: _.template($('#person-template').html()),
         tagName: "tr",
         initialize: function () {
             console.log('PersonView initialize');
             this.model.bind('change', this.render, this);
             this.model.bind('remove', this.unrender, this);
         },
         render: function () {
             console.log('PersonView render');
             $(this.el).html(this.template(this.model.toJSON()));
             return this;
         },
         unrender: function () {
             console.log('PersonView unrender');
             $(this.el).remove();
             return this;
         },
         events: {
             "click .person-edit": 'EditPerson',
             "click .person-delete": 'DeletePerson'
         },
         EditPerson: function () {
             console.log('PersonView EditPerson');
             this.model.set({ FirstName: 'Unknown' });
             var self = this;
             this.model.save(this.model, { success: function () {
                 $("input:button", $(self.el)).button();
             }});
        },
        DeletePerson: function () {
            console.log('PersonView DeletePerson');
            this.model.destroy();
        }
    });

    // Actual App view
    var AppView = Backbone.View.extend({
        initialize: function () {
            console.log('AppView initialize');
            this.collection.bind('add', this.AppendPerson, this);
        },
        el: '#person-container',
        counter: 3,
        events: {
            "click #btn-create-new-person": "AddNewPerson"
        },
        AddNewPerson: function () {
            console.log('AppView AddNewPerson');
            this.counter++;
            var newPerson = new Person({ ID: this.counter, FirstName: 'Unknown ' + this.counter, LastName: 'Damn ' + this.counter, Age: this.counter });
            this.collection.add(newPerson);
            newPerson.save(newPerson, { success: function () {
                $("input:button", "#person-list").button();
            }});
        },
        AppendPerson: function (person) {
            console.log('AppView AppendPerson');
            var personView = new PersonView({ model: person });
            $(this.el).find('table').append(personView.render().el);
        },
        render: function () {
            console.log('AppView render');
            if (this.collection.length > 0) {
                this.collection.each(this.AppendPerson, this);
            }
            $("input:button", "#person-list").button();
        }
    });

    var persons = new PersonCollection();
    var view = new AppView({ collection: persons });

    persons.fetch({ success: function () {
        console.log('Fetch called');
        view.render();
    }});
});

Y en el servidor (en mi caso asp.net MVC 3 con C#):

public class PersonController : Controller
{
    List<Person> Persons = new List<Person> {
        new Person (1, "Federico", "Ponte" , 23),
        new Person (2, "Alejandro", "Drago" , 23),
    };

    // Get Person
    [AcceptVerbs(HttpVerbs.Get)]
    public JsonResult List(int? ID)
    {
        if (ID.HasValue)
        {
            Person PersonResult = Persons.Find(p => p.ID == ID);
            return Json(PersonResult, JsonRequestBehavior.AllowGet);
        }
        return Json(Persons, JsonRequestBehavior.AllowGet);
    }

    // Update Person
    [AcceptVerbs(HttpVerbs.Put)]
    public JsonResult List(int ID, Person UpdatedPerson)
    {
        Person PersonResult = Persons.Find(p => p.ID == ID);
        PersonResult.FirstName = UpdatedPerson.FirstName;
        PersonResult.LastName = UpdatedPerson.LastName;
        PersonResult.Age = UpdatedPerson.Age;
        return Json(PersonResult, JsonRequestBehavior.DenyGet);
    }

    //Add Person
    [AcceptVerbs(HttpVerbs.Post)]
    public JsonResult List(Person CreatePerson)
    {
        Persons.Add(CreatePerson);
        return Json(CreatePerson, JsonRequestBehavior.DenyGet);
    }

    //Delete Person
    [AcceptVerbs(HttpVerbs.Delete)]
    public JsonResult List(int ID)
    {
        Person PersonResult = Persons.Find(p => p.ID == ID);
        Persons.Remove(PersonResult);
        return Json(PersonResult, JsonRequestBehavior.DenyGet);
    }
}
public class Person
{
    public Person(int _ID, string _FirstName, string _LastName, int _Age)
    {
        ID = _ID;
        FirstName = _FirstName;
        LastName = _LastName;
        Age = _Age;
    }

    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

Como verán es trabajoso, pero trae sus ventajas: super configurable, sirve para celulares, se tienen los servicios web, etc. Si se quiere escalar, es muy fácil.

Es un poco complicado al comienzo, pero una vez que se entiende y se acostumbra es sencillo.

Knockout

Hace uso del patrón Model-View-View Model. Es muy fácil de aprender y es bastante poderoso. Ya viene con un sistema de templates bastante completo y muchas funciones hechas. Se crea el modelo y basta con modificarlo directamente para que las vistas se actualicen. Tiene buena documentación y no es nada complejo.  Para saber más ingresa aquí.

Un modelo sería:

function PersonModel () {
    var self = this;

    self.ID = ko.observable(0);
    self.FirstName = ko.observable('Unknown');
    self.LastName = ko.observable('Unknown');
    self.Age = ko.observable(0);
}

function PersonCollectionModel () {
    var self = this;

    self.Persons = ko.observableArray()
}

$(function (){
    ko.applyBindings(new PersonCollectionModel());
});

La fastidioso es hacer la funcionalidad: no es tan estructurada. Un ejemplo sería lo siguiente:

function PersonModel () {
    var self = this;

    self.ID = ko.observable(0);
    self.FirstName = ko.observable('Unknown');
    self.LastName = ko.observable('Unknown');
    self.Age = ko.observable(0);

    self.changeAndAlert = function (){
        self.FirstName('Hola');
        self.LastName('Chao');

        alert('Me cambie a ' + self.FirstName() + ' ' + self.LastName());
    }
}
</span></span></span>
<pre><pre><pre><div>
    <fieldset>
        <legend>Person List - Using Knockout</legend>
        <div id="person-container">
            <input type="button" value= "Create New" class="Add" id="btn-create-new-person" />
            <table id="person-list">
                <tr>
                    <th>
                        Name
                    </th>
                    <th>
                        Description
                    </th>
                    <th>
                    </th>
                </tr>
                <!-- ko foreach : persons -->
                    <tr>
                        <td data-bind="text : FirstName"></td>
                        <td data-bind="text : LastName"></td>
                        <td><input type="button" data-bind="click : changeAndAlert" value="ChangeAndAlert" /></td>
                    </tr>
                <!-- /ko -->
            </table>
        </div>
    </fieldset>
</div>

El resto de la funcionalidad implementada en el caso de Backbone.js es sencilla de hacer. Con saber usar bien jQuery o alguna otra librería basta con hacer las llamadas ajax correspondientes y modificar el modelo.

Comparación

Personalmente me gustó mucho Backbone.js. Me sentí más cómodo con él. La forma en que incita a uno a programar da una fácil mantenibilidad y pone de forma sencilla el poder escalar. Es un poco complejo de agarrar al comienzo  pero luego se hace fácil.

En cuanto Knockout es el que más he usado y es bastante sencillo. Se aprende fácilmente y es muy simple.

Ambos son igual de capaces, la decisión es por gusto.

Otras

Hace poco me conseguí me con esta librería patrocinada por Google.

Angular JS

El tiempo

Me pareció interesante escribir un poco sobre una de las cosas que los humanos no entendemos bien y dudo que lo logremos: el tiempo.

Las personas siempre se han visto en la necesidad de medir la duración de los eventos, de ahí que el concepto de tiempo es intrínseco a la humanidad. Pero aún mas interesante es la evolución de este concepto y la forma que lo vemos hoy en día.

La física ha avanzado bastante y gracias a Einstein surgió la teoría que el tiempo no es independiente del observador, es decir ya no es algo absoluto, sino relativo. Indudablemente esto representó una revolución para la forma de ver las cosas. El pensar que el tiempo entre dos personas no es el mismo es difícil de creer.

Otra de las cosas fascinantes del tiempo es la posibilidad de viajar a través de él, bien sea al pasado o al futuro. De acá hay muchas películas e historias. También hay muchas teorías y especulaciones de lo que puede pasar si se logra hacer. He visto muchas cosas que lo manejan de formas diferentes:

  1. Hay una sola línea del tiempo, la cual cambia si el pasado es modificado.
  2. Cada vez que el pasado es modificado, se crea una nueva línea del tiempo y el otro sigue como tal.
  3. Hay infinitas líneas del tiempo y puede suceder tanto la primera como la segunda.

Quería recomendar las siguientes historias que me han encantado:

  • El efecto mariposa : Excelente película que trata la vida de una persona que es capaz de cambiar su presente modificando su pasado (opción 1). Es fascinante ver como cada opción modifica la vida del protagonista.
  • Mr. Nobody : Trata sobre todas las posibles vida que pudo haber tenido el protagonista. Muy buena la historia.
  • Steins;Gate : Es un anime, y personalmente es uno de mis favoritos. La historia es original y fascinante. El comienzo es un poco lento y aburrido, pero después uno no se puede despegar. Está muy bien hecha y la recomiendo 100%. Lo que dice la revisión de uno de los usuarios en la página de IMDB es 100% lo que yo pienso. El tiempo se ve como la opción 2.
  • A briefer history of time : Lamentablemente quede por la mitad leyendo este libro, pero es una obra maestra escrita por Stephen Hawking. Es un resumen para personas normales de lo que es la física hoy en día. Muy interesante.

Espero que les guste, chao.

Números primos

El fin estaba algo aburrido y venía de leer el siguiente artículo:

http://tech-queries.blogspot.com/2009/04/amazon-interview.html

Lo conseguí ya que me dio curiosidad como es el Fibonacci con eficiencia (n*log(n)) (http://tech-queries.blogspot.com/2010/09/nth-fibbonacci-number-in-ologn.html)

En eso me dio por hacer un problema en http://www.spoj.pl. Entre en mi cuenta, en la cual tengo como 7 problema hechos y vi cual hacer. Elegí uno de generar números primos( http://www.spoj.pl/problems/PRIME1/). Se da una serie de intervalos y hay que imprimir los números primos que hay en ellos.

Empece a programar en Python y yo ya conocía de la criba de Eratóstenes (http://es.wikipedia.org/wiki/Criba_de_Erat%C3%B3stenes) para generar números primos. Fui por una solución simple, buscaba el máximo número en el cual un intervalo terminaba y calculaba los primos hasta ahí y luego imprimía los que había en cada uno de los intervalos.

#!/usr/bin/python
# -*- coding: utf-8 -*-

from sys import stdin

def sieve(end):
    primes = range(2, end+1)
    for i in primes:
        j = 2
        while i * j <= primes[-1]:
            if i * j in primes:
	            primes.remove(i*j)
            j += 1
    return primes


if __name__ == "__main__":
    end = 0
    ncases = int(stdin.readline())
    cases = []

    for ncase in xrange(ncases):
        case = stdin.readline()
        case_start, case_end = map(int, case.split(' '))
        cases.append({'start' : case_start, 'end' : case_end})
        end = max(end, case_end)

    primes = sieve(end)

    count = 1

    for case in cases:
        for prime in primes:
            if prime < case['start']:
                continue
            elif prime <= case['end']:
                print prime
            else:
                break

        if count != ncases:
            print ''

        count += 1

No cumplió por problemas de memoria, ya que el arreglo de primos era muy grande, así que decido hacer lo mismo, pero en C++. Me encargue de hacerlo super eficiente en memoria, usando 1 bit por cada primo, en vez de 1 byte. Con mi computadora me tomó unos minutos sacar todos los primos hasta 1000000000. Me generó un archivo de 500 megas.

#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
#include <stdlib.h>
using namespace std;

const char masks [] = {-2, -3, -5, -9, -17, -33, -65, 127};

char *sieve(int max)
{
    int max_index = max/8 + 1;
    char *primes = new char[max_index];

    for(int i = 0; i < max_index; i++)
        primes [i] = 255;

    for(int i = 2; i <= max; i++)
    {
        int j = 2;
        int mult =  0;
        while((mult =  i * j) <= max)
        {
            int index = (mult - 1)/8;
            primes[index] &= masks[(mult - 1) % 8];
            j++;
        }

    }

    return primes;

}

int main()
{

    int ntest;
    int case_start, case_end;
    int max_end = 0, test = 1;
    vector<pair<int, int> > cases;

    cin >> ntest;

    for(; test <= ntest; test++)
    {
        cin >> case_start;
        cin >> case_end;

        pair<int, int> test_case(case_start, case_end);

        cases.push_back(test_case);

        max_end = (case_end > max_end ? case_end : max_end);

    }

    char *primes = sieve(max_end);

    vector<pair<int, int> >::iterator it;
    test = 1;

    for ( it=cases.begin() ; it != cases.end(); it++, test++ )
    {
        pair<int, int> test_case = *it;
        case_start = test_case.first;
        case_end = test_case.second;

        if(!(case_start & 1))
            case_start++;

        for(case_start; case_start <= case_end; case_start += 2)
        {
            if(case_start == 1) continue;
            int index = (case_start -1)/8;
            if(primes[index] & (1 << ((case_start -1) % 8)))
                cout << case_start << endl;
        }

        if(test != ntest)
            cout << endl;
    }

}

Esta vez se cayó por tiempo. Era claro que no use el modo correcto para calcular las cosas. Pensé un rato y leí un poco por Internet. Resulta que existe una versión segmentada de la criba de Eratóstenes.  Se calculan los primos hasta la raíz cuadrada del número (en este caso 32000) y luego con esos primos, se revisa en el intervalo si algo de esos es múltiplo de él, sino es un primo. Lo implemente y por tratar de programar de modo legible, entendible y bonito, se me cayo por tiempo. A la final elimine funciones e hice casi todo en la función principal y lo logre. Perdí un buen tiempo, pero fue interesante.

#include <iostream>
#include <fstream>
#include <vector>
#include <math.h>
#include <stdlib.h>
#include <string.h>
using namespace std;

#define MAX_FIRST_SIEVE_INDEX 32000
#define MAX_FIRST_SIEVE_PRIME 32000
#define MAX_PRIMES 4000

bool sieve[MAX_FIRST_SIEVE_INDEX];
int primes[MAX_PRIMES];

void gen_first()
{
    int i = 0, k = 0;

    memset(sieve, true, MAX_FIRST_SIEVE_INDEX);

    for(i = 2; i <= MAX_FIRST_SIEVE_PRIME; i++)
    {
        int j = 2;
        int mult =  0;
        if(sieve[i-1]) 
            primes[k++] = i;

        while((mult =  i * j) <= MAX_FIRST_SIEVE_PRIME)
        {
            sieve[mult-1] = false;
            j++;
        }

    }

}

int main()
{
    int ntest;

    cin >> ntest;
    gen_first();

    for(int test = 1; test <= ntest; test++)
    {
        int case_start, case_end;

        cin >> case_start;
        cin >> case_end;

        for(int i = (case_start > 2 ? case_start : 2); i <= case_end; i++)
        {
            bool print = true;

            for(int j = 0; primes[j]*primes[j] <= i; j++)
            {
                if(i % primes[j] == 0 )
                {
                    print = false;
                    break;
                }
            }
            if(print) cout << i << endl;

        }

        if(test != ntest)
            cout << endl;
    }


}

Big Data, mi opinión y varias cosas cool en Python

Big Data

Ayer revisando mi twitter, me encuentro con lo siguiente:

http://techcrunch.com/2012/10/27/big-data-right-now-five-trendy-open-source-technologies/

Varias de esas tecnología las he escuchado y usado: he usado un poco hadoop mediante pig y otros en el trabajo usan Kafka. Es increíble hacia donde esta yendo el mundo de la computación e información. Ciertamente las metaheurísticas que vi y use para hacer data clustering en mi tesis están en el rumbo correcto. Ya la programación normal no se de abasto. Pensar en paralelización y formas para manejar cantidades gigantes de datos es el futuro. Es la era de la información y hay que saber como explotar y sacar todo lo posible de los datos. Ya veremos como siguen las cosas, mientras a conocer un poco de estas cosas.

Python

En lo que estaba haciendo me vi en la necesidad de hacer request a MySQL, a páginas web, mandar correos, hacer gráficas, entre otras cosas. Todo lo hice mediante Python y ciertos bash para ayudarme.

Request a páginas web

Use lo siguiente: http://docs.python-requests.org/en/latest/. La libreria urllib2 es muy buena y es posible que no halla tenido que usar esta, pero en verdad fue lo que me salió más rápido y conseguí de primero.

Hacer una petición POST es así de tonto:

import requests
    result = request.post(url, params = parametros[, cookies = ....])

Si queremos que sea una petición GET, siemplemente se cambie la palabra. Por ejemplo si queremos atentificarnos en una página y luego sacar información el script sería algo así:

import request

auth_cookies = None
def login():
    request_result = requests.post(url, params = {'username' : usuario, 'password' : clave})
    request_result.raise_for_status()
    global auth_cookies
    auth_cookies = request_result.cookies

def get_information():
    request_result = requests.get(url', params = ..., cookies = auth_cookies)
    request_result.raise_for_status()
    #En request.text esta el resultado, lo parseamos o buscamos lo que necesitamos de acá

if __name__ == "__main__":
    login()
    get_info()
    ....

Así de fácil.

Mandar email

Lo saque de internet y le comenté ciertas cosas que no me agarranon bien:

import os
import smtplib
import mimetypes
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.MIMEAudio import MIMEAudio
from email.MIMEImage import MIMEImage
from email.Encoders import encode_base64
from sys import argv

def sendMail(subject, text, *attachmentFilePaths):
    gmailUser = ''
    gmailPassword = ''
    recipient = ''
    msg = MIMEMultipart()
    msg['From'] = gmailUser
    msg['To'] = recipient
    msg['Subject'] = subject
    msg.attach(MIMEText(text))
    for attachmentFilePath in attachmentFilePaths:
        msg.attach(getAttachment(attachmentFilePath))
        mailServer = smtplib.SMTP('smtp.gmail.com', 587)
        mailServer.ehlo()
        mailServer.starttls()
        mailServer.ehlo()
        mailServer.login(gmailUser, gmailPassword)
        mailServer.sendmail(gmailUser, recipient, msg.as_string())
        mailServer.close()
       print('Email enviado a %s' % recipient)

def getAttachment(attachmentFilePath):
    contentType, encoding = mimetypes.guess_type(attachmentFilePath)
    if contentType is None or encoding is not None:
    contentType = 'application/octet-stream'
    mainType, subType = contentType.split('/', 1)
    file = open(attachmentFilePath, 'rb')
    '''
    if mainType == 'text':
        attachment = MIMEText(file.read())
    elif mainType == 'message':
        attachment = email.message_from_file(file)
    elif mainType == 'image':
        attachment = MIMEImage(file.read(),_subType=subType)
    elif mainType == 'audio':
        attachment = MIMEAudio(file.read(),_subType=subType)
    else:
    '''
    attachment = MIMEBase(mainType, subType)
    attachment.set_payload(file.read())
    encode_base64(attachment)
    file.close()
    attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(attachmentFilePath))
    return attachment
 

Mandarlo es simplemente completar las variables y usar las funciones como uno desee.

System call hooking

El otro día, me encuentro que hay un rootkit creado para pasar gran parte de los kernel de MAC, haciendo uso de system call hooking. Encontré este artículo bastante interesante que explica por cimienta el tema. Muchas cosas me llamaron la atención, veré si leo más del tema. Tampoco esta demás aprender un poco del funcionamiento del kernel de linux y sus módulos.

Como vamos

Primero comentare del pasado domingo brevemente:

No hubo fraude, simplemente tenemos una mayoría en el país que fue exluida por 40 años y ahora que le dan migajas de esperanzas, dan su voto por la mediocridad. Un cambio es necesario y es hora de una política seria.

Desde hace que no posteo nada, he estado ajustado de tiempo. Las cosas que han pasado:

  • Ya no ando programando en asp.NET (use MVC 3.0 con VB y 2.0 con C#)
  • Lo del artículo va en camino de tortuga.
  • Ahora ando en un proyecto de investigación, donde he tenido que usar Java, Python, bash y SQL.
  • Me compre un Nexus 7 y unos audífonos. Excelente hasta ahora, 100% recomendables.
  • asp.net MVC >= 3.0 no tiene nada que envidiarle a otro frameworks. Es facil de usar y de programar. En mi caso use el EntityFramework para manejar la parte del modelo. Es bastante configurable y permite usar stored procedures. Ésto último es muy buena práctica. IIS lo poco que tuve que tocar, me pareció bueno. Mis quejas serían tener que pagar por algo que se puede tener gratis igual o mejor (RoR, Django) y la documentación no es tan buena en comparación con las cosas que son open source.
  • Team Fundation y svn, son un asco al lado de git. Gracias Linus Trovalds.
  • Como escribí antes me encanta Python, lástima que lo conocí y aprendí tarde. Es bastante legible y poderoso. Ando seguro que Perl es muy usado y posiblemente más poderoso, pero odio los $ (si odio php).
  • Es increíble la cantidad de herramientas que existen hoy en día. Ejempo son hadoop, pig, oozie, que otros en el trabajo andan usando.
  • Con respecto al anime, me leí gran parte de las novelas de Sword Art Online. Muy buenas. Salió una ova de Code Gueass.
  • Me puse a ver Breaking Bad. Voy terminando la 3era temporada. Que serie tan buena. Tiene unas partes que te mantienen pegado, pero debo decir que a veces se pone algo calmada y lenta. Ya veremos como sigue.

A ver si tengo cosas más interesantes que colocar, ya veremos.

La verdad

Esta vez si tengo un buen tiempo sin escribir, pero no tengo tanta inspiración ni tiempo como antes. Esta vez se me ocurrió escribir de algo totalmente apartado de la computación.

Empezare con un hecho y de ahí partiré con una idea. Me recuerdo hace como seis años presentando el examen de la UCV, una de las lecturas en habilidad verbal. Planteaba dos puntos de vista entorno a la verdad.

¿La realidad que percibimos es la correcta?

¿Cómo demostramos que lo que decimos es cierto?

A mi parecer es bastante interesante la temática que gira alrededor de éstas preguntas. No hay una respuesta concreta, lo único que puede surgir es una explicación basada en nuestra imaginación.

Al ser un fiel creyente de las ciencias, pensaría que no queda mas que aceptar las verdades que provienen del resultado del método científico. A través de la historia hemos visto como se van modificando nuestras creencias. Un día pensamos que la cinética funciona de cierta forma y unos siglos después pensamos de otra forma. Y así sucede con muchas cosas. Lo importante es que en el fondo estas transformaciones vienen de un estudio, demostraciones y análisis, que de una forma lógica, nos hacen pensar que son las correctas.

Todo lo mencionado anteriormente se puede encerrar en un término: la razón. Ésta domina en todo el mundo científico. He de acá que sea de gran influencia. Lamentablemente este es sumamente pequeño, representa un porcentaje muy bajo de la población. Uno creería, que sucede lo mismo en el resto de la humanidad, pero eso nunca ha sido ni será así. A mi parecer la gente es muy maleable y de fácil engaño. No soy un experto en historia, pero a través de ella se puede ver, que las cosas inexplicables y sobrenaturales, cautivan mucho más a las masas y causan todo tipo de eventos.

En el pasado eran los dioses en Grecia y Roma, todas las religiones. Actualmente son las falacias de los políticos en búsqueda de tener poder. Da mucha tristeza ver el funcionamiento de muchas cosas en el mundo actualmente, en particular en mi país.

Y es que en la misma sociedad que uno se encuentra ve la cantidad de mentiras y falta de razonamiento para todo. La corrupción, malos servicios, las mentiras que dicen todas las personas (donde me incluyó, en menor grado, pero la necesidad de mentir por temor o no querer hacer daño existe), etc.

Dos animes me han hecho pensar cómo sería un mundo donde no existen las mentiras y todo sean puras verdades : Evangelion y Code Geass. En ambos, el plan de los antagonistas, es implantar un mundo donde ésto suceda. Y en ambos, los “buenos” rechazan esas intenciones, con la idea de que dejaríamos de ser humanos. Argumento totalmente válido, pero los mismo problemas de la actualidad seguirían, pensaría yo. Claro está, que eso nunca lo sabremos a ciencia cierta.

Y así se puede seguir desglosando dudas, opiniones y respuestas de este interesante tema.

Lenguajes de Programación

Tenía un rato sin escribir. Muchas cosas encima.

Estaba acordándome de muchas cosas que vi en la universidad. Una de ella fue la electiva de lenguajes de programación. Justo me he estado acordando, primero por programar todo el tiempo y estar leyendo cosas nuevas, que salen. También he programado en muchos lenguajes, en algunos poco y en otros bastante, y siempre ando aprendiendo cosas nuevas.

De la universidad tengo uno que otro libro. Los cuadernos tendría que buscarlo bastante. A lo que quiero llegar, es que lo único que guarde fueron los apuntes de esas cosas que aprendí.

Esa electiva es la abren cada 2 años debido a la poca demanda. Segundo, es considerada bastante compleja y difícil, lo cual es muy cierto. En ella se ve toda la teoría detrás de los compiladores, optimización y alguna que otra cosa que el profesor desee dar (en mi caso, fue equivalencia de lenguajes o algo por el estilo, no me acuerdo 100% bien). Estás razones, agregándole el poco “uso” a la hora de trabajar hacen que muy pocas personas la vean.

Me agradaría comentar el porque yo elegí verla, que opino de ella y que cosas vi y aprendí.

Primero, nunca he sido un gran amante de tener un horario, trabajar y siempre quise primero, tener mucho conocimiento y luego aplicarlo.  Sumando el hecho de mi indecisión de tomar tesis o pasantía, las fechas en que abren las materias, la termine cursando. Me pareció una excelente oportunidad de expandir mis conocimientos y aprender algo que es sumamente complicado en algún trabajo. Me llamó mucho la atención la dificultad, el hecho que se complementara con la otra electiva que tome (diseño de algoritmos) y de tener una gran teórica a la hora que desee aplicar a un postgrado.

Ahora mi opinión. Me pareció excelente, al principio espere otra cosa, pero ya a la mitad del curso se puso sumamente interesante. Capte mucho mejor la teoría detrás de los lexers/parsers. Viví en carne propia como se hace la generación de código ensamblador, lo cual en realidad no es complicado, sino trabajoso. El manejo de memoria estática, como se hace con las variables anidadas. Debido a que el proyecto era en parejas y la cantidad de tiempo limitada, el hacer una manejador de memoria dinámica era opcional y evidentemente no lo hice.

Una de las cosas que más me gusto fueron las técnicas de optimización de código. Vi como 7 – 8,  pero de las más importantes y que mejoran la velocidad significativamente. Es de mucha ayuda generar primero un código intermedio, al cual se le pueden hacer análisis de flujo, optimización de ciclos, eliminar variables innecesarias, etc. Y luego generar el código de máquina objetivo y aplicar las optimizaciones respectivas que se le puedan hacer a eso. Viendo los grafos de flujo del código, se puede eliminar código que no se usar, ver que variables permanecen vivas a medida que el código se ejecuta y mediante eso hacer muchas mejoras.

Con los ciclos se puede sacar invariantes, calcular mucho más rapido el acceso a estructuras (por ejemplo, arreglos), y así muchas otras cosas.

Yo solo vi como un abre boca a la cantidad de mejoras que se pueden hacer. Lo interesante es que en el análisis de flujo, se usan unas ecuaciones matemáticas bastante interesantes llamadas, ecuaciones de punto fijo (fixed point en inglés). Es posible que ande mal, pero sino me equivoco son dos fórmulas recursivas dependientes entre sí mismas. Ya hay un algoritmo matemático que las resuelve y el análisis del flujo se expresa en ese formato.  Se puede crear una especia de librería que tenga la capacidad de optimizar el código y no dudaría si ya existen.

Pienso que salí como un gran programador después de ver la cadena. En mi opinión saber programar y hacerlo bien es más importante que tener todo el conocimiento en algún lenguaje. La capacidad que uno adquiere de adaptarse a cualquier lenguaje, librería, software, luego de ver la electiva, me parece que aumenta. Opino que no tiene nada que envidiarle a cualquier otra electiva y no hay nada que temerle. El conocer como es el funcionamiento por debajo de un lenguaje, las decisiones que se toman a la hora de su diseño, las capacidades, etc., son muy útiles en la vida real.

Eso era todo quería expresar ésto!

Proyectos olvidados

En mi aburrimiento me provocó escribir sobre cosas que he querido terminar, pero he dejado a medias.

Soy una persona muy curiosa y me agrada saber cosas interesantes.

Siempre me ha gustado leer historia de matemáticos/computistas/físicos/cualquier cosa afín científica. Me he propuesto proyectos personales y por flojera, o el tener que dedicarme a otras cosas, he tenido que abandonarlo. Hablare de tres en específicos que espero algún día terminarlo.

Dos de ellos son leer libros.

El primero es nada mas y nada menos “Una breve historia del tiempo” por Stephen Hawking. Siempre me ha cautivado toda la filosofía e ideas detras de la relatividad, física cuántica, agujeros negros, el tiempo, las estrellas, etc. Este libro fue escrito para que cualquier persona, sin muchos conocimientos, sea capaz de entender la física actual. Me compre el libro en uno de mis viajes y lo leí hasta la mitad. Super interesante y siempre lo quise terminar.

El segundo es un libro que me compre en argentina llamdo Gödel para todos, donde se explica el teorema de la incompletitud. Es decir la demostración de que en las matemáticas que conocemos hoy en día hay cosas indemostrable. Se toca toda la temática alrededor: implicaciones, como surgió, su demotración, etc. Parte importante para Gödel fue demostrar que en la lógica que se usa todo es demostrable. Esa temática también es tocada en el libro.

Finalmente de lo que quería hablar es de un proyecto de programación que no termine. Una de las electivas que vi en la universidad fue lenguajes de programación. En los dos trimestre se ve al comienzo toda la teoría de crear parsers y luego ya se entra en la parte de optimizar código. El proyecto es uno sólo y consiste en hacer un compilador para un lenguaje de tamaño mediano. Para mi fue un proyecto full complejo, debido a la cantidad de detalles que hay que tomar en cuenta. Se tuvo que usar java para crear el compilador y para el código generado era en x64 (NASM, es decir, sintaxis intel) sin optimizaciones. El manejo de memoria era estático y el lenguaje podría decirse que era C sin malloc. Lo único que falto fue afinar detalles, entre los cuales uno era la asignación. No era tan simple ya que se podían asignar estructuras complejas, lo que dificulto en cierto modo la generación de código. Hace un rato arregle algo de código para hacerlo más legible y organizado en especial, pero aun tiene cosas que hacen que no compile. Y por supuesto que falta terminar la asignación. Me encantaría finalizarlo por dos motivos. El primero sería para que cualquier persona lo pueda tomar y aprender y el segundo por algo personal. Ya veremos, espero poder dedicarle algún tiempo y tener eso listo pronto. Espero refrescar todo éstos conocimientos algún día.

Eso sería todo, hablamos !