Skip to content Skip to navigation

Connexions

You are here: Home » Content » Introdução a Design de Software

Navigation

Content Actions

  • Download module PDF
  • Add to ...
    Add the module to:
    • My Favorites
    • A lens
    • An external social bookmarking service
    • My Favorites (What is 'My Favorites'?)
      'My Favorites' is a special kind of lens which you can use to bookmark modules and collections directly in Connexions. 'My Favorites' can only be seen by you, and collections saved in 'My Favorites' can remember the last module you were on. You need a Connexions account to use 'My Favorites'.
    • A lens (What is a lens?)

      Definition of a lens

      Lenses

      A lens is a custom view of Connexions content. You can think of it as a fancy kind of list that will let you see Connexions through the eyes of organizations and people you trust.

      What is in a lens?

      Lens makers point to Connexions materials (modules and collections), creating a guide that includes their own comments and descriptive tags about the content.

      Who can create a lens?

      Any individual Connexions member, a community, or a respected organization.

      What are tags? tag icon

      Tags are descriptors added by lens makers to help label content, attaching a vocabulary that is meaningful in the context of the lens.

    • External bookmarks
  • E-mail the author
  • Rate this module (How does the rating system work?)

    Rating system

    Ratings

    Ratings allow you to judge the quality of modules. If other users have ranked the module then its average rating is displayed below. Ratings are calculated on a scale from one star (Poor) to five stars (Excellent).

    How to rate a module

    Hover over the star that corresponds to the rating you wish to assign. Click on the star to add your rating. Your rating should be based on the quality of the content. You must have an account and be logged in to rate content.

    (0 ratings)

Recently Viewed

This feature requires Javascript to be enabled.

Introdução a Design de Software

Module by: Guilherme Mauro Germoglio Barbosa

Summary: Este capítulo é uma introdução a design de software. Seu objetivo é fundamentar o conhecimento do estudante de forma a fazê-lo reconhecer a relevância e os benefícios proporcionados pelo design de software.

Note: Your browser may not currently support MathML. See our browser support page for additional details. You can always view the correct math in the PDF version.

Antes de começarmos o estudo e a prática na disciplina de Arquitetura de Software, é apropriado sabermos onde ela se encaixa ao longo do Corpo de Conhecimento de Engenharia de Software ( Software Engineering Body of Knowledge). Design arquitetural, ou projeto da arquitetura, é a primeira das duas atividades que compõem a área de conhecimento de Design de Software ( Software Design Knowledge Area). A atividade seguinte é design detalhado. Por ser uma atividade de Design, o design arquitetural se faz por uma mistura de conhecimento e criatividade. Como criatividade é algo que se obtém através da experiência, não é nosso objetivo ensiná-la. No entanto, buscamos ao longo desse livro transmitir o conhecimento necessário para a criação de arquiteturas de sistemas de software.

Certamente, uma base conceitual em Design de Software é necessária para uma melhor compreensão desse livro. Dessa maneira, esse capítulo procura fundamentar o conhecimento do leitor nessa área, de forma que sua importância e seus benefícios proporcionados sejam reconhecidos. Em outras palavras, esse capítulo fará com que o leitor seja capaz de:

  • Reconhecer os conceitos básicos de design de software
  • Descrever problemas de design através de seus elementos fundamentais
  • Identificar princípios de design de software e explicar seus benefícios
  • Diferenciar design de baixo-nível de design de alto-nível e saber quando aplicar cada um

Design de Software

A relevância de se projetar – ou fazer design de – software pode ser explicada pela complexidade crescente dos sistemas de software. Devido a essa complexidade, o risco de se construir um sistema que não alcance seus objetivos é eminente.

Para evitar tal risco, a prática comum de qualquer engenharia para se construir um artefato complexo, um sistema de software complexo em nosso caso, é construí-lo de acordo com um plano. Em outras palavras, projetar o sistema antes de construí-lo. O resultado dessa atividade, também conhecida como de atividade de design, é também chamado de design. O design facilita em duas atividades que são essenciais no ciclo de vida de um sistema de software. Primeiro, ele possibilita a avaliação do sistema contra seus objetivos antes mesmo dele ser construído. Dessa maneira, ele aumenta a confiança de que o sistema construído alcançará seus objetivos. Obviamente, uma vez que nesse ponto há apenas o modelo do sistema – o design –, a avaliação não será completa, mas isso também não quer dizer que ela não ofereça resultados importantes para o sucesso do sistema. Já a outra atividade beneficiada pelo design é a própria construção do sistema, dado que ele também serve como guia para a implementação do software.

