Wednesday, August 14, 2013

De Roshka a Amazon


Apenas termine la facultad empecé a trabajar en Roshka y estuve aquí por 2 años y medio, trabaje en varios proyectos, no solamente con desarrolladores Clase A sino también con gente Clase A. Por lejos el mejor grupo humano con el que me toco trabajar en la vida. Me apoyaron para muchísimas cosas, entre las mas claves, enseñar en la UCA y enviarnos a todo el #devTeam a un diplomado de Java en la Universidad Comunera (UCOM), sin dudar un segundo, el mejor curso de Java del planeta.

A finales del 2011 me dieron una beca Fulbright por lo que ya empezaba a despedirme de Roshka y a sentirme alumno de The Ohio State University. Al comienzo del segundo semestre del masterado asistí a una feria de trabajo en la universidad, al ver el cartel de Amazon y de otras empresas grandes ya estábamos todos demasiado contentos, aunque sea con que nos escuchen un ratito y acepten nuestros CV's. Después de un par de semanas me llamaron y me pidieron que vaya a una serie de entrevistas, me hicieron muchísimas preguntas, sobre todo temas de Java, POO y algoritmos. Si no era por el curso de Java de la UCOM (gracias Pollo, Maestro, Mirnac, Angie, Miguel, en fin, todos los profes y la Roshka), sinceramente no tenia ni una chance en esa entrevista. Finalmente, me ofrecieron ir a trabajar el verano en el headquarters de Amazon en Seattle para un internship de 12 semanas.

En los primeros días tuvimos varias presentaciones sobre Amazon y sobre todas las herramientas de desarrollo que utilizan. Ahí recién empecé a dimensionar lo gigante que era la empresa. Amazon tiene 97.000 empleados, de los cuales 1400 éramos interns. No manejo bien estos números, pero creo que solo un 25% de estos empleados son desarrolladores, el resto son de logística, marketing, finanzas, etc. La experiencia estuvo impecable, el trato, la gente y los beneficios por ser solamente un pasante son de otro planeta. La empresa se encarga de absolutamente todo, vos lo único que tenes que hacer es programar, programar y programar.

Amazon - Edificio Port 99, cafetería del piso 21.
Trabaje en el Departamento de Global Payment Systems. Muchísimo Java, Spring, Scala y un poco de Perl. Los dos proyectos en los que trabaje eran sobre DynamoDB, que es un No-SQL database desarrollado por Amazon, parte de los Amazon Web Services. Estuve ubicado en el piso 21 del edificio Port 99, en Virginia y la 8va. En la imagen se ve de fondo Seattle con el clásico Space Needle.



Los temas que mas me impresionaron de la experiencia:

1. Amazon no solamente es el retail website que todos conocemos y sus mas de 160 millones de usuarios activos, tiene muchas otras empresas y emprendimientos, los mas populares en mi opinión: AWS, Kindle, Amazon Studios, IMDb, Zappos. La arquitectura dentro de la empresa es orientada a servicios, cada departamento tiene una serie de clientes y a la vez es consumidor de una serie de servicios. Cada departamento tiene independencia tecnológica, lo que significa que siempre que cumplan ciertas normas pueden elegir las tecnologías que quieran para desarrollar sus servicios.

2. "It's still Day 1 at Amazon", por mas que la empresa haya crecido muchísimo desde su fundación en el 1995, todavía mantienen ese espíritu de startup, de adaptarse rápido a los cambios y de tomar decisiones sin demasiada burocracia. Claro reflejo de esto, en la empresa hay un deploy de software cada 7 minutos.

3. Me impresiono también la calidad técnica de muchos de los desarrolladores y el buen ambiente laboral que hay adentro, muchísima libertad dentro del trabajo, siempre y cuando entregues tu trabajo terminado y bien hecho.
Amazon - Port 99, piso 24.

Todos los pisos con paredes-pizarron por donde mires, de lo mas normal ver a la gente discutir ideas en cualquier momento/lugar. Muchas actividades para distender también como mesas de ping-pong, esos old-school arcade games gigantes, mesas de pool, beer-friday, entre otras.




4. Tienen un build-system que se llama Brazil, al comienzo no entendía los beneficios de un build-system tan complejo, pero después de un par de semanas comencé a apreciar los beneficios. Básicamente un servicio esta formado por N paquetes, vos podes hacer checkouts independientes, es decir, bajas 1 de los N paquetes, modificas, probas en localhost, y estas listo para hacer un deploy. NO necesitas bajar los N paquetes para probar el servicio (siempre y cuando no necesites modificar los N paquetes).

