<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4824498855019132836</id><updated>2024-09-12T23:31:00.228-03:00</updated><category term="Haskell"/><category term="Programming"/><category term="Filosofia"/><category term="Programação"/><category term="Java"/><category term="Principles"/><category term="Functional"/><category term="QCon"/><category term="Questionamento"/><category term="Self"/><category term="Android"/><category term="DuDuHoX"/><category term="Game"/><category term="OpenGL"/><category term="Reality check"/><category term="TDD"/><category term="Book"/><category term="C"/><category term="C#"/><category term="C++"/><category term="CisneNegro"/><category term="Concatenative"/><category term="Concurrent"/><category term="Conventions"/><category term="DDD"/><category term="Domain-driven design"/><category term="Google"/><category term="Livro"/><category term="Network"/><category term="OpenAL"/><category term="Paralelismo"/><category term="Play Store"/><category term="Play StoreTurtlerise"/><category term="Política"/><category term="Pure"/><category term="Relacionamento"/><category term="Turtlerise"/><category term="Type-safety"/><category term="Unity3D"/><title type='text'>Thiago B. Negri</title><subtitle type='html'>Filosofia, Programação, Haskell, Java</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>31</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-8838398032151661048</id><published>2014-11-01T14:01:00.003-02:00</published><updated>2014-11-01T14:01:58.961-02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Filosofia"/><title type='text'>A primeira impressão é a que fica</title><content type='html'>O velho ditado &quot;a primeira impressão é a que fica&quot; tem base científica.&lt;br /&gt;
&lt;br /&gt;
Bruner e Potter (1964) realizaram um experimento simples com 89 pessoas: cada pessoa via uma imagem com qualidade indo de borrada até &amp;nbsp;levemente desfocada. Ao final a pessoa tinha que tentar acertar o que era aquela imagem.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy94tuR9Pg7m1Wd1cY-EHMwBI3qYOf0X03CJBl4vXzRcPzcPnT5CYATfOYOLUOZSCqdlvs_M2Q5XGcIvRuyrRCnLKBhzaYSVSdiruuuwo0MBQu1ctVbg-8PtdNlMX7JiNGTASBQTblmLI/s1600/_20141101_133003.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy94tuR9Pg7m1Wd1cY-EHMwBI3qYOf0X03CJBl4vXzRcPzcPnT5CYATfOYOLUOZSCqdlvs_M2Q5XGcIvRuyrRCnLKBhzaYSVSdiruuuwo0MBQu1ctVbg-8PtdNlMX7JiNGTASBQTblmLI/s1600/_20141101_133003.JPG&quot; height=&quot;320&quot; width=&quot;292&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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%.&lt;br /&gt;
&lt;br /&gt;
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 &amp;nbsp;levemente desfocada para borrada. Esse grupo não teve sua taxa de acerto prejudicada.&lt;br /&gt;
&lt;br /&gt;
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 &amp;nbsp;original estava certa.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/8838398032151661048/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2014/11/a-primeira-impressao-e-que-fica.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/8838398032151661048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/8838398032151661048'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2014/11/a-primeira-impressao-e-que-fica.html' title='A primeira impressão é a que fica'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiy94tuR9Pg7m1Wd1cY-EHMwBI3qYOf0X03CJBl4vXzRcPzcPnT5CYATfOYOLUOZSCqdlvs_M2Q5XGcIvRuyrRCnLKBhzaYSVSdiruuuwo0MBQu1ctVbg-8PtdNlMX7JiNGTASBQTblmLI/s72-c/_20141101_133003.JPG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-5780267163681480898</id><published>2014-10-28T20:28:00.000-02:00</published><updated>2014-10-28T20:28:30.292-02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="CisneNegro"/><category scheme="http://www.blogger.com/atom/ns#" term="Filosofia"/><category scheme="http://www.blogger.com/atom/ns#" term="Política"/><title type='text'>Somos todos porcos</title><content type='html'>&lt;p&gt;Acabei de ver a seguinte imagem compartilhada no Facebook:
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3JAOf4uuXXrBCZQnPwEUEIApHG9WYxR_l391lH7phCOwOttI8nz8o8lnGKIa_66RsxiNJGRRxyer0vTrpLPgtW9EAwMIhKQywZ68PUq4GMQPidZCbO_8i0mmB2ykDDYY_CYW8ufYBCNo/s1600/porcos.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3JAOf4uuXXrBCZQnPwEUEIApHG9WYxR_l391lH7phCOwOttI8nz8o8lnGKIa_66RsxiNJGRRxyer0vTrpLPgtW9EAwMIhKQywZ68PUq4GMQPidZCbO_8i0mmB2ykDDYY_CYW8ufYBCNo/s320/porcos.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Essa frase parece meio clichê e argumento de revoltadinho, mas não é.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Se desenhássemos um gráfico indicando o nível de confiança do porco para com o ser humano, ele estaria assim:
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh50DHoVm-_Uu2dYchHpQIYkSExG_mtp-QEh5gogsYaNe7zHhYkwdO6p6Zb9lhob_WHiHhSlDgtsLr3BcrIgSbYfHETeFisGdst42Fgsg6TKvXJw-NwkLqa35ZTF0YnIEbWi-3VMzzDD2w/s1600/confianca-1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh50DHoVm-_Uu2dYchHpQIYkSExG_mtp-QEh5gogsYaNe7zHhYkwdO6p6Zb9lhob_WHiHhSlDgtsLr3BcrIgSbYfHETeFisGdst42Fgsg6TKvXJw-NwkLqa35ZTF0YnIEbWi-3VMzzDD2w/s320/confianca-1.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2mWlBuebhxLsktft80kmzjDNNx9QeAZXTbUpQxUa-mC_wVDRIqizqWZqZCeYztfvf9KZattUEOBrryevtWbDM5vY5-ki8N2xTSqgm60RMSV4j17pBrR7QKmB6Ow3R-TqARlh_YQ6sfu4/s1600/confianca-2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2mWlBuebhxLsktft80kmzjDNNx9QeAZXTbUpQxUa-mC_wVDRIqizqWZqZCeYztfvf9KZattUEOBrryevtWbDM5vY5-ki8N2xTSqgm60RMSV4j17pBrR7QKmB6Ow3R-TqARlh_YQ6sfu4/s320/confianca-2.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Infelizmente, para o porco já é tarde de mais.&lt;/p&gt;

&lt;p&gt;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 &quot;cisne negro&quot;: um evento imprevisto de alto impacto.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Quer conhecer mais sobre cisnes negros? Recomendo a leitura do livro do Nassim Nicholas Taleb: &lt;a href=&quot;http://www.amazon.com/Black-Swan-Improbable-Robustness-Fragility/dp/081297381X&quot;&gt;The Black Swan&lt;/a&gt;, ou em português: &lt;a href=&quot;http://www.buscape.com.br/a-logica-do-cisne-negro-nassim-nicholas-taleb-8576842122.html&quot;&gt;A Lógica do Cisne Negro&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/5780267163681480898/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2014/10/somos-todos-porcos.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/5780267163681480898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/5780267163681480898'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2014/10/somos-todos-porcos.html' title='Somos todos porcos'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3JAOf4uuXXrBCZQnPwEUEIApHG9WYxR_l391lH7phCOwOttI8nz8o8lnGKIa_66RsxiNJGRRxyer0vTrpLPgtW9EAwMIhKQywZ68PUq4GMQPidZCbO_8i0mmB2ykDDYY_CYW8ufYBCNo/s72-c/porcos.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-1970914867786093423</id><published>2014-07-29T14:59:00.001-03:00</published><updated>2014-07-29T14:59:42.281-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="DDD"/><category scheme="http://www.blogger.com/atom/ns#" term="Domain-driven design"/><category scheme="http://www.blogger.com/atom/ns#" term="Game"/><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Unity3D"/><title type='text'>Unity3D, Bejeweled e Domain-driven design</title><content type='html'>&lt;p&gt;Estou trabalhando em um novo jogo ao estilo de &lt;a href=&quot;https://en.wikipedia.org/wiki/Bejeweled&quot;&gt;Bejeweled&lt;/a&gt;. Estou feliz com a liberdade de organização do código que a &lt;i&gt;engine&lt;/i&gt; Unity3D está permitindo. Nos meus primeiros contatos com a &lt;i&gt;engine&lt;/i&gt;, achei que muita coisa teria que ser feita orientada à classe &lt;tt&gt;&lt;a href=&quot;http://docs.unity3d.com/ScriptReference/MonoBehaviour.html&quot;&gt;MonoBehaviour&lt;/a&gt;&lt;/tt&gt;, mas isto não é verdade. Essa classe é necessária apenas como um ponto de cola entre qualquer código C# e os objetos da &lt;i&gt;engine&lt;/i&gt;. 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:
&lt;iframe width=&quot;420&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/_hlOdd1MdEk&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Iniciei a construção criando um &lt;tt&gt;GameObject&lt;/tt&gt; para cada entidade que identifiquei na mecânica do jogo:
&lt;ol&gt;
&lt;li&gt;Tabuleiro&lt;/li&gt;
&lt;li&gt;Peça&lt;/li&gt;
&lt;/ol&gt;
O tabuleiro contém todas as peças associadas e é responsável por elas:
&lt;pre&gt;
public class Board : MonoBehaviour {
  private GameObject[,] pieces;
  void Awake() {
    pieces = /* Initialize pieces */;
  }
}
&lt;/pre&gt;
O tipo da peça é definido por um &lt;tt&gt;MonoBehaviour&lt;/tt&gt; associado que expõe uma enumeração para escolha:
&lt;pre&gt;
public class Piece : MonoBehaviour {
  public PieceType Type;
}
public enum PieceType {
  Circle,
  Square,
  Star,
  Triangle,
  Hexagon,
  Polygon
}
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;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 (&lt;i&gt;e.g.&lt;/i&gt; 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.&lt;/p&gt;

&lt;p&gt;Já havia lido algumas coisas sobre &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-driven_design&quot;&gt;Domain-driven design&lt;/a&gt; (DDD)&lt;/em&gt; e resolvi aplicar um pouco disto na construção deste jogo. O primeiro passo foi separar o meu &lt;em&gt;core domain&lt;/em&gt; 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.&lt;/p&gt;

&lt;p&gt;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:
&lt;pre&gt;
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
}
&lt;/pre&gt;
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.
&lt;pre&gt;
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 &#39;board&#39; */;
  }

  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);
    }
  }
}
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;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, &lt;em&gt;i.e.&lt;/em&gt; existe um sequenciamento temporal entre alguns eventos.&lt;/p&gt;

&lt;p&gt;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 &lt;i&gt;listener&lt;/i&gt;:
&lt;pre&gt;
#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&amp;lt;BoardEvent&amp;gt; SwapPieces(BoardPosition a, BoardPosition b) { /* ... */ }
public List&amp;lt;BoardEvent&amp;gt; StepGameState() { /* ... */ }
#endregion
&lt;/pre&gt;
Tudo o que mudou é que agora a interface precisa chamar os &lt;i&gt;handlers&lt;/i&gt; sozinha e decidir quando tratar cada evento:
&lt;pre&gt;
public class BoardView : MonoBehaviour {
  private List&amp;lt;BoardEvent&amp;gt; events;
  void Update() {
    if (events.Count &lt; 1) { events = board.StepGameState(); }
    foreach (BoardEvent e in events) {
      if (CanHandleNow(e)) {
        Handle(e);
      }
    }
    // ...
    if (HandledEverything) { events.Clear(); }
  }
}
&lt;/pre&gt;
Ainda assim, o conceito de sequenciamento temporal não estava muito claro. Parecia que ele estava &quot;flutuando no ar&quot; 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 &lt;tt&gt;BoardEvent&lt;/tt&gt; tem um &lt;tt&gt;public int When()&lt;/tt&gt; que informa o momento sequencial do tempo em que ele ocorreu.
&lt;pre&gt;
public class Board {
  private int timeCounter;
  public List&amp;lt;BoardEvent&amp;gt; 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&amp;lt;BoardEvent&amp;gt; events;
  void Update() {
    if (events.Count &lt; 1) { events = board.StepGameState(); }
    foreach (BoardEvent e in events) {
      if (e.When() == timeCounter) Handle(e);
      if (e.When() &gt; timeCounter) {
        stillHasEventsToHandle = true;
        break;
      }
    }
    if (/*handledAnimationOfAllEventsOfMyTimeCounter*/) { 
      // Advance time perception of view
      timeCounter++;
    }
    if (!stillHasEventsToHandle) {
      events.Clear(); // Will step game state at next frame
    }
  }
}
&lt;/pre&gt;
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.
&lt;/p&gt;

&lt;p&gt;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 &lt;i&gt;commands&lt;/i&gt; do modelo sempre mantém o tabuleiro todo cheio, sem estados pela metade, porém o método de &lt;em&gt;step&lt;/em&gt; 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 &lt;tt&gt;StepGameState&lt;/tt&gt; 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 &lt;em&gt;step&lt;/em&gt; 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 &lt;em&gt;lazy&lt;/em&gt; do Haskell.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/1970914867786093423/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2014/07/unity3d-bejeweled-e-domain-driven-design.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/1970914867786093423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/1970914867786093423'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2014/07/unity3d-bejeweled-e-domain-driven-design.html' title='Unity3D, Bejeweled e Domain-driven design'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-6944015382868618082</id><published>2014-05-01T20:54:00.001-03:00</published><updated>2014-05-01T20:58:46.470-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="Game"/><category scheme="http://www.blogger.com/atom/ns#" term="Google"/><category scheme="http://www.blogger.com/atom/ns#" term="Play Store"/><category scheme="http://www.blogger.com/atom/ns#" term="Play StoreTurtlerise"/><category scheme="http://www.blogger.com/atom/ns#" term="Turtlerise"/><title type='text'>Turtlerise</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXU5tNcwmN874zvxhmdD7zQkRJm3bIGLzQKAAoDenZ7T81_lFSSlJV8Ca5BlDfZkavdssNe4rIum7Ph0NZdWUQx-oe7rvxvwOC1SXtvee1Pv67FlLjsPnpC64KvY6dW7oa1YZhTQ7R8Lk/s1600/Logo.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXU5tNcwmN874zvxhmdD7zQkRJm3bIGLzQKAAoDenZ7T81_lFSSlJV8Ca5BlDfZkavdssNe4rIum7Ph0NZdWUQx-oe7rvxvwOC1SXtvee1Pv67FlLjsPnpC64KvY6dW7oa1YZhTQ7R8Lk/s320/Logo.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Olá, povo! É com grande orgulho que lanço minha segunda aplicação na Play Store.&lt;/p&gt;

&lt;p&gt;Desta vez é um jogo para todos: Turtlerise.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

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

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

&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Jogo na Play Store: &lt;a href=&quot;https://play.google.com/store/apps/details?id=com.turtlecorp.turtlerise&quot;&gt;https://play.google.com/store/apps/details?id=com.turtlecorp.turtlerise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Página do jogo no Facebook: &lt;a href=&quot;https://www.facebook.com/turtlerise&quot;&gt;https://www.facebook.com/turtlerise&lt;/a&gt;&lt;/li&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/6944015382868618082/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2014/05/turtlerise.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/6944015382868618082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/6944015382868618082'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2014/05/turtlerise.html' title='Turtlerise'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXU5tNcwmN874zvxhmdD7zQkRJm3bIGLzQKAAoDenZ7T81_lFSSlJV8Ca5BlDfZkavdssNe4rIum7Ph0NZdWUQx-oe7rvxvwOC1SXtvee1Pv67FlLjsPnpC64KvY6dW7oa1YZhTQ7R8Lk/s72-c/Logo.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-7170793241996920970</id><published>2014-04-14T22:16:00.000-03:00</published><updated>2014-04-14T22:16:01.434-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><category scheme="http://www.blogger.com/atom/ns#" term="QCon"/><title type='text'>Terceiro e ultimo dia de QConSP 2014</title><content type='html'>&lt;p&gt;
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.
&lt;/p&gt;

&lt;p&gt;
O terceiro e ultimo dia do QConSP 2014 começou com a apresentação &lt;strong&gt;Introduction to Hadoop&lt;/strong&gt;. Achei bem estranho uma &lt;em&gt;keynote&lt;/em&gt; com &quot;Introduction&quot; 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.
&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM_4h4-Q9I4x1MbM_sqFun9RloC13w87-o3MinroUN0oe2m_0ufS6aPmRG-ZaFd_ZHHg0s2A7fvX6RSUg2N-NaNeUkYuv_gYuCSjtMqsh9ER0uKx9lFJAGXreOkfV7UrFbS2SSgUT30m8/s1600/Triple-facepalm.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM_4h4-Q9I4x1MbM_sqFun9RloC13w87-o3MinroUN0oe2m_0ufS6aPmRG-ZaFd_ZHHg0s2A7fvX6RSUg2N-NaNeUkYuv_gYuCSjtMqsh9ER0uKx9lFJAGXreOkfV7UrFbS2SSgUT30m8/s320/Triple-facepalm.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;h2&gt;Design-Driven Development &amp; Context-Driven Experience&lt;/h2&gt;
&lt;p&gt;
A segunda keynote do dia foi de um designer que trabalha na &lt;a href=&quot;http://prezi.com/&quot;&gt;Prezi&lt;/a&gt;. Mostrou um pouco de história e do processo de desenvolvimento interno: iterativo e incremental. Parece que todo mundo reforça o modelo &quot;fail fast, iterate&quot;.
&lt;/p&gt;
&lt;p&gt;
Trouxe a tona um fato interessante: muita gente no evento estava usando &lt;a href=&quot;https://getpebble.com/&quot;&gt;Pebble Smartwatch&lt;/a&gt; e que as próximas tecnologias dominantes serão &quot;vestíveis&quot;. Curiosamente isto combinou com um artigo que li no mesmo dia afirmando que o fundador do Evernote disse que &lt;a href=&quot;http://www.inc.com/christine-lagorio/evernote-founder-phil-libin-future-of-apps-and-wearables.html&quot;&gt;&quot;Apps Will Soon Be Obsolete&quot;&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
O apresentador falou que é necessário pensar em três coisas a respeito da experiência do usuário para atender multi-dispositivos:
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Consistente&lt;/em&gt;: 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.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Contínua&lt;/em&gt;: 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.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Complementar&lt;/em&gt;: 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.&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkVj4J9Jf7sC_Ngv4klSJ1pyKwRVuttGAIvSVETFBOcWpOdfzxtlr03UOI_T5buMwzohs5NdDDmxbOsofyTqg90L2uPrEpuuqv_ngz09QDQJbhGhsEZs74D6914r4rwwKEsFpVSVJimy0/s1600/IMG_20140411_110649.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkVj4J9Jf7sC_Ngv4klSJ1pyKwRVuttGAIvSVETFBOcWpOdfzxtlr03UOI_T5buMwzohs5NdDDmxbOsofyTqg90L2uPrEpuuqv_ngz09QDQJbhGhsEZs74D6914r4rwwKEsFpVSVJimy0/s320/IMG_20140411_110649.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5BejhLbq4uLjT5Oq5HMxHPoNujH4B268EKp5gosIv8fd2m_6XcIt130BaQU1KcPgR5IIObFidPTA5dAgh-PSi27R88RPALAu4w97f_pylCphpCoGLduV_nQVLZ02nTBHBWALkYXfJqVw/s1600/IMG_20140411_112627.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5BejhLbq4uLjT5Oq5HMxHPoNujH4B268EKp5gosIv8fd2m_6XcIt130BaQU1KcPgR5IIObFidPTA5dAgh-PSi27R88RPALAu4w97f_pylCphpCoGLduV_nQVLZ02nTBHBWALkYXfJqVw/s320/IMG_20140411_112627.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4tFlkJh7AbdhMZ_Yrh_LnRvjW7OHD9EOnv3bl67JrbZI3Jq2Ux8L0ZKZd8kcUxQpXUR-2y1E5ThBx6EJbttf8R41VPphqU2oPqlAZCurqK9fl05KA4AEh1NHc_vMv0k0Bdh0GNnwmWw0/s1600/IMG_20140411_112832.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4tFlkJh7AbdhMZ_Yrh_LnRvjW7OHD9EOnv3bl67JrbZI3Jq2Ux8L0ZKZd8kcUxQpXUR-2y1E5ThBx6EJbttf8R41VPphqU2oPqlAZCurqK9fl05KA4AEh1NHc_vMv0k0Bdh0GNnwmWw0/s320/IMG_20140411_112832.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;