Para definir design de software, alguns autores o fazem em dois sentidos distintos: quando design de software é usado como produto e quando é usado como processo. Quando usado no primeiro sentido, o termo design de software indica o produto que emerge do ato (ou processo) de projetar um sistema de software e sendo assim algum documento ou outro tipo de representação do desejo do projetista (ou designer). Esse produto é o resultado das decisões do designer para formar uma abstração do sistema que é desejado no mundo real. Já quando o termo é usado no segundo sentido, fazer design indica o processo seguido para se obter um projeto. Esse processo é orientado a objetivos, mas também orientado a pessoas. Ele envolve diversos interessados nos objetivos e extrai a essência do conhecimento do designer e do domínio do problema onde ele atua [12].

A partir da visão de produto do design de software, podemos observar que ele deve descrever diversos aspectos de um sistema de software para que, assim, possibilite sua construção. Budgen menciona alguns desses aspectos [6]:

  • a estrutura estática do sistema, incluindo a hierarquia de seus subprogramas;
  • os objetos de dados a serem usados;
  • os algoritmos a serem usados;
  • o empacotamento do sistema, em termos de como os módulos estão agrupados em unidades de compilação; e
  • as interações entre módulos, incluindo as regras de como elas devem acontecer e sua motivação.

Assim, podemos chegar a uma definição mais pragmática de design de software [7]:

Definição 1: design de software
É tanto o processo de definição da arquitetura, módulos, interfaces e outras características de um sistema quanto o resultado desse processo.

Características de Design de Software

Uma vez que projetar os diversos aspectos de um sistema de software é trabalhoso, mostraremos a seguir os benefícios alcançados por esse processo.

Design de software permite avaliação prévia. Como desenvolver software custa tempo e dinheiro, não parece sensato alguém investir seus recursos no desenvolvimento de um sistema que não soluciona os problemas propostos pelos interessados. Dessa maneira, a avaliação prévia do sistema se torna imprescindível para garantir que ele alcance os objetivos desses interessados. Como o design descreve diversos aspectos que estarão presentes no sistema quando construído, ele permite esse tipo de avaliação. Além disso, fazer o design de um sistema é, geralmente, mais barato que construí-lo.

Design de software estimula modelagem. Ao modelar um sistema, o designer se concentra no domínio do problema, ignorando temporariamente detalhes menos significativos para se alcançar a solução. Isso facilita na separação da complexidade essencial da complexidade acidental do problema. E, como já dito por Brooks [5], essa separação é benéfica para a qualidade final do sistema projetado.

Design de software envolve planejamento. Uma vez que o design serve de guia para a construção do sistema, o designer deve então antecipar o que será necessário para tanto. Esse planejamento ajuda na estimativa dos diversos custos envolvidos no desenvolvimento do sistema.

Exemplo 1: Diferentes custos envolvidos na construção de um sistema

  • Quanto tempo durará todo o desenvolvimento,
  • Quantos desenvolvedores serão necessários para o módulo A,
  • Se comprado, quanto custará o módulo B, e se for implementado,
  • Ou qual será o custo total do desenvolvimento do sistema.

Design de software facilita a comunicação, pois contém conhecimento sobre o sistema que pode ser gravado, transmitido e discutido entre os interessados.

Exemplo 2: Casos do design de software servindo como veículo de comunicação

Ao apresentar um sistema a novos membros de um time de desenvolvimento, informações valiosas, e.g., quais os principais módulos e seus diversos comportamentos, lhes podem ser passadas através do design do sistema antes de mostrá-los o código-fonte. Dessa maneira, essas informações de alto nível de abstração ajudarão a situá-los no código posteriormente.

No entanto, o design não serve apenas para os desenvolvedores. Um usuário do sistema pode procurar no design informações de um nível ainda maior de abstração, e.g., quais funções o sistema é capaz de realizar, ou qual o desempenho delas.

Por outro lado, design de software também demanda algumas observações importantes.

O problema a ser resolvido pode não permanecer o mesmo durante o processo de design. Ao passo que o design é implementado, o cliente, que é o interessado que deseja o software construído para a solução de um problema em particular, (1) pode mudar de idéia quanto à natureza do problema; (2) pode ter descrito o problema incorretamente; ou ainda (3) pode decidir que o problema mudou ou mesmo que já fora resolvido enquanto o design era projetado. Essas possibilidades não devem ser ignoradas durante o desenvolvimento, uma vez que elas podem ocasionar em perda de tempo e dinheiro durante a fase de design ou ainda ocasionar o fracasso no atendimento das necessidades do cliente.

