Artigo .net Magazine 65 - Construa uma Aplicação 100% OO – Parte 5

Uma visão prática e realista do desenvolvimento de sistemas orientados a objetos.

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).

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('')", _ 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=&id=", _ +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=", +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

Artigos relacionados