&lt;h2&gt;Track talks&lt;/h2&gt;
&lt;p&gt;
&lt;strong&gt;Java 8 na prática, do Lambda às novas APIs&lt;/strong&gt;: 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.
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Monadic Java: Functional Programming Patterns Applied&lt;/strong&gt;: 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 &lt;a href=&quot;https://www.youtube.com/watch?v=ZhuHCtR3xq8&quot;&gt;Brian Beckman: Don&#39;t fear the Monad&lt;/a&gt;.
&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDoM4PEf2tY0b5LxtMk2bSr0EbbWKQvG3YGt00u66f5nHFGky7PakqGm5aCpv07Rufm3ibdsFrJcdN_jNeXvIGf1sChh_u13MOqv4Wf6XR2Y0ZPMeGiGvoLVRbKOnxxJUoRU75h_XAtns/s1600/IMG_20140411_143308.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDoM4PEf2tY0b5LxtMk2bSr0EbbWKQvG3YGt00u66f5nHFGky7PakqGm5aCpv07Rufm3ibdsFrJcdN_jNeXvIGf1sChh_u13MOqv4Wf6XR2Y0ZPMeGiGvoLVRbKOnxxJUoRU75h_XAtns/s320/IMG_20140411_143308.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf0K5A7Hg1OJSrjWxg4O4n8eHUNK0fhXvecHrYJAq-d8zBw-02-T4MVhZIAXboW3C-6aMIwAEYTFLDyLYFy5gdvSbERy2ei26btIdlR2Ysku9dBBTWsIiCS3oq2_i_RwxSVq2-0SD9DnI/s1600/IMG_20140411_144546.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhf0K5A7Hg1OJSrjWxg4O4n8eHUNK0fhXvecHrYJAq-d8zBw-02-T4MVhZIAXboW3C-6aMIwAEYTFLDyLYFy5gdvSbERy2ei26btIdlR2Ysku9dBBTWsIiCS3oq2_i_RwxSVq2-0SD9DnI/s320/IMG_20140411_144546.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJbaIV7T0K9-MykwvktcoZmTmuoPzSs_SPLWQ8qR4S8rQpLxI9SkvYa_HWhueb_vBKQyMOgD0fWkApvqjuLHu2ZpYvtzssJHvIpFMtvb4bzXyqHIWRLw5dInihW6AaQBSSbYXKa__k-Lw/s1600/IMG_20140411_150126.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJbaIV7T0K9-MykwvktcoZmTmuoPzSs_SPLWQ8qR4S8rQpLxI9SkvYa_HWhueb_vBKQyMOgD0fWkApvqjuLHu2ZpYvtzssJHvIpFMtvb4bzXyqHIWRLw5dInihW6AaQBSSbYXKa__k-Lw/s320/IMG_20140411_150126.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg2YOrZ2wvqr6DWj0kEtCZRufO7JkJuD-2IbiWXylRwQa0H3saOmwVlqA5WyoMXHaamyFOHil_cRlsra66_Sm-TxjoO16P0QcGCEUBr8RzJcCu7dGUO6NbDVvaA_jOJuI4olUCogmD5fk/s1600/IMG_20140411_150624.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgg2YOrZ2wvqr6DWj0kEtCZRufO7JkJuD-2IbiWXylRwQa0H3saOmwVlqA5WyoMXHaamyFOHil_cRlsra66_Sm-TxjoO16P0QcGCEUBr8RzJcCu7dGUO6NbDVvaA_jOJuI4olUCogmD5fk/s320/IMG_20140411_150624.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;

&lt;p&gt;
&lt;strong&gt;Falling in Love with APIs without divorcing legacy software&lt;/strong&gt;: Apresentação falou do uso do &lt;a href=&quot;http://www.mulesoft.org/&quot;&gt;Mulesoft&lt;/a&gt; para expor APIs de código legado. Foi uma apresentação agradável e bem animadora. O produto deles parece estar muito bom.
&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv4IJBDphvoE_emAf3vAharFulfj2lzvvUbeCku1CW6sDiBW0CWU357R6gmaONAcjdmNZRRXnSa37ZjavNesG-3woQS8UufulCzNA5lTJ5NvFxkApGRiCLuF3AreE_3cY_6yUSJRXVpZE/s1600/IMG_20140411_155207.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiv4IJBDphvoE_emAf3vAharFulfj2lzvvUbeCku1CW6sDiBW0CWU357R6gmaONAcjdmNZRRXnSa37ZjavNesG-3woQS8UufulCzNA5lTJ5NvFxkApGRiCLuF3AreE_3cY_6yUSJRXVpZE/s320/IMG_20140411_155207.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2fqlFoqTvP7mcdtCg5AXiXMi6vqBrAPjoeokfkebE64Xnc6mWi-UdATm6Al8cSP_9-04hSH6sE2vUdaJAMMQwSwUYdYQRSSjB5q3PIfQ55TCVxxvKEmhAhFhwG6lR_nO5ZDLoRY4hzFk/s1600/IMG_20140411_160322.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2fqlFoqTvP7mcdtCg5AXiXMi6vqBrAPjoeokfkebE64Xnc6mWi-UdATm6Al8cSP_9-04hSH6sE2vUdaJAMMQwSwUYdYQRSSjB5q3PIfQ55TCVxxvKEmhAhFhwG6lR_nO5ZDLoRY4hzFk/s320/IMG_20140411_160322.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgymLI4q-f8etNUwU7tueY75ZlG87sl1FPNkyfrUFaBKBbAVsuh1dGkBWQFaHXbwyula5JPGLtoinazTFoDQPy5zeU6QxWWqcZzZAqNssU-N8idpcSmpyuXQcYGOLtGePJN65-r74UB59A/s1600/IMG_20140411_160539.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgymLI4q-f8etNUwU7tueY75ZlG87sl1FPNkyfrUFaBKBbAVsuh1dGkBWQFaHXbwyula5JPGLtoinazTFoDQPy5zeU6QxWWqcZzZAqNssU-N8idpcSmpyuXQcYGOLtGePJN65-r74UB59A/s320/IMG_20140411_160539.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGMJONnePEiAy3_6mTKCUeq5x5MEqW8I6o13pT4qBvs83_wL0wyIa6K-TyGwQGB1o7hmeOD-eIMHTCKuFrHBc0EtquZnZTBbgtp_leZ5HkZxR46MzmYyTQRbV-EoH0niePh_8yUQzRb0Y/s1600/IMG_20140411_160616.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGMJONnePEiAy3_6mTKCUeq5x5MEqW8I6o13pT4qBvs83_wL0wyIa6K-TyGwQGB1o7hmeOD-eIMHTCKuFrHBc0EtquZnZTBbgtp_leZ5HkZxR46MzmYyTQRbV-EoH0niePh_8yUQzRb0Y/s320/IMG_20140411_160616.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIihGhWHepS9vImVF59siXVtVjuDzX9ToOz3-iQERX-kaeXndR1VL-uQ-k2agW1zdIu6qYuriEwD6KSn6KD2QrHRkGoTz9U0zdOTuXv6Emwp0yL2aFjtJXnkuGxCuI-kjqV7uXm1L19-E/s1600/IMG_20140411_155338.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiIihGhWHepS9vImVF59siXVtVjuDzX9ToOz3-iQERX-kaeXndR1VL-uQ-k2agW1zdIu6qYuriEwD6KSn6KD2QrHRkGoTz9U0zdOTuXv6Emwp0yL2aFjtJXnkuGxCuI-kjqV7uXm1L19-E/s320/IMG_20140411_155338.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;

&lt;p&gt;
&lt;strong&gt;Multithreading e Java EE: pouca mudança no código e muita nos resultados&lt;/strong&gt;: Mostrou a utilização da anotação &lt;tt&gt;@Asynchronous&lt;/tt&gt; 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.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Arquiteturas na nuvem com os custos sob controle: processando bilhões de páginas na AWS sem estourar o cartão&lt;/strong&gt;: 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 (&lt;em&gt;spot instances&lt;/em&gt;). Achei muito interessante. Comentaram que pretender abrir como open source, então fiquem ligados nas noticias da &lt;a href=&quot;http://www.tailtarget.com/&quot;&gt;TailTarget&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;FIM&lt;/strong&gt;. 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 &quot;tosco&quot;, podiam pelo menos ter dito &quot;até mais, e obrigado pelos peixes&quot;, ou qualquer frase curta para deixar o pessoal brevemente empolgado e falando bem do evento.
&lt;/p&gt;

&lt;p&gt;
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... :)
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/7170793241996920970/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2014/04/terceiro-e-ultimo-dia-de-qconsp-2014.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/7170793241996920970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/7170793241996920970'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2014/04/terceiro-e-ultimo-dia-de-qconsp-2014.html' title='Terceiro e ultimo dia de QConSP 2014'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhM_4h4-Q9I4x1MbM_sqFun9RloC13w87-o3MinroUN0oe2m_0ufS6aPmRG-ZaFd_ZHHg0s2A7fvX6RSUg2N-NaNeUkYuv_gYuCSjtMqsh9ER0uKx9lFJAGXreOkfV7UrFbS2SSgUT30m8/s72-c/Triple-facepalm.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-4308507075401179449</id><published>2014-04-10T20:31:00.000-03:00</published><updated>2014-04-10T20:31:41.016-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Functional"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="QCon"/><title type='text'>Segundo dia de QConSP 2014</title><content type='html'>&lt;p&gt;O segundo dia de QConSP 2014 começou com duas keynotes &lt;em&gt;fantásticas&lt;/em&gt;. O primeiro a falar foi um membro do Jet Propulsion Lab da NASA: Rob Witoff, seguido por Jarrod Overson, que trabalha na &lt;a href=&quot;http://www.riotgames.com/&quot;&gt;RIOT Games&lt;/a&gt; (a empresa por trás de &lt;a href=&quot;http://leagueoflegends.com/&quot;&gt;League of Legends&lt;/a&gt;). Depois começaram as tracks com palestras simultâneas, escolhi participar das que tinham algum relacionamento direto com desenvolvimento. Post rápido!&lt;/p&gt;

&lt;h2&gt;Building a Data Science Program at NASA/JPL with Visual Analytics&lt;/h2&gt;
&lt;p&gt;O palestrante é um data scientist que trabalha na NASA. Fez uma analogia interessante, em resumo do que minha memória permite: &quot;uma vasta porção do nosso universo é &lt;em&gt;dark matter&lt;/em&gt;, que nós ainda não entendemos; da mesma forma os dados que nós temos e não entendemos são &lt;em&gt;dark data&lt;/em&gt;; podemos ter muito conhecimento interessante escondido nos nossos silos de armazenamento de dados&quot;.&lt;/p&gt;
&lt;p&gt;Ele elencou passos importantes para explorar a &lt;em&gt;dark data&lt;/em&gt;:
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Liberate data&lt;/em&gt;: 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, &lt;em&gt;i.e.&lt;/em&gt; 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.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Enable engineers&lt;/em&gt;: torne possível que as pessoas possam interagir com os dados, que eles consigam fazer o que precisa ser feito: filtrar, combinar, analisar, etc.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Infuse data science&lt;/em&gt;: coloque &lt;em&gt;data science&lt;/em&gt; em tudo isso, correlacione os dados, encontre padrões.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Innovate&lt;/em&gt;: 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.&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
&lt;p&gt;A NASA possui um negócio bem interessante chamado &lt;em&gt;&quot;innovation vacation&quot;&lt;/em&gt; que consiste em tirar &quot;férias&quot; para inovação. Um profissional tem uma ideia; a ideia é boa; este profissional irá tirar &quot;férias para inovação&quot; 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 &lt;em&gt;coaching&lt;/em&gt; deste profissional durante este período; este tempo possui três &quot;marcos&quot; fundamentais: alinhamento, demo e entrega, &lt;em&gt;i.e.&lt;/em&gt; é 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 &lt;strong&gt;e fim&lt;/strong&gt;, não há adiamentos ou prolongamentos.&lt;/p&gt;
&lt;p&gt;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:
&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Fail fast. Iterate.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run like a startup&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiBJ0TFVAS4EblRXh5xc6ffnAstfth8f3izKTlMcEUoy5kCHXmDU2CJ06OM5ykYK9INV1de9xsQp98LpCRoQEEWDcR_jCeaC6bx-1hRU1ndYA36d89-b4KrXDtsU4iwCx8fVj6P3Y6F1E/s1600/failfastiterate.JPG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiBJ0TFVAS4EblRXh5xc6ffnAstfth8f3izKTlMcEUoy5kCHXmDU2CJ06OM5ykYK9INV1de9xsQp98LpCRoQEEWDcR_jCeaC6bx-1hRU1ndYA36d89-b4KrXDtsU4iwCx8fVj6P3Y6F1E/s320/failfastiterate.JPG&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDOSSasYz0PCrt8yhyphenhyphenjM3HYGFGr2XDoWhzgsV_SCgqj1iMdny3HCWXSrhvDHxr16-hLeq2SF1BkoIdpQvaJJB5Vw9OlKqVuat_m-Wx20ltBJhFUidgh_bP-zBVg4gTo2nz1tel7yQGX9k/s1600/runlikeastartup.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDOSSasYz0PCrt8yhyphenhyphenjM3HYGFGr2XDoWhzgsV_SCgqj1iMdny3HCWXSrhvDHxr16-hLeq2SF1BkoIdpQvaJJB5Vw9OlKqVuat_m-Wx20ltBJhFUidgh_bP-zBVg4gTo2nz1tel7yQGX9k/s320/runlikeastartup.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK1_8VNgzhuuu02f6KLDJ7CDFcuFLp4qUwEj12auu8OcO9mXG0Gnu3li_KvsUm9lXoqsOTvEHTLTDUHHrmNfWgoffenaOuHd8Ue-uQV7H_rlfKVEmjYoELVY9FG9W3n3adCec7pp4FgxU/s1600/foursteps.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK1_8VNgzhuuu02f6KLDJ7CDFcuFLp4qUwEj12auu8OcO9mXG0Gnu3li_KvsUm9lXoqsOTvEHTLTDUHHrmNfWgoffenaOuHd8Ue-uQV7H_rlfKVEmjYoELVY9FG9W3n3adCec7pp4FgxU/s320/foursteps.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLtET55w7FPgF1LX28dRW9ZuIep8xMrxtafJjMt_jU2BSBSbigqekLxAJopaAzhVaBSk7RoPjPin7HKy2bzY_kfUd9KBgzHOBtYHH0YwwiQJuS9eph3AMQ7XlQKRQlVUpfzlYfsY5BPDo/s1600/vacation.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLtET55w7FPgF1LX28dRW9ZuIep8xMrxtafJjMt_jU2BSBSbigqekLxAJopaAzhVaBSk7RoPjPin7HKy2bzY_kfUd9KBgzHOBtYHH0YwwiQJuS9eph3AMQ7XlQKRQlVUpfzlYfsY5BPDo/s320/vacation.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDjgcf3jX0yYhF-T1Y51tWHfZRCDz6IcPNg-KcODWeYH98vjS03rckGmleXtLQ5wB6RICuaP2OEXvVZQrMW9hP_6xtn-z_HcrIRcuVyY6jQzDRhOX3pptUKa3nrdewvLbvKtesx8_QcWs/s1600/incubate.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgDjgcf3jX0yYhF-T1Y51tWHfZRCDz6IcPNg-KcODWeYH98vjS03rckGmleXtLQ5wB6RICuaP2OEXvVZQrMW9hP_6xtn-z_HcrIRcuVyY6jQzDRhOX3pptUKa3nrdewvLbvKtesx8_QcWs/s320/incubate.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;

&lt;h2&gt;Scaling League of Legends: managing culture, extreme complexity and 30 million active users&lt;/h2&gt;
&lt;p&gt;Achei que esta apresentação seria mais técnica, mas falou do problema de escalar pessoas, processos, etc. Comentou que o quê funciona no &quot;pequeno&quot; não funciona no &quot;grande&quot;. 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:
&lt;ol&gt;&lt;li&gt;Ela precisa ser distribuída, pessoas do mundo inteiro irão acessar conteúdos espalhados por todo lugar.&lt;/li&gt;
&lt;li&gt;Precisa ser assíncrona e levar em consideração timezones diferentes.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
&lt;p&gt;Ele relaciona estes pontos da Web para tornar uma empresa escalável: &lt;strong&gt;você precisa ter formas de comunicação assíncronas, reuniões não são escaláveis&lt;/strong&gt;; 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 &lt;em&gt;top da balada&lt;/em&gt;.)&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&quot;http://haste-lang.org/&quot;&gt;Haste&lt;/a&gt; (compilador Haskell com target para Javascript).&lt;/p&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7G02nOPUCu6GsFcOQHRm0p1d4wXOPOa09I_C_GRLBaiNBtnRTlpoxSGHvio_DUAh8aXs3togR6gMgGojcDOrlNIniPmHCSVD7L5dulgFhwfUI_r4LFgf0EIayth_mHU7NYnqvynY8DrM/s1600/IMG_20140410_110821.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7G02nOPUCu6GsFcOQHRm0p1d4wXOPOa09I_C_GRLBaiNBtnRTlpoxSGHvio_DUAh8aXs3togR6gMgGojcDOrlNIniPmHCSVD7L5dulgFhwfUI_r4LFgf0EIayth_mHU7NYnqvynY8DrM/s320/IMG_20140410_110821.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_AcsdfMJFRTdzkbWpYDQbkLQkkyqb07m3yVkL76Sgw03yfG2kGJt3hlQNKJKd1gomUg03hZ7BuZ8K9FLrUJ_komJ_F-4cn3NOsYHmlbYpJ9FmPus48BI7UgLVeLnGQSXDSruyhqQZZsI/s1600/IMG_20140410_110858.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_AcsdfMJFRTdzkbWpYDQbkLQkkyqb07m3yVkL76Sgw03yfG2kGJt3hlQNKJKd1gomUg03hZ7BuZ8K9FLrUJ_komJ_F-4cn3NOsYHmlbYpJ9FmPus48BI7UgLVeLnGQSXDSruyhqQZZsI/s320/IMG_20140410_110858.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiT7HzUzOAHDg-69QZZ8XASFDqKQcA3EqF356advPuGNmsGM2l_AwJEaV_38qdP4eRXzO1q9ETsc1dBZFCVtNXauPMF_eTZlUnKMXH4hWmMPirfVsZhyphenhyphenQbfzmmom0YeloMTH7ctReqsbLQ/s1600/IMG_20140410_111403.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiT7HzUzOAHDg-69QZZ8XASFDqKQcA3EqF356advPuGNmsGM2l_AwJEaV_38qdP4eRXzO1q9ETsc1dBZFCVtNXauPMF_eTZlUnKMXH4hWmMPirfVsZhyphenhyphenQbfzmmom0YeloMTH7ctReqsbLQ/s320/IMG_20140410_111403.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYNrpLMPTKeMygx_tN_NN9VRTM-bTOuAIkG_txr1-EP3OImg-gC-wH79UmXaRJEcGy2cVRVWTVJeIKO2OrCumgFlcqenKuSZaTHAoE92ualoh01FggbUk6FPWUa_cUgkeucnZF8qh-cLg/s1600/IMG_20140410_111935.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYNrpLMPTKeMygx_tN_NN9VRTM-bTOuAIkG_txr1-EP3OImg-gC-wH79UmXaRJEcGy2cVRVWTVJeIKO2OrCumgFlcqenKuSZaTHAoE92ualoh01FggbUk6FPWUa_cUgkeucnZF8qh-cLg/s320/IMG_20140410_111935.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaTJXLQVD5hxB-RRrJWPveE2IdyrwSDzcF4kAAAh21mwYFSD_cAM6Q-5FseDHdLGm1D40HUbXDKRBSbF9ae8x2ismictto390MLojpqJLlGwsbWcZSQzJap82Mn02AmNXUxGJwJK3SlPw/s1600/IMG_20140410_112108.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaTJXLQVD5hxB-RRrJWPveE2IdyrwSDzcF4kAAAh21mwYFSD_cAM6Q-5FseDHdLGm1D40HUbXDKRBSbF9ae8x2ismictto390MLojpqJLlGwsbWcZSQzJap82Mn02AmNXUxGJwJK3SlPw/s320/IMG_20140410_112108.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxEsIWk_D_01VZPMbxs10zfeSbG5gIxMfQY7G4LbanB5XgakfYfWcQqqRSzuMesFlCewE08ahVavJSh85yzzR8SPEhkyrKsxuiGjagy5qYlSw6AiH1uvh0Xb3s1rdUxJl37i1AEsjUsew/s1600/IMG_20140410_112144.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxEsIWk_D_01VZPMbxs10zfeSbG5gIxMfQY7G4LbanB5XgakfYfWcQqqRSzuMesFlCewE08ahVavJSh85yzzR8SPEhkyrKsxuiGjagy5qYlSw6AiH1uvh0Xb3s1rdUxJl37i1AEsjUsew/s320/IMG_20140410_112144.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div style=&quot;float:left;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXdeAZ5HIAjsjg_qED1plaja2lRxjQHKJ7AnmLs7mwZTBxWCmunMiW26kHwtNP0AN26nY0IWgtXomDo7x1nirSMlI2TEt2H90Anu0ax4KFJgh9AdIV74reMlGgTlAbXpw_DJXFMHG4ywM/s1600/IMG_20140410_112433.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXdeAZ5HIAjsjg_qED1plaja2lRxjQHKJ7AnmLs7mwZTBxWCmunMiW26kHwtNP0AN26nY0IWgtXomDo7x1nirSMlI2TEt2H90Anu0ax4KFJgh9AdIV74reMlGgTlAbXpw_DJXFMHG4ywM/s320/IMG_20140410_112433.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;/div&gt;

