Atenção: esse artigo tem uma palestra complementar. Clique e assista!

Artigo no estilo: Curso

Do que trata o artigo

Metodologias de desenvolvimento de sistemas orientados a objetos (MDS-OO)

Técnicas de gestão de projeto

Processo Unificado de Desenvolvimento de Software

UML

Fases e artefatos do projeto de desenvolvimento de sistemas


Para que serve

Uma visão prática e realista do desenvolvimento de sistemas orientados a objetos utilizando técnicas de gestão de projetos e de modelagem de sistemas.


Em que situação o tema é útil

Projetos de desenvolvimento de sistema orientados a objeto.

Resumo do DevMan

Construir um pequeno sistema de computador utilizando as mais modernas técnicas de gerenciamento de projeto, modelagem orientada a objetos e uma metodologia de desenvolvimento de sistemas com aborda­gem iterativa e incremental.

Este artigo tem o objetivo de demonstrar a execução de um projeto de desenvolvimento de sistema sob a ótica da engenharia de software, fazendo uso do desenvolvimento orientado a objetos. Nesta quinta e última parte, chegamos à implementação do código-fonte, que permitirá compreender como ocorre a transformação do abstrato para o concreto, do modelo para o código implementado.

Nas partes anteriores, modelamos o processo de negócio que será suportado pelo sistema em desenvolvimento, empregando técnicas de levantamento de dados através da observação direta e da entrevista com o cliente. A modelagem do processo de negócio deu origem aos requisitos funcionais e não funcionais do sistema e a construção de uma proposta de solução, materializada no protótipo do sistema.

Passamos então para a especificação de casos de uso, diagramas de atividades e classes, sempre focados na evolução gradativa da solução, passamos pela solução arquitetural e chegamos, finalmente, à implementação do código, que será abordada nessa parte do artigo.

A Implementação

Com o amadurecimento do modelo proposto e tomadas as decisões pertinentes à arquitetura, infraestrutura, ambiente de servidor de aplicação e banco de dados, ferramentas e linguagem de desenvolvimento, estamos aptos a iniciar a fase de implementação.

A implementação é a etapa (disciplina) responsável pela construção dos scripts de criação da estrutura do banco de dados, pela construção do código-fonte do aplicativo e pela execução dos testes, tendo como entrada os artefatos elaborados nas fases anteriores.

Para a codificação, nesse artigo, utilizaremos o Microsoft Visual Web Developer 2008 Express Edition, uma versão freeware do Visual Studio 2008, e a linguagem Visual Basic. Como sistema gerenciador de banco de dados utilizaremos o Firebird Server 2.1.1, um excelente sistema de banco de dados padrão SQL de código aberto (open source).

Nota

O servidor de banco de dados Firebird Server pode ser obtido no site oficial do projeto, http://www.firebirdsql.org, e pode ser livremente instalado e utilizado em servidores ou estações de trabalho das principais plataformas do mercado: Win32, Win64, Linux x86, Linux AMD64, MacOSX e Solaris.

Estrutura de pacotes do projeto

Começaremos a implementação pela criação, no Visual Studio, de dois novos projetos: Um projeto web, que chamamos neste exemplo de SCRMweb, para a camada de apresentação e um projeto biblioteca de classes (class library), chamado SCRMsrv, para a camada de negócio e de persistência. Os dois projetos estarão contidos em uma solução denominada SCRM. A Figura 1 apresenta a janela Solution Explorer, com a estrutura dos projetos e os respectivos arquivos de programas implementados.

Figura 1. Estrutura de projetos

Para criar a estrutura de projeto proposta, abra o Visual Studio e, no menu File, selecione a opção New Project. No quadro Project Types, selecione a linguagem de programação a ser utilizada (Visual Basic) e o tipo do primeiro projeto a ser criado (Windows). No quadro Templates, selecione o modelo Class Library. Os demais campos devem ser preenchidos conforme exemplificado na Figura 2. Com esse procedimento criaremos a solução SCRM e o projeto SCRMsrv, sendo necessário ainda que adicionemos à solução um novo projeto ASP.Net Web Application, nomeado como SCRMweb.

Figura 2. Criando a ClassLibrary

Os arquivos de programa (classes) do projeto SCRMsrv foram fisicamente organizados em uma estrutura composta por três pastas (subdiretórios) e logicamente identificados por pacotes (namespaces) análogos às pastas criadas. O projeto foi estruturado da seguinte forma:

· Modelo: Composto de classes que representam as entidades de negócio do sistema, sendo, portanto, constituídas por atributos privados (private) e propriedades públicas (public property), responsáveis pela exposição dos dados da classe (métodos getters e setters).

  • Negócio: Composto por classes públicas com métodos, igualmente públicos, responsáveis pelo comportamento e aplicação das regras de negócio. Essas classes não possuem atributos e seus métodos podem receber e/ou retornar as classes (ou coleções de classes) do pacote Modelo.
  • Integração: Nesse pacote serão escritas as classes responsáveis pela interação com o sistema de banco de dados, que controlam as conexões, executam as instruções SQL e retornam o resultado para o pacote Negócio, que sempre será o acionador dos métodos do pacote Integração. As classes do pacote Integração serão de visibilidade privativa às classes do projeto (friend).

A estrutura de projeto criada nesses primeiros passos da etapa de implementação está em conformidade com o Diagrama de Pacotes apresentado e discutido na parte 4 deste artigo.

Construindo a camada de negócios e dados

Ao longo da modelagem do sistema – Requisitos, Análise e Projeto – foram confeccionados artefatos (documentos de texto, planilhas e diagramas), previstos na metodologia de desenvolvimento de sistemas adotada, com o objetivo de documentar o sistema e apoiar o trabalho dos projetistas envolvidos.

Comentamos também, mais de uma vez, que durante a etapa de implementação muitos dos artefatos de análise e projeto seriam quase que diretamente convertidos em linhas de código. A criação automática de código a partir de modelos UML é uma realidade de mercado e uma grande vantagem, não apenas para ganhar produtividade e facilitar a vida do codificador, mas, principalmente, para garantir o sincronismo da documentação com o código. Praticamente todas as ferramentas de modelagem, incluindo as gratuitas, possuem, pelo menos, a capacidade de gerar o código a partir do modelo (forward engineering). Algumas ferramentas mais sofisticadas possuem ainda a capacidade de transformação bidirecional de modelo e código, de forma que podemos alterar o modelo e visualizar o código resultante, assim como alterar o código e visualizar as respectivas alterações no modelo.

Em nosso artigo utilizamos o StarUML, uma ferramenta gratuita de modelagem que realiza a transformação unidirecional do modelo em código C#, C++ e Java. Optamos por construir nossa aplicação em VB.Net e, por isso, geraremos nosso código manualmente, iniciando pela construção das classes do pacote de modelo. As classes do pacote Modelo, como explicado anteriormente, representam entidades de negócio. Na Listagem 1 podemos visualizar o código-fonte da classe referente à entidade grupo de recursos.

Listagem 1. Classe GrupoRecursos

Namespace Modelo
     Public Class GrupoRecursos
  
         Private numId As Integer
         Public Property id() As Integer
             Get
                 Return numId
             End Get
             Set(ByVal value As Integer)
                 numId = value
             End Set
         End Property
  
         Private strDescricao As String
         Public Property descricao() As String
             Get
                 Return strDescricao
             End Get
             Set(ByVal value As String)
                 strDescricao = value
             End Set
         End Property
  
         Private strNatureza As Natureza
         Public Property natureza() As Natureza
             Get
                 Return strNatureza
             End Get
             Set(ByVal value As Natureza)
                 strNatureza = value
             End Set
         End Property
  
     End Class
 End Namespace

Podemos observar, logo na primeira linha da Listagem 1, que foi incluída a declaração Namespace com o nome do pacote correspondente, no caso, Modelo. A seguir, encontramos a declaração da classe como pública (public). Observe também que essa classe é composta apenas por variáveis locais privadas (private) e propriedades públicas. O mesmo procedimento será realizado para as demais entidades identificadas no modelo do projeto.

O próximo passo é a criação das classes do pacote de integração. Essas classes possuem a responsabilidade de estabelecer a ligação (integração) com o gerenciador de banco de dados. A primeira classe do pacote de integração será a classe GrupoRecursosDAO, exibida na Listagem 2.

Listagem 2. Classe GrupoRecursosDAO