Como parte del build-system hay un plugin para Eclipse e IntelliJ. El plugin te baja los fuentes y te agrega un VersionSet que es el conjunto especifico de las librerías que necesitas para compilar y correr todo localmente. Esto hace que arreglar un bug o agregar una funcionalidad sea extremadamente sencillo. Aquí hay mas detalles de un ex-empleado que en teoría trabajo en el equipo de desarrollo de esta herramienta.

5. Tienen un deployment-system llamado Apollo. Básicamente una vez que haces un check-in de tu código, arma un subconjunto de tu VersionSet para hacer el deploy, y a la par tenes una herramienta web que te muestra en un pipeline como va corriendo el deploy desde la etapa Alpha, Betha, Gamma, Development, Pre-Production hasta Production. Todo haces desde tu IDE, sin distraerte ni un segundo con línea de comandos ni nada extraño.

6. Nadie puede hacer check-in de UNA línea de código antes de pasar por un Code Review. De nuevo, tienen un plugin y todo esto esta integradísimo con el IDE y con una herramienta web que te ayuda a responder a los comentarios que hicieron sobre tu código. Cuidan mucho también los coding/naming conventions. Mucho TDD también dentro de los equipos, cada pedazo de código que escribís, tiene que tener adjunto su conjunto de unit/integration tests.

7. En honor al glorioso #runningTeam de la Roshka le metía un 7K por esta zona los fines de semana, solo en honor, ya que no me considero parte de esa elite de atletas de la Roshka. Entre semana normalmente no había mucho tiempo, a pesar de ser interns, muchos recibimos proyectos que incluso llegaban a Producción, o sea que no era un paseo nomas es el tema.


En fin, a esta altura ya nadie esta leyendo esto, pero no quiero terminar sin decir que aguante La Roshka y toda su gente, ojala tenga el honor de compartir de nuevo la #piezaInternacional o la de #inviernoTodoElAño con el impecable #roshkaDevTeam. Salud!




Todo esto es exclusivamente una opinión mía, en ningún momento escribo en nombre de Amazon ni de ninguno de mis compañeros de trabajo.


Tuesday, July 9, 2013

Staff remoto

Hoy anunciamos que cerramos trato con nuestro primer programador IDE remoto. Es Andrea "Pandita" Mercado.


Es conocida de la casa, había trabajado con nosotros y tuvo que salir por mudarse a vivir a otra ciudad, pero como tanto la extrañábamos, decidimos hacer un plan piloto de trabajo remoto para probar a ver qué tal puede funcionar para nuestro mercado un esquema así.

Ojalá ella sea la primera de muchos otros, porque la vanguardia, es así.

Bienvenida de vuelta, Pandita!

Friday, August 24, 2012

Android EditText with number format input

Some applications require formatting the EditText's value while typing. I.E., a number that needs to be formatted with decimal and thousands separators.

We've created a little helper class implementing TextWatcher to do just that.

import java.text.DecimalFormat;
import java.text.ParseException;

import android.text.Editable;
import android.text.TextWatcher;
import android.widget.EditText;

public class NumberTextWatcher implements TextWatcher {
    
    private DecimalFormat df;
    private DecimalFormat dfnd;
    private boolean hasFractionalPart;
    
    private EditText et;
    
    public NumberTextWatcher(EditText et)
    {
        df = new DecimalFormat("#,###.##");
        df.setDecimalSeparatorAlwaysShown(true);
        dfnd = new DecimalFormat("#,###");
        this.et = et;
        hasFractionalPart = false;
    }
    
    @SuppressWarnings("unused")
    private static final String TAG = "NumberTextWatcher";

    @Override
    public void afterTextChanged(Editable s)
    {
        et.removeTextChangedListener(this);
        
        try {
            int inilen, endlen;
            inilen = et.getText().length();
            
            String v = s.toString().replace(String.valueOf(df.getDecimalFormatSymbols().getGroupingSeparator()), "");
            Number n = df.parse(v);
            int cp = et.getSelectionStart();
            if (hasFractionalPart) {
                et.setText(df.format(n));
            } else {
                et.setText(dfnd.format(n));
            }
            endlen = et.getText().length();
            int sel = (cp + (endlen - inilen));
            if (sel > 0 && sel <= et.getText().length()) {
                et.setSelection(sel);
            } else {
                // place cursor at the end?
                et.setSelection(et.getText().length() - 1);
            }
        } catch (NumberFormatException nfe) {
            // do nothing?
        } catch (ParseException e) {
            // do nothing?
        }
        
        et.addTextChangedListener(this);
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after)
    {
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count)
    {
        if (s.toString().contains(String.valueOf(df.getDecimalFormatSymbols().getDecimalSeparator())))
        {
            hasFractionalPart = true;
        } else {
            hasFractionalPart = false;
        }
    }

}