&lt;h2&gt;Track talks&lt;/h2&gt;
&lt;p&gt;Vou tentar resumir as talks das tracks, pois não achei nenhuma que merecesse destaque.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Programação funcional reativa: Lidando com código assíncrono&lt;/strong&gt;: 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JavaScript Funcional&lt;/strong&gt;: Bem didática e boa abordagem, porém muito introdutório, aproveitei pouco, exceto por ter conhecido o link &lt;a href=&quot;http://functionaltalks.org/&quot;&gt;FunctionalTalks.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Uma startup em Scala: Dos patterns à produção&lt;/strong&gt;: 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.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;C# e C++/CX - O que há de novo nas linguagens para suportar o desenvolvimento de aplicações modernas&lt;/strong&gt;: 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 &lt;em&gt;fantástica&lt;/em&gt;: código C++/CX chamado de Javascript e vice-versa, C# no meio, novos conceitos de &quot;aplicações modernas&quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Building a Cloud IDE you might not hate: the Orion experience and beyond&lt;/strong&gt;: 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.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/4308507075401179449/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2014/04/segundo-dia-de-qconsp-2014.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4308507075401179449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4308507075401179449'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2014/04/segundo-dia-de-qconsp-2014.html' title='Segundo dia de QConSP 2014'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiBJ0TFVAS4EblRXh5xc6ffnAstfth8f3izKTlMcEUoy5kCHXmDU2CJ06OM5ykYK9INV1de9xsQp98LpCRoQEEWDcR_jCeaC6bx-1hRU1ndYA36d89-b4KrXDtsU4iwCx8fVj6P3Y6F1E/s72-c/failfastiterate.JPG" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-2860768890563325528</id><published>2014-04-09T20:38:00.003-03:00</published><updated>2014-04-09T20:39:36.559-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Functional"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Principles"/><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="QCon"/><category scheme="http://www.blogger.com/atom/ns#" term="Questionamento"/><title type='text'>Primeiro dia de QConSP 2014</title><content type='html'>&lt;p&gt;Hoje foi o primeiro dia do evento &lt;a href=&quot;http://qconsp.com/&quot;&gt;QConSP&lt;/a&gt; 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 (&lt;em&gt;short-talks&lt;/em&gt;). Elaborei este post de forma rápida, desculpe se o texto está difícil de entender.&lt;/p&gt;

&lt;h2&gt;Iniciando com &lt;em&gt;Continuous Delivery&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;O primeiro tutorial que participei falava sobre entrega contínua (&lt;em&gt;Continuous Delivery&lt;/em&gt;). Algo que já estou estudando e tentando praticar, porém até agora somente em &lt;em&gt;provas de conceito&lt;/em&gt; e testes, nada colocado em produção de fato. Decidi participar deste tutorial para ver se conseguia conectar com as minhas experiências.&lt;/p&gt;
&lt;p&gt;Quanto mais estudo sobre &lt;em&gt;arquitetura orientada a serviços&lt;/em&gt;, &lt;em&gt;integração contínua&lt;/em&gt; e &lt;em&gt;entrega contínua&lt;/em&gt; mais percebo que são assuntos cada vez mais consolidados e todos eles se resumem basicamente em &lt;em&gt;atitude&lt;/em&gt;. Que inclusive foi algo comentado pelos palestrantes Fabricio Leoti e Rodrigo Russo. Não existe uma &lt;em&gt;bala de prata&lt;/em&gt; para a &quot;nova indústria de software&quot;, 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, &lt;em&gt;i.e.&lt;/em&gt; 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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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: &lt;em&gt;todos&lt;/em&gt; precisam querer e buscar este nível de &lt;em&gt;excelência&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Acredito que as partes deste tutorial que mais podem contribuir com meu trabalho atualmente são:
&lt;ol&gt;
&lt;li&gt;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 &lt;em&gt;startup&lt;/em&gt;: todos comemorarão com os sucessos e todos sofrerão com os fracassos.&lt;/li&gt;
&lt;li&gt;Uma funcionalidade só é considerada &quot;entregue&quot; 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 &quot;entregue&quot; se não tem ninguém usando? Frases como &quot;está pronto, só faltam os testes&quot; ou &quot;está pronto, só falta jogar para produção&quot; não fazem o menor sentido!&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;

&lt;h2&gt;NoSQL Aplicado&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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, &lt;em&gt;i.e.&lt;/em&gt; &quot;aplicado&quot; só no título do tutorial.&lt;/p&gt;
&lt;p&gt;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 &lt;a href=&quot;http://zookeeper.apache.org/&quot;&gt;ZooKeeper&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Short-talks&lt;/h2&gt;
&lt;p&gt;As apresentações curtas que assisti foram &quot;Hadoop: Mãos à massa!&quot;, &quot;Cassandra no Desenvolvimento de Serviços para Apps Mobile&quot; e &quot;Play, do zero ao deploy em 20 minutos&quot;. 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.&lt;/p&gt;
&lt;p&gt;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 &quot;NoSQL Aplicado&quot; do que o tutorial, mas como foi muito rápido só ficou como aprendizado: &quot;é possível começar um serviço com base relacional e trocar por um NoSQL depois&quot;, 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 &lt;em&gt;static checking&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;Organização&lt;/h2&gt;
&lt;p&gt;Este ano o evento está muito melhor organizado. O evento está acontecendo no &lt;a href=&quot;http://www.worldtradecentersp.com.br/pt/&quot;&gt;WTC SP&lt;/a&gt; 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.&lt;/p&gt;

&lt;h2&gt;Comentários&lt;/h2&gt;
&lt;p&gt;Alguns pensamentos que passaram pela minha cabeça hoje durante o evento:
&lt;ol&gt;
&lt;li&gt;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?&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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 &quot;aplicar na vida real&quot;. Por mais que eu seja um entusiasta de Haskell e querer que a programação funcional se torne &lt;em&gt;mainstream&lt;/em&gt;, parece que ainda há uma barreira natural para que isto aconteça. Ouvi comentários de que &quot;programação orientada à funções era estranho&quot;. De certa forma não tiro razão destes comentários, ouvi que a apresentação de &quot;Lambdas em Java&quot; falou de estruturas persistentes e deu como exemplo a da estrutura de árvore, que é &quot;modafoca&quot; para entender. Acho que isto é uma falha dos entusiastas das linguagens funcionais: nós ficamos tão empolgados com as inúmeras &quot;qualidades&quot; deste modelo, que atravessamos tudo e tentamos passar todo conhecimento em uma única apresentação.&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/2860768890563325528/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2014/04/primeiro-dia-de-qconsp-2014.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/2860768890563325528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/2860768890563325528'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2014/04/primeiro-dia-de-qconsp-2014.html' title='Primeiro dia de QConSP 2014'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-5030328694280274031</id><published>2014-04-07T22:01:00.000-03:00</published><updated>2014-04-07T22:01:51.883-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Filosofia"/><category scheme="http://www.blogger.com/atom/ns#" term="Principles"/><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Questionamento"/><category scheme="http://www.blogger.com/atom/ns#" term="Reality check"/><title type='text'>Otimização prematura: não é apenas sobre código</title><content type='html'>&lt;p&gt;
Quando falamos sobre desempenho, não devemos olhar apenas para &lt;em&gt;desempenho da execução de código&lt;/em&gt;.
Existem mais tipos que devemos prestar atenção, como &lt;em&gt;tempo para mercado&lt;/em&gt;, &lt;em&gt;tempo de desenvolvimento&lt;/em&gt; e &lt;em&gt;processos&lt;/em&gt;.
Na verdade, não devemos olhar qualquer uma destas medidas de desempenho de uma única perspectiva.
Penso que todas estas medidas se unificam para constituir um único valor de &lt;em&gt;desempenho de negócio&lt;/em&gt;.
&lt;/p&gt;

&lt;p&gt;
Existem muitas coisas que podem desacelerar seu negócio, e se você tiver um negócio devagar, será difícil acompanhar o ritmo de seus concorrentes.
A partir do momento que você vê que algumas áreas da sua empresa podem estar te atrasando, você pode sentir-se tentado a adicionar &lt;em&gt;indicadores de desempenho&lt;/em&gt; em cada passo, tentando espremer todo valor possível de cada parte do seu processo.
Isto pode trazer um monte de novos problemas, seu negócio pode ser visto como um &lt;em&gt;sistema complexo&lt;/em&gt; e ele irá se adaptar para mostrar bons resultados mesmo em cenários caóticos. [1]
&lt;/p&gt;

&lt;p&gt;
Então, para evitar ficar maluco com indicadores para todos os lados, você decide evitar gargalos desde o princípio.
Para cada coisa nova que você precisa entregar, começará uma rotina de planejamento preciso, escolhendo entre uma infinidade de fornecedores, tecnologias e unicórnios para evitar a todo custo ter um novo gargalo no futuro.
Isto é o que gosto de chamar de &lt;em&gt;otimização prematura de desempenho de negócio&lt;/em&gt;.
&lt;/p&gt;

&lt;p&gt;
De forma simples: você não pode ter um negócio se você não tiver um negócio.
Como você pode saber de todos os eventos futuros que irão impactar na decisão que você toma hoje?
&lt;em&gt;Você não pode.&lt;/em&gt;
Não estou dizendo que planejar é errado ou uma Coisa Ruim&amp;#0153;.
O que eu realmente quero é evitar perder energia em coisas que não farão a menor diferença.
Você pode gastar um ano inteiro escolhendo entre maçãs e laranjas, e no final ser esmagado por algum maluco brincando com tecnologias esquisitas.
Por quê? Porque ele não estava preocupado com gargalos futuros. Ele estava realmente tentando fazer &lt;em&gt;algo legal&lt;/em&gt;, e ele fez isto enquanto você estava discutindo em intermináveis reuniões sem propósito.
&lt;/p&gt;

&lt;p&gt;
Você sempre está escolhendo entre medidas de desempenho.
Por exemplo, todo mundo está falando a respeito de arquitetura orientada a serviços (SOA), mas o que isso significa em termos de negócio?
Significa uma troca entre desempenho de execução de código e outros benefícios para o negócio como um todo, como crescimento descentralizado e entrega contínua.
Ou, você pode olhar nas diferenças entre os modelos da App Store da Apple e a Play Store do Google.
Existe uma troca gigantesca entre garantia de qualidade e tempo de mercado entre estes dois jogadores: um oferece a seus clientes (donos de smartphones), aplicativos com qualidade assegurada; o outro oferece a seus clientes (usuários do sistema operacional), tempo para lançamento ao mercado acelerado para seus aplicativos.
&lt;/p&gt;

&lt;p&gt;
A grande questão realmente é: o quê você está tentando entregar ao seu cliente?
Você está tentando entregar &lt;em&gt;software sobre tempo&lt;/em&gt; ou &lt;em&gt;valor sobre tempo&lt;/em&gt;?
Eu aposto que a maioria de vocês estão tentando entregar valor sobre tempo, então por quê se preocupar com otimização prematura de tecnologias ou processos?
Deixe que as coisas ruins morram por si só: &lt;em&gt;falhar rápido é dezenas de vezes melhor do que não fazer nada&lt;/em&gt;.
E deixe que as coisas boas te acompanhem para onde você quer ir.
&lt;/p&gt;

&lt;p&gt;
Não gaste seu tempo adivinhando o futuro, abrace a incerteza da vida: você não pode prever como um sistema complexo irá se comportar, você não pode saber como seus sistemas, serviços ou seja lá o que você esteja fazendo, irão se comportar no mundo real.
Coloque eles para funcionar, receba as reclamações e ajuste o que for preciso (ou jogue tudo fora), isto é um processo constante. [2]
&lt;/p&gt;

&lt;p&gt;
Comece a medir quanto você está entregando em determinado tempo e pare de planejar tanto. Seu objetivo final é entregar coisas. O mundo não poderia se importar menos com o que você &lt;em&gt;consegue fazer&lt;/em&gt;, ele só se importa com o que você &lt;em&gt;faz&lt;/em&gt;.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;Referências&lt;/strong&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://thechaoscomputing.blogspot.com.br/2014/03/complex-systems-and-key-performance.html&quot;&gt;Complex Systems and Key Performance Indicators&lt;/a&gt; - Márcio Geovani Jasinski&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.codinghorror.com/complaint-driven-development/&quot;&gt;Complaint-Driven Development&lt;/a&gt; - Jeff Atwood&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/5030328694280274031/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2014/04/otimizacao-prematura-nao-e-apenas-sobre.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/5030328694280274031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/5030328694280274031'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2014/04/otimizacao-prematura-nao-e-apenas-sobre.html' title='Otimização prematura: não é apenas sobre código'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-1467393296557060404</id><published>2013-08-05T16:29:00.000-03:00</published><updated>2013-08-05T16:36:07.035-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Questionamento"/><title type='text'>Infectado por exceções</title><content type='html'>&lt;p&gt;Acredito que códigos infectados por exceções sejam ruins. Imagine o seguinte código inofensivo:
&lt;pre&gt;
public static Foo newFoo(int bar) {
  switch (bar) {
    case 1: 
      return new FooOne();

    case 2: 
      return new FooTwo();

    default: 
      throw new IllegalArgumentException(&quot;invalid bar code: &quot; + bar);
  }
}
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Você utiliza ele no meio da sua regra de negócio, com a maior tranquilidade. O código compila e tudo:
&lt;pre&gt;
public static List&amp;lt;BazFoo&amp;gt; getAllBazFoo() {
  List&amp;lt;BazFoo&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
  List&amp;lt;Baz&amp;gt; allBaz = BazDAO.getAllBaz();
  for (Baz baz : allBaz) {
    int id = baz.getId();
    int bar = baz.getBar();
    Foo foo = Foo.newFoo(bar);
    BazFoo e = new BazFoo(id, foo);
    result.add(e);
  }
  return result;
}
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;O problema é que a chamada &lt;tt&gt;Foo.newFoo(bar)&lt;/tt&gt; pode lançar um &lt;tt&gt;IllegalArgumentException&lt;/tt&gt; e quando
isto ocorrer você não terá pista nenhuma de qual &lt;tt&gt;Baz&lt;/tt&gt; está com a informação inválida.&lt;/p&gt;
&lt;p&gt;Para tratar isto e tornar a mensagem mais útil, temos que lembrar de adicionar um &lt;tt&gt;try/catch&lt;/tt&gt; no código:
&lt;pre&gt;
public static List&amp;lt;BazFoo&amp;gt; getAllBazFoo() {
  List&amp;lt;BazFoo&amp;gt; result = new ArrayList&amp;lt;&amp;gt;();
  List&amp;lt;Baz&amp;gt; allBaz = BazDAO.getAllBaz();
  for (Baz baz : allBaz) {
    int id = baz.getId();
    int bar = baz.getBar();
    Foo foo;
    try {
      foo = Foo.newFoo(bar);
    } catch (IllegalArgumentException e) {
      throw new IllegalArgumentException(&quot;invalid baz: &quot; + id, e);
    }
    BazFoo e = new BazFoo(id, foo);
    result.add(e);
  }
  return result;
}
&lt;/pre&gt;
&lt;/p&gt;
&lt;p&gt;Adicione várias camadas de abstração à sua aplicação e pronto: espagueti sabor excepcional.
Ao adicionar exceção em algum ponto, você terá que revisar toda a pilha de abstrações que você tem e
garantir que a exceção não faça mal a ninguém e que tenha uma mensagem útil para futuras manutenções.&lt;/p&gt;
&lt;p&gt;Haskell resolve boa parte da necessidade de exceções com retornos que simbolizam falhas, e.g. &lt;tt&gt;Maybe&lt;/tt&gt; e 
&lt;tt&gt;Either&lt;/tt&gt;, e o uso de &lt;tt&gt;Monad&lt;/tt&gt; elimina a necessidade de verificar os retornos a cada passo.&lt;/p&gt;
&lt;p&gt;Porém, ainda existem exceções em Haskell, por quê? Não consigo entender o motivo para preferir exceções
ao invés de retornos especiais. Em quais situações usar exceções é melhor? Mais me parecem um &lt;tt&gt;goto&lt;/tt&gt; modernizado.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/1467393296557060404/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2013/08/infectado-por-excecoes.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/1467393296557060404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/1467393296557060404'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2013/08/infectado-por-excecoes.html' title='Infectado por exceções'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-7666498812347477026</id><published>2013-07-06T16:52:00.000-03:00</published><updated>2013-07-06T16:52:55.430-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Book"/><category scheme="http://www.blogger.com/atom/ns#" term="Livro"/><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>Livro: Code Simplicity</title><content type='html'>&lt;p&gt;Acabei de ler o livro &quot;&lt;a href=&quot;http://www.amazon.com/Code-Simplicity-The-Fundamentals-Software/dp/1449313892/ref=sr_1_1?ie=UTF8&amp;qid=1373131429&amp;sr=8-1&amp;keywords=code+simplicity&quot;&gt;Code Simplicity: The Fundamentals of Software&lt;/a&gt;&quot; (em português: &quot;&lt;a href=&quot;http://www.novatec.com.br/livros/projetosoftware/&quot;&gt;As Leis Fundamentais do Projeto de Software&lt;/a&gt;&quot;).&lt;/p&gt;

&lt;p&gt;O autor tenta criar uma ciência em cima do desenvolvimento de software. São cerca de 90 páginas que falam sobre detalhes importantes desta engenharia sem mostrar nenhuma linha de código.&lt;/p&gt;

&lt;p&gt;Entre os assuntos citados pelo autor, o que mais me impressionou foi a fórmula do custo de uma alteração em um software.&lt;/p&gt;