Há diferenças entre o design e o sistema construído a partir dele. O design de um software é apenas um modelo, do qual o nível de detalhes pode não ser adequado para certos tipos de avaliação. Por sinal, avaliar um design insuficientemente detalhado pode levar a resultados errôneos e, conseqüentemente, a sistemas que não resolvem os problemas da forma esperada. Isso é comum acontecer, por exemplo, quando se tenta avaliar desempenho e maus designers não incluem detalhes suficientes para esse tipo de avaliação.

Exemplo 3

Uma avaliação de desempenho baseada num dado design de um sistema atestou que esse sistema seria capaz de arcar com o acesso dez mil usuários simultâneos. No entanto, esse design não detalhou corretamente o quanto de recursos cada usuário consome em cada acesso. Assim, a avaliação do desempenho considerou para cada ação de usuário menos recursos do que seriam consumidos na realidade. Como esperado, o sistema em produção não suportou os diversos acessos quando o número de usuários simultâneos chegou próximo ao limite esperado.

Por mais eficaz que um design seja, sua implementação pode não ser. Por isso, devemos nos preparar contra implementação divergente do design, uma vez que ela pode resultar num sistema que não alcança os objetivos esperados da mesma forma que um design insuficiente pode não alcançar.

Elementos do processo de design de software

O processo de design pode ser descrito como o processo de escolha da representação de uma solução a partir de várias alternativas, dadas as restrições que um conjunto de objetivos envolve. Esse processo, ilustrado na Figura 1, pode ser dividido em duas fases [2]: diversificação e convergência.

Figura 1: Ilustração do processo de design
Figura 1 (designprocess.png)

É durante a fase de diversificação em que as alternativas são geradas. Por alternativas, não nos referimos necessariamente a documentos descrevendo uma possível solução, mas também a idéias de solução. Essas alternativas são soluções em potencial e são geradas/obtidas a partir do conhecimento e da experiência do designer. Já na fase de convergência, o designer escolhe a alternativa (ou combinação de alternativas) que satisfaz(em) os objetivos esperados. A escolha comporá a solução que se sujeitará às restrições impostas pelo domínio do problema. Essa solução será descrita por meio de alguma representação e essa representação escolhida deve estar de acordo com seus propósitos: descrever a solução e permitir a construção do sistema que melhor alcança os objetivos esperados.

Os elementos enfatizados no parágrafo anterior (objetivos, restrições, alternativas, representações e soluções), juntos, definem um arcabouço conceitual que nos ajuda a entender o processo de design de software [11].

Objetivos

O processo de design tem início com uma necessidade. Se algo é projetado, e conseqüentemente construído, é porque o produto proveniente do projeto suprirá essa necessidade. Em Engenharia de Software, a necessidade parte do cliente que especifica quais suas necessidades e, portanto, quais os objetivos a serem atingidos pelo sistema de software a ser projetado. Assim, o objetivo do processo de design pode ser definido como:

Definição 2: objetivo de design
Aquilo que se pretende alcançar para resolver as necessidades do cliente.

Em design de software, objetivos também são chamados de requisitos. O design se preocupa com dois tipos de requisitos: requisitos funcionais e requisitos não-funcionais. Um requisito funcional especifica a funcionalidade que um sistema exibe.

Definição 3: requisito funcional
É a declaração de uma função ou comportamento providos pelo sistema sob condições específicas.

Em outras palavras, o que o sistema faz para alcançar às expectativas do cliente. Por exemplo, um requisito funcional de um programa de ordenação de números pode ser descrita como sua capacidade de ordenar inteiros; ou, se estamos falando de um sistema de informação de uma locadora de filmes em DVD, temos como requisitos funcionais, entre outros, a capacidade de buscar um filme usando palavras-chave, a capacidade de realizar o aluguel de um ou vários DVDs, ou a capacidade de realizar a devolução de um ou vários DVDs.

Por outro lado, um requisito não-funcional, também chamado de atributo de qualidade, especifica propriedades ou características que o sistema de software deve exibir diferentes dos requisitos funcionais.

Definição 4: atributo de qualidade (requisito não-funcional)
É a descrição de propriedades, características ou restrições que o software apresenta exibidas por suas funcionalidades.

