sexta-feira, 12 de novembro de 2010

Dicas simples para análise e desenvolvimento de software

Olá, estudantes de análise/programação e afins.

Neste artigo eu pretendo dar algumas dicas simples para você que gosta de desenvolver software. Sim, essa é para você que curte passar noites em claro na frente do PC programando aquele aplicativo inovador ou aquele protótipo de jogo que você nem pretende que seja um jogo completo, você só quer ter o prazer de programar alguns pedaços do sistema e ver se funcionam como esperado! Aqui você vai encontrar dicas para agilizar e facilitar a análise e o desenvolvimento das suas parafernalhas programáticas que você tanto ama.

Um detalhe importante, é que aqui eu não discuto sobre UML nem outras linguagens de modelagem/especificação ou ferramentas programáticas que são úteis na análise de sistemas, porque aqui eu pretendo valorizar a simplicidade e clareza para os iniciantes nessa área, e dificilmente um iniciante vai entender UML.

Portanto, como iniciante em análise/desenvolvimento aqui você vai se sentir à vontade, aqui você não vai ver diagramas UML complicados nem terminologia obscura. Mas chega de papo-furado, vamos ao que interessa!

As dicas aqui se referem basicamente à programação estruturada, por isso você pode aplicá-las ao programar em qualquer linguagem deste paradigma, como C, por exemplo.

Importante deixar claro também, é que quando se fala em Análise e Desenvolvimento de Sistemas eu sou adepto ao chamado "Modelo em Cascata". O modelo em cascata é um modelo de desenvolvimento de software seqüencial no qual o desenvolvimento é visto como um fluir constante para frente (como uma cascata) através das fases de análise de requisitos, projeto, implementação, testes (validação), integração, e manutenção de software. Saiba mais sobre isso na Wikipédia, clicando aqui: Modelo em Cascata, ou veja o original em inglês (bem mais detalhado) aqui: Waterfall Model.


Etapas da Análise e Desenvolvimento de Sistema no modelo em cascata



Dicas para a análise do sistema


A primeira coisa a fazer quando você decide desenvolver um software é definir os requisitos e especificá-lo. Isso na prática significa o seguinte: Você precisa escrever um documento detalhando tudo o que o futuro software deverá fazer, como ele deverá ser, tudo nos mínimos detalhes. Esse documento é o que chamamos de Documento de Especificação. Parece muito trabalho? Dependendo do tamanho do projeto não chega a ser uma parte tão trabalhosa. Dizem que essa é a parte mais importante pois tudo o que você especificar no documento deverá ser implementado no sistema depois, então esse documento facilita o seu trabalho quando você estiver desenvolvendo o código do programa.

Para escrever um documento de especificação basta você abrir o Bloco de Notas ou o Word e usar a cabeça. Lembre-se também de que isso não é o programa em si, isso é somente um documento de especificação onde você apenas vai escrever em bom e claro português. Você não vai digitar código nenhum por enquanto, afinal aqui você ainda está na parte da análise.

Importante deixar claro também, é que estas dicas são destinadas a você que programa sozinho em casa, para as suas parafernalhas programáticas simples e individuais. Se você trabalha em grupo ou o seu projeto é enorme ou muito sofisticado, talvez você precise de outras ferramentas como UML, já que nesses casos um simples documentinho de especificação como esse não vai ser suficiente.

Enfim, um modelo que você pode seguir é o seguinte, observe abaixo o "esqueleto" de um documento de especificação em 6 passos (no meu estilo):

Esqueleto de um Documento de Especificação simples:

1º - Cabeçalho
2º - Objetivo
3º - Detalhes
4º - Objetos necessários
5º - Funções necessárias
6º - Constantes necessárias

Veja agora mais detalhes sobre cada passo a seguir:

Cabeçalho:

Aqui você coloca o nome do software sendo analisado (provisório, até você arrumar um nome decente)

Objetivo(s):

Aqui você descreve em texto simples e em bom português o objetivo do software que você pretende desenvolver. Não é uma redação sobre o programa, aqui você simplesmente vai deixar claro para si mesmo o que o programa é, para que ele vai servir, qual é o propósito dele. Você obviamente não vai analisar nem desenvolver um software que não sirva pra p**** nenhuma, né? Dependendo do tamanho do seu projeto, você vai precisar descrever um maior ou menor número de linhas. Veja exemplo tirado do meu pequeno aplicativo Map Editor:

"O objetivo do programa é permitir que o usuário edite um arquivo de mapa e seja capaz de salvá-lo, ou que o usuário possa carregar um arquivo de mapa previamente salvo para visualizá-lo e/ou editá-lo."

No exemplo acima, obviamente, "editar" um arquivo é uma descrição muito abstrata. E o que seria um "arquivo de mapa"? Acontece que os detalhes de "como fazer tal coisa" ou "o que é tal coisa" você define depois. Essa parte é apenas uma visão geral.

Detalhes:

Nesta parte você vai discutir os detalhes que ficaram mal-explicados na parte "Objetivos". No exemplo que citei do meu programa Map Editor, a parte do "editar" um arquivo ficou mal-explicada. Editar como? E que tipo de arquivo é esse? O que é um "arquivo de mapa"? Como abrir e salvar esse arquivo? No meu exemplo, eu resolvi essa parte explicando o que é um "mapa" no contexto do meu programa e qual o formato desse tipo arquivo, ou seja, eu realmente desenvolvi um novo tipo de arquivo que somente o meu programa sabe abrir e sabe o que fazer com ele. Nesta parte você deve especificar todos os detalhes, de forma generalizada, de como o programa executará suas funções. Veja como eu especifiquei todos esses detalhes nesta parte no documento:

O Mapa:

Um mapa é apenas um array bidimensional (uma matriz) de tamanho fixo, sempre menor ou igual ao tamanho de linhas e colunas da tela de um console do Windows (tipo a janela do prompt de comando). Os valores do array são do tipo "chtype", que é um tipo definido na biblioteca Curses. Este tipo de dados encapsula um caractere ASCII com uma cor de frente e uma cor de fundo.

Quando o usuário editar um mapa, ele estará alterando diretamente os dados "chtype" de dentro da matriz.

Ao salvar o mapa, o programa apenas enviará todos os dados do array com o tipo "int", pois no Windows o tipo "chtype" tem o mesmo tamanho de um "int".

Ao carregar o mapa, o programa lerá todos os "int" do arquivo e os converterá cada um em um "chtype", colocando cada um no array bidimensional, e quando terminar, irá mostrar o mapa na tela, permitindo que o usuário visualize e/ou edite este mapa.

Como você deve ter percebido, eu especifiquei detalhes do que seria o "mapa" no contexto do meu programa, inclusive citei a biblioteca que seria utilizada para auxiliar o programa nas suas funções, e no caso do meu programa a biblioteca Curses foi escolhida.

Como neste meu exemplo eu precisei criar um novo tipo de arquivo, eu tive que especificar isso também, portanto se houver um tipo específico de arquivo que o seu programa precise, você deve especificar (se já não tiver sido especificado) o formato do arquivo e detalhes de como escrever/ler este tipo de arquivo. Seguindo o mesmo exemplo do meu programa, veja como eu especifiquei o formato de um "arquivo de mapa":

Formato do arquivo de mapa:

Um arquivo de mapa contem três seções:

1ª seção - Contém o nome do mapa com no máximo 80 caracteres.
2ª seção - Contém uma descrição do mapa com no máximo 256 caracteres.
3ª seção - Contém todos os dados que representam elementos do mapa em si (isto é, os valores "int" que serão convertidos em "chtype" pelo programa). O tamanho desta seção corresponde ao tamanho do array bidimensional representando o mapa dentro do programa, ou seja, a quantidade de valores "int" no arquivo corresponde à expressão matemática: LINHAS_DO_ARRAY * COLUNAS_DO_ARRAY.

Por convenção, um arquivo de mapa possui a extensão ".MAP".

Seguindo todas estas informações da parte de "Detalhes", você já tem uma boa idéia dos objetos e funções que você vai precisar para finalmente implementar o sistema. Veja o que fazer a seguir, nas próximas partes do documento.

Objetos necessários para implementar o sistema:

Aqui é onde você determina quais objetos são necessários para implementar o sistema, baseado em tudo o que ficou especificado na parte de "Detalhes". Por exemplo, no caso do meu programa eu precisava de um array bidimensional para representar internamente um "mapa", como especificado antes. Justamente, o primeiro objeto que me veio à cabeça é o array bidimensional do tipo apropriado. Pois é isso que você deve fazer nesta parte do documento. Aqui você vai realmente fazer uma lista citando cada um dos objetos, variáveis, strings, arrays, etc. que você sabe que o programa vai precisar. Para isso você precisa usar a cabeça por uns minutos (ou horas). Pense em tudo o que o seu programa fará, releia toda a parte de "Detalhes" e "Objetivo" do documento, e determine quais objetos são necessários para que o programa faça o que você pretende. Veja como eu especifiquei essa parte no documento, seguindo o exemplo do meu programa:

Os objetos necessários para implementar o sistema:

- Um array bidimensional do tipo "chtype" (uma matriz de "chtype")
- Coordenadas X e Y para o cursor
- Valor de um caractere ASCII
- Valor de uma cor de fundo
- Valor de uma cor de frente
- Um chtype representando o caractere atual com seus atributos de cor
- Uma variável booleana para indicar se a edição automática está habilitada/desabilitada
- Uma variável booleana para indicar se o arquivo atual já foi salvo (se foi editado) ou não
- Um ponteiro para um arquivo, que será usado para salvar/carregar mapas
- Uma string para representar o nome de arquivo atual
- Uma string para representar o nome do mapa
- Uma string para representar uma descricao do mapa

Reparem que eu determinei uma boa parte dos objetos que eu sabia que o programa iria precisar para funcionar e fazer tudo o que eu pretendia que ele fizesse. Obviamente, depois na hora de programar você vai perceber que alguns ou vários objetos vêm à sua mente na hora da implementação, variáveis que você nem imaginava que iria precisar, ou até mesmo você vai acabar percebendo que aquela variável do documento de especificação nem sequer era necessária no programa. Mas isso é normal, afinal de contas você não é vidente, não tem como prever a direção que o programa vai tomar depois que estiver sendo implementado. Podem (e vão) surgir inconsistências e/ou divergências entre o documento de especificação e o produto final, o software. Desenvolvimento de software seria um processo perfeito se o programa se tornasse exatamente o que o documento especifica. "Software perfeito"... é como diria Pe. Quevedo, "Isto non ecziste!"... Piadas à parte, vejamos o que fazer a seguir.

Funções necessárias para implementar o sistema:

Aqui você vai determinar as funções do seu programa. Facilita se você dividir as funções em categorias, baseando-se no tipo de tarefa ao qual elas estão relacionadas. Por exemplo, funções relacionadas a E/S (entrada e saída) de arquivos, funções relacionadas à UI (interface com o usuário), etc. Para escrever essa parte do documento, você precisa rever todas as partes anteriores. Dessa forma, você vai ter uma visão clara de tudo o que você já decidiu que o programa deverá ser e fazer, bastando aqui fazer uma lista citando cada função que o programa deverá executar em cada situação. Repare como isso é típico de programação estruturada, cuja unidade de programação é justamente a função. Observe como eu especifiquei essa parte, seguindo o mesmo exemplo anterior do meu programa:

As funções necessárias para implementar o sistema:

Relacionadas à entrada/saída de arquivos:

- Abrir um arquivo
- Ler um arquivo, carregando os dados para dentro do programa
- Salvar um arquivo, enviando os dados do mapa para dentro dele

Relacionadas à edição de um mapa:

- Mover cursor
- Selecionar caractere atual
- Selecionar cor de fundo atual
- Selecionar cor de frente atual
- Colocar caractere com seus atributos de cor no mapa
- Obter um caractere do mapa com seus atributos de cor e torná-lo o caractere atual
- Preencher todo o mapa com o caractere atual
- Apagar o caractere na posicao do cursor
- Apagar todo o mapa
- Habilitar/desabilitar edição automática (quando habilitado basta mover o cursor para que o programa coloque o caractere atual na posição do cursor automaticamente)

Relacionadas ao diálogo com o usuário, avisos, confirmações, etc.:

- Acusar algum erro
- Perguntar o nome do arquivo a ser salvo
- Perguntar o nome do arquivo a ser carregado
- Perguntar qual o nome do mapa
- Perguntar qual a descrição do mapa
- Pedir confirmação para apagar todo o mapa
- Pedir confirmação para sair do programa ou carregar outro mapa antes de salvar o atual, caso ele não tenha sido salvo ainda

Relacionadas à GUI (interface gráfica com o usuário):

- Desenhar a janela de edição dentro da qual aparece o mapa e o cursor
- Desenhar o cursor nas suas coordenadas
- Desenhar a barra de título onde aparece o nome do mapa atual
- Desenhar a barra de status onde aparecem várias informações como as coordenadas do cursor, o caractere atual com seus atributos (o valor do chtype), o nome do arquivo atual, etc.
- Desenhar todas as janelas nas suas posições corretas dentro da tela
- Desenhar (ou "refrescar") o mapa dentro da janela de edição

Observem neste exemplo acima, como eu categorizei todas as funções, citando a qual parte do sistema elas estão relacionadas. Concluindo isso, veja a última parte do documento de especificação.

Constantes necessárias para implementar o sistema:

Nesta última seção do documento, você vai fazer uma lista citando todas as constantes que você prevê serem necessárias para auxiliar a implementação do sistema. Quando eu digo "constantes" eu quero dizer os "valores constantes", isto é, em alguma linguagem de programação, seria aquela variável que você determina o valor dela e esse valor continua o mesmo durante toda a execução do programa. Usamos constantes, por exemplo, para determinar a largura, altura e posição de uma janela (parte da interface gráfica) fixa do programa, de forma que ela sempre apareça no mesmo lugar e sempre tenha o mesmo tamanho. Ou então para determinar o valor mínimo ou máximo de uma variável. Existem muitas situações onde é útil a definição de constantes. E é justamente nesta parte do documento que você vai listar todas as que você no momento imagina que serão necessárias. Seguindo o exemplo do meu programa, vejam a lista que fiz das constantes:

As definições (constantes) necessárias para implementar o sistema:

- Coordenadas X e Y da janela de edição
- Altura e largura da janela de edição
- Altura e largura de um mapa (corresponde ao número de linhas e colunas do array bidimensional que representa internamente um mapa)
- Coordenadas X e Y da barra de status
- Coordenadas X e Y da barra de título
- Coordenadas X e Y da linha de diálogo (onde aparecem os prompts para receber nomes de arquivo, nomes de mapas e descrições)

Obviamente, no código final do programa existem MUITO mais constantes do que as que eu especifiquei no documento. Isso porque durante a implementação surgem outros detalhes imprevistos, e acaba sendo necessário a definição de constantes e até de outros objetos e funções auxiliares que estão (e estarão eternamente) ausentes do documento de especificação.

Enfim, o documento de especificação é isso. Debulhar todo o programa antes mesmo de programar. Partindo desse documento, agora basta transformar tudo isso em código na linguagem que você quizer. Este programa cujo exemplo eu expus aqui foi implementado em C e C++.


Dicas para a implementação do sistema


Com o documento de especificação aberto no seu desktop, você já pode começar a programar, sempre baseando-se nele. Você vai começar definindo num arquivo de cabeçalho (em C) todas as constantes da lista no documento (usando #define, por exemplo). Então, você vai pegar a lista dos objetos no documento e vai declará-los no código. Por exemplo, se você escreveu na lista: "uma string contendo o nome do usuário", você vai no código e declara "String usuario" ou (em C) "char* usuario". Assim você vai declarando todos os objetos da lista, um por um. Depois você vai pegar a lista das funções no documento e declará-las no código também, uma por uma. E por último, a implementação das funções. Nessa parte, naturalmente vão começar a surgir diversos objetos, constantes e funções auxiliares que você não havia especificado no documento. Isso é normal, como já expliquei antes. Então não se preocupe. Seguindo o documento de especificação e improvisando tudo aquilo que não foi especificado por algum motivo ou outro, e testando cada função desenvolvida, você eventualmente vai chegar ao produto final: O SOFTWARE!


Quer ver o pequeno programa que eu usei como exemplo neste artigo? Leia meu artigo sobre o Map Editor, clicando aqui: Map Editor




Espero que as minhas dicas tenham sido úteis. Me deixe saber.