1 de novembro de 2014

A primeira impressão é a que fica

O velho ditado "a primeira impressão é a que fica" tem base científica.

Bruner e Potter (1964) realizaram um experimento simples com 89 pessoas: cada pessoa via uma imagem com qualidade indo de borrada até  levemente desfocada. Ao final a pessoa tinha que tentar acertar o que era aquela imagem.

Foram formados nove grupos. Todos os grupos viram a mesma imagem final, o que mudava de um grupo para o outro era a qualidade inicial da imagem e o tempo de exposição. Quanto pior era a qualidade inicial, pior era a taxa de acerto do grupo.


A tabela acima indica a taxa de acerto de cada grupo, o grupo VB-FQ é o que recebeu a pior imagem inicial, MB-FQ o que recebeu uma imagem de qualidade média inicialmente e as pessoas que receberam a imagem com melhor qualidade inicialmente estão no grupo LB-FQ.

A diferença na taxa de acerto é gigante: o grupo que não viu a imagem ruim inicialmente acertou 72,9% das respostas, enquanto que o grupo que viu a imagem ruim acertou apenas 25%.

Uma hipótese pode ser o excesso de informação que levava o grupo a teorizar mais e por consequência errar mais. Para verificar isso fizeram mais uma rodada de maneira inversa: pessoas viram a imagem indo de  levemente desfocada para borrada. Esse grupo não teve sua taxa de acerto prejudicada.

A explicação encontrada foi que independente da qualidade inicial da imagem, todas as pessoas, naturalmente, tentavam reconhecer o que estava ali. Era difícil as pessoas se desfazerem dessa impressão inicial, elas buscavam apenas confirmações de que a ideia  original estava certa.

Temos a tendência de nos agarrar à uma ideia ou julgamento inicial sobre qualquer assunto. Desfazer essa ideia inicial é afirmar que estávamos errados, e isso parece ser difícil, mesmo que seja inconsciente.

O relatório publicado é curto, tem apenas uma página indicando como o experimento foi realizado e quais resultados foram obtidos. Está disponível aqui para quem quiser ler (em inglês): http://cvcl.mit.edu/SUNSeminar/brunerpotter1964.pdf


28 de outubro de 2014

Somos todos porcos

Acabei de ver a seguinte imagem compartilhada no Facebook:

Essa frase parece meio clichê e argumento de revoltadinho, mas não é.

Façamos um exercício mental sobre o ponto de vista do porco: ele vive em um local confinado e nunca teve contato com porcos livres. Tudo o que conhece e presencia todos os dias é que um ser humano vem alimentá-lo.

No começo o porco até pode ficar assustado e desconfiado do ser humano. Sem saber do motivo real por trás da alimentação, a confiança entre o porco e o ser humano aumenta a cada dia. Pois todo o conhecimento empírico dele indica que o ser humano é confiável.

Se desenhássemos um gráfico indicando o nível de confiança do porco para com o ser humano, ele estaria assim:

Neste exato ponto no tempo, não importa quão sofisticado seja o modelo matemático utilizado pelo porco, todos os indicadores numéricos indicarão que o ser humano é confiável. Logo, o porco votaria no ser humano para representá-lo, pois seria irracional dizer que o ser humano está mal-intencionado.

Até o momento em que o ser humano leva o porco para ser abatido. Neste momento o porco perde toda a confiança que ele havia construído para com o ser humano.

Infelizmente, para o porco já é tarde de mais.

Esta mudança repentina na linha de tendência é óbvia para nós, seres humanos que conhecemos o processo envolvido na criação do porco. Porém, este evento para o porco é conhecido como um "cisne negro": um evento imprevisto de alto impacto.

Ora, a imprevisibilidade depende do ponto de vista: o evento só é imprevisível para o porco, não para o ser humano. Tudo o que muda de um observador para o outro é o nível de informação sobre o processo envolvido: se o porco, mesmo sendo porco, tivesse a informação necessária, ele seria capaz de prever este evento e teria tentado se proteger de alguma forma.

A única forma de prevenção deste tipo de evento é o conhecimento. Portanto, tomemos cuidado com a mão que nos alimenta.