&lt;p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-IpozUNSxcBc/Udhx3gp_9EI/AAAAAAAAATg/cy50f_L8FDE/s1600/formula.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-IpozUNSxcBc/Udhx3gp_9EI/AAAAAAAAATg/cy50f_L8FDE/s320/formula.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Esta fórmula, quando aplicada ao tempo, deixa claro que o valor futuro e o custo da manutenção de uma alteração tem um peso muito maior do que o custo e o valor imediato gerado por uma alteração. Pois com o passar do tempo, o valor investido para manter a funcionalidade supera muito o valor investido inicialmente para codificá-la. Não vou entrar em muitos detalhes, se ficou curioso: &lt;em&gt;vá ler o livro.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-TZEcaVVYlso/Udhx-Rm5TyI/AAAAAAAAATo/cvfjYC2OHLU/s1600/tabela1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-TZEcaVVYlso/Udhx-Rm5TyI/AAAAAAAAATo/cvfjYC2OHLU/s320/tabela1.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Foi uma leitura muito prazerosa. Apenas fico triste pois cheguei neste livro por um acaso, não recebi nenhuma indicação. Meu sentimento é que se tivesse lido este livro antes, teria poupado boa parte das frustrações que vivi nestes anos como desenvolvedor. As explicações detalhadas do autor parece que se encaixam perfeitamente com os sentimentos e realizações que presenciei escrevendo e mantendo código.&lt;/p&gt;

&lt;p&gt;Deixo aqui minha indicação para todos que trabalham na área de software: &lt;em&gt;você precisa ler este livro!&lt;/em&gt; Independente de ser desenvolvedor ou não, você terá uma base muito melhor para tomar decisões que afetam o seu produto.&lt;/p&gt;

&lt;p&gt;Se você já leu, deixe seus comentários sobre o que achou.&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/7666498812347477026/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2013/07/livro-code-simplicity.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/7666498812347477026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/7666498812347477026'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2013/07/livro-code-simplicity.html' title='Livro: Code Simplicity'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-IpozUNSxcBc/Udhx3gp_9EI/AAAAAAAAATg/cy50f_L8FDE/s72-c/formula.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-2431732240668974464</id><published>2013-06-12T00:22:00.000-03:00</published><updated>2013-06-12T00:22:36.829-03:00</updated><title type='text'>Cantinho da Criança</title><content type='html'>&lt;p&gt;Está pronto e publicado no Google Play o jogo infantil Cantinho da Criança!&lt;/p&gt;

&lt;p&gt;O objetivo do jogo é ajudar crianças a reconhecer algumas coisas do dia-a-dia, auxiliando no aprendizado e no desenvolvimento. Indicado para crianças de 0 a 3 anos.&lt;/p&gt;

&lt;p&gt;Colocamos imagens bem coloridas e uma música bem animada para ensinar e divertir ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;Se tiver filhos nessa faixa etária, não deixe de conferir: &lt;a href=&quot;https://play.google.com/store/apps/developer?id=Haeres&quot;&gt;Google Play - Apps by Haeres&lt;/a&gt;&lt;/p&gt;

