<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Superfície Reflexiva &#187; Desenvolvimento</title>
	<atom:link href="http://logbr.reflectivesurface.com/categoria/desenvolvimento/feed/" rel="self" type="application/rss+xml" />
	<link>http://logbr.reflectivesurface.com</link>
	<description>Ainda movido por uma contradição em termos</description>
	<lastBuildDate>Sun, 17 Apr 2011 20:43:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Sobre jedis, ninjas e samurais</title>
		<link>http://logbr.reflectivesurface.com/2011/01/08/sobre-jedis-ninjas-e-samurais/</link>
		<comments>http://logbr.reflectivesurface.com/2011/01/08/sobre-jedis-ninjas-e-samurais/#comments</comments>
		<pubDate>Sat, 08 Jan 2011 21:14:22 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Coisas de Geek]]></category>
		<category><![CDATA[Cultura Internet]]></category>
		<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[Tecnologia]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/?p=1505</guid>
		<description><![CDATA[Geeks de todos os tipos adoram se colocarem como os equivalentes tecnológicos de alguma sociedade guerreira&#8211;real ou imaginada&#8211;que exiba uma quantidade excessiva de coolness no dia-a-dia. Eu não posso culpar ninguém que faz isso porque eu também já fiz a mesma coisa muitas vezes. É claro, eu nunca gostei tanto de Star Wars. Sendo um [...]]]></description>
			<content:encoded><![CDATA[<p><span class="foreign-word">Geeks</span> de todos os tipos adoram se colocarem como os equivalentes tecnológicos de alguma sociedade guerreira&#8211;real ou imaginada&#8211;que exiba uma quantidade excessiva de <span class="foreign-word">coolness</span> no dia-a-dia. Eu não posso culpar ninguém que faz isso porque eu também já fiz a mesma coisa muitas vezes.</p>

<p>É claro, eu nunca gostei tanto de Star Wars. Sendo um fã de Star Trek, eu sempre considerei Star Wars como algo que você superava quando crescia&#8211;bom para crianças, mas não para muito além disso (por favor, sem ameaças de morte, estou brincando&#8211;bem, nem tanto assim). Star Wars é fantasia e Star Trek é ciência. Claro, os Jedi são muito mais legais e eu preferiria andar com um sabre de luz do que com um <span class="foreign-word">phaser</span> mas me dê um torpedo quântico qualquer dia sobre qualquer arma do Império ou da República.</p>

<p>E há sempre os samurais&#8211;aquela velha escola, valorosa, sempre envolvida em negócios por conta de honra, muitas vezes sem qualquer esperança de sucesso. De <a href="http://www.imdb.com/title/tt0047478/">Seven Samurai</a> a <a href="http://www.imdb.com/title/tt0325710/">The Last Samurai</a>&#8211;e não dá para esquecer os livros do <a href="http://en.wikipedia.org/wiki/Musashi_(novel)">Eiji Yoshikawa</a>&#8211;nós ocidentais sempre admiramos a forma como esses guerreiros japoneses se conduziam, considerando o seu <a href="http://en.wikipedia.org/wiki/Bushido">Caminho do Guerreiro</a> como algo a aspirar.</p>

<p>Finalmente, há também os ninjas ou <span class="foreign-word">shinobi</span>. Não muito populares hoje em dia, mas houve um tempo em que eram a febre entre a população mais jovem. Como os samurais, a <a href="http://en.wikipedia.org/wiki/Ninjutsu">arte</a> deles também era baseada em princípios de honra e dever&#8211;embora, no seu auge, eles fosse mais equivalentes a guerrilhas ou equipes <span class="foreign-word">Black Ops</span> do que o modelo mais <span class="foreign-word">Special Forces</span> dos samurais.</p>

<p>Mas uma coisa que todas ordens tem em comum é que elas eram bem monásticas, baseadas em códigos estritos sobre como proceder, treinamentos estritos ao longo dos anos e especialmente, disciplina&#8211;em muitos casos, com o peso da honra coibindo qualquer relação além da com os companheiros de armas.</p>

<p>Como <span class="foreign-word">geeks</span> geralmente gostamos de nos comparar essas ordens porque elas são, bem, fascinantes, e sempre estavam fazendo coisas além no normal, com seus procedimentos arcanos para lidar com situações acima do que uma pessoa normal poderia encontrar. </p>

<p>Mas há algo que é sempre esquecido sobre essas ordens&#8211;como mencionado acima, elas eram primariamente e acima de tudo sobre disciplina; sobre um modo de vida ordenado que permitia com que a pessoa se concentrasse no que realmente importava. Tanto o treinamento histórico e real dos samurais e <span class="foreign-word">shinobi</span> quanto o imaginado, inspirado pelos anteriores, dos Jedi exigia um compromisso com a disciplina que supera qualquer outra coisa que a pessoa precisaria fazer no curso de sua existência como membro dessas ordens. E, acima de tudo, requeria compromissos entre o possível e desejado e o necessário.</p>

<p>O que me traz ao meu ponto.</p>

<p>Nos últimos quatro ou cinco anos, eu fui parte de quase dez times diferentes. Já vi equipes sucederem a falharam, se recuperaram e continuarem, se unirem e se tornaram grandes, acabarem e seguir com suas vidas. Em resumo, fui parte de um número enorme de situações em que pude participar ou observar como times interagem e fazem as coisas acontecerem.</p>

<p>E em todos esses anos, uma das coisas mais importantes que separou os times ruins ou medianos dos grandes times foi a disciplina, que geralmente a parte mais desprezada nos exemplos que os fãs desses grupos tentam emular quando escolhem seus heróis.</p>

<p>É um tanto irônico que pessoas professem gostar tanto de metodologias ágeis porque estas criam ordem do caos através de times auto-gerenciáveis&#8211;times que não precisam de muita direção para fazer e acontecer, times que não precisam ser monitorados continuamente para garantir que estão indo na direção certa&#8211;esqueçam de que gerar ordem do caos exige disciplina.</p>

<p>A verdade é que agilidade em times só acontecem naqueles que são disciplinados e que entendem o que se ganha e o que se perde quando um projeto tem que ser cumprido. Sim, agilidade tem tudo a ver com encarar mudanças mas isso só significa que você tem que conseguir trabalhar muito bem com seus pares e com a organização como tudo&#8211;entendendo o que está mudando e quais são os meio-termos a serem alcançados&#8211;para realizar seus objetivos. Mudança sem contexto, sem disciplina, só gera caos. E isso é que muitos parecem esquecer quando se encantam com o Scrum e suas disciplinas irmãs.</p>

<p>Eu estava falando com um amigo outro dia e estávamos discutindo o fato de que muitos programadores usam a desculpa do <a href="http://en.wikipedia.org/wiki/Attention-deficit_hyperactivity_disorder">ADD</a> para procrastinarem ou para justificar distrações. <span class="foreign-word">Geeks</span>, ele estava dizendo, são notórios pela sua baixa capacidade de atenção.</p>

<p>Eu acho&#8211;e disse para ele&#8211;que o contrário é o correto. Os verdadeiros <span class="foreign-word">geeks</span> são disciplinados o suficiente para manter o seu foco e continuar no que estão fazendo a despeito das distrações. Você precisa ser muito focado se quer depurar aquele <span class="foreign-word">heisenbug</span> que está mantendo você acordado nas últimas 40 horas, fazendo com que seu servidor capote a cada hora e meia. Você precisa de disciplina para continuar afundando na documentação, indo e voltando para encontrar aquela informação elusiva de permitirá que você otimize a sua rotina para que ela rode em massas de dados enormes. E você precisa de um senso forte de direção para participar de um time sem controle gerencial direto em um ambiente que está mudando continuamente.</p>

<p>Em resumo, disciplina é o que separa os diletantes dos artesãos. É que faz as coisas acontecerem e que realmente cria grandes times. Não quer dizer que você tenha que ser um mala sobre horários, procedimentos ou qualquer coisa assim. Não significa que você não possa se divertir ou que tenha que seguir passos ordenados toda vez que vai fazer alguma coisa. Mas significa que você tem que praticar  e pensar e se focar até que isso se torna uma segunda natureza, até que você se torne um mestre no que está fazendo.</p>

<p>E isso é o que ninjas e samurais e Jedi fazem. Eles não param, não correm quando a proverbial situação fica preta. Eles&#8211;você sabe&#8211;simplesmente vão lá e fazem, e fazem bem.</p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2011/01/08/sobre-jedis-ninjas-e-samurais/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Mirror</title>
		<link>http://logbr.reflectivesurface.com/2009/11/28/mirror/</link>
		<comments>http://logbr.reflectivesurface.com/2009/11/28/mirror/#comments</comments>
		<pubDate>Sat, 28 Nov 2009 16:43:11 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Coisas de Geek]]></category>
		<category><![CDATA[Desenvolvimento]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/?p=1459</guid>
		<description><![CDATA[Hoje, sábado de sol, está acontecendo o Dev In Sampa, um evento de desenvolvedores para desenvolvedores. Se você não conseguiu participar por algum motivo, pode acompanhar um pouco pelo livestream do evento&#8211;as palestras estão excelentes. Mas não se preocupe, as palestras estão sendo filmadas também e serão disponibilizadas após o evento. Eu participei falando sobre [...]]]></description>
			<content:encoded><![CDATA[<p>Hoje, sábado de sol, está acontecendo o <a href="http://devinsampa.com.br/">Dev In Sampa</a>, um evento de desenvolvedores para desenvolvedores. Se você não conseguiu participar por algum motivo, pode acompanhar um pouco pelo <a href="http://live.blogblogs.com.br/devinsampa/">livestream</a> do evento&#8211;as palestras estão excelentes. Mas não se preocupe, as palestras estão sendo filmadas também e serão disponibilizadas após o evento.</p>

<p>Eu participei falando sobre a criação de linguagens de programação e para os que já querem ver alguma coisa, segue abaixo a apresentação do <a href="http://www.slideshare.net/ronaldoferraz/criando-sua-prpria-linguagem-de-programao">SlideShare</a>:</p>

<div style="width:425px;text-align:left" id="__ss_2602315"><a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/ronaldoferraz/criando-sua-prpria-linguagem-de-programao" title="Criando sua própria linguagem de programação">Criando sua própria linguagem de programação</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=creating-your-own-programming-language-091128082446-phpapp02&#038;stripped_title=criando-sua-prpria-linguagem-de-programao" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=creating-your-own-programming-language-091128082446-phpapp02&#038;stripped_title=criando-sua-prpria-linguagem-de-programao" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>

<p>O repositório da <span class="foreign-word" lang="en">toy language</span> que eu criei para demonstração já <a href="http://github.com/rferraz/mirror">está disponível também no GitHub</a>. Só não espere muito do código já que ele foi produzido em pouco tempo em madrugadas disponíveis. <img src='http://logbr.reflectivesurface.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>

<p>Para o resto, a caixa de comentários está aberta. <img src='http://logbr.reflectivesurface.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/11/28/mirror/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>LazyWeb: Escolhendo um framework</title>
		<link>http://logbr.reflectivesurface.com/2009/11/11/lazyweb-escolhendo-um-framework/</link>
		<comments>http://logbr.reflectivesurface.com/2009/11/11/lazyweb-escolhendo-um-framework/#comments</comments>
		<pubDate>Wed, 11 Nov 2009 10:37:45 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Seaside]]></category>
		<category><![CDATA[Smalltalk]]></category>
		<category><![CDATA[Squeak]]></category>
		<category><![CDATA[Misc]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/?p=1448</guid>
		<description><![CDATA[Um amigo de Belo Horizonte me consultou esses dias sobre uma questão fundamental para a aplicação que ele está planejando começar a escrever nos próximos dias: framework de programação usar (e por extensão, qual linguagem)? Como minha experiência nos últimos tempos tem sido confessadamente restrita a Rails e alguns experimentos em outros, resolvi apelar para [...]]]></description>
			<content:encoded><![CDATA[<p>Um amigo de Belo Horizonte me consultou esses dias sobre uma questão fundamental para a aplicação que ele está planejando começar a escrever nos próximos dias: <span class="foreign-word" lang="en">framework</span> de programação usar (e por extensão, qual linguagem)? </p>

<p>Como minha experiência nos últimos tempos tem sido confessadamente restrita a Rails e alguns experimentos em outros, resolvi apelar para a caridade dos meus leitores. Qual <span class="foreign-word" lang="en">framework</span> você usaria para seu próximo projeto?</p>

<p>Esse meu amigo não tem problemas com linguagens de programação em si. De fato, a não ser que seja algo tão esotérico quando Haskell ou Erlang, ele é capaz de se familiarizar com uma linguagem ou <span class="foreign-word" lang="en">framework</span> em alguns dias.</p>

<p>Obviamente, não posso dar muitos detalhes sobre a aplicação, mas dá para dizer que o objetivo é escalar gradualmente. Ela não precisar começar escalando para o mundo inteiro, mas um caminho seria bom. Um outro detalhe nesse aspecto é que a aplicação é comparativamente particionada: um usuário terá acesso a alguns itens e compartilhará esse acesso com algumas dezenas ou centenas de pessoas. Esses itens possuem moldes variáveis e seriam bom ter flexibilidade na criação do mesmos.</p>

<p>Finalmente, hospedagem é uma questão também. Não necessariamente preço, mas facilidade. Linode é uma opção mas preferivelmente algo que possa ser colocado em alguma coisa pequena e ir escalando conforme a necessidade, no estilo do Heroku (o que limitaria a Rails, claro). Python parece uma boa opção, mas ele precisa de evidências.</p>

<p>E aí, alguém anima a ajudar um pobre compadre em armas? <img src='http://logbr.reflectivesurface.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/11/11/lazyweb-escolhendo-um-framework/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>A prática de arquitetura</title>
		<link>http://logbr.reflectivesurface.com/2009/11/09/a-pratica-de-arquitetura/</link>
		<comments>http://logbr.reflectivesurface.com/2009/11/09/a-pratica-de-arquitetura/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 08:00:41 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Tecnologia]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/?p=1433</guid>
		<description><![CDATA[O Lucas Húngaro, que trabalhou comigo na WebCo, escreveu há poucos dias um artigo muito bom sobre a dificuldade de dissociar nomes e funções em projetos de software e sobre sua visão do processo de desenvolvimento e arquitetura. Desnecessário dizer, concordo essencialmente com tudo o que ele diz, com algumas pequenas ressalvas. O leitor atento [...]]]></description>
			<content:encoded><![CDATA[<p>O Lucas Húngaro, que trabalhou comigo na WebCo, escreveu <a href="http://www.makemesimple.com/blog/2009/11/04/desenvolvedor-arquiteto-programador-engenheiro/">há poucos dias um artigo muito bom</a> sobre a dificuldade de dissociar nomes e funções em projetos de <span class="foreign-word" lang="en">software</span> e sobre sua visão do processo de desenvolvimento e arquitetura. Desnecessário dizer, concordo essencialmente com tudo o que ele diz, com algumas pequenas ressalvas.</p>

<p>O leitor atento do <span class="foreign-word" lang="en">blog</span> deve estar se perguntando agora: mas, <a href="http://logbr.reflectivesurface.com/2009/11/03/o-gap-arquitetural/">há menos de uma semana, você não disse</a> que lidera uma equipe separada de arquitetura onde trabalha agora&#8211;isso não é uma contradição? Na verdade, não. Antes de responder a questão, porém, peço que o leitor me acompanhe por algumas considerações.</p>

<p>Como o Lucas menciona eu seu texto, o tópico de arquitetura de <span class="foreign-word" lang="en">software</span> é bastante controverso. De fato, ao longo das quase sete décadas desde que existe algum processo de desenvolvimento, nunca se chegou a um consenso sobre o que esse termo realmente significa. Ano após ano, novos artigos e livros são escritos para explicar o que se entende pela prática e metáforas abundam. </p>

<p>Eu não vou dizer que tenho a palavra final sobre o assunto, é claro. Nos últimos anos, entretanto, eu tenho pensado continuamente sobre o tema, especialmente como uma reflexão sobre o meu trabalho e cheguei a uma conclusão de que minha visão é bastante similar à <a href="http://logbr.reflectivesurface.com/2009/10/22/fred-brooks-sobre-colaboracao/">advogada por Fred Brooks</a>, com algumas pequenas diferenças que refletem minha experiência própria.</p>

<p>Brooks, na palestra que assisti, propôs o seguinte postulado: &#8220;Não há tecnologias ingênuas no Ocidente&#8221;. O que ele quis dizer com isso é que em qualquer domínio de conhecimento, a faixa de conhecimento e habilidades exigidas é maior do que uma única pessoa pode dominar em um dado projeto. </p>

<p>Ele usou como exemplo o caso de fabricantes de <span class="foreign-word" lang="en">shampoo</span> que usam simulações do fluxo de fluidos viscosos para garantir que as lâminas misturadoras não separem a emulsão de camadas triplas do produto final; adicionalmente, ele também comentou sobre uma fábrica de bolos em que a receita do dia é modificada pela análise química dos ingredientes que chegam a cada dia na planta. </p>

<p>O fato é que esse tipo de especialização de engenharia é uma constante reconhecida mesmo por metodologias ágeis em que a multi-disciplinaridade das equipes é exigida como uma das premissas para o funcionamento do processo.</p>

<p>Por conta disso, Brooks chega à conclusão de que a única maneira de atingir algum nível de consistência e integridade no desenho arquitetural de um sistema é obter uma visão única de como as estruturas devem se comportar no seu nível mais alto: em outras palavras, criar a arquitetura de um sistema.</p>

<p>Em seu livro <a href="http://www.amazon.com/exec/obidos/ASIN/0201105578/">Computer Architecture: Concepts and Evolution</a> (escrito em parceria com Gerrit A. Blaauw), Brooks define arquitetura de sistemas computacionais da seguinte forma:</p>

<blockquote>
  <p>The architecture of a computer system we define as <strong>the minimal set of properties</strong> that determine what programs will run and what results they will produce. The architecture is thus the system’s functional appearance to its immediate user, the conceptual structure and functional behavior as seen by one who programs in machine language.</p>
</blockquote>

<p>Eu ressaltei <strong><span class="foreign-word" lang="en">the minimal set of properties</span></strong> porque isso representa uma dos grandes desentendimentos sobre o que arquitetura de <span class="foreign-word" lang="en">software</span> realmente significa e quais são os entregáveis da mesma. Como Brooks e Blaauw apontam, se arquitetura é o conjunto mínimo de propriedades de um sistema, existem outras coisas que, por definição não são arquiteturais e que ainda assim precisam existir para que a implementação suceda. </p>

<p>Nesse sentido, podemos fazer uma distinção bem clara entre a arquitetura e o <span class="foreign-word" lang="en">design</span> de um sistema para entender o desdobramento do projeto de um sistema qualquer. Enquanto a arquitetura existe mais no nível do mapeamento e organização fundamental de um sistema, como entendida através de seus componentes, os relacionamentos entre esses e sua distribuição em domínios de tempo, economia (sim, porque dinheiro também é arquitetura) e escala, o <span class="foreign-word" lang="en">design</span> está mais centrado no domínio de resolução de problemas e planejamento para implementação da solução. </p>

<p>Em outras palavras, a arquitetura é voltada a atingir necessidades de negócio através de blocos maiores de construção do sistema enquanto o <span class="foreign-word" lang="en">design</span> é a disseminação técnica desses objetivos em algoritmos, sub-sistemas e escolhas de implementação.</p>

<p>O que leva à conclusão, por parte de Brooks, e com a qual eu concordo, de que para que se consiga integridade conceitual e estrutural da arquitetura, a figura de um arquiteto-chefe é necessária. Isso é óbvio quando se pensa no negócio como um todo e seus desdobramentos em múltiplas responsabilidades, projetos, sistemas de sistemas e relacionamentos da construção do <span class="foreign-word" lang="en">software</span> em si. </p>

<p>Uma palavra-chave aqui que ajuda esclarecer a distinção aqui é <em>grande porte</em>. Por grande porte, eu quero dizer projetos com um escopo grande ou com grandes características de distribuição. Como Brooks mesmo elabora em seus textos e palestras, se o sistema é pequeno o suficiente, não é necessário que exista uma distinção entre arquitetura, <span class="foreign-word" lang="en">design</span> e implementação. Brooks, na verdade, vai além ao sugerir que o arquiteto e implementador sejam uma única pessoa. Para projetos de porte maior, entretanto, sem uma visão consistente é impossível conseguir a consistência necessária entre as partes. </p>

<p>O arquiteto de sistemas, em outras palavras, é alguém que é capaz de enxergar o projeto com um todo, necessariamente além do escopo de um time qualquer de implementação, mesmo quando o <span class="foreign-word" lang="en">design</span> que esse time está seguindo é auto-contido dentro das premissas daquele time e somente se comunica com externalidades através de protocolos e convenções arquiteturas definidas anteriormente.</p>

<p>Como um exemplo disso, <a href="http://www.bcs.org/upload/pdf/turing2005report.pdf">em uma de suas palestras</a>, Brooks menciona uma discussão que ele teve com a pessoal responsável pela arquitetura de sistemas do <span class="foreign-word" lang="en">Global Positioning System</span> (GPS). Esse arquiteto entendia que o sistema como um todo era baseada na interação complexa entre muitos componentes (satélites e outros) e que a moeda corrente entre esses sistema era tempo, dividido em micro-segundos. Ainda mais, o arquiteto via como sua responsabilidade garantir que cada processo conseguisse a fatia necessária de micro-segundos para sua operação&#8211;com, como Brooks colocou, bastante micro-segundos sobrando em seus bolsos para resgatar partes do sistema que estivessem em dificuldade.</p>

<p>E isso é o que realmente eu entendo por arquitetura de sistemas. Aos proponentes de arquitetura emergente&#8211;tão comum entre praticantes de metodologias ágeis&#8211;a implicação é clara: é simplesmente impossível que arquitetura nesse porte, dessa complexidade, venha algum dia a emergir de times separados, trabalhando em componentes próprios, com suas próprias necessidades. Primeiro, por conta da onipresente necessidade de integridade conceitual e, segundo, por conta da degradação de comunicação à medida que o sistema de torna mais complexo e decisões maiores são cristalizada em um conjunto de <span class="foreign-word" lang="en">constraints</span> e especificações&#8211;o que Brooks chama de <span class="foreign-word" lang="en">style sheet</span> do projeto.</p>

<p>Volto a Brooks aqui para afirmar o ponto de que um comitê não é um bom lugar para se buscar integridade arquitetural:</p>

<blockquote>
  <p>Textbook examples of design are almost always &#8220;way too simple,&#8221; said Brooks. In particular, they ignore the fact that complexity often forces designs to change halfway through, and these changes then involves many other changes. Finally, there is no substitute for &#8220;the dreariness of labour and the loneliness of thought&#8221;&#8211;even though it has been joked that committees are a place where people seek refuge from that.</p>
</blockquote>

<p>O arquiteto de sistemas é, em última instância, como Brooks também coloca, um advogado do usuário. Ele advoga pelo usuário em termos funcionais, em termos econômicos, e em termos de escala. Como mostrado na citação acima, o arquiteto de sistemas representa a aparência funcional do sistema para seu usuário imediato, visto pela lente de alguém que programa em linguagem de máquina. E, sim, é um papel técnico.</p>

<p>Para <a href="http://tesugen.com/archives/04/08/brooks-architecture-2">citar Brooks mais uma vez</a>:</p>

<blockquote>
  <p>Computer architecture, like other architecture, is the art of determining the needs of the user of a structure and then designing to meet those needs as effectively as possible within economic and technological constraints. Architecture must include engineering considerations, so that the design will be economical and feasible; but the emphasis in architecture is on the needs of the user, whereas in engineering the emphasis is on the needs of the fabricator.</p>
</blockquote>

<p>Note a diferença em ênfase como colocada por Brooks: arquitetura enfatiza as necessidades do usuário enquanto engenharia enfatiza as necessidades do construtor. </p>

<p>As implicações são bastante óbvias e essencialmente respondem à questão da minha concordância com o que o Lucas disse e com o fato de que eu lidero uma equipe de arquitetura: as necessidades de desenvolvimento são completamente diferentes. </p>

<p>Tirando um exemplo da minha própria experiência, quando eu trabalhava na WebCo, tínhamos apenas dois produtos: <a href="http://brasigo.com.br/">Brasigo</a> e <a href="http://blogblogs.com.br/">BlogBlogs</a>. Por mais complexos que ambos sistemas fossem, suas necessidades arquiteturais eram comparativamente pequenas. Da mesma forma, por mais similares que ambos fossem (aplicações escritas em Rails, virtualizadas, com gargalo em banco de dados, etc), havia poucas conexões arquiteturais para que a figura de um arquiteto-chefe fosse necessária.</p>

<p>E, de fato, pelo tamanho dos projetos, podíamos ter, sem problemas, a figura de um arquiteto em cada time, servindo como líder técnico, ponto focal em discussões entre produtos, alguém como senioridade o suficiente para fazer um papel de mentor para membros mais novos da equipe.</p>

<p>Esse não é o caso em minha posição atual, na Abril Digital. Não só a complexidade dos sistemas é maior, tanto em escala como em distribuição, como a relação entre eles é mais porosa e necessitando de coordenação. Construir um sistema de sistemas constituído de dezenas de sub-sistemas, cada um com suas necessidades, escopo e papel  é fundamentalmente diferente de construir um único produto, com limites e condições bem específicos. Não estamos construindo algo do tamanho de um sistema de GPS, claro, mas estamos construindo coisas que possuem necessidades maiores que simplesmente as de um único escopo.</p>

<p>Por conta disso, surge <a href="http://scalingsoftwareagility.wordpress.com/2008/09/22/enterprise-agility-the-big-picture-12-architectural-runway/">a necessidade de arquitetura</a> como uma colaboração de papéis empregando arquitetos de sistemas e arquitetos de <span class="foreign-word" lang="en">software</span> (chamados de <span class="foreign-word" lang="en">tech leaders</span> internamente) para chegar a um <span class="foreign-word" lang="en">design</span> final coerente. </p>

<p>Isso é ainda mais fundamental em projetos terceirizados que, em um ponto ou outro, precisam se encaixar em nossa infra-estrutura e arquitetura em <em>múltiplos times e instâncias de sistemas</em>.  Uma equipe dedicada serve para ajudar nessa coordenação, oferecendo visões do problema.  O <span class="foreign-word" lang="en">gap</span> arquitetural é assim resolvido já que existe uma rodovia arquitetural contendo épicos que guiam a quebra de sistemas nas partes necessárias. </p>

<p>Dessa quebra nascem preocupações que podem ser traduzidas no <span class="foreign-word" lang="en">design</span> emergente em cada equipe, contribuindo ao final, para o retorno ao <span class="foreign-word" lang="en">pool</span> arquitetural de conceitos e implementações feitas no ato de descoberta que é o processo de desenvolvimento.</p>

<p>Eu acredito nessa colaboração de papéis como essencial para garantir a agilidade. Citando um dos artigos de <a href="http://martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf">Martin Fowler</a>:</p>

<blockquote>
  <p>This kind of architect must be very aware of what’s going on in the project, looking out for important issues and tackling them before they become a serious problem. When I see an architect like this, the most noticeable part of the work is the intense collaboration. In the morning, the architect programs with a developer, trying to harvest some common locking code. In the afternoon, the architect participates in a requirements session, helping explain to the requirements people the technical consequences of some of their ideas in non-technical terms&#8211;such as development costs.</p>
</blockquote>

<p>Nesse artigo, Fowler usa uma versão limitada do que Brooks diz para definir um tipo de arquiteto não desejável. E Fowler está correto: usar o argumento de Brooks simplesmente para suportar alguém que simplesmente &#8220;toma as decisões mais importantes&#8221; não faz sentido.</p>

<p>Isso tudo que foi dito anteriormente não significa, também, que essa arquitetura de sistemas não possa falhar. Ela falha, sim, e algumas vezes catastroficamente. E, na maioria das vezes, a falha pode ser rastreada para decisões que foram tomadas em pontos errados do processo por problemas de comunicação ou de definição de escopo resultado em <span class="foreign-word" lang="en">design</span> inconsistente pelo qual ninguém quer tomar a responsabilidade. A falha, nesse caso, é de todos envolvidos no processo.</p>

<p>Para resumir toda a conversa, considerando que esse texto acabou quase se tornando um ensaio, eu concordo com o Lucas: cada time deve ter o seu arquiteto. Mas acredito também que, para projetos com maior escopo, deve existir um nível mais alto de arquitetura&#8211;e por mais alto aqui não quero dizer em termos de uma elite ou de conhecimento mas simplesmente um papel que defina o que é mais alto simplesmente porque tecnicamente, alguém define que esse é o nível mais alto necessário.</p>

<p>Esse arquiteto, dentro do time, é um desenvolvedor sênior capaz de fazer decisões de <span class="foreign-word" lang="en">design</span> em colaboração com seus pares, praticar a mentoria, planejar e executar escolhas de implementação, atuando em conjunto com um time de arquitetos de sistemas que está preocupado com o todo e que não tenta, de forma alguma, forçar decisões de implementação ou <span class="foreign-word" lang="en">design</span>, que busca embasar suas decisões pela velha métrica do <span class="foreign-word" lang="en"><a href="http://en.wikipedia.org/wiki/Rough_consensus">running code and rough consensus</a></span>, que pratica código diariamente pelos meios necessários.</p>

<p>O que significa, essencialmente, que a arquitetura não tem que ser fechada no começo e permanecer imutável depois disso. Ao contrário, precisa evoluir como qualquer outra parte do sistema na percepção do que funciona e do que não funciona. Como <a href="http://www.theregister.co.uk/2005/09/11/beck_on_xp_architecture/">Kent Beck diz</a>:</p>

<blockquote>
  <p>The process of building architecture should have lots of feedback built in and it should be kept simple, because extra elements in the architecture introduce instability and unpredictability. The big difference from current practice is that: &#8220;I would stop apologizing for architecting this way,&#8221; he says</p>
</blockquote>

<p>Espero com esses monte de palavras ter clarificado um pouco a visão do que andei escrevendo aqui nos últimos tempos. Obrigado ao Lucas por fornecer a oportunidade de uma discussão boa como essa&#8211;espero que ela continue, por sinal.</p>

<p>Aos leitores que tiveram paciência de chegar até esse ponto, quais são suas visões e comentários sobre o assunto? A caixa de comentários lhes espera impacientemente. <img src='http://logbr.reflectivesurface.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/11/09/a-pratica-de-arquitetura/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>O gap arquitetural</title>
		<link>http://logbr.reflectivesurface.com/2009/11/03/o-gap-arquitetural/</link>
		<comments>http://logbr.reflectivesurface.com/2009/11/03/o-gap-arquitetural/#comments</comments>
		<pubDate>Tue, 03 Nov 2009 11:28:27 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Tecnologia]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/?p=1419</guid>
		<description><![CDATA[Desde que comecei a trabalhar com uma forma ou outra de metodologias ágeis, um dos assuntos que sempre me causou reflexão foi a questão de como lidar com arquitetura em um ambiente ágil. Obviamente, eu não sou o único que se questiona sobre isso: a discussão em torno de Big Design Up Front é tão [...]]]></description>
			<content:encoded><![CDATA[<p>Desde que comecei a trabalhar com uma forma ou outra de metodologias ágeis, um dos assuntos que sempre me causou reflexão foi a questão de como lidar com arquitetura em um ambiente ágil. Obviamente, eu não sou o único que se questiona sobre isso: a discussão em torno de <span class="foreign-word" lang="en"><a href="http://en.wikipedia.org/wiki/Big_Design_Up_Front">Big Design Up Front</a></span> é tão velha quando a própria indústria. Existe uma polarização imensa sobre o assunto e é bem raro encontrar alguém que tenha desenvolvido alguma idéia que se encaixe no meio do caminho. </p>

<p>De fato, proponentes de metodologias ágeis geralmente gravitam em torno do que se comumente denomina <span class="foreign-word" lang="en">design</span> emergente, ou seja, a criação e concepção de conceitos arquiteturais&#8211;especialmente os não funcionais&#8211;ao longo do processo de amadurecimento da própria solução.</p>

<p>Duas coisas me levaram a repensar sobre o assunto nos últimos dias. </p>

<p>A primeira foi participar de uma <a href="http://logbr.reflectivesurface.com/2009/10/22/fred-brooks-sobre-colaboracao/">palestra</a> dada por ninguém menos do que Fred Brooks. Brooks é um dos autores mais influentes sobre a questão de arquitetura e <span class="foreign-word" lang="en">design</span> e eu sempre tive uma concordância forte com seus pontos de vista, especialmente no que tangem à necessidade de centralização de arquitetura como fonte de integridade conceitual em uma solução. <a href="http://www.elsevier.com.br/site/produtos/Detalhe-produto.aspx?tid=50219&amp;seg=3&amp;isbn=9788535234879&amp;cat=8">O Mítico Homem-Mês</a> toca profundamente nesse questão&#8211;de fato o livro pode ser considerado uma coleção de ensaios em torno desse tema&#8211;e Brooks sempre volta-se para essa necessidade de <span class="foreign-word" lang="en">design</span> arquitetural prévio para garantir soluções sólidas.</p>

<p>A segunda coisa que me levou a pensar sobre o assunto foi um <span class="foreign-word" lang="en"><a href="http://twitter.com/bigballofmud/status/5237625116">tweet</a></span> de Brian Foote, reportando da OOPSLA:</p>

<blockquote>
  <p>When we extol the benefits of architecture emerging in agile, we are really saying developers are better architects than Architects. #oopsla</p>
</blockquote>

<p>Foote, conhecido pelo seu trabalho com Joseph Yoder, <a href="http://www.laputan.org/mud/">Big Ball of Mud</a>, em que descreve a estruturação impensada de sistemas resultando em algo impossível de manter e impossível de se confiar, está correto em sua avaliação.</p>

<p>É claro que, nesse ponto, muita gente deve estar pensando que eu sou um elitista, que, de uma forma ou outra, considero arquitetos melhores do que desenvolvedores. Meu cargo atual pode até dar a entender isso&#8211;sou um gerente de arquitetura e engenharia de <span class="foreign-word" lang="en">software</span> na empresa onde trabalho&#8211;mas esse não é caso.</p>

<p>De fato, se eu tivesse hoje que me descrever em um currículo, eu teria bastante dificuldade de me conceituar em uma categoria qualquer. Eu poderia colocar que sou um desenvolvedor, já que faço isso. Também poderia colocar que sou um arquiteto, igualmente válido para o que faço. Poderia recorrer aos tradicionais programador ou analista de sistemas. A verdade é que sou tudo isso. </p>

<p>Para mim, um arquiteto não é alguém que atingiu um estado de santificação tal que pode abandonar os conturbados e lamacentos meandros da programação e recolher-se em sua torre de marfim para dispensar sua sabedoria sobre as massas menos iluminadas. Antes, tenho certeza de que a maioria dos meus colegas que se descrevem como arquitetos concordariam que arquitetura é mais uma questão de atuação e experiência do que de grau ou de talento nato. Eu não trabalharia com um desenvolvedor que não fosse capaz de responder por sua arquitetura e também não trabalharia com um arquiteto incapaz de codificar um algoritmo qualquer. Tentar extrair uma coisa da outra seria uma violação das premissas.</p>

<p>Voltando ao ponto, é justamente aí que entra a figura que Brooks descreve, o arquiteto-chefe que, por experiência, treinamento e sensibilidade adquiridos na prática, é capaz de guiar um sistema à integridade conceitual necessária para o seu bom desenvolvimento. </p>

<p>O que resolve, finalmente, para mim, a questão de emergência em metodologias ágeis. Eu acredito que, sim, deve haver arquitetura propriamente dita em qualquer projeto, mesmo os que subscrevem a metodologias ágeis e acho que isso nunca esteve fora da visão dos criadores das mesmas. Antes, essa é uma visão equivocada do que deve ou não emergir dentro das mesmas, que é a solução em si.</p>

<p>Arquitetura, por definição, é algo que precisa ser feito antes até um certo ponto, mesmo que depois sofra as mudanças necessárias por sua própria evolução gradual. Ela não pode ser estática&#8211;exceto em circunstâncias especiais que normalmente quase nenhum desenvolvedor encontrará ao longo de sua carreira&#8211;mas também não pode ser completamente <span class="foreign-word" lang="la">ad hoc</span> já que isso seria pouco mais do que pensar apenas no que está imediatamente adiante, sem se preocupar com os temas maiores que podem afetar o trabalho.</p>

<p>Em última instância, a arquitetura então não é necessariamente emergente: a solução o é. E por solução aqui, eu entendo o conjunto completo representado pelo produto, sua arquitetura, seu desenvolvimento e sua transição em produção. A responsabilidade de um arquiteto é traduzir o <span class="foreign-word" lang="en">backlog</span>, ou seja qual for seu equivalente, em temas conceituais que possuem integridade em conjunto e que levam a um desenvolvimento das características do <span class="foreign-word" lang="en">software</span> a seu tempo e com as suas necessidades atendidas.</p>

<p>Esse é um <span class="foreign-word" lang="en">gap</span> que fica claro na maior parte da discussão sobre arquitetura e metodologias ágeis e que precisa ser tratado mais freqüentemente pela literatura e seus proponentes.</p>

<p>Para finalizar, essa é apenas uma visão rápida do que tenho pensado nos últimos tempos sobre o assunto. Espero ter deixado minha visão um pouco mais clara do que estava em discussões passadas aqui no <span class="foreign-word" lang="en">blog</span>. Como sempre, comentários e discussões adicionais são sempre bem-vindos.</p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/11/03/o-gap-arquitetural/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Sinergia Arquitetural</title>
		<link>http://logbr.reflectivesurface.com/2009/10/27/sinergia-arquitetural/</link>
		<comments>http://logbr.reflectivesurface.com/2009/10/27/sinergia-arquitetural/#comments</comments>
		<pubDate>Tue, 27 Oct 2009 10:00:00 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Tecnologia]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/2009/10/27/sinergia-arquitetural/</guid>
		<description><![CDATA[syn&#8226;er&#8226;gy &#124;ˈsinərjē&#124; noun the interaction or cooperation of two or more organizations, substances, or other agents to produce a combined effect greater than the sum of their separate effects &#8212; Apple&#8217;s Mac OS X Dictionary A definição acima não é muito padrão mas expressa bem o conceito em que a palavra é entendida hoje em [...]]]></description>
			<content:encoded><![CDATA[<blockquote>
<p><strong>syn&#8226;er&#8226;gy</strong> |ˈsinərjē|<br />
noun<br />
the interaction or cooperation of two or more organizations, substances, or other agents to produce a combined effect greater than the sum of their separate effects</p>
<p align="right"><cite>&mdash; Apple&#8217;s Mac OS X Dictionary</cite></p>
</blockquote>

<p>A definição acima não é muito padrão mas expressa bem o conceito em que a palavra é entendida hoje em dia. Sinergia vem do grego <span class="foreign-word" lang="gr">sunergos</span>, que literalmente significa <em>trabalhar em conjunto</em>. </p>

<p>Em inglês, a palavra data de cerca de 1650, e tinha um sentido bastante medicinal, podendo indicar tanto a ação cooperativa entre dois ou mais músculos do corpo para a realização de um esforço ou a ação combinada de medicamentos ou drogas para criar um estímulo maior no paciente.</p>

<p>O <a href="http://en.wiktionary.org/wiki/synergy">Wikitionary</a> define sinergia também com o &#8220;comportamento de um sistema que não pode ser previsto pelo comportamento de suas partes&#8221;, o que é uma definição bastante interessante e diversa do sentido necessariamente positivo que a palavra ganhou nas últimas décadas.</p>

<p>De fato, sinergia hoje em dia é considerada uma <span class="foreign-word" lang="en">buzzword</span>, uma palavra sem significado para indicar a vontade de que algum esforço conjunto qualquer resulte em mais lucro, para qualquer valor de lucro, do que um esforço individual das partes envolvidas&#8211;a palavra-chave na mudança de definição aqui sendo &#8220;vontade&#8221; versus o efeito real.</p>

<p>No meu trabalho com arquitetura de <span class="foreign-word" lang="en">software</span>, entretanto, sinergia é algo que faz sentido naturalmente no desenho de sistemas. De fato, sistemas de sistemas tender a exibir isso de uma forma quase que óbvio já que não é possível desenhar os mesmos de outra forma. Não é sem motivo que <a href="http://en.wikipedia.org/wiki/System_of_systems">a página na Wikipedia que explica o conceito</a> usa sinergismo, uma variação de sinergia para explicar a motivação primária desse objetivo. O Unix é um exemplo bem óbvio disso e algumas pessoas chegam a se referir a isso como o <a href="http://logbr.reflectivesurface.com/2005/06/24/tao/">Tao do Unix</a> pelo fato de que as peças se encaixam com tal perfeição que é impossível pensar em trabalhar de outra forma.</p>

<p>Sistemas de sistemas fazem sentido em praticamente qualquer situação em que a complexidade das partes individuais torne o sistema final potencialmente (e exponencialmente) difícil de ser descrito de maneira consistente.</p>

<p>Essa é uma das razões, inclusive, pela qual as pessoas se decepcionam tanto com <span class="foreign-word" lang="en">frameworks</span> como Rails ou Django quando precisam de expandir aplicações já existentes para níveis maiores de complementaridade ou escalabilidade. <span class="foreign-word" lang="en">Frameworks</span> fechados simplesmente não exibem esse tipo de sinergia integral necessária para garantir que os princípios aplicáveis em aplicações menores sejam os mesmos de aplicações maiores. O resultado é que, essencialmente, todos esses princípios são violados à medida que o sistema precisa crescer resultando em um entendimento completamente diferente do que se desejava a princípio. Funciona, mas sem elegância ou beleza.</p>

<p>A despeito do significado amortecido, uma reflexão cuidadosa sobre sinergia e sua aplicabilidade ao desenho de sistemas faria bem a qualquer desenvolvedor ou arquiteto de sistemas. <a href="http://en.wikipedia.org/wiki/Sapir-Whorf_hypothesis">Sapir-Whorf</a> sendo fraca ou não, um entendimento real é impossível se o vocabulário natural é desprezado.</p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/10/27/sinergia-arquitetural/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Fred Brooks sobre colaboração</title>
		<link>http://logbr.reflectivesurface.com/2009/10/22/fred-brooks-sobre-colaboracao/</link>
		<comments>http://logbr.reflectivesurface.com/2009/10/22/fred-brooks-sobre-colaboracao/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 16:10:01 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Tecnologia]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/2009/10/22/fred-brooks-sobre-colaboracao/</guid>
		<description><![CDATA[Ontem, cortesia da Caelum, tive oportunidade de ver Fred Brooks falar sobre desenvolvimento, arquitetura de sistemas e colaboração entre times. O evento, lançamento da tradução brasileira de seu trabalho mais famoso&#8211;O Mítico Homem-Mês&#8211;contou com várias outras palestras e uma sessão de Q&#38;A com Brooks mas, infelizmente, só pude participar dos quarenta ou cinqüenta minutos que [...]]]></description>
			<content:encoded><![CDATA[<p>Ontem, cortesia da <a href="http://www.caelum.com.br/">Caelum</a>, tive oportunidade de ver <a href="http://en.wikipedia.org/wiki/Fred_Brooks">Fred Brooks</a> falar sobre desenvolvimento, arquitetura de sistemas e colaboração entre times. </p>

<p>O evento, lançamento da tradução brasileira de seu trabalho mais famoso&#8211;<a href="http://www.elsevier.com.br/site/produtos/Detalhe-produto.aspx?tid=50219&amp;seg=3&amp;isbn=9788535234879&amp;cat=8">O Mítico Homem-Mês</a>&#8211;contou com várias outras palestras e uma sessão de Q&amp;A com Brooks mas, infelizmente, só pude participar dos quarenta ou cinqüenta minutos que ele passou discorrendo sobre o assunto. Mesmo assim, foi muito bom ver o velho professor&#8211;ele está com quase 80 anos atualmente&#8211;falando sobre assuntos que eram relevantes em 1975, quando o livro foi impresso pela primeira vez, e que ainda são relevantes hoje, quase 40 anos depois.</p>

<p><em>O Mítico Homem-Mês</em> é um livro que qualquer pessoa que desenvolve ou gerencia algum processo de desenvolvimento de <span class="foreign-word" lang="en">software</span> deveria ler. Apesar da ironia do próprio Brooks ao dizer que seu livro é como uma Bíblia de Engenharia de <span class="foreign-word" lang="en">Software</span>, porque &#8220;todo mundo lê mas ninguém faz nada sobre o assunto&#8221;, o livro permanece uma influência seminal entre todos os trabalhos que foram feitos no campo nos últimos 30 anos, especialmente entre os responsáveis por grande parte das metodologias de desenvolvimento que são usadas atualmente.</p>

<p>Um dos pontos interessantes da palestra&#8211;e algo que que só tem um conhecimento superficial do livro não notaria&#8211;é que Brooks possui uma visão particular de desenvolvimento que vai muito contra o que se fala hoje em termos de desenvolvimento &#8220;ágil&#8221;. Um dos exemplos engraçados disso foi quando um dos participantes, ao final da palestra, perguntou o que ele pensava sobre o papel da arquitetura e <span class="foreign-word" lang="en">design</span> colaborativos dentro de um time ágil&#8211;um time de Scrum, digamos. Brooks declarou enfaticamente, em resposta à insistência do participante, que, sem um arquiteto-chefe, nada que fosse feito teria a consistência&#8211;a integridade conceitual, por assim dizer&#8211;necessária para o bom desenvolvimento do <span class="foreign-word" lang="en">software</span>.</p>

<p>Falando sobre colaboração, Brooks apontou o papel do trabalho solo de grandes artistas e realizadores como essencial para a criação de obras duradouras. Mesmo no contexto de colaboração, ele diz, as maiores equipes raramente passam de uma colaboração complementar entre duas pessoas. Mais do que isso resulta em difusão da integridade conceitual da obra em face a desafios maiores. </p>

<p>Inclusive, comparando com o modelo de colaboração de projetos de código livre ou aberto, Brooks aponta o fato de que, nesses projetos, os construtores e clientes geralmente são os mesmos e isso torna o desenvolvimento algo completamente diferente. Há integridade conceitual, sim, não do sistema como um todo mas de suas partes. Isso pode realmente ser comprovado de maneira fácil do desenvolvimento dos grandes projetos como o Linux onde uma pessoa retém a visão intelectual mais profunda do desenvolvimento e onde as partes são íntegras entre si por via de convenções&#8211;<span class="foreign-word" lang="en">style sheets</span> de desenvolvimento, como Brooks denomina o processo.</p>

<p>Em suma, a visão de Brooks é refrescante em tempos em que metodologias ágeis estão em voga em uma compreensão real do que elas representam. É bom ver alguém que pensou exaustivamente sobre o assunto&#8211;e que está pronto para lançar mais um livro sobre suas reflexões ao longo dos anos&#8211;mostrar o que realmente importa no desenvolvimento. Raros são os times e empresas que possuem maturidade para ver as coisas dessa forma.</p>

<p>Minha única tristeza na participação do evento foi não ter podido pedir a Brooks para autografar meu exemplar&#8211;que repousa em Belo Horizonte à espera de uma mudança futura para São Paulo.</p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/10/22/fred-brooks-sobre-colaboracao/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Treetop: Implementando Brainfuck</title>
		<link>http://logbr.reflectivesurface.com/2009/10/01/treetop-implementando-brainfuck/</link>
		<comments>http://logbr.reflectivesurface.com/2009/10/01/treetop-implementando-brainfuck/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 11:00:27 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[DSL]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Treetop]]></category>
		<category><![CDATA[Tecnologia]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/?p=1342</guid>
		<description><![CDATA[Introdução Continuando a série sobre Treetop, é hora de brincar um pouco mais com todos os conceitos envolvidos e implementar uma linguagem Turing-complete. Para não complicar as coisas, vamos usar uma linguagem bem simples, que demonstre os conceitos e não fique presa em detalhes de sintaxes. Brainfuck, apesar do nome, é uma boa escolha. Extremamente [...]]]></description>
			<content:encoded><![CDATA[<h3>Introdução</h3>

<p>Continuando a <a href="http://logbr.reflectivesurface.com/categoria/treetop/">série sobre Treetop</a>, é hora de brincar um pouco mais com todos os conceitos envolvidos e implementar uma linguagem <span class="foreign-word" lang="en"><a href="http://en.wikipedia.org/wiki/Turing_completeness">Turing-complete</a></span>. </p>

<p>Para não complicar as coisas, vamos usar uma linguagem bem simples, que demonstre os conceitos e não fique presa em detalhes de sintaxes. <a href="http://en.wikipedia.org/wiki/Brainfuck">Brainfuck</a>, apesar do nome, é uma boa escolha. Extremamente minimalista&#8211;possui somente oito comandos usando oito símbolos&#8211;permite uma implementação rápida e ao mesmo tempo permite brincar com os vários conceitos que estamos vendo. Tudo bem, eu admito que ela é um <a href="http://en.wikipedia.org/wiki/Turing_tarpit">Turing tarpit</a> mas serve com uma base interessante para esse artigo. </p>

<p><em>Brainfuck</em> consiste em oito comandos, como mencionado acima, que manipulam um espaço de células de memória. Um ponteiro de instrução é definido para a primeira instrução e os comandos manipulam esse ponteiro para executar as várias instruções. Como cada comando é um simples símbolo, a ambigüidade da gramática é nula. Qualquer outro símbolo dentro do programa é ignorado e pode ser usado como uma comentário. </p>

<p>Os comandos da linguagem são:</p>

<ul>
<li><strong>></strong>, incrementa o ponteiro de dados;</li>
<li><strong>&lt;</strong>, decrementa o ponteiro de dados;</li>
<li><strong>+</strong>, incrementa o <span class="foreign-word" lang="en">byte</span> apontado pelo ponteiro de dados;</li>
<li><strong>-</strong>, decrementa o <span class="foreign-word" lang="en">byte</span> apontado pelo ponteiro de dados;</li>
<li><strong>.</strong>, escreve o valor do <span class="foreign-word" lang="en">byte</span> apontado pelo ponteiro de dados;</li>
<li><strong>.</strong>, lê um <span class="foreign-word" lang="en">byte</span> e armazena no endereço apontado pelo ponteiro de dados;</li>
<li><strong>[</strong>, se o <span class="foreign-word" lang="en">byte</span> no endereço atual do ponteiro de dados é zero, pula para frente até o próximo comando <strong>]</strong>;</li>
<li><strong>]</strong>, se o <span class="foreign-word" lang="en">byte</span> no endereço atual do ponteiro de dados não é zero, pula para trás até o próximo comando <strong>[</strong>.</li>
</ul>

<h3>Reconhecendo a linguagem</h3>

<p>Vamos olhar então como ficaria a gramática da linguagem:</p>

<pre><code>grammar Brainfuck

  rule program
    instruction*
  end
  
  rule instruction
    loop / 
    simple /
    comment
  end
  
  rule loop
    '[' instructions:instruction* ']&#8216;
  end
  
  rule simple
    &#8216;>&#8217; /
    &#8216;<' /
    '+' /
    '-' /
    ',' / 
    '.'
  end
  
  rule comment
    [^\[\]><+-,.]
  end
  
end</code></pre>

<p>A descrição da gramática é simples:</p>

<ul>
<li>Um programa é uma série de zero ou mais instruções;</li>
<li>Uma instruções pode ser composta--ou seja, um <span class="foreign-word" lang="en">loop</span>, denotado pelos comandos <code>[</code> e <code>]</code>--, uma instrução simples, ou um comentário (que é qualquer caractere que não seja uma instrução);</li>
<li>Dentro de um <span class="foreign-word" lang="en">loop</span>, podem existir zero ou mais instruções.</li>
</ul>

<p>Podemos ver que a gramática funciona executando comandos como abaixo:</p>

<pre><code>>> require "rubygems"
=> false
>> require "treetop"
=> true
>> require "brainfuck"
=> true
>> p = BrainfuckParser.new
=> #<BrainfuckParser:0x101375ad0 @consume_all_input=true>
>> p.parse("&gt;&lt;+-[]")
=> SyntaxNode offset=0, "><+-[]":
  SyntaxNode offset=0, ">"
  SyntaxNode offset=1, "<"
  SyntaxNode offset=2, "+"
  SyntaxNode offset=3, "-"
  SyntaxNode+Loop0 offset=4, "[]":
    SyntaxNode offset=4, "["
    SyntaxNode offset=5, ""
    SyntaxNode offset=5, "]"</code></pre>

<p>Note que os comentários também são marcados por nós sintáticos, já que estamos processando os mesmos. Obviamente, quando da interpretação do programa, precisaremos eliminá-los.</p>

<h3>Criando uma árvore sintática</h3>

<p>A partir da gramática, o nosso objetivo é criar uma árvore manipulável, eliminando comentários, agrupando instruções de <span class="foreign-word" lang="en">loop</span> e preparando um ambiente para a execução em si.</p>

<p>Podemos usar a mesma técnica que usamos nos artigos anteriores.</p>

<p>Primeiro, definimos uma representação sintática. O arquivo <var>brainfuck_ast.rb</var> ficaria assim inicialmente:</p>

<pre><code>class Program
  
  attr_reader :instructions
  
  def initialize(instructions)
    @instructions = instructions
  end
  
end

class Instruction
  
  attr_reader :command
  
  def initialize(command)
    @command = command
  end
  
end

class Loop
  
  attr_reader :instructions
  
  def initialize(instructions)
    @instructions = instructions
  end
  
end</code></pre>

<p>Efetivamente, precisamos somente de três tipos de nós: o programa em si, para servir como um <span class="foreign-word" lang="en">container</span> inicial do ambiente, instruções simples e <span class="foreign-word" lang="en">loops</span>.</p>

<p>A seguir precisamos reconhecer isso em nossa gramática. Mostrando a gramática adaptada em um único passo, teríamos algo assim:</p>

<pre><code>grammar Brainfuck

  rule program
    instruction* <strong>&lt;ProgramPredicate&gt;</strong>
  end
  
  rule instruction
    loop / 
    simple /
    comment
  end
  
  rule loop
    '[' instructions:instruction* ']' <strong>&lt;LoopPredicate&gt;</strong>
  end
  
  rule simple
    '>' <strong>&lt;InstructionPredicate&gt;</strong> /
    '<' <strong>&lt;InstructionPredicate&gt;</strong> /
    '+' <strong>&lt;InstructionPredicate&gt;</strong> /
    '-' <strong>&lt;InstructionPredicate&gt;</strong> /
    ',' <strong>&lt;InstructionPredicate&gt;</strong> / 
    '.' <strong>&lt;InstructionPredicate&gt;</strong>
  end
  
  rule comment
    [^\[\]&gt;&lt;+-,.] <strong>&lt;CommentPredicate&gt;</strong>
  end
  
end</code></pre>

<p>E finalmente, o arquivo contendo as extensões, <var>brainfuck_ext.rb</var>, ficaria assim:</p>

<pre><code>module Common
  
  def build_elements(elements)
    elements.
      select { |element| element.respond_to?(:build) }.
      collect { |element| element.build }
  end
  
end

module ProgramPredicate
  
  include Common
  
  def build
    Program.new(build_elements(elements))
  end
  
end

module LoopPredicate
  
  include Common
  
  def build
    Loop.new(build_elements(instructions.elements))
  end
  
end

module InstructionPredicate
  
  def build
    Instruction.new(text_value)
  end
  
end

module CommentPredicate
  
end</code></pre>

<p>No código acima, primeiro definimos um módulo comum que pode ser incluído em outros e possui um método que seleciona instruções que podem ser utilizadas. Depois definimos módulos para o que precisamos processar. E finalmente ignoramos os comentários.</p>

<h3>Interpretando</h3>

<p>Agora precisamos converter o código acima em um interpretador. A implementação é trivial e vamos acompanhá-la passo a passo, escrevendo o arquivo <var>brainfuck_int.rb</var>, que conterá o interpretador:</p>

<pre><code>class BrainfuckInterpreter
  
  def initialize(commands)
    @ast = BrainfuckParser.new.parse(commands).build
  end
    
end</code></pre>

<p>Esse método inicializa o interpretador recebendo uma série de comandos na forma de uma <code>string</code> e construindo uma árvore sintática final da mesma. </p>

<p>O próximo passo é começar a execução em si. Um interpretador <em>Brainfuck</em> deve inicialmente alocar um espaço de memória para execução e inicializar o ponteiro de instruções. Em seguida, deve seguir de instrução em instrução, rodando o comando em questão. O método que faz isso é o seguinte:</p>

<pre><code>class BrainfuckInterpreter
  
  def initialize(commands)
    @ast = BrainfuckParser.new.parse(commands).build
  end
    
  <strong>def execute
    @addresses = [0] * 3000
    @pointer = 0
    execute_ast_node(@ast)
  end</strong>
    
end</code></pre>

<p>Esse método inicializa o espaço de instruções e o ponteiro e em seguida chama a execução de um nó da árvore. Embora esse nó sempre seja um nó do tipo <code>Program</code>, o método está preparado para executar qualquer instrução.</p>

<p>Na seqüência, está a implementação do método <code>execute_ast_node</code>:</p>

<pre><code>class BrainfuckInterpreter
  
  def initialize(commands)
    @ast = BrainfuckParser.new.parse(commands).build
  end
    
  def execute
    @addresses = [0] * 3000
    @pointer = 0
    execute_ast_node(@ast)
  end
  
  protected
  
  <strong>def execute_ast_node(ast)
    send("execute_" + ast.class.name.downcase, ast)
  end</strong>
    
end</code></pre>

<p>O método é simplesmente um <code>dispatch</code> para o método apropriado para lidar com o tipo de nó em si. </p>

<p>O nó <code>program</code> é o que possui a implementação mais simples. Com o mesmo representa somente uma lista de instruções, a execução consiste em nada mais do que rodar essa lista, pedindo a execução de cada nó filho. A implementação fica, então, como mostrado abaixo:</p>

<pre><code>class BrainfuckInterpreter
  
  def initialize(commands)
    @ast = BrainfuckParser.new.parse(commands).build
  end
    
  def execute
    @addresses = [0] * 3000
    @pointer = 0
    execute_ast_node(@ast)
  end
  
  protected
  
  def execute_ast_node(ast)
    send("execute_" + ast.class.name.downcase, ast)
  end
  
  <strong>def execute_program(ast)
    ast.instructions.each { |instruction| execute_ast_node(instruction) }
  end</strong>
    
end</code></pre>

<p>A implementação dos nós <code>instruction</code> é igualmente simples:</p>

<pre><code>class BrainfuckInterpreter
  
  def initialize(commands)
    @ast = BrainfuckParser.new.parse(commands).build
  end
    
  def execute
    @addresses = [0] * 3000
    @pointer = 0
    execute_ast_node(@ast)
  end
  
  protected
  
  def execute_ast_node(ast)
    send("execute_" + ast.class.name.downcase, ast)
  end
  
  def execute_program(ast)
    ast.instructions.each { |instruction| execute_ast_node(instruction) }
  end
  
  <strong>def execute_instruction(ast)
    case ast.command
    when '>'
      @pointer += 1
    when '<'
      @pointer -= 1      
    when '+'
      @addresses[@pointer] += 1
    when '-'
      @addresses[@pointer] -= 1      
    when ','
      @addresses[@pointer] = STDIN.getc
    when '.'
      STDOUT.print @addresses[@pointer].chr
    end
  end</strong>
    
end</code></pre>

<p>Para cada instrução, executamos a instrução correspondente. As duas primeiras simplesmente movem o ponteiro de instrução--não estamos aqui, executando qualquer tipo de testes para evitar instruções inválidas. A duas instruções seguintes não movem o ponteiro de dados e simplesmente manipulam o dado que está no endereço especificado. Finalmente, as demais instruções lêem um <span class="foreign-word" lang="en">byte</span> da entrada padrão para o endereço atual ou emitem o <span class="foreign-word" lang="en">byte</span> atual para a saída padrão.</p>

<p>Finalmente, temos a implementação de um <span class="foreign-word" lang="en">loop</span> que também é trivial:</p>

<pre><code>class BrainfuckInterpreter
  
  def initialize(commands)
    @ast = BrainfuckParser.new.parse(commands).build
  end
    
  def execute
    @addresses = [0] * 3000
    @pointer = 0
    execute_ast_node(@ast)
  end
  
  protected
  
  def execute_ast_node(ast)
    send("execute_" + ast.class.name.downcase, ast)
  end
  
  def execute_program(ast)
    ast.instructions.each { |instruction| execute_ast_node(instruction) }
  end
  
  def execute_instruction(ast)
    case ast.command
    when '>'
      @pointer += 1
    when '<'
      @pointer -= 1      
    when '+'
      @addresses[@pointer] += 1
    when '-'
      @addresses[@pointer] -= 1      
    when ','
      @addresses[@pointer] = STDIN.getc
    when '.'
      STDOUT.print @addresses[@pointer].chr
    end
  end
  
  <strong>def execute_loop(ast)
    while @addresses[@pointer] != 0
      ast.instructions.each { |instruction| execute_ast_node(instruction) }
    end
  end
  </strong>
    
end</code></pre>

<p>A implementação simplesmente verifica se o endereço atual contém um valor nulo e caso contrário continua a execução das instruções aninhadas. Isso é o mesmo que pular para frente a para trás nos operadores <code>[</code> e <code>]</code>.</p>

<p>Para completar o quadro e facilitar a execução, podemos incluir métodos auxiliares:</p>

<pre><code>class BrainfuckInterpreter
  
  def initialize(commands)
    @ast = BrainfuckParser.new.parse(commands).build
  end
    
  def execute
    @addresses = [0] * 3000
    @pointer = 0
    execute_ast_node(@ast)
  end
  
  <strong>def self.run(commands)
    BrainfuckInterpreter.new(commands).execute
  end

  def self.run_file(file)
    BrainfuckInterpreter.new(File.readlines(file).join).execute
  end</strong>
  
  
  protected
  
  def execute_ast_node(ast)
    send("execute_" + ast.class.name.downcase, ast)
  end
  
  def execute_program(ast)
    ast.instructions.each { |instruction| execute_ast_node(instruction) }
  end
  
  def execute_instruction(ast)
    case ast.command
    when '>'
      @pointer += 1
    when '<'
      @pointer -= 1      
    when '+'
      @addresses[@pointer] += 1
    when '-'
      @addresses[@pointer] -= 1      
    when ','
      @addresses[@pointer] = STDIN.getc
    when '.'
      STDOUT.print @addresses[@pointer].chr
    end
  end
  
  def execute_loop(ast)
    while @addresses[@pointer] != 0
      ast.instructions.each { |instruction| execute_ast_node(instruction) }
    end
  end
    
end</code></pre>

<p>E com isso, podemos testar um programa. Abra um novo arquivo chamado <var>brainfuck_test.rb</var> e introduza o seguinte código:</p>

<p><pre><code>require "rubygems"
require "treetop"
require "brainfuck"
require "brainfuck<em>ext"
require "brainfuck</em>ast"
require "brainfuck_int"</p>

<p>code = &lt;&lt;-EOF
    +++ +++ +++ +           initialize counter (cell #0) to 10
    [                       use loop to set the next four cells to 70/100/30/10
        &gt; +++ +++ +             add  7 to cell #1
        &gt; +++ +++ +++ +         add 10 to cell #2 
        &gt; +++                   add  3 to cell #3
        &gt; +                     add  1 to cell #4
        &lt;&lt;&lt; &lt; -                 decrement counter (cell #0)
    ]<br />
    &gt;++ .                   print 'H'
    &gt;+.                     print 'e'
    +++ +++ +.              print 'l'
    .                       print 'l'
    +++ .                   print 'o'
    &gt;++ .                   print ' '
    &lt;&lt;+ +++ +++ +++ +++ ++. print 'W'
    &gt;.                      print 'o'
    +++ .                   print 'r'
    --- --- .               print 'l'
    --- --- --.             print 'd'
    &gt;+.                     print '!'
    &gt;.                      print '\n'
EOF</p>

<p>BrainfuckInterpreter.run(code)</pre></code></p>

<p>O código está "comentado" (lembre-se que comandos não reconhecidos são ignorados). Se você rodar o programa agora, obterá o resultado desejado:</p>

<pre><code>~$ ruby brainfuck_test.rb 
Hello World!</code></pre>

<p>Pronto! Você agora possui um interpretador funcional--embora seriamente lento e incrivelmente complexo de se programar--de uma linguagem computacionalmente completa, capaz de realizar qualquer tarefa que você deseje executar.</p>

<p>Um outro teste interessante é rodar o código que imprime a canção <a href="http://99-bottles-of-beer.net/language-brainfuck-1718.html">99 bottles of beer on the wall</a>, cuja versão em Brainfuck é um pesadelo. Você verá que, embora lento, o código consegue imprimir as linhas com relativa facilidade.</p>

<p>Comparando a velocidade de uma versão Ruby e uma versão <em>Brainfuck</em> da canção temos os resultados (Ruby 1.9; iMac 2.8Ghz recente rodando Snow Leopard):</p>

<pre><code>~$ time 99.bf
  real  0m0.679s
  user  0m0.586s
  sys   0m0.045s
  
~$ time 99.rb
  real  0m0.016s
  user  0m0.006s
  sys   0m0.006s</code></pre>

<p>Digamos que imprimir caracteres um a um não é uma forma eficiente de se trabalhar. Obviamente, <code>double dispatching</code> também não é uma técnica boa em todos os casos e vai adicionar um certo <span class="foreign-word" lang="en">overhead</span> em troca de flexibilidade. Mas, mesmo removendo o tempo de carga do Ruby, não haveria tantas melhoras no programa.</p>

<h3>Conclusão</h3>

<p>Como esse artigo vimos como fazer a cadeia completa de implementação, incluindo a implementação de um interpretador funcional. Mesmo que a implementação seja bem simples, as lições são as mesmas para qualquer outra linguagem e o limite está mais na sintaxe e semântica do que nas técnicas em si. Um exercício para o leitor é implementar um otimizador para <em>Brainfuck</em> que agrupe instruções iguais e efetue as operações em uma única passagem. Aqui, é claro, cabe uma aviso: implementações de linguagens generalizadas de programação obviamente precisam de muito mais do que isso para funcionar bem. O Treetop oferece uma conveniência quando velocidade máxima de execução não é o desejado e sim velocidade de implementação.</p>

<p>Com isso encerramos essa série sobre Treetop. Eventualmente, é possível que eu escreva um artigo sobre a implementação de uma linguagem menos minimalista, mas no momento não há tempo para isso. Espero que o tempo gasto lendo esses artigos tenha sido proveitoso.</p>

<p><strong>Nota:</strong> Para ver a série completa, siga a categoria <a href="http://logbr.reflectivesurface.com/categoria/treetop/">Treetop</a> deste <span class="foreign-word" lang="en">blog</span>.</p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/10/01/treetop-implementando-brainfuck/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Treetop: Depuração</title>
		<link>http://logbr.reflectivesurface.com/2009/09/30/treetop-depuracao/</link>
		<comments>http://logbr.reflectivesurface.com/2009/09/30/treetop-depuracao/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 11:00:37 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[DSL]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Treetop]]></category>
		<category><![CDATA[Tecnologia]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/?p=1313</guid>
		<description><![CDATA[Introdução Continuando a série sobre Treetop, o objetivo desse artigo é falar um pouco sobre a depuração de gramáticas. Muitas vezes, o mecanismo de verificação do que a gramática está esperando, ilustrado no primeiro artigo, não é suficiente para identificar porque um reconhecimento está faltando&#8211;especialmente quando a gramática se torna mais complexa. Parte da depuração [...]]]></description>
			<content:encoded><![CDATA[<h3>Introdução</h3>

<p>Continuando a <a href="http://logbr.reflectivesurface.com/categoria/treetop/">série sobre Treetop</a>, o objetivo desse artigo é falar um pouco sobre a depuração de gramáticas. Muitas vezes, o mecanismo de verificação do que a gramática está esperando, ilustrado no primeiro artigo, não é suficiente para identificar porque um reconhecimento está faltando&#8211;especialmente quando a gramática se torna mais complexa.</p>

<p>Parte da depuração consiste, na verdade, em tentar evitar erros mais primários. Outra parte consiste em usar alguns mecanismos para identificar problemas quando os erros primários já foram removidos. Falaremos de cada um deles na seqüência.</p>

<h3>Evitando erros comuns</h3>

<p>Um detalhe que deixei de fora no primeiro artigo é que uma PEG representa um <span class="foreign-word" lang="en">parser</span> descendente recursivo. E uma das fraquezas desse tipo de <span class="foreign-word" lang="en">parser</span> é que eles não são capazes de lidar com recursividade à esquerda. </p>

<p>Por exemplo, veja a regra abaixo:</p>

<pre><code>string-of-a := string-of-a 'a' | 'a'</code></pre>

<p>A lógica dita que isso deveria reconhecer uma seqüência de caracteres &#8220;a&#8221;. Na prática, isso não acontecer porque a regra está escrita de tal forma que para reconhecer a produção &#8220;string-of-a&#8221; seria necessário reconhecer &#8220;string-of-a&#8221; em seguida, o que leva, necessariamente, a recursividade infinita.</p>

<p>Existem <span class="foreign-word" lang="en">packrat parsers</span> que são capazes de lidar com isso mas não é o caso do Treetop. Existem <a href="http://en.wikipedia.org/wiki/Left_recursion#Removing_left_recursion">técnicas formais</a> para lidar com isso mas geralmente a melhor opção é criar uma regra que faça o processamento indireto do que se precisar e, com alguma criatividade, reescrever o necessário em uma fase posterior. </p>

<p>Para ilustrar ainda mais o ponto, veja a gramática abaixo que é uma variação da que estamos usando. </p>

<pre><code>value := [0-9]+ / '(' expression ')'
product := expression (('*' / '/') expression)*
sum := expression (('+' / '-') expression)*
expression := product / sum / value</code></pre>

<p>O problema com esse é que para saber o que é uma expressão, precisamos saber o que é um produto. Mas, para saber um produto, precisamos também saber o que é uma expressão.</p>

<p>A solução é simples:</p>

<pre><code>expression := sum
sum := product (('+' / '-')) product)*
product := value (('*' / '/')) value)*
value := number / '(' expression ')'
number := [0-9]+</code></pre>

<p>Um segundo ponto é utilizar apropriadamente operadores de <span class="foreign-word" lang="en">lookahead</span> para ajudar a remover ambigüidades da gramática. O uso dos mesmos é especialmente necessário por conta do modo como o operador de escolha ordenada trabalha. Como a segunda opção somente é considerada caso a primeira falhe, algumas vezes é necessário especificar cenários de falha na primeira para forçar a segunda a acontecer.</p>

<p>Suponha, por exemplo, que você tenha a seguinte gramática:</p>

<pre><code>expression := numeric_expression / string_expression
numeric_expression := identifier ('+' identifier)*
string_expression := identifier ('||' identifier)*
identifier := [a-z]+</code></pre>

<p>O problema dessa gramática é que a regra <code>string_expression</code> jamais será reconhecida. O que acontece é que para tentar descobrir se uma expressão é numérica, o <span class="foreign-word" lang="en">parser</span> precisa encontrar um identificador. Quando isso acontece, como a regra <code>numeric_expression</code> já possui um reconhecimento parcial, o <span class="foreign-word" lang="en">parser</span> tenta então encontrar o terminal <code>+</code>. Se isso não acontece&#8211;porque há um terminal <code>||</code>&#8211;o <span class="foreign-word" lang="en">parser</span> aborta por não ter como seguir naquela regra. </p>

<p>Uma solução simples para resolver a ambigüidade é olhar para a frente e somente dizer que algo é uma expressão numérica se o identificador não for seguido por um operador que atue sobre <code>strings</code>. A gramática ficaria assim então:</p>

<pre><code>expression := numeric_expression / string_expression
numeric_expression := identifier <strong>!'||'</strong> ('+' identifier)*
string_expression := identifier ('||' identifier)*
identifier := [a-z]+</code></pre>

<p>Na maioria dos casos, isso é tudo o que você precisa para resolver a situação. Uma outra alternativa, é claro, é condensar as duas expressões, já que elas são essencialmente equivalentes, e fazer a diferenciação semântica em uma fase posterior (na análise semântica, mais ao ponto).</p>

<p>Um terceiro ponto é saber distinguir bem os separadores necessários para reconhecimento dos terminais. Em muitos casos, o modo mais simples é ideal. Algumas vezes, entretanto, é preciso usar alguma sofisticação. Para ilustrar, usando um exemplo da própria documentação do Treetop, teríamos algo como:</p>

<pre><code>rule end_keyword
  'end' ![a-zA-Z0-9_]
end</code></pre>

<p>Essa regra reconhece uma palavra chave <code>end</code> em uma linguagem em que palavras chaves podem ser seguidas por pontuação qualquer mas não por caracteres alfanuméricos. </p>

<h3>Representações gráficas</h3>

<p>Em muitos casos, é interessante visualizar o que o Treetop está reconhecendo. Para isso, uma característica interessante do mesmo adicionada em versões recentes é a habilidade de gerar um arquivo para o <a href="http://www.graphviz.org/">Graphviz</a>. O uso é bem simples.</p>

<pre><code>>> require "treetop"
=> true
>> require "simple_math"
=> true
>> p = SimpleMathParser.new
=> #<SimpleMathParser:0x101361210 @consume_all_input=true>
>> p.parse("1+2*3-(4/5)").write_dot_file("results")
=> nil</code></pre>

<p>O resultado é um arquivo <var>results.dot</var> que pode ser processado em uma imagem como no exemplo abaixo:</p>

<pre><code>~$ dot -Tpng results.dot > results.png</code></pre>

<p>A imagem final ficaria assim:</p>

<p><img src="http://logbr.reflectivesurface.com/wp-content/uploads/2009/09/parsing_123_4_5.png" alt="Parsing 1+2*3-(4/5)" /></p>

<p>Essa é uma maneira fácil de ver como o Treetop reconhecer a sintaxe de maneira mais básica.</p>

<h3>Capturando a execução</h3>

<p>Uma última forma de capturar o resultado da execução é interceptar as chamadas do <span class="foreign-word" lang="en">parser</span> gerado pelo Treetop. Essa é a forma menos confiável porque depende do conhecimento da estrutura interna do Treetop, que pode mudar a qualquer momento. Apesar disso, mesmo com adaptações necessárias de quando em quando, é uma boa forma de saber o que o Treetop está fazendo por trás das cenas.</p>

<p>A primeira coisa a fazer é gerar o arquivo do <span class="foreign-word" lang="en">parser</span> em si:</p>

<pre><code>~$ tt simple_math.rb</code></pre>

<p>Isso gera o <span class="foreign-word" lang="en">parser</span> em sua forma final, ao invés de compilá-lo cada vez que o <code>require</code> é feito.</p>

<p>A partir disso, é possível construir sobre os módulos que o Treetop gerou. Existe um módulo <code>default</code> com o nome que foi dado a gramática&#8211;no nosso caso, esse módulo é o <code>SimpleMath</code>. Em um arquivo <var>simple<em>math</em>debug.rb</var>, poderíamos ter o seguinte código:</p>

<pre><code>require "treetop"
require "simple_math"

module SimpleMath
  
  def __depth
    @__depth ||= 0
  end
  
  def __inc_depth
    @__depth = __depth + 1
  end

  def __dec_depth
    @__depth = __depth - 1
  end
  
end

SimpleMath.instance_methods.each do |method|
  
  next unless method =~ /^_nt_(.*)$/
  
  rule = $1
  
  SimpleMath.send(:alias_method, ("_old" + method).to_sym, method.to_sym)
  
  SimpleMath.send(:define_method, method.to_sym) do
    puts (" " * __depth) + rule
    __inc_depth
    result = send("_old" + method)
    __dec_depth
    result
  end  
  
end</code></pre>

<p>O que o código acima faz é interceptar as chamadas aos métodos que começam com <code>_nt_</code>, que são os métodos que efetivamente implementam o reconhecimento de produções e rastrear a profundidade em que estão sendo chamados para exibir a ordem em que as mesmas foram feitos.</p>

<p>Veja um exemplo de chamada:</p>

<pre><code>>> require "simple_math_debug"
=> true
>> p = SimpleMathParser.new
=> #<SimpleMathParser:0x10143d8a0 @consume_all_input=true>
>> p.parse("1+2*3")
expression
 term
  factor
   number
  factor
 expression
  term
   factor
    number
   term
    factor
     number
    factor
  term
=> SyntaxNode+Expression0 offset=0, "1+2*3" (expression,term):
  SyntaxNode offset=0, "1":
    SyntaxNode offset=0, "1"
  SyntaxNode offset=1, "+"
  SyntaxNode+Term0 offset=2, "2*3" (factor,term):
    SyntaxNode offset=2, "2":
      SyntaxNode offset=2, "2"
    SyntaxNode offset=3, "*"
    SyntaxNode offset=4, "3":
      SyntaxNode offset=4, "3"
>> p.parse("1+")
expression
 term
  factor
   number
  factor
 expression
  term
   factor
    number
   factor
  term
 term
</code></pre>

<p>Essa é uma maneira simples de saber o que está acontecendo e de ver se há falhas no reconhecimento específico de alguma regra. Como algumas regras podem ser bem complexas em sua implementação, esse tipo de estratégia permite uma visualização das entradas e saídas dos métodos.</p>

<h3>Conclusão</h3>

<p>Embora o Treetop seja relativamente simples em sua implementação, em alguns momentos é preciso quebrar a abstração e olhar o que está sob o código externalizado. As técnicas acima podem ajudar a resolver problemas comuns que vão surgir durante a implementação de uma linguagem qualquer.</p>

<p>No próximo artigo, um bônus: uma linguagem <span class="foreign-word" lang="en">Turing-complete</span> implementada usando o Treetop para análise sintática.</p>

<p><strong>Nota:</strong> Para seguir a série completa, siga a categoria <a href="http://logbr.reflectivesurface.com/categoria/treetop/">Treetop</a> deste <span class="foreign-word" lang="en">blog</span>.</p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/09/30/treetop-depuracao/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Treetop: Usando árvores sintáticas</title>
		<link>http://logbr.reflectivesurface.com/2009/09/29/treetop-usando-arvores-sintaticas/</link>
		<comments>http://logbr.reflectivesurface.com/2009/09/29/treetop-usando-arvores-sintaticas/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 11:00:03 +0000</pubDate>
		<dc:creator>Ronaldo</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[DSL]]></category>
		<category><![CDATA[Programação]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Treetop]]></category>
		<category><![CDATA[Tecnologia]]></category>

		<guid isPermaLink="false">http://logbr.reflectivesurface.com/?p=1311</guid>
		<description><![CDATA[Introdução Continuando a série sobre Treetop, vamos evoluir a utilização do parser de interpretação direta para um formato mais sofisticado que leve em conta outras características de processamento posterior. Na maioria dos casos, interpretação direta é suficiente para extrair da linguagem o necessário para a transformação ou execução. Algumas vezes, entretanto, as estruturas reconhecidas precisarão [...]]]></description>
			<content:encoded><![CDATA[<h3>Introdução</h3>

<p>Continuando a <a href="http://logbr.reflectivesurface.com/categoria/treetop/">série sobre Treetop</a>, vamos evoluir a utilização do <span class="foreign-word" lang="en">parser</span> de interpretação direta para um formato mais sofisticado que leve em conta outras características de processamento posterior. Na maioria dos casos, interpretação direta é suficiente para extrair da linguagem o necessário para a transformação ou execução. Algumas vezes, entretanto, as estruturas reconhecidas precisarão de algum refinamento ou recombinação posterior que fazer valer a pena um formato intermediário.</p>

<p>Para ilustrar isso, vamos usar a mesma gramática dos exemplos anteriores para gerar uma árvore sintática formalizada para as estruturas reconhecidas. E para fazer isso, vamos também usar algumas características adicionais do Treetop que gerar código mais elegante e com acoplamento menor. </p>

<p>Nossa gramática inicial permanece a mesma, como visto abaixo:</p>

<pre><code>grammar SimpleMath

  rule expression
    term ('+' / '-') expression / 
    term
  end
  
  rule term
    factor ('*' / '/') term / 
    factor
  end
  
  rule factor
    '(' expression ')' / 
    number
  end
  
  rule number
    [0-9]+
  end
  
end</code></pre>

<h3>Usando módulos adicionais</h3>

<p>Além de permitir a inserção de código Ruby diretamente na gramática, o Treetop permite duas outras formas de extensão da gramática. Uma dessas formas é definir classes específicas que herdam de SyntaxNode e permitem injeção de código manual no <span class="foreign-word" lang="en">run-time</span> do Treetop. Uma segunda forma, ainda mais elegante, é a definição de módulos que serão automaticamente utilizados pelo Treetop através do mecanismo usual de <span class="foreign-word" lang="en">mixins</span> do Ruby. Esse é o método que utilizaremos agora.</p>

<p>Vamos dizer que queremos transformar as produções reconhecidas pela linguagem definida por nossa gramática em uma árvore sintática específica para a mesma que possa ser guardada e posteriormente executada. </p>

<p>Obviamente, estamos usando uma linguagem tão simples que não há muitos benefícios em fazer isso. Mas, muitas vezes, isso faz sentido até por razões de performance. Digamos, por exemplo, que você esteja extraindo uma representação que será executada várias vezes com parâmetros diferentes. Não vale a pena executar o <span class="foreign-word" lang="en">parsing</span> a cada momento, utilizando o código diretamente injetado. Para esses momentos, uma representação sintática definida e específica para o domínio é bem mais interessante.</p>

<p>Para deixar as coisas mais interessantes, vamos modificar a nossa gramática acima para permitir que variáveis externas seja definidas e utilizadas, como por exemplo, para computar a expressão <code>(b * b) - (4 * a * c)</code> onde <code>a</code>, <code>b</code> e <code>c</code> são parâmetros variáveis fornecidos pelo ambiente de execução. </p>

<p>A gramática ficaria assim:</p>

<pre><code>grammar SimpleMath

  rule expression
    term ('+' / '-') expression / 
    term
  end
  
  rule term
    factor ('*' / '/') term / 
    factor
  end
  
  rule factor
    '(' expression ')' / 
    primary
  end
  
  rule primary
    variable /
    number
  end
  
  rule variable
    [a-z]+
  end
  
  rule number
    [0-9]+
  end
  
end</code></pre>

<p>Como é fácil perceber, não mudamos muita coisa. Existe agora uma regra adicional que define uma primária que pode ser um número ou uma variável e uma variável é simples um identificador alfabético simples.</p>

<p>Nossa árvore sintática será definida por uma coleção de nós com tipos que representam as várias <em>estruturas</em> que queremos ter no final. Por exemplo, queremos representar operações (um nó com um operador e dois operadores), variáveis e constantes. Essa é uma representação que definimos e que não necessariamente corresponde à árvore sintática reconhecida inicialmente pelo <span class="foreign-word" lang="en">parser</span>. Estamos transformando uma representação em outra.</p>

<p>A primeira coisa que precisamos, então é definir essas classes. Em um arquivo adicional, chamado <var>simple<em>math</em>ast.rb</var>, vamos inserir o seguinte código inicial:</p>

<pre><code>class Constant
  
  def initialize(value)
    @value = value
  end
  
end</code></pre>

<p>O código é trivial e, inicialmente, só define como vamos armazenar as informações. É fácil perceber que não estamos assumindo absolutamente nada sobre os dois operandos (<code>left_side</code> e <code>right_side</code>) na classe <code>Operation</code>. Os dois operandos podem ser outros nós da árvore tão complexos ou simples como necessário, ou seja, podem ser outras operações ou variáveis ou constantes. </p>

<p>O que precisamos agora é uma forma de construir a nossa árvore. Para isso, vamos interceptar a execução do <span class="foreign-word" lang="en">parser</span> usando módulos adicionais que serão inseridos nos nós sintáticos do Treetop para gerar o que precisamos.</p>

<p>A primeira coisa a fazer é adaptar a gramática. Como no artigo anterior, vamos começar de modo simples, reconhecendo somente números. A gramática ficaria assim:</p>

<pre><code>grammar SimpleMath

  rule expression
    term ('+' / '-') expression / 
    term
  end
  
  rule term
    factor ('*' / '/') term / 
    factor
  end
  
  rule factor
    '(' expression ')' / 
    primary
  end
  
  rule primary
    variable /
    number
  end
  
  rule variable
    [a-z]+
  end
  
  rule number
    [0-9]+ <strong>&lt;NumberPredicate&gt;</strong>
  end
  
end</code></pre>

<p>Veja a notação em negrito. Essa notação pede ao Treetop que introduza um módulo chamado <code>NumberPredicate</code> no nó sintático que reconhece números. Os métodos disponíveis no módulo serão, conseqüentemente, disponibilizados para o nó. </p>

<p>Para definir esse módulo, vamos usar um arquivo chamado <var>simple<em>math</em>ext.rb</var> com o seguinte conteúdo inicialmente:</p>

<pre><code>module NumberPredicate
  
  def build
    Constant.new(text_value.to_f)
  end
  
end</code></pre>

<p>O código define um módulo que será injetado no reconhecimento da produção <code>number</code> da gramática e que possui um método <code>build</code> que fará a construção inicial da árvore sintática. Esse método será usado para geração final da árvore. Vamos ver o método em execução no irb:</p>

<pre><code>>> require "treetop"
=> true
>> require "simple_math_ast"
=> true
>> require "simple_math_ext"
=> true
>> require "simple_math_4"
=> true
>> p = SimpleMathParser.new
=> #<SimpleMathParser:0x10133c320 @consume_all_input=true>
>> p.parse("1")
=> SyntaxNode+NumberPredicate offset=0, "1" (build):
  SyntaxNode offset=0, "1"
>> p.parse("1").build
=> #<Constant:0x1012b6c98 @value=1.0></code></pre>

<p>Note como o nó sintático que representa o número agora possui automaticamente o módulo <code>NumberPredicate</code> adicionado e como o método <code>build</code> também faz parte do mesmo. Um problema que temos é a visualização da árvore, que pode ficar complicada à medida que mais nós são adicionados. Para resolver isso, uma maneira conveniente é utilizar <a href="http://en.wikipedia.org/wiki/S-expression">S-expressions</a> para gerar a visualização. A implementação é trivial:</p>

<pre><code>class Constant
  
  def initialize(value)
    @value = value
  end
  
  <strong>def to_sexp
    [:constant, @value]
  end</strong>
  
end</code></pre>

<p>E o resultado agora poderia ser visto com mais clareza:</p>

<pre><code>>> p.parse("1").build.to_sexp
=> [:constant, 1.0]</code></pre>

<p>A implementação de variáveis é similar. O nó da árvore sintática seria descrito no arquivo <var>simple<em>math</em>ast.rb</var> como mostrado abaixo:</p>

<pre><code><strong>class Variable
  
  def initialize(name)
    @name = name
  end
  
  def to_sexp
    [:variable, @name]
  end
  
end</strong>

class Constant
  
  def initialize(value)
    @value = value
  end
  
  def to_sexp
    [:constant, @value]
  end
  
end</code></pre>

<p>Precisamos então criar o predicado que gera esse novo nó. No arquivo <var>simple<em>math</em>ext.rb</var>, o código ficaria assim:</p>

<pre><code><strong>module VariablePredicate

  def build
    Variable.new(text_value.downcase.to_sym)
  end
  
end</strong>

module NumberPredicate
  
  def build
    Constant.new(text_value.to_f)
  end
  
end</code></pre>

<p>Finalmente, a gramática seria modificada para reconhecer isso:</p>

<pre><code>grammar SimpleMath

  rule expression
    term ('+' / '-') expression / 
    term
  end
  
  rule term
    factor ('*' / '/') term / 
    factor
  end
  
  rule factor
    '(' expression ')' / 
    primary
  end
  
  rule primary
    variable /
    number
  end
  
  rule variable
    [a-z]+ <strong>&lt;VariablePredicate&gt;</strong>
  end
  
  rule number
    [0-9]+ &lt;NumberPredicate&gt;
  end
  
end</code></pre>

<p>Usando o código, teríamos a possibilidade de fazer algo assim:</p>

<pre><code>>> p.parse("x")
=> SyntaxNode+VariablePredicate offset=0, "x" (build):
  SyntaxNode offset=0, "x"
>> p.parse("x").build.to_sexp
=> [:variable, &#x3a;x]</code></pre>

<p>Implementar o nó que reconhece operações é também uma tarefa relativamente simples. Primeiro, temos o código do nó em si:</p>

<pre><code><strong>class Operation
  
  def initialize(operator, left_side, right_size)
    @operator = operator
    @left_side = left_side
    @right_side = right_size
  end
  
  def to_sexp
    [@operator, @left_side.to_sexp, @right_side.to_sexp]
  end
  
end</strong>

class Variable
  
  def initialize(name)
    @name = name
  end
  
  def to_sexp
    [:variable, @name]
  end
  
end

class Constant
  
  def initialize(value)
    @value = value
  end
  
  def to_sexp
    [:constant, @value]
  end
  
end</code></pre>

<p>Note o uso recursivo dos lados esquerdo e direito na implementação do método <code>to_sexp</code>. </p>

<p>A implementação do predicado é um pouco maior agora já que precisamos lidar com dois casos: operações simples e expressões que estão entre parênteses (da mesma fora que fizemos no artigo anterior). A maneira mais simples é usar não um, mas dois predicados:</p>

<pre><code><strong>module NestedExpressionPredicate
  
  def build
    expression.build
  end
  
end

module OperationPredicate
  
  def build
    Operation.new(operator.text_value.downcase.to_sym, 
      operand1.build, operand2.build)
  end
  
end</strong>

module VariablePredicate

  def build
    Variable.new(text_value.downcase.to_sym)
  end
  
end

module NumberPredicate
  
  def build
    Constant.new(text_value.to_f)
  end
  
end</code></pre>

<p>Usaremos o primeiro predicado para construir as expressões entre parênteses. Nesse caso, não precisamos construir a expressão simplesmente já que queremos somente ignorar os parênteses e construir a árvore da expressão aninhada. Por outro lado, o predicado da expressão já constrói um nó formal, da maneira que precisamos. Inserir isso na gramática é simples:</p>

<pre><code>grammar SimpleMath

  rule expression
    <strong>operand1:</strong>term <strong>operator:</strong>('+' / '-') <strong>operand2:</strong>expression <strong>&lt;OperationPredicate&gt;</strong> / 
    term
  end
  
  rule term
    <strong>operand1:</strong>factor <strong>operator:</strong>('*' / '/') <strong>operand2:</strong>term <strong>&lt;OperationPredicate&gt;</strong> / 
    factor
  end
  
  rule factor
    '(' expression ')' <strong>&lt;NestedExpressionPredicate&gt;</strong> / 
    primary
  end
  
  rule primary
    variable /
    number
  end
  
  rule variable
    [a-z]+ <VariablePredicate>
  end
  
  rule number
    [0-9]+ <NumberPredicate>
  end
  
end</code></pre>

<p>Note que estamos nomeando terminais para uso nos módulos. As regras são as mesmas que descrevemos no último artigo.</p>

<p>Com isso pronto, podemos reconhecer expressões inteiras:</p>

<pre><code>>> p.parse("x").build.to_sexp
=> [:variable, &#x3a;x]
>> p.parse("1+1").build.to_sexp
=> [:+, [:constant, 1.0], [:constant, 1.0]]
>> p.parse("x+1").build.to_sexp
=> [:+, [:variable, &#x3a;x], [:constant, 1.0]]
>> p.parse("x+1-y").build.to_sexp
=> [:+, [:variable, &#x3a;x], [:-, [:constant, 1.0], [:variable, :y]]]
>> p.parse("(b*b)-(4*a*c)").build.to_sexp
=> [:-, 
    [:*, [:variable, :b], [:variable, :b]], 
    [:*, [:constant, 4.0], [:*, [:variable, :a], [:variable, :c]]]]</code></pre>

<p>A última linha foi quebrada para facilitar o entendimento da expressão gerada. </p>

<p>Se você observar agora somente o resultado de uma chamada ao método <code>build</code>, verá claramente que as estruturas estão aninhadas, com nós do tipo <code>Operation</code> codificando esse aninhamento. </p>

<p>É fácil perceber que não há muito mistério na criação de árvores sintáticas derivadas. Caso você queira ver um exemplo bem sofisticado disso, o projeto <a href="http://cukes.info/">Cucumber</a> é uma boa opção. Para <span class="foreign-word" lang="en">parsing</span> das estórias, o projeto usa um linguagem bem sofisticada descrita com o Treetop.</p>

<h3>Interpretando a árvore sintática</h3>

<p>Agora que temos uma árvore, podemos continuar executando a representação descrita pela árvore. Existem várias maneiras de fazer isso, mas a mais simples é usar a própria árvore recursivamente. Podemos criar um método <code>run</code> em cada nó que devolve o valor executado do mesmo. Esse método precisa receber algum tipo de ambiente para que variáveis possam receber seus valores. É fácil perceber que podemos gerar um árvore uma única vez e processá-la múltiplas vezes usado ambientes diferentes. </p>

<p>A maneira mais simples de implementar um ambiente é passar um <code>hash</code> que contenha as variáveis. A implementação, que é trivial, ficaria assim:</p>

<pre><code>class Operation
  
  def initialize(operator, left_side, right_size)
    @operator = operator
    @left_side = left_side
    @right_side = right_size
  end
  
  <strong>def run(env = {})
    @left_side.run(env).send(@operator, @right_side.run(env))
  end</strong>
  
  def to_sexp
    [@operator, @left_side.to_sexp, @right_side.to_sexp]
  end
  
end

class Variable
  
  def initialize(name)
    @name = name
  end
  
  <strong>def run(env = {})
    env[@name] || (raise "The variable #{@name} is undefined")
  end</strong>
  
  def to_sexp
    [:variable, @name]
  end
  
end

class Constant
  
  def initialize(value)
    @value = value
  end
  
  <strong>def run(env = {})
    @value
  end</strong>
  
  def to_sexp
    [:constant, @value]
  end
  
end</code></pre>

<p>Estamos usando exatamente a mesma técnica descrita no artigo anterior, recursivamente operando sobre a árvore para chegar a um resultado final. A diferença é que, nesse caso, estamos utilizando somente três tipos de nós nomeados. Poderíamos, é claro, ter feito algo mais sofisticado usando um nó diferente para cada operação mas isso seria mais do que precisamos no momento.</p>

<p>O código em operação ficaria assim:</p>

<pre><code>>> require "rubygems"
=> false
>> require "treetop"
=> true
>> require "simple_math_ext"
=> true
>> require "simple_math_ast"
=> true
>> require "simple_math_4"
=> true
>> p = SimpleMathParser.new
=> ...
>> ast = p.parse("(b*b)-(4*a*c)").build
=> ...
>> ast.run(:a => 1, :b => 2, :c => 3)
=> -8.0
>> ast.run(:a => 0, :b => 2, :c => 10)
=> 4.0
>> ast.run(:a => 3.2, :b => 4.1, :c => 1.8)
=> -6.23
>> ast.run(:a => 0, :c => 0)
RuntimeError: The variable b is undefined</code></pre>

<p>Alguns resultados foram elididos na representação acima mas é fácil ver como o código funciona. Mesmo o caso em que uma variável não é declarada, é possível capturar e processar o erro. De certa forma, isso representa um nível incipiente de análise semântica do código&#8211;que, nesse caso, aborta na primeira tentativa. Seria igualmente possível continuar o processamento e capturar todas as variáveis não declaradas de uma só vez.</p>

<h3>Conclusão</h3>

<p>Nesse artigo vimos que é possível processar o reconhecimento de uma linguagem qualquer com o <span class="foreign-word" lang="en">parser</span> gerado pelo Treetop em qualquer nível de sofisticação desejado. Obviamente, o exemplo que estamos usando é bem simples mas a mesma técnica poderia ser usada para realizar qualquer tipo de interpretação ou compilação desejada. </p>

<p>Um extensão possível do código acima, que pode ficar como um exercício, é implementar algum sistema de <span class="foreign-word" lang="en">double dispatching</span> para realizar geração de código (C, por exemplo), que faça o trabalho necessário. </p>

<p>No próximo artigo, veremos algumas técnicas rápidas para a depuração básica e identificação de erros em gramáticas Treetop.</p>

<p><strong>Nota:</strong> Para seguir a série completa, siga a categoria <a href="http://logbr.reflectivesurface.com/categoria/treetop/">Treetop</a> deste <span class="foreign-word" lang="en">blog</span>.</p>
]]></content:encoded>
			<wfw:commentRss>http://logbr.reflectivesurface.com/2009/09/29/treetop-usando-arvores-sintaticas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

