Tarefa: Identificar Elementos de Design
Essa tarefa explica como identificar Subsistemas, Classes, interfaces, Eventos e Sinais.
Disciplinas: Análise e Design
Objetivo
  • Analisar interações de classes de análise para identificar elementos de modelo de designs
Relacionamentos
Descrição Principal

A Tarefa: Análise de Caso de Uso resulta em classes de análise, que representam coisas conceituais que podem executar o comportamento. Em design, classes de análise evoluem para vários tipos de elementos de design:

  • classes, para representar um conjunto refinado de responsabilidades;
  • subsistemas, para representar um conjunto não-refinado de responsabilidades, talvez composto de um outro conjunto de subsistemas, mas, por último, um conjunto de classes;
  • classes ativas, que representam encadeamentos no sistema;
  • interfaces, para representar declarações abstratas de responsabilidades fornecidas por uma classe ou subsistema.

Além disso, no design, é necessário identificar:

  • eventos, que são especificações de ocorrências interessantes no tempo e no espaço que costumam (se forem importantes) exigir alguma resposta do sistema; e
  • sinais, para representar mecanismos assíncronos usados para transmitir determinados tipos de eventos no sistema.

Essas distinções mais refinadas permitem examinar diferentes aspectos do design:

  • Os Eventos, e os Sinais usados para transmiti-los, permitem descrever os triggers assíncronos de comportamento aos quais o sistema deverá responder.
  • As Classes e os Subsistemas permitem agrupar responsabilidades relacionadas em unidades que podem ser desenvolvidas de forma relativamente independente; as classes desempenham um conjunto indivisível de responsabilidades relacionadas, enquanto os subsistemas são blocos de construção compostos que, por sua vez, são formados de classes ou outros subsistemas. Os subsistemas são usados para representar os produtos de trabalho de uma equipe de desenvolvimento como uma unidade integral de funcionalidade e, sendo assim, são usados como unidades de gerenciamento de controle e configuração, e elementos lógicos de design.
  • As classes ativas são utilizadas para representar encadeamentos de controle no sistema, permitindo a modelagem da simultaneidade. Muitas vezes, são utilizadas na composição com outras classes que normalmente, mas não necessariamente, são passivas. Tal composição pode então ser utilizada - da mesma maneira que uma colaboração - para modelar comportamento complexo.

    Nos sistemas em tempo real, as cápsulas são usadas no lugar das classes ativas e oferecem uma semântica mais sólida para simplificar o design e aumentar a confiabilidade dos aplicativos simultâneos. Cápsulas compartilham alguns aspectos de classes e subsistemas; são de fato colaborações encapsuladas de classes que juntas representam um encadeamento de controle no sistema. Diferem de subsistemas no sentido de que uma cápsula é responsabilidade de um único designer, enquanto um subsistema é de responsabilidade (normalmente) de uma equipe de desenvolvedores; um subsistema pode conter cápsulas, contudo. 

  • As interfaces permitem examinar e capturar as 'junções' do sistema, definindo precisamente como as suas partes constitutivas funcionarão umas com as outras.
  • Nos sistemas em tempo real, é necessário usar Protocolos para definir precisamente as mensagens que poderão ser enviadas e recebidas na porta de uma cápsula.

Separando assuntos e lidando com cada questão representada por esses conceitos isoladamente, é possível simplificar o processo de design e esclarecer as soluções.

Se a rastreabilidade precisar ser mantida entre modelos de subsistemas, isso deverá ser documentado durante esta tarefa.  Para obter informações adicionais sobre como documentar a rastreabilidade entre o Modelo de Design e outros modelos do sistema, consulte Diretriz: Modelo de Design.

 Representação da UML 1.x

De acordo com a UML 1.5, um subsistema é, efetivamente, um tipo especial de pacote que só possui interfaces como elementos públicos. As interfaces fornecem uma camada de encapsulamento, permitindo que o design interno do subsistema permaneça oculto dos outros elementos do modelo. O subsistema de conceito é utilizado para distingui-lo dos pacotes "comuns", que são contêineres sem semântica de elementos de modelo; o subsistema representa uma utilização particular de pacotes com propriedades (comportamentais) semelhantes a classe.

No RUP, Cápsulas são representadas utilizando a notação da UML 1.5. Muito disso pode ser representado em UML 2.0 utilizando o Conceito: Classe Estruturada.

Consulte Diferenças entre a UML 1.x e a UML 2.0para obter informações adicionais.