Namespace Integracao
  
     ''' Classe de manipulação do banco de dados
     Friend Class GrupoRecursosDAO
  
         Private Sub New()
         End Sub
  
         ''' Recupera do banco de dados do sistema um objeto GrupoRecursos
         ''' Código do grupo de recursos
         ''' Objeto GrupoRecursos recuperado
         Public Shared Function ObterObjeto(ByVal id As Integer) As Modelo.GrupoRecursos
             Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
             Dim objComando = objDBMediator.Command("SELECT * FROM GrupoRecursos WHERE grpID = @grpID")
             Dim objDataReader As Data.IDataReader
             Dim objGrupoRecursos As Modelo.GrupoRecursos = Nothing
             objComando.Parameters.Add(objDBMediator.Parameter("@grpID", id))
             objDataReader = objDBMediator.MontaReader(objComando)
             If objDataReader.Read Then
                 objGrupoRecursos = MontaObjeto(objDataReader)
             End If
             objDataReader.Close()
             objDataReader.Dispose()
             objDataReader = Nothing
             Return objGrupoRecursos
         End Function
  
         ''' Recupera do banco de dados do sistema um objeto GrupoRecursos
         ''' Descrição do grupo de recursos
         ''' Objeto GrupoRecursos recuperado
         Public Shared Function ObterObjeto(ByVal descricao As String) As Modelo.GrupoRecursos
             Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
             Dim objComando = objDBMediator.Command("SELECT * FROM GrupoRecursos WHERE grpDescricao =
          @grpDescricao")
             Dim objDataReader As Data.IDataReader
             Dim objGrupoRecursos As Modelo.GrupoRecursos = Nothing
             objComando.Parameters.Add(objDBMediator.Parameter("@grpDescricao", descricao))
             objDataReader = objDBMediator.MontaReader(objComando)
             If objDataReader.Read Then
                 objGrupoRecursos = MontaObjeto(objDataReader)
             End If
             objDataReader.Close()
             objDataReader.Dispose()
             objDataReader = Nothing
             Return objGrupoRecursos
         End Function
  
         ''' Recupera um coleção de objetos GrupoRecursos
         ''' Coleção de objetos GrupoRecursos
         Public Shared Function Listar() As List(Of Modelo.GrupoRecursos)
             Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
             Dim objComando = objDBMediator.Command("SELECT * FROM GrupoRecursos ORDER BY grpDescricao")
             Dim objDataReader As Data.IDataReader
             Dim listGrupoRecursos As List(Of Modelo.GrupoRecursos) = New List(Of Modelo.GrupoRecursos)
             objDataReader = objDBMediator.MontaReader(objComando)
             While objDataReader.Read
                 listGrupoRecursos.Add(MontaObjeto(objDataReader))
             End While
             objDataReader.Close()
             objDataReader.Dispose()
             objDataReader = Nothing
             Return listGrupoRecursos
         End Function
  
         Private Shared Function MontaObjeto(ByRef objDataReader As Data.IDataReader) As Modelo.GrupoRecursos
             Dim objGrupoRecursos As Modelo.GrupoRecursos = New Modelo.GrupoRecursos()
             objGrupoRecursos.id = objDataReader("grpID")
             objGrupoRecursos.descricao = objDataReader("grpDescricao")
             objGrupoRecursos.natureza = objDataReader("grpNatureza")
             Return objGrupoRecursos
         End Function
  
         ''' Recupera a quantidade de recursos associados a um determinado grupo de recursos
         ''' Código de identificação do grupo de recursos a ser excluído do banco de dados
         ''' Número inteiro referente à quantidade de recursos associados ao grupo de recursos
         Public Shared Function ObterQtdRecursosAssociados(ByVal id As Integer) As Integer
             Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
             Dim objComando = objDBMediator.Command("SELECT COUNT(*) FROM Recurso WHERE grpID = @grpID")
             objComando.Parameters.Add(objDBMediator.Parameter("@grpID", id))
             Return objDBMediator.MontaScalar(objComando)
         End Function
  
         ''' Adiciona um novo grupo de recursos ao banco de dados do sistema
         ''' Objeto GrupoRecursos a ser adicionado ao banco de dados
         ''' Objeto GrupoRecursos adicionado
         Public Shared Function Incluir(ByVal objGrupoRecursos As Modelo.GrupoRecursos) As Modelo.GrupoRecursos
             Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
             Dim objComando = objDBMediator.Command("SELECT * FROM Add_GrupoRecursos(@grpDescricao,
          @grpNatureza)")
             objComando.Parameters.Add(objDBMediator.Parameter("@grpDescricao", objGrupoRecursos.descricao))
             objComando.Parameters.Add(objDBMediator.Parameter("@grpNatureza", objGrupoRecursos.natureza))
             Try
                 objGrupoRecursos.id = objDBMediator.MontaScalar(objComando)
                 Return objGrupoRecursos
             Catch ex As Exception
                 Return Nothing
             End Try
         End Function
  
         ''' Altera um grupo de recursos do banco de dados do sistema
         ''' Objeto GrupoRecursos a ser alterado no banco de dados
         ''' True se a alteração foi realizada com sucesso e False se ocorreu algum erro
         Public Shared Function Alterar(ByVal objGrupoRecursos As Modelo.GrupoRecursos) As Boolean
             Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
             Dim objComando = objDBMediator.Command("UPDATE GrupoRecursos SET grpDescricao = @grpDescricao,
          grpNatureza = @grpNatureza WHERE grpID = @grpID")
             objComando.Parameters.Add(objDBMediator.Parameter("@grpDescricao", objGrupoRecursos.descricao))
             objComando.Parameters.Add(objDBMediator.Parameter("@grpNatureza", objGrupoRecursos.natureza))
             objComando.Parameters.Add(objDBMediator.Parameter("@grpID", objGrupoRecursos.id))
             Try
                 objDBMediator.ExecutaQuery(objComando)
                 Return True
             Catch ex As Exception
                 Return False
             End Try
         End Function
  
         ''' Exclui um grupo de recursos ao banco de dados do sistema
         ''' Código de identificação do grupo de recursos a ser excluído do banco de dados
         ''' True se a exclusão foi realizada com sucesso ou False se ocorreu algum erro
         Public Shared Function Excluir(ByVal id As Integer) As Boolean
             Dim objDBMediator = Integracao.DBMediatorFactory.ObterDBMediator
             Dim objComando = objDBMediator.Command("DELETE FROM GrupoRecursos WHERE grpID = @grpID")
             objComando.Parameters.Add(objDBMediator.Parameter("@grpID", id))
             Try
                 objDBMediator.ExecutaQuery(objComando)
                 Return True
             Catch ex As Exception
                 Return False
             End Try
         End Function
  
     End Class
 End Namespace

A classe GrupoRecursosDAO, logo na primeira linha, possui a declaração do Namespace e a identificação do pacote Integração. A quarta linha inicia com a declaração Friend, restringindo a visibilidade da classe as outras classes e objetos do assembly que será gerado.

O uso de tags de documentação é um boa prática. Para tanto, observe que todos os métodos (functions e subs) da classe são precedidos de linhas de comentário com tags de documentação XML. Essas linhas são sempre iniciadas por três aspas simples (apóstrofos), seguidos por tags com a descrição resumida do método (summary), a identificação e a descrição dos parâmetros (param) e, no caso de funções, com o retorno (returns) que devem ser esperados. Esse tipo de documentação é especialmente útil em métodos públicos, que serão utilizados por outros métodos, por serem reconhecidos pelo Visual Studio e exibidos pelo IntelliSense durante a edição do código-fonte.

Para finalizar a organização dos pacotes da biblioteca de classes SCRMsrv, será criado o pacote Negocio para os objetos de negócio (Business Object) da aplicação. Criaremos a classes GrupoRecursosBO, exibida na Listagem 3.

Listagem 3. Classe GrupoRecursosBO

Namespace Negocio
  
     ''' Classe para validação de regras de negócio
     Public Class GrupoRecursosBO
  
         ''' Recupera os dados de um objeto GrupoRecursos
         ''' Código do grupo de recursos
         ''' Objeto GrupoRecursos recuperado
         Public Shared Function ObterObjeto(ByVal grupoID As Integer) As Modelo.GrupoRecursos
             Return Integracao.GrupoRecursosDAO.ObterObjeto(grupoID)
         End Function
  
         ''' Recupera os dados de um objeto GrupoRecursos
         ''' Descrição do grupo de recursos
         ''' Objeto GrupoRecursos recuperado
         Public Shared Function ObterObjeto(ByVal descricao As String) As Modelo.GrupoRecursos
             Return Integracao.GrupoRecursosDAO.ObterObjeto(descricao)
         End Function
  
         ''' Recupera um coleção de objetos GrupoRecursos
         ''' Coleção de objetos GrupoRecursos
         Public Shared Function Listar() As List(Of Modelo.GrupoRecursos)
             Return Integracao.GrupoRecursosDAO.Listar()
         End Function
  
         ''' Adiciona um novo grupo de recursos ao banco de dados do sistema
         ''' Objeto GrupoRecursos a ser adicionado ao banco de dados
         ''' Objeto GrupoRecursos adicionado
         Public Shared Function Incluir(ByRef objGrupoRecursos As Modelo.GrupoRecursos) As List(Of String)
             Dim strMsgs As List(Of String) = New List(Of String)
             If Not RN06(objGrupoRecursos.descricao) Then
                 strMsgs.Add(TipoExcecaoBO.GrupoRecursosIncluir_DescricaoRepetida.ToString)
             Else
                 objGrupoRecursos = Integracao.GrupoRecursosDAO.Incluir(objGrupoRecursos)
                 If objGrupoRecursos Is Nothing Then
                     strMsgs.Add(TipoExcecaoBO.GrupoRecursosIncluir_Falha.ToString)
                 End If
             End If
             Return strMsgs
         End Function
  
         ''' Altera um grupo de recursos do banco de dados do sistema
         ''' Objeto GrupoRecursos a ser alterado no banco de dados
         ''' Resultado da operação de alteração
         Public Shared Function Alterar(ByVal objGrupoRecursos As Modelo.GrupoRecursos) As List(Of String)
             Dim strMsgs As List(Of String) = New List(Of String)
             If Not RN06(objGrupoRecursos) Then
                 strMsgs.Add(TipoExcecaoBO.GrupoRecursosAlterar_DescricaoRepetida.ToString)
             ElseIf Integracao.GrupoRecursosDAO.Alterar(objGrupoRecursos) = False Then
                 strMsgs.Add(TipoExcecaoBO.GrupoRecursosAlterar_Falha.ToString)
             End If
             Return strMsgs
         End Function
  
         ''' Exclui um grupo de recursos ao banco de dados do sistema
         ''' Código de identificação do grupo de recursos a ser excluído do banco de dados
         ''' Resultado da operação de exclusão
         Public Shared Function Excluir(ByVal grupoID As Integer) As List(Of String)
             Dim strMsgs As List(Of String) = New List(Of String)
             If Not RN01(grupoID) Then strMsgs.Add(TipoExcecaoBO.GrupoRecursosExcluir_RecursosAssociados.ToString)
             If Not RN02(grupoID) Then strMsgs.Add(TipoExcecaoBO.GrupoRecursosExcluir_ReservasFuturas.ToString)
             If strMsgs.Count = 0 Then
                 If Integracao.GrupoRecursosDAO.Excluir(grupoID) = False Then
                     strMsgs.Add(TipoExcecaoBO.GrupoRecursosExcluir_Falha.ToString)
                 End If
             End If
             Return strMsgs
         End Function
  
         ''' Validar a exclusão de grupo de recursos com recursos associados
         Private Shared Function RN01(ByVal grupoID As Integer) As Boolean
             If Integracao.GrupoRecursosDAO.ObterQtdRecursosAssociados(grupoID) > 0 Then
                 Return False
             Else
                 Return True
             End If
         End Function
  
         ''' Validar a exclusão de grupo de recursos com reservas futuras
         Private Shared Function RN02(ByVal grupoID As Integer) As Boolean
             'TODO: Implementar verificação da existência de solicitações de reservas para datas futuras
             Return True
         End Function
  
         ''' Validar a duplicidade da descrição do grupo de recursos
         Private Shared Function RN06(ByVal objGrupoNew As Modelo.GrupoRecursos) As Boolean
             Dim objGrupoOld As Modelo.GrupoRecursos = Integracao.GrupoRecursosDAO.
          ObterObjeto(objGrupoNew.descricao)
             If objGrupoOld Is Nothing Then
                 Return True
             Else
                 If objGrupoOld.id = objGrupoNew.id Then
                     Return True
                 Else
                     Return False
                 End If
             End If
         End Function
  
         ''' Validar a duplicidade da descrição do grupo de recursos
         Private Shared Function RN06(ByVal descricao As String) As Boolean
             Dim objGrupoOld As Modelo.GrupoRecursos = Integracao.GrupoRecursosDAO.ObterObjeto(descricao)
             If objGrupoOld Is Nothing Then
                 Return True
             Else
                 Return False
             End If
         End Function
  
     End Class
 End Namespace
 <p align="left">

Além das peculiaridades comentadas anteriormente (declaração Namespace, visibilidade da classe e uso de tags de documentação XML), podemos observar que a classe é composta por métodos públicos, responsáveis pelo comportamento, e por funções privadas, responsáveis pela implementação de regras de negócio. Os métodos privados relativos às regras de negócio, por uma questão de compatibilidade com a documentação do projeto, foram nomeados com a mesma identificação do artefato de especificação de regras de negócio, apresentado na parte 2 deste artigo. Desta forma, a RN01 será implementada no método RN01, facilitando a rastreabilidade do código, o que será muito útil em futuras manutenções evolutivas e corretivas.

A função privada RN02, linhas 80 a 83, implementa a regra de negócio que validará a exclusão de um grupo de recurso com reservas futuras. Essa regra de negócio, apesar de ter sido identificada e especificada durante a fase de análise de requisitos (vide parte 2 desse artigo), somente será detalhada durante a próxima iteração do projeto, não havendo, nesse momento, informações suficientes para realizarmos sua construção. Nesse caso, a função foi criada de maneira que retornará sempre verdadeiro (true), o que possibilita seu uso pelo restante do sistema, mesmo que sem efeito. Quando forem obtidas as informações necessárias, retornaremos a esse arquivo e incrementaremos a função, sem a necessidade de alterar o restante do código. Essa é uma prática comum sempre que trabalhamos com um método de desenvolvimento que seja iterativo e incremental.

Incluímos ainda nessa função uma linha de comentário com a palavra chave “TODO” (do inglês, To Do – A Fazer). Essa linha de comentário fará com que o Visual Studio adicione uma entrada na lista de tarefas “Comments” com o texto da linha de comentário, permitindo a rápida e fácil localização do que está pendente em nosso código-fonte.

Nossa camada de negócios é composta ainda por outros arquivos de programas correspondentes às entidades Recurso e Usuário e aos componentes relacionados, tendo sido implementado, ao todo, 13 arquivos de programa. Por motivos óbvios não abordaremos nesse artigo a construção das demais classes da camada de negócio (Business Objects e Modelos) devido às similaridades existentes.

As classes implementadas são de complexidade baixa, com uma arquitetura modular que nos possibilitou ter métodos bastante coesos e, por consequência, bastante simples. Para a construção do material desse artigo foi alocado um programador experiente que implementou os 13 arquivos de programa dessa camada em apenas um dia de trabalho. Isso foi possível porque visamos uma documentação clara e consistente, além de adotarmos uma arquitetura sólida e padronizada.

Construindo a camada de apresentação

A camada de apresentação, conforme abordado na parte 4 desse artigo, poderá ser implementada em um aplicativo independente da camada de negócios, graças a alta reusabilidade obtida com a arquitetura do sistema, que isolou a camada de negócios em uma aplicação distinta. Poderíamos, por exemplo, criar também uma aplicação para dispositivos móveis, na plataforma Java ME, que reutilizasse a camada de negócios construída. Poderíamos ainda agregar à nossa camada de negócios uma interface WCF (Windows Communication Foundation), para que a camada de negócios pudesse ser hospedada em um computador e a camada de apresentação web pudesse ser hospedada em outro computador, um servidor de aplicação. Estaríamos então operando em um ambiente distribuído e de alta escalabilidade, sem a necessidade de implementar grandes mudanças no código do sistema.

Devemos lembrar também que durante a análise de requisitos foi construído um protótipo da solução proposta (vide parte 2 desse artigo). Na codificação do protótipo, utilizamos uma arquitetura em camadas, no padrão MVC, no intuito de reutilizar as páginas web durante a implementação da camada de apresentação na fase de construção do sistema.

Criamos, no Visual Studio, a solução SCRM, que contém o projeto SCRMweb, nossa camada de apresentação. Para reutilizar o protótipo, devemos copiar para o diretório da aplicação os arquivos das páginas web (aspx e aspx.vb), da folha de estilo (principal.css) e da master page (principal.master). Os arquivos foram copiados de um diretório para o outro porque agora podemos atualizá-los, mantendo o protótipo na situação original, aprovada pelo cliente.

Começaremos pela implementação da rotina de CRUD (Create, Read, Update and Delete) do cadastro de grupos de recursos. No arquivo GrupoRecursosLista.aspx, que apresenta um grid com os grupos de recursos cadastrados, precisaremos reconfigurar o controle ObjectDataSource, alterando as propriedades TypeName e SelectMethod, para que apontem para a classe GrupoRecursosBO, da camada de negócios, e o método Listar, respectivamente. O controle ficará da seguinte forma:

 SelectMethod="Listar" TypeName=
         "SCRMsrv.Negocio.
             GrupoRecursosBO" />

Precisamos ainda incluir o tratamento para alguns dos eventos da página, como por exemplo, o click nos botões da página. Na Listagem 4 vemos o code-behind correspondente.

Listagem 4. Arquivo GrupoRecursosLista.aspx.vb

Imports SCRMsrv
  
 Partial Class GrupoRecursosLista
     Inherits System.Web.UI.Page
  
     Protected Sub grdGrupoRecursos_RowDataBound(ByVal sender As Object, _
          ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) _
          Handles grdGrupoRecursos.RowDataBound
         If e.Row.RowType = DataControlRowType.DataRow Then
             Dim objGrupoRecursos As Modelo.GrupoRecursos = e.Row.DataItem
             Dim btnAlterar As ImageButton = e.Row.FindControl("btnAlterar")
             Dim btnExcluir As ImageButton = e.Row.FindControl("btnExcluir")
             e.Row.Cells(1).Text = Enumeration.getName(GetType(Modelo.Natureza), objGrupoRecursos.natureza.ToString)
             btnAlterar.AlternateText = String.Format(Resources.Labels.Grupo_btnAlterar_Alt, objGrupoRecursos.descricao)
             btnAlterar.CommandArgument = objGrupoRecursos.id
             btnExcluir.AlternateText = String.Format(Resources.Labels.Grupo_btnExcluir_Alt, objGrupoRecursos.descricao)
             btnExcluir.CommandArgument = objGrupoRecursos.id
             btnExcluir.OnClientClick = String.Format("return confirm('{0}')", _
          String.Format(Resources.Labels.Grupo_btnExcluir_Confirm, objGrupoRecursos.descricao))
         End If
     End Sub
  
     Protected Sub grdGrupoRecursos_RowCommand(ByVal sender As Object, _
          ByVal e As System.Web.UI.WebControls.GridViewCommandEventArgs) _
          Handles grdGrupoRecursos.RowCommand
         If e.CommandName = "Excluir" Then
             ExcluiGrupo(e.CommandArgument)
         ElseIf e.CommandName = "Alterar" Then
             Server.Transfer(String.Format("GrupoRecursosFicha.aspx?action={0}&id={1}", _
          +ActionType.Alterar, e.CommandArgument))
         End If
     End Sub
  
     Protected Sub btnIncluir_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnIncluir.Click
         Server.Transfer(String.Format("GrupoRecursosFicha.aspx?action={0}", +ActionType.Incluir))
     End Sub
  
     Private Sub ExcluiGrupo(ByVal grupoID As Integer)
         Dim objGrupoRecursos As Modelo.GrupoRecursos = Negocio.GrupoRecursosBO.ObterObjeto(grupoID)
         Dim strMsgs As List(Of String) = Negocio.GrupoRecursosBO.Excluir(grupoID)
         Me.blstMensagem.Items.Clear()
         If strMsgs.Count > 0 Then
             Me.blstMensagem.CssClass = "validatorErro"
             Me.blstMensagem.DataSource = MsgErro.ConverteExcecaoBO(strMsgs)
             Me.blstMensagem.DataBind()
         Else
             strMsgs.Add(String.Format(Resources.Mensagens.SUC004, objGrupoRecursos.descricao))
             Me.blstMensagem.CssClass = "validatorSucesso"
             Me.blstMensagem.DataSource = strMsgs
             Me.blstMensagem.DataBind()
             Me.grdGrupoRecursos.DataBind()
         End If
     End Sub
 End Class

Para concluir a rotina de cadastro do grupo de recursos precisamos atualizar a ficha de cadastro. O protótipo o arquivo GrupoRecursosFicha.aspx possui um controle DropDownList com dois itens fixados no próprio controle. A configuração do controle deve ser alterada para que possamos recuperar o conteúdo da coleção Natureza. Incluiremos também o tratamento de eventos da página. A Listagem 5 apresenta o code-behind da página.

Listagem 5. Arquivo GrupoRecursosFicha.aspx.vb

Imports SCRMsrv
  
 Partial Class GrupoRecursosFicha
     Inherits System.Web.UI.Page
  
     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
         If Not Page.IsPostBack Then
             Dim numAcao As ActionType = Request.QueryString("action")
             If numAcao = ActionType.Alterar Then
                 Dim numId As Integer = Request.QueryString("id")
                 Dim objGrupo As SCRMsrv.Modelo.GrupoRecursos =
                    SCRMsrv.Negocio.GrupoRecursosBO.ObterObjeto(numId)
                 If objGrupo IsNot Nothing Then
                     PopulaNatureza()
                     Me.txtDescricao.Text = objGrupo.descricao
                     Me.cboNatureza.SelectedValue = objGrupo.natureza
                     Me.txtDescricao.Focus()
                     ViewState("action") = ActionType.Alterar
                     ViewState("id") = numId
                 End If
             ElseIf numAcao = ActionType.Incluir Then
                 PopulaNatureza()
                 Me.txtDescricao.Focus()
                 ViewState("action") = ActionType.Incluir
             Else
                 Server.Transfer("AcessoInvalido.htm")
             End If
         End If
     End Sub
  
     Private Sub PopulaNatureza()
         Me.cboNatureza.DataSource = Enumeration.getNames(GetType(SCRMsrv.Modelo.Natureza))
         Me.cboNatureza.DataValueField = "value"
         Me.cboNatureza.DataTextField = "name"
         Me.cboNatureza.DataBind()
     End Sub
  
     Protected Sub btnOk_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnOk.Click
         Dim strMsgs As List(Of String) = New List(Of String)
         Dim strMsgSucesso As String
         Dim objGrupoRecursos As Modelo.GrupoRecursos = New Modelo.GrupoRecursos()
         objGrupoRecursos.descricao = Me.txtDescricao.Text.Trim
         objGrupoRecursos.natureza = Me.cboNatureza.SelectedValue
         Me.blstMensagem.Items.Clear()
         If ViewState("action") = ActionType.Incluir Then
             strMsgSucesso = Resources.Mensagens.SUC001
             strMsgs = Negocio.GrupoRecursosBO.Incluir(objGrupoRecursos)
             If strMsgs.Count = 0 Then Me.btnOk.Enabled = False
         ElseIf ViewState("action") = ActionType.Alterar Then
             strMsgSucesso = Resources.Mensagens.SUC002
             objGrupoRecursos.id = ViewState("id")
             strMsgs = Negocio.GrupoRecursosBO.Alterar(objGrupoRecursos)
         Else
             Server.Transfer("AcessoInvalido.htm")
             Exit Sub
         End If
         If strMsgs.Count > 0 Then
             Me.blstMensagem.CssClass = "validatorErro"
             Me.blstMensagem.DataSource = MsgErro.ConverteExcecaoBO(strMsgs)
             Me.blstMensagem.DataBind()
         Else
             strMsgs.Add(strMsgSucesso)
             Me.blstMensagem.CssClass = "validatorSucesso"
             Me.blstMensagem.DataSource = strMsgs
             Me.blstMensagem.DataBind()
         End If
     End Sub
 
 
     Protected Sub btnCancelar_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnCancelar.Click
         Server.Transfer("~/GrupoRecursosLista.aspx")
     End Sub
  
 End Class

Com muito pouco esforço incrementamos o protótipo e implementamos a camada de apresentação. A rotina de cadastro completa, composta por quatro arquivos de programas, foi implementada por um programador experiente com apenas duas horas de trabalho. Poderíamos ainda ter alocado dois profissionais, um para implementar a biblioteca de classes (SCRMsrv) e outro para implementar a camada de apresentação (SCRMweb), em paralelo, reduzindo a duração total do cronograma do projeto.

Por último, vemos que a reutilização do protótipo garantiu também a integridade entre o que foi prototipado, avaliado e aprovado pelo cliente e o produto final, que por consequência será mais facilmente aprovado.

Nota

Os artefatos de projeto, arquivos de código-fonte, scripts de definição de estruturas de banco de dados e todo o material confeccionado durante o desenvolvimento do sistema de controle de recursos materiais, objeto de estudo desse artigo, está disponível para download no site da DevMedia.

Conclusão

Ao longo deste artigo, organizado em cinco partes (mas tínhamos assunto para muito mais), desnudamos o processo de desenvolvimento de um sistema real e factível. Começamos com o termo de abertura do projeto de desenvolvimento e com a declaração de escopo e concluímos, nessa última parte, com a implementação do código-fonte de uma iteração completa. Navegamos pelo mundo da engenharia de software e da modelagem de sistemas, passando do abstrato ao concreto, do artefato ao código implementado e testado.

O artigo foi escrito a quatro mãos, por dois profissionais que têm em comum o entusiasmo pela engenharia de software, mas com conhecimentos específicos distintos, que se somaram. Um especialista em tecnologia .Net e o outro um pesquisador de Java e software livre. A parceria entre dois universos paralelos foi possível porque a engenharia de software e as metodologias de desenvolvimento orientadas a objeto são perenes e independentes dos padrões tecnológicos e dos modismos do mercado. Chegamos até mesmo a discutir, como uma provação adicional, a publicação de duas versões dessa última parte do artigo, uma na plataforma .Net e outra em Java. Acabamos desistindo (por enquanto).

Desejamos fechar essa última parte do artigo com a mesma frase que abriu muitas das partes anteriores – Programar é divertido, mas desenvolver sistemas com qualidade é difícil – tal como um mantra, buscando criar a transformação para o crescimento daqueles que nos lêem.

Nota do DevMan

Nesse artigo foi utilizado o BrOffice.org para a elaboração dos textos, o Microsoft Visual Web Developer 2008 Express Edition como ferramenta de desenvolvimento, o IBExpert Personal Edition da HK Software como ferramenta de gerenciamento do banco de dados e o Firebird Server 2.1.1 como gerenciador de banco de dados. Todas essas ferramentas são gratuitas.

Referências Bibliográficas

Larman, Craig. 2002. Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and the Uni­fied Process. Second Edition. Prentice Hall PTR.

Vários. 2007. Metodologia de Desenvolvimento de Projetos da Dataprev: Paradigma da Orientação a Objetos – Versão 3.1.

Vários. 2007. Implementing Data Transfer Object in .NET with a DataSet.
http://msdn2.microsoft.com/en-us/library/ms998527.aspx

Vários. 2007. Implementing Data Transfer Object in .NET with a Typed DataSet.
http://msdn2.microsoft.com/en-us/library/ms998529.aspx

Vários. 2007. Data Transfer Object.
http://msdn2.microsoft.com/en-us/library/ms978717.aspx

Chiba, Cláudio e Nardi, Alexandre. 2007. Desenvolvimento em Camadas.
http://www.microsoft.com/brasil/msdn/tecnologias/arquitetura/Layers_Developing.mspx

Filho, Fernando Gebara. 2007. Solução para um sistema largamente distribuído.
http://www.microsoft.com/brasil/msdn/tecnologias/Arquitetura/Solucao_Sistema_Distribuido.mspx

Kalidindi, Ravi e Kalidindi, Rohini. 2007. Best Practices to Improve Performance Using Patterns in J2EE. http://www.pre­cisejava.com/javaperf/j2ee/Patterns.htm

Neward, Ted. 2006. Arquitetura Pragmática: Camadas.
http://www.microsoft.com/brasil/msdn/tecnologias/arquitetura/NPALayering.mspx

Panchal, Nimesh. 2003. Implementing MVC Design Pattern in .NET.
http://www.c-sharpcorner.com/uploadfile/napanchal/mvcdesign12052005035152am/mvcdesign.aspx

Macoratti, José Carlos. 2007. Padrões de Projeto: O modelo MVC – Model View Controller.
http://www.macoratti.net/vbn_mvc.htm