Leve este exercício mental para o cenário da política brasileira neste momento. Pare de acreditar que seu partido político é seu time de futebol, você não precisa mostrar para ninguém que seu partido é melhor ou menos pior do que outro. Ajuda a gerar informações que previnam os cisnes negros, independente do partido ou do político envolvido. É desta forma que ajudaremos a defender nossos vizinhos e a nós mesmos, não esqueça que todo mundo pode estar errado: tanto você quanto sua oposição.

Quer conhecer mais sobre cisnes negros? Recomendo a leitura do livro do Nassim Nicholas Taleb: The Black Swan, ou em português: A Lógica do Cisne Negro.

29 de julho de 2014

Unity3D, Bejeweled e Domain-driven design

Estou trabalhando em um novo jogo ao estilo de Bejeweled. Estou feliz com a liberdade de organização do código que a engine Unity3D está permitindo. Nos meus primeiros contatos com a engine, achei que muita coisa teria que ser feita orientada à classe MonoBehaviour, mas isto não é verdade. Essa classe é necessária apenas como um ponto de cola entre qualquer código C# e os objetos da engine. Abaixo relato como comecei a codificação deste jogo e as mudanças que fiz na modelagem, antes disso deixo um vídeo de demonstração do estado atual do jogo:

Iniciei a construção criando um GameObject para cada entidade que identifiquei na mecânica do jogo:

  1. Tabuleiro
  2. Peça
O tabuleiro contém todas as peças associadas e é responsável por elas:
public class Board : MonoBehaviour {
  private GameObject[,] pieces;
  void Awake() {
    pieces = /* Initialize pieces */;
  }
}
O tipo da peça é definido por um MonoBehaviour associado que expõe uma enumeração para escolha:
public class Piece : MonoBehaviour {
  public PieceType Type;
}
public enum PieceType {
  Circle,
  Square,
  Star,
  Triangle,
  Hexagon,
  Polygon
}

Depois dessa definição das entidades que participam do jogo, comecei a codificar a lógica dentro dessas classes já existentes. Funcionou até certo ponto, mas alguns problemas começaram a surgir quando eu decidia colocar mais alguma funcionalidade. As classes se responsabilizavam por muitas atividades (e.g. respeitar as regras, cuidar de cada animação, tratar a entrada do usuário) e isto tornava difícil a codificação de algumas coisas, pois eu sempre tinha que manter tudo isso em meu mapa mental para evitar quebrar alguma coisa. Além disso, durante as animações o tabuleiro em memória as vezes ficava em um estado inconsistente, esperando o término de alguma animação para então criar uma outra peça. Este comportamento também contribuía com a dificuldade de manutenção deste modelo.

Já havia lido algumas coisas sobre Domain-driven design (DDD) e resolvi aplicar um pouco disto na construção deste jogo. O primeiro passo foi separar o meu core domain do restante, entendi que a mecânica do jogo é o domínio principal: se esta mecânica não estiver bem resolvida e a manutenção ou criação de novas funcionalidades neste domínio for difícil, estarei ferrado. Então fui criar classes deste domínio completamente separadas de qualquer outro conhecimento necessário para fazer o jogo funcionar, ignorei a existência da Unity3D neste momento.

Só visualizei uma entidade para este meu domínio: o tabuleiro. Não faz sentido a peça existir por si só, tudo que envolve peças sempre acontece dentro de um tabuleiro. Apesar de eu ainda ter uma classe separada para representar a peça e seu tipo, elas possuem um papel interno e só são acessadas através do tabuleiro. Minha modelagem ficou neste formato:

public class BoardPosition {
  public readonly int Row;
  public readonly int Column;
  public BoardPosition(int row, int column) {
    Row = row;
    Column = column;
  }
}

public class Board {
  private Piece[,] pieces;
  public Board() {
    pieces = /* Initialize pieces */;
  }

#region Queries
  public Piece PieceAt(BoardPosition p) { /* ... */ }
#endregion

#region Events
  public delegate void PieceCreatedDelegate(BoardPosition position, Piece piece);
  public event PieceCreatedDelegate PieceCreated;

  public delegate void PieceDestroyedDelegate(BoardPosition position);
  public event PieceDestroyedDelegate PieceDestroyed;

  public delegate void PieceMovedDelegate(BoardPosition from, BoardPosition to);
  public event PieceMovedDelegate PieceMoved;