Etapas
Identificar Eventos e Sinais
Finalidade Identificar os sinais e eventos externos e internos aos quais o sistema deve responder. 

Eventos são ocorrências externas e internas que provocam uma ação no sistema. Os eventos e suas características podem ajudar a conduzir a identificação dos principais elementos de design, como classes ativas.

Uma lista inicial de eventos externos pode originar-se do Modelo de Caso de Uso, das interações dos agentes com os casos de uso. Eventos internos podem originar-se do texto nos fluxos de casos de uso ou podem ser identificados conforme a evolução do design.

São características importantes dos eventos:

  • internos vs. externos - O evento é externo ou interno?
  • prioridade - Esse evento precisa provocar a suspensão de outros processos para ser tratado?
  • freqüência - Com que freqüência o evento ocorre?
  • distribuição da freqüência - O evento ocorre em intervalos regulares ou há picos?
  • requisitos de resposta - Qual a velocidade com que o sistema deve responder ao evento (pode precisar distinguir entre caso médio e pior).
  • tipo- Esse é um Evento de Chamada, de Tempo, de Sinal ou de Mudança (consulte Conceito: Eventos e Sinais para obter as definições)?

As características dos eventos devem ser capturadas conforme necessário para conduzir a identificação dos elementos de design que os tratam. A captura das características dos eventos costuma ser mais importante em sistemas reativos (dirigidos a eventos), mas pode ser útil em outros sistemas, como naqueles com simultaneidade e/ou mensagens assíncronas.

Eventos de comunicação assíncrona podem ser modelados como Sinais para expressar os dados que transportam ou as relações entre os sinais, como generalização. Em alguns sistemas, particularmente em sistemas reativos, é importante relacionar os sinais recebidos de dispositivos externos com mecanismos específicos, como interrupções ou mensagens de polling específicas.

Identificar Classes, Classes Ativas e Subsistemas
Finalidade Refinar as classes de análise nos elementos de modelo de design apropriados 

Identificar Classes. Quando a classe de análise for simples e já representar uma abstração lógica individual, poderá ser mapeada diretamente, 1:1, para uma classe de design. Em geral, as classes de entidade permanecem relativamente intactas no Design. Como também costumam ser persistentes, decida se a classe de design deverá ser persistente e registre a sua decisão na descrição correspondente.

Ao identificar classes, agrupe-as em Produto de Trabalho: Pacotes de Design, para fins de gerenciamento organizacional e de configuração. Consulte Diretriz de Produto de Trabalho: Pacote de Design para obter informações adicionais sobre como tomar decisões de empacotamento.

Identificar Classes Ativas. Considere os requisitos de simultaneidade do sistema no contexto dos objetos de análise identificados: há necessidade de que o sistema responda aos eventos gerados externamente e, se for o caso, quais classes de análise estarão 'ativas' quando os eventos ocorrerem? Os eventos externos no Modelo de Casos de Uso são representados por estímulos provenientes de agentes que interagem com um caso de uso. Observe as Realizações de Casos de Uso correspondentes para ver os objetos que interagem quando um evento ocorre. Comece agrupando os objetos em conjuntos autônomos de objetos de colaboração - esses agrupamentos representam um recorte inicial em um grupo que pode formar uma classe ativa composta.

Se os eventos tiverem atributos importantes que precisam ser capturados, considere a possibilidade de modelá-los como classes, <<sinal>> estereotipadas. Nos sistemas em tempo real, é necessário agrupar os conjuntos de objetos identificados em cápsulas, que possuem uma semântica sólida de encapsulamento.

As instâncias de classes ativas representam encadeamentos de execução 'lógicos' independentes. Esses encadeamentos de execução 'lógicos' não devem ser confundidos com os encadeamentos de execução do sistema operacional nem ser mapeados literalmente para eles (embora, em algum momento, eles sejam mapeados para os encadeamentos de execução do sistema operacional). Ao contrário, eles representam encadeamentos de execução conceituais independentes no espaço de solução. A nossa meta ao identificá-los nesta etapa do design é permitir a divisão da solução em unidades independentes com base nas 'junções de simultaneidade' naturais do sistema. A divisão do trabalho dessa forma simplifica, do ponto de vista conceitual, os problemas que envolvem a simultaneidade, já que é possível lidar com encadeamentos de execução independentes separadamente, exceto no ponto em que eles compartilham classes passivas subjacentes.

Em geral, convém considerar uma classe ativa sempre que houver simultaneidade e conflitos de simultaneidade na área do problema. Use uma classe ativa para representar um objeto simultâneo externo ou uma atividade simultânea no computador. Com isso, é possível monitorar e controlar atividades simultâneas.