To use it, all you need to do is add a TextChangedListener to the EditText component.

editText.addTextChangedListener(new NumberTextWatcher(editText));


You can get the source code directly from GitHub.



Friday, August 10, 2012

Parecer > Ser

Hace muchos años en circunstancias completamente diferentes, dos grandes amigos de la casa me dijeron básicamente la misma cosa:
Entre ser y parecer, siempre tenés que elegir parecer.
Victor Cálcena estaba criticando mi vestimenta y Miguel Balsevich nuestra página WEB.

Nuestra página fue migrando con los años, pero nunca fue algo a que le tomamos demasiada atención. La primera es una joya de 2002 (templatazo del venerable Frontpage de Microsoft):



La segunda es de 2004. Dio paso a un largo periodo de ausentismo en la WEB:



La tercera es de 2005. Se hizo con Metadot. No tenemos archivos de esa página, pero en algún lado debe estar. La cuarta es de 2008. Una página minimalista que siguió viva hasta hoy:





Ya hora, sin más preámbulo, les presentamos nuestra nueva página web. Con esta, empezamos a parecer un poquito más que antes.




De los detalles técnicos, le vamos a pedir a Gustavo que nos cuente en una entrada más adelante. El excelente diseño es de nuestro diseñador estrella Diego Garcete.

Monday, July 16, 2012

Roshka participa de WSA Paraguay 2012

Qué es WSA? De la WEB del concurso:

WSA (WORLD SUMMIT AWARDS) ES UNA CONFERENCIA Y PREMIO MUNDIAL CREADO PARA PROMOVER Y SELECCIONAR LOS MEJORES CONTENIDOS ELECTRÓNICOS Y APLICACIONES TECNOLÓGICAS CON EL OBJETIVO DE TENER UNA SOCIEDAD DE LA INFORMACIÓN MÁS INCLUSIVA.

Este es el sitio WEB internacional oficial, y este es el sitio WEB de Núcleo S.A. que organiza dicho concurso para el Paraguay.

Nosotros nos presentamos este año con 3 aplicaciones:


  • Bubble Drill (juego para iOS)
Bubble Drill es un juego muy divertido y adictivo que consiste que agrupar burbujas del mismo color para reventarlas y evitar que un gran taladro aplaste nuestro mundo.

Disponible de manera gratuita en el AppStore de Apple. Más información, acá.


  • Red Social Roshka (aplicación de Redes Sociales para ser utilizada desde celulares con SMS y MMS)
Red Social Roshka es una aplicación que permite  la conexión a redes sociales (Facebook, Twitter) en celulares usando tecnología SMS / MMS, por lo tanto habilitando a personas que no tienen acceso a la red de DATOS o a un SMARTPHONE acceder a servicios de redes sociales.

Sus principales funcionalidades son:

-FacebookChat
-Twitter
-Envio/recepción de fotos de facebook x MMS.
-Cambio de Status de Facebook.
-Cambio de Status en Twitter

Disponible en Facebook. Acá hay información de cuando la lanzamos al mercado.


  • iFogOfWar (juego para iOS)
iFogOfWar es un juego de estrategia para dos jugadores basado en el popular juego de tablero Stratego. Usa un tablero de 10x10 donde equipos con 40 piezas cada uno pelean por capturar la bandera enemiga.