  public delegate void PiecesSwappedDelegate(BoardPosition a, BoardPosition b);
  public event PiecesSwappedDelegate PiecesSwapped;
#endregion

#region Commands
  public void SwapPieces(BoardPosition a, BoardPosition b) {
    ...; // Swap pieces
    PiecesSwapped(a, b);
  }

  public void StepGameState() {
    ...; // Destroy pieces
    ...; // Move pieces
    ...; // Create pieces

    for (...) {
      PieceDestroyed(...);
    }
    for (...) {
      PieceMoved(...);
    }
    for (...) {
      PieceCreated(...);
    }
  }
#endregion
}
Desta forma, as classes responsáveis por apresentar o jogo de forma visual se registram para os eventos gerados pelo tabuleiro e atualizam a interface conforme necessidade.
public class BoardView : MonoBehaviour {
  private Board board;
  private GameObject[,] pieces;
  void Awake() {
    board = new Board();
    board.PieceCreated += HandlePieceCreated;
    board.PieceDestroyed += HandlePieceDestroyed;
    board.PieceMoved += HandlePieceMoved;
    board.PiecesSwapped += HandlePiecesSwapped;
    pieces = /* Initialize pieces based on 'board' */;
  }

  public void HandlePieceCreated(BoardPosition position, Piece piece) { /* ... */ }
  public void HandlePieceDestroyed(BoardPosition position) { /* ... */ }
  public void HandlePieceMoved(BoardPosition from, BoardPosition to) { /* ... */ }
  public void HandlePiecesSwapped(BoardPosition a, BoardPosition b) { /* ... */ }

  void Update() {
    board.Step();
    if (/* ... */) {
      board.SwapPieces(a, b);
    }
  }
}

O que senti de dificuldade neste formato foi sincronizar o modelo com a representação gráfica. Como o próprio modelo notifica seus interessados, sobra pouco espaço para o cliente decidir quando tratar cada evento. No meu caso, alguns eventos geram animações que precisam segurar outros eventos de acontecer, i.e. existe um sequenciamento temporal entre alguns eventos.

Decidi então alterar meu modelo para informar os eventos que ocorreram em cada comando executado ao invés de já causar a execução do código do listener:

#region Events
public interface BoardEvent {}
public class PieceCreated : BoardEvent { /* ... */ }
public class PieceDestroyed : BoardEvent { /* ... */ }
public class PieceMoved : BoardEvent { /* ... */ }
public class PiecesSwapped : BoardEvent { /* ... */ }
#endregion

#region Commands
public List<BoardEvent> SwapPieces(BoardPosition a, BoardPosition b) { /* ... */ }
public List<BoardEvent> StepGameState() { /* ... */ }
#endregion
Tudo o que mudou é que agora a interface precisa chamar os handlers sozinha e decidir quando tratar cada evento:
public class BoardView : MonoBehaviour {
  private List<BoardEvent> events;
  void Update() {
    if (events.Count < 1) { events = board.StepGameState(); }
    foreach (BoardEvent e in events) {
      if (CanHandleNow(e)) {
        Handle(e);
      }
    }
    // ...
    if (HandledEverything) { events.Clear(); }
  }
}
Ainda assim, o conceito de sequenciamento temporal não estava muito claro. Parecia que ele estava "flutuando no ar" e precisava ser fixado. Entendi que isto faz parte do domínio do meu problema e cada evento passou a ter um identificador de sequenciamento no tempo, cada BoardEvent tem um public int When() que informa o momento sequencial do tempo em que ele ocorreu.
public class Board {
  private int timeCounter;
  public List<BoardEvent> StepGameState() {
    ...; // Destroy pieces
    for (...) {
      events.add(new PieceDestroyed(timeCounter, ...));
    }
    if (eventHappened) { timeCounter++; }

    ...; // Move pieces
    for (...) {
      events.add(new PieceMoved(timeCounter, ...));
    }
    if (eventHappened) { timeCounter++; }

    ...; // Create pieces
    for (...) {
      events.add(new PieceCreated(timeCounter, ...));
    }
    if (eventHappened) { timeCounter++; }

    return events;
  }
}