Outra opção natural é utilizar classes ativas como representativas internas de dispositivos físicos externos que estão conectadas a um computador, já que essas entidades físicas são inerentemente simultâneas. As classes de "driver de dispositivo"; servem não só para monitorar e controlar os dispositivos físicos correspondentes, mas também para isolar o restante do sistema das especificações dos dispositivos. Isso significa que o restante do sistema poderá não ser afetado mesmo se a tecnologia dos dispositivos subjacente evoluir.

As classes ativas também são usadas para representar atividades simultâneas lógicas. Uma atividade lógica representa um ";objeto" simultâneo conceitual, como por exemplo, uma transação financeira ou uma ligação telefônica. Embora elas não sejam manifestadas diretamente como entidades físicas (apesar de ocorrerem no mundo físico), há geralmente motivos para tratá-las como tal. Por exemplo, talvez seja necessário reter temporariamente uma transação financeira específica para evitar um conflito de simultaneidade ou talvez seja necessário anulá-la devido a falhas no sistema. Como esses objetos conceituais precisam ser manipulados como uma unidade, convém representá-los como objetos com interfaces próprias que oferecem os recursos funcionais apropriados.

Um controlador de objetos ativos é um exemplo específico desse tipo de objeto conceitual. A sua finalidade é gerenciar de forma contínua outros objetos ativos. Normalmente, isso envolve colocar cada objeto no estado operacional desejado, mantê-lo nesse estado apesar das diversas interrupções, como falhas parciais, e sincronizar a operação correspondente com a operação de outros objetos. Esses controladores de objetos ativos costumam evoluir dos objetos de Controle identificados durante a Tarefa: Análise de Caso de Uso.

Devido à sua capacidade de resolver conflitos de simultaneidade de forma simples e correta, as classes ativas também são úteis como guardiãs de recursos compartilhados. Nesse caso, um ou mais recursos exigidos por diversas atividades simultâneas são encapsulados na classe ativa. Devido à sua semântica de exclusão mútua interna, as guardiãs protegem automaticamente os recursos contra conflitos de simultaneidade.

Em sistemas de tempo real, as cápsulas devem ser utilizadas no lugar das classes ativas: onde quer que você tenha identificado a necessidade de uma classe ativa, de acordo com a heurística descrita anteriormente, uma cápsula deverá ser substituída.

Identificar Subsistemas. Quando uma classe de análise é complexa, de maneira que pareça incorporar comportamentos que não podem ser a responsabilidade de uma classe única agindo sozinha, a classe de análise deverá ser mapeada para um subsistema de design. Esse subsistema é usado para encapsular colaborações de tal modo que os clientes dele podem não ter conhecimento nenhum do seu design interno, mesmo quando usam os serviços que ele oferece.

Um subsistema é modelado como um componente da UML, que só possui interfaces como elementos públicos. As interfaces fornecem uma camada de encapsulamento, permitindo que o design interno do subsistema permaneça oculto dos outros elementos do modelo. O subsistema de conceitos é utilizado para distingui-lo dos pacotes, que são contêineres sem semântica de elementos de modelo.

A decisão de criar um subsistema a partir de um conjunto de classes de análise colaboradoras se baseia, em grande parte, no fato de que a colaboração poderá ser ou será desenvolvida de forma independente por uma equipe de design distinta. Se for possível incluir todas as colaborações em um pacote com as classes colaboradoras, um subsistema poderá permitir uma forma de encapsulamento mais sólida do que a permitida por um pacote simples. O conteúdo e as colaborações de um subsistema estão isolados completamente, atrás de uma ou mais interfaces, de forma que o cliente dele dependa apenas da interface. Dessa forma, o designer do subsistema está completamente isolado das dependências externas; o designer (ou a equipe de design) precisa especificar como a interface é realizada, mas tem permissão total para alterar o design interno do subsistema sem afetar as dependências externas. Em sistemas grandes, com equipes bastante independentes, esse grau de desacoplamento, combinado com a imposição arquitetural fornecida pelas interfaces formais, são um argumento sólido para escolher subsistemas em vez de pacotes simples. Consulte Diretriz de Produto de Trabalho: Subsistema de Design para obter informações adicionais sobre fatores que afetem a escolha do uso de subsistemas como elementos de design.

Identificar Interfaces de Subsistema
Finalidade Identificar os elementos de design que formalizam as junções no sistema.  