Em outras palavras, é basicamente como o sistema funcionará. De volta ao exemplo do programa de ordenar números, um atributo de qualidade que podemos mencionar é o tempo de execução da função de ordenação do sistema (e.g., é aceitável que o tempo de execução do algoritmo de ordenação tenha uma taxa de crescimento de O ( n log n ) O ( n log n ) , onde n é o tamanho da entrada). Já no sistema da locadora de filmes, um exemplo de atributo de qualidade é a exposição de algumas de suas funcionalidades via internet (e.g., busca e reserva de filmes através de um site disponibilizado pelo sistema).

Como atributos de qualidade têm um papel importante na arquitetura do software, nós dedicaremos um capítulo a eles, onde serão descritos, categorizados e exemplificados em detalhes, além de serem relacionados aos interessados que os demandam.

Restrições

O produto de design deve ser viável. Dessa maneira, restrições são as regras, requisitos, relações, convenções, ou princípios que definem o contexto do processo de design, de forma que seu produto seja viável.

Definição 5: restrição de design
A regra, requisito, relação, convenção, ou princípio que define o texto do processo de design.

É importante saber que restrições são diretamente relacionadas a objetivos e que, em alguns casos, eles são intercambiáveis. No entanto, uma vez que não são apenas os objetivos que guiam o processo de design, é necessário diferenciar objetivos de restrições. Em outras palavras, um sistema pode ter objetivos claros, mas seu design ou algumas alternativas dele podem ser inviáveis devido às restrições.

A seguir, apresentamos dois exemplos que nos ajudarão a entender o papel das restrições no design. No primeiro exemplo, apesar de um sistema ter um objetivo claro, seu design não é viável devido a uma restrição.

Exemplo 4

Consideremos que um cliente deseje um sistema com um único objetivo: o sistema deve decidir se um programa, cuja descrição é informada como parâmetro de entrada, termina sua execução ou não.

Um designer inexperiente pode até tentar encontrar alguma alternativa de design para esse requisito – mas podemos ter certeza que a tentativa será em vão. Como é bem conhecido, há uma restrição teórica em Ciência da Computação, conhecida como o problema da parada, que impede o desenvolvimento de um programa capaz de alcançar o objetivo proposto. Como essa restrição impede a criação de qualquer alternativa de design que satisfaça o cliente, podemos observar que um design pode ser se tornar inviável mesmo que seus objetivos sejam bem claros.

Já no segundo exemplo, o sistema também tem um objetivo claro. No entanto, uma restrição torna uma possibilidade de design inviável.

Exemplo 5

Um cliente especifica o seguinte requisito para seu sistema de software: ele deve ser capaz de ler dados de um leitor de cartões de um modelo específico. No entanto, ao estudar o requisito e, conseqüentemente, o leitor de cartões, o designer encontra a seguinte restrição. O fabricante do leitor em questão não o fornece driver necessário para um dos sistemas operacionais em que o sistema deve executar.

Podemos observar que, se não fosse por essa restrição, o design para o módulo de entrada de dados do sistema seria simples: apenas dependeria do driver do leitor para obter os dados dos cartões. No entanto, agora o designer terá que criar um design alternativo para contornar a restrição encontrada. Para isso, podemos citar algumas possibilidades desse design. Uma possibilidade seria emular um dos sistemas operacionais suportados quando o software estivesse executando num s.o. não suportado. Isso significa que seria necessária a criação de uma camada de abstração entre o driver do leitor e o sistema operacional onde o software está executando, onde essa camada representaria o ambiente operacional suportado. Essa camada de abstração, então, seria implementada pelo sistema nativo ou por um emulado, caso o nativo fosse o não-suportado pelo driver. Outra possibilidade de design seria o projeto e implementação do driver para o ambiente não-suportado.

endexample

Alternativas

Uma alternativa de design é uma possibilidade de solução. Uma vez que problemas de design geralmente possuem múltiplas soluções possíveis [6], é comum que sejam geradas mais de uma alternativa para a solução de um único problema ao menos em nível de conhecimento dos designers. Note que o designer não necessariamente documentará todas as possibilidades de solução, mas, ao menos, considerará algumas delas para eleição de uma solução, mesmo que informalmente.

Definição 6: alternativa de design
Uma possibilidade de solução representada em nível de conhecimento.

O que precisamos observar é que o designer deve realizar duas tarefas essenciais após entender os objetivos e restrições envolvidos no problema de design: gerar alternativas de design e eleger a solução do problema dentre as alternativas geradas.

A geração de alternativas é o real desafio para os designers. Diferente dos problemas de decisão, onde alternativas são conhecidas ou buscadas através de métodos conhecidos, problemas de design pedem a criação de alternativas. O processo de criação deve ser controlado por princípios de design, pela experiência e imaginação do designer [11]. Alguns princípios essenciais de design serão apresentados ainda nesse capítulo.