public class BoardView : MonoBehaviour {
  private int timeCounter;
  private List<BoardEvent> events;
  void Update() {
    if (events.Count < 1) { events = board.StepGameState(); }
    foreach (BoardEvent e in events) {
      if (e.When() == timeCounter) Handle(e);
      if (e.When() > timeCounter) {
        stillHasEventsToHandle = true;
        break;
      }
    }
    if (/*handledAnimationOfAllEventsOfMyTimeCounter*/) { 
      // Advance time perception of view
      timeCounter++;
    }
    if (!stillHasEventsToHandle) {
      events.Clear(); // Will step game state at next frame
    }
  }
}
Desta forma, tanto o modelo quanto a representação gráfica possuem um contador temporal e a própria representação se responsabiliza por sincronizar o tempo percebido pelo usuário da interface com o tempo percebido pelo modelo.

Até então o código está mais ou menos como foi listado acima, este modelo está atendendo bem até então. Ainda me sinto mal com um ponto: os commands do modelo sempre mantém o tabuleiro todo cheio, sem estados pela metade, porém o método de step faz no máximo uma iteração de eventos e checagem de colisões no tabuleiro, porém podem ocorrer novas colisões depois de mover e criar as peças. Apesar do tabuleiro nunca estar inconsistente, pode ser que sejam necessárias várias execuções de StepGameState até que o tabuleiro fique em um estado consolidado, sem nada a ser feito e aguardando entrada do usuário. Não queria fazer várias iterações em uma única chamada do step para não ter perigos de entupir a memória do jogo com eventos antes deles começarem a ser tratados pela interface. Nestas horas sinto falta da avaliação lazy do Haskell.

Ainda tenho alguns itens para adicionar nesta mecânica de jogo. Verei quais os problemas deste formato nos próximos dias e postarei novidades com as próximas mudanças. Sugestões também são bem vindas.

1 de maio de 2014

Turtlerise

Olá, povo! É com grande orgulho que lanço minha segunda aplicação na Play Store.

Desta vez é um jogo para todos: Turtlerise.

O jogo tem uma mecânica simples: você precisa fazer com que uma tartaruga suba, quanto mais alto ela for, mais pontos você fará. Para fazê-la subir, você posiciona pedras para ela rebater. Alguns outros elementos fazem parte do jogo para deixá-lo mais interessante.

O gameplay é rápido e é para representar um desafio para os jogadores, fazer pontos não é tão fácil quanto parece!

O jogo está integrado ao Facebook, então é possível acompanhar um placar entre você e seus amigos para ver quem chega mais alto.

Links

14 de abril de 2014

Terceiro e ultimo dia de QConSP 2014

Este post demorou um pouco para sair porque no ultimo dia do QCon meu notebook ficou sem bateria e o hotel não tinha nenhuma tomada no padrão novo, pode isso? Até tentei escrever o texto no aplicativo do Blogger no celular, mas acabei desistindo depois de perder o texto duas vezes. O dia logo após o término do QCon foi consumido pela viagem de volta para casa e uma confraternização; o dia subsequente foi consumido por um passeio turístico em outra cidade. Mas, finalmente estou em casa e, mesmo cansado, escrevo este post para nossa alegria.

O terceiro e ultimo dia do QConSP 2014 começou com a apresentação Introduction to Hadoop. Achei bem estranho uma keynote com "Introduction" no título. Acredito que ficou como keynote apenas por causa do palestrante: Todd Lipcon, um membro-fundador do Hadoop. Achei uma apresentação bem introdutória e não motivadora, logo não mereceria destaque como uma keynote. Na mesma lógica, não terá destaque neste post, até porque não tem muito o que falar mesmo. A parte memorável foi ver ele tentando fazer um notebook com Ubuntu e uma espécie de Fluxbox funcionar para projetar a apresentação. Deu dó. Depois de uns cinco minutos se batendo com a resolução, ele abriu uma máquina virtual com Windows XP para abrir a apresentação PPTX dele. Ha-ha. Mas daí a resolução não encaixou e ele se rendeu à utilizar um Macbook de um organizador.

Design-Driven Development & Context-Driven Experience

A segunda keynote do dia foi de um designer que trabalha na Prezi. Mostrou um pouco de história e do processo de desenvolvimento interno: iterativo e incremental. Parece que todo mundo reforça o modelo "fail fast, iterate".

Trouxe a tona um fato interessante: muita gente no evento estava usando Pebble Smartwatch e que as próximas tecnologias dominantes serão "vestíveis". Curiosamente isto combinou com um artigo que li no mesmo dia afirmando que o fundador do Evernote disse que "Apps Will Soon Be Obsolete".