Disponible de manera gratuita en el AppStore de Apple. Más información, acá.



    ------------------------------

    A través de esta entrada en el BLOG, queremos invitar a todas las empresas colegas a publicar sus producciones, para que este tipo de iniciativas siga haciendo crecer nuestra incipiente Industria Nacional del Software paraguayo.

    Y por supuesto, queremos pedirles que nos den sus votos (en forma de LIKEs en Facebook) para que tengan mayor consideración de parte del jurado internacional. Pueden bajar e instalar las aplicaciones sin problemas, son gratuitas. Además, los enlaces para votar:

    Gracias a todos de antemano.

    Saturday, July 7, 2012

    HTTP POST commands within Oracle's PL/SQL

    Sometimes for system integration it's pretty interesting to perform POST (or GET) HTTP request within Oracle's PL/SQL. It's pretty straightforward, but I have a hard time looking for a specific example (at least for POST) in Oracle's documentation.

    OK. But why on earth you would like to use PL/SQL to perform a HTTP POST request!? Turns out, there still are a lot of software shops or businesses with a software department with extremely highly skilled Oracle developers, that need to focus on solving complex business issues with a database instead of learning the new cool programming language that you can use to do this exact same task with two lines of code. For them, a PL/SQL wrapper around a RESTful API is pretty convenient.

    So, here's what I did to perform a POST passing two parameters along:

    create or replace
    package wsaccess_pkg as
    
      /* 
         suppose your RESTful API requires a POST with two parameters: id, name  
         and it returns a string containing an xml
      */
      
      -- id number
      -- name string
      
      function executews
      (
          p_id number,
          p_name varchar2
      )
      return varchar2;
      
    end wsaccess_pkg;
    
    create or replace
    package body wsaccess_pkg as
    
      function executews
        (
          p_id number,
          p_name varchar2
        )
      return varchar2 AS
        postData clob;
        xmlData clob;
        v_url varchar2(500);
        v_msg varchar(512);
        req utl_http.req;
        resp utl_http.resp;
      begin
      
        utl_http.set_response_error_check(enable => TRUE);
    
        -- this is your RESTful API's URL where you would POST data
        v_url := 'http://www.example.com/api/scoreCard';
    
        postData := '';
        postData := postData || 'id=' || p_id || '&';
        postData := postData || 'name=' || p_name || '&';
        
        -- begin request stating that method will be POST
        req := utl_http.begin_request(url => v_url, method => 'POST');
        
        -- setup request's headers. you need both: Content-Type and Content-Length
        utl_http.set_header(req, 'Content-Type', 'application/x-www-form-urlencoded');
        utl_http.set_header(req, 'Content-Length', length(postData));
        
        -- optionally, you might want to set User Agent header
        utl_http.set_header(req, 'User-Agent', 'MyCoolHttpClientFromWSAccessPkg/1.5');
        
        -- send data: this function handles URL encoding for us!
        utl_http.write_text(req, postData);
        
        -- read the response
        resp := utl_http.get_response(r => req);
        xmlData := '';
        begin
          loop
            utl_http.read_text(r => resp, data => v_msg);
            xmlData := xmlData || v_msg;
          end loop;
        exception
          when utl_http.end_of_body then
            null;
        end;
        
        -- end response
        utl_http.end_response(r => resp);
        
        return xmlData;
      end executews;
    
    end wsaccess_pkg;
    

    You could also parse the XML response and return a pure PL/SQL object. That's even better. But I would probably talk about in a separate blog entry.

    Friday, June 15, 2012

    Restoring a lost crontab

    I recently issued a command like this on a production server:

    $ crontab -r

    I really meant to issue this command instead:

    $ crontab -e

    (I was trying to add an entry to a very important crontab).

    Needless to say, after the command I mistakenly executed, my crontab was gone. 

    From crontab's man page:
           -r     The current crontab will be removed.
    I went to google to search for some answers and here's what I had to do in order to restore my removed crontab file (I am using CentOS 5):

    First, there is directory in /var/spool/cron which holds all crontab files for all users. Mine was gone. So you can't get it from there unless you have a backup (which I didn't). So I couldn't t use it to restore my crontab.

    But, there is a log file which turned out to be pretty useful. They are located in /var/logs. The file names are 'cron*'.

    So I copied them to a folder to avoid working directly on them:

    # cp /var/logs/cron* /home/myuser/cron_restore/
    # chown -R myuser:myuser /home/myuser/cron_restore/

    Then I extracted all different commands that had been running by crond:

    $ cd /home/myuser/cron_restore/
    $ cat cron* | grep crond | awk '{ split($0, a, "CMD "); print a[2]; }' | sort | uniq

    After running the command, I got a list of all different command run and logged by the cron daemon. Of course, this will only bring you the commands that were still present on the log files. But it happened that I got to recover all I needed. Don't know if it will be the same for someone logging some stuff on a yearly or even monthly basis.

    Hope you find this entry useful.