Já a eleição da solução é simplesmente a escolha de uma dentre as alternativas geradas, desde que essa sirva para a solução do problema. A escolha da solução deve ser realizada baseada em avaliações e experiência.

beginexample De volta ao nosso programa de ordenação, consideremos apenas uma de suas características: o algoritmo de ordenação a ser usado, e vamos observar quantas alternativas um designer poderia gerar só a partir dessa característica.

Uma rápida pesquisa na internet retorna nove algoritmos que respeitam o requisito imposto anteriormente de crescimento do tempo de execução ( O ( n log n ) O ( n log n ) ): binary tree sort, heapsort, in-place merge sort, introsort, library sort, merge sort, quicksort, smoothsort, strand sort. Assim, esses nove algoritmos poderiam ser transformados em nove alternativas de design. Adicionalmente, um designer mais experiente em ordenação saberia que os dados de entrada podem definir o desempenho real do algoritmo, uma vez que uma das alternativas pode ter um ótimo desempenho para uma determinada entrada, enquanto outra alternativa, ainda que respeitando o mesmo O ( n log n ) O ( n log n ) , pode ter um péssimo desempenho para a mesma entrada. Assim, ele definiria que dois algoritmos serão usados no design, de forma que, de acordo com os dados de entrada, o algoritmo de melhor desempenho real para esses dados seja escolhido em tempo de execução. Assim, ainda mais alternativas de design são geradas. endexample

Devemos observar que a geração de alternativas poderia continuar indefinidamente caso o designer considerasse outros aspectos do problema. Dessa maneira, quando parar a geração de alternativas é um problema também a ser resolvido pelo designer, uma vez que problemas de design geralmente têm um número infinito de soluções em potencial. Essa noção de quando parar o processo de geração de alternativas, certamente, é adquirida com a experiência.

Representações

A representação é a linguagem do design. Apesar do real produto do processo de design ser a representação de um sistema de software que possibilita sua construção, descrever o sistema não é o único propósito das representações. A representação também facilita o próprio processo de design, uma vez que ajuda na comunicação dos interessados e também serve como registro das decisões tomadas.

Definição 7: representação de design
A linguagem do processo de design que representa o produto do design para sua construção e também dá suporte ao processo de design como um todo.

A representação facilita a comunicação porque torna as alternativas em produtos manipuláveis, que podem ser comunicados, avaliados, e discutidos, não só por seus criadores, mas também por outros interessados.

É importante observar que existem diversas dimensões a serem representadas numa única alternativa de design. Essas dimensões abrangem comportamento, estrutura, relações entre entidades lógicas e entidades físicas, entre outros. Essas dimensões são normalmente descritas em diferentes tipos de representações, que, em outro momento, serão chamadas de visões.

Para exemplificar representações de design, apresentaremos duas dimensões derivadas do nosso programa-exemplo de ordenação usando duas representações diferentes. A primeira representação, ilustrada pela Figura 2, mostra a dimensão estrutural de uma alternativa de design usando Unified Modeling Language (UML) [9]. Examinando essa representação, podemos observar como a solução foi decomposta em classes funcionais, como as diversas classes da estrutura se relacionam entre si, ou até em que pontos poderíamos reusar pedaços de software prontos para a construção, desde que implementem as mesmas interfaces descritas na representação. No entanto, devemos também observar que essa representação não é autocontida, uma vez que é necessário conhecimento em UML para entendê-la completamente.

Figura 2: Representação estrutural do programa de ordenação
Figura 2 (sorting-class-diagram.png)

Já a segunda representação, Figura 3, mostra parte do comportamento do programa de ordenação com alto nível de detalhe. Apesar de não conseguirmos extrair dessa representação a mesma informação apresentada na figura anterior, essa nos permite analisar seu comportamento assimtoticamente em relação ao crescimento do tamanho dos dados de entrada. Além disso, podemos também analisar o espaço consumido na execução do algoritmo.

Figura 3: Pseudocódigo do Merge sort [13]
Figura 3 (sort-pseudocode.png)

Ambas as representações mostram aspectos importantes do design de um software. No entanto, as pessoas envolvidas no seu desenvolvimento podem ainda estar interessadas em outros aspectos além da estrutura ou análise assimtótica do algoritmo. Dessa maneira, outras representações podem ainda ser necessárias para mostrar outros aspectos do sistema, e é papel do processo de design – e do designer – provê-las.