O apresentador falou que é necessário pensar em três coisas a respeito da experiência do usuário para atender multi-dispositivos:

  1. Consistente: A experiência deve ser consistente com o dispositivo sendo utilizado. Cada dispositivo terá uma maneira diferente de apresentar e de interagir com o usuário.
  2. Contínua: A experiência deve ser contínua entre os dispositivos. Ele não deve ter que pensar toda vez que for mudar de dispositivo, e.g. ao começar a ler um livro no smartphone, ao pegar o tablet, o livro deve abrir na mesma página.
  3. Complementar: A experiência de um dispositivo pode complementar a de outro. A experiência pode iniciar em um dispositivo, continuar em outro e terminar em um terceiro. Um complementando o outro, e.g. comprar um ticket pelo notebook e utilizar o smartphone como carteira virtual.

Track talks

Java 8 na prática, do Lambda às novas APIs: Mostrou novas APIs do Java 8 para tratamento de datas e como ficou a sintaxe das expressões lambdas. Achei a sintaxe e as APIs apresentadas bem agradáveis. Apesar de serem mudanças bem suaves, mostram que a linguagem está evoluindo.

Monadic Java: Functional Programming Patterns Applied: Detectou três monads na nova API do Java 8 e tentou explicar de forma simples o que é um monad. Achei a apresentação válida, mas a explicação de monad foi fraca, não sei se o apresentador conseguiu atingir o objetivo. Eu achei tranquilo porque já passei por algumas tentativas de implementar monads no Java, já presenciei os problemas relacionados ao sistema de tipos do Java em relação à isto, então a apresentação dele me pareceu bem entendível e palatável. De qualquer forma, a melhor explicação que eu vi sobre monads até hoje está no YouTube no vídeo Brian Beckman: Don't fear the Monad.

Falling in Love with APIs without divorcing legacy software: Apresentação falou do uso do Mulesoft para expor APIs de código legado. Foi uma apresentação agradável e bem animadora. O produto deles parece estar muito bom.

Multithreading e Java EE: pouca mudança no código e muita nos resultados: Mostrou a utilização da anotação @Asynchronous em JavaEE. JavaEE é uma coisa estranha: é um padrão despadronizado. Cada servidor faz de um jeito. Durante a apresentação ocorreram duas exceções completamente alienígenas, mas que o apresentador já conhecia, então ele resolveu rápido. Não gosto muito de coisas que acontecem de forma demasiadamente mágica, que dependem do contexto em questão.

Arquiteturas na nuvem com os custos sob controle: processando bilhões de páginas na AWS sem estourar o cartão: Contou como eles fazem para utilizar a infraestrutura da AWS sem gastar muito. Desenvolveram um sistema interno para otimizar a compra de máquinas por leilão (spot instances). Achei muito interessante. Comentaram que pretender abrir como open source, então fiquem ligados nas noticias da TailTarget.

FIM. Pois é, acabou. Assim, sem mais e nem menos. Quando saí da apresentação anterior, os patrocinadores já estavam se recolhendo e os nerds estavam indo embora. Ano passado teve um keynote no final que permitiu que a organização fizesse um breve discurso de encerramento. Este ano não teve isto, achei bem estranho e meio "tosco", podiam pelo menos ter dito "até mais, e obrigado pelos peixes", ou qualquer frase curta para deixar o pessoal brevemente empolgado e falando bem do evento.

Gostou dos posts que fiz sobre o QCon? Então adiciona meu blog nos teus feeds. Nem falei de Haskell nesse post, o que mostra que também posso ser um cara legal! Afinal, eu podia estar falando de Haskell, mas tô aqui pedindo sua assinatura... :)

10 de abril de 2014

Segundo dia de QConSP 2014

O segundo dia de QConSP 2014 começou com duas keynotes fantásticas. O primeiro a falar foi um membro do Jet Propulsion Lab da NASA: Rob Witoff, seguido por Jarrod Overson, que trabalha na RIOT Games (a empresa por trás de League of Legends). Depois começaram as tracks com palestras simultâneas, escolhi participar das que tinham algum relacionamento direto com desenvolvimento. Post rápido!

Building a Data Science Program at NASA/JPL with Visual Analytics

