<?xml version="1.0" encoding="ISO-8859-1"?><article xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<front>
<journal-meta>
<journal-id>0009-6725</journal-id>
<journal-title><![CDATA[Ciência e Cultura]]></journal-title>
<abbrev-journal-title><![CDATA[Cienc. Cult.]]></abbrev-journal-title>
<issn>0009-6725</issn>
<publisher>
<publisher-name><![CDATA[Sociedade Brasileira para o Progresso da Ciência]]></publisher-name>
</publisher>
</journal-meta>
<article-meta>
<article-id>S0009-67252003000200022</article-id>
<title-group>
<article-title xml:lang="pt"><![CDATA[Refinamento: a essência da engenharia de software]]></article-title>
</title-group>
<contrib-group>
<contrib contrib-type="author">
<name>
<surname><![CDATA[Cavalcanti]]></surname>
<given-names><![CDATA[Ana]]></given-names>
</name>
</contrib>
</contrib-group>
<aff id="A">
<institution><![CDATA[,  ]]></institution>
<addr-line><![CDATA[ ]]></addr-line>
</aff>
<pub-date pub-type="pub">
<day>00</day>
<month>04</month>
<year>2003</year>
</pub-date>
<pub-date pub-type="epub">
<day>00</day>
<month>04</month>
<year>2003</year>
</pub-date>
<volume>55</volume>
<numero>2</numero>
<fpage>33</fpage>
<lpage>38</lpage>
<copyright-statement/>
<copyright-year/>
<self-uri xlink:href="http://cienciaecultura.bvs.br/scielo.php?script=sci_arttext&amp;pid=S0009-67252003000200022&amp;lng=en&amp;nrm=iso"></self-uri><self-uri xlink:href="http://cienciaecultura.bvs.br/scielo.php?script=sci_abstract&amp;pid=S0009-67252003000200022&amp;lng=en&amp;nrm=iso"></self-uri><self-uri xlink:href="http://cienciaecultura.bvs.br/scielo.php?script=sci_pdf&amp;pid=S0009-67252003000200022&amp;lng=en&amp;nrm=iso"></self-uri></article-meta>
</front><body><![CDATA[ <p align="center"><img src="/img/revistas/cic/v55n2/tb17.gif"></p>     <p>&nbsp;</p>     <p><b><font size="4">R<small>EFINAMENTO: A ESS&Ecirc;NCIA DA ENGENHARIA DE SOFTWARE</small></font></b></p>     <p>Ana Cavalcanti</p>     <p>&nbsp;</p>     <p><font size=5><b>A</b></font> no&ccedil;&atilde;o de refinamento captura a    ess&ecirc;ncia das atividades di&aacute;rias de engenheiros de software, que    projetam sistemas baseados em especifica&ccedil;&otilde;es, e de programadores,    que implementam estes projetos. Em ambos os casos, o principal objetivo &eacute;    a constru&ccedil;&atilde;o de sistemas e programas de acordo com documentos    que os definem. O produto final, acima de tudo, deve ser, ou tem que ser, correto.</p>     <p>Refinamento &eacute; a rela&ccedil;&atilde;o que existe entre uma especifica&ccedil;&atilde;o,    seus projetos e implementa&ccedil;&otilde;es corretas, do ponto de vista funcional.    M&eacute;todos de desenvolvimento de programa s&atilde;o baseados nesta no&ccedil;&atilde;o    de uma forma ou de outra.</p>     <p>Uma t&eacute;cnica formal vai al&eacute;m, no sentido que ela prov&ecirc; uma    base matem&aacute;tica para garantia de corre&ccedil;&atilde;o. Neste caso,    a meta primordial &eacute; o refinamento de uma especifica&ccedil;&atilde;o    inicial para obten&ccedil;&atilde;o de uma implementa&ccedil;&atilde;o aceit&aacute;vel.    Crit&eacute;rios de aceita&ccedil;&atilde;o podem incluir, por exemplo, efici&ecirc;ncia,    mas a garantia fornecida &eacute; que a especifica&ccedil;&atilde;o e a implementa&ccedil;&atilde;o    est&atilde;o relacionadas por refinamento.</p>     <p>&nbsp;</p>     <p><b>C<small>ONCEITOS</small> B<small>&Aacute;SICOS</small></b> Inicialmente,    refinamento foi estudado para programas seq&uuml;enciais, aonde o foco &eacute;    a rela&ccedil;&atilde;o entre as entradas e sa&iacute;das de um programa. Foi    identificado que h&aacute; basicamente duas formas de refinar uma especifica&ccedil;&atilde;o.    A primeira &eacute; a introdu&ccedil;&atilde;o e a transforma&ccedil;&atilde;o    de estruturas de programa&ccedil;&atilde;o e controle como atribui&ccedil;&otilde;es,    condi&ccedil;&otilde;es, e la&ccedil;os. Isto &eacute; chamado refinamento algor&iacute;tmico.</p>     ]]></body>
<body><![CDATA[<p>A segunda forma de refinamento &eacute; relacionada com as estruturas de dados    usadas no programa. Sistemas s&atilde;o especificados em termos de tipos de    dados que s&atilde;o apropriados para descrever propriedades do dom&iacute;nio    de aplica&ccedil;&atilde;o; neste est&aacute;gio do desenvolvimento, n&atilde;o    se faz, por exemplo, considera&ccedil;&otilde;es relacionadas &agrave; efici&ecirc;ncia.</p>     <p>Decis&otilde;es de projeto, no entanto, normalmente introduzem estruturas de    dados mais elaboradas e apropriadas para implementa&ccedil;&atilde;o. A mudan&ccedil;a    de representa&ccedil;&atilde;o de dados envolvida nessa tarefa &eacute; chamada    refinamento de dados.</p>     <p>O ponto de partida de qualquer m&eacute;todo formal &eacute; uma especifica&ccedil;&atilde;o    formal. Corre&ccedil;&atilde;o &eacute; uma no&ccedil;&atilde;o relativa: dizemos    que um programa &eacute; correto se ele implementa a sua especifica&ccedil;&atilde;o.    Para garantir corre&ccedil;&atilde;o, n&oacute;s precisamos de uma especifica&ccedil;&atilde;o    formal do programa.</p>     <p>H&aacute; muitas linguagens e formalismos em uso hoje. N&oacute;s usaremos    uma linguagem de especifica&ccedil;&atilde;o chamada Z para apresentar um exemplo.    Uma especifica&ccedil;&atilde;o de sistema em Z consiste basicamente de uma    defini&ccedil;&atilde;o de um estado e de uma cole&ccedil;&atilde;o de opera&ccedil;&otilde;es.    O estado &eacute; composto de vari&aacute;veis que representam os dados usados    e registrados no sistema. As opera&ccedil;&otilde;es recebem entradas e produzem    sa&iacute;das, possivelmente alterando o estado.</p>     <p>Tanto o estado quanto as opera&ccedil;&otilde;es s&atilde;o definidas por esquemas:    uma nota&ccedil;&atilde;o gr&aacute;fica para agrupar declara&ccedil;&otilde;es    de vari&aacute;veis e suas propriedades.</p>     <p>&nbsp;</p>     <p><b>E<small>XEMPLO</small></b> N&oacute;s apresentamos a especifica&ccedil;&atilde;o    de um sistema que calcula a m&eacute;dia de uma seq&uuml;&ecirc;ncia de n&uacute;meros    recebidos como entrada. O estado deste sistema s&oacute; tem um componente:    a seq&uuml;&ecirc;ncia de inteiros.</p>     <p><img src="/img/revistas/cic/v55n2/15527x01.gif"></p>     <p>O nome do estado,<i>Calculadora</i> , &eacute; definido, e o seu &uacute;nico    componente &eacute; declarado.</p>     <p>Este sistema tem tr&ecirc;s opera&ccedil;&otilde;es. A primeira, <i>Inicia</i>,    inicializa o estado.</p>     ]]></body>
<body><![CDATA[<p><img src="/img/revistas/cic/v55n2/15527x02.gif"></p>     <p>A refer&ecirc;ncia &agrave; <i>Calculadora</i> indica que esta &eacute; uma    opera&ccedil;&atilde;o sobre este estado. Em uma defini&ccedil;&atilde;o de    opera&ccedil;&atilde;o, n&oacute;s podemos nos referir &agrave; <i>seq</i>,    que representa o valor do componente de estado antes da opera&ccedil;&atilde;o,    e &agrave; <i>seq</i>', o valor depois da opera&ccedil;&atilde;o. A defini&ccedil;&atilde;o    de <i>Inicia</i> especifica que, inicialmente, <i>seq</i> &eacute; seq&uuml;&ecirc;ncia    vazia: n&atilde;o foi dado entrada em nenhum n&uacute;mero.</p>     <p>A segunda opera&ccedil;&atilde;o, <i>Entra</i>, registra um valor <i>n</i>?    recebido como entrada.</p>     <p><img src="/img/revistas/cic/v55n2/15527x03.gif"></p>     <p>O <font face="Symbol">D </font>na frente de <i>Calculadora</i> indica que <i>Entra</i>    muda o estado. A vari&aacute;vel <i>n</i>? representa o n&uacute;mero recebido    como entrada. A nova seq&uuml;&ecirc;ncia <i>seq'</i> pode ser obtida pela inser&ccedil;&atilde;o    de <i>n</i>? ao final de <i>seq</i>; <font face="Symbol">&Ccedil; </font>&eacute;    o operador de concatena&ccedil;&atilde;o de seq&uuml;&ecirc;ncias e &lt;<i>n</i>?&gt;    &eacute; a seq&uuml;&ecirc;ncia que s&oacute; cont&ecirc;m <i>n</i>?.</p>     <p>A &uacute;ltima opera&ccedil;&atilde;o, <i>Media</i>, calcula a m&eacute;dia    dos n&uacute;meros recebidos como entrada at&eacute; ent&atilde;o.</p>     <p><img src="/img/revistas/cic/v55n2/15527x04.gif"></p>     <p>O <img src="/img/revistas/cic/v55n2/15527s1.gif"> indica que <i>Media</i> n&atilde;o muda o    estado. A sa&iacute;da &eacute; representada pela vari&aacute;vel <i>m</i>!.    A especifica&ccedil;&atilde;o requer que a seq&uuml;&ecirc;ncia <i>seq</i> n&atilde;o    seja vazia. Esta &eacute; a <b>pr&eacute;-condi&ccedil;&atilde;o</b> da opera&ccedil;&atilde;o:    se <i>Media</i> for executada quando esta condi&ccedil;&atilde;o n&atilde;o    for satisfeita, seu resultado n&atilde;o &eacute; previs&iacute;vel. Se, no    entanto, a pr&eacute;-condi&ccedil;&atilde;o for satisfeita, a especifica&ccedil;&atilde;o    de <i>Media</i> requer que a sa&iacute;da seja a soma dos elementos da seq&uuml;&ecirc;ncia    dividida pelo seu tamanho.</p>     <p>Especificar um sistema &eacute; o primeiro passo para obten&ccedil;&atilde;o    de uma implementa&ccedil;&atilde;o correta. Um m&eacute;todo de desenvolvimento    formal usa a especifica&ccedil;&atilde;o como uma base para a produ&ccedil;&atilde;o    de uma implementa&ccedil;&atilde;o correta, que refina a especifica&ccedil;&atilde;o.</p>     <p>Refinamento &eacute; baseado na id&eacute;ia de que uma especifica&ccedil;&atilde;o    &eacute; um contrato entre o cliente e o desenvolvedor. O cliente n&atilde;o    pode reclamar se, quando executadas em estados que satisfazem as suas pr&eacute;-condi&ccedil;&otilde;es,    as opera&ccedil;&otilde;es da implementa&ccedil;&atilde;o produzem sa&iacute;das    que satisfazem as propriedades estabelecidas na especifica&ccedil;&atilde;o.    Neste caso, n&oacute;s temos uma implementa&ccedil;&atilde;o correta.</p>     ]]></body>
<body><![CDATA[<p>&nbsp;</p>     <p><b>R<small>EFINAMENTO DE DADOS</small></b> Tipicamente, a primeira oportunidade    de refinamento &eacute; a mudan&ccedil;a de representa&ccedil;&atilde;o dos    componentes de estado. A especifica&ccedil;&atilde;o descreve a rela&ccedil;&atilde;o    entre as entradas e as sa&iacute;das, quando o sistema &eacute; inicializado    e uma seq&uuml;&ecirc;ncia de opera&ccedil;&otilde;es &eacute; executada. Os    valores dos componentes de estado, no entanto, n&atilde;o s&atilde;o vis&iacute;veis.</p>     <p>No nosso exemplo, n&oacute;s usamos uma seq&uuml;&ecirc;ncia para registrar    os n&uacute;meros recebidos; esta &eacute; uma forma natural de descrever o    sistema. Entretanto, n&oacute;s podemos economizar mem&oacute;ria se n&oacute;s    registrarmos apenas a soma e o n&uacute;mero de inteiros recebidos como entrada.    Se as opera&ccedil;&otilde;es forem modificadas apropriadamente, esta &eacute;    uma mudan&ccedil;a de representa&ccedil;&atilde;o de estado v&aacute;lida.</p>     <p>Este tipo de mudan&ccedil;a &eacute; conhecida como refinamento de dados; a    especifica&ccedil;&atilde;o original &eacute; considerada abstrata e a nova    especifica&ccedil;&atilde;o, concreta. Na verdade, a especifica&ccedil;&atilde;o    concreta &eacute; um projeto do sistema, em que estruturas de dados mais apropriadas    para a implementa&ccedil;&atilde;o s&atilde;o introduzidas.</p>     <p>A outra oportunidade de refinamento &eacute; o desenvolvimento de implementa&ccedil;&otilde;es    para as opera&ccedil;&otilde;es. Como estas implementa&ccedil;&otilde;es s&atilde;o    afetadas pelas mudan&ccedil;as no estado, n&oacute;s consideramos refinamento    de dados primeiro. Neste est&aacute;gio, n&oacute;s mudamos as opera&ccedil;&otilde;es    apenas para adapt&aacute;-las ao novo tipo de dados. Em Z, n&oacute;s escrevemos    a especifica&ccedil;&atilde;o concreta no mesmo estilo usado para a especifica&ccedil;&atilde;o    abstrata.</p>     <p>&nbsp;</p>     <p><b>E<small>XEMPLO</small></b> O estado concreto sugerido acima pode ser definido    como mostrado abaixo.</p>     <p><img src="/img/revistas/cic/v55n2/15527x05.gif"></p>     <p>H&aacute; dois componentes: o tamanho <i>tam</i> da seq&uuml;&ecirc;ncia de    n&uacute;meros recebidos como entrada, e a sua <i>soma</i>.</p>     <p>As novas defini&ccedil;&otilde;es das opera&ccedil;&otilde;es s&atilde;o apresentadas    a seguir. A inicializa&ccedil;&atilde;o, <i>IniciaC</i>, registra que nenhum    n&uacute;mero foi recebido.</p>     ]]></body>
<body><![CDATA[<p><img src="/img/revistas/cic/v55n2/15527x06.gif"></p>     <p>A opera&ccedil;&atilde;o <i>EntraC,</i> que registra um n&uacute;mero <i>n</i>?    recebido como entrada, incrementa <i>tam</i> e adiciona a entrada a <i>soma</i></p>     <p><img src="/img/revistas/cic/v55n2/15527x07.gif"></p>     <p>A opera&ccedil;&atilde;o que calcula a m&eacute;dia tem uma especifica&ccedil;&atilde;o    muito mais simples.</p>     <p><img src="/img/revistas/cic/v55n2/15527x08.gif"></p>     <p>Os valores necess&aacute;rio est&atilde;o prontamente dispon&iacute;veis em    <i>soma</i> e <i>tam</i> .</p>     <p>Depois de prover a especifica&ccedil;&atilde;o concreta, n&oacute;s temos que    provar que ela satisfaz a propriedade mencionada anteriormente: os clientes    que contrataram uma implementa&ccedil;&atilde;o da especifica&ccedil;&atilde;o    abstrata n&atilde;o podem reclamar se receberem uma implementa&ccedil;&atilde;o    da especifica&ccedil;&atilde;o concreta. A t&eacute;cnica mais utilizada para    realiza&ccedil;&atilde;o dessa prova &eacute; conhecida como <b>simula&ccedil;&atilde;o</b>.    Ela envolve a defini&ccedil;&atilde;o de uma rela&ccedil;&atilde;o entre os    estados abstratos e concretos que especifica como a informa&ccedil;&atilde;o    no estado abstrato &eacute; representada no estado concreto. Em Z, esta rela&ccedil;&atilde;o    &eacute; conhecida como rela&ccedil;&atilde;o de recupera&ccedil;&atilde;o.</p>     <p>Para o nosso exemplo, a rela&ccedil;&atilde;o apropriada pode ser especificada    como segue.</p>     <p><img src="/img/revistas/cic/v55n2/15527x09.gif"></p>     <p>A inclus&atilde;o dos estados abstrato e concreto reflete o fato que n&oacute;s    estamos especificando uma rela&ccedil;&atilde;o entre eles. Basicamente, um    estado concreto est&aacute; relacionado a um estado abstrato quando o valor    de <i>tam</i> &eacute; de fato o tamanho (operador #) de <i>seq</i>, e <i>soma</i>    &eacute; a soma dos n&uacute;meros nesta seq&uuml;&ecirc;ncia.</p>     ]]></body>
<body><![CDATA[<p>Dada uma rela&ccedil;&atilde;o de recupera&ccedil;&atilde;o, n&oacute;s precisamos    primeiro verificar que a nova inicializa&ccedil;&atilde;o &eacute; adequada:    dado um estado inicial concreto, h&aacute; um estrado abstrato inicial correspondente.    No nosso exemplo, como o tamanho e a soma dos elementos da seq&uuml;&ecirc;ncia    vazia &eacute; 0, n&oacute;s temos o resultado requerido. Na pr&aacute;tica,    este resultado &eacute; formalizado atrav&eacute;s de um teorema matem&aacute;tico,    que pode ser provado usando ferramentas computacionais apropriadas para Z.</p>     <p>N&oacute;s tamb&eacute;m precisamos provar que as opera&ccedil;&otilde;es da    especifica&ccedil;&atilde;o concreta est&atilde;o de acordo com as opera&ccedil;&otilde;es    correspondentes da especifica&ccedil;&atilde;o abstrata. H&aacute; dois pontos    que precisam ser verificados: <b>aplicabilidade</b> e <b>corre&ccedil;&atilde;o</b>.    Aplicabilidade requer que, sempre que a pr&eacute;-condi&ccedil;&atilde;o da    opera&ccedil;&atilde;o abstrata for v&aacute;lida em um determinado estado,    os estados concretos relacionados satisfa&ccedil;am a pr&eacute;-condi&ccedil;&atilde;o    da opera&ccedil;&atilde;o concreta. Em outras palavras, a opera&ccedil;&atilde;o    concreta deve ter um comportamento bem definido, sempre que a opera&ccedil;&atilde;o    abstrata tiver.</p>     <p>No nosso exemplo, as pr&eacute;-condi&ccedil;&otilde;es de <i>Entra</i> e <i>EntraC</i>    s&atilde;o ambas sempre satisfeitas, de forma que este requisito &eacute; trivialmente    v&aacute;lido. A pr&eacute;-condi&ccedil;&atilde;o de <i>Media</i> &eacute;    que a seq&uuml;&ecirc;ncia n&atilde;o seja vazia; a de <i>MediaC</i> &eacute;    <i>tam</i> <img src="/img/revistas/cic/v55n2/15527s2.gif"> 0. Se a seq&uuml;&ecirc;ncia n&atilde;o    &eacute; vazia, e <i>tam</i> &eacute; o seu comprimento, como estabelecido na    rela&ccedil;&atilde;o de recupera&ccedil;&atilde;o, ent&atilde;o <i>tam</i>    &eacute; diferente de zero, como requerido.</p>     <p>Quanto a corre&ccedil;&atilde;o, o requisito &eacute; que, toda vez que as    opera&ccedil;&otilde;es abstrata e concreta forem executadas em estados relacionados,    para qualquer estado resultante da execu&ccedil;&atilde;o da opera&ccedil;&atilde;o    concreta, deve existir um estado abstrato relacionado que poderia ser obtido    com a execu&ccedil;&atilde;o da opera&ccedil;&atilde;o abstrata. Na verdade,    esta restri&ccedil;&atilde;o deve valer apenas quando as opera&ccedil;&otilde;es    forem executadas em situa&ccedil;&otilde;es em que suas pr&eacute;-condi&ccedil;&otilde;es    valem. Se a pr&eacute;-condi&ccedil;&atilde;o da opera&ccedil;&atilde;o abstrata    n&atilde;o for satisfeita, n&atilde;o h&aacute; restri&ccedil;&otilde;es sobre    a opera&ccedil;&atilde;o concreta.</p>     <p>&nbsp;</p>     <p>Por exemplo, no caso de <i>Media</i> e <i>MediaC</i>, n&oacute;s temos que    provar que, se a seq&uuml;&ecirc;ncia n&atilde;o for vazia, ent&atilde;o dados    <i>tam'</i> e <i>soma'</i> como definidos em <i>MediaC</i> , o <i>seq'</i> definido    em <i>Media</i> est&aacute; relacionado a eles. Isto &eacute; verdade porque,    <i>tam'</i> &eacute; igual a <i>tam</i> mais 1, e <i>soma'</i> &eacute; igual    a <i>soma</i> mais <i>n</i>?, aonde <i>tam</i> e <i>soma</i> s&atilde;o o comprimento    e a soma dos elementos de <i>seq</i>. Assim sendo, <i>tam'</i>e <i>soma</i>'    s&atilde;o o comprimento e a soma dos elementos de <i>seq</i> <font face="Symbol">&Ccedil;</font>    &lt;<i>n</i>?&gt;, que &eacute; a defini&ccedil;&atilde;o de <i>seq'</i> em    <i>Media</i>.</p>     <p>Como antes, estas verifica&ccedil;&otilde;es podem ser formalizadas atrav&eacute;s    de teoremas. A maioria deles s&atilde;o longos, mas simples.</p>     <p>Refinamento de dados tamb&eacute;m pode ser aplicado a m&oacute;dulos. Sempre    que tivermos uma estrutura que encapsula informa&ccedil;&otilde;es, este tipo    de modifica&ccedil;&atilde;o &eacute; poss&iacute;vel.</p>     <p>&nbsp;</p>     <p><b>R<small>EFINAMENTO</small> A<small>LGOR&Iacute;TMICO</small></b> Uma vez    que decidimos os tipos de dados que devem ser usados no programa final, n&oacute;s    podemos prosseguir com a implementa&ccedil;&atilde;o das opera&ccedil;&otilde;es.    H&aacute; duas abordagens: verifica&ccedil;&atilde;o e c&aacute;lculo. No caso    de refinamento de dados, n&oacute;s propusemos uma nova especifica&ccedil;&atilde;o    e ent&atilde;o provamos que ela &eacute; satisfat&oacute;ria: n&oacute;s <b>verificamos</b>    que o refinamento proposto &eacute; correto.</p>     ]]></body>
<body><![CDATA[<p>No caso de refinamento algor&iacute;tmico, as t&eacute;cnicas mais modernas    sugerem o uso de uma abordagem baseada em c&aacute;lculo. Nestas t&eacute;cnicas,    chamadas c&aacute;lculos de refinamentos, a especifica&ccedil;&atilde;o inicial    &eacute; usada como ponto de partida para uma seq&uuml;&ecirc;ncia de transforma&ccedil;&otilde;es,    cada uma formalizada como uma lei matem&aacute;tica, chamada de lei de refinamento.    A cada passo, a especifica&ccedil;&atilde;o &eacute; gradualmente transformada    em um programa.</p>     <p>A linguagem de um c&aacute;lculo de refinamentos inclui construtores de especifica&ccedil;&atilde;o    e programa&ccedil;&atilde;o. No caso do c&aacute;lculo de Z, al&eacute;m dos    esquemas, n&oacute;s temos atribui&ccedil;&otilde;es, condicionais, la&ccedil;os,    e outros construtores. Durante o desenvolvimento, n&oacute;s podemos ter, por    exemplo, la&ccedil;os cujo corpo &eacute; um esquema.</p>     <p>Para a aplica&ccedil;&atilde;o de uma t&eacute;cnica de refinamento algor&iacute;tmico,    os pap&eacute;is diferenciados das pr&eacute;-condi&ccedil;&otilde;es e das    p&oacute;s-condi&ccedil;&otilde;es s&atilde;o muito relevantes. Como esquemas    n&atilde;o os distinguem sintaticamente, pode ser conveniente transformar um    esquema num comando de especifica&ccedil;&atilde;o. Neste, os componentes de    estado que podem ser modificados pela opera&ccedil;&atilde;o s&atilde;o listados,    e a pr&eacute;-condi&ccedil;&atilde;o e a p&oacute;s-condi&ccedil;&atilde;o    s&atilde;o especificados separadamente. Por exemplo, <i>EntraC</i> pode ser    especificada pelo seguinte comando de especifica&ccedil;&atilde;o.</p>     <p><img src="/img/revistas/cic/v55n2/15527x10.gif"></p>     <p>Ela modifica <i>tam</i> e <i>soma,</i> sua pr&eacute;-condi&ccedil;&atilde;o    &eacute; sempre satisfeita <i>(true),</i>e a sua p&oacute;s-condi&ccedil;&atilde;o    &eacute; <i>tam' = tam+1</i> e <i>soma' = soma +n?.</i> No caso <i>MediaC,</i>    n&oacute;s temos o comando de especifica&ccedil;&atilde;o <i>m</i>! : [ <i>tam</i>    <img src="/img/revistas/cic/v55n2/15527s2.gif"> 0, <i>m</i>! <i>= soma</i> div <i>tam</i>] .Aqui,    a pr&eacute;-condi&ccedil;&atilde;o n&atilde;o &eacute; trivial e est&aacute;    claramente separada da p&oacute;s-condi&ccedil;&atilde;o, o que n&atilde;o ocorre    no esquema. Uma lei de refinamento pode ser usada para transformar as especifica&ccedil;&otilde;es    de <i>EntraC</i> e <i>MediaC</i> que usam esquemas nos comandos acima.</p>     <p>As leis de refinamento refletem e formalizam a intui&ccedil;&atilde;o dos programadores.    Por exemplo, &eacute; &oacute;bvio para um programador que a melhor maneira    de implementar <i>MediaC</i> &eacute; atrav&eacute;s da atribui&ccedil;&atilde;o    <i>m! := soma</i> div <i>tam</i>. De fato, h&aacute; uma lei de refinamento    que permite a transforma&ccedil;&atilde;o do comando de especifica&ccedil;&atilde;o    que define <i>MediaC</i> nesta atribui&ccedil;&atilde;o. A intui&ccedil;&atilde;o    do programador &eacute; que, nas situa&ccedil;&otilde;es em que <i>tam</i> &eacute;    diferente de 0, a atribui&ccedil;&atilde;o de <i>soma div tam</i> a <i>m!</i>    far&aacute; com que a igualdade colocada na p&oacute;s-condi&ccedil;&atilde;o    de <i>MediaC</i> seja satisfeita. Este &eacute; exatamente o teorema que tem    que ser provado quando aplicamos a lei de refinamento que transforma um comando    de especifica&ccedil;&atilde;o em uma atribui&ccedil;&atilde;o.</p>     <p>Desenvolvimentos mais interessantes geram um seq&uuml;&ecirc;ncia de aplica&ccedil;&otilde;es    de lei. Como um exemplo simples, n&oacute;s consideramos o desenvolvimento de    <i>EntraC</i>. Intuitivamente, vemos que precisamos de duas atribui&ccedil;&otilde;es:    uma a <i>tam</i> e outro a <i>soma</i>. A seq&uuml;&ecirc;ncia de comandos pode    ser introduzida com a aplica&ccedil;&atilde;o de uma lei que transforma <i>EntraC</i>    no seguinte programa.</p>     <p><img src="/img/revistas/cic/v55n2/15527x11.gif"></p>     <p>Neste exemplo, n&oacute;s temos uma combina&ccedil;&atilde;o de construtores    de programa&ccedil;&atilde;o (; e atribui&ccedil;&atilde;o) com um comando de    especifica&ccedil;&atilde;o. A segunda atribui&ccedil;&atilde;o &eacute; introduzida,    mas o primeiro comando da seq&uuml;&ecirc;ncia ainda &eacute; uma especifica&ccedil;&atilde;o,    que precisa ser implementada. &Eacute; claro que &eacute; poss&iacute;vel ter    uma lei que introduz as duas atribui&ccedil;&otilde;es de uma s&oacute; vez,    mas a id&eacute;ia do c&aacute;lculo &eacute; introduzir os diferentes componentes    do programa gradualmente.</p>     <p>Como a atribui&ccedil;&atilde;o j&aacute; atualiza a <i>soma</i>, a p&oacute;s-condi&ccedil;&atilde;o    do comando de especifica&ccedil;&atilde;o requer apenas que seu valor n&atilde;o    seja alterado. Com outra aplica&ccedil;&atilde;o de lei, podemos transformar    esta especifica&ccedil;&atilde;o na atribui&ccedil;&atilde;o <i>tam = tam</i>    + 1. O programa gerado &eacute; o seguinte.</p>     ]]></body>
<body><![CDATA[<p><img src="/img/revistas/cic/v55n2/15527x12.gif"></p>     <p>Com a prova dos teoremas associados a aplica&ccedil;&atilde;o de cada lei,    podemos ter certeza que a implementa&ccedil;&atilde;o obtida satisfaz a especifica&ccedil;&atilde;o    inicial. Para este exemplo, o resultado &eacute; &oacute;bvio; para sistemas    reais, o ganho &eacute; enorme.</p>     <p>&nbsp;</p>     <p><b>L<small>INGUAGENS ORIENTADAS A OBJETOS</small></b> Em uma linguagem orientada    a objetos como Java (3), programas s&atilde;o formados por <b>classes</b>. Como    um sistema em Z, classes possuem componentes chamados <b>atributos</b> que registram    informa&ccedil;&atilde;o usada e manipulada pela classe. Opera&ccedil;&otilde;es    sobre atributos s&atilde;o definidas por procedimentos (ou fun&ccedil;&otilde;es)    chamados <b>m&eacute;todos</b>.</p>     <p>Uma classe &eacute; um m&oacute;dulo de programa&ccedil;&atilde;o, mas pode    ser usada como um tipo de dados. N&oacute;s podemos declarar vari&aacute;veis    cujo tipo &eacute; uma classe; os valores que tais vari&aacute;veis podem assumir    s&atilde;o chamados objetos. Um <b>objeto</b> cujo tipo &eacute; uma classe    <tt>C</tt> &eacute; semelhante a um registro que associa um valor a cada um    dos atributos de <tt>C</tt>.</p>     <p>Objetos s&atilde;o manipulados atrav&eacute;s dos m&eacute;todos de sua classe.    O comando <tt>x</tt>.m &eacute; uma <b>chamada de m&eacute;todo</b>; ele invoca    o m&eacute;todo m da classe de <tt>x</tt>, que age sobre os atributos de <tt>x</tt>.</p>     <p>Classes podem ser definidas atrav&eacute;s da extens&atilde;o e modifica&ccedil;&atilde;o    de classes existentes com o uso do mecanismo de <b>heran&ccedil;a</b>. Quando    n&oacute;s definimos uma classe <tt>C2</tt>, n&oacute;s podemos declarar que    ela &eacute; uma <b>subclasse</b> de, por exemplo, <tt>C1</tt>. N&oacute;s dizemos    tamb&eacute;m que <tt>C1</tt> &eacute; uma <b>superclasse</b> de <tt>C2</tt>.    Neste caso, em linhas gerais, <tt>C2</tt> tem todos os atributos de <tt>C1</tt>    e mais os atributos declarados em sua defini&ccedil;&atilde;o. Em outras palavras,    os atributos de <tt>C1</tt> s&atilde;o herdados por <tt>C2</tt>. O mesmo se    aplica para os m&eacute;todos de <tt>C2</tt>, exceto pelo fato de que, al&eacute;m    de declarar m&eacute;todos adicionais, <tt>C2</tt> pode redefinir m&eacute;todos    de <tt>C1</tt>.</p>     <p>Uma vari&aacute;vel <tt>x</tt> cujo tipo declarado &eacute; uma classe C, pode    ter como valor objetos da classe C ou de qualquer uma de suas subclasses. N&oacute;s    dizemos que C &eacute; o <b>tipo est&aacute;tico</b> de <tt>x</tt>, e o tipo    do objeto que define o valor de <tt>x</tt> em um determinado instante &eacute;    o seu <b>tipo din&acirc;mico</b>.</p>     <p>Do ponto de vista de refinamento, o uso de classes como tipos de dados requer    cuidados adicionais. O refinamento de uma classe n&atilde;o &eacute; muito diferente    do refinamento de uma especifica&ccedil;&atilde;o em Z. No entanto, novas t&eacute;cnicas    s&atilde;o necess&aacute;rias.</p>     <p>A intui&ccedil;&atilde;o geral &eacute; que se uma classe <tt>C1</tt> &eacute;    refinada por uma classe <tt>C2</tt>, ent&atilde;o usos de objetos de <tt>C1</tt>    podem ser substitu&iacute;dos por usos de objetos de <tt>C2</tt>. Entretanto,    testes e coer&ccedil;&atilde;o de tipos podem ser usados para distinguir objetos    de classes diferentes. Mesmo que duas classes tenham os mesmos atributos e m&eacute;todos,    mas nomes diferentes, testes de tipo (e coer&ccedil;&atilde;o) podem ser usados    para distinguir objetos destas classes.</p>     ]]></body>
<body><![CDATA[<p>Em Java, um teste de tipo pode ser feito com o uso da opera&ccedil;&atilde;o    <tt>instanceof:</tt> se <tt>C</tt> &eacute; uma classe e <tt>x</tt> &eacute;    uma vari&aacute;vel cujo tipo est&aacute;tico &eacute; uma superclasse de <tt>C</tt>,    ent&atilde;o o teste <tt>x instanceof C</tt> &eacute; v&aacute;lido se o valor    de <tt>x</tt> &eacute; um objeto da classe <tt>C</tt> ou de qualquer uma de    suas subclasses. Usando um teste de tipo, n&oacute;s podemos escrever o comando    <tt>if (x instanceof C2) while (true) {}</tt>; em Java. Suponha que <tt>C1</tt>    n&atilde;o &eacute; uma subclasse de <tt>C2</tt>, ou vice-versa, mas que o tipo    est&aacute;tico de <tt>x</tt> &eacute; uma superclasse de ambos. Se <tt>x</tt>    &eacute; uma inst&acirc;ncia de <tt>C1</tt> e, portanto, n&atilde;o &eacute;    uma inst&acirc;ncia de <tt>C2</tt>, o comando acima termina e n&atilde;o modifica    nenhuma vari&aacute;vel. Se, por outro lado, <tt>x</tt> &eacute; uma inst&acirc;ncia    de <tt>C2</tt>, ele n&atilde;o termina. Claramente, objetos da classe <tt>C1</tt>    n&atilde;o podem ser substitu&iacute;dos por objetos de <tt>C2</tt>, mesmo que    estas classes tenham os mesmos atributos e m&eacute;todos.</p>     <p>Em conclus&atilde;o, &eacute; preciso cuidado quando comparamos classes com    nomes diferentes ou com posi&ccedil;&otilde;es diferentes na hierarquia de heran&ccedil;a.    Em contextos aonde comandos como o mostrado acima est&atilde;o presentes, isto    n&atilde;o &eacute; poss&iacute;vel. Em programas bem projetados, n&oacute;s    devemos ter apenas comandos c para os quais o bloco de comandos <tt>{ C1 x =    new C1(); c }</tt>, que declara a vari&aacute;vel <tt>x</tt> com o tipo est&aacute;tico    <tt>C1</tt> e a inicializa, antes de executar c, &eacute; refinado pelo bloco    de comandos <tt>{C2 x= new C2(); c }</tt>. Isto significa que c n&atilde;o faz    uso do fato que <tt>x</tt> &eacute; uma inst&acirc;ncia de <tt>C1</tt> ou <tt>C2</tt>.</p>     <p>Para classes com o mesmo nome e posi&ccedil;&atilde;o na hierarquia de heran&ccedil;a,    refinamento &eacute; bem mais parecido com refinamento de dados tradicional.    Simula&ccedil;&atilde;o &eacute; uma t&eacute;cnica v&aacute;lida. No entanto,    para estabelecer uma simula&ccedil;&atilde;o, n&oacute;s precisamos comparar    os m&eacute;todos das classes, da mesma forma que comparamos as opera&ccedil;&otilde;es    abstratas e concretas de especifica&ccedil;&otilde;es em <tt>Z</tt>. Neste contexto,    entretanto, n&oacute;s temos chamadas de m&eacute;todos; elas s&atilde;o um    desafio.</p>     <p>Em uma linguagem imperativa, uma chamada de procedimento (ou fun&ccedil;&atilde;o)    necessariamente invoca a execu&ccedil;&atilde;o do comando na sua &uacute;nica    defini&ccedil;&atilde;o: o corpo do procedimento. Para provar propriedades da    chamada, n&oacute;s podemos nos basear no corpo do procedimento. No caso de    uma chamada de m&eacute;todo <tt>x.m</tt>, o m&eacute;todo m executado depende    do tipo din&acirc;mico de <tt>x</tt>. Se o tipo est&aacute;tico de <tt>x</tt>    &eacute; uma classe <tt>C</tt>, ent&atilde;o qualquer uma das defini&ccedil;&otilde;es    de <tt>m</tt> em <tt>C</tt> e em suas subclasses pode ser invocada em tempo    de execu&ccedil;&atilde;o. Para provar propriedades de uma chamada de m&eacute;todo,    n&oacute;s temos que considerar todas as possibilidades.</p>     <p>Atualmente, o consenso &eacute; que refinamento de programas orientados a objetos    s&oacute; &eacute; pr&aacute;tico se todas as classes estiverem relacionadas    &agrave;s suas subclasses atrav&eacute;s de uma rela&ccedil;&atilde;o de refinamento    chamada subtipo comportamental. Em Java, e na maioria das linguagens orientadas    a objetos com tipos fortes, a heran&ccedil;a garante subtipos. Isto significa    que, quando uma vari&aacute;vel <tt>x</tt> de tipo est&aacute;tico <tt>C</tt>    &eacute; usada para acesso a um atributo ou m&eacute;todo declarado em <tt>C</tt>,    nunca ocorre um erro em tempo de execu&ccedil;&atilde;o, mesmo que <tt>x</tt>    tenha como valor um objeto de uma subclasse de <tt>C</tt>.</p>     <p>Subtipo, entretanto, n&atilde;o prov&ecirc; nenhuma garantia com rela&ccedil;&atilde;o    ao comportamento dos m&eacute;todos das subclasses. Para redefinir um m&eacute;todo    m de <tt>C</tt> em uma de suas subclasses, n&oacute;s precisamos prover uma    nova declara&ccedil;&atilde;o para m que tem os mesmos par&acirc;metros, mas    n&atilde;o h&aacute; restri&ccedil;&otilde;es sobre o efeito do novo m&eacute;todo.    Por exemplo, se em <tt>C</tt> o m&eacute;todo m incrementa o valor de um atributo    a de um valor dado por um argumento <tt>v</tt>, em uma subclasse de <tt>C</tt>,    para redefinir <tt>m</tt>, n&oacute;s precisamos manter o argumento <tt>v</tt>,    com o mesmo tipo, mas n&oacute;s podemos usar este valor para decrementar a,    ao inv&eacute;s de incrementar, por exemplo.</p>     <p>Esta pr&aacute;tica torna mais dif&iacute;cil provar refinamento de programas,    devido &agrave; liga&ccedil;&atilde;o din&acirc;mica. Toda vez que n&oacute;s    mudamos a defini&ccedil;&atilde;o de uma classe, ou adicionamos uma subclasse,    n&oacute;s temos que verificar que todas as propriedades das chamadas de m&eacute;todos    previamente provadas ainda valem. Uma vez que extens&atilde;o e reuso s&atilde;o    um ponto forte do paradigma de orienta&ccedil;&atilde;o a objetos, esta situa&ccedil;&atilde;o    n&atilde;o &eacute; aceit&aacute;vel.</p>     <p>N&oacute;s precisamos de um t&eacute;cnica de refinamento que permita que provas    sejam feitas com base no tipo est&aacute;tico das vari&aacute;veis. Os resultados    obtidos devem ser v&aacute;lidos para todos os tipos din&acirc;micos que essas    vari&aacute;veis podem vir a ter, e n&atilde;o devem ser afetados por mudan&ccedil;as    e adi&ccedil;&otilde;es de subclasses. Para que isto seja poss&iacute;vel, a    estrat&eacute;gia sugerida &eacute; que as subclasses sejam sempre subtipos    comportamentais. Isto requer que uma redefini&ccedil;&atilde;o de m&eacute;todo    refine a defini&ccedil;&atilde;o original.</p>     <p>Outro desafio imposto pelas linguagens orientadas a objetos &eacute; o uso    maci&ccedil;o de ponteiros e compartilhamento. A maioria dos trabalhos na &aacute;rea    de refinamento de programas imperativos tradicionais n&atilde;o considera a    possibilidade de compartilhamento. Neste contexto, compartilhamento ocorre apenas    como consequ&ecirc;ncia do uso expl&iacute;cito de ponteiros ou passagem de    par&acirc;metro por refer&ecirc;ncia. Na grande maioria dos casos, compartilhamento    &eacute; considerado uma m&aacute; pr&aacute;tica de programa&ccedil;&atilde;o.    Por outro lado, se o uso de ponteiros n&atilde;o envolve compartilhamento, ent&atilde;o    refinamento n&atilde;o &eacute; afetado. Assim, ponteiros e compartilhamento    s&atilde;o normalmente ignorados.</p>     <p>No caso de linguagens orientadas a objetos, o uso de ponteiros &eacute; muito    mais comum. A pr&aacute;tica adotada por essas linguagens usualmente leva a    programas que fazem uso disciplinado de ponteiros, e compartilhamento n&atilde;o    &eacute; considerado uma m&aacute; pr&aacute;tica. Para ilustrar o problema    no tratamento de programas que fazem uso de compartilhamento, n&oacute;s apresentamos    o seguinte comando.</p>     ]]></body>
<body><![CDATA[<p><tt><img src="/img/revistas/cic/v55n2/15527x13.gif"></tt></p>     <p>A atribui&ccedil;&atilde;o inicial de <tt>y</tt> a <tt>x</tt> faz com que estas    vari&aacute;veis apontem para o mesmo objeto. Quando n&oacute;s atribu&iacute;mos    1 ao atributo a de <tt>x</tt>, e ent&atilde;o 2 ao mesmo atributo de <tt>y</tt>,    n&oacute;s estamos na verdade fazendo duas atribui&ccedil;&otilde;es ao mesmo    atributo do objeto apontado por <tt>x</tt> e <tt>y</tt>. Em outras palavras,    este comando &eacute; equivalente a <tt><img src="/img/revistas/cic/v55n2/15527s3.gif" align="absmiddle"></tt>.</p>     <p>Entretanto, isto n&atilde;o &eacute; verdade se a atribui&ccedil;&atilde;o    <tt>x = y</tt> cria uma c&oacute;pia do objeto apontado por <tt>y</tt> e faz    <tt>x</tt> apontar para esta c&oacute;pia. Esta abordagem equivale a ignorar    o uso de ponteiros e considerar que o valor de<tt>y</tt> &eacute; atribu&iacute;do    ao valor de <tt>x</tt>, que &eacute; a abordagem usada no tratamento de linguagens    imperativas tradicionais. Os contextos diferentes requerem no&ccedil;&otilde;es    de refinamento e t&eacute;cnicas diferentes.</p>     <p>&nbsp;</p>     <p><b>C<small>ONCORR&Ecirc;NCIA</small></b> No caso de sistemas concorrentes,    como sistemas de controle de equipamentos, especifica&ccedil;&otilde;es e projetos    se concentram principalmente nas intera&ccedil;&otilde;es com outros sistemas    e com o ambiente. Funcionalidade n&atilde;o &eacute; caracterizada pela rela&ccedil;&atilde;o    entre entradas e sa&iacute;das, como no caso de sistemas seq&uuml;enciais, mas    pela maneira em que comunica&ccedil;&otilde;es e sincroniza&ccedil;&otilde;es    podem ocorrer. Entradas e sa&iacute;das s&atilde;o formas particulares de comunica&ccedil;&atilde;o.</p>     <p>Termina&ccedil;&atilde;o n&atilde;o &eacute; um requisito importante, uma vez    que sistemas que n&atilde;o terminam, como sistemas operacionais, mas que continuamente    interagem com o seu ambiente para atingir um determinado objetivo, s&atilde;o    &uacute;teis. Neste contexto, refinamento deve considerar o comportamento dos    sistemas em cada uma de suas intera&ccedil;&otilde;es.</p>     <p>Programas concorrentes s&atilde;o tipicamente formados por v&aacute;rios componentes,    que n&oacute;s chamamos de processos. Eles interagem entre si e com o ambiente    externo. Especifica&ccedil;&atilde;o, projeto, e implementa&ccedil;&atilde;o    de processos foram extensivamente estudados no contexto de um formalismo chamado    CSP (3). Recentemente, tem havido esfor&ccedil;os no sentido de enriquecer Java    com as facilidades de CSP.</p>     <p>Uma intera&ccedil;&atilde;o &eacute; caracterizada em CSP como um evento. Na    especifica&ccedil;&atilde;o de um processo, o primeiro elemento de interesse    &eacute; o conjunto de eventos em que ele pode participar. A defini&ccedil;&atilde;o    de um evento simplesmente declara o seu nome.</p>     <p>&nbsp;</p>     <p><b>E<small>XEMPLO</small></b> Um processo que controla uma porta girat&oacute;ria    pode ser caracterizado em termos dos eventos <i>chega, roda, sai</i> e <i>para</i>.    O primeiro representa a chegada de algu&eacute;m na &aacute;rea ao redor da    porta; o segundo, o momento em que a porta come&ccedil;a a girar; <i>sai</i>    &eacute; o evento que modela a sa&iacute;da de uma pessoa da &aacute;rea da    porta; finalmente, <i>para</i> ocorre quando a porta para de mover.</p>     ]]></body>
<body><![CDATA[<p>Na especifica&ccedil;&atilde;o da porta, entradas e sa&iacute;das n&atilde;o    s&atilde;o uma preocupa&ccedil;&atilde;o; o ponto relevante &eacute; o modo    com que a porta interage com o ambiente: as pessoas que usam a porta. A seguir,    n&oacute;s apresentamos a defini&ccedil;&atilde;o dos processos <i>Porta (i)</i>,    onde <i>i</i> &eacute; o n&uacute;mero de pessoas que est&atilde;o usando a    porta.</p>     <p>Se n&atilde;o h&aacute; ningu&eacute;m usando a porta, o &uacute;nico evento    poss&iacute;vel &eacute; a chegada de algu&eacute;m; depois, a porta come&ccedil;a    a rodar, e passa a se comportar como uma porta que est&aacute; sendo usada por    uma pessoa. Na especifica&ccedil;&atilde;o de <i>Porta</i> (0), n&oacute;s usamos    o operador prefixo <i>a</i> <font face="Symbol">&reg;</font><i>P</i>, que especifica    o &uacute;nico evento <i>a</i> em que o processo est&aacute; preparado para    participar, e um processo <i>P</i> que caracteriza o seu comportamento subseq&uuml;ente.</p>     <p><img src="/img/revistas/cic/v55n2/15527x14.gif"></p>     <p>N&oacute;s usamos prefixo duas vezes: primeiro, a porta est&aacute; preparada    para registrar o evento <i>chega,</i> depois o &uacute;nico evento poss&iacute;vel    &eacute; <i>roda,</i> e ent&atilde;o a porta se comporta como <i>Porta</i> (1).</p>     <p>Se h&aacute; uma pessoa usando a porta, ent&atilde;o outra pessoa chega ou    aquela pessoa sai. N&oacute;s usamos o operador de escolha de <i>P</i>[]<i>Q</i>    para especificar este comportamento: este processo est&aacute; preparado para    se comportar como <i>P</i> ou <i>Q</i>; a escolha &eacute; feita pelo ambiente.</p>     <p><img src="/img/revistas/cic/v55n2/15527x15.gif"></p>     <p>Se o evento <i>chega</i> ocorre, ent&atilde;o a porta se comporta como uma    porta usada por duas pessoas. Se o evento <i>sai</i> ocorre, o &uacute;nico    poss&iacute;vel &eacute; <i>para,</i> e ent&atilde;o n&oacute;s temos o comportamento    de <i>Porta</i> (0) de novo.</p>     <p>Portas com duas ou mais pessoas se comportam de maneira semelhante.</p>     <p><img src="/img/revistas/cic/v55n2/15527x16.gif"></p>     <p>Se algu&eacute;m entra em uma porta com <i>n</i> pessoas para <i>n</i> maior    do 1, ent&atilde;o n&oacute;s temos o comportamento de uma porta com <i>n</i>+1    pessoas. Se algu&eacute;m sai, ent&atilde;o o comportamento &eacute; o de uma    porta com <i>n</i> -1 pessoas.</p>     ]]></body>
<body><![CDATA[<p>Em um pr&eacute;dio grande, n&oacute;s normalmente temos v&aacute;rias portas    girat&oacute;rias. Elas trabalham em paralelo, mas independentemente. N&oacute;s    definimos um processo <i>Entrada</i> com <i>m</i> portas da seguinte forma.</p>     <p><img src="/img/revistas/cic/v55n2/15527x17.gif"></p>     <p>Neste processo, h&aacute; <i>m</i> c&oacute;pias de <i>Porta</i>(0) registrando    eventos <i>i.chega, i.roda</i>, <i>i.sai</i>, e <i>i.para</i>, para <i>i</i>    entre 1 e <i>m</i>. O conjunto de eventos de <i>Entrada</i> inclui todos os    <i>m</i> events: 4 para cada uma das <i>m</i> portas.</p>     <p>Uma porta "educada" cont&eacute;m um componente adicional: um processo que    detecta que algu&eacute;m chegou e emite uma mensagem falada de boas vindas.    Este processo pode ser especificado como mostrado abaixo.</p>     <p><img src="/img/revistas/cic/v55n2/15527x18.gif"></p>     <p>O evento adicional <i>bem-vindo</i> registra a emiss&atilde;o da mensagem de    boas-vindas. A porta educada poder ser caracterizada pela execu&ccedil;&atilde;o    paralela da porta <i>Porta</i>(0) e <i>Educada.</i></p>     <p><img src="/img/revistas/cic/v55n2/15527x19.gif"></p>     <p>Neste processo paralelo, h&aacute; uma intera&ccedil;&atilde;o entre os dois    componentes; eles n&atilde;o s&atilde;o independentes como no exemplo anterior.    Uma vez que <i>chega</i> &eacute; um evento tanto de <i>Porta</i> como de <i>Educada</i>    , estes processos sincronizam nesse evento.Toda vez que algu&eacute;m chega,    <i>Porta</i>(0) e <i>Educada</i> agem conjuntamente; do ponto de vista de <i>PEducada</i>,    apenas um evento ocorre.</p>     <p>Refinamento &eacute; baseado nas poss&iacute;veis intera&ccedil;&otilde;es    dos processos. Basicamente, as intera&ccedil;&otilde;es da implementa&ccedil;&atilde;o    tem que ser intera&ccedil;&otilde;es em que a especifica&ccedil;&atilde;o poderia    participar.</p>     <p>No caso do nosso exemplo, n&atilde;o &eacute; real&iacute;stico assumir que    um n&uacute;mero arbitr&aacute;rio de pessoas pode usar uma porta ao mesmo tempo.    Um poss&iacute;vel projeto de <i>Porta</i>(0) pode ser obtido se n&oacute;s    consideramos que este n&uacute;mero &eacute; no m&aacute;ximo <i>max</i>, e    definirmos <i>Porta</i>(<i>max</i>) como se segue, aonde n&oacute;s assumimos    que <i>max</i> &gt; 2.</p>     ]]></body>
<body><![CDATA[<p><img src="/img/revistas/cic/v55n2/15527x20.gif"></p>     <p>Quando o n&uacute;mero m&aacute;ximo de pessoas &eacute; atingido, a porta    n&atilde;o aceita mais a chegada de novas pessoas. O &uacute;nico evento aceito    &eacute; <i>sai</i>.</p>     <p>O n&uacute;mero de pessoas que usam a porta &eacute; parte de seu estado e    n&atilde;o &eacute; vis&iacute;vel ao ambiente. Em CSP, cada processo encapsula    seu estado; intera&ccedil;&atilde;o entre os processos ocorre atrav&eacute;s    de eventos. Refinamento est&aacute; relacionado apenas a eventos.</p>     <p>Assim sendo, n&oacute;s podemos considerar refinamento de dados. Por exemplo,    n&oacute;s podemos usar os inteiros negativos para representar o n&uacute;mero    de pessoas usando uma porta, como mostrado abaixo.</p>     <p><img src="/img/revistas/cic/v55n2/15527x21.gif"></p>     <p>Os processos <i>Porta</i>(0) e <i>PortaN</i>(0) s&atilde;o equivalentes. Entretanto,    este tipo de refinamento n&atilde;o &eacute; de interesse da comunidade de CSP    porque a linguagem de defini&ccedil;&atilde;o de daods de CSP &eacute; muito    simples.</p>     <p>Um outro ponto relacionado ao refinamento de processos concorrentes s&atilde;o    os eventos em que um processo pode se recusar a participar, e as seq&uuml;&ecirc;ncias    de eventos que podem levar a diverg&ecirc;ncia. Por exemplo, a especifica&ccedil;&atilde;o    da porta &eacute; um processo que n&atilde;o se recusa a reconhecer a chegada    de pessoa em qualquer situac&atilde;o; a implementa&ccedil;&atilde;o, por outro    lado, pode ignorar este evento se a porta estiver cheia. Deste ponto de vista,    n&oacute;s n&atilde;o temos realmente uma implementa&ccedil;&atilde;o da porta.    A especifica&ccedil;&atilde;o precisa ser mais flex&iacute;vel para permitir    uma implementa&ccedil;&atilde;o real&iacute;stica.</p>     <p>Para concluir, t&eacute;cnicas de refinamento prov&ecirc;em justificativas    organizadas e claras para a intui&ccedil;&atilde;o que milh&otilde;es de programadores    usam todo dia para convencer a si mesmos e a outros que os seus projetos e implementa&ccedil;&otilde;es    est&atilde;o corretos. A falta de uma t&eacute;cnica formal t&ecirc;m sido uma    das respons&aacute;veis por desenvolvimentos mal documentados, desnecessariamente    complexos, ou simplesmente errados.</p>     <p>O entendimento de refinamento como a base cient&iacute;fica para m&eacute;todos    de desenvolvimento pode ajudar bons engenheiros e programadores a desempenhar    suas fun&ccedil;&otilde;es mais efetivamente. Conhecimento das propriedades    da rela&ccedil;&atilde;o de refinamento na forma de, por exemplo, leis de refinamento,    leva a uma maior habilidade nas tarefas de programa&ccedil;&atilde;o e projeto,    mesmo que uma t&eacute;cnica formal de refinamento n&atilde;o seja aplicada.</p>     <p>Mais recentemente, linguagens integradas que combinam, por exemplo, Z e CSP,    t&ecirc;m sido propostas; algumas destas linguagens incluem tamb&eacute;m aspectos    de orienta&ccedil;&atilde;o a objetos. A id&eacute;ia &eacute; tornar poss&iacute;vel    o tratamento dos problemas que n&oacute;s consideramos aqui isoladamente: tipos    de dados, orienta&ccedil;&atilde;o a objetos, e concorr&ecirc;ncia.</p>     ]]></body>
<body><![CDATA[<p>&nbsp;</p>     <p><i><b>Ana Cavalcanti</b> &eacute; pesquisadora do Computing Laboratory, University    of Kent at Canterbury, Inglaterra</i></p>     <p>&nbsp;</p>     <p>&nbsp;</p>     <p><b>Bibliografia consultada</b></p>     <p>J. C. P. Woodcock and J. Davies. Using Z - <i>Specification, Refinement, and    Proof</i>. Prentice-Hall, 1996.</p>     <p>J. Gosling, B. Joy, and G. Steele. <i>The Java Language Specification</i>.    Addison-Wesley, 1996.</p>     <p>A. W. Roscoe.<i>The Theory and Practice of Concurrency. Prentice-Hall Series    in Computer Science</i>. Prentice-Hall, 1998.</p>      ]]></body>
</article>