As interfaces definem um conjunto de operações que são realizadas por um classificador. No Modelo de Design, as interfaces são usadas principalmente para definir as interfaces de subsistemas. Isso não quer dizer que também não podem ser usadas para classes, mas, para uma classe única, em geral basta definir operações públicas na classe que, de fato, determinam sua 'interface'. As interfaces são importantes para subsistemas porque permitem a separação da declaração do comportamento (a interface) da realização dele (as classes específicas no subsistema que realizam a interface). Esse desacoplamento permite aumentar a independência das equipes de desenvolvimento que trabalham em partes distintas do sistema e, ao mesmo tempo, reter definições precisas dos 'contratos' entre essas diferentes partes.

Para cada subsistema, identifique um conjunto de sugestões de interfaces. Usando as colaborações agrupadas identificadas no passo anterior, identifique a responsabilidade que é 'ativada' quando a colaboração é iniciada. Para refinar depois essa responsabilidade, determine quais informações devem ser fornecidas pelo 'cliente' e quais são retornadas quando a colaboração é concluída; esses conjuntos de informações passam a ser os parâmetros de entrada e saída do protótipo e retornam um valor para uma operação que o subsistema realizará. Defina um nome para essa operação, utilizando as convenções de nomenclatura definidas no Produto de Trabalho: Diretrizes Específicas do ProjetoRepita esse procedimento até definir todas as operações que serão realizadas pelo subsistema.

Em seguida, agrupe as operações de acordo com as responsabilidades relacionadas. Convém criar grupos pequenos em vez de grupos grandes, já que é mais provável obter um conjunto coeso de responsabilidades comuns se há poucas operações no grupo. Fique atento também à reutilização - procure semelhanças que possam facilitar a identificação da funcionalidade reutilizável relacionada. No entanto, não gaste muito tempo tentando encontrar o agrupamento de responsabilidades ideal; lembre-se de que esse é apenas um agrupamento inicial, que continuará a ser refinado de forma iterativa durante a fase de elaboração.

Procure por similaridades entre as interfaces. No conjunto de sugestões de interfaces, procure nomes, responsabilidades e operações semelhantes. Reajuste as interfaces que apresentam as mesmas operações, extraindo as operações comuns para uma nova interface. Não se esqueça de verificar também as interfaces existentes, reutilizando-as sempre que possível. A meta é manter a coesão das interfaces e, ao mesmo tempo, remover operações redundantes entre elas. Isso facilitará a compreensão e o desenvolvimento das interfaces ao longo do tempo.

Defina dependências de interface. Os parâmetros e o valor de retorno de cada operação da interface têm um tipo específico: eles devem realizar uma determinada interface ou devem ser instâncias de um tipo de dados simples. Nos casos em que os parâmetros são objetos que realizam uma interface específica, defina relacionamentos de dependência entre a interface e as interfaces das quais ela depende. A definição de dependências entre interfaces fornece informações de acoplamento úteis ao arquiteto de software, já que essas dependências definem as principais dependências entre elementos no modelo de design.

Mapeie as interfaces para subsistemas. Uma vez identificadas as interfaces, crie associações de realização entre o subsistema e as interfaces realizadas por ele. Uma realização do subsistema para uma interface indica que existem um ou mais elementos no subsistema que realizam as operações da interface. Posteriormente, quando o subsistema for projetado, as realizações entre ele e a interface serão refinadas, e o designer do subsistema definirá os elementos específicos dele que realizam as operações da interface. Essas realizações refinadas podem ser visualizadas apenas pelo designer do subsistema; para o cliente do subsistema, apenas a realização entre o subsistema e a interface está visível.

Defina o comportamento especificado pelas interfaces. As interfaces em geral definem uma máquina de estado implícita para os elementos que realizam a interface. Se for necessário disparar as operações da interface em uma ordem específica (por exemplo, é necessário ativar a conexão com o banco de dados antes de usá-lo), será preciso definir uma máquina de estados com os estados visíveis (ou inferidos) publicamente que deverão ser suportados pelos elementos de design que realizam a interface. Essa máquina de estados ajudará o usuário da interface a compreendê-la melhor e ajudará o designer dos elementos que realizam a interface a especificar o comportamento adequado deles.

Empacote as interfaces. As interfaces são de propriedade do arquiteto de software; mudanças nas interfaces são sempre arquiteturalmente significativas. Para gerenciar essas mudanças, é necessário agrupar as interfaces em um ou mais pacotes pertencentes ao arquiteto de software. Se cada interface for realizada por um único subsistema, será possível colocá-las no mesmo pacote com o subsistema. Se forem realizadas por mais de um subsistema, deverão ser colocadas em um outro pacote pertencente ao arquiteto de software. Com isso, é possível gerenciar e controlar as interfaces independentemente dos próprios subsistemas.