Por fim, se considerarmos múltiplas versões ao longo do tempo de uma única representação, poderemos observar a evolução das decisões de design feitas ao longo desse período. Assim, se considerarmos as diversas versões obtidas até se alcançar o algoritmo descrito na Figura 3, perceberemos a evolução desde o merge sort padrão até o merge sort in-place considerado pelo designer. Então, o histórico do design se torna peça fundamental para se entender quais decisões passadas levaram ao estado atual do design – e do sistema.

Soluções

Uma solução do design não é nada além do que a descrição que permite desenvolvedores construir um sistema de software a partir dos detalhes especificados por uma ou diversas representações. Suas principais características serão descritas nos parágrafos a seguir.

Definição 8: solução do design
A descrição do design que permite a construção do sistema de software que alcança os objetivos do design.

Soluções de design refletem a complexidade do problema, geralmente por mostrar diversos elementos e relações que compõem o problema. É possível observar essa característica quando, por exemplo, fazendo o design do sistema de informação de uma locadora que já mencionamos anteriormente. Qualquer que seja a solução, ela conterá elementos como filmes, DVDs, clientes, gêneros de filmes, etc. Todos eles inerentes ao problema em questão. No entanto, só os elementos não são o bastante para compor a solução. A solução deve também conter relações do tipo: “um cliente pode alugar um ou mais DVDs”, “um filme pode ter um ou mais gêneros”, ou “um DVD pode conter um ou mais filmes”. Em outras palavras, a solução deve conter relações similares às relações encontradas no domínio do problema. Por fim, quando diversos elementos têm diversas relações diferentes entre si, a complexidade emerge.

É difícil validar soluções de design. A complexidade inerente ao problema faz surgir diversos pontos de possível validação em relação aos objetivos de design. No entanto, o problema reside na precisão da descrição dos objetivos. Normalmente, para problemas complexos, objetivos são descritos num alto-nível de abstração que dificulta ou impossibilita bastante a avaliação das soluções.

E, por fim, a maioria dos problemas de design aceita diversas soluções. Isso é algo natural a problemas de design: uma vez que diversas alternativas podem ser geradas a partir de um único problema de design, diversas soluções podem ser obtidas [6].

Níveis de design de software

O produto do processo de design é sempre uma solução de design. No entanto, apesar de ser uma descrição que permite a construção do sistema, nada é dito sobre o nível de detalhe contido nessa solução. Na verdade, o design pode acontecer em diversos níveis de detalhe.

De acordo com o Guia para o Corpo de Conhecimento de Engenharia de Software [1], o processo de design de software consiste em duas atividades: design de alto nível e design detalhado.

O design de alto nível, também conhecido como design arquitetural, trata de descrever a organização fundamental do sistema, identificando seus diversos módulos (e sua relações entre si e com o ambiente) para que se alcancem os objetivos propostos pelo cliente.

Definição 9: design arquitetural
Descreve como o software é decomposto e organizado em módulos e suas relações.

Ao contrário do design de alto nível, o design detalhado se preocupa com a descrição detalhada de cada módulo possibilitando a construção e se adequando ao design de alto nível.

Definição 10: design detalhado
Descreve o comportamento específico e em detalhes dos módulos que compõem o design arquitetural.

Apesar dessa divisão conceitual de design em duas atividades, essa divisão pode não acontecer durante o processo de desenvolvimento do software. Algumas vezes, o designer – ou quem assume seu papel – realiza ambas as atividades em paralelo, concebendo assim um produto de design que permitirá tanto o alcance dos requisitos de qualidade, quanto a construção precisa do sistema por meio de seus detalhes. No entanto, adotaremos a separação conceitual das duas atividades de forma que possamos nos focar no design arquitetural, que é o principal assunto desse livro e que será discutido nos próximos capítulos.

No entanto, antes de iniciarmos nossos estudos em Arquitetura de Software, gostaríamos de lembrar alguns princípios e técnicas essenciais ao design de software.

Princípios e técnicas de design de software

Há diversos princípios, técnicas, e abordagens nessa área que geralmente resultam em bons produtos de design de software. Uma vez que há muitos livros e artigos sobre esse assunto, gostaríamos apenas de fazer uma breve exposição do assunto nessa seção, contribuindo assim com referências para textos mais abrangentes. Os princípios, técnicas e abordagens essenciais para um designer que apresentaremos são as seguintes:

  • Abstração
  • Encapsulamento
  • Modularização
  • Separação de preocupações
  • Acoplamento e coesão
  • Separação de políticas da execução de algoritmos
  • Separação de interfaces de suas implementações

Abstração