O palestrante é um data scientist que trabalha na NASA. Fez uma analogia interessante, em resumo do que minha memória permite: "uma vasta porção do nosso universo é dark matter, que nós ainda não entendemos; da mesma forma os dados que nós temos e não entendemos são dark data; podemos ter muito conhecimento interessante escondido nos nossos silos de armazenamento de dados".

Ele elencou passos importantes para explorar a dark data:

  1. Liberate data: consistem em liberar este dado escondido e torná-lo acessível. Eles fizeram muito nisso e tornaram vários dados acessíveis através de APIs Web públicas, i.e. torne fácil de acessar os dados, construa uma camada em cima deles, esqueça strings de conexão cabulosas para acessar os repositórios.
  2. Enable engineers: torne possível que as pessoas possam interagir com os dados, que eles consigam fazer o que precisa ser feito: filtrar, combinar, analisar, etc.
  3. Infuse data science: coloque data science em tudo isso, correlacione os dados, encontre padrões.
  4. Innovate: agora você já tem tudo que precisa para inovar, então vá e inove! Mostre estes dados de formas diferentes e tire conclusões sobre eles, construa camadas em cima de camadas e continue inovando.

A NASA possui um negócio bem interessante chamado "innovation vacation" que consiste em tirar "férias" para inovação. Um profissional tem uma ideia; a ideia é boa; este profissional irá tirar "férias para inovação" para construir a ideia junto com o pessoal de inovação, são no máximo duas semanas em que a pessoal fica completamente isolada do resto da empresa: sem acesso a e-mails, sem reuniões, etc; o time do palestrante faz uma espécie de coaching deste profissional durante este período; este tempo possui três "marcos" fundamentais: alinhamento, demo e entrega, i.e. é feito um alinhamento inicial da ideia e das expectativas, depois de um certo trabalho é feito uma demonstração para ver se está indo no caminho certo e no final do ciclo é feita a entrega e fim, não há adiamentos ou prolongamentos.

Dois slides desta apresentação me deixaram muito feliz, que fala como funciona a parte de inovação da NASA e que apoiam o que escrevi no post sobre otimização prematura de negócio e com alguns comentários do post sobre o primeiro dia de QCon:

  • Fail fast. Iterate.
  • Run like a startup

Scaling League of Legends: managing culture, extreme complexity and 30 million active users

Achei que esta apresentação seria mais técnica, mas falou do problema de escalar pessoas, processos, etc. Comentou que o quê funciona no "pequeno" não funciona no "grande". A apresentação trouxe a Web como exemplo de algo que escalou muito bem e o apresentador afirma que ela escalou porque ela precisava escalar de um jeito ou de outro e podemos aprender com ela:

  1. Ela precisa ser distribuída, pessoas do mundo inteiro irão acessar conteúdos espalhados por todo lugar.
  2. Precisa ser assíncrona e levar em consideração timezones diferentes.
  3. Todos são iguais, não importa se você tem doutorado ou ainda está no colégio, você tem o direito de ver e publicar conteúdo.

Ele relaciona estes pontos da Web para tornar uma empresa escalável: você precisa ter formas de comunicação assíncronas, reuniões não são escaláveis; você precisa ter uma maneira de colaboração, em que todos são ouvidos; você precisa lidar com times remotos; etc. (A parte em ênfase foi a que achei top da balada.)

Depois ele entrou mais em detalhes da parte Web, mostrando que ela passou a ser um target de compilação válido. Unity está compilando jogos para rodar na web; Asm.js está fazendo o Javascript ser mais nativo/rápido; Web Components estão aí; HTTP2.0 irá revolucionar a forma de trabalho. Achei interessante, pois depois relacionei isto com as demais apresentações e é notável de que tudo parece estar com uma perna nas tecnologias fundamentais para a Web (HTML, CSS, JS). O que me fez ver mais valor ainda em iniciativas como o Haste (compilador Haskell com target para Javascript).

Track talks

Vou tentar resumir as talks das tracks, pois não achei nenhuma que merecesse destaque.

Programação funcional reativa: Lidando com código assíncrono: Interessante, pelo menos ele falou que gosta de Haskell. Mostrou como funciona o RxJS, um framework com grande influência de FRP (Functional Reactive Programming) para Javascript.

JavaScript Funcional: Bem didática e boa abordagem, porém muito introdutório, aproveitei pouco, exceto por ter conhecido o link FunctionalTalks.org.