Identificar Protocolos de Cápsula

Finalidade

Identificar os elementos de design que formalizam as junções no sistema (design RT apenas).

Protocolos são semelhantes a interfaces em sistemas dirigidos a eventos: eles identificam o 'contrato' entre cápsulas definindo um conjunto combinado de sinais, utilizados para a comunicação entre encadeamentos de controle independentes. Enquanto as interfaces são usadas principalmente para definir um serviço de mensagens síncrono através de um modelo de chamada de funções, os protocolos são usados principalmente para definir a comunicação assíncrona através de um serviço de mensagens baseado em sinais. Os protocolos permitem a separação da declaração do comportamento (o conjunto de sinais) da realização dele (os elementos no subsistema que realizam a interface). Esse desacoplamento permite aumentar a independência das equipes de desenvolvimento que trabalham em partes distintas do sistema e, ao mesmo tempo, reter definições precisas dos 'contratos' entre essas diferentes partes.

Para cada cápsula, identifique um conjunto de sinais de entrada e de saída. Usando as colaborações agrupadas identificadas nos passos anteriores, identifique a responsabilidade que é 'ativada' quando a colaboração é iniciada. Para refinar depois essa responsabilidade, determine quais informações devem ser fornecidas pelo 'cliente' e quais são retornadas quando a colaboração é concluída; esses conjuntos de informações passam a ser os parâmetros de entrada do protótipo para um sinal que a cápsula realizará através de uma de suas portas. Defina um nome para esse sinal, utilizando as convenções de nomenclatura definidas no Produto de Trabalho: Diretrizes Específicas do Projeto. Repita esse procedimento até definir todos os sinais que serão realizados pelo subsistema.

Em seguida, agrupe os sinais de acordo com as responsabilidades relacionadas. Convém criar grupos pequenos em vez de grupos grandes, já que é mais provável obter um conjunto coeso de responsabilidades comuns se há poucos sinais no grupo. Fique atento também à reutilização - procure semelhanças que possam facilitar a identificação da funcionalidade reutilizável relacionada. No entanto, não gaste muito tempo tentando encontrar o agrupamento de responsabilidades ideal; lembre-se de que esse é apenas um agrupamento inicial, que continuará a ser refinado de forma iterativa durante a fase de elaboração. Atribua ao protocolo um nome significativo que descreva a função que ele desempenha nas colaborações de cápsula.

Procure por similaridades entre os protocolos. No conjunto de sugestões de protocolos, procure nomes, responsabilidades e sinais semelhantes. Reajuste os protocolos que apresentam os mesmos sinais, extraindo os sinais comuns para uma nova interface. Não se esqueça de verificar também os protocolos existentes, reutilizando-os sempre que possível. A meta é manter a coesão dos protocolos e, ao mesmo tempo, remover sinais redundantes entre eles. Isso facilitará a compreensão e o desenvolvimento dos protocolos ao longo do tempo.

Mapeie os protocolos para cápsulas. Uma vez identificados os protocolos, crie portas nas cápsulas que os realizam. As portas da cápsula definem suas 'interfaces', o comportamento que pode ser solicitado dela. Posteriormente, quando ela for projetada, o comportamento especificado pelas portas será descrito pela máquina de estados da cápsula.

Defina o comportamento especificado pelos protocolosOs protocolos em geral definem uma máquina de estado implícita para os elementos que realizam a interface. Se for necessário receber os sinais de entrada na interface em uma ordem específica (p. ex., é necessário receber um sinal 'o sistema está pronto' antes de receber um sinal de erro específico), será preciso definir uma máquina de estados com os estados visíveis (ou inferidos) publicamente que deverão ser suportados pelos elementos de design que realizam o protocolo. Essa máquina de estados ajudará o usuário das cápsulas que realizam o protocolo a entender melhor o comportamento delas e ajudará o designer das cápsulas a apresentar o comportamento adequado para os elementos correspondentes.

Empacote os protocolos. Os protocolos são de propriedade do arquiteto de software; alterações nos protocolos são sempre arquiteturalmente significativas. Para gerenciar essas mudanças, é necessário agrupá-los em um ou mais pacotes pertencentes ao arquiteto de software. Com isso, é possível gerenciar e controlar os protocolos independentemente das cápsulas que os realizam.


Informações Adicionais