Abstração é um princípio essencial para se lidar com complexidade. Esse princípio recomenda que um elemento que compõe o design deva ser representado apenas por suas características essenciais, de forma que permita a distinção de outros elementos por parte do observador [3]. Como resultado, temos a representação de um elemento do design mais simples, uma vez que detalhes desnecessários são descartados, facilitando então o entendimento, comunicação e avaliação.

O que poderemos observar é que a maioria das técnicas empregadas por designers ajudam na elevação do nível de abstração do design e, assim, baixam o nível de complexidade da solução.

Encapsulamento

Encapsulamento está relacionado à ocultação de detalhes de implementação de um elemento de um sistema aos que usarão esse elemento [4]. Fazendo isso, o acoplamento entre os elementos é minimizado e sua contribuição para a complexidade do sistema é restringida às informações que eles expõem.

Encapsulamento pode ser obtido de diferentes maneiras: modularizando o sistema, separando suas preocupações, separando interfaces de implementações, ou separando políticas da execução de algoritmos.

Modularização

Modularização é a decomposição significativa do sistema em módulos. A modularização introduz partições bem-definidas e documentadas ao sistema ao decidir como estruturas lógicas do sistema serão divididas fisicamente. Podemos citar alguns benefícios da modularização:

  • Facilita o entendimento, uma vez que cada módulo pode ser estudado separadamente;
  • Facilita o desenvolvimento, uma vez que cada módulo pode ser projetado, implementado e testado separadamente;
  • Diminui o tempo de desenvolvimento, uma vez que módulos podem ser implementados em paralelo, ou ainda reusados; e
  • Promove a flexibilidade no produto, uma vez que um módulo pode ser substituído por outro, desde que implemente as mesmas interfaces.

Separação de preocupações

A separação de preocupações está fortemente ligada ao princípio da modularização. De certa maneira, a separação de preocupações define a regra para definir os módulos de um sistema: preocupações diferentes ou não-relacionadas devem se restringir a módulos diferentes. Assim, separando preocupações, obtemos benefícios semelhantes aos da modularização.

Acoplamento e coesão

Acoplamento e coesão são princípios usados para medir se módulos de um design foram bem divididos.

Acoplamento é a medida de interdependência entre módulos de software. Ou seja, quanto mais dependente um módulo A é da implementação do módulo B, maior é o acoplamento entre os módulos A e B. Alto acoplamento implica que (1) os módulos envolvidos serão mais difíceis de entender, uma vez que precisam ser entendidos em conjunto; (2) os módulos envolvidos serão mais difíceis de modificar, uma vez que as mudanças impactarão mais de um módulo; e (3) os módulos envolvidos serão mais difíceis de manter, uma vez que um problema num módulo se espalhará pelos módulos com quem está altamente acoplados.

Por outro lado, coesão é uma medida intramódulo. Ela é a medida da relação entre tarefas realizadas dentro de um mesmo módulo. As tarefas de um módulo podem estar relacionadas entre si por diferentes motivos. Esses motivos são usados para classificar os diferentes tipos de coesão:

  • Coesão funcional: : as tarefas estão agrupadas por suas funções serem similares.
  • Coesão seqüencial: : as tarefas estão agrupadas por elas pertencerem à mesma seqüência de operações. Elas compartilham dados a cada etapa da seqüência, mas não realizam uma operação completa quando executadas juntas.
  • Coesão comunicativa: : as tarefas estão agrupadas porque usam os mesmos dados, mas não estão relacionadas de nenhuma outra maneira.
  • Coesão temporal: : as tarefas estão agrupadas por serem executadas no mesmo intervalo de tempo.
  • Coesão procedural: : as tarefas estão agrupadas porque elas devem ser executadas numa ordem específica.
  • Coesão lógica: : as tarefas estão agrupadas por compartilharem uma mesma flag de controle, que indicará qual tarefa será realizada durante a execução do sistema.
  • Coesão coincidente: : as tarefas estão agrupadas sem qualquer critério.

Para alcançarmos bons designs, podemos ordenar os tipos de coesão dos mais desejáveis para os menos desejáveis [8]: funcional, seqüencial, comunicativa, temporal, procedural, lógica, e coincidente.

Separação de Políticas e Execução de Algoritmos

Essa técnica realiza a separação de preocupações. Essa técnica dita uma abordagem simples de divisão de preocupações: ou um módulo deve se preocupar com as decisões sensíveis a contexto ou com a execução de algoritmos, mas não ambos [4]. Em outras palavras, alguns módulos devem apenas executar algoritmos sem fazer qualquer decisão sensível a contexto. Essas decisões devem ser deixadas para os módulos específicos para realização dessas decisões e que também serão responsáveis por suprir parâmetros para os módulos de execução de algoritmos.