&lt;a href=&quot;http://1.bp.blogspot.com/-fKYTVHmOJjo/UbfonqtEUjI/AAAAAAAAAKo/StW2ck8L8qg/s1600/Screenshot_2013-06-10-20-40-28.jpg&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://1.bp.blogspot.com/-fKYTVHmOJjo/UbfonqtEUjI/AAAAAAAAAKo/StW2ck8L8qg/s320/Screenshot_2013-06-10-20-40-28.jpg&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-6T1AvRkHQ0s/UbfotV1IfHI/AAAAAAAAAK0/4sq8KABUXQU/s1600/Screenshot_2013-06-10-20-41-01.jpg&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-6T1AvRkHQ0s/UbfotV1IfHI/AAAAAAAAAK0/4sq8KABUXQU/s320/Screenshot_2013-06-10-20-41-01.jpg&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-6hMpCzm0xOI/UbfpAkE4XII/AAAAAAAAALg/kqA1a2-UXHQ/s1600/Screenshot_2013-06-10-20-41-12.jpg&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-6hMpCzm0xOI/UbfpAkE4XII/AAAAAAAAALg/kqA1a2-UXHQ/s320/Screenshot_2013-06-10-20-41-12.jpg&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-bqivmhTVBZA/UbfotGRYSnI/AAAAAAAAAKw/fjj4mdsJqlE/s1600/Screenshot_2013-06-10-20-41-22.jpg&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-bqivmhTVBZA/UbfotGRYSnI/AAAAAAAAAKw/fjj4mdsJqlE/s320/Screenshot_2013-06-10-20-41-22.jpg&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-WSNMZgMW850/Ubfo1dbN36I/AAAAAAAAALA/k8vveGC5BLs/s1600/Screenshot_2013-06-10-20-41-30.jpg&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-WSNMZgMW850/Ubfo1dbN36I/AAAAAAAAALA/k8vveGC5BLs/s320/Screenshot_2013-06-10-20-41-30.jpg&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://2.bp.blogspot.com/-KwgBhOp5jh8/Ubfo3H9oMNI/AAAAAAAAALI/cl5az83nmGo/s1600/Screenshot_2013-06-10-20-41-38.jpg&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://2.bp.blogspot.com/-KwgBhOp5jh8/Ubfo3H9oMNI/AAAAAAAAALI/cl5az83nmGo/s320/Screenshot_2013-06-10-20-41-38.jpg&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://4.bp.blogspot.com/-bGXDwUWhg2w/Ubfo950nYDI/AAAAAAAAALY/DjIqoJYGz_0/s1600/Screenshot_2013-06-10-20-41-57.jpg&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://4.bp.blogspot.com/-bGXDwUWhg2w/Ubfo950nYDI/AAAAAAAAALY/DjIqoJYGz_0/s320/Screenshot_2013-06-10-20-41-57.jpg&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://3.bp.blogspot.com/-qsQD2kdzn_o/Ubfo9pCpxtI/AAAAAAAAALQ/WhzfNVE1xOQ/s1600/Screenshot_2013-06-10-20-42-41.jpg&quot; imageanchor=&quot;1&quot; &gt;&lt;img border=&quot;0&quot; src=&quot;http://3.bp.blogspot.com/-qsQD2kdzn_o/Ubfo9pCpxtI/AAAAAAAAALQ/WhzfNVE1xOQ/s320/Screenshot_2013-06-10-20-42-41.jpg&quot; /&gt;&lt;/a&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/2431732240668974464/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2013/06/cantinho-da-crianca.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/2431732240668974464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/2431732240668974464'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2013/06/cantinho-da-crianca.html' title='Cantinho da Criança'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-fKYTVHmOJjo/UbfonqtEUjI/AAAAAAAAAKo/StW2ck8L8qg/s72-c/Screenshot_2013-06-10-20-40-28.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-3772191714111015492</id><published>2013-06-05T20:21:00.000-03:00</published><updated>2013-06-12T00:12:22.858-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Android"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>Abrace Android</title><content type='html'>&lt;p&gt;
Já faz um tempo que não escrevo neste blog. As minhas aventuranças no mundo Haskell pararam um pouco depois do último post que fiz (&quot;&lt;a href=http://eu-hunz.blogspot.com.br/2013/01/c-c-haskell-java.html&quot;&gt;C, C++, Java, Haskell?&lt;/a&gt;&quot;).
&lt;/p&gt;

&lt;p&gt;
Dediquei um bom pedaço deste tempo ausente para tentar fazer um jogo em C. Tive um bom começo: fiz um personagem se movimentar, pular e colidir com outros objetos. Comecei a perceber onde estava me metendo quando estas perguntas surgiram na minha mente: 
&lt;ul&gt;
&lt;li&gt;Como vou distribuir meu jogo?&lt;/li&gt;
&lt;li&gt;Como vou lançar uma atualização?&lt;/li&gt;
&lt;li&gt;Como vou comercializar?&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;
Neste momento estava com uma conexão carinhosa com o projeto e foi difícil aceitar que estas dificuldades poderiam ser maiores do que meu esforço disponível. Passada esta fase de aceitação, decidi que precisava tirar todas estas preocupações da cabeça para conseguir me dedicar ao desenvolvimento do jogo. Para isto precisava de uma plataforma que me oferecesse todos os itens que coloquei na lista acima.
&lt;/p&gt;

&lt;div style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Android_robot.svg/100px-Android_robot.svg.png&quot; alt=&quot;Android&quot; /&gt;&lt;/div&gt; 

&lt;p&gt;
Escolhi a plataforma Android por conseguir acesso a um ambiente de desenvolvimento de forma mais fácil, pois poderia continuar utilizando meu notebook rodando Windows para programar e realizar testes no meu celular Samsung Galaxy 5. Sem chance de investir em um ambiente para iOS no momento.
&lt;/p&gt;

&lt;p&gt;
Para garantir que a plataforma atendia a todos os itens que listei acima, fiz o processo do começo ao fim:
&lt;ol&gt;
&lt;li&gt;Criei um aplicativo de exemplo&lt;/li&gt;
&lt;li&gt;Testei no meu celular&lt;/li&gt;
&lt;li&gt;Publiquei o aplicativo (&lt;em&gt;Como vou distribuir meu jogo?&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Alterei algumas coisas e lancei atualizações para ele (&lt;em&gt;Como vou lançar uma atualização?&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Criei uma versão free com propagandas e uma paga sem propagandas (&lt;em&gt;Como vou comercializar?&lt;/em&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;

&lt;p&gt;
O resultado disto tudo foi muito agradável. Agora não me restam dúvidas sobre o ambiente Android, basta continuar meu aprendizado na plataforma e o desenvolvimento do projeto em paralelo. Espero que em breve eu consiga postar no blog um link para o resultado do projeto publicado. :)
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/3772191714111015492/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2013/06/abrace-android.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/3772191714111015492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/3772191714111015492'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2013/06/abrace-android.html' title='Abrace Android'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-1039322443808600573</id><published>2013-01-20T20:40:00.000-02:00</published><updated>2013-01-20T20:40:50.915-02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C"/><category scheme="http://www.blogger.com/atom/ns#" term="C++"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Programação"/><title type='text'>C, C++, Haskell, Java?</title><content type='html'>&lt;p&gt;
Estou empolgado e agoniado com meu aprendizado sobre OpenGL. Ao mesmo tempo em que aprender OpenGL me deixa muito satisfeito, também me deixa inquieto: dediquei muito tempo aprendendo Haskell e fui envolvido de uma forma a gostar muito da linguagem e da comunidade. Porém, fazer algo em OpenGL se mostrou muito difícil e até mesmo solitário. Existem pouquíssimos materiais sobre isso e a maioria deles estão obsoletos.
&lt;/p&gt;

&lt;p&gt;
Tive que largar Haskell por um tempo e religar os neurônios da linguagem C para aprender o &lt;a href=&quot;http://www.duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Table-of-Contents.html&quot;&gt;fluxo das versões mais modernas do OpenGL&lt;/a&gt;, com shaders e buffer objects. O motivo foi simples: não consegui fazer nada funcionar em Haskell e não tive certeza se a culpa era minha ou das bibliotecas que utilizava.
&lt;/p&gt;

&lt;p&gt;
Pois bem, fazer uma câmera se movimentar em um mundo 3D em C também não foi nada fácil. Mas com a abundância de material, consegui deixar funcionando de uma forma que me deixou bem satisfeito.
&lt;/p&gt;

&lt;p&gt;
Decidi então voltar para Haskell e aplicar este conhecimento que acabei de conquistar.
&lt;/p&gt;

&lt;p&gt;
Que trabalheira! Fazer tudo se encaixar da maneira certa e &lt;a href=&quot;https://github.com/haskell-opengl/OpenGLRaw/issues/15&quot;&gt;com os tipos corretos&lt;/a&gt; me fez suar algumas camisas. Se não fosse tão teimoso, não teria conseguido. Tive que trocar o pacote &lt;a href=&quot;http://hackage.haskell.org/package/OpenGL&quot;&gt;OpenGL&lt;/a&gt; pelo &lt;a href=&quot;http://hackage.haskell.org/package/OpenGLRaw&quot;&gt;OpenGLRaw&lt;/a&gt; pois o pacote &lt;a href=&quot;https://github.com/haskell-opengl/OpenGL/issues/33&quot;&gt;OpenGL não tem binding para &quot;glUniformMatrix*&quot;&lt;/a&gt;; também troquei o &lt;a href=&quot;http://hackage.haskell.org/package/GLFW&quot;&gt;GLFW&lt;/a&gt; pelo &lt;a href=&quot;http://hackage.haskell.org/package/GLFW-b&quot;&gt;GLFW-b&lt;/a&gt; porque o primeiro dependia do pacote OpenGL.
&lt;/p&gt;

&lt;p&gt;
Recentemente li &lt;a href=&quot;http://www.infoq.com/news/2013/01/C-Language&quot;&gt;um artigo no InfoQ questionando se a linguagem C ainda era útil&lt;/a&gt;. Me fez pensar em muita coisa, inclusive em abandonar definitivamente Haskell e voltar às origens: ponteiros, gerenciamento de memória manual, strings cabulosas, ...
&lt;/p&gt;

&lt;p&gt;
Talvez seja porque sou muito novo neste mundo, mas me sinto meio improdutivo programando em Haskell. A impressão que tenho é que, a menos que seja algo muito bem consolidado e utilizado por muitas pessoas da comunidade, muito tempo será gasto atrás de bibliotecas que normalmente são apenas um binding para uma escrita em C. Quando não for isto, só para ter uma breve ideia do que a API de uma biblioteca faz, acabo lendo alguns papers relembrando o que são Functors e Monads (para entender Arrows acho que vou precisar comprar um livro!).
&lt;/p&gt;

&lt;p&gt;
Entender ponteiros e gerenciamento de memória em C também foi difícil. Mas naquela época eu era um jovenzinho no mundo da programação, meu conhecimento era muito limitado, se baseava muito em bater no código até que ele fizesse o que eu queria. Agora não consigo mais aceitar fazer alguma coisa sem entender o que estou fazendo.
&lt;/p&gt;

&lt;p&gt;
Eu lembro que tive bons motivos para trocar C por Java. Depois de passar um tempo utilizando Java, vejo também as partes negativas da linguagem. Meu trabalho de conclusão da graduação foi dedicado a evidenciar os motivos desta troca e do futuro promissor de linguagens como Haskell. 
&lt;/p&gt;

&lt;p&gt;
No final das contas, acredito que esta pseudo-decepção acontece com toda linguagem em que você dedica bastante tempo para aprendê-la. A propaganda e os primeiros passos são maravilhosos. Parece que você descobriu um novo mundo onde todos são ricos e podem desfrutar de todas as coisas boas. Com o tempo você percebe que não é bem assim: cada escolha que a linguagem fez significa pontos positivos e negativos para nós usuários. Foi assim com C, Python, Java e agora com Haskell.
&lt;/p&gt;

&lt;p&gt;
Java escolheu uma abordagem orientada a objetos: mesmo que seja uma função estática ou uma variável global, será necessária a roupagem de uma classe para acomodar este código. Haskell escolheu o funcional puro: mesmo operações que envolvam I/O recebem a roupagem de um monad.
&lt;/p&gt;

&lt;p&gt;
Não que isto seja ruim. A utilização de monads para modelar computação sequencial foi uma grande descoberta que proporcionou a criação de inúmeras soluções. Estas escolhas trazem pontos positivos e negativos. Só devemos ter cuidado com o purismo extremo para não criar aberrações (e.g. Singleton).
&lt;/p&gt;

&lt;p&gt;
Enfim, estou agoniado pois não sei o que escolher:
&lt;ul&gt;
&lt;li&gt;C me parece flexível mas com as complexidades que não quero ter. C11 parece solucionar algumas coisas (e.g. &lt;tt&gt;&amp;lt;threads.h&amp;gt;&lt;/tt&gt;), mas o GCC ainda não suporta;&lt;/li&gt;
&lt;li&gt;Sou bem produtivo em Java mas o overhead obrigatório e a necessidade de ter uma JVM me irritam profundamente;&lt;/li&gt;
&lt;li&gt;C++ ainda é uma incógnita para mim, se for para ir neste nível ainda prefiro utilizar C. Java já me fez ver os motivos para dizer não à O.O. Por outro lado, boa parte de quem utilizava C está indo para C++, inclusive o &lt;a href=&quot;http://gcc.gnu.org/ml/gcc-patches/2012-08/msg00711.html&quot;&gt;GCC está utilizando C++&lt;/a&gt;. As bibliotecas disponíveis para C++ também pesam bastante (e.g. &lt;a href=&quot;http://glm.g-truc.net/&quot;&gt;GLM&lt;/a&gt;, &lt;a href=&quot;http://www.boost.org/&quot;&gt;Boost&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;Haskell é minha linguagem da vez mas está começando a me incomodar um pouco, sentimento de improdutividade me deixa muito tenso. Talvez precise dedicar mais tempo para que isto passe. Não sei se este esforço irá valer a pena ou poderia ser melhor aproveitado aprimorando meus conhecimentos em outra linguagem.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;
A diferença de desempenho entre C e Haskell não me preocupa muito, pois &lt;a href=&quot;http://paulspontifications.blogspot.com.br/2013/01/when-haskell-is-faster-than-c.html&quot;&gt;não vou escovar bits para ter um bom desempenho&lt;/a&gt; tão cedo.
&lt;/p&gt;

&lt;p&gt;
No final das contas, a opinião mais correta sempre é: depende do projeto, escolha a melhor linguagem para o seu projeto. Pois bem, não tenho projeto nenhum, mas quero me aprofundar no desenvolvimento de jogos.
&lt;/p&gt;

&lt;p&gt;
E agora?
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/1039322443808600573/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2013/01/c-c-haskell-java.html#comment-form' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/1039322443808600573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/1039322443808600573'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2013/01/c-c-haskell-java.html' title='C, C++, Haskell, Java?'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-629027159267820082</id><published>2013-01-09T11:11:00.000-02:00</published><updated>2013-01-09T11:11:23.554-02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DuDuHoX"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="OpenAL"/><category scheme="http://www.blogger.com/atom/ns#" term="OpenGL"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>DuDuHoX com som: OpenAL</title><content type='html'>&lt;p&gt;Trabalhar no DuDuHoX está cada vez mais difícil. Já pensei em desistir em alguns problemas que tive, seja com código ou com bibliotecas.&lt;/p&gt;

&lt;p&gt;Colocar animação no jogo foi muito complicado. Porque o motor do jogo não tem estados intermediários em que o personagem está indo de uma casa para outra. O estado do jogo só permite que o personagem ocupe uma casa e não metade de uma e metade de outra.&lt;/p&gt;

&lt;p&gt;Minha solução para isto foi colocar a informação de animação no código da interface gráfica (OpenGL). Após pressionar alguma tecla que movimente o personagem, o motor do jogo já estará no estado novo completo, mas a interface não aceitará mais nenhuma entrada enquanto não terminar de exibir a animação de movimentação.&lt;/p&gt;

&lt;p&gt;Outro grande problema que tive foi quando decidi colocar sons no jogo. Meus objetivos são: música de fundo e sons posicionais. A biblioteca que achei para isto foi a &lt;a href=&quot;https://en.wikipedia.org/wiki/OpenAL&quot; target=&quot;blank_&quot;&gt;OpenAL&lt;/a&gt;. Ela é feita em C mas existe o &lt;a href=&quot;http://hackage.haskell.org/package/OpenAL/&quot; target=&quot;blank_&quot;&gt;pacote Haskell&lt;/a&gt; que faz o binding.&lt;/p&gt;

&lt;p&gt;Mas, nem tudo é tão bonito. Instalar a biblioteca OpenAL no Windows foi um tremendo caos. Foi uma tarde inteira tentando fazer isto. Quando finalmente consegui instalar, percebi que também iria precisar da biblioteca &lt;a href=&quot;http://hackage.haskell.org/package/ALUT&quot; target=&quot;blank_&quot;&gt;ALUT&lt;/a&gt;. Esta não foi tão difícil de instalar, porém, ocorriam erros de link durante a compilação. Felizmente encontrei um bug reportado para o GHC que tratava exatamente do meu problema: &lt;a href=&quot;http://hackage.haskell.org/trac/ghc/ticket/1243&quot; target=&quot;blank_&quot;&gt;Ticket 1243&lt;/a&gt;. Depois de aplicar o patch, tudo funcionou.&lt;/p&gt;

&lt;p&gt;Fiz uma música no &lt;a href=&quot;http://openmpt.org/&quot; target=&quot;blank_&quot;&gt;OpenMPT&lt;/a&gt;, desenhei o personagem no &lt;a href=&quot;http://www.gimp.org/&quot; target=&quot;blank_&quot;&gt;GIMP&lt;/a&gt; e coloquei tudo dentro do jogo.&lt;/p&gt;

&lt;p&gt;Apesar das dificuldades, estou muito feliz com resultado que estou obtendo em fazer o DuDuHoX em Haskell. Decidi gravar um gameplay com o &lt;a href=&quot;http://camstudio.org/&quot; target=&quot;blank_&quot;&gt;CamStudio&lt;/a&gt; e compartilhar com vocês através do YouTube:&lt;/p&gt;

&lt;p&gt;
&lt;iframe width=&quot;420&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/etVOPfktwSc&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/629027159267820082/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2013/01/duduhox-com-som-openal.html#comment-form' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/629027159267820082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/629027159267820082'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2013/01/duduhox-com-som-openal.html' title='DuDuHoX com som: OpenAL'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://img.youtube.com/vi/etVOPfktwSc/default.jpg" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-4377293850307634495</id><published>2012-12-31T11:17:00.001-02:00</published><updated>2012-12-31T11:22:24.353-02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="DuDuHoX"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="OpenGL"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>OpenGL em Haskell</title><content type='html'>&lt;p&gt;
Continuo trabalhando no &lt;a href=&quot;http://eu-hunz.blogspot.com.br/2012/08/criando-um-jogo-de-labirinto-em-haskell.html&quot; target=&quot;blank_&quot;&gt;DuDuHoX&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
A primeira interface do jogo é em console. Utiliza o pacote &lt;tt&gt;System.Console.ANSI&lt;/tt&gt;. Funciona muito bem em Linux e Mac OS, apenas no Windows tem um pequeno problema de buffer, forçando com que o jogador tenha que apertar &lt;tt&gt;enter&lt;/tt&gt; após cada jogada.
&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://i767.photobucket.com/albums/xx311/evohunz/duduhox_console_zps08d00348.png&quot; alt=&quot;DuDuHoX versão console&quot; /&gt;&lt;/p&gt;

&lt;p&gt;
Esta semana decidi fazer uma nova interface para o jogo: com gráficos e sem o problema de buffer do console do Windows.
&lt;/p&gt;

&lt;p&gt;
Primeiramente tentei utilizar &lt;a href=&quot;http://www.libsdl.org/&quot; target=&quot;blank_&quot;&gt;SDL&lt;/a&gt;, pois foi ela que utilizei para fazer DuDuRoX em C. Infelizmente, não tive sucesso nenhum, nem mesmo consegui fazer um exemplo compilar.
&lt;/p&gt;

&lt;p&gt;
Pensei em utilizar diretamente &lt;a href=&quot;https://www.opengl.org/&quot; target=&quot;blank_&quot;&gt;OpenGL&lt;/a&gt; para o gráfico, mas não sabia o que utilizar para gerenciar a entrada do usuário (apertar de teclas). Já vi reclamações a respeito de OpenGL/GLUT. Foi então que depois de algumas pesquisas conheci o &lt;a href=&quot;http://www.glfw.org/&quot; target=&quot;blank_&quot;&gt;GLFW&lt;/a&gt;, um biblioteca C open-source que fazia tudo que eu precisava, e o mais importante: existe o &lt;a href=&quot;http://hackage.haskell.org/packages/archive/GLFW/latest/doc/html/Graphics-UI-GLFW.html#GLFW&quot; target=&quot;blank_&quot;&gt;pacote GLFW para Haskell&lt;/a&gt; que faz o binding.
&lt;/p&gt;

&lt;p&gt;
Depois de algumas horas aprendendo OpenGL e GLFW para Haskell, o resultado é este:
&lt;/p&gt;

&lt;p&gt;
&lt;img src=&quot;http://i767.photobucket.com/albums/xx311/evohunz/duduhox_first_opengl_zps0abe8c94.png&quot; alt=&quot;DuDuHoX versão gráfica&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;
Já está jogável com esta interface, porém a versão console possui mais funcionalidades. Então, para as próximas semanas, vou tentar passar todas as funcionalidades da versão console para a versão gráfica e adicionar algumas texturas bacanas. A lista de coisas a fazer e todo o código está disponível no GitHub: &lt;a href=&quot;https://github.com/thiago-negri/DuDuHoX&quot; target=&quot;blank_&quot;&gt;https://github.com/thiago-negri/DuDuHoX&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Feliz 2013!&lt;/em&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/4377293850307634495/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/12/opengl-em-haskell.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4377293850307634495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4377293850307634495'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/12/opengl-em-haskell.html' title='OpenGL em Haskell'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-4495220238994713602</id><published>2012-08-15T21:42:00.000-03:00</published><updated>2012-08-23T12:25:40.958-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Functional"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Pure"/><category scheme="http://www.blogger.com/atom/ns#" term="TDD"/><title type='text'>Programação funcional pura e útil</title><content type='html'>&lt;p&gt;Acho que todos os programadores acostumados com o modelo imperativo ficam espantados em imaginar quão maluco é o modelo funcional puro. Afinal, como podemos fazer qualquer coisa útil sem gerar efeitos colaterais? Sem imprimir no console? Sem abrir uma tela? Sem gerar logs? Sem alterar variáveis? &lt;b&gt;OMG&lt;/b&gt;.&lt;/p&gt;

&lt;p&gt;Este também foi um espanto meu ao conhecer Haskell e por uma feliz insistência descobri que o problema está na cabeça do programador e não no modelo funcional puro.&lt;/p&gt;

&lt;h3&gt;Diferenças&lt;/h3&gt;
&lt;p&gt;Viver muito tempo no contexto das linguagens imperativas acabou modelando minha forma de pensar em uma maneira sequêncial. Eu sempre precisei dizer como fazer cada passo da computação, quais estados manter, quais variáveis alterar, quando retornar um valor, etc.&lt;/p&gt;

&lt;p&gt;Enquanto que no mundo funcional puro, fui obrigado a pensar em uma maneira de transformação de dados. Ao invés de pensar em como fazer cada etapa, preciso pensar como transformar um dado em outro, i.e. como extrair a representação que quero a partir do dado que tenho.&lt;/p&gt;

&lt;p&gt;Os exemplos clássicos para demonstrar esta diferença envolve a manipulação de listas.&lt;/p&gt;

&lt;h4&gt;Exemplo #1&lt;/h4&gt;
&lt;p&gt;Para calcular a somatória no estilo imperativo, é necessário pensar no controle sobre o estado da soma atual, que deve ser acumulado durante a iteração da lista.
&lt;pre&gt;
int sum(int[] list) {
  int result = 0;
  for (int i : list)
    result += i;
  return result;
}
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Do outro lado, no mundo funcional, é necessário pensar em como transformar uma lista em um único número que represente a soma de todos os elementos, i.e. a soma de uma lista vazia sempre será zero e a soma de qualquer outra lista é definida pelo seu primeiro valor acrescentado da soma do restante da lista.
&lt;pre&gt;
sum [] = 0
sum (x:xs) = x + sum xs
&lt;/pre&gt;
&lt;/p&gt;

&lt;h4&gt;Exemplo #2&lt;/h4&gt;
&lt;p&gt;Já em um exemplo um pouco mais complexo, em que precisamos manter duas listas no mundo imperativo, uma de entrada e outra de saída, precisamos incluir o controle sobre o índice de cada lista, para evitar erros de indexação.
&lt;pre&gt;
String[] toText(int[] list) {
    String[] result = new String[list.length];
    for (int i = 0; i &lt; list.length; ++i)
        result[i] = Integer.toString(list[i]);
    return result;
}
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Enquanto que o mesmo exemplo no mundo funcional continua simples como a somatória da lista, a única diferença é que ao invés de transformarmos a lista utilizando a adição, utilizamos o próprio construtor de listas (representado pelo operador &#39;:&#39;).
&lt;pre&gt;
toText [] = []
toText (x:xs) = show x : toText xs
&lt;/pre&gt;&lt;/p&gt;

&lt;h3&gt;Motivação&lt;/h3&gt;
&lt;p&gt;Para demonstrar que o modelo funcional puro pode fazer muitas coisas além dos exemplos clássicos, de uma forma que considero bonita e com vantagens gratuitas, escrevo este post.&lt;/p&gt;

&lt;h3&gt;Calculadora&lt;/h3&gt;
&lt;p&gt;Hoje vamos criar uma calculadora em Haskell. Todo o código será puro, sem nenhum tipo de efeito colateral, incluindo uma &lt;a href=&quot;http://c2.com/cgi/wiki?DomainSpecificLanguage&quot;&gt;DSL&lt;/a&gt; para escrever testes, o próprio executor dos testes e dois transformadores de cenários de teste, um para escrever o teste no formato de texto e outro para escrever o mesmo teste no formato de um JUnit.&lt;/p&gt;

&lt;h3&gt;Formato dos testes&lt;/h3&gt;
&lt;p&gt;Primeiramente, definimos o formato em que os testes serão escritos. Neste caso, será uma sequência de ações e validações:
&lt;pre&gt;
data TestSequence =
    Do Action TestSequence
  | Check Assertion TestSequence
  | Done
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Com esta estrutura de dados, os testes poderão ser escritos neste formato:
&lt;pre&gt;
test =
  Do a.
  Do b.
  Do c.
  Check d$
  Done
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;A necessidade de ter o &quot;Done&quot; no final do teste me incomoda. Para evitar que precise escrever isto, indicarei que os testes sempre terminem de forma aberta, i.e. permitindo continuar a sequência:
&lt;pre&gt;
type Test = TestSequence -&gt; TestSequence
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Agora podemos escrever o teste da seguinte forma:
&lt;pre&gt;
test =
  Do a.
  Do b.
  Do c.
  Check d
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Para mim, já está classificada como uma DSL funcional para testes.&lt;/p&gt;
 
&lt;p&gt;O único tipo de ação disponível na calculadora é o de apertar seus botões e a única validação será a verificação do seu display. Os botões disponíveis são os padrões de uma calculadora.
&lt;pre&gt;
data Action =
    Press Button

data Assertion =
    DisplayHasNumber Int

data Button =
    Zero
  | One
  | Two
  | Three
  | Four
  | Five
  | Six
  | Seven
  | Eight
  | Nine
  | Plus
  | Minus
  | Times
  | Divide
  | Equals
  | Clear
    deriving (Show)
&lt;/pre&gt;
&lt;/p&gt;

&lt;h3&gt;Primeiro teste&lt;/h3&gt;
&lt;p&gt;O primeiro passo está pronto. Já temos uma DSL para testes compilando. Hora de escrever nosso primeiro teste, que também já compila:
&lt;pre&gt;
sample :: Test
sample =
    Do (Press One).
    Do (Press Plus).
    Do (Press One).
    Do (Press Equals).
    Check (DisplayHasNumber 2).

    Do (Press Clear).
    Check (DisplayHasNumber 0).

    Do (Press Two).
    Do (Press Zero).
    Check (DisplayHasNumber 20).
    Do (Press Divide).
    Do (Press Two).
    Check (DisplayHasNumber 2).
    Do (Press Equals).
    Check (DisplayHasNumber 10)
&lt;/pre&gt;
&lt;/p&gt;

&lt;h3&gt;Transformadores do teste&lt;/h3&gt;
&lt;p&gt;Como nosso teste está escrito na forma de uma estrutura de dados, isto nos dá muitas possibilidades para tratamento do caso de teste. Para facilitar as transformações desta estrutura, definimos uma função que aplica uma função genérica a cada passo do teste e agrupa os resultados em uma lista:
&lt;pre&gt;
unroll :: (TestSequence -&gt; a) -&gt; Test -&gt; [a]
unroll f t = g (t Done)
  where g Done = [f Done]
        g v@(Do _ next) = f v : g next
        g v@(Check _ next) = f v : g next
&lt;/pre&gt;
&lt;/p&gt;

&lt;h4&gt;Teste -&gt; Texto&lt;/h4&gt;
&lt;p&gt;
Podemos processar o teste e gerar uma saída textual do cenário:
&lt;pre&gt;
prettyPrint :: Test -&gt; String
prettyPrint = unlines . unroll prettyPrintTestSequence

prettyPrintTestSequence :: TestSequence -&gt; String
prettyPrintTestSequence s =
    case s of
      Done              -&gt; &quot;end&quot;
      Do action _       -&gt; prettyPrintAction action
      Check assertion _ -&gt; prettyPrintAssertion assertion

prettyPrintAction :: Action -&gt; String
prettyPrintAction (Press button) = 
    &quot;press &quot; ++ prettyPrintButton button

prettyPrintButton :: Button -&gt; String
prettyPrintButton = map toLower . show

prettyPrintAssertion :: Assertion -&gt; String
prettyPrintAssertion (DisplayHasNumber number) = 
    &quot;the display should be showing the number &quot; ++ 
    show number
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;
Testando no GHCi:
&lt;pre&gt;
\&gt; putStr $ prettyPrint sample
press one
press plus
press one
press equals
the display should be showing the number 2
press clear
the display should be showing the number 0
press two
press zero
the display should be showing the number 20
press divide
press two
the display should be showing the number 2
press equals
the display should be showing the number 10
end
&lt;/pre&gt;
&lt;/p&gt;

&lt;h4&gt;Teste -&gt; JUnit&lt;/h4&gt;
&lt;p&gt;Também podemos gerar casos de teste para uma possível solução Java da nossa calculadora:
&lt;pre&gt;
generateJUnit :: Test -&gt; String
generateJUnit = 
    (&quot;@Test\npublic void test() {\n&quot; ++) . 
    unlines .
    unroll generateJUnitTestSequence

generateJUnitTestSequence :: TestSequence -&gt; String
generateJUnitTestSequence s =
    case s of
      Done      -&gt; &quot;}&quot;
      Do a _    -&gt; generateJUnitAction a
      Check a _ -&gt; generateJUnitAssertion a

generateJUnitAction :: Action -&gt; String
generateJUnitAction (Press b) =
    generateJUnitButton b ++ &quot;.press();&quot;

generateJUnitButton :: Button -&gt; String
generateJUnitButton b = &quot;getButton&quot; ++ show b ++ &quot;()&quot;

generateJUnitAssertion :: Assertion -&gt; String
generateJUnitAssertion (DisplayHasNumber n) =
    &quot;assertEquals(&quot; ++ show n ++ &quot;, getDisplayNumber());&quot;
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Testando no GHCi:
&lt;pre&gt;
\&gt; putStr $ generateJUnit sample
@Test
public void test() {
getButtonOne().press();
getButtonPlus().press();
getButtonOne().press();
getButtonEquals().press();
assertEquals(2, getDisplayNumber());
getButtonClear().press();
assertEquals(0, getDisplayNumber());
getButtonTwo().press();
getButtonZero().press();
assertEquals(20, getDisplayNumber());
getButtonDivide().press();
getButtonTwo().press();
assertEquals(2, getDisplayNumber());
getButtonEquals().press();
assertEquals(10, getDisplayNumber());
}
&lt;/pre&gt;
&lt;/p&gt;

&lt;h4&gt;Teste de fato&lt;/h4&gt;
&lt;p&gt;E claro, também podemos utilizar nosso teste no formato de uma estrutura de dados para realmente testar uma calculadora:
&lt;pre&gt;
data TestResult =
    Ok
  | Failed FailureMessage

type FailureMessage = String

instance Show TestResult where
    show Ok = &quot;Test passed&quot;
    show (Failed m) = &quot;Test failed: &quot; ++ m

checkTest :: Test -&gt; TestResult
checkTest t = 
    evalState 
    (threadCheckState . unroll checkTestSequence $ t)
    mkCalculator

threadCheckState :: [State Calculator TestResult] -&gt;
                    State Calculator TestResult 
threadCheckState = go 0
  where go _ [] = return Ok
        go n (x:xs) = x &gt;&gt;= (f n xs)
        f n xs Ok = go (n + 1) xs
        f n _ (Failed m) = 
          return . Failed $
            &quot;Step &quot; ++ show n ++ &quot;. &quot; ++ m

checkTestSequence :: TestSequence -&gt; 
                     State Calculator TestResult
checkTestSequence Done = return Ok
checkTestSequence (Do a _) = checkAction a
checkTestSequence (Check a _) = checkAssertion a

checkAction :: Action -&gt; State Calculator TestResult
checkAction (Press b) = do
    modify $ pressButton b 
    return Ok

checkAssertion :: Assertion -&gt; State Calculator TestResult
checkAssertion (DisplayHasNumber n) =
    get &gt;&gt;= \c -&gt;
      if displayNumber c == n
        then return Ok
        else return . Failed $ 
          &quot;Wrong number in display, should be &quot; ++
          show n ++ &quot; but was &quot; ++ show (displayNumber c)
&lt;/pre&gt;
&lt;/p&gt;

&lt;h3&gt;O coração da calculadora&lt;/h3&gt;
&lt;p&gt;Finalmente, para que o testador-de-fato compile, precisamos definir uma primeira versão da nossa calculadora. Aqui você poderia tentar criar sua própria implementação. Cheguei neste código para atender ao cenário do teste:
&lt;pre&gt;
data Calculator = Calculator {
    displayNumber :: Int
  , operation :: Maybe (Int -&gt; Int -&gt; Int)
  , savedNumber :: Int
  }

pressButton :: Button -&gt; Calculator -&gt; Calculator
pressButton b =
  case b of
    Zero    -&gt; appendNumber 0
    One     -&gt; appendNumber 1
    Two     -&gt; appendNumber 2
    Three   -&gt; appendNumber 3
    Four    -&gt; appendNumber 4
    Five    -&gt; appendNumber 5
    Six     -&gt; appendNumber 6
    Seven   -&gt; appendNumber 7
    Eight   -&gt; appendNumber 8
    Nine    -&gt; appendNumber 9
    Plus    -&gt; saveOperation (+)
    Minus   -&gt; saveOperation (-)
    Times   -&gt; saveOperation (*)
    Divide  -&gt; saveOperation div
    Equals  -&gt; performOperation
    Clear   -&gt; clear

appendNumber :: Int -&gt; Calculator -&gt; Calculator
appendNumber i c = 
  c { 
    displayNumber = (displayNumber c) * 10 + i 
  }

saveOperation :: (Int -&gt; Int -&gt; Int) -&gt; 
                 Calculator -&gt; Calculator
saveOperation f c = 
  c { 
    savedNumber = (displayNumber c)
  , displayNumber = 0
  , operation = Just f
  }

performOperation :: Calculator -&gt; Calculator
performOperation c = 
  c { 
    savedNumber = newNumber
  , displayNumber = newNumber 
  }
  where newNumber = 
          case (operation c) of
            Nothing -&gt; displayNumber c
            Just f  -&gt; let a = savedNumber c
                           b = displayNumber c 
                        in
                           f a b

clear :: Calculator -&gt; Calculator
clear = const mkCalculator

mkCalculator :: Calculator
mkCalculator = 
  Calculator { 
    displayNumber = 0
  , operation = Nothing
  , savedNumber = 0
  }
&lt;/pre&gt;
&lt;/p&gt;

&lt;h3&gt;Testando a calculadora&lt;/h3&gt;
&lt;p&gt;Agora podemos executar o testador-de-fato contra nossa calculadora no GHCi. Vamos experimentar:
&lt;pre&gt;
\&gt; checkTest sample
Test passed
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;Isto significa que nossa calculadora está atendendo ao cenário de teste. Para garantir que o teste capture um comportamento que não corresponda ao cenário de teste, podemos introduzir um erro: alteramos o valor da multiplicação na função &quot;appendNumber&quot; de &quot;10&quot; para &quot;100&quot;. Se rodarmos novamente o teste, teremos este resultado:
&lt;pre&gt;
\&gt; checkTest sample
Test failed: Step 9. Wrong number in display, should be 20 but was 200
&lt;/pre&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Magavilha.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;Conclusão&lt;/h3&gt;
&lt;p&gt;Construímos um código básico de uma calculadora funcionando que atende ao especificado no cenário de teste. Agora basta adicionarmos novos testes e continuar incrementando nossa calculadora, parecido com um TDD. Tudo isto foi feito de uma forma 100% pura, sem depender de nada que envolva IO, estado, variáveis ou logs.&lt;/p&gt;

&lt;p&gt;Além do benefício de podermos fazer qualquer tipo de transformação nos cenários de teste, também podemos rodar quantas transformações e quantos testes quisermos de forma paralela, pois tanto o teste quanto a calculadora são thread-safe pelo simples fato de serem escritos de forma pura.&lt;/p&gt;

&lt;p&gt;Conseguimos fazer tudo isto em míseras 251 linhas de código ou 5635 caracteres, incluindo comentários e linhas em branco. Quantas classes e/ou linhas seriam necessárias para contemplar todas as funcionalidades e seguranças demonstradas neste post na sua linguagem imperativa favorita?&lt;/p&gt;

&lt;p&gt;Espero que este post sirva para inspirar vossas mentes a pensar &quot;fora-da-caixa&quot; do mundo imperativo. Existem muitas vantagens em aprender uma linguagem funcional pura, mesmo que você utilize linguagens imperativas para trabalhar.&lt;/p&gt;

&lt;p&gt;O código inteiro está disponível no GitHub: &lt;a href=&quot;https://gist.github.com/3354394&quot;&gt;https://gist.github.com/3354394&lt;/a&gt;. Para testar, é só baixar o código e carregar no GHCi.&lt;/p&gt;

&lt;h3&gt;Exemplos reais&lt;/h3&gt;
&lt;p&gt;
Apenas para finalizar, alguns exemplos de aplicativos reais em uso desenvolvidos em Haskell:
&lt;ul&gt;
&lt;li&gt;Compilador Haskell: &lt;a href=&quot;http://www.haskell.org/ghc/&quot;&gt;The Glasgow Haskell Compiler (GHC)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Frameworks para desenvolvimento web: &lt;a href=&quot;http://www.yesodweb.com/&quot;&gt;Yesod&lt;/a&gt;, &lt;a href=&quot;http://happstack.com/&quot;&gt;Happstack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gerenciador de janelas do X: &lt;a href=&quot;http://xmonad.org/&quot;&gt;XMonad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Gerenciador de fontes com um conceito novo (teoria de patches): &lt;a href=&quot;http://darcs.net/&quot;&gt;Darcs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.haskell.org/haskellwiki/Haskell_in_industry&quot;&gt;Entre outros...&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/4495220238994713602/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/08/programacao-funcional-pura-e-util.html#comment-form' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4495220238994713602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4495220238994713602'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/08/programacao-funcional-pura-e-util.html' title='Programação funcional pura e útil'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-2954802372988182398</id><published>2012-08-12T19:40:00.000-03:00</published><updated>2012-08-12T19:43:24.646-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Self"/><title type='text'>Criando um jogo de labirinto em Haskell</title><content type='html'>&lt;p&gt;Quando eu estava aprendendo a programar em C, eu fiz vários pequenos projetos para colocar meu conhecimento à prova.&lt;/p&gt;

&lt;p&gt;É muito bom olhar estes códigos antigos e perceber que aprendi muito nestes anos. Também é prazeroso ver que mesmo sem conhecer quase nada, consegui fazer muitas coisas divertidas.&lt;/p&gt;

&lt;p&gt;Uma das primeiras coisas que fiz em C, foi um jogo de labirinto para terminal do Windows. Fiquei inacreditavelmente feliz e me achando muito inteligente por conseguir fazer um jogo assim.&lt;/p&gt;

&lt;p&gt;Após algum tempo já programando, depois de conhecer a biblioteca SDL para criar jogos gráficos em C, o joguinho de labirinto chegou na sua terceira versão: &lt;a href=&quot;http://dudurox.codigolivre.org.br/&quot;&gt;DuDuRoX&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Como agora estou aprendendo Haskell e quero manter a tradição, irei criar um novo DuDuRoX nesta linguagem: &lt;a href=&quot;https://github.com/thiago-negri/DuDuHoX&quot;&gt;DuDuHoX&lt;/a&gt;. Notem a pequena variação no nome demonstrando minha imensa criatividade.&lt;/p&gt;

&lt;p&gt;Quem quiser acompanhar o progresso e fazer comentários, todo o código está disponível no GitHub (link no parágrafo acima).&lt;/p&gt;

&lt;p&gt;Bastantes coisas já estão funcionando, até já é possível jogar. Quem quiser experimentar, é só baixar a &lt;a href=&quot;http://hackage.haskell.org/platform//&quot;&gt;plataforma Haskell&lt;/a&gt;, fazer um clone do repositório, executar o comando &lt;tt&gt;cabal install&lt;/tt&gt; na pasta do jogo e ele estará disponível no seu terminal como &quot;DuDuHoX&quot;.&lt;/p&gt;

&lt;p&gt;Quem quiser dar uma olhada em códigos antigos, meus primeiros passos na programação estão postados no site Viva O Linux:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.vivaolinux.com.br/script/Jogo-da-Velha&quot;&gt;Jogo da Velha com GOTO&lt;/a&gt;: Primeiro código que coloco no site e o primeiro comentário foi muito encorajador: &quot;quem usa goto vai para o inferno&quot;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.vivaolinux.com.br/script/Jogo-da-Velha-(corrigido)&quot;&gt;Jogo da Velha sem GOTO&lt;/a&gt;: Quero ver alguém me mandar pro inferno agora... hahaha&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.vivaolinux.com.br/script/Jogo-da-Velha-com-IA-invencivel&quot;&gt;Jogo da Velha com I.A. invencível (console)&lt;/a&gt;: I.A. com força bruta.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.vivaolinux.com.br/script/Jogo-da-Velha-com-IA-invencivel-1&quot;&gt;Jogo da Velha com I.A. invencível (gráfico)&lt;/a&gt;: Primeiros contatos com SDL.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.vivaolinux.com.br/script/Agenda-Telefonica&quot;&gt;Agenda telefônica&lt;/a&gt;: Primeiros contatos com alocação dinâmica de memória.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;Alguns códigos mais &quot;avançados&quot;, acabei não compartilhando, porém tenho eles salvos no meu computador, se alguém se interessar posso compartilhar também:
&lt;ul&gt;
&lt;li&gt;MultiMines: Jogo de campo minado.&lt;/li&gt;
&lt;li&gt;HChess: Jogo de xadrez.&lt;/li&gt;
&lt;li&gt;ObjectDetector: Tratador de imagem para realçar as bordas de objetos.&lt;/li&gt;
&lt;li&gt;LConv: Conversor de &quot;linguagens&quot;, a partir de uma pseudo-linguagem, o usuário conseguia definir regras de criptografia e aplicar a textos.&lt;/li&gt;
&lt;li&gt;GATesting: Algoritmo genético para encontrar qualquer formula matemática que trouxesse como resultado o valor informado.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/2954802372988182398/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/08/criando-um-jogo-de-labirinto-em-haskell.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/2954802372988182398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/2954802372988182398'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/08/criando-um-jogo-de-labirinto-em-haskell.html' title='Criando um jogo de labirinto em Haskell'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-5450353537361654735</id><published>2012-07-14T13:53:00.000-03:00</published><updated>2012-07-14T13:53:03.882-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><title type='text'>O futuro da programação</title><content type='html'>&lt;em&gt;Postado originalmente em &lt;a href=&quot;http://www.senior.com.br/seniortec/o-futuro-da-programacao/&quot;&gt;Seniortec&lt;/a&gt;.&lt;/em&gt;

&lt;p&gt;
De acordo com o &lt;a href=&quot;http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html&quot; target=&quot;_blank&quot;&gt;índice TIOBE&lt;/a&gt;, em 1996 a linguagem de programação mais utilizada era C. Apenas dez anos mais tarde, em 2006, Java passou a ocupar o primeiro lugar. Por quê?
&lt;/p&gt;

&lt;p&gt;
Com o baixo custo e o fácil acesso a grandes quantidades de memória, a transição de C para Java foi um reflexo natural dos programadores em busca de maneiras mais fáceis de gerenciar este recurso que crescia de maneira muito rápida.
&lt;/p&gt;

&lt;p&gt;
Novamente estamos passando por uma quebra no paradigma computacional. A busca incansável por maior quantidade de ciclos é deixada de lado e da lugar à busca por paralelismo de operações e quantidade de núcleos de processamento.
&lt;/p&gt;

&lt;p&gt;
As linguagens atuais estão preparadas para estas mudanças? Java ainda é bom o suficiente para manter sua hegemonia? Perguntas como estas começam a aparecer em &lt;a href=&quot;http://research.microsoft.com/en-us/um/people/simonpj/papers/stm/beautiful.pdf&quot; target=&quot;_blank&quot;&gt;artigos&lt;/a&gt;, fóruns, &lt;a href=&quot;http://yow.eventer.com/events/1004/talks/1055&quot; target=&quot;_blank&quot;&gt;apresentações&lt;/a&gt; e &lt;a href=&quot;http://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hickey&quot; target=&quot;_blank&quot;&gt;congressos&lt;/a&gt; de nossa área.
&lt;/p&gt;

&lt;p&gt;
Juntamente com estas perguntas, começa a surgir um interesse súbito por linguagens funcionais, como mostra a mensagem deste mês do índice TIOBE:

&lt;blockquote&gt;
&quot;Last month we asked ourselves the question what language could become the next big new programming language. We suggested several candidates such as Scala, Erlang and Clojure. Clearly, the new thing was expected to come from the functional programming field. A functional language not explicitly mentioned was Haskell. And this month it was Haskell that jumped from #35 to #25. Looking at the TIOBE trend graph of Haskell (starting in 2003) it shows a constant rise, with peaks in 2006, 2010 and now in 2012. This certainly sounds promising.&quot;&lt;/blockquote&gt;
&lt;/p&gt;

&lt;p&gt;
Todo este interesse não é preciosismo de alguns estudiosos. O paradigma funcional puro soluciona de uma forma muito suave a maioria dos problemas encontrados quando tratamos de assuntos de importância fundamental para esta nova arquitetura computacional: concorrência, paralelismo e escalabilidade.
&lt;/p&gt;

&lt;p&gt;
A linguagem &lt;a href=&quot;http://www.haskell.org/haskellwiki/Haskell&quot; target=&quot;_blank&quot;&gt;Haskell&lt;/a&gt;, por exemplo, oferece:

&lt;ul&gt;
&lt;li&gt;
&lt;a href=&quot;http://www.cs.cmu.edu/~rwh/theses/okasaki.pdf&quot; target=&quot;_blank&quot;&gt;Estruturas de dados persistentes&lt;/a&gt;: seguras para ambientes concorrentes.
&lt;/li&gt;
&lt;li&gt;Operações que envolvem I/O são discriminadas de forma estática pelo sistema de tipos, o que gera uma cultura que preza pela pureza das bibliotecas. Garantindo escalabilidade de forma natural.&lt;/li&gt;
&lt;li&gt;
Operações que envolvem I/O são modeladas dentro de um conceito puro (Monad), permitindo composição, backtracking, computação não determinística, etc.
&lt;/li&gt;
&lt;li&gt;
Polimorfismo aberto permite uma consolidação de uma única biblioteca e conceito, mesmo que construído de forma incompleta no primeiro release.
&lt;/li&gt;
&lt;li&gt;
Avaliação preguiçosa possibilita um melhor gerenciamento do processamento e localidade em ambientes com escalabilidade.
&lt;/li&gt;
&lt;li&gt;
Multiparadigmas para concorrência e paralelismo: locks, memória transacional, mensageria, filas, tópicos, paralelismo grátis com balanceamento de carga automático e threads baratas.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;
É fácil notar que Java já percebeu sua deficiência e busca soluções com as liberações novas. Neste ano será feita a liberação do Java 8 com suporte a mecanismos funcionais (&lt;a href=&quot;http://openjdk.java.net/projects/lambda/&quot; target=&quot;_blank&quot;&gt;projeto Lambda&lt;/a&gt;). A Apache decidiu não esperar pela nova versão e já têm a biblioteca &lt;a href=&quot;http://commons.apache.org/functor/&quot; target=&quot;_blank&quot;&gt;Functor&lt;/a&gt; para tentar suprir estas necessidades. Assim também fez o Google com adições funcionais à biblioteca &lt;a href=&quot;http://code.google.com/p/guava-libraries/&quot; target=&quot;_blank&quot;&gt;Guava&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
Para a JVM já existem algumas linguagens tentando manter a plataforma aderente ao novo modelo de computação, por exemplo: &lt;a href=&quot;http://clojure.org/&quot; target=&quot;_blank&quot;&gt;Clojure&lt;/a&gt;, &lt;a href=&quot;http://groovy.codehaus.org/&quot; target=&quot;_blank&quot;&gt;Groovy&lt;/a&gt; e &lt;a href=&quot;http://www.scala-lang.org/&quot; target=&quot;_blank&quot;&gt;Scala&lt;/a&gt;.
&lt;/p&gt;

&lt;p&gt;
E você, está se preparando? Se você ainda não experimentou nenhuma linguagem funcional, te aconselho a ir logo conhecer o que este paradigma oferece. Seguindo o &lt;a href=&quot;http://www.paulgraham.com/avg.html&quot; target=&quot;_blank&quot;&gt;paradoxo de Blub&lt;/a&gt;, o ideal é começar com uma linguagem funcional pura, como Haskell, antes de avaliar linguagens como Scala que são híbridas e oferecem o paradigma tradicional.
&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/5450353537361654735/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/07/o-futuro-da-programacao.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/5450353537361654735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/5450353537361654735'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/07/o-futuro-da-programacao.html' title='O futuro da programação'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-4730975536375391159</id><published>2012-05-15T22:21:00.001-03:00</published><updated>2012-05-19T11:05:14.481-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Concurrent"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Network"/><title type='text'>Haskell Chat</title><content type='html'>&lt;p&gt;Este post apresentará um programa simples de bate-papo por Telnet na linguagem Haskell.&lt;/p&gt;&lt;p&gt;Este programa servirá como um servidor de bate-papo, bastando que as pessoas conectem nele para que possam trocar mensagens entre si. As pessoas não precisarão conhecer onde os outros participantes do bate-papo estão na rede, o servidor se encarregará de redirecionar cada mensagem. Ele atuará parecido com um roteador.&lt;/p&gt;&lt;p&gt;As informações trafegadas na rede serão texto puro, tanto do cliente quanto do servidor, sendo assim não é necessário um cliente especial para utilização do serviço de bate-papo. Os clientes poderão se conectar ao servidor utilizando o Telnet.&lt;/p&gt;&lt;h3&gt;Cabeçalho&lt;/h3&gt;&lt;p&gt;Nosso servidor de bate-papo será um módulo Haskell projetado para rodar como um aplicativo O nome deste módulo será Main:&lt;/p&gt;&lt;pre&gt;module Main(main) where&lt;/pre&gt;&lt;h4&gt;Imports&lt;/h4&gt;&lt;p&gt;Para que o bate-papo funcione e possamos enviar informações pela rede, precisamos de acesso à camada de rede do sistema operacional:&lt;/p&gt;&lt;pre&gt;import Network&lt;/pre&gt;&lt;p&gt;Além disto, precisaremos utilizar controles sobre efeitos colaterais para que possamos atender mais de um usuário ao mesmo tempo:&lt;/p&gt;&lt;pre&gt;import System.IO
import Control.Monad
import Control.Concurrent&lt;/pre&gt;&lt;p&gt;Para que nosso servidor não ﬁque apenas como um mediador de mensagens, faremos alguns tratamentos aos textos recebidos pelos usuários, por exemplo a utilização de alguns comandos, para isto precisaremos manipular Strings, que nada mais são do que listas de caracteres:&lt;/p&gt;&lt;pre&gt;import Data.List&lt;/pre&gt;&lt;h3&gt;Tipos&lt;/h3&gt;&lt;p&gt;Para controlar as informações que serão armazenadas e trafegadas. Iremos deﬁnir alguns tipos para nos ajudar a realizar este controle.&lt;/p&gt;&lt;h4&gt;Mensagens&lt;/h4&gt;&lt;p&gt;As mensagens trocadas entre usuários nada mais são do que Strings, então esta será nossa deﬁnição de mensagem:&lt;/p&gt;&lt;pre&gt;type Message = String&lt;/pre&gt;&lt;h4&gt;Usuários&lt;/h4&gt;&lt;p&gt;Será necessário dinstinguir quem mandou cada mensagem para saber para quem repassar cada mensagem, evitando que o próprio usuário receba sua própria mensagem e para que o bate-papo faça sentido.&lt;/p&gt;&lt;p&gt;Para isto precisaremos de um tipo que represente um usuário do bate-papo e que seja possível compará-lo com outros usuários. Este usuário será identiﬁcado por um nome e, para que seja possível distinguir usuários com o mesmo nome, por um identiﬁcador único.&lt;/p&gt;&lt;pre&gt;data ChatUser = ChatUser { 
    userId :: Int, 
    username :: String }
        deriving Eq&lt;/pre&gt;&lt;h4&gt;Mensagens de bate-papo&lt;/h4&gt;&lt;p&gt;A mensagem que recebemos pela rede é texto puro, mas precisamos associá-la ao usuário que fez o envio. Por isto temos um tipo que vincula uma mensagem a um usuário.&lt;/p&gt;&lt;pre&gt;data ChatMessage =
    ChatMessage { 
        messageFrom :: ChatUser, 
        messageText :: Message }&lt;/pre&gt;&lt;p&gt;E, para que seja possível notiﬁcar sobre a entrada ou saída de algum usuário, iremos declarar também outros dois tipo de mensagens do bate-papo: as mensagens de saída e as mensagens de entrada. As mensagens de saída poderão ter algum texto de despedida do usuário.&lt;/p&gt;&lt;pre&gt;| QuitMessage { 
        messageFrom :: ChatUser,
        messageText :: Message }
    | JoinMessage {
        messageFrom :: ChatUser }&lt;/pre&gt;&lt;h4&gt;Instâncias&lt;/h4&gt;&lt;p&gt;Como o servidor irá transmitir apenas texto puro, ao receber uma mensagem de um usuário e repassá-la a outro, será necessário exibir o usuário que enviou a mensagem de forma textual. Para isto declaramos uma instância de Show para nosso tipo ChatUser:&lt;/p&gt;&lt;pre&gt;instance Show ChatUser where
    show (ChatUser uid name) = 
        name ++ &quot;(&quot; ++ show uid ++ &quot;)&quot;&lt;/pre&gt;&lt;p&gt;Também será necessário trafegar os diferentes tipos de mensagens na forma de texto puro pela rede:&lt;/p&gt;&lt;pre&gt;instance Show ChatMessage where
    show (ChatMessage user message) =
        show user ++ &quot;: &quot; ++ message
    show (QuitMessage user message)
        | null message =
            &quot;! &quot; ++ show user ++ &quot; saiu.&quot;
        | otherwise =
            &quot;! &quot; ++ show user ++ &quot; saiu: &quot; ++ message
    show (JoinMessage user) =
        &quot;! &quot; ++ show user ++ &quot; entrou.&quot;&lt;/pre&gt;&lt;h3&gt;Main&lt;/h3&gt;&lt;h4&gt;Porta de comunicação&lt;/h4&gt;&lt;p&gt;Nosso bate-papo tem como principal objetivo funcionar via Telnet, então para isto faremos com que o servidor escute na porta 23, que é a porta padrão utilizada pelo Telnet.&lt;/p&gt;&lt;pre&gt;port :: PortID
port = PortNumber 23&lt;/pre&gt;&lt;h4&gt;Identificação dos usuários&lt;/h4&gt;&lt;p&gt;O identiﬁcador único de cada usuário será determinado pela ordem de chegada no servidor, i.e. o primeiro usuário terá o identiﬁcador 1, o segundo terá o identiﬁcador 2, e assim por diante.&lt;/p&gt;&lt;h4&gt;Suportando múltiplos usuários&lt;/h4&gt;&lt;p&gt;Para que nosso servidor não ﬁque travado lidando com apenas um usuário, iremos criar Threads para lidar com cada usuário de forma concorrente.&lt;/p&gt;&lt;p&gt;Ao receber uma mensagem de um usuário, a Thread responsável por aquela conexão terá que repassar esta informação às demais, para isto utilizaremos um canal de envio e recebimento de mensagens que será compartilhado entre todas as Threads.&lt;/p&gt;&lt;p&gt;Este canal funciona como um tópico, quando alguém escreve nele, todos que estiverem escutando irão receber a mensagem. Assim será possível que a Thread lidando com outro usuário receba esta mensagem através deste canal de comunicação e repasse ao cliente.&lt;/p&gt;&lt;p&gt;Porém, se utilizarmos apenas uma Thread por cliente, esta só teria a chance de ler deste canal de comunicação depois do cliente enviar alguma mensagem. Pois a Thread ficaria bloqueada esperando por uma escrita no Socket.&lt;/p&gt;&lt;p&gt;Para evitar este problema, serão utilizadas duas Threads por cliente: uma responsável pelo recebimento de mensagens e outra responsável pelo envio.&lt;/p&gt;&lt;h4&gt;Main&lt;/h4&gt;&lt;p&gt;Nosso servidor iniciará deﬁnindo o número inicial de conexões (userCount), criando um canal de comunicação (chan), abrindo um Socket para escutar na porta deﬁnida anteriormente (socket) e aguardando conexões.&lt;/p&gt;&lt;pre&gt;main :: IO ()
main = withSocketsDo $ do
         let userCount = 0
         chan &amp;lt;- newChan
         socket &amp;lt;- listenOn port
         handleConnections socket userCount chan&lt;/pre&gt;&lt;h4&gt;Aceitando conexões&lt;/h4&gt;&lt;p&gt;Ao receber uma conexão, precisamos manter o handle para realizar a leitura e escrita de mensagens. Desligamos o buffer para que as mensagens sejam trocadas em tempo real.&lt;/p&gt;&lt;p&gt;Após deﬁnida a conexão, precisamos liberar nosso servidor para que possa atender outros usuários, então será criado um processo concorrente que atenderá esta conexão. O identiﬁcador único do usuário será deﬁnido no processo principal para evitar que dois usuários tenham o mesmo identiﬁcador.&lt;/p&gt;&lt;pre&gt;handleConnections :: Socket -&amp;gt; 
                     Int -&amp;gt; 
                     Chan ChatMessage -&amp;gt;
                     IO ()
handleConnections socket userCount chan = do
    (socketHandle, _, _) &amp;lt;- accept socket
    hSetBuffering socketHandle NoBuffering
    let nextUser = (userCount + 1)
    _ &amp;lt;- forkIO $
      handleUserConnection chan socketHandle nextUser
    handleConnections socket nextUserNumber chan&lt;/pre&gt;&lt;h4&gt;Atendendo uma conexão&lt;/h4&gt;&lt;p&gt;Para iniciar o atendimento à uma conexão, precisamos inicialmente do nome do usuário.&lt;/p&gt;&lt;pre&gt;handleUserConnection :: Chan ChatMessage -&amp;gt;
                        Handle -&amp;gt;
                        Int -&amp;gt;
                        IO ()
handleUserConnection chan socketHandle userNumber = do
    name &amp;lt;- readUsername socketHandle&lt;/pre&gt;&lt;p&gt;Com o nome do usuário e o identificador único fornecido pelo processo principal do servidor, conseguimos definir o usuário desta conexão e enviar uma mensagem ao canal de comunicação informando que o usuário entrou no bate-papo.&lt;/p&gt;&lt;pre&gt;let thisUser = ChatUser userNumber name
    broadcast chan $ JoinMessage thisUser&lt;/pre&gt;&lt;p&gt;Para que este usuário comece a receber as mensagens do bate-papo, criamos uma Thread separada para efetuar a leitura do canal de comunicação:&lt;/p&gt;&lt;pre&gt;chanReader &amp;lt;- dupChan chan
    readerThread &amp;lt;- forkIO $
      startReader chanReader socketHandle thisUser&lt;/pre&gt;&lt;p&gt;Este processo irá efetuar a escrita do canal de comunicação a partir das mensagens recebidas pelo Socket do cliente. O resultado deste processo, será uma mensagem de saída do usuário, caso ele deixe alguma. Caso ele desconecte sem deixar nenhuma mensagem, a exceção será capturada e convertida em uma mensagem vazia de despedida do usuário.&lt;/p&gt;&lt;pre&gt;quitMessage &amp;lt;- (startSender chan 
                            socketHandle thisUser)
                            `catch` (\_ -&amp;gt; return &quot;&quot;)&lt;/pre&gt;&lt;p&gt;Com a mensagem de despedida em mãos, informamos os demais usuários que este deixou o bate-papo. Encerramos a Thread responsável por fazer a leitura do canal de comunicação e fechamos a conexão com o cliente:&lt;/p&gt;&lt;pre&gt;broadcast chan $ QuitMessage thisUser quitMessage
    killThread readerThread
    hClose socketHandle&lt;/pre&gt;&lt;h4&gt;Recebendo o nome do usuário&lt;/h4&gt;&lt;p&gt;Para receber o nome do usuário, apenas enviamos uma mensagem pedindo que ele informe seu nome e fazemos a leitura do Socket:&lt;/p&gt;&lt;pre&gt;readUsername :: Handle -&amp;gt; IO String
readUsername socketHandle = do
    hPutStr socketHandle &quot;Informe seu nome: &quot;
    readLine $ socketHandle&lt;/pre&gt;&lt;h4&gt;Recebendo mensagens do canal de comunicação&lt;/h4&gt;&lt;p&gt;O processo responsável por receber as mensagens do canal de comunicação só será encerrado com a desconexão do usuário, então ele sempre deve estar lendo do canal e publicando ao usuário. O próprio usuário irá enviar mensagens para o canal de comunicação, para evitar que ele receba mensagens dele mesmo, é aplicado um filtro para que só sejam exibidas mensagens de usuários diferentes dele.&lt;/p&gt;&lt;pre&gt;startReader :: Chan ChatMessage -&amp;gt;
               Handle -&amp;gt;
               ChatUser -&amp;gt;
               IO ()
startReader chanReader socketHandle thisUser =
    forever $ do
        message &amp;lt;- readChan chanReader
        when ((messageFrom message) /= thisUser) $
            display message socketHandle&lt;/pre&gt;&lt;h4&gt;Enviando mensagens ao canal de comunicação&lt;/h4&gt;&lt;p&gt;O processo responsável por enviar mensagens ao canal de comunicação deverá terminar de alguma forma. Seja por desconexão do usuário ou por uma mensagem de despedida do mesmo.&lt;/p&gt;&lt;p&gt;Para que o usuário saia do bate-papo, basta que ele envie uma mensagem iniciando com &lt;tt&gt;/quit&lt;/tt&gt; seguido de sua mensagem de despedida. As demais mensagens recebidas do usuário serão repassadas ao canal de comunicação e não encerrarão o processo.&lt;/p&gt;&lt;pre&gt;startSender :: Chan ChatMessage -&amp;gt;
               Handle -&amp;gt;
               ChatUser -&amp;gt;
               IO String
startSender chan socketHandle thisUser = do
    line &amp;lt;- readLine socketHandle
    if &quot;/quit&quot; `isPrefixOf` line
        then return . dropWhile (== &#39; &#39;) $ drop 5 line
        else do
             broadcast chan $
                 ChatMessage thisUser line
             startSender chan socketHandle thisUser&lt;/pre&gt;&lt;h3&gt;Utilitários&lt;/h3&gt;&lt;h4&gt;Notificando os processos responsáveis por cada usuário&lt;/h4&gt;&lt;p&gt;Para enviar uma mensagem a todos os usuários, basta realizar uma escrita no canal de comunicação.&lt;/p&gt;&lt;pre&gt;broadcast :: Chan ChatMessage -&amp;gt; ChatMessage -&amp;gt; IO ()
broadcast = writeChan&lt;/pre&gt;&lt;h4&gt;Enviando mensagens para um usuário&lt;/h4&gt;&lt;p&gt;Para enviar uma mensagem a um usuário, escrevemos a mensagem no Socket seguida de uma quebra de linha no formato Windows, para que a utilização via Telnet seja agradável.&lt;/p&gt;&lt;pre&gt;display :: ChatMessage -&amp;gt; Handle -&amp;gt; IO ()
display message socketHandle = do
    hPutStr socketHandle (show message ++ &quot;\r\n&quot;)
    hFlush socketHandle&lt;/pre&gt;&lt;h4&gt;Lendo mensagens de um usuário&lt;/h4&gt;&lt;p&gt;Para ler uma mensagem do usuário, lemos uma linha do Socket e removemos o retorno do carro, para que ﬁque apenas a mensagem escrita por ele.&lt;/p&gt;&lt;pre&gt;readLine :: Handle -&amp;gt; IO String
readLine = liftM (filter (/= &#39;\r&#39;)) . hGetLine&lt;/pre&gt;&lt;h3&gt;Código completo&lt;/h3&gt;&lt;p&gt;O código completo está disponível no GitHub com a descrição &lt;a href=&quot;https://gist.github.com/2706161&quot; target=&quot;_blank&quot;&gt;Sample telnet chat in Haskell&lt;/a&gt;.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/4730975536375391159/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/05/haskell-chat.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4730975536375391159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4730975536375391159'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/05/haskell-chat.html' title='Haskell Chat'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-83194771990800751</id><published>2012-04-03T22:07:00.000-03:00</published><updated>2012-05-17T20:41:34.514-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="Principles"/><title type='text'>Sobrevivente.run()</title><content type='html'>&lt;p&gt;
Como sobreviver sem repetição de código no &lt;a href=&quot;http://steve-yegge.blogspot.com.br/2006/03/execution-in-kingdom-of-nouns.html&quot; target=&quot;_blank&quot;&gt;reino dos substantivos&lt;/a&gt;?
&lt;/p&gt;

&lt;p&gt;
O que fazer quando encontramos código deste tipo:
&lt;/p&gt;

&lt;h4&gt;
A.java
&lt;/h4&gt;
&lt;pre&gt;
Button button = new Button(&quot;Limpar&quot;);
button.addActionListener(new ActionListener() {
  public void performAction() {
    if (foo) {
      askConfirmation();
      bar.clear();
    }
  }
});
&lt;/pre&gt;

&lt;h4&gt;
B.java
&lt;/h4&gt;
&lt;pre&gt;
Button button = new Button(&quot;Limpar&quot;);
  button.addActionListener(new ActionListener() {
    public void performAction() {
      if (bacon) {
        askConfirmation();
        eggs.clear();
      }
    }
});
&lt;/pre&gt;

&lt;h4&gt;
C.java
&lt;/h4&gt;
&lt;pre&gt;
Button button = new Button(&quot;Limpar&quot;);
button.addActionListener(new ActionListener() {
  public void performAction() {
    if (baz) {
      askConfirmation();
      spam.clear();
    }
  }
});
&lt;/pre&gt;

&lt;p&gt;
Meu jeito é criar um verbo disfarçado de substantivo que leva consigo a ação que eu quero:
&lt;/p&gt;

&lt;pre&gt;
interface MagicClearWord {
  boolean isDirty();
  void clear();
}
class MagicClearWordExecutor implements ActionListener {
  private final MagicClearWord e;
  MagicClearWordExecutor(MagicClearWord e) {
    this.e = e;
  }
  public void performAction() {
    if (e.isDirty()) {
      askConfirmation();
      e.clear();
    }
  }
}
&lt;/pre&gt;

&lt;p&gt;
E depois utilizar como se fosse um &quot;substantivo anônimo&quot; (&lt;strike&gt;#nonsense&lt;/strike&gt;):
&lt;/p&gt;

&lt;h4&gt;
A.java
&lt;/h4&gt;
&lt;pre&gt;
Button button = new Button(&quot;Limpar&quot;);
button.addActionListener(new MagicClearWordExecutor(
  new MagicClearWord() {
    public boolean isDirty() {
      return foo;
    }
    public void clear() {
      bar.clear();
    }
  })
);
&lt;/pre&gt;

&lt;h4&gt;
B.java
&lt;/h4&gt;
&lt;pre&gt;
Button button = new Button(&quot;Limpar&quot;);
button.addActionListener(new MagicClearWordExecutor(
  new MagicClearWord() {
    public boolean isDirty() {
      return bacon;
    }
    public void clear() {
      eggs.clear();
    }
  })
);
&lt;/pre&gt;

&lt;h4&gt;
C.java
&lt;/h4&gt;
&lt;pre&gt;
Button button = new Button(&quot;Limpar&quot;);
button.addActionListener(new MagicClearWordExecutor(
  new MagicClearWord() {
    public boolean isDirty() {
      return baz;
    }
    public void clear() {
      spam.clear();
    }
  })
);
&lt;/pre&gt;

&lt;p&gt;
Ainda assim os substantivos e seus amigos gulosos comem seu tempo e seu espaço em disco com tanta palavra vazia. Parece que estamos presos mesmo.
&lt;/p&gt;

&lt;p&gt;
&lt;em&gt;Oh God, why?&lt;/em&gt;
&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/83194771990800751/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/04/sobreviventerun.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/83194771990800751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/83194771990800751'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/04/sobreviventerun.html' title='Sobrevivente.run()'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-4333760035166793295</id><published>2012-03-13T21:12:00.000-03:00</published><updated>2012-05-19T10:35:37.380-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Paralelismo"/><title type='text'>Almoço grátis de paralelismo em Haskell</title><content type='html'>&lt;p&gt;Hoje irei exagerar um pouco e verificar o quão grátis é o almoço de paralelismo servido pelo ecossistema Haskell. &lt;/p&gt;&lt;p&gt;Para fins de estudo, irei criar um algoritmo bastante simples e ideal para utilizar paralelismo: duas funções distintas com cargas de trabalho parecidas que não possuem dependência entre si. &lt;/p&gt;&lt;p&gt;Uma destas funções calculará qual é o menor valor de uma lista e a outra calculará o maior valor. Sendo assim, as duas precisarão consultar todos os elementos da lista e fazer a mesma quantidade de comparações. Os dois valores serão somados e impressos ao usuário: &lt;/p&gt;&lt;pre&gt;module Main where

import Data.List (foldl1&#39;)

main = print result
  where result = a + b
        a = foldl1&#39; min list
        b = foldl1&#39; max list
        list = [1..19999999]
&lt;/pre&gt;&lt;p&gt;Compilei o código com &lt;tt&gt;ghc -rtsopts&lt;/tt&gt; e executei ele com &lt;tt&gt;+RTS -s&lt;/tt&gt; para verificar como ele se comportou: &lt;/p&gt;&lt;pre&gt;20000000
     803,172,764 bytes allocated in the heap
     860,135,516 bytes copied during GC
     233,464,876 bytes maximum residency (9 sample(s))
      30,086,296 bytes maximum slop
             483 MB total memory in use (0 MB lost due to fragmentation)

  Generation 0:  1523 collections,     0 parallel,  0.80s,  0.97s elapsed
  Generation 1:     9 collections,     0 parallel,  0.92s,  1.30s elapsed

  INIT  time    0.00s  (  0.00s elapsed)
  MUT   time    0.90s  (  0.98s elapsed)
  GC    time    1.72s  (  2.27s elapsed)
  EXIT  time    0.00s  (  0.00s elapsed)
  Total time    2.62s  (  3.25s elapsed)

  %GC time      65.5%  (69.8% elapsed)

  Alloc rate    887,674,003 bytes per MUT second

  Productivity  34.5% of total user, 27.8% of total elapsed
&lt;/pre&gt;&lt;p&gt;Esta saída significa que o programa levou 3,25 segundos para executar e ocupou &lt;strong&gt;483 MB&lt;/strong&gt; de memória. Um valor um tanto absurdo para algo que deveria ser simples e rápido em Haskell. O problema do algoritmo é que durante o cálculo do valor mínimo, o coletor de lixo não coleta os itens já passados pois o cálculo do valor máximo possui referência para o inicio da lista. &lt;/p&gt;&lt;p&gt;Para resolver o problema é possível gerar listas diferentes, uma para cada cálculo na forma de uma função constante: &lt;/p&gt;&lt;pre&gt;module Main where

import Data.List (foldl1&#39;)

main = print result
  where result = a + b
        a = foldl1&#39; min $ list ()
        b = foldl1&#39; max $ list ()
        list _ = [1..19999999]
&lt;/pre&gt;&lt;p&gt;Esta versão termina em 1,6 segundos e consome apenas 1 MB de memória. &lt;em&gt;Atenção: se o programa for compilado com &lt;tt&gt;-O2&lt;/tt&gt;, o GHC irá otimizar a declaração de função deixando a referencia para a lista no lugar e o programa continuará a usar os 483 MB de memória.&lt;/em&gt; &lt;/p&gt;&lt;p&gt;Este é o momento de refatorar o algoritmo para evitar duplicidade de código. Para um programa deste tamanho, acredito que normalmente não é feito, porém para que a transição para a utilização de paralelismo fique mais suave, é um passo necessário: &lt;/p&gt;&lt;pre&gt;module Main where

import Data.List (foldl1&#39;)
import Control.Arrow ((&amp;&amp;&amp;))

main = print result
  where result = (+) `uncurry` constMinMax list
        list _ = [1..19999999]

(.:) f g a b = f a (g b)
constApp = ($ ())
constMinMax = constMinList &amp;&amp;&amp; constMaxList
constFold = foldl1&#39; .: constApp
constMinList = constFold min
constMaxList = constFold max
&lt;/pre&gt;&lt;p&gt;O resultado e o tempo do algoritmo continuam os mesmos. Agora como tornamos este algoritmo preparado para rodar em paralelo? &lt;em&gt;Simples&lt;/em&gt;: trocamos a utilização da função &lt;tt&gt;uncurry&lt;/tt&gt; por &lt;tt&gt;parUncurry&lt;/tt&gt;: &lt;/p&gt;&lt;pre&gt;module Main where

import Data.List (foldl1&#39;)
import Control.Arrow ((&amp;&amp;&amp;))
import Control.Parallel (par, pseq)

main = print result
  where result = (+) `parUncurry` constMinMax list
        list _ = [1..19999999]

(.:) f g a b = f a (g b)
constApp = ($ ())
constMinMax = constMinList &amp;&amp;&amp; constMaxList
constFold = foldl1&#39; .: constApp
constMinList = constFold min
constMaxList = constFold max
parUncurry f (a, b) = a `par` b `pseq` f a b
&lt;/pre&gt;&lt;p&gt;Adicionamos à compilação do programa o argumento &lt;tt&gt;-threaded&lt;/tt&gt; e para executar utilizamos &lt;tt&gt;+RTS -s -N2&lt;/tt&gt; para que o programa utilize duas threads do sistema operacional. O resultado: &lt;/p&gt;&lt;pre&gt;20000000
   1,606,300,044 bytes allocated in the heap
          74,364 bytes copied during GC
          28,352 bytes maximum residency (1 sample(s))
          24,896 bytes maximum slop
               2 MB total memory in use (0 MB lost due to fragmentation)

  Generation 0:  1566 collections,  1565 parallel,  0.06s,  0.02s elapsed
  Generation 1:     1 collections,     1 parallel,  0.00s,  0.00s elapsed

  Parallel GC work balance: 1.79 (15355 / 8588, ideal 2)

                        MUT time (elapsed)       GC time  (elapsed)
  Task  0 (worker) :    0.00s    (  0.81s)       0.00s    (  0.00s)
  Task  1 (worker) :    0.75s    (  0.81s)       0.06s    (  0.01s)
  Task  2 (bound)  :    0.83s    (  0.81s)       0.00s    (  0.00s)
  Task  3 (worker) :    0.00s    (  0.00s)       0.00s    (  0.00s)

  SPARKS: 1 (1 converted, 0 pruned)

  INIT  time    0.00s  (  0.00s elapsed)
  MUT   time    1.58s  (  0.81s elapsed)
  GC    time    0.06s  (  0.02s elapsed)
  EXIT  time    0.00s  (  0.00s elapsed)
  Total time    1.64s  (  0.83s elapsed)

  %GC time       3.8%  (1.9% elapsed)

  Alloc rate    1,019,478,198 bytes per MUT second

  Productivity  96.2% of total user, 189.6% of total elapsed

gc_alloc_block_sync: 78
whitehole_spin: 0
gen[0].sync_large_objects: 0
gen[1].sync_large_objects: 0
&lt;/pre&gt;&lt;p&gt;Conseguimos reduzir o tempo de execução para 0,83 segundos: a metade do tempo da versão sequencial. Tudo isto com a mudança de uma chamada (partindo do principio de que o programa está bem escrito). &lt;/p&gt;&lt;p&gt;Qual seria o tamanho da mudança necessária na linguagem que você utiliza hoje para ter este mesmo ganho de desempenho? &lt;/p&gt;&lt;p&gt;Apesar do exemplo deste post ser levemente exagerado, este tipo de ganho com apenas uma mudança é algo real em Haskell. A apresentação &lt;a href=&quot;http://yow.eventer.com/events/1004/talks/1055&quot; target=&quot;_blank&quot;&gt;The Future is Parallel, and the Future of Parallel is Declarative&lt;/a&gt; feita por &lt;a href=&quot;http://research.microsoft.com/en-us/people/simonpj/&quot; target=&quot;_blank&quot;&gt;Simon Peyton Jones&lt;/a&gt; dá exemplos de aplicações que se beneficiaram deste paralelismo grátis. &lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/4333760035166793295/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/03/almoco-gratis-de-paralelismo-em-haskell.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4333760035166793295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/4333760035166793295'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/03/almoco-gratis-de-paralelismo-em-haskell.html' title='Almoço grátis de paralelismo em Haskell'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-5525078030705262795</id><published>2012-03-02T22:18:00.000-03:00</published><updated>2012-05-17T20:57:04.053-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Concatenative"/><category scheme="http://www.blogger.com/atom/ns#" term="Conventions"/><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Principles"/><category scheme="http://www.blogger.com/atom/ns#" term="Programming"/><category scheme="http://www.blogger.com/atom/ns#" term="Type-safety"/><title type='text'>Convenções e obrigações</title><content type='html'>&lt;p&gt;
&lt;em&gt;Aviso.&lt;/em&gt; Este post apenas levanta algumas questões sem oferecer nenhuma resposta, apenas sugestões.
&lt;/p&gt;

&lt;p&gt;
Na programação orientada a objetos, os principios &lt;a href=&quot;http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod&quot; target=&quot;_blank&quot;&gt;SOLID&lt;/a&gt; são bem difundidos. São cinco principios reunindo boas práticas em forma de convenções que tornam a programação orientada a objetos melhor, porém não são exigências do paradigma, &lt;i&gt;i.e.&lt;/i&gt; os principios melhoram a vida e deveriam ser aplicados, mas não existe maneira de assegurar que eles foram. São eles:
&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;b&gt;S&lt;/b&gt;ingle responsibility principle (SRP): Cada classe deve ter apenas uma responsabilidade e apenas uma razão para que ela sofra mudanças.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;O&lt;/b&gt;pen/closed principle (OCP): As classes devem estar abertas para extensão e fechadas para modificações. Funcionalidades são adicionadas ao sistema através de código novo e não através de modificações de código existente.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;L&lt;/b&gt;iskov substitution principle (LSP): Uma classe só pode ser subclasse de outra se o funcionamento do código que utilize esta hierarquia não for alterado ao substituir uma pela outra. &amp;nbsp;Isto é, se uma função depende de uma coleção de objetos, não importa se o argumento é uma lista ou uma árvore, o resultado deve ser o mesmo.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;I&lt;/b&gt;nterface segregation principle (ISP): Contratos devem ser resumidos, funções devem depender de contratos que reflitam apenas sua necessidade e nada mais. &amp;nbsp;Vários contratos pequenos são melhores do que um alguns contratos grandes.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;D&lt;/b&gt;ependency inversion principle (DIP): Métodos devem depender de contratos e não de tipos concretos.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;
Além destes existe um principio que vale para todos os paradigmas: &quot;&lt;a href=&quot;http://en.wikipedia.org/wiki/Don%27t_repeat_yourself&quot; target=&quot;_blank&quot;&gt;Don&#39;t repeat yourself&lt;/a&gt;&quot; (DRY). &amp;nbsp;O nome deste é bem intuitivo: não repita código.&lt;br /&gt;
&lt;/p&gt;

&lt;p&gt;
Apesar de todas estas convenções serem boas, todas elas possuem a mesma falha: são convenções. Convenções são facilmente esquecidas, postergadas e até mesmo ignoradas. Nem todos os programadores possuem o mesmo nível de apreço pelo código produzido. O respeito a cada uma das convenções é medido de forma qualitativa e não quantitativa. Não existe fornecimento de segurança apenas utilizando convenções.
&lt;/p&gt;

&lt;p&gt;
Esta falta de segurança resulta em &lt;a href=&quot;http://martinfowler.com/bliki/TechnicalDebt.html&quot; target=&quot;_blank&quot;&gt;dividas técnicas&lt;/a&gt; para as bases de código. O sistema inteiro vira um espagueti, quanto mais o código é trabalhado, mais enrolado ele fica.
&lt;/p&gt;

&lt;p&gt;
Assim como utilizamos equipamentos de segurança para garantir a integridade de algum objeto ou entidade, por que não asseguramos a integridade de nossas bases de código? Fábricas de software asseguram a integridade do ambiente de trabalho utilizando catracas, cancelas, guaritas, etc. Mas utilizam o quê para assegurar a integridade do seu produto (código)? Sistemas de controle de versão apenas garantem a versão atual do seu sistema caso uma cagada colossal aconteça em uma versão futura.
&lt;/p&gt;

&lt;p&gt;
&lt;a href=&quot;http://www.infoq.com/news/2012/02/tech-debt-361&quot; target=&quot;_blank&quot;&gt;Dividas técnicas custam caro&lt;/a&gt; no fechamento das contas: quanto mais espagueti o código está, mais tempo e empenho serão gastos para novas funcionalidades e correções. Então por quê não previnimos isto de alguma forma? Como poderíamos prevenir?
&lt;/p&gt;

&lt;p&gt;
Recentemente li o artigo &lt;a href=&quot;http://evincarofautumn.blogspot.com/2012/02/why-concatenative-programming-matters.html&quot; target=&quot;_blank&quot;&gt;Why Concatenative Programming Matters&lt;/a&gt; de Jon Purdy e notei a ligação direta entre o paradigma de programação concatenativa e o principio DRY. Pelo fato da programação concatenativa ser livre de contexto, é possível eliminar todo código duplicado com um simples find/replace. Sendo assim, este é o paradigma de programação ideal para que o principio DRY seja aplicado. É possível que o próprio compilador dê sugestões para eliminar ou obrigue a eliminação de repetições no código, garantindo um código melhor para todos.
&lt;/p&gt;

&lt;p&gt;
Com a leitura do artigo de Jon Purdy, comecei a ponderar sobre as questões lançadas neste post e percebi que as &lt;a href=&quot;http://www.haskell.org/tutorial/classes.html&quot; target=&quot;_blank&quot;&gt;type classes da linguagem Haskell&lt;/a&gt; se encaixam como uma solução brilhante para OCP. Elas permitem que contratos sejam definidos de forma aberta, aceitando extensões de forma fácil e com garantia em tempo de compilação (nada de monkey patching).
&lt;/p&gt;

&lt;p&gt;
Se olharmos as type classes, podemos perceber que elas sempre abstraem um único tipo de dado e suas funções. Garantindo coesão de código e o cumprimento da convenção ISP, pois cada type class se restringe a um tipo de operação.
&lt;/p&gt;

&lt;p&gt;
A linguagem Haskell possui inferencia de tipos, o que permite que o compilador produza assinaturas dos tipos mais abstratos possíveis, garantindo o cumprimento da DIP de forma automática.
&lt;/p&gt;

&lt;p&gt;
Sobre a LSP, acredito que linguagens como &lt;a href=&quot;http://coq.inria.fr/&quot; target=&quot;_blank&quot;&gt;Coq&lt;/a&gt; podem garantir o cumprimento desta convenção. Porém, não me aventurei muito sobre este tipo de linguagem &lt;em&gt;ainda&lt;/em&gt;, então não posso garantir. Mas vale a pena dar uma verificada no assunto.
&lt;/p&gt;

&lt;p&gt;
&lt;strong&gt;tl;dr&lt;/strong&gt; Convenções podem ser checadas de forma estática:
&lt;ul&gt;
&lt;li&gt;DRY: Concatenative programming.&lt;/li&gt;
&lt;li&gt;OCP &amp;amp; ISP: Haskell type classes.&lt;/li&gt;
&lt;li&gt;DIP: Haskell type inference.&lt;/li&gt;
&lt;li&gt;LSP: Coq.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/5525078030705262795/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/03/convencoes-e-obrigacoes.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/5525078030705262795'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/5525078030705262795'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/03/convencoes-e-obrigacoes.html' title='Convenções e obrigações'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-1672494991809268327</id><published>2012-02-29T21:01:00.000-03:00</published><updated>2012-05-17T21:05:41.121-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Haskell"/><category scheme="http://www.blogger.com/atom/ns#" term="Java"/><category scheme="http://www.blogger.com/atom/ns#" term="TDD"/><title type='text'>Levando o conhecimento de Haskell para Java</title><content type='html'>&lt;p&gt;
Resgatando o blog e trocando um pouco o tema para falar sobre programação.
&lt;/p&gt;
&lt;p&gt;
Existem muitos tutoriais sobre orientação a objetos e desenvolvimento orientado por testes (TDD) pela internet. Grande parte se utiliza de um exemplo simples: uma calculadora.
&lt;/p&gt;
&lt;p&gt;
Para desenvolver a calculadora, demonstram o poder do polimorfismo construindo abstrações sobre operações binárias e a utilidade do TDD através de uma programação incremental.
&lt;/p&gt;
&lt;p&gt;
Neste post tentarei extender este exemplo de calculadora, porém focando em outro ponto do problema: a interação com o usuário.
&lt;/p&gt;
&lt;p&gt;
Os exemplos estão na &lt;a href=&quot;http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html&quot; target=&quot;_blank&quot;&gt;linguagem orientada a objetos mais utilizada do planeta: Java&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Programa:&lt;/b&gt; Calculadora para terminal.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Requisito:&lt;/b&gt; Ler cálculos no formato &quot;&lt;tt&gt;2 + 2&lt;/tt&gt;&quot; e informar o usuário sobre o resultado do cálculo: &quot;&lt;tt&gt;4&lt;/tt&gt;&quot;.
&lt;li&gt;&lt;b&gt;Problema:&lt;/b&gt; Como testar a interação com o usuário?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Por ser um programa feito para rodar em terminal, utilizaremos &lt;tt&gt;System.in&lt;/tt&gt; e &lt;tt&gt;System.out&lt;/tt&gt; para interagir com o usuário. Porém, se amarrarmos o algoritmo de cálculo diretamente à estes recursos, ficará muito difícil e não-produtivo criar e manter testes para este sistema.
&lt;/p&gt;
&lt;p&gt;
Algo importante que aprendi com a linguagem &lt;a href=&quot;http://www.haskell.org/&quot; target=&quot;_blank&quot;&gt;Haskell&lt;/a&gt; é a de separar o código em áreas puras e impuras. Uma área de código pura é um conjunto de funções que dependem apenas de seus argumentos e só produzem um resultado, &lt;i&gt;i.e.&lt;/i&gt; funções que não alteram nenhuma informação e dependem apenas de seus argumentos. A área de código impura é aquela composta pelas demais funções que dependem de I/O, alterações na memória, banco de dados, etc.
&lt;/p&gt;
&lt;p&gt;
A linguagem Haskell faz um trabalho incrível para assegurar que esta distinção seja mantida pelos programadores através do seu sistema de tipos que diferenciam funções puras e funções impuras. Nas linguagens tradicionais, como Java, não existe esta distinção: todo pedaço de código tem a liberdade de ser impuro. Desta forma, os programadores devem sempre prestar atenção para o que cada parte do código está executando.
&lt;/p&gt;
&lt;p&gt;
Para separar a parte &quot;pura&quot; e &quot;impura&quot; da nossa calculadora, precisamos primeiro identificar quais funções pertencem a cada parte.
&lt;/p&gt;
&lt;p&gt;
Toda a parte de código que realiza o cálculo pode se encaixar perfeitamente na área de código pura, afinal são apenas representações para funções matemáticas, que são puras por definição.
&lt;/p&gt;
&lt;p&gt;
Por outro lado, a parte que faz a interação com o usuário é impura, pois altera informações que vão além de seu alcance em termos de código: imprime caracteres no terminal, e recebe informações que vão além de seus argumentos: teclas pressionadas pelo usuário.
&lt;/p&gt;
&lt;p&gt;
A parte impura do código é muito difícil de ser testada e por isto deve ser mantida reduzida e de forma controlada, que faça apenas o necessário para o funcionamento. No caso da calculadora para terminal, a parte impura é apenas interação com o usuário no seguinte formato:
&lt;ol&gt;
&lt;li&gt;Usuário digita um texto.&lt;/li&gt;
&lt;li&gt;Programa responde com outro texto.&lt;/li&gt;
&lt;li&gt;Volte para 1.&lt;/li&gt;
&lt;/ol&gt;
&lt;/p&gt;
&lt;p&gt;
Esta interação é abstrata o suficiente para ser totalmente separada da parte que realiza o processamento. Por exemplo, o seguinte código encapsularia toda a parte impura da nossa calculadora:
&lt;/p&gt;
&lt;pre&gt;
public interface Programa {
  String processar(String entrada);
}

public class InteracaoTerminal {
  public void interagir(Programa programa) {
    Scanner s = new Scanner(System.in);
    while (true) {
      String entrada = s.nextLine();
      String saida = programa.processar(entrada);
      System.out.println(saida);
    }
  }
}
&lt;/pre&gt;
&lt;p&gt;
Desta forma a interface &lt;tt&gt;Programa&lt;/tt&gt; é 100% testavel, por exemplo:
&lt;/p&gt;
&lt;pre&gt;
assertEquals(&quot;4&quot;, programa.processar(&quot;2 + 2&quot;));
assertEquals(&quot;6&quot;, programa.processar(&quot;2 + 2 * 2&quot;));
&lt;/pre&gt;
&lt;p&gt;
Além de testavel, a implementação da nossa calculadora apenas manipulará &lt;tt&gt;String&lt;/tt&gt;s, sem dependência direta com o &lt;tt&gt;System&lt;/tt&gt;. Isto significa que poderemos aproveitar o código em outros lugares, quem sabe utilizar o mesmo código para duas interfaces diferentes: uma interage com o usuário através de um terminal e outra através de um aplicativo gráfico.
&lt;/p&gt;
&lt;p&gt;
A abstração colocada como exemplo tem uma limitação: cada interação com o usuário é feita através de uma linha de entrada e uma linha de saída. Deixo como exercício aprimorar esta abstração para que seja possível ter mais de uma linha de entrada e mais de uma linha como saída de uma única interação. Se você conhece Haskell, poderá se basear na função &lt;a href=&quot;http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:interact&quot; target=&quot;_blank&quot;&gt;interact&lt;/a&gt;, e se você não conhece: &lt;a href=&quot;http://haskell.tailorfontela.com.br/chapters&quot; target=&quot;_blank&quot;&gt;Aprender Haskell será um grande bem para você!&lt;/a&gt;
&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/1672494991809268327/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2012/02/resgatando-o-blog-e-trocando-um-pouco-o.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/1672494991809268327'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/1672494991809268327'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2012/02/resgatando-o-blog-e-trocando-um-pouco-o.html' title='Levando o conhecimento de Haskell para Java'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-7245369275744553875</id><published>2009-02-11T11:25:00.001-02:00</published><updated>2012-05-19T10:39:38.944-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Filosofia"/><title type='text'>Mendigos...</title><content type='html'>Por que o mendigo é mendigo?&lt;br /&gt;
Desde quanto ele é mendigo?&lt;br /&gt;
Tornou-se mendigo ou sempre foi?&lt;br /&gt;
De onde vem o mendigo?&lt;br /&gt;
Onde estão seus pais?&lt;br /&gt;
Escolheu ser mendigo?&lt;br /&gt;
É bom ser mendigo?&lt;br /&gt;
Mendigo tem mais liberdade que nós?&lt;br /&gt;
Até quanto posso justificar minha falta de vida pela aquisição de bens materiais?&lt;br /&gt;
Quem vive mais, eu ou o mendigo?&lt;br /&gt;
Será que não sou também um mendigo?&lt;br /&gt;
Por que eu não sou um mendigo?&lt;br /&gt;
Eu escolhi não ser um mendigo?&lt;br /&gt;
Escolheram por mim?&lt;br /&gt;
O que me torna diferente do mendigo?&lt;br /&gt;
Eu precisei me esforçar para não ser um mendigo?&lt;br /&gt;
Quem sou eu para julgar o que não vivi?&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/7245369275744553875/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2009/02/mendigos.html#comment-form' title='1 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/7245369275744553875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/7245369275744553875'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2009/02/mendigos.html' title='Mendigos...'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4824498855019132836.post-3466426947340079236</id><published>2009-02-01T19:56:00.000-02:00</published><updated>2012-05-19T10:40:21.147-03:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Filosofia"/><title type='text'>Equilibrio</title><content type='html'>Se 1 ganha, 1 perde.&lt;br /&gt;
Se 2 ganham, 2 perdem.&lt;br /&gt;
Se tudo ganha, tudo perde.&lt;br /&gt;
Se nada ganha, nada perde.&lt;br /&gt;
Quem não ganha, não faz outro perder.&lt;br /&gt;
Quem perde, faz outro ganhar.&lt;br /&gt;
&lt;br /&gt;
Ganhar, ganhar, ganhar, ganhar...&lt;br /&gt;
Fazer perder, fazer perder, fazer perder, fazer perder...&lt;br /&gt;
&lt;br /&gt;
O que você quer?</content><link rel='replies' type='application/atom+xml' href='http://eu-hunz.blogspot.com/feeds/3466426947340079236/comments/default' title='Postar comentários'/><link rel='replies' type='text/html' href='http://eu-hunz.blogspot.com/2009/02/equilibrio.html#comment-form' title='0 Comentários'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/3466426947340079236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4824498855019132836/posts/default/3466426947340079236'/><link rel='alternate' type='text/html' href='http://eu-hunz.blogspot.com/2009/02/equilibrio.html' title='Equilibrio'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/00272477003241969410</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>