Uma startup em Scala: Dos patterns à produção: Muita introdução, mais do mesmo. Ver código Scala sempre me dá vontade de vomitar. É verborrágico de mais. O pessoal se gaba do type-system, mas o negócio leva décadas para compilar. Me gusta Haskell, great type system, great compilation time.

C# e C++/CX - O que há de novo nas linguagens para suportar o desenvolvimento de aplicações modernas: Esta trouxe uma visão legal da unificação que a Microsoft está fazendo em suas quatro plataformas: Smartphone, Tablet, Desktop e XBox. A interoperabilidade que ela está fazendo me pareceu fantástica: código C++/CX chamado de Javascript e vice-versa, C# no meio, novos conceitos de "aplicações modernas".

Building a Cloud IDE you might not hate: the Orion experience and beyond: Comentou sobre a construção da IDE na nuvem chamada Orion e mostrou alguns concorrentes, nada muito interessante até o momento, apenas mostra que existe um movimento forte de várias empresas e iniciativas da comunidade para uma IDE na nuvem.

9 de abril de 2014

Primeiro dia de QConSP 2014

Hoje foi o primeiro dia do evento QConSP 2014. Vou tentar resumir minhas percepções sobre este primeiro dia de evento. O dia foi composto de dois tutoriais: um de manhã e um a tarde e finalizava com três apresentações curtas (short-talks). Elaborei este post de forma rápida, desculpe se o texto está difícil de entender.

Iniciando com Continuous Delivery

O primeiro tutorial que participei falava sobre entrega contínua (Continuous Delivery). Algo que já estou estudando e tentando praticar, porém até agora somente em provas de conceito e testes, nada colocado em produção de fato. Decidi participar deste tutorial para ver se conseguia conectar com as minhas experiências.

Quanto mais estudo sobre arquitetura orientada a serviços, integração contínua e entrega contínua mais percebo que são assuntos cada vez mais consolidados e todos eles se resumem basicamente em atitude. Que inclusive foi algo comentado pelos palestrantes Fabricio Leoti e Rodrigo Russo. Não existe uma bala de prata para a "nova indústria de software", o que existem são profissionais com atitude comprometidos em fazer algo funcionar; profissionais que estão acima de crenças e de seus próprios egos; o novo profissional de software deve fazer o melhor possível para integrar várias ferramentas de mercado em seu favor, sempre buscando eliminar sua própria existência como uma necessidade para a empresa, i.e. automatizar e tornar mais eficientes todos os processos para que fique livre para explorar coisas mais interessantes e que tragam valor para a corporação.

Este novo modelo de trabalho está se tornando cada vez mais forte. O que percebo é que é uma questão de tempo: quem não se adaptar, não conseguirá captar e reter os melhores profissionais e consequentemente, com o tempo, não conseguirá mais entregar valor para seus clientes, que procurarão fornecedores que acompanhem o novo ritmo do mundo. A entrega contínua faz parte desse novo mundo: todos que querem se manter atualizados precisam aprender e se adaptar.

Para obter a entrega contínua é preciso disciplina: é preciso ter processos de provisionamento automatizados e um processo de integração contínua funcionando 100%. A preparação deve ser feita na parte cultural da equipe: todos precisam querer e buscar este nível de excelência.

Acredito que as partes deste tutorial que mais podem contribuir com meu trabalho atualmente são:

  1. Todos devem ser responsabilizados por tudo: a qualidade não é responsabilidade só do time de testes; a evolução do produto não é só responsabilidade do gerente de produto; o erro não é responsabilidade só do time de desenvolvimento. Todos precisam se sentir envolvidos e donos do produto final. É como se a equipe se tornasse uma startup: todos comemorarão com os sucessos e todos sofrerão com os fracassos.
  2. Uma funcionalidade só é considerada "entregue" quando ela está em produção e em uso pelos clientes. Pensando bem, não sei como não cheguei nesta conclusão por conta própria. É um pensamento completamente razoável e com sentido. Na verdade, pensar de outra forma é que não faz o menor sentido: como você pode considerar uma funcionalidade como "entregue" se não tem ninguém usando? Frases como "está pronto, só faltam os testes" ou "está pronto, só falta jogar para produção" não fazem o menor sentido!

NoSQL Aplicado

Compareci neste tutorial para ver na prática as aplicações de bases NoSQL. Estou começando a trabalhar um pouco com o MongoDB, mas sempre ouço falar bem do Cassandra, HBase, etc. Gostaria de aproveitar este tempo para ver as aplicações destes diferentes bancos para evitar ter que passar por processos de tentativa e erro ou grandes sessões de leitura para poder decidir qual banco utilizar para cada situação.

Confesso que me decepcionei com a apresentação. Ela se resumiu em apresentar as bases NoSQL e um pouco da arquitetura interna delas. Coisas que são relativamente fáceis de buscar na internet e que eu já tinha uma noção básica. No final das contas, o conteúdo apresentado não me fez saber melhor qual base utilizar em cada situação e não vi nenhuma aplicação do NoSQL, i.e. "aplicado" só no título do tutorial.

Mas, apesar de não satisfazer minhas expectativas, foi possível aproveitar um pouco do conteúdo do tutorial. O mais relevante para mim na verdade ficou como tarefa de casa: aprender ZooKeeper.

Short-talks

As apresentações curtas que assisti foram "Hadoop: Mãos à massa!", "Cassandra no Desenvolvimento de Serviços para Apps Mobile" e "Play, do zero ao deploy em 20 minutos". Mas estas tiveram o mesmo problema que ocorreu na edição de 2013 do evento: o tempo é curto de mais! Todos os apresentadores estouraram o tempo. Mesmo se não tivessem estourado, o conteúdo passado sempre é demasiadamente superficial.

Os palestrantes foram ótimos, todos os três. A de Hadoop utilizou humor, a de Cassandra trouxe um caso do mundo real e a do Play foi direta ao ponto. Mas são apresentações que só servem para despertar o interesse do ouvinte. Como eu já tinha visto da história de Hadoop no tutorial de NoSQL, foi meio repetitivo; a de Cassandra conseguiu ter mais "NoSQL Aplicado" do que o tutorial, mas como foi muito rápido só ficou como aprendizado: "é possível começar um serviço com base relacional e trocar por um NoSQL depois", que vai de encontro com o que escrevi no post passado sobre otimização precoce; a última que falou do Play Framework despertou um interesse muito saudável, vou procurar saber mais sobre ele por algumas propriedades dele que brilharam aos meus olhos, principalmente static checking.

Organização

Este ano o evento está muito melhor organizado. O evento está acontecendo no WTC SP que possui um espaço muito melhor do que o local do ano passado. O credenciamento foi bem tranquilo, apesar de que só recebi a credencial à tarde, mas porque a compra do dia de tutoriais foi feita em cima da hora (ontem). As pausas com café entre as apresentações também estão mais generosas e com uma distribuição melhor pelo local, em nenhum momento senti falta de suco, café, água e alimentação.

Comentários

Alguns pensamentos que passaram pela minha cabeça hoje durante o evento:

  1. Com o crescimento de bases NoSQL e de BigData, o papel exclusivo de um administrador de banco de dados parece estar perdendo força. Juntando com a entrega contínua, em que todo mundo se responsabiliza por tudo, os desenvolvedores precisam pensar em como o dado será lido antes de armazená-lo, precisa entender da topologia de onde ficarão os dados e etc. Será que faz sentido ainda ter um papel exclusivo para isto?
  2. Entrega contínua significa metodologia ágil. Não sei como colocar um processo cascata que faz entrega contínua. Já é difícil fazer com que todos se sintam responsáveis pelo produto em uma metodologia tradicional.
  3. O número de apresentações sobre programação funcional cresceu do ano passado para cá. Mas não sei se todos estão preparados para esta mudança. Teve um tutorial exclusivo de Clojure este ano, gostaria de ter participado, mas a de entrega contínua pareceu mais fácil de "aplicar na vida real". Por mais que eu seja um entusiasta de Haskell e querer que a programação funcional se torne mainstream, parece que ainda há uma barreira natural para que isto aconteça. Ouvi comentários de que "programação orientada à funções era estranho". De certa forma não tiro razão destes comentários, ouvi que a apresentação de "Lambdas em Java" falou de estruturas persistentes e deu como exemplo a da estrutura de árvore, que é "modafoca" para entender. Acho que isto é uma falha dos entusiastas das linguagens funcionais: nós ficamos tão empolgados com as inúmeras "qualidades" deste modelo, que atravessamos tudo e tentamos passar todo conhecimento em uma única apresentação.