Essa separação facilita o reuso e manutenção, principalmente dos módulos de algoritmos, uma vez que eles são menos específicos que os módulos de decisões sensíveis a contexto.

Separação de Interfaces de suas Implementações

A separação entre interfaces e implementações também beneficia a modularização. Essa técnica recomenda a descrição da funcionalidade a ser implementada por algum módulo por meio de contratos, chamados interfaces. Assim, os módulos implementarão as interfaces de forma a comporem o sistema.

Usando essa técnica, o acoplamento entre módulos e seus clientes é diminuído, uma vez que os clientes estarão ligados apenas a interfaces – e não implementações –, e benefícios como facilidade no reuso, melhor entendimento do código, e menor custo de manutenção são alcançados.

Resumo

Esse capítulo expôs o conhecimento necessário sobre Design de Software para o estudo de Arquitetura de Software. Espera-se que, ao final desse capítulo, o leitor saiba:

  • o que é design software, seja como produto ou como processo, e quais são suas características e benefícios;
  • como os problemas de design de software podem ser decompostos; e
  • o que são os princípios e técnicas de design de software e quais seus benefícios.

Pela existência de ótimos livros sobre Design de Software já escritos tendo em vista o mesmo público-alvo que nós (o leitor ainda inexperiente), nós preferimos não nos aprofundar nos assuntos expostos nesse capítulo, uma vez que nossa intenção foi de apenas introduzi-los. Para informações mais detalhadas, recomendamos os livros sobre Design de Software referenciados na bibliografia desse capítulo.

Exercícios

Exercício 1

Quais os benefícios de se projetar sistemas?

Exercício 2

Duas fases importantes do projeto de software são as fases de Divergência e Convergência. Descreva o que é feito em cada fase.

Exercício 3

Jack Reeves, em What is Software Design? [10], afirma que o código fonte é design. Qual a sua opinião a respeito da afirmativa?

Exercício 4

Qual padrão de projeto viabiliza a separação de política e implementação?

Exercício 5

Defina para coesão e acoplamento e sugira métricas para medi-las em software.

References

  1. Abran, Alain and Moore, James W. and Bourque, Pierre and Dupuis, Robert and Tripp, Leonard L. (2004). Guide to the Software Engineering Body of Knowledge (SWEBOK). IEEE.
  2. Belady, L. (1981). Foreword. In Software Design: Methods and Techniques (L.J. Peters, author). Yourdon Press.
  3. Booch, Grady and Maksimchuk, Robert A. and Engel, Michael W. and Young, Bobbi J. and Conallen, Jim and Houston, Kelli A. (2007, April). Object-Oriented Analysis and Design with Applications (3rd Edition). Addison-Wesley Professional.
  4. Buschmann, Frank and Meunier, Regine and Rohnert, Hans and Sommerlad, Peter and Stal, Michael and Sommerlad, Peter and Stal, Michael. (1996, August). Pattern-Oriented Software Architecture, Volume 1: A System of Patterns. John Wiley & Sons.
  5. Brooks, Frederick P. (1995, August). The Mythical Man-Month: Essays on Software Engineering, 20th Anniversary Edition. Addison-Wesley Professional.
  6. Budgen, David. (2003, May). Software Design (2nd Edition). Addison Wesley.
  7. (1991). IEEE Standard Computer Dictionary: Compilation of IEEE Standard Computer Glossaries. Institute of Electrical and Electronics Engineers Inc., The.
  8. Mcconnell, Steve. (2004, June). Code Complete, Second Edition. Microsoft Press.
  9. Object Management Group, Inc.,. (2008, September). Unified Modeling Language. http://www.uml.org.
  10. Reeves, Jack W. (1992). What is Software Design? C++ Journal.
  11. Smith, G. F. and Browne, G. J. (1993). Conceptual Foundations of Design Problem Solving. Systems, Man and Cybernetics, IEEE Transactions on, 23(5), 1209–1219.
  12. Taylor, Richard N. and van der Hoek, Andre. (2007). Software Design and Architecture – The Once and Future Focus of Software Engineering. In FOSE '07: 2007 Future of Software Engineering. (p. 226–243). Washington, DC, USA: IEEE Computer Society.
  13. Wikipedia,. (2008). Merge Sort – Wikipedia, The Free Encyclopedia. [[Online; accessed 2-September-2008]].

Comments, questions, feedback, criticisms?